From accd11d960f5de3e9e36d5fd6afc73e0d462bde5 Mon Sep 17 00:00:00 2001 From: highlander Date: Fri, 24 Jul 2026 19:01:20 -0300 Subject: [PATCH 01/22] release(7.15.0-rc18): stage final audit candidate --- .github/workflows/ci.yml | 109 +- .github/workflows/release.yml | 149 +- .gitmodules | 6 +- CMakeLists.txt | 59 +- cmake/toolchains/mingw-w64-x86_64.cmake | 40 + deps/crypto/CMakeLists.txt | 11 + deps/crypto/trezor-firmware | 2 +- deps/device-protocol | 2 +- deps/python-keepkey | 2 +- docs/Generalized-Tendermint-Signing.md | 537 +++++ docs/README.md | 2 + docs/security/7.15.0-rc17-hardening.md | 294 +++ docs/security/7.15.0-rc18-release-shape.md | 43 + include/keepkey/board/bsd_compat.h | 28 + include/keepkey/board/confirm_sm.h | 4 + include/keepkey/board/draw.h | 25 + include/keepkey/board/font.h | 5 + include/keepkey/board/layout.h | 15 + include/keepkey/board/messages.h | 6 + include/keepkey/board/util.h | 5 +- include/keepkey/emulator/libkkemu.h | 78 +- include/keepkey/firmware/app_confirm.h | 14 + include/keepkey/firmware/app_layout.h | 10 +- include/keepkey/firmware/authenticator.h | 5 +- include/keepkey/firmware/binance.h | 4 + include/keepkey/firmware/bip85.h | 22 + include/keepkey/firmware/coins.def | 2 + include/keepkey/firmware/coins.h | 2 + include/keepkey/firmware/eip712.h | 14 +- include/keepkey/firmware/eos.h | 3 + include/keepkey/firmware/ethereum.h | 3 + .../firmware/ethereum_contracts/thortx.h | 28 +- .../firmware/ethereum_contracts/zxliquidtx.h | 3 + include/keepkey/firmware/ethereum_tokens.h | 10 +- include/keepkey/firmware/fsm.h | 20 + include/keepkey/firmware/hive.h | 261 +++ include/keepkey/firmware/mayachain.h | 9 + include/keepkey/firmware/osmosis.h | 25 +- include/keepkey/firmware/reset.h | 10 + include/keepkey/firmware/signed_metadata.h | 223 +++ include/keepkey/firmware/signtx_tendermint.h | 15 +- include/keepkey/firmware/solana.h | 17 + include/keepkey/firmware/storage.h | 20 +- include/keepkey/firmware/tendermint.h | 6 + include/keepkey/firmware/thorchain.h | 20 +- include/keepkey/firmware/tiny-json.h | 5 +- include/keepkey/firmware/tron.h | 55 + include/keepkey/firmware/zcash.h | 384 ++++ include/keepkey/transport/interface.h | 2 + .../transport/messages-ethereum.options | 3 + .../keepkey/transport/messages-hive.options | 58 + .../keepkey/transport/messages-ripple.options | 2 + .../keepkey/transport/messages-solana.options | 1 + .../transport/messages-thorchain.options | 1 + .../keepkey/transport/messages-zcash.options | 54 + lib/board/confirm_sm.c | 51 +- lib/board/draw.c | 85 +- lib/board/font.c | 44 +- lib/board/layout.c | 149 +- lib/board/messages.c | 130 +- lib/board/signatures.c | 48 +- lib/board/timer.c | 30 +- lib/board/udp.c | 6 + lib/board/usb.c | 49 +- lib/board/util.c | 61 +- lib/emulator/CMakeLists.txt | 7 + lib/emulator/libkkemu.c | 337 +++- lib/emulator/setup.c | 33 +- lib/emulator/udp.c | 10 +- lib/firmware/CMakeLists.txt | 65 +- lib/firmware/app_confirm.c | 176 +- lib/firmware/app_layout.c | 92 +- lib/firmware/authenticator.c | 105 +- lib/firmware/binance.c | 76 +- lib/firmware/bip85.c | 105 + lib/firmware/coins.c | 2 + lib/firmware/eip712.c | 600 +++--- lib/firmware/eos.c | 26 +- lib/firmware/ethereum.c | 210 +- lib/firmware/ethereum_contracts.c | 24 +- lib/firmware/ethereum_contracts/saproxy.c | 3 +- lib/firmware/ethereum_contracts/thortx.c | 232 ++- lib/firmware/ethereum_contracts/zxappliquid.c | 196 +- lib/firmware/ethereum_contracts/zxliquidtx.c | 258 +-- lib/firmware/ethereum_contracts/zxswap.c | 20 +- .../ethereum_contracts/zxtransERC20.c | 4 + lib/firmware/ethereum_tokens.c | 5 +- lib/firmware/fsm.c | 44 +- lib/firmware/fsm_msg_binance.h | 45 +- lib/firmware/fsm_msg_bip85.h | 142 ++ lib/firmware/fsm_msg_coin.h | 9 +- lib/firmware/fsm_msg_common.h | 75 +- lib/firmware/fsm_msg_cosmos.h | 31 +- lib/firmware/fsm_msg_crypto.h | 36 +- lib/firmware/fsm_msg_ethereum.h | 240 ++- lib/firmware/fsm_msg_hive.h | 1024 ++++++++++ lib/firmware/fsm_msg_mayachain.h | 99 +- lib/firmware/fsm_msg_osmosis.h | 261 +-- lib/firmware/fsm_msg_ripple.h | 15 + lib/firmware/fsm_msg_solana.h | 569 ++++-- lib/firmware/fsm_msg_tendermint.h | 75 +- lib/firmware/fsm_msg_thorchain.h | 95 +- lib/firmware/fsm_msg_ton.h | 87 +- lib/firmware/fsm_msg_tron.h | 201 +- lib/firmware/fsm_msg_zcash.h | 1414 +++++++++++++ lib/firmware/hive.c | 1096 ++++++++++ lib/firmware/mayachain.c | 206 +- lib/firmware/messagemap.def | 48 + lib/firmware/osmosis.c | 100 +- lib/firmware/recovery_cipher.c | 81 +- lib/firmware/reset.c | 34 +- lib/firmware/ripple.c | 19 + lib/firmware/signed_metadata.c | 1068 ++++++++++ lib/firmware/signtx_tendermint.c | 94 +- lib/firmware/solana.c | 246 ++- lib/firmware/storage.c | 253 ++- lib/firmware/storage.h | 43 + lib/firmware/storage_versions.inc | 3 +- lib/firmware/tendermint.c | 42 + lib/firmware/thorchain.c | 285 ++- lib/firmware/tiny-json.c | 8 +- lib/firmware/transaction.c | 9 + lib/firmware/tron.c | 359 ++++ lib/firmware/zcash.c | 1133 +++++++++++ lib/rand/rng.c | 50 +- lib/transport/CMakeLists.txt | 18 + scripts/build/docker/device/release.sh | 7 +- scripts/emulator/python-keepkey-tests.sh | 9 +- tools/check_sram_budget.py | 124 ++ tools/emulator/CMakeLists.txt | 44 +- tools/firmware/CMakeLists.txt | 4 +- tools/firmware/keepkey.ld | 10 + tools/sram-budgets.json | 9 + unittests/crypto/CMakeLists.txt | 16 + unittests/firmware/CMakeLists.txt | 37 +- unittests/firmware/app_confirm.cpp | 42 + unittests/firmware/authenticator.cpp | 111 ++ unittests/firmware/binance.cpp | 83 + unittests/firmware/coins.cpp | 11 + unittests/firmware/cosmos.cpp | 46 +- unittests/firmware/eip712.cpp | 67 + unittests/firmware/eos.cpp | 17 + unittests/firmware/ethereum.cpp | 216 +- unittests/firmware/hive.cpp | 983 +++++++++ unittests/firmware/mayachain.cpp | 176 +- unittests/firmware/osmosis.cpp | 158 ++ unittests/firmware/signed_metadata.cpp | 1551 +++++++++++++++ unittests/firmware/solana.cpp | 369 +++- unittests/firmware/storage.cpp | 132 +- unittests/firmware/thorchain.cpp | 644 +++++- unittests/firmware/tron.cpp | 495 +++++ unittests/firmware/zcash.cpp | 1757 +++++++++++++++++ 152 files changed, 20961 insertions(+), 1786 deletions(-) create mode 100644 cmake/toolchains/mingw-w64-x86_64.cmake create mode 100644 docs/Generalized-Tendermint-Signing.md create mode 100644 docs/security/7.15.0-rc17-hardening.md create mode 100644 docs/security/7.15.0-rc18-release-shape.md create mode 100644 include/keepkey/board/bsd_compat.h create mode 100644 include/keepkey/firmware/bip85.h create mode 100644 include/keepkey/firmware/hive.h create mode 100644 include/keepkey/firmware/signed_metadata.h create mode 100644 include/keepkey/firmware/zcash.h create mode 100644 include/keepkey/transport/messages-hive.options create mode 100644 include/keepkey/transport/messages-zcash.options create mode 100644 lib/firmware/bip85.c create mode 100644 lib/firmware/fsm_msg_bip85.h create mode 100644 lib/firmware/fsm_msg_hive.h create mode 100644 lib/firmware/fsm_msg_zcash.h create mode 100644 lib/firmware/hive.c create mode 100644 lib/firmware/signed_metadata.c create mode 100644 lib/firmware/zcash.c create mode 100644 tools/check_sram_budget.py create mode 100644 tools/sram-budgets.json create mode 100644 unittests/firmware/app_confirm.cpp create mode 100644 unittests/firmware/authenticator.cpp create mode 100644 unittests/firmware/binance.cpp create mode 100644 unittests/firmware/eip712.cpp create mode 100644 unittests/firmware/hive.cpp create mode 100644 unittests/firmware/osmosis.cpp create mode 100644 unittests/firmware/signed_metadata.cpp create mode 100644 unittests/firmware/tron.cpp create mode 100644 unittests/firmware/zcash.cpp diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 784473e79..4f433560c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,15 +9,16 @@ # └─ check-submodules verify all deps present # # Stage 2: BUILD (parallel, gated by Stage 1) -# ├─ build-emulator Docker image → artifact -# └─ build-arm-firmware cross-compile → .bin/.elf (downloadable) +# ├─ build-emulator Docker image → artifact [matrix: full / bitcoin-only] +# └─ build-arm-firmware cross-compile → .bin/.elf (downloadable) [same matrix] # # Stage 3: TEST (parallel, gated by Stage 2) -# ├─ unit-tests GoogleTest (make xunit) -# └─ python-integration full test suite +# ├─ unit-tests GoogleTest (make xunit) [same matrix — proves each +# │ variant's coin/token gating actually compiles+passes] +# └─ python-integration full test suite (full/default variant only) # # Stage 4: PUBLISH (manual trigger, all tests must pass) -# └─ publish-emulator DockerHub push (workflow_dispatch only) +# └─ publish-emulator DockerHub push, full/default variant only (workflow_dispatch only) name: CI @@ -99,7 +100,7 @@ jobs: static-analysis: runs-on: ubuntu-latest - timeout-minutes: 5 + timeout-minutes: 10 steps: - name: Checkout uses: actions/checkout@v6 @@ -212,9 +213,22 @@ jobs: # ═══════════════════════════════════════════════════════════ build-emulator: + name: build-emulator${{ matrix.label }} needs: [lint-format, static-analysis, check-submodules, secret-scan] runs-on: ubuntu-latest timeout-minutes: 15 + strategy: + fail-fast: false + matrix: + include: + # Regular/full includes every supported chain, including Zcash + # shielded/Orchard. Bitcoin-only is the sole reduced build. + - variant: full + label: "" + cmake_flags: "" + - variant: bitcoin-only + label: " (bitcoin-only)" + cmake_flags: "-DKK_BITCOIN_ONLY=ON" steps: - name: Checkout uses: actions/checkout@v6 @@ -250,27 +264,39 @@ jobs: if: steps.cache-base.outputs.cache-hit == 'true' run: docker load -i /tmp/base-image.tar - - name: Build emulator image + - name: Build emulator image (${{ matrix.variant }}) run: | docker build \ - -t ${{ env.EMU_IMAGE }} \ + -t ${{ env.EMU_IMAGE }}-${{ matrix.variant }} \ + --build-arg coinsupport="${{ matrix.cmake_flags }}" \ -f scripts/emulator/Dockerfile \ . - name: Save emulator image - run: docker save ${{ env.EMU_IMAGE }} -o /tmp/emu-image.tar + run: docker save ${{ env.EMU_IMAGE }}-${{ matrix.variant }} -o /tmp/emu-image.tar - name: Upload emulator image artifact uses: actions/upload-artifact@v7 with: - name: emu-image + name: emu-image-${{ matrix.variant }} path: /tmp/emu-image.tar retention-days: 1 build-arm-firmware: + name: build-arm-firmware${{ matrix.label }} needs: [lint-format, static-analysis, check-submodules, secret-scan] runs-on: ubuntu-latest timeout-minutes: 15 + strategy: + fail-fast: false + matrix: + include: + - variant: full + label: "" + cmake_flags: "" + - variant: bitcoin-only + label: " (bitcoin-only)" + cmake_flags: "-DKK_BITCOIN_ONLY=ON" steps: - name: Checkout uses: actions/checkout@v6 @@ -312,7 +338,7 @@ jobs: echo "git_short=${GIT_SHORT}" >> "$GITHUB_OUTPUT" echo "Firmware version: ${FW_VERSION} (${GIT_SHORT})" - - name: Cross-compile firmware for ARM + - name: Cross-compile firmware for ARM (${{ matrix.variant }}) run: | docker run --rm \ -v ${{ github.workspace }}:/root/keepkey-firmware:z \ @@ -320,34 +346,55 @@ jobs: mkdir /root/build && cd /root/build && \ cmake -C /root/keepkey-firmware/cmake/caches/device.cmake /root/keepkey-firmware \ -DCMAKE_BUILD_TYPE=MinSizeRel \ - -DCMAKE_COLOR_MAKEFILE=ON && \ + -DCMAKE_COLOR_MAKEFILE=ON \ + ${{ matrix.cmake_flags }} && \ make && \ mkdir -p /root/keepkey-firmware/bin && \ cp bin/*.bin /root/keepkey-firmware/bin/ && \ cp bin/*.elf /root/keepkey-firmware/bin/ && \ + cp bin/*.map /root/keepkey-firmware/bin/ 2>/dev/null || true && \ + arm-none-eabi-size -A bin/firmware.keepkey.elf > /root/keepkey-firmware/bin/firmware.keepkey.size.txt 2>/dev/null || true && \ + find . -name '*.su' -print0 | tar czf /root/keepkey-firmware/bin/stack-usage.tgz --null -T - && \ chmod -R a+rw /root/keepkey-firmware/bin" + # SRAM budget gate — RC7's privacy-enabled build hard-faulted on boot + # because static SRAM left an 11.2 KB gap while msg_write() carried a + # 12.4 KB stack frame. keepkey.ld now ASSERTs a 16 KiB reserve at link + # time; this step reports the numbers and enforces the frame margin + # (tools/sram-budgets.json). + - name: SRAM budget gate (${{ matrix.variant }}) + run: | + pip install --quiet pyelftools + python3 tools/check_sram_budget.py \ + --elf bin/firmware.keepkey.elf \ + --su-tar bin/stack-usage.tgz \ + --budgets tools/sram-budgets.json \ + --variant "${{ matrix.variant }}" + - name: Rename firmware artifacts run: | cd bin for f in *.bin; do [ -f "$f" ] || continue - mv "$f" "firmware.keepkey.v${{ steps.version.outputs.fw_version }}-${{ steps.version.outputs.git_short }}-${f}" + mv "$f" "firmware.keepkey.v${{ steps.version.outputs.fw_version }}-${{ steps.version.outputs.git_short }}-${{ matrix.variant }}-${f}" done for f in *.elf; do [ -f "$f" ] || continue - mv "$f" "firmware.keepkey.v${{ steps.version.outputs.fw_version }}-${{ steps.version.outputs.git_short }}-${f}" + mv "$f" "firmware.keepkey.v${{ steps.version.outputs.fw_version }}-${{ steps.version.outputs.git_short }}-${{ matrix.variant }}-${f}" done ls -lh - echo "::notice::Firmware v${{ steps.version.outputs.fw_version }} built successfully" + echo "::notice::Firmware v${{ steps.version.outputs.fw_version }} (${{ matrix.variant }}) built successfully" - name: Upload firmware artifacts uses: actions/upload-artifact@v7 with: - name: firmware-v${{ steps.version.outputs.fw_version }}-${{ steps.version.outputs.git_short }} + name: firmware-v${{ steps.version.outputs.fw_version }}-${{ steps.version.outputs.git_short }}-${{ matrix.variant }} path: | bin/*.bin bin/*.elf + bin/*.map + bin/*.size.txt + bin/stack-usage.tgz retention-days: 90 # ═══════════════════════════════════════════════════════════ @@ -355,27 +402,38 @@ jobs: # ═══════════════════════════════════════════════════════════ unit-tests: + name: unit-tests${{ matrix.label }} needs: build-emulator runs-on: ubuntu-latest timeout-minutes: 10 + strategy: + fail-fast: false + matrix: + include: + - variant: full + label: "" + cmake_flags: "" + - variant: bitcoin-only + label: " (bitcoin-only)" + cmake_flags: "-DKK_BITCOIN_ONLY=ON" steps: - name: Download emulator image uses: actions/download-artifact@v8 with: - name: emu-image + name: emu-image-${{ matrix.variant }} path: /tmp - name: Load emulator image run: docker load -i /tmp/emu-image.tar - - name: Run unit tests + - name: Run unit tests (${{ matrix.variant }}) run: | # make xunit returns non-zero if any test fails — capture # exit code so JUnit XML still gets copied for reporting docker run --rm \ -v ${{ github.workspace }}/test-reports:/kkemu/test-reports \ --entrypoint /bin/sh \ - ${{ env.EMU_IMAGE }} \ + ${{ env.EMU_IMAGE }}-${{ matrix.variant }} \ -c "mkdir -p /kkemu/test-reports/firmware-unit && \ make xunit; RC=\$?; \ cp -r unittests/*.xml /kkemu/test-reports/firmware-unit/ 2>/dev/null; \ @@ -385,7 +443,7 @@ jobs: uses: actions/upload-artifact@v7 if: always() with: - name: unit-test-results + name: unit-test-results-${{ matrix.variant }} path: test-reports/firmware-unit/ retention-days: 30 @@ -684,7 +742,9 @@ jobs: uses: actions/download-artifact@v4 continue-on-error: true with: - name: unit-test-results + # Report covers the regular/full build. Bitcoin-only is built and + # unit-tested in its own matrix leg but does not get a PDF. + name: unit-test-results-full path: test-reports/firmware-unit/ - name: Download python test results @@ -744,7 +804,8 @@ jobs: - name: Download emulator image uses: actions/download-artifact@v8 with: - name: emu-image + # Publish the regular/full image, including Zcash privacy support. + name: emu-image-full path: /tmp - name: Load emulator image @@ -759,8 +820,8 @@ jobs: - name: Tag images for publish run: | - docker tag ${{ env.EMU_IMAGE }} kktech/kkemu:latest - docker tag ${{ env.EMU_IMAGE }} kktech/kkemu:v${{ steps.version.outputs.fw_version }} + docker tag ${{ env.EMU_IMAGE }}-full kktech/kkemu:latest + docker tag ${{ env.EMU_IMAGE }}-full kktech/kkemu:v${{ steps.version.outputs.fw_version }} - name: Login to DockerHub uses: docker/login-action@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ee6c178c7..5603f459b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,14 +1,14 @@ # KeepKey Firmware Release Pipeline # -# Triggered by version tags (v*) on master. +# Triggered by version tags (v*). # Builds firmware, computes reproducible hashes, # and creates a draft GitHub Release with all artifacts. # -# Git-flow: tag master after merging a release/* or hotfix/* branch. +# Tag a commit only after its CI workflow has completed successfully. # # Usage: -# git tag v7.11.0 -# git push origin v7.11.0 +# git tag -a v7.15.0-rc17 -m "KeepKey firmware 7.15.0 RC17 test candidate" +# git push origin v7.15.0-rc17 name: Release @@ -29,19 +29,53 @@ jobs: timeout-minutes: 3 outputs: fw_version: ${{ steps.version.outputs.fw_version }} + tag_name: ${{ steps.version.outputs.tag_name }} + is_prerelease: ${{ steps.version.outputs.is_prerelease }} steps: - uses: actions/checkout@v6 - with: - submodules: recursive - name: Extract and verify version id: version run: | TAG_VERSION="${GITHUB_REF_NAME#v}" FW_VERSION=$(sed -n '/^project/,/)/p' CMakeLists.txt | grep -oP '\d+\.\d+\.\d+') - echo "fw_version=${FW_VERSION}" >> "$GITHUB_OUTPUT" + IS_PRERELEASE=false + RC_PREFIX="${FW_VERSION}-rc" + if [ "$TAG_VERSION" != "$FW_VERSION" ]; then - echo "::error::Tag (${TAG_VERSION}) != CMakeLists.txt (${FW_VERSION})" + if [[ "$TAG_VERSION" != "${RC_PREFIX}"* ]]; then + echo "::error::Tag (${TAG_VERSION}) must be ${FW_VERSION} or ${RC_PREFIX}" + exit 1 + fi + + RC_NUMBER="${TAG_VERSION#"${RC_PREFIX}"}" + if ! [[ "$RC_NUMBER" =~ ^[0-9]+$ ]]; then + echo "::error::Invalid release-candidate tag (${TAG_VERSION}); expected ${RC_PREFIX}" + exit 1 + fi + IS_PRERELEASE=true + fi + + { + echo "fw_version=${FW_VERSION}" + echo "tag_name=${GITHUB_REF_NAME}" + echo "is_prerelease=${IS_PRERELEASE}" + } >> "$GITHUB_OUTPUT" + + - name: Require green CI on the tagged commit + env: + GH_TOKEN: ${{ github.token }} + run: | + # A tag on a red (or untested) commit must not produce release + # artifacts. The tagged SHA already ran the CI workflow on its + # branch push; require that run to exist and have succeeded. + CONCLUSION=$(gh run list --repo "$GITHUB_REPOSITORY" \ + --workflow CI --commit "$GITHUB_SHA" \ + --json status,conclusion \ + --jq '[.[] | select(.status == "completed")] | map(.conclusion) | first') + echo "CI conclusion for $GITHUB_SHA: ${CONCLUSION:-none}" + if [ "$CONCLUSION" != "success" ]; then + echo "::error::No successful CI run found for ${GITHUB_SHA} — refusing to release." exit 1 fi @@ -49,10 +83,25 @@ jobs: needs: validate runs-on: ubuntu-latest timeout-minutes: 20 + strategy: + fail-fast: false + matrix: + include: + - variant: full + cmake_flags: "" + - variant: bitcoin-only + cmake_flags: "-DKK_BITCOIN_ONLY=ON" steps: - uses: actions/checkout@v6 - with: - submodules: recursive + + - name: Init required submodules + run: | + git submodule update --init deps/crypto/trezor-firmware + git submodule update --init deps/device-protocol + git submodule update --init --recursive deps/python-keepkey + git submodule update --init deps/googletest + git submodule update --init deps/qrenc/QR-Code-generator + git submodule update --init deps/sca-hardening/SecAESSTM32 - name: Cache base image id: cache-base @@ -71,7 +120,7 @@ jobs: if: steps.cache-base.outputs.cache-hit == 'true' run: docker load -i /tmp/base-image.tar - - name: Cross-compile firmware + - name: Cross-compile firmware (${{ matrix.variant }}) run: | docker run --rm \ -v ${{ github.workspace }}:/root/keepkey-firmware:z \ @@ -79,18 +128,31 @@ jobs: mkdir /root/build && cd /root/build && \ cmake -C /root/keepkey-firmware/cmake/caches/device.cmake /root/keepkey-firmware \ -DCMAKE_BUILD_TYPE=MinSizeRel \ - -DCMAKE_COLOR_MAKEFILE=ON && \ + -DCMAKE_COLOR_MAKEFILE=ON \ + ${{ matrix.cmake_flags }} && \ make && \ mkdir -p /root/keepkey-firmware/release && \ cp bin/firmware.keepkey.bin /root/keepkey-firmware/release/ && \ cp bin/firmware.keepkey.elf /root/keepkey-firmware/release/ && \ cp bin/bootloader.bin /root/keepkey-firmware/release/ 2>/dev/null || true && \ + find . -name '*.su' -print0 | tar czf /root/keepkey-firmware/release/stack-usage.tgz --null -T - && \ chmod -R a+rw /root/keepkey-firmware/release" + # Same SRAM budget gate CI enforces (rc8 boot-fault class): release + # artifacts must clear it too, not just the 16 KiB linker ASSERT. + - name: SRAM budget gate (${{ matrix.variant }}) + run: | + pip install --quiet pyelftools + python3 tools/check_sram_budget.py \ + --elf release/firmware.keepkey.elf \ + --su-tar release/stack-usage.tgz \ + --budgets tools/sram-budgets.json \ + --variant "${{ matrix.variant }}" + - name: Compute hashes working-directory: release run: | - echo "# KeepKey Firmware v${{ needs.validate.outputs.fw_version }} — Hash Manifest" > HASHES.txt + echo "# KeepKey Firmware v${{ needs.validate.outputs.fw_version }} (${{ matrix.variant }}) — Hash Manifest" > HASHES.txt echo "" >> HASHES.txt for f in *.bin; do [ -f "$f" ] || continue @@ -109,15 +171,17 @@ jobs: working-directory: release run: | VER="${{ needs.validate.outputs.fw_version }}" - [ -f firmware.keepkey.bin ] && mv firmware.keepkey.bin "firmware.keepkey.v${VER}.bin" - [ -f firmware.keepkey.elf ] && mv firmware.keepkey.elf "firmware.keepkey.v${VER}.elf" - [ -f bootloader.bin ] && mv bootloader.bin "bootloader.v${VER}.bin" + VARIANT="${{ matrix.variant }}" + [ -f firmware.keepkey.bin ] && mv firmware.keepkey.bin "firmware.keepkey.v${VER}-${VARIANT}.bin" + [ -f firmware.keepkey.elf ] && mv firmware.keepkey.elf "firmware.keepkey.v${VER}-${VARIANT}.elf" + [ -f bootloader.bin ] && mv bootloader.bin "bootloader.v${VER}-${VARIANT}.bin" + mv HASHES.txt "HASHES-${VARIANT}.txt" ls -lh - name: Upload release artifacts uses: actions/upload-artifact@v7 with: - name: release-firmware + name: release-firmware-${{ matrix.variant }} path: release/* retention-days: 90 @@ -125,10 +189,25 @@ jobs: needs: validate runs-on: ubuntu-latest timeout-minutes: 20 + strategy: + fail-fast: false + matrix: + include: + - variant: full + cmake_flags: "" + - variant: bitcoin-only + cmake_flags: "-DKK_BITCOIN_ONLY=ON" steps: - uses: actions/checkout@v6 - with: - submodules: recursive + + - name: Init required submodules + run: | + git submodule update --init deps/crypto/trezor-firmware + git submodule update --init deps/device-protocol + git submodule update --init --recursive deps/python-keepkey + git submodule update --init deps/googletest + git submodule update --init deps/qrenc/QR-Code-generator + git submodule update --init deps/sca-hardening/SecAESSTM32 - name: Cache base image id: cache-base @@ -147,10 +226,12 @@ jobs: if: steps.cache-base.outputs.cache-hit == 'true' run: docker load -i /tmp/base-image.tar - - name: Build and test emulator + - name: Build and test emulator (${{ matrix.variant }}) run: | - docker build -t kkemu-release -f scripts/emulator/Dockerfile . - docker run --rm --entrypoint /bin/sh kkemu-release \ + docker build -t kkemu-release-${{ matrix.variant }} \ + --build-arg coinsupport="${{ matrix.cmake_flags }}" \ + -f scripts/emulator/Dockerfile . + docker run --rm --entrypoint /bin/sh kkemu-release-${{ matrix.variant }} \ -c "make xunit; RC=\$?; exit \$RC" create-release: @@ -163,30 +244,41 @@ jobs: - name: Download firmware artifacts uses: actions/download-artifact@v8 with: - name: release-firmware + pattern: release-firmware-* path: artifacts + merge-multiple: true - name: Prepare release assets run: | mkdir -p release-assets - cp artifacts/*.bin artifacts/*.elf artifacts/HASHES.txt release-assets/ + cp artifacts/*.bin artifacts/*.elf artifacts/HASHES-*.txt release-assets/ ls -lh release-assets/ - name: Generate release body run: | VER="${{ needs.validate.outputs.fw_version }}" cat > release-body.md <.txt \`\`\` - > **DRAFT** — firmware must be signed by 3/5 key holders before publishing. + > **DRAFT TEST CANDIDATE** — RC artifacts are unsigned and intended for + > release-candidate testing. Firmware must be signed by 3/5 key holders + > before publishing a production release. - ### Signing Checklist + ### Signing Checklist (per variant) - [ ] Built on multiple machines, hashes match - [ ] Signed on air-gapped machine (3/5 signers) - [ ] Storage upgrade tested on production device @@ -198,7 +290,8 @@ jobs: uses: softprops/action-gh-release@v2 with: draft: true - name: "Firmware v${{ needs.validate.outputs.fw_version }}" + prerelease: ${{ needs.validate.outputs.is_prerelease }} + name: "Firmware ${{ needs.validate.outputs.tag_name }}" body_path: release-body.md files: release-assets/* fail_on_unmatched_files: true diff --git a/.gitmodules b/.gitmodules index 2d6c4446a..b8d6fe804 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,7 +1,7 @@ [submodule "deps/device-protocol"] path = deps/device-protocol -url = https://github.com/keepkey/device-protocol.git -branch = master + url = https://github.com/keepkey/device-protocol.git +branch = up/release-protocol [submodule "deps/trezor-firmware"] path = deps/crypto/trezor-firmware url = https://github.com/keepkey/trezor-firmware.git @@ -14,7 +14,7 @@ url = https://github.com/keepkey/code-signing-keys.git [submodule "deps/python-keepkey"] path = deps/python-keepkey url = https://github.com/keepkey/python-keepkey.git -branch = master +branch = reconcile/upstream-sync [submodule "deps/qrenc/QR-Code-generator"] path = deps/qrenc/QR-Code-generator url = https://github.com/keepkey/QR-Code-generator.git diff --git a/CMakeLists.txt b/CMakeLists.txt index cee2e661e..a2d8d7979 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ endif() project( KeepKeyFirmware - VERSION 7.14.1 + VERSION 7.15.0 LANGUAGES C CXX ASM) set(BOOTLOADER_MAJOR_VERSION 2) @@ -20,6 +20,16 @@ option(KK_EMULATOR "Build the emulator" OFF) option(KK_BUILD_DYLIB "Build libkkemu shared library (.dylib/.so)" OFF) option(KK_DEBUG_LINK "Build with debug-link enabled" OFF) option(KK_BUILD_FUZZERS "Build the fuzzers?" OFF) +option(KK_BITCOIN_ONLY "Build Bitcoin-only firmware (strip all non-BTC coins)" OFF) +# Zcash shielded/Orchard support is part of the regular firmware. It is an +# internal compile selection, not a third release variant: bitcoin-only strips +# the Zcash coin and privacy engine; every regular device/emulator build ships +# both. Keep the value macro below so bitcoin-only can compile the sources out. +if(KK_BITCOIN_ONLY) + set(KK_ZCASH_PRIVACY OFF) +else() + set(KK_ZCASH_PRIVACY ON) +endif() # When building the dylib, every static lib it links (kkfirmware, kkboard, # trezorcrypto, kkrand, kktransport, qrcodegenerator, SecAESSTM32, ...) must @@ -84,6 +94,13 @@ endif() if(${KK_EMULATOR}) add_definitions(-DEMULATOR) add_definitions(-DCONFIDENTIAL=) + # macOS/BSD declare strlcpy/strlcat in ; glibc (Linux) and MinGW + # (Windows) do not. Force-include the prototypes so the ~20 call sites build + # without -Werror=implicit-function-declaration (definitions come from + # lib/board/strlcpy.c + strlcat.c). Apple already has them in . + if(NOT APPLE) + add_compile_options(-include ${CMAKE_SOURCE_DIR}/include/keepkey/board/bsd_compat.h) + endif() else() add_definitions(-DCONFIDENTIAL=__attribute__\(\(section\("confidential"\)\)\)) endif() @@ -97,13 +114,21 @@ add_definitions(-DED25519_FORCE_32BIT=1) add_definitions(-DUSE_PRECOMPUTED_CP=0) -add_definitions(-DUSE_ETHEREUM=1) +if(${KK_BITCOIN_ONLY}) + # Bitcoin-only: strip the coin-specific trezor-crypto primitives whose only + # callers (ethereum.c / nano.c) are compiled out below. KECCAK stays on -- + # marginal size win, and it is a generic hash we don't want to risk. + add_definitions(-DUSE_ETHEREUM=0) + add_definitions(-DUSE_NANO=0) +else() + add_definitions(-DUSE_ETHEREUM=1) + add_definitions(-DUSE_NANO=1) +endif() add_definitions(-DUSE_KECCAK=1) add_definitions(-DUSE_GRAPHENE=0) add_definitions(-DUSE_CARDANO=0) add_definitions(-DUSE_MONERO=0) add_definitions(-DUSE_NEM=0) -add_definitions(-DUSE_NANO=1) add_definitions(-DRAND_PLATFORM_INDEPENDENT=0) @@ -123,12 +148,34 @@ add_definitions(-DBIP39_WORDLIST_PADDED=1) add_definitions(-DAES_128=1) +# NOTE: AES table size is selected per release product below. The regular +# image includes Zcash and its Pallas curve arithmetic, so it uses the smaller +# AES tables to preserve flash headroom. Bitcoin-only keeps FOUR_TABLES AES. + if(${KK_DEBUG_LINK}) add_definitions(-DDEBUG_LINK=1) else() add_definitions(-DDEBUG_LINK=0) endif() +# Value macros (always defined 0/1) -- device builds use -Wundef -Werror, so an +# undefined identifier in `#if` is a hard error. Guard code with `#if FLAG`. +if(${KK_BITCOIN_ONLY}) + add_definitions(-DBITCOIN_ONLY=1) +else() + add_definitions(-DBITCOIN_ONLY=0) +endif() + +if(${KK_ZCASH_PRIVACY}) + add_definitions(-DZCASH_PRIVACY=1) + # The Orchard engine leaves the regular image tightest on flash; shrink the + # Gladman AES lookup tables from 4KB to 1KB each (-15,360 bytes ROM, + # slightly slower AES). Bitcoin-only keeps the fast FOUR_TABLES. + add_definitions(-DAES_SMALL_TABLES) +else() + add_definitions(-DZCASH_PRIVACY=0) +endif() + if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") add_definitions(-DDEBUG_ON) add_definitions(-DMEMORY_PROTECT=0) @@ -161,6 +208,12 @@ if(NOT ${KK_EMULATOR}) link_directories(${LIBOPENCM3_PATH}/lib) include_directories(${LIBOPENCM3_PATH}/include) + # Emit per-function stack-frame sizes (.su files) on device builds. CI's + # SRAM budget gate (tools/check_sram_budget.py) reports the largest frames + # and fails when the linker-asserted stack reserve minus the largest frame + # leaves less than the configured margin. See tools/firmware/keepkey.ld. + add_compile_options(-fstack-usage) + # Dummy empty libraries for stack smashing protection support, since we # implement __stack_chk_guard and __stack_chk_fail ourselves. file(WRITE ${CMAKE_BINARY_DIR}/ssp.c "") diff --git a/cmake/toolchains/mingw-w64-x86_64.cmake b/cmake/toolchains/mingw-w64-x86_64.cmake new file mode 100644 index 000000000..974f1a49c --- /dev/null +++ b/cmake/toolchains/mingw-w64-x86_64.cmake @@ -0,0 +1,40 @@ +# MinGW-w64 cross-compile toolchain for the Windows emulator DLL (libkkemu.dll, +# x86_64). Lets us cross-build the Windows DLL from the existing macOS/Linux +# emulator build host — no Windows runner required. +# +# Usage: +# cmake -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/mingw-w64-x86_64.cmake \ +# -DKK_EMULATOR=ON -DKK_BUILD_DYLIB=ON -DKK_DEBUG_LINK=ON ... +# cmake --build --target kkemulator_dylib +# +# Install MinGW: `brew install mingw-w64` (macOS) / `apt-get install mingw-w64`. +# +# Only the kkemulator_dylib target is meant to cross-compile. The standalone +# UDP `kkemu` binary is gated out on Windows (tools/emulator/CMakeLists.txt). + +set(CMAKE_SYSTEM_NAME Windows) +set(CMAKE_SYSTEM_PROCESSOR x86_64) + +set(TOOLCHAIN_PREFIX x86_64-w64-mingw32) +find_program(CMAKE_C_COMPILER NAMES ${TOOLCHAIN_PREFIX}-gcc) +find_program(CMAKE_CXX_COMPILER NAMES ${TOOLCHAIN_PREFIX}-g++) +find_program(CMAKE_RC_COMPILER NAMES ${TOOLCHAIN_PREFIX}-windres) + +if(NOT CMAKE_C_COMPILER) + message(FATAL_ERROR + "${TOOLCHAIN_PREFIX}-gcc not found. Install MinGW-w64 " + "(brew install mingw-w64 / apt-get install mingw-w64).") +endif() + +# Derive the target sysroot from the compiler location so this works across +# Homebrew versions and Linux package layouts. +get_filename_component(_kk_cc "${CMAKE_C_COMPILER}" REALPATH) +get_filename_component(_kk_bin "${_kk_cc}" DIRECTORY) +get_filename_component(_kk_root "${_kk_bin}/.." ABSOLUTE) +set(CMAKE_FIND_ROOT_PATH "${_kk_root}/${TOOLCHAIN_PREFIX}") + +# Find host programs on the host; libraries/headers in the target sysroot. +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) diff --git a/deps/crypto/CMakeLists.txt b/deps/crypto/CMakeLists.txt index cd735668c..47ca306f2 100644 --- a/deps/crypto/CMakeLists.txt +++ b/deps/crypto/CMakeLists.txt @@ -57,6 +57,17 @@ set(sources #trezor-firmware/crypto/aes/aestst.c trezor-firmware/crypto/aes/aestab.c) +# Pallas/Orchard curve arithmetic (~2.4k LOC) -- only the Zcash shielded engine +# uses it. Excluded from the default and bitcoin-only images. +if(${KK_ZCASH_PRIVACY}) + list(APPEND sources + trezor-firmware/crypto/pallas.c + trezor-firmware/crypto/pallas_sinsemilla.c + trezor-firmware/crypto/pallas_swu.c + trezor-firmware/crypto/redpallas.c + trezor-firmware/crypto/zcash_zip316.c) +endif() + # Clang 5.0 in the docker image (kktech/firmware:v7) is missing # , which breaks these. Until they're needed, we'll just elide # them. diff --git a/deps/crypto/trezor-firmware b/deps/crypto/trezor-firmware index 03d8a55a8..56f404e45 160000 --- a/deps/crypto/trezor-firmware +++ b/deps/crypto/trezor-firmware @@ -1 +1 @@ -Subproject commit 03d8a55a832fb61bb89477ef7239a80ecb367080 +Subproject commit 56f404e452bc7738cd3b3e14454dfecb25c083bf diff --git a/deps/device-protocol b/deps/device-protocol index d637b7829..47e19d8b0 160000 --- a/deps/device-protocol +++ b/deps/device-protocol @@ -1 +1 @@ -Subproject commit d637b78291a423fd8119df9935a9365be8a7758e +Subproject commit 47e19d8b0816db20e15d9b1e27da83c70d5ed88d diff --git a/deps/python-keepkey b/deps/python-keepkey index fabd6c618..892ae04ff 160000 --- a/deps/python-keepkey +++ b/deps/python-keepkey @@ -1 +1 @@ -Subproject commit fabd6c6189b7f1b3ea7cbd1d372fc13729761178 +Subproject commit 892ae04ff3cefea5f57c516e7f796bf1939eb810 diff --git a/docs/Generalized-Tendermint-Signing.md b/docs/Generalized-Tendermint-Signing.md new file mode 100644 index 000000000..69ee80588 --- /dev/null +++ b/docs/Generalized-Tendermint-Signing.md @@ -0,0 +1,537 @@ +# Generalized Cosmos and Tendermint signing + +Status: future design proposal + +This document describes a path to full Cosmos SDK `SIGN_MODE_DIRECT` support, +generalized Tendermint/CometBFT-family signing, and IBC transfers across supported +chains. It is not part of the 7.15.0-rc17 release scope and does not change that +release's acceptance criteria. + +The name "Tendermint" is retained where it refers to the existing KeepKey +protocol. New code should use the more precise terms "Cosmos SDK" and +"CometBFT-family." + +## Product position + +Blind signing with an explicit warning is a valid first support tier for a new +chain or message type. KeepKey already uses this phased model for Ethereum +contract data and opaque Solana, TRON, TON, and EOS operations. Generalized +Cosmos support should follow the same model: + +1. Sign the exact transaction bytes in Advanced Mode after an unmistakable blind + signing warning. +2. Parse and display transaction envelope fields that can be bound to those + exact bytes. +3. Add clear-signing adapters for common messages over time. +4. Automatically replace blind review with clear review as message adapters + become available. + +Unknown does not mean forbidden. It means the device must never present an +unknown message as understood. + +This distinction makes broad compatibility practical: + +- A Cosmos SDK transaction using a supported key algorithm and + `SIGN_MODE_DIRECT` can be signed even when one or more `Any` message values are + not understood by the firmware. +- Recognized messages receive semantic clear-signing screens. +- Unrecognized messages receive blind-signing screens and an exact transaction + commitment. +- A non-Cosmos application built on Tendermint or CometBFT can reuse the + generalized byte-signing engine, but still needs an adapter defining its + signing domain, preimage, and key algorithm. A Cosmos `SignDoc` is not a + universal transaction format for every CometBFT application. + +The target is therefore universal signing compatibility for supported +algorithms and defined signing domains, not a claim that the firmware +semantically understands every application. + +## Goals + +- Implement Cosmos SDK protobuf `SIGN_MODE_DIRECT`. +- Preserve legacy Amino support for chains that still require it. +- Blind-sign otherwise valid, unsupported Cosmos messages behind Advanced Mode. +- Progressively clear-sign known bank, staking, distribution, governance, IBC, + authz, feegrant, CosmWasm, and chain-specific messages. +- Derive and display addresses for arbitrary compatible chains without + conflating display names, registry identities, and Bech32 prefixes. +- Support arbitrary Cosmos coin denoms, canonical integer amounts, multiple + coins, fee grants, and fee payers within explicit resource limits. +- Clear-sign ICS-20 transfers for all valid routes and assets, including + voucher, factory, and long trace-derived denoms. +- Reuse a bounded, session-oriented byte-signing core for non-Cosmos + CometBFT-family adapters. +- Keep every reviewed value cryptographically bound to the exact signed + preimage. + +## Non-goals and boundaries + +- The firmware does not discover IBC paths, channels, counterparty chains, or + relayers. The host builds the route; the device reviews the source-chain + transaction. +- Blind signing does not provide semantic verification. A digest and byte count + prove which bytes were approved, not what an unknown message will do. +- Host-provided labels, symbols, decimals, recipients, or amounts must never + substitute for values parsed from the signed bytes. +- `SIGN_MODE_DIRECT` does not cover every non-Cosmos CometBFT application. + Applications with different signing preimages or algorithms require explicit + adapters. +- Multisig, `SIGN_MODE_DIRECT_AUX`, `SIGN_MODE_TEXTUAL`, and non-secp256k1 keys + are not implied by the first implementation. They require explicit protocol + and UX decisions. + +## Current implementation and gaps + +The existing generic Tendermint protocol is a legacy Amino implementation. It is +useful compatibility code, but it is not a base for universal support. + +| Area | Current behavior | Required v2 behavior | +| --- | --- | --- | +| Sign mode | Legacy Amino JSON only | Exact protobuf `SignDoc` bytes for `SIGN_MODE_DIRECT`, plus legacy Amino | +| Generic messages | Wire schema advertises several message types; firmware handler accepts only `send` | Known messages clear-sign; every other valid `Any` can blind-sign | +| IBC | Generic IBC schema has no amount field | Bind token, sender, receiver, port, channel, timeouts, and memo | +| Amounts | Message amount is `uint64`; fee is `uint32` | Canonical unsigned decimal strings with an explicit maximum | +| Denoms | Generic denom is limited to 9 characters | Long exact denoms, including `ibc/<64-hex>` and factory denoms | +| Fees | One session-wide denom is reused | Repeated fee coins, independent message coins, gas, payer, and granter | +| Chain identity | `chain_name` is both coin lookup name and address HRP; `address_prefix` is ignored | Immutable, separate chain ID, registry ID, display name, and HRPs | +| Address support | Limited by the compiled coin registry | Validated chain descriptors and explicit path policy | +| Tests | Generic coverage is primarily session/config binding | Cross-SDK vectors, parser adversarial tests, emulator UX, and hardware QA | +| Host integration | Generic address support is partial; generic signing is not end-to-end | Protocol, hdwallet, Vault, registry, builder, and broadcast support | + +The existing `Tendermint*`, `Cosmos*`, and `Osmosis*` message IDs must remain +compatible. The new design should use new v2 message IDs and implementation +state rather than changing the meaning or size limits of old fields. + +## Signing and review tiers + +The transaction is assigned the least-trusted tier required by any component. +One unknown message downgrades the transaction to blind or mixed review; it must +not inherit a clear-sign label from neighboring known messages. + +### Tier A: clear signing + +All security-relevant fields are parsed from the exact signed bytes and displayed: + +- chain ID and signing account; +- message actions, senders, recipients, validators, contracts, and parameters; +- exact coin amounts and denoms; +- memo and timeout values; +- fees, gas, payer, granter, and sequence as applicable. + +Friendly symbols or decimal conversion may supplement raw values only when the +metadata is trusted and the exact denom remains reviewable. + +### Tier B: mixed review + +The firmware understands the transaction envelope and some messages, but at +least one message or extension is opaque. It: + +- clearly labels the whole transaction as containing unverified actions; +- displays all safely parsed envelope and known-message fields; +- displays each unknown `type_url`, value byte count, and value digest; +- displays an overall signing-preimage digest and byte count; +- requires Advanced Mode and explicit blind-sign confirmation. + +### Tier C: blind signing + +The adapter can validate the signing domain and sign the exact preimage, but +cannot semantically parse the application payload. It: + +- requires Advanced Mode; +- displays a prominent "Blind Sign" warning; +- displays the chain/signing domain, derivation path or derived address, exact + byte count, and full transaction digest; +- never displays host side-channel values as if they came from the transaction; +- signs only after an explicit final confirmation. + +Malformed framing, an unsupported key algorithm, a path that cannot be bound to +the signer, an oversized payload, or an ambiguous/non-canonical clear-sign parse +is rejected. Unsupported semantics alone may fall back to Tier B or C. + +Advanced Mode is a hard gate, not the only warning. Enabling it once does not +silently approve future blind signatures. + +## Exact-byte invariant + +The principal invariant is: + +> The device hashes and signs exactly the bytes whose properties and digest it +> reviewed. + +For `SIGN_MODE_DIRECT`, the secp256k1 signature is over the SHA-256 digest of the +serialized `cosmos.tx.v1beta1.SignDoc`: + +- `body_bytes` +- `auth_info_bytes` +- `chain_id` +- `account_number` + +The preferred protocol streams the serialized `SignDoc` bytes to the device. +The device simultaneously: + +1. validates ordered chunk framing and the declared total length; +2. hashes the exact incoming bytes; +3. parses display information from those same immutable bytes; +4. binds the selected key and signer information; +5. performs the required review flow; +6. signs the accumulated digest without reconstructing a different `SignDoc`. + +Hashing host-provided structured fields and later reserializing them creates an +avoidable display/signature mismatch risk. If structured transport is retained +for memory reasons, the framing itself must define one canonical serialized +preimage and the firmware must both parse and hash that exact stream. + +For Tier A clear signing, protobuf handling must reject encodings whose meaning +could differ between the firmware and a node, including ambiguous duplicate +singular fields, malformed or overlong varints, invalid lengths, truncated +submessages, conflicting signer modes, and unsupported critical extension +options. A structurally valid unknown `Any` is not malformed and may use the +blind tier. + +For Tier B or C, the transaction digest should be shown in full using the +existing exact-byte pager. The digest is an exact commitment, not a semantic +summary. + +## Proposed v2 protocol + +Exact names and field numbers require a device-protocol review. The logical flow +is: + +```text +CosmosSignDirectInit + -> CosmosSignDirectRequest(offset, max_chunk) + -> CosmosSignDirectChunk(offset, bytes) + -> ... repeat ... + -> device review + -> CosmosSignedDirect(public_key, signature, sign_doc_hash) +``` + +`CosmosSignDirectInit` should bind at least: + +- derivation path; +- expected serialized `SignDoc` length; +- expected SHA-256 digest, used only as a transport cross-check; +- requested signing mode and key algorithm; +- optional registry identity and descriptor version; +- host-declared review expectation, which the device may only downgrade. + +The device owns the running offset, remaining length, parser state, and hash. +Chunks must be contiguous and accepted exactly once. Any unexpected message, +offset, length, initialization attempt, cancellation, USB reset, or parser error +aborts and wipes the session. + +The response returns the compressed public key, compact 64-byte signature, and +the device-computed `SignDoc` digest so the host can cross-check the exact +preimage. + +The implementation should not accept a host-computed digest as the only thing +to sign. A future prehashed expert primitive, if ever required by a distinct +application, must be a separately named domain, use a stronger warning, and +display the complete digest. + +## Direct-mode parser + +The parser operates incrementally with bounded memory. It recognizes: + +- `TxBody.messages` as repeated `Any { type_url, value }`; +- memo and timeout height; +- extension and non-critical extension options; +- `AuthInfo.signer_infos`, public keys, `ModeInfo`, and sequence; +- `Fee.amount`, gas limit, payer, and granter; +- tip fields where the target SDK supports them. + +Initial scope should require one signer and `SIGN_MODE_DIRECT`. The firmware +derives the public key, verifies that the signer info and account address belong +to that key where those values are available, and rejects a mode substitution. +Multisig and multi-signer transactions should remain unsupported until the +review flow and signature assembly contract are specified. + +Message adapters consume the exact `Any.value` bytes. They may promote a message +to clear signing only after: + +- the `type_url` is an exact supported value; +- required fields and canonical encodings validate; +- signer/owner/sender fields bind to the derived key where applicable; +- all security-relevant fields fit and are reviewable; +- unknown critical fields cannot change the reviewed meaning. + +An adapter failure caused by unknown semantics downgrades to blind review. A +failure caused by malformed or contradictory encoding rejects the transaction. + +## Chain descriptors and addresses + +A v2 chain descriptor separates values that the legacy protocol conflates: + +- immutable registry ID and descriptor version; +- network chain ID; +- display name; +- account, validator, and consensus Bech32 HRPs; +- derivation path policy and SLIP-0044 coin type; +- public-key/signature algorithm; +- allowed sign modes; +- trusted native asset metadata, if any. + +The transaction-bound chain ID is always displayed. A friendly chain name cannot +replace it. + +Descriptors may be firmware-curated or supplied by a host registry with an +authenticated provenance model. Until that trust model is implemented, +host-supplied metadata is untrusted: display raw chain ID, HRP, path, exact denom, +and atomic amount. An unknown descriptor may still use blind signing when its +algorithm and address construction are supported. + +Address requests must use the explicit account HRP, not a coin lookup name. +Non-standard paths require the existing path warning policy. The displayed +address and the signing key must be derived from the same descriptor and path. + +The first algorithm target is Cosmos-style secp256k1. Ethermint +`ethsecp256k1`, ed25519, and other application key types require explicit +derivation, address, signature, and test-vector support; they must not be +silently treated as standard Cosmos secp256k1. + +## Coins, amounts, and fees + +The v2 schema should model Cosmos `Coin` directly: + +```text +Coin { + string denom + string amount +} +``` + +- `amount` is a canonical unsigned base-10 integer string: digits only, no sign, + whitespace, decimal point, exponent, or leading zeroes except `"0"`. +- Firmware defines and tests an explicit maximum digit count. A 256-bit ceiling + is a reasonable initial engineering target, subject to SDK compatibility and + OLED/resource tests. +- `denom` has a documented byte maximum large enough for IBC and factory denoms + and validates the relevant Cosmos SDK grammar. +- Every message owns its own coin list; fee coins are independent and repeated. +- Unknown metadata displays atomic amount plus exact denom. Trusted metadata may + add a decimal rendering but cannot hide the atomic pair. + +## IBC support + +The first clear-sign IBC adapter should support the protobuf +`ibc.applications.transfer.v1.MsgTransfer` forms used by target SDK versions. +Review must bind and show: + +- source port and channel; +- token amount and exact denom; +- sender and receiver; +- timeout height revision number and revision height; +- timeout timestamp; +- memo, including packet-forwarding JSON as exact text unless a separately + validated adapter interprets it. + +This works for native denoms, `ibc/` voucher denoms, factory denoms, and +other valid source-chain denominations. The firmware does not need a compiled +pairwise matrix of every source and destination chain. + +"IBC between all supported chains" means the host may construct any valid +source-chain ICS-20 route and the device can sign it. It does not mean the device +asserts that a channel reaches the host-claimed destination. Without trusted, +fresh channel proofs, the device should display the exact port/channel and +receiver rather than invent a destination-chain guarantee. + +IBC messages from unknown modules remain viable through the blind tier. + +## Legacy Amino + +Legacy Amino remains available for older chains but should also receive a v2 +transport rather than extending the current fixed-width schema. + +Two safe approaches are possible: + +1. stream the exact canonical Amino JSON sign bytes and blind-sign them; or +2. stream typed fields while the firmware constructs one canonical JSON + preimage and clear-signs supported message adapters. + +The first approach provides broad compatibility sooner. The second provides +stronger semantic review. They can coexist, with exact-byte blind support first +and structured adapters added incrementally. + +The v2 Amino model must separate message and fee denoms, use string amounts, +support long denoms and multiple coins, and bind all configuration to one +session. The old protocol continues unchanged for compatibility. + +## Non-Cosmos CometBFT applications + +The generalized core should expose an internal adapter contract: + +```text +domain identifier +preimage framing rules +hash function +key/signature algorithm +optional bounded parser +review classification +``` + +A new application can begin at Tier C by defining and testing its exact signing +preimage. Later parser adapters can promote its operations to Tier B or A. This +is the path to genuinely broad Tendermint/CometBFT support without pretending +all applications share Cosmos protobuf transaction semantics. + +Every external protocol gets a distinct domain identifier. Cross-domain ACKs, +chunks, finalization calls, and session reuse are rejected. + +## Rollout + +### Phase 0: specification and vectors + +- Freeze v2 threat model, wire flow, limits, canonical protobuf policy, and abort + behavior. +- Collect `SIGN_MODE_DIRECT` golden vectors from Cosmos SDK and at least one + independent host implementation. +- Choose an initial descriptor trust model and supported key algorithms. + +### Phase 1: universal Cosmos direct blind signing + +- Stream and hash exact `SignDoc` bytes on device. +- Validate the envelope enough to establish domain, chain ID, signer mode, + signer key, and resource safety. +- Permit unknown `Any` messages through Tier B/C in Advanced Mode. +- Show the blind warning, path/address, byte count, and full digest. +- Return signature, public key, and device-computed digest. + +This phase deliberately provides useful new-chain support before every module +has a clear-signing adapter. + +### Phase 2: envelope clear signing + +- Clear-sign chain ID, account number, sequence, memo, timeout, fee coins, gas, + payer, and granter when parsed unambiguously. +- Add trusted/untrusted chain descriptor UX. +- Downgrade extension options that are valid but not understood. + +### Phase 3: common message clear signing + +- Bank send and multi-send. +- Staking delegate, undelegate, redelegate, and cancel-unbonding. +- Distribution rewards and validator commission. +- Governance vote, deposit, and proposal variants. +- ICS-20 transfer. + +### Phase 4: application adapters + +- CosmWasm execute/instantiate/migrate, with contract payload remaining blind + until schema-aware review exists. +- Authz and feegrant, including nested-message downgrade rules. +- Chain-specific modules chosen by use and risk. +- Additional CometBFT signing domains and key algorithms. + +### Phase 5: default clear signing + +- Promote well-tested chains and message families to Tier A by default. +- Keep Advanced Mode fallback for valid unknown additions so protocol upgrades + do not make the chain unusable. + +## Workstreams + +| Repository/layer | Work | +| --- | --- | +| device-protocol | Add v2 init/chunk/request/response messages, limits, generated bindings, and message IDs | +| firmware transport | Session isolation, ordered streaming, abort/wipe behavior, and response framing | +| firmware crypto | Exact-byte hashing, secp256k1 signing, key/signer binding, and domain separation | +| firmware parser | Bounded `SignDoc`, `TxBody`, `AuthInfo`, `Any`, `Coin`, and message adapters | +| firmware UX | Tier labels, blind warning, digest/byte count, exact-value paging, and cancellation | +| hdwallet | Generic address and sign APIs, chunk driver, registry plumbing, and signature cross-checks | +| Vault | Generic address/sign endpoints, policy errors, transport recovery, and no metadata substitution | +| chain registry | Versioned descriptors, HRPs, paths, algorithms, assets, and provenance | +| host integrations | Transaction building, IBC route discovery, broadcast, and chain test vectors | +| QA/release | Unit, emulator, hardware OLED, fuzzing, interoperability, and downgrade tests | + +## Test and release gates + +### Cryptographic and interoperability + +- Device signatures match Cosmos SDK and independent host vectors. +- The returned digest equals SHA-256 of the exact serialized `SignDoc`. +- Signatures verify and broadcast on representative SDK versions and chains. +- Legacy Amino behavior remains byte-for-byte compatible. + +### Parser and transport adversarial tests + +- truncated fields and submessages; +- oversized lengths, integer overflow, and resource-limit boundaries; +- non-minimal/overlong varints and duplicate singular fields; +- unknown fields, unknown `Any` values, and extension options; +- chunk replay, gaps, overlap, reordering, early finalization, and excess bytes; +- session replacement, cross-domain ACKs, stale chunks, and USB interruption; +- signer-mode, public-key, path, chain-ID, fee, and sequence substitution; +- cancellation from every screen, proving that no signature is returned. + +### Review classification + +- fully known transactions are Tier A; +- any opaque nested or top-level action forces Tier B/C; +- unknown semantics can blind-sign in Advanced Mode; +- malformed transactions never downgrade to blind signing; +- no host-only label is presented as signed data; +- blind review always shows warning, byte count, and full digest; +- disabling Advanced Mode blocks every blind path. + +### Asset and IBC matrix + +- native, IBC voucher, factory, slash-containing, and maximum-length denoms; +- maximum amount values and multiple message/fee coins; +- native and non-native fee denoms; +- IBC timeout height, timeout timestamp, memo, and no-timeout edge cases; +- receivers with different valid HRPs and maximum supported length; +- packet-forwarding memos and unknown IBC module messages; +- representative Cosmos Hub, Osmosis, THORChain/MAYAChain-style legacy, and + additional SDK chains. + +### Device evidence + +- full firmware and constrained configurations fit ROM/SRAM budgets; +- parser stack frames retain the required reserve; +- fuzz targets and sanitizer builds pass on the host; +- emulator and physical OLED captures prove every maximum-length field can be + reviewed; +- cancellation and blind-sign policy behavior pass on physical hardware. + +## Open decisions + +- Stream a complete serialized `SignDoc`, or stream its exact field framing? + Complete exact bytes are preferred if the incremental parser can meet memory + limits. +- Require canonical protobuf for all tiers, or only for clear signing? The + safest initial policy is canonical envelope encoding for every tier. +- Use only global Advanced Mode, or add a per-session blind-sign capability? + Initial recommendation: Advanced Mode plus confirmation on every transaction. +- What descriptor provenance is trusted enough for symbols and decimals? +- What exact maxima apply to transaction bytes, nesting, messages, denoms, + amounts, HRPs, and type URLs? +- Which Ethermint key/address variants are in the first supported algorithm set? +- How should multisig, multiple signer infos, tips, fee payers, authz nesting, + and fee grants be reviewed? +- When should `SIGN_MODE_DIRECT_AUX` and `SIGN_MODE_TEXTUAL` be added? +- Which legacy Amino chains require exact JSON streaming before direct-mode + support? + +## Definition of done + +The generalized Cosmos milestone is complete when: + +- any structurally valid, resource-bounded Cosmos SDK `SIGN_MODE_DIRECT` + transaction using a supported key algorithm can be signed through an explicit + Advanced Mode blind path, even when its messages are unknown; +- known message adapters clear-sign only values parsed from the exact signed + bytes; +- arbitrary valid coin denoms and integer amounts work within documented limits; +- any valid host-constructed ICS-20 source-chain transfer can be signed, without + a compiled pairwise chain matrix; +- the address, signer key, signing mode, chain ID, and signed preimage are bound + to one isolated session; +- malformed data, ambiguous clear-sign encodings, and unsupported algorithms + fail closed; +- cancellation never produces a signature; +- protocol, firmware, hdwallet, Vault, registry, and hardware QA are delivered + together. + +The broader CometBFT-family milestone is complete only when each additional +application has an explicit, tested signing-domain adapter. Its initial adapter +may be blind-only; semantic clear signing can follow. diff --git a/docs/README.md b/docs/README.md index e456f6ad5..0fe1dae06 100644 --- a/docs/README.md +++ b/docs/README.md @@ -5,3 +5,5 @@ * [Supported Coins](Coins.md) * [Host Communications](Host.md) * [Release Process](Release.md) +* [7.15.0 RC18 Release Shape](security/7.15.0-rc18-release-shape.md) +* [Generalized Cosmos and Tendermint Signing](Generalized-Tendermint-Signing.md) diff --git a/docs/security/7.15.0-rc17-hardening.md b/docs/security/7.15.0-rc17-hardening.md new file mode 100644 index 000000000..08c4606ec --- /dev/null +++ b/docs/security/7.15.0-rc17-hardening.md @@ -0,0 +1,294 @@ +# Firmware 7.15.0 RC17 security hardening + +Date: 2026-07-22 +Integration baseline: `develop` at +`d18571307a2f5bad3ec2949c7b27fd06e6914a8c` (RC16 firmware code plus +test-client submodule updates) + +This candidate applies focused hardening passes to security-sensitive parsing, +confirmation, clear-signing, and signing-policy paths. It includes remediation +for three follow-up reviews, including two full-tree static reachability +passes. The `rc17` suffix is a release-candidate branch/tag; the firmware +protocol version remains `7.15.0`. + +The release decision remains **NO-GO** until the pull-request CI matrix is green +and an explicit release decision is made. The physical-device smoke gate below +is complete. Automated evidence, including the generated Python report, is the +authoritative exhaustive screen and boundary review; physical QA is intentionally +limited to major device smoke tests. + +Qualified candidate head: `f746c52b2c0e5584fde9df04471eeb36ebbbf03b`. +Its pull-request CI matrix completed successfully in GitHub Actions run +`29980175333` on 2026-07-23. + +## Follow-up audit block + +The original candidate head +`f7eacc3862fd391bd9e9421474efeaba464d1334` is release-blocked. A follow-up +review found five P1 release blockers, four P2 defects, and one P3 cleanup +defect. It must not be merged, promoted, tagged, or installed for final QA. +Only a later head containing the remediations below may be reconsidered after +its complete CI matrix and physical-device checks pass. + +| Finding | Severity | Remediation | +| --- | --- | --- | +| Hive `custom_json` could wrap below the visible body | P1 | Select every page boundary with the renderer's actual font, width, word-wrap, and three-row limit | +| Uniswap deadline displayed only the low 64 bits | P1 | Reject a deadline with any nonzero upper 192 bits before clear-signing | +| Arbitrary contracts could masquerade as LP approvals | P1 | Require the transaction target to equal a mainnet factory-derived WETH pair for a known token | +| Liquidity recognition was not chain-bound | P1 | Require an explicit Ethereum mainnet chain ID for liquidity and LP approval recognition | +| `removeLiquidityETH` mislabeled LP liquidity as the underlying token | P1 | Parse add/remove independently and format remove word 1 as an 18-decimal LP amount | +| `bn_format()` overflow produced a blank amount | P2 | Use 96-byte amount buffers, check every formatter return, and require the result to fit three rendered rows | +| ABI address words accepted nonzero upper bytes | P2 | Require canonical zero-padded token, recipient, and spender address words | +| Duplicate authenticator identities survived deletion | P2 | Reject new duplicates and remove every legacy matching slot in one confirmed mutation | +| Brute-forceable short TOTP secrets were accepted | P2 | Require at least 16 decoded secret bytes | +| Partial TOTP decode output survived a decode error | P3 | Route every post-decode exit through one `memzero()` cleanup path | + +## Second full-tree re-audit block + +The remediated first-pass head +`9f4920ef144ed3a1e28a04a0621d2f21e48674b3` is also release-blocked. A +full-tree static reachability review found ten additional P1 release blockers. +They are separate from the ten findings above and cover signer memory safety, +display/signature binding, and blind-signing policy enforcement. + +| Finding | Severity | Remediation | +| --- | --- | --- | +| Binance denomination stack overwrite | P1 | Validate the effective 31-character schema bound and grammar, use a correctly sized destination, check formatting, and fail closed on malformed transfer/session state | +| Bitcoin-family `SignMessage` NUL/OOB display mismatch | P1 | Review the explicit protobuf byte length; render complete printable payloads and complete hex for binary payloads | +| Ethereum `SignMessage` hidden suffix | P1 | Remove the 114-character/57-byte preview and page every signed byte | +| TRON `SignMessage` hidden suffix | P1 | Remove the capped preview and page every signed byte | +| Ethereum typed-hash AdvancedMode bypass | P1 | Reject precomputed typed-hash signing unless AdvancedMode is enabled | +| EIP-712 display not bound to canonical values | P1 | Page every field/value and primary type; require canonical address, bytes, integer, boolean, and JSON node shapes before encoding | +| EOS unknown-action AdvancedMode bypass | P1 | Abort opaque action signing when AdvancedMode is disabled and keep `eosio::newaccount` on its structured path | +| Cosmos IBC receiver omitted from review | P1 | Require and page the exact receiver and sender, require the signed `uatom` denomination, and retain channel/port/timeout review | +| Tendermint ACK could substitute asset/protocol fields | P1 | Bind every ACK to the initialized protocol, chain name, denomination, and message-type prefix and review the exact signed configuration | +| Binance/Tendermint/Cosmos/Osmosis memo suffixes hidden | P1 | Route all four through one renderer-measured exact-length pager | + +## Third full-surface re-audit block + +The second-pass remediated head +`a8ec50a72e12741f0a1b9878b863959385fe02a3` is also release-blocked. A +full-surface re-audit confirmed that the prior 20 exploit paths were closed, +then found three additional P1 blockers in the Osmosis signer plus one related +display/signature hardening defect. + +| Finding | Severity | Remediation | +| --- | --- | --- | +| Osmosis `MsgSend` displayed a host denomination but always signed `uosmo` | P1 | Validate and review the supplied canonical denomination, then serialize that exact denomination; native and non-native fixtures must produce different signatures | +| Maximum Send/Swap fields wrapped below the three-row OLED body | P1 | Review each signed amount, denomination, destination, and minimum independently with renderer-measured exact-length pages; hard-wrap overlong identifiers that the legacy renderer would horizontally clip | +| `base_to_precision()` wrote one byte out of bounds and omitted the final LP digit | P1 | Compute the exact destination length, copy every digit without `strlcpy()`, terminate inside the caller's buffer, and fail closed when the output does not fit | +| Noncanonical or overflowing decimal strings displayed a different value than the signed string | P2 | Accept only the canonical unsigned-decimal spelling, enforce protobuf bounds, and reject native `uosmo` values above `UINT64_MAX` before confirmation or hashing | + +## Remediated findings + +### Hive raw-operation review + +- Reject non-canonical LEB128 varints so the reviewed bytes cannot differ from + the chain's canonical reserialization. +- Validate every account field as a Hive account name before rendering it, + rejecting embedded NULs, newlines, controls, and malformed names. +- Bound `custom_json` authorization sets to four accounts, require canonical + ordering and uniqueness, retain every account in the parsed operation, and + confirm each account individually. +- Page the complete custom JSON ID and JSON payload using measured rendered + lines rather than byte-count chunks. The adversarial 69-byte `%`/space + payload from the follow-up audit is covered by a regression test. + +### Authenticator mutations + +- Make add, remove, and wipe operations fail closed when the user cancels. +- Stop authenticator processing when passphrase acquisition fails. +- Reject overlong or control-character domain/account fields before lookup, + display, or mutation. +- Put the TOTP secret on its own confirmation screen so it cannot overflow the + domain/account screen, and wipe the decoded secret from the stack after use. +- Require at least 128 bits of decoded TOTP secret material, reject duplicate + identities, remove all matching legacy duplicates, and wipe partial decoder + output on failure. + +### Legacy Ethereum Uniswap V2 clear-signing + +- Propagate every confirmation result so cancellation cannot continue to a + signature. +- Display the native-asset value for `addLiquidityETH` and reject a nonzero + native value for `removeLiquidityETH`. +- Reject unknown token contracts rather than formatting a misleading amount. +- Require the exact fixed ABI length and declared protobuf field shape before + any selector or fixed-offset read; trailing calldata is not clear-signed. +- Require Ethereum mainnet, canonical ABI address padding, a deadline that fits + the displayed 64-bit Unix value, and a factory-derived known LP pair for + approval clear-signing. +- Parse add/remove amount semantics separately, display liquidity burned as an + 18-decimal LP amount, check all amount-formatting returns, and keep every + formatted uint256 within the OLED body budget. +- Wipe the derived HD node after the recipient-address comparison. + +### Exact-byte message and memo review + +- Add one shared confirmation primitive that accepts an explicit byte length, + computes page boundaries with the OLED renderer's font, width, word wrapping, + and three-row body limit, and propagates rejection from every page. +- Render printable ASCII completely as text. If any byte is a control or + non-ASCII value, render the complete payload as hexadecimal so embedded NULs + and binary suffixes cannot disappear. +- Use the primitive for Bitcoin-family, Ethereum, and TRON message signing and + verification; Binance, Tendermint, Cosmos, and Osmosis memos; and existing + THORChain/MAYAChain/Ripple/TRON memo wrappers. +- Apply the same rule to Solana/TON blind messages, Solana off-chain messages + and memos, identity signing challenges, and Bitcoin-family `OP_RETURN` + review. These adjacent paths had the same preview or C-string failure mode. + +### Signing policies and structured-data parsing + +- Require AdvancedMode for Ethereum precomputed typed-hash signing and EOS + unknown-action signing. A warning is not treated as policy enforcement. +- Keep `EOS_NewAccount` in the supported-action allowlist so it cannot be + downgraded to an opaque fingerprint flow. +- Require exact EIP-712 primitive type syntax and JSON node shapes; reject + short, overlong, non-hex, odd-nibble, or wrong-sized address/bytes values. +- Require exact `EIP712Domain` primary-type matching, page the primary type, + field names, and every value, and fail closed on missing typed values rather + than dereferencing a null JSON node. +- Bound type-string construction and integer parsing, reject invalid boolean + spellings and integer ranges, and remove partially parsed adjacent-memory + behavior from address/bytes encoding. + +### Binance, Cosmos, and generic Tendermint signing + +- Match Binance's effective denomination schema bound, reject unsafe + characters and non-positive/mismatched transfer amounts, and make signer + initialization/update/finalization state explicit and fail closed. +- Require Cosmos IBC receiver, sender, amount, denomination, channel, port, and + both timeout-height components. Review the exact sender and receiver instead + of labeling the sender as the destination. +- Separate Cosmos and generic Tendermint signing sessions so one protocol's ACK + cannot advance the other. Generic ACK metadata must exactly match the + initialized chain name, denomination, and message-type prefix. +- Display generic Tendermint amounts in their exact signed atomic units and + denomination; do not relabel or rescale them with unrelated coin metadata. +- Review the initialized chain ID, chain name, denomination, and message-type + prefix before final signature approval. + +### Osmosis signer invariants + +- Bind legacy Amino `MsgSend` denominations end-to-end, including direct + `OsmosisMsgAck` traffic that bypasses high-level clients. Validate and review + the supplied denomination, pass it into the serializer, and revalidate it at + the hashing boundary so a non-native denomination cannot be displayed while + a hardcoded `uosmo` value is signed. +- Validate every displayed amount as a canonical, schema-bounded unsigned + decimal. Preserve unknown asset amounts exactly, and require native `uosmo` + amounts to fit the supported 64-bit range. +- Validate denomination length and identifier grammar before using it in a + display string or Amino JSON. +- Put Send amount/destination and Swap input/minimum output on independent + renderer-measured confirmations. Force pixel-width hard breaks for long IBC + identifiers so the display behavior matches the pager's three-row model. +- Repair LP share conversion so a maximum 32-digit input retains its final + digit, fits a 34-byte destination, and cannot write beyond the stack buffer. + Make LP maximum/minimum assets and share amounts separately reviewable. +- Apply the same fail-closed amount review to delegate, undelegate, + redelegate, liquidity, Swap, and IBC paths. Require the receiver and amount + fields for Osmosis IBC and fence redelegation to its serialized `uosmo` + denomination. + +## Automated evidence + +All builds used the pinned `kktech/firmware:v15` toolchain image. + +| Configuration | Firmware tests | ARM build | SRAM reserve | Largest frame | Reserve after frame | +| --- | ---: | --- | ---: | ---: | ---: | +| Full, shipped (`KK_ZCASH_PRIVACY=OFF`) | 303/303 | Pass | 23,364 B | 7,664 B | 15,700 B | +| Bitcoin-only | 28/28 | Pass | 32,908 B | 7,664 B | 25,244 B | +| Zcash privacy | 362/362 | Pass | 19,064 B | 7,664 B | 11,400 B | + +Additional gates: + +- 43 focused Hive, authenticator, and Ethereum regression tests pass, + including 14 directly covering the follow-up remediation cluster. +- 19 new or updated regressions directly exercise the second-pass Binance, + exact-byte pager, EIP-712, EOS, Tendermint, and policy remediations. A broader + 34-test security filter covering the affected suites also passes. +- Four new firmware regressions cover canonical and overflow amount rejection, + exact maximum LP formatting with a stack canary, truncation rejection, and + maximum Swap renderer boundaries. Three Python regressions exercise raw-wire + native/non-native denomination signature separation, raw-wire + noncanonical/overflow rejection, and the full maximum-length Swap + review/signing sequence. +- The full Python emulator suite passes 574 tests with 16 expected skips. Its + settled OLED capture shows both 32-digit Swap values and both complete + 68-character IBC denominations before signing. +- The generated Python report contains 303 scenarios: 297 passed, 6 intentionally + skipped, and 0 failed. It is the release evidence for exhaustive confirmation + screens, maximum-length paging, rejection paths, and signing-flow coverage. +- Cppcheck completes with zero findings. +- Changed production files pass the pinned Clang Format 20 gate. +- `git diff --check` passes. +- Every variant exceeds the 16,384-byte SRAM reserve floor and 4,096-byte + reserve-after-largest-frame margin. + +## Physical-device evidence — 2026-07-23 + +The following checks were repeated against a connected physical KeepKey running +the exact candidate revision +`f746c52b2c0e5584fde9df04471eeb36ebbbf03b`. The device reported firmware +`7.15.0`, variant `KeepKey`, and the repository's public disposable QA address +`osmo1rs7fckgznkaxs4sq02pexwjgar43p5wnkx9s92`. Requests were signed locally +through Vault and were not broadcast. + +- Otherwise-identical `MsgSend` transactions using `uosmo` and `uatom` both + returned 64-byte signatures, and the signatures differed. This proves the + supplied denomination reaches the signed digest instead of a hardcoded + `uosmo` value. +- Amount strings `01`, `-1`, ` 1`, and `18446744073709551616` each failed with + `Invalid Osmosis amount or denomination` and returned no signature. +- A maximum Swap with two 32-digit amounts and two 68-character IBC + denominations completed and returned a signature. +- Maximum 32-digit LP-add and LP-remove share amounts completed and returned + signatures. The device remained connected, initialized, and on the same + candidate revision after the runs; no reset or memory fault was observed. +- With exclusive WebUSB access, a direct LP-remove run approved Minimum Output + A, Minimum Output B, and Pool ID, then sent protocol `Cancel` on button + request four (`LP Shares to Redeem`). Firmware returned cancellation with no + signature, remained initialized, and reported the same candidate revision. + +The operator explicitly confirmed after the run that both maximum Swap +disclosures showed their complete 68-character denominations through the final +`A`, and that the LP share disclosure showed the complete converted value +through its final `...789012`. No OLED truncation or hidden suffix was observed. + +## Physical release smoke gate + +The physical gate verifies that the automated result survives real hardware and +real transport. It does not repeat the Python report screen by screen. The +screen matrix, maximum boundaries, malformed inputs, policy combinations, and +per-page cancellation cases belong in automated tests and the generated report. + +The RC17 physical smoke gate is: + +1. Boot and reconnect the shipped full-firmware candidate; confirm the device + reports firmware `7.15.0`, variant `KeepKey`, and the expected candidate + revision. +2. Complete a representative address and transaction-signing flow through + Vault and receive a valid 64-byte signature. +3. Cancel a representative in-progress signing flow; confirm that no signature + is returned and the device remains initialized and connected. +4. Run the highest-risk changed renderer/memory flow at its accepted maximum; + confirm the final values are visible and the device neither resets nor + reports a memory fault. +5. Perform an operator visual sanity check that the physical screens match the + settled Python/emulator report. + +The evidence recorded above satisfies all five items: the exact candidate +booted and reconnected through Vault; multiple Osmosis transactions signed; the +LP cancellation returned no signature and preserved the session; maximum Swap +and LP values completed without a reset or memory fault; and the operator +confirmed the complete maximum-length disclosures. + +The former exhaustive 15-step physical checklist is retired as a release gate. +Its screen-level and adversarial cases are covered by the automated suite and +Python report. Any uncovered case should be added as a regression test rather +than expanded into recurring manual release ceremony. + +RC17 may be considered for promotion after the current pull-request CI matrix +is green and the release owner makes an explicit GO decision. diff --git a/docs/security/7.15.0-rc18-release-shape.md b/docs/security/7.15.0-rc18-release-shape.md new file mode 100644 index 000000000..d63fae18d --- /dev/null +++ b/docs/security/7.15.0-rc18-release-shape.md @@ -0,0 +1,43 @@ +# Firmware 7.15.0 RC18 Release Shape + +Date: 2026-07-24 + +RC18 collapses the former three-product build into two release products: + +| Product | Contents | +| --- | --- | +| Regular (`full`) | Every supported chain, including Zcash shielded/Orchard | +| Bitcoin-only | Bitcoin only; all non-Bitcoin coins and Zcash privacy code removed | + +There is no separate `zcash-privacy` artifact. Zcash privacy is part of the +regular firmware and cannot be disabled as a release choice. The internal +`ZCASH_PRIVACY` compile value remains only so bitcoin-only can compile the +privacy sources out. + +## Release and CI invariants + +- Device, emulator, unit-test, SRAM, and tagged-release matrices contain only + `full` and `bitcoin-only`. +- An unflagged CMake build is the regular product and sets + `BITCOIN_ONLY=0`, `ZCASH_PRIVACY=1`, and `AES_SMALL_TABLES`. +- `-DKK_BITCOIN_ONLY=ON` sets `BITCOIN_ONLY=1` and `ZCASH_PRIVACY=0`. +- The published emulator is the regular/full image. +- Release notes and reproducible-build instructions name only the regular and + bitcoin-only artifacts. + +## Automated evidence + +Both ARM builds used the pinned `kktech/firmware:v15` toolchain image. + +| Product | ARM build | Firmware tests | Board tests | Crypto tests | SRAM reserve | Largest frame | Reserve after frame | +| --- | --- | ---: | ---: | ---: | ---: | ---: | ---: | +| Regular (`full`) | Pass | 363/363 | 2/2 | 4/4 | 19,064 B | 7,664 B | 11,400 B | +| Bitcoin-only | Pass | 28/28 | 2/2 | 4/4 | 32,908 B | 7,664 B | 25,244 B | + +The regular ARM build produced `zcash.c.obj`; the bitcoin-only build did not. +Both products pass the 16,384-byte minimum SRAM reserve and 4,096-byte +reserve-after-largest-frame gates. + +Workflow YAML parsing, SRAM-budget JSON parsing, Python syntax compilation, +`git diff --check`, and the release-shape search for stale `zcash-privacy` +matrix entries also pass. diff --git a/include/keepkey/board/bsd_compat.h b/include/keepkey/board/bsd_compat.h new file mode 100644 index 000000000..0e2b46495 --- /dev/null +++ b/include/keepkey/board/bsd_compat.h @@ -0,0 +1,28 @@ +#ifndef KEEPKEY_BOARD_BSD_COMPAT_H +#define KEEPKEY_BOARD_BSD_COMPAT_H + +/* + * Declarations for BSD libc extensions that macOS/BSD expose via + * but glibc (Linux) and MinGW (Windows) do not. The emulator build compiles + * lib/board/strlcpy.c + strlcat.c when the libc lacks the definitions + * (KK_HAVE_STRLCPY / KK_HAVE_STRLCAT), so only the prototypes are missing. + * + * Force-included for non-Apple emulator builds (see CMakeLists.txt) so every + * translation unit sees the prototypes without us having to chase down ~20 + * call sites — and without touching the real hardware (ARM) build at all. + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +size_t strlcpy(char *dst, const char *src, size_t siz); +size_t strlcat(char *dst, const char *src, size_t siz); + +#ifdef __cplusplus +} +#endif + +#endif /* KEEPKEY_BOARD_BSD_COMPAT_H */ diff --git a/include/keepkey/board/confirm_sm.h b/include/keepkey/board/confirm_sm.h index fa74c829f..765a90125 100644 --- a/include/keepkey/board/confirm_sm.h +++ b/include/keepkey/board/confirm_sm.h @@ -95,6 +95,10 @@ bool confirm(ButtonRequestType type, const char* request_title, const char* request_body, ...) __attribute__((format(printf, 3, 4))); +bool confirm_with_icon(ButtonRequestType type, IconType iconNum, + const char* request_title, const char* request_body, ...) + __attribute__((format(printf, 4, 5))); + bool confirm_constant_power(ButtonRequestType type, const char* request_title, const char* request_body, ...) __attribute__((format(printf, 3, 4))); diff --git a/include/keepkey/board/draw.h b/include/keepkey/board/draw.h index f1e6f0627..a1a1c90ca 100644 --- a/include/keepkey/board/draw.h +++ b/include/keepkey/board/draw.h @@ -51,6 +51,31 @@ void draw_char_simple(Canvas* canvas, const Font* font, char c, uint8_t color, void draw_box(Canvas* canvas, BoxDrawableParams* p); void draw_box_simple(Canvas* canvas, uint8_t color, uint16_t x, uint16_t y, uint16_t width, uint16_t height); +/* + * draw_bitmap_mono_rle_valid() - Validate an RLE stream against a geometry. + * + * Pure and side-effect-free: decodes nothing, writes nothing, touches no + * canvas. Returns true iff the stream is EXACTLY well-formed for a w*h image: + * - every packet count is valid (never 0, never 0x80/-128 — the decoder's + * counter is int8_t and cannot represent a 128 literal), + * - no run straddles the end of the image, + * - exactly w*h pixels are produced, and + * - the whole input is consumed (no trailing packets). + * + * The drawing path is lenient by construction (it stops once the canvas is + * full), so callers that accept host-supplied streams MUST validate here at + * the trust boundary rather than infer validity from a successful draw. + * + * INPUT + * - data: RLE stream + * - length: stream length in bytes + * - w, h: target image geometry + * OUTPUT + * true iff the stream decodes exactly to w*h pixels + */ +bool draw_bitmap_mono_rle_valid(const uint8_t* data, uint32_t length, + uint16_t w, uint16_t h); + bool draw_bitmap_mono_rle(Canvas* canvas, const AnimationFrame* frame, bool erase); diff --git a/include/keepkey/board/font.h b/include/keepkey/board/font.h index 95933f2a5..1fe6eedf4 100644 --- a/include/keepkey/board/font.h +++ b/include/keepkey/board/font.h @@ -20,6 +20,7 @@ #ifndef FONT_H #define FONT_H +#include #include /* Data pertaining to the image of a character */ @@ -53,5 +54,9 @@ uint32_t font_width(const Font* font); uint32_t calc_str_width(const Font* font, const char* str); uint32_t calc_str_line(const Font* font, const char* str, uint16_t line_width); +uint32_t calc_str_line_n(const Font* font, const char* str, size_t str_len, + uint16_t line_width); +size_t calc_str_page(const Font* font, const char* str, size_t str_len, + uint16_t line_width, uint32_t max_lines); #endif diff --git a/include/keepkey/board/layout.h b/include/keepkey/board/layout.h index ed5ab8f33..08e7ab368 100644 --- a/include/keepkey/board/layout.h +++ b/include/keepkey/board/layout.h @@ -79,6 +79,11 @@ typedef enum { typedef enum { NO_ICON = 0, ETHEREUM_ICON, + VERIFIED_ICON, + /* A runtime-supplied 1bpp mono RLE bitmap (e.g. a loaded clear-sign identity + * logo). The frame is set via layout_set_runtime_icon() before the confirm; + * drawn by layout_add_icon(). */ + RUNTIME_ICON, } IconType; typedef void (*AnimateCallback)(void* data, uint32_t duration, @@ -111,6 +116,12 @@ void layout_constant_power_notification(const char* str1, const char* str2, NotificationType type); void layout_notification_icon(NotificationType type, DrawableParams* sp); void layout_add_icon(IconType type); + +/// \brief Set the frame drawn for RUNTIME_ICON on the next confirm. Pass NULL +/// to clear. The AnimationFrame + its Image must outlive the confirm +/// (typically file-static in the caller). +struct AnimationFrame_; +void layout_set_runtime_icon(const struct AnimationFrame_* frame); void layout_warning(const char* str); void layout_warning_static(const char* str); void layout_simple_message(const char* str); @@ -124,6 +135,10 @@ void animating_progress_handler(const char* desc, int permil); void layoutProgress(const char* desc, int permil); void layoutProgressForAuth(const char* otp, const char* desc, int permil); void layoutProgressSwipe(const char* desc, int permil); +void layoutProgressTrickle(const char* desc, int base_permil, + int target_permil); +void layoutProgressTrickleStop(void); +void layout_animate_poll(void); void layout_add_animation(AnimateCallback callback, void* data, uint32_t duration); void layout_animate_images(void* data, uint32_t duration, uint32_t elapsed); diff --git a/include/keepkey/board/messages.h b/include/keepkey/board/messages.h index fd0c6e4c3..9b6dbbf97 100644 --- a/include/keepkey/board/messages.h +++ b/include/keepkey/board/messages.h @@ -102,6 +102,12 @@ typedef void (*raw_msg_handler_t)(RawMessage* msg, uint32_t frame_length); const pb_field_t* message_fields(MessageMapType type, MessageType msg_id, MessageMapDirection dir); +/* Shared frame arena (defined in messages.c). Acquiring the arena for TX or + * scratch drops any partially reassembled inbound frame — see the FrameArena + * contract in messages.c. Single-threaded transport only. */ +TrezorFrameBuffer* frame_arena_tx(void); +uint16_t* frame_arena_scratch2049(void); + bool msg_write(MessageType msg_id, const void* msg); #if DEBUG_LINK diff --git a/include/keepkey/board/util.h b/include/keepkey/board/util.h index 5272a41ea..f6fab624a 100644 --- a/include/keepkey/board/util.h +++ b/include/keepkey/board/util.h @@ -54,8 +54,7 @@ void dec64_to_str(uint64_t dec64_val, char* str); bool is_valid_ascii(const uint8_t* data, uint32_t size); -int base_to_precision(uint8_t* dest, const uint8_t* value, - const uint8_t dest_len, const uint8_t value_len, - const uint8_t precision); +int base_to_precision(uint8_t* dest, const uint8_t* value, size_t dest_len, + size_t value_len, uint8_t precision); #endif diff --git a/include/keepkey/emulator/libkkemu.h b/include/keepkey/emulator/libkkemu.h index ec75ff957..6e5b8f336 100644 --- a/include/keepkey/emulator/libkkemu.h +++ b/include/keepkey/emulator/libkkemu.h @@ -3,7 +3,16 @@ * * The host process provides a pre-allocated 1MB flash buffer. * All I/O goes through ring buffers (no UDP sockets). - * Single-threaded: call kkemu_poll() from your event loop. + * + * Two drive modes: + * - Host-driven (default): call kkemu_poll() from your event loop. Purely + * single-threaded — used by the FFI/python test harnesses. + * - Thread-driven: call kkemu_start() once after kkemu_init() and let a + * dedicated dylib thread own the event loop. Required for screen-first + * confirm gating (confirm_helper can block in C without freezing the host + * event loop). The host then never calls kkemu_poll(); it interacts only + * through the lock-free rings (kkemu_write/read/pop_frame) and brackets + * flash snapshots with kkemu_lock()/kkemu_unlock(). */ #ifndef LIBKKEMU_H #define LIBKKEMU_H @@ -77,20 +86,16 @@ int kkemu_read(uint8_t* buf, size_t len, int iface); int kkemu_poll(void); /** - * Get the OLED framebuffer (256x64, 1-bit per pixel = 2048 bytes). + * Snapshot the current OLED framebuffer (256x64, 1-bit, 2048 bytes) into + * internal scratch and return a pointer to it (valid until the next call). * - * This returns a pointer to internal scratch storage containing a snapshot - * of the current display in packed SSD1306 page format. + * WARNING: host-driven mode ONLY. Reads the live canvas with no synchronization + * against the poll thread — do NOT call it once kkemu_start() is running. In + * thread-driven mode use kkemu_pop_frame() (the lock-free SPSC ring) instead. + * Returns NULL if the emulator is not initialized. * * @param width Receives 256. * @param height Receives 64. - * @return Pointer to framebuffer data. The pointer remains valid only until - * the next call to kkemu_get_display(), which overwrites the same - * scratch buffer. Calling kkemu_poll() may update the emulator's - * display state, but it does not refresh previously returned data - * in place; call kkemu_get_display() again after kkemu_poll() to - * obtain an updated framebuffer snapshot. Returns NULL if emulator - * is not initialized. */ const uint8_t* kkemu_get_display(int* width, int* height); @@ -98,14 +103,15 @@ const uint8_t* kkemu_get_display(int* width, int* height); * Pop the next captured framebuffer from the display capture ring. * * Every display_refresh() inside the firmware (including those that fire - * inside confirm_helper's busy loop within a single kkemu_poll() call) - * snapshots the canvas into a ring buffer. Adjacent identical frames - * are deduplicated. This lets the host see intermediate screen states - * (confirm dialogs, cipher prompts, recovery screens) that would - * otherwise be invisible — they exist only inside synchronous C calls. + * inside confirm_helper's busy loop) snapshots the canvas into a lock-free + * SPSC ring. Adjacent identical frames are deduplicated. This is the canonical + * way to observe intermediate screen states (confirm dialogs, cipher prompts, + * recovery screens) — and the only display path that is safe to call while the + * poll thread runs. * * @param out_packed Buffer of at least 2048 bytes (256x64, 1-bit packed - * SSD1306 page format — same as kkemu_get_display). + * SSD1306 page format: byte index = x + (y/8)*256, + * bit within byte = y%8). * @return 1 if a frame was popped, 0 if the ring is empty. */ int kkemu_pop_frame(uint8_t* out_packed); @@ -115,6 +121,44 @@ int kkemu_pop_frame(uint8_t* out_packed); */ int kkemu_is_running(void); +/** + * Start the dedicated poll thread (thread-driven mode). + * + * After this returns 0, a dylib-internal thread owns the firmware event loop + * and the host MUST NOT call kkemu_poll() anymore. Idempotent. Requires + * kkemu_init() to have succeeded. + * + * @return 0 on success (or already started), -1 on error. + */ +int kkemu_start(void); + +/** + * Stop + join the poll thread. Injects a Cancel first so a confirm_helper + * parked waiting for a button decision unblocks and the thread can exit. + * Idempotent; a no-op if the thread was never started. kkemu_shutdown() + * calls this automatically. + */ +void kkemu_stop(void); + +/** + * Bracket a host-side read of the flash buffer (e.g. before encrypting and + * persisting it) so it can't tear a concurrent storage_commit() on the poll + * thread. No-op in host-driven mode. Must be balanced with kkemu_unlock(). + * + * kkemu_lock() BLOCKS and must not be used from a host loop that also has to + * stay alive to deliver a confirm decision — use kkemu_trylock() there. + */ +void kkemu_lock(void); +void kkemu_unlock(void); + +/** + * Non-blocking acquire of the firmware lock. Returns 1 if acquired (balance + * with kkemu_unlock()), 0 if currently held by the poll thread (e.g. during a + * pending confirm) — yield the host event loop and retry. Returns 1 as a no-op + * when the poll thread isn't running. + */ +int kkemu_trylock(void); + #ifdef __cplusplus } #endif diff --git a/include/keepkey/firmware/app_confirm.h b/include/keepkey/firmware/app_confirm.h index 15fcd7c64..cf1630288 100644 --- a/include/keepkey/firmware/app_confirm.h +++ b/include/keepkey/firmware/app_confirm.h @@ -24,6 +24,7 @@ #include #include +#include #define CONFIRM_SIGN_IDENTITY_TITLE 32 #define CONFIRM_SIGN_IDENTITY_BODY 416 @@ -46,10 +47,23 @@ bool confirm_load_device(bool is_node); bool confirm_address(const char* desc, const char* address); bool confirm_xpub(const char* node_str, const char* xpub); bool confirm_sign_identity(const IdentityType* identity, const char* challenge); +/** + * Review every byte of a length-delimited payload. Printable ASCII and LF line + * breaks are paged as text; any payload containing another control/non-ASCII + * byte is paged as complete hexadecimal. Page boundaries use the OLED + * renderer's actual font and word-wrap budget, so no accepted byte can be + * clipped below the third row. + */ +bool confirm_bytes_is_text(const uint8_t* data, size_t size); +bool confirm_bytes(ButtonRequestType button_request, const char* title, + const uint8_t* data, size_t size); bool confirm_cosmos_address(const char* desc, const char* address); bool confirm_osmosis_address(const char* desc, const char* address); bool confirm_ethereum_address(const char* desc, const char* address); bool confirm_nano_address(const char* desc, const char* address); +#if ZCASH_PRIVACY +bool confirm_zcash_address(const char* desc, const char* address); +#endif bool confirm_omni(ButtonRequestType button_request, const char* title, const uint8_t* data, uint32_t size); bool confirm_data(ButtonRequestType button_request, const char* title, diff --git a/include/keepkey/firmware/app_layout.h b/include/keepkey/firmware/app_layout.h index fc6d9ca96..10e35b891 100644 --- a/include/keepkey/firmware/app_layout.h +++ b/include/keepkey/firmware/app_layout.h @@ -118,8 +118,16 @@ void layout_ethereum_address_notification(const char* desc, const char* address, NotificationType type); void layout_nano_address_notification(const char* desc, const char* address, NotificationType type); +#if ZCASH_PRIVACY +void layout_zcash_address_notification(const char* desc, const char* address, + NotificationType type); +void layout_zcash_address_text_notification(const char* desc, + const char* address, + NotificationType type); +#endif void layout_pin(const char* str, char* pin); -void layout_cipher(const char* current_word, const char* cipher); +void layout_cipher(const char* current_word, const char* cipher, + const char* prev_word_info); void layout_address(const char* address, QRSize qr_size); void set_leaving_handler(leaving_handler_t leaving_func); diff --git a/include/keepkey/firmware/authenticator.h b/include/keepkey/firmware/authenticator.h index bb9981f68..a2fdf8775 100644 --- a/include/keepkey/firmware/authenticator.h +++ b/include/keepkey/firmware/authenticator.h @@ -26,6 +26,7 @@ #define ACCOUNT_SIZE 12 // allow 11 chars for account string #define AUTHSECRET_SIZE_MAX \ 20 // 128-bit key len is the recommended minimum, this is room for 160-bit +#define AUTHSECRET_SIZE_MIN 16 // reject brute-forceable TOTP secrets #define AUTHDATA_SIZE \ 10 // WARNING: This value must be coordinated with the size of uint8_t // encrypted_sec[] in in lib/firmware/storage.h and the storage version @@ -41,6 +42,8 @@ enum AUTH_ERR_TYPE { LARGESEED, BADPASS, UNKERR, + DUPLICATE, + AUTH_CANCELLED, NUM_AUTHERRS }; @@ -68,7 +71,7 @@ unsigned generateOTP(char* accountWithMsg, char otpStr[]); unsigned addAuthAccount(char* accountWithSeed); unsigned getAuthAccount(const char* slotStr, char acc[]); unsigned removeAuthAccount(char* domAcc); -void wipeAuthData(void); +unsigned wipeAuthData(void); #if DEBUG_LINK void getAuthSlot(char* authSlotData); #endif diff --git a/include/keepkey/firmware/binance.h b/include/keepkey/firmware/binance.h index 9f42dcc60..035b37094 100644 --- a/include/keepkey/firmware/binance.h +++ b/include/keepkey/firmware/binance.h @@ -12,6 +12,10 @@ typedef struct _BinanceTransferMsg BinanceTransferMsg; typedef struct _BinanceTransferMsg_BinanceInputOutput BinanceInputOutput; typedef struct _BinanceTransferMsg_BinanceCoin BinanceCoin; +#define BINANCE_MAX_DENOM_LEN 31 + +bool binance_isValidDenom(const char* denom); +bool binance_validateTransfer(const BinanceTransferMsg* transfer); bool binance_signTxInit(const HDNode* _node, const BinanceSignTx* _msg); bool binance_serializeCoin(const BinanceCoin* coin); bool binance_serializeInputOutput(const BinanceInputOutput* io); diff --git a/include/keepkey/firmware/bip85.h b/include/keepkey/firmware/bip85.h new file mode 100644 index 000000000..73c197995 --- /dev/null +++ b/include/keepkey/firmware/bip85.h @@ -0,0 +1,22 @@ +#ifndef BIP85_H +#define BIP85_H + +#include +#include +#include + +/** + * Derive a child BIP-39 mnemonic via BIP-85. + * + * Path: m/83696968'/39'/0'/'/' + * + * @param word_count Number of words: 12, 18, or 24. + * @param index Child index (0-based). + * @param mnemonic Output buffer (must be at least 241 bytes). + * @param mnemonic_len Size of the output buffer. + * @return true on success, false on error. + */ +bool bip85_derive_mnemonic(uint32_t word_count, uint32_t index, char *mnemonic, + size_t mnemonic_len); + +#endif diff --git a/include/keepkey/firmware/coins.def b/include/keepkey/firmware/coins.def index 5d872061c..b99ba9fa2 100644 --- a/include/keepkey/firmware/coins.def +++ b/include/keepkey/firmware/coins.def @@ -2,6 +2,7 @@ //coin_name coin_shortcut address_type maxfee_kb p2sh signed_message_header bip44_account_path forkid/chain_id decimals contract_address xpub_magic segwit force_bip143 curve_name cashaddr_prefix bech32_prefix decred xpub_magic_segwit_p2sh xpub_mmagic_segwit_native nanoaddr_prefix taproot X(true, "Bitcoin", true, "BTC", true, 0, true, 100000, true, 5, true, "Bitcoin Signed Message:\n", true, 0x80000000, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", true, "bc", false, false, true, 77429938, true, 78792518, false, "", true, true ) X(true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 196, true, "Bitcoin Signed Message:\n", true, 0x80000001, false, 0, true, 8, false, NO_CONTRACT, true, 70617039, true, true, true, false, true, SECP256K1_STRING, false, "", true, "tb", false, false, true, 71979618, true, 73342198, false, "", true, true ) +#if !BITCOIN_ONLY X(true, "BitcoinCash", true, "BCH", true, 0, true, 500000, true, 5, true, "Bitcoin Signed Message:\n", true, 0x80000091, true, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, true, true, SECP256K1_STRING, true, "bitcoincash", false, "", false, false, false, 0, false, 0, false, "", true, false ) X(true, "Namecoin", true, "NMC", true, 52, true, 10000000, true, 5, true, "Namecoin Signed Message:\n", true, 0x80000007, false, 0, true, 8, false, NO_CONTRACT, true, 27108450, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "", true, false ) X(true, "Litecoin", true, "LTC", true, 48, true, 1000000, true, 50, true, "Litecoin Signed Message:\n", true, 0x80000002, false, 0, true, 8, false, NO_CONTRACT, true, 27108450, true, true, true, false, true, SECP256K1_STRING, false, "", true, "ltc", false, false, true, 28471030, true, 78792518, false, "", true, false ) @@ -47,6 +48,7 @@ X(true, "Terra", true, "LUNA", false, NA, false, NA, false, N X(true, "Kava", true, "KAVA", false, NA, false, NA, false, NA, false, {0}, true, 0x800001cb, false, 0, true, 6, false, NO_CONTRACT, false, 0, false, false, false, false, true, SECP256K1_STRING, false, "", false, "kava", false, false, false, 0, false, 0, false, "", true, false ) X(true, "Secret", true, "SCRT", false, NA, false, NA, false, NA, false, {0}, true, 0x80000211, false, 0, true, 6, false, NO_CONTRACT, false, 0, false, false, false, false, true, SECP256K1_STRING, false, "", false, "secret", false, false, false, 0, false, 0, false, "", true, false ) X(true, "MAYAChain", true, "CACAO", false, NA, false, NA, false, NA, false, {0}, true, 0x800003a3, false, 0, true, 10, false, NO_CONTRACT, false, 0, false, false, false, false, true, SECP256K1_STRING, false, "", false, "maya", false, false, false, 0, false, 0, false, "", true, false ) +#endif // !BITCOIN_ONLY #undef X #undef NO_CONTRACT diff --git a/include/keepkey/firmware/coins.h b/include/keepkey/firmware/coins.h index f5ede136d..5dec19f7e 100644 --- a/include/keepkey/firmware/coins.h +++ b/include/keepkey/firmware/coins.h @@ -44,9 +44,11 @@ enum { CONCAT(CoinIndex, __COUNTER__), #include "keepkey/firmware/coins.def" +#if !BITCOIN_ONLY // ERC-20 tokens excluded from the bitcoin-only image #define X(INDEX, NAME, SYMBOL, DECIMALS, CONTRACT_ADDRESS) \ CONCAT(CoinIndex, __COUNTER__), #include "keepkey/firmware/tokens.def" +#endif CoinIndexLast, CoinIndexFirst = 0 diff --git a/include/keepkey/firmware/eip712.h b/include/keepkey/firmware/eip712.h index 686acd6de..165a52fd6 100644 --- a/include/keepkey/firmware/eip712.h +++ b/include/keepkey/firmware/eip712.h @@ -25,9 +25,9 @@ Parser wants to see C strings, not javascript strings: requires all complete json message strings to be enclosed by braces, i.e., { ... } Cannot have entire json string quoted, i.e., "{ ... }" will not - work. Remove all quote escape chars, e.g., {"types": not {\"types\": int - values must be hex. Negative sign indicates negative value, e.g., -5, -8a67 - Note: Do not prefix ints or uints with 0x + work. Remove all quote escape chars, e.g., {"types": not {\"types\": + Integer values must use canonical base-10 digits. Negative values use a + leading minus sign. Do not prefix ints or uints with 0x. All hex and byte strings must be big-endian Byte strings and address should be prefixed by 0x */ @@ -95,10 +95,16 @@ typedef enum { DOMAIN = 1, MESSAGE } dm; #define JSON_TYPE_T_NOVAL 31 #define ADDR_STRING_NULL 32 #define JSON_TYPE_WNOVAL 33 +#define USER_CANCELLED 34 -#define LAST_ERROR JSON_TYPE_WNOVAL +#define LAST_ERROR USER_CANCELLED int encode(const json_t* jsonTypes, const json_t* jsonVals, const char* typeS, uint8_t* hashRet); +/* Exposed for strict-value regression tests. */ +int encAddress(const char* string, uint8_t* encoded); +int encodeBytes(const char* string, uint8_t* encoded); +int encodeBytesN(const char* typeT, const char* string, uint8_t* encoded); + #endif diff --git a/include/keepkey/firmware/eos.h b/include/keepkey/firmware/eos.h index 3f925c9b8..10c0cf4d6 100644 --- a/include/keepkey/firmware/eos.h +++ b/include/keepkey/firmware/eos.h @@ -86,6 +86,9 @@ uint32_t eos_actionsRemaining(void); bool eos_hasActionUnknownDataRemaining(void); +bool eos_isSupportedAction(const EosActionCommon* common); +bool eos_unknownActionPolicyAllows(bool advanced_mode); + /// \returns true iff successful. bool eos_compileActionUnknown(const EosActionCommon* common, const EosActionUnknown* action); diff --git a/include/keepkey/firmware/ethereum.h b/include/keepkey/firmware/ethereum.h index 77c8f4775..e9ccbbb91 100644 --- a/include/keepkey/firmware/ethereum.h +++ b/include/keepkey/firmware/ethereum.h @@ -36,6 +36,7 @@ typedef struct _CoinType CoinType; void ethereum_signing_init(EthereumSignTx* msg, const HDNode* node, bool needs_confirm); void ethereum_signing_abort(void); +bool ethereum_signing_isInProgress(void); void ethereum_signing_txack(EthereumTxAck* tx); void format_ethereum_address(const uint8_t* to, char* destination_str, uint32_t destination_str_len); @@ -70,6 +71,8 @@ void bn_from_bytes(const uint8_t* value, size_t value_len, bignum256* val); void ethereum_typed_hash_sign(const EthereumSignTypedHash* msg, const HDNode* node, EthereumTypedDataSignature* resp); +bool ethereum_typed_hash_policy_allows(bool advanced_mode); +bool ethereum_eip712_is_domain_primary_type(const char* primary_type); bool ethereum_path_check(uint32_t address_n_count, const uint32_t* address_n, bool pubkey_export, uint64_t chain); void e712_types_values(Ethereum712TypesValues* msg, diff --git a/include/keepkey/firmware/ethereum_contracts/thortx.h b/include/keepkey/firmware/ethereum_contracts/thortx.h index 8f61c27f3..8f71c7fcc 100644 --- a/include/keepkey/firmware/ethereum_contracts/thortx.h +++ b/include/keepkey/firmware/ethereum_contracts/thortx.h @@ -30,7 +30,31 @@ "\xee\xee\xee\xee\xee\xee\xee\xee\xee\xee\xee\xee\xee\xee\xee\xee\xee\xee" \ "\xee\xee" -#define THOR_ROUTER "42a5ed456650a09dc10ebc6361a7480fdd61f27b" +/* THORChain ETH router (mainnet), current v4.1.1. + * NOTE: THORChain migrates this router periodically (v1 42a5ed.. -> v3 + * 3624525.. -> v4 d37bbe..). A hardcoded pin must be updated on each migration; + * the durable path is the signed-metadata clear-sign protocol (host-signed, + * key-pinned) which needs no firmware update per router change. */ +#define THOR_ROUTER "d37bbe5744d730a1d98d8dc97c42f0ca46ad7146" + +/* THORChain deploys its Router at a DIFFERENT address on every EVM chain, so + * the pin must be chain-scoped (see thor_router_for_chain): a deposit on any + * chain but mainnet can never match THOR_ROUTER and would fall to the + * blind-sign gate. Avalanche C-Chain router, verified live against THORChain + * /inbound_addresses via a Pioneer quote (2026-07). Lowercase, no 0x, to match + * thor_format_to_addr's output. Same migration caveat as THOR_ROUTER. + * ponytail: BSC (chainId 56) and Base (8453) routers also exist on-chain but + * are omitted until verified against a live node — the shipped Pioneer catalog + * lists STALE addresses (its AVAX entry 8f66c4ae.. is already wrong vs the live + * 00dc6100..), and Pioneer currently routes BSC/Base swaps via Relay, not a + * THORChain deposit, so no such tx reaches the device today. Add each here once + * verified live. */ +#define THOR_ROUTER_AVAX "00dc6100103bc402d490aee3f9a5560cbd91f1d4" + +/* Maya Protocol ETH router v4 (mainnet), verified on Etherscan + * (0xe3985e6b61b814f7cdb188766562ba71b446b46d). The prior pin + * d89dce57.. has never held contract code on mainnet. */ +#define MAYA_ROUTER "e3985e6b61b814f7cdb188766562ba71b446b46d" /* deposit(address,address,uint256,string) — legacy selector */ #define THOR_SELECTOR_DEPOSIT "\x1f\xec\xe7\xb4" @@ -43,6 +67,8 @@ typedef struct _EthereumSignTx EthereumSignTx; bool thor_has_deposit_selector(const EthereumSignTx* msg); bool thor_is_expiry_variant(const EthereumSignTx* msg); bool thor_isThorchainTx(const EthereumSignTx* msg); +bool thor_isMayachainTx(const EthereumSignTx* msg); bool thor_confirmThorTx(uint32_t data_total, const EthereumSignTx* msg); +bool thor_confirmMayaTx(uint32_t data_total, const EthereumSignTx* msg); #endif diff --git a/include/keepkey/firmware/ethereum_contracts/zxliquidtx.h b/include/keepkey/firmware/ethereum_contracts/zxliquidtx.h index 6287da2bd..1a4c6046d 100644 --- a/include/keepkey/firmware/ethereum_contracts/zxliquidtx.h +++ b/include/keepkey/firmware/ethereum_contracts/zxliquidtx.h @@ -22,6 +22,7 @@ #include #include +#include #define UNISWAP_ROUTER_ADDRESS \ "\x7a\x25\x0d\x56\x30\xB4\xcF\x53\x97\x39\xdF\x2C\x5d\xAc\xb4\xc6\x59\xF2" \ @@ -31,5 +32,7 @@ typedef struct _EthereumSignTx EthereumSignTx; bool zx_isZxLiquidTx(const EthereumSignTx* msg); bool zx_confirmZxLiquidTx(uint32_t data_total, const EthereumSignTx* msg); +bool zx_formatZxLiquidityPrimaryAmount(const EthereumSignTx* msg, char* out, + size_t out_len); #endif diff --git a/include/keepkey/firmware/ethereum_tokens.h b/include/keepkey/firmware/ethereum_tokens.h index 7e26bd164..0f5c040f8 100644 --- a/include/keepkey/firmware/ethereum_tokens.h +++ b/include/keepkey/firmware/ethereum_tokens.h @@ -25,6 +25,9 @@ #include #include +#if BITCOIN_ONLY +#define TOKENS_COUNT 0 // no ERC-20 tokens in the bitcoin-only image +#else enum { #define X(CHAIN_ID, CONTRACT_ADDR, TICKER, DECIMALS) \ CONCAT(TokenIndex, __COUNTER__), @@ -35,11 +38,12 @@ enum { }; #define TOKENS_COUNT ((int)TokenIndexLast - (int)TokenIndexFirst) +#endif typedef struct _TokenType { const char* const address; const char* const ticker; - uint8_t chain_id; + uint32_t chain_id; uint8_t decimals; } TokenType; @@ -51,7 +55,7 @@ extern const TokenType* UnknownToken; const TokenType* tokenIter(int32_t* ctr); -const TokenType* tokenByChainAddress(uint8_t chain_id, const uint8_t* address); +const TokenType* tokenByChainAddress(uint32_t chain_id, const uint8_t* address); /// Tokens don't have unique tickers, so this might not return the one you're /// looking for :/ @@ -64,7 +68,7 @@ const TokenType* tokenByChainAddress(uint8_t chain_id, const uint8_t* address); /// \param[out] token The found token, assuming it was uniquely determinable. /// \returns true iff the token can be uniquely found in the list of known /// tokens. -bool tokenByTicker(uint8_t chain_id, const char* ticker, +bool tokenByTicker(uint32_t chain_id, const char* ticker, const TokenType** token); void coinFromToken(CoinType* coin, const TokenType* token); diff --git a/include/keepkey/firmware/fsm.h b/include/keepkey/firmware/fsm.h index 656f0c127..81e3e841d 100644 --- a/include/keepkey/firmware/fsm.h +++ b/include/keepkey/firmware/fsm.h @@ -85,6 +85,8 @@ void fsm_msgEthereumSignMessage(EthereumSignMessage* msg); void fsm_msgEthereumVerifyMessage(const EthereumVerifyMessage* msg); void fsm_msgEthereumSignTypedHash(const EthereumSignTypedHash* msg); void fsm_msgEthereum712TypesValues(Ethereum712TypesValues* msg); +void fsm_msgEthereumTxMetadata(const EthereumTxMetadata* msg); +void fsm_msgLoadClearsignSigner(const LoadClearsignSigner* msg); void fsm_msgNanoGetAddress(NanoGetAddress* msg); void fsm_msgNanoSignTx(NanoSignTx* msg); @@ -131,6 +133,22 @@ void fsm_msgSolanaSignTx(const SolanaSignTx* msg); void fsm_msgSolanaSignMessage(const SolanaSignMessage* msg); void fsm_msgSolanaSignOffchainMessage(const SolanaSignOffchainMessage* msg); +#if ZCASH_PRIVACY +void fsm_msgZcashSignPCZT(const ZcashSignPCZT* msg); +void fsm_msgZcashPCZTAction(const ZcashPCZTAction* msg); +void fsm_msgZcashGetOrchardFVK(const ZcashGetOrchardFVK* msg); +void fsm_msgZcashTransparentOutput(const ZcashTransparentOutput* msg); +void fsm_msgZcashTransparentInput(const ZcashTransparentInput* msg); +void fsm_msgZcashDisplayAddress(const ZcashDisplayAddress* msg); +#endif +void fsm_msgHiveGetPublicKey(const HiveGetPublicKey* msg); +void fsm_msgHiveGetPublicKeys(const HiveGetPublicKeys* msg); +void fsm_msgHiveSignTx(const HiveSignTx* msg); +void fsm_msgHiveSignAccountCreate(const HiveSignAccountCreate* msg); +void fsm_msgHiveSignAccountUpdate(const HiveSignAccountUpdate* msg); +void fsm_msgHiveSignMessage(const HiveSignMessage* msg); +void fsm_msgHiveSignOperations(const HiveSignOperations* msg); + #if DEBUG_LINK // void fsm_msgDebugLinkDecision(DebugLinkDecision *msg); void fsm_msgDebugLinkGetState(DebugLinkGetState* msg); @@ -142,4 +160,6 @@ void fsm_msgFlashWrite(FlashWrite* msg); void fsm_msgFlashHash(FlashHash* msg); void fsm_msgSoftReset(SoftReset* msg); +void fsm_msgGetBip85Mnemonic(const GetBip85Mnemonic* msg); + #endif diff --git a/include/keepkey/firmware/hive.h b/include/keepkey/firmware/hive.h new file mode 100644 index 000000000..ad98b4731 --- /dev/null +++ b/include/keepkey/firmware/hive.h @@ -0,0 +1,261 @@ +#ifndef KEEPKEY_FIRMWARE_HIVE_H +#define KEEPKEY_FIRMWARE_HIVE_H + +#include "trezor/crypto/bip32.h" +#include "messages-hive.pb.h" + +// ── Hive mainnet chain ID ───────────────────────────────────────────────── +#define HIVE_CHAIN_ID \ + "\xbe\xea\xb0\xde\x00\x00\x00\x00\x00\x00\x00\x00" \ + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \ + "\x00\x00\x00\x00\x00\x00\x00\x00" + +#define HIVE_CHAIN_ID_LEN 32 + +// ── STM public key prefix (Hive inherited from Steem / Graphene) ────────── +#define HIVE_PUBKEY_PREFIX "STM" + +// ── SLIP-0048 derivation constants (all hardened) ───────────────────────── +// Path: m/48'/13'/role'/account_index'/0' +// 13' is the de-facto Hive network index shipped by Ledger (LedgerHQ/app-hive) +// and hive-ledger-cli, NOT the slip-0048.md registry entry (0xbee = 3054', +// which no wallet implements). Chosen deliberately for seed-level key +// compatibility with the existing hardware-wallet ecosystem. +#define HIVE_SLIP48_PURPOSE (0x80000030u) // 48' +#define HIVE_SLIP48_NETWORK (0x8000000Du) // 13' +#define HIVE_ROLE_OWNER \ + (0x80000000u) // 0' — account recovery, authority changes +#define HIVE_ROLE_ACTIVE (0x80000001u) // 1' — transfers, staking +#define HIVE_ROLE_MEMO (0x80000003u) // 3' — memo field encryption +#define HIVE_ROLE_POSTING (0x80000004u) // 4' — votes, posts, follows + +/** + * Validate a complete Hive SLIP-0048 path: + * m/48'/13'/role'/account'/0'. The role must be one of owner, active, memo, + * or posting; every component is hardened. + */ +bool hive_slip48_path_valid(const uint32_t* address_n, size_t count); + +/** Validate a complete Hive SLIP-0048 path for one required role. */ +bool hive_slip48_path_valid_for_role(const uint32_t* address_n, size_t count, + uint32_t required_role); + +// ── Graphene operation type IDs ─────────────────────────────────────────── +#define HIVE_OP_VOTE 0 +#define HIVE_OP_COMMENT 1 +#define HIVE_OP_TRANSFER 2 +#define HIVE_OP_TRANSFER_TO_VESTING 3 +#define HIVE_OP_WITHDRAW_VESTING 4 +#define HIVE_OP_LIMIT_ORDER_CREATE 5 +#define HIVE_OP_LIMIT_ORDER_CANCEL 6 +#define HIVE_OP_CONVERT 8 +#define HIVE_OP_ACCOUNT_CREATE 9 +#define HIVE_OP_ACCOUNT_UPDATE 10 +#define HIVE_OP_CUSTOM_JSON 18 +#define HIVE_OP_COMMENT_OPTIONS 19 +#define HIVE_OP_TRANSFER_TO_SAVINGS 32 +#define HIVE_OP_TRANSFER_FROM_SAVINGS 33 +#define HIVE_OP_CLAIM_REWARD_BALANCE 39 +#define HIVE_OP_DELEGATE_VESTING_SHARES 40 +#define HIVE_OP_ACCOUNT_UPDATE2 43 + +// ── Protocol limits ─────────────────────────────────────────────────────── +#define HIVE_DECIMALS 3 // HIVE and HBD both use 3 decimal places +// Maximum memo length that fits safely in the signer's tx_buf[512] with all +// other fields. Non-memo overhead: header(12) + from(17) + to(17) + asset(16) +// + footer(1) = ~63 bytes. 512 - 63 - 3 (varint) = 446; 440 is conservative. +#define HIVE_MAX_MEMO_LEN 440 +// Maximum signable message length. MUST match HiveSignMessage.message +// max_size in messages-hive.options (proto cap and code cap kept in sync). +#define HIVE_MAX_MESSAGE_LEN 1024 +// Maximum host-serialized transaction length for HiveSignOperations. MUST +// match HiveSignOperations.serialized_tx max_size in messages-hive.options. +#define HIVE_MAX_OPS_TX_LEN 2048 +// Maximum operations per HiveSignOperations transaction. +#define HIVE_MAX_TX_OPS 4 +// Graphene asset: int64 LE amount + uint8 precision + 7-byte NUL-padded +// symbol (append_asset layout). +#define HIVE_ASSET_LEN 16 +// Most assets carried by a single op in the table (claim_reward_balance +// carries three: HIVE, HBD, VESTS). +#define HIVE_MAX_OP_ASSETS 3 +// Most comment_payout_beneficiaries entries accepted on a comment_options op. +// Matches the host serializer's cap; hived itself allows more, but eight is +// all that can be reviewed on the OLED before approval fatigue sets in. +#define HIVE_MAX_BENEFICIARIES 8 +// Maximum custom_json authorization accounts accepted per operation. Every +// account is confirmed individually; bounding the set prevents an unreviewable +// approval loop and keeps the parsed transaction's static RAM use predictable. +#define HIVE_MAX_CUSTOM_JSON_AUTHS 4 + +// Symbol whitelist bits for the asset parser. Every asset field in the op +// table pins an explicit set — an op that accepts HIVE must never silently +// accept VESTS, since the two differ by 1000x in displayed magnitude. +#define HIVE_SYM_HIVE (1u << 0) +#define HIVE_SYM_HBD (1u << 1) +#define HIVE_SYM_VESTS (1u << 2) + +// ── Public API ──────────────────────────────────────────────────────────── +/** + * Encode a 33-byte compressed public key in Hive/Steem STM-prefix base58 + * format. Uses RIPEMD checksum (Graphene convention, not SHA256d). + */ +bool hive_getPublicKey(const uint8_t public_key[33], char* out, size_t out_len); + +/** + * Derive one SLIP-0048 role key for a given account index to raw 33 bytes. + * role_hardened: HIVE_ROLE_OWNER | HIVE_ROLE_ACTIVE | HIVE_ROLE_MEMO | + * HIVE_ROLE_POSTING account_index_hardened: account_index | 0x80000000u Returns + * false if derivation fails. + */ +bool hive_deriveRawKey(const HDNode* root, uint32_t role_hardened, + uint32_t account_index_hardened, uint8_t out[33]); + +/** + * Derive all four SLIP-0048 role keys for a given account index and encode + * each as an STM-prefixed string. All output buffers must be >= 64 bytes. + * Returns false if any derivation or encoding step fails. + */ +bool hive_getPublicKeys(const HDNode* root, uint32_t account_index, + char* owner_out, size_t owner_len, char* active_out, + size_t active_len, char* memo_out, size_t memo_len, + char* posting_out, size_t posting_len); + +/** + * Sign a Hive transfer transaction (op type 2). + * Rejects memos longer than HIVE_MAX_MEMO_LEN (440 bytes). + */ +void hive_signTx(const HDNode* node, const HiveSignTx* msg, HiveSignedTx* resp); + +// ── Parsed operations (HiveSignOperations) ──────────────────────────────── + +typedef struct { + uint32_t op_type; + bool needs_active; // custom_json with required_auths; false = posting tier + // Borrowed slices into the request's serialized_tx (NOT NUL-terminated): + const uint8_t* acct; // vote: voter / comment: author / cj: first auth name + uint16_t acct_len; + const uint8_t* target; // vote: author / comment: title / cj: id + uint16_t target_len; + const uint8_t* detail; // vote: permlink / comment: body / cj: json + uint16_t detail_len; + const uint8_t* parent_author; // comment only + uint16_t parent_author_len; + const uint8_t* + parent_permlink; // comment only (category for a top-level post) + uint16_t parent_permlink_len; + const uint8_t* permlink; // comment only: this post/reply's permlink + uint16_t permlink_len; + const uint8_t* json_metadata; // comment only + uint16_t json_metadata_len; + int16_t weight; // vote (-10000..10000), or a 0..10000 basis-point + // percent (comment_options percent_hbd, + // set_withdraw_vesting_route percent) + bool is_top_level; // comment only: parent_author empty + uint8_t n_auths; // custom_json only: total auth account names + const uint8_t* auth_acct[HIVE_MAX_CUSTOM_JSON_AUTHS]; + uint16_t auth_acct_len[HIVE_MAX_CUSTOM_JSON_AUTHS]; + + // ── Phase-3 op fields ─────────────────────────────────────────────────── + // Borrowed HIVE_ASSET_LEN-byte asset slices in the op's own field order: + // transfer_to_vesting/convert/claim_account/savings: [0] = amount + // withdraw_vesting/delegate_vesting_shares: [0] = vesting_shares + // limit_order_create: [0] = amount_to_sell, [1] = min_to_receive + // claim_reward_balance: [0] = HIVE, [1] = HBD, [2] = VESTS + // comment_options: [0] = max_accepted_payout + const uint8_t* assets[HIVE_MAX_OP_ASSETS]; + uint8_t n_assets; + uint32_t req_id; // convert requestid / savings request_id / order id + uint32_t expiration; // limit_order_create only + bool flag; // fill_or_kill / approve / auto_vest / allow_votes + bool flag2; // comment_options: allow_curation_rewards + uint8_t n_benef; // comment_options: beneficiary count (0 = none) + const uint8_t* benef_acct[HIVE_MAX_BENEFICIARIES]; + uint16_t benef_acct_len[HIVE_MAX_BENEFICIARIES]; + uint16_t benef_weight[HIVE_MAX_BENEFICIARIES]; // basis points +} HiveTxOp; + +typedef struct { + uint8_t num_ops; + bool needs_active; // tx tier: active' path required, else posting' + HiveTxOp ops[HIVE_MAX_TX_OPS]; +} HiveParsedTx; + +/** + * Parse and validate a host-serialized Graphene transaction against the + * device clear-sign op table. Returns NULL on success or a static error + * message. Slices in `out` borrow from `tx` — keep it alive. + * + * Ops 2 (transfer), 9 (account_create) and 10 (account_update) are + * permanently excluded; everything not in the table is refused outright — + * there is no blind-sign fallback. + */ +const char* hive_parseOperations(const uint8_t* tx, size_t len, + HiveParsedTx* out); + +/** + * Accessors for a HIVE_ASSET_LEN-byte asset slice stored in HiveTxOp.assets. + * The parser has already validated the symbol/precision pair, so the symbol + * is always a NUL-terminated "HIVE" / "HBD" / "VESTS" and the amount is + * non-negative. + */ +uint64_t hive_assetAmount(const uint8_t* asset); +uint8_t hive_assetPrecision(const uint8_t* asset); +const char* hive_assetSymbol(const uint8_t* asset); + +/** + * Sign a parsed HiveSignOperations transaction: digest is + * SHA256(chain_id || serialized_tx), identical to HiveSignTx. The caller + * (FSM handler) is responsible for parsing, display, and role checks. + */ +void hive_signOperations(const HDNode* node, const HiveSignOperations* msg, + HiveSignedOperations* resp); + +/** + * Sign an arbitrary message per the Hive Keychain signBuffer contract: + * signature over SHA256(message bytes) only — no chain_id prepend, no + * message prefix. Emits the 65-byte compact recoverable signature plus the + * signing key's 33-byte compressed public key. + */ +void hive_signMessage(const HDNode* node, const HiveSignMessage* msg, + HiveSignedMessage* resp); + +/** + * True iff every byte is printable ASCII (0x20-0x7e). Hive message signing + * requires this: a transaction digest is SHA256(chain_id || serialized_tx) + * whose chain_id and serialized fields are binary, so a printable-only message + * domain can never collide with a transaction preimage on ANY chain id. This + * closes the cross-chain message→transaction signature oracle that a + * mainnet-only prefix reject cannot. Empty (len == 0) returns true. + */ +bool hive_message_is_printable(const uint8_t* message, size_t len); + +/** + * Sign a Hive account_create transaction (op type 9). + * owner/active/posting/memo_raw must be device-derived 33-byte compressed keys. + * The firmware uses these directly; host-supplied key strings in msg are + * ignored. + */ +void hive_signAccountCreate(const HDNode* signing_node, + const HiveSignAccountCreate* msg, + const uint8_t owner_raw[33], + const uint8_t active_raw[33], + const uint8_t posting_raw[33], + const uint8_t memo_raw[33], + HiveSignedAccountCreate* resp); + +/** + * Sign a Hive account_update transaction (op type 10). + * owner/active/posting/memo_raw must be device-derived 33-byte compressed keys. + * The firmware uses these directly; host-supplied new_*_key strings in msg are + * ignored. + */ +void hive_signAccountUpdate(const HDNode* signing_node, + const HiveSignAccountUpdate* msg, + const uint8_t owner_raw[33], + const uint8_t active_raw[33], + const uint8_t posting_raw[33], + const uint8_t memo_raw[33], + HiveSignedAccountUpdate* resp); + +#endif // KEEPKEY_FIRMWARE_HIVE_H diff --git a/include/keepkey/firmware/mayachain.h b/include/keepkey/firmware/mayachain.h index c3d40380d..9b541ac41 100644 --- a/include/keepkey/firmware/mayachain.h +++ b/include/keepkey/firmware/mayachain.h @@ -10,6 +10,15 @@ typedef struct _MayachainSignTx MayachainSignTx; typedef struct _MayachainMsgDeposit MayachainMsgDeposit; +// Returns true iff `denom` is a plausible MAYAChain denom: non-empty, +// and contains only lowercase alpha, digits, '.', '/', or '-'. +bool mayachain_isValidDenom(const char* denom); + +// Deposit asset grammar: as above but uppercase alpha also allowed. +bool mayachain_isValidAsset(const char* asset); +// Deposit signer must be bech32 with the active network's HRP. +bool mayachain_isValidSigner(const char* signer); + bool mayachain_signTxInit(const HDNode* _node, const MayachainSignTx* _msg); bool mayachain_signTxUpdateMsgSend(const uint64_t amount, const char* to_address, const char* denom); diff --git a/include/keepkey/firmware/osmosis.h b/include/keepkey/firmware/osmosis.h index 330c4b9a1..74325a125 100644 --- a/include/keepkey/firmware/osmosis.h +++ b/include/keepkey/firmware/osmosis.h @@ -5,6 +5,7 @@ #include "trezor/crypto/bip32.h" #include +#include #include typedef struct _OsmosisSignTx OsmosisSignTx; @@ -16,7 +17,8 @@ void debug_intermediate_hash(void); bool osmosis_signTxInit(const HDNode* _node, const OsmosisSignTx* _msg); -bool osmosis_signTxUpdateMsgSend(const char* amount, const char* to_address); +bool osmosis_signTxUpdateMsgSend(const char* amount, const char* to_address, + const char* denom); bool osmosis_signTxUpdateMsgDelegate(const char* amount, const char* delegator_address, @@ -66,6 +68,27 @@ bool osmosis_signTxUpdateMsgSwap(const uint64_t pool_id, const char* token_in_denom, const char* token_out_min_amount); +#define OSMOSIS_PRECISION 6 +#define OSMOSIS_MAX_AMOUNT_DIGITS 32 +#define OSMOSIS_MAX_DENOM_LEN 68 + +// Longest amount a confirm screen renders: the digits, a point, a space and +// the longest denom a message can carry. +#define OSMOSIS_AMOUNT_STR_LEN 103 + +/** + * Render an integer base-unit amount for a confirm screen: + * ("1500000", "uosmo") -> "1.500000 OSMO". + * + * Only uosmo is scaled — any other denom is shown exactly as the chain states + * it, because the device does not know its precision. Returns false unless the + * amount is a canonical, schema-bounded unsigned decimal and the denomination + * is a schema-bounded Cosmos asset identifier. Native uosmo additionally must + * fit uint64, which is the range accepted by the native-asset display policy. + */ +bool osmosis_formatAmount(char* out, size_t out_len, const char* value, + const char* denom); + bool osmosis_signTxFinalize(uint8_t* public_key, uint8_t* signature); bool osmosis_signingIsInited(void); bool osmosis_signingIsFinished(void); diff --git a/include/keepkey/firmware/reset.h b/include/keepkey/firmware/reset.h index a41cb101d..da5ae10f6 100644 --- a/include/keepkey/firmware/reset.h +++ b/include/keepkey/firmware/reset.h @@ -33,6 +33,16 @@ MAX_WORDS*(MAX_WORD_LEN + ADDITIONAL_WORD_PAD) + 1 #define MNEMONIC_BY_SCREEN_BUF WORDS_PER_SCREEN*(MAX_WORD_LEN + 1) + 1 +/* Paginated-mnemonic display scratch, shared between the backup flow here and + * the BIP-85 display flow (fsm_msg_bip85.h) — one ~2.8 KB set instead of two. + * Both flows are modal and single-threaded: each formats and displays inside + * its own handler call. Every user MUST memzero the set at entry AND on every + * exit path. Defined in reset.c (.confidential). */ +extern char mnemonic_scratch_tokened[TOKENED_MNEMONIC_BUF]; +extern char mnemonic_scratch_formatted[MAX_PAGES][FORMATTED_MNEMONIC_BUF]; +extern char mnemonic_scratch_display[FORMATTED_MNEMONIC_BUF]; +extern char mnemonic_scratch_word[MAX_WORD_LEN + ADDITIONAL_WORD_PAD]; + void reset_init(bool display_random, uint32_t _strength, bool passphrase_protection, bool pin_protection, const char* language, const char* label, bool _no_backup, diff --git a/include/keepkey/firmware/signed_metadata.h b/include/keepkey/firmware/signed_metadata.h new file mode 100644 index 000000000..0f50a32ca --- /dev/null +++ b/include/keepkey/firmware/signed_metadata.h @@ -0,0 +1,223 @@ +#ifndef KEEPKEY_FIRMWARE_SIGNED_METADATA_H +#define KEEPKEY_FIRMWARE_SIGNED_METADATA_H + +#include +#include +#include + +typedef struct _EthereumSignTx EthereumSignTx; + +#define METADATA_MAX_ARGS 8 +#define METADATA_MAX_METHOD_LEN 64 +#define METADATA_MAX_ARG_NAME_LEN 32 +/* Sized for TOKEN_AMOUNT: decimals(1) + symbol_len(1) + symbol(<=10) + + * amount(<=32). Other formats remain capped at 32 by their own guards. */ +#define METADATA_MAX_ARG_VALUE_LEN 44 +#define METADATA_MAX_TOKEN_SYMBOL_LEN 10 +#define METADATA_MAX_KEYS 4 +#define METADATA_ALIAS_MAX_LEN 31 +/* Identity icon cap (1bpp mono RLE). Must equal the device-protocol + * LoadClearsignSigner.icon max_size and storage.h CLEARSIGN_ICON_MAX + * (static-asserted in signed_metadata.c). */ +#define METADATA_ICON_MAX 384 +/* hex(first 4 bytes of sha256(pubkey)) + NUL */ +#define METADATA_FINGERPRINT_LEN 9 + +typedef enum { + METADATA_OPAQUE = 0, + METADATA_VERIFIED = 1, + METADATA_MALFORMED = 2, +} MetadataClassification; + +/* + * Blob format versions (the first payload byte). + * + * LEGACY (v1): per-transaction. The blob carries a committed tx_hash and the + * pre-decoded argument VALUES; the host is trusted for the decode and the + * device only binds it to the signed digest (signed_metadata_enforce). This is + * the format that requires an online, per-tx signer holding the attestation + * key. + * + * SCHEMA (v2): static. The blob carries NO tx_hash and NO values — only how to + * decode the call: (chainId, contract, selector, method, per-arg name + display + * format [+ static decimals/symbol]). The DEVICE decodes the argument values + * from the exact calldata it is about to sign, so the display is bound to the + * signature by construction. No tx_hash, no per-tx signing: the catalog is + * signed ONCE, offline, and can be served from a host CDN (no hot key). + */ +#define METADATA_VERSION_LEGACY 0x01 +#define METADATA_VERSION_SCHEMA 0x02 + +/* + * Argument display formats. The goal of clear-signing is that the device + * answers WHO the user is dealing with (validated contract address, protocol + * name), WHAT the transaction does (method + human-readable typed args: + * recipient, "Amount: 1,000 USDC"), and WHY the decode can be trusted + * (signer attestation bound to the exact tx hash). RAW/BYTES hex dumps are + * the fallback, not the product. + */ +typedef enum { + ARG_FORMAT_RAW = 0, /* hex dump (first 16 bytes) */ + ARG_FORMAT_ADDRESS = 1, /* 20 bytes -> full EIP-55 address, never truncated */ + ARG_FORMAT_AMOUNT = 2, /* big-endian uint256 -> raw integer, "wei" */ + ARG_FORMAT_BYTES = 3, /* hex dump (first 16 bytes) */ + /* Attested printable label, e.g. protocol: "Uniswap V2". Same character + * rules as the signer alias minus length (printable subset, no '%'). */ + ARG_FORMAT_STRING = 4, + /* decimals(1) + symbol_len(1) + symbol(<=10, [A-Za-z0-9]) + amount(1..32 + * big-endian). Rendered as a decimal-scaled amount with the symbol, e.g. + * "1000 USDC"; all-0xFF 32-byte amounts render "UNLIMITED ". */ + ARG_FORMAT_TOKEN_AMOUNT = 5, +} ArgFormat; + +typedef struct { + char name[METADATA_MAX_ARG_NAME_LEN + 1]; + ArgFormat format; + uint8_t value[METADATA_MAX_ARG_VALUE_LEN]; + uint16_t value_len; +} MetadataArg; + +typedef struct { + uint8_t version; + uint32_t chain_id; + uint8_t contract_address[20]; + uint8_t selector[4]; + uint8_t tx_hash[32]; + char method_name[METADATA_MAX_METHOD_LEN + 1]; + uint8_t num_args; + MetadataArg args[METADATA_MAX_ARGS]; + MetadataClassification classification; + uint32_t timestamp; + uint8_t key_id; + uint8_t signature[64]; + uint8_t recovery; +} SignedMetadata; + +bool signed_metadata_available(void); + +/* True when the stored v2 (schema) metadata was decoded from the current tx's + * calldata by the most recent signed_metadata_matches_tx() call. Reset at the + * top of every matches_tx() so it reflects only that call (never a stale prior + * match). The v2 enforce path requires it; exported for unit testing. */ +bool signed_metadata_schema_decoded(void); + +void signed_metadata_clear(void); + +/* + * Runtime-loaded clearsign signers (phase 1: the ONLY verification path). + * + * A signer is a compressed secp256k1 pubkey + display alias loaded into a + * key slot at the host's request, gated by a mandatory on-device confirm + * (see fsm_msgLoadClearsignSigner). Loaded signers live in RAM only and are + * gone on reboot. Metadata verified by a loaded signer always shows a + * warning screen naming the alias before any clearsign page — only the + * built-in (phase 2) keys sign warning-free. + */ + +/* Pure validation: slot in range and not occupied by a built-in key, pubkey a + * valid compressed secp256k1 point, alias non-empty printable ASCII within + * METADATA_ALIAS_MAX_LEN. No state, no I/O. */ +bool signed_metadata_signer_valid(uint8_t key_id, const uint8_t* pubkey, + size_t pubkey_len, const char* alias); + +/* Store a signer into a slot. Caller (the FSM handler) MUST have passed + * signed_metadata_signer_valid() and obtained on-device user confirmation + * first — this function is the post-consent write, nothing more. + * + * icon (optional, icon_len<=384, 1bpp mono RLE) is kept as the session icon for + * the slot; icon_len==0 => text-only identity. When persist=true the signer + * (incl. icon) is ALSO written to flash so it survives reboot. Returns false + * only when persist was requested but every persistent slot is occupied by a + * different identity — the RAM (session) signer is stored regardless. */ +bool signed_metadata_store_signer(uint8_t key_id, const uint8_t* pubkey, + const char* alias, const uint8_t* icon, + uint8_t icon_w, uint8_t icon_h, + uint16_t icon_len, bool persist); + +/* Resolve a slot's alias / icon from the RAM session copy, else a persisted + * identity that survived reboot. alias returns NULL and icon returns false when + * the slot has no signer / no icon (text-only). Used by the per-tx confirm. */ +const char* signed_metadata_signer_alias(uint8_t key_id); +bool signed_metadata_signer_icon(uint8_t key_id, const uint8_t** icon_out, + uint8_t* w_out, uint8_t* h_out, + uint16_t* len_out); + +/* The LoadClearsignSigner consent screen: leads with the identity's logo (if + * any) + alias + fingerprint. Returns true iff the user confirmed. The FSM + * handler calls this before storing the signer. */ +bool signed_metadata_confirm_load(const char* alias, const char* fingerprint, + const uint8_t* icon, uint8_t icon_w, + uint8_t icon_h, uint16_t icon_len, + bool persist); + +/* Drop all runtime-loaded signers (and any metadata they verified). */ +void signed_metadata_clear_signers(void); + +/* out = hex of the first 4 bytes of sha256(pubkey[33]), NUL-terminated. + * Shown at load-confirm and on the per-tx warning screen so the user can + * correlate the two. */ +void signed_metadata_pubkey_fingerprint(const uint8_t pubkey[33], + char out[METADATA_FINGERPRINT_LEN]); + +/* True when the currently stored metadata was verified by a runtime-loaded + * signer (=> its confirm flow is warning-first, never "Insight Verified"). */ +bool signed_metadata_from_loaded_signer(void); +MetadataClassification signed_metadata_process(const uint8_t* payload, + size_t payload_len, + uint8_t key_id); + +/* Generic attestation check reusing the (chain-agnostic) clear-sign signer + * keyring: returns true iff a signer is loaded/pinned for `key_id` AND the + * 64-byte compact ECDSA signature `sig` verifies over sha256(data). Used by + * non-EVM paths (e.g. Solana signed token definitions) that want to trust + * host-supplied data only when a loaded signer attests to it. */ +bool signed_metadata_verify_attestation(uint8_t key_id, const uint8_t* data, + size_t data_len, const uint8_t* sig, + size_t sig_len); + +/* Fingerprint (hex of sha256(pubkey)[0:4]) of the signer loaded/pinned in + * `key_id`, written NUL-terminated to `out`. Returns false if no signer is + * present. Lets non-EVM callers disambiguate signers (aliases are not unique) + * the same way the EVM per-tx warning does. */ +bool signed_metadata_signer_fingerprint(uint8_t key_id, + char out[METADATA_FINGERPRINT_LEN]); +/* Display gate: does this metadata plausibly describe `msg`? Binds contract + * address, selector and chain id so the wrong method is never shown. The + * authoritative full-tx binding is enforced later by signed_metadata_enforce(). + */ +bool signed_metadata_matches_tx(const EthereumSignTx* msg); +bool signed_metadata_confirm(void); + +/* True once a verified confirm has suppressed the raw-data confirmation, i.e. + * the signature is now gated on the metadata matching the final tx hash. */ +bool signed_metadata_relied(void); + +/* Authoritative binding, called after the real Ethereum sighash is finalized + * (in send_signature, the only point it exists). Returns true if signing may + * proceed: either no metadata was relied upon, or the relied-upon metadata's + * committed tx_hash equals `hash`. Fail-closed on any mismatch. */ +bool signed_metadata_enforce(const uint8_t hash[32]); + +/* Pure enforcement decision, exported for unit testing. Given the module flags + * and the metadata's committed tx hash, decides whether signing may proceed for + * the just-finalized `hash`. signed_metadata_enforce() is a thin wrapper that + * feeds the module state into this function. No state, no I/O. */ +bool signed_metadata_enforce_decision(bool relied, bool available, + int classification, + const uint8_t* stored_hash, + const uint8_t* hash); + +/* Pure enforcement decision for v2 (static schema) blobs, exported for unit + * testing. v2 has no committed tx_hash; the binding is structural (args decoded + * from the signed calldata), so signing proceeds when the relied-upon metadata + * is available, VERIFIED, and was actually decoded (`decoded`) — no digest + * comparison. `decoded` must be the recorded result of decode_v2_args() for + * this signing operation, not inferred from call order. + * signed_metadata_enforce() dispatches here when the stored blob's version is + * METADATA_VERSION_SCHEMA. */ +bool signed_metadata_enforce_schema_decision(bool relied, bool available, + bool decoded, int classification); + +const SignedMetadata* signed_metadata_get(void); + +#endif diff --git a/include/keepkey/firmware/signtx_tendermint.h b/include/keepkey/firmware/signtx_tendermint.h index 9277a370f..082fb4970 100644 --- a/include/keepkey/firmware/signtx_tendermint.h +++ b/include/keepkey/firmware/signtx_tendermint.h @@ -9,8 +9,15 @@ typedef struct _TendermintSignTx TendermintSignTx; +typedef enum { + TENDERMINT_SIGNING_NONE = 0, + TENDERMINT_SIGNING_COSMOS, + TENDERMINT_SIGNING_GENERIC, +} TendermintSigningType; + bool tendermint_signTxInit(const HDNode* _node, const void* _msg, - const size_t msgsize, const char* denom); + const size_t msgsize, const char* denom, + TendermintSigningType type); bool tendermint_signTxUpdateMsgSend(const uint64_t amount, const char* to_address, const char* chainstr, const char* denom, @@ -41,9 +48,11 @@ bool tendermint_signTxUpdateMsgIBCTransfer( const char* revision_number, const char* revision_height, const char* chainstr, const char* denom, const char* msgTypePrefix); bool tendermint_signTxFinalize(uint8_t* public_key, uint8_t* signature); -bool tendermint_signingIsInited(void); +bool tendermint_signingIsInited(TendermintSigningType type); +bool tendermint_signingConfigMatches(const char* chain_name, const char* denom, + const char* message_type_prefix); bool tendermint_signingIsFinished(void); void tendermint_signAbort(void); const void* tendermint_getSignTx(void); -#endif \ No newline at end of file +#endif diff --git a/include/keepkey/firmware/solana.h b/include/keepkey/firmware/solana.h index a56611dad..177f345a4 100644 --- a/include/keepkey/firmware/solana.h +++ b/include/keepkey/firmware/solana.h @@ -156,6 +156,10 @@ typedef struct { uint8_t mint[SOL_PUBKEY_SIZE]; bool has_mint; uint8_t extra_u8; + /* Instruction payload (memo body display). Points into the raw message + * buffer passed to solana_inspectTx — valid only while that buffer is. */ + const uint8_t* data; + uint16_t data_len; } SolanaParsedInstruction; /* Parsed transaction header */ @@ -195,6 +199,19 @@ void solana_formatTokenAmount(char* buf, size_t len, uint64_t amount, const SolanaTokenInfo* solana_findTokenInfo( const SolanaSignTx* msg, const uint8_t mint[SOL_PUBKEY_SIZE]); +/* True iff `ti` carries a valid attestation: an ECDSA signature (by a clearsign + * signer the user loaded) over a domain-separated (mint, decimals, symbol) + * digest. Range-checks signer_key_id before narrowing it. Verifies only the + * attested tuple — the caller must additionally confirm the attested decimals + * match the signed instruction before trusting the amount. */ +bool solana_token_info_trusted(const SolanaTokenInfo* ti); + +/* ceil(price * limit / 1,000,000) priority-fee lamports, overflow-safe. Returns + * false (and leaves *out untouched) if the true value exceeds UINT64_MAX — the + * caller must then refuse to sign rather than display a wrapped figure. */ +bool solana_priority_fee_lamports(uint64_t price, uint64_t limit, + uint64_t* out); + /* Sign transaction */ bool solana_signTx(const HDNode* node, const SolanaSignTx* msg, SolanaSignedTx* resp); diff --git a/include/keepkey/firmware/storage.h b/include/keepkey/firmware/storage.h index 9fc8c1954..494eedf0b 100644 --- a/include/keepkey/firmware/storage.h +++ b/include/keepkey/firmware/storage.h @@ -26,7 +26,19 @@ #include "keepkey/firmware/authenticator.h" #define STORAGE_VERSION \ - 17 /* Must add case fallthrough in storage_fromFlash after increment*/ + 18 /* Must add case fallthrough in storage_fromFlash after increment*/ + +/* A seed CREATED under bitcoin-only firmware is stamped with a version in a + * reserved band (base + the normal version). Multi-chain firmware that knows + * the band refuses to load it and requires an explicit wipe; older multi-chain + * firmware treats it as an unknown version and resets. Either way a seed born + * on bitcoin-only firmware is never usable by multi-chain code. A pre-existing + * multi-chain wallet keeps its normal version and stays portable (it was + * already multi-chain-exposed). Multi-chain versions MUST stay below the band + * forever (static-asserted in storage.c). */ +#define STORAGE_VERSION_BTC_ONLY_BASE 10000 +#define STORAGE_VERSION_BTC_ONLY \ + (STORAGE_VERSION_BTC_ONLY_BASE + STORAGE_VERSION) #define STORAGE_RETRIES 3 #define RANDOM_SALT_LEN 32 @@ -39,6 +51,12 @@ /// \brief Validate storage content and copy data to shadow memory. void storage_init(void); +/// \brief True iff flash holds storage written by bitcoin-only firmware that +/// this (multi-chain) firmware refuses to load. The device must be +/// wiped before it can be used; the seed stays intact in flash so +/// reflashing bitcoin-only firmware recovers the wallet. +bool storage_isBitcoinOnlyLocked(void); + /// \brief Reset configuration UUID with random numbers. void storage_resetUuid(void); diff --git a/include/keepkey/firmware/tendermint.h b/include/keepkey/firmware/tendermint.h index aa29399d1..67cad3ff2 100644 --- a/include/keepkey/firmware/tendermint.h +++ b/include/keepkey/firmware/tendermint.h @@ -28,6 +28,12 @@ bool tendermint_pathMismatched(const CoinType* coin, const uint32_t* address_n, bool tendermint_getAddress(const HDNode* node, const char* prefix, char* address); +bool tendermint_isValidDenom(const char* denom); + +bool tendermint_isValidAsset(const char* asset); + +bool tendermint_isValidSigner(const char* signer, const char* hrp); + void tendermint_sha256UpdateEscaped(SHA256_CTX* ctx, const char* s, size_t len); bool tendermint_snprintf(SHA256_CTX* ctx, char* temp, size_t len, diff --git a/include/keepkey/firmware/thorchain.h b/include/keepkey/firmware/thorchain.h index 5ebb2a993..398495863 100644 --- a/include/keepkey/firmware/thorchain.h +++ b/include/keepkey/firmware/thorchain.h @@ -10,9 +10,18 @@ typedef struct _ThorchainSignTx ThorchainSignTx; typedef struct _ThorchainMsgDeposit ThorchainMsgDeposit; +// Returns true iff denom contains only chars safe in JSON without escaping. +// Valid: [a-z0-9./\-]. Rejects empty string, quotes, backslashes, whitespace. +bool thorchain_isValidDenom(const char* denom); + +// Deposit asset grammar: as above but uppercase alpha also allowed. +bool thorchain_isValidAsset(const char* asset); +// Deposit signer must be bech32 with the active network's HRP. +bool thorchain_isValidSigner(const char* signer); + bool thorchain_signTxInit(const HDNode* _node, const ThorchainSignTx* _msg); bool thorchain_signTxUpdateMsgSend(const uint64_t amount, - const char* to_address); + const char* to_address, const char* denom); bool thorchain_signTxUpdateMsgDeposit(const ThorchainMsgDeposit* depmsg); bool thorchain_signTxFinalize(uint8_t* public_key, uint8_t* signature); bool thorchain_signingIsInited(void); @@ -28,4 +37,13 @@ const ThorchainSignTx* thorchain_getThorchainSignTx(void); // true if thorchain data parsed and confirmed by user, false otherwise bool thorchain_parseConfirmMemo(const char* swapStr, size_t size); +// Pages the COMPLETE raw memo (ASCII as text pages, binary as hex pages) so no +// byte is ever truncated behind confirm()'s body budget. Native THOR/MAYA +// deposit/send handlers call this as the authoritative disclosure after their +// best-effort structured summary, so a field the structured view omits (or a +// long field that would truncate) can never be signed unseen. Returns false if +// the user rejects any page. Shared by the MAYA path (same memo grammar). +bool thorchain_confirm_full_memo(const char* title, const char* memo, + size_t len); + #endif diff --git a/include/keepkey/firmware/tiny-json.h b/include/keepkey/firmware/tiny-json.h index 7ba75ec38..d4a76a019 100644 --- a/include/keepkey/firmware/tiny-json.h +++ b/include/keepkey/firmware/tiny-json.h @@ -35,6 +35,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + #define json_containerOf(ptr, type, member) \ ((type*)((char*)ptr - offsetof(type, member))) @@ -66,7 +70,6 @@ typedef struct json_s { jsonType_t type; } json_t; -extern int errno; /** Parse a string to get a json. * @param str String pointer with a JSON object. It will be modified. * @param mem Array of json properties to allocate. diff --git a/include/keepkey/firmware/tron.h b/include/keepkey/firmware/tron.h index 6e51d8040..f50bc2de8 100644 --- a/include/keepkey/firmware/tron.h +++ b/include/keepkey/firmware/tron.h @@ -24,12 +24,67 @@ #include "messages-tron.pb.h" +#include +#include +#include + // TRON address length (Base58Check, typically 34 chars starting with 'T') #define TRON_ADDRESS_MAX_LEN 64 // TRON decimals (1 TRX = 1,000,000 SUN) #define TRON_DECIMALS 6 +// Raw 21-byte TRON address: 0x41 prefix + 20-byte keccak hash tail +#define TRON_RAW_ADDRESS_SIZE 21 + +/** + * On-device classification of a TronSignTx raw_data payload. + * + * The device signs sha256(raw_data), so anything shown to the user MUST be + * decoded from raw_data itself — never from side-channel proto fields. + * Unless every field of the payload is understood, the transaction is + * TRON_TX_UNVERIFIED and only the blind-sign path may be offered. + */ +typedef enum { + TRON_TX_UNVERIFIED = 0, // not fully understood — blind-sign only + TRON_TX_TRANSFER, // single TransferContract (native TRX send) + TRON_TX_TRC20_TRANSFER, // single TriggerSmartContract: + // transfer(address,uint256) +} TronTxType; + +typedef struct { + TronTxType type; + uint8_t owner[TRON_RAW_ADDRESS_SIZE]; // spending account + uint8_t to[TRON_RAW_ADDRESS_SIZE]; // TRX or token recipient + uint8_t contract[TRON_RAW_ADDRESS_SIZE]; // TRC-20 token contract + uint64_t amount; // SUN, TransferContract only + uint8_t trc20_amount[32]; // big-endian uint256 token base units + bool has_fee_limit; + uint64_t fee_limit; // SUN + const uint8_t* memo; // points into caller's raw_data + uint16_t memo_len; +} TronParsedTx; + +/** + * Parse a TRON raw_data protobuf for on-device display. + * Fail-closed: any unrecognized top-level field, contract type, extra + * contract, or unexpected parameter field yields TRON_TX_UNVERIFIED. + * out->memo points into raw — valid only while raw is alive. + */ +TronTxType tron_parseRawTx(const uint8_t* raw, size_t len, TronParsedTx* out); + +/** + * Base58Check-encode a raw 21-byte TRON address for display. + */ +bool tron_addressFromBytes(const uint8_t addr[TRON_RAW_ADDRESS_SIZE], char* out, + size_t out_len); + +/** + * Format a TRC-20 uint256 amount (big-endian) as a decimal string of token + * base units. Token decimals are unknown on-device, so no scaling is done. + */ +bool tron_formatTrc20Amount(const uint8_t amount_be[32], char* buf, size_t len); + /** * Generate TRON address from secp256k1 public key * @param public_key secp256k1 public key (33 bytes compressed) diff --git a/include/keepkey/firmware/zcash.h b/include/keepkey/firmware/zcash.h new file mode 100644 index 000000000..79b27c391 --- /dev/null +++ b/include/keepkey/firmware/zcash.h @@ -0,0 +1,384 @@ +/* + * This file is part of the KeepKey project. + * + * Copyright (C) 2025 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. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef KEEPKEY_FIRMWARE_ZCASH_H +#define KEEPKEY_FIRMWARE_ZCASH_H + +#include +#include +#include + +/* Orchard spending keys derived via ZIP-32. + * cppcheck doesn't see these used because the consumers live in + * fsm_msg_zcash.h which is #include'd into fsm.c rather than compiled + * separately, so the struct members appear "unused" in this TU. */ +typedef struct { + // cppcheck-suppress unusedStructMember + uint8_t sk[32]; /* Spending key (master secret at this level) */ + // cppcheck-suppress unusedStructMember + uint8_t ask[32]; /* Spend authorizing key (scalar) */ + // cppcheck-suppress unusedStructMember + uint8_t nk[32]; /* Nullifier deriving key */ + // cppcheck-suppress unusedStructMember + uint8_t rivk[32]; /* Commitment randomness key */ + // cppcheck-suppress unusedStructMember + uint8_t dk[32]; /* Diversifier key */ +} ZcashOrchardKeys; + +typedef struct { + bool has_header_digest; + size_t header_digest_size; + bool has_transparent_digest; + size_t transparent_digest_size; + bool has_sapling_digest; + size_t sapling_digest_size; + bool has_orchard_digest; + size_t orchard_digest_size; + bool has_orchard_flags; + uint32_t orchard_flags; + bool has_orchard_value_balance; + bool has_orchard_anchor; + size_t orchard_anchor_size; + bool has_header_fields; + uint32_t n_transparent_inputs; + uint32_t n_transparent_outputs; +} ZcashPCZTSigningRequestMeta; + +typedef enum { + ZCASH_PCZT_SIGNING_REQUEST_OK = 0, + ZCASH_PCZT_SIGNING_REQUEST_MISSING_TX_DIGESTS, + ZCASH_PCZT_SIGNING_REQUEST_INVALID_DIGEST_SIZE, + ZCASH_PCZT_SIGNING_REQUEST_MISSING_HEADER_FIELDS, + ZCASH_PCZT_SIGNING_REQUEST_UNSUPPORTED_SAPLING_COMPONENT, + ZCASH_PCZT_SIGNING_REQUEST_MISSING_ORCHARD_METADATA, + ZCASH_PCZT_SIGNING_REQUEST_MISSING_TRANSPARENT_DIGEST, +} ZcashPCZTSigningRequestStatus; + +typedef struct { + const uint8_t* prevout_txid; + uint32_t prevout_index; + uint32_t sequence; + uint64_t value; + const uint8_t* script_pubkey; + size_t script_pubkey_size; +} ZcashTransparentInputDigestInfo; + +typedef struct { + uint64_t value; + const uint8_t* script_pubkey; + size_t script_pubkey_size; +} ZcashTransparentOutputDigestInfo; + +#define ZCASH_ORCHARD_RAW_RECEIVER_SIZE 43 +#define ZCASH_ORCHARD_UNIFIED_ADDRESS_SIZE 128 + +/** + * Validate the clear-signing metadata required before Orchard signatures. + * + * This rejects the legacy flow where the host supplied only a per-action + * sighash. The firmware must assemble the ZIP-244 sighash from transaction + * component digests and verify the Orchard digest against streamed action data + * before returning signatures. + */ +ZcashPCZTSigningRequestStatus zcash_pczt_signing_request_status( + const ZcashPCZTSigningRequestMeta* meta); + +bool zcash_pczt_signing_request_is_clear( + const ZcashPCZTSigningRequestMeta* meta); + +/** + * Derive Orchard spending keys from the device seed via ZIP-32. + * Path: m_orchard / 32' / 133' / account' + * + * Uses BLAKE2b with personalization "ZcashIP32Orchard" for key derivation. + * + * @param seed BIP-39 master seed + * @param seed_len Seed length (typically 64 bytes) + * @param account Account index (0-based, will be hardened) + * @param keys Output: derived Orchard keys + * @return true on success + */ +bool zcash_derive_orchard_keys(const uint8_t* seed, uint32_t seed_len, + uint32_t account, ZcashOrchardKeys* keys); + +/** + * Compute the ZIP 244 shielded sighash for Orchard spend authorization. + * + * For shielded-only transactions, transparent_sig_digest uses the "no inputs" + * form. For mixed transactions, transparent data must be provided separately. + * + * @param header_digest 32-byte pre-computed header digest + * @param transparent_digest 32-byte transparent sig digest (or empty hash) + * @param sapling_digest 32-byte sapling digest (or empty hash) + * @param orchard_digest 32-byte orchard digest + * @param branch_id Consensus branch ID (LE) + * @param sighash_out 32-byte output sighash + * @return true on success + */ +bool zcash_compute_shielded_sighash(const uint8_t header_digest[32], + const uint8_t transparent_digest[32], + const uint8_t sapling_digest[32], + const uint8_t orchard_digest[32], + uint32_t branch_id, + uint8_t sighash_out[32]); + +/** + * Compute ZIP-244 T.1 header_digest from plaintext transaction header fields. + */ +bool zcash_compute_header_digest(uint32_t version, uint32_t version_group_id, + uint32_t branch_id, uint32_t lock_time, + uint32_t expiry_height, + uint8_t digest_out[32]); + +/** + * Compute ZIP-244 T.2 transparent_digest from plaintext transparent data. + * + * This is the digest mixed into the Orchard/Sapling signing commitment. It is + * not the same as the per-input transparent signature digest. + */ +bool zcash_compute_transparent_digest( + const ZcashTransparentInputDigestInfo* inputs, size_t n_inputs, + const ZcashTransparentOutputDigestInfo* outputs, size_t n_outputs, + uint8_t digest_out[32]); + +/** + * Compute ZIP-244 §4.9 transparent_sig_digest for Orchard spend authorization. + * + * Uses the S.2 form with EMPTY txin_sig_digest when n_inputs > 0 (shield txs), + * or falls back to T.1 when n_inputs == 0 (deshield / private-send). This is + * what the Zcash consensus node uses to verify Orchard spend auth sigs and the + * binding signature in a hybrid (transparent + Orchard) transaction. + */ +bool zcash_compute_orchard_transparent_sig_digest( + const ZcashTransparentInputDigestInfo* inputs, size_t n_inputs, + const ZcashTransparentOutputDigestInfo* outputs, size_t n_outputs, + uint8_t digest_out[32]); + +/** + * Compute ZIP-244 S.2 per-input transparent signature digest. + * + * This currently accepts SIGHASH_ALL only, matching the existing transparent + * signing flow. + */ +bool zcash_compute_transparent_sighash_digest( + const ZcashTransparentInputDigestInfo* inputs, size_t n_inputs, + const ZcashTransparentOutputDigestInfo* outputs, size_t n_outputs, + uint32_t signable_input_index, uint8_t sighash_type, + uint8_t digest_out[32]); + +/** + * Encode a raw Orchard receiver (d || pk_d) as an Orchard-only ZIP-316 Unified + * Address for display. This is for recipient review; it does not derive or + * prove ownership of the receiver. + */ +bool zcash_orchard_receiver_to_unified_address( + const uint8_t receiver[ZCASH_ORCHARD_RAW_RECEIVER_SIZE], const char* hrp, + char* address_out, size_t address_out_len); + +/** + * Recompute an Orchard output note commitment x-coordinate (cmx). + * + * cmx = Extract_P(NoteCommit_rcm^Orchard(g_d, pk_d, v, rho, psi)) + * where receiver = d || pk_d, rho is the action nullifier, and rseed is the + * output note seed. This binds the user-displayed receiver/value to the action + * commitment before any authorization signature is emitted. + */ +bool zcash_orchard_compute_cmx( + const uint8_t receiver[ZCASH_ORCHARD_RAW_RECEIVER_SIZE], uint64_t value, + const uint8_t rho[32], const uint8_t rseed[32], uint8_t cmx_out[32]); + +/** + * Derive an Orchard diversifier from a diversifier key and 88-bit index. + * + * ZIP-32 defines Orchard diversifiers as: + * d_j = FF1-AES256.Encrypt(dk, "", I2LEBSP_88(j)) + * + * Both index_le and diversifier_out are 11-byte LEBS2OSP encodings of the + * 88-bit bitstrings. + * + * @param dk 32-byte Orchard diversifier key + * @param index_le 11-byte little-endian diversifier index bitstring + * @param diversifier_out 11-byte output diversifier + * @return true on success + */ +bool zcash_orchard_derive_diversifier(const uint8_t dk[32], + const uint8_t index_le[11], + uint8_t diversifier_out[11]); + +/** + * Compute DiversifyHash^Orchard(d) as a serialized Pallas point. + * + * g_d = GroupHash^Pallas("z.cash:Orchard-gd", d) + * + * If the group hash ever returns the identity, Orchard falls back to hashing + * the empty message under the same domain. + * + * @param diversifier 11-byte Orchard diversifier + * @param gd_out 32-byte compressed Pallas point + * @return true on success + */ +bool zcash_orchard_diversify_hash(const uint8_t diversifier[11], + uint8_t gd_out[32]); + +/** + * Derive an Orchard diversified transmission key. + * + * g_d = DiversifyHash^Orchard(d) + * pk_d = KA^Orchard.DerivePublic(ivk, g_d) = [ivk] g_d + * + * @param ivk 32-byte nonzero Orchard incoming viewing key encoding + * @param diversifier 11-byte Orchard diversifier + * @param gd_out optional 32-byte compressed g_d output, may be NULL + * @param pkd_out 32-byte compressed diversified transmission key + * @return true on success + */ +bool zcash_orchard_derive_transmission_key(const uint8_t ivk[32], + const uint8_t diversifier[11], + uint8_t gd_out[32], + uint8_t pkd_out[32]); + +/** + * Derive the external Orchard incoming viewing key from FVK components. + * + * ivk = Commit^ivk.Output(ExtractP(ak), nk, rivk) + * + * @param ak 32-byte Orchard spend validating key encoding, sign bit clear + * @param nk 32-byte Orchard nullifier deriving key + * @param rivk 32-byte Orchard IVK commitment randomness + * @param ivk_out 32-byte nonzero Orchard incoming viewing key + * @return true on success + */ +bool zcash_orchard_derive_ivk(const uint8_t ak[32], const uint8_t nk[32], + const uint8_t rivk[32], uint8_t ivk_out[32]); + +/** + * Derive a raw Orchard receiver from external FVK components and index. + * + * d_j = DiversifierKey(dk).get(j) + * ivk = Commit^ivk.Output(ExtractP(ak), nk, rivk) + * pk_dj = KA^Orchard.DerivePublic(ivk, DiversifyHash(d_j)) + * + * @param ak 32-byte Orchard spend validating key encoding + * @param nk 32-byte Orchard nullifier deriving key + * @param rivk 32-byte Orchard IVK commitment randomness + * @param dk 32-byte Orchard diversifier key + * @param index_le 11-byte little-endian diversifier index bitstring + * @param receiver_out 43-byte raw receiver: d_j || pk_dj + * @return true on success + */ +bool zcash_orchard_derive_receiver(const uint8_t ak[32], const uint8_t nk[32], + const uint8_t rivk[32], const uint8_t dk[32], + const uint8_t index_le[11], + uint8_t receiver_out[43]); + +/** + * Derive an Orchard-only ZIP-316 Unified Address from derived Orchard keys. + * + * ak = [ask] G_spendauth + * receiver = d_j || pk_dj + * address = Bech32m(HRP, F4Jumble(Orchard receiver payload)) + * + * @param keys ZIP-32-derived Orchard key material + * @param index_le 11-byte little-endian diversifier index bitstring + * @param hrp ZIP-316 HRP ("u" for mainnet, "utest" for testnet) + * @param address_out NUL-terminated output address + * @param address_out_len Size of address_out + * @return true on success + */ +bool zcash_orchard_derive_unified_address(const ZcashOrchardKeys* keys, + const uint8_t index_le[11], + const char* hrp, char* address_out, + size_t address_out_len); + +/** + * Compute the ZIP-32 §6.1 seed fingerprint. + * + * SeedFingerprint := BLAKE2b-256( + * "Zcash_HD_Seed_FP", I2LEBSP_8(len(seed)) || seed) + * + * The 1-byte length prefix domain-separates seeds of different lengths that + * happen to share a prefix. + * + * 32-byte stable identifier of a seed. Used by host wallets and PCZTs + * (zip32_derivation.seed_fingerprint) to confirm which device seed produced + * a given key, address, or signature. Trivial seeds (all-zero, all-0xFF) + * and seeds outside [32, 252] bytes are rejected per ZIP-32 §6.1. + * + * @param seed Seed bytes (BIP-39 seed or BIP-32 master seed) + * @param seed_len Seed length, must be in [32, 252] + * @param fingerprint_out 32-byte output fingerprint + * @return true on success, false if seed is invalid + */ +bool zcash_calculate_seed_fingerprint(const uint8_t* seed, uint32_t seed_len, + uint8_t fingerprint_out[32]); + +/** + * Validate the wire shape of an optional asserted seed fingerprint. Omission is + * valid; a present assertion must be exactly 32 bytes. + */ +bool zcash_seed_fingerprint_request_valid(bool present, size_t size); + +/* ── Storage-scoped wrappers ─────────────────────────────────────────── + * + * The two functions below own the seed access. Implementations live in + * lib/firmware/storage.c so the raw 64-byte BIP-39 seed never escapes + * that translation unit. Callers (FSM handlers) get only the derived + * material — Orchard keys or the 32-byte fingerprint — never a pointer + * to the seed itself. This is the only sanctioned way for production + * firmware code to consume seed-derived Zcash material. + * + * The bare zcash_derive_orchard_keys() / zcash_calculate_seed_fingerprint() + * functions above remain in the header for unit tests, which feed them + * known test vectors directly. + */ + +/** + * Derive Orchard keys for an account using the device's session seed. + * + * @param account Account index (0-based, will be hardened) + * @param usePassphrase Whether to apply the passphrase (prompts if needed) + * @param keys_out Output: derived Orchard keys + * @return true on success, false if seed unavailable or derivation fails + */ +bool storage_zcashOrchardKeys(uint32_t account, bool usePassphrase, + ZcashOrchardKeys* keys_out); + +/** + * Compute the ZIP-32 §6.1 seed fingerprint for the device's session seed. + * + * @param usePassphrase Whether to apply the passphrase (prompts if needed) + * @param fingerprint_out 32-byte output fingerprint + * @return true on success, false if seed unavailable + */ +bool storage_zcashSeedFingerprint(bool usePassphrase, + uint8_t fingerprint_out[32]); + +/** + * Tear down any in-progress Zcash signing session. + * + * Wipes the static signing state (active flag, derived Orchard keys, + * accumulated signatures, sub-digest contexts, transparent-input + * counters) so a host cannot resume streaming PCZTAction or + * TransparentInput messages against a previously-approved session + * after Initialize, Cancel, or ClearSession. Safe to call when no + * session is active. + */ +void zcash_signing_abort(void); + +#endif diff --git a/include/keepkey/transport/interface.h b/include/keepkey/transport/interface.h index 45e5a09e6..6ec14d24e 100644 --- a/include/keepkey/transport/interface.h +++ b/include/keepkey/transport/interface.h @@ -38,6 +38,8 @@ #include "messages-tron.pb.h" #include "messages-ton.pb.h" #include "messages-solana.pb.h" +#include "messages-zcash.pb.h" +#include "messages-hive.pb.h" #include "types.pb.h" #include "trezor_transport.h" diff --git a/include/keepkey/transport/messages-ethereum.options b/include/keepkey/transport/messages-ethereum.options index 65b6a1a2f..e4a769b7d 100644 --- a/include/keepkey/transport/messages-ethereum.options +++ b/include/keepkey/transport/messages-ethereum.options @@ -49,4 +49,7 @@ Ethereum712TypesValues.eip712data max_size:2048 EthereumTxMetadata.signed_payload max_size:1024 EthereumMetadataAck.display_summary max_size:32 +LoadClearsignSigner.pubkey max_size:33 +LoadClearsignSigner.alias max_size:32 +LoadClearsignSigner.icon max_size:384 diff --git a/include/keepkey/transport/messages-hive.options b/include/keepkey/transport/messages-hive.options new file mode 100644 index 000000000..d39d59215 --- /dev/null +++ b/include/keepkey/transport/messages-hive.options @@ -0,0 +1,58 @@ +HiveGetPublicKey.address_n max_count:8 + +HivePublicKey.public_key max_size:64 +HivePublicKey.raw_public_key max_size:33 + +HiveGetPublicKeys.account_index int_size:IS_32 + +HivePublicKeys.owner_key max_size:64 +HivePublicKeys.active_key max_size:64 +HivePublicKeys.memo_key max_size:64 +HivePublicKeys.posting_key max_size:64 + +HiveSignTx.address_n max_count:8 +HiveSignTx.chain_id max_size:32 +HiveSignTx.from max_size:16 +HiveSignTx.to max_size:16 +HiveSignTx.amount int_size:IS_64 +HiveSignTx.asset_symbol max_size:10 +HiveSignTx.memo max_size:2048 + +HiveSignedTx.signature max_size:65 +HiveSignedTx.serialized_tx max_size:512 + +HiveSignAccountCreate.address_n max_count:8 +HiveSignAccountCreate.chain_id max_size:32 +HiveSignAccountCreate.creator max_size:16 +HiveSignAccountCreate.new_account_name max_size:16 +HiveSignAccountCreate.owner_key max_size:64 +HiveSignAccountCreate.active_key max_size:64 +HiveSignAccountCreate.posting_key max_size:64 +HiveSignAccountCreate.memo_key max_size:64 +HiveSignAccountCreate.fee_amount int_size:IS_64 + +HiveSignedAccountCreate.signature max_size:65 +HiveSignedAccountCreate.serialized_tx max_size:512 + +HiveSignAccountUpdate.address_n max_count:8 +HiveSignAccountUpdate.chain_id max_size:32 +HiveSignAccountUpdate.account max_size:16 +HiveSignAccountUpdate.new_owner_key max_size:64 +HiveSignAccountUpdate.new_active_key max_size:64 +HiveSignAccountUpdate.new_posting_key max_size:64 +HiveSignAccountUpdate.new_memo_key max_size:64 + +HiveSignedAccountUpdate.signature max_size:65 +HiveSignedAccountUpdate.serialized_tx max_size:512 + +HiveSignMessage.address_n max_count:8 +HiveSignMessage.message max_size:1024 + +HiveSignedMessage.signature max_size:65 +HiveSignedMessage.public_key max_size:33 + +HiveSignOperations.address_n max_count:8 +HiveSignOperations.chain_id max_size:32 +HiveSignOperations.serialized_tx max_size:2048 + +HiveSignedOperations.signature max_size:65 diff --git a/include/keepkey/transport/messages-ripple.options b/include/keepkey/transport/messages-ripple.options index b3f2e1987..219014bf6 100644 --- a/include/keepkey/transport/messages-ripple.options +++ b/include/keepkey/transport/messages-ripple.options @@ -6,5 +6,7 @@ RippleSignTx.address_n max_count:8 RipplePayment.destination max_size:36 +RippleSignTx.memo max_size:200 + RippleSignedTx.signature max_size:75 RippleSignedTx.serialized_tx max_size:1024 diff --git a/include/keepkey/transport/messages-solana.options b/include/keepkey/transport/messages-solana.options index ded9d68c1..b71dfc113 100644 --- a/include/keepkey/transport/messages-solana.options +++ b/include/keepkey/transport/messages-solana.options @@ -5,6 +5,7 @@ SolanaAddress.address max_size:64 SolanaTokenInfo.mint max_size:32 SolanaTokenInfo.symbol max_size:13 +SolanaTokenInfo.signature max_size:64 SolanaSignTx.address_n max_count:8 SolanaSignTx.coin_name max_size:21 diff --git a/include/keepkey/transport/messages-thorchain.options b/include/keepkey/transport/messages-thorchain.options index 14cb39b18..c17a9368c 100644 --- a/include/keepkey/transport/messages-thorchain.options +++ b/include/keepkey/transport/messages-thorchain.options @@ -8,6 +8,7 @@ ThorchainSignTx.memo max_size:256 ThorchainMsgSend.from_address max_size:46 ThorchainMsgSend.to_address max_size:46 +ThorchainMsgSend.denom max_size:69 ThorchainMsgDeposit.asset max_size:20 ThorchainMsgDeposit.memo max_size:256 diff --git a/include/keepkey/transport/messages-zcash.options b/include/keepkey/transport/messages-zcash.options new file mode 100644 index 000000000..f7776b869 --- /dev/null +++ b/include/keepkey/transport/messages-zcash.options @@ -0,0 +1,54 @@ +ZcashSignPCZT.address_n max_count:10 +ZcashSignPCZT.pczt_data max_size:0 +ZcashSignPCZT.total_amount int_size:IS_64 +ZcashSignPCZT.fee int_size:IS_64 +ZcashSignPCZT.header_digest max_size:32 +ZcashSignPCZT.transparent_digest max_size:32 +ZcashSignPCZT.sapling_digest max_size:32 +ZcashSignPCZT.orchard_digest max_size:32 +ZcashSignPCZT.orchard_value_balance int_size:IS_64 +ZcashSignPCZT.orchard_anchor max_size:32 +ZcashSignPCZT.expected_seed_fingerprint max_size:32 + +ZcashPCZTAction.alpha max_size:32 +ZcashPCZTAction.sighash max_size:32 +ZcashPCZTAction.cv_net max_size:32 +ZcashPCZTAction.value int_size:IS_64 +ZcashPCZTAction.nullifier max_size:32 +ZcashPCZTAction.cmx max_size:32 +ZcashPCZTAction.epk max_size:32 +ZcashPCZTAction.enc_compact max_size:52 +ZcashPCZTAction.enc_memo max_size:512 +ZcashPCZTAction.enc_noncompact max_size:564 +ZcashPCZTAction.rk max_size:32 +ZcashPCZTAction.out_ciphertext max_size:80 +ZcashPCZTAction.recipient max_size:43 +ZcashPCZTAction.rseed max_size:32 + +ZcashSignedPCZT.signatures max_count:16, max_size:64 +ZcashSignedPCZT.txid max_size:32 + +ZcashGetOrchardFVK.address_n max_count:10 + +ZcashOrchardFVK.ak max_size:32 +ZcashOrchardFVK.nk max_size:32 +ZcashOrchardFVK.rivk max_size:32 +ZcashOrchardFVK.seed_fingerprint max_size:32 + +ZcashTransparentOutput.amount int_size:IS_64 +ZcashTransparentOutput.script_pubkey max_size:128 + +ZcashTransparentInput.sighash max_size:32 +ZcashTransparentInput.address_n max_count:8 +ZcashTransparentInput.amount int_size:IS_64 +ZcashTransparentInput.prevout_txid max_size:32 +ZcashTransparentInput.script_pubkey max_size:128 + +ZcashTransparentSig.signature max_size:73 +ZcashTransparentSigned.signatures max_count:8, max_size:73 + +ZcashDisplayAddress.address_n max_count:8 +ZcashDisplayAddress.expected_seed_fingerprint max_size:32 + +ZcashAddress.address max_size:128 +ZcashAddress.seed_fingerprint max_size:32 diff --git a/lib/board/confirm_sm.c b/lib/board/confirm_sm.c index 0669536ab..8804f5f24 100644 --- a/lib/board/confirm_sm.c +++ b/lib/board/confirm_sm.c @@ -315,6 +315,29 @@ bool confirm(ButtonRequestType type, const char* request_title, return ret; } +bool confirm_with_icon(ButtonRequestType type, IconType iconNum, + const char* request_title, const char* request_body, + ...) { + button_request_acked = false; + + va_list vl; + va_start(vl, request_body); + vsnprintf(strbuf, sizeof(strbuf), request_body, vl); + va_end(vl); + + ButtonRequest resp; + memset(&resp, 0, sizeof(ButtonRequest)); + resp.has_code = true; + resp.code = type; + msg_write(MessageType_MessageType_ButtonRequest, &resp); + + bool ret = + confirm_helper(request_title, strbuf, &layout_standard_notification, + false, iconNum, false); + memzero(strbuf, sizeof(strbuf)); + return ret; +} + bool confirm_constant_power(ButtonRequestType type, const char* request_title, const char* request_body, ...) { button_request_acked = false; @@ -414,10 +437,11 @@ bool review(ButtonRequestType type, const char* request_title, resp.code = type; msg_write(MessageType_MessageType_ButtonRequest, &resp); - (void)confirm_helper(request_title, strbuf, &layout_standard_notification, - false, NO_ICON, false); + bool ret = + confirm_helper(request_title, strbuf, &layout_standard_notification, + false, NO_ICON, false); memzero(strbuf, sizeof(strbuf)); - return true; + return ret; } bool review_without_button_request(const char* request_title, @@ -429,10 +453,11 @@ bool review_without_button_request(const char* request_title, vsnprintf(strbuf, sizeof(strbuf), request_body, vl); va_end(vl); - (void)confirm_helper(request_title, strbuf, &layout_standard_notification, - false, NO_ICON, false); + bool ret = + confirm_helper(request_title, strbuf, &layout_standard_notification, + false, NO_ICON, false); memzero(strbuf, sizeof(strbuf)); - return true; + return ret; } bool review_with_icon(ButtonRequestType type, IconType iconNum, @@ -452,10 +477,11 @@ bool review_with_icon(ButtonRequestType type, IconType iconNum, resp.code = type; msg_write(MessageType_MessageType_ButtonRequest, &resp); - (void)confirm_helper(request_title, strbuf, &layout_standard_notification, - false, iconNum, false); + bool ret = + confirm_helper(request_title, strbuf, &layout_standard_notification, + false, iconNum, false); memzero(strbuf, sizeof(strbuf)); - return true; + return ret; } bool review_immediate(ButtonRequestType type, const char* request_title, @@ -474,8 +500,9 @@ bool review_immediate(ButtonRequestType type, const char* request_title, resp.code = type; msg_write(MessageType_MessageType_ButtonRequest, &resp); - (void)confirm_helper(request_title, strbuf, &layout_standard_notification, - false, NO_ICON, true); + bool ret = + confirm_helper(request_title, strbuf, &layout_standard_notification, + false, NO_ICON, true); memzero(strbuf, sizeof(strbuf)); - return true; + return ret; } diff --git a/lib/board/draw.c b/lib/board/draw.c index 3a51e145f..6b94907fc 100644 --- a/lib/board/draw.c +++ b/lib/board/draw.c @@ -287,6 +287,58 @@ void draw_box_simple(Canvas* canvas, uint8_t color, uint16_t x, uint16_t y, * OUTPUT * true/false whether image was drawn */ +/* + * draw_bitmap_mono_rle_valid() - see draw.h. Pure walk of the RLE grammar; + * writes nothing. The drawing path below stops as soon as the canvas is full, + * so it cannot tell a well-formed stream from one whose last run straddles the + * image or that carries trailing packets. Host-supplied icons must be checked + * here, at the trust boundary, before they are shown or persisted. + */ +bool draw_bitmap_mono_rle_valid(const uint8_t* data, uint32_t length, + uint16_t w, uint16_t h) { + if (!data || w == 0 || h == 0) { + return false; + } + + const uint32_t pixels = (uint32_t)w * (uint32_t)h; + uint32_t emitted = 0; + uint32_t i = 0; + + while (emitted < pixels) { + if (i >= length) { + return false; /* ran out of input mid-image */ + } + const uint8_t raw = data[i]; + if (raw == 0x80u || raw == 0u) { + return false; /* undecodable (int8_t counter) / not a packet */ + } + i++; + + uint32_t run; + if (raw > 127u) { + run = (uint32_t)(256u - raw); /* LITERAL: 1..127 distinct values */ + if (i + run > length) { + return false; /* literal body truncated */ + } + i += run; + } else { + run = raw; /* RUN: 1..127 copies of one value */ + if (i >= length) { + return false; /* missing the run's value byte */ + } + i++; + } + + if (emitted + run > pixels) { + return false; /* run straddles the end of the image */ + } + emitted += run; + } + + /* Exactly filled, and nothing left over. */ + return emitted == pixels && i == length; +} + bool draw_bitmap_mono_rle(Canvas* canvas, const AnimationFrame* frame, bool erase) { if (!frame || !canvas) { @@ -302,6 +354,16 @@ bool draw_bitmap_mono_rle(Canvas* canvas, const AnimationFrame* frame, return false; } + /* Validate the whole stream up front. The loop below fills the canvas and + * stops, so on its own it cannot reject a final run that straddles the image + * or trailing packets past the last pixel — it would draw and report success. + * Checking first makes the return value mean "this stream is well-formed AND + * was drawn", which is what callers gating on host-supplied icons need. + * (Verified: every bundled image stream terminates exactly.) */ + if (!draw_bitmap_mono_rle_valid(img->data, img->length, img->w, img->h)) { + return false; + } + int8_t sequence = 0; int8_t nonsequence = 0; uint32_t pixel_index = 0; @@ -315,12 +377,29 @@ bool draw_bitmap_mono_rle(Canvas* canvas, const AnimationFrame* frame, // sequence > 0 implies the next x pixels are the same // sequence < 0 implies the next -x pixels are all different if ((sequence == 0) && (nonsequence == 0)) { - sequence = img->data[pixel_index]; + /* Read the packet count. 0x80 (-128) is rejected: `nonsequence` below + * is int8_t, so -(-128) = 128 does not fit and wraps back to -128, + * breaking the `nonsequence > 0` invariant. Under NDEBUG the assert is + * compiled out and we would decode with a negative counter + * (signed-overflow UB). 0 is likewise not a valid packet: it leaves + * both counters at zero and breaks the same invariant. A host-supplied + * icon reaches here, so fail closed rather than trust the encoder. */ + const uint8_t raw = img->data[pixel_index]; + if (raw == 0x80u || raw == 0u) { + return false; + } pixel_index++; - if (sequence < 0) { - nonsequence = -sequence; + /* Explicit two's-complement read. Narrowing a uint8_t > 127 straight + * into an int8_t is implementation-defined, so spell the conversion + * out: 1..127 stay positive (RUN), 129..255 become -127..-1 (LITERAL). + */ + if (raw > 127u) { + nonsequence = (int8_t)((int)raw - 256); /* -127..-1 */ + nonsequence = (int8_t)(-nonsequence); /* 1..127, fits int8_t */ sequence = 0; + } else { + sequence = (int8_t)raw; /* 1..127 */ } } diff --git a/lib/board/font.c b/lib/board/font.c index 5fccfcb33..d00c215e7 100644 --- a/lib/board/font.c +++ b/lib/board/font.c @@ -21,6 +21,7 @@ #include "keepkey/board/font.h" #include +#include /* --- Image Font ------------------------------------------------------------ */ @@ -2598,29 +2599,31 @@ uint32_t calc_str_width(const Font* font, const char* str) { * OUTPUT * line count */ -uint32_t calc_str_line(const Font* font, const char* str, uint16_t line_width) { +uint32_t calc_str_line_n(const Font* font, const char* str, size_t str_len, + uint16_t line_width) { uint8_t line_count = 1; uint16_t x_offset = 0; + size_t offset = 0; - while (*str) { - uint8_t character_width = font_get_char(font, str[0])->width; + while (offset < str_len && str[offset]) { + uint8_t character_width = font_get_char(font, str[offset])->width; uint16_t word_width = character_width; - const char* next_character = str + 1; + size_t next_offset = offset + 1; /* Allow line breaks */ - if (*str == '\n') { + if (str[offset] == '\n') { line_count++; x_offset = 0; - str++; + offset++; continue; } /* Calculate next work width */ - if (*str == ' ') { - while (*next_character && *next_character != ' ' && - *next_character != '\n') { - word_width += font_get_char(font, *next_character)->width; - next_character++; + if (str[offset] == ' ') { + while (next_offset < str_len && str[next_offset] && + str[next_offset] != ' ' && str[next_offset] != '\n') { + word_width += font_get_char(font, str[next_offset])->width; + next_offset++; } } @@ -2631,14 +2634,27 @@ uint32_t calc_str_line(const Font* font, const char* str, uint16_t line_width) { } /* Remove leading spaces */ - if (x_offset == 0 && *str == ' ') { - str++; + if (x_offset == 0 && str[offset] == ' ') { + offset++; continue; } x_offset += character_width; - str++; + offset++; } return line_count; } + +uint32_t calc_str_line(const Font* font, const char* str, uint16_t line_width) { + return calc_str_line_n(font, str, strlen(str), line_width); +} + +size_t calc_str_page(const Font* font, const char* str, size_t str_len, + uint16_t line_width, uint32_t max_lines) { + size_t best = 0; + for (size_t take = 1; take <= str_len; take++) { + if (calc_str_line_n(font, str, take, line_width) <= max_lines) best = take; + } + return best; +} diff --git a/lib/board/layout.c b/lib/board/layout.c index 59e9dd9e2..7c4d44d66 100644 --- a/lib/board/layout.c +++ b/lib/board/layout.c @@ -324,12 +324,30 @@ void layout_standard_notification(const char* str1, const char* str2, * OUTPUT * none */ +/* Frame drawn for RUNTIME_ICON — a loaded clear-sign identity logo. Set by + * layout_set_runtime_icon() before the confirm; the caller owns the storage. */ +static const AnimationFrame* runtime_icon_frame = NULL; + +void layout_set_runtime_icon(const struct AnimationFrame_* frame) { + runtime_icon_frame = frame; +} + void layout_add_icon(IconType type) { switch (type) { case ETHEREUM_ICON: + /* ponytail: reuse the ETH glyph as the "verified" mark — it's an ETH tx. + * Swap in a dedicated checkmark bitmap if the trust mark needs to differ. + */ + case VERIFIED_ICON: draw_bitmap_mono_rle(canvas, get_ethereum_icon_frame(), false); break; + case RUNTIME_ICON: + if (runtime_icon_frame) { + draw_bitmap_mono_rle(canvas, runtime_icon_frame, false); + } + break; + default: /* no action requires */ break; @@ -706,11 +724,20 @@ static const char* _otpStr = ""; * OTP in large font desc - text to display permil - progress in units of 1 to * 1000 OUTPUT none */ -void animating_progress_handler(const char* desc, int permil) { +/* Render the progress bar into the framebuffer WITHOUT clearing the animation + * queue, so an animation callback (trickle_progress_callback) can redraw itself + * every frame without removing itself from the queue. + * + * marker_phase: 0..999 breathes a glint on the fill's leading segment (a + * perpetual "working" cue that keeps the display visibly moving even after + * the eased fill has pixel-saturated); pass -1 for no glint. */ +static void progress_render_ex(const char* desc, int permil, int marker_phase) { if (!canvas) return; - call_leaving_handler(); - layout_clear(); + layout_clear_static(); +#if DEBUG_LINK + layout_debuglink_watermark(); +#endif permil = permil >= 1000 ? 1000 : permil; permil = permil <= 0 ? 0 : permil; @@ -775,9 +802,43 @@ void animating_progress_handler(const char* desc, int permil) { draw_box(canvas, &bp); } + // Front glint: the fill's leading segment breathes (dim <-> bright) while + // the trickle is active. Activity always shows exactly at the progress + // front — unlike a marker sweeping the track, it cannot detach from the + // fill and open a gap, and it cannot run out of travel as the unfilled + // span shrinks near 100% (long final-action proofs). + if (marker_phase >= 0 && finished_width > 4) { + const uint32_t glint_max = 10; + uint32_t glint_w = + finished_width - 2 < glint_max ? finished_width - 2 : glint_max; + /* Triangle wave 0..500..0 over one breath period. */ + uint32_t tri = (uint32_t)marker_phase < 500 ? (uint32_t)marker_phase + : 1000 - (uint32_t)marker_phase; + bp.width = glint_w; + bp.height = height - 2; + bp.base.x = x + finished_width - glint_w; + bp.base.y = y + 1; + bp.base.color = (uint8_t)(0x44 + (tri * 0x66) / 500); + draw_box(canvas, &bp); + } + display_refresh(); } +static void progress_render(const char* desc, int permil) { + progress_render_ex(desc, permil, -1); +} + +/* One-shot progress draw: clears any queued animation (historical behaviour, so + * a stray animation cannot redraw over a static progress screen) then renders. + */ +void animating_progress_handler(const char* desc, int permil) { + if (!canvas) return; + call_leaving_handler(); + layout_clear_animations(); + progress_render(desc, permil); +} + void layoutProgress(const char* desc, int permil) { animating_progress_handler(desc, permil); } @@ -818,6 +879,87 @@ void layout_add_animation(AnimateCallback callback, void* data, animation_queue_push(&active_queue, animation); } +/* --- Trickle progress for long host-driven operations ----------------------- + * Shielded Zcash signing blocks on the host generating zk-proofs, so the device + * would otherwise sit on a frozen progress bar and look like it has failed. + * This ramps a "trickle" smoothly through most of the gap to the next real + * milestone over the expected host-proof duration, holding short of it (so it + * never falsely shows work done). It is driven off the animation timer, which + * layout_animate_poll() pumps from usbPoll() while the device blocks on host + * I/O. A dedicated flag gates that pump so no other flow is affected. */ +static volatile bool trickle_active = false; +static struct { + const char* desc; + int base; /* permil committed by the last real milestone */ + int target; /* permil to ease toward (the next milestone) */ +} trickle; + +static void trickle_progress_callback(void* data, uint32_t duration, + uint32_t elapsed) { + (void)data; + (void)duration; + /* Host proof windows between milestones run ~40-50s. Ramp linearly through + * 90% of the milestone span over that guessed duration, then hold — the + * last 10% is only crossed by the next REAL milestone, so the bar never + * claims work that hasn't happened. The breathing glint keeps signalling + * activity while the ramp holds. + * ponytail: EXPECTED_MS is a guess, not a measurement — retune if host + * proof times change materially. */ + const uint32_t EXPECTED_MS = 45000; + int span = trickle.target - trickle.base; + int cap = (span * 9) / 10; + int add = 0; + if (cap > 0) { + add = elapsed >= EXPECTED_MS + ? cap + : (int)(((uint64_t)cap * elapsed) / EXPECTED_MS); + } + /* Glint phase loops forever, so the display keeps changing even after the + * eased fill has stopped producing new pixels (long zk-proof waits). */ + const uint32_t BREATH_PERIOD = 1600; /* ms per dim<->bright breath cycle */ + int phase = (int)(((elapsed % BREATH_PERIOD) * 1000) / BREATH_PERIOD); + /* Draw via progress_render_ex (not animating_progress_handler) so redrawing + * the frame does not clear the animation queue and remove this callback. */ + progress_render_ex(trickle.desc, trickle.base + add, phase); +} + +/* (Re-)arm the trickle to ease from base_permil toward target_permil. Re-adding + * the callback resets its elapsed to 0 so the ease restarts from base_permil. + */ +void layoutProgressTrickle(const char* desc, int base_permil, + int target_permil) { + trickle.desc = desc; + trickle.base = base_permil; + trickle.target = target_permil; + trickle_active = true; + layout_add_animation(&trickle_progress_callback, NULL, 0 /* loop forever */); + force_animation_start(); + /* Draw the first frame now (at base, glint at its dimmest) so the bar + * appears immediately, before the animation timer next fires. + * progress_render_ex keeps the animation queue intact. */ + progress_render_ex(desc, base_permil, 0); +} + +void layoutProgressTrickleStop(void) { + trickle_active = false; + Animation* animation = + animation_queue_get(&active_queue, &trickle_progress_callback); + if (animation != NULL) { + animation_queue_push(&free_queue, animation); + } +} + +/* Advance a queued progress animation one step if the timer has ticked. Called + * from usbPoll() so the trickle keeps moving while we block on host I/O. Gated + * on trickle_active so it is a no-op for every other flow (confirm dialogs, + * PIN entry, etc. are untouched). */ +void layout_animate_poll(void) { + if (trickle_active && is_animating()) { + animate(); + display_refresh(); + } +} + /* * layout_clear_animations() - Clear all animation from queue * @@ -827,6 +969,7 @@ void layout_add_animation(AnimateCallback callback, void* data, * none */ void layout_clear_animations(void) { + trickle_active = false; Animation* animation = animation_queue_pop(&active_queue); while (animation != NULL) { diff --git a/lib/board/messages.c b/lib/board/messages.c index ffa5f3079..6e111f9e6 100644 --- a/lib/board/messages.c +++ b/lib/board/messages.c @@ -43,6 +43,66 @@ static msg_debug_link_get_state_t msg_debug_link_get_state; */ bool reset_msg_stack = false; +/* ── Shared frame arena ────────────────────────────────────────────────── + * One MAX_FRAME_SIZE-class buffer shared by three mutually-exclusive users: + * + * 1. Inbound frame reassembly (usb_rx_helper writes frame_arena.rx). + * 2. Outbound wire encode (msg_write / msg_debug_write encode into + * frame_arena.tx via frame_arena_tx()) — previously a 12 KB automatic + * TrezorFrameBuffer on the msg_write stack, which is what overflowed + * the zcash-privacy variant's 11 KB stack gap on the STM32F205. + * 3. Large transient in-handler scratch (frame_arena_scratch2049 for the + * recovery-cipher wordlist permutation). + * + * Why this is safe: the transport is strictly cooperative/single-threaded. + * usbd_poll() runs only from explicit usbPoll() call sites (main loop, the + * tiny-message pump, u2f) — there is no USB ISR — so RX can never preempt + * a TX encode or an executing handler. Tiny-mode RX (button/pin/cancel + * during a handler wait) goes through msg_read_tiny's own 64-byte buffer + * and never touches this arena. RAW dispatch hands handlers the 64-byte + * packet buffer, not the arena. + * + * Contract: acquiring the arena for TX or scratch DROPS any partially + * reassembled inbound frame. Only a host that pipelines a second request + * before reading the first response can hit this; it gets a Failure on its + * next continuation frame instead of silent corruption (the protocol is + * strict request-response). + */ +typedef union { + uint8_t rx[MAX_FRAME_SIZE]; + TrezorFrameBuffer tx; + uint16_t scratch_u16[2049]; +} FrameArena; + +static FrameArena frame_arena; + +/* Inbound reassembly state — file scope so arena acquisition can reset it. */ +static bool rxFirstFrame = true; +static uint16_t rxMsgId = 0xffff; +static uint32_t rxMsgSize = 0; +static size_t + rxCursor; //< Index into frame_arena.rx where the next frame lands. +static const MessagesMap_t* rxEntry = NULL; + +static void frame_arena_rx_reset(void) { + rxMsgId = 0xffff; + rxMsgSize = 0; + memset(frame_arena.rx, 0, sizeof(frame_arena.rx)); + rxCursor = 0; + rxFirstFrame = true; + rxEntry = NULL; +} + +TrezorFrameBuffer* frame_arena_tx(void) { + frame_arena_rx_reset(); + return &frame_arena.tx; +} + +uint16_t* frame_arena_scratch2049(void) { + frame_arena_rx_reset(); + return frame_arena.scratch_u16; +} + /* * message_map_entry() - Finds a requested message map entry * @@ -193,21 +253,15 @@ static void raw_dispatch(const MessagesMap_t* entry, const uint8_t* msg, /// Common helper that handles USB messages from host void usb_rx_helper(const uint8_t* buf, size_t length, MessageMapType type) { - static bool firstFrame = true; - - static uint16_t msgId; - static uint32_t msgSize; - static uint8_t msg[MAX_FRAME_SIZE]; - static size_t - cursor; //< Index into msg where the current frame is to be written. - static const MessagesMap_t* entry; - - if (firstFrame) { - msgId = 0xffff; - msgSize = 0; - memset(msg, 0, sizeof(msg)); - cursor = 0; - entry = NULL; + /* Reassembly state + buffer live at file scope (frame_arena.rx) so that + * frame_arena_tx()/frame_arena_scratch2049() can invalidate a partial + * inbound frame — see the FrameArena contract above. */ + if (rxFirstFrame) { + rxMsgId = 0xffff; + rxMsgSize = 0; + memset(frame_arena.rx, 0, sizeof(frame_arena.rx)); + rxCursor = 0; + rxEntry = NULL; } assert(buf != NULL); @@ -222,7 +276,7 @@ void usb_rx_helper(const uint8_t* buf, size_t length, MessageMapType type) { goto reset; } - if (firstFrame && (buf[1] != '#' || buf[2] != '#')) { + if (rxFirstFrame && (buf[1] != '#' || buf[2] != '#')) { (*msg_failure)(FailureType_Failure_UnexpectedMessage, "Malformed packet"); goto reset; } @@ -231,25 +285,25 @@ void usb_rx_helper(const uint8_t* buf, size_t length, MessageMapType type) { const uint8_t* frame; size_t frameSize; - if (firstFrame) { + if (rxFirstFrame) { // Reset the buffer that we're writing fragments into. - memset(msg, 0, sizeof(msg)); + memset(frame_arena.rx, 0, sizeof(frame_arena.rx)); // Then fish out the id / size, which are big-endian uint16 / // uint32's respectively. - msgId = buf[4] | ((uint16_t)buf[3]) << 8; - msgSize = buf[8] | ((uint32_t)buf[7]) << 8 | ((uint32_t)buf[6]) << 16 | - ((uint32_t)buf[5]) << 24; + rxMsgId = buf[4] | ((uint16_t)buf[3]) << 8; + rxMsgSize = buf[8] | ((uint32_t)buf[7]) << 8 | ((uint32_t)buf[6]) << 16 | + ((uint32_t)buf[5]) << 24; // Determine callback handler and message map type. - entry = message_map_entry(type, msgId, IN_MSG); + rxEntry = message_map_entry(type, rxMsgId, IN_MSG); // And reset the cursor. - cursor = 0; + rxCursor = 0; // Then take note of the fragment boundaries. frame = &buf[9]; - frameSize = MIN(length - 9, msgSize); + frameSize = MIN(length - 9, rxMsgSize); } else { // Otherwise it's a continuation/fragment. frame = &buf[1]; @@ -257,49 +311,45 @@ void usb_rx_helper(const uint8_t* buf, size_t length, MessageMapType type) { } // If the msgId wasn't in our map, bail. - if (!entry) { + if (!rxEntry) { (*msg_failure)(FailureType_Failure_UnexpectedMessage, "Unknown message"); goto reset; } - if (entry->dispatch == RAW) { + if (rxEntry->dispatch == RAW) { /* Call dispatch for every segment since we are not buffering and parsing, * and assume the raw dispatched callbacks will handle their own state and * buffering internally */ - raw_dispatch(entry, frame, frameSize, msgSize); - firstFrame = false; + raw_dispatch(rxEntry, frame, frameSize, rxMsgSize); + rxFirstFrame = false; return; } size_t end; - if (check_uadd_overflow(cursor, frameSize, &end) || sizeof(msg) < end) { + if (check_uadd_overflow(rxCursor, frameSize, &end) || + sizeof(frame_arena.rx) < end) { (*msg_failure)(FailureType_Failure_UnexpectedMessage, "Malformed message"); goto reset; } // Copy content to frame buffer. - memcpy(&msg[cursor], frame, frameSize); + memcpy(&frame_arena.rx[rxCursor], frame, frameSize); // Advance the cursor. - cursor = end; + rxCursor = end; // Only parse and message map if all segments have been buffered. - bool last_segment = cursor >= msgSize; + bool last_segment = rxCursor >= rxMsgSize; if (!last_segment) { - firstFrame = false; + rxFirstFrame = false; return; } - dispatch(entry, msg, msgSize); + dispatch(rxEntry, frame_arena.rx, rxMsgSize); reset: - msgId = 0xffff; - msgSize = 0; - memset(msg, 0, sizeof(msg)); - cursor = 0; - firstFrame = true; - entry = NULL; + frame_arena_rx_reset(); } /* Tiny messages */ diff --git a/lib/board/signatures.c b/lib/board/signatures.c index f4be6bf82..9bf2107fb 100644 --- a/lib/board/signatures.c +++ b/lib/board/signatures.c @@ -20,7 +20,9 @@ #include "trezor/crypto/sha2.h" #include "trezor/crypto/ecdsa.h" #include "trezor/crypto/secp256k1.h" +#include "trezor/crypto/memzero.h" #include "keepkey/board/memory.h" +#include "keepkey/board/memcmp_s.h" #include "keepkey/board/signatures.h" #include "keepkey/board/pubkeys.h" @@ -68,23 +70,51 @@ int signatures_ok(void) { return KEY_EXPIRED; } /* Expired signing key */ + /* F3 hardening: double-compute SHA-256, compare in constant time */ + uint8_t firmware_fingerprint2[32]; sha256_Raw((uint8_t*)FLASH_APP_START, codelen, firmware_fingerprint); + asm volatile("" ::: "memory"); + sha256_Raw((uint8_t*)FLASH_APP_START, codelen, firmware_fingerprint2); - if (ecdsa_verify_digest(&secp256k1, pubkey[sigindex1 - 1], - (uint8_t*)FLASH_META_SIG1, - firmware_fingerprint) != 0) { /* Failure */ + if (memcmp_s(firmware_fingerprint, firmware_fingerprint2, 32) != 0) { + memzero(firmware_fingerprint, sizeof(firmware_fingerprint)); + memzero(firmware_fingerprint2, sizeof(firmware_fingerprint2)); return SIG_FAIL; } + memzero(firmware_fingerprint2, sizeof(firmware_fingerprint2)); - if (ecdsa_verify_digest(&secp256k1, pubkey[sigindex2 - 1], - (uint8_t*)FLASH_META_SIG2, - firmware_fingerprint) != 0) { /* Failure */ + /* F3 hardening: infective aggregation — accumulate all three ECDSA + * results instead of early-returning on each. Forces attacker to + * corrupt all three verify calls, not just skip one branch. */ + volatile int verify_acc = 0; + volatile int verify_sentinel = 0; + + verify_acc |= + ecdsa_verify_digest(&secp256k1, pubkey[sigindex1 - 1], + (uint8_t*)FLASH_META_SIG1, firmware_fingerprint); + verify_sentinel++; + asm volatile("" ::: "memory"); + + verify_acc |= + ecdsa_verify_digest(&secp256k1, pubkey[sigindex2 - 1], + (uint8_t*)FLASH_META_SIG2, firmware_fingerprint); + verify_sentinel++; + asm volatile("" ::: "memory"); + + verify_acc |= + ecdsa_verify_digest(&secp256k1, pubkey[sigindex3 - 1], + (uint8_t*)FLASH_META_SIG3, firmware_fingerprint); + verify_sentinel++; + asm volatile("" ::: "memory"); + + memzero(firmware_fingerprint, sizeof(firmware_fingerprint)); + + /* All three verifies must have executed and all must have passed */ + if (verify_sentinel != 3) { return SIG_FAIL; } - if (ecdsa_verify_digest(&secp256k1, pubkey[sigindex3 - 1], - (uint8_t*)FLASH_META_SIG3, - firmware_fingerprint) != 0) { /* Failure */ + if (verify_acc != 0) { return SIG_FAIL; } diff --git a/lib/board/timer.c b/lib/board/timer.c index 3868b6d16..c66c62e4d 100644 --- a/lib/board/timer.c +++ b/lib/board/timer.c @@ -25,6 +25,11 @@ #else #include #include +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN /* exclude winsock.h — it declares \ + shutdown(SOCKET,int) */ +#include /* Sleep() */ +#endif #endif #include "keepkey/board/keepkey_board.h" @@ -229,11 +234,13 @@ void timer_init(void) { nvic_set_priority(NVIC_TIM4_IRQ, 16 * 2); timer_enable_counter(TIM4); -#else +#elif !defined(_WIN32) void tim4_sighandler(int sig); signal(SIGALRM, tim4_sighandler); ualarm(1000, 1000); #endif + /* _WIN32: no SIGALRM/ualarm — libkkemu's kkemu_poll() drives timerisr_usr(). + */ } uint32_t fi_defense_delay(volatile uint32_t value) { @@ -287,8 +294,21 @@ void delay_us(uint32_t us) { void delay_ms(uint32_t ms) { remaining_delay = ms; +#ifdef _WIN32 + /* No async SIGALRM timer on Windows, and kkemu_poll() drives timerisr_usr() + * only once per poll — so a plain spin here would never make progress when + * delay_ms() is reached from inside usbPoll() (e.g. PIN/U2F/authenticator + * flows). Advance the tick ourselves from wall-clock Sleep instead. Keeps + * timeSinceWakeup + the runnable queue moving exactly like the SIGALRM path, + * and stays single-threaded (no data races). */ while (remaining_delay > 0) { + Sleep(1); + timerisr_usr(); } +#else + while (remaining_delay > 0) { + } +#endif } /* @@ -310,6 +330,12 @@ void delay_ms_with_callback(uint32_t ms, callback_func_t callback_func, if (remaining_delay % frequency_ms == 0) { (*callback_func)(); } +#ifdef _WIN32 + /* See delay_ms(): drive the tick from wall-clock Sleep on Windows so this + * loop terminates when reached from inside usbPoll(). */ + Sleep(1); + timerisr_usr(); +#endif } } @@ -348,7 +374,7 @@ void timerisr_usr(void) { #endif } -#ifdef EMULATOR +#if defined(EMULATOR) && !defined(_WIN32) void tim4_sighandler(int sig) { timerisr_usr(); } #endif diff --git a/lib/board/udp.c b/lib/board/udp.c index ba35d15ec..1240c2155 100644 --- a/lib/board/udp.c +++ b/lib/board/udp.c @@ -21,6 +21,7 @@ #include "keepkey/board/usb.h" #include "keepkey/board/timer.h" +#include "keepkey/board/layout.h" #include "keepkey/emulator/emulator.h" #include @@ -62,6 +63,11 @@ void usbPoll(void) { // msg_read_tiny(msg.message, sizeof(msg.message)); } } + + // Keep a queued progress animation moving while we block on host I/O (e.g. + // Zcash proof generation on the host), matching device usbPoll(). No-op + // unless a trickle animation is active. + layout_animate_poll(); } bool usb_tx(const uint8_t* msg, uint32_t len) { diff --git a/lib/board/usb.c b/lib/board/usb.c index 0db5e32c6..53fb07a89 100644 --- a/lib/board/usb.c +++ b/lib/board/usb.c @@ -414,6 +414,11 @@ void usbInit(const char* origin_url) { void usbPoll(void) { // poll read buffer usbd_poll(usbd_dev); + // Keep a queued progress animation moving while we block on host I/O (e.g. + // Zcash proof generation on the host), so the screen never looks frozen. + // No-op unless a trickle animation is active, so all other flows are + // unaffected. + layout_animate_poll(); } void usbReconnect(void) { @@ -435,28 +440,31 @@ bool msg_write(MessageType msg_id, const void* msg) { if (!fields) return false; - TrezorFrameBuffer framebuf; - memset(&framebuf, 0, sizeof(framebuf)); - framebuf.frame.usb_header.hid_type = '?'; - framebuf.frame.header.pre1 = '#'; - framebuf.frame.header.pre2 = '#'; - framebuf.frame.header.id = __builtin_bswap16(msg_id); + /* Encode into the shared frame arena instead of a 12 KB automatic — that + * stack frame overflowed the zcash-privacy variant's SRAM gap. Safe on the + * single-threaded transport; see the FrameArena contract in messages.c. */ + TrezorFrameBuffer* framebuf = frame_arena_tx(); + memset(framebuf, 0, sizeof(*framebuf)); + framebuf->frame.usb_header.hid_type = '?'; + framebuf->frame.header.pre1 = '#'; + framebuf->frame.header.pre2 = '#'; + framebuf->frame.header.id = __builtin_bswap16(msg_id); pb_ostream_t os = - pb_ostream_from_buffer(framebuf.buffer, sizeof(framebuf.buffer)); + pb_ostream_from_buffer(framebuf->buffer, sizeof(framebuf->buffer)); if (!pb_encode(&os, fields, msg)) return false; - framebuf.frame.header.len = __builtin_bswap32(os.bytes_written); + framebuf->frame.header.len = __builtin_bswap32(os.bytes_written); // Chunk out data - for (uint32_t pos = 1; pos < sizeof(framebuf.frame) + os.bytes_written; + for (uint32_t pos = 1; pos < sizeof(framebuf->frame) + os.bytes_written; pos += 64 - 1) { uint8_t tmp_buffer[64] = {0}; tmp_buffer[0] = '?'; - memcpy(tmp_buffer + 1, ((const uint8_t*)&framebuf) + pos, 64 - 1); + memcpy(tmp_buffer + 1, ((const uint8_t*)framebuf) + pos, 64 - 1); #ifndef EMULATOR while (usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_IN, tmp_buffer, @@ -476,28 +484,29 @@ bool msg_debug_write(MessageType msg_id, const void* msg) { if (!fields) return false; - TrezorFrameBuffer framebuf; - memset(&framebuf, 0, sizeof(framebuf)); - framebuf.frame.usb_header.hid_type = '?'; - framebuf.frame.header.pre1 = '#'; - framebuf.frame.header.pre2 = '#'; - framebuf.frame.header.id = __builtin_bswap16(msg_id); + /* Same shared-arena encode as msg_write — see the FrameArena contract. */ + TrezorFrameBuffer* framebuf = frame_arena_tx(); + memset(framebuf, 0, sizeof(*framebuf)); + framebuf->frame.usb_header.hid_type = '?'; + framebuf->frame.header.pre1 = '#'; + framebuf->frame.header.pre2 = '#'; + framebuf->frame.header.id = __builtin_bswap16(msg_id); pb_ostream_t os = - pb_ostream_from_buffer(framebuf.buffer, sizeof(framebuf.buffer)); + pb_ostream_from_buffer(framebuf->buffer, sizeof(framebuf->buffer)); if (!pb_encode(&os, fields, msg)) return false; - framebuf.frame.header.len = __builtin_bswap32(os.bytes_written); + framebuf->frame.header.len = __builtin_bswap32(os.bytes_written); // Chunk out data - for (uint32_t pos = 1; pos < sizeof(framebuf.frame) + os.bytes_written; + for (uint32_t pos = 1; pos < sizeof(framebuf->frame) + os.bytes_written; pos += 64 - 1) { uint8_t tmp_buffer[64] = {0}; tmp_buffer[0] = '?'; - memcpy(tmp_buffer + 1, ((const uint8_t*)&framebuf) + pos, 64 - 1); + memcpy(tmp_buffer + 1, ((const uint8_t*)framebuf) + pos, 64 - 1); #ifndef EMULATOR while (usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_DEBUG_IN, tmp_buffer, diff --git a/lib/board/util.c b/lib/board/util.c index 027f53522..f9948b967 100644 --- a/lib/board/util.c +++ b/lib/board/util.c @@ -103,33 +103,48 @@ bool is_valid_ascii(const uint8_t* data, uint32_t size) { } /* convert number in base units to specified decimal precision */ -int base_to_precision(uint8_t* dest, const uint8_t* value, - const uint8_t dest_len, const uint8_t value_len, - const uint8_t precision) { - if (!(dest && value)) { - // invalid pointer - return -1; +int base_to_precision(uint8_t* dest, const uint8_t* value, size_t dest_len, + size_t value_len, uint8_t precision) { + if (!dest || !value || dest_len == 0 || value_len == 0) return -1; + + // Decimal inputs are signed as strings. Accept only their unique canonical + // representation so the value shown on the OLED is byte-for-byte bound to + // the value placed in the transaction. + if ((value_len > 1 && value[0] == '0')) return -1; + for (size_t i = 0; i < value_len; i++) { + if (value[i] < '0' || value[i] > '9') return -1; } - if (value_len + 1 > dest_len) { - // value too large for output buffer - return -1; + + size_t rendered_len; + if (precision == 0) { + rendered_len = value_len; + } else if (value_len <= precision) { + rendered_len = (size_t)precision + 2; // "0." + precision digits + } else { + rendered_len = value_len + 1; // digits plus decimal point } - memset(dest, '0', dest_len); - uint8_t leading_digits = - ((value_len - precision) > 0) ? (value_len - precision) : 0; - - if (!leading_digits) { - memcpy(dest, "0.", 2); - uint8_t offset = - 2 + (((precision - value_len) > 0) ? (precision - value_len) : 0); - strlcpy((char*)&dest[offset], (char*)value, value_len); + if (rendered_len + 1 > dest_len) return -1; + + size_t offset = 0; + if (precision == 0) { + memcpy(dest, value, value_len); + offset = value_len; + } else if (value_len <= precision) { + dest[offset++] = '0'; + dest[offset++] = '.'; + const size_t zeroes = (size_t)precision - value_len; + memset(dest + offset, '0', zeroes); + offset += zeroes; + memcpy(dest + offset, value, value_len); + offset += value_len; } else { - uint8_t copy_len = MIN((value_len - leading_digits), precision); + const size_t leading_digits = value_len - precision; memcpy(dest, value, leading_digits); - dest[leading_digits] = '.'; - strlcpy((char*)&dest[leading_digits + 1], (char*)&value[leading_digits], - copy_len); + offset = leading_digits; + dest[offset++] = '.'; + memcpy(dest + offset, value + leading_digits, precision); + offset += precision; } - dest[dest_len] = '\0'; + dest[offset] = '\0'; return 0; } diff --git a/lib/emulator/CMakeLists.txt b/lib/emulator/CMakeLists.txt index fa5909a17..c1fcdcb4d 100644 --- a/lib/emulator/CMakeLists.txt +++ b/lib/emulator/CMakeLists.txt @@ -35,6 +35,13 @@ if(${KK_EMULATOR}) ${CMAKE_SOURCE_DIR}/include ${CMAKE_BINARY_DIR}/include ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-crypto) + # libkkemu.c runs the firmware event loop on a dedicated thread (POSIX + # pthreads; Win32 CreateThread under MinGW). Threads::Threads is a no-op on + # the Win32 path and pulls in -lpthread on POSIX. Use the PLAIN signature — + # tools/emulator/CMakeLists.txt links this same target plainly, and CMake + # forbids mixing keyword (PRIVATE) and plain target_link_libraries calls. + find_package(Threads REQUIRED) + target_link_libraries(kkemulator_dylib Threads::Threads) set_target_properties(kkemulator_dylib PROPERTIES OUTPUT_NAME "kkemu" POSITION_INDEPENDENT_CODE ON) diff --git a/lib/emulator/libkkemu.c b/lib/emulator/libkkemu.c index be45bf608..e09d14ad6 100644 --- a/lib/emulator/libkkemu.c +++ b/lib/emulator/libkkemu.c @@ -24,11 +24,58 @@ #include #include #include +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN /* exclude winsock.h — it declares \ + shutdown(SOCKET,int) */ +#include +#else #include +#include +#include +#endif /* Defined in firmware — we just need the declaration */ extern void fsm_init(void); +/* ── Poll thread (Approach B: reactive confirm) ────────────────────────── + * + * Optional: the host calls kkemu_start() to run the firmware event loop on a + * dedicated thread inside the dylib. This lets confirm_helper's blocking C + * busy-loop wait for a button decision IN C without freezing the host's event + * loop — so the vault can render the real OLED confirm frame, HOLD it, and + * deliver the DebugLinkDecision only when the user clicks (screen-first gating, + * like a physical device). + * + * Only the poll thread ever drives firmware execution (kkemu_poll_body). The + * host interacts solely through the lock-free SPSC rings (kkemu_write/read, + * kkemu_pop_frame). g_fw_lock serializes the poll body against host-side flash + * snapshots (kkemu_lock/unlock) so storage_commit can't tear a saveFlash read. + * + * When the thread is NOT started (g_poll_running == 0) the dylib stays purely + * single-threaded and host-driven via kkemu_poll() — exactly as the FFI test + * suite and python-keepkey tests use it. The lock helpers no-op in that mode. + */ +#ifdef _WIN32 +static CRITICAL_SECTION g_fw_lock; +static HANDLE g_poll_thread = NULL; +#define FW_LOCK() EnterCriticalSection(&g_fw_lock) +#define FW_UNLOCK() LeaveCriticalSection(&g_fw_lock) +#else +static pthread_mutex_t g_fw_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_t g_poll_thread; +#define FW_LOCK() pthread_mutex_lock(&g_fw_lock) +#define FW_UNLOCK() pthread_mutex_unlock(&g_fw_lock) +#endif + +/* Cross-thread poll-running flag. _Atomic (not volatile — volatile is not a + * synchronization primitive in C): the poll thread reads it each loop while + * start/stop write it from the host thread. acquire/release publishes the + * surrounding firmware/ring state alongside the flag. */ +#include +static _Atomic int g_poll_running = 0; +#define POLL_RUNNING() atomic_load_explicit(&g_poll_running, memory_order_acquire) +#define POLL_SET(v) atomic_store_explicit(&g_poll_running, (v), memory_order_release) + /* ── Ring buffers (replace UDP sockets) ─────────────────────────────── */ static RingBuf rb_main_in; /* host → firmware (main interface) */ @@ -45,18 +92,27 @@ static int libkkemu_initialized = 0; * The host drains via kkemu_pop_frame(). Adjacent identical frames are * skipped so an idle firmware doesn't spam the ring. * - * Sized for ~4 seconds at 16ms refresh; if the host falls behind the - * oldest frames are dropped (write advances past read). + * Sized for ~4 seconds at 16ms refresh. Cross-thread in thread-driven mode: + * the poll thread is the sole producer, the host (kkemu_pop_frame) the sole + * consumer — a lock-free SPSC ring with the same atomic discipline as the HID + * rings (ringbuf.c). When the ring is full the producer drops the NEW frame + * (it must NOT overwrite a slot the consumer may be mid-copy on, and it must + * NOT write the consumer-owned read index). */ #define FRAME_PACKED_SIZE 2048 #define FRAME_RING_SIZE 64 +/* Host poll cadence (the vault's setInterval is ~16ms). kkemu_poll() ticks the + * firmware ms-timer this many times per call so animations advance at ~real + * speed without relying on the (host-runtime-unreliable) SIGALRM timer. */ +#define KKEMU_POLL_INTERVAL_MS 16 + static uint8_t frame_ring[FRAME_RING_SIZE][FRAME_PACKED_SIZE]; -static uint8_t last_packed[FRAME_PACKED_SIZE]; -static int last_packed_valid = 0; -static uint32_t frame_write_idx = - 0; /* monotonic, mod FRAME_RING_SIZE for slot */ -static uint32_t frame_read_idx = 0; /* monotonic */ +static uint8_t last_packed[FRAME_PACKED_SIZE]; /* producer-only (poll thread) */ +static int last_packed_valid = 0; /* producer-only */ +static uint8_t capture_scratch[FRAME_PACKED_SIZE]; /* producer-only pack buffer */ +static _Atomic uint32_t frame_write_idx = 0; /* written by producer ONLY */ +static _Atomic uint32_t frame_read_idx = 0; /* written by consumer ONLY */ /* * Scratch returned by kkemu_get_display(). File-scope (not function-static) @@ -107,28 +163,38 @@ size_t libkkemu_socketWrite(int iface, const void* buffer, size_t size) { static void libkkemu_capture_frame(const uint8_t* canvas_buf) { if (!canvas_buf) return; - uint8_t* slot = frame_ring[frame_write_idx % FRAME_RING_SIZE]; - memset(slot, 0, FRAME_PACKED_SIZE); + /* Pack into a producer-private scratch — NOT a ring slot. When the ring is + * full the next write slot still holds an unread frame the consumer may be + * copying, so we must decide to publish/drop before touching it. */ + memset(capture_scratch, 0, FRAME_PACKED_SIZE); for (int x = 0; x < 256; x++) { for (int y = 0; y < 64; y++) { if (canvas_buf[y * 256 + x] > 0) { - slot[x + (y / 8) * 256] |= (uint8_t)(1u << (y % 8)); + capture_scratch[x + (y / 8) * 256] |= (uint8_t)(1u << (y % 8)); } } } - /* Dedup: skip if identical to last captured */ - if (last_packed_valid && memcmp(slot, last_packed, FRAME_PACKED_SIZE) == 0) { + /* Dedup against the last captured frame (producer-only state). */ + if (last_packed_valid && + memcmp(capture_scratch, last_packed, FRAME_PACKED_SIZE) == 0) { return; } - memcpy(last_packed, slot, FRAME_PACKED_SIZE); - last_packed_valid = 1; - frame_write_idx++; - /* Drop oldest if host fell behind */ - if (frame_write_idx - frame_read_idx > FRAME_RING_SIZE) { - frame_read_idx = frame_write_idx - FRAME_RING_SIZE; - } + /* SPSC publish, drop-on-full (same discipline as ringbuf.c). The producer + * writes only frame_write_idx; the consumer writes only frame_read_idx. When + * not full, write%SIZE != read%SIZE (their distance is in [1, SIZE-1]), so + * producer and consumer never touch the same slot. last_packed is updated + * ONLY on a real publish, so a frame dropped while full can still be captured + * on a later tick. */ + uint32_t w = atomic_load_explicit(&frame_write_idx, memory_order_relaxed); + uint32_t r = atomic_load_explicit(&frame_read_idx, memory_order_acquire); + if (w - r >= FRAME_RING_SIZE) return; /* full → drop the new frame */ + + memcpy(frame_ring[w % FRAME_RING_SIZE], capture_scratch, FRAME_PACKED_SIZE); + memcpy(last_packed, capture_scratch, FRAME_PACKED_SIZE); + last_packed_valid = 1; + atomic_store_explicit(&frame_write_idx, w + 1, memory_order_release); } /* ── Public API ─────────────────────────────────────────────────────── */ @@ -151,12 +217,21 @@ int kkemu_init(uint8_t* flash_buf, size_t flash_len) { * Production hosts of libkkemu should treat a logged failure as a * security warning and refuse to load secrets. */ +#ifdef _WIN32 + if (!VirtualLock(flash_buf, flash_len)) { + fprintf(stderr, + "[libkkemu] VirtualLock(%zu bytes) failed (err %lu) — flash buffer " + "may be paged to disk; do not load production secrets\n", + flash_len, (unsigned long)GetLastError()); + } +#else if (mlock(flash_buf, flash_len) != 0) { fprintf(stderr, "[libkkemu] mlock(%zu bytes) failed: %s — flash buffer may be " "swapped to disk; do not load production secrets\n", flash_len, strerror(errno)); } +#endif /* Initialize ring buffers (replaces UDP socket init) */ libkkemu_socketInit(); @@ -193,6 +268,11 @@ int kkemu_init(uint8_t* flash_buf, size_t flash_len) { void kkemu_shutdown(void) { if (!libkkemu_initialized) return; + /* Stop + join the poll thread FIRST so nothing drives firmware execution + * while we commit storage and zero the rings below (idempotent if the host + * never started the thread). */ + kkemu_stop(); + /* Flush any pending storage to the flash buffer */ storage_commit(); @@ -220,6 +300,7 @@ void kkemu_shutdown(void) { memzero(&rb_debug_out, sizeof(rb_debug_out)); memzero(frame_ring, sizeof(frame_ring)); memzero(last_packed, sizeof(last_packed)); + memzero(capture_scratch, sizeof(capture_scratch)); memzero(display_packed_scratch, sizeof(display_packed_scratch)); last_packed_valid = 0; frame_write_idx = 0; @@ -231,7 +312,11 @@ void kkemu_shutdown(void) { * want to inspect / persist post-mortem state. Documented contract. */ if (emulator_flash_base) { +#ifdef _WIN32 + VirtualUnlock(emulator_flash_base, KKEMU_FLASH_SIZE); +#else munlock(emulator_flash_base, KKEMU_FLASH_SIZE); +#endif emulator_flash_base = NULL; } @@ -254,35 +339,198 @@ int kkemu_read(uint8_t* buf, size_t len, int iface) { return ringbuf_pop(rb, buf, KKEMU_PACKET_SIZE) ? KKEMU_PACKET_SIZE : 0; } -int kkemu_poll(void) { - if (!libkkemu_initialized) return -1; +/* + * One iteration of the firmware event loop. Same as exec() in main.cpp: + * usbPoll() — reads input, dispatches through FSM + * animate() — updates screen animations + * display_refresh() — renders framebuffer + * + * usbPoll() internally calls emulatorSocketRead() which we've replaced with + * libkkemu_socketRead() via the ring buffers. + * + * Drive the firmware millisecond timer from the poll on EVERY platform. The + * dylib is caller-driven; relying on the SIGALRM/ualarm timer (which the + * standalone kkemu binary uses) is unreliable inside the host runtime — Bun + * does not deliver the firmware's SIGALRM, so animate_flag never flips and + * every animation (boot logo, screensaver) stays frozen → a blank OLED at + * rest. Tick ~one poll-interval of milliseconds so the periodic animation + * runnable fires and animations + delay_ms() advance at roughly real speed. + */ +static void kkemu_poll_body(void) { + for (int t = 0; t < KKEMU_POLL_INTERVAL_MS; t++) timerisr_usr(); - /* - * This is the same as exec() in main.cpp: - * usbPoll() — reads input, dispatches through FSM - * animate() — updates screen animations - * display_refresh() — renders framebuffer - * - * usbPoll() internally calls emulatorSocketRead() which we've - * replaced with libkkemu_socketRead() via the ring buffers. - */ usbPoll(); animate(); display_refresh(); +} +int kkemu_poll(void) { + if (!libkkemu_initialized) return -1; + /* When the poll thread owns execution, the host must not also poll — + * that would be two threads driving the single-threaded firmware core. + * Treat a stray host poll as a no-op rather than a data race. */ + if (POLL_RUNNING()) return 0; + kkemu_poll_body(); return 0; } +static void kkemu_sleep_ms(int ms) { +#ifdef _WIN32 + Sleep((DWORD)ms); +#else + struct timespec ts = {ms / 1000, (long)(ms % 1000) * 1000000L}; + nanosleep(&ts, NULL); +#endif +} + +/* The poll thread holds g_fw_lock across each body call, releasing it during + * the inter-poll sleep. While confirm_helper busy-waits for a decision the body + * does not return, so the lock stays held for the whole confirm — but that must + * NOT block the host: the decision is delivered through the lock-free rings, and + * the host acquires the lock for flash snapshots via kkemu_trylock() (which + * never blocks the host event loop). The host must never take g_fw_lock with a + * blocking call while a confirm may be pending, or it would deadlock against the + * very loop that needs the host alive to deliver the decision. */ +static void kkemu_poll_loop(void) { + while (POLL_RUNNING()) { + FW_LOCK(); + if (POLL_RUNNING()) kkemu_poll_body(); + FW_UNLOCK(); + kkemu_sleep_ms(KKEMU_POLL_INTERVAL_MS); + } +} + +#ifdef _WIN32 +static DWORD WINAPI kkemu_poll_thread_fn(LPVOID arg) { + (void)arg; + kkemu_poll_loop(); + return 0; +} +#else +static void* kkemu_poll_thread_fn(void* arg) { + (void)arg; + kkemu_poll_loop(); + return NULL; +} +#endif + +/* Push a Cancel (MessageType 20) into the main input ring so a confirm_helper + * blocked on the poll thread reads it, returns false, and lets the thread exit + * its loop — otherwise kkemu_stop() would join a thread parked forever waiting + * for a button decision that will never arrive. + * + * This injected Cancel is the ONLY firmware-side wakeup for a parked confirm + * (confirm_helper has no idle timeout in EMULATOR builds), and kkemu_stop() + * then joins the thread with no deadline — so a SILENTLY dropped Cancel would + * freeze the (single-threaded) host forever, beyond any watchdog's reach. The + * push can only fail if rb_main_in is full; the parked confirm drains one input + * frame per spin, so a slot frees within ~a poll tick. Retry briefly, and shout + * loudly if it somehow never takes rather than dropping it. */ +static void kkemu_inject_cancel(void) { + uint8_t frame[KKEMU_PACKET_SIZE]; + memset(frame, 0, sizeof(frame)); + frame[0] = 0x3F; /* '?' HID report marker */ + frame[1] = 0x23; /* '#' */ + frame[2] = 0x23; /* '#' */ + frame[3] = 0x00; /* MessageType_Cancel high */ + frame[4] = 0x14; /* MessageType_Cancel low (20) */ + /* payload length 0 (bytes 5-8 already zero) */ + for (int i = 0; i < 200; i++) { + if (ringbuf_push(&rb_main_in, frame, sizeof(frame))) return; + kkemu_sleep_ms(1); + } + fprintf(stderr, + "[libkkemu] FATAL: could not inject Cancel to wake a parked confirm " + "before join — rb_main_in stayed full for ~200ms; the poll thread may " + "not exit\n"); +} + +int kkemu_start(void) { + if (!libkkemu_initialized) return -1; + if (POLL_RUNNING()) return 0; /* idempotent */ + +#ifdef _WIN32 + InitializeCriticalSection(&g_fw_lock); + POLL_SET(1); + g_poll_thread = CreateThread(NULL, 0, kkemu_poll_thread_fn, NULL, 0, NULL); + if (!g_poll_thread) { + POLL_SET(0); + DeleteCriticalSection(&g_fw_lock); + return -1; + } +#else + POLL_SET(1); + if (pthread_create(&g_poll_thread, NULL, kkemu_poll_thread_fn, NULL) != 0) { + POLL_SET(0); + return -1; + } +#endif + return 0; +} + +void kkemu_stop(void) { + if (!POLL_RUNNING()) return; + + POLL_SET(0); + /* Unblock any confirm_helper currently parked on the thread, then join. */ + kkemu_inject_cancel(); +#ifdef _WIN32 + if (g_poll_thread) { + WaitForSingleObject(g_poll_thread, INFINITE); + CloseHandle(g_poll_thread); + g_poll_thread = NULL; + } + DeleteCriticalSection(&g_fw_lock); +#else + pthread_join(g_poll_thread, NULL); +#endif +} + +/* Host-side guard for reading the shared flash buffer (saveFlash) without + * tearing a concurrent storage_commit on the poll thread. No-op when the + * thread isn't running (single-threaded test path needs no lock, and on + * Windows the CRITICAL_SECTION only exists between start and stop). + * + * WARNING: kkemu_lock() BLOCKS, and the poll thread can hold g_fw_lock for the + * whole duration of a pending confirm. The host must therefore NOT call + * kkemu_lock() from a thread/loop that also has to stay alive to deliver the + * confirm decision (it would deadlock). Use kkemu_trylock() + an event-loop + * yield there instead. kkemu_lock() is retained for paths with no pending + * confirm. */ +void kkemu_lock(void) { + if (POLL_RUNNING()) FW_LOCK(); +} + +void kkemu_unlock(void) { + if (POLL_RUNNING()) FW_UNLOCK(); +} + +/* Non-blocking acquire. Returns 1 if the firmware lock is now held by the + * caller (balance with kkemu_unlock()), 0 if it is currently held by the poll + * thread (e.g. mid-confirm) — the caller should yield its event loop and retry, + * which keeps the loop alive to deliver the decision that releases the lock. + * No-op success (returns 1, nothing to unlock) when the thread isn't running. */ +int kkemu_trylock(void) { + if (!POLL_RUNNING()) return 1; +#ifdef _WIN32 + return TryEnterCriticalSection(&g_fw_lock) ? 1 : 0; +#else + return pthread_mutex_trylock(&g_fw_lock) == 0 ? 1 : 0; +#endif +} + +/* + * Snapshot the current OLED canvas into packed SSD1306 format (byte index = + * x + (y/8)*256, bit = y%8). Host-driven convenience used by the python + * screenshot harness, which drives the firmware single-threaded via kkemu_poll. + * + * WARNING: NOT thread-safe. It reads the live firmware canvas directly with no + * synchronization against the poll thread, so it is only safe in HOST-DRIVEN + * mode (no kkemu_start). In thread-driven mode the canonical, race-free way to + * observe the display is the SPSC capture ring via kkemu_pop_frame(); do not + * wire kkemu_get_display into a threaded host. + */ const uint8_t* kkemu_get_display(int* width, int* height) { - /* - * Pack the firmware's 8-bpp grayscale canvas (256×64 = 16384 bytes) into - * the 1-bit packed layout vault expects (2048 bytes). Same format - * DebugLinkGetState.layout uses: byte index = x + (y/8)*256, - * bit within byte = y%8 (LSB = top row of the 8-pixel column). - * - * Output goes into the file-scope `display_packed_scratch` so - * kkemu_shutdown() can zero it on teardown alongside the frame ring. - */ if (!libkkemu_initialized) { if (width) *width = 0; if (height) *height = 0; @@ -312,10 +560,13 @@ const uint8_t* kkemu_get_display(int* width, int* height) { int kkemu_pop_frame(uint8_t* out_packed) { if (!libkkemu_initialized || !out_packed) return 0; - if (frame_read_idx == frame_write_idx) return 0; - const uint8_t* slot = frame_ring[frame_read_idx % FRAME_RING_SIZE]; - memcpy(out_packed, slot, FRAME_PACKED_SIZE); - frame_read_idx++; + /* SPSC consume: read frame_read_idx (we own it) and frame_write_idx (acquire, + * to see the producer's slot write). Empty when the indices are equal. */ + uint32_t r = atomic_load_explicit(&frame_read_idx, memory_order_relaxed); + uint32_t w = atomic_load_explicit(&frame_write_idx, memory_order_acquire); + if (r == w) return 0; + memcpy(out_packed, frame_ring[r % FRAME_RING_SIZE], FRAME_PACKED_SIZE); + atomic_store_explicit(&frame_read_idx, r + 1, memory_order_release); return 1; } diff --git a/lib/emulator/setup.c b/lib/emulator/setup.c index 1b4d657d4..69b9a65dd 100644 --- a/lib/emulator/setup.c +++ b/lib/emulator/setup.c @@ -22,46 +22,73 @@ #include "keepkey/rand/rng.h" #include -#include #include #include #include +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN /* exclude winsock.h — it declares \ + shutdown(SOCKET,int) */ +#include +#include +#else +#include #include #include +#endif #define EMULATOR_FLASH_FILE "emulator.img" -uint32_t __stack_chk_guard; +/* __stack_chk_guard is defined once in lib/board/keepkey_board.c (as + * uintptr_t). It used to be redefined here as uint32_t, which is (a) the wrong + * size on 64-bit hosts and (b) a duplicate strong symbol. Apple's ld silently + * merged the two; GNU/MinGW ld rejects it ("multiple definition"), which + * blocked the Linux .so and Windows .dll builds. Removed — the board copy is + * canonical. */ static int urandom = -1; static void setup_urandom(void); + +#ifndef _WIN32 static void setup_flash(void); void setup(void) { setup_urandom(); setup_flash(); } +#endif /* For libkkemu: init RNG only (flash buffer provided by host) */ void setup_urandom_only(void) { setup_urandom(); } void emulatorRandom(void* buffer, size_t size) { +#ifdef _WIN32 + /* Windows has no /dev/urandom — use the system CSPRNG. */ + if (BCryptGenRandom(NULL, (PUCHAR)buffer, (ULONG)size, + BCRYPT_USE_SYSTEM_PREFERRED_RNG) != 0) { + fprintf(stderr, "BCryptGenRandom failed\n"); + exit(1); + } +#else ssize_t n = read(urandom, buffer, size); if (n < 0 || ((size_t)n) != size) { perror("Failed to read /dev/urandom"); exit(1); } +#endif } static void setup_urandom(void) { +#ifndef _WIN32 urandom = open("/dev/urandom", O_RDONLY); if (urandom < 0) { perror("Failed to open /dev/urandom"); exit(1); } +#endif } +#ifndef _WIN32 static void setup_flash(void) { int fd = open(EMULATOR_FLASH_FILE, O_RDWR | O_SYNC | O_CREAT, 0644); if (fd < 0) { @@ -92,3 +119,5 @@ static void setup_flash(void) { memset(emulator_flash_base, 0xff, FLASH_TOTAL_SIZE); } } +#endif /* !_WIN32 — setup_flash is standalone-UDP only; the dylib/DLL host \ + owns flash */ diff --git a/lib/emulator/udp.c b/lib/emulator/udp.c index 671c6437b..265886c63 100644 --- a/lib/emulator/udp.c +++ b/lib/emulator/udp.c @@ -17,17 +17,22 @@ * along with this library. If not, see . */ -#include #include #include #include #include -#include #ifndef KEEPKEY_UDP_PORT #define KEEPKEY_UDP_PORT 11044 #endif +#ifndef KKEMU_DYLIB +/* Sockets are only used by the standalone UDP binary. In dylib/DLL mode all + * I/O goes through ring buffers (below), so skip the BSD socket headers and + * helpers entirely — they don't exist on MinGW/Windows. */ +#include +#include + struct usb_socket { int fd; struct sockaddr_in from; @@ -95,6 +100,7 @@ static size_t socket_read(struct usb_socket* sock, void* buffer, size_t size) { return n; } +#endif /* !KKEMU_DYLIB — socket helpers are standalone-UDP only */ #ifdef KKEMU_DYLIB /* diff --git a/lib/firmware/CMakeLists.txt b/lib/firmware/CMakeLists.txt index f23ebcfb8..ff28a5e86 100644 --- a/lib/firmware/CMakeLists.txt +++ b/lib/firmware/CMakeLists.txt @@ -2,48 +2,61 @@ set(sources app_confirm.c app_layout.c authenticator.c - binance.c + bip85.c coins.c crypto.c - eip712.c - eos.c - eos-contracts/eosio.system.c - eos-contracts/eosio.token.c - ethereum.c - ethereum_contracts.c - ethereum_contracts/makerdao.c - ethereum_contracts/saproxy.c - ethereum_contracts/zxappliquid.c - ethereum_contracts/thortx.c - ethereum_contracts/zxliquidtx.c - ethereum_contracts/zxtransERC20.c - ethereum_contracts/zxswap.c - ethereum_tokens.c fsm.c home_sm.c - mayachain.c - nano.c - osmosis.c passphrase_sm.c pin_sm.c policy.c recovery_cipher.c reset.c - ripple.c - ripple_base58.c signing.c - signtx_tendermint.c - solana.c storage.c - tron.c - ton.c - tendermint.c - thorchain.c tiny-json.c transaction.c txin_check.c u2f.c) +# Non-Bitcoin coin families -- excluded from the bitcoin-only image. +if(NOT ${KK_BITCOIN_ONLY}) + list(APPEND sources + binance.c + eip712.c + eos.c + eos-contracts/eosio.system.c + eos-contracts/eosio.token.c + ethereum.c + ethereum_contracts.c + ethereum_contracts/makerdao.c + ethereum_contracts/saproxy.c + ethereum_contracts/zxappliquid.c + ethereum_contracts/thortx.c + ethereum_contracts/zxliquidtx.c + ethereum_contracts/zxtransERC20.c + ethereum_contracts/zxswap.c + ethereum_tokens.c + signed_metadata.c + mayachain.c + nano.c + osmosis.c + ripple.c + ripple_base58.c + signtx_tendermint.c + solana.c + hive.c + tron.c + ton.c + tendermint.c + thorchain.c) +endif() + +# Zcash shielded/Orchard engine -- transparent Zcash needs none of this. +if(${KK_ZCASH_PRIVACY}) + list(APPEND sources zcash.c) +endif() + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/scm_revision.h.in" "${CMAKE_CURRENT_BINARY_DIR}/scm_revision.h" @ONLY) diff --git a/lib/firmware/app_confirm.c b/lib/firmware/app_confirm.c index d0b17e9bc..fdd9378a8 100644 --- a/lib/firmware/app_confirm.c +++ b/lib/firmware/app_confirm.c @@ -30,6 +30,7 @@ #include "keepkey/board/layout.h" #include "keepkey/board/messages.h" #include "keepkey/board/confirm_sm.h" +#include "keepkey/board/font.h" #include "keepkey/board/usb.h" #include "keepkey/board/util.h" @@ -321,6 +322,31 @@ bool confirm_nano_address(const char* desc, const char* address) { desc, "%s", address); } +/* + * confirm_zcash_address() - Show zcash address confirmation + * + * INPUT + * - desc: description (title) shown on both screens + * - address: zcash unified address — full text on the first screen, + * QR on the second + * OUTPUT + * true/false of confirmation + * + */ +#if ZCASH_PRIVACY +bool confirm_zcash_address(const char* desc, const char* address) { + if (!confirm_with_custom_layout(&layout_zcash_address_text_notification, + ButtonRequestType_ButtonRequest_Address, desc, + "%s", address)) { + return false; + } + + return confirm_with_custom_layout(&layout_zcash_address_notification, + ButtonRequestType_ButtonRequest_Address, + desc, "%s", address); +} +#endif + /* * confirm_address() - Show address confirmation * @@ -391,6 +417,142 @@ bool confirm_sign_identity(const IdentityType* identity, body); } +bool confirm_bytes_is_text(const uint8_t* data, size_t size) { + if (!data && size != 0) return false; + bool has_visible_character = false; + for (size_t i = 0; i < size; i++) { + if (data[i] == '\n') continue; + if (data[i] < 0x20 || data[i] > 0x7e) return false; + if (data[i] != ' ') has_visible_character = true; + } + return has_visible_character; +} + +static size_t confirm_bytes_render_page(const uint8_t* data, size_t size, + bool text, + char rendered[BODY_CHAR_MAX]) { + if (size == 0) return 0; + + const Font* font = get_body_font(); + size_t consumed = 0; + size_t written = 0; + uint32_t row = 1; + uint16_t x = 0; + + while (consumed < size) { + if (text && data[consumed] == '\n') { + // A page boundary already advances past the current third row. Consume + // its terminating LF without adding a blank row to the next page. + consumed++; + if (row == BODY_ROWS) break; + if (written + 1 >= BODY_CHAR_MAX) break; + rendered[written++] = '\n'; + row++; + x = 0; + continue; + } + + char chars[2]; + size_t char_count; + if (text) { + chars[0] = (char)data[consumed]; + char_count = 1; + } else { + static const char hex[] = "0123456789abcdef"; + chars[0] = hex[data[consumed] >> 4]; + chars[1] = hex[data[consumed] & 0x0f]; + char_count = 2; + } + + uint16_t width = 0; + for (size_t i = 0; i < char_count; i++) { + width += font_get_char(font, chars[i])->width; + } + + // draw_string() wraps only at spaces and otherwise clips overlong words. + // Pre-insert hard line breaks so long addresses, hashes and IBC denoms are + // actually visible rather than merely counted as one renderer line. + if (text && chars[0] == ' ') { + uint32_t word_width = width; + for (size_t i = consumed + 1; + i < size && data[i] != ' ' && data[i] != '\n'; i++) { + word_width += font_get_char(font, (char)data[i])->width; + } + if (x == 0) { + // The renderer discards a leading separator. Consume it here only + // after the preceding word has been disclosed on this or the prior + // page; the visual line/page boundary remains the separator. + consumed++; + continue; + } + if ((uint32_t)x + word_width > BODY_WIDTH) { + if (row == BODY_ROWS) break; + if (written + 1 >= BODY_CHAR_MAX) break; + rendered[written++] = '\n'; + row++; + x = 0; + consumed++; + continue; + } + } + + if ((uint32_t)x + width > BODY_WIDTH) { + if (row == BODY_ROWS) break; + if (written + 1 >= BODY_CHAR_MAX) break; + rendered[written++] = '\n'; + row++; + x = 0; + } + if (written + char_count >= BODY_CHAR_MAX) break; + memcpy(rendered + written, chars, char_count); + written += char_count; + x += width; + consumed++; + } + + rendered[written] = '\0'; + return consumed; +} + +bool confirm_bytes(ButtonRequestType button_request, const char* title, + const uint8_t* data, size_t size) { + if (!title || (!data && size != 0)) return false; + if (size == 0) return confirm(button_request, title, "(empty)"); + + const bool text = confirm_bytes_is_text(data, size); + size_t pages = 0; + size_t offset = 0; + while (offset < size) { + char rendered[BODY_CHAR_MAX]; + const size_t take = + confirm_bytes_render_page(data + offset, size - offset, text, rendered); + if (take == 0) return false; + offset += take; + pages++; + } + + offset = 0; + for (size_t page = 0; page < pages; page++) { + char rendered[BODY_CHAR_MAX]; + const size_t take = + confirm_bytes_render_page(data + offset, size - offset, text, rendered); + if (take == 0) return false; + + char page_title[TITLE_CHAR_MAX]; + if (pages > 1 || !text) { + snprintf(page_title, sizeof(page_title), + text ? "%s %u/%u" : "%s Hex %u/%u", title, (unsigned)(page + 1), + (unsigned)pages); + } else { + strlcpy(page_title, title, sizeof(page_title)); + } + + if (!confirm(button_request, page_title, "%s", rendered)) return false; + offset += take; + } + return true; +} + bool confirm_omni(ButtonRequestType button_request, const char* title, const uint8_t* data, uint32_t size) { uint32_t tx_type; @@ -428,17 +590,5 @@ bool confirm_omni(ButtonRequestType button_request, const char* title, bool confirm_data(ButtonRequestType button_request, const char* title, const uint8_t* data, uint32_t size) { - const char* str = (const char*)data; - char hex[50 * 2 + 1]; - if (!is_valid_ascii(data, size)) { - if (size > 50) size = 50; - memset(hex, 0, sizeof(hex)); - data2hex(data, size, hex); - if (size > 50) { - hex[50 * 2 - 1] = '.'; - hex[50 * 2 - 2] = '.'; - } - str = hex; - } - return confirm(button_request, title, "%s", str); + return confirm_bytes(button_request, title, data, size); } diff --git a/lib/firmware/app_layout.c b/lib/firmware/app_layout.c index 25b0db18b..2499916be 100644 --- a/lib/firmware/app_layout.c +++ b/lib/firmware/app_layout.c @@ -597,6 +597,81 @@ void layout_nano_address_notification(const char* desc, const char* address, layout_notification_icon(type, &sp); } +#if ZCASH_PRIVACY +/* + * layout_zcash_address_notification() - Display zcash unified address QR + * with title; the second confirm step in the view-on-device flow. + * + * INPUT + * - desc: title text (e.g. "Zcash #0 Orchard") + * - address: zcash unified address (rendered as QR only — full text is + * shown on the preceding confirm step) + * - type: notification type + * OUTPUT + * none + */ +void layout_zcash_address_notification(const char* desc, const char* address, + NotificationType type) { + DrawableParams sp; + Canvas* canvas = layout_get_canvas(); + + call_leaving_handler(); + layout_clear(); + + if (strcmp(desc, "") != 0) { + const Font* title_font = get_title_font(); + sp.y = TOP_MARGIN_FOR_TWO_LINES; + sp.x = LEFT_MARGIN + 65; + sp.color = BODY_COLOR; + draw_string(canvas, title_font, desc, &sp, TRANSACTION_WIDTH - 2, + font_height(title_font) + BODY_FONT_LINE_PADDING); + } + + layout_address(address, QR_LARGE); + layout_notification_icon(type, &sp); +} + +/* + * layout_zcash_address_text_notification() - Display full zcash unified + * address text with title; the first confirm step in the view-on-device flow. + * + * INPUT + * - desc: title text (e.g. "Zcash #0 Orchard") + * - address: zcash unified address to display as text (3 lines) + * - type: notification type + * OUTPUT + * none + */ +void layout_zcash_address_text_notification(const char* desc, + const char* address, + NotificationType type) { + DrawableParams sp; + Canvas* canvas = layout_get_canvas(); + const Font* address_font = get_body_font(); + + call_leaving_handler(); + layout_clear(); + + if (strcmp(desc, "") != 0) { + const Font* title_font = get_title_font(); + sp.y = TOP_MARGIN_FOR_THREE_LINES; + sp.x = LEFT_MARGIN; + sp.color = BODY_COLOR; + draw_string(canvas, title_font, desc, &sp, TRANSACTION_WIDTH - 2, + font_height(title_font) + BODY_FONT_LINE_PADDING); + } + + /* Full UA below the title; -25 leaves the right column for confirm icons. */ + sp.y = TOP_MARGIN_FOR_THREE_LINES + ADDRESS_XPUB_TOP_MARGIN; + sp.x = LEFT_MARGIN; + sp.color = BODY_COLOR; + draw_string(canvas, address_font, address, &sp, TRANSACTION_WIDTH - 25, + font_height(address_font) + BODY_FONT_LINE_PADDING); + + layout_notification_icon(type, &sp); +} +#endif // ZCASH_PRIVACY + /* * layout_address_notification() - Display address notification * @@ -693,7 +768,8 @@ void layout_pin(const char* str, char pin[]) { * OUTPUT * none */ -void layout_cipher(const char* current_word, const char* cipher) { +void layout_cipher(const char* current_word, const char* cipher, + const char* prev_word_info) { DrawableParams sp; const Font* title_font = get_body_font(); Canvas* canvas = layout_get_canvas(); @@ -701,8 +777,18 @@ void layout_cipher(const char* current_word, const char* cipher) { call_leaving_handler(); layout_clear(); - /* Draw prompt */ - sp.y = 11; + /* Draw previous word info at top-left -- must be x < 76 to avoid + * being wiped by cipher animation which clears x >= CIPHER_START_X */ + if (prev_word_info && prev_word_info[0]) { + sp.y = 2; + sp.x = 4; + sp.color = CIPHER_FONT_COLOR; /* gray -- less prominent than current word */ + draw_string(canvas, title_font, prev_word_info, &sp, 68, + font_height(title_font)); + } + + /* Draw prompt -- push down when prev word is shown */ + sp.y = (prev_word_info && prev_word_info[0]) ? 14 : 11; sp.x = 4; sp.color = BODY_COLOR; draw_string(canvas, title_font, "Recovery Cipher:", &sp, 58, diff --git a/lib/firmware/authenticator.c b/lib/firmware/authenticator.c index 851a48ad2..e07b0007c 100644 --- a/lib/firmware/authenticator.c +++ b/lib/firmware/authenticator.c @@ -57,6 +57,16 @@ static bool getAuthData(void) { static void setAuthData(void) { storage_setAuthData(authData); } +static bool authDisplayFieldValid(const char* value, size_t max_len) { + size_t len = strnlen(value, max_len + 1); + if (len == 0 || len > max_len) return false; + for (size_t i = 0; i < len; i++) { + uint8_t ch = (uint8_t)value[i]; + if (ch < 0x20 || ch > 0x7e) return false; + } + return true; +} + #if DEBUG_LINK static unsigned _otpSlot = 0; void getAuthSlot(char* authSlotData) { @@ -77,29 +87,31 @@ void getAuthSlot(char* authSlotData) { } #endif -void wipeAuthData(void) { - confirm(ButtonRequestType_ButtonRequest_Other, "Confirm Wipe Authdata", - "Do you want to PERMANENTLY delete all authenticator accounts?\n If " - "not, unplug Keepkey now."); +unsigned wipeAuthData(void) { + if (!confirm(ButtonRequestType_ButtonRequest_Other, "Confirm Wipe Authdata", + "Do you want to PERMANENTLY delete all authenticator accounts?")) + return AUTH_CANCELLED; // wipe storage and reset authdata encryption flag storage_wipeAuthData(); // wipe local copy memzero(authData, sizeof(authData)); localAuthdataUpdate = true; - return; + return NOERR; } unsigned addAuthAccount(char* accountWithSeed) { char *domain, *account, *seedStr; - unsigned slot; - char authSecret[AUTHSECRET_SIZE_MAX]; // 128-bit key len is the recommended - // minimum, this is room for 160-bit + unsigned slot = AUTHDATA_SIZE; + char authSecret[AUTHSECRET_SIZE_MAX] = { + 0}; // 128-bit key len is the recommended minimum, this is room for + // 160-bit size_t authSecretLen; + unsigned result = UNKERR; // accountWithSeed should be of the form "domain:account:seedStr" domain = strtok(accountWithSeed, ":"); // get the domain string token - if (NULL == domain) { + if (NULL == domain || !authDisplayFieldValid(domain, DOMAIN_SIZE - 1)) { return TOKERR; } @@ -107,7 +119,7 @@ unsigned addAuthAccount(char* accountWithSeed) { if (NULL == account) { return TOKERR; } - if (0 == strlen(account)) { + if (!authDisplayFieldValid(account, ACCOUNT_SIZE - 1)) { return TOKERR; } @@ -120,6 +132,9 @@ unsigned addAuthAccount(char* accountWithSeed) { } authSecretLen = base32_decoded_length(strlen(seedStr)); + if (authSecretLen < AUTHSECRET_SIZE_MIN) { + return BADSECRET; + } if (AUTHSECRET_SIZE_MAX < authSecretLen) { return LARGESEED; } @@ -128,11 +143,14 @@ unsigned addAuthAccount(char* accountWithSeed) { return BADPASS; // fingerprint did not match, passphrase incorrect } - // look for first empty slot - for (slot = 0; slot < AUTHDATA_SIZE; slot++) { - if (authData[slot].secretSize == 0) { - break; - } + // Reject duplicate identities and remember the first empty slot. Legacy + // duplicates are removed together by removeAuthAccount(). + for (unsigned i = 0; i < AUTHDATA_SIZE; i++) { + if (authData[i].secretSize != 0 && + strncmp(authData[i].domain, domain, DOMAIN_SIZE) == 0 && + strncmp(authData[i].account, account, ACCOUNT_SIZE) == 0) + return DUPLICATE; + if (slot == AUTHDATA_SIZE && authData[i].secretSize == 0) slot = i; } if (slot == AUTHDATA_SIZE) { return NOSLOT; // no empty slots @@ -141,12 +159,21 @@ unsigned addAuthAccount(char* accountWithSeed) { if (NULL == base32_decode((const char*)seedStr, strlen(seedStr), (uint8_t*)authSecret, sizeof(authSecret), BASE32_ALPHABET_RFC4648)) { - return BADSECRET; // bad decode + result = BADSECRET; + goto cleanup; } - confirm(ButtonRequestType_ButtonRequest_Other, "Confirm add account", - "Domain: %.*s\nAccount: %.*s\nSecret: %s", DOMAIN_SIZE, domain, - ACCOUNT_SIZE, account, seedStr); + // Keep the secret on its own screen. A 32-character base32 secret appended + // after domain/account can wrap past the OLED's three body rows, leaving the + // tail signed into storage but invisible to the user. + if (!confirm(ButtonRequestType_ButtonRequest_Other, "Add Auth Account", + "Domain: %.*s\nAccount: %.*s", DOMAIN_SIZE, domain, ACCOUNT_SIZE, + account) || + !confirm(ButtonRequestType_ButtonRequest_Other, "TOTP Secret", "%s", + seedStr)) { + result = AUTH_CANCELLED; + goto cleanup; + } authData[slot].secretSize = authSecretLen; memcpy(authData[slot].authSecret, authSecret, authData[slot].secretSize); @@ -154,8 +181,11 @@ unsigned addAuthAccount(char* accountWithSeed) { strlcpy(authData[slot].account, account, ACCOUNT_SIZE); setAuthData(); + result = NOERR; - return NOERR; // success +cleanup: + memzero(authSecret, sizeof(authSecret)); + return result; } unsigned generateOTP(char* accountWithMsg, char otpStr[]) { @@ -297,18 +327,18 @@ unsigned getAuthAccount(const char* slotStr, char acc[]) { unsigned removeAuthAccount(char* domAcc) { char *domain, *account; - unsigned slot; + bool found = false; // accountWithSeed should be of the form "domain:account" domain = strtok(domAcc, ":"); // get the domain string token - if (NULL == domain) { + if (NULL == domain || !authDisplayFieldValid(domain, DOMAIN_SIZE - 1)) { return TOKERR; } account = strtok(NULL, ""); // get the account string token if (NULL == account) { return TOKERR; } - if (0 == strlen(account)) { + if (!authDisplayFieldValid(account, ACCOUNT_SIZE - 1)) { return TOKERR; } @@ -316,23 +346,30 @@ unsigned removeAuthAccount(char* domAcc) { return BADPASS; // fingerprint did not match, passphrase incorrect } - // find slot for account - for (slot = 0; slot < AUTHDATA_SIZE; slot++) { - if ((0 == strncmp(authData[slot].domain, domain, DOMAIN_SIZE - 1)) && - (0 == strncmp(authData[slot].account, account, ACCOUNT_SIZE - 1))) { - break; - } + // Find every matching slot. Older firmware allowed duplicate identities, so + // a confirmed deletion must remove all copies atomically. + for (unsigned slot = 0; slot < AUTHDATA_SIZE; slot++) { + if (authData[slot].secretSize != 0 && + strncmp(authData[slot].domain, domain, DOMAIN_SIZE) == 0 && + strncmp(authData[slot].account, account, ACCOUNT_SIZE) == 0) + found = true; } - if (slot == AUTHDATA_SIZE) { + if (!found) { return NOACC; // account not found } - confirm(ButtonRequestType_ButtonRequest_Other, "Confirm Delete Account", - "Do you want to PERMANENTLY delete account %.*s:%.*s?", - DOMAIN_SIZE - 1, domain, ACCOUNT_SIZE - 1, account); + if (!confirm(ButtonRequestType_ButtonRequest_Other, "Confirm Delete Account", + "Do you want to PERMANENTLY delete account %.*s:%.*s?", + DOMAIN_SIZE - 1, domain, ACCOUNT_SIZE - 1, account)) + return AUTH_CANCELLED; - memzero((void*)&authData[slot], sizeof(authType)); + for (unsigned slot = 0; slot < AUTHDATA_SIZE; slot++) { + if (authData[slot].secretSize != 0 && + strncmp(authData[slot].domain, domain, DOMAIN_SIZE) == 0 && + strncmp(authData[slot].account, account, ACCOUNT_SIZE) == 0) + memzero((void*)&authData[slot], sizeof(authType)); + } setAuthData(); return NOERR; // success } diff --git a/lib/firmware/binance.c b/lib/firmware/binance.c index 868301db4..aac7f8aba 100644 --- a/lib/firmware/binance.c +++ b/lib/firmware/binance.c @@ -16,12 +16,49 @@ static BinanceSignTx msg; const BinanceSignTx* binance_getBinanceSignTx(void) { return &msg; } +bool binance_isValidDenom(const char* denom) { + if (!denom) return false; + const size_t len = strnlen(denom, BINANCE_MAX_DENOM_LEN + 1); + if (len == 0 || len > BINANCE_MAX_DENOM_LEN) return false; + for (size_t i = 0; i < len; i++) { + const char c = denom[i]; + if (!((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-')) + return false; + } + return true; +} + +bool binance_validateTransfer(const BinanceTransferMsg* transfer) { + if (!transfer || transfer->inputs_count != 1 || + transfer->inputs[0].coins_count != 1 || transfer->outputs_count != 1 || + transfer->outputs[0].coins_count != 1) + return false; + + const BinanceInputOutput* input = &transfer->inputs[0]; + const BinanceInputOutput* output = &transfer->outputs[0]; + const BinanceCoin* input_coin = &input->coins[0]; + const BinanceCoin* output_coin = &output->coins[0]; + if (!input->has_address || !output->has_address || !input_coin->has_amount || + !output_coin->has_amount || !input_coin->has_denom || + !output_coin->has_denom || input_coin->amount <= 0 || + output_coin->amount <= 0 || input_coin->amount != output_coin->amount || + strcmp(input_coin->denom, output_coin->denom) != 0 || + !binance_isValidDenom(input_coin->denom)) + return false; + + return true; +} + bool binance_signTxInit(const HDNode* _node, const BinanceSignTx* _msg) { - initialized = true; + binance_signAbort(); + if (!_node || !_msg || !_msg->has_msg_count || _msg->msg_count == 0 || + !_msg->has_account_number || _msg->account_number < 0 || + !_msg->has_chain_id || _msg->chain_id[0] == '\0' || !_msg->has_sequence || + _msg->sequence < 0 || !_msg->has_source || _msg->source < 0) + return false; + msgs_remaining = _msg->msg_count; - has_message = false; - memzero(&node, sizeof(node)); memcpy(&node, _node, sizeof(node)); memcpy(&msg, _msg, sizeof(msg)); @@ -32,7 +69,7 @@ bool binance_signTxInit(const HDNode* _node, const BinanceSignTx* _msg) { success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), "{\"account_number\":\"%" PRIu64 "\"", - msg.account_number); + (uint64_t)msg.account_number); const char* const chainid_prefix = ",\"chain_id\":\""; sha256_Update(&ctx, (uint8_t*)chainid_prefix, strlen(chainid_prefix)); @@ -45,16 +82,25 @@ bool binance_signTxInit(const HDNode* _node, const BinanceSignTx* _msg) { } sha256_Update(&ctx, (const uint8_t*)"\",\"msgs\":[", 10); - return success; + if (!success) { + binance_signAbort(); + return false; + } + initialized = true; + return true; } bool binance_serializeCoin(const BinanceCoin* coin) { + if (!coin || !coin->has_amount || coin->amount <= 0 || !coin->has_denom || + !binance_isValidDenom(coin->denom)) + return false; + bool success = true; char buffer[64 + 1]; success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), "{\"amount\":%" PRIu64 ",\"denom\":\"%s\"}", - coin->amount, coin->denom); + (uint64_t)coin->amount, coin->denom); return success; } @@ -83,6 +129,9 @@ bool binance_serializeInputOutput(const BinanceInputOutput* io) { } bool binance_signTxUpdateTransfer(const BinanceTransferMsg* _msg) { + if (!initialized || msgs_remaining == 0 || !binance_validateTransfer(_msg)) + return false; + bool success = true; sha256_Update(&ctx, (const uint8_t*)"{\"inputs\":[", 11); @@ -103,18 +152,23 @@ bool binance_signTxUpdateTransfer(const BinanceTransferMsg* _msg) { sha256_Update(&ctx, (const uint8_t*)"]}", 2); - has_message = true; - msgs_remaining--; + if (success) { + has_message = true; + msgs_remaining--; + } return success; } bool binance_signTxFinalize(uint8_t* public_key, uint8_t* signature) { + if (!initialized || msgs_remaining != 0 || !has_message || !public_key || + !signature) + return false; char buffer[64 + 1]; if (!tendermint_snprintf(&ctx, buffer, sizeof(buffer), "],\"sequence\":\"%" PRIu64 "\",\"source\":\"%" PRIu64 "\"}", - msg.sequence, msg.source)) + (uint64_t)msg.sequence, (uint64_t)msg.source)) return false; hdnode_fill_public_key(&node); @@ -128,7 +182,9 @@ bool binance_signTxFinalize(uint8_t* public_key, uint8_t* signature) { bool binance_signingIsInited(void) { return initialized; } -bool binance_signingIsFinished(void) { return msgs_remaining == 0; } +bool binance_signingIsFinished(void) { + return initialized && msgs_remaining == 0 && has_message; +} void binance_signAbort(void) { initialized = false; diff --git a/lib/firmware/bip85.c b/lib/firmware/bip85.c new file mode 100644 index 000000000..7d2ef6c81 --- /dev/null +++ b/lib/firmware/bip85.c @@ -0,0 +1,105 @@ +#include "keepkey/firmware/bip85.h" +#include "keepkey/firmware/storage.h" +#include "trezor/crypto/bip32.h" +#include "trezor/crypto/bip39.h" +#include "trezor/crypto/curves.h" +#include "trezor/crypto/hmac.h" +#include "trezor/crypto/memzero.h" + +#include + +/* + * BIP-85: Deterministic Entropy From BIP32 Keychains + * + * For BIP-39 mnemonic derivation: + * path = m / 83696968' / 39' / 0' / ' / ' + * k = derived_node.private_key (32 bytes) + * hmac = HMAC-SHA512(key="bip-entropy-from-k", msg=k) + * entropy = hmac[0 : entropy_bytes] + * 12 words -> 16 bytes, 18 words -> 24 bytes, 24 words -> 32 bytes + * mnemonic = bip39_from_entropy(entropy) + */ + +/* BIP-85 application number for deriving entropy from a key */ +static const uint8_t BIP85_HMAC_KEY[] = "bip-entropy-from-k"; +#define BIP85_HMAC_KEY_LEN 18 + +bool bip85_derive_mnemonic(uint32_t word_count, uint32_t index, char *mnemonic, + size_t mnemonic_len) { + /* Reject index >= 0x80000000 to avoid hardened-bit collision */ + if (index & 0x80000000) { + return false; + } + + /* Validate word count and compute entropy length */ + int entropy_bytes; + switch (word_count) { + case 12: + entropy_bytes = 16; + break; + case 18: + entropy_bytes = 24; + break; + case 24: + entropy_bytes = 32; + break; + default: + return false; + } + + /* BIP-85 derivation path: m/83696968'/39'/0'/'/' */ + uint32_t address_n[5]; + address_n[0] = 0x80000000 | 83696968; /* purpose (hardened) */ + address_n[1] = 0x80000000 | 39; /* BIP-39 app (hardened) */ + address_n[2] = 0x80000000; /* English language 0 (hardened) */ + address_n[3] = 0x80000000 | word_count; /* word count (hardened) */ + address_n[4] = 0x80000000 | index; /* child index (hardened) */ + + /* Get the master node from storage (respects passphrase) */ + static CONFIDENTIAL HDNode node; + if (!storage_getRootNode(SECP256K1_NAME, true, &node)) { + memzero(&node, sizeof(node)); + return false; + } + + /* Derive to the BIP-85 path */ + for (int i = 0; i < 5; i++) { + if (hdnode_private_ckd(&node, address_n[i]) == 0) { + memzero(&node, sizeof(node)); + return false; + } + } + + /* HMAC-SHA512(key="bip-entropy-from-k", msg=private_key) */ + static CONFIDENTIAL uint8_t hmac_out[64]; + hmac_sha512(BIP85_HMAC_KEY, BIP85_HMAC_KEY_LEN, node.private_key, 32, + hmac_out); + + /* We no longer need the derived node */ + memzero(&node, sizeof(node)); + + /* Truncate HMAC output to the required entropy length */ + static CONFIDENTIAL uint8_t entropy[32]; + memcpy(entropy, hmac_out, entropy_bytes); + memzero(hmac_out, sizeof(hmac_out)); + + /* Convert entropy to BIP-39 mnemonic */ + const char *words = mnemonic_from_data(entropy, entropy_bytes); + memzero(entropy, sizeof(entropy)); + + if (!words) { + return false; + } + + /* Copy to output buffer */ + size_t words_len = strlen(words); + if (words_len >= mnemonic_len) { + mnemonic_clear(); + return false; + } + + memcpy(mnemonic, words, words_len + 1); + mnemonic_clear(); + + return true; +} diff --git a/lib/firmware/coins.c b/lib/firmware/coins.c index 71a37d4da..a231bc41a 100644 --- a/lib/firmware/coins.c +++ b/lib/firmware/coins.c @@ -85,6 +85,7 @@ const CoinType coins[COINS_COUNT] = { TAPROOT}, #include "keepkey/firmware/coins.def" +#if !BITCOIN_ONLY // ERC-20 tokens excluded from the bitcoin-only image #define X(INDEX, NAME, SYMBOL, DECIMALS, CONTRACT_ADDRESS) \ { \ true, \ @@ -131,6 +132,7 @@ const CoinType coins[COINS_COUNT] = { false, /* has_taproot, taproot*/ \ }, #include "keepkey/firmware/tokens.def" +#endif // !BITCOIN_ONLY }; _Static_assert(sizeof(coins) / sizeof(coins[0]) == COINS_COUNT, diff --git a/lib/firmware/eip712.c b/lib/firmware/eip712.c index 1fec75f4b..84da58083 100644 --- a/lib/firmware/eip712.c +++ b/lib/firmware/eip712.c @@ -31,11 +31,13 @@ strings and address should be prefixed by 0x */ +#include #include #include #include #include "keepkey/board/confirm_sm.h" #include "keepkey/board/memory.h" +#include "keepkey/firmware/app_confirm.h" #include "keepkey/firmware/eip712.h" #include "keepkey/firmware/ethereum_tokens.h" #include "keepkey/firmware/tiny-json.h" @@ -47,38 +49,117 @@ static dm confirmProp; static const char* nameForValue; +static bool append_type_string(char* dest, const char* value) { + if (!dest || !value) return false; + const size_t used = strnlen(dest, STRBUFSIZE + 1); + const size_t added = strlen(value); + if (used > STRBUFSIZE || added > STRBUFSIZE - used) return false; + memcpy(dest + used, value, added + 1); + return true; +} + +static bool type_array_suffix_is_valid(const char* suffix) { + if (*suffix == '\0') return true; + if (*suffix++ != '[') return false; + while (*suffix >= '0' && *suffix <= '9') suffix++; + return suffix[0] == ']' && suffix[1] == '\0'; +} + +static bool type_matches(const char* type, const char* base) { + const size_t len = strlen(base); + return strncmp(type, base, len) == 0 && + type_array_suffix_is_valid(type + len); +} + +static bool type_is_integer(const char* type, const char* prefix) { + const size_t prefix_len = strlen(prefix); + if (strncmp(type, prefix, prefix_len) != 0) return false; + const char* p = type + prefix_len; + unsigned bits = 0; + bool has_bits = false; + while (*p >= '0' && *p <= '9') { + has_bits = true; + bits = bits * 10 + (unsigned)(*p++ - '0'); + } + if (has_bits && (bits < 8 || bits > 256 || (bits % 8) != 0)) return false; + return type_array_suffix_is_valid(p); +} + +static unsigned integer_type_width(const char* type, const char* prefix) { + const char* p = type + strlen(prefix); + if (*p < '0' || *p > '9') return 256; + unsigned bits = 0; + while (*p >= '0' && *p <= '9') { + bits = bits * 10 + (unsigned)(*p++ - '0'); + } + return bits; +} + +static bool type_is_bytes(const char* type, unsigned* byte_size, + bool* dynamic) { + if (strncmp(type, "bytes", 5) != 0) return false; + const char* p = type + 5; + if (*p == '\0' || *p == '[') { + if (!type_array_suffix_is_valid(p)) return false; + *byte_size = 0; + *dynamic = true; + return true; + } + unsigned size = 0; + bool has_size = false; + while (*p >= '0' && *p <= '9') { + has_size = true; + size = size * 10 + (unsigned)(*p++ - '0'); + } + if (!has_size || size == 0 || size > 32 || !type_array_suffix_is_valid(p)) + return false; + *byte_size = size; + *dynamic = false; + return true; +} + +static int hex_nibble(char c) { + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'a' && c <= 'f') return c - 'a' + 10; + if (c >= 'A' && c <= 'F') return c - 'A' + 10; + return -1; +} + +static bool hex_string_is_valid(const char* string, size_t expected_bytes, + bool exact_size) { + if (!string || string[0] != '0' || string[1] != 'x') return false; + const size_t chars = strlen(string + 2); + if ((chars & 1) != 0 || (exact_size && chars != 2 * expected_bytes)) + return false; + for (size_t i = 0; i < chars; i++) { + if (hex_nibble(string[i + 2]) < 0) return false; + } + return true; +} + int encodableType(const char* typeStr) { int ctr; - if (0 == strncmp(typeStr, "address", sizeof("address") - 1)) { + if (!typeStr || typeStr[0] == '\0') return NOT_ENCODABLE; + + if (type_matches(typeStr, "address")) { return ADDRESS; } - if (0 == strncmp(typeStr, "string", sizeof("string") - 1)) { + if (type_matches(typeStr, "string")) { return STRING; } - if (0 == strncmp(typeStr, "int", sizeof("int") - 1)) { - // This could be 'int8', 'int16', ..., 'int256' + if (type_is_integer(typeStr, "int")) { return INT; } - if (0 == strncmp(typeStr, "uint", sizeof("uint") - 1)) { - // This could be 'uint8', 'uint16', ..., 'uint256' + if (type_is_integer(typeStr, "uint")) { return UINT; } - if (0 == strncmp(typeStr, "bytes", sizeof("bytes") - 1)) { - // This could be 'bytes', 'bytes1', ..., 'bytes32' - if (0 == strcmp(typeStr, "bytes")) { - return BYTES; - } else { - // parse out the length val - uint8_t byteTypeSize = (uint8_t)(strtol((typeStr + 5), NULL, 10)); - if (byteTypeSize > 32) { - return NOT_ENCODABLE; - } else { - return BYTES_N; - } - } + unsigned byte_size = 0; + bool dynamic = false; + if (type_is_bytes(typeStr, &byte_size, &dynamic)) { + return dynamic ? BYTES : BYTES_N; } - if (0 == strcmp(typeStr, "bool")) { + if (type_matches(typeStr, "bool")) { return BOOL; } @@ -90,10 +171,11 @@ int encodableType(const char* typeStr) { strtok(typeNoArrTok, "["); // eliminate the array tokens if there if (udefList[ctr] != 0) { - if (0 == strncmp(udefList[ctr], typeNoArrTok, - strlen(udefList[ctr]) - strlen(typeNoArrTok))) { + const size_t previous_len = strcspn(udefList[ctr], "["); + const size_t candidate_len = strlen(typeNoArrTok); + if (previous_len == candidate_len && + strncmp(udefList[ctr], typeNoArrTok, candidate_len) == 0) { return PREV_USERDEF; - } else { } } else { @@ -134,8 +216,10 @@ int parseType(const json_t* eip712Types, const char* typeS, char* typeStr) { return JSON_TYPE_S_NAMEERR; } - strncat(typeStr, nameTest, STRBUFSIZE - strlen((const char*)typeStr)); - strncat(typeStr, "(", STRBUFSIZE - strlen((const char*)typeStr)); + if (!append_type_string(typeStr, nameTest) || + !append_type_string(typeStr, "(")) { + return UDEF_NAME_ERROR; + } tarray = json_getChild(jType); while (tarray != 0) { @@ -189,10 +273,12 @@ int parseType(const json_t* eip712Types, const char* typeS, char* typeStr) { if (NULL == pVal) { return JSON_NOPAIRVAL; } - strncat(typeStr, typeType, STRBUFSIZE - strlen((const char*)typeStr)); - strncat(typeStr, " ", STRBUFSIZE - strlen((const char*)typeStr)); - strncat(typeStr, pVal, STRBUFSIZE - strlen((const char*)typeStr)); - strncat(typeStr, ",", STRBUFSIZE - strlen((const char*)typeStr)); + if (!append_type_string(typeStr, typeType) || + !append_type_string(typeStr, " ") || + !append_type_string(typeStr, pVal) || + !append_type_string(typeStr, ",")) { + return UDEF_NAME_ERROR; + } } tarray = json_getSibling(tarray); } @@ -202,32 +288,28 @@ int parseType(const json_t* eip712Types, const char* typeS, char* typeStr) { typeStr[strlen(typeStr) - 1] = ')'; } else { // append paren, there are no parameters - strncat(typeStr, ")", STRBUFSIZE - 1); + if (!append_type_string(typeStr, ")")) return UDEF_NAME_ERROR; } if (strlen(append) > 0) { - strncat(typeStr, append, STRBUFSIZE - strlen((const char*)append)); + if (!append_type_string(typeStr, append)) return UDEF_NAME_ERROR; } return SUCCESS; } int encAddress(const char* string, uint8_t* encoded) { - unsigned ctr; - char byteStrBuf[3] = {0}; - - if (string == NULL) { + if (!string) { return ADDR_STRING_NULL; } - if (ADDRESS_SIZE < strlen(string)) { + if (strlen(string) != ADDRESS_SIZE || + !hex_string_is_valid(string, 20, true)) { return ADDR_STRING_VFLOW; } - for (ctr = 0; ctr < 12; ctr++) { - encoded[ctr] = '\0'; - } - for (ctr = 12; ctr < 32; ctr++) { - strncpy(byteStrBuf, &string[2 * ((ctr - 12)) + 2], 2); - encoded[ctr] = (uint8_t)(strtol(byteStrBuf, NULL, 16)); + memset(encoded, 0, 12); + for (size_t i = 0; i < 20; i++) { + encoded[12 + i] = (uint8_t)((hex_nibble(string[2 + 2 * i]) << 4) | + hex_nibble(string[3 + 2 * i])); } return SUCCESS; } @@ -242,17 +324,15 @@ int encString(const char* string, uint8_t* encoded) { } int encodeBytes(const char* string, uint8_t* encoded) { + if (!hex_string_is_valid(string, 0, false)) return GENERAL_ERROR; struct SHA3_CTX byteCtx; const char* valStrPtr = string + 2; - uint8_t valByte[1]; - char byteStrBuf[3] = {0}; sha3_256_Init(&byteCtx); while (*valStrPtr != '\0') { - strncpy(byteStrBuf, valStrPtr, 2); - valByte[0] = (uint8_t)(strtol(byteStrBuf, NULL, 16)); - sha3_Update(&byteCtx, (const unsigned char*)valByte, - (size_t)sizeof(uint8_t)); + const uint8_t valByte = + (uint8_t)((hex_nibble(valStrPtr[0]) << 4) | hex_nibble(valStrPtr[1])); + sha3_Update(&byteCtx, &valByte, sizeof(valByte)); valStrPtr += 2; } keccak_Final(&byteCtx, encoded); @@ -260,44 +340,39 @@ int encodeBytes(const char* string, uint8_t* encoded) { } int encodeBytesN(const char* typeT, const char* string, uint8_t* encoded) { - char byteStrBuf[3] = {0}; - unsigned ctr; - - if (MAX_ENCBYTEN_SIZE < strlen(string)) { - return BYTESN_STRING_ERROR; - } - - // parse out the length val - uint8_t byteTypeSize = (uint8_t)(strtol((typeT + 5), NULL, 10)); - if (32 < byteTypeSize) { + unsigned byteTypeSize = 0; + bool dynamic = false; + if (!type_is_bytes(typeT, &byteTypeSize, &dynamic) || dynamic) { return BYTESN_SIZE_ERROR; } - for (ctr = 0; ctr < 32; ctr++) { - // zero padding - encoded[ctr] = 0; + if (!hex_string_is_valid(string, byteTypeSize, true)) { + return BYTESN_STRING_ERROR; } - unsigned zeroFillLen = 32 - ((strlen(string) - 2 /* skip '0x' */) / 2); - // bytesN are zero padded on the right - for (ctr = zeroFillLen; ctr < 32; ctr++) { - strncpy(byteStrBuf, &string[2 + 2 * (ctr - zeroFillLen)], 2); - encoded[ctr - zeroFillLen] = (uint8_t)(strtol(byteStrBuf, NULL, 16)); + memset(encoded, 0, 32); + for (size_t i = 0; i < byteTypeSize; i++) { + encoded[i] = (uint8_t)((hex_nibble(string[2 + 2 * i]) << 4) | + hex_nibble(string[3 + 2 * i])); } return SUCCESS; } int confirmName(const char* name, bool valAvailable) { - if (valAvailable) { - nameForValue = name; - } else { - (void)review(ButtonRequestType_ButtonRequest_Other, "MESSAGE DATA", - "Press button to continue for\n\"%s\" values", name); + (void)valAvailable; + if (!name) return GENERAL_ERROR; + nameForValue = name; + if (!confirm_bytes(ButtonRequestType_ButtonRequest_Other, "EIP-712 Field", + (const uint8_t*)name, strlen(name))) { + return USER_CANCELLED; } return SUCCESS; } int confirmValue(const char* value) { - (void)review(ButtonRequestType_ButtonRequest_Other, "MESSAGE DATA", "%s %s", - nameForValue, value); + if (!value || !confirm_bytes(ButtonRequestType_ButtonRequest_Other, + nameForValue ? "EIP-712 Value" : "MESSAGE DATA", + (const uint8_t*)value, strlen(value))) { + return USER_CANCELLED; + } return SUCCESS; } @@ -320,15 +395,18 @@ void marshallDsVals(const char* value) { return; } -void dsConfirm(void) { +static int confirmTypedValue(bool ds_vals, const char* value) { + if (ds_vals) marshallDsVals(value); + return confirmValue(value); +} + +int dsConfirm(void) { // First check if we recognize the contract - const TokenType* assetToken; uint8_t addrHexStr[20] = {0}; char name[41] = {0}; char version[11] = {0}; uint32_t chainInt; bool noChain = true; - int ctr; IconType iconNum = NO_ICON; char title[64] = {0}; char* fillerStr = ""; @@ -343,9 +421,13 @@ void dsConfirm(void) { } if (dsverifyingContract != NULL) { - for (ctr = 2; ctr < 42; ctr += 2) { - sscanf((char*)&dsverifyingContract[ctr], "%2hhx", - &addrHexStr[(ctr - 2) / 2]); + // Same two-chars-then-strtol idiom as encAddress(). sscanf("%2hhx") did + // this before, and it was the firmware's only caller of newlib's scanf + // engine — ~6KB of ROM on a part with none to spare. + char byteStrBuf[3] = {0}; + for (int ctr = 2; ctr < 42; ctr += 2) { + strncpy(byteStrBuf, (char*)&dsverifyingContract[ctr], 2); + addrHexStr[(ctr - 2) / 2] = (uint8_t)strtol(byteStrBuf, NULL, 16); } strcat(verifyingContract, "Verifying Contract: "); strncat(verifyingContract, dsverifyingContract, @@ -354,11 +436,7 @@ void dsConfirm(void) { if (NULL != dschainId) { noChain = false; -#ifdef EMULATOR - sscanf((char*)dschainId, "%u", &chainInt); -#else - sscanf((char*)dschainId, "%ld", &chainInt); -#endif + chainInt = (uint32_t)strtoul((const char*)dschainId, NULL, 10); // As more chains are supported, add icon choice below // TBD: not implemented for first release // if (chainInt == 1) { @@ -366,7 +444,8 @@ void dsConfirm(void) { // } } if (noChain == false && dsverifyingContract != NULL) { - assetToken = tokenByChainAddress(chainInt, (uint8_t*)addrHexStr); + const TokenType* assetToken = + tokenByChainAddress(chainInt, (uint8_t*)addrHexStr); (void)assetToken; fillerStr = ""; } @@ -380,12 +459,17 @@ void dsConfirm(void) { snprintf(chainStr, 32, "chain %s, ", dschainId); } // snprintf(contractStr, 64, "verifyingContract: %s", verifyingContract); - (void)review_with_icon(ButtonRequestType_ButtonRequest_Other, iconNum, title, - "%s %s%s", chainStr, verifyingContract, fillerStr); + bool approved = + review_with_icon(ButtonRequestType_ButtonRequest_Other, iconNum, title, + "%s %s%s", chainStr, verifyingContract, fillerStr); dsname = NULL; dsversion = NULL; dschainId = NULL; dsverifyingContract = NULL; + if (!approved) { + return USER_CANCELLED; + } + return SUCCESS; } /* @@ -438,7 +522,6 @@ int parseVals(const json_t* eip712Types, const json_t* jType, walkVals = nextVal; while (0 != walkVals) { if (0 == strcmp(json_getName(walkVals), typeName)) { - valStr = json_getValue(walkVals); break; } else { // keep looking for val @@ -446,28 +529,35 @@ int parseVals(const json_t* eip712Types, const json_t* jType, } } - bool hasValue = (JSON_TEXT == json_getType(walkVals) || - JSON_INTEGER == json_getType(walkVals)); - confirmName(typeName, hasValue); - if (walkVals == 0) { return JSON_TYPE_WNOVAL; - } else { - if (0 == strncmp("address", typeType, strlen("address") - 1)) { + } + const jsonType_t value_type = json_getType(walkVals); + const bool hasValue = value_type == JSON_TEXT || + value_type == JSON_INTEGER || + value_type == JSON_BOOLEAN; + valStr = hasValue ? json_getValue(walkVals) : NULL; + if (SUCCESS != (errRet = confirmName(typeName, hasValue))) { + return errRet; + } + + { + if (type_matches(typeType, "address")) { if (']' == typeType[strlen(typeType) - 1]) { // array of addresses + if (value_type != JSON_ARRAY) return GENERAL_ERROR; json_t const* addrVals = json_getChild(walkVals); sha3_256_Init(&valCtx); // hash of concatenated encoded strings while (0 != addrVals) { + if (json_getType(addrVals) != JSON_TEXT) return GENERAL_ERROR; + const char* address = json_getValue(addrVals); // just walk the string values assuming, for fixed sizes, all // values are there. - if (ds_vals) { - marshallDsVals(json_getValue(addrVals)); - } else { - confirmValue(json_getValue(addrVals)); + if (SUCCESS != (errRet = confirmTypedValue(ds_vals, address))) { + return errRet; } - errRet = encAddress(json_getValue(addrVals), encBytes); + errRet = encAddress(address, encBytes); if (SUCCESS != errRet) { return errRet; } @@ -476,10 +566,9 @@ int parseVals(const json_t* eip712Types, const json_t* jType, } keccak_Final(&valCtx, encBytes); } else { - if (ds_vals) { - marshallDsVals(valStr); - } else { - confirmValue(valStr); + if (value_type != JSON_TEXT) return GENERAL_ERROR; + if (SUCCESS != (errRet = confirmTypedValue(ds_vals, valStr))) { + return errRet; } errRet = encAddress(valStr, encBytes); if (SUCCESS != errRet) { @@ -487,21 +576,23 @@ int parseVals(const json_t* eip712Types, const json_t* jType, } } - } else if (0 == strncmp("string", typeType, strlen("string") - 1)) { + } else if (type_matches(typeType, "string")) { if (']' == typeType[strlen(typeType) - 1]) { // array of strings + if (value_type != JSON_ARRAY) return GENERAL_ERROR; json_t const* stringVals = json_getChild(walkVals); uint8_t strEncBytes[32]; sha3_256_Init(&valCtx); // hash of concatenated encoded strings while (0 != stringVals) { + if (json_getType(stringVals) != JSON_TEXT) return GENERAL_ERROR; + const char* string_value = json_getValue(stringVals); // just walk the string values assuming, for fixed sizes, all // values are there. - if (ds_vals) { - marshallDsVals(json_getValue(stringVals)); - } else { - confirmValue(json_getValue(stringVals)); + if (SUCCESS != + (errRet = confirmTypedValue(ds_vals, string_value))) { + return errRet; } - errRet = encString(json_getValue(stringVals), strEncBytes); + errRet = encString(string_value, strEncBytes); if (SUCCESS != errRet) { return errRet; } @@ -510,10 +601,9 @@ int parseVals(const json_t* eip712Types, const json_t* jType, } keccak_Final(&valCtx, encBytes); } else { - if (ds_vals) { - marshallDsVals(valStr); - } else { - confirmValue(valStr); + if (value_type != JSON_TEXT) return GENERAL_ERROR; + if (SUCCESS != (errRet = confirmTypedValue(ds_vals, valStr))) { + return errRet; } errRet = encString(valStr, encBytes); if (SUCCESS != errRet) { @@ -521,18 +611,19 @@ int parseVals(const json_t* eip712Types, const json_t* jType, } } - } else if ((0 == strncmp("uint", typeType, strlen("uint") - 1)) || - (0 == strncmp("int", typeType, strlen("int") - 1))) { + } else if (type_is_integer(typeType, "uint") || + type_is_integer(typeType, "int")) { if (']' == typeType[strlen(typeType) - 1]) { return INT_ARRAY_ERROR; } else { - if (ds_vals) { - marshallDsVals(valStr); - } else { - confirmValue(valStr); + if (value_type != JSON_TEXT && value_type != JSON_INTEGER) + return GENERAL_ERROR; + if (SUCCESS != (errRet = confirmTypedValue(ds_vals, valStr))) { + return errRet; } + const bool is_uint = type_is_integer(typeType, "uint"); uint8_t negInt = 0; // 0 is positive, 1 is negative - if (0 == strncmp("int", typeType, strlen("int") - 1)) { + if (!is_uint) { if (*valStr == '-') { negInt = 1; } @@ -548,147 +639,184 @@ int parseVals(const json_t* eip712Types, const json_t* jType, } } // all int strings are assumed to be base 10 and fit into 64 bits - long long intVal = strtoll(valStr, NULL, 10); + const char* digits = valStr + (negInt ? 1 : 0); + if (*digits == '\0') return GENERAL_ERROR; + for (const char* p = digits; *p; p++) { + if (*p < '0' || *p > '9') return GENERAL_ERROR; + } + errno = 0; + char* endptr = NULL; + long long intVal = strtoll(valStr, &endptr, 10); + if (errno == ERANGE || endptr == valStr || *endptr != '\0') { + return GENERAL_ERROR; + } + if (is_uint && intVal < 0) { + return GENERAL_ERROR; + } + const unsigned declared_bits = + integer_type_width(typeType, is_uint ? "uint" : "int"); + if (declared_bits < 64) { + if (is_uint) { + const uint64_t max_value = (UINT64_C(1) << declared_bits) - 1; + if ((uint64_t)intVal > max_value) return GENERAL_ERROR; + } else { + const int64_t min_value = -(INT64_C(1) << (declared_bits - 1)); + const int64_t max_value = + (INT64_C(1) << (declared_bits - 1)) - 1; + if (intVal < min_value || intVal > max_value) + return GENERAL_ERROR; + } + } // Needs to be big endian, so add to encBytes appropriately - encBytes[24] = (intVal >> 56) & 0xff; - encBytes[25] = (intVal >> 48) & 0xff; - encBytes[26] = (intVal >> 40) & 0xff; - encBytes[27] = (intVal >> 32) & 0xff; - encBytes[28] = (intVal >> 24) & 0xff; - encBytes[29] = (intVal >> 16) & 0xff; - encBytes[30] = (intVal >> 8) & 0xff; - encBytes[31] = (intVal) & 0xff; + const uint64_t intBits = (uint64_t)intVal; + encBytes[24] = (intBits >> 56) & 0xff; + encBytes[25] = (intBits >> 48) & 0xff; + encBytes[26] = (intBits >> 40) & 0xff; + encBytes[27] = (intBits >> 32) & 0xff; + encBytes[28] = (intBits >> 24) & 0xff; + encBytes[29] = (intBits >> 16) & 0xff; + encBytes[30] = (intBits >> 8) & 0xff; + encBytes[31] = intBits & 0xff; } - } else if (0 == strncmp("bytes", typeType, strlen("bytes"))) { - if (']' == typeType[strlen(typeType) - 1]) { - return BYTESN_ARRAY_ERROR; - } else { - // This could be 'bytes', 'bytes1', ..., 'bytes32' - if (ds_vals) { - marshallDsVals(valStr); + } else { + unsigned byte_size = 0; + bool dynamic_bytes = false; + if (type_is_bytes(typeType, &byte_size, &dynamic_bytes)) { + if (']' == typeType[strlen(typeType) - 1]) { + return BYTESN_ARRAY_ERROR; } else { - confirmValue(valStr); - } - if (0 == strcmp(typeType, "bytes")) { - errRet = encodeBytes(valStr, encBytes); - if (SUCCESS != errRet) { + if (value_type != JSON_TEXT) return GENERAL_ERROR; + // This could be 'bytes', 'bytes1', ..., 'bytes32' + if (SUCCESS != (errRet = confirmTypedValue(ds_vals, valStr))) { return errRet; } + if (dynamic_bytes) { + errRet = encodeBytes(valStr, encBytes); + if (SUCCESS != errRet) { + return errRet; + } - } else { - errRet = encodeBytesN(typeType, valStr, encBytes); - if (SUCCESS != errRet) { - return errRet; + } else { + errRet = encodeBytesN(typeType, valStr, encBytes); + if (SUCCESS != errRet) { + return errRet; + } } } - } - } else if (0 == strncmp("bool", typeType, strlen(typeType))) { - if (']' == typeType[strlen(typeType) - 1]) { - return BOOL_ARRAY_ERROR; - } else { - if (ds_vals) { - marshallDsVals(valStr); + } else if (type_matches(typeType, "bool")) { + if (']' == typeType[strlen(typeType) - 1]) { + return BOOL_ARRAY_ERROR; } else { - confirmValue(valStr); - } - for (ctr = 0; ctr < 32; ctr++) { - // leading zeros in bool - encBytes[ctr] = 0; - } - if (0 == strncmp(valStr, "true", sizeof("true"))) { - encBytes[31] = 0x01; + if (value_type != JSON_BOOLEAN && value_type != JSON_TEXT) + return GENERAL_ERROR; + if (SUCCESS != (errRet = confirmTypedValue(ds_vals, valStr))) { + return errRet; + } + if (strcmp(valStr, "true") != 0 && strcmp(valStr, "false") != 0) + return GENERAL_ERROR; + for (ctr = 0; ctr < 32; ctr++) { + // leading zeros in bool + encBytes[ctr] = 0; + } + if (strcmp(valStr, "true") == 0) { + encBytes[31] = 0x01; + } } - } - - } else { - // encode user defined type - char encSubTypeStr[STRBUFSIZE + 1] = {0}; - // clear out the user-defined types list - for (ctr = 0; ctr < MAX_USERDEF_TYPES; ctr++) { - udefList[ctr] = NULL; - } - char typeNoArrTok[MAX_TYPESTRING] = {0}; - // need to get typehash of type first - if (']' == typeType[strlen(typeType) - 1]) { - // array of structs. To parse name, remove array tokens. - strncpy(typeNoArrTok, typeType, sizeof(typeNoArrTok) - 1); - if (strlen(typeNoArrTok) < strlen(typeType)) { - return UDEF_ARRAY_NAME_ERR; - } - strtok(typeNoArrTok, "["); - if (STACK_GOOD != (errRet = memcheck(STACK_SIZE_GUARD))) { - return errRet; - } - if (SUCCESS != (errRet = parseType(eip712Types, typeNoArrTok, - encSubTypeStr))) { - return errRet; - } } else { - if (STACK_GOOD != (errRet = memcheck(STACK_SIZE_GUARD))) { - return errRet; - } - if (SUCCESS != - (errRet = parseType(eip712Types, typeType, encSubTypeStr))) { - return errRet; + // encode user defined type + char encSubTypeStr[STRBUFSIZE + 1] = {0}; + // clear out the user-defined types list + for (ctr = 0; ctr < MAX_USERDEF_TYPES; ctr++) { + udefList[ctr] = NULL; } - } - sha3_256_Init(&valCtx); - sha3_Update(&valCtx, (const unsigned char*)encSubTypeStr, - (size_t)strlen(encSubTypeStr)); - keccak_Final(&valCtx, encBytes); - if (']' == typeType[strlen(typeType) - 1]) { - // array of udefs - struct SHA3_CTX eleCtx = {0}; // local hash context - struct SHA3_CTX arrCtx = {0}; // array elements hash context - uint8_t eleHashBytes[32]; + char typeNoArrTok[MAX_TYPESTRING] = {0}; + // need to get typehash of type first + if (']' == typeType[strlen(typeType) - 1]) { + // array of structs. To parse name, remove array tokens. + if (value_type != JSON_ARRAY) return GENERAL_ERROR; + strncpy(typeNoArrTok, typeType, sizeof(typeNoArrTok) - 1); + if (strlen(typeNoArrTok) < strlen(typeType)) { + return UDEF_ARRAY_NAME_ERR; + } + strtok(typeNoArrTok, "["); + if (STACK_GOOD != (errRet = memcheck(STACK_SIZE_GUARD))) { + return errRet; + } + if (SUCCESS != (errRet = parseType(eip712Types, typeNoArrTok, + encSubTypeStr))) { + return errRet; + } + } else { + if (STACK_GOOD != (errRet = memcheck(STACK_SIZE_GUARD))) { + return errRet; + } + if (SUCCESS != + (errRet = parseType(eip712Types, typeType, encSubTypeStr))) { + return errRet; + } + } + sha3_256_Init(&valCtx); + sha3_Update(&valCtx, (const unsigned char*)encSubTypeStr, + (size_t)strlen(encSubTypeStr)); + keccak_Final(&valCtx, encBytes); - sha3_256_Init(&arrCtx); + if (']' == typeType[strlen(typeType) - 1]) { + // array of udefs + struct SHA3_CTX eleCtx = {0}; // local hash context + struct SHA3_CTX arrCtx = {0}; // array elements hash context + uint8_t eleHashBytes[32]; + + sha3_256_Init(&arrCtx); + + json_t const* udefVals = json_getChild(walkVals); + while (0 != udefVals) { + if (json_getType(udefVals) != JSON_OBJ) return GENERAL_ERROR; + sha3_256_Init(&eleCtx); + sha3_Update(&eleCtx, (const unsigned char*)encBytes, 32); + if (STACK_GOOD != (errRet = memcheck(STACK_SIZE_GUARD))) { + return errRet; + } + if (SUCCESS != + (errRet = parseVals( + eip712Types, + json_getProperty(eip712Types, + strtok(typeNoArrTok, "]")), + json_getChild(udefVals), // where to get the values + &eleCtx // encode hash happens in parse, this is the + // return + ))) { + return errRet; + } + keccak_Final(&eleCtx, eleHashBytes); + sha3_Update(&arrCtx, (const unsigned char*)eleHashBytes, 32); + // just walk the udef values assuming, for fixed sizes, all + // values are there. + udefVals = json_getSibling(udefVals); + } + keccak_Final(&arrCtx, encBytes); - json_t const* udefVals = json_getChild(walkVals); - while (0 != udefVals) { - sha3_256_Init(&eleCtx); - sha3_Update(&eleCtx, (const unsigned char*)encBytes, 32); + } else { + if (value_type != JSON_OBJ) return GENERAL_ERROR; + sha3_256_Init(&valCtx); + sha3_Update(&valCtx, (const unsigned char*)encBytes, + (size_t)sizeof(encBytes)); if (STACK_GOOD != (errRet = memcheck(STACK_SIZE_GUARD))) { return errRet; } if (SUCCESS != (errRet = parseVals( - eip712Types, - json_getProperty(eip712Types, strtok(typeNoArrTok, "]")), - json_getChild(udefVals), // where to get the values - &eleCtx // encode hash happens in parse, this is the - // return + eip712Types, json_getProperty(eip712Types, typeType), + json_getChild(walkVals), // where to get the values + &valCtx // val hash happens in parse, this is the return ))) { return errRet; } - keccak_Final(&eleCtx, eleHashBytes); - sha3_Update(&arrCtx, (const unsigned char*)eleHashBytes, 32); - // just walk the udef values assuming, for fixed sizes, all values - // are there. - udefVals = json_getSibling(udefVals); + keccak_Final(&valCtx, encBytes); } - keccak_Final(&arrCtx, encBytes); - - } else { - sha3_256_Init(&valCtx); - sha3_Update(&valCtx, (const unsigned char*)encBytes, - (size_t)sizeof(encBytes)); - if (STACK_GOOD != (errRet = memcheck(STACK_SIZE_GUARD))) { - return errRet; - } - if (SUCCESS != - (errRet = parseVals( - eip712Types, json_getProperty(eip712Types, typeType), - json_getChild(walkVals), // where to get the values - &valCtx // val hash happens in parse, this is the return - ))) { - return errRet; - } - keccak_Final(&valCtx, encBytes); } } } @@ -699,7 +827,9 @@ int parseVals(const json_t* eip712Types, const json_t* jType, tarray = json_getSibling(tarray); } if (ds_vals) { - dsConfirm(); + if (SUCCESS != (errRet = dsConfirm())) { + return errRet; + } } return SUCCESS; diff --git a/lib/firmware/eos.c b/lib/firmware/eos.c index 45e7acacc..ab40aa4bf 100644 --- a/lib/firmware/eos.c +++ b/lib/firmware/eos.c @@ -385,7 +385,7 @@ bool eos_compilePermissionLevel(const EosPermissionLevel* auth) { bool eos_hasActionUnknownDataRemaining(void) { return 0 < unknown_remaining; } -static bool isSupportedAction(const EosActionCommon* common) { +bool eos_isSupportedAction(const EosActionCommon* common) { if (common->account == EOS_eosio || common->account == EOS_eosio_token) { switch (common->name) { case EOS_Transfer: @@ -402,15 +402,18 @@ static bool isSupportedAction(const EosActionCommon* common) { case EOS_DeleteAuth: case EOS_LinkAuth: case EOS_UnlinkAuth: + case EOS_NewAccount: return true; } } return false; } +bool eos_unknownActionPolicyAllows(bool advanced_mode) { return advanced_mode; } + bool eos_compileActionUnknown(const EosActionCommon* common, const EosActionUnknown* action) { - if (isSupportedAction(common)) { + if (eos_isSupportedAction(common)) { fsm_sendFailure( FailureType_Failure_SyntaxError, "EosActionUnknown cannot be used with supported contract actions"); @@ -418,10 +421,15 @@ bool eos_compileActionUnknown(const EosActionCommon* common, return false; } - if (!storage_isPolicyEnabled("AdvancedMode")) { - (void)review(ButtonRequestType_ButtonRequest_Other, "Warning", - "Signing of arbitrary EOS actions is recommended only for " - "experienced users. Enable 'AdvancedMode' policy to dismiss."); + if (!eos_unknownActionPolicyAllows(storage_isPolicyEnabled("AdvancedMode"))) { + (void)review(ButtonRequestType_ButtonRequest_Other, "Blocked", + "Arbitrary EOS actions require AdvancedMode. " + "Enable in device settings."); + fsm_sendFailure(FailureType_Failure_ActionCancelled, + "Arbitrary EOS action signing disabled by policy"); + eos_signingAbort(); + layoutHome(); + return false; } if (unknown_remaining == 0) { @@ -534,7 +542,13 @@ bool eos_signTx(EosSignedTx* tx) { time_t expiry = header.expiration; char expiry_str[26]; +#ifdef _WIN32 + // asctime_s is the bounds-checked Windows variant; output truncated below. + // cppcheck-suppress asctime_sCalled + asctime_s(expiry_str, sizeof(expiry_str), gmtime(&expiry)); +#else asctime_r(gmtime(&expiry), expiry_str); +#endif expiry_str[24] = 0; // cut off the '\n' uint32_t delay = header.delay_sec; if (!confirm(ButtonRequestType_ButtonRequest_SignTx, "Sign Transaction", diff --git a/lib/firmware/ethereum.c b/lib/firmware/ethereum.c index b7c12c1b5..f1b2037e7 100644 --- a/lib/firmware/ethereum.c +++ b/lib/firmware/ethereum.c @@ -33,6 +33,7 @@ #include "keepkey/firmware/eip712.h" #include "keepkey/firmware/ethereum_contracts.h" #include "keepkey/firmware/ethereum_contracts/makerdao.h" +#include "keepkey/firmware/signed_metadata.h" #include "keepkey/firmware/ethereum_tokens.h" #include "keepkey/firmware/storage.h" #include "keepkey/firmware/thorchain.h" @@ -48,6 +49,14 @@ #define _(X) (X) +bool ethereum_typed_hash_policy_allows(bool advanced_mode) { + return advanced_mode; +} + +bool ethereum_eip712_is_domain_primary_type(const char* primary_type) { + return primary_type && strcmp(primary_type, "EIP712Domain") == 0; +} + #define MAX_CHAIN_ID 2147483630 #define ETHEREUM_TX_TYPE_LEGACY 0UL @@ -204,6 +213,20 @@ static void hash_rlp_number(uint32_t number) { hash_rlp_field(data + offset, 4 - offset); } +/* Strip leading zero bytes before RLP-encoding an integer field. + * Per the Ethereum yellow paper, integer fields (nonce, gas, value, etc.) + * must not have leading zeros. Addresses are NOT integers and must not use + * this function. */ +static void hash_rlp_bytes_stripped(const uint8_t* buf, size_t size) { + size_t offset = 0; + while (offset < size && buf[offset] == 0) offset++; + if (offset == size) { + hash_rlp_field(buf, 0); + } else { + hash_rlp_field(buf + offset, size - offset); + } +} + /* * Calculate the number of bytes needed for an RLP length header. * NOTE: supports up to 16MB of data (how unlikely...) @@ -223,6 +246,21 @@ static int rlp_calculate_length(int length, uint8_t firstbyte) { } } +/* Length of an RLP-encoded integer field AFTER stripping leading zero bytes. + * MUST mirror hash_rlp_bytes_stripped(): the Stage-1 list-length header + * (hash_rlp_list_length) and the Stage-2 bytes actually hashed have to agree, + * or the keccak pre-image is malformed and the signature recovers to a garbage + * address (looks like a "random signer" / dropped tx). Any integer field whose + * big-endian form has a leading zero byte hits this. */ +static int rlp_calculate_length_stripped(const uint8_t* buf, size_t size) { + size_t offset = 0; + while (offset < size && buf[offset] == 0) offset++; + if (offset == size) { + return rlp_calculate_length(0, 0); + } + return rlp_calculate_length(size - offset, buf[offset]); +} + static int rlp_calculate_number_length(uint32_t number) { if (number <= 0x7f) { return 1; @@ -265,6 +303,19 @@ static void send_signature(void) { } keccak_Final(&keccak_ctx, hash); + + /* Insight clear-signing binding. If a verified metadata blob suppressed the + * raw-data confirmation, the actual signed digest MUST equal the tx hash the + * metadata committed to. This is the first point that digest exists, so the + * check reuses it rather than re-deriving the RLP pre-image. Fail closed — + * never emit a signature the displayed decoded screen did not cover. */ + if (!signed_metadata_enforce(hash)) { + fsm_sendFailure(FailureType_Failure_Other, + "Metadata does not match signed transaction"); + ethereum_signing_abort(); + return; + } + if (ecdsa_sign_digest(&secp256k1, privkey, hash, sig, &v, ethereum_is_canonic) != 0) { fsm_sendFailure(FailureType_Failure_Other, "Signing failed"); @@ -388,6 +439,9 @@ void ethereumFormatAmount(const bignum256* amnt, const TokenType* token, case 137: suffix = " MATIC"; break; // Polygon Mainnet + case 43114: + suffix = " AVAX"; + break; // Avalanche C-Chain } } } @@ -585,8 +639,13 @@ static bool ethereum_signing_check(const EthereumSignTx* msg) { return false; } - if (msg->gas_price.size + msg->gas_limit.size > 30) { - // sanity check that fee doesn't overflow + // Sanity-bound the fee field that this tx type actually uses, so the + // on-screen fee (fee_per_gas * gas_limit) cannot overflow into the modular + // bn_multiply and display a wrong value. EIP-1559 uses max_fee_per_gas; + // legacy uses gas_price (which is 0 for EIP-1559 and vice versa). + size_t fee_per_gas_size = msg->has_max_fee_per_gas ? msg->max_fee_per_gas.size + : msg->gas_price.size; + if (fee_per_gas_size + msg->gas_limit.size > 30) { return false; } @@ -648,17 +707,30 @@ void ethereum_signing_init(EthereumSignTx* msg, const HDNode* node, ethereum_tx_type = ETHEREUM_TX_TYPE_LEGACY; } - if (ethereum_tx_type == ETHEREUM_TX_TYPE_EIP_1559 && chain_id == 0) { - fsm_sendFailure(FailureType_Failure_SyntaxError, - _("EIP-1559 transactions require chain_id")); - ethereum_signing_abort(); - return; - } - - if (ethereum_tx_type == ETHEREUM_TX_TYPE_EIP_1559 && - !msg->has_max_fee_per_gas) { + /* The typed prefix (0x02) and access list are emitted based on + * ethereum_tx_type, while the fee fields are selected by has_max_fee_per_gas. + * If those two disagree, Stage 1 (rlp_length) and Stage 2 (hashed bytes) + * describe different field lists and the signature recovers to a wrong + * address. Enforce a consistent shape up front. */ + if (ethereum_tx_type == ETHEREUM_TX_TYPE_EIP_1559) { + if (chain_id == 0) { + /* chain_id is the mandatory first RLP field of an EIP-1559 tx; absent + * chain_id is counted (1 byte) in Stage 1 but hash_rlp_number(0) hashes + * nothing in Stage 2. */ + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("EIP-1559 transactions require chain_id")); + ethereum_signing_abort(); + return; + } + if (!msg->has_max_fee_per_gas) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("EIP-1559 transactions require max_fee_per_gas")); + ethereum_signing_abort(); + return; + } + } else if (msg->has_max_fee_per_gas) { fsm_sendFailure(FailureType_Failure_SyntaxError, - _("EIP-1559 transactions require max_fee_per_gas")); + _("max_fee_per_gas requires an EIP-1559 (type 2) tx")); ethereum_signing_abort(); return; } @@ -718,6 +790,30 @@ void ethereum_signing_init(EthereumSignTx* msg, const HDNode* node, data_needs_confirm = false; } + // Signed metadata clear signing (backwards compatible). + // Only fires if host sent EthereumTxMetadata before this EthereumSignTx. + if (data_needs_confirm && data_total > 0 && signed_metadata_available()) { + if (signed_metadata_matches_tx(msg)) { + if (signed_metadata_confirm()) { + // Decoded who/what/why approved; raw-data confirm is suppressed. The + // signature is bound to this metadata's tx hash in send_signature(). + needs_confirm = false; + data_needs_confirm = false; + } else { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + "Signing cancelled by user"); + ethereum_signing_abort(); // clears metadata + return; + } + } + } + // Drop metadata now UNLESS we relied on it to suppress the raw-data confirm + // (then it must survive to bind the signature). Prevents stale reuse when the + // contractHandled / ERC-20 paths bypass the metadata check above. + if (!signed_metadata_relied()) { + signed_metadata_clear(); + } + // detect ERC-20 token if (data_total == 68 && ethereum_isStandardERC20Transfer(msg)) { token = tokenByChainAddress(chain_id, msg->to.bytes); @@ -763,15 +859,15 @@ void ethereum_signing_init(EthereumSignTx* msg, const HDNode* node, memset(confirm_body_message, 0, sizeof(confirm_body_message)); if (token == NULL && data_total > 0 && data_needs_confirm) { - // KeepKey custom: warn the user that they're trying to do something - // that is potentially dangerous. People (generally) aren't great at - // parsing raw transaction data, and we can't effectively show them - // what they're about to do in the general case. + // AdvancedMode policy: hard gate for blind-signing arbitrary contract data if (!storage_isPolicyEnabled("AdvancedMode")) { - (void)review( - ButtonRequestType_ButtonRequest_Other, "Warning", - "Signing of arbitrary ETH contract data is recommended only for " - "experienced users. Enable 'AdvancedMode' policy to dismiss."); + (void)review(ButtonRequestType_ButtonRequest_Other, "Blocked", + "Blind signing requires AdvancedMode. " + "Enable in device settings."); + fsm_sendFailure(FailureType_Failure_ActionCancelled, + "Blind signing disabled by policy"); + ethereum_signing_abort(); + return; } layoutEthereumData(msg->data_initial_chunk.bytes, @@ -808,24 +904,24 @@ void ethereum_signing_init(EthereumSignTx* msg, const HDNode* node, rlp_length += rlp_calculate_number_length(chain_id); } - rlp_length += rlp_calculate_length(msg->nonce.size, msg->nonce.bytes[0]); - if (ethereum_tx_type == ETHEREUM_TX_TYPE_EIP_1559) { + rlp_length += + rlp_calculate_length_stripped(msg->nonce.bytes, msg->nonce.size); + if (msg->has_max_fee_per_gas) { rlp_length += - rlp_calculate_length(msg->max_priority_fee_per_gas.size, - msg->max_priority_fee_per_gas.size - ? msg->max_priority_fee_per_gas.bytes[0] - : 0); - rlp_length += rlp_calculate_length(msg->max_fee_per_gas.size, - msg->max_fee_per_gas.bytes[0]); + rlp_calculate_length_stripped(msg->max_priority_fee_per_gas.bytes, + msg->max_priority_fee_per_gas.size); + rlp_length += rlp_calculate_length_stripped(msg->max_fee_per_gas.bytes, + msg->max_fee_per_gas.size); } else { - rlp_length += - rlp_calculate_length(msg->gas_price.size, msg->gas_price.bytes[0]); + rlp_length += rlp_calculate_length_stripped(msg->gas_price.bytes, + msg->gas_price.size); } rlp_length += - rlp_calculate_length(msg->gas_limit.size, msg->gas_limit.bytes[0]); + rlp_calculate_length_stripped(msg->gas_limit.bytes, msg->gas_limit.size); rlp_length += rlp_calculate_length(msg->to.size, msg->to.bytes[0]); - rlp_length += rlp_calculate_length(msg->value.size, msg->value.bytes[0]); + rlp_length += + rlp_calculate_length_stripped(msg->value.bytes, msg->value.size); rlp_length += rlp_calculate_length(data_total, msg->data_initial_chunk.bytes[0]); @@ -872,19 +968,26 @@ void ethereum_signing_init(EthereumSignTx* msg, const HDNode* node, hash_rlp_number(chain_id); } - hash_rlp_field(msg->nonce.bytes, msg->nonce.size); + hash_rlp_bytes_stripped(msg->nonce.bytes, msg->nonce.size); - if (ethereum_tx_type == ETHEREUM_TX_TYPE_EIP_1559) { - hash_rlp_field(msg->max_priority_fee_per_gas.bytes, - msg->max_priority_fee_per_gas.size); - hash_rlp_field(msg->max_fee_per_gas.bytes, msg->max_fee_per_gas.size); + if (msg->has_max_fee_per_gas) { + /* max_priority_fee_per_gas is a mandatory EIP-1559 field; when absent it + * encodes as the empty integer (0x80). Stage 1 always counts it + * (unconditionally, above), so Stage 2 must always hash it too -- guarding + * on has_max_priority_fee_per_gas here would under-hash and leave the list + * header over-declared (the same wrong-signer class this commit fixes). + * .size is 0 when unset, which hash_rlp_bytes_stripped emits as 0x80. */ + hash_rlp_bytes_stripped(msg->max_priority_fee_per_gas.bytes, + msg->max_priority_fee_per_gas.size); + hash_rlp_bytes_stripped(msg->max_fee_per_gas.bytes, + msg->max_fee_per_gas.size); } else { - hash_rlp_field(msg->gas_price.bytes, msg->gas_price.size); + hash_rlp_bytes_stripped(msg->gas_price.bytes, msg->gas_price.size); } - hash_rlp_field(msg->gas_limit.bytes, msg->gas_limit.size); - hash_rlp_field(msg->to.bytes, msg->to.size); - hash_rlp_field(msg->value.bytes, msg->value.size); + hash_rlp_bytes_stripped(msg->gas_limit.bytes, msg->gas_limit.size); + hash_rlp_field(msg->to.bytes, msg->to.size); /* address: no strip */ + hash_rlp_bytes_stripped(msg->value.bytes, msg->value.size); hash_rlp_length(data_total, msg->data_initial_chunk.bytes[0]); hash_data(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size); data_left = data_total - msg->data_initial_chunk.size; @@ -932,11 +1035,14 @@ void ethereum_signing_txack(EthereumTxAck* tx) { void ethereum_signing_abort(void) { if (ethereum_signing) { memzero(privkey, sizeof(privkey)); + signed_metadata_clear(); layoutHome(); ethereum_signing = false; } } +bool ethereum_signing_isInProgress(void) { return ethereum_signing; } + static void ethereum_message_hash(const uint8_t* message, size_t message_len, uint8_t hash[32]) { struct SHA3_CTX ctx; @@ -1126,9 +1232,14 @@ const char* failMsgReturn[LAST_ERROR - 2] = { "EIP-712 typeType has no name in parseVals", "EIP-712 address string is NULL", "EIP-712 no value for type during walkVals", // 33 + "EIP-712 cancelled", // 34 (USER_CANCELLED) }; void failMessage(int err) { + if (err == USER_CANCELLED) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + return; + } if (err < GENERAL_ERROR || err > LAST_ERROR) { // unknown error number fsm_sendFailure(FailureType_Failure_Other, _("EIP-712 unknown failure")); @@ -1205,14 +1316,23 @@ void e712_types_values(Ethereum712TypesValues* msg, failMessage(JSON_PTYPENAMEERR); return; } + if (json_getType(obTest) != JSON_TEXT) { + failMessage(JSON_PTYPEVALERR); + return; + } const char* primeType; - if (0 == (primeType = json_getValue(obTest))) { + if (0 == (primeType = json_getValue(obTest)) || primeType[0] == '\0') { failMessage(JSON_PTYPEVALERR); return; } - if (0 != strncmp(primeType, "EIP712Domain", - strlen(primeType))) { // if primaryType is "EIP712Domain", - // message hash is NULL + if (!confirm_bytes(ButtonRequestType_ButtonRequest_Other, + "EIP-712 Primary Type", (const uint8_t*)primeType, + strlen(primeType))) { + failMessage(USER_CANCELLED); + return; + } + if (!ethereum_eip712_is_domain_primary_type( + primeType)) { // domain-only signatures have no message hash errRet = encode(jsonT, jsonV, primeType, resp->message_hash.bytes); if (!(SUCCESS == errRet || NULL_MSG_HASH == errRet)) { failMessage(errRet); diff --git a/lib/firmware/ethereum_contracts.c b/lib/firmware/ethereum_contracts.c index 87fb61488..deec3b4eb 100644 --- a/lib/firmware/ethereum_contracts.c +++ b/lib/firmware/ethereum_contracts.c @@ -20,6 +20,7 @@ #include "keepkey/firmware/ethereum_contracts.h" +#include "keepkey/firmware/ethereum.h" // completes EthereumSignTx (msg fields) #include "keepkey/firmware/ethereum_contracts/saproxy.h" #include "keepkey/firmware/ethereum_contracts/thortx.h" #include "keepkey/firmware/ethereum_contracts/zxappliquid.h" @@ -32,12 +33,32 @@ bool ethereum_contractHandled(uint32_t data_total, const EthereumSignTx* msg, const HDNode* node) { (void)node; - if (sa_isWithdrawFromSalary(msg)) return true; + /* Only a CALL to a contract may be clear-signed, never a CREATE + * (to.size == 0 must reach the deploy screen). */ + if (msg->to.size != 20) { + return false; + } + + /* 0x transformERC20 is pinned to the ExchangeProxy and bounded by its + * displayed input/min-output amounts, so it is safe to clear-sign at ANY + * calldata size; its transformations[] tail legitimately exceeds one 1024- + * byte chunk. (It guards its own fixed-offset reads against + * data_initial_chunk.size.) */ if (zx_isZxTransformERC20(msg)) return true; + + /* Every other handler must have the ENTIRE calldata in the first chunk, so + * the fields it parses and displays are the whole transaction and nothing + * unshown streams in afterwards. */ + if (data_total != msg->data_initial_chunk.size) { + return false; + } + + if (sa_isWithdrawFromSalary(msg)) return true; if (zx_isZxSwap(msg)) return true; if (zx_isZxLiquidTx(msg)) return true; if (zx_isZxApproveLiquid(msg)) return true; + if (thor_isMayachainTx(msg)) return true; if (thor_isThorchainTx(msg)) return true; if (makerdao_isMakerDAO(data_total, msg)) return true; @@ -62,6 +83,7 @@ bool ethereum_contractConfirmed(uint32_t data_total, const EthereumSignTx* msg, if (zx_isZxApproveLiquid(msg)) return zx_confirmApproveLiquidity(data_total, msg); + if (thor_isMayachainTx(msg)) return thor_confirmMayaTx(data_total, msg); if (thor_isThorchainTx(msg)) return thor_confirmThorTx(data_total, msg); if (makerdao_isMakerDAO(data_total, msg)) diff --git a/lib/firmware/ethereum_contracts/saproxy.c b/lib/firmware/ethereum_contracts/saproxy.c index ccab30ba6..c7514995f 100644 --- a/lib/firmware/ethereum_contracts/saproxy.c +++ b/lib/firmware/ethereum_contracts/saproxy.c @@ -45,7 +45,8 @@ bool sa_isWithdrawFromSalary(const EthereumSignTx* msg) { bool sa_confirmWithdrawFromSalary(uint32_t data_total, const EthereumSignTx* msg) { - (void)data_total; + /* reads selector + 2 32-byte words (salaryId, withdrawAmount) */ + if (data_total < 4 + 2 * 32) return false; char confStr[41]; bignum256 salaryId, withdrawAmount; diff --git a/lib/firmware/ethereum_contracts/thortx.c b/lib/firmware/ethereum_contracts/thortx.c index 6f48d1ab5..d86e98e52 100644 --- a/lib/firmware/ethereum_contracts/thortx.c +++ b/lib/firmware/ethereum_contracts/thortx.c @@ -41,28 +41,123 @@ bool thor_is_expiry_variant(const EthereumSignTx* msg) { THOR_SELECTOR_DEPOSIT_WITH_EXPIRY, 4) == 0; } -bool thor_isThorchainTx(const EthereumSignTx* msg) { - if (msg->has_to && msg->to.size == 20 && thor_has_deposit_selector(msg)) { - return true; +/* Format msg->to as lowercase hex string (40 chars + NUL) */ +static void thor_format_to_addr(const EthereumSignTx* msg, char out[41]) { + for (uint32_t i = 0; i < 20; i++) { + snprintf(&out[i * 2], 3, "%02x", msg->to.bytes[i]); } - return false; + out[40] = '\0'; } -bool thor_confirmThorTx(uint32_t data_total, const EthereumSignTx* msg) { +bool thor_isMayachainTx(const EthereumSignTx* msg) { + if (!msg->has_to || msg->to.size != 20) return false; + /* MAYA_ROUTER is an Ethereum-mainnet identity; the same address on another + * EVM chain may hold unrelated attacker code. Bind to mainnet so a + * host-selected chain_id cannot borrow the trusted router UX. */ + if (!msg->has_chain_id || msg->chain_id != 1) return false; + if (!thor_has_deposit_selector(msg)) return false; + char toStr[41]; + thor_format_to_addr(msg, toStr); + return strncmp(toStr, MAYA_ROUTER, 40) == 0; +} + +/* The THORChain router address for this tx's chain, or NULL if the chain has + * no pinned router (then the deposit is not clear-signed and falls to the + * blind-sign gate). Each router address is a per-chain identity — the same + * address on another chain may hold unrelated attacker code — so the pin is + * (chain_id, address) together. A tx with NO chain_id gets no router at all: + * ethereum.c would default it to mainnet for hashing, but an identity pin + * must never be inherited from a default the host simply omitted. */ +static const char* thor_router_for_chain(const EthereumSignTx* msg) { + if (!msg->has_chain_id) return NULL; + switch (msg->chain_id) { + case 1: + return THOR_ROUTER; /* Ethereum */ + case 43114: + return THOR_ROUTER_AVAX; /* Avalanche C-Chain */ + default: + return NULL; + } +} + +bool thor_isThorchainTx(const EthereumSignTx* msg) { + if (!msg->has_to || msg->to.size != 20) return false; + if (!thor_has_deposit_selector(msg)) return false; + /* Pin to the THORChain router FOR THIS CHAIN. Without the pin, ANY contract + * carrying the deposit selector would get the THORChain clear-sign UX and + * bypass the AdvancedMode blind-sign gate, letting an attacker contract + * drain while the device shows a benign deposit. Without the chain scope, + * only mainnet deposits ever match (the AVAX->ETH blind-sign bug). */ + const char* router = thor_router_for_chain(msg); + if (!router) return false; + char toStr[41]; + thor_format_to_addr(msg, toStr); + return strncmp(toStr, router, 40) == 0; +} + +static bool thor_confirm_deposit_tx(uint32_t data_total, + const EthereumSignTx* msg, + const char* protocol_label, + const char* router_label) { (void)data_total; - /* Minimum calldata: selector(4) + vault(32) + asset(32) + amount(32) + - * memo_offset(32) + memo_length(32) = 164 bytes for deposit(), - * + expiry(32) = 196 bytes for depositWithExpiry(). */ + /* Minimum calldata to read the fixed head through the memo_length word: + * selector(4) + vault(32) + asset(32) + amount(32) + memo_offset(32) + + * memo_length(32) = 164 bytes for deposit(), + expiry(32) = 196 for + * depositWithExpiry(). The exact memo bounds are enforced below from the ABI + * memo length, so a short memo (e.g. "ADD:ETH.ETH") still clear-signs rather + * than being rejected by an over-tight fixed floor. */ const bool is_expiry = thor_is_expiry_variant(msg); - const size_t min_chunk = is_expiry ? 260 : 228; + const size_t min_chunk = is_expiry ? 196 : 164; if (msg->data_initial_chunk.size < min_chunk) return false; - char confStr[41], *conf; - const TokenType* assetToken; + /* The memo is a dynamic `string`; its ABI head pointer (word 3, offset + * 4+3*32) must be canonical (0x80 for deposit's 4 head words, 0xa0 for + * depositWithExpiry's 5), else abi.decode on the router reads the memo from a + * different location than we display from the fixed offset below -> the + * executed swap destination can differ from what the user approved. */ + { + static const uint8_t MEMO_OFF_DEPOSIT[32] = {[31] = 0x80}; + static const uint8_t MEMO_OFF_EXPIRY[32] = {[31] = 0xa0}; + const uint8_t* expected = is_expiry ? MEMO_OFF_EXPIRY : MEMO_OFF_DEPOSIT; + if (memcmp(msg->data_initial_chunk.bytes + 4 + 3 * 32, expected, 32) != 0) { + return false; + } + } + + /* The memo is a dynamic `string`: read its ABI length word instead of + * assuming a fixed 64 bytes. A longer memo places router-executed fields + * (destination, affiliate, aggregator, min-out) past byte 64 that a fixed + * parse never displays. Reject dirty high bytes, cap at THORChain's 256-byte + * memo max, require the whole calldata to be in this chunk, and require the + * padded memo to end exactly at the calldata end so no trailing bytes hide. + */ + const uint8_t* memo_len_word = + msg->data_initial_chunk.bytes + 4 + (is_expiry ? 5 : 4) * 32; + for (int i = 0; i < 28; i++) { + if (memo_len_word[i] != 0) return false; + } + const uint32_t memo_len = ((uint32_t)memo_len_word[28] << 24) | + ((uint32_t)memo_len_word[29] << 16) | + ((uint32_t)memo_len_word[30] << 8) | + (uint32_t)memo_len_word[31]; + if (memo_len > 256) return false; + const size_t memo_off = (size_t)(4 + (is_expiry ? 6 : 5) * 32); + const size_t memo_padded = ((memo_len + 31u) / 32u) * 32u; + if (msg->has_data_length && + msg->data_length != msg->data_initial_chunk.size) { + return false; /* whole calldata must be in the initial chunk to bound it */ + } + if (memo_off + memo_padded != msg->data_initial_chunk.size) { + return false; /* trailing bytes after the memo would be executed but hidden + */ + } + + char confStr[41]; + const char* conf; uint8_t* thorchainData; const uint8_t* contractAssetAddress; - const uint8_t *vaultAddress, *assetAddress; + const uint8_t* vaultAddress; uint32_t ctr; bignum256 Amount; @@ -75,15 +170,16 @@ bool thor_confirmThorTx(uint32_t data_total, const EthereumSignTx* msg) { (uint8_t*)(msg->data_initial_chunk.bytes + 4 + (is_expiry ? 6 : 5) * 32); // Start confirmations - for (ctr = 0; ctr < 20; ctr++) { - snprintf(&confStr[ctr * 2], 3, "%02x", msg->to.bytes[ctr]); - } - if (strncmp(confStr, THOR_ROUTER, sizeof(THOR_ROUTER)) == 0) { + thor_format_to_addr(msg, confStr); + const char* thor_router = thor_router_for_chain(msg); + if (thor_router && strncmp(confStr, thor_router, 40) == 0) { conf = "Thorchain router"; + } else if (strncmp(confStr, MAYA_ROUTER, 40) == 0) { + conf = router_label; } else { conf = confStr; } - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "Thorchain data", + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, protocol_label, "Routing through %s", conf)) { return false; } @@ -92,50 +188,92 @@ bool thor_confirmThorTx(uint32_t data_total, const EthereumSignTx* msg) { for (ctr = 0; ctr < 20; ctr++) { snprintf(&confStr[ctr * 2], 3, "%02x", vaultAddress[ctr]); } - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "Thorchain data", + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, protocol_label, "Using Asgard vault %s", confStr)) { return false; } - if (memcmp(contractAssetAddress, ETH_ADDRESS, sizeof(ETH_ADDRESS)) == 0) { - assetAddress = (const uint8_t*) - ETH_NATIVE; // get eth native parameters if asset is not a token - } else { - assetAddress = contractAssetAddress; - } - - assetToken = tokenByChainAddress(msg->chain_id, assetAddress); + /* Both pinned routers treat ONLY address(0) as native (and require + * msg.value == 0 for any other asset), so the 0xEeee..Ee sentinel is NOT + * native here — accepting it would clear-sign a tx that reverts on-chain and + * burns gas. Match address(0) exactly (20 bytes, not sizeof, whose literal + * NUL would over-read into the amount word). */ + const bool is_native = memcmp(contractAssetAddress, ETH_ADDRESS, 20) == 0; + bignum256 Value; + bn_from_bytes(msg->value.bytes, msg->value.size, &Value); + if (is_native) { + /* Display msg.value — the amount the router actually forwards — not the ABI + * amount word it ignores. That alone closes the "display 0.01 while sending + * 100" gap; we do NOT additionally require amount == value, since the ABI + * amount is a router-ignored hint that legitimately differs. Format with a + * NULL token so the ticker is the CHAIN's native asset (ETH on mainnet, + * AVAX on Avalanche); the 0xEE pseudo-token entry is pinned to " ETH" and + * would mislabel every other chain's native deposit. */ + ethereumFormatAmount(&Value, NULL, msg->chain_id, confStr, sizeof(confStr)); - if (strncmp(assetToken->ticker, " UNKN", 5) == 0) { - // just display token address and amount as string - for (ctr = 0; ctr < 20; ctr++) { - snprintf(&confStr[ctr * 2], 3, "%02x", assetAddress[ctr]); - } - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, - "Thorchain data", "from asset %s", confStr)) { + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, protocol_label, + "Confirm sending %s", confStr)) { return false; } - // We don't know what the exponent should be so just confirm raw unformatted - // number - bn_format(&Amount, NULL, " unformatted", 0, 0, false, confStr, - sizeof(confStr)); - - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, - "Thorchain data", "amount %s", confStr)) { + } else { + /* A token deposit must not also carry native value (the router pulls tokens + * via transferFrom); nonzero msg.value would be swept and never shown. */ + if (!bn_is_zero(&Value)) { return false; } + const uint8_t* assetAddress = contractAssetAddress; - } else { - ethereumFormatAmount(&Amount, assetToken, msg->chain_id, confStr, - sizeof(confStr)); + const TokenType* assetToken = + tokenByChainAddress(msg->chain_id, assetAddress); - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, - "Thorchain data", "Confirm sending %s", confStr)) { - return false; + if (strncmp(assetToken->ticker, " UNKN", 5) == 0) { + // just display token address and amount as string + for (ctr = 0; ctr < 20; ctr++) { + snprintf(&confStr[ctr * 2], 3, "%02x", assetAddress[ctr]); + } + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + protocol_label, "from asset %s", confStr)) { + return false; + } + // We don't know what the exponent should be so just confirm raw + // unformatted number + bn_format(&Amount, NULL, " unformatted", 0, 0, false, confStr, + sizeof(confStr)); + + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + protocol_label, "amount %s", confStr)) { + return false; + } + + } else { + ethereumFormatAmount(&Amount, assetToken, msg->chain_id, confStr, + sizeof(confStr)); + + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + protocol_label, "Confirm sending %s", confStr)) { + return false; + } } } - if (!thorchain_parseConfirmMemo((const char*)thorchainData, 64)) return false; + if (!thorchain_parseConfirmMemo((const char*)thorchainData, memo_len)) + return false; + + /* Page the complete raw memo as the authoritative disclosure: a long + * structured field (dest/affiliate/aggregator) would otherwise truncate in + * its single confirm and hide the tail that the router still executes. */ + if (!thorchain_confirm_full_memo("Memo", (const char*)thorchainData, + memo_len)) + return false; return true; } + +bool thor_confirmThorTx(uint32_t data_total, const EthereumSignTx* msg) { + return thor_confirm_deposit_tx(data_total, msg, "Thorchain data", + "Thorchain router"); +} + +bool thor_confirmMayaTx(uint32_t data_total, const EthereumSignTx* msg) { + return thor_confirm_deposit_tx(data_total, msg, "Maya data", "Maya router"); +} diff --git a/lib/firmware/ethereum_contracts/zxappliquid.c b/lib/firmware/ethereum_contracts/zxappliquid.c index 76d7d3cda..841fd5fe2 100644 --- a/lib/firmware/ethereum_contracts/zxappliquid.c +++ b/lib/firmware/ethereum_contracts/zxappliquid.c @@ -7,108 +7,138 @@ * 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. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see . */ #include "keepkey/firmware/ethereum_contracts/zxappliquid.h" #include "keepkey/firmware/ethereum_contracts/zxliquidtx.h" #include "keepkey/board/confirm_sm.h" +#include "keepkey/board/font.h" +#include "keepkey/board/layout.h" #include "keepkey/board/util.h" -#include "keepkey/firmware/app_confirm.h" -#include "keepkey/firmware/coins.h" #include "keepkey/firmware/ethereum.h" #include "keepkey/firmware/ethereum_tokens.h" -#include "keepkey/firmware/fsm.h" -#include "keepkey/firmware/storage.h" -#include "trezor/crypto/address.h" -#include "trezor/crypto/bip32.h" -#include "trezor/crypto/curves.h" -#include "trezor/crypto/memzero.h" +#include "trezor/crypto/bignum.h" #include "trezor/crypto/sha3.h" -bool zx_confirmApproveLiquidity(uint32_t data_total, - const EthereumSignTx *msg) { - (void)data_total; - const char *to, *tikstr, *poolstr, *allowance, *amt; - unsigned char data[40]; - uint8_t digest[SHA3_256_DIGEST_LENGTH] = {0}; - uint8_t tokdigest[SHA3_256_DIGEST_LENGTH] = {0}; - char digestStr[2 * SHA3_256_DIGEST_LENGTH + 1], amtStr[2 * 32 + 1] = {0}; - int32_t ctr, tokctr; - uint32_t wethord; - const TokenType *WETH, *ttoken; - - if (!tokenByTicker(msg->chain_id, "WETH", &WETH)) return false; - wethord = read_be((const uint8_t *)WETH->address); - to = (const char *)msg->to.bytes; - tokctr = 0; - while (tokctr != -1) { - ttoken = tokenIter(&tokctr); - - // https://uniswap.org/docs/v2/smart-contract-integration/getting-pair-addresses/ - uint32_t ttokenord = read_be((const uint8_t *)ttoken->address); - if (ttokenord < wethord) { - memcpy(data, ttoken->address, 20); - memcpy(&data[20], WETH->address, 20); - } else { - memcpy(data, WETH->address, 20); - memcpy(&data[20], ttoken->address, 20); - } - keccak_256(data, sizeof(data), tokdigest); - SHA3_CTX ctx = {0}; - keccak_256_Init(&ctx); - keccak_Update(&ctx, (unsigned char *)"\xff", 1); - keccak_Update(&ctx, (unsigned char *)"\x5C\x69\xbE\xe7\x01\xef\x81\x4a\x2B\x6a\x3E\xDD\x4B\x16\x52\xCB\x9c\xc5\xaA\x6f", 20); - keccak_Update(&ctx, tokdigest, sizeof(tokdigest)); - keccak_Update(&ctx, (unsigned char *)"\x96\xe8\xac\x42\x77\x19\x8f\xf8\xb6\xf7\x85\x47\x8a\xa9\xa3\x9f\x40\x3c\xb7\x68\xdd\x02\xcb\xee\x32\x6c\x3e\x7d\xa3\x48\x84\x5f", 32); - keccak_Final(&ctx, digest); - if (memcmp(to, &digest[12], 20) == 0) break; +#include +#include + +#define UNISWAP_APPROVE_CALL_SIZE (4 + 2 * 32) +#define UNISWAP_AMOUNT_TEXT_SIZE 96 + +static const uint8_t UNISWAP_FACTORY_ADDRESS[20] = { + 0x5c, 0x69, 0xbe, 0xe7, 0x01, 0xef, 0x81, 0x4a, 0x2b, 0x6a, + 0x3e, 0xdd, 0x4b, 0x16, 0x52, 0xcb, 0x9c, 0xc5, 0xaa, 0x6f}; +static const uint8_t UNISWAP_PAIR_INIT_CODE_HASH[32] = { + 0x96, 0xe8, 0xac, 0x42, 0x77, 0x19, 0x8f, 0xf8, 0xb6, 0xf7, 0x85, + 0x47, 0x8a, 0xa9, 0xa3, 0x9f, 0x40, 0x3c, 0xb7, 0x68, 0xdd, 0x02, + 0xcb, 0xee, 0x32, 0x6c, 0x3e, 0x7d, 0xa3, 0x48, 0x84, 0x5f}; +static const uint8_t WETH_MAINNET_ADDRESS[20] = { + 0xc0, 0x2a, 0xaa, 0x39, 0xb2, 0x23, 0xfe, 0x8d, 0x0a, 0x0e, + 0x5c, 0x4f, 0x27, 0xea, 0xd9, 0x08, 0x3c, 0x75, 0x6c, 0xc2}; + +static bool tx_value_is_zero(const EthereumSignTx* msg) { + if (!msg->has_value && msg->value.size != 0) return false; + for (size_t i = 0; i < msg->value.size; i++) { + if (msg->value.bytes[i] != 0) return false; } + return true; +} + +static bool spender_word_is_router(const EthereumSignTx* msg) { + const uint8_t* word = msg->data_initial_chunk.bytes + 4; + for (size_t i = 0; i < 12; i++) { + if (word[i] != 0) return false; + } + return memcmp(word + 12, UNISWAP_ROUTER_ADDRESS, 20) == 0; +} - if (tokctr != -1) { - for (ctr = 0; ctr < SHA3_256_DIGEST_LENGTH; ctr++) { - snprintf(&digestStr[ctr * 2], 3, "%02x", digest[ctr]); - } - tikstr = ttoken->ticker; - poolstr = &digestStr[12 * 2]; +static void derive_pair_address(const uint8_t* token_a, const uint8_t* token_b, + uint8_t pair[20]) { + uint8_t ordered[40]; + if (memcmp(token_a, token_b, 20) < 0) { + memcpy(ordered, token_a, 20); + memcpy(ordered + 20, token_b, 20); } else { - for (ctr = 0; ctr < 20; ctr++) { - snprintf(&digestStr[ctr * 2], 3, "%02x", to[ctr]); - } - tikstr = ""; - poolstr = digestStr; + memcpy(ordered, token_b, 20); + memcpy(ordered + 20, token_a, 20); } - allowance = (char *)(msg->data_initial_chunk.bytes + 4 + 32); - if (memcmp(allowance, (uint8_t *)&MAX_ALLOWANCE, 32) == 0) { - amt = "full balance"; + uint8_t salt[SHA3_256_DIGEST_LENGTH]; + uint8_t digest[SHA3_256_DIGEST_LENGTH]; + keccak_256(ordered, sizeof(ordered), salt); + SHA3_CTX ctx = {0}; + keccak_256_Init(&ctx); + const uint8_t prefix = 0xff; + keccak_Update(&ctx, &prefix, 1); + keccak_Update(&ctx, UNISWAP_FACTORY_ADDRESS, sizeof(UNISWAP_FACTORY_ADDRESS)); + keccak_Update(&ctx, salt, sizeof(salt)); + keccak_Update(&ctx, UNISWAP_PAIR_INIT_CODE_HASH, + sizeof(UNISWAP_PAIR_INIT_CODE_HASH)); + keccak_Final(&ctx, digest); + memcpy(pair, digest + 12, 20); +} + +static const TokenType* pool_underlying_token(const EthereumSignTx* msg) { + int32_t token_index = 0; + while (token_index >= 0) { + const TokenType* token = tokenIter(&token_index); + if (token == UnknownToken) break; + if (token->chain_id != 1 || + memcmp(token->address, WETH_MAINNET_ADDRESS, 20) == 0) + continue; + uint8_t pair[20]; + derive_pair_address((const uint8_t*)token->address, WETH_MAINNET_ADDRESS, + pair); + if (memcmp(msg->to.bytes, pair, 20) == 0) return token; + } + return NULL; +} + +static bool approve_shape_is_clear_signable(const EthereumSignTx* msg) { + if (!msg->has_chain_id || msg->chain_id != 1 || !msg->has_to || + msg->to.size != 20 || !msg->has_data_initial_chunk || + msg->data_initial_chunk.size != UNISWAP_APPROVE_CALL_SIZE || + memcmp(msg->data_initial_chunk.bytes, "\x09\x5e\xa7\xb3", 4) != 0 || + msg->value.size > 32 || !tx_value_is_zero(msg) || + !spender_word_is_router(msg)) + return false; + return pool_underlying_token(msg) != NULL; +} + +bool zx_confirmApproveLiquidity(uint32_t data_total, + const EthereumSignTx* msg) { + if (data_total != UNISWAP_APPROVE_CALL_SIZE || + !approve_shape_is_clear_signable(msg)) + return false; + + const TokenType* token = pool_underlying_token(msg); + const uint8_t* allowance = msg->data_initial_chunk.bytes + 4 + 32; + char amount_text[UNISWAP_AMOUNT_TEXT_SIZE]; + if (memcmp(allowance, (const uint8_t*)MAX_ALLOWANCE, 32) == 0) { + strlcpy(amount_text, "full LP balance", sizeof(amount_text)); } else { - for (ctr = 0; ctr < 32; ctr++) { - snprintf(&amtStr[ctr * 2], 3, "%02x", allowance[ctr]); - } - amt = amtStr; + bignum256 amount; + bn_from_bytes(allowance, 32, &amount); + if (bn_format(&amount, NULL, " LP", 18, 0, false, amount_text, + sizeof(amount_text)) == 0 || + calc_str_line(get_body_font(), amount_text, BODY_WIDTH) > BODY_ROWS) + return false; } - const char *appStr = "uniswap approve liquidity"; - confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, appStr, "Amount: %s", - amt); - confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, appStr, - "approve for pool %s %s", tikstr, poolstr); - return true; + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Uniswap LP Approval", "%s", amount_text)) + return false; + + char pair_text[43] = {'0', 'x', '\0'}; + for (size_t i = 0; i < 20; i++) { + snprintf(pair_text + 2 + i * 2, 3, "%02x", msg->to.bytes[i]); + } + return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Uniswap LP Pool", "%s\n%s", token->ticker, pair_text); } -bool zx_isZxApproveLiquid(const EthereumSignTx *msg) { - if (memcmp(msg->data_initial_chunk.bytes, "\x09\x5e\xa7\xb3", 4) == 0) - if (memcmp((uint8_t *)(msg->data_initial_chunk.bytes + 4 + 32 - 20), - UNISWAP_ROUTER_ADDRESS, 20) == 0) - return true; - return false; +bool zx_isZxApproveLiquid(const EthereumSignTx* msg) { + return approve_shape_is_clear_signable(msg); } diff --git a/lib/firmware/ethereum_contracts/zxliquidtx.c b/lib/firmware/ethereum_contracts/zxliquidtx.c index e70ccd4e3..568080722 100644 --- a/lib/firmware/ethereum_contracts/zxliquidtx.c +++ b/lib/firmware/ethereum_contracts/zxliquidtx.c @@ -20,164 +20,200 @@ #include "keepkey/firmware/ethereum_contracts/zxliquidtx.h" #include "keepkey/board/confirm_sm.h" -#include "keepkey/board/util.h" -#include "keepkey/firmware/app_confirm.h" -#include "keepkey/firmware/coins.h" +#include "keepkey/board/font.h" +#include "keepkey/board/layout.h" #include "keepkey/firmware/ethereum.h" #include "keepkey/firmware/ethereum_tokens.h" -#include "keepkey/firmware/fsm.h" #include "keepkey/firmware/storage.h" #include "trezor/crypto/address.h" +#include "trezor/crypto/bignum.h" #include "trezor/crypto/bip32.h" #include "trezor/crypto/curves.h" #include "trezor/crypto/memzero.h" -#include "trezor/crypto/sha3.h" -#include +#include +#include -static HDNode* zx_getDerivedNode(const char* curve, const uint32_t* address_n, - size_t address_n_count, - uint32_t* fingerprint) { - static HDNode CONFIDENTIAL node; - if (fingerprint) { - *fingerprint = 0; - } +#define UNISWAP_LIQUIDITY_CALL_SIZE (4 + 6 * 32) +#define UNISWAP_TOKEN_WORD 0 +#define UNISWAP_PRIMARY_AMOUNT_WORD 1 +#define UNISWAP_TOKEN_MIN_WORD 2 +#define UNISWAP_NATIVE_MIN_WORD 3 +#define UNISWAP_RECIPIENT_WORD 4 +#define UNISWAP_DEADLINE_WORD 5 +#define UNISWAP_AMOUNT_TEXT_SIZE 96 - if (!get_curve_by_name(curve)) { - return 0; - } +static const uint8_t* abi_word(const EthereumSignTx* msg, size_t word) { + return msg->data_initial_chunk.bytes + 4 + word * 32; +} - if (!storage_getRootNode(curve, true, &node)) { - return 0; +static bool abi_address_is_canonical(const uint8_t* word) { + for (size_t i = 0; i < 12; i++) { + if (word[i] != 0) return false; } + return true; +} - if (!address_n || address_n_count == 0) { - return &node; +static bool uint256_fits_u64(const uint8_t* word) { + for (size_t i = 0; i < 24; i++) { + if (word[i] != 0) return false; } + return true; +} - if (hdnode_private_ckd_cached(&node, address_n, address_n_count, - fingerprint) == 0) { - return 0; +static bool tx_value_is_zero(const EthereumSignTx* msg) { + if (!msg->has_value && msg->value.size != 0) return false; + for (size_t i = 0; i < msg->value.size; i++) { + if (msg->value.bytes[i] != 0) return false; } - - return &node; + return true; } static bool isAddLiquidityEthCall(const EthereumSignTx* msg) { - if (memcmp(msg->data_initial_chunk.bytes, "\xf3\x05\xd7\x19", 4) == 0) - return true; - - return false; + return memcmp(msg->data_initial_chunk.bytes, "\xf3\x05\xd7\x19", 4) == 0; } static bool isRemoveLiquidityEthCall(const EthereumSignTx* msg) { - if (memcmp(msg->data_initial_chunk.bytes, "\x02\x75\x1c\xec", 4) == 0) - return true; + return memcmp(msg->data_initial_chunk.bytes, "\x02\x75\x1c\xec", 4) == 0; +} - return false; +static const TokenType* liquidity_token(const EthereumSignTx* msg) { + const uint8_t* token_address = abi_word(msg, UNISWAP_TOKEN_WORD) + 12; + const TokenType* token = tokenByChainAddress(1, token_address); + return token == UnknownToken ? NULL : token; } -static bool confirmFromAccountMatch(const EthereumSignTx* msg, - const char* addremStr) { - // Determine withdrawal address - char addressStr[43] = {'0', 'x', '\0'}; - const char* fromSrc; - const uint8_t* fromAddress; - uint8_t addressBytes[20]; +static bool liquidity_shape_is_clear_signable(const EthereumSignTx* msg) { + if (!msg->has_chain_id || msg->chain_id != 1 || !msg->has_to || + msg->to.size != 20 || + memcmp(msg->to.bytes, UNISWAP_ROUTER_ADDRESS, 20) != 0 || + !msg->has_data_initial_chunk || + msg->data_initial_chunk.size != UNISWAP_LIQUIDITY_CALL_SIZE || + msg->value.size > 32 || (!msg->has_value && msg->value.size != 0)) + return false; - HDNode* node = zx_getDerivedNode(SECP256K1_NAME, msg->address_n, - msg->address_n_count, NULL); - if (!node) return false; + if (!isAddLiquidityEthCall(msg) && !isRemoveLiquidityEthCall(msg)) + return false; + if (!abi_address_is_canonical(abi_word(msg, UNISWAP_TOKEN_WORD)) || + !abi_address_is_canonical(abi_word(msg, UNISWAP_RECIPIENT_WORD)) || + !uint256_fits_u64(abi_word(msg, UNISWAP_DEADLINE_WORD))) + return false; + if (liquidity_token(msg) == NULL) return false; + if (isRemoveLiquidityEthCall(msg) && !tx_value_is_zero(msg)) return false; + return true; +} - if (!hdnode_get_ethereum_pubkeyhash(node, addressBytes)) { - memzero(node, sizeof(*node)); +static bool format_amount(const bignum256* amount, const char* suffix, + unsigned int decimals, char* out, size_t out_len) { + if (bn_format(amount, NULL, suffix, decimals, 0, false, out, out_len) == 0) + return false; + return calc_str_line(get_body_font(), out, BODY_WIDTH) <= BODY_ROWS; +} + +bool zx_formatZxLiquidityPrimaryAmount(const EthereumSignTx* msg, char* out, + size_t out_len) { + if (!out || out_len == 0 || !liquidity_shape_is_clear_signable(msg)) + return false; + + bignum256 amount; + bn_from_bytes(abi_word(msg, UNISWAP_PRIMARY_AMOUNT_WORD), 32, &amount); + if (isAddLiquidityEthCall(msg)) { + const TokenType* token = liquidity_token(msg); + return format_amount(&amount, token->ticker, token->decimals, out, out_len); } + return format_amount(&amount, " LP", 18, out, out_len); +} - fromAddress = - (const uint8_t*)(msg->data_initial_chunk.bytes + 4 + 5 * 32 - 20); +static HDNode* zx_getDerivedNode(const char* curve, const uint32_t* address_n, + size_t address_n_count, + uint32_t* fingerprint) { + static HDNode CONFIDENTIAL node; + if (fingerprint) *fingerprint = 0; + if (!get_curve_by_name(curve)) return NULL; + if (!storage_getRootNode(curve, true, &node)) return NULL; + if (!address_n || address_n_count == 0) return &node; + if (hdnode_private_ckd_cached(&node, address_n, address_n_count, + fingerprint) == 0) + return NULL; + return &node; +} + +static bool confirmFromAccountMatch(const EthereumSignTx* msg) { + char address_str[43] = {'0', 'x', '\0'}; + uint8_t address_bytes[20]; - if (memcmp(fromAddress, addressBytes, 20) == 0) { - fromSrc = "self"; - } else { - fromSrc = "NOT this wallet"; + HDNode* node = zx_getDerivedNode(SECP256K1_NAME, msg->address_n, + msg->address_n_count, NULL); + if (!node) return false; + if (!hdnode_get_ethereum_pubkeyhash(node, address_bytes)) { + memzero(node, sizeof(*node)); + return false; } + memzero(node, sizeof(*node)); - for (uint32_t ctr = 0; ctr < 20; ctr++) { - snprintf(&addressStr[2 + ctr * 2], 3, "%02x", fromAddress[ctr]); + const uint8_t* recipient = abi_word(msg, UNISWAP_RECIPIENT_WORD) + 12; + bool is_self = memcmp(recipient, address_bytes, 20) == 0; + for (uint32_t i = 0; i < 20; i++) { + snprintf(&address_str[2 + i * 2], 3, "%02x", recipient[i]); } - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, addremStr, - "Confirming ETH address is %s: %s", fromSrc, addressStr)) { + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Uniswap Recipient", "%s\n%s", + is_self ? "this wallet" : "NOT this wallet", address_str)) return false; - } - return true; + return is_self; } bool zx_isZxLiquidTx(const EthereumSignTx* msg) { - if (memcmp(msg->to.bytes, UNISWAP_ROUTER_ADDRESS, 20) == - 0) { // correct contract address? - - if (isAddLiquidityEthCall(msg)) return true; - - if (isRemoveLiquidityEthCall(msg)) return true; - } - return false; + return liquidity_shape_is_clear_signable(msg); } bool zx_confirmZxLiquidTx(uint32_t data_total, const EthereumSignTx* msg) { - (void)data_total; - const TokenType* token; - char constr1[40], constr2[40], tokbuf[32]; - const char* arStr = ""; - const uint8_t *tokenAddress, *deadlineBytes; - bignum256 Amount; - uint64_t deadline; + if (data_total != UNISWAP_LIQUIDITY_CALL_SIZE || + !liquidity_shape_is_clear_signable(msg)) + return false; - if (isAddLiquidityEthCall(msg)) { - arStr = "uniswap add liquidity"; - } else if (isRemoveLiquidityEthCall(msg)) { - arStr = "uniswap remove liquidity"; - } else { + const TokenType* token = liquidity_token(msg); + bignum256 amount; + char amount_text[UNISWAP_AMOUNT_TEXT_SIZE]; + + if (!zx_formatZxLiquidityPrimaryAmount(msg, amount_text, + sizeof(amount_text)) || + !confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + isAddLiquidityEthCall(msg) ? "Uniswap Token" : "Uniswap LP Burn", + "%s", amount_text)) return false; - } - tokenAddress = (const uint8_t*)(msg->data_initial_chunk.bytes + 4 + 32 - 20); - token = tokenByChainAddress(msg->chain_id, tokenAddress); - deadlineBytes = - (const uint8_t*)(msg->data_initial_chunk.bytes + 4 + 6 * 32 - 8); - deadline = ((uint64_t)deadlineBytes[0] << 8 * 7) | - ((uint64_t)deadlineBytes[1] << 8 * 6) | - ((uint64_t)deadlineBytes[2] << 8 * 5) | - ((uint64_t)deadlineBytes[3] << 8 * 4) | - ((uint64_t)deadlineBytes[4] << 8 * 3) | - ((uint64_t)deadlineBytes[5] << 8 * 2) | - ((uint64_t)deadlineBytes[6] << 8 * 1) | - ((uint64_t)deadlineBytes[7]); - - bn_from_bytes(msg->data_initial_chunk.bytes + 4 + 32, 32, - &Amount); // token amount - ethereumFormatAmount(&Amount, token, msg->chain_id, tokbuf, sizeof(tokbuf)); - snprintf(constr1, 32, "%s", tokbuf); - bn_from_bytes(msg->data_initial_chunk.bytes + 4 + 2 * 32, 32, - &Amount); // token min amount - ethereumFormatAmount(&Amount, token, msg->chain_id, tokbuf, sizeof(tokbuf)); - snprintf(constr2, 32, "%s", tokbuf); - confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, arStr, - "%s\nMinimum %s", constr1, constr2); - if (!confirmFromAccountMatch(msg, arStr)) { + bn_from_bytes(abi_word(msg, UNISWAP_TOKEN_MIN_WORD), 32, &amount); + if (!format_amount(&amount, token->ticker, token->decimals, amount_text, + sizeof(amount_text)) || + !confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Uniswap Token Min", "%s", amount_text)) return false; - } - bn_from_bytes(msg->data_initial_chunk.bytes + 4 + 3 * 32, 32, - &Amount); // eth min amount - ethereumFormatAmount(&Amount, NULL, msg->chain_id, tokbuf, sizeof(tokbuf)); + if (!confirmFromAccountMatch(msg)) return false; - snprintf(constr1, 32, "%s", tokbuf); - confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, arStr, "Minimum %s", - constr1); + if (isAddLiquidityEthCall(msg)) { + bn_from_bytes(msg->value.bytes, msg->value.size, &amount); + if (!format_amount(&amount, " ETH", 18, amount_text, sizeof(amount_text)) || + !confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "Uniswap ETH", + "%s", amount_text)) + return false; + } - confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, arStr, "Deadline %s", - ctime((const time_t*)&deadline)); + bn_from_bytes(abi_word(msg, UNISWAP_NATIVE_MIN_WORD), 32, &amount); + if (!format_amount(&amount, " ETH", 18, amount_text, sizeof(amount_text)) || + !confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "Uniswap ETH Min", + "%s", amount_text)) + return false; - return true; + const uint8_t* deadline_word = abi_word(msg, UNISWAP_DEADLINE_WORD); + uint64_t deadline = 0; + for (size_t i = 24; i < 32; i++) { + deadline = (deadline << 8) | deadline_word[i]; + } + char deadline_text[21]; + snprintf(deadline_text, sizeof(deadline_text), "%" PRIu64, deadline); + return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Uniswap Deadline", "%s", deadline_text); } diff --git a/lib/firmware/ethereum_contracts/zxswap.c b/lib/firmware/ethereum_contracts/zxswap.c index 5d033e804..15dccb699 100644 --- a/lib/firmware/ethereum_contracts/zxswap.c +++ b/lib/firmware/ethereum_contracts/zxswap.c @@ -44,7 +44,22 @@ bool zx_isZxSwap(const EthereumSignTx* msg) { } bool zx_confirmZxSwap(uint32_t data_total, const EthereumSignTx* msg) { - (void)data_total; + /* fixed reads run through the fromAddress word at offset 4 + 5*32 + 12 .. +20 + * (== 4 + 6*32); the toAddress word is bounds-checked below once its + * position is known from numOfTokens. */ + if (data_total < 4 + 6 * 32) return false; + + /* The first head word is the ABI offset pointer to the dynamic `tokens[]` + * array. We read numOfTokens / tokens[] at FIXED offsets that are only + * correct when this pointer is canonical (0x80 = 4 head words). If it is + * not, the Solidity decoder follows it elsewhere, so what we display would + * differ from what executes (a drain via display/execution mismatch). Reject + * the non-canonical encoding -> falls through to the blind-sign path. */ + static const uint8_t TOKENS_OFFSET_CANON[32] = {[31] = 0x80}; + if (memcmp(msg->data_initial_chunk.bytes + 4, TOKENS_OFFSET_CANON, 32) != 0) { + return false; + } + const TokenType *from, *to; const uint8_t *fromAddress, *toAddress; char constr1[40], constr2[40]; @@ -71,6 +86,9 @@ bool zx_confirmZxSwap(uint32_t data_total, const EthereumSignTx* msg) { break; } + /* toAddress word ends at offset 4 + (6 + adder + 1) * 32 */ + if (data_total < 4 + (7 + adder) * 32) return false; + fromAddress = (const uint8_t*)(msg->data_initial_chunk.bytes + 4 + 5 * 32 + 12); toAddress = (const uint8_t*)(msg->data_initial_chunk.bytes + 4 + diff --git a/lib/firmware/ethereum_contracts/zxtransERC20.c b/lib/firmware/ethereum_contracts/zxtransERC20.c index 75f64c160..83074443e 100644 --- a/lib/firmware/ethereum_contracts/zxtransERC20.c +++ b/lib/firmware/ethereum_contracts/zxtransERC20.c @@ -45,6 +45,10 @@ bool zx_isZxTransformERC20(const EthereumSignTx* msg) { bool zx_confirmZxTransERC20(uint32_t data_total, const EthereumSignTx* msg) { (void)data_total; + /* Reads selector + 4 static head words (in/out token, in/out amount). This + * handler is allowed at any data_total (large transformations[] tail), so + * guard the read extent against the RECEIVED chunk, not the total length. */ + if (msg->data_initial_chunk.size < 4 + 4 * 32) return false; const TokenType *in, *out; const uint8_t *inAddress, *outAddress; char constr1[40], constr2[40]; diff --git a/lib/firmware/ethereum_tokens.c b/lib/firmware/ethereum_tokens.c index 15e5f0678..dd7f57f60 100644 --- a/lib/firmware/ethereum_tokens.c +++ b/lib/firmware/ethereum_tokens.c @@ -42,7 +42,8 @@ const TokenType* tokenIter(int32_t* ctr) { return &(tokens[*ctr - 1]); } -const TokenType* tokenByChainAddress(uint8_t chain_id, const uint8_t* address) { +const TokenType* tokenByChainAddress(uint32_t chain_id, + const uint8_t* address) { if (!address) return 0; for (int i = 0; i < TOKENS_COUNT; i++) { if (chain_id == tokens[i].chain_id && @@ -57,7 +58,7 @@ const TokenType* tokenByChainAddress(uint8_t chain_id, const uint8_t* address) { return UnknownToken; } -bool tokenByTicker(uint8_t chain_id, const char* ticker, +bool tokenByTicker(uint32_t chain_id, const char* ticker, const TokenType** token) { *token = NULL; diff --git a/lib/firmware/fsm.c b/lib/firmware/fsm.c index d9d8f4a1f..b62431b53 100644 --- a/lib/firmware/fsm.c +++ b/lib/firmware/fsm.c @@ -35,6 +35,7 @@ #include "keepkey/firmware/app_confirm.h" #include "keepkey/firmware/app_layout.h" #include "keepkey/firmware/authenticator.h" +#include "keepkey/firmware/bip85.h" #include "keepkey/firmware/coins.h" #include "keepkey/firmware/cosmos.h" #include "keepkey/firmware/binance.h" @@ -55,7 +56,10 @@ #include "keepkey/firmware/ripple.h" #include "keepkey/firmware/signing.h" #include "keepkey/firmware/signtx_tendermint.h" +#include "keepkey/firmware/signed_metadata.h" #include "keepkey/firmware/solana.h" +#include "keepkey/firmware/zcash.h" +#include "keepkey/firmware/hive.h" #include "keepkey/firmware/storage.h" #include "keepkey/firmware/tendermint.h" #include "keepkey/firmware/thorchain.h" @@ -90,6 +94,8 @@ #include "messages-tron.pb.h" #include "messages-ton.pb.h" #include "messages-solana.pb.h" +#include "messages-zcash.pb.h" +#include "messages-hive.pb.h" #include @@ -111,6 +117,15 @@ static uint8_t msg_resp[MAX_FRAME_SIZE] __attribute__((aligned(4))); return; \ } +#define CHECK_NOT_BTC_ONLY_LOCKED \ + if (storage_isBitcoinOnlyLocked()) { \ + fsm_sendFailure(FailureType_Failure_Other, \ + "Device holds a bitcoin-only wallet. Wipe the " \ + "device to use multi-chain firmware."); \ + layoutHome(); \ + return; \ + } + #define CHECK_PIN \ if (!pin_protect_cached()) { \ layoutHome(); \ @@ -272,16 +287,21 @@ void fsm_sendFailure(FailureType code, const char* text) { void fsm_msgClearSession(ClearSession* msg) { (void)msg; + zcash_signing_abort(); session_clear(/*clear_pin=*/true); fsm_sendSuccess("Session cleared"); } +// Always-on handlers: Bitcoin/common (fsm_msg_coin), CipherKeyValue/identity +// (fsm_msg_crypto), debug-link, and BIP85 -- none are coin engines. #include "fsm_msg_common.h" #include "fsm_msg_coin.h" -#include "fsm_msg_ethereum.h" -#include "fsm_msg_nano.h" #include "fsm_msg_crypto.h" #include "fsm_msg_debug.h" +#include "fsm_msg_bip85.h" +#if !BITCOIN_ONLY +#include "fsm_msg_ethereum.h" +#include "fsm_msg_nano.h" #include "fsm_msg_eos.h" #include "fsm_msg_cosmos.h" #include "fsm_msg_osmosis.h" @@ -293,3 +313,23 @@ void fsm_msgClearSession(ClearSession* msg) { #include "fsm_msg_tron.h" #include "fsm_msg_ton.h" #include "fsm_msg_solana.h" +#include "fsm_msg_hive.h" +#else +// Bitcoin-only: the coin engines above are compiled out, but the always-on +// Initialize/ClearSession/Cancel handlers still call their *_abort() hooks, +// and factory-reset calls signed_metadata_clear_signers() (EVM clearsign). +// With no state to reset, no-ops are correct. +void ethereum_signing_abort(void) {} +void tendermint_signAbort(void) {} +void eos_signingAbort(void) {} +void signed_metadata_clear_signers(void) {} +#endif // !BITCOIN_ONLY +#if ZCASH_PRIVACY +#include "fsm_msg_zcash.h" +#else +// Zcash shielded/Orchard engine compiled out. The always-on +// Initialize/ClearSession/Cancel handlers still call zcash_signing_abort(); +// with no privacy state to reset, a no-op is correct. (Bitcoin-only forces +// privacy off, so this stub also covers the bitcoin-only image.) +void zcash_signing_abort(void) {} +#endif diff --git a/lib/firmware/fsm_msg_binance.h b/lib/firmware/fsm_msg_binance.h index 0adf00c62..72f75b2e5 100644 --- a/lib/firmware/fsm_msg_binance.h +++ b/lib/firmware/fsm_msg_binance.h @@ -95,30 +95,38 @@ static void binance_response(void); void fsm_msgBinanceTransferMsg(const BinanceTransferMsg* msg) { CHECK_PARAM(binance_signingIsInited(), "Signing not in progress?"); - CHECK_PARAM(msg->inputs_count == 1, "Malformed BinanceTransferMsg") - CHECK_PARAM(msg->inputs[0].coins_count == 1, "Malformed BinanceTransferMsg") - CHECK_PARAM(msg->outputs_count == 1, "Malformed BinanceTransferMsg") - CHECK_PARAM(msg->outputs[0].coins_count == 1, "Malformed BinanceTransferMsg") - CHECK_PARAM(msg->inputs[0].coins[0].amount == msg->outputs[0].coins[0].amount, - "Malformed BinanceTransferMsg") - CHECK_PARAM(strcmp(msg->inputs[0].coins[0].denom, - msg->outputs[0].coins[0].denom) == 0, - "Malformed BinanceTransferMsg") + if (!binance_validateTransfer(msg)) { + binance_signAbort(); + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Malformed BinanceTransferMsg"); + layoutHome(); + return; + } const CoinType* coin = fsm_getCoin(true, "Binance"); if (!coin) { + binance_signAbort(); + layoutHome(); return; } switch (msg->outputs[0].address_type) { case OutputAddressType_TRANSFER: default: { - char amount_str[42]; - char denom_str[14]; - snprintf(denom_str, strlen(msg->outputs[0].coins[0].denom) + 2, " %s", - msg->outputs[0].coins[0].denom); - bn_format_uint64(msg->outputs[0].coins[0].amount, NULL, denom_str, 8, 0, - false, amount_str, sizeof(amount_str)); + char amount_str[64]; + char denom_str[BINANCE_MAX_DENOM_LEN + 2]; + const int denom_len = snprintf(denom_str, sizeof(denom_str), " %s", + msg->outputs[0].coins[0].denom); + if (denom_len <= 0 || (size_t)denom_len >= sizeof(denom_str) || + !bn_format_uint64((uint64_t)msg->outputs[0].coins[0].amount, NULL, + denom_str, 8, 0, false, amount_str, + sizeof(amount_str))) { + binance_signAbort(); + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Invalid Binance transfer amount"); + layoutHome(); + return; + } if (!confirm_transaction_output( ButtonRequestType_ButtonRequest_ConfirmOutput, amount_str, msg->outputs[0].address)) { @@ -151,13 +159,16 @@ static void binance_response(void) { const CoinType* coin = fsm_getCoin(true, "Binance"); if (!coin) { + binance_signAbort(); + layoutHome(); return; } const BinanceSignTx* sign_tx = binance_getBinanceSignTx(); - if (sign_tx->has_memo && !confirm(ButtonRequestType_ButtonRequest_ConfirmMemo, - _("Memo"), "%s", sign_tx->memo)) { + if (sign_tx->has_memo && + !confirm_bytes(ButtonRequestType_ButtonRequest_ConfirmMemo, _("Memo"), + (const uint8_t*)sign_tx->memo, strlen(sign_tx->memo))) { binance_signAbort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); diff --git a/lib/firmware/fsm_msg_bip85.h b/lib/firmware/fsm_msg_bip85.h new file mode 100644 index 000000000..48b343303 --- /dev/null +++ b/lib/firmware/fsm_msg_bip85.h @@ -0,0 +1,142 @@ +void fsm_msgGetBip85Mnemonic(const GetBip85Mnemonic *msg) { + CHECK_INITIALIZED + + /* Validate word count (required field, always present in nanopb) */ + if (msg->word_count != 12 && msg->word_count != 18 && msg->word_count != 24) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + "word_count must be 12, 18, or 24"); + layoutHome(); + return; + } + + /* Reject index >= 0x80000000 (hardened-bit collision) */ + if (msg->index & 0x80000000) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + "index must be less than 2147483648"); + layoutHome(); + return; + } + + CHECK_PIN + + /* User confirmation */ + char desc[80]; + snprintf(desc, sizeof(desc), "Derive %lu-word child seed at index %lu?", + (unsigned long)msg->word_count, (unsigned long)msg->index); + + if (!confirm(ButtonRequestType_ButtonRequest_Other, "BIP-85 Derive Seed", + "%s", desc)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + "BIP-85 derivation cancelled"); + layoutHome(); + return; + } + + layout_simple_message("Deriving child seed..."); + + /* Derive the mnemonic */ + static CONFIDENTIAL char mnemonic_buf[241]; + if (!bip85_derive_mnemonic(msg->word_count, msg->index, mnemonic_buf, + sizeof(mnemonic_buf))) { + memzero(mnemonic_buf, sizeof(mnemonic_buf)); + fsm_sendFailure(FailureType_Failure_Other, "BIP-85 derivation failed"); + layoutHome(); + return; + } + + /* + * Display mnemonic on device screen only — never send over USB. + * Uses the same paginated display as the backup flow in reset.c. + */ + uint32_t word_count = 0, page_count = 0; + + /* Display scratch shared with the backup flow — see reset.h. Zero the whole + * set at entry per the sharing contract (a prior user may have aborted). */ + memzero(mnemonic_scratch_tokened, sizeof(mnemonic_scratch_tokened)); + memzero(mnemonic_scratch_formatted, sizeof(mnemonic_scratch_formatted)); + memzero(mnemonic_scratch_display, sizeof(mnemonic_scratch_display)); + memzero(mnemonic_scratch_word, sizeof(mnemonic_scratch_word)); + + strlcpy(mnemonic_scratch_tokened, mnemonic_buf, TOKENED_MNEMONIC_BUF); + memzero(mnemonic_buf, sizeof(mnemonic_buf)); + + const char *tok = strtok(mnemonic_scratch_tokened, " "); + + while (tok) { + snprintf(mnemonic_scratch_word, MAX_WORD_LEN + ADDITIONAL_WORD_PAD, + (word_count & 1) ? "%lu.%s\n" : "%lu.%s", + (unsigned long)(word_count + 1), tok); + + /* Check that we have enough room on display to show word */ + snprintf(mnemonic_scratch_display, FORMATTED_MNEMONIC_BUF, "%s %s", + mnemonic_scratch_formatted[page_count], mnemonic_scratch_word); + + if (calc_str_line(get_body_font(), mnemonic_scratch_display, BODY_WIDTH) > + 3) { + page_count++; + + if (MAX_PAGES <= page_count) { + memzero(mnemonic_scratch_tokened, sizeof(mnemonic_scratch_tokened)); + memzero(mnemonic_scratch_formatted, sizeof(mnemonic_scratch_formatted)); + memzero(mnemonic_scratch_display, sizeof(mnemonic_scratch_display)); + memzero(mnemonic_scratch_word, sizeof(mnemonic_scratch_word)); + fsm_sendFailure(FailureType_Failure_Other, + "Too many pages of mnemonic words"); + layoutHome(); + return; + } + + snprintf(mnemonic_scratch_display, FORMATTED_MNEMONIC_BUF, "%s %s", + mnemonic_scratch_formatted[page_count], mnemonic_scratch_word); + } + + strlcpy(mnemonic_scratch_formatted[page_count], mnemonic_scratch_display, + FORMATTED_MNEMONIC_BUF); + + tok = strtok(NULL, " "); + word_count++; + } + + /* Switch from 0-indexing to 1-indexing */ + page_count++; + + display_constant_power(true); + + /* Show each page of the mnemonic on screen */ + for (uint32_t current_page = 0; current_page < page_count; current_page++) { + char title[MEDIUM_STR_BUF]; + + if (page_count > 1) { + snprintf(title, MEDIUM_STR_BUF, "BIP-85 Seed %" PRIu32 "/%" PRIu32, + current_page + 1, page_count); + } else { + snprintf(title, MEDIUM_STR_BUF, "BIP-85 Seed"); + } + + if (!confirm_constant_power(ButtonRequestType_ButtonRequest_ConfirmWord, + title, "%s", + mnemonic_scratch_formatted[current_page])) { + memzero(mnemonic_scratch_tokened, sizeof(mnemonic_scratch_tokened)); + memzero(mnemonic_scratch_formatted, sizeof(mnemonic_scratch_formatted)); + memzero(mnemonic_scratch_display, sizeof(mnemonic_scratch_display)); + memzero(mnemonic_scratch_word, sizeof(mnemonic_scratch_word)); + display_constant_power(false); + fsm_sendFailure(FailureType_Failure_ActionCancelled, + "BIP-85 display cancelled"); + layoutHome(); + return; + } + } + + display_constant_power(false); + + /* Wipe all sensitive buffers */ + memzero(mnemonic_scratch_tokened, sizeof(mnemonic_scratch_tokened)); + memzero(mnemonic_scratch_formatted, sizeof(mnemonic_scratch_formatted)); + memzero(mnemonic_scratch_display, sizeof(mnemonic_scratch_display)); + memzero(mnemonic_scratch_word, sizeof(mnemonic_scratch_word)); + + /* Send success — mnemonic is NOT sent over the wire */ + fsm_sendSuccess("BIP-85 seed displayed on device"); + layoutHome(); +} diff --git a/lib/firmware/fsm_msg_coin.h b/lib/firmware/fsm_msg_coin.h index 8b7267cd3..978c80712 100644 --- a/lib/firmware/fsm_msg_coin.h +++ b/lib/firmware/fsm_msg_coin.h @@ -270,8 +270,8 @@ void fsm_msgSignMessage(SignMessage* msg) { CHECK_INITIALIZED - if (!confirm(ButtonRequestType_ButtonRequest_SignMessage, "Sign Message", - "%s", (char*)msg->message.bytes)) { + if (!confirm_bytes(ButtonRequestType_ButtonRequest_SignMessage, + "Sign Message", msg->message.bytes, msg->message.size)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Sign message cancelled"); layoutHome(); @@ -325,8 +325,9 @@ void fsm_msgVerifyMessage(VerifyMessage* msg) { layoutHome(); return; } - if (!review(ButtonRequestType_ButtonRequest_Other, "Message Verified", "%s", - (char*)msg->message.bytes)) { + if (!confirm_bytes(ButtonRequestType_ButtonRequest_Other, + "Message Verified", msg->message.bytes, + msg->message.size)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Action cancelled by user")); layoutHome(); diff --git a/lib/firmware/fsm_msg_common.h b/lib/firmware/fsm_msg_common.h index 44173a24c..ed0363dc5 100644 --- a/lib/firmware/fsm_msg_common.h +++ b/lib/firmware/fsm_msg_common.h @@ -5,6 +5,7 @@ void fsm_msgInitialize(Initialize* msg) { ethereum_signing_abort(); tendermint_signAbort(); eos_signingAbort(); + zcash_signing_abort(); session_clear(false); // do not clear PIN layoutHome(); fsm_msgGetFeatures(0); @@ -42,8 +43,53 @@ void fsm_msgGetFeatures(GetFeatures* msg) { /* Variant Name */ resp->has_firmware_variant = true; - strlcpy(resp->firmware_variant, variant_getName(), - sizeof(resp->firmware_variant)); +#if BITCOIN_ONLY + /* Bitcoin-only build. Uses the established KeepKeyBTC / EmulatorBTC names so + existing clients (python-keepkey requires_fullFeature, etc.) skip + multi-chain-only behaviour and never offer multi-chain firmware. The lock + sentinel is reachable here too: a NEWER bitcoin-only wallet than this + firmware understands refuses to load (storage_isBitcoinOnlyLocked), and + hosts need the same signal the other builds emit. */ + if (storage_isBitcoinOnlyLocked()) { + strlcpy(resp->firmware_variant, "bitcoin-only-locked", + sizeof(resp->firmware_variant)); + } else { +#ifdef EMULATOR + strlcpy(resp->firmware_variant, "EmulatorBTC", + sizeof(resp->firmware_variant)); +#else + strlcpy(resp->firmware_variant, "KeepKeyBTC", + sizeof(resp->firmware_variant)); +#endif + } +#elif ZCASH_PRIVACY + /* Zcash/Orchard privacy build. Distinct variant name so hosts can gate + variant-partitioned features — the clearsign session icon cache is + compiled out of this build to fit SRAM (identities still work; persistent + identity icons still render from storage). */ + if (storage_isBitcoinOnlyLocked()) { + strlcpy(resp->firmware_variant, "bitcoin-only-locked", + sizeof(resp->firmware_variant)); + } else { +#ifdef EMULATOR + strlcpy(resp->firmware_variant, "EmulatorZcash", + sizeof(resp->firmware_variant)); +#else + strlcpy(resp->firmware_variant, "KeepKeyZcash", + sizeof(resp->firmware_variant)); +#endif + } +#else + if (storage_isBitcoinOnlyLocked()) { + /* Multi-chain firmware refusing to touch a bitcoin-only wallet; a wipe + is required before this device can be used. */ + strlcpy(resp->firmware_variant, "bitcoin-only-locked", + sizeof(resp->firmware_variant)); + } else { + strlcpy(resp->firmware_variant, variant_getName(), + sizeof(resp->firmware_variant)); + } +#endif /* Security settings */ resp->has_pin_protection = true; @@ -150,8 +196,10 @@ void fsm_msgGetCoinTable(GetCoinTable* msg) { for (size_t i = 0; i < msg->end - msg->start; i++) { if (msg->start + i < COINS_COUNT) { resp->table[i] = coins[msg->start + i]; +#if !BITCOIN_ONLY } else if (msg->start + i - COINS_COUNT < TOKENS_COUNT) { coinFromToken(&resp->table[i], &tokens[msg->start + i - COINS_COUNT]); +#endif } } } @@ -166,13 +214,14 @@ static bool isValidModelNumber(const char* model) { return false; } -void checkPassphrase(void) { +static bool checkPassphrase(void) { if (!passphrase_protect()) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "authenticator needs passphrase"); layoutHome(); - return; + return false; } + return true; } void fsm_msgPing(Ping* msg) { @@ -198,6 +247,8 @@ void fsm_msgPing(Ping* msg) { "Authenticator secret seed too large", "passphrase incorrect for authdata", "Auth secret unknown error", + "Authenticator account already exists", + "Authenticator action cancelled", }; typedef enum _AUTH_MSG_TYPE { @@ -238,7 +289,7 @@ void fsm_msgPing(Ping* msg) { 0}; // allow room for domain + ":" + account CHECK_PIN - checkPassphrase(); + if (!checkPassphrase()) return; switch (authMsg) { case INITAUTH: @@ -277,8 +328,7 @@ void fsm_msgPing(Ping* msg) { break; case WIPEADATA: - wipeAuthData(); - errcode = NOERR; + errcode = wipeAuthData(); resp->has_message = false; break; @@ -325,6 +375,7 @@ void fsm_msgPing(Ping* msg) { } void fsm_msgChangePin(ChangePin* msg) { + CHECK_NOT_BTC_ONLY_LOCKED bool removal = msg->has_remove && msg->remove; bool confirmed = false; @@ -375,6 +426,7 @@ void fsm_msgChangePin(ChangePin* msg) { } void fsm_msgChangeWipeCode(ChangeWipeCode* msg) { + CHECK_NOT_BTC_ONLY_LOCKED bool removal = msg->has_remove && msg->remove; bool confirmed = false; @@ -460,6 +512,9 @@ void fsm_msgWipeDevice(WipeDevice* msg) { storage_reset(); storage_resetUuid(); storage_commit(); + /* Factory reset drops runtime trust anchors too: loaded clearsign + * signers (and any metadata they verified) must not survive a wipe. */ + signed_metadata_clear_signers(); fsm_sendSuccess("Device wiped"); layoutHome(); @@ -500,6 +555,7 @@ void fsm_msgGetEntropy(GetEntropy* msg) { } void fsm_msgLoadDevice(LoadDevice* msg) { + CHECK_NOT_BTC_ONLY_LOCKED CHECK_NOT_INITIALIZED if (!confirm_load_device(msg->has_node)) { @@ -528,6 +584,7 @@ void fsm_msgLoadDevice(LoadDevice* msg) { } void fsm_msgResetDevice(ResetDevice* msg) { + CHECK_NOT_BTC_ONLY_LOCKED CHECK_NOT_INITIALIZED reset_init(msg->has_display_random && msg->display_random, @@ -557,10 +614,12 @@ void fsm_msgCancel(Cancel* msg) { ethereum_signing_abort(); tendermint_signAbort(); eos_signingAbort(); + zcash_signing_abort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, "Aborted"); } void fsm_msgApplySettings(ApplySettings* msg) { + CHECK_NOT_BTC_ONLY_LOCKED if (msg->has_label) { if (!confirm(ButtonRequestType_ButtonRequest_ChangeLabel, "Change Label", "Do you want to change the label to \"%s\"?", msg->label)) { @@ -651,6 +710,7 @@ void fsm_msgApplySettings(ApplySettings* msg) { } void fsm_msgRecoveryDevice(RecoveryDevice* msg) { + CHECK_NOT_BTC_ONLY_LOCKED if (msg->has_dry_run && msg->dry_run) { CHECK_INITIALIZED } else { @@ -681,6 +741,7 @@ void fsm_msgCharacterAck(CharacterAck* msg) { } void fsm_msgApplyPolicies(ApplyPolicies* msg) { + CHECK_NOT_BTC_ONLY_LOCKED CHECK_PARAM(msg->policy_count > 0, "No policies provided"); for (size_t i = 0; i < msg->policy_count; ++i) { diff --git a/lib/firmware/fsm_msg_cosmos.h b/lib/firmware/fsm_msg_cosmos.h index 082fe2eed..b7aff7560 100644 --- a/lib/firmware/fsm_msg_cosmos.h +++ b/lib/firmware/fsm_msg_cosmos.h @@ -92,7 +92,8 @@ void fsm_msgCosmosSignTx(const CosmosSignTx* msg) { RESP_INIT(CosmosMsgRequest); - if (!tendermint_signTxInit(node, (void*)msg, sizeof(CosmosSignTx), "uatom")) { + if (!tendermint_signTxInit(node, (void*)msg, sizeof(CosmosSignTx), "uatom", + TENDERMINT_SIGNING_COSMOS)) { tendermint_signAbort(); memzero(node, sizeof(*node)); fsm_sendFailure(FailureType_Failure_FirmwareError, @@ -108,7 +109,8 @@ void fsm_msgCosmosSignTx(const CosmosSignTx* msg) { void fsm_msgCosmosMsgAck(const CosmosMsgAck* msg) { // Confirm transaction basics - CHECK_PARAM(tendermint_signingIsInited(), "Signing not in progress"); + CHECK_PARAM(tendermint_signingIsInited(TENDERMINT_SIGNING_COSMOS), + "Cosmos signing not in progress"); const CoinType* coin = fsm_getCoin(true, "Cosmos"); if (!coin) { @@ -375,12 +377,13 @@ void fsm_msgCosmosMsgAck(const CosmosMsgAck* msg) { } } else if (msg->has_ibc_transfer) { /** Confirm required transaction parameters exist */ - if (!msg->ibc_transfer.has_sender || + if (!msg->ibc_transfer.has_receiver || !msg->ibc_transfer.has_sender || !msg->ibc_transfer.has_source_channel || !msg->ibc_transfer.has_source_port || !msg->ibc_transfer.has_revision_height || !msg->ibc_transfer.has_revision_number || - !msg->ibc_transfer.has_denom) { + !msg->ibc_transfer.has_denom || !msg->ibc_transfer.has_amount || + strcmp(msg->ibc_transfer.denom, "uatom") != 0) { tendermint_signAbort(); fsm_sendFailure(FailureType_Failure_FirmwareError, _("Message is missing required parameters")); @@ -393,7 +396,19 @@ void fsm_msgCosmosMsgAck(const CosmosMsgAck* msg) { amount_str, sizeof(amount_str)); if (!confirm(ButtonRequestType_ButtonRequest_Other, "IBC Transfer", - "Transfer %s to %s?", amount_str, msg->ibc_transfer.sender)) { + "Transfer %s via IBC?", amount_str)) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + if (!confirm_bytes(ButtonRequestType_ButtonRequest_Other, "IBC Sender", + (const uint8_t*)msg->ibc_transfer.sender, + strlen(msg->ibc_transfer.sender)) || + !confirm_bytes(ButtonRequestType_ButtonRequest_Other, "IBC Receiver", + (const uint8_t*)msg->ibc_transfer.receiver, + strlen(msg->ibc_transfer.receiver))) { tendermint_signAbort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); @@ -462,8 +477,8 @@ void fsm_msgCosmosMsgAck(const CosmosMsgAck* msg) { } if (sign_tx->has_memo && (strlen(sign_tx->memo) > 0)) { - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmMemo, _("Memo"), "%s", - sign_tx->memo)) { + if (!confirm_bytes(ButtonRequestType_ButtonRequest_ConfirmMemo, _("Memo"), + (const uint8_t*)sign_tx->memo, strlen(sign_tx->memo))) { tendermint_signAbort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); @@ -509,4 +524,4 @@ void fsm_msgCosmosMsgAck(const CosmosMsgAck* msg) { tendermint_signAbort(); layoutHome(); msg_write(MessageType_MessageType_CosmosSignedTx, resp); -} \ No newline at end of file +} diff --git a/lib/firmware/fsm_msg_crypto.h b/lib/firmware/fsm_msg_crypto.h index 838b6bd05..309ac487a 100644 --- a/lib/firmware/fsm_msg_crypto.h +++ b/lib/firmware/fsm_msg_crypto.h @@ -63,9 +63,31 @@ void fsm_msgSignIdentity(SignIdentity* msg) { CHECK_INITIALIZED - if (!confirm_sign_identity(&(msg->identity), msg->has_challenge_visual - ? msg->challenge_visual - : 0)) { + CHECK_PARAM(msg->has_identity, "Invalid identity"); + + const bool sign_ssh = + msg->identity.has_proto && strcmp(msg->identity.proto, "ssh") == 0; + const bool sign_gpg = + msg->identity.has_proto && strcmp(msg->identity.proto, "gpg") == 0; + + /* SSH/GPG sign only challenge_hidden. The legacy confirmation displayed + * challenge_visual instead, allowing a host to show benign text while the + * device signed unrelated bytes. Generic identity signatures bind both + * challenges, so review both there; SSH/GPG review only the actual signed + * payload and never present the unsigned visual field as authoritative. */ + if (!confirm_sign_identity(&msg->identity, NULL) || + ((!sign_ssh && !sign_gpg) && + !confirm_bytes( + ButtonRequestType_ButtonRequest_SignIdentity, "Visual Challenge", + (const uint8_t*)msg->challenge_visual, + msg->has_challenge_visual ? strlen(msg->challenge_visual) : 0)) || + !confirm_bytes( + ButtonRequestType_ButtonRequest_SignIdentity, + sign_ssh ? "Signed SSH Challenge" + : sign_gpg ? "Signed GPG Digest" + : "Hidden Challenge", + msg->challenge_hidden.bytes, + msg->has_challenge_hidden ? msg->challenge_hidden.size : 0)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Sign identity cancelled"); layoutHome(); @@ -75,8 +97,7 @@ void fsm_msgSignIdentity(SignIdentity* msg) { CHECK_PIN uint8_t hash[32]; - if (!msg->has_identity || - cryptoIdentityFingerprint(&(msg->identity), hash) == 0) { + if (cryptoIdentityFingerprint(&(msg->identity), hash) == 0) { fsm_sendFailure(FailureType_Failure_Other, "Invalid identity"); layoutHome(); return; @@ -102,11 +123,6 @@ void fsm_msgSignIdentity(SignIdentity* msg) { return; } - bool sign_ssh = - msg->identity.has_proto && (strcmp(msg->identity.proto, "ssh") == 0); - bool sign_gpg = - msg->identity.has_proto && (strcmp(msg->identity.proto, "gpg") == 0); - int result = 0; layout_simple_message("Signing Identity..."); diff --git a/lib/firmware/fsm_msg_ethereum.h b/lib/firmware/fsm_msg_ethereum.h index 5c9827164..643d652db 100644 --- a/lib/firmware/fsm_msg_ethereum.h +++ b/lib/firmware/fsm_msg_ethereum.h @@ -19,6 +19,134 @@ * along with this library. If not, see . */ +#include "keepkey/firmware/signed_metadata.h" + +void fsm_msgEthereumTxMetadata(const EthereumTxMetadata* msg) { + CHECK_INITIALIZED + CHECK_PIN + + /* Metadata must arrive before signing starts. signed_metadata_process() + * clears the binding on entry, so accepting metadata mid-signing would + * drop the tx<->metadata binding without aborting: a host could approve a + * benign decode (suppressing the blind-sign gate), then inject metadata to + * clear the binding and stream attacker-chosen calldata for the rest. + * Refuse and abort any in-progress signing session. */ + if (ethereum_signing_isInProgress()) { + ethereum_signing_abort(); + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + _("Metadata not allowed during signing")); + layoutHome(); + return; + } + + RESP_INIT(EthereumMetadataAck); + + MetadataClassification result = signed_metadata_process( + msg->signed_payload.bytes, msg->signed_payload.size, + msg->has_key_id ? msg->key_id : 0); + + resp->classification = (uint32_t)result; + resp->has_display_summary = true; + + switch (result) { + case METADATA_VERIFIED: + strlcpy(resp->display_summary, "Verified", sizeof(resp->display_summary)); + break; + case METADATA_OPAQUE: + strlcpy(resp->display_summary, "Unverified", + sizeof(resp->display_summary)); + break; + case METADATA_MALFORMED: + default: + strlcpy(resp->display_summary, "Invalid", sizeof(resp->display_summary)); + break; + } + + msg_write(MessageType_MessageType_EthereumMetadataAck, resp); +} + +void fsm_msgLoadClearsignSigner(const LoadClearsignSigner* msg) { + CHECK_INITIALIZED + CHECK_PIN + + CHECK_PARAM(msg->has_key_id && msg->has_pubkey && msg->has_alias, + _("key_id, pubkey and alias required")); + /* Range-check as uint32 BEFORE narrowing: (uint8_t)256 would alias slot 0 */ + CHECK_PARAM(msg->key_id < METADATA_MAX_KEYS, _("key_id out of range")); + CHECK_PARAM( + signed_metadata_signer_valid((uint8_t)msg->key_id, msg->pubkey.bytes, + msg->pubkey.size, msg->alias), + _("Invalid clearsign signer")); + + /* Optional identity icon (1bpp mono RLE). The proto caps icon at 384 bytes; + * bound the dims too so the render path never scans a bogus geometry. An icon + * with zero/oversized dims is rejected rather than silently dropped so a + * malformed upload is visible, not a mystery text-only identity. */ + const uint8_t* icon = NULL; + uint16_t icon_len = 0; + uint8_t icon_w = 0, icon_h = 0; + if (msg->has_icon && msg->icon.size > 0) { + CHECK_PARAM(msg->icon.size <= METADATA_ICON_MAX, _("icon too large")); + /* Width is capped at the confirm screen's icon column + * (LEFT_MARGIN_WITH_ICON = 40), NOT at the 64px height. Title/body text + * begins at x=40 and the icon is drawn AFTER the text, so a wider + * host-supplied icon would paint over the alias, fingerprint and the + * "NOT verified by KeepKey" warning — on the very screen that exists to + * carry that warning. This is the trust boundary for icons arriving on the + * wire; icons READ BACK from flash are re-checked independently in + * signed_metadata_signer_icon(), since a record persisted by older firmware + * never passes through here again after a reboot. */ + CHECK_PARAM(msg->has_icon_width && msg->has_icon_height && + msg->icon_width > 0 && + msg->icon_width <= LEFT_MARGIN_WITH_ICON && + msg->icon_height > 0 && msg->icon_height <= 64, + _("icon dimensions out of range")); + /* Reject a malformed RLE stream HERE rather than discovering it at draw + * time. The render path returns a bool that layout_add_icon() discards, so + * an undecodable icon would otherwise show no logo, still return Success, + * and be persisted to flash — the user consents to an identity whose logo + * silently does not exist. Validation is exact (every packet well-formed, + * no run straddling the image, whole input consumed) and side-effect-free. + */ + CHECK_PARAM(draw_bitmap_mono_rle_valid( + msg->icon.bytes, (uint32_t)msg->icon.size, + (uint16_t)msg->icon_width, (uint16_t)msg->icon_height), + _("invalid icon encoding")); + icon = msg->icon.bytes; + icon_len = (uint16_t)msg->icon.size; + icon_w = (uint8_t)msg->icon_width; + icon_h = (uint8_t)msg->icon_height; + } + bool persist = msg->has_persist && msg->persist; + + /* Mandatory on-device consent — leads with the identity's logo (if any) + + * alias + fingerprint. The whole trust model hangs on this confirm; the same + * fingerprint reappears on every per-tx identity screen. persist makes the + * trust anchor durable across reboots, so it's called out. */ + char fingerprint[METADATA_FINGERPRINT_LEN]; + signed_metadata_pubkey_fingerprint(msg->pubkey.bytes, fingerprint); + if (!signed_metadata_confirm_load(msg->alias, fingerprint, icon, icon_w, + icon_h, icon_len, persist)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("Load clearsign signer cancelled")); + layoutHome(); + return; + } + + if (!signed_metadata_store_signer((uint8_t)msg->key_id, msg->pubkey.bytes, + msg->alias, icon, icon_w, icon_h, icon_len, + persist)) { + /* Session signer stored, but no persistent slot was free. Tell the truth + * rather than silently keeping it RAM-only under a persist request. */ + fsm_sendFailure(FailureType_Failure_Other, + _("No free persistent identity slot — wipe an old one")); + layoutHome(); + return; + } + fsm_sendSuccess(_("Clearsign signer loaded")); + layoutHome(); +} + static int process_ethereum_xfer(const CoinType* coin, EthereumSignTx* msg) { if (!ethereum_isStandardERC20Transfer(msg) && msg->data_length != 0) return TXOUT_COMPILE_ERROR; @@ -191,44 +319,16 @@ void fsm_msgEthereumGetAddress(EthereumGetAddress* msg) { layoutHome(); } -#define MSG_MAX (38 * 3) // 38 chars per line, three lines max void fsm_msgEthereumSignMessage(EthereumSignMessage* msg) { - char msgBuf[MSG_MAX + 1] = {0}; - const char* typeIndicator; - unsigned ctr; - unsigned msgLen = 0; - bool canPrint = true; - RESP_INIT(EthereumMessageSignature); CHECK_INITIALIZED CHECK_PIN - // truncate to display size if too long - msgLen = msg->message.size * 2; - if (msgLen > MSG_MAX) { - msgLen = MSG_MAX; - } - for (ctr = 0; ctr < msg->message.size; ctr++) { - if (isprint(msg->message.bytes[ctr]) == false) { - canPrint = false; - break; - } - } - if (canPrint) { - typeIndicator = "Sign Message"; - strncpy(msgBuf, (char*)msg->message.bytes, MSG_MAX + 1); - msgBuf[MSG_MAX] = '\0'; - } else { - typeIndicator = "Sign Bytes"; - for (ctr = 0; ctr < msgLen / 2; ctr++) { - snprintf(&msgBuf[2 * ctr], 3, "%02x", msg->message.bytes[ctr]); - } - } - - if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _(typeIndicator), - "%s", msgBuf)) { + if (!confirm_bytes(ButtonRequestType_ButtonRequest_ProtectCall, + "Sign Ethereum Message", msg->message.bytes, + msg->message.size)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; @@ -244,12 +344,6 @@ void fsm_msgEthereumSignMessage(EthereumSignMessage* msg) { } void fsm_msgEthereumVerifyMessage(const EthereumVerifyMessage* msg) { - char msgBuf[MSG_MAX + 1] = {0}; - const char* typeIndicator; - unsigned ctr; - unsigned msgLen = 0; - bool canPrint = true; - CHECK_PARAM(msg->has_address, _("No address provided")); CHECK_PARAM(msg->has_message, _("No message provided")); @@ -266,29 +360,9 @@ void fsm_msgEthereumVerifyMessage(const EthereumVerifyMessage* msg) { return; } - // truncate to display size if too long - msgLen = msg->message.size; - if (msgLen > MSG_MAX) { - msgLen = MSG_MAX; - } - for (ctr = 0; ctr < msgLen; ctr++) { - if (isprint(msg->message.bytes[ctr]) == false) { - canPrint = false; - break; - } - } - if (canPrint) { - typeIndicator = "Message Verified"; - strncpy(msgBuf, (char*)msg->message.bytes, MSG_MAX + 1); - msgBuf[MSG_MAX] = '\0'; - } else { - typeIndicator = "Bytes Verified"; - for (ctr = 0; ctr < msgLen / 2; ctr++) { - snprintf(&msgBuf[2 * ctr], 3, "%02x", msg->message.bytes[ctr]); - } - } - if (!confirm(ButtonRequestType_ButtonRequest_Other, _(typeIndicator), "%s", - msgBuf)) { + if (!confirm_bytes(ButtonRequestType_ButtonRequest_Other, + "Ethereum Message Verified", msg->message.bytes, + msg->message.size)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; @@ -305,6 +379,20 @@ void fsm_msgEthereumSignTypedHash(const EthereumSignTypedHash* msg) { CHECK_PIN + /* This endpoint receives only precomputed hashes, so the device cannot bind + * them to the typed data the host claims they represent. Treat it exactly + * like every other blind-signing path. */ + if (!ethereum_typed_hash_policy_allows( + storage_isPolicyEnabled("AdvancedMode"))) { + (void)review(ButtonRequestType_ButtonRequest_Other, "Blocked", + "Typed-hash signing requires AdvancedMode. " + "Enable in device settings."); + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("Typed-hash signing disabled by policy")); + layoutHome(); + return; + } + if (msg->domain_separator_hash.size != 32 || (msg->has_message_hash && msg->message_hash.size != 32)) { fsm_sendFailure(FailureType_Failure_Other, @@ -331,24 +419,40 @@ void fsm_msgEthereumSignTypedHash(const EthereumSignTypedHash* msg) { char str[64 + 1]; int ctr; - confirm(ButtonRequestType_ButtonRequest_Other, "Verify Address", - "Confirm address: %s", resp->address); + if (!confirm(ButtonRequestType_ButtonRequest_Other, "Verify Address", + "Confirm address: %s", resp->address)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } for (ctr = 0; ctr < 64 / 2; ctr++) { snprintf(&str[2 * ctr], 3, "%02x", msg->domain_separator_hash.bytes[ctr]); } - confirm(ButtonRequestType_ButtonRequest_Other, "Typed Data domain", - "Confirm hash digest: %s", str); + if (!confirm(ButtonRequestType_ButtonRequest_Other, "Typed Data domain", + "Confirm hash digest: %s", str)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } if (msg->has_message_hash) { for (ctr = 0; ctr < 64 / 2; ctr++) { snprintf(&str[2 * ctr], 3, "%02x", msg->message_hash.bytes[ctr]); } - confirm(ButtonRequestType_ButtonRequest_Other, "Typed Data message", - "Confirm hash digest: %s", str); + if (!confirm(ButtonRequestType_ButtonRequest_Other, "Typed Data message", + "Confirm hash digest: %s", str)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } } else { - confirm(ButtonRequestType_ButtonRequest_Other, "Typed Data message", - "Confirm: No message"); + if (!confirm(ButtonRequestType_ButtonRequest_Other, "Typed Data message", + "Confirm: No message")) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } } ethereum_typed_hash_sign(msg, node, resp); diff --git a/lib/firmware/fsm_msg_hive.h b/lib/firmware/fsm_msg_hive.h new file mode 100644 index 000000000..d87188a14 --- /dev/null +++ b/lib/firmware/fsm_msg_hive.h @@ -0,0 +1,1024 @@ +/* + * 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 as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + */ + +// ── HiveGetPublicKey ────────────────────────────────────────────────────── +// Returns a single STM-prefixed public key for the given SLIP-0048 path. +// Path format: m/48'/13'/role'/account'/0' (all 5 components hardened). + +void fsm_msgHiveGetPublicKey(const HiveGetPublicKey* msg) { + RESP_INIT(HivePublicKey); + + CHECK_INITIALIZED + CHECK_PIN + + if (!hive_slip48_path_valid(msg->address_n, msg->address_n_count)) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Invalid Hive SLIP-0048 path")); + layoutHome(); + return; + } + + HDNode* node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, + msg->address_n_count, NULL); + if (!node) return; + hdnode_fill_public_key(node); + + resp->has_raw_public_key = true; + resp->raw_public_key.size = 33; + memcpy(resp->raw_public_key.bytes, node->public_key, 33); + + resp->has_public_key = true; + if (!hive_getPublicKey(node->public_key, resp->public_key, + sizeof(resp->public_key))) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_FirmwareError, + _("Failed to encode Hive public key")); + layoutHome(); + return; + } + + if (msg->has_show_display && msg->show_display) { + // Label the key by the role in the ACTUAL derivation path + // (m/48'/13'/role'/account'/0'), never the host-supplied msg->role, + // which could mislabel the exported key. + const char* role_label = "Hive Public Key"; + if (msg->address_n_count >= 3) { + switch (msg->address_n[2] & 0x7FFFFFFFu) { + case 0: + role_label = "Hive Owner Key"; + break; + case 1: + role_label = "Hive Active Key"; + break; + case 3: + role_label = "Hive Memo Key"; + break; + case 4: + role_label = "Hive Posting Key"; + break; + default: + break; + } + } + if (!confirm_ethereum_address(role_label, resp->public_key)) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Cancelled")); + layoutHome(); + return; + } + } + + memzero(node, sizeof(*node)); + msg_write(MessageType_MessageType_HivePublicKey, resp); + layoutHome(); +} + +// ── HiveGetPublicKeys ───────────────────────────────────────────────────── +// Returns all four SLIP-0048 role keys (owner/active/memo/posting) for a +// given account index in a single device interaction. + +void fsm_msgHiveGetPublicKeys(const HiveGetPublicKeys* msg) { + RESP_INIT(HivePublicKeys); + + CHECK_INITIALIZED + CHECK_PIN + + uint32_t account_index = msg->has_account_index ? msg->account_index : 0; + + HDNode* root = fsm_getDerivedNode(SECP256K1_NAME, NULL, 0, NULL); + if (!root) return; + + resp->has_owner_key = true; + resp->has_active_key = true; + resp->has_memo_key = true; + resp->has_posting_key = true; + + if (!hive_getPublicKeys(root, account_index, resp->owner_key, + sizeof(resp->owner_key), resp->active_key, + sizeof(resp->active_key), resp->memo_key, + sizeof(resp->memo_key), resp->posting_key, + sizeof(resp->posting_key))) { + memzero(root, sizeof(*root)); + fsm_sendFailure(FailureType_Failure_FirmwareError, + _("Failed to derive Hive keys")); + layoutHome(); + return; + } + + if (msg->has_show_display && msg->show_display) { + if (!confirm(ButtonRequestType_ButtonRequest_Other, "Hive Keys", + "Export all Hive keys for account %u?", + (unsigned int)account_index)) { + memzero(root, sizeof(*root)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Cancelled")); + layoutHome(); + return; + } + } + + memzero(root, sizeof(*root)); + msg_write(MessageType_MessageType_HivePublicKeys, resp); + layoutHome(); +} + +// ── SLIP-0048 path validation ───────────────────────────────────────────── +// All three sign handlers enforce the full path shape before anything is +// derived or signed: m/48'/13'/role'/account'/0' (all 5 components hardened), +// with the role pinned to the one the operation needs on-chain: +// transfer -> active' (post-HF28 hived no longer accepts higher-role +// substitution, and the cold owner key must not be spent) +// create/update -> owner' (the attestation contract: the sponsor verifies +// the signature recovers to the device OWNER key, and +// account_update replaces the owner authority itself) +// Rejecting arbitrary host paths means a compromised host can never make the +// device produce a Hive signature with a key from another coin's derivation +// tree, nor with the wrong role's key. + +static bool hive_slip48_path_ok(const uint32_t* address_n, uint32_t count, + uint32_t required_role) { + return hive_slip48_path_valid_for_role(address_n, count, required_role); +} + +static bool hive_confirm_slice(ButtonRequestType type, const char* title, + const uint8_t* s, uint16_t len); + +// ── HiveSignTx (transfer) ───────────────────────────────────────────────── + +void fsm_msgHiveSignTx(const HiveSignTx* msg) { + RESP_INIT(HiveSignedTx); + + CHECK_INITIALIZED + CHECK_PIN + + if (!msg->has_from || !msg->has_to || !msg->has_amount || + !msg->has_ref_block_num || !msg->has_ref_block_prefix || + !msg->has_expiration) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Missing required Hive transaction fields")); + layoutHome(); + return; + } + + if (!hive_slip48_path_ok(msg->address_n, msg->address_n_count, + HIVE_ROLE_ACTIVE)) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Invalid Hive SLIP-0048 path (transfer needs active')")); + layoutHome(); + return; + } + + // Reject over-long memos up front with a specific error; the serializer's + // own bounds check would otherwise surface as a generic signing failure. + if (msg->has_memo && strlen(msg->memo) > HIVE_MAX_MEMO_LEN) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Hive memo too long (max 440 bytes)")); + layoutHome(); + return; + } + + HDNode* node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, + msg->address_n_count, NULL); + if (!node) return; + hdnode_fill_public_key(node); + + // Display precision MUST match the precision the serializer signs + // (append_asset uses msg->decimals), otherwise the user approves an + // amount that differs from what is signed. Reject implausible precision. + uint8_t prec = msg->has_decimals ? (uint8_t)msg->decimals : HIVE_DECIMALS; + if (prec > 18) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Invalid Hive asset precision")); + layoutHome(); + return; + } + const char* symbol = msg->has_asset_symbol ? msg->asset_symbol : "HIVE"; + char suffix[sizeof(msg->asset_symbol) + 2]; // leading space + symbol + NUL + snprintf(suffix, sizeof(suffix), " %s", symbol); + char amount_str[32]; + bn_format_uint64(msg->amount, NULL, suffix, prec, 0, false, amount_str, + sizeof(amount_str)); + + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "Send Hive", + "Send %s to @%s?", amount_str, msg->to)) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + if (msg->has_memo && strlen(msg->memo) > 0) { + if (!hive_confirm_slice(ButtonRequestType_ButtonRequest_ConfirmMemo, "Memo", + (const uint8_t*)msg->memo, + (uint16_t)strlen(msg->memo))) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } + + if (!confirm(ButtonRequestType_ButtonRequest_SignTx, "Sign Transaction", + "Sign Hive transaction from @%s?", msg->from)) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + hive_signTx(node, msg, resp); + memzero(node, sizeof(*node)); + + if (!resp->has_signature) { + fsm_sendFailure(FailureType_Failure_FirmwareError, + _("Hive signing failed")); + layoutHome(); + return; + } + + msg_write(MessageType_MessageType_HiveSignedTx, resp); + layoutHome(); +} + +typedef struct { + uint8_t owner[33]; + uint8_t active[33]; + uint8_t posting[33]; + uint8_t memo[33]; +} HiveRoleKeys; + +static bool hive_prepare_account_sign(const uint32_t* address_n, + uint32_t address_n_count, + HiveRoleKeys* keys, HDNode** node_out, + char* owner_stm, size_t owner_stm_len) { + if (!hive_slip48_path_ok(address_n, address_n_count, HIVE_ROLE_OWNER)) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Invalid Hive SLIP-0048 path (needs owner')")); + layoutHome(); + return false; + } + uint32_t account_index = address_n[3] & 0x7FFFFFFFu; + + // Derive all four role keys from the device root. + // Do this BEFORE fetching the signing node so the root static buffer + // is not clobbered by the second fsm_getDerivedNode call. + const HDNode* root = fsm_getDerivedNode(SECP256K1_NAME, NULL, 0, NULL); + if (!root) return false; + + uint32_t acc_hardened = account_index | 0x80000000u; + bool keys_ok = + hive_deriveRawKey(root, HIVE_ROLE_OWNER, acc_hardened, keys->owner) && + hive_deriveRawKey(root, HIVE_ROLE_ACTIVE, acc_hardened, keys->active) && + hive_deriveRawKey(root, HIVE_ROLE_POSTING, acc_hardened, keys->posting) && + hive_deriveRawKey(root, HIVE_ROLE_MEMO, acc_hardened, keys->memo); + // root static buffer is done with; signing node derivation may overwrite it. + + if (!keys_ok) { + memzero(keys, sizeof(*keys)); + fsm_sendFailure(FailureType_Failure_FirmwareError, + _("Failed to derive Hive keys")); + layoutHome(); + return false; + } + + // Now get the signing node (owner key, overwrites root static buffer). + HDNode* node = + fsm_getDerivedNode(SECP256K1_NAME, address_n, address_n_count, NULL); + if (!node) { + memzero(keys, sizeof(*keys)); + return false; + } + hdnode_fill_public_key(node); + + // Encode the device-derived owner key for display confirmation. + if (!hive_getPublicKey(keys->owner, owner_stm, owner_stm_len)) { + memzero(node, sizeof(*node)); + memzero(keys, sizeof(*keys)); + fsm_sendFailure(FailureType_Failure_FirmwareError, + _("Failed to encode Hive owner key")); + layoutHome(); + return false; + } + + *node_out = node; + return true; +} + +// ── HiveSignAccountCreate ───────────────────────────────────────────────── +// Signs a Graphene account_create operation. +// Device derives all four role keys internally; host-supplied key strings +// are informational only (displayed for confirmation) and never used for +// the actual transaction. KeepKey is the sole root of trust from genesis. + +void fsm_msgHiveSignAccountCreate(const HiveSignAccountCreate* msg) { + RESP_INIT(HiveSignedAccountCreate); + + CHECK_INITIALIZED + CHECK_PIN + + if (!msg->has_new_account_name || !msg->has_creator || + !msg->has_ref_block_num || !msg->has_ref_block_prefix || + !msg->has_expiration) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Missing required account_create fields")); + layoutHome(); + return; + } + + HiveRoleKeys keys; + HDNode* node = NULL; + char owner_stm[64]; + if (!hive_prepare_account_sign(msg->address_n, msg->address_n_count, &keys, + &node, owner_stm, sizeof(owner_stm))) { + return; + } + + // Primary confirmation: show the new username prominently. + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Create Hive Account", + "Create @%s secured by KeepKey?\n\nAll keys from your device.", + msg->new_account_name)) { + memzero(node, sizeof(*node)); + memzero(&keys, sizeof(keys)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + // Secondary confirmation: show device-derived owner key so user can verify. + if (!confirm(ButtonRequestType_ButtonRequest_Other, "Owner Key", "%s", + owner_stm)) { + memzero(node, sizeof(*node)); + memzero(&keys, sizeof(keys)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + // Tertiary confirmation: show sponsor + fee. + char fee_str[32]; + uint64_t fee = msg->has_fee_amount ? msg->fee_amount : 3000; + snprintf(fee_str, sizeof(fee_str), "%" PRIu64 ".%03" PRIu64 " HIVE", + fee / 1000, fee % 1000); + if (!confirm(ButtonRequestType_ButtonRequest_SignTx, "Creation Fee", + "Fee: %s paid by @%s", fee_str, msg->creator)) { + memzero(node, sizeof(*node)); + memzero(&keys, sizeof(keys)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + hive_signAccountCreate(node, msg, keys.owner, keys.active, keys.posting, + keys.memo, resp); + memzero(node, sizeof(*node)); + memzero(&keys, sizeof(keys)); + + if (!resp->has_signature) { + fsm_sendFailure(FailureType_Failure_FirmwareError, + _("Hive account_create signing failed")); + layoutHome(); + return; + } + + msg_write(MessageType_MessageType_HiveSignedAccountCreate, resp); + layoutHome(); +} + +// ── HiveSignAccountUpdate ───────────────────────────────────────────────── +// Signs a Graphene account_update operation. +// Device derives all four new role keys internally; host-supplied new_*_key +// strings are not used for signing. The device-derived owner key is shown +// so the user can verify it matches their device before replacing all keys. + +void fsm_msgHiveSignAccountUpdate(const HiveSignAccountUpdate* msg) { + RESP_INIT(HiveSignedAccountUpdate); + + CHECK_INITIALIZED + CHECK_PIN + + if (!msg->has_account || !msg->has_ref_block_num || + !msg->has_ref_block_prefix || !msg->has_expiration) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Missing required account_update fields")); + layoutHome(); + return; + } + + HiveRoleKeys keys; + HDNode* node = NULL; + char owner_stm[64]; + if (!hive_prepare_account_sign(msg->address_n, msg->address_n_count, &keys, + &node, owner_stm, sizeof(owner_stm))) { + return; + } + + // Warning: this replaces all existing keys. + if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, + "Secure Hive Account", + "Replace ALL keys for @%s with KeepKey keys?\n\nOld keys will " + "be retired.", + msg->account)) { + memzero(node, sizeof(*node)); + memzero(&keys, sizeof(keys)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + // Show device-derived owner key so user can verify it's their device. + if (!confirm(ButtonRequestType_ButtonRequest_SignTx, "New Owner Key", "%s", + owner_stm)) { + memzero(node, sizeof(*node)); + memzero(&keys, sizeof(keys)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + hive_signAccountUpdate(node, msg, keys.owner, keys.active, keys.posting, + keys.memo, resp); + memzero(node, sizeof(*node)); + memzero(&keys, sizeof(keys)); + + if (!resp->has_signature) { + fsm_sendFailure(FailureType_Failure_FirmwareError, + _("Hive account_update signing failed")); + layoutHome(); + return; + } + + msg_write(MessageType_MessageType_HiveSignedAccountUpdate, resp); + layoutHome(); +} + +// ── HiveSignMessage (Keychain signBuffer) ───────────────────────────────── +// The Hive dApp login primitive: Aioha / Keychain-SDK dApps authenticate by +// having the account sign a challenge string, then recover the pubkey and +// check it against the account's authority on-chain. Contract (hive-js +// Signature.signBuffer): sig over SHA256(raw message bytes) — no chain_id, +// no prefix. Roles: posting/active/memo, Keychain's requestSignBuffer +// surface. owner' is deliberately rejected — no consumer offers it, and the +// cold owner key must not be normalized into dApp flows. The full path +// shape is still enforced like the tx handlers. + +static bool hive_slip48_message_path_ok(const uint32_t* address_n, + uint32_t count, + const char** role_label) { + if (!hive_slip48_path_valid(address_n, count)) return false; + switch (address_n[2]) { + case HIVE_ROLE_ACTIVE: + *role_label = "active"; + return true; + case HIVE_ROLE_MEMO: + *role_label = "memo"; + return true; + case HIVE_ROLE_POSTING: + *role_label = "posting"; + return true; + default: + return false; + } +} + +void fsm_msgHiveSignMessage(const HiveSignMessage* msg) { + RESP_INIT(HiveSignedMessage); + + CHECK_INITIALIZED + CHECK_PIN + + if (!msg->has_message || msg->message.size == 0) { + fsm_sendFailure(FailureType_Failure_SyntaxError, _("Missing message")); + layoutHome(); + return; + } + + // Mirrors the proto max_size cap so proto and code can never disagree + // (the memo-length lesson from the transfer handler). + if (msg->message.size > HIVE_MAX_MESSAGE_LEN) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Hive message too long (max 1024 bytes)")); + layoutHome(); + return; + } + + // A Hive TRANSACTION digest is SHA256(chain_id || tx), and this message + // digest is SHA256(message) — so a "message" that begins with the mainnet + // chain-id bytes would hash to a broadcastable transaction's digest. No + // legitimate challenge starts with the chain id; refuse the collision. + const uint8_t hive_chain_id[HIVE_CHAIN_ID_LEN] = HIVE_CHAIN_ID; + if (msg->message.size >= HIVE_CHAIN_ID_LEN && + memcmp(msg->message.bytes, hive_chain_id, HIVE_CHAIN_ID_LEN) == 0) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Message must not start with the Hive chain ID")); + layoutHome(); + return; + } + + const char* role_label = NULL; + if (!hive_slip48_message_path_ok(msg->address_n, msg->address_n_count, + &role_label)) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Invalid Hive SLIP-0048 path")); + layoutHome(); + return; + } + + HDNode* node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, + msg->address_n_count, NULL); + if (!node) return; + hdnode_fill_public_key(node); + + // Domain-separate messages from transactions. A Hive TRANSACTION digest is + // SHA256(chain_id || serialized_tx), where the 32-byte chain_id and the + // serialized Graphene fields (ref_block_prefix, expiration, ...) are BINARY. + // Constraining signable messages to printable ASCII puts them in a domain + // disjoint from every transaction preimage — for ANY chain id, not just + // mainnet — so a binary "message" equal to C || serialized_tx can no longer + // be signed into a valid transaction signature on a fork chain C. This is the + // real fix; the mainnet-only prefix reject above is a belt-and-suspenders + // subset of it. hive-js signBuffer signs printable challenges, so nothing + // legitimate is lost. (A prefix blacklist could never be complete because the + // host chooses the chain id; a printable-only whitelist is complete by + // construction against binary preimages.) + if (!hive_message_is_printable(msg->message.bytes, msg->message.size)) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Hive messages must be printable text")); + layoutHome(); + return; + } + + // Page the FULL message (72-char ASCII pages) so no trailing content is ever + // truncated behind a benign-looking prefix, and name the signing key. + if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, "Sign Hive Message", + "Signing with %s key", role_label) || + !hive_confirm_slice(ButtonRequestType_ButtonRequest_ProtectCall, + "Hive Message", msg->message.bytes, + (uint16_t)msg->message.size)) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + hive_signMessage(node, msg, resp); + memzero(node, sizeof(*node)); + + if (!resp->has_signature) { + fsm_sendFailure(FailureType_Failure_FirmwareError, + _("Hive message signing failed")); + layoutHome(); + return; + } + + msg_write(MessageType_MessageType_HiveSignedMessage, resp); + layoutHome(); +} + +// ── HiveSignOperations (parsed generic op signing) ──────────────────────── +// The host serializes the transaction; firmware parses the Graphene bytes, +// clear-signs the ops it recognizes (vote, comment, custom_json), and +// refuses everything else — no blind-sign fallback. Everything shown on the +// OLED is re-derived from the bytes being signed, so a host serializer bug +// can only produce a node rejection, never a silent wrong-sign. + +// Dedicated path validator: {posting', active'} ONLY, pinned to the tx tier. +// Do NOT fold into hive_slip48_message_path_ok — that one deliberately +// accepts memo' (a legitimate signBuffer target), but no Graphene operation +// uses memo authority; a memo-path vote must be refused here, not +// discovered at the chain. owner' is likewise excluded. +static bool hive_slip48_ops_path_ok(const uint32_t* address_n, uint32_t count, + bool needs_active) { + return hive_slip48_path_valid_for_role( + address_n, count, needs_active ? HIVE_ROLE_ACTIVE : HIVE_ROLE_POSTING); +} + +// User-controlled string fields are paged in full. Printable fields are shown +// as text; fields containing non-ASCII bytes are shown as complete hex rather +// than a short preview. Page boundaries are selected with the same font and +// word-wrapping calculation used by draw_string(), so no signed suffix can be +// pushed below the OLED's three visible body rows. + +static bool hive_slice_is_ascii(const uint8_t* s, uint16_t len) { + bool ascii = true; + for (uint16_t i = 0; i < len; i++) { + if (s[i] < 0x20 || s[i] > 0x7e) { + ascii = false; + break; + } + } + return ascii; +} + +static uint16_t hive_rendered_page_len(const uint8_t* s, uint16_t len, + bool ascii) { + if (len == 0) return 0; + + if (ascii) { + size_t candidate = len; + if (candidate >= BODY_CHAR_MAX) candidate = BODY_CHAR_MAX - 1; + return (uint16_t)calc_str_page(get_body_font(), (const char*)s, candidate, + BODY_WIDTH, BODY_ROWS); + } + + uint16_t candidate = len; + if (candidate > (BODY_CHAR_MAX - 1) / 2) candidate = (BODY_CHAR_MAX - 1) / 2; + char rendered[BODY_CHAR_MAX]; + for (uint16_t i = 0; i < candidate; i++) { + snprintf(rendered + 2 * i, 3, "%02x", s[i]); + } + size_t chars = calc_str_page(get_body_font(), rendered, 2 * candidate, + BODY_WIDTH, BODY_ROWS); + return (uint16_t)(chars / 2); +} + +static bool hive_confirm_slice(ButtonRequestType type, const char* title, + const uint8_t* s, uint16_t len) { + if (len == 0) return confirm(type, title, "(empty)"); + + bool ascii = hive_slice_is_ascii(s, len); + uint16_t pages = 0; + uint16_t offset = 0; + while (offset < len) { + uint16_t take = hive_rendered_page_len(s + offset, len - offset, ascii); + if (take == 0) return false; + offset = (uint16_t)(offset + take); + pages++; + } + + offset = 0; + for (uint16_t page = 0; page < pages; page++) { + uint16_t take = hive_rendered_page_len(s + offset, len - offset, ascii); + if (take == 0) return false; + + char page_title[TITLE_CHAR_MAX]; + if (pages > 1 || !ascii) { + snprintf(page_title, sizeof(page_title), + ascii ? "%s %u/%u" : "%s Hex %u/%u", title, (unsigned)(page + 1), + (unsigned)pages); + } else { + strlcpy(page_title, title, sizeof(page_title)); + } + + if (ascii) { + char rendered[BODY_CHAR_MAX]; + memcpy(rendered, s + offset, take); + rendered[take] = '\0'; + if (!confirm(type, page_title, "%s", rendered)) return false; + } else { + char rendered[BODY_CHAR_MAX]; + for (uint16_t i = 0; i < take; i++) { + snprintf(rendered + 2 * i, 3, "%02x", s[offset + i]); + } + if (!confirm(type, page_title, "%s", rendered)) return false; + } + offset = (uint16_t)(offset + take); + } + return true; +} + +// "1.234 HIVE" — precision comes from the asset bytes being signed, which +// the parser has already pinned to the symbol's protocol-fixed value. +static void hive_format_asset(const uint8_t* a, char* out, size_t out_len) { + char suffix[9]; // space + longest symbol ("VESTS") + NUL + snprintf(suffix, sizeof(suffix), " %s", hive_assetSymbol(a)); + bn_format_uint64(hive_assetAmount(a), NULL, suffix, hive_assetPrecision(a), 0, + false, out, out_len); +} + +// Basis points (0..10000) as "12.34%". +static void hive_format_percent(int16_t bp, char* out, size_t out_len) { + snprintf(out, out_len, "%d.%02d%%", bp / 100, bp % 100); +} + +static void hive_copy_slice(char* out, size_t out_len, const uint8_t* s, + uint16_t len) { + if (out_len == 0) return; + size_t take = len; + if (take >= out_len) take = out_len - 1; + memcpy(out, s, take); + out[take] = '\0'; +} + +void fsm_msgHiveSignOperations(const HiveSignOperations* msg) { + RESP_INIT(HiveSignedOperations); + + CHECK_INITIALIZED + CHECK_PIN + + if (!msg->has_serialized_tx || msg->serialized_tx.size == 0) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Missing serialized transaction")); + layoutHome(); + return; + } + + static HiveParsedTx parsed; // slices borrow from the static msg buffer + const char* parse_err = hive_parseOperations( + msg->serialized_tx.bytes, msg->serialized_tx.size, &parsed); + if (parse_err) { + fsm_sendFailure(FailureType_Failure_SyntaxError, _(parse_err)); + layoutHome(); + return; + } + + if (!hive_slip48_ops_path_ok(msg->address_n, msg->address_n_count, + parsed.needs_active)) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + parsed.needs_active + ? _("Invalid Hive SLIP-0048 path (needs active')") + : _("Invalid Hive SLIP-0048 path (needs posting')")); + layoutHome(); + return; + } + + HDNode* node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, + msg->address_n_count, NULL); + if (!node) return; + hdnode_fill_public_key(node); + + // Confirm operation summaries and payloads, then show a final sign prompt. + for (uint8_t i = 0; i < parsed.num_ops; i++) { + const HiveTxOp* op = &parsed.ops[i]; + char name[17]; // hive account names are <= 16 chars, length-validated + hive_copy_slice(name, sizeof(name), op->acct, op->acct_len); + + bool approved = false; + switch (op->op_type) { + case HIVE_OP_VOTE: { + char target[17]; + hive_copy_slice(target, sizeof(target), op->target, op->target_len); + int w = op->weight < 0 ? -op->weight : op->weight; + approved = + confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + op->weight < 0 ? "Downvote" : "Vote", + "@%s -> @%s at %d.%02d%%", name, target, w / 100, w % 100); + if (approved) { + approved = + hive_confirm_slice(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Vote Target", op->detail, op->detail_len); + } + break; + } + case HIVE_OP_COMMENT: { + char parent[17]; + hive_copy_slice(parent, sizeof(parent), op->parent_author, + op->parent_author_len); + approved = + op->is_top_level + ? confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "Post", + "Create post by @%s?", name) + : confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Comment", "Reply by @%s to @%s?", name, parent); + if (approved) { + approved = hive_confirm_slice( + ButtonRequestType_ButtonRequest_ConfirmOutput, + op->is_top_level ? "Post Category" : "Reply Target", + op->parent_permlink, op->parent_permlink_len); + } + if (approved) { + approved = hive_confirm_slice( + ButtonRequestType_ButtonRequest_ConfirmOutput, "Post Permlink", + op->permlink, op->permlink_len); + } + if (approved && op->target_len > 0) { + approved = + hive_confirm_slice(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Post Title", op->target, op->target_len); + } + if (approved) { + approved = + hive_confirm_slice(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Post Body", op->detail, op->detail_len); + } + if (approved && op->json_metadata_len > 0) { + approved = hive_confirm_slice( + ButtonRequestType_ButtonRequest_ConfirmOutput, "Post Metadata", + op->json_metadata, op->json_metadata_len); + } + break; + } + case HIVE_OP_CUSTOM_JSON: { + approved = true; + for (uint8_t a = 0; approved && a < op->n_auths; a++) { + char auth_name[17]; + hive_copy_slice(auth_name, sizeof(auth_name), op->auth_acct[a], + op->auth_acct_len[a]); + approved = confirm( + ButtonRequestType_ButtonRequest_ConfirmOutput, "Custom JSON Auth", + "%u/%u: @%s\n%s key", (unsigned)(a + 1), (unsigned)op->n_auths, + auth_name, op->needs_active ? "Active" : "Posting"); + } + if (approved) { + approved = + hive_confirm_slice(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Custom JSON ID", op->target, op->target_len); + } + if (approved) { + approved = + hive_confirm_slice(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Custom JSON", op->detail, op->detail_len); + } + break; + } + case HIVE_OP_TRANSFER_TO_VESTING: { + char amount[40], target[17]; + hive_format_asset(op->assets[0], amount, sizeof(amount)); + hive_copy_slice(target, sizeof(target), op->target, op->target_len); + approved = + op->target_len == 0 + ? confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Power Up", "Power up\n%s\nto @%s", amount, name) + : confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Power Up", "%s\nfrom @%s\nto @%s", amount, name, + target); + break; + } + case HIVE_OP_WITHDRAW_VESTING: { + char amount[40]; + hive_format_asset(op->assets[0], amount, sizeof(amount)); + approved = + hive_assetAmount(op->assets[0]) == 0 + ? confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Stop Power Down", "Cancel power down\nfor @%s", name) + : confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Power Down", "Power down\n%s\nfrom @%s", amount, + name); + break; + } + case HIVE_OP_LIMIT_ORDER_CREATE: { + char sell[40], receive[40]; + hive_format_asset(op->assets[0], sell, sizeof(sell)); + hive_format_asset(op->assets[1], receive, sizeof(receive)); + approved = confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Market Order", "@%s sells\n%s\nfor >= %s", name, + sell, receive); + if (approved) { + // Order id and fill_or_kill decide whether an unfilled order rests + // on the book or is discarded, so they get their own screen rather + // than being crowded off the first one. + approved = confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Order Terms", "Order #%u\n%s\nExpires %u", + (unsigned)op->req_id, + op->flag ? "Fill or kill" : "Rests on book", + (unsigned)op->expiration); + } + break; + } + case HIVE_OP_LIMIT_ORDER_CANCEL: + approved = confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Cancel Order", "Cancel order #%u\nfor @%s?", + (unsigned)op->req_id, name); + break; + case HIVE_OP_CONVERT: { + char amount[40]; + hive_format_asset(op->assets[0], amount, sizeof(amount)); + approved = confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Convert", "Convert %s\nto HIVE for @%s\n(#%u)", + amount, name, (unsigned)op->req_id); + break; + } + case HIVE_OP_COMMENT_OPTIONS: { + char max_payout[40], percent[16]; + hive_format_asset(op->assets[0], max_payout, sizeof(max_payout)); + hive_format_percent(op->weight, percent, sizeof(percent)); + approved = confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Payout Options", "@%s\nMax %s\nHBD split %s", name, + max_payout, percent); + if (approved) { + approved = confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Payout Options", "Votes: %s\nCuration: %s", + op->flag ? "allowed" : "disabled", + op->flag2 ? "allowed" : "disabled"); + } + // Beneficiaries divert payout to other accounts — each one is + // confirmed individually rather than summarized as a count. + for (uint8_t b = 0; approved && b < op->n_benef; b++) { + char benef[17], benef_pct[16]; + hive_copy_slice(benef, sizeof(benef), op->benef_acct[b], + op->benef_acct_len[b]); + hive_format_percent((int16_t)op->benef_weight[b], benef_pct, + sizeof(benef_pct)); + approved = confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Payout Beneficiary", "%u/%u: @%s\ngets %s", + (unsigned)(b + 1), (unsigned)op->n_benef, benef, + benef_pct); + } + if (approved) { + approved = hive_confirm_slice( + ButtonRequestType_ButtonRequest_ConfirmOutput, "Payout Permlink", + op->permlink, op->permlink_len); + } + break; + } + case HIVE_OP_TRANSFER_TO_SAVINGS: + case HIVE_OP_TRANSFER_FROM_SAVINGS: { + char amount[40], target[17]; + bool deposit = (op->op_type == HIVE_OP_TRANSFER_TO_SAVINGS); + hive_format_asset(op->assets[0], amount, sizeof(amount)); + hive_copy_slice(target, sizeof(target), op->target, op->target_len); + // One variable per row. A 16-character account name sharing a row + // with a label can wrap into a fourth row, which the display drops + // silently — and here that row carries the destination account. + // req_id is deliberately not shown: it is a cancellation handle, not + // a fund-routing field, and crowding it in costs the destination row. + approved = confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + deposit ? "Savings Deposit" : "Savings Withdraw", + "%s\nfrom @%s\nto @%s", amount, name, target); + if (approved && op->detail_len > 0) { + approved = + hive_confirm_slice(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Savings Memo", op->detail, op->detail_len); + } + break; + } + case HIVE_OP_CLAIM_REWARD_BALANCE: { + char hive_amt[40], hbd_amt[40], vests_amt[40]; + hive_format_asset(op->assets[0], hive_amt, sizeof(hive_amt)); + hive_format_asset(op->assets[1], hbd_amt, sizeof(hbd_amt)); + hive_format_asset(op->assets[2], vests_amt, sizeof(vests_amt)); + // Three assets plus the account name cannot share one screen: the + // OLED body fits exactly three rows (layout.c places rows at y = + // 24/38/52 and draw_char_with_shift silently drops any glyph past + // y+height > 64), so a fourth row would be signed but never shown. + approved = confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Claim Rewards", "@%s claims\n%s\n%s", name, + hive_amt, hbd_amt); + if (approved) { + approved = + confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Claim Rewards", "@%s claims\n%s", name, vests_amt); + } + break; + } + case HIVE_OP_DELEGATE_VESTING_SHARES: { + char amount[40], target[17]; + hive_format_asset(op->assets[0], amount, sizeof(amount)); + hive_copy_slice(target, sizeof(target), op->target, op->target_len); + approved = + hive_assetAmount(op->assets[0]) == 0 + ? confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Remove Delegation", + "@%s removes its\ndelegation to @%s?", name, target) + : confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Delegate", "@%s delegates\n%s\nto @%s", name, amount, + target); + break; + } + case HIVE_OP_ACCOUNT_UPDATE2: + approved = confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Profile Update", "Update profile\nof @%s?", name); + if (approved && op->detail_len > 0) { + approved = hive_confirm_slice( + ButtonRequestType_ButtonRequest_ConfirmOutput, "Account Metadata", + op->detail, op->detail_len); + } + if (approved && op->json_metadata_len > 0) { + approved = hive_confirm_slice( + ButtonRequestType_ButtonRequest_ConfirmOutput, "Profile Metadata", + op->json_metadata, op->json_metadata_len); + } + break; + default: + break; // unreachable — parser rejected unknown ops + } + if (!approved) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } + + if (!confirm(ButtonRequestType_ButtonRequest_SignTx, "Sign Transaction", + "Sign %u Hive operation%s with the %s key?", + (unsigned)parsed.num_ops, parsed.num_ops == 1 ? "" : "s", + parsed.needs_active ? "active" : "posting")) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + hive_signOperations(node, msg, resp); + memzero(node, sizeof(*node)); + + if (!resp->has_signature) { + fsm_sendFailure(FailureType_Failure_FirmwareError, + _("Hive operation signing failed")); + layoutHome(); + return; + } + + msg_write(MessageType_MessageType_HiveSignedOperations, resp); + layoutHome(); +} diff --git a/lib/firmware/fsm_msg_mayachain.h b/lib/firmware/fsm_msg_mayachain.h index be9229665..4b2daaf2c 100644 --- a/lib/firmware/fsm_msg_mayachain.h +++ b/lib/firmware/fsm_msg_mayachain.h @@ -141,15 +141,38 @@ void fsm_msgMayachainMsgAck(const MayachainMsgAck* msg) { const MayachainSignTx* sign_tx = mayachain_getMayachainSignTx(); + // Default to "cacao" for backward compatibility; validate all non-default + // denoms before any display so untrusted strings never reach the UI or + // the signing JSON. + const char* coin_denom = + (msg->has_send && msg->send.has_denom && msg->send.denom[0]) + ? msg->send.denom + : "cacao"; + if (msg->has_send) { + if (!mayachain_isValidDenom(coin_denom)) { + mayachain_signAbort(); + fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid denom"); + layoutHome(); + return; + } + switch (msg->send.address_type) { case OutputAddressType_TRANSFER: default: { + // Amount (no denom suffix) must fit amount_str[32]; a long denom + // appended here would overflow bn_format and blank the amount while + // the real value is still signed. Confirm the denom on its own + // screen instead (matches the THORChain send path). char amount_str[32]; - char denom_str[71]; - sprintf(denom_str, " %s", msg->send.denom); - bn_format_uint64(msg->send.amount, NULL, denom_str, 10, 0, false, - amount_str, sizeof(amount_str)); + if (!bn_format_uint64(msg->send.amount, NULL, NULL, 10, 0, false, + amount_str, sizeof(amount_str))) { + mayachain_signAbort(); + fsm_sendFailure(FailureType_Failure_FirmwareError, + _("Failed to format amount")); + layoutHome(); + return; + } if (!confirm_transaction_output( ButtonRequestType_ButtonRequest_ConfirmOutput, amount_str, msg->send.to_address)) { @@ -158,12 +181,19 @@ void fsm_msgMayachainMsgAck(const MayachainMsgAck* msg) { layoutHome(); return; } + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "Asset", + "%s", coin_denom)) { + mayachain_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } break; } } if (!mayachain_signTxUpdateMsgSend(msg->send.amount, msg->send.to_address, - msg->send.denom)) { + coin_denom)) { mayachain_signAbort(); fsm_sendFailure(FailureType_Failure_SyntaxError, "Failed to include send message in transaction"); @@ -172,8 +202,21 @@ void fsm_msgMayachainMsgAck(const MayachainMsgAck* msg) { } } else if (msg->has_deposit) { - char amount_str[32]; - char asset_str[21]; + // Validate before any display so untrusted strings never reach the UI + // or the sign bytes. + if (!mayachain_isValidAsset(msg->deposit.asset) || + !mayachain_isValidSigner(msg->deposit.signer)) { + mayachain_signAbort(); + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Invalid deposit asset or signer"); + layoutHome(); + return; + } + // Long-form assets (e.g. + // ETH.USDT-0XDAC17F958D2EE523A2206206994597C13D831EC7) are ~50 chars; + // amount_str must fit amount + asset suffix or bn_format zeroes it out. + char amount_str[96]; + char asset_str[64]; asset_str[0] = ' '; strlcpy(&(asset_str[1]), msg->deposit.asset, sizeof(asset_str) - 1); bn_format_uint64(msg->deposit.amount, NULL, asset_str, 10, 0, false, @@ -188,17 +231,16 @@ void fsm_msgMayachainMsgAck(const MayachainMsgAck* msg) { } if (msg->deposit.has_memo) { - // See if we can parse the memo - if (!mayachain_parseConfirmMemo(msg->deposit.memo, - sizeof(msg->deposit.memo))) { - // Memo not recognizable, ask to confirm it - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmMemo, _("Memo"), - "%s", msg->deposit.memo)) { - mayachain_signAbort(); - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } + size_t memo_len = strnlen(msg->deposit.memo, sizeof(msg->deposit.memo)); + // Page the complete raw memo as the sole, authoritative disclosure (no + // structured pre-parse: its bool return conflates unrecognized with user + // reject, so a reject must not be followed by these pages then signing). + if (!thorchain_confirm_full_memo(_("Memo"), msg->deposit.memo, + memo_len)) { + mayachain_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; } } @@ -218,17 +260,14 @@ void fsm_msgMayachainMsgAck(const MayachainMsgAck* msg) { } if (sign_tx->has_memo && !msg->deposit.has_memo) { - // See if we can parse the tx memo. This memo ignored if deposit msg has - // memo - if (!mayachain_parseConfirmMemo(sign_tx->memo, sizeof(sign_tx->memo))) { - // Memo not recognizable, ask to confirm it - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmMemo, _("Memo"), "%s", - sign_tx->memo)) { - mayachain_signAbort(); - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } + // Ignored if the deposit msg has a memo. Page the full raw memo as the sole + // gate (see the deposit path above for why there is no structured pass). + size_t memo_len = strnlen(sign_tx->memo, sizeof(sign_tx->memo)); + if (!thorchain_confirm_full_memo(_("Memo"), sign_tx->memo, memo_len)) { + mayachain_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; } } @@ -245,7 +284,7 @@ void fsm_msgMayachainMsgAck(const MayachainMsgAck* msg) { if (!confirm(ButtonRequestType_ButtonRequest_SignTx, node_str, "Sign this %s transaction on %s? " "Additional network fees apply.", - msg->has_send ? msg->send.denom : "CACAO", sign_tx->chain_id)) { + msg->has_send ? coin_denom : "CACAO", sign_tx->chain_id)) { mayachain_signAbort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); diff --git a/lib/firmware/fsm_msg_osmosis.h b/lib/firmware/fsm_msg_osmosis.h index c654f744d..b64daf9a8 100644 --- a/lib/firmware/fsm_msg_osmosis.h +++ b/lib/firmware/fsm_msg_osmosis.h @@ -1,7 +1,16 @@ -#include -#define OSMOSIS_PRECISION 6 #define OSMOSIS_LP_ASSET_PRECISION 18 +static bool osmosis_formatAmountOrFail(char* out, size_t out_len, + const char* value, const char* denom) { + if (osmosis_formatAmount(out, out_len, value, denom)) return true; + + osmosis_signAbort(); + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Invalid Osmosis amount or denomination"); + layoutHome(); + return false; +} + void fsm_msgOsmosisGetAddress(const OsmosisGetAddress* msg) { RESP_INIT(OsmosisAddress); @@ -132,7 +141,8 @@ void fsm_msgOsmosisMsgAck(const OsmosisMsgAck* msg) { /** Confirm required transaction parameters exist */ if (msg->has_send) { - if (!msg->send.has_to_address || !msg->send.has_amount) { + if (!msg->send.has_to_address || !msg->send.has_amount || + !msg->send.has_denom) { osmosis_signAbort(); fsm_sendFailure(FailureType_Failure_FirmwareError, _("Message is missing required parameters")); @@ -140,27 +150,28 @@ void fsm_msgOsmosisMsgAck(const OsmosisMsgAck* msg) { return; } - float amount = atof(msg->send.amount); - const char* denom = msg->send.denom; - if (!strcmp(msg->send.denom, "uosmo")) { - amount /= pow(10, OSMOSIS_PRECISION); - denom = "OSMO"; + char amount_str[OSMOSIS_AMOUNT_STR_LEN]; + if (!osmosis_formatAmountOrFail(amount_str, sizeof(amount_str), + msg->send.amount, msg->send.denom)) { + return; } - char amount_str[103]; - snprintf(amount_str, sizeof(amount_str) - 1, "%.6f %s", amount, denom); - - /** Confirm transaction parameters on screen */ - if (!confirm_transaction_output( - ButtonRequestType_ButtonRequest_ConfirmOutput, amount_str, - msg->send.to_address)) { + // Amount and destination are independent renderer-measured disclosures. + // A single wrapped "Send ... to ..." body could hide the destination. + if (!confirm_bytes(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Send Amount", (const uint8_t*)amount_str, + strlen(amount_str)) || + !confirm_bytes(ButtonRequestType_ButtonRequest_ConfirmOutput, "Send To", + (const uint8_t*)msg->send.to_address, + strlen(msg->send.to_address))) { osmosis_signAbort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } - if (!osmosis_signTxUpdateMsgSend(msg->send.amount, msg->send.to_address)) { + if (!osmosis_signTxUpdateMsgSend(msg->send.amount, msg->send.to_address, + msg->send.denom)) { osmosis_signAbort(); fsm_sendFailure(FailureType_Failure_SyntaxError, "Failed to include send message in transaction"); @@ -171,7 +182,8 @@ void fsm_msgOsmosisMsgAck(const OsmosisMsgAck* msg) { } else if (msg->has_delegate) { /** Confirm required transaction parameters exist */ if (!msg->delegate.has_delegator_address || - !msg->delegate.has_validator_address || !msg->delegate.has_amount) { + !msg->delegate.has_validator_address || !msg->delegate.has_amount || + !msg->delegate.has_denom) { osmosis_signAbort(); fsm_sendFailure(FailureType_Failure_FirmwareError, _("Message is missing required parameters")); @@ -179,11 +191,11 @@ void fsm_msgOsmosisMsgAck(const OsmosisMsgAck* msg) { return; } - float amount = atof(msg->delegate.amount); - const char* denom = msg->delegate.denom; - if (!strcmp(msg->delegate.denom, "uosmo")) { - amount /= pow(10, OSMOSIS_PRECISION); - denom = "OSMO"; + char amount_str[OSMOSIS_AMOUNT_STR_LEN]; + if (!osmosis_formatAmountOrFail(amount_str, sizeof(amount_str), + msg->delegate.amount, + msg->delegate.denom)) { + return; } /** Confirm transaction parameters on-screen */ @@ -203,8 +215,8 @@ void fsm_msgOsmosisMsgAck(const OsmosisMsgAck* msg) { return; } - if (!confirm(ButtonRequestType_ButtonRequest_Other, "Confirm Amount", - "%.6f %s", amount, denom)) { + if (!confirm_bytes(ButtonRequestType_ButtonRequest_Other, "Confirm Amount", + (const uint8_t*)amount_str, strlen(amount_str))) { osmosis_signAbort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); @@ -223,7 +235,8 @@ void fsm_msgOsmosisMsgAck(const OsmosisMsgAck* msg) { } else if (msg->has_undelegate) { /** Confirm required transaction parameters exist */ if (!msg->undelegate.has_delegator_address || - !msg->undelegate.has_validator_address || !msg->undelegate.has_amount) { + !msg->undelegate.has_validator_address || !msg->undelegate.has_amount || + !msg->undelegate.has_denom) { osmosis_signAbort(); fsm_sendFailure(FailureType_Failure_FirmwareError, _("Message is missing required parameters")); @@ -231,11 +244,11 @@ void fsm_msgOsmosisMsgAck(const OsmosisMsgAck* msg) { return; } - float amount = atof(msg->undelegate.amount); - const char* denom = msg->undelegate.denom; - if (!strcmp(msg->undelegate.denom, "uosmo")) { - amount /= pow(10, OSMOSIS_PRECISION); - denom = "OSMO"; + char amount_str[OSMOSIS_AMOUNT_STR_LEN]; + if (!osmosis_formatAmountOrFail(amount_str, sizeof(amount_str), + msg->undelegate.amount, + msg->undelegate.denom)) { + return; } /** Confirm transaction parameters on-screen */ @@ -255,8 +268,8 @@ void fsm_msgOsmosisMsgAck(const OsmosisMsgAck* msg) { return; } - if (!confirm(ButtonRequestType_ButtonRequest_Other, "Confirm Amount", - "%.6f %s", amount, denom)) { + if (!confirm_bytes(ButtonRequestType_ButtonRequest_Other, "Confirm Amount", + (const uint8_t*)amount_str, strlen(amount_str))) { osmosis_signAbort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); @@ -285,44 +298,45 @@ void fsm_msgOsmosisMsgAck(const OsmosisMsgAck* msg) { return; } - char insoamt[33] = {0}; - uint8_t outsoamt[34] = {0}; - strlcpy(insoamt, msg->lp_add.share_out_amount, - sizeof(msg->lp_add.share_out_amount)); - - if (base_to_precision(outsoamt, (uint8_t*)insoamt, sizeof(outsoamt), - strlen(insoamt), OSMOSIS_LP_ASSET_PRECISION) < 0) { + char outsoamt[34] = {0}; + if (base_to_precision( + (uint8_t*)outsoamt, (const uint8_t*)msg->lp_add.share_out_amount, + sizeof(outsoamt), strlen(msg->lp_add.share_out_amount), + OSMOSIS_LP_ASSET_PRECISION) < 0) { osmosis_signAbort(); - fsm_sendFailure(FailureType_Failure_Other, NULL); + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Invalid LP share amount"); layoutHome(); return; } - float amount_in_max_b = atof(msg->lp_add.amount_in_max_b); - const char* denom_in_max_b = msg->lp_add.denom_in_max_b; - if (!strcmp(msg->lp_add.denom_in_max_b, "uosmo")) { - amount_in_max_b /= pow(10, OSMOSIS_PRECISION); - denom_in_max_b = "OSMO"; + char amount_in_max_b_str[OSMOSIS_AMOUNT_STR_LEN]; + if (!osmosis_formatAmountOrFail( + amount_in_max_b_str, sizeof(amount_in_max_b_str), + msg->lp_add.amount_in_max_b, msg->lp_add.denom_in_max_b)) { + return; } - float amount_in_max_a = atof(msg->lp_add.amount_in_max_a); - const char* denom_in_max_a = msg->lp_add.denom_in_max_a; - if (!strcmp(msg->lp_add.denom_in_max_a, "uosmo")) { - amount_in_max_a /= pow(10, OSMOSIS_PRECISION); - denom_in_max_a = "OSMO"; + char amount_in_max_a_str[OSMOSIS_AMOUNT_STR_LEN]; + if (!osmosis_formatAmountOrFail( + amount_in_max_a_str, sizeof(amount_in_max_a_str), + msg->lp_add.amount_in_max_a, msg->lp_add.denom_in_max_a)) { + return; } /** Confirm transaction parameters on-screen */ - if (!confirm(ButtonRequestType_ButtonRequest_Other, "Add Liquidity", - "Deposit %.6f %s and...", amount_in_max_b, denom_in_max_b)) { + if (!confirm_bytes(ButtonRequestType_ButtonRequest_Other, "Max Deposit A", + (const uint8_t*)amount_in_max_a_str, + strlen(amount_in_max_a_str))) { osmosis_signAbort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } - if (!confirm(ButtonRequestType_ButtonRequest_Other, "Add Liquidity", - "... %.6f %s?", amount_in_max_a, denom_in_max_a)) { + if (!confirm_bytes(ButtonRequestType_ButtonRequest_Other, "Max Deposit B", + (const uint8_t*)amount_in_max_b_str, + strlen(amount_in_max_b_str))) { osmosis_signAbort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); @@ -330,16 +344,16 @@ void fsm_msgOsmosisMsgAck(const OsmosisMsgAck* msg) { } if (!confirm(ButtonRequestType_ButtonRequest_Other, "Confirm Pool ID", - "%lld", msg->lp_add.pool_id)) { + "%" PRIu64, msg->lp_add.pool_id)) { osmosis_signAbort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } - if (!confirm(ButtonRequestType_ButtonRequest_Other, - "Confirm Share Out Amount", "Receive %s GAMM-%lld shares?", - outsoamt, msg->lp_add.pool_id)) { + if (!confirm_bytes(ButtonRequestType_ButtonRequest_Other, + "Minimum LP Shares", (const uint8_t*)outsoamt, + strlen(outsoamt))) { osmosis_signAbort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); @@ -372,45 +386,45 @@ void fsm_msgOsmosisMsgAck(const OsmosisMsgAck* msg) { return; } - char insoamt[33] = {0}; - uint8_t outsoamt[34] = {0}; - strlcpy(insoamt, msg->lp_remove.share_in_amount, - sizeof(msg->lp_remove.share_in_amount)); - - if (base_to_precision(outsoamt, (uint8_t*)insoamt, sizeof(outsoamt), - strlen(insoamt), OSMOSIS_LP_ASSET_PRECISION) < 0) { + char outsoamt[34] = {0}; + if (base_to_precision( + (uint8_t*)outsoamt, (const uint8_t*)msg->lp_remove.share_in_amount, + sizeof(outsoamt), strlen(msg->lp_remove.share_in_amount), + OSMOSIS_LP_ASSET_PRECISION) < 0) { osmosis_signAbort(); - fsm_sendFailure(FailureType_Failure_Other, NULL); + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Invalid LP share amount"); layoutHome(); return; } - float amount_out_min_b = atof(msg->lp_remove.amount_out_min_b); - const char* denom_out_min_b = msg->lp_remove.denom_out_min_b; - if (!strcmp(msg->lp_remove.denom_out_min_b, "uosmo")) { - amount_out_min_b /= pow(10, OSMOSIS_PRECISION); - denom_out_min_b = "OSMO"; + char amount_out_min_b_str[OSMOSIS_AMOUNT_STR_LEN]; + if (!osmosis_formatAmountOrFail( + amount_out_min_b_str, sizeof(amount_out_min_b_str), + msg->lp_remove.amount_out_min_b, msg->lp_remove.denom_out_min_b)) { + return; } - float amount_out_min_a = atof(msg->lp_remove.amount_out_min_a); - const char* denom_out_min_a = msg->lp_remove.denom_out_min_a; - if (!strcmp(msg->lp_remove.denom_out_min_a, "uosmo")) { - amount_out_min_a /= pow(10, OSMOSIS_PRECISION); - denom_out_min_a = "OSMO"; + char amount_out_min_a_str[OSMOSIS_AMOUNT_STR_LEN]; + if (!osmosis_formatAmountOrFail( + amount_out_min_a_str, sizeof(amount_out_min_a_str), + msg->lp_remove.amount_out_min_a, msg->lp_remove.denom_out_min_a)) { + return; } /** Confirm transaction parameters on-screen */ - if (!confirm(ButtonRequestType_ButtonRequest_Other, "Remove Liquidity", - "Withdraw %.6f %s and...", amount_out_min_b, - denom_out_min_b)) { + if (!confirm_bytes(ButtonRequestType_ButtonRequest_Other, + "Minimum Output A", (const uint8_t*)amount_out_min_a_str, + strlen(amount_out_min_a_str))) { osmosis_signAbort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } - if (!confirm(ButtonRequestType_ButtonRequest_Other, "Remove Liquidity", - "... %.6f %s ?", amount_out_min_a, denom_out_min_a)) { + if (!confirm_bytes(ButtonRequestType_ButtonRequest_Other, + "Minimum Output B", (const uint8_t*)amount_out_min_b_str, + strlen(amount_out_min_b_str))) { osmosis_signAbort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); @@ -418,16 +432,16 @@ void fsm_msgOsmosisMsgAck(const OsmosisMsgAck* msg) { } if (!confirm(ButtonRequestType_ButtonRequest_Other, "Confirm Pool ID", - "%lld", msg->lp_remove.pool_id)) { + "%" PRIu64, msg->lp_remove.pool_id)) { osmosis_signAbort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } - if (!confirm(ButtonRequestType_ButtonRequest_Other, "Pool share amount", - "Redeem %s GAMM-%lld shares?", outsoamt, - msg->lp_remove.pool_id)) { + if (!confirm_bytes(ButtonRequestType_ButtonRequest_Other, + "LP Shares to Redeem", (const uint8_t*)outsoamt, + strlen(outsoamt))) { osmosis_signAbort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); @@ -450,7 +464,7 @@ void fsm_msgOsmosisMsgAck(const OsmosisMsgAck* msg) { if (!msg->redelegate.has_delegator_address || !msg->redelegate.has_validator_src_address || !msg->redelegate.has_validator_dst_address || - !msg->redelegate.has_amount) { + !msg->redelegate.has_amount || !msg->redelegate.has_denom) { osmosis_signAbort(); fsm_sendFailure(FailureType_Failure_FirmwareError, _("Message is missing required parameters")); @@ -458,11 +472,24 @@ void fsm_msgOsmosisMsgAck(const OsmosisMsgAck* msg) { return; } - float amount = atof(msg->redelegate.amount) / pow(10, OSMOSIS_PRECISION); + if (strcmp(msg->redelegate.denom, "uosmo") != 0) { + osmosis_signAbort(); + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Only uosmo is supported for Osmosis redelegation"); + layoutHome(); + return; + } + + char amount_str[OSMOSIS_AMOUNT_STR_LEN]; + if (!osmosis_formatAmountOrFail(amount_str, sizeof(amount_str), + msg->redelegate.amount, + msg->redelegate.denom)) { + return; + } /** Confirm transaction parameters on-screen */ - if (!confirm(ButtonRequestType_ButtonRequest_Other, "Redelegate", - "Redelegate %.6f OSMO?", amount)) { + if (!confirm_bytes(ButtonRequestType_ButtonRequest_Other, "Redelegate", + (const uint8_t*)amount_str, strlen(amount_str))) { osmosis_signAbort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); @@ -559,24 +586,27 @@ void fsm_msgOsmosisMsgAck(const OsmosisMsgAck* msg) { return; } - float token_in_amount = atof(msg->swap.token_in_amount); - const char* token_in_denom = msg->swap.token_in_denom; - if (!strcmp(msg->swap.token_in_denom, "uosmo")) { - token_in_amount /= pow(10, OSMOSIS_PRECISION); - token_in_denom = "OSMO"; + char token_in_str[OSMOSIS_AMOUNT_STR_LEN]; + if (!osmosis_formatAmountOrFail(token_in_str, sizeof(token_in_str), + msg->swap.token_in_amount, + msg->swap.token_in_denom)) { + return; } - float token_out_min_amount = atof(msg->swap.token_out_min_amount); - const char* token_out_denom = msg->swap.token_out_denom; - if (!strcmp(msg->swap.token_out_denom, "uosmo")) { - token_out_min_amount /= pow(10, OSMOSIS_PRECISION); - token_out_denom = "OSMO"; + char token_out_min_str[OSMOSIS_AMOUNT_STR_LEN]; + if (!osmosis_formatAmountOrFail( + token_out_min_str, sizeof(token_out_min_str), + msg->swap.token_out_min_amount, msg->swap.token_out_denom)) { + return; } - /** Confirm transaction parameters on-screen */ - if (!confirm(ButtonRequestType_ButtonRequest_Other, "Swap", - "Swap %.6f %s for at least %.6f %s?", token_in_amount, - token_in_denom, token_out_min_amount, token_out_denom)) { + // Each signed asset is paged independently so neither the input denom nor + // the minimum output can fall below the OLED's three visible body rows. + if (!confirm_bytes(ButtonRequestType_ButtonRequest_Other, "Swap Input", + (const uint8_t*)token_in_str, strlen(token_in_str)) || + !confirm_bytes(ButtonRequestType_ButtonRequest_Other, "Minimum Output", + (const uint8_t*)token_out_min_str, + strlen(token_out_min_str))) { osmosis_signAbort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); @@ -584,7 +614,7 @@ void fsm_msgOsmosisMsgAck(const OsmosisMsgAck* msg) { } if (!confirm(ButtonRequestType_ButtonRequest_Other, "Confirm Pool ID", - "%lld", msg->swap.pool_id)) { + "%" PRIu64, msg->swap.pool_id)) { osmosis_signAbort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); @@ -609,7 +639,8 @@ void fsm_msgOsmosisMsgAck(const OsmosisMsgAck* msg) { !msg->ibc_transfer.has_source_port || !msg->ibc_transfer.has_revision_height || !msg->ibc_transfer.has_revision_number || - !msg->ibc_transfer.has_denom) { + !msg->ibc_transfer.has_denom || !msg->ibc_transfer.has_amount || + !msg->ibc_transfer.has_receiver) { osmosis_signAbort(); fsm_sendFailure(FailureType_Failure_FirmwareError, _("Message is missing required parameters")); @@ -617,16 +648,16 @@ void fsm_msgOsmosisMsgAck(const OsmosisMsgAck* msg) { return; } - float amount = atof(msg->ibc_transfer.amount); - const char* denom = msg->ibc_transfer.denom; - if (!strcmp(msg->ibc_transfer.denom, "uosmo")) { - amount /= pow(10, OSMOSIS_PRECISION); - denom = "OSMO"; + char amount_str[OSMOSIS_AMOUNT_STR_LEN]; + if (!osmosis_formatAmountOrFail(amount_str, sizeof(amount_str), + msg->ibc_transfer.amount, + msg->ibc_transfer.denom)) { + return; } /** Confirm transaction parameters on-screen */ - if (!confirm(ButtonRequestType_ButtonRequest_Other, "IBC Transfer", - "Transfer %.6f %s?", amount, denom)) { + if (!confirm_bytes(ButtonRequestType_ButtonRequest_Other, "IBC Transfer", + (const uint8_t*)amount_str, strlen(amount_str))) { osmosis_signAbort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); @@ -702,8 +733,8 @@ void fsm_msgOsmosisMsgAck(const OsmosisMsgAck* msg) { } if (sign_tx->has_memo && (strlen(sign_tx->memo) > 0)) { - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmMemo, _("Memo"), "%s", - sign_tx->memo)) { + if (!confirm_bytes(ButtonRequestType_ButtonRequest_ConfirmMemo, _("Memo"), + (const uint8_t*)sign_tx->memo, strlen(sign_tx->memo))) { osmosis_signAbort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); @@ -748,4 +779,4 @@ void fsm_msgOsmosisMsgAck(const OsmosisMsgAck* msg) { osmosis_signAbort(); layoutHome(); msg_write(MessageType_MessageType_OsmosisSignedTx, resp); -} \ No newline at end of file +} diff --git a/lib/firmware/fsm_msg_ripple.h b/lib/firmware/fsm_msg_ripple.h index ddd25af35..bbe7fa6cf 100644 --- a/lib/firmware/fsm_msg_ripple.h +++ b/lib/firmware/fsm_msg_ripple.h @@ -109,6 +109,21 @@ void fsm_msgRippleSignTx(RippleSignTx* msg) { } } + if (msg->has_memo && msg->memo[0] != '\0') { + /* Page the COMPLETE memo (72-char ASCII / 40-byte hex pages) like every + * other memo surface. A single unpaged confirm renders only 3 OLED lines, + * silently drops the overflow, and honors embedded newlines — so a memo + * whose visible first line looks benign could carry ~180 signed-but-unseen + * bytes into the Memos field that exchanges and bridges use for deposit + * routing. */ + if (!thorchain_confirm_full_memo("Memo", msg->memo, strlen(msg->memo))) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled"); + layoutHome(); + return; + } + } + if (!confirm(ButtonRequestType_ButtonRequest_SignTx, "Transaction", "Really send %s, with a transaction fee of %s?", amount_string, fee_string)) { diff --git a/lib/firmware/fsm_msg_solana.h b/lib/firmware/fsm_msg_solana.h index ea3072b07..675219449 100644 --- a/lib/firmware/fsm_msg_solana.h +++ b/lib/firmware/fsm_msg_solana.h @@ -40,6 +40,86 @@ static void solana_pubkeyToStr(const uint8_t key[SOL_PUBKEY_SIZE], char* out, key[31]); } +/* Confirm one labelled account address on its own screen. Factoring this keeps + * the many "which account is being acted on" disclosures small (ROM matters on + * the zcash-privacy variant). Returns false if the user rejects. */ +static bool solana_confirm_account(const char* title, const char* label, + const uint8_t key[SOL_PUBKEY_SIZE]) { + char s[45]; + solana_pubkeyToStr(key, s, sizeof(s)); + return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, "%s\n%s", + label, s); +} + +/* A host-supplied token symbol is untrusted and only length-capped by the + * proto. Reject anything but printable ASCII so it cannot inject newlines or + * control bytes that push the mint or recipient off the confirm screen. */ +static bool solana_symbol_is_safe(const char* sym) { + if (!sym || sym[0] == '\0') return false; + for (const char* p = sym; *p; p++) { + if ((uint8_t)*p < 0x20 || (uint8_t)*p > 0x7e) return false; + } + return true; +} + +static bool solana_confirm_memo(const char* title, const uint8_t* s, + uint16_t len) { + return confirm_bytes(ButtonRequestType_ButtonRequest_ConfirmMemo, title, s, + len); +} + +/* Priority fee = ceil(cu_price_micro_lamports * cu_limit / 1e6) lamports, and + * it is charged even if the transaction fails. Compute-budget instructions show + * only raw CU price/limit with no units, so a malicious host could bury a large + * SOL loss there. When the tx sets a CU price, show the fee payer and the + * MAXIMUM priority fee in SOL (using the 1.4M-CU protocol cap when no explicit + * limit is set, so the figure is never an understatement). Returns false on + * user reject. */ +static bool solana_confirm_priority_fee(const SolanaParsedTx* tx, + const uint8_t* fee_payer) { + uint64_t price = 0; + bool have_price = false; + uint64_t cu_limit = 0; + bool have_limit = false; + for (uint8_t i = 0; i < tx->num_instructions; i++) { + const SolanaParsedInstruction* pi = &tx->instructions[i]; + if (pi->type == SOL_INSTR_COMPUTE_BUDGET_UNIT_PRICE) { + price = pi->extra_value; + have_price = true; + } else if (pi->type == SOL_INSTR_COMPUTE_BUDGET_UNIT_LIMIT) { + cu_limit = pi->extra_value; + have_limit = true; + } + } + if (!have_price || price == 0) { + return true; /* no priority fee to disclose */ + } + const uint64_t kMaxCuLimit = 1400000u; /* Solana per-tx CU cap */ + uint64_t limit = have_limit ? cu_limit : kMaxCuLimit; + + /* Overflow-safe ceil(price*limit/1e6); false => the fee exceeds u64 lamports + * (>1.8e10 SOL) — refuse to sign rather than display a wrapped/zero figure. + */ + uint64_t lamports = 0; + if (!solana_priority_fee_lamports(price, limit, &lamports)) { + (void)confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "Fee", + "Priority fee too large to display. Refusing to sign."); + return false; + } + char fee_str[40]; + solana_formatAmount(fee_str, sizeof(fee_str), lamports); + if (fee_payer) { + char payer_str[45]; + solana_pubkeyToStr(fee_payer, payer_str, sizeof(payer_str)); + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "Fee", + "Fee payer\n%s", payer_str)) { + return false; + } + } + return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "Fee", + "Max priority fee\n%s", fee_str); +} + /* Confirm a single parsed instruction */ static bool solana_confirmInstruction(const SolanaParsedInstruction* pi, const SolanaSignTx* msg, uint8_t idx, @@ -65,10 +145,14 @@ static bool solana_confirmInstruction(const SolanaParsedInstruction* pi, } case SOL_INSTR_SYSTEM_ADVANCE_NONCE: - return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, - "Advance nonce account?"); + return solana_confirm_account(title, "Advance nonce account", pi->from); case SOL_INSTR_SYSTEM_WITHDRAW_NONCE: { + /* Withdrawing the full balance can destroy the nonce account — show it. + */ + if (!solana_confirm_account(title, "Nonce account", pi->from)) { + return false; + } char amount_str[32]; solana_formatAmount(amount_str, sizeof(amount_str), pi->lamports); char to_str[45]; @@ -77,11 +161,23 @@ static bool solana_confirmInstruction(const SolanaParsedInstruction* pi, "Withdraw nonce %s to %s?", amount_str, to_str); } - case SOL_INSTR_SYSTEM_INITIALIZE_NONCE: + case SOL_INSTR_SYSTEM_INITIALIZE_NONCE: { + if (!solana_confirm_account(title, "Initialize nonce account", + pi->from)) { + return false; + } + /* Show the nonce authority being set — it can later advance/withdraw. */ + char auth_str[45]; + solana_pubkeyToStr(pi->authority, auth_str, sizeof(auth_str)); return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, - "Initialize nonce account?"); + "Nonce authority %s?", auth_str); + } case SOL_INSTR_SYSTEM_AUTHORIZE_NONCE: { + /* Show WHICH nonce account is rekeyed, not just the new authority. */ + if (!solana_confirm_account(title, "Nonce account", pi->from)) { + return false; + } char auth_str[45]; solana_pubkeyToStr(pi->extra, auth_str, sizeof(auth_str)); return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, @@ -89,41 +185,136 @@ static bool solana_confirmInstruction(const SolanaParsedInstruction* pi, } case SOL_INSTR_SYSTEM_ASSIGN: { - char prog_str[45]; - solana_pubkeyToStr(pi->extra, prog_str, sizeof(prog_str)); - return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, - "Assign account to %s?", prog_str); + /* Assign hands control of an account to a program — show WHICH account, + * not just the new owner. */ + if (!solana_confirm_account(title, "Assign account", pi->from)) { + return false; + } + return solana_confirm_account(title, "to owner program", pi->extra); } - case SOL_INSTR_SYSTEM_ALLOCATE: + case SOL_INSTR_SYSTEM_ALLOCATE: { + if (!solana_confirm_account(title, "Allocate for account", pi->from)) { + return false; + } return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, "Allocate %llu bytes?", (unsigned long long)pi->extra_value); + } - case SOL_INSTR_TOKEN_TRANSFER: - case SOL_INSTR_TOKEN_TRANSFER_CHECKED: { + case SOL_INSTR_TOKEN_TRANSFER: { char to_str[45]; solana_pubkeyToStr(pi->to, to_str, sizeof(to_str)); - /* Try to find token info from host-provided metadata */ const SolanaTokenInfo* ti = NULL; - if (pi->has_mint) { + if (pi->has_mint && msg) { ti = solana_findTokenInfo(msg, pi->mint); } - if (ti && ti->has_symbol && ti->has_decimals) { + /* The mint is the only authenticated token identity. Show it on its own + * screen — a host-controlled symbol shares no line with it, so it cannot + * push the mint off-view. */ + if (pi->has_mint) { + char mint_str[45]; + solana_pubkeyToStr(pi->mint, mint_str, sizeof(mint_str)); + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, + "Token mint\n%s", mint_str)) { + return false; + } + } + + /* Use the claimed symbol only when it is safe printable text; otherwise a + * raw token count, so an unvalidated symbol cannot manipulate the amount + * screen (the mint above still identifies the token). */ + if (ti && ti->has_symbol && ti->has_decimals && + solana_symbol_is_safe(ti->symbol)) { char amount_str[48]; solana_formatTokenAmount(amount_str, sizeof(amount_str), pi->amount, ti->symbol, (uint8_t)ti->decimals); return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, "Send %s to %s?", amount_str, to_str); - } else { - char amount_str[32]; - snprintf(amount_str, sizeof(amount_str), "%llu tokens", - (unsigned long long)pi->amount); + } + char amount_str[32]; + snprintf(amount_str, sizeof(amount_str), "%llu tokens", + (unsigned long long)pi->amount); + return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, + "Send %s to %s?", amount_str, to_str); + } + + case SOL_INSTR_TOKEN_TRANSFER_CHECKED: { + char to_str[45]; + solana_pubkeyToStr(pi->to, to_str, sizeof(to_str)); + + /* For TransferChecked, decimals come from the signed instruction + * bytes (pi->extra_u8) — host-supplied ti->decimals is untrusted. */ + const SolanaTokenInfo* ti = NULL; + if (pi->has_mint && msg) { + ti = solana_findTokenInfo(msg, pi->mint); + } + + /* Decide symbol trust before drawing the mint screen so its label can say + * whether the symbol is attested. Trust rules: + * - attestation present + verifies against a loaded signer -> trusted; + * - attestation present + INVALID -> reject the symbol entirely (an + * attacker offered a bad signature; never fall back to the claim); + * - no attestation (today's hosts) -> show the symbol next to the + * always-authenticated mint (unchanged behavior). */ + const char* symbol = NULL; + bool symbol_verified = false; + if (ti && ti->has_symbol && solana_symbol_is_safe(ti->symbol)) { + if (ti->has_signature) { + /* Trust the symbol only if the attestation verifies AND the attested + * decimals equal the signed instruction's decimals (pi->extra_u8) — + * otherwise the attested (mint,decimals,symbol) tuple disagrees with + * the transaction being signed and must not earn "verified". */ + if (solana_token_info_trusted(ti) && ti->decimals == pi->extra_u8) { + symbol = ti->symbol; + symbol_verified = true; + } + } else { + symbol = ti->symbol; + } + } + + /* Mint on its own screen (see TOKEN_TRANSFER): the authenticated identity + * cannot be pushed off-view by a host-controlled symbol. */ + if (pi->has_mint) { + char mint_str[45]; + solana_pubkeyToStr(pi->mint, mint_str, sizeof(mint_str)); + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, + "Token mint\n%s", mint_str)) { + return false; + } + } + + /* Name WHO attested the symbol, with the signer's fingerprint — aliases + * are host-chosen and not unique, so the fingerprint is what actually + * identifies the key. symbol_verified implies a signer is loaded for this + * key_id (solana_token_info_trusted verified against it), so both + * resolve; there is no "unknown" verified case. */ + if (symbol_verified) { + const char* alias = signed_metadata_signer_alias(ti->signer_key_id); + char fp[METADATA_FINGERPRINT_LEN] = {0}; + signed_metadata_signer_fingerprint((uint8_t)ti->signer_key_id, fp); + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, + "Token \"%s\"\nby %s %s", symbol, alias ? alias : "", + fp)) { + return false; + } + } + + if (symbol) { + char amount_str[48]; + solana_formatTokenAmount(amount_str, sizeof(amount_str), pi->amount, + symbol, pi->extra_u8); return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, "Send %s to %s?", amount_str, to_str); } + char amount_str[32]; + snprintf(amount_str, sizeof(amount_str), "%llu tokens", + (unsigned long long)pi->amount); + return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, + "Send %s to %s?", amount_str, to_str); } case SOL_INSTR_TOKEN_APPROVE: { @@ -135,8 +326,8 @@ static bool solana_confirmInstruction(const SolanaParsedInstruction* pi, } case SOL_INSTR_TOKEN_REVOKE: - return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, - "Revoke token approval?"); + return solana_confirm_account(title, "Revoke approval on account", + pi->from); case SOL_INSTR_TOKEN_SET_AUTHORITY: { char auth_str[45]; @@ -145,92 +336,190 @@ static bool solana_confirmInstruction(const SolanaParsedInstruction* pi, "Set token authority to %s?", auth_str); } - case SOL_INSTR_TOKEN_MINT_TO: + case SOL_INSTR_TOKEN_MINT_TO: { + /* Show the mint (which token) and the recipient, not just the amount. */ + char mint_str[45]; + char to_str[45]; + solana_pubkeyToStr(pi->mint, mint_str, sizeof(mint_str)); + solana_pubkeyToStr(pi->to, to_str, sizeof(to_str)); + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, + "Mint token\n%s", mint_str)) { + return false; + } return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, - "Mint %llu tokens?", (unsigned long long)pi->amount); + "Mint %llu\nto %s?", (unsigned long long)pi->amount, + to_str); + } - case SOL_INSTR_TOKEN_BURN: + case SOL_INSTR_TOKEN_BURN: { + /* Show the mint (which token) and the source account burned from. */ + char mint_str[45]; + char from_str[45]; + solana_pubkeyToStr(pi->mint, mint_str, sizeof(mint_str)); + solana_pubkeyToStr(pi->from, from_str, sizeof(from_str)); + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, + "Burn token\n%s", mint_str)) { + return false; + } return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, - "Burn %llu tokens?", (unsigned long long)pi->amount); + "Burn %llu\nfrom %s?", (unsigned long long)pi->amount, + from_str); + } - case SOL_INSTR_TOKEN_CLOSE_ACCOUNT: - return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, - "Close token account?"); + case SOL_INSTR_TOKEN_CLOSE_ACCOUNT: { + /* Closing sweeps the account's ENTIRE lamport balance (which the device + * cannot see, e.g. wrapped SOL) to the destination — show both the + * account being closed and where its balance goes. */ + if (!solana_confirm_account(title, "Close token account", pi->from)) { + return false; + } + return solana_confirm_account(title, "send balance to", pi->to); + } - case SOL_INSTR_TOKEN_FREEZE_ACCOUNT: - return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, - "Freeze token account?"); + case SOL_INSTR_TOKEN_FREEZE_ACCOUNT: { + /* Show the account frozen AND its mint (freeze authority is per-mint). */ + if (!solana_confirm_account(title, "Freeze token account", pi->from)) { + return false; + } + return solana_confirm_account(title, "of mint", pi->mint); + } - case SOL_INSTR_TOKEN_THAW_ACCOUNT: - return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, - "Thaw token account?"); + case SOL_INSTR_TOKEN_THAW_ACCOUNT: { + if (!solana_confirm_account(title, "Thaw token account", pi->from)) { + return false; + } + return solana_confirm_account(title, "of mint", pi->mint); + } case SOL_INSTR_TOKEN_SYNC_NATIVE: - return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, - "Sync wrapped SOL?"); + return solana_confirm_account(title, "Sync wrapped SOL account", + pi->from); case SOL_INSTR_STAKE_DELEGATE: { - return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, - "Delegate stake?"); + /* Show which stake account is delegated, not just the vote account — a + * host could delegate a different stake account of the same authority. */ + if (!solana_confirm_account(title, "Delegate stake account", pi->from)) { + return false; + } + return solana_confirm_account(title, "to vote account", pi->to); } case SOL_INSTR_STAKE_WITHDRAW: { + /* Show WHICH stake account is drained (a host could substitute another of + * the same authority) and the recipient. */ + if (!solana_confirm_account(title, "Withdraw from stake", pi->from)) { + return false; + } char amount_str[32]; solana_formatAmount(amount_str, sizeof(amount_str), pi->lamports); + char to_str[45]; + solana_pubkeyToStr(pi->to, to_str, sizeof(to_str)); return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, - "Withdraw %s from stake?", amount_str); + "Withdraw %s\nto %s?", amount_str, to_str); } case SOL_INSTR_STAKE_AUTHORIZE: { + /* Show WHICH stake account is rekeyed (a host could substitute another of + * the same signer) and which power is handed over (staker vs withdrawer). + */ + if (!solana_confirm_account(title, "Stake account", pi->from)) { + return false; + } char auth_str[45]; solana_pubkeyToStr(pi->extra, auth_str, sizeof(auth_str)); + const char* role = pi->extra_u8 == 0 ? "staker" : "withdrawer"; return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, - "Authorize stake to %s?", auth_str); + "Authorize %s\nto %s?", role, auth_str); } case SOL_INSTR_STAKE_SPLIT: { + /* Show the source stake account being split, and the destination. */ + if (!solana_confirm_account(title, "Split from stake", pi->from)) { + return false; + } char amount_str[32]; solana_formatAmount(amount_str, sizeof(amount_str), pi->lamports); + char to_str[45]; + solana_pubkeyToStr(pi->to, to_str, sizeof(to_str)); return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, - "Split stake by %s?", amount_str); + "Split %s\nto %s?", amount_str, to_str); } case SOL_INSTR_STAKE_DEACTIVATE: - return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, - "Deactivate stake?"); + return solana_confirm_account(title, "Deactivate stake account", + pi->from); - case SOL_INSTR_STAKE_MERGE: + case SOL_INSTR_STAKE_MERGE: { + /* Show source and destination — merge moves the source's stake into the + * destination account. */ + char from_str[45]; + char to_str[45]; + solana_pubkeyToStr(pi->from, from_str, sizeof(from_str)); + solana_pubkeyToStr(pi->to, to_str, sizeof(to_str)); + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, + "Merge stake from\n%s", from_str)) { + return false; + } return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, - "Merge stake accounts?"); + "Merge stake into\n%s?", to_str); + } case SOL_INSTR_VOTE_AUTHORIZE: { + /* Show WHICH vote account is rekeyed; Voter vs Withdrawer both matter + * (the withdrawer can move the vote account's SOL). */ + if (!solana_confirm_account(title, "Vote account", pi->from)) { + return false; + } char auth_str[45]; solana_pubkeyToStr(pi->extra, auth_str, sizeof(auth_str)); + const char* role = pi->extra_u8 == 0 ? "voter" : "withdrawer"; return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, - "Authorize vote to %s?", auth_str); + "Authorize vote %s\nto %s?", role, auth_str); } case SOL_INSTR_VOTE_WITHDRAW: { + /* Show the source vote account and the recipient. */ + if (!solana_confirm_account(title, "Withdraw from vote", pi->from)) { + return false; + } char amount_str[32]; solana_formatAmount(amount_str, sizeof(amount_str), pi->lamports); + char to_str[45]; + solana_pubkeyToStr(pi->to, to_str, sizeof(to_str)); return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, - "Withdraw vote %s?", amount_str); + "Withdraw vote %s\nto %s?", amount_str, to_str); } case SOL_INSTR_VOTE_UPDATE_VALIDATOR: { - char validator_str[45]; - solana_pubkeyToStr(pi->extra, validator_str, sizeof(validator_str)); - return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, - "Update validator to %s?", validator_str); + /* The new validator is the account (pi->extra now holds account index 1, + * not fabricated instruction bytes); show the vote account too. */ + if (!solana_confirm_account(title, "Vote account", pi->from)) { + return false; + } + return solana_confirm_account(title, "New validator identity", pi->extra); } - case SOL_INSTR_VOTE_UPDATE_COMMISSION: + case SOL_INSTR_VOTE_UPDATE_COMMISSION: { + if (!solana_confirm_account(title, "Vote account", pi->from)) { + return false; + } return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, "Set vote commission to %u%%?", pi->extra_u8); + } - case SOL_INSTR_ATA_CREATE: + case SOL_INSTR_ATA_CREATE: { + /* Show the wallet owner and the token mint the new account is for. */ + char owner_str[45]; + char mint_str[45]; + solana_pubkeyToStr(pi->authority, owner_str, sizeof(owner_str)); + solana_pubkeyToStr(pi->mint, mint_str, sizeof(mint_str)); + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, + "Create token account\nfor %s", owner_str)) { + return false; + } return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, - "Create associated token account?"); + "Token account mint\n%s?", mint_str); + } case SOL_INSTR_COMPUTE_BUDGET_HEAP_FRAME: return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, @@ -253,8 +542,11 @@ static bool solana_confirmInstruction(const SolanaParsedInstruction* pi, (unsigned long long)pi->extra_value); case SOL_INSTR_MEMO: - return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, title, - "Memo attached"); + /* Page the FULL memo — swap intents (e.g. THORChain '=:ETH.ETH:...') ride + * in the memo, so a byte-count summary would hide where the funds go. + * Printable memos page as text, binary memos page as hex; nothing is + * hidden and the tx stays clear-signable regardless of length. */ + return solana_confirm_memo(title, pi->data, pi->data_len); case SOL_INSTR_UNKNOWN: default: { @@ -287,6 +579,24 @@ static bool solana_signerInTx(const uint8_t* pubkey, const SolanaParsedTx* tx) { return false; } +/* The single verified-transaction confirmation flow shared by BOTH + * SolanaSignTx and SolanaSignMessage (transaction-shaped messages are equally + * broadcastable), so their security screens — per-instruction disclosure AND + * the priority-fee screen — cannot drift apart. `msg` is NULL on the + * SignMessage path (host token symbols are unavailable there). Returns false if + * the user rejects any screen. */ +static bool solana_confirm_verified_tx(const SolanaParsedTx* parsed, + const SolanaSignTx* msg) { + for (uint8_t i = 0; i < parsed->num_instructions; i++) { + if (!solana_confirmInstruction(&parsed->instructions[i], msg, i, + parsed->num_instructions)) { + return false; + } + } + return solana_confirm_priority_fee( + parsed, parsed->num_accounts > 0 ? parsed->accounts[0] : NULL); +} + void fsm_msgSolanaGetAddress(const SolanaGetAddress* msg) { RESP_INIT(SolanaAddress); @@ -386,16 +696,13 @@ void fsm_msgSolanaSignTx(const SolanaSignTx* msg) { } if (tx_review == SOL_TX_REVIEW_VERIFIED) { - /* Per-instruction confirmation for fully verified messages */ - for (uint8_t i = 0; i < parsed.num_instructions; i++) { - if (!solana_confirmInstruction(&parsed.instructions[i], msg, i, - parsed.num_instructions)) { - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_ActionCancelled, - _("Signing cancelled")); - layoutHome(); - return; - } + /* Per-instruction disclosure + priority fee, shared with SignMessage. */ + if (!solana_confirm_verified_tx(&parsed, msg)) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("Signing cancelled")); + layoutHome(); + return; } } else if (tx_review == SOL_TX_REVIEW_OPAQUE) { /* Unsupported or opaque message: allow explicit blind-sign only. */ @@ -458,13 +765,27 @@ void fsm_msgSolanaSignMessage(const SolanaSignMessage* msg) { return; } - /* AdvancedMode gate: Solana message signing has no domain separation. - * A signed message is indistinguishable from a signed transaction on - * the Solana network (both are raw Ed25519 over arbitrary bytes). - * A malicious dApp could craft a message that is also a valid tx. + /* Solana "message" signing has no domain separation: the signed bytes + * are indistinguishable from a transaction message on the network. + * If the payload actually parses as a fully-verifiable Solana + * transaction, treat it as one — clear-sign it per instruction instead + * of blind-signing a hex blob. Wallet integrations sign versioned (v0) + * swap transactions through this message, so this is the path that + * turns swap blind-signing into clear-signing. */ + /* Note: solana_inspectTx tolerates a 0x00 signature-count prefix, but + * here the signature covers the exact message bytes — only a payload + * that IS a tx message from byte 0 may be displayed as one. */ + SolanaParsedTx parsed; + bool is_verified_tx = msg->message.bytes[0] != 0 && + solana_inspectTx(msg->message.bytes, msg->message.size, + &parsed) == SOL_TX_REVIEW_VERIFIED; + + /* AdvancedMode gate for anything we cannot verify: a malicious dApp + * could craft a "message" that is also a valid tx. * See: https://github.com/trezor/trezor-firmware/issues/4371 - * Require AdvancedMode to proceed — same gate as ETH blind-signing. */ - if (!storage_isPolicyEnabled("AdvancedMode")) { + * Same gate as ETH blind-signing. Fully verified transactions are + * clear-signed below and need no gate — the user sees the contents. */ + if (!is_verified_tx && !storage_isPolicyEnabled("AdvancedMode")) { (void)review(ButtonRequestType_ButtonRequest_Other, "Blocked", "Solana message signing is experimental. " "Enable AdvancedMode in device settings."); @@ -489,44 +810,43 @@ void fsm_msgSolanaSignMessage(const SolanaSignMessage* msg) { if (!node) return; hdnode_fill_public_key(node); - /* Always require on-device confirmation (matches Ethereum behavior). - * Display message content if printable, hex preview otherwise. */ - { - char msgBuf[129] = {0}; - const char* typeLabel; - bool printable = true; - for (unsigned i = 0; i < msg->message.size; i++) { - if (msg->message.bytes[i] < 0x20 || msg->message.bytes[i] > 0x7e) { - printable = false; - break; - } + if (is_verified_tx) { + /* Clear-sign path: same rules as SolanaSignTx. */ + if (!solana_signerInTx(node->public_key + 1, &parsed)) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_Other, + _("Derived key is not a signer for this tx")); + layoutHome(); + return; } - if (printable && msg->message.size <= sizeof(msgBuf) - 1) { - typeLabel = "Sign Message"; - memcpy(msgBuf, msg->message.bytes, msg->message.size); - msgBuf[msg->message.size] = '\0'; - } else { - typeLabel = "Sign Bytes"; - /* Show hex preview (up to 64 hex chars = 32 bytes) */ - unsigned show = msg->message.size; - if (show > 32) show = 32; - for (unsigned i = 0; i < show; i++) { - snprintf(&msgBuf[2 * i], 3, "%02x", msg->message.bytes[i]); - } - msgBuf[2 * show] = '\0'; - if (msg->message.size > 32) { - snprintf(&msgBuf[64], sizeof(msgBuf) - 64, "... (%u bytes)", - (unsigned)msg->message.size); - } + /* Same verified-tx flow as SolanaSignTx (incl. the priority-fee screen), so + * a broadcastable transaction-shaped message can't dodge a security screen. + * msg=NULL: host token symbols aren't provided on the message path. */ + if (!solana_confirm_verified_tx(&parsed, NULL)) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("Signing cancelled")); + layoutHome(); + return; } - if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _(typeLabel), - "%s", msgBuf)) { + if (!confirm(ButtonRequestType_ButtonRequest_SignTx, "Solana", + "Sign this Solana transaction?")) { memzero(node, sizeof(*node)); fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled")); layoutHome(); return; } + } else if (!confirm_bytes(ButtonRequestType_ButtonRequest_ProtectCall, + "Sign Solana Message", msg->message.bytes, + msg->message.size)) { + /* AdvancedMode permits the opaque primitive, but every signed byte still + * has to be reviewable; previews recreate the hidden-suffix bug. */ + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("Signing cancelled")); + layoutHome(); + return; } /* Ed25519 sign */ @@ -604,45 +924,14 @@ void fsm_msgSolanaSignOffchainMessage(const SolanaSignOffchainMessage* msg) { if (!node) return; hdnode_fill_public_key(node); - /* Confirm dialog. Format 0 (ASCII) is always renderable; format 1 - * (UTF-8 limited) we render as printable bytes only — non-printable - * sequences fall through to a hex preview to avoid encoding - * surprises on the OLED. */ - { - char msgBuf[129] = {0}; - const char* typeLabel; - bool printable = true; - for (unsigned i = 0; i < msg->message.size; i++) { - if (msg->message.bytes[i] < 0x20 || msg->message.bytes[i] > 0x7e) { - printable = false; - break; - } - } - if (printable && msg->message.size <= sizeof(msgBuf) - 1) { - typeLabel = "Off-chain Message"; - memcpy(msgBuf, msg->message.bytes, msg->message.size); - msgBuf[msg->message.size] = '\0'; - } else { - typeLabel = "Off-chain Bytes"; - unsigned show = msg->message.size; - if (show > 32) show = 32; - for (unsigned i = 0; i < show; i++) { - snprintf(&msgBuf[2 * i], 3, "%02x", msg->message.bytes[i]); - } - msgBuf[2 * show] = '\0'; - if (msg->message.size > 32) { - snprintf(&msgBuf[64], sizeof(msgBuf) - 64, "... (%u bytes)", - (unsigned)msg->message.size); - } - } - if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _(typeLabel), - "%s", msgBuf)) { - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_ActionCancelled, - _("Signing cancelled")); - layoutHome(); - return; - } + if (!confirm_bytes(ButtonRequestType_ButtonRequest_ProtectCall, + "Sign Solana Off-chain Message", msg->message.bytes, + msg->message.size)) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("Signing cancelled")); + layoutHome(); + return; } if (!solana_offchain_message_sign(node, msg, resp)) { diff --git a/lib/firmware/fsm_msg_tendermint.h b/lib/firmware/fsm_msg_tendermint.h index 42a031e38..320acc55d 100644 --- a/lib/firmware/fsm_msg_tendermint.h +++ b/lib/firmware/fsm_msg_tendermint.h @@ -94,7 +94,7 @@ void fsm_msgTendermintSignTx(const TendermintSignTx* msg) { RESP_INIT(TendermintMsgRequest); if (!tendermint_signTxInit(node, (void*)msg, sizeof(TendermintSignTx), - msg->denom)) { + msg->denom, TENDERMINT_SIGNING_GENERIC)) { tendermint_signAbort(); memzero(node, sizeof(*node)); fsm_sendFailure(FailureType_Failure_FirmwareError, @@ -110,7 +110,20 @@ void fsm_msgTendermintSignTx(const TendermintSignTx* msg) { void fsm_msgTendermintMsgAck(const TendermintMsgAck* msg) { // Confirm transaction basics - CHECK_PARAM(tendermint_signingIsInited(), "Signing not in progress"); + CHECK_PARAM(tendermint_signingIsInited(TENDERMINT_SIGNING_GENERIC), + "Tendermint signing not in progress"); + const TendermintSignTx* sign_tx = + (const TendermintSignTx*)tendermint_getSignTx(); + if (!msg->has_chain_name || !msg->has_denom || + !msg->has_message_type_prefix || + !tendermint_signingConfigMatches(msg->chain_name, msg->denom, + msg->message_type_prefix)) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Tendermint ACK does not match signing session"); + layoutHome(); + return; + } if (!msg->has_send || !msg->send.has_to_address || !msg->send.has_amount) { tendermint_signAbort(); // 8 + ^14 + 13 + 1 = 36 @@ -124,23 +137,28 @@ void fsm_msgTendermintMsgAck(const TendermintMsgAck* msg) { } const CoinType* coin = fsm_getCoin(true, msg->chain_name); - if (!coin || !coin->has_coin_shortcut || !coin->has_decimals) { + if (!coin) { + tendermint_signAbort(); + layoutHome(); return; } - const TendermintSignTx* sign_tx = (TendermintSignTx*)tendermint_getSignTx(); - switch (msg->send.address_type) { case OutputAddressType_TRANSFER: default: { - char amount_str[32]; - char suffix[sizeof(coin->coin_shortcut) + - 1]; // sizeof(coin->coin_shortcut) includes space for the - // terminator - strlcpy(suffix, " ", sizeof(suffix)); - strlcat(suffix, coin->coin_shortcut, sizeof(suffix)); - bn_format_uint64(msg->send.amount, NULL, suffix, coin->decimals, 0, false, - amount_str, sizeof(amount_str)); + /* The host-supplied denomination is part of the signed Amino JSON. Do + * not relabel or rescale it using unrelated coin metadata. */ + char amount_str[48]; + const int amount_len = + snprintf(amount_str, sizeof(amount_str), "%" PRIu64 " %s", + msg->send.amount, msg->denom); + if (amount_len <= 0 || (size_t)amount_len >= sizeof(amount_str)) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Invalid Tendermint amount display"); + layoutHome(); + return; + } if (!confirm_transaction_output( ButtonRequestType_ButtonRequest_ConfirmOutput, amount_str, msg->send.to_address)) { @@ -170,8 +188,29 @@ void fsm_msgTendermintMsgAck(const TendermintMsgAck* msg) { return; } - if (sign_tx->has_memo && !confirm(ButtonRequestType_ButtonRequest_ConfirmMemo, - _("Memo"), "%s", sign_tx->memo)) { + if (sign_tx->has_memo && + !confirm_bytes(ButtonRequestType_ButtonRequest_ConfirmMemo, _("Memo"), + (const uint8_t*)sign_tx->memo, strlen(sign_tx->memo))) { + tendermint_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + /* Review the exact session values that bind the signed JSON. These fields + * are host supplied, so a friendly chain label must never substitute for + * the denomination or message-type prefix actually hashed. */ + if (!confirm_bytes(ButtonRequestType_ButtonRequest_Other, "Chain ID", + (const uint8_t*)sign_tx->chain_id, + strlen(sign_tx->chain_id)) || + !confirm_bytes(ButtonRequestType_ButtonRequest_Other, "Chain Name", + (const uint8_t*)sign_tx->chain_name, + strlen(sign_tx->chain_name)) || + !confirm_bytes(ButtonRequestType_ButtonRequest_Other, "Denomination", + (const uint8_t*)sign_tx->denom, strlen(sign_tx->denom)) || + !confirm_bytes(ButtonRequestType_ButtonRequest_Other, "Message Type", + (const uint8_t*)sign_tx->message_type_prefix, + strlen(sign_tx->message_type_prefix))) { tendermint_signAbort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); @@ -189,10 +228,8 @@ void fsm_msgTendermintMsgAck(const TendermintMsgAck* msg) { } if (!confirm(ButtonRequestType_ButtonRequest_SignTx, node_str, - "Sign %s transaction on %s? " - "It includes a fee of %" PRIu32 " %s and %" PRIu32 " gas.", - msg->chain_name, sign_tx->chain_id, sign_tx->fee_amount, - msg->denom, sign_tx->gas)) { + "Sign transaction? Fee: %" PRIu32 " %s. Gas: %" PRIu32 ".", + sign_tx->fee_amount, sign_tx->denom, sign_tx->gas)) { tendermint_signAbort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); diff --git a/lib/firmware/fsm_msg_thorchain.h b/lib/firmware/fsm_msg_thorchain.h index 801af7872..25912a383 100644 --- a/lib/firmware/fsm_msg_thorchain.h +++ b/lib/firmware/fsm_msg_thorchain.h @@ -141,12 +141,31 @@ void fsm_msgThorchainMsgAck(const ThorchainMsgAck* msg) { const ThorchainSignTx* sign_tx = thorchain_getThorchainSignTx(); if (msg->has_send) { + const char* coin_denom = + (msg->send.has_denom && msg->send.denom[0]) ? msg->send.denom : "rune"; + + // Validate before any display so untrusted strings never reach the UI. + if (!thorchain_isValidDenom(coin_denom)) { + thorchain_signAbort(); + fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid denom"); + layoutHome(); + return; + } + switch (msg->send.address_type) { case OutputAddressType_TRANSFER: default: { + // amount_str only needs to hold the numeric part (no denom suffix). + // Denom is confirmed on a separate screen so no truncation is possible. char amount_str[32]; - bn_format_uint64(msg->send.amount, NULL, " RUNE", 8, 0, false, - amount_str, sizeof(amount_str)); + if (!bn_format_uint64(msg->send.amount, NULL, NULL, 8, 0, false, + amount_str, sizeof(amount_str))) { + thorchain_signAbort(); + fsm_sendFailure(FailureType_Failure_FirmwareError, + _("Failed to format amount")); + layoutHome(); + return; + } if (!confirm_transaction_output( ButtonRequestType_ButtonRequest_ConfirmOutput, amount_str, msg->send.to_address)) { @@ -155,12 +174,20 @@ void fsm_msgThorchainMsgAck(const ThorchainMsgAck* msg) { layoutHome(); return; } + // Confirm the asset denom on its own screen. + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "Asset", + "%s", coin_denom)) { + thorchain_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } break; } } - if (!thorchain_signTxUpdateMsgSend(msg->send.amount, - msg->send.to_address)) { + if (!thorchain_signTxUpdateMsgSend(msg->send.amount, msg->send.to_address, + coin_denom)) { thorchain_signAbort(); fsm_sendFailure(FailureType_Failure_SyntaxError, "Failed to include send message in transaction"); @@ -169,8 +196,21 @@ void fsm_msgThorchainMsgAck(const ThorchainMsgAck* msg) { } } else if (msg->has_deposit) { - char amount_str[32]; - char asset_str[21]; + // Validate before any display so untrusted strings never reach the UI + // or the sign bytes. + if (!thorchain_isValidAsset(msg->deposit.asset) || + !thorchain_isValidSigner(msg->deposit.signer)) { + thorchain_signAbort(); + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Invalid deposit asset or signer"); + layoutHome(); + return; + } + // Long-form assets (e.g. + // ETH.USDT-0XDAC17F958D2EE523A2206206994597C13D831EC7) are ~50 chars; + // amount_str must fit amount + asset suffix or bn_format zeroes it out. + char amount_str[96]; + char asset_str[64]; asset_str[0] = ' '; strlcpy(&(asset_str[1]), msg->deposit.asset, sizeof(asset_str) - 1); bn_format_uint64(msg->deposit.amount, NULL, asset_str, 8, 0, false, @@ -185,17 +225,17 @@ void fsm_msgThorchainMsgAck(const ThorchainMsgAck* msg) { } if (msg->deposit.has_memo) { - // See if we can parse the memo - if (!thorchain_parseConfirmMemo(msg->deposit.memo, - sizeof(msg->deposit.memo))) { - // Memo not recognizable, ask to confirm it - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmMemo, _("Memo"), - "%s", msg->deposit.memo)) { - thorchain_signAbort(); - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } + size_t memo_len = strnlen(msg->deposit.memo, sizeof(msg->deposit.memo)); + // Page the complete raw memo as the sole, authoritative disclosure. No + // structured pre-parse here: its bool return conflates "unrecognized" + // with "user rejected a screen", so a reject could be followed by these + // pages and then signing. The raw pager's own reject aborts. + if (!thorchain_confirm_full_memo(_("Memo"), msg->deposit.memo, + memo_len)) { + thorchain_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; } } @@ -215,17 +255,14 @@ void fsm_msgThorchainMsgAck(const ThorchainMsgAck* msg) { } if (sign_tx->has_memo && !msg->deposit.has_memo) { - // See if we can parse the tx memo. This memo ignored if deposit msg has - // memo - if (!thorchain_parseConfirmMemo(sign_tx->memo, sizeof(sign_tx->memo))) { - // Memo not recognizable, ask to confirm it - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmMemo, _("Memo"), "%s", - sign_tx->memo)) { - thorchain_signAbort(); - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } + // Ignored if the deposit msg has a memo. Page the full raw memo as the sole + // gate (see the deposit path above for why there is no structured pass). + size_t memo_len = strnlen(sign_tx->memo, sizeof(sign_tx->memo)); + if (!thorchain_confirm_full_memo(_("Memo"), sign_tx->memo, memo_len)) { + thorchain_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; } } @@ -240,7 +277,7 @@ void fsm_msgThorchainMsgAck(const ThorchainMsgAck* msg) { } if (!confirm(ButtonRequestType_ButtonRequest_SignTx, node_str, - "Sign this RUNE transaction on %s? " + "Sign this THORChain transaction on %s? " "Additional network fees apply.", sign_tx->chain_id)) { thorchain_signAbort(); diff --git a/lib/firmware/fsm_msg_ton.h b/lib/firmware/fsm_msg_ton.h index 5f4844896..6f2aae06b 100644 --- a/lib/firmware/fsm_msg_ton.h +++ b/lib/firmware/fsm_msg_ton.h @@ -99,6 +99,20 @@ void fsm_msgTonSignTx(TonSignTx* msg) { return; } + /* AdvancedMode gate: to_address/amount are display-only, so this is + * length-only blind signing of raw bytes. Same fence as TonSignMessage + * and Solana/TRON opaque signing until the displayed fields are parsed + * from and bound to raw_tx. */ + if (!storage_isPolicyEnabled("AdvancedMode")) { + (void)review(ButtonRequestType_ButtonRequest_Other, "Blocked", + "TON transaction signing is blind-only. " + "Enable AdvancedMode in device settings."); + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("Transaction signing disabled by policy")); + layoutHome(); + return; + } + // Derive node using Ed25519 curve HDNode* node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); @@ -112,24 +126,14 @@ void fsm_msgTonSignTx(TonSignTx* msg) { return; } - bool needs_confirm = true; - - // Display transaction details if available - if (needs_confirm && msg->has_to_address && msg->has_amount) { - char amount_str[32]; - ton_formatAmount(amount_str, sizeof(amount_str), msg->amount); - - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "Send", - "Send %s TON to %s?", amount_str, msg->to_address)) { - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled"); - layoutHome(); - return; - } - } - - if (!confirm(ButtonRequestType_ButtonRequest_SignTx, "Transaction", - "Really sign this TON transaction?")) { + /* to_address and amount are display-only fields not bound to raw_tx bytes. + * A malicious host could show one recipient while getting a different + * transaction signed. Show only the raw_tx size. */ + char blind_msg[48]; + snprintf(blind_msg, sizeof(blind_msg), "Sign %u-byte TON transaction?", + (unsigned)msg->raw_tx.size); + if (!confirm(ButtonRequestType_ButtonRequest_SignTx, "TON Blind Sign", "%s", + blind_msg)) { memzero(node, sizeof(*node)); fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled"); layoutHome(); @@ -190,43 +194,16 @@ void fsm_msgTonSignMessage(const TonSignMessage* msg) { if (!node) return; hdnode_fill_public_key(node); - /* Always require on-device confirmation. Display message content if - * printable, hex preview otherwise. */ - { - char msgBuf[129] = {0}; - const char* typeLabel; - bool printable = true; - for (unsigned i = 0; i < msg->message.size; i++) { - if (msg->message.bytes[i] < 0x20 || msg->message.bytes[i] > 0x7e) { - printable = false; - break; - } - } - if (printable && msg->message.size <= sizeof(msgBuf) - 1) { - typeLabel = "Sign TON Message"; - memcpy(msgBuf, msg->message.bytes, msg->message.size); - msgBuf[msg->message.size] = '\0'; - } else { - typeLabel = "Sign TON Bytes"; - unsigned show = msg->message.size; - if (show > 32) show = 32; - for (unsigned i = 0; i < show; i++) { - snprintf(&msgBuf[2 * i], 3, "%02x", msg->message.bytes[i]); - } - msgBuf[2 * show] = '\0'; - if (msg->message.size > 32) { - snprintf(&msgBuf[64], sizeof(msgBuf) - 64, "... (%u bytes)", - (unsigned)msg->message.size); - } - } - if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _(typeLabel), - "%s", msgBuf)) { - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_ActionCancelled, - _("Signing cancelled")); - layoutHome(); - return; - } + /* AdvancedMode permits the opaque primitive, but never permits a hidden + * suffix: review every signed byte using renderer-measured pages. */ + if (!confirm_bytes(ButtonRequestType_ButtonRequest_ProtectCall, + "Sign TON Message", msg->message.bytes, + msg->message.size)) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("Signing cancelled")); + layoutHome(); + return; } if (!ton_message_sign(node, msg, resp)) { diff --git a/lib/firmware/fsm_msg_tron.h b/lib/firmware/fsm_msg_tron.h index aee20c602..22d0a4fd6 100644 --- a/lib/firmware/fsm_msg_tron.h +++ b/lib/firmware/fsm_msg_tron.h @@ -102,15 +102,96 @@ void fsm_msgTronSignTx(TronSignTx* msg) { return; } - bool needs_confirm = true; + /* Clear-sign from raw_data itself — the exact bytes being signed. + * (The proto's side-channel to_address/amount fields are never trusted: + * they are not part of what is signed.) */ + TronParsedTx parsed; + TronTxType tx_type = + tron_parseRawTx(msg->raw_data.bytes, msg->raw_data.size, &parsed); + + if (tx_type == TRON_TX_UNVERIFIED) { + /* Unrecognized contract or payload: explicit blind-sign only, + * same policy gate as Solana opaque transactions. */ + if (!storage_isPolicyEnabled("AdvancedMode")) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_Other, + _("Enable AdvancedMode to blind-sign")); + layoutHome(); + return; + } + char blind_msg[48]; + snprintf(blind_msg, sizeof(blind_msg), "Sign %u-byte TRON transaction?", + (unsigned)msg->raw_data.size); + if (!confirm(ButtonRequestType_ButtonRequest_SignTx, "TRON Blind Sign", + "%s", blind_msg)) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled"); + layoutHome(); + return; + } + } else { + /* The parsed owner account is the one spending — it must be ours. */ + char derived_addr[TRON_ADDRESS_MAX_LEN]; + char owner_addr[TRON_ADDRESS_MAX_LEN]; + if (!tron_getAddress(node->public_key, derived_addr, + sizeof(derived_addr)) || + !tron_addressFromBytes(parsed.owner, owner_addr, sizeof(owner_addr)) || + strcmp(derived_addr, owner_addr) != 0) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_Other, + _("TX owner does not match derived key")); + layoutHome(); + return; + } + + char to_str[TRON_ADDRESS_MAX_LEN]; + if (!tron_addressFromBytes(parsed.to, to_str, sizeof(to_str))) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_Other, _("Address encoding failed")); + layoutHome(); + return; + } - // Display transaction details if available - if (needs_confirm && msg->has_to_address && msg->has_amount) { - char amount_str[32]; - tron_formatAmount(amount_str, sizeof(amount_str), msg->amount); + bool confirmed = false; + if (tx_type == TRON_TX_TRANSFER) { + char amount_str[32]; + tron_formatAmount(amount_str, sizeof(amount_str), parsed.amount); + confirmed = confirm(ButtonRequestType_ButtonRequest_SignTx, "TRON", + "Send %s to %s?", amount_str, to_str); + } else { /* TRON_TX_TRC20_TRANSFER */ + char contract_str[TRON_ADDRESS_MAX_LEN]; + char amount_str[90]; + confirmed = + tron_addressFromBytes(parsed.contract, contract_str, + sizeof(contract_str)) && + tron_formatTrc20Amount(parsed.trc20_amount, amount_str, + sizeof(amount_str)) && + confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "TRC-20 Transfer", "Token contract %s", contract_str) && + /* Token decimals are not known on-device; show base units. */ + confirm(ButtonRequestType_ButtonRequest_SignTx, "TRC-20 Transfer", + "Send %s base units to %s?", amount_str, to_str); + } + + if (confirmed && parsed.has_fee_limit) { + char fee_str[32]; + tron_formatAmount(fee_str, sizeof(fee_str), parsed.fee_limit); + confirmed = confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "TRON", + "Max network fee %s", fee_str); + } - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "Send", - "Send %s TRX to %s?", amount_str, msg->to_address)) { + if (confirmed && parsed.memo_len > 0) { + /* Page the COMPLETE memo (72-char ASCII / 40-byte hex pages) like every + * other memo surface. The old single-screen path showed up to 114 chars + * unpaged, but 3 OLED lines only guarantee ~84 chars with wide glyphs — + * an 85..114-char memo could have its signed tail (affiliate bps, + * destination tail) silently clipped. The pager also discloses + * non-printable memos as complete hex instead of a byte-count summary. */ + confirmed = thorchain_confirm_full_memo("Memo", (const char*)parsed.memo, + parsed.memo_len); + } + + if (!confirmed) { memzero(node, sizeof(*node)); fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled"); layoutHome(); @@ -118,14 +199,6 @@ void fsm_msgTronSignTx(TronSignTx* msg) { } } - if (!confirm(ButtonRequestType_ButtonRequest_SignTx, "Transaction", - "Really sign this TRON transaction?")) { - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled"); - layoutHome(); - return; - } - // Sign the transaction with secp256k1 if (!tron_signTx(node, msg, resp)) { memzero(node, sizeof(*node)); @@ -139,11 +212,6 @@ void fsm_msgTronSignTx(TronSignTx* msg) { layoutHome(); } -#ifndef TRON_MSG_DISPLAY_MAX -#define TRON_MSG_DISPLAY_MAX \ - (38 * 3) // mirrors ETH MSG_MAX (3 lines × 38 chars) -#endif - void fsm_msgTronSignMessage(TronSignMessage* msg) { RESP_INIT(TronMessageSignature); @@ -160,37 +228,9 @@ void fsm_msgTronSignMessage(TronSignMessage* msg) { return; } - char msgBuf[TRON_MSG_DISPLAY_MAX + 1] = {0}; - const char* typeIndicator; - bool canPrint = true; - unsigned ctr; - - for (ctr = 0; ctr < msg->message.size; ctr++) { - if (isprint(msg->message.bytes[ctr]) == false) { - canPrint = false; - break; - } - } - - if (canPrint) { - typeIndicator = "Sign TRON Message"; - unsigned copy = msg->message.size; - if (copy > TRON_MSG_DISPLAY_MAX) copy = TRON_MSG_DISPLAY_MAX; - memcpy(msgBuf, msg->message.bytes, copy); - msgBuf[copy] = '\0'; - } else { - typeIndicator = "Sign TRON Bytes"; - unsigned hexBytes = msg->message.size; - if (hexBytes * 2 > TRON_MSG_DISPLAY_MAX) { - hexBytes = TRON_MSG_DISPLAY_MAX / 2; - } - for (ctr = 0; ctr < hexBytes; ctr++) { - snprintf(&msgBuf[2 * ctr], 3, "%02x", msg->message.bytes[ctr]); - } - } - - if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _(typeIndicator), - "%s", msgBuf)) { + if (!confirm_bytes(ButtonRequestType_ButtonRequest_ProtectCall, + "Sign TRON Message", msg->message.bytes, + msg->message.size)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; @@ -230,37 +270,9 @@ void fsm_msgTronVerifyMessage(const TronVerifyMessage* msg) { return; } - char msgBuf[TRON_MSG_DISPLAY_MAX + 1] = {0}; - const char* typeIndicator; - bool canPrint = true; - unsigned ctr; - - for (ctr = 0; ctr < msg->message.size; ctr++) { - if (isprint(msg->message.bytes[ctr]) == false) { - canPrint = false; - break; - } - } - - if (canPrint) { - typeIndicator = "Message Verified"; - unsigned copy = msg->message.size; - if (copy > TRON_MSG_DISPLAY_MAX) copy = TRON_MSG_DISPLAY_MAX; - memcpy(msgBuf, msg->message.bytes, copy); - msgBuf[copy] = '\0'; - } else { - typeIndicator = "Bytes Verified"; - unsigned hexBytes = msg->message.size; - if (hexBytes * 2 > TRON_MSG_DISPLAY_MAX) { - hexBytes = TRON_MSG_DISPLAY_MAX / 2; - } - for (ctr = 0; ctr < hexBytes; ctr++) { - snprintf(&msgBuf[2 * ctr], 3, "%02x", msg->message.bytes[ctr]); - } - } - - if (!confirm(ButtonRequestType_ButtonRequest_Other, _(typeIndicator), "%s", - msgBuf)) { + if (!confirm_bytes(ButtonRequestType_ButtonRequest_Other, + "TRON Message Verified", msg->message.bytes, + msg->message.size)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; @@ -306,6 +318,31 @@ void fsm_msgTronSignTypedHash(const TronSignTypedHash* msg) { return; } + /* Blind-sign gate: device only receives pre-computed hashes — it cannot + * reconstruct or verify the original typed-data struct. Require the same + * AdvancedMode policy as TronSignTx blind-signing so this message type + * can't be used to route around the kill-switch. */ + if (!storage_isPolicyEnabled("AdvancedMode")) { + memzero(node, sizeof(*node)); + (void)review(ButtonRequestType_ButtonRequest_Other, "Blocked", + "TIP-712 blind signing is disabled. " + "Enable AdvancedMode in device settings."); + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("Blind signing disabled by policy")); + layoutHome(); + return; + } + + /* The user must explicitly acknowledge blind signing before the hashes. */ + if (!confirm(ButtonRequestType_ButtonRequest_Other, "TIP-712 Blind Sign", + "Device cannot verify typed-data contents. " + "Only proceed if you trust the host application.")) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + if (!confirm(ButtonRequestType_ButtonRequest_Other, "Verify Address", "Confirm address: %s", address)) { memzero(node, sizeof(*node)); diff --git a/lib/firmware/fsm_msg_zcash.h b/lib/firmware/fsm_msg_zcash.h new file mode 100644 index 000000000..cd40a8022 --- /dev/null +++ b/lib/firmware/fsm_msg_zcash.h @@ -0,0 +1,1414 @@ +/* + * This file is part of the KeepKey project. + * + * Copyright (C) 2025 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. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Zcash-specific headers — included here because fsm_msg_zcash.h + * is #include'd inside fsm.c, not compiled separately. */ +#include + +#include "keepkey/firmware/zcash.h" +#include "trezor/crypto/blake2b.h" +#include "trezor/crypto/pallas.h" +#include "trezor/crypto/redpallas.h" +#include "trezor/crypto/memzero.h" + +/* Precomputed empty digest constants for shielded-only transactions. + * These are BLAKE2b-256 with the respective personalizations over empty input. + * Verified against Keystone3 test vectors. */ +static const uint8_t EMPTY_TRANSPARENT_DIGEST[32] = { + 0xc3, 0x3f, 0x2e, 0x95, 0x70, 0x5f, 0xaa, 0xb3, 0x5f, 0x8d, 0x53, + 0x3f, 0xa6, 0x1e, 0x95, 0xc3, 0xb7, 0xaa, 0xba, 0x07, 0x76, 0xb8, + 0x74, 0xa9, 0xf7, 0x4f, 0xc1, 0x27, 0x84, 0x37, 0x6a, 0x59}; + +static const uint8_t EMPTY_SAPLING_DIGEST[32] = { + 0x6f, 0x2f, 0xc8, 0xf9, 0x8f, 0xea, 0xfd, 0x94, 0xe7, 0x4a, 0x0d, + 0xf4, 0xbe, 0xd7, 0x43, 0x91, 0xee, 0x0b, 0x5a, 0x69, 0x94, 0x5e, + 0x4c, 0xed, 0x8c, 0xa8, 0xa0, 0x95, 0x20, 0x6f, 0x00, 0xae}; + +#define ZCASH_MAX_ACTIONS 16 +#define ZCASH_MAX_TRANSPARENT_INPUTS 8 +#define ZCASH_MAX_TRANSPARENT_OUTPUTS 8 +#define ZCASH_MAX_TRANSPARENT_SCRIPT_PUBKEY 128 + +typedef struct { + bool received; + uint8_t prevout_txid[32]; + uint32_t prevout_index; + uint32_t sequence; + uint64_t amount; + uint8_t script_pubkey[ZCASH_MAX_TRANSPARENT_SCRIPT_PUBKEY]; + size_t script_pubkey_size; + uint32_t address_n[8]; + uint32_t address_n_count; +} ZcashTransparentInputState; + +typedef struct { + bool received; + uint64_t amount; + uint8_t script_pubkey[ZCASH_MAX_TRANSPARENT_SCRIPT_PUBKEY]; + size_t script_pubkey_size; +} ZcashTransparentOutputState; + +/* Zcash shielded signing state */ +static struct { + bool active; + uint32_t account; + uint32_t n_actions; + uint32_t current_action; + uint64_t total_amount; + uint64_t fee; + uint32_t branch_id; + ZcashOrchardKeys keys; + uint8_t header_digest[32]; + uint8_t sighash[32]; + /* Phase 2a: on-device sighash computation */ + bool has_device_sighash; + /* Phase 2b: incremental orchard digest verification */ + bool verify_orchard_digest; + uint8_t expected_orchard_digest[32]; + BLAKE2B_CTX compact_ctx; + BLAKE2B_CTX memos_ctx; + BLAKE2B_CTX noncompact_ctx; + uint8_t orchard_flags; + int64_t orchard_value_balance; + uint8_t orchard_anchor[32]; + /* Signatures buffer: one 64-byte sig per action */ + uint8_t signatures[ZCASH_MAX_ACTIONS][64]; + /* Phase 3: transparent shielding state */ + bool has_expected_transparent_digest; + uint8_t expected_transparent_digest[32]; + bool transparent_digest_verified; + uint32_t n_transparent_outputs; + uint32_t current_transparent_output; + uint32_t n_transparent_inputs; + uint32_t current_transparent_input; + ZcashTransparentOutputState + transparent_outputs[ZCASH_MAX_TRANSPARENT_OUTPUTS]; + ZcashTransparentInputState transparent_inputs[ZCASH_MAX_TRANSPARENT_INPUTS]; + /* Deferred transparent ECDSA sigs — buffered until Orchard/fee final gate */ + bool has_pending_transparent; + ZcashTransparentSigned pending_transparent; +} zcash_signing; + +/* Public API; declared in keepkey/firmware/zcash.h. */ +void zcash_signing_abort(void) { + /* Centralized cleanup: stop the trickle progress animation here so every + * abort path (Cancel, ClearSession, failures) kills it even when the caller + * does not go through layoutHome()/layout_clear_animations(). */ + layoutProgressTrickleStop(); + memzero(&zcash_signing, sizeof(zcash_signing)); +} + +static bool zcash_script_is_p2pkh(const uint8_t* script, size_t script_size) { + return script && script_size == 25 && script[0] == 0x76 && + script[1] == 0xa9 && script[2] == 0x14 && script[23] == 0x88 && + script[24] == 0xac; +} + +static bool zcash_script_is_p2sh(const uint8_t* script, size_t script_size) { + return script && script_size == 23 && script[0] == 0xa9 && + script[1] == 0x14 && script[22] == 0x87; +} + +static bool zcash_script_is_standard_transparent(const uint8_t* script, + size_t script_size) { + return zcash_script_is_p2pkh(script, script_size) || + zcash_script_is_p2sh(script, script_size); +} + +static bool zcash_transparent_script_to_address(const uint8_t* script, + size_t script_size, char* out, + size_t out_size) { + if (!script || !out || out_size == 0) return false; + + const CoinType* coin = fsm_getCoin(true, "Zcash"); + if (!coin) return false; + + uint32_t address_type; + const uint8_t* hash160; + if (zcash_script_is_p2pkh(script, script_size)) { + if (!coin->has_address_type) return false; + address_type = coin->address_type; + hash160 = script + 3; + } else if (zcash_script_is_p2sh(script, script_size)) { + if (!coin->has_address_type_p2sh) return false; + address_type = coin->address_type_p2sh; + hash160 = script + 2; + } else { + return false; + } + + uint8_t raw[4 + 20] = {0}; + size_t prefix_len = address_prefix_bytes_len(address_type); + if (prefix_len == 0 || prefix_len + 20 > sizeof(raw)) return false; + address_write_prefix_bytes(address_type, raw); + memcpy(raw + prefix_len, hash160, 20); + return base58_encode_check(raw, (int)(prefix_len + 20), HASHER_SHA2D, out, + (int)out_size) != 0; +} + +static void zcash_format_amount(uint64_t amount, char* out, size_t out_size) { + snprintf(out, out_size, "%llu.%08llu ZEC", + (unsigned long long)(amount / 100000000ULL), + (unsigned long long)(amount % 100000000ULL)); +} + +/* Determine account — require explicit account or strict ZIP-32 path + * m/32'/133'/account' (all hardened, exactly 3 elements). Shared by + * ZcashSignPCZT / ZcashGetOrchardFVK / ZcashDisplayAddress so a malformed + * host path cannot silently resolve to an unintended account. */ +static bool zcash_resolve_account(bool has_account, uint32_t account_field, + const uint32_t* address_n, + uint32_t address_n_count, + uint32_t* account_out) { + if (has_account) { + *account_out = account_field; + return true; + } + if (address_n_count == 3 && address_n[0] == (0x80000000 | 32) && + address_n[1] == (0x80000000 | 133) && (address_n[2] & 0x80000000)) { + *account_out = address_n[2] & 0x7FFFFFFF; + return true; + } + fsm_sendFailure( + FailureType_Failure_SyntaxError, + _("Require account field or ZIP-32 path m/32'/133'/account'")); + return false; +} + +/* Optional seed_fingerprint binding (ZIP-32 §6.1). If the host asserts a + * seed identity, verify it matches this device's seed before proceeding. + * Catches "wrong device" attacks where the host accidentally targets a + * different seed than the one it built the request against. */ +static bool zcash_check_seed_fingerprint(bool has_expected, + const uint8_t* expected, + size_t expected_size) { + if (!zcash_seed_fingerprint_request_valid(has_expected, expected_size)) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Seed fingerprint must be 32 bytes")); + return false; + } + if (!has_expected) return true; + + uint8_t actual_fp[32]; + if (!storage_zcashSeedFingerprint(true, actual_fp)) { + fsm_sendFailure(FailureType_Failure_NotInitialized, + _("Device not initialized or seed unavailable")); + return false; + } + bool match = memcmp(actual_fp, expected, 32) == 0; + memzero(actual_fp, sizeof(actual_fp)); + if (!match) { + fsm_sendFailure(FailureType_Failure_Other, + _("Seed fingerprint mismatch — wrong device")); + return false; + } + return true; +} + +static bool zcash_verify_and_confirm_orchard_output( + const ZcashPCZTAction* msg) { + if (!msg->has_value || !msg->has_recipient || + msg->recipient.size != ZCASH_ORCHARD_RAW_RECEIVER_SIZE || + !msg->has_rseed || msg->rseed.size != 32) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Missing Orchard output metadata")); + return false; + } + + uint8_t computed_cmx[32]; + if (!zcash_orchard_compute_cmx(msg->recipient.bytes, msg->value, + msg->nullifier.bytes, msg->rseed.bytes, + computed_cmx) || + memcmp(computed_cmx, msg->cmx.bytes, 32) != 0) { + memzero(computed_cmx, sizeof(computed_cmx)); + fsm_sendFailure(FailureType_Failure_Other, + _("Orchard note commitment mismatch")); + return false; + } + memzero(computed_cmx, sizeof(computed_cmx)); + + char address[ZCASH_ORCHARD_UNIFIED_ADDRESS_SIZE]; + if (!zcash_orchard_receiver_to_unified_address(msg->recipient.bytes, "u", + address, sizeof(address))) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Invalid Orchard recipient")); + return false; + } + + char amount_str[32]; + zcash_format_amount(msg->value, amount_str, sizeof(amount_str)); + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "Zcash Output", + "Send shielded ZEC?\n%s\nAmount: %s", address, amount_str)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("Signing cancelled")); + memzero(address, sizeof(address)); + return false; + } + + memzero(address, sizeof(address)); + return true; +} + +static bool zcash_compute_verified_fee(uint64_t* fee_out) { + if (!fee_out) return false; + + int64_t net_transparent = 0; + for (uint32_t i = 0; i < zcash_signing.n_transparent_inputs; i++) { + const uint64_t amount = zcash_signing.transparent_inputs[i].amount; + if (amount > (uint64_t)INT64_MAX || + net_transparent > INT64_MAX - (int64_t)amount) { + return false; + } + net_transparent += (int64_t)amount; + } + + for (uint32_t i = 0; i < zcash_signing.n_transparent_outputs; i++) { + const uint64_t amount = zcash_signing.transparent_outputs[i].amount; + if (amount > (uint64_t)INT64_MAX || + net_transparent < INT64_MIN + (int64_t)amount) { + return false; + } + net_transparent -= (int64_t)amount; + } + + const int64_t value_balance = zcash_signing.orchard_value_balance; + if ((value_balance > 0 && net_transparent > INT64_MAX - value_balance) || + (value_balance < 0 && net_transparent < INT64_MIN - value_balance)) { + return false; + } + + const int64_t signed_fee = net_transparent + value_balance; + if (signed_fee < 0) return false; + + *fee_out = (uint64_t)signed_fee; + return true; +} + +static bool zcash_verify_and_confirm_fee(void) { + uint64_t verified_fee = 0; + if (!zcash_compute_verified_fee(&verified_fee)) { + fsm_sendFailure(FailureType_Failure_Other, _("Invalid transaction fee")); + return false; + } + + if (verified_fee != zcash_signing.fee) { + fsm_sendFailure(FailureType_Failure_Other, _("Fee mismatch")); + return false; + } + + char fee_str[32]; + zcash_format_amount(verified_fee, fee_str, sizeof(fee_str)); + if (!confirm(ButtonRequestType_ButtonRequest_SignTx, "Zcash Fee", + "Confirm transaction fee?\n%s", fee_str)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("Signing cancelled")); + return false; + } + + return true; +} + +static void zcash_send_action_ack(uint32_t next_index) { + ZcashPCZTActionAck* resp_ack = (ZcashPCZTActionAck*)msg_resp; + memset(resp_ack, 0, sizeof(ZcashPCZTActionAck)); + resp_ack->has_next_index = true; + resp_ack->next_index = next_index; + msg_write(MessageType_MessageType_ZcashPCZTActionAck, resp_ack); + + /* The device now blocks until the host generates the (slow) Orchard proof for + * this action. Ease the progress bar from the milestone already reached + * toward the one this action will complete, so the screen keeps moving + * instead of looking stuck at a frozen value. Stopped again when the action + * arrives. */ + uint32_t n = zcash_signing.n_actions; + if (n > 0) { + int base = (int)((next_index * 1000) / n); + int target = (int)(((next_index + 1) * 1000) / n); + layoutProgressTrickle(_("Signing Zcash"), base, target); + } +} + +static void zcash_send_transparent_output_ack(uint32_t next_index) { + ZcashTransparentAck* resp = (ZcashTransparentAck*)msg_resp; + memset(resp, 0, sizeof(ZcashTransparentAck)); + resp->has_next_output_index = true; + resp->next_output_index = next_index; + msg_write(MessageType_MessageType_ZcashTransparentAck, resp); +} + +static void zcash_send_transparent_input_ack(uint32_t next_index) { + ZcashTransparentAck* resp = (ZcashTransparentAck*)msg_resp; + memset(resp, 0, sizeof(ZcashTransparentAck)); + resp->has_next_input_index = true; + resp->next_input_index = next_index; + msg_write(MessageType_MessageType_ZcashTransparentAck, resp); +} + +static bool zcash_build_transparent_digest_info( + ZcashTransparentInputDigestInfo inputs[ZCASH_MAX_TRANSPARENT_INPUTS], + ZcashTransparentOutputDigestInfo outputs[ZCASH_MAX_TRANSPARENT_OUTPUTS]) { + for (uint32_t i = 0; i < zcash_signing.n_transparent_inputs; i++) { + const ZcashTransparentInputState* stored = + &zcash_signing.transparent_inputs[i]; + if (!stored->received) return false; + inputs[i].prevout_txid = stored->prevout_txid; + inputs[i].prevout_index = stored->prevout_index; + inputs[i].sequence = stored->sequence; + inputs[i].value = stored->amount; + inputs[i].script_pubkey = stored->script_pubkey; + inputs[i].script_pubkey_size = stored->script_pubkey_size; + } + + for (uint32_t i = 0; i < zcash_signing.n_transparent_outputs; i++) { + const ZcashTransparentOutputState* stored = + &zcash_signing.transparent_outputs[i]; + if (!stored->received) return false; + outputs[i].value = stored->amount; + outputs[i].script_pubkey = stored->script_pubkey; + outputs[i].script_pubkey_size = stored->script_pubkey_size; + } + + return true; +} + +static bool zcash_finalize_transparent_digest(void) { + if (!zcash_signing.has_expected_transparent_digest) return false; + + ZcashTransparentInputDigestInfo inputs[ZCASH_MAX_TRANSPARENT_INPUTS] = {0}; + ZcashTransparentOutputDigestInfo outputs[ZCASH_MAX_TRANSPARENT_OUTPUTS] = {0}; + uint8_t transparent_digest[32] = {0}; + + if (!zcash_build_transparent_digest_info(inputs, outputs) || + !zcash_compute_orchard_transparent_sig_digest( + inputs, zcash_signing.n_transparent_inputs, outputs, + zcash_signing.n_transparent_outputs, transparent_digest)) { + memzero(transparent_digest, sizeof(transparent_digest)); + memzero(inputs, sizeof(inputs)); + memzero(outputs, sizeof(outputs)); + return false; + } + + if (memcmp(transparent_digest, zcash_signing.expected_transparent_digest, + 32) != 0) { + memzero(transparent_digest, sizeof(transparent_digest)); + memzero(inputs, sizeof(inputs)); + memzero(outputs, sizeof(outputs)); + return false; + } + + zcash_compute_shielded_sighash( + zcash_signing.header_digest, transparent_digest, EMPTY_SAPLING_DIGEST, + zcash_signing.expected_orchard_digest, zcash_signing.branch_id, + zcash_signing.sighash); + zcash_signing.has_device_sighash = true; + zcash_signing.transparent_digest_verified = true; + + memzero(transparent_digest, sizeof(transparent_digest)); + memzero(inputs, sizeof(inputs)); + memzero(outputs, sizeof(outputs)); + return true; +} + +static bool zcash_sign_transparent_inputs(bool* cancelled) { + if (!zcash_signing.transparent_digest_verified) return false; + if (cancelled) *cancelled = false; + + bool ok = false; + ZcashTransparentInputDigestInfo inputs[ZCASH_MAX_TRANSPARENT_INPUTS] = {0}; + ZcashTransparentOutputDigestInfo outputs[ZCASH_MAX_TRANSPARENT_OUTPUTS] = {0}; + if (!zcash_build_transparent_digest_info(inputs, outputs)) goto cleanup; + + const CoinType* coin = fsm_getCoin(true, "Zcash"); + if (!coin) goto cleanup; + + memset(&zcash_signing.pending_transparent, 0, sizeof(ZcashTransparentSigned)); + zcash_signing.pending_transparent.signatures_count = + zcash_signing.n_transparent_inputs; + + for (uint32_t i = 0; i < zcash_signing.n_transparent_inputs; i++) { + const ZcashTransparentInputState* stored = + &zcash_signing.transparent_inputs[i]; + + char input_str[64]; + char amount_str[32]; + zcash_format_amount(stored->amount, amount_str, sizeof(amount_str)); + snprintf(input_str, sizeof(input_str), "Input %lu: %s", + (unsigned long)(i + 1), amount_str); + if (!confirm(ButtonRequestType_ButtonRequest_SignTx, "Sign Input", + "Sign transparent input?\n%s", input_str)) { + if (cancelled) *cancelled = true; + goto cleanup; + } + + HDNode* node = fsm_getDerivedNode(coin->curve_name, stored->address_n, + stored->address_n_count, NULL); + if (!node) goto cleanup; + + /* ZIP-244 §4.4: signature_digest = ZcashTxHash_( + * header_digest || transparent_sig_digest || sapling_digest || + * orchard_digest) Binding the transparent ECDSA sig to all four components + * ensures it cannot be replayed in a transaction with different + * Orchard/header data. */ + uint8_t t_sig_digest[32] = {0}; + uint8_t full_sighash[32] = {0}; + uint8_t sig[64] = {0}; + uint8_t der_sig[73] = {0}; + + bool sign_ok = + zcash_compute_transparent_sighash_digest( + inputs, zcash_signing.n_transparent_inputs, outputs, + zcash_signing.n_transparent_outputs, i, 0x01, t_sig_digest) && + zcash_compute_shielded_sighash(zcash_signing.header_digest, + t_sig_digest, EMPTY_SAPLING_DIGEST, + zcash_signing.expected_orchard_digest, + zcash_signing.branch_id, full_sighash) && + hdnode_sign_digest(node, full_sighash, sig, NULL, NULL) == 0; + + memzero(node, sizeof(*node)); + memzero(t_sig_digest, sizeof(t_sig_digest)); + memzero(full_sighash, sizeof(full_sighash)); + + if (!sign_ok) { + memzero(sig, sizeof(sig)); + goto cleanup; + } + + int der_len = ecdsa_sig_to_der(sig, der_sig); + zcash_signing.pending_transparent.signatures[i].size = der_len; + memcpy(zcash_signing.pending_transparent.signatures[i].bytes, der_sig, + der_len); + + memzero(sig, sizeof(sig)); + memzero(der_sig, sizeof(der_sig)); + } + + zcash_signing.has_pending_transparent = true; + ok = true; + +cleanup: + memzero(inputs, sizeof(inputs)); + memzero(outputs, sizeof(outputs)); + return ok; +} + +void fsm_msgZcashSignPCZT(const ZcashSignPCZT* msg) { + RESP_INIT(ZcashPCZTActionAck); + + CHECK_INITIALIZED + + CHECK_PIN + + /* Validate parameters */ + if (!msg->has_n_actions || msg->n_actions == 0) { + fsm_sendFailure(FailureType_Failure_SyntaxError, _("No actions specified")); + layoutHome(); + return; + } + + if (msg->n_actions > ZCASH_MAX_ACTIONS) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Too many Orchard actions")); + layoutHome(); + return; + } + + uint32_t account; + if (!zcash_resolve_account(msg->has_account, msg->account, msg->address_n, + msg->address_n_count, &account)) { + layoutHome(); + return; + } + + uint32_t n_tinputs = + msg->has_n_transparent_inputs ? msg->n_transparent_inputs : 0; + if (n_tinputs > ZCASH_MAX_TRANSPARENT_INPUTS) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Too many transparent inputs")); + layoutHome(); + return; + } + + uint32_t n_toutputs = + msg->has_n_transparent_outputs ? msg->n_transparent_outputs : 0; + if (n_toutputs > ZCASH_MAX_TRANSPARENT_OUTPUTS) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Too many transparent outputs")); + layoutHome(); + return; + } + + uint32_t branch_id = msg->has_branch_id ? msg->branch_id : 0; + + ZcashPCZTSigningRequestMeta signing_meta = {0}; + signing_meta.has_header_digest = msg->has_header_digest; + signing_meta.header_digest_size = msg->header_digest.size; + signing_meta.has_transparent_digest = msg->has_transparent_digest; + signing_meta.transparent_digest_size = msg->transparent_digest.size; + signing_meta.has_sapling_digest = msg->has_sapling_digest; + signing_meta.sapling_digest_size = msg->sapling_digest.size; + signing_meta.has_orchard_digest = msg->has_orchard_digest; + signing_meta.orchard_digest_size = msg->orchard_digest.size; + signing_meta.has_orchard_flags = msg->has_orchard_flags; + signing_meta.orchard_flags = msg->orchard_flags; + signing_meta.has_orchard_value_balance = msg->has_orchard_value_balance; + signing_meta.has_orchard_anchor = msg->has_orchard_anchor; + signing_meta.orchard_anchor_size = msg->orchard_anchor.size; + signing_meta.has_header_fields = + msg->has_tx_version && msg->has_version_group_id && msg->has_branch_id && + msg->has_lock_time && msg->has_expiry_height; + signing_meta.n_transparent_inputs = n_tinputs; + signing_meta.n_transparent_outputs = n_toutputs; + + const ZcashPCZTSigningRequestStatus status = + zcash_pczt_signing_request_status(&signing_meta); + if (status != ZCASH_PCZT_SIGNING_REQUEST_OK) { + static const char* const status_msgs[] = { + [ZCASH_PCZT_SIGNING_REQUEST_MISSING_TX_DIGESTS] = + "Missing transaction digests", + [ZCASH_PCZT_SIGNING_REQUEST_INVALID_DIGEST_SIZE] = + "Invalid transaction digest", + [ZCASH_PCZT_SIGNING_REQUEST_MISSING_HEADER_FIELDS] = + "Missing transaction header", + [ZCASH_PCZT_SIGNING_REQUEST_UNSUPPORTED_SAPLING_COMPONENT] = + "Sapling not supported", + [ZCASH_PCZT_SIGNING_REQUEST_MISSING_TRANSPARENT_DIGEST] = + "Missing transparent digest", + [ZCASH_PCZT_SIGNING_REQUEST_MISSING_ORCHARD_METADATA] = + "Missing Orchard metadata", + }; + const char* status_msg = + ((size_t)status < sizeof(status_msgs) / sizeof(status_msgs[0]) && + status_msgs[status]) + ? status_msgs[status] + : "Missing Orchard metadata"; + fsm_sendFailure(FailureType_Failure_SyntaxError, _(status_msg)); + layoutHome(); + return; + } + + uint8_t header_digest[32]; + if (!zcash_compute_header_digest(msg->tx_version, msg->version_group_id, + branch_id, msg->lock_time, + msg->expiry_height, header_digest) || + memcmp(header_digest, msg->header_digest.bytes, 32) != 0) { + fsm_sendFailure(FailureType_Failure_Other, _("Header digest mismatch")); + layoutHome(); + return; + } + + /* Confirm with user */ + char amount_str[32]; + char fee_str[32]; + uint64_t total = msg->has_total_amount ? msg->total_amount : 0; + uint64_t fee = msg->has_fee ? msg->fee : 0; + + /* Format amounts (1 ZEC = 100,000,000 zatoshis) */ + zcash_format_amount(total, amount_str, sizeof(amount_str)); + zcash_format_amount(fee, fee_str, sizeof(fee_str)); + + /* Display confirmation — different text for shielded-only vs hybrid */ + if (n_tinputs > 0) { + if (!confirm(ButtonRequestType_ButtonRequest_SignTx, "Zcash Shield", + "Shield transparent ZEC to Orchard?\n" + "Amount: %s\nFee: %s\nInputs: %lu\nOutputs: %lu\nActions: %lu", + amount_str, fee_str, (unsigned long)n_tinputs, + (unsigned long)n_toutputs, (unsigned long)msg->n_actions)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("Signing cancelled")); + layoutHome(); + return; + } + } else if (n_toutputs > 0) { + if (!confirm(ButtonRequestType_ButtonRequest_SignTx, "Zcash Shielded", + "Sign transaction with transparent outputs?\n" + "Amount: %s\nFee: %s\nOutputs: %lu\nActions: %lu", + amount_str, fee_str, (unsigned long)n_toutputs, + (unsigned long)msg->n_actions)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("Signing cancelled")); + layoutHome(); + return; + } + } else { + if (!confirm(ButtonRequestType_ButtonRequest_SignTx, "Zcash Shielded", + "Sign shielded transaction?\n" + "Amount: %s\nFee: %s\nActions: %lu", + amount_str, fee_str, (unsigned long)msg->n_actions)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("Signing cancelled")); + layoutHome(); + return; + } + } + + /* Approved — show the signing screen before Orchard key derivation, which + * is seconds of Pallas math with nothing else drawing. */ + layoutProgress(_("Signing Zcash"), 0); + + if (!zcash_check_seed_fingerprint(msg->has_expected_seed_fingerprint, + msg->expected_seed_fingerprint.bytes, + msg->expected_seed_fingerprint.size)) { + layoutHome(); + return; + } + + /* Clear any stale state from a prior (possibly abandoned) session before + * starting a new one, so buffered transparent signatures or Orchard state + * from an earlier PCZT can never leak into this transaction. */ + zcash_signing_abort(); + + /* Derive Orchard keys via storage; the seed never leaves storage.c. */ + if (!storage_zcashOrchardKeys(account, true, &zcash_signing.keys)) { + fsm_sendFailure(FailureType_Failure_Other, + _("Orchard key derivation failed")); + layoutHome(); + return; + } + + /* Initialize signing state */ + zcash_signing.active = true; + zcash_signing.account = account; + zcash_signing.n_actions = msg->n_actions; + zcash_signing.current_action = 0; + zcash_signing.total_amount = total; + zcash_signing.fee = fee; + zcash_signing.branch_id = branch_id; + memcpy(zcash_signing.header_digest, header_digest, 32); + zcash_signing.has_device_sighash = false; + zcash_signing.verify_orchard_digest = false; + zcash_signing.n_transparent_outputs = + msg->has_n_transparent_outputs ? msg->n_transparent_outputs : 0; + zcash_signing.current_transparent_output = 0; + zcash_signing.n_transparent_inputs = + msg->has_n_transparent_inputs ? msg->n_transparent_inputs : 0; + zcash_signing.current_transparent_input = 0; + zcash_signing.has_expected_transparent_digest = false; + zcash_signing.transparent_digest_verified = false; + + /* Phase 2a: Compute sighash on-device from validated sub-digests. + * + * TRUST MODEL: + * + * What the device verifies: + * - Orchard digest: recomputed from streamed action data (Phase 2b) + * covering nullifiers, commitments, ephemeral keys, ciphertexts, + * value commitments, randomized keys, flags, value balance, anchor. + * - Orchard outputs: each displayed receiver/value is bound to cmx by + * recomputing the note commitment from recipient/value/rseed/rho before + * any authorization signature is emitted. + * - Transaction fee: computed from streamed transparent totals plus + * orchard_value_balance and compared to the requested fee before final + * user confirmation. + * - Sighash: assembled on-device from the 4 sub-digests. + * - transparent_digest: recomputed from streamed transparent outputs and + * inputs before any transparent or Orchard signature is emitted. + * - header_digest: recomputed from plaintext transaction header fields + * and compared to the supplied component digest. + * - Sapling: explicitly unsupported in this signing path. The device + * always uses the ZIP-244 empty Sapling digest and rejects any + * host-provided Sapling component. + * + * total_amount is a summary prompt. Transparent recipients, Orchard output + * recipients, Orchard output values, and the transaction fee all have their + * own verification gates before signatures are released. + * + * For shielded-only transactions (no transparent inputs): + * transparent_digest defaults to the well-known empty hash, + * so no trust assumption is needed for that component. + * + * For mixed transactions: + * transparent_digest is mandatory and verified against plaintext + * transparent metadata before local sighash derivation. */ + uint8_t t_digest[32], s_digest[32]; + + if (n_tinputs == 0 && n_toutputs == 0) { + memcpy(t_digest, EMPTY_TRANSPARENT_DIGEST, 32); + memcpy(s_digest, EMPTY_SAPLING_DIGEST, 32); + + zcash_compute_shielded_sighash( + header_digest, t_digest, s_digest, msg->orchard_digest.bytes, + zcash_signing.branch_id, zcash_signing.sighash); + zcash_signing.has_device_sighash = true; + zcash_signing.transparent_digest_verified = true; + } else { + memcpy(zcash_signing.expected_transparent_digest, + msg->transparent_digest.bytes, 32); + zcash_signing.has_expected_transparent_digest = true; + } + memzero(t_digest, sizeof(t_digest)); + memzero(s_digest, sizeof(s_digest)); + + /* Phase 2b: Orchard digest verification is mandatory for signing. + * The device incrementally hashes each action's data and verifies the + * computed orchard_digest matches the one used for sighash. */ + memcpy(zcash_signing.expected_orchard_digest, msg->orchard_digest.bytes, 32); + zcash_signing.orchard_flags = (uint8_t)msg->orchard_flags; + zcash_signing.orchard_value_balance = msg->orchard_value_balance; + memcpy(zcash_signing.orchard_anchor, msg->orchard_anchor.bytes, 32); + + blake2b_InitPersonal(&zcash_signing.compact_ctx, 32, "ZTxIdOrcActCHash", 16); + blake2b_InitPersonal(&zcash_signing.memos_ctx, 32, "ZTxIdOrcActMHash", 16); + blake2b_InitPersonal(&zcash_signing.noncompact_ctx, 32, "ZTxIdOrcActNHash", + 16); + zcash_signing.verify_orchard_digest = true; + + /* Draw the initial static progress BEFORE requesting the first component: + * for the actions-only path zcash_send_action_ack() arms the trickle, and a + * layoutProgress() after it would clear the animation queue and freeze it. */ + layoutProgress(_("Signing Zcash"), 0); + + /* Request the first plaintext component. Transparent outputs are reviewed + * before any transparent input or Orchard signature can be emitted. */ + if (zcash_signing.n_transparent_outputs > 0) { + zcash_send_transparent_output_ack(0); + } else if (zcash_signing.n_transparent_inputs > 0) { + zcash_send_transparent_input_ack(0); + } else { + zcash_send_action_ack(0); + } +} + +void fsm_msgZcashGetOrchardFVK(const ZcashGetOrchardFVK* msg) { + RESP_INIT(ZcashOrchardFVK); + + CHECK_INITIALIZED + + CHECK_PIN + + uint32_t account; + if (!zcash_resolve_account(msg->has_account, msg->account, msg->address_n, + msg->address_n_count, &account)) { + layoutHome(); + return; + } + + if (msg->has_show_display && msg->show_display && + !confirm(ButtonRequestType_ButtonRequest_ProtectCall, + "Export Zcash View Key", + "Export Orchard viewing key for account %u?\nReveals Zcash " + "activity.", + (unsigned)account)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Cancelled")); + layoutHome(); + return; + } + + /* Derive Orchard keys via storage; the seed never leaves storage.c. */ + layoutProgress(_("Deriving Zcash"), 0); + ZcashOrchardKeys keys; + if (!storage_zcashOrchardKeys(account, true, &keys)) { + fsm_sendFailure(FailureType_Failure_NotInitialized, + _("Orchard key derivation failed (seed unavailable?)")); + layoutHome(); + return; + } + + /* Compute ak = [ask]G_spendauth on Pallas curve (SpendAuth basepoint) */ + bignum256 ask_scalar; + bn_read_le(keys.ask, &ask_scalar); + curve_point ak_point; + redpallas_scalar_mult_spendauth_G(&ask_scalar, &ak_point); + + /* Serialize ak as Pallas point (LE x-coord, sign bit in high byte) */ + uint8_t ak_bytes[32]; + bignum256 x_copy; + bn_copy(&ak_point.x, &x_copy); + bn_write_le(&x_copy, ak_bytes); + if (bn_is_odd(&ak_point.y)) { + ak_bytes[31] |= 0x80; + } + + /* Build response */ + resp->has_ak = true; + resp->ak.size = 32; + memcpy(resp->ak.bytes, ak_bytes, 32); + + resp->has_nk = true; + resp->nk.size = 32; + memcpy(resp->nk.bytes, keys.nk, 32); + + resp->has_rivk = true; + resp->rivk.size = 32; + memcpy(resp->rivk.bytes, keys.rivk, 32); + + /* Seed identity (ZIP-32 §6.1). Lets the host pin this FVK to a + * specific device-seed identity for later signing/display flows. */ + uint8_t fp[32]; + if (storage_zcashSeedFingerprint(true, fp)) { + resp->has_seed_fingerprint = true; + resp->seed_fingerprint.size = 32; + memcpy(resp->seed_fingerprint.bytes, fp, 32); + memzero(fp, sizeof(fp)); + } + + /* Clean up sensitive data */ + memzero(&ask_scalar, sizeof(ask_scalar)); + memzero(&keys, sizeof(keys)); + + msg_write(MessageType_MessageType_ZcashOrchardFVK, resp); + layoutHome(); +} + +void fsm_msgZcashDisplayAddress(const ZcashDisplayAddress* msg) { + RESP_INIT(ZcashAddress); + + CHECK_INITIALIZED + + CHECK_PIN + + uint32_t account; + if (!zcash_resolve_account(msg->has_account, msg->account, msg->address_n, + msg->address_n_count, &account)) { + layoutHome(); + return; + } + + if (!zcash_check_seed_fingerprint(msg->has_expected_seed_fingerprint, + msg->expected_seed_fingerprint.bytes, + msg->expected_seed_fingerprint.size)) { + layoutHome(); + return; + } + + /* Derive Orchard keys via storage; the seed never leaves storage.c. */ + layoutProgress(_("Deriving Zcash"), 0); + ZcashOrchardKeys keys; + if (!storage_zcashOrchardKeys(account, true, &keys)) { + fsm_sendFailure(FailureType_Failure_NotInitialized, + _("Orchard key derivation failed (seed unavailable?)")); + layoutHome(); + return; + } + + layoutProgress(_("Deriving address"), 650); + char derived_address[sizeof(resp->address)]; + const uint8_t default_receiver_index[11] = {0}; + if (!zcash_orchard_derive_unified_address(&keys, default_receiver_index, "u", + derived_address, + sizeof(derived_address))) { + memzero(&keys, sizeof(keys)); + fsm_sendFailure(FailureType_Failure_Other, + _("Orchard address derivation failed")); + layoutHome(); + return; + } + + /* Clean up sensitive key material BEFORE display prompt. */ + memzero(&keys, sizeof(keys)); + + layoutProgress(_("Loading address"), 1000); + + char desc[48]; + snprintf(desc, sizeof(desc), "Zcash #%lu Orchard", (unsigned long)account); + if (!confirm_zcash_address(desc, derived_address)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("Address display cancelled")); + layoutHome(); + return; + } + + /* User confirmed — return the address bound to this device's seed. */ + resp->has_address = true; + strlcpy(resp->address, derived_address, sizeof(resp->address)); + + /* Seed identity (ZIP-32 §6.1) — pin the attestation to this device. */ + uint8_t fp[32]; + if (storage_zcashSeedFingerprint(true, fp)) { + resp->has_seed_fingerprint = true; + resp->seed_fingerprint.size = 32; + memcpy(resp->seed_fingerprint.bytes, fp, 32); + memzero(fp, sizeof(fp)); + } + + msg_write(MessageType_MessageType_ZcashAddress, resp); + layoutHome(); +} + +void fsm_msgZcashPCZTAction(const ZcashPCZTAction* msg) { + if (!zcash_signing.active) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + _("Not in Zcash signing mode")); + layoutHome(); + return; + } + + /* An action arrived: stop the trickle so the exact per-action milestone (and + * the fee confirm reached at completion) draws cleanly. Re-armed by the next + * zcash_send_action_ack() if more actions remain. */ + layoutProgressTrickleStop(); + + /* Enforce transparent phase completion: if the session declared any + * transparent data, all plaintext must be streamed and verified before + * Orchard actions. + * This prevents a malicious host from skipping transparent-input + * confirmations and jumping straight to Orchard signing. */ + if (zcash_signing.current_transparent_output < + zcash_signing.n_transparent_outputs || + zcash_signing.current_transparent_input < + zcash_signing.n_transparent_inputs || + ((zcash_signing.n_transparent_outputs > 0 || + zcash_signing.n_transparent_inputs > 0) && + !zcash_signing.transparent_digest_verified)) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + _("Transparent data not yet complete")); + zcash_signing_abort(); + layoutHome(); + return; + } + + /* Validate action index */ + if (!msg->has_index || msg->index != zcash_signing.current_action) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Unexpected action index")); + zcash_signing_abort(); + layoutHome(); + return; + } + + /* Validate required fields */ + if (!msg->has_alpha || msg->alpha.size != 32) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Missing or invalid alpha randomizer")); + zcash_signing_abort(); + layoutHome(); + return; + } + + /* Phase 2a: a device-computed sighash is mandatory. */ + if (!zcash_signing.has_device_sighash) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Missing transaction digests")); + zcash_signing_abort(); + layoutHome(); + return; + } + + const bool has_orchard_action_data = + zcash_signing.verify_orchard_digest && msg->has_nullifier && + msg->nullifier.size == 32 && msg->has_cmx && msg->cmx.size == 32 && + msg->has_epk && msg->epk.size == 32 && msg->has_enc_compact && + msg->enc_compact.size == 52 && msg->has_enc_memo && + msg->enc_memo.size == 512 && msg->has_enc_noncompact && + /* 580-byte enc_ciphertext = compact(52) + memo(512) + noncompact(16); + * pin the exact size like every sibling field so a host serializer bug + * fails fast per-action instead of as an end-of-flow digest mismatch. */ + msg->enc_noncompact.size == 16 && msg->has_cv_net && + msg->cv_net.size == 32 && msg->has_rk && msg->rk.size == 32 && + msg->has_out_ciphertext && msg->out_ciphertext.size == 80; + + if (!has_orchard_action_data) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Missing Orchard action data")); + zcash_signing_abort(); + layoutHome(); + return; + } + + if (!zcash_verify_and_confirm_orchard_output(msg)) { + zcash_signing_abort(); + layoutHome(); + return; + } + + /* The user just approved — switch to the signing screen NOW. RedPallas + * signing below is many seconds of pure device-side math, and without + * this draw the dismissed dialog would sit on screen the whole time. */ + layoutProgress(_("Signing Zcash"), (zcash_signing.current_action * 1000) / + zcash_signing.n_actions); + + /* Phase 2b: feed action data into incremental BLAKE2b contexts */ + blake2b_Update(&zcash_signing.compact_ctx, msg->nullifier.bytes, 32); + blake2b_Update(&zcash_signing.compact_ctx, msg->cmx.bytes, 32); + blake2b_Update(&zcash_signing.compact_ctx, msg->epk.bytes, 32); + blake2b_Update(&zcash_signing.compact_ctx, msg->enc_compact.bytes, 52); + + blake2b_Update(&zcash_signing.memos_ctx, msg->enc_memo.bytes, 512); + + blake2b_Update(&zcash_signing.noncompact_ctx, msg->cv_net.bytes, 32); + blake2b_Update(&zcash_signing.noncompact_ctx, msg->rk.bytes, 32); + blake2b_Update(&zcash_signing.noncompact_ctx, msg->enc_noncompact.bytes, + msg->enc_noncompact.size); + blake2b_Update(&zcash_signing.noncompact_ctx, msg->out_ciphertext.bytes, 80); + + const uint8_t* sighash = zcash_signing.sighash; + + /* Sign this action with RedPallas: + * sig = RedPallas.sign(ask, alpha, sighash) */ + if (redpallas_sign_digest(zcash_signing.keys.ask, msg->alpha.bytes, sighash, + zcash_signing.signatures[msg->index]) != 0) { + fsm_sendFailure(FailureType_Failure_Other, _("RedPallas signing failed")); + zcash_signing_abort(); + layoutHome(); + return; + } + + zcash_signing.current_action++; + + /* Update progress */ + uint32_t progress = + (zcash_signing.current_action * 1000) / zcash_signing.n_actions; + layoutProgress(_("Signing Zcash"), progress); + + /* Check if all actions are signed */ + if (zcash_signing.current_action >= zcash_signing.n_actions) { + /* Phase 2b: verify orchard digest before returning signatures */ + if (zcash_signing.verify_orchard_digest) { + uint8_t compact_hash[32], memos_hash[32], noncompact_hash[32]; + + blake2b_Final(&zcash_signing.compact_ctx, compact_hash, 32); + blake2b_Final(&zcash_signing.memos_ctx, memos_hash, 32); + blake2b_Final(&zcash_signing.noncompact_ctx, noncompact_hash, 32); + + /* Compute orchard_digest = BLAKE2b("ZTxIdOrchardHash", + * compact_hash || memos_hash || noncompact_hash || + * flags(1) || value_balance(8) || anchor(32)) */ + BLAKE2B_CTX orchard_ctx; + blake2b_InitPersonal(&orchard_ctx, 32, "ZTxIdOrchardHash", 16); + blake2b_Update(&orchard_ctx, compact_hash, 32); + blake2b_Update(&orchard_ctx, memos_hash, 32); + blake2b_Update(&orchard_ctx, noncompact_hash, 32); + blake2b_Update(&orchard_ctx, &zcash_signing.orchard_flags, 1); + blake2b_Update(&orchard_ctx, + (const uint8_t*)&zcash_signing.orchard_value_balance, 8); + blake2b_Update(&orchard_ctx, zcash_signing.orchard_anchor, 32); + + uint8_t computed_orchard_digest[32]; + blake2b_Final(&orchard_ctx, computed_orchard_digest, 32); + + /* Verify computed matches expected */ + if (memcmp(computed_orchard_digest, zcash_signing.expected_orchard_digest, + 32) != 0) { + fsm_sendFailure(FailureType_Failure_Other, + _("Orchard digest mismatch: transaction data " + "does not match sighash")); + zcash_signing_abort(); + layoutHome(); + return; + } + } + + if (!zcash_verify_and_confirm_fee()) { + zcash_signing_abort(); + layoutHome(); + return; + } + + /* Release deferred transparent ECDSA sigs at the same gate as Orchard sigs + * — both are sent only after Orchard digest verification and fee + * confirmation. */ + if (zcash_signing.has_pending_transparent) { + ZcashTransparentSigned* t_resp = (ZcashTransparentSigned*)msg_resp; + memcpy(t_resp, &zcash_signing.pending_transparent, + sizeof(ZcashTransparentSigned)); + msg_write(MessageType_MessageType_ZcashTransparentSigned, t_resp); + } + + /* All done - send the collected Orchard signatures */ + ZcashSignedPCZT* resp_signed = (ZcashSignedPCZT*)msg_resp; + memset(resp_signed, 0, sizeof(ZcashSignedPCZT)); + + resp_signed->signatures_count = zcash_signing.n_actions; + for (uint32_t i = 0; i < zcash_signing.n_actions; i++) { + resp_signed->signatures[i].size = 64; + memcpy(resp_signed->signatures[i].bytes, zcash_signing.signatures[i], 64); + } + + /* Clean up */ + zcash_signing_abort(); + + msg_write(MessageType_MessageType_ZcashSignedPCZT, resp_signed); + layoutHome(); + } else { + /* Request next action */ + zcash_send_action_ack(zcash_signing.current_action); + } +} + +void fsm_msgZcashTransparentOutput(const ZcashTransparentOutput* msg) { + if (!zcash_signing.active) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + _("Not in Zcash signing mode")); + layoutHome(); + return; + } + + if (zcash_signing.n_transparent_outputs == 0) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + _("No transparent outputs expected")); + zcash_signing_abort(); + layoutHome(); + return; + } + + if (zcash_signing.current_transparent_input != 0) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + _("Transparent outputs must come first")); + zcash_signing_abort(); + layoutHome(); + return; + } + + if (msg->index != zcash_signing.current_transparent_output) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Unexpected transparent output index")); + zcash_signing_abort(); + layoutHome(); + return; + } + + if (!msg->has_amount || !msg->has_script_pubkey || + msg->script_pubkey.size == 0 || + msg->script_pubkey.size > ZCASH_MAX_TRANSPARENT_SCRIPT_PUBKEY) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Invalid transparent output script")); + zcash_signing_abort(); + layoutHome(); + return; + } + + char address[64]; + if (!zcash_transparent_script_to_address(msg->script_pubkey.bytes, + msg->script_pubkey.size, address, + sizeof(address))) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Unsupported transparent output script")); + zcash_signing_abort(); + layoutHome(); + return; + } + + char amount_str[32]; + zcash_format_amount(msg->amount, amount_str, sizeof(amount_str)); + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "Zcash Output", + "Send transparent ZEC?\n%s\nAmount: %s", address, amount_str)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("Signing cancelled")); + zcash_signing_abort(); + layoutHome(); + return; + } + + ZcashTransparentOutputState* stored = + &zcash_signing.transparent_outputs[msg->index]; + stored->received = true; + stored->amount = msg->amount; + stored->script_pubkey_size = msg->script_pubkey.size; + memcpy(stored->script_pubkey, msg->script_pubkey.bytes, + msg->script_pubkey.size); + + zcash_signing.current_transparent_output++; + + /* Static draw before the dispatch: the actions transition below arms the + * trickle, and a layoutProgress() after it would clear and freeze it. */ + layoutProgress(_("Signing Zcash"), 0); + + if (zcash_signing.current_transparent_output < + zcash_signing.n_transparent_outputs) { + zcash_send_transparent_output_ack(zcash_signing.current_transparent_output); + } else if (zcash_signing.n_transparent_inputs > 0) { + zcash_send_transparent_input_ack(0); + } else { + if (!zcash_finalize_transparent_digest()) { + fsm_sendFailure(FailureType_Failure_Other, + _("Transparent digest mismatch")); + zcash_signing_abort(); + layoutHome(); + return; + } + zcash_send_action_ack(0); + } +} + +/* Phase 3: Transparent plaintext streaming for hybrid shielding + * transactions. The host streams all outputs first, then all inputs. Only after + * the firmware verifies transparent_digest from the streamed plaintext does it + * derive per-input ZIP-244 sighashes and emit ECDSA signatures. */ +void fsm_msgZcashTransparentInput(const ZcashTransparentInput* msg) { + if (!zcash_signing.active) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + _("Not in Zcash signing mode")); + layoutHome(); + return; + } + + if (zcash_signing.n_transparent_inputs == 0) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + _("No transparent inputs expected")); + zcash_signing_abort(); + layoutHome(); + return; + } + + if (zcash_signing.current_transparent_output < + zcash_signing.n_transparent_outputs) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + _("Transparent outputs not yet complete")); + zcash_signing_abort(); + layoutHome(); + return; + } + + if (msg->index != zcash_signing.current_transparent_input) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Unexpected transparent input index")); + zcash_signing_abort(); + layoutHome(); + return; + } + + if (msg->has_sighash) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Host transparent sighash rejected")); + zcash_signing_abort(); + layoutHome(); + return; + } + + if (!msg->has_amount || !msg->has_prevout_txid || + msg->prevout_txid.size != 32 || !msg->has_prevout_index || + !msg->has_sequence || !msg->has_script_pubkey || + msg->script_pubkey.size == 0 || + msg->script_pubkey.size > ZCASH_MAX_TRANSPARENT_SCRIPT_PUBKEY) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Invalid transparent input data")); + zcash_signing_abort(); + layoutHome(); + return; + } + + if (!zcash_script_is_standard_transparent(msg->script_pubkey.bytes, + msg->script_pubkey.size)) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Unsupported transparent input script")); + zcash_signing_abort(); + layoutHome(); + return; + } + + /* PATH ENFORCEMENT: transparent inputs must use exactly + * m/44'/133'/account'/change/index where: + * - account' is hardened and matches the session account + * - change is 0 (external) or 1 (internal) + * - index is unhardened + * + * This prevents a compromised host from pivoting a shielding approval + * into signing with arbitrary secp256k1 keys on the device. */ + if (msg->address_n_count != 5) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Path must be m/44'/133'/account'/change/index")); + zcash_signing_abort(); + layoutHome(); + return; + } + + if (msg->address_n[0] != (0x80000000 | 44) || + msg->address_n[1] != (0x80000000 | 133)) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Path must start with m/44'/133'")); + zcash_signing_abort(); + layoutHome(); + return; + } + + /* Account must be hardened and match the approved session */ + if (!(msg->address_n[2] & 0x80000000)) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Account must be hardened")); + zcash_signing_abort(); + layoutHome(); + return; + } + + uint32_t path_account = msg->address_n[2] & 0x7FFFFFFF; + if (path_account != zcash_signing.account) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Account does not match approved session")); + zcash_signing_abort(); + layoutHome(); + return; + } + + /* Change must be 0 (external) or 1 (internal), unhardened */ + if (msg->address_n[3] > 1) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Change must be 0 or 1")); + zcash_signing_abort(); + layoutHome(); + return; + } + + /* Index must be unhardened */ + if (msg->address_n[4] & 0x80000000) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Index must not be hardened")); + zcash_signing_abort(); + layoutHome(); + return; + } + + ZcashTransparentInputState* stored = + &zcash_signing.transparent_inputs[msg->index]; + stored->received = true; + stored->amount = msg->amount; + memcpy(stored->prevout_txid, msg->prevout_txid.bytes, 32); + stored->prevout_index = msg->prevout_index; + stored->sequence = msg->sequence; + stored->script_pubkey_size = msg->script_pubkey.size; + memcpy(stored->script_pubkey, msg->script_pubkey.bytes, + msg->script_pubkey.size); + stored->address_n_count = msg->address_n_count; + memcpy(stored->address_n, msg->address_n, + msg->address_n_count * sizeof(msg->address_n[0])); + + zcash_signing.current_transparent_input++; + + if (zcash_signing.current_transparent_input < + zcash_signing.n_transparent_inputs) { + zcash_send_transparent_input_ack(zcash_signing.current_transparent_input); + layoutProgress(_("Signing Zcash"), 0); + return; + } + + if (!zcash_finalize_transparent_digest()) { + fsm_sendFailure(FailureType_Failure_Other, + _("Transparent digest mismatch")); + zcash_signing_abort(); + layoutHome(); + return; + } + + bool cancelled = false; + if (!zcash_sign_transparent_inputs(&cancelled)) { + fsm_sendFailure(cancelled ? FailureType_Failure_ActionCancelled + : FailureType_Failure_Other, + cancelled ? _("Signing cancelled") + : _("Transparent input signing failed")); + zcash_signing_abort(); + layoutHome(); + return; + } + + /* Transparent ECDSA sigs are buffered in zcash_signing.pending_transparent. + * They are released at the same final gate as Orchard sigs, after Orchard + * digest verification and fee confirmation. */ + /* Static draw before arming: zcash_send_action_ack() arms the trickle, so a + * layoutProgress() after it would clear the animation queue and freeze it. */ + layoutProgress(_("Signing Zcash"), 0); + zcash_send_action_ack(0); +} diff --git a/lib/firmware/hive.c b/lib/firmware/hive.c new file mode 100644 index 000000000..304f673ae --- /dev/null +++ b/lib/firmware/hive.c @@ -0,0 +1,1096 @@ +/* + * 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 as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + */ + +#include "keepkey/firmware/hive.h" + +#include "trezor/crypto/base58.h" +#include "trezor/crypto/memzero.h" +#include "trezor/crypto/secp256k1.h" +#include "trezor/crypto/sha2.h" + +#include +#include + +// ── STM public key encoding ─────────────────────────────────────────────── + +bool hive_getPublicKey(const uint8_t public_key[33], char* out, + size_t out_len) { + const size_t prefix_len = strlen(HIVE_PUBKEY_PREFIX); + if (out_len < prefix_len + 1) return false; + strlcpy(out, HIVE_PUBKEY_PREFIX, out_len); + // Graphene uses RIPEMD checksum (not SHA256d) for public key encoding + return base58_encode_check(public_key, 33, HASHER_RIPEMD, out + prefix_len, + out_len - prefix_len); +} + +// ── Single-role key derivation to raw 33 bytes ──────────────────────────── +// Path: m/48'/13'/role_hardened/account_index_hardened/0' +// hdnode_private_ckd() returns 1 on success, 0 on failure. + +static bool hive_role_valid(uint32_t role) { + return role == HIVE_ROLE_OWNER || role == HIVE_ROLE_ACTIVE || + role == HIVE_ROLE_MEMO || role == HIVE_ROLE_POSTING; +} + +bool hive_slip48_path_valid(const uint32_t* address_n, size_t count) { + if (!address_n || count != 5) return false; + if (address_n[0] != HIVE_SLIP48_PURPOSE) return false; + if (address_n[1] != HIVE_SLIP48_NETWORK) return false; + if (!hive_role_valid(address_n[2])) return false; + if ((address_n[3] & 0x80000000u) == 0) return false; + if (address_n[4] != 0x80000000u) return false; + return true; +} + +bool hive_slip48_path_valid_for_role(const uint32_t* address_n, size_t count, + uint32_t required_role) { + return hive_role_valid(required_role) && + hive_slip48_path_valid(address_n, count) && + address_n[2] == required_role; +} + +bool hive_deriveRawKey(const HDNode* root, uint32_t role_hardened, + uint32_t account_index_hardened, uint8_t out[33]) { + HDNode node; + memcpy(&node, root, sizeof(HDNode)); + if (!hdnode_private_ckd(&node, HIVE_SLIP48_PURPOSE)) goto fail; + if (!hdnode_private_ckd(&node, HIVE_SLIP48_NETWORK)) goto fail; + if (!hdnode_private_ckd(&node, role_hardened)) goto fail; + if (!hdnode_private_ckd(&node, account_index_hardened)) goto fail; + if (!hdnode_private_ckd(&node, 0x80000000u)) goto fail; + hdnode_fill_public_key(&node); + memcpy(out, node.public_key, 33); + memzero(&node, sizeof(node)); + return true; +fail: + memzero(&node, sizeof(node)); + return false; +} + +// ── SLIP-0048 multi-role key derivation ─────────────────────────────────── + +bool hive_getPublicKeys(const HDNode* root, uint32_t account_index, + char* owner_out, size_t owner_len, char* active_out, + size_t active_len, char* memo_out, size_t memo_len, + char* posting_out, size_t posting_len) { + const uint32_t roles[4] = { + HIVE_ROLE_OWNER, + HIVE_ROLE_ACTIVE, + HIVE_ROLE_MEMO, + HIVE_ROLE_POSTING, + }; + char* outs[4] = {owner_out, active_out, memo_out, posting_out}; + const size_t lens[4] = {owner_len, active_len, memo_len, posting_len}; + + uint32_t account_hardened = account_index | 0x80000000u; + + for (int i = 0; i < 4; i++) { + uint8_t raw[33]; + if (!hive_deriveRawKey(root, roles[i], account_hardened, raw)) return false; + if (!hive_getPublicKey(raw, outs[i], lens[i])) { + memzero(raw, sizeof(raw)); + return false; + } + memzero(raw, sizeof(raw)); + } + return true; +} + +// ── Graphene binary serialization helpers ───────────────────────────────── + +static void append_u8(uint8_t** buf, const uint8_t* end, uint8_t v) { + if (*buf < end) { + **buf = v; + (*buf)++; + } +} + +static void append_u16_le(uint8_t** buf, const uint8_t* end, uint16_t v) { + append_u8(buf, end, v & 0xFF); + append_u8(buf, end, (v >> 8) & 0xFF); +} + +static void append_u32_le(uint8_t** buf, const uint8_t* end, uint32_t v) { + append_u8(buf, end, v & 0xFF); + append_u8(buf, end, (v >> 8) & 0xFF); + append_u8(buf, end, (v >> 16) & 0xFF); + append_u8(buf, end, (v >> 24) & 0xFF); +} + +static void append_u64_le(uint8_t** buf, const uint8_t* end, uint64_t v) { + for (int i = 0; i < 8; i++) { + append_u8(buf, end, v & 0xFF); + v >>= 8; + } +} + +static void append_varint(uint8_t** buf, const uint8_t* end, uint64_t v) { + do { + uint8_t b = v & 0x7F; + v >>= 7; + if (v) b |= 0x80; + append_u8(buf, end, b); + } while (v); +} + +static void append_string(uint8_t** buf, const uint8_t* end, const char* s) { + size_t len = s ? strlen(s) : 0; + append_varint(buf, end, len); + for (size_t i = 0; i < len && *buf < end; i++) + append_u8(buf, end, (uint8_t)s[i]); +} + +/* + * Graphene asset encoding: int64 LE amount + uint8 precision + 7-byte symbol + */ +static void append_asset(uint8_t** buf, const uint8_t* end, uint64_t amount, + uint8_t precision, const char* symbol) { + append_u64_le(buf, end, amount); + append_u8(buf, end, precision); + char sym[7] = {0}; + if (symbol) strncpy(sym, symbol, 6); + for (int i = 0; i < 7 && *buf < end; i++) + append_u8(buf, end, (uint8_t)sym[i]); +} + +/* + * Graphene authority structure (Hive wire format): + * weight_threshold (uint32 LE) = 1 + * num_account_auths (varint) = 0 + * num_key_auths (varint) = 1 + * compressed public key (33 bytes, no type prefix) + * weight (uint16 LE) = 1 + * + * Note: Hive does NOT use a key-type prefix byte before the 33 raw bytes. + */ +static void append_authority(uint8_t** buf, const uint8_t* end, + const uint8_t pubkey[33]) { + append_u32_le(buf, end, 1); // weight_threshold = 1 + append_varint(buf, end, 0); // 0 account auths + append_varint(buf, end, 1); // 1 key auth + for (int i = 0; i < 33 && *buf < end; i++) append_u8(buf, end, pubkey[i]); + append_u16_le(buf, end, 1); // weight = 1 +} + +/* + * Common transaction header: ref_block_num, ref_block_prefix, expiration, + * then a varint op count = 1, then the op type varint. + */ +static void append_tx_header(uint8_t** buf, const uint8_t* end, + uint16_t ref_block_num, uint32_t ref_block_prefix, + uint32_t expiration, uint32_t op_type) { + append_u16_le(buf, end, ref_block_num); + append_u32_le(buf, end, ref_block_prefix); + append_u32_le(buf, end, expiration); + append_varint(buf, end, 1); // 1 operation + append_varint(buf, end, op_type); +} + +static void append_tx_footer(uint8_t** buf, const uint8_t* end) { + append_varint(buf, end, 0); // 0 extensions +} + +/* + * Graphene legacy canonical-signature rule (identical to EOS/Steem): high bit + * of both r and s must be clear — same predicate as eos_is_canonic. Modern + * hived (post-HF28) actually enforces only BIP-0062 low-S (fc is_canonical -> + * is_bip_0062_canonical), which trezor-crypto's low-S normalization already + * guarantees; keeping the stricter legacy rule costs an occasional extra + * RFC6979 iteration and stays compatible with every historical verifier. + */ +static int hive_is_canonic(uint8_t v, uint8_t signature[64]) { + (void)v; + return !(signature[0] & 0x80) && + !(signature[0] == 0 && !(signature[1] & 0x80)) && + !(signature[32] & 0x80) && + !(signature[32] == 0 && !(signature[33] & 0x80)); +} + +/* + * Core sign helper over an already-computed 32-byte digest → 65-byte + * compact recoverable sig: header (27 + recovery_id + 4 compressed-key + * flag), then r(32) ‖ s(32). + */ +static bool hive_sign_raw_digest(const HDNode* node, const uint8_t digest[32], + uint8_t sig[65]) { + uint8_t pby; + if (ecdsa_sign_digest(&secp256k1, node->private_key, digest, sig + 1, &pby, + hive_is_canonic) != 0) { + return false; + } + // Compact signature header: 27 + recovery_id + 4 (compressed key flag) + sig[0] = 27 + pby + 4; + return true; +} + +/* + * Transaction sign helper: SHA256(chain_id || serialized_tx) → compact sig. + * Writes 65 bytes into sig[]. Returns true on success. + */ +static bool hive_sign_digest(const HDNode* node, const uint8_t* chain_id, + const uint8_t* tx_buf, size_t tx_len, + uint8_t sig[65]) { + SHA256_CTX sha; + sha256_Init(&sha); + sha256_Update(&sha, chain_id, HIVE_CHAIN_ID_LEN); + sha256_Update(&sha, tx_buf, tx_len); + uint8_t digest[32]; + sha256_Final(&sha, digest); + + bool ok = hive_sign_raw_digest(node, digest, sig); + memzero(digest, sizeof(digest)); + return ok; +} + +/* + * Chain-id select (host-supplied 32-byte chain_id or mainnet default) + + * hive_sign_digest, writing the 65-byte compact signature into sig[]. + */ +static bool hive_sign_tx_sig(const HDNode* node, bool has_chain_id, + const uint8_t* chain_id_bytes, + size_t chain_id_size, const uint8_t* tx_buf, + size_t tx_len, uint8_t sig[65]) { + const uint8_t default_chain_id[32] = HIVE_CHAIN_ID; + /* Pin to Hive mainnet. A host-supplied chain_id is accepted only if it equals + * mainnet; any other value is refused rather than signed under an undisclosed + * network domain (the confirmations just say "Hive"). This also keeps the tx + * digest domain singular — SHA256(mainnet_chain_id || tx) — so the + * message-signing guard that rejects messages beginning with the mainnet + * chain id fully closes the tx/message signature collision. */ + if (has_chain_id) { + if (chain_id_size != HIVE_CHAIN_ID_LEN || + memcmp(chain_id_bytes, default_chain_id, HIVE_CHAIN_ID_LEN) != 0) { + return false; + } + } + return hive_sign_digest(node, default_chain_id, tx_buf, tx_len, sig); +} + +// ── Parsed operation signing (HiveSignOperations) ───────────────────────── +// +// The host serializes the transaction; firmware re-derives everything it +// displays from the bytes and refuses anything outside the phase-1 op table. +// Digest/signature are identical to HiveSignTx: SHA256(chain_id || tx). + +typedef struct { + const uint8_t* p; + const uint8_t* end; +} HiveCur; + +/* + * Bounded unsigned LEB128: at most 5 bytes, must fit uint32, overlong + * encodings rejected (an unbounded shift is a classic overflow hole). + */ +static bool cur_varint(HiveCur* c, uint32_t* out) { + uint32_t v = 0; + for (int shift = 0; shift <= 28; shift += 7) { + if (c->p >= c->end) return false; + uint8_t b = *c->p++; + if (shift == 28 && (b & 0xF0)) return false; // overflow or 6th byte + v |= (uint32_t)(b & 0x7F) << shift; + if (!(b & 0x80)) { + // A multi-byte LEB128 whose final group is zero has a shorter encoding. + // hived re-serializes values canonically when checking a signature, so + // accepting an overlong form would make the device sign bytes the chain + // interprets and hashes differently. + if (shift > 0 && (b & 0x7F) == 0) return false; + *out = v; + return true; + } + } + return false; +} + +/* varint length + bytes, bounds-checked against the buffer AND field caps. */ +static bool cur_string(HiveCur* c, const uint8_t** s, uint16_t* slen, + uint32_t min_len, uint32_t max_len) { + uint32_t n; + if (!cur_varint(c, &n)) return false; + if (n < min_len || n > max_len) return false; + if ((size_t)(c->end - c->p) < n) return false; + *s = c->p; + *slen = (uint16_t)n; + c->p += n; + return true; +} + +/* + * Hive account names are rendered in compact multi-field confirmation screens, + * so they must be valid protocol names rather than arbitrary byte strings. + * This rejects embedded NUL/newline/control bytes that would truncate or + * reshape the OLED while later bytes remained covered by the signature. + */ +static bool hive_account_name_valid(const uint8_t* s, uint16_t len, + bool allow_empty) { + if (len == 0) return allow_empty; + if (len < 3 || len > 16) return false; + + bool at_segment_start = true; + bool previous_hyphen = false; + for (uint16_t i = 0; i < len; i++) { + uint8_t ch = s[i]; + if (at_segment_start) { + if (ch < 'a' || ch > 'z') return false; + at_segment_start = false; + previous_hyphen = false; + } else if (ch == '.') { + if (previous_hyphen || i + 1 == len) return false; + at_segment_start = true; + } else if ((ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')) { + previous_hyphen = false; + } else if (ch == '-') { + previous_hyphen = true; + } else { + return false; + } + } + return !at_segment_start && !previous_hyphen; +} + +static bool cur_account(HiveCur* c, const uint8_t** s, uint16_t* slen, + bool allow_empty) { + if (!cur_string(c, s, slen, allow_empty ? 0 : 1, 16)) return false; + return hive_account_name_valid(*s, *slen, allow_empty); +} + +static int hive_slice_cmp(const uint8_t* a, uint16_t a_len, const uint8_t* b, + uint16_t b_len) { + uint16_t min_len = a_len < b_len ? a_len : b_len; + int cmp = memcmp(a, b, min_len); + if (cmp != 0) return cmp; + return (a_len > b_len) - (a_len < b_len); +} + +/* Fixed-width little-endian readers, bounds-checked against the buffer. */ +static bool cur_u16(HiveCur* c, uint16_t* out) { + if ((size_t)(c->end - c->p) < 2) return false; + *out = (uint16_t)((uint16_t)c->p[0] | ((uint16_t)c->p[1] << 8)); + c->p += 2; + return true; +} + +static bool cur_u32(HiveCur* c, uint32_t* out) { + if ((size_t)(c->end - c->p) < 4) return false; + *out = (uint32_t)c->p[0] | ((uint32_t)c->p[1] << 8) | + ((uint32_t)c->p[2] << 16) | ((uint32_t)c->p[3] << 24); + c->p += 4; + return true; +} + +/* + * Graphene serializes bool as one byte. Anything other than 0/1 is a host + * serializer bug, not a truthy value — reject rather than normalize, so a + * malformed fill_or_kill or allow_votes can never be silently coerced. + */ +static bool cur_bool(HiveCur* c, bool* out) { + if (c->p >= c->end) return false; + uint8_t b = *c->p++; + if (b > 1) return false; + *out = (b == 1); + return true; +} + +uint64_t hive_assetAmount(const uint8_t* asset) { + uint64_t v = 0; + for (int i = 7; i >= 0; i--) v = (v << 8) | asset[i]; + return v; +} + +uint8_t hive_assetPrecision(const uint8_t* asset) { return asset[8]; } + +// Wire symbol → display symbol. The chain serializes the pre-rebrand names; +// the user knows the post-rebrand ones. cur_asset() has already validated the +// symbol and its NUL padding, so the compares below are exact. +const char* hive_assetSymbol(const uint8_t* asset) { + const char* sym = (const char*)(asset + 9); + if (memcmp(sym, "STEEM", 6) == 0) return "HIVE"; + if (memcmp(sym, "SBD", 4) == 0) return "HBD"; + return sym; +} + +/* + * One 16-byte Graphene asset: int64 LE amount, uint8 precision, 7-byte + * NUL-padded symbol. + * + * The symbol must be in `allowed` and carry its protocol-fixed precision. + * Both checks are load-bearing for display integrity: an unexpected symbol + * lets a host swap VESTS for HIVE (a ~2000x difference in real value behind + * an identical-looking number), and a wrong precision moves the decimal + * point on the confirmation screen relative to what the chain applies. + */ +static bool cur_asset(HiveCur* c, const uint8_t** out, uint32_t allowed) { + if ((size_t)(c->end - c->p) < HIVE_ASSET_LEN) return false; + const uint8_t* a = c->p; + const uint8_t* sym = a + 9; + + uint32_t bit; + uint8_t want_precision; + size_t sym_len; + // WIRE symbols, not display symbols: the 2020 rebrand renamed the tokens but + // NOT their on-chain serialization, so hived still encodes HIVE as "STEEM" + // and HBD as "SBD". Accepting the display spellings would let us sign bytes + // hived can never validate — its signature check re-serializes the operation + // and recovers a key from different bytes, surfacing as the misleading + // "missing required active authority". hive_assetSymbol() maps back for the + // OLED so the user still reads HIVE/HBD. + if (memcmp(sym, "STEEM", 5) == 0) { + bit = HIVE_SYM_HIVE; + want_precision = 3; + sym_len = 5; + } else if (memcmp(sym, "SBD", 3) == 0) { + bit = HIVE_SYM_HBD; + want_precision = 3; + sym_len = 3; + } else if (memcmp(sym, "VESTS", 5) == 0) { + bit = HIVE_SYM_VESTS; + want_precision = 6; + sym_len = 5; + } else { + return false; + } + // The prefix compares above would also accept a longer symbol sharing the + // prefix ("HBDX"); the padding check is what makes them exact, and it also + // guarantees hive_assetSymbol() returns a NUL-terminated C string. + for (size_t i = sym_len; i < 7; i++) { + if (sym[i] != 0) return false; + } + if (!(bit & allowed)) return false; + if (a[8] != want_precision) return false; + // Every asset field in this table is a quantity. A negative int64 would + // render as an enormous positive number through the unsigned formatter. + if (a[7] & 0x80) return false; + + *out = a; + c->p += HIVE_ASSET_LEN; + return true; +} + +/* + * Shared rejection reasons. + * + * These are diagnostics, not security surface: the protection is that the + * device REFUSES, and the host already knows which operation it sent. One + * bespoke sentence per failure site cost ~1.8KB of rodata on a part with + * single-digit KB of flash left, so failures are grouped by reason instead. + * The three that carry a distinct security meaning — an authority rotation, + * a detached comment_options, a wrong-tier request — stay separate so they + * are never confused with an ordinary parse failure in a bug report. + */ +static const char E_MALFORMED[] = "Hive tx: malformed operation"; +static const char E_RANGE[] = "Hive tx: value out of range"; +static const char E_AMOUNT[] = "Hive tx: amount must be greater than zero"; +static const char E_NOOP[] = "Hive tx: operation has no effect"; +static const char E_EXTENSIONS[] = "Hive tx: extensions must be empty"; +static const char E_BENEFICIARIES[] = "Hive tx: invalid beneficiaries"; +static const char E_SYMBOLS[] = "Hive tx: order symbols must differ"; +static const char E_AUTHORITY[] = "Hive tx: authority changes not supported"; +static const char E_BINDING[] = + "Hive tx: comment_options must follow its comment"; +static const char E_MIXED_TIER[] = "Hive tx: mixed posting/active ops"; + +const char* hive_parseOperations(const uint8_t* tx, size_t len, + HiveParsedTx* out) { + memzero(out, sizeof(*out)); + // 10-byte header + op_count varint + extensions varint is the structural + // minimum; op bodies are bounds-checked as they parse. + if (len < 12) return "Hive tx too short"; + if (len > HIVE_MAX_OPS_TX_LEN) return "Hive tx too long"; // = proto cap + + // Header (ref_block_num u16, ref_block_prefix u32, expiration u32) is + // covered by the signature but carries nothing to confirm on-device. + HiveCur c = {tx + 10, tx + len}; + + uint32_t op_count; + if (!cur_varint(&c, &op_count)) return E_MALFORMED; + if (op_count < 1 || op_count > HIVE_MAX_TX_OPS) + return "Hive tx: op count must be 1-4"; + out->num_ops = (uint8_t)op_count; + + bool any_posting = false, any_active = false; + + for (uint32_t i = 0; i < op_count; i++) { + HiveTxOp* op = &out->ops[i]; + uint32_t op_type; + if (!cur_varint(&c, &op_type)) return E_MALFORMED; + op->op_type = op_type; + + switch (op_type) { + case HIVE_OP_VOTE: { // posting authority + if (!cur_account(&c, &op->acct, &op->acct_len, false) || + !cur_account(&c, &op->target, &op->target_len, false) || + !cur_string(&c, &op->detail, &op->detail_len, 1, 256)) + return E_MALFORMED; + if ((size_t)(c.end - c.p) < 2) return E_MALFORMED; + int16_t w = (int16_t)((uint16_t)c.p[0] | ((uint16_t)c.p[1] << 8)); + c.p += 2; + if (w < -10000 || w > 10000) return E_RANGE; + op->weight = w; + any_posting = true; + break; + } + case HIVE_OP_COMMENT: { // posting authority + const uint8_t *pa, *ppl, *permlink, *jm; + uint16_t pa_len, ppl_len, permlink_len, jm_len; + if (!cur_account(&c, &pa, &pa_len, true) || + !cur_string(&c, &ppl, &ppl_len, 1, 256) || + !cur_account(&c, &op->acct, &op->acct_len, false) || + !cur_string(&c, &permlink, &permlink_len, 1, 256) || + !cur_string(&c, &op->target, &op->target_len, 0, 256) || + !cur_string(&c, &op->detail, &op->detail_len, 1, + HIVE_MAX_OPS_TX_LEN) || + !cur_string(&c, &jm, &jm_len, 0, HIVE_MAX_OPS_TX_LEN)) + return E_MALFORMED; + op->parent_author = pa; + op->parent_author_len = pa_len; + op->parent_permlink = ppl; + op->parent_permlink_len = ppl_len; + op->permlink = permlink; + op->permlink_len = permlink_len; + op->json_metadata = jm; + op->json_metadata_len = jm_len; + op->is_top_level = (pa_len == 0); + any_posting = true; + break; + } + case HIVE_OP_CUSTOM_JSON: { // posting OR active authority + uint32_t n_active, n_posting; + if (!cur_varint(&c, &n_active)) return E_MALFORMED; + if (n_active > HIVE_MAX_CUSTOM_JSON_AUTHS) return E_RANGE; + const uint8_t* previous_auth = NULL; + uint16_t previous_auth_len = 0; + for (uint32_t k = 0; k < n_active; k++) { + const uint8_t* s; + uint16_t sl; + if (!cur_account(&c, &s, &sl, false)) return E_MALFORMED; + if (previous_auth && + hive_slice_cmp(previous_auth, previous_auth_len, s, sl) >= 0) + return E_MALFORMED; + op->auth_acct[op->n_auths] = s; + op->auth_acct_len[op->n_auths++] = sl; + previous_auth = s; + previous_auth_len = sl; + if (!op->acct) { + op->acct = s; + op->acct_len = sl; + } + } + if (!cur_varint(&c, &n_posting)) return E_MALFORMED; + if (n_posting > HIVE_MAX_CUSTOM_JSON_AUTHS - n_active) return E_RANGE; + previous_auth = NULL; + previous_auth_len = 0; + for (uint32_t k = 0; k < n_posting; k++) { + const uint8_t* s; + uint16_t sl; + if (!cur_account(&c, &s, &sl, false)) return E_MALFORMED; + if (previous_auth && + hive_slice_cmp(previous_auth, previous_auth_len, s, sl) >= 0) + return E_MALFORMED; + op->auth_acct[op->n_auths] = s; + op->auth_acct_len[op->n_auths++] = sl; + previous_auth = s; + previous_auth_len = sl; + if (!op->acct) { + op->acct = s; + op->acct_len = sl; + } + } + if (n_active + n_posting == 0) return E_MALFORMED; + // Both tiers on one op can never be satisfied by a single signature + // (post-HF28 hived requires the exact authority) — malformed input. + if (n_active > 0 && n_posting > 0) return E_MIXED_TIER; + if (!cur_string(&c, &op->target, &op->target_len, 1, 32) || + !cur_string(&c, &op->detail, &op->detail_len, 1, + HIVE_MAX_OPS_TX_LEN)) + return E_MALFORMED; + op->needs_active = (n_active > 0); + if (op->needs_active) + any_active = true; + else + any_posting = true; + break; + } + case HIVE_OP_TRANSFER_TO_VESTING: { // active authority + // `to` may be empty — hived reads that as "power up to self". + if (!cur_account(&c, &op->acct, &op->acct_len, false) || + !cur_account(&c, &op->target, &op->target_len, true) || + !cur_asset(&c, &op->assets[0], HIVE_SYM_HIVE)) + return E_MALFORMED; + if (hive_assetAmount(op->assets[0]) == 0) return E_AMOUNT; + op->n_assets = 1; + any_active = true; + break; + } + case HIVE_OP_WITHDRAW_VESTING: { // active authority + // 0.000000 VESTS is meaningful here: it cancels an in-progress + // power-down, so zero must NOT be rejected. + if (!cur_account(&c, &op->acct, &op->acct_len, false) || + !cur_asset(&c, &op->assets[0], HIVE_SYM_VESTS)) + return E_MALFORMED; + op->n_assets = 1; + any_active = true; + break; + } + case HIVE_OP_LIMIT_ORDER_CREATE: { // active authority + if (!cur_account(&c, &op->acct, &op->acct_len, false) || + !cur_u32(&c, &op->req_id) || + !cur_asset(&c, &op->assets[0], HIVE_SYM_HIVE | HIVE_SYM_HBD) || + !cur_asset(&c, &op->assets[1], HIVE_SYM_HIVE | HIVE_SYM_HBD) || + !cur_bool(&c, &op->flag) || !cur_u32(&c, &op->expiration)) + return E_MALFORMED; + if (hive_assetAmount(op->assets[0]) == 0 || + hive_assetAmount(op->assets[1]) == 0) + return E_AMOUNT; + // The internal market only pairs HIVE against HBD. A same-symbol + // order is rejected on-chain anyway, and on the OLED it would read + // as a harmless self-trade while burning the fill. + if (memcmp(op->assets[0] + 9, op->assets[1] + 9, 7) == 0) + return E_SYMBOLS; + op->n_assets = 2; + any_active = true; + break; + } + case HIVE_OP_LIMIT_ORDER_CANCEL: { // active authority + if (!cur_account(&c, &op->acct, &op->acct_len, false) || + !cur_u32(&c, &op->req_id)) + return E_MALFORMED; + any_active = true; + break; + } + case HIVE_OP_CONVERT: { // active authority + if (!cur_account(&c, &op->acct, &op->acct_len, false) || + !cur_u32(&c, &op->req_id) || + !cur_asset(&c, &op->assets[0], HIVE_SYM_HBD)) + return E_MALFORMED; + if (hive_assetAmount(op->assets[0]) == 0) return E_AMOUNT; + op->n_assets = 1; + any_active = true; + break; + } + case HIVE_OP_COMMENT_OPTIONS: { // posting authority + uint16_t percent_hbd; + if (!cur_account(&c, &op->acct, &op->acct_len, false) || + !cur_string(&c, &op->permlink, &op->permlink_len, 1, 256) || + !cur_asset(&c, &op->assets[0], HIVE_SYM_HBD) || + !cur_u16(&c, &percent_hbd) || !cur_bool(&c, &op->flag) || + !cur_bool(&c, &op->flag2)) + return E_MALFORMED; + if (percent_hbd > 10000) return E_RANGE; + op->weight = (int16_t)percent_hbd; + op->n_assets = 1; + + // SECURITY: this op redirects a post's payout. It binds to exactly + // one post, so it is accepted ONLY immediately after a comment op + // with the same author and permlink. Standing alone it could attach + // beneficiaries to a post the user published earlier and is not + // reviewing on this screen. + if (i == 0 || out->ops[i - 1].op_type != HIVE_OP_COMMENT) + return E_BINDING; + const HiveTxOp* prev = &out->ops[i - 1]; + if (prev->acct_len != op->acct_len || + memcmp(prev->acct, op->acct, op->acct_len) != 0 || + prev->permlink_len != op->permlink_len || + memcmp(prev->permlink, op->permlink, op->permlink_len) != 0) + return E_BINDING; + + uint32_t ext_n; + if (!cur_varint(&c, &ext_n)) return E_MALFORMED; + // hived permits only one comment_payout_beneficiaries extension; + // two would let a host split 16 beneficiaries past a per-extension + // bound check. + if (ext_n > 1) return E_BENEFICIARIES; + if (ext_n == 1) { + uint32_t tag, n_benef; + if (!cur_varint(&c, &tag) || tag != 0) return E_BENEFICIARIES; + if (!cur_varint(&c, &n_benef) || n_benef < 1 || + n_benef > HIVE_MAX_BENEFICIARIES) + return E_BENEFICIARIES; + uint32_t weight_sum = 0; + const uint8_t* prev_acct = NULL; + uint16_t prev_acct_len = 0; + for (uint32_t k = 0; k < n_benef; k++) { + if (!cur_account(&c, &op->benef_acct[k], &op->benef_acct_len[k], + false) || + !cur_u16(&c, &op->benef_weight[k])) + return E_MALFORMED; + if (op->benef_weight[k] > 10000) return E_RANGE; + // hived requires strictly ascending account names, which also + // enforces uniqueness. An unsorted list is rejected on-chain, so + // signing it would only waste a device confirmation. + if (prev_acct) { + if (hive_slice_cmp(prev_acct, prev_acct_len, op->benef_acct[k], + op->benef_acct_len[k]) >= 0) + return E_BENEFICIARIES; + } + prev_acct = op->benef_acct[k]; + prev_acct_len = op->benef_acct_len[k]; + weight_sum += op->benef_weight[k]; + } + if (weight_sum > 10000) return E_BENEFICIARIES; + op->n_benef = (uint8_t)n_benef; + } + any_posting = true; + break; + } + case HIVE_OP_TRANSFER_TO_SAVINGS: { // active authority + if (!cur_account(&c, &op->acct, &op->acct_len, false) || + !cur_account(&c, &op->target, &op->target_len, false) || + !cur_asset(&c, &op->assets[0], HIVE_SYM_HIVE | HIVE_SYM_HBD) || + !cur_string(&c, &op->detail, &op->detail_len, 0, HIVE_MAX_MEMO_LEN)) + return E_MALFORMED; + if (hive_assetAmount(op->assets[0]) == 0) return E_AMOUNT; + op->n_assets = 1; + any_active = true; + break; + } + case HIVE_OP_TRANSFER_FROM_SAVINGS: { // active authority + if (!cur_account(&c, &op->acct, &op->acct_len, false) || + !cur_u32(&c, &op->req_id) || + !cur_account(&c, &op->target, &op->target_len, false) || + !cur_asset(&c, &op->assets[0], HIVE_SYM_HIVE | HIVE_SYM_HBD) || + !cur_string(&c, &op->detail, &op->detail_len, 0, HIVE_MAX_MEMO_LEN)) + return E_MALFORMED; + if (hive_assetAmount(op->assets[0]) == 0) return E_AMOUNT; + op->n_assets = 1; + any_active = true; + break; + } + case HIVE_OP_CLAIM_REWARD_BALANCE: { // posting authority + if (!cur_account(&c, &op->acct, &op->acct_len, false) || + !cur_asset(&c, &op->assets[0], HIVE_SYM_HIVE) || + !cur_asset(&c, &op->assets[1], HIVE_SYM_HBD) || + !cur_asset(&c, &op->assets[2], HIVE_SYM_VESTS)) + return E_MALFORMED; + if (hive_assetAmount(op->assets[0]) == 0 && + hive_assetAmount(op->assets[1]) == 0 && + hive_assetAmount(op->assets[2]) == 0) + return E_NOOP; + op->n_assets = 3; + any_posting = true; + break; + } + case HIVE_OP_DELEGATE_VESTING_SHARES: { // active authority + // 0.000000 VESTS is meaningful: it removes an existing delegation. + if (!cur_account(&c, &op->acct, &op->acct_len, false) || + !cur_account(&c, &op->target, &op->target_len, false) || + !cur_asset(&c, &op->assets[0], HIVE_SYM_VESTS)) + return E_MALFORMED; + op->n_assets = 1; + any_active = true; + break; + } + case HIVE_OP_ACCOUNT_UPDATE2: { // active or posting authority + uint32_t ext_n; + if (!cur_account(&c, &op->acct, &op->acct_len, false)) + return E_MALFORMED; + // SECURITY: account_update2 can rotate owner/active/posting/memo + // keys. Only the profile-metadata form is in the table — this is the + // op-9/10 device-derived-keys invariant applied field-level. Any + // authority field present is a hard reject; do NOT soften this + // without the authority-management design review. + for (int k = 0; k < 4; k++) { + bool present; + if (!cur_bool(&c, &present)) return E_MALFORMED; + if (present) return E_AUTHORITY; + } + if (!cur_string(&c, &op->detail, &op->detail_len, 0, + HIVE_MAX_OPS_TX_LEN) || + !cur_string(&c, &op->json_metadata, &op->json_metadata_len, 0, + HIVE_MAX_OPS_TX_LEN)) + return E_MALFORMED; + if (op->detail_len == 0 && op->json_metadata_len == 0) return E_NOOP; + if (!cur_varint(&c, &ext_n)) return E_MALFORMED; + if (ext_n != 0) return E_EXTENSIONS; + // json_metadata is an active-key field; a posting_json_metadata-only + // update is a posting-tier profile change. + op->needs_active = (op->detail_len > 0); + if (op->needs_active) + any_active = true; + else + any_posting = true; + break; + } + case HIVE_OP_TRANSFER: + case HIVE_OP_ACCOUNT_CREATE: + case HIVE_OP_ACCOUNT_UPDATE: + // PERMANENTLY excluded from this table: transfer keeps the stronger + // dedicated HiveSignTx display path; the account ops keep the + // device-derived-keys-only invariant (a generic raw-bytes path + // would let a host slip third-party authorities into an + // account_update). Never add these here. + return "Hive tx: op requires its dedicated message type"; + default: + return "Hive tx: unsupported operation type"; + } + } + + uint32_t ext_count; + if (!cur_varint(&c, &ext_count)) return E_MALFORMED; + if (ext_count != 0) return E_EXTENSIONS; + if (c.p != c.end) return "Hive tx: trailing bytes"; + + // One signature cannot satisfy posting- and active-tier ops at once. + if (any_posting && any_active) return E_MIXED_TIER; + out->needs_active = any_active; + return NULL; +} + +void hive_signOperations(const HDNode* node, const HiveSignOperations* msg, + HiveSignedOperations* resp) { + if (!msg->has_serialized_tx || msg->serialized_tx.size == 0 || + msg->serialized_tx.size > HIVE_MAX_OPS_TX_LEN) + return; + + // Hash straight from the decoded message — no stack copy of the 2KB tx. + if (!hive_sign_tx_sig(node, msg->has_chain_id, msg->chain_id.bytes, + msg->chain_id.size, msg->serialized_tx.bytes, + msg->serialized_tx.size, resp->signature.bytes)) { + return; + } + + resp->has_signature = true; + resp->signature.size = 65; +} + +// ── Message signing (Keychain signBuffer contract) ──────────────────────── +// Digest is SHA256(message bytes) ONLY: no chain_id prepend (unlike +// transactions) and no Bitcoin/Solana-style message prefix. hive-js +// Signature.signBuffer — which every Hive dApp verifies against — hashes +// the raw bytes exactly once; any added prefix silently breaks all dApp +// verification. + +bool hive_message_is_printable(const uint8_t* message, size_t len) { + for (size_t i = 0; i < len; i++) { + if (message[i] < 0x20 || message[i] > 0x7e) return false; + } + return true; +} + +void hive_signMessage(const HDNode* node, const HiveSignMessage* msg, + HiveSignedMessage* resp) { + if (!msg->has_message || msg->message.size > HIVE_MAX_MESSAGE_LEN) return; + + uint8_t digest[32]; + sha256_Raw(msg->message.bytes, msg->message.size, digest); + + uint8_t sig[65]; + if (!hive_sign_raw_digest(node, digest, sig)) { + memzero(digest, sizeof(digest)); + memzero(sig, sizeof(sig)); + return; + } + + resp->has_signature = true; + resp->signature.size = 65; + memcpy(resp->signature.bytes, sig, 65); + + // Caller must have run hdnode_fill_public_key(node). Returned so the host + // can build Keychain's publicKey response field without a second call. + resp->has_public_key = true; + resp->public_key.size = 33; + memcpy(resp->public_key.bytes, node->public_key, 33); + + memzero(digest, sizeof(digest)); + memzero(sig, sizeof(sig)); +} + +// ── Transfer (op type 2) ────────────────────────────────────────────────── + +static size_t hive_serialize_transfer(const HiveSignTx* msg, uint8_t* buf, + size_t buf_len) { + uint8_t* p = buf; + const uint8_t* end = buf + buf_len; + + append_tx_header(&p, end, (uint16_t)(msg->ref_block_num & 0xFFFF), + msg->ref_block_prefix, msg->expiration, HIVE_OP_TRANSFER); + + append_string(&p, end, msg->has_from ? msg->from : ""); + append_string(&p, end, msg->has_to ? msg->to : ""); + + const char* sym = msg->has_asset_symbol ? msg->asset_symbol : "HIVE"; + uint8_t prec = (uint8_t)(msg->has_decimals ? msg->decimals : HIVE_DECIMALS); + append_asset(&p, end, msg->amount, prec, sym); + + append_string(&p, end, msg->has_memo ? msg->memo : ""); + append_tx_footer(&p, end); + return (size_t)(p - buf); +} + +void hive_signTx(const HDNode* node, const HiveSignTx* msg, + HiveSignedTx* resp) { + // Reject memos that would overflow the fixed-size tx_buf. + if (msg->has_memo && strlen(msg->memo) > HIVE_MAX_MEMO_LEN) return; + + uint8_t tx_buf[512]; + size_t tx_len = hive_serialize_transfer(msg, tx_buf, sizeof(tx_buf)); + + if (!hive_sign_tx_sig(node, msg->has_chain_id, msg->chain_id.bytes, + msg->chain_id.size, tx_buf, tx_len, + resp->signature.bytes)) { + return; + } + + resp->has_signature = true; + resp->signature.size = 65; + + resp->has_serialized_tx = true; + resp->serialized_tx.size = tx_len; + memcpy(resp->serialized_tx.bytes, tx_buf, tx_len); + + memzero(tx_buf, tx_len); +} + +// ── Account create (op type 9) ──────────────────────────────────────────── +// +// All four role keys are device-derived by the caller (FSM handler) and +// passed as raw 33-byte compressed public keys. The firmware never uses +// host-supplied key strings for the actual transaction. + +static size_t hive_serialize_account_create(const HiveSignAccountCreate* msg, + const uint8_t owner_raw[33], + const uint8_t active_raw[33], + const uint8_t posting_raw[33], + const uint8_t memo_raw[33], + uint8_t* buf, size_t buf_len) { + uint8_t* p = buf; + const uint8_t* end = buf + buf_len; + + append_tx_header(&p, end, (uint16_t)(msg->ref_block_num & 0xFFFF), + msg->ref_block_prefix, msg->expiration, + HIVE_OP_ACCOUNT_CREATE); + + // fee (asset) + uint64_t fee = msg->has_fee_amount ? msg->fee_amount : 3000; + append_asset(&p, end, fee, HIVE_DECIMALS, "HIVE"); + + // creator + append_string(&p, end, msg->has_creator ? msg->creator : ""); + + // new_account_name + append_string(&p, end, + msg->has_new_account_name ? msg->new_account_name : ""); + + // authority fields use device-derived raw bytes (no host trust, no type + // prefix) + append_authority(&p, end, owner_raw); + append_authority(&p, end, active_raw); + append_authority(&p, end, posting_raw); + + // memo_key: 33 raw bytes, no authority wrapper, no type prefix byte + for (int i = 0; i < 33 && p < end; i++) append_u8(&p, end, memo_raw[i]); + + // json_metadata (empty) + append_string(&p, end, ""); + append_tx_footer(&p, end); + + return (size_t)(p - buf); +} + +void hive_signAccountCreate(const HDNode* signing_node, + const HiveSignAccountCreate* msg, + const uint8_t owner_raw[33], + const uint8_t active_raw[33], + const uint8_t posting_raw[33], + const uint8_t memo_raw[33], + HiveSignedAccountCreate* resp) { + uint8_t tx_buf[512]; + size_t tx_len = + hive_serialize_account_create(msg, owner_raw, active_raw, posting_raw, + memo_raw, tx_buf, sizeof(tx_buf)); + + if (!hive_sign_tx_sig(signing_node, msg->has_chain_id, msg->chain_id.bytes, + msg->chain_id.size, tx_buf, tx_len, + resp->signature.bytes)) { + memzero(tx_buf, sizeof(tx_buf)); + return; + } + + resp->has_signature = true; + resp->signature.size = 65; + + resp->has_serialized_tx = true; + resp->serialized_tx.size = tx_len; + memcpy(resp->serialized_tx.bytes, tx_buf, tx_len); + + memzero(tx_buf, tx_len); +} + +// ── Account update (op type 10) ─────────────────────────────────────────── +// +// All four new role keys are device-derived by the caller (FSM handler). +// The host-supplied new_*_key fields in the message are not used for signing. + +static size_t hive_serialize_account_update(const HiveSignAccountUpdate* msg, + const uint8_t owner_raw[33], + const uint8_t active_raw[33], + const uint8_t posting_raw[33], + const uint8_t memo_raw[33], + uint8_t* buf, size_t buf_len) { + uint8_t* p = buf; + const uint8_t* end = buf + buf_len; + + append_tx_header(&p, end, (uint16_t)(msg->ref_block_num & 0xFFFF), + msg->ref_block_prefix, msg->expiration, + HIVE_OP_ACCOUNT_UPDATE); + + // account name + append_string(&p, end, msg->has_account ? msg->account : ""); + + /* + * account_update optional authority fields use a Graphene "optional" wrapper: + * present: 0x01 + authority bytes + * absent: 0x00 + * We always include all four — this replaces all authorities. + */ + append_u8(&p, end, 0x01); // owner present + append_authority(&p, end, owner_raw); + append_u8(&p, end, 0x01); // active present + append_authority(&p, end, active_raw); + append_u8(&p, end, 0x01); // posting present + append_authority(&p, end, posting_raw); + + // memo_key: 33 raw bytes, always present, no type prefix byte + for (int i = 0; i < 33 && p < end; i++) append_u8(&p, end, memo_raw[i]); + + // json_metadata (empty) + append_string(&p, end, ""); + append_tx_footer(&p, end); + + return (size_t)(p - buf); +} + +void hive_signAccountUpdate(const HDNode* signing_node, + const HiveSignAccountUpdate* msg, + const uint8_t owner_raw[33], + const uint8_t active_raw[33], + const uint8_t posting_raw[33], + const uint8_t memo_raw[33], + HiveSignedAccountUpdate* resp) { + uint8_t tx_buf[512]; + size_t tx_len = + hive_serialize_account_update(msg, owner_raw, active_raw, posting_raw, + memo_raw, tx_buf, sizeof(tx_buf)); + + if (!hive_sign_tx_sig(signing_node, msg->has_chain_id, msg->chain_id.bytes, + msg->chain_id.size, tx_buf, tx_len, + resp->signature.bytes)) { + memzero(tx_buf, sizeof(tx_buf)); + return; + } + + resp->has_signature = true; + resp->signature.size = 65; + + resp->has_serialized_tx = true; + resp->serialized_tx.size = tx_len; + memcpy(resp->serialized_tx.bytes, tx_buf, tx_len); + + memzero(tx_buf, tx_len); +} diff --git a/lib/firmware/mayachain.c b/lib/firmware/mayachain.c index a4613ad11..bfa2ce0fa 100644 --- a/lib/firmware/mayachain.c +++ b/lib/firmware/mayachain.c @@ -29,8 +29,17 @@ #include "trezor/crypto/segwit_addr.h" #include +#include #include +bool mayachain_isValidDenom(const char* denom) { + return tendermint_isValidDenom(denom); +} + +bool mayachain_isValidAsset(const char* asset) { + return tendermint_isValidAsset(asset); +} + static CONFIDENTIAL HDNode node; static SHA256_CTX ctx; static bool initialized; @@ -38,6 +47,10 @@ static uint32_t msgs_remaining; static MayachainSignTx msg; static bool testnet; +bool mayachain_isValidSigner(const char* signer) { + return tendermint_isValidSigner(signer, testnet ? "smaya" : "maya"); +} + const MayachainSignTx* mayachain_getMayachainSignTx(void) { return &msg; } bool mayachain_signTxInit(const HDNode* _node, const MayachainSignTx* _msg) { @@ -119,16 +132,27 @@ bool mayachain_signTxUpdateMsgSend(const uint64_t amount, return false; } + // Default to "cacao" for backward compatibility; validate all non-default + // denoms. Defended here too (not just by the FSM caller) so this signing + // path is safe even if called directly or reused elsewhere later. + const char* coin_denom = (denom && denom[0]) ? denom : "cacao"; + if (!mayachain_isValidDenom(coin_denom)) { + return false; + } + bool success = true; const char* const prelude = "{\"type\":\"mayachain/MsgSend\",\"value\":{"; sha256_Update(&ctx, (uint8_t*)prelude, strlen(prelude)); - // 21 + ^20 + 11 + ^69 + 3 = ^124 - success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), - "\"amount\":[{\"amount\":\"%" PRIu64 - "\",\"denom\":\"%s\"}]", - amount, denom); + // Write amount prefix: 21 + ^20 = ^41 + success &= tendermint_snprintf( + &ctx, buffer, sizeof(buffer), + "\"amount\":[{\"amount\":\"%" PRIu64 "\",\"denom\":\"", amount); + // Use escaping as defense-in-depth; valid denoms have no escapable chars + tendermint_sha256UpdateEscaped(&ctx, coin_denom, strlen(coin_denom)); + // Close coins array: 3 bytes + sha256_Update(&ctx, (uint8_t*)"\"}]", 3); // 17 + 45 + 1 = 63 success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), @@ -145,6 +169,13 @@ bool mayachain_signTxUpdateMsgSend(const uint64_t amount, bool mayachain_signTxUpdateMsgDeposit(const MayachainMsgDeposit* depmsg) { char buffer[64 + 1]; + // Defended here too (not just by the FSM caller) so this signing path is + // safe even if called directly or reused elsewhere later. + if (!mayachain_isValidAsset(depmsg->asset) || + !mayachain_isValidSigner(depmsg->signer)) { + return false; + } + bool success = true; const char* const prelude = "{\"type\":\"mayachain/MsgDeposit\",\"value\":{"; @@ -155,9 +186,11 @@ bool mayachain_signTxUpdateMsgDeposit(const MayachainMsgDeposit* depmsg) { "\"coins\":[{\"amount\":\"%" PRIu64 "\"", depmsg->amount); - // 10 + ^20 + 3 = ^33 - success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), - ",\"asset\":\"%s\"}]", depmsg->asset); + // Use escaping as defense-in-depth; valid assets have no escapable chars + const char* const asset_prefix = ",\"asset\":\""; + sha256_Update(&ctx, (uint8_t*)asset_prefix, strlen(asset_prefix)); + tendermint_sha256UpdateEscaped(&ctx, depmsg->asset, strlen(depmsg->asset)); + sha256_Update(&ctx, (uint8_t*)"\"}]", 3); // const char* const memo_prefix = ",\"memo\":\""; @@ -205,98 +238,120 @@ bool mayachain_parseConfirmMemo(const char* swapStr, size_t size) { Input: swapStr is candidate mayachain data size is the size of swapStr (<= 256) Memos should be of the form: - transaction:chain.ticker-id:destination:limit + transaction:chain.ticker-id:destination:limit:affiliate:fee_bps ^^^^^^^^^^^^^^----------asset - So, swap USDT to dest address 0x41e55..., limit 420 - SWAP:ETH.USDT-0xdac17f958d2ee523a2206206994597c13d831ec7:0x41e5560054824ea6b0732e656e3ad64e20e94e45:420 + So, swap USDT to dest address 0x41e55..., limit 420, affiliate "kk" + skimming 75 basis points: + SWAP:ETH.USDT-0xdac17f958d2ee523a2206206994597c13d831ec7:0x41e5560054824ea6b0732e656e3ad64e20e94e45:420:kk:75 Swap transactions can be indicated by "SWAP" or "s" or "=" + + Fields are split on ':' PRESERVING empty fields so a blank field (e.g. + an empty limit in "=:ETH.ETH:0xdest::kk:75") can never shift a later + field (e.g. the affiliate) into an earlier display slot. */ - char* parseTokPtrs[7] = {NULL, NULL, NULL, NULL, - NULL, NULL, NULL}; // we can parse up to 7 tokens - char* tok; - char memoBuf[256]; - uint16_t ctr; + char* fields[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; + /* Memos are documented/accepted up to 256 bytes; memoBuf reserves one + * extra byte so a full 256-byte memo still leaves a guaranteed NUL + * terminator, instead of the copy silently dropping its last byte. */ + enum { MEMO_MAX = 256 }; + char memoBuf[MEMO_MAX + 1]; + size_t nfields, i; + char *chain, *asset; // check if memo data is recognized - if (size > sizeof(memoBuf)) return false; + if (size > MEMO_MAX) return false; memzero(memoBuf, sizeof(memoBuf)); - strlcpy(memoBuf, swapStr, size); - memoBuf[255] = '\0'; // ensure null termination - tok = strtok(memoBuf, ":"); - - // get transaction and asset - for (ctr = 0; ctr < 3; ctr++) { - if (tok != NULL) { - parseTokPtrs[ctr] = tok; - tok = strtok(NULL, ":."); - } else { - break; + /* size is a byte count, not necessarily including a NUL: the BTC + * OP_RETURN caller passes raw memo bytes with no terminator. strlcpy + * would copy only size-1 bytes and silently drop the memo's last + * character (turning an affiliate fee of "75" bps into "7"). Copy the + * bytes exactly (size <= MEMO_MAX < sizeof(memoBuf), so this never + * overflows and always leaves at least one zeroed terminator byte); + * the zeroed buffer provides termination. */ + memcpy(memoBuf, swapStr, size); + + // Split on ':', keeping empty fields + nfields = 0; + fields[nfields++] = memoBuf; + for (i = 0; memoBuf[i] != '\0' && nfields < 8; i++) { + if (memoBuf[i] == ':') { + memoBuf[i] = '\0'; + fields[nfields++] = &memoBuf[i + 1]; } } - if (ctr != 3) { - // Must have three tokens at this point: transaction, chain, asset. If - // not, just confirm data + if (nfields < 2) { + // Must have at least transaction and chain.asset. If not, just confirm + // data + return false; + } + + // Split chain.asset at the first '.' + chain = fields[1]; + asset = strchr(chain, '.'); + if (asset == NULL) { + // No chain.asset pair; not recognizable mayachain data, just confirm data return false; } + *asset = '\0'; + asset++; // Check for swap - if (strncmp(parseTokPtrs[0], "SWAP", 4) == 0 || *parseTokPtrs[0] == 's' || - *parseTokPtrs[0] == '=') { + if (strncmp(fields[0], "SWAP", 4) == 0 || *fields[0] == 's' || + *fields[0] == '=') { // This is a swap, set up destination and limit - // This is the dest, may be blank which means swap to self - parseTokPtrs[3] = "self"; - parseTokPtrs[4] = "none"; - if (tok != NULL) { - if ((uint32_t)(tok - (parseTokPtrs[2] + strlen(parseTokPtrs[2]))) == 1) { - // has dest address - parseTokPtrs[3] = tok; - tok = strtok(NULL, ":"); - } - if (tok != NULL) { - // has limit - parseTokPtrs[4] = tok; - } - } + // The dest may be blank which means swap to self + const char* dest = + (nfields > 2 && fields[2][0] != '\0') ? fields[2] : "self"; + const char* limit = + (nfields > 3 && fields[3][0] != '\0') ? fields[3] : "none"; + const char* affiliate = + (nfields > 4 && fields[4][0] != '\0') ? fields[4] : NULL; + const char* fee_bps = + (nfields > 5 && fields[5][0] != '\0') ? fields[5] : "unspecified"; if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, - "Mayachain swap", "Confirm swap asset %s\n on chain %s", - parseTokPtrs[2], parseTokPtrs[1])) { + "Mayachain swap", "Confirm swap asset %s\n on chain %s", asset, + chain)) { return false; } if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, - "Mayachain swap", "Confirm to %s", parseTokPtrs[3])) { + "Mayachain swap", "Confirm to %s", dest)) { return false; } if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, - "Mayachain swap", "Confirm limit %s", parseTokPtrs[4])) { + "Mayachain swap", "Confirm limit %s", limit)) { return false; } + // Never hide the affiliate fee skim from the user + if (affiliate != NULL) { + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Mayachain swap", "Affiliate fee %s bps to %s", fee_bps, + affiliate)) { + return false; + } + } return true; } // Check for add liquidity - else if (strncmp(parseTokPtrs[0], "ADD", 3) == 0 || *parseTokPtrs[0] == 'a' || - *parseTokPtrs[0] == '+') { - if (tok != NULL) { - // add liquidity pool address - parseTokPtrs[3] = tok; - } + else if (strncmp(fields[0], "ADD", 3) == 0 || *fields[0] == 'a' || + *fields[0] == '+') { + // add liquidity pool address (optional) + const char* pool = (nfields > 2 && fields[2][0] != '\0') ? fields[2] : NULL; if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "Mayachain add liquidity", - "Confirm add asset %s\n on chain %s pool", parseTokPtrs[2], - parseTokPtrs[1])) { + "Confirm add asset %s\n on chain %s pool", asset, chain)) { return false; } - if (tok != NULL) { + if (pool != NULL) { if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, - "Mayachain add liquidity", "Confirm to %s", - parseTokPtrs[3])) { + "Mayachain add liquidity", "Confirm to %s", pool)) { return false; } } @@ -304,22 +359,33 @@ bool mayachain_parseConfirmMemo(const char* swapStr, size_t size) { } // Check for withdraw liquidity - else if (strncmp(parseTokPtrs[0], "WITHDRAW", 8) == 0 || - strncmp(parseTokPtrs[0], "wd", 2) == 0 || *parseTokPtrs[0] == '-') { - if (tok != NULL) { - // add liquidity pool address - parseTokPtrs[3] = tok; - } else { + else if (strncmp(fields[0], "WITHDRAW", 8) == 0 || + strncmp(fields[0], "wd", 2) == 0 || *fields[0] == '-') { + if (nfields < 3 || fields[2][0] == '\0') { return false; // malformed memo } + /* WD:POOL:BPS[:ASSET] — refuse only genuinely-unknown structure (>4 + * fields), mirroring thorchain.c. */ + if (nfields > 4) { + return false; + } - float percent = (float)(atoi(parseTokPtrs[3])) / 100; + float percent = (float)(atoi(fields[2])) / 100; if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "Mayachain withdraw liquidity", "Confirm withdraw %3.2f%% of asset %s on chain %s", percent, - parseTokPtrs[2], parseTokPtrs[1])) { + asset, chain)) { return false; } + /* Field 4 selects an ASYMMETRIC (single-sided) withdrawal payout asset — + * it directs money and must never sign unseen (see thorchain.c). */ + if (nfields > 3 && fields[3][0] != '\0') { + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Mayachain withdraw liquidity", + "Withdraw single-sided as %s", fields[3])) { + return false; + } + } return true; } else { diff --git a/lib/firmware/messagemap.def b/lib/firmware/messagemap.def index ee82cc2bd..30f8fb1bf 100644 --- a/lib/firmware/messagemap.def +++ b/lib/firmware/messagemap.def @@ -33,6 +33,7 @@ MSG_IN(MessageType_MessageType_RecoveryDevice, RecoveryDevice, fsm_msgRecoveryDevice) MSG_IN(MessageType_MessageType_CharacterAck, CharacterAck, fsm_msgCharacterAck) MSG_IN(MessageType_MessageType_ApplyPolicies, ApplyPolicies, fsm_msgApplyPolicies) +#if !BITCOIN_ONLY MSG_IN(MessageType_MessageType_EthereumGetAddress, EthereumGetAddress, fsm_msgEthereumGetAddress) MSG_IN(MessageType_MessageType_EthereumSignTx, EthereumSignTx, fsm_msgEthereumSignTx) MSG_IN(MessageType_MessageType_EthereumTxAck, EthereumTxAck, fsm_msgEthereumTxAck) @@ -72,6 +73,9 @@ MSG_IN(MessageType_MessageType_MayachainGetAddress, MayachainGetAddress, fsm_msgMayachainGetAddress) MSG_IN(MessageType_MessageType_MayachainSignTx, MayachainSignTx, fsm_msgMayachainSignTx) MSG_IN(MessageType_MessageType_MayachainMsgAck, MayachainMsgAck, fsm_msgMayachainMsgAck) +#endif // !BITCOIN_ONLY + + MSG_IN(MessageType_MessageType_GetBip85Mnemonic, GetBip85Mnemonic, fsm_msgGetBip85Mnemonic) /* Normal Out Messages */ MSG_OUT(MessageType_MessageType_Success, Success, NO_PROCESS_FUNC) @@ -95,6 +99,7 @@ MSG_OUT(MessageType_MessageType_PassphraseRequest, PassphraseRequest, NO_PROCESS_FUNC) MSG_OUT(MessageType_MessageType_WordRequest, WordRequest, NO_PROCESS_FUNC) MSG_OUT(MessageType_MessageType_CharacterRequest, CharacterRequest, NO_PROCESS_FUNC) +#if !BITCOIN_ONLY MSG_OUT(MessageType_MessageType_EthereumAddress, EthereumAddress, NO_PROCESS_FUNC) MSG_OUT(MessageType_MessageType_EthereumTxRequest, EthereumTxRequest, NO_PROCESS_FUNC) MSG_OUT(MessageType_MessageType_EthereumMessageSignature, EthereumMessageSignature, NO_PROCESS_FUNC) @@ -163,6 +168,43 @@ MSG_OUT(MessageType_MessageType_SolanaSignedTx, SolanaSignedTx, NO_PROCESS_FUNC) MSG_OUT(MessageType_MessageType_SolanaMessageSignature, SolanaMessageSignature, NO_PROCESS_FUNC) MSG_OUT(MessageType_MessageType_SolanaOffchainMessageSignature, SolanaOffchainMessageSignature, NO_PROCESS_FUNC) +#endif // !BITCOIN_ONLY + + /* Zcash shielded/Orchard (privacy engine). Transparent t-address Zcash uses + the generic SignTx/GetAddress rows above and needs none of these. */ +#if ZCASH_PRIVACY + MSG_IN(MessageType_MessageType_ZcashSignPCZT, ZcashSignPCZT, fsm_msgZcashSignPCZT) + MSG_IN(MessageType_MessageType_ZcashPCZTAction, ZcashPCZTAction, fsm_msgZcashPCZTAction) + MSG_IN(MessageType_MessageType_ZcashGetOrchardFVK, ZcashGetOrchardFVK, fsm_msgZcashGetOrchardFVK) + MSG_IN(MessageType_MessageType_ZcashTransparentOutput, ZcashTransparentOutput, fsm_msgZcashTransparentOutput) + MSG_IN(MessageType_MessageType_ZcashTransparentInput, ZcashTransparentInput, fsm_msgZcashTransparentInput) + MSG_IN(MessageType_MessageType_ZcashDisplayAddress, ZcashDisplayAddress, fsm_msgZcashDisplayAddress) + + MSG_OUT(MessageType_MessageType_ZcashPCZTActionAck, ZcashPCZTActionAck, NO_PROCESS_FUNC) + MSG_OUT(MessageType_MessageType_ZcashSignedPCZT, ZcashSignedPCZT, NO_PROCESS_FUNC) + MSG_OUT(MessageType_MessageType_ZcashOrchardFVK, ZcashOrchardFVK, NO_PROCESS_FUNC) + MSG_OUT(MessageType_MessageType_ZcashTransparentSigned, ZcashTransparentSigned, NO_PROCESS_FUNC) + MSG_OUT(MessageType_MessageType_ZcashTransparentAck, ZcashTransparentAck, NO_PROCESS_FUNC) + MSG_OUT(MessageType_MessageType_ZcashAddress, ZcashAddress, NO_PROCESS_FUNC) +#endif +#if !BITCOIN_ONLY + /* Hive */ + MSG_IN(MessageType_MessageType_HiveGetPublicKey, HiveGetPublicKey, fsm_msgHiveGetPublicKey) + MSG_IN(MessageType_MessageType_HiveGetPublicKeys, HiveGetPublicKeys, fsm_msgHiveGetPublicKeys) + MSG_IN(MessageType_MessageType_HiveSignTx, HiveSignTx, fsm_msgHiveSignTx) + MSG_IN(MessageType_MessageType_HiveSignAccountCreate, HiveSignAccountCreate, fsm_msgHiveSignAccountCreate) + MSG_IN(MessageType_MessageType_HiveSignAccountUpdate, HiveSignAccountUpdate, fsm_msgHiveSignAccountUpdate) + MSG_IN(MessageType_MessageType_HiveSignMessage, HiveSignMessage, fsm_msgHiveSignMessage) + MSG_IN(MessageType_MessageType_HiveSignOperations, HiveSignOperations, fsm_msgHiveSignOperations) + + MSG_OUT(MessageType_MessageType_HivePublicKey, HivePublicKey, NO_PROCESS_FUNC) + MSG_OUT(MessageType_MessageType_HivePublicKeys, HivePublicKeys, NO_PROCESS_FUNC) + MSG_OUT(MessageType_MessageType_HiveSignedTx, HiveSignedTx, NO_PROCESS_FUNC) + MSG_OUT(MessageType_MessageType_HiveSignedAccountCreate, HiveSignedAccountCreate, NO_PROCESS_FUNC) + MSG_OUT(MessageType_MessageType_HiveSignedAccountUpdate, HiveSignedAccountUpdate, NO_PROCESS_FUNC) + MSG_OUT(MessageType_MessageType_HiveSignedMessage, HiveSignedMessage, NO_PROCESS_FUNC) + MSG_OUT(MessageType_MessageType_HiveSignedOperations, HiveSignedOperations, NO_PROCESS_FUNC) +#endif // !BITCOIN_ONLY #if DEBUG_LINK /* Debug Messages */ @@ -178,3 +220,9 @@ DEBUG_OUT(MessageType_MessageType_DebugLinkLog, DebugLinkLog, NO_PROCESS_FUNC) DEBUG_OUT(MessageType_MessageType_DebugLinkFlashDumpResponse, DebugLinkFlashDumpResponse, NO_PROCESS_FUNC) #endif + +#if !BITCOIN_ONLY + MSG_IN(MessageType_MessageType_EthereumTxMetadata, EthereumTxMetadata, fsm_msgEthereumTxMetadata) + MSG_OUT(MessageType_MessageType_EthereumMetadataAck, EthereumMetadataAck, NO_PROCESS_FUNC) + MSG_IN(MessageType_MessageType_LoadClearsignSigner, LoadClearsignSigner, fsm_msgLoadClearsignSigner) +#endif // !BITCOIN_ONLY diff --git a/lib/firmware/osmosis.c b/lib/firmware/osmosis.c index 6d0657257..0348c6d15 100644 --- a/lib/firmware/osmosis.c +++ b/lib/firmware/osmosis.c @@ -96,7 +96,52 @@ bool osmosis_signTxInit(const HDNode* _node, const OsmosisSignTx* _msg) { return success; } -bool osmosis_signTxUpdateMsgSend(const char* amount, const char* to_address) { +static bool osmosis_isCanonicalAmount(const char* value) { + if (!value) return false; + const size_t len = strlen(value); + if (len == 0 || len > OSMOSIS_MAX_AMOUNT_DIGITS || + (len > 1 && value[0] == '0')) { + return false; + } + for (size_t i = 0; i < len; i++) { + if (value[i] < '0' || value[i] > '9') return false; + } + return true; +} + +static bool osmosis_isCanonicalUint64(const char* value) { + if (!osmosis_isCanonicalAmount(value)) return false; + + uint64_t parsed = 0; + for (size_t i = 0; value[i]; i++) { + const uint8_t digit = (uint8_t)(value[i] - '0'); + if (parsed > (UINT64_MAX - digit) / 10) return false; + parsed = parsed * 10 + digit; + } + return true; +} + +static bool osmosis_isValidDenom(const char* denom) { + if (!denom) return false; + const size_t len = strlen(denom); + if (len == 0 || len > OSMOSIS_MAX_DENOM_LEN) return false; + + // Cosmos/Osmosis denominations are printable identifiers, not arbitrary + // JSON. This includes native, IBC and factory-style paths while excluding + // whitespace, quotes, backslashes and control bytes. + for (size_t i = 0; i < len; i++) { + const char c = denom[i]; + if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || c == '/' || c == ':' || c == '.' || + c == '_' || c == '-')) { + return false; + } + } + return true; +} + +bool osmosis_signTxUpdateMsgSend(const char* amount, const char* to_address, + const char* denom) { const char mainnetp[] = "osmo"; const char testnetp[] = "tosmo"; const char* pfix; @@ -105,7 +150,8 @@ bool osmosis_signTxUpdateMsgSend(const char* amount, const char* to_address) { size_t decoded_len; char hrp[45] = {0}; uint8_t decoded[38] = {0}; - if (!bech32_decode(hrp, decoded, &decoded_len, to_address)) { + if (!osmosis_isCanonicalUint64(amount) || !osmosis_isValidDenom(denom) || + !bech32_decode(hrp, decoded, &decoded_len, to_address)) { return false; } @@ -125,10 +171,16 @@ bool osmosis_signTxUpdateMsgSend(const char* amount, const char* to_address) { const char* const prelude = "{\"type\":\"cosmos-sdk/MsgSend\",\"value\":{"; sha256_Update(&ctx, (uint8_t*)prelude, strlen(prelude)); - // 21 + ^20 + 19 = ^60 - success &= tendermint_snprintf( - &ctx, buffer, sizeof(buffer), - "\"amount\":[{\"amount\":\"%s\",\"denom\":\"uosmo\"}]", amount); + // IBC and factory denoms may exceed the fixed 64-byte scratch buffer. + // These values are canonical and JSON-safe, so hash the field in segments. + static const char amount_prefix[] = "\"amount\":[{\"amount\":\""; + static const char denom_prefix[] = "\",\"denom\":\""; + static const char coin_suffix[] = "\"}]"; + sha256_Update(&ctx, (const uint8_t*)amount_prefix, sizeof(amount_prefix) - 1); + sha256_Update(&ctx, (const uint8_t*)amount, strlen(amount)); + sha256_Update(&ctx, (const uint8_t*)denom_prefix, sizeof(denom_prefix) - 1); + sha256_Update(&ctx, (const uint8_t*)denom, strlen(denom)); + sha256_Update(&ctx, (const uint8_t*)coin_suffix, sizeof(coin_suffix) - 1); // 17 + 45 + 1 = 63 success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), @@ -618,6 +670,42 @@ bool osmosis_signTxFinalize(uint8_t* public_key, uint8_t* signature) { NULL) == 0; } +/* + * Cosmos amounts arrive as integer base-unit strings. These screens used to + * render them with atof() + "%.6f", which rounds anything past ~7 significant + * digits — on the very screen the user approves — and linked newlib's floating + * point engine into a ROM budget with no room for it. bn_format_uint64 places + * the decimal point in integer math, the same way the Hive and Ethereum + * confirm screens do. + */ +bool osmosis_formatAmount(char* out, size_t out_len, const char* value, + const char* denom) { + if (!out || out_len == 0) return false; + out[0] = '\0'; + if (!osmosis_isCanonicalAmount(value) || !osmosis_isValidDenom(denom) || + (strcmp(denom, "uosmo") == 0 && !osmosis_isCanonicalUint64(value))) { + return false; + } + + int written; + if (strcmp(denom, "uosmo") == 0) { + char scaled[OSMOSIS_MAX_AMOUNT_DIGITS + 2]; + if (base_to_precision((uint8_t*)scaled, (const uint8_t*)value, + sizeof(scaled), strlen(value), + OSMOSIS_PRECISION) < 0) { + return false; + } + written = snprintf(out, out_len, "%s OSMO", scaled); + } else { + written = snprintf(out, out_len, "%s %s", value, denom); + } + if (written < 0 || (size_t)written >= out_len) { + out[0] = '\0'; + return false; + } + return true; +} + bool osmosis_signingIsInited(void) { return initialized; } bool osmosis_signingIsFinished(void) { return msgs_remaining == 0; } diff --git a/lib/firmware/recovery_cipher.c b/lib/firmware/recovery_cipher.c index 0db3d1616..acfade212 100644 --- a/lib/firmware/recovery_cipher.c +++ b/lib/firmware/recovery_cipher.c @@ -53,6 +53,13 @@ static CONFIDENTIAL char mnemonic[MNEMONIC_BUF]; static char english_alphabet[ENGLISH_ALPHABET_BUF] = "abcdefghijklmnopqrstuvwxyz"; static CONFIDENTIAL char cipher[ENGLISH_ALPHABET_BUF]; +/* Accumulators for the word currently being entered. File-scope so + * recovery_delete_character() can keep them in sync with backspaces — + * otherwise stale bytes make a re-entered word fail validation and wipe a + * real recovery. last_completed_word backs the "previous word" indicator. */ +static CONFIDENTIAL char coded_word[12]; +static CONFIDENTIAL char decoded_word[12]; +static CONFIDENTIAL char last_completed_word[12]; #if DEBUG_LINK static char auto_completed_word[CURRENT_WORD_BUF]; @@ -74,6 +81,9 @@ void recovery_cipher_abort(void) { word_count = 0; memzero(mnemonic, sizeof(mnemonic)); memzero(cipher, sizeof(cipher)); + memzero(coded_word, sizeof(coded_word)); + memzero(decoded_word, sizeof(decoded_word)); + memzero(last_completed_word, sizeof(last_completed_word)); } /// Formats the passed word to show position in mnemonic as well as characters @@ -181,7 +191,11 @@ bool attempt_auto_complete(char* partial_word) { return false; } - static uint16_t CONFIDENTIAL permute[2049]; + /* 4 KB permutation table lives in the shared frame arena: too big for the + * stack, wasteful as its own static. Transient within this call (memzero'd + * on every exit), and this function never encodes a USB response while the + * table is live — see the FrameArena contract in messages.c. */ + uint16_t* permute = frame_arena_scratch2049(); for (int i = 0; i < 2049; i++) { permute[i] = i; } @@ -215,18 +229,18 @@ bool attempt_auto_complete(char* partial_word) { } if (precise_match) { - memzero(permute, sizeof(permute)); + memzero(permute, 2049 * sizeof(*permute)); return true; } /* Autocomplete if we can */ if (match == 1) { strlcpy(partial_word, words[permute[found]], CURRENT_WORD_BUF); - memzero(permute, sizeof(permute)); + memzero(permute, 2049 * sizeof(*permute)); return true; } - memzero(permute, sizeof(permute)); + memzero(permute, 2049 * sizeof(*permute)); return false; } @@ -376,8 +390,16 @@ void next_character(void) { format_current_word(word_pos, current_word, auto_completed, &formatted_word); memzero(current_word, sizeof(current_word)); + /* Format previous word indicator (e.g. "(1.alcohol)" when entering word 2) */ + static char prev_info[32]; + prev_info[0] = '\0'; + if (word_pos > 0 && last_completed_word[0]) { + snprintf(prev_info, sizeof(prev_info), "(%" PRIu32 ".%s)", word_pos, + last_completed_word); + } + /* Show cipher and partial word */ - layout_cipher(formatted_word, cipher); + layout_cipher(formatted_word, cipher, prev_info); memzero(formatted_word, sizeof(formatted_word)); } @@ -420,14 +442,13 @@ void recovery_character(const char* character) { // Count of words we think the user has entered without using the cipher: static int uncyphered_word_count = 0; static bool definitely_using_cipher = false; - static CONFIDENTIAL char coded_word[12]; - static CONFIDENTIAL char decoded_word[12]; if (!mnemonic[0]) { uncyphered_word_count = 0; definitely_using_cipher = false; memzero(coded_word, sizeof(coded_word)); memzero(decoded_word, sizeof(decoded_word)); + memzero(last_completed_word, sizeof(last_completed_word)); } char decoded_character[2] = " "; @@ -462,6 +483,30 @@ void recovery_character(const char* character) { } } } else { + /* Per-word BIP39 validation: reject immediately if the decoded word + * doesn't match any entry in the wordlist. decoded_word is kept in sync + * with backspaces by recovery_delete_character(), so a corrected word is + * validated on its real (post-edit) value. */ + if (strlen(decoded_word) > 0) { + static CONFIDENTIAL char check_word[CURRENT_WORD_BUF]; + strlcpy(check_word, decoded_word, sizeof(check_word)); + bool valid = attempt_auto_complete(check_word); + if (enforce_wordlist && !valid) { + memzero(check_word, sizeof(check_word)); + memzero(coded_word, sizeof(coded_word)); + memzero(decoded_word, sizeof(decoded_word)); + recovery_cipher_abort(); + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Word not found in BIP39 wordlist"); + layout_warning_static("Word not in wordlist"); + return; + } + /* Record the just-completed (auto-expanded) word for the "previous + * word" indicator — only at a real word boundary, never mid-word. */ + strlcpy(last_completed_word, check_word, sizeof(last_completed_word)); + memzero(check_word, sizeof(check_word)); + } + memzero(coded_word, sizeof(coded_word)); memzero(decoded_word, sizeof(decoded_word)); @@ -512,6 +557,22 @@ void recovery_delete_character(void) { mnemonic[len - 1] = '\0'; } + /* Resync the current-word accumulators with the edited mnemonic so a + * corrected word is validated on its real value (stale bytes here would + * fail validation and trigger a storage_reset on a real recovery). + * decoded_word is the typed prefix of the current word; coded_word is its + * reverse-cipher form (session cipher is fixed, so it is reconstructable). */ + char cur[CURRENT_WORD_BUF]; + get_current_word(cur); + strlcpy(decoded_word, cur, sizeof(decoded_word)); + memzero(cur, sizeof(cur)); + size_t wlen = strlen(decoded_word); + for (size_t i = 0; i < wlen && i + 1 < sizeof(coded_word); i++) { + char d = decoded_word[i]; + coded_word[i] = (d >= 'a' && d <= 'z') ? cipher[d - 'a'] : d; + } + coded_word[wlen < sizeof(coded_word) ? wlen : sizeof(coded_word) - 1] = '\0'; + next_character(); } @@ -575,7 +636,11 @@ void recovery_cipher_finalize(void) { } memzero(temp_word, sizeof(temp_word)); - if (!auto_completed && !enforce_wordlist) { + /* Cipher recovery decodes to BIP-39 words, so every word must + * auto-complete regardless of enforce_wordlist. Failing only when + * enforce_wordlist was set left the default (host-omitted) path storing a + * mistyped/garbage phrase as the seed and reporting success. */ + if (!auto_completed) { if (!dry_run) { storage_reset(); } diff --git a/lib/firmware/reset.c b/lib/firmware/reset.c index 362b3b49e..574930f6c 100644 --- a/lib/firmware/reset.c +++ b/lib/firmware/reset.c @@ -43,6 +43,13 @@ static bool awaiting_entropy = false; static char CONFIDENTIAL current_words[MNEMONIC_BY_SCREEN_BUF]; static bool no_backup; +/* Shared paginated-mnemonic display scratch — see reset.h for the contract + * (also used by the BIP-85 flow; each user zeroes at entry and exit). */ +char CONFIDENTIAL mnemonic_scratch_tokened[TOKENED_MNEMONIC_BUF]; +char CONFIDENTIAL mnemonic_scratch_formatted[MAX_PAGES][FORMATTED_MNEMONIC_BUF]; +char CONFIDENTIAL mnemonic_scratch_display[FORMATTED_MNEMONIC_BUF]; +char CONFIDENTIAL mnemonic_scratch_word[MAX_WORD_LEN + ADDITIONAL_WORD_PAD]; + void reset_init(bool display_random, uint32_t _strength, bool passphrase_protection, bool pin_protection, const char* language, const char* label, bool _no_backup, @@ -167,16 +174,23 @@ void reset_entropy(const uint8_t* ext_entropy, uint32_t len) { } /* - * Format mnemonic for user review + * Format mnemonic for user review. Display scratch is the set shared with + * the BIP-85 flow (see reset.h) — zero it at entry: the format loop below + * depends on empty page strings, and a prior user may have aborted. */ uint32_t word_count = 0, page_count = 0; - static char CONFIDENTIAL tokened_mnemonic[TOKENED_MNEMONIC_BUF]; static char CONFIDENTIAL mnemonic_by_screen[MAX_PAGES][MNEMONIC_BY_SCREEN_BUF]; - static char CONFIDENTIAL - formatted_mnemonic[MAX_PAGES][FORMATTED_MNEMONIC_BUF]; - static char CONFIDENTIAL mnemonic_display[FORMATTED_MNEMONIC_BUF]; - static char CONFIDENTIAL formatted_word[MAX_WORD_LEN + ADDITIONAL_WORD_PAD]; + char* tokened_mnemonic = mnemonic_scratch_tokened; + char (*formatted_mnemonic)[FORMATTED_MNEMONIC_BUF] = + mnemonic_scratch_formatted; + char* mnemonic_display = mnemonic_scratch_display; + char* formatted_word = mnemonic_scratch_word; + memzero(mnemonic_scratch_tokened, sizeof(mnemonic_scratch_tokened)); + memzero(mnemonic_scratch_formatted, sizeof(mnemonic_scratch_formatted)); + memzero(mnemonic_scratch_display, sizeof(mnemonic_scratch_display)); + memzero(mnemonic_scratch_word, sizeof(mnemonic_scratch_word)); + memzero(mnemonic_by_screen, sizeof(mnemonic_by_screen)); strlcpy(tokened_mnemonic, temp_mnemonic, TOKENED_MNEMONIC_BUF); @@ -257,11 +271,11 @@ void reset_entropy(const uint8_t* ext_entropy, uint32_t len) { exit: memzero(&ctx, sizeof(ctx)); - memzero(tokened_mnemonic, sizeof(tokened_mnemonic)); + memzero(mnemonic_scratch_tokened, sizeof(mnemonic_scratch_tokened)); memzero(mnemonic_by_screen, sizeof(mnemonic_by_screen)); - memzero(formatted_mnemonic, sizeof(formatted_mnemonic)); - memzero(mnemonic_display, sizeof(mnemonic_display)); - memzero(formatted_word, sizeof(formatted_word)); + memzero(mnemonic_scratch_formatted, sizeof(mnemonic_scratch_formatted)); + memzero(mnemonic_scratch_display, sizeof(mnemonic_scratch_display)); + memzero(mnemonic_scratch_word, sizeof(mnemonic_scratch_word)); layoutHome(); } diff --git a/lib/firmware/ripple.c b/lib/firmware/ripple.c index eba787ee8..a78106769 100644 --- a/lib/firmware/ripple.c +++ b/lib/firmware/ripple.c @@ -223,6 +223,25 @@ bool ripple_serialize(uint8_t** buf, const uint8_t* end, const RippleSignTx* tx, if (tx->payment.has_destination) ripple_serializeAddress(&ok, buf, end, &RFM_destination, tx->payment.destination); + // Memos array (ARRAY type=15 key=9) comes last per XRPL canonical ordering. + // Layout: 0xF9 [Memos start] 0xEA [Memo object start] + // 0x7D [MemoData VL] + // 0xE1 [object end] 0xF1 [array end] + if (tx->has_memo && tx->memo[0] != '\0') { + size_t memo_len = strlen(tx->memo); + append_u8(&ok, buf, end, 0xF9); // STArray[9] = Memos + append_u8(&ok, buf, end, 0xEA); // STObject[10] = Memo + append_u8(&ok, buf, end, 0x7D); // VL[13] = MemoData + ripple_serializeVarint(&ok, buf, end, (int)memo_len); + if (ok && *buf + memo_len <= end) { + memcpy(*buf, tx->memo, memo_len); + *buf += memo_len; + } else { + ok = false; + } + append_u8(&ok, buf, end, 0xE1); // end STObject + append_u8(&ok, buf, end, 0xF1); // end STArray + } return ok; } diff --git a/lib/firmware/signed_metadata.c b/lib/firmware/signed_metadata.c new file mode 100644 index 000000000..cbb95a3f9 --- /dev/null +++ b/lib/firmware/signed_metadata.c @@ -0,0 +1,1068 @@ +#include "keepkey/firmware/signed_metadata.h" + +#include "storage.h" // ClearsignIdentity + persistent-slot accessors +#include "keepkey/board/confirm_sm.h" +#include "keepkey/board/draw.h" // draw_bitmap_mono_rle_valid +#include "keepkey/board/layout.h" // RUNTIME_ICON + layout_set_runtime_icon +#include "keepkey/board/variant.h" // Image / AnimationFrame +#include "keepkey/board/util.h" +#include "keepkey/firmware/ethereum.h" +#include "trezor/crypto/address.h" +#include "trezor/crypto/bignum.h" +#include "trezor/crypto/ecdsa.h" +#include "trezor/crypto/memzero.h" +#include "trezor/crypto/secp256k1.h" +#include "trezor/crypto/sha2.h" + +#include +#include + +#define _(X) (X) + +static bool metadata_available = false; +static bool relied_on_metadata = false; +static bool metadata_signer_loaded = false; +/* v2 only: set true once decode_v2_args() has decoded this metadata's args from + * the tx calldata. The v2 enforce path REQUIRES it — v2 has no committed + * tx_hash, so this is the explicit proof (not an implicit call-order + * assumption) that the displayed values came from the calldata being signed. */ +static bool metadata_schema_decoded = false; +static SignedMetadata stored_metadata; + +/* Phase 1 ships with NO built-in verification keys: every clearsign signer is + * loaded at runtime via LoadClearsignSigner. Phase 2 restores the production + * key. */ + +/* Runtime-loaded signers. RAM only — cleared on reboot by construction. + * A signer loaded with persist=true is ALSO written to flash (V18 storage) and + * reconsulted after reboot via storage_getClearsignIdentity(). The RAM slot is + * the session working copy; the flash slot is the durable trust anchor. */ +static uint8_t loaded_pubkeys[METADATA_MAX_KEYS][33]; +static char loaded_aliases[METADATA_MAX_KEYS][METADATA_ALIAS_MAX_LEN + 1]; +/* Per-slot session icon (1bpp mono RLE). icon_len==0 => text-only identity. */ +_Static_assert(CLEARSIGN_ICON_MAX == METADATA_ICON_MAX, + "storage icon cap must match the clearsign icon cap"); +#if !ZCASH_PRIVACY +/* Session icon cache for ephemeral (RAM-only) signers. The zcash-privacy + * variant compiles this out to fit SRAM (the Orchard engine leaves it the + * tightest variant): ephemeral signers render text-only there, while + * PERSISTENT identity icons still render straight from the storage shadow. + * Hosts detect this from firmware_variant (KeepKeyZcash/EmulatorZcash). */ +static uint8_t loaded_icons[METADATA_MAX_KEYS][CLEARSIGN_ICON_MAX]; +static uint8_t loaded_icon_w[METADATA_MAX_KEYS]; +static uint8_t loaded_icon_h[METADATA_MAX_KEYS]; +static uint16_t loaded_icon_len[METADATA_MAX_KEYS]; +#endif + +/* Find the persistent identity that reloads into `key_id`, or NULL. */ +static const ClearsignIdentity* persistent_identity_for(uint8_t key_id) { + int n = storage_clearsignIdentityCount(); + for (int i = 0; i < n; i++) { + const ClearsignIdentity* id = storage_getClearsignIdentity(i); + if (id && id->key_id == key_id) return id; + } + return NULL; +} + +static bool read_u8(const uint8_t** cursor, const uint8_t* end, uint8_t* out) { + if ((size_t)(end - *cursor) < 1) { + return false; + } + + *out = **cursor; + *cursor += 1; + return true; +} + +static bool read_be_u16(const uint8_t** cursor, const uint8_t* end, + uint16_t* out) { + if ((size_t)(end - *cursor) < 2) { + return false; + } + + *out = ((uint16_t)(*cursor)[0] << 8) | (*cursor)[1]; + *cursor += 2; + return true; +} + +static bool read_be_u32(const uint8_t** cursor, const uint8_t* end, + uint32_t* out) { + if ((size_t)(end - *cursor) < 4) { + return false; + } + + *out = ((uint32_t)(*cursor)[0] << 24) | ((uint32_t)(*cursor)[1] << 16) | + ((uint32_t)(*cursor)[2] << 8) | (*cursor)[3]; + *cursor += 4; + return true; +} + +static bool read_bytes(const uint8_t** cursor, const uint8_t* end, uint8_t* out, + size_t size) { + if ((size_t)(end - *cursor) < size) { + return false; + } + + memcpy(out, *cursor, size); + *cursor += size; + return true; +} + +/* method_name and arg names render through confirm() bodies exactly like + * STRING values and signer aliases do — hold them to the same allowlist + * (printable ASCII, '%' excluded) so no metadata-carried text can embed + * control bytes or format specifiers. Only a trusted signer could author + * such a blob, but the charset rule should not depend on who signs. */ +static bool display_text_ok(const uint8_t* text, size_t len) { + for (size_t i = 0; i < len; i++) { + if (text[i] < 0x20 || text[i] > 0x7e || text[i] == '%') { + return false; + } + } + return true; +} + +static bool read_string(const uint8_t** cursor, const uint8_t* end, char* out, + size_t max_len) { + uint16_t value_len = 0; + if (!read_be_u16(cursor, end, &value_len) || value_len == 0 || + value_len > max_len || (size_t)(end - *cursor) < value_len) { + return false; + } + if (!display_text_ok(*cursor, value_len)) { + return false; + } + + memcpy(out, *cursor, value_len); + out[value_len] = '\0'; + *cursor += value_len; + return true; +} + +static bool read_arg_name(const uint8_t** cursor, const uint8_t* end, char* out, + size_t max_len) { + uint8_t value_len = 0; + if (!read_u8(cursor, end, &value_len) || value_len == 0 || + value_len > max_len || (size_t)(end - *cursor) < value_len) { + return false; + } + if (!display_text_ok(*cursor, value_len)) { + return false; + } + + memcpy(out, *cursor, value_len); + out[value_len] = '\0'; + *cursor += value_len; + return true; +} + +/* Per-format value validation, fail-closed at parse time. STRING and + * TOKEN_AMOUNT carry display semantics, so their byte layout is enforced + * before anything is stored; legacy formats keep their original 32-byte cap + * (METADATA_MAX_ARG_VALUE_LEN grew only to fit TOKEN_AMOUNT). */ +static bool arg_value_ok(uint8_t format, const uint8_t* value, uint16_t len) { + switch (format) { + case ARG_FORMAT_STRING: { + /* Attested printable label ("protocol: Uniswap V2"). Rendered through + * confirm() bodies: printable ASCII only, '%' excluded. */ + if (len == 0 || len > 32) { + return false; + } + for (uint16_t i = 0; i < len; i++) { + if (value[i] < 0x20 || value[i] > 0x7e || value[i] == '%') { + return false; + } + } + return true; + } + case ARG_FORMAT_TOKEN_AMOUNT: { + /* decimals(1) + symbol_len(1) + symbol + amount(1..32 BE) */ + if (len < 4) { + return false; + } + uint8_t decimals = value[0]; + uint8_t symlen = value[1]; + if (decimals > 36 || symlen == 0 || + symlen > METADATA_MAX_TOKEN_SYMBOL_LEN || + (uint16_t)(2 + symlen) >= len || len - 2 - symlen > 32) { + return false; + } + for (uint8_t i = 0; i < symlen; i++) { + char c = (char)value[2 + i]; + bool ok = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9'); + if (!ok) { + return false; + } + } + return true; + } + default: + return len <= 32; + } +} + +/* chain_id(4) + contract(20) + selector(4) — shared by both blob versions. */ +static bool parse_common_head(const uint8_t** cursor, const uint8_t* end, + SignedMetadata* out) { + return read_be_u32(cursor, end, &out->chain_id) && + read_bytes(cursor, end, out->contract_address, + sizeof(out->contract_address)) && + read_bytes(cursor, end, out->selector, sizeof(out->selector)); +} + +/* classification(1) + timestamp(4) + key_id(1) + sig(64) + recovery(1), then + * the cursor must land exactly on `end` — identical for v1 and v2. */ +static bool parse_trailer(const uint8_t** cursor, const uint8_t* end, + SignedMetadata* out) { + uint8_t classification = 0; + if (!read_u8(cursor, end, &classification) || classification > 2 || + !read_be_u32(cursor, end, &out->timestamp) || + !read_u8(cursor, end, &out->key_id) || + !read_bytes(cursor, end, out->signature, sizeof(out->signature)) || + !read_u8(cursor, end, &out->recovery) || *cursor != end) { + return false; + } + out->classification = (MetadataClassification)classification; + return true; +} + +/* v1 args: name + format + explicit (host-decoded) value. */ +static bool parse_v1_args(const uint8_t** cursor, const uint8_t* end, + SignedMetadata* out) { + for (uint8_t i = 0; i < out->num_args; i++) { + uint8_t format = 0; + uint16_t value_len = 0; + MetadataArg* arg = &out->args[i]; + + if (!read_arg_name(cursor, end, arg->name, METADATA_MAX_ARG_NAME_LEN) || + !read_u8(cursor, end, &format) || format > ARG_FORMAT_TOKEN_AMOUNT || + !read_be_u16(cursor, end, &value_len) || + value_len > METADATA_MAX_ARG_VALUE_LEN || + !read_bytes(cursor, end, arg->value, value_len) || + !arg_value_ok(format, arg->value, value_len)) { + return false; + } + arg->format = (ArgFormat)format; + arg->value_len = value_len; + } + return true; +} + +/* v2 args: name + display format only (NO value — decoded from calldata later). + * TOKEN_AMOUNT additionally carries its static decimals + symbol, pre-stored as + * the value prefix [decimals, symlen, symbol...] so decode_v2_args() only has + * to append the 32-byte amount word. v2 supports the fixed single-word ABI + * types ADDRESS / AMOUNT / TOKEN_AMOUNT; anything else is out of scope -> blind + * sign. */ +static bool parse_v2_args(const uint8_t** cursor, const uint8_t* end, + SignedMetadata* out) { + for (uint8_t i = 0; i < out->num_args; i++) { + uint8_t format = 0; + MetadataArg* arg = &out->args[i]; + + if (!read_arg_name(cursor, end, arg->name, METADATA_MAX_ARG_NAME_LEN) || + !read_u8(cursor, end, &format)) { + return false; + } + switch (format) { + case ARG_FORMAT_ADDRESS: + case ARG_FORMAT_AMOUNT: + arg->value_len = 0; /* filled from the tx calldata at decode time */ + break; + case ARG_FORMAT_TOKEN_AMOUNT: { + uint8_t decimals = 0, symlen = 0; + if (!read_u8(cursor, end, &decimals) || + !read_u8(cursor, end, &symlen) || decimals > 36 || symlen == 0 || + symlen > METADATA_MAX_TOKEN_SYMBOL_LEN || + (size_t)(end - *cursor) < symlen) { + return false; + } + arg->value[0] = decimals; + arg->value[1] = symlen; + for (uint8_t j = 0; j < symlen; j++) { + char c = (char)(*cursor)[j]; + bool ok = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9'); + if (!ok) { + return false; + } + arg->value[2 + j] = (uint8_t)c; + } + *cursor += symlen; + arg->value_len = (uint16_t)(2 + symlen); + break; + } + default: + return false; + } + arg->format = (ArgFormat)format; + } + return true; +} + +static bool parse_metadata_binary(const uint8_t* payload, size_t payload_len, + SignedMetadata* out) { + const uint8_t* cursor = payload; + const uint8_t* end = payload + payload_len; + memset(out, 0, sizeof(*out)); + + if (!read_u8(&cursor, end, &out->version)) { + return false; + } + + if (out->version == METADATA_VERSION_LEGACY) { + /* Min: version(1)+chain_id(4)+contract(20)+selector(4)+tx_hash(32)+ + * method_len(2)+method(1)+num_args(1)+trailer(71) = 136 */ + if (payload_len < 136 || !parse_common_head(&cursor, end, out) || + !read_bytes(&cursor, end, out->tx_hash, sizeof(out->tx_hash)) || + !read_string(&cursor, end, out->method_name, METADATA_MAX_METHOD_LEN) || + !read_u8(&cursor, end, &out->num_args) || + out->num_args > METADATA_MAX_ARGS || + !parse_v1_args(&cursor, end, out)) { + return false; + } + } else if (out->version == METADATA_VERSION_SCHEMA) { + /* Min (0 args): version(1)+chain_id(4)+contract(20)+selector(4)+ + * method_len(2)+method(1)+num_args(1)+trailer(71) = 104 (no tx_hash) */ + if (payload_len < 104 || !parse_common_head(&cursor, end, out) || + !read_string(&cursor, end, out->method_name, METADATA_MAX_METHOD_LEN) || + !read_u8(&cursor, end, &out->num_args) || + out->num_args > METADATA_MAX_ARGS || + !parse_v2_args(&cursor, end, out)) { + return false; + } + } else { + return false; + } + + return parse_trailer(&cursor, end, out); +} + +/* + * v2 decode: fill each schema arg's value from the transaction calldata. + * + * All v2 args are fixed single 32-byte ABI head words, laid out sequentially + * from offset 4 (right after the selector). We require the ENTIRE calldata to + * be exactly selector + num_args words, wholly present in the initial chunk — + * so the device decodes, displays, AND signs the same bytes with nothing hidden + * in a later chunk or trailing the words. That structural completeness is what + * binds the displayed decode to the signature; v2 has no tx_hash. + */ +static bool decode_v2_args(SignedMetadata* md, const EthereumSignTx* msg) { + uint32_t expected = 4u + 32u * (uint32_t)md->num_args; + uint32_t initsz = msg->data_initial_chunk.size; + uint32_t total = msg->has_data_length ? msg->data_length : initsz; + if (total != expected || initsz != expected) { + return false; + } + + for (uint8_t i = 0; i < md->num_args; i++) { + const uint8_t* word = msg->data_initial_chunk.bytes + 4 + 32u * i; + MetadataArg* arg = &md->args[i]; + + switch (arg->format) { + case ARG_FORMAT_ADDRESS: + /* ABI address is a left-zero-padded 20-byte value; reject dirty high + * bytes rather than silently truncate (they could hide meaning). */ + for (int j = 0; j < 12; j++) { + if (word[j] != 0) { + return false; + } + } + memcpy(arg->value, word + 12, 20); + arg->value_len = 20; + break; + case ARG_FORMAT_AMOUNT: + memcpy(arg->value, word, 32); + arg->value_len = 32; + break; + case ARG_FORMAT_TOKEN_AMOUNT: { + /* value holds [decimals, symlen, symbol] from parse; append the amount. + * Derive the prefix from symlen (value[1]), NOT the current value_len, + * so a repeated decode of the same arg is idempotent (value_len already + * includes a previously-appended amount; value[1] does not change). */ + uint16_t prefix = (uint16_t)(2 + arg->value[1]); + if ((size_t)prefix + 32 > METADATA_MAX_ARG_VALUE_LEN) { + return false; + } + memcpy(arg->value + prefix, word, 32); + arg->value_len = (uint16_t)(prefix + 32); + break; + } + default: + return false; + } + } + return true; +} + +static void bn_from_metadata_bytes(const uint8_t* value, size_t value_len, + bignum256* out) { + uint8_t padded[32] = {0}; + if (value_len > sizeof(padded)) { + value_len = sizeof(padded); + } + memcpy(padded + (sizeof(padded) - value_len), value, value_len); + bn_read_be(padded, out); + memzero(padded, sizeof(padded)); +} + +bool signed_metadata_available(void) { return metadata_available; } + +bool signed_metadata_schema_decoded(void) { return metadata_schema_decoded; } + +void signed_metadata_clear(void) { + memzero(&stored_metadata, sizeof(stored_metadata)); + metadata_available = false; + relied_on_metadata = false; + metadata_signer_loaded = false; + metadata_schema_decoded = false; +} + +void signed_metadata_clear_signers(void) { + memzero(loaded_pubkeys, sizeof(loaded_pubkeys)); + memzero(loaded_aliases, sizeof(loaded_aliases)); +#if !ZCASH_PRIVACY + memzero(loaded_icons, sizeof(loaded_icons)); + memzero(loaded_icon_w, sizeof(loaded_icon_w)); + memzero(loaded_icon_h, sizeof(loaded_icon_h)); + memzero(loaded_icon_len, sizeof(loaded_icon_len)); +#endif + /* Metadata verified by a now-dropped signer must not outlive it. NB: this + * clears only the RAM session copies; persisted identities live in flash and + * are cleared by WipeDevice, not here. */ + signed_metadata_clear(); +} + +bool signed_metadata_signer_valid(uint8_t key_id, const uint8_t* pubkey, + size_t pubkey_len, const char* alias) { + curve_point point; + size_t alias_len; + + if (key_id >= METADATA_MAX_KEYS || !pubkey || pubkey_len != 33 || !alias) { + return false; + } + + /* Alias is rendered INSIDE quotes on the load screen and the per-tx warning + * ("Trust signer '%s' ..."). Restrict to a strict allowlist — letters, + * digits, space, '-' and '_' — so a host-chosen alias cannot break out of + * its quoted region or inject a semantic trust claim (e.g. a quote to close + * the quotes, or "." / "(" to append "verified by KeepKey."). '%' is also + * excluded so it can never reach the format string as a specifier. */ + alias_len = strlen(alias); + if (alias_len == 0 || alias_len > METADATA_ALIAS_MAX_LEN) { + return false; + } + for (size_t i = 0; i < alias_len; i++) { + char c = alias[i]; + bool ok = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9') || c == ' ' || c == '-' || c == '_'; + if (!ok) { + return false; + } + } + + /* Compressed form only — ecdsa_read_pubkey would read 65 bytes for an + * uncompressed 0x04 prefix, past our 33-byte buffer. Requiring 0x02/0x03 + * also excludes the all-zero "empty slot" sentinel. */ + if (pubkey[0] != 0x02 && pubkey[0] != 0x03) { + return false; + } + return ecdsa_read_pubkey(&secp256k1, pubkey, &point) == 1; +} + +bool signed_metadata_store_signer(uint8_t key_id, const uint8_t* pubkey, + const char* alias, const uint8_t* icon, + uint8_t icon_w, uint8_t icon_h, + uint16_t icon_len, bool persist) { + if (key_id >= METADATA_MAX_KEYS) { + return false; + } + memcpy(loaded_pubkeys[key_id], pubkey, sizeof(loaded_pubkeys[key_id])); + strlcpy(loaded_aliases[key_id], alias, sizeof(loaded_aliases[key_id])); + + /* A load without an icon clears any prior one for the slot (icon_len + * already validated <= max by the caller — belt-and-braces here). */ + bool has_icon = icon && icon_len > 0 && icon_len <= CLEARSIGN_ICON_MAX; + +#if !ZCASH_PRIVACY + /* Session icon into the RAM working slot. The zcash-privacy variant has no + * session icon cache (SRAM); persist below still stores the icon bytes, so + * persistent identities keep their logo across variants. */ + memzero(loaded_icons[key_id], sizeof(loaded_icons[key_id])); + if (has_icon) { + memcpy(loaded_icons[key_id], icon, icon_len); + loaded_icon_w[key_id] = icon_w; + loaded_icon_h[key_id] = icon_h; + loaded_icon_len[key_id] = icon_len; + } else { + loaded_icon_w[key_id] = 0; + loaded_icon_h[key_id] = 0; + loaded_icon_len[key_id] = 0; + } +#endif + + bool persisted = true; + if (persist) { + ClearsignIdentity id; + memzero(&id, sizeof(id)); + id.present = true; + id.key_id = key_id; + memcpy(id.pubkey, pubkey, sizeof(id.pubkey)); + strlcpy(id.alias, alias, sizeof(id.alias)); + if (has_icon) { + id.icon_w = icon_w; + id.icon_h = icon_h; + id.icon_len = icon_len; + memcpy(id.icon, icon, icon_len); + } + persisted = storage_upsertClearsignIdentity(&id); + memzero(&id, sizeof(id)); + } + + /* Replacing a signer invalidates anything the old one verified. */ + signed_metadata_clear(); + return persisted; +} + +/* Resolve the alias for a slot (RAM working copy, else a persisted identity). + * Returns NULL if the slot has no loaded/persisted signer. */ +const char* signed_metadata_signer_alias(uint8_t key_id) { + if (key_id >= METADATA_MAX_KEYS) return NULL; + if (loaded_pubkeys[key_id][0] != 0x00) return loaded_aliases[key_id]; + const ClearsignIdentity* pid = persistent_identity_for(key_id); + return pid ? pid->alias : NULL; +} + +/* Resolve the icon for a slot (RAM working copy, else a persisted identity). + * Returns false when the slot has no icon (text-only identity). */ +/* An icon is renderable only if its geometry fits the confirm's icon column + * AND its RLE stream decodes exactly to that geometry. This is the single + * choke point for STORED icons: signed_metadata_signer_icon() is what both the + * load-confirm and the per-tx identity screen call, and the per-tx screen + * stages the frame itself (it never goes through stage_runtime_icon), so + * validating in the staging helper alone would leave that path — and every + * legacy flash record — unchecked. Fail closed to a text-only identity: a + * missing logo is cosmetic, an over-wide one erases the alias, fingerprint and + * the "NOT verified by KeepKey" warning. */ +static bool icon_renderable(const uint8_t* icon, uint16_t icon_len, + uint8_t icon_w, uint8_t icon_h) { + if (!icon || icon_len == 0) return false; + if (icon_w == 0 || icon_w > LEFT_MARGIN_WITH_ICON) return false; + if (icon_h == 0 || icon_h > 64) return false; + return draw_bitmap_mono_rle_valid(icon, (uint32_t)icon_len, icon_w, icon_h); +} + +bool signed_metadata_signer_icon(uint8_t key_id, const uint8_t** icon_out, + uint8_t* w_out, uint8_t* h_out, + uint16_t* len_out) { + if (key_id >= METADATA_MAX_KEYS) return false; + if (loaded_pubkeys[key_id][0] != 0x00) { +#if ZCASH_PRIVACY + /* No session icon cache in this variant — an ephemeral signer renders + * text-only. It must NOT fall through to the persistent slot below: that + * would put a different identity's logo on this signer's screens. */ + return false; +#else + if (loaded_icon_len[key_id] == 0) return false; + if (!icon_renderable(loaded_icons[key_id], loaded_icon_len[key_id], + loaded_icon_w[key_id], loaded_icon_h[key_id])) { + return false; + } + if (icon_out) *icon_out = loaded_icons[key_id]; + if (w_out) *w_out = loaded_icon_w[key_id]; + if (h_out) *h_out = loaded_icon_h[key_id]; + if (len_out) *len_out = loaded_icon_len[key_id]; + return true; +#endif + } + const ClearsignIdentity* pid = persistent_identity_for(key_id); + if (!pid || pid->icon_len == 0) return false; + /* Flash records predate the geometry/encoding rules and are NOT re-validated + * by the load handler after a reboot, so an identity persisted by older + * firmware can carry a 41-64px or malformed icon. Check it here. */ + if (!icon_renderable(pid->icon, pid->icon_len, pid->icon_w, pid->icon_h)) { + return false; + } + if (icon_out) *icon_out = pid->icon; + if (w_out) *w_out = pid->icon_w; + if (h_out) *h_out = pid->icon_h; + if (len_out) *len_out = pid->icon_len; + return true; +} + +/* Render an AnimationFrame from a stored icon into the confirm's left column. + * Image + frame are the CALLER's (must outlive the synchronous confirm); this + * only wires them up. Returns RUNTIME_ICON when an icon was set, else NO_ICON. + * Positioning tuned on device — icon column is ~40px, height 64px. */ +static IconType stage_runtime_icon(Image* img, AnimationFrame* frame, + const uint8_t* icon, uint8_t icon_w, + uint8_t icon_h, uint16_t icon_len) { + if (!icon || icon_len == 0) return NO_ICON; + /* Fail closed on an over-wide icon rather than drawing it at x=0: text begins + * at x=40 and the icon is drawn AFTER the text, so a wider icon would paint + * over the alias, fingerprint and the "NOT verified by KeepKey" warning. + * fsm_msgLoadClearsignSigner already rejects width > LEFT_MARGIN_WITH_ICON, + * but an icon persisted to flash by older firmware re-enters here straight + * from storage without passing that check — so enforce it again at the point + * of use. Dropping the logo degrades to a text-only identity; letting it + * erase the warning does not. */ + if (icon_w == 0 || icon_w > LEFT_MARGIN_WITH_ICON || icon_h == 0 || + icon_h > 64) { + return NO_ICON; + } + img->w = icon_w; + img->h = icon_h; + img->length = icon_len; + img->data = icon; + /* Center inside the confirm's left icon column (LEFT_MARGIN_WITH_ICON=40px). + * Vertically center in the 64px height. */ + frame->x = (uint16_t)((LEFT_MARGIN_WITH_ICON - icon_w) / 2); + frame->y = (icon_h < 64) ? (uint16_t)((64 - icon_h) / 2) : 0; + frame->duration = 0; + /* Decoder does value*color/100; color=100 => data bytes are direct 0-255. */ + frame->color = 100; + frame->image = img; + layout_set_runtime_icon(frame); + return RUNTIME_ICON; +} + +bool signed_metadata_confirm_load(const char* alias, const char* fingerprint, + const uint8_t* icon, uint8_t icon_w, + uint8_t icon_h, uint16_t icon_len, + bool persist) { + Image icon_img; + AnimationFrame icon_frame; + IconType id_icon = stage_runtime_icon(&icon_img, &icon_frame, icon, icon_w, + icon_h, icon_len); + + char body[160]; + memset(body, 0, sizeof(body)); + /* Lead with the identity (its logo + alias + fingerprint). The trust model + * hangs on this consent; the fingerprint reappears on every per-tx screen. */ + snprintf(body, sizeof(body), + "Trust '%s' (%s) to describe transactions?%s NOT verified by " + "KeepKey.", + alias, fingerprint, persist ? " Kept until wiped." : ""); + bool ok = confirm_with_icon(ButtonRequestType_ButtonRequest_Other, id_icon, + _("Load Clearsigner"), "%s", body); + layout_set_runtime_icon(NULL); + return ok; +} + +void signed_metadata_pubkey_fingerprint(const uint8_t pubkey[33], + char out[METADATA_FINGERPRINT_LEN]) { + uint8_t digest[32]; + sha256_Raw(pubkey, 33, digest); + data2hex(digest, 4, out); + memzero(digest, sizeof(digest)); +} + +bool signed_metadata_from_loaded_signer(void) { + return metadata_available && metadata_signer_loaded; +} + +/* Resolve the verification key for a slot. */ +static const uint8_t* metadata_pubkey_for(uint8_t key_id, bool* is_loaded) { + *is_loaded = false; + if (key_id >= METADATA_MAX_KEYS) { + return NULL; + } + if (loaded_pubkeys[key_id][0] != 0x00) { + *is_loaded = true; + return loaded_pubkeys[key_id]; + } + /* Not in a RAM slot this session — fall back to a persisted identity that + * survived reboot. (A fresh load into the same slot supersedes it above.) */ + const ClearsignIdentity* pid = persistent_identity_for(key_id); + if (pid) { + *is_loaded = true; + return pid->pubkey; + } + return NULL; +} + +bool signed_metadata_signer_fingerprint(uint8_t key_id, + char out[METADATA_FINGERPRINT_LEN]) { + bool is_loaded = false; + const uint8_t* pubkey = metadata_pubkey_for(key_id, &is_loaded); + if (!pubkey) { + return false; + } + signed_metadata_pubkey_fingerprint(pubkey, out); + return true; +} + +bool signed_metadata_verify_attestation(uint8_t key_id, const uint8_t* data, + size_t data_len, const uint8_t* sig, + size_t sig_len) { + if (!data || data_len == 0 || !sig || sig_len != 64) { + return false; + } + bool is_loaded = false; + const uint8_t* pubkey = metadata_pubkey_for(key_id, &is_loaded); + if (!pubkey) { + return false; + } + uint8_t digest[32]; + sha256_Raw(data, data_len, digest); + bool ok = ecdsa_verify_digest(&secp256k1, pubkey, sig, digest) == 0; + memzero(digest, sizeof(digest)); + return ok; +} + +MetadataClassification signed_metadata_process(const uint8_t* payload, + size_t payload_len, + uint8_t key_id) { + uint8_t digest[32]; + size_t signed_len; + bool is_loaded = false; + const uint8_t* pubkey; + + signed_metadata_clear(); + + pubkey = metadata_pubkey_for(key_id, &is_loaded); + if (!pubkey || !payload || payload_len < 65) { + return METADATA_MALFORMED; + } + + if (!parse_metadata_binary(payload, payload_len, &stored_metadata) || + stored_metadata.key_id != key_id) { + signed_metadata_clear(); + return METADATA_MALFORMED; + } + + signed_len = payload_len - sizeof(stored_metadata.signature) - 1; + sha256_Raw(payload, signed_len, digest); + + if (ecdsa_verify_digest(&secp256k1, pubkey, stored_metadata.signature, + digest) != 0) { + signed_metadata_clear(); + return METADATA_MALFORMED; + } + + metadata_available = true; + metadata_signer_loaded = is_loaded; + return stored_metadata.classification; +} + +bool signed_metadata_matches_tx(const EthereumSignTx* msg) { + /* Reset the v2 decode proof up front: it must reflect ONLY the current call. + * Any early return below (unavailable, wrong contract/selector/chain) leaves + * it false, so a stale `true` from a prior successful match can never let + * signed_metadata_enforce() pass for a v2 blob that did not decode this tx. + */ + metadata_schema_decoded = false; + + if (!metadata_available || !msg || + stored_metadata.classification != METADATA_VERIFIED || + msg->to.size != sizeof(stored_metadata.contract_address) || + msg->data_initial_chunk.size < sizeof(stored_metadata.selector)) { + return false; + } + + /* Contract address binding */ + if (memcmp(stored_metadata.contract_address, msg->to.bytes, + sizeof(stored_metadata.contract_address)) != 0) { + return false; + } + + /* Function selector binding */ + if (memcmp(stored_metadata.selector, msg->data_initial_chunk.bytes, + sizeof(stored_metadata.selector)) != 0) { + return false; + } + + /* Chain ID binding */ + if ((msg->has_chain_id ? msg->chain_id : 0) != stored_metadata.chain_id) { + return false; + } + + if (stored_metadata.version == METADATA_VERSION_SCHEMA) { + /* v2 commits to calldata only — never to msg->value — and a v2 match + * suppresses the native-value confirm screen in ethereum.c. A payable + * method could then clear-sign an arbitrary ETH transfer whose value is + * never shown. The schema cannot express a value binding, so refuse to + * clear-sign any tx that moves native value; fall through to the blind-sign + * path (AdvancedMode) instead. (v1 is safe: its tx_hash covers value.) */ + for (uint32_t i = 0; i < msg->value.size; i++) { + if (msg->value.bytes[i] != 0) { + return false; + } + } + /* v2 has no committed values or tx_hash: decode the args straight from the + * calldata this tx will sign. Success here means the schema fully accounts + * for the calldata (decode_v2_args enforces exact length + presence), so + * the display is bound to the signature structurally — nothing is enforced + * later against a digest (there is no tx_hash). A decode failure falls + * through to the normal blind-sign path. Record the decode explicitly: + * signed_metadata_enforce() requires it for v2, so a signature can never be + * emitted for a v2 blob whose args were not decoded from this tx. */ + metadata_schema_decoded = decode_v2_args(&stored_metadata, msg); + return metadata_schema_decoded; + } + + /* v1 only gates what we DISPLAY (so a benign-looking method screen can't be + * shown for the wrong call). The metadata commits to the full tx hash; that + * is enforced against the real signed digest in signed_metadata_enforce() + * because the digest does not exist until send_signature() finalizes it. */ + return true; +} + +/* Renders the clearsign screens in sequence. When a signer with an icon is + * loaded, its logo (the compass) is set as RUNTIME_ICON and STAYS set for the + * whole flow, so every screen — identity, method, contract, each arg — carries + * it. The caller (signed_metadata_confirm) clears the runtime icon once on + * return, covering every early-exit path. */ +static bool signed_metadata_confirm_screens(void) { + char body[128]; + /* Compass shown on every screen once a signer with an icon is loaded. */ + IconType screen_icon = NO_ICON; + Image icon_img; + AnimationFrame icon_frame; + + if (metadata_signer_loaded) { + /* Lead with the loaded IDENTITY (logo, if any, + alias + fingerprint) + * BEFORE any clearsign page. The user approved this identity as their + * trust anchor, so showing it — not a scary "NOT verified by KeepKey" + * banner — is the honest framing. The fingerprint stays reachable so a + * swapped provider is still detectable. */ + uint8_t key_id = stored_metadata.key_id; + bool is_loaded = false; + const uint8_t* pk = metadata_pubkey_for(key_id, &is_loaded); + const char* alias = signed_metadata_signer_alias(key_id); + char fingerprint[METADATA_FINGERPRINT_LEN]; + if (pk) { + signed_metadata_pubkey_fingerprint(pk, fingerprint); + } else { + strlcpy(fingerprint, "????????", sizeof(fingerprint)); + } + if (!alias) alias = "unknown"; + + /* Draw the identity logo in the confirm's left icon column if one was + * loaded. Image + frame are local — valid for the synchronous confirm + * call, then the runtime icon is cleared. (Positioning tuned on device.) */ + const uint8_t* icon_data; + uint8_t icon_w, icon_h; + uint16_t icon_len; + if (signed_metadata_signer_icon(key_id, &icon_data, &icon_w, &icon_h, + &icon_len)) { + icon_img.w = icon_w; + icon_img.h = icon_h; + icon_img.length = icon_len; + icon_img.data = icon_data; + icon_frame.x = 0; + icon_frame.y = (icon_h < 52) ? (uint16_t)((52 - icon_h) / 2 + 6) : 6; + icon_frame.duration = 0; + /* Decoder computes pixel = data * color / 100, so color=100 makes the + * icon's data bytes direct 0-255 intensities (matches the built-in + * icons). color=0xff would overflow uint8 and corrupt every pixel. */ + icon_frame.color = 100; + icon_frame.image = &icon_img; + layout_set_runtime_icon(&icon_frame); + screen_icon = RUNTIME_ICON; + } + + memset(body, 0, sizeof(body)); + snprintf(body, sizeof(body), "%s (%s)\ndescribes this tx.", alias, + fingerprint); + /* Runtime icon stays set from here on — every subsequent screen shows the + * compass. Cleared once by the caller. */ + if (!confirm_with_icon(ButtonRequestType_ButtonRequest_ConfirmOutput, + screen_icon, "Identity", "%s", body)) { + return false; + } + + /* Method screen — same identity compass, no "Insight Verified" branding + * (that presentation is reserved for the built-in phase-2 keys). */ + memset(body, 0, sizeof(body)); + snprintf(body, sizeof(body), "Call:\n%s", stored_metadata.method_name); + if (!confirm_with_icon(ButtonRequestType_ButtonRequest_ConfirmOutput, + screen_icon, "Clearsign", "%s", body)) { + return false; + } + } else { + /* Screen 1: Verified method — use review_with_icon for trust indicator */ + memset(body, 0, sizeof(body)); + snprintf(body, sizeof(body), "Verified call:\n%s", + stored_metadata.method_name); + if (!confirm_with_icon(ButtonRequestType_ButtonRequest_ConfirmOutput, + VERIFIED_ICON, "Insight Verified", "%s", body)) { + return false; + } + } + + /* Screen 2: Contract address — ALWAYS show full address, never truncate. + * Truncation is a spoofing vector (attacker crafts matching prefix+suffix). + */ + char contract_addr[43] = "0x"; + ethereum_address_checksum(stored_metadata.contract_address, contract_addr + 2, + false, stored_metadata.chain_id); + memset(body, 0, sizeof(body)); + snprintf(body, sizeof(body), "Contract:\n%s", contract_addr); + if (!confirm_with_icon(ButtonRequestType_ButtonRequest_ConfirmOutput, + screen_icon, stored_metadata.method_name, "%s", + body)) { + return false; + } + + /* Screen 3..N: Each decoded argument */ + for (uint8_t i = 0; i < stored_metadata.num_args; i++) { + MetadataArg* arg = &stored_metadata.args[i]; + memset(body, 0, sizeof(body)); + + switch (arg->format) { + case ARG_FORMAT_ADDRESS: { + char addr_full[43] = "0x"; + if (arg->value_len != 20) { + return false; + } + ethereum_address_checksum(arg->value, addr_full + 2, false, + stored_metadata.chain_id); + snprintf(body, sizeof(body), "%s:\n%s", arg->name, addr_full); + break; + } + case ARG_FORMAT_AMOUNT: { + bignum256 amount; + bn_from_metadata_bytes(arg->value, arg->value_len, &amount); + /* Check for MAX_UINT256 (unlimited approval) */ + bool is_max = true; + for (uint16_t j = 0; j < arg->value_len; j++) { + if (arg->value[j] != 0xFF) { + is_max = false; + break; + } + } + if (is_max && arg->value_len == 32) { + snprintf(body, sizeof(body), "%s:\nUNLIMITED", arg->name); + } else { + char formatted[48]; + bn_format(&amount, NULL, " wei", 0, 0, false, formatted, + sizeof(formatted)); + snprintf(body, sizeof(body), "%s:\n%s", arg->name, formatted); + } + break; + } + case ARG_FORMAT_STRING: { + /* Attested printable label, validated at parse (arg_value_ok). */ + char text[33]; + memcpy(text, arg->value, arg->value_len); + text[arg->value_len] = '\0'; + snprintf(body, sizeof(body), "%s:\n%s", arg->name, text); + break; + } + case ARG_FORMAT_TOKEN_AMOUNT: { + /* decimals + symbol + big-endian amount, validated at parse. + * This is the "Amount: 1,000 USDC" the clear-signing plan calls for + * instead of a raw wei integer. */ + uint8_t decimals = arg->value[0]; + uint8_t symlen = arg->value[1]; + char suffix[METADATA_MAX_TOKEN_SYMBOL_LEN + 2]; + suffix[0] = ' '; + memcpy(suffix + 1, arg->value + 2, symlen); + suffix[1 + symlen] = '\0'; + + const uint8_t* amt = arg->value + 2 + symlen; + uint16_t amt_len = arg->value_len - 2 - symlen; + bool is_max = amt_len == 32; + for (uint16_t j = 0; j < amt_len && is_max; j++) { + if (amt[j] != 0xFF) { + is_max = false; + } + } + if (is_max) { + snprintf(body, sizeof(body), "%s:\nUNLIMITED%s", arg->name, suffix); + } else { + bignum256 amount; + bn_from_metadata_bytes(amt, amt_len, &amount); + char formatted[48]; + bn_format(&amount, NULL, suffix, decimals, 0, false, formatted, + sizeof(formatted)); + snprintf(body, sizeof(body), "%s:\n%s", arg->name, formatted); + } + break; + } + case ARG_FORMAT_BYTES: + case ARG_FORMAT_RAW: + default: { + char hex[(METADATA_MAX_ARG_VALUE_LEN * 2) + 1]; + size_t display_len = arg->value_len > 16 ? 16 : (size_t)arg->value_len; + data2hex(arg->value, display_len, hex); + snprintf(body, sizeof(body), "%s:\n%s%s", arg->name, hex, + arg->value_len > 16 ? "..." : ""); + break; + } + } + + if (!confirm_with_icon(ButtonRequestType_ButtonRequest_ConfirmOutput, + screen_icon, stored_metadata.method_name, "%s", + body)) { + return false; + } + } + + /* User approved the decoded who/what/why. From here the raw-data confirm is + * suppressed, so the signature MUST be bound to this metadata's tx hash. */ + relied_on_metadata = true; + return true; +} + +bool signed_metadata_confirm(void) { + if (!metadata_available || + stored_metadata.classification != METADATA_VERIFIED) { + return false; + } + bool ok = signed_metadata_confirm_screens(); + /* Single cleanup for every screen-flow exit — the runtime icon frame lives on + * the helper's stack, so it must not outlive this call. */ + layout_set_runtime_icon(NULL); + return ok; +} + +bool signed_metadata_relied(void) { return relied_on_metadata; } + +bool signed_metadata_enforce_decision(bool relied, bool available, + int classification, + const uint8_t* stored_hash, + const uint8_t* hash) { + if (!relied) { + return true; /* signature was not gated by metadata */ + } + /* Fail closed: relied on metadata but it's gone, not verified, or the signed + * digest differs from what was displayed → refuse to emit a signature. + * tx_hash is 32 bytes (see SignedMetadata). */ + return hash != NULL && stored_hash != NULL && available && + classification == METADATA_VERIFIED && + memcmp(stored_hash, hash, 32) == 0; +} + +bool signed_metadata_enforce_schema_decision(bool relied, bool available, + bool decoded, int classification) { + /* v2 (static schema) has no committed tx_hash. Its binding is structural: the + * args were decoded from the exact calldata being signed, and that calldata + * cannot change between decode and sign within one signing operation. So if + * we relied on a verified v2 decode, signing may proceed; there is no digest + * to compare. `decoded` is the explicit proof that decode_v2_args() ran and + * succeeded for this signing operation — required rather than inferred from + * call order, since v2 has no digest fallback. If we did not rely on the + * metadata, signing was never gated by it. */ + return !relied || + (available && decoded && classification == METADATA_VERIFIED); +} + +bool signed_metadata_enforce(const uint8_t hash[32]) { + if (metadata_available && + stored_metadata.version == METADATA_VERSION_SCHEMA) { + return signed_metadata_enforce_schema_decision( + relied_on_metadata, metadata_available, metadata_schema_decoded, + stored_metadata.classification); + } + return signed_metadata_enforce_decision( + relied_on_metadata, metadata_available, stored_metadata.classification, + stored_metadata.tx_hash, hash); +} + +const SignedMetadata* signed_metadata_get(void) { + return metadata_available ? &stored_metadata : NULL; +} diff --git a/lib/firmware/signtx_tendermint.c b/lib/firmware/signtx_tendermint.c index 0f849d64b..92491f877 100644 --- a/lib/firmware/signtx_tendermint.c +++ b/lib/firmware/signtx_tendermint.c @@ -36,19 +36,19 @@ static CONFIDENTIAL HDNode node; static SHA256_CTX ctx; static bool has_message; static bool initialized; +static TendermintSigningType signing_type; static uint32_t msgs_remaining; static TendermintSignTx tmsg; const void* tendermint_getSignTx(void) { return (void*)&tmsg; } bool tendermint_signTxInit(const HDNode* _node, const void* _msg, - const size_t msgsize, const char* denom) { - initialized = true; - msgs_remaining = ((TendermintSignTx*)_msg)->msg_count; - has_message = false; - - memzero(&node, sizeof(node)); - memcpy(&node, _node, sizeof(node)); + const size_t msgsize, const char* denom, + TendermintSigningType type) { + tendermint_signAbort(); + if (!_node || !_msg || !denom || + (type != TENDERMINT_SIGNING_COSMOS && type != TENDERMINT_SIGNING_GENERIC)) + return false; /* _msg is expected to be of type TendermintSignTx, CosmosSignTx or @@ -65,6 +65,11 @@ bool tendermint_signTxInit(const HDNode* _node, const void* _msg, return false; } + const TendermintSignTx* common = (const TendermintSignTx*)_msg; + if (!common->has_msg_count || common->msg_count == 0) return false; + + msgs_remaining = common->msg_count; + memcpy(&node, _node, sizeof(node)); memcpy((void*)&tmsg, _msg, msgsize); bool success = true; @@ -103,13 +108,24 @@ bool tendermint_signTxInit(const HDNode* _node, const void* _msg, // 10 sha256_Update(&ctx, (uint8_t*)"\",\"msgs\":[", 10); - return success; + if (!success) { + tendermint_signAbort(); + return false; + } + initialized = true; + signing_type = type; + return true; +} + +static bool tendermint_canUpdate(void) { + return initialized && msgs_remaining > 0; } bool tendermint_signTxUpdateMsgSend(const uint64_t amount, const char* to_address, const char* chainstr, const char* denom, const char* msgTypePrefix) { + if (!tendermint_canUpdate()) return false; char buffer[128]; size_t decoded_len; char hrp[45]; @@ -163,8 +179,10 @@ bool tendermint_signTxUpdateMsgSend(const uint64_t amount, success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), "%s\"}}", to_address); - has_message = true; - msgs_remaining--; + if (success) { + has_message = true; + msgs_remaining--; + } return success; } @@ -173,6 +191,7 @@ bool tendermint_signTxUpdateMsgDelegate(const uint64_t amount, const char* validator_address, const char* chainstr, const char* denom, const char* msgTypePrefix) { + if (!tendermint_canUpdate()) return false; char buffer[128]; size_t decoded_len; char hrp[45]; @@ -226,8 +245,10 @@ bool tendermint_signTxUpdateMsgDelegate(const uint64_t amount, success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), "%s\"}}", validator_address); - has_message = true; - msgs_remaining--; + if (success) { + has_message = true; + msgs_remaining--; + } return success; } bool tendermint_signTxUpdateMsgUndelegate(const uint64_t amount, @@ -236,6 +257,7 @@ bool tendermint_signTxUpdateMsgUndelegate(const uint64_t amount, const char* chainstr, const char* denom, const char* msgTypePrefix) { + if (!tendermint_canUpdate()) return false; char buffer[128]; size_t decoded_len; char hrp[45]; @@ -289,8 +311,10 @@ bool tendermint_signTxUpdateMsgUndelegate(const uint64_t amount, success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), "%s\"}}", validator_address); - has_message = true; - msgs_remaining--; + if (success) { + has_message = true; + msgs_remaining--; + } return success; } @@ -298,6 +322,7 @@ bool tendermint_signTxUpdateMsgRedelegate( const uint64_t amount, const char* delegator_address, const char* validator_src_address, const char* validator_dst_address, const char* chainstr, const char* denom, const char* msgTypePrefix) { + if (!tendermint_canUpdate()) return false; char buffer[128]; size_t decoded_len; char hrp[45]; @@ -359,8 +384,10 @@ bool tendermint_signTxUpdateMsgRedelegate( success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), "%s\"}}", validator_src_address); - has_message = true; - msgs_remaining--; + if (success) { + has_message = true; + msgs_remaining--; + } return success; } @@ -369,6 +396,7 @@ bool tendermint_signTxUpdateMsgRewards(const uint64_t* amount, const char* validator_address, const char* chainstr, const char* denom, const char* msgTypePrefix) { + if (!tendermint_canUpdate()) return false; char buffer[128]; size_t decoded_len; char hrp[45]; @@ -425,8 +453,10 @@ bool tendermint_signTxUpdateMsgRewards(const uint64_t* amount, success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), "%s\"}}", validator_address); - has_message = true; - msgs_remaining--; + if (success) { + has_message = true; + msgs_remaining--; + } return success; } @@ -435,6 +465,7 @@ bool tendermint_signTxUpdateMsgIBCTransfer( const char* source_channel, const char* source_port, const char* revision_number, const char* revision_height, const char* chainstr, const char* denom, const char* msgTypePrefix) { + if (!tendermint_canUpdate()) return false; char buffer[128]; size_t decoded_len; char hrp[45]; @@ -505,12 +536,15 @@ bool tendermint_signTxUpdateMsgIBCTransfer( "\",\"denom\":\"%s\"}}}", amount, denom); - has_message = true; - msgs_remaining--; + if (success) { + has_message = true; + msgs_remaining--; + } return success; } bool tendermint_signTxFinalize(uint8_t* public_key, uint8_t* signature) { + if (!initialized || msgs_remaining != 0 || !has_message) return false; char buffer[128]; // 14 + ^20 + 2 = ^36 @@ -528,14 +562,28 @@ bool tendermint_signTxFinalize(uint8_t* public_key, uint8_t* signature) { NULL) == 0; } -bool tendermint_signingIsInited(void) { return initialized; } +bool tendermint_signingIsInited(TendermintSigningType type) { + return initialized && signing_type == type; +} + +bool tendermint_signingConfigMatches(const char* chain_name, const char* denom, + const char* message_type_prefix) { + return tendermint_signingIsInited(TENDERMINT_SIGNING_GENERIC) && chain_name && + denom && message_type_prefix && + strcmp(chain_name, tmsg.chain_name) == 0 && + strcmp(denom, tmsg.denom) == 0 && + strcmp(message_type_prefix, tmsg.message_type_prefix) == 0; +} -bool tendermint_signingIsFinished(void) { return msgs_remaining == 0; } +bool tendermint_signingIsFinished(void) { + return initialized && msgs_remaining == 0; +} void tendermint_signAbort(void) { initialized = false; + signing_type = TENDERMINT_SIGNING_NONE; has_message = false; msgs_remaining = 0; memzero(&tmsg, sizeof(tmsg)); memzero(&node, sizeof(node)); -} \ No newline at end of file +} diff --git a/lib/firmware/solana.c b/lib/firmware/solana.c index abadf4cfe..302a1340f 100644 --- a/lib/firmware/solana.c +++ b/lib/firmware/solana.c @@ -19,6 +19,7 @@ #include "keepkey/firmware/solana.h" +#include "keepkey/firmware/signed_metadata.h" #include "trezor/crypto/memzero.h" #include @@ -122,10 +123,17 @@ static void copy_account(uint8_t out[SOL_PUBKEY_SIZE], const SolanaParsedTx* tx, } } +/* allow_external_indices: versioned (v0) messages may reference accounts + * loaded from address lookup tables — indices at or beyond the static + * account list. Those accounts are not present in the message, so an + * instruction touching them cannot be verified on-device: it is left + * SOL_INSTR_UNKNOWN and the whole tx is forced opaque instead of being + * rejected as malformed. Legacy messages must never contain such indices. */ static int parse_instruction_section(const uint8_t* raw, size_t raw_len, size_t* pos_io, SolanaParsedTx* tx, uint16_t num_accounts, bool* has_unknown, - bool* force_opaque) { + bool* force_opaque, + bool allow_external_indices) { size_t pos = *pos_io; uint16_t num_instructions; int n = read_compact_u16(raw + pos, raw_len - pos, &num_instructions); @@ -133,11 +141,10 @@ static int parse_instruction_section(const uint8_t* raw, size_t raw_len, pos += n; if (num_instructions > SOL_MAX_INSTRUCTIONS) { + /* Too many to display — opaque. Keep walking the section so the + * structural checks (and any trailing sections) stay meaningful. */ *force_opaque = true; tx->num_instructions = 0; - /* Don't attempt to parse instruction data — treat as opaque. */ - *pos_io = raw_len; - return 0; } else { tx->num_instructions = (uint8_t)num_instructions; } @@ -145,7 +152,11 @@ static int parse_instruction_section(const uint8_t* raw, size_t raw_len, for (uint16_t i = 0; i < num_instructions; i++) { if (pos >= raw_len) return -1; uint8_t program_idx = raw[pos++]; - if (program_idx >= num_accounts) return -1; + bool external = false; + if (program_idx >= num_accounts) { + if (!allow_external_indices) return -1; + external = true; + } uint16_t num_acct_indices; n = read_compact_u16(raw + pos, raw_len - pos, &num_acct_indices); @@ -157,7 +168,10 @@ static int parse_instruction_section(const uint8_t* raw, size_t raw_len, pos += num_acct_indices; for (uint16_t j = 0; j < num_acct_indices; j++) { - if (acct_indices[j] >= num_accounts) return -1; + if (acct_indices[j] >= num_accounts) { + if (!allow_external_indices) return -1; + external = true; + } } uint16_t data_len; @@ -169,11 +183,19 @@ static int parse_instruction_section(const uint8_t* raw, size_t raw_len, const uint8_t* instr_data = raw + pos; pos += data_len; - if (i >= SOL_MAX_INSTRUCTIONS) { + if (i >= SOL_MAX_INSTRUCTIONS || tx->num_instructions == 0) { continue; } SolanaParsedInstruction* pi = &tx->instructions[i]; + + if (external) { + /* Accounts resolved via lookup tables: unverifiable on-device. */ + pi->type = SOL_INSTR_UNKNOWN; + *force_opaque = true; + continue; + } + memcpy(pi->program_id, tx->accounts[program_idx], SOL_PUBKEY_SIZE); /* Classify and decode */ @@ -191,6 +213,12 @@ static int parse_instruction_section(const uint8_t* raw, size_t raw_len, pi->lamports = read_le64(instr_data + 4); copy_account(pi->from, tx, acct_indices, num_acct_indices, 0); copy_account(pi->to, tx, acct_indices, num_acct_indices, 1); + /* CreateAccount also assigns the new account's space and OWNER + * program (bytes not parsed here); the owner controls the account, so + * a partial "amount only" screen is unsafe. Require AdvancedMode + * until a full screen (destination + amount + owner + space) exists. + */ + *force_opaque = true; } else if (instr_type == SOL_SYS_ADVANCE_NONCE) { pi->type = SOL_INSTR_SYSTEM_ADVANCE_NONCE; copy_account(pi->from, tx, acct_indices, num_acct_indices, 0); @@ -230,6 +258,12 @@ static int parse_instruction_section(const uint8_t* raw, size_t raw_len, 0 || memcmp(pi->program_id, SOL_TOKEN_2022_PROGRAM, SOL_PUBKEY_SIZE) == 0) { + /* Token-2022 transfers can invoke a configured transfer-hook program with + * extra accounts and arbitrary logic (and levy transfer fees) that we can + * neither authenticate nor display. Treat them as opaque (AdvancedMode) + * rather than clear-sign only source/mint/dest/amount. */ + const bool is_token2022 = + memcmp(pi->program_id, SOL_TOKEN_2022_PROGRAM, SOL_PUBKEY_SIZE) == 0; if (data_len >= 1) { uint8_t token_instr = instr_data[0]; if (token_instr == SOL_TOKEN_TRANSFER_IX && data_len >= 9) { @@ -238,22 +272,41 @@ static int parse_instruction_section(const uint8_t* raw, size_t raw_len, copy_account(pi->from, tx, acct_indices, num_acct_indices, 0); copy_account(pi->to, tx, acct_indices, num_acct_indices, 1); copy_account(pi->authority, tx, acct_indices, num_acct_indices, 2); + /* Unchecked Transfer carries no signed mint, so the device cannot + * prove which token is moving — a host can pick any signer-controlled + * account. Force the AdvancedMode blind-sign gate; only the *Checked + * variant (mint signed + displayed) clear-signs. */ + *force_opaque = true; } else if (token_instr == SOL_TOKEN_TRANSFER_CHECKED_IX && - data_len >= 9) { + data_len >= 10 && num_acct_indices >= 4) { + /* Canonical TransferChecked ONLY: opcode + amount(8) + decimals(1) + * and all four accounts [source, mint, dest, authority]. A 9-byte + * encoding (no decimals) or a short account list would otherwise + * classify VERIFIED while skipping the mint screen and showing a + * zeroed destination — such non-canonical shapes fall through to + * UNKNOWN and force the whole tx opaque. */ pi->type = SOL_INSTR_TOKEN_TRANSFER_CHECKED; pi->amount = read_le64(instr_data + 1); copy_account(pi->from, tx, acct_indices, num_acct_indices, 0); copy_account(pi->mint, tx, acct_indices, num_acct_indices, 1); - pi->has_mint = (num_acct_indices >= 2); + pi->has_mint = true; copy_account(pi->to, tx, acct_indices, num_acct_indices, 2); copy_account(pi->authority, tx, acct_indices, num_acct_indices, 3); - pi->extra_u8 = data_len >= 10 ? instr_data[9] : 0; + pi->extra_u8 = instr_data[9]; + /* Token-2022 checked transfers may carry an undisclosed transfer hook + * / fee — do not clear-sign them. */ + if (is_token2022) { + *force_opaque = true; + } } else if (token_instr == SOL_TOKEN_APPROVE_IX && data_len >= 9) { pi->type = SOL_INSTR_TOKEN_APPROVE; pi->amount = read_le64(instr_data + 1); copy_account(pi->from, tx, acct_indices, num_acct_indices, 0); copy_account(pi->to, tx, acct_indices, num_acct_indices, 1); copy_account(pi->authority, tx, acct_indices, num_acct_indices, 2); + /* Unchecked Approve hides the mint (which token is being delegated), + * same as unchecked Transfer — require AdvancedMode. */ + *force_opaque = true; } else if (token_instr == SOL_TOKEN_REVOKE_IX) { pi->type = SOL_INSTR_TOKEN_REVOKE; copy_account(pi->from, tx, acct_indices, num_acct_indices, 0); @@ -266,6 +319,12 @@ static int parse_instruction_section(const uint8_t* raw, size_t raw_len, if (data_len >= 35 && instr_data[2] == 1) { memcpy(pi->extra, instr_data + 3, SOL_PUBKEY_SIZE); } + /* Authority handover (owner/close/mint/freeze) is an account-takeover + * vector, and the "set to None" (clear) case is not distinguished + * from an all-zero authority in the parsed struct. Require + * AdvancedMode until a full screen (authority type + target + + * new/None) exists. */ + *force_opaque = true; } else if ((token_instr == SOL_TOKEN_MINT_TO_IX || token_instr == SOL_TOKEN_MINT_TO_CHECKED_IX) && data_len >= 9) { @@ -335,7 +394,10 @@ static int parse_instruction_section(const uint8_t* raw, size_t raw_len, copy_account(pi->from, tx, acct_indices, num_acct_indices, 0); copy_account(pi->to, tx, acct_indices, num_acct_indices, 1); copy_account(pi->authority, tx, acct_indices, num_acct_indices, 4); - } else if (stake_instr == SOL_STAKE_AUTHORIZE_IX && data_len >= 36) { + } else if (stake_instr == SOL_STAKE_AUTHORIZE_IX && data_len >= 40) { + /* new_authority(32) at +4 then authorize_type(le32) at +36, so the + * instruction needs >= 40 bytes — reading extra_u8 at +36 with only + * 36 bytes was a 4-byte over-read. */ pi->type = SOL_INSTR_STAKE_AUTHORIZE; memcpy(pi->extra, instr_data + 4, SOL_PUBKEY_SIZE); copy_account(pi->from, tx, acct_indices, num_acct_indices, 0); @@ -380,11 +442,16 @@ static int parse_instruction_section(const uint8_t* raw, size_t raw_len, copy_account(pi->to, tx, acct_indices, num_acct_indices, 1); copy_account(pi->authority, tx, acct_indices, num_acct_indices, 2); } else if (vote_instr == SOL_VOTE_UPDATE_VALIDATOR_IX && - data_len >= 36) { + data_len == 4) { + /* UpdateValidatorIdentity has NO data payload: the new validator is + * account index 1. Reading 32 bytes from the data would display + * attacker-supplied trailing bytes instead of the account actually + * used, so require the canonical 4-byte encoding and read account 1. + */ pi->type = SOL_INSTR_VOTE_UPDATE_VALIDATOR; - memcpy(pi->extra, instr_data + 4, SOL_PUBKEY_SIZE); copy_account(pi->from, tx, acct_indices, num_acct_indices, 0); - copy_account(pi->authority, tx, acct_indices, num_acct_indices, 1); + copy_account(pi->extra, tx, acct_indices, num_acct_indices, 1); + copy_account(pi->authority, tx, acct_indices, num_acct_indices, 2); } else if (vote_instr == SOL_VOTE_UPDATE_COMMISSION_IX && data_len >= 5) { pi->type = SOL_INSTR_VOTE_UPDATE_COMMISSION; @@ -438,6 +505,8 @@ static int parse_instruction_section(const uint8_t* raw, size_t raw_len, } } else if (memcmp(pi->program_id, SOL_MEMO_PROGRAM, SOL_PUBKEY_SIZE) == 0) { pi->type = SOL_INSTR_MEMO; + pi->data = instr_data; + pi->data_len = data_len; } else { pi->type = SOL_INSTR_UNKNOWN; *has_unknown = true; @@ -487,7 +556,8 @@ static SolanaTxReview solana_parseLegacyTx(const uint8_t* raw, size_t raw_len, pos += SOL_PUBKEY_SIZE; n = parse_instruction_section(raw, raw_len, &pos, tx, num_accounts, - &has_unknown, &force_opaque); + &has_unknown, &force_opaque, + /*allow_external_indices=*/false); if (n < 0) return SOL_TX_REVIEW_MALFORMED; /* Reject if there are unconsumed bytes — prevents hidden trailing data */ @@ -505,7 +575,7 @@ static SolanaTxReview solana_parseVersionedTx(const uint8_t* raw, memset(tx, 0, sizeof(*tx)); size_t pos = 0; bool has_unknown = false; - bool force_opaque = true; + bool force_opaque = false; if (raw_len < 1) return SOL_TX_REVIEW_MALFORMED; uint8_t version_prefix = raw[pos++]; @@ -536,7 +606,8 @@ static SolanaTxReview solana_parseVersionedTx(const uint8_t* raw, pos += SOL_PUBKEY_SIZE; n = parse_instruction_section(raw, raw_len, &pos, tx, num_accounts, - &has_unknown, &force_opaque); + &has_unknown, &force_opaque, + /*allow_external_indices=*/true); if (n < 0) return SOL_TX_REVIEW_MALFORMED; uint16_t lookup_table_count; @@ -563,7 +634,31 @@ static SolanaTxReview solana_parseVersionedTx(const uint8_t* raw, } if (pos != raw_len) return SOL_TX_REVIEW_MALFORMED; - return SOL_TX_REVIEW_OPAQUE; + + /* A v0 message whose instructions only touch static accounts is exactly + * as verifiable as a legacy message. Lookup-table sections are allowed + * to exist; any instruction actually reaching into them forced opaque + * above (external indices). */ + if (tx->num_instructions == 0 || has_unknown || force_opaque) { + return SOL_TX_REVIEW_OPAQUE; + } + return SOL_TX_REVIEW_VERIFIED; +} + +/* Normalize the bytes that are actually signed. Solana signs the serialized + * MESSAGE. Clients may send either the bare message (byte 0 = num_required_sigs + * >= 1) or a full unsigned transaction whose byte 0 is a compact-u16 signature + * count of 0. Strip that single prefix byte so parsing (solana_inspectTx) and + * signing (solana_signTx) operate on the IDENTICAL slice — otherwise the device + * would display one message but sign 0x00||message, which never verifies. */ +static void solana_message_slice(const uint8_t* raw, size_t raw_len, + const uint8_t** msg_out, size_t* len_out) { + if (raw_len > 1 && raw[0] == 0) { + raw++; + raw_len--; + } + *msg_out = raw; + *len_out = raw_len; } SolanaTxReview solana_inspectTx(const uint8_t* raw, size_t raw_len, @@ -573,24 +668,18 @@ SolanaTxReview solana_inspectTx(const uint8_t* raw, size_t raw_len, return SOL_TX_REVIEW_MALFORMED; } - /* Skip signature count prefix if present. - * Clients may send either the raw message (header starts at byte 0) - * or a full unsigned transaction (compact-u16 sig count = 0 at byte 0). - * A valid legacy message header has num_required_sigs >= 1 at byte 0. - * If byte 0 is 0, it's a signature count prefix — skip it. */ - if (raw[0] == 0 && raw_len > 1) { - raw++; - raw_len--; - } + const uint8_t* msg; + size_t msg_len; + solana_message_slice(raw, raw_len, &msg, &msg_len); /* Versioned Solana messages set the top bit in byte 0. * Parse them structurally so malformed v0/ALT payloads fail closed, * but keep the result opaque until the firmware can verify semantics. */ - if (raw[0] & SOL_VERSION_FLAG) { - return solana_parseVersionedTx(raw, raw_len, tx); + if (msg[0] & SOL_VERSION_FLAG) { + return solana_parseVersionedTx(msg, msg_len, tx); } - return solana_parseLegacyTx(raw, raw_len, tx); + return solana_parseLegacyTx(msg, msg_len, tx); } bool solana_parseTx(const uint8_t* raw, size_t raw_len, SolanaParsedTx* tx) { @@ -601,6 +690,41 @@ bool solana_parseTx(const uint8_t* raw, size_t raw_len, SolanaParsedTx* tx) { /* Formatting */ /* ------------------------------------------------------------------ */ +bool solana_priority_fee_lamports(uint64_t price, uint64_t limit, + uint64_t* out) { + /* ceil(price * limit / 1e6) with no overflow and no silent wrap. price/limit + * are u64; the product can exceed u64, and even ceil(product/1e6) can exceed + * u64. Split price = q*D + r and accumulate so every step is checked; return + * false (do NOT saturate) if the true lamport value exceeds UINT64_MAX. */ + const uint64_t D = 1000000u; + uint64_t q = price / D; + uint64_t r = price % D; + if (limit != 0 && r > UINT64_MAX / limit) { + return false; /* r*limit overflows (only for absurd limits) */ + } + uint64_t rl = r * limit; + uint64_t lamports = rl / D; + bool ceil_up = (rl % D) != 0; + if (q != 0 && limit != 0) { + if (q > UINT64_MAX / limit) { + return false; + } + uint64_t ql = q * limit; + if (ql > UINT64_MAX - lamports) { + return false; + } + lamports += ql; + } + if (ceil_up) { + if (lamports == UINT64_MAX) { + return false; + } + lamports++; + } + *out = lamports; + return true; +} + void solana_formatAmount(char* buf, size_t len, uint64_t lamports) { uint64_t whole = lamports / SOL_LAMPORTS_DIVISOR; uint64_t frac = lamports % SOL_LAMPORTS_DIVISOR; @@ -654,6 +778,43 @@ const SolanaTokenInfo* solana_findTokenInfo( return NULL; } +bool solana_token_info_trusted(const SolanaTokenInfo* ti) { + if (!ti || !ti->has_signature || !ti->has_signer_key_id || !ti->has_mint || + ti->mint.size != SOL_PUBKEY_SIZE || !ti->has_symbol || + !ti->has_decimals) { + return false; + } + /* uint32 field: reject out-of-range slots BEFORE narrowing to the uint8 the + * keyring uses, so key_id 256 can't alias slot 0. */ + if (ti->signer_key_id >= METADATA_MAX_KEYS) { + return false; + } + size_t sym_len = strnlen(ti->symbol, sizeof(ti->symbol)); + if (sym_len == 0) { + return false; + } + /* Domain tag prevents a signature made for any other purpose (e.g. an EVM + * metadata blob signed by the same key) from being replayed as a token def. + * Preimage: tag || mint(32) || decimals(le32) || symbol. */ + static const char kTag[] = "KeepKeySolanaTokenDef/1"; + uint8_t blob[sizeof(kTag) - 1 + SOL_PUBKEY_SIZE + 4 + sizeof(ti->symbol)]; + size_t n = 0; + memcpy(blob + n, kTag, sizeof(kTag) - 1); + n += sizeof(kTag) - 1; + memcpy(blob + n, ti->mint.bytes, SOL_PUBKEY_SIZE); + n += SOL_PUBKEY_SIZE; + uint32_t dec = ti->decimals; + blob[n++] = (uint8_t)dec; + blob[n++] = (uint8_t)(dec >> 8); + blob[n++] = (uint8_t)(dec >> 16); + blob[n++] = (uint8_t)(dec >> 24); + memcpy(blob + n, ti->symbol, sym_len); + n += sym_len; + return signed_metadata_verify_attestation((uint8_t)ti->signer_key_id, blob, n, + ti->signature.bytes, + ti->signature.size); +} + /* ------------------------------------------------------------------ */ /* Signing */ /* ------------------------------------------------------------------ */ @@ -662,11 +823,28 @@ bool solana_signTx(const HDNode* node, const SolanaSignTx* msg, SolanaSignedTx* resp) { if (!msg->has_raw_tx || msg->raw_tx.size == 0) return false; - /* Ed25519 sign the raw transaction message directly - * (Solana signs the serialized message, not a hash of it) */ + /* Sign the exact same message slice that solana_inspectTx parsed and the user + * approved (Solana signs the serialized message, not a hash of it). */ + const uint8_t* message; + size_t message_len; + solana_message_slice(msg->raw_tx.bytes, msg->raw_tx.size, &message, + &message_len); + uint8_t sig[SOL_SIG_SIZE]; - ed25519_sign(msg->raw_tx.bytes, msg->raw_tx.size, node->private_key, - node->public_key + 1, sig); + ed25519_sign(message, message_len, node->private_key, node->public_key + 1, + sig); + +#if !ZCASH_PRIVACY + /* Defense-in-depth: refuse to emit a signature that does not verify over + * those exact bytes. solana_message_slice() already guarantees parsing and + * signing operate on the identical message, so this is a redundant check; + * it is compiled out on the ROM-tight zcash-privacy variant, where pulling in + * the ed25519 verification path would overflow flash. */ + if (ed25519_sign_open(message, message_len, node->public_key + 1, sig) != 0) { + memzero(sig, sizeof(sig)); + return false; + } +#endif resp->has_signature = true; resp->signature.size = SOL_SIG_SIZE; diff --git a/lib/firmware/storage.c b/lib/firmware/storage.c index c1cd77d12..975899444 100644 --- a/lib/firmware/storage.c +++ b/lib/firmware/storage.c @@ -45,6 +45,7 @@ #include "keepkey/firmware/passphrase_sm.h" #include "keepkey/firmware/policy.h" #include "keepkey/firmware/u2f.h" +#include "keepkey/firmware/zcash.h" #include "keepkey/rand/rng.h" #include "keepkey/transport/interface.h" #include "trezor/crypto/aes/aes.h" @@ -90,6 +91,28 @@ _Static_assert(sizeof(ConfigFlash) <= FLASH_STORAGE_LEN, "ConfigFlash struct is too large for storage partition"); static ConfigFlash CONFIDENTIAL shadow_config; +/* This firmware found storage in flash it must refuse to load or overwrite + * until the user explicitly wipes: a bitcoin-only wallet seen by multi-chain + * firmware, or (on bitcoin-only firmware) a newer in-band wallet than this + * build understands. Set from the SUS_BitcoinOnlyLocked path in either build. + */ +static bool btc_only_locked = false; + +bool storage_isBitcoinOnlyLocked(void) { return btc_only_locked; } + +// Stamp a newly-created seed into the reserved bitcoin-only version band so +// multi-chain firmware refuses it (see storage_fromFlash). Called only from +// seed-creation paths, so a pre-existing multi-chain wallet migrated under +// bitcoin-only firmware keeps its normal, portable version. No-op (but still +// referenced, so no -Wunused) in multi-chain builds. +#if BITCOIN_ONLY +static void storage_stampBitcoinOnlySeed(void) { + shadow_config.storage.version = STORAGE_VERSION_BTC_ONLY; +} +#else +static void storage_stampBitcoinOnlySeed(void) {} +#endif + #if DEBUG_LINK // These won't survive resets like the stuff in flash would, but thats a // reasonable compromise given how testing works. @@ -176,6 +199,18 @@ static void write_u32_le(char* ptr, uint32_t val) { ptr[3] = (val >> 24) & 0xff; } +/* Cast each byte through uint8_t first: on the emulator (signed char) a raw + * (uint16_t)ptr[i] would sign-extend a 0x80+ low byte (icon_len reaches 384). + */ +static uint16_t read_u16_le(const char* ptr) { + return (uint16_t)((uint8_t)ptr[0]) | ((uint16_t)((uint8_t)ptr[1]) << 8); +} + +static void write_u16_le(char* ptr, uint16_t val) { + ptr[0] = val & 0xff; + ptr[1] = (val >> 8) & 0xff; +} + static bool read_bool(const char* ptr) { return *ptr; } static void write_bool(char* ptr, bool val) { *ptr = val ? 1 : 0; } @@ -184,8 +219,14 @@ enum StorageVersion { StorageVersion_NONE, #define STORAGE_VERSION_ENTRY(VAL) StorageVersion_##VAL, #include "storage_versions.inc" + StorageVersion_BTC_ONLY, // reserved band, never in storage_versions.inc }; +// The normal storage version must stay below the bitcoin-only band, or a +// bitcoin-only wallet would become loadable by multi-chain firmware. +_Static_assert(STORAGE_VERSION < STORAGE_VERSION_BTC_ONLY_BASE, + "storage version must stay below the bitcoin-only band"); + static enum StorageVersion version_from_int(int version) { #define STORAGE_VERSION_LAST(VAL) \ _Static_assert(VAL == STORAGE_VERSION, \ @@ -193,6 +234,12 @@ static enum StorageVersion version_from_int(int version) { "storage_versions.inc"); #include "storage_versions.inc" + // Any version in the reserved bitcoin-only band maps here regardless of + // build; storage_fromFlash decides load-vs-refuse from the exact value, so + // an in-band firmware downgrade refuses rather than silently wiping a newer + // bitcoin-only wallet. + if (version >= STORAGE_VERSION_BTC_ONLY_BASE) return StorageVersion_BTC_ONLY; + switch (version) { #define STORAGE_VERSION_ENTRY(VAL) \ case VAL: \ @@ -1080,6 +1127,55 @@ void storage_readStorageV17(Storage* storage, const char* ptr, size_t len) { memcpy(storage->encrypted_sec, ptr + 1501, sizeof(storage->encrypted_sec)); } +// V18 appends the persistent clear-sign identities block immediately after the +// V17 encrypted_sec (which ends at ptr + 1501 + V17_ENCSEC_SIZE = ptr + 2525). +// Everything before it is the byte-identical V17 layout — never reorder it. +// One identity serializes to CLEARSIGN_IDENTITY_SERIALIZED_LEN bytes: +// +0 present(u8) +1 key_id(u8) +2 pubkey[33] +35 alias[32] +67 icon_w(u8) +// +68 icon_h(u8) +69 icon_len(u16 le) +71 icon[CLEARSIGN_ICON_MAX] = 71+384 +#define CLEARSIGN_IDENTITY_BLOCK_OFF (1501 + V17_ENCSEC_SIZE) // 2525 +#define CLEARSIGN_IDENTITY_SERIALIZED_LEN (71 + CLEARSIGN_ICON_MAX) // 455 + +void storage_writeStorageV18(char* ptr, size_t len, const Storage* storage) { + storage_writeStorageV17(ptr, len, storage); + + for (int i = 0; i < PERSISTENT_IDENTITY_COUNT; i++) { + const ClearsignIdentity* id = &storage->pub.clearsign_identities[i]; + char* p = ptr + CLEARSIGN_IDENTITY_BLOCK_OFF + + (size_t)i * CLEARSIGN_IDENTITY_SERIALIZED_LEN; + write_u8(p + 0, id->present ? 1 : 0); + write_u8(p + 1, id->key_id); + memcpy(p + 2, id->pubkey, sizeof(id->pubkey)); // 33 + memcpy(p + 35, id->alias, sizeof(id->alias)); // 32 + write_u8(p + 67, id->icon_w); + write_u8(p + 68, id->icon_h); + write_u16_le(p + 69, id->icon_len); + memcpy(p + 71, id->icon, sizeof(id->icon)); // CLEARSIGN_ICON_MAX + } +} + +void storage_readStorageV18(Storage* storage, const char* ptr, size_t len) { + storage_readStorageV17(storage, ptr, len); + + for (int i = 0; i < PERSISTENT_IDENTITY_COUNT; i++) { + ClearsignIdentity* id = &storage->pub.clearsign_identities[i]; + const char* p = ptr + CLEARSIGN_IDENTITY_BLOCK_OFF + + (size_t)i * CLEARSIGN_IDENTITY_SERIALIZED_LEN; + id->present = read_u8(p + 0) != 0; + id->key_id = read_u8(p + 1); + memcpy(id->pubkey, p + 2, sizeof(id->pubkey)); + memcpy(id->alias, p + 35, sizeof(id->alias)); + id->alias[sizeof(id->alias) - 1] = + '\0'; // never trust flash to be NUL-term + id->icon_w = read_u8(p + 67); + id->icon_h = read_u8(p + 68); + id->icon_len = read_u16_le(p + 69); + if (id->icon_len > CLEARSIGN_ICON_MAX) + id->icon_len = 0; // corrupt => no icon + memcpy(id->icon, p + 71, sizeof(id->icon)); + } +} + void storage_readCacheV1(Cache* cache, const char* ptr, size_t len) { if (len < 65 + 10) return; cache->root_seed_cache_status = read_u8(ptr); @@ -1148,12 +1244,25 @@ void storage_writeV17(char* flash, size_t len, const ConfigFlash* src) { storage_writeStorageV17(flash + 44, 852, &src->storage); } +void storage_readV18(ConfigFlash* dst, const char* flash, size_t len) { + if (len < 1024) return; + storage_readMeta(&dst->meta, flash, 44); + storage_readStorageV18(&dst->storage, flash + 44, 852); +} + +void storage_writeV18(char* flash, size_t len, const ConfigFlash* src) { + if (len < 1024) return; + storage_writeMeta(flash, 44, &src->meta); + storage_writeStorageV18(flash + 44, 852, &src->storage); +} + StorageUpdateStatus storage_fromFlash(SessionState* ss, ConfigFlash* dst, const char* flash) { memzero(dst, sizeof(*dst)); // Load config values from active config node. - enum StorageVersion version = version_from_int(read_u32_le(flash + 44)); + uint32_t raw_version = read_u32_le(flash + 44); + enum StorageVersion version = version_from_int(raw_version); switch (version) { case StorageVersion_1: @@ -1199,9 +1308,54 @@ StorageUpdateStatus storage_fromFlash(SessionState* ss, ConfigFlash* dst, dst->storage.version = STORAGE_VERSION; return dst->storage.version == version ? SUS_Valid : SUS_Updated; case StorageVersion_17: + // Migrate up: the V17 reader leaves clearsign_identities zeroed (the + // memzero(dst) at the top => present=false), so no data loss. Stamping + // STORAGE_VERSION (18) makes this SUS_Updated, and the re-commit writes + // the V18 layout (empty identities block). storage_readV17(dst, flash, STORAGE_SECTOR_LEN); dst->storage.version = STORAGE_VERSION; return dst->storage.version == version ? SUS_Valid : SUS_Updated; + case StorageVersion_18: + storage_readV18(dst, flash, STORAGE_SECTOR_LEN); + dst->storage.version = STORAGE_VERSION; + return dst->storage.version == version ? SUS_Valid : SUS_Updated; + + case StorageVersion_BTC_ONLY: +#if BITCOIN_ONLY + { + // Our own bitcoin-only wallet. The stored wire version is the multi-chain + // storage version plus the band base, so recover the underlying layout + // version and load it through the normal migration chain. Exact-matching + // STORAGE_VERSION_BTC_ONLY here would lock every existing bitcoin-only + // wallet out of its own firmware on the next STORAGE_VERSION bump. + uint32_t underlying = raw_version - STORAGE_VERSION_BTC_ONLY_BASE; + if (underlying > (uint32_t)STORAGE_VERSION) { + // A newer bitcoin-only wallet than this firmware understands: refuse + // rather than wipe, so a firmware downgrade never destroys it. + return SUS_BitcoinOnlyLocked; + } + // Read via the reader matching the underlying version (same mapping as + // the multi-chain path above), then keep the band stamp so multi-chain + // firmware still refuses it. + if (underlying <= 15) { + storage_readV11(dst, flash, STORAGE_SECTOR_LEN); + } else if (underlying == 16) { + storage_readV16(dst, flash, STORAGE_SECTOR_LEN); + } else if (underlying == 17) { + storage_readV17(dst, flash, STORAGE_SECTOR_LEN); + } else { + storage_readV18(dst, flash, STORAGE_SECTOR_LEN); + } + dst->storage.version = STORAGE_VERSION_BTC_ONLY; + return (underlying == (uint32_t)STORAGE_VERSION) ? SUS_Valid + : SUS_Updated; + } +#else + // Written by bitcoin-only firmware: refuse to load. The wallet stays + // intact in flash (reflash bitcoin-only firmware to recover it); using + // multi-chain firmware requires an explicit wipe. + return SUS_BitcoinOnlyLocked; +#endif case StorageVersion_NONE: return SUS_Invalid; @@ -1340,6 +1494,13 @@ void storage_init(void) { // that it's available on next boot without conversion. storage_commit(); break; + case SUS_BitcoinOnlyLocked: + // Bitcoin-only wallet in flash: act as an uninitialized, locked device. + // Do NOT commit -- flash stays untouched so reflashing bitcoin-only + // firmware recovers the wallet; leaving requires an explicit wipe. + btc_only_locked = true; + storage_reset(); + break; } if (!storage_hasPin()) { @@ -1386,6 +1547,9 @@ void storage_wipe(void) { flash_erase_word(FLASH_STORAGE1); flash_erase_word(FLASH_STORAGE2); flash_erase_word(FLASH_STORAGE3); + + // The bitcoin-only wallet (if any) is gone; the device may be used freely. + btc_only_locked = false; } void storage_clearKeys(void) { @@ -1460,9 +1624,17 @@ pintest_t session_clear_impl(SessionState* ss, Storage* storage, } void storage_commit(void) { + // Never overwrite a bitcoin-only wallet from multi-chain firmware; the + // only way out is storage_wipe() (which clears the lock). This is the + // backstop behind the per-handler checks. + if (btc_only_locked) return; + // Temporary storage for marshalling secrets in & out of flash. - // Size of v17 storage layout (2525 bytes) + size of meta (44 bytes) + 1 - static char flash_temp[2570]; + // V18 storage layout = V17 (2525 bytes) + persistent identities block + // (PERSISTENT_IDENTITY_COUNT * CLEARSIGN_IDENTITY_SERIALIZED_LEN = 2*455 = + // 910) = 3435; + meta (44) = 3479. Rounded up to a multiple of 4 (the CRC + // below iterates uint32_t words) => 3480 (1 byte of slack). + static char flash_temp[3480]; memzero(flash_temp, sizeof(flash_temp)); @@ -1472,7 +1644,7 @@ void storage_commit(void) { // commit what was in storage->encrypted_sec } - storage_writeV17(flash_temp, sizeof(flash_temp), &shadow_config); + storage_writeV18(flash_temp, sizeof(flash_temp), &shadow_config); memcpy(&shadow_config, STORAGE_MAGIC_STR, STORAGE_MAGIC_LEN); @@ -1624,6 +1796,10 @@ void storage_loadDevice(LoadDevice* msg) { memset(&session.seed, 0, sizeof(session.seed)); } + if (msg->has_node || msg->has_mnemonic) { + storage_stampBitcoinOnlySeed(); + } + if (msg->has_language) { storage_setLanguage(msg->language); } @@ -1657,6 +1833,45 @@ const char* storage_getLabel(void) { return shadow_config.storage.pub.label; } +// ── Persistent clear-sign identities (V18) ─────────────────────────────── + +int storage_clearsignIdentityCount(void) { return PERSISTENT_IDENTITY_COUNT; } + +const ClearsignIdentity* storage_getClearsignIdentity(int slot) { + if (slot < 0 || slot >= PERSISTENT_IDENTITY_COUNT) return NULL; + const ClearsignIdentity* id = + &shadow_config.storage.pub.clearsign_identities[slot]; + return id->present ? id : NULL; +} + +// Write an identity to a persistent slot and commit. Reuses the slot already +// holding this pubkey (re-load with a new icon/alias), else the first free +// slot. Returns false if all slots are taken by other identities (caller keeps +// the RAM-only signer working — persistence just didn't happen). +bool storage_upsertClearsignIdentity(const ClearsignIdentity* id) { + if (!id) return false; + int free_slot = -1; + int target = -1; + for (int i = 0; i < PERSISTENT_IDENTITY_COUNT; i++) { + const ClearsignIdentity* cur = + &shadow_config.storage.pub.clearsign_identities[i]; + if (cur->present && memcmp(cur->pubkey, id->pubkey, 33) == 0) { + target = i; + break; + } + if (!cur->present && free_slot < 0) free_slot = i; + } + if (target < 0) target = free_slot; + if (target < 0) return false; // no room + + ClearsignIdentity* dst = + &shadow_config.storage.pub.clearsign_identities[target]; + memcpy(dst, id, sizeof(*dst)); + dst->present = true; + storage_commit(); + return true; +} + void storage_setLanguage(const char* lang) { if (!lang) { return; @@ -1866,6 +2081,34 @@ const uint8_t* storage_getSeed(const ConfigFlash* cfg, bool usePassphrase) { return NULL; } +/* ── Zcash storage-scoped wrappers ─────────────────────────────────── + * + * ZIP-32 Orchard derives keys directly from the raw 64-byte BIP-39 seed + * (not the BIP-32 master node). Rather than expose a generic + * "give me the seed" function, storage owns the seed access and only + * returns derived material — Orchard keys or the 32-byte fingerprint. + * The seed pointer never leaves this translation unit. + */ + +#if ZCASH_PRIVACY +bool storage_zcashOrchardKeys(uint32_t account, bool usePassphrase, + ZcashOrchardKeys* keys_out) { + if (!keys_out) return false; + const uint8_t* seed = storage_getSeed(&shadow_config, usePassphrase); + if (!seed) return false; + animating_progress_handler(_("Deriving Zcash"), 250); + return zcash_derive_orchard_keys(seed, 64, account, keys_out); +} + +bool storage_zcashSeedFingerprint(bool usePassphrase, + uint8_t fingerprint_out[32]) { + if (!fingerprint_out) return false; + const uint8_t* seed = storage_getSeed(&shadow_config, usePassphrase); + if (!seed) return false; + return zcash_calculate_seed_fingerprint(seed, 64, fingerprint_out); +} +#endif + bool storage_getRootNode(const char* curve, bool usePassphrase, HDNode* node) { // if storage has node, decrypt and use it if (shadow_config.storage.pub.has_node && @@ -1994,6 +2237,7 @@ void storage_setMnemonicFromWords(const char (*words)[12], shadow_config.storage.pub.has_mnemonic = true; shadow_config.storage.has_sec = true; + storage_stampBitcoinOnlySeed(); storage_compute_u2froot(&session, shadow_config.storage.sec.mnemonic, &shadow_config.storage.pub.u2froot); @@ -2011,6 +2255,7 @@ void storage_setMnemonic(const char* m) { #endif shadow_config.storage.pub.has_mnemonic = true; shadow_config.storage.has_sec = true; + storage_stampBitcoinOnlySeed(); storage_compute_u2froot(&session, shadow_config.storage.sec.mnemonic, &shadow_config.storage.pub.u2froot); diff --git a/lib/firmware/storage.h b/lib/firmware/storage.h index 10b84217b..220afa493 100644 --- a/lib/firmware/storage.h +++ b/lib/firmware/storage.h @@ -32,6 +32,31 @@ #define V16_ENCSEC_SIZE 512 // for reading old encrypted sec size #define V17_ENCSEC_SIZE 1024 +/* Persistent clear-sign identities (the "KeepKey + identity" trust anchors). + * A loaded signer whose LoadClearsignSigner carried persist=true is written to + * flash here so it survives reboot; RAM-only signers (signed_metadata.c) are + * unaffected. WipeDevice clears these along with the rest of storage. + * pubkey : 33-byte compressed secp256k1 (matches signed_metadata slots) + * alias : METADATA_ALIAS_MAX_LEN(31)+1, printable [A-Za-z0-9 _-] + * icon : 1bpp mono row-major bitmap, <= CLEARSIGN_ICON_MAX bytes, + * icon_len==0 => text-only identity (no logo) + * Serialized size is fixed (CLEARSIGN_IDENTITY_SERIALIZED_LEN) — appended after + * encrypted_sec in the V18 storage layout; never reorder existing fields. */ +#define CLEARSIGN_ICON_MAX 384 +#define CLEARSIGN_IDENTITY_ALIAS_SIZE 32 /* METADATA_ALIAS_MAX_LEN(31) + 1 */ +#define PERSISTENT_IDENTITY_COUNT 2 +typedef struct _ClearsignIdentity { + bool present; + uint8_t key_id; // the signer slot (1..METADATA_MAX_KEYS-1) this identity + // reloads into; the per-tx blob's key_id selects it + uint8_t pubkey[33]; + char alias[CLEARSIGN_IDENTITY_ALIAS_SIZE]; + uint8_t icon_w; + uint8_t icon_h; + uint16_t icon_len; + uint8_t icon[CLEARSIGN_ICON_MAX]; +} ClearsignIdentity; + typedef struct _authBlockType { authType authData[AUTHDATA_SIZE]; // 450 uint8_t reserved[512 - sizeof(authType) * AUTHDATA_SIZE]; // 62 @@ -70,6 +95,9 @@ typedef struct _Storage { bool authdata_encrypted; uint8_t random_salt[32]; uint8_t authdata_fingerprint[32]; + /* V18: persistent clear-sign identities. Zero-initialized (present=false) + * for wallets migrated up from V17 — no data loss. */ + ClearsignIdentity clearsign_identities[PERSISTENT_IDENTITY_COUNT]; } pub; bool has_sec; @@ -181,10 +209,23 @@ pintest_t session_clear_impl(SessionState* ss, Storage* storage, /// \returns NULL on error, otherwise \returns the private seed. const uint8_t* storage_getSeed(const ConfigFlash* cfg, bool usePassphrase); +/// \brief Number of persistent clear-sign identity slots. +int storage_clearsignIdentityCount(void); + +/// \brief The persistent clear-sign identity in `slot`, or NULL if empty/out +/// of range. Pointer into shadow storage — valid until the next commit. +const ClearsignIdentity* storage_getClearsignIdentity(int slot); + +/// \brief Persist a clear-sign identity (reuse its pubkey's slot, else the +/// first free one) and commit. Returns false if all slots are occupied +/// by other identities. +bool storage_upsertClearsignIdentity(const ClearsignIdentity* id); + typedef enum { SUS_Invalid, SUS_Valid, SUS_Updated, + SUS_BitcoinOnlyLocked, // written by bitcoin-only firmware; refuse to load } StorageUpdateStatus; /// \brief Copy configuration from storage partition in flash memory to shadow @@ -203,8 +244,10 @@ void storage_readV2(SessionState* ss, ConfigFlash* dst, const char* flash, size_t len); void storage_readV11(ConfigFlash* dst, const char* flash, size_t len); void storage_readV16(ConfigFlash* dst, const char* flash, size_t len); +void storage_readV18(ConfigFlash* dst, const char* flash, size_t len); void storage_writeV11(char* flash, size_t len, const ConfigFlash* src); void storage_writeV16(char* flash, size_t len, const ConfigFlash* src); +void storage_writeV18(char* flash, size_t len, const ConfigFlash* src); void storage_readMeta(Metadata* meta, const char* ptr, size_t len); void storage_readPolicyV1(PolicyType* policy, const char* ptr, size_t len); diff --git a/lib/firmware/storage_versions.inc b/lib/firmware/storage_versions.inc index a2e6eda30..a6c15e4ec 100644 --- a/lib/firmware/storage_versions.inc +++ b/lib/firmware/storage_versions.inc @@ -22,7 +22,8 @@ STORAGE_VERSION_ENTRY(13) STORAGE_VERSION_ENTRY(14) STORAGE_VERSION_ENTRY(15) STORAGE_VERSION_ENTRY(16) -STORAGE_VERSION_LAST(17) +STORAGE_VERSION_ENTRY(17) +STORAGE_VERSION_LAST(18) #undef STORAGE_VERSION_ENTRY diff --git a/lib/firmware/tendermint.c b/lib/firmware/tendermint.c index 60d50a281..5d10bb23c 100644 --- a/lib/firmware/tendermint.c +++ b/lib/firmware/tendermint.c @@ -6,6 +6,7 @@ #include #include +#include static int convert_bits(uint8_t* out, size_t* outlen, int outbits, const uint8_t* in, size_t inlen, int inbits, int pad) { @@ -64,6 +65,47 @@ bool tendermint_getAddress(const HDNode* node, const char* prefix, BECH32_ENCODING_BECH32) == 1; } +// Allow lowercase alpha, digits, and the punctuation used in Cosmos-style +// asset identifiers (e.g. "eth.eth", "btc/btc", cross-chain synthetic +// prefixes). Rejects anything that needs JSON escaping (backslash, quote). +bool tendermint_isValidDenom(const char* denom) { + if (!denom || !denom[0]) return false; + for (size_t i = 0; denom[i]; i++) { + char c = denom[i]; + if (!((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '.' || + c == '/' || c == '-')) { + return false; + } + } + return true; +} + +// Deposit assets share the denom grammar but are conventionally uppercase +// (e.g. ETH.USDT-0XDAC1...); allow both cases, digits, and . / - only. +bool tendermint_isValidAsset(const char* asset) { + if (!asset || !asset[0]) return false; + for (size_t i = 0; asset[i]; i++) { + char c = asset[i]; + if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || c == '.' || c == '/' || c == '-')) { + return false; + } + } + return true; +} + +// Deposit signer is host-supplied; require a valid bech32 address with the +// expected HRP before it is displayed or signed. +bool tendermint_isValidSigner(const char* signer, const char* hrp) { + size_t decoded_len; + char decoded_hrp[45]; + uint8_t decoded[38]; + if (!signer || !bech32_decode(decoded_hrp, decoded, &decoded_len, signer)) { + return false; + } + return 0 == strcmp(decoded_hrp, hrp); +} + void tendermint_sha256UpdateEscaped(SHA256_CTX* ctx, const char* s, size_t len) { for (size_t i = 0; i != len; i++) { diff --git a/lib/firmware/thorchain.c b/lib/firmware/thorchain.c index 92b075d4f..48d396c05 100644 --- a/lib/firmware/thorchain.c +++ b/lib/firmware/thorchain.c @@ -20,6 +20,7 @@ #include "keepkey/firmware/thorchain.h" #include "keepkey/board/confirm_sm.h" #include "keepkey/board/util.h" +#include "keepkey/firmware/app_confirm.h" #include "keepkey/firmware/home_sm.h" #include "keepkey/firmware/storage.h" #include "keepkey/firmware/tendermint.h" @@ -29,8 +30,17 @@ #include "trezor/crypto/segwit_addr.h" #include +#include #include +bool thorchain_isValidDenom(const char* denom) { + return tendermint_isValidDenom(denom); +} + +bool thorchain_isValidAsset(const char* asset) { + return tendermint_isValidAsset(asset); +} + static CONFIDENTIAL HDNode node; static SHA256_CTX ctx; static bool initialized; @@ -38,6 +48,10 @@ static uint32_t msgs_remaining; static ThorchainSignTx msg; static bool testnet; +bool thorchain_isValidSigner(const char* signer) { + return tendermint_isValidSigner(signer, testnet ? "tthor" : "thor"); +} + const ThorchainSignTx* thorchain_getThorchainSignTx(void) { return &msg; } bool thorchain_signTxInit(const HDNode* _node, const ThorchainSignTx* _msg) { @@ -95,7 +109,7 @@ bool thorchain_signTxInit(const HDNode* _node, const ThorchainSignTx* _msg) { } bool thorchain_signTxUpdateMsgSend(const uint64_t amount, - const char* to_address) { + const char* to_address, const char* denom) { const char mainnetp[] = "thor"; const char testnetp[] = "tthor"; const char* pfix; @@ -119,15 +133,26 @@ bool thorchain_signTxUpdateMsgSend(const uint64_t amount, return false; } + // Default to "rune" for backward compatibility; validate all non-default + // denoms + const char* coin_denom = (denom && denom[0]) ? denom : "rune"; + if (!thorchain_isValidDenom(coin_denom)) { + return false; + } + bool success = true; const char* const prelude = "{\"type\":\"thorchain/MsgSend\",\"value\":{"; sha256_Update(&ctx, (uint8_t*)prelude, strlen(prelude)); - // 21 + ^20 + 19 = ^60 + // Write amount prefix: 21 + ^20 = ^41 success &= tendermint_snprintf( &ctx, buffer, sizeof(buffer), - "\"amount\":[{\"amount\":\"%" PRIu64 "\",\"denom\":\"rune\"}]", amount); + "\"amount\":[{\"amount\":\"%" PRIu64 "\",\"denom\":\"", amount); + // Use escaping as defense-in-depth; valid denoms have no escapable chars + tendermint_sha256UpdateEscaped(&ctx, coin_denom, strlen(coin_denom)); + // Close coins array: 3 bytes + sha256_Update(&ctx, (uint8_t*)"\"}]", 3); // 17 + 45 + 1 = 63 success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), @@ -144,6 +169,13 @@ bool thorchain_signTxUpdateMsgSend(const uint64_t amount, bool thorchain_signTxUpdateMsgDeposit(const ThorchainMsgDeposit* depmsg) { char buffer[64 + 1]; + // Defended here too (not just by the FSM caller) so this signing path is + // safe even if called directly or reused elsewhere later. + if (!thorchain_isValidAsset(depmsg->asset) || + !thorchain_isValidSigner(depmsg->signer)) { + return false; + } + bool success = true; const char* const prelude = "{\"type\":\"thorchain/MsgDeposit\",\"value\":{"; @@ -154,9 +186,11 @@ bool thorchain_signTxUpdateMsgDeposit(const ThorchainMsgDeposit* depmsg) { "\"coins\":[{\"amount\":\"%" PRIu64 "\"", depmsg->amount); - // 10 + ^20 + 3 = ^33 - success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), - ",\"asset\":\"%s\"}]", depmsg->asset); + // Use escaping as defense-in-depth; valid assets have no escapable chars + const char* const asset_prefix = ",\"asset\":\""; + sha256_Update(&ctx, (uint8_t*)asset_prefix, strlen(asset_prefix)); + tendermint_sha256UpdateEscaped(&ctx, depmsg->asset, strlen(depmsg->asset)); + sha256_Update(&ctx, (uint8_t*)"\"}]", 3); // const char* const memo_prefix = ",\"memo\":\""; @@ -199,103 +233,206 @@ void thorchain_signAbort(void) { memzero(&node, sizeof(node)); } +/* Page the COMPLETE raw memo so nothing is truncated behind confirm()'s body + * budget. THORChain memos are ASCII; a non-printable byte gets a hex page so + * even a malformed memo is fully disclosed rather than hidden. Shared with the + * MAYA path (mayachain memos use the same grammar) and the native signing + * handlers, which page this as the authoritative disclosure after any + * best-effort structured summary. */ +bool thorchain_confirm_full_memo(const char* title, const char* memo, + size_t len) { + return confirm_bytes(ButtonRequestType_ButtonRequest_ConfirmOutput, title, + (const uint8_t*)memo, len); +} + bool thorchain_parseConfirmMemo(const char* swapStr, size_t size) { /* Input: swapStr is candidate thorchain data size is the size of swapStr (<= 256) Memos should be of the form: - transaction:chain.ticker-id:destination:limit + transaction:chain.ticker-id:destination:limit:affiliate:fee_bps ^^^^^^^^^^^^^^----------asset - So, swap USDT to dest address 0x41e55..., limit 420 - SWAP:ETH.USDT-0xdac17f958d2ee523a2206206994597c13d831ec7:0x41e5560054824ea6b0732e656e3ad64e20e94e45:420 + So, swap USDT to dest address 0x41e55..., limit 420, affiliate "kk" + skimming 75 basis points: + SWAP:ETH.USDT-0xdac17f958d2ee523a2206206994597c13d831ec7:0x41e5560054824ea6b0732e656e3ad64e20e94e45:420:kk:75 Swap transactions can be indicated by "SWAP" or "s" or "=" + + Fields are split on ':' PRESERVING empty fields so a blank field (e.g. + an empty limit in "=:ETH.ETH:0xdest::kk:75") can never shift a later + field (e.g. the affiliate) into an earlier display slot. */ - char* parseTokPtrs[7] = {NULL, NULL, NULL, NULL, - NULL, NULL, NULL}; // we can parse up to 7 tokens - char* tok; - char memoBuf[256]; - uint16_t ctr; + /* Up to 9 fields for a DEX-aggregator swap + * (SWAP:ASSET:DEST:LIM:AFFILIATE:FEE:AGGREGATOR:FINALTOKEN:MINOUT); the 10th + * slot lets us detect (and reject) a memo with more fields than any known + * grammar rather than silently merging the tail into a displayed field. */ + char* fields[10] = {NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL}; + /* Memos are documented/accepted up to 256 bytes; memoBuf reserves one + * extra byte so a full 256-byte memo still leaves a guaranteed NUL + * terminator, instead of the copy silently dropping its last byte. */ + enum { MEMO_MAX = 256 }; + char memoBuf[MEMO_MAX + 1]; + size_t nfields, i; + char *chain, *asset; // check if memo data is recognized - if (size > sizeof(memoBuf)) return false; + if (size > MEMO_MAX) return false; memzero(memoBuf, sizeof(memoBuf)); - strlcpy(memoBuf, swapStr, size); - memoBuf[255] = '\0'; // ensure null termination - tok = strtok(memoBuf, ":"); - - // get transaction and asset - for (ctr = 0; ctr < 3; ctr++) { - if (tok != NULL) { - parseTokPtrs[ctr] = tok; - tok = strtok(NULL, ":."); - } else { - break; + /* size is a byte count, not necessarily including a NUL: the BTC + * OP_RETURN caller passes raw memo bytes with no terminator. strlcpy + * would copy only size-1 bytes and silently drop the memo's last + * character (turning an affiliate fee of "75" bps into "7"). Copy the + * bytes exactly (size <= MEMO_MAX < sizeof(memoBuf), so this never + * overflows and always leaves at least one zeroed terminator byte); + * the zeroed buffer provides termination. */ + memcpy(memoBuf, swapStr, size); + + // Split on ':', keeping empty fields + nfields = 0; + fields[nfields++] = memoBuf; + for (i = 0; memoBuf[i] != '\0' && nfields < 10; i++) { + if (memoBuf[i] == ':') { + memoBuf[i] = '\0'; + fields[nfields++] = &memoBuf[i + 1]; } } - if (ctr != 3) { - // Must have three tokens at this point: transaction, chain, asset. If - // not, just confirm data + if (nfields < 2) { + // Must have at least transaction and chain.asset. If not, just confirm + // data + return false; + } + + // Split chain.asset at the first '.' + chain = fields[1]; + asset = strchr(chain, '.'); + if (asset == NULL) { + // No chain.asset pair; not recognizable thorchain data, just confirm data return false; } + *asset = '\0'; + asset++; // Check for swap - if (strncmp(parseTokPtrs[0], "SWAP", 4) == 0 || *parseTokPtrs[0] == 's' || - *parseTokPtrs[0] == '=') { - // This is a swap, set up destination and limit - // This is the dest, may be blank which means swap to self - parseTokPtrs[3] = "self"; - parseTokPtrs[4] = "none"; - if (tok != NULL) { - if ((uint32_t)(tok - (parseTokPtrs[2] + strlen(parseTokPtrs[2]))) == 1) { - // has dest address - parseTokPtrs[3] = tok; - tok = strtok(NULL, ":"); - } - if (tok != NULL) { - // has limit - parseTokPtrs[4] = tok; + if (strncmp(fields[0], "SWAP", 4) == 0 || *fields[0] == 's' || + *fields[0] == '=') { + /* Aggregator outbound memo: field 8 is MinAmountOut|OUTBOUND_MEMO, and + * everything after '|' is forwarded to the outbound contract. That suffix + * can itself contain ':' which our ':'-split would scatter (or overflow + * past field 9), so a single confirm could truncate it. When a '|' is + * present, skip structured field display and page the COMPLETE raw memo so + * every signed byte is shown. */ + if (memchr(swapStr, '|', size) != NULL) { + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Thorchain swap", "Confirm swap asset %s\n on chain %s", + asset, chain)) { + return false; } + return thorchain_confirm_full_memo("Swap memo", swapStr, size); + } + // This is a swap, set up destination and limit + // The dest may be blank which means swap to self + const char* dest = + (nfields > 2 && fields[2][0] != '\0') ? fields[2] : "self"; + const char* limit = + (nfields > 3 && fields[3][0] != '\0') ? fields[3] : "none"; + const char* affiliate = + (nfields > 4 && fields[4][0] != '\0') ? fields[4] : NULL; + const char* fee_bps = + (nfields > 5 && fields[5][0] != '\0') ? fields[5] : "unspecified"; + /* DEX-aggregator swap-out fields — all router-executed, so all displayed. + */ + const char* agg_addr = + (nfields > 6 && fields[6][0] != '\0') ? fields[6] : NULL; + const char* final_token = + (nfields > 7 && fields[7][0] != '\0') ? fields[7] : NULL; + const char* min_out = + (nfields > 8 && fields[8][0] != '\0') ? fields[8] : NULL; + + /* Refuse only genuinely-unknown structure — more fields than any THORChain + * swap grammar defines (>9), which we cannot label and must not hide. */ + if (nfields > 9) { + return false; } if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, - "Thorchain swap", "Confirm swap asset %s\n on chain %s", - parseTokPtrs[2], parseTokPtrs[1])) { + "Thorchain swap", "Confirm swap asset %s\n on chain %s", asset, + chain)) { return false; } if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, - "Thorchain swap", "Confirm to %s", parseTokPtrs[3])) { + "Thorchain swap", "Confirm to %s", dest)) { return false; } if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, - "Thorchain swap", "Confirm limit %s", parseTokPtrs[4])) { + "Thorchain swap", "Confirm limit %s", limit)) { + return false; + } + // Never hide the affiliate fee skim from the user + if (affiliate != NULL) { + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Thorchain swap", "Affiliate fee %s bps to %s", fee_bps, + affiliate)) { + return false; + } + } + // DEX-aggregator routing: the router forwards the output through this + // aggregator to a final token, so both must be visible. + if (agg_addr != NULL && + !confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Thorchain swap", "DEX aggregator %s", agg_addr)) { + return false; + } + if (final_token != NULL && + !confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Thorchain swap", "Final token %s", final_token)) { + return false; + } + if (min_out != NULL && + !confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Thorchain swap", "Min output %s", min_out)) { return false; } return true; } // Check for add liquidity - else if (strncmp(parseTokPtrs[0], "ADD", 3) == 0 || *parseTokPtrs[0] == 'a' || - *parseTokPtrs[0] == '+') { - if (tok != NULL) { - // add liquidity pool address - parseTokPtrs[3] = tok; + else if (strncmp(fields[0], "ADD", 3) == 0 || *fields[0] == 'a' || + *fields[0] == '+') { + // ADD:POOL:PAIREDADDR:AFFILIATE:FEE — paired address, affiliate and fee are + // all optional but router-executed, so none may be hidden. + const char* pool = (nfields > 2 && fields[2][0] != '\0') ? fields[2] : NULL; + const char* affiliate = + (nfields > 3 && fields[3][0] != '\0') ? fields[3] : NULL; + const char* fee_bps = + (nfields > 4 && fields[4][0] != '\0') ? fields[4] : "unspecified"; + + /* ADD grammar defines at most 5 fields; more than that is structure we + * cannot label and must not sign hidden, so refuse it. */ + if (nfields > 5) { + return false; } if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "Thorchain add liquidity", - "Confirm add asset %s\n on chain %s pool", parseTokPtrs[2], - parseTokPtrs[1])) { + "Confirm add asset %s\n on chain %s pool", asset, chain)) { return false; } - if (tok != NULL) { + if (pool != NULL) { + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Thorchain add liquidity", "Confirm to %s", pool)) { + return false; + } + } + // Never hide the affiliate fee skim from the user + if (affiliate != NULL) { if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, - "Thorchain add liquidity", "Confirm to %s", - parseTokPtrs[3])) { + "Thorchain add liquidity", "Affiliate fee %s bps to %s", + fee_bps, affiliate)) { return false; } } @@ -303,26 +440,40 @@ bool thorchain_parseConfirmMemo(const char* swapStr, size_t size) { } // Check for withdraw liquidity - else if (strncmp(parseTokPtrs[0], "WITHDRAW", 8) == 0 || - strncmp(parseTokPtrs[0], "wd", 2) == 0 || *parseTokPtrs[0] == '-') { - if (tok != NULL) { - // add liquidity pool address - parseTokPtrs[3] = tok; - } else { + else if (strncmp(fields[0], "WITHDRAW", 8) == 0 || + strncmp(fields[0], "wd", 2) == 0 || *fields[0] == '-') { + if (nfields < 3 || fields[2][0] == '\0') { return false; // malformed memo } + /* WD:POOL:BPS[:ASSET] — refuse only genuinely-unknown structure (>4 + * fields), mirroring the SWAP (>9) and ADD (>5) caps. */ + if (nfields > 4) { + return false; + } - float percent = (float)(atoi(parseTokPtrs[3])) / 100; + float percent = (float)(atoi(fields[2])) / 100; if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "Thorchain withdraw liquidity", "Confirm withdraw %3.2f%% of asset %s on chain %s", percent, - parseTokPtrs[2], parseTokPtrs[1])) { + asset, chain)) { return false; } + /* Field 4 is the ASYMMETRIC-withdrawal asset selector: WD:POOL:BPS:ASSET + * pays the whole withdrawal out single-sided in ASSET instead of the + * symmetric split. It directs money, so it must never sign unseen — + * otherwise the screens for the asymmetric form are identical to the + * symmetric one. */ + if (nfields > 3 && fields[3][0] != '\0') { + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Thorchain withdraw liquidity", + "Withdraw single-sided as %s", fields[3])) { + return false; + } + } return true; } else { // Just confirm whatever coin data if no thorchain intention data parsable return false; } -} \ No newline at end of file +} diff --git a/lib/firmware/tiny-json.c b/lib/firmware/tiny-json.c index c915eff58..80f0e9e21 100644 --- a/lib/firmware/tiny-json.c +++ b/lib/firmware/tiny-json.c @@ -33,7 +33,9 @@ // #include -int errno = 0; +/* Renamed from `errno` to avoid colliding with the libc macro on + * glibc/MinGW (where errno expands to (*_errno())). Write-only, never read. */ +int json_errno = 0; /** Structure to handle a heap of JSON properties. */ typedef struct jsonStaticPool_s { @@ -73,7 +75,7 @@ static bool isEndOfPrimitive(char ch); json_t const* json_createWithPool(char* str, jsonPool_t* pool) { char* ptr = goBlank(str); if (!ptr || (*ptr != '{' && *ptr != '[')) { - errno = -1; + json_errno = -1; return 0; } json_t* obj = pool->init(pool); @@ -82,7 +84,7 @@ json_t const* json_createWithPool(char* str, jsonPool_t* pool) { obj->u.c.child = 0; ptr = objValue(ptr, obj, pool); if (!ptr) { - errno = -2; + json_errno = -2; return 0; } return obj; diff --git a/lib/firmware/transaction.c b/lib/firmware/transaction.c index 1405401a7..9d30f1acd 100644 --- a/lib/firmware/transaction.c +++ b/lib/firmware/transaction.c @@ -238,6 +238,7 @@ int compile_output(const CoinType* coin, const HDNode* root, TxOutputType* in, } } else { // is this thorchain data? +#if !BITCOIN_ONLY if (!thorchain_parseConfirmMemo((const char*)in->op_return_data.bytes, (size_t)in->op_return_data.size)) { if (!confirm_data(ButtonRequestType_ButtonRequest_ConfirmOutput, @@ -246,6 +247,14 @@ int compile_output(const CoinType* coin, const HDNode* root, TxOutputType* in, return -1; // user aborted } } +#else + // bitcoin-only: no THORChain memo decoding, confirm raw OP_RETURN + if (!confirm_data(ButtonRequestType_ButtonRequest_ConfirmOutput, + _("Confirm OP_RETURN"), in->op_return_data.bytes, + in->op_return_data.size)) { + return -1; // user aborted + } +#endif } } uint32_t r = 0; diff --git a/lib/firmware/tron.c b/lib/firmware/tron.c index b8d3ec618..38fe3d7d6 100644 --- a/lib/firmware/tron.c +++ b/lib/firmware/tron.c @@ -21,11 +21,13 @@ #include "keepkey/crypto/curves.h" #include "trezor/crypto/base58.h" +#include "trezor/crypto/bignum.h" #include "trezor/crypto/ecdsa.h" #include "trezor/crypto/memzero.h" #include "trezor/crypto/secp256k1.h" #include "trezor/crypto/sha3.h" +#include #include #define TRON_ADDRESS_PREFIX 0x41 // Mainnet addresses start with 'T' @@ -80,6 +82,363 @@ void tron_formatAmount(char* buf, size_t len, uint64_t amount) { bn_format(&val, NULL, " TRX", TRON_DECIMALS, 0, false, buf, len); } +bool tron_addressFromBytes(const uint8_t addr[TRON_RAW_ADDRESS_SIZE], char* out, + size_t out_len) { + return base58_encode_check(addr, TRON_RAW_ADDRESS_SIZE, HASHER_SHA2D, out, + out_len); +} + +bool tron_formatTrc20Amount(const uint8_t amount_be[32], char* buf, + size_t len) { + bignum256 val; + bn_read_be(amount_be, &val); + return bn_format(&val, NULL, NULL, 0, 0, false, buf, len); +} + +/* ------------------------------------------------------------------ */ +/* raw_data protobuf parser */ +/* */ +/* The device signs sha256(raw_data), so display decisions are made */ +/* from these exact bytes. Minimal protobuf wire-format reader — */ +/* fail-closed: anything not fully understood ends TRON_TX_UNVERIFIED */ +/* ------------------------------------------------------------------ */ + +/* TRON protocol.Transaction.raw field numbers */ +#define TRON_RAW_REF_BLOCK_BYTES 1 +#define TRON_RAW_REF_BLOCK_NUM 3 +#define TRON_RAW_REF_BLOCK_HASH 4 +#define TRON_RAW_EXPIRATION 8 +#define TRON_RAW_DATA 10 /* memo */ +#define TRON_RAW_CONTRACT 11 +#define TRON_RAW_TIMESTAMP 14 +#define TRON_RAW_FEE_LIMIT 18 + +/* protocol.Transaction.Contract */ +#define TRON_CONTRACT_TYPE 1 +#define TRON_CONTRACT_PARAMETER 2 + +/* google.protobuf.Any */ +#define TRON_ANY_TYPE_URL 1 +#define TRON_ANY_VALUE 2 + +/* protocol.Transaction.Contract.ContractType enum values */ +#define TRON_CT_TRANSFER_CONTRACT 1 +#define TRON_CT_TRIGGER_SMART_CONTRACT 31 + +/* TRC-20 transfer(address,uint256) selector */ +static const uint8_t TRC20_TRANSFER_SELECTOR[4] = {0xa9, 0x05, 0x9c, 0xbb}; + +static bool pb_read_varint(const uint8_t* buf, size_t len, size_t* pos, + uint64_t* out) { + uint64_t val = 0; + for (unsigned shift = 0; shift < 64; shift += 7) { + if (*pos >= len) return false; + uint8_t b = buf[(*pos)++]; + uint8_t payload = b & 0x7f; + if (shift == 63 && payload > 1) { + /* The 10th byte can only contribute bit 63 to a 64-bit value + * (63 + 7 > 64); any payload bit above bit 0 here claims more + * precision than 64 bits hold. The shift below would silently + * drop those bits rather than reject them, letting a malformed + * key/length/amount/fee varint parse as if it were well-formed + * — reject instead of truncating. */ + return false; + } + val |= (uint64_t)payload << shift; + if (!(b & 0x80)) { + *out = val; + return true; + } + } + return false; /* varint too long / overflows 64 bits */ +} + +static bool pb_read_key(const uint8_t* buf, size_t len, size_t* pos, + uint32_t* field, uint8_t* wire) { + uint64_t key; + if (!pb_read_varint(buf, len, pos, &key)) return false; + *wire = (uint8_t)(key & 0x7); + if ((key >> 3) > UINT32_MAX) return false; + *field = (uint32_t)(key >> 3); + return *field != 0; +} + +static bool pb_read_bytes(const uint8_t* buf, size_t len, size_t* pos, + const uint8_t** out, size_t* out_len) { + uint64_t blen; + if (!pb_read_varint(buf, len, pos, &blen)) return false; + if (blen > len - *pos) return false; + *out = buf + *pos; + *out_len = (size_t)blen; + *pos += (size_t)blen; + return true; +} + +static bool pb_skip(const uint8_t* buf, size_t len, size_t* pos, uint8_t wire) { + uint64_t dummy; + const uint8_t* bp; + size_t bl; + switch (wire) { + case 0: /* varint */ + return pb_read_varint(buf, len, pos, &dummy); + case 1: /* fixed64 */ + if (len - *pos < 8) return false; + *pos += 8; + return true; + case 2: /* length-delimited */ + return pb_read_bytes(buf, len, pos, &bp, &bl); + case 5: /* fixed32 */ + if (len - *pos < 4) return false; + *pos += 4; + return true; + default: + return false; + } +} + +static bool tron_isRawAddress(const uint8_t* p, size_t len) { + return len == TRON_RAW_ADDRESS_SIZE && p[0] == TRON_ADDRESS_PREFIX; +} + +/* Parse protocol.TransferContract { owner_address=1, to_address=2, amount=3 } + */ +static bool tron_parseTransferContract(const uint8_t* buf, size_t len, + TronParsedTx* out) { + size_t pos = 0; + bool has_owner = false, has_to = false, has_amount = false; + while (pos < len) { + uint32_t field; + uint8_t wire; + if (!pb_read_key(buf, len, &pos, &field, &wire)) return false; + const uint8_t* bp; + size_t bl; + uint64_t v; + if (field == 1 && wire == 2) { + if (!pb_read_bytes(buf, len, &pos, &bp, &bl)) return false; + if (!tron_isRawAddress(bp, bl) || has_owner) return false; + memcpy(out->owner, bp, TRON_RAW_ADDRESS_SIZE); + has_owner = true; + } else if (field == 2 && wire == 2) { + if (!pb_read_bytes(buf, len, &pos, &bp, &bl)) return false; + if (!tron_isRawAddress(bp, bl) || has_to) return false; + memcpy(out->to, bp, TRON_RAW_ADDRESS_SIZE); + has_to = true; + } else if (field == 3 && wire == 0) { + if (!pb_read_varint(buf, len, &pos, &v) || has_amount) return false; + if (v > INT64_MAX) return false; + out->amount = v; + has_amount = true; + } else { + /* Unknown field in a value-moving payload: refuse to summarize. */ + return false; + } + } + return has_owner && has_to && has_amount; +} + +/* Parse protocol.TriggerSmartContract: + * owner_address=1, contract_address=2, call_value=3, data=4, + * call_token_value=5, token_id=6 + * Only a plain TRC-20 transfer(address,uint256) with zero call_value and + * no TRC-10 tokens attached is considered verified. */ +static bool tron_parseTriggerSmartContract(const uint8_t* buf, size_t len, + TronParsedTx* out) { + size_t pos = 0; + bool has_owner = false, has_contract = false, has_data = false; + const uint8_t* data = NULL; + size_t data_len = 0; + while (pos < len) { + uint32_t field; + uint8_t wire; + if (!pb_read_key(buf, len, &pos, &field, &wire)) return false; + const uint8_t* bp; + size_t bl; + uint64_t v; + if (field == 1 && wire == 2) { + if (!pb_read_bytes(buf, len, &pos, &bp, &bl)) return false; + if (!tron_isRawAddress(bp, bl) || has_owner) return false; + memcpy(out->owner, bp, TRON_RAW_ADDRESS_SIZE); + has_owner = true; + } else if (field == 2 && wire == 2) { + if (!pb_read_bytes(buf, len, &pos, &bp, &bl)) return false; + if (!tron_isRawAddress(bp, bl) || has_contract) return false; + memcpy(out->contract, bp, TRON_RAW_ADDRESS_SIZE); + has_contract = true; + } else if (field == 3 && wire == 0) { + /* call_value: transfer(address,uint256) is non-payable — any TRX + * attached to the call is something we can't explain to the user. */ + if (!pb_read_varint(buf, len, &pos, &v)) return false; + if (v != 0) return false; + } else if (field == 4 && wire == 2) { + if (!pb_read_bytes(buf, len, &pos, &data, &data_len) || has_data) + return false; + has_data = true; + } else { + /* token_id / call_token_value / anything else: refuse. */ + return false; + } + } + if (!has_owner || !has_contract || !has_data) return false; + + /* data must be exactly selector + address word + amount word */ + if (data_len != 4 + 32 + 32) return false; + if (memcmp(data, TRC20_TRANSFER_SELECTOR, 4) != 0) return false; + + /* Address word: 12 zero bytes then the 20-byte address. TRON tooling + * sometimes writes the 0x41 network prefix at byte 11; the TVM decodes + * only the low 160 bits, so accept 0x41 there and nothing else. */ + const uint8_t* word = data + 4; + for (int i = 0; i < 11; i++) { + if (word[i] != 0) return false; + } + if (word[11] != 0 && word[11] != TRON_ADDRESS_PREFIX) return false; + + out->to[0] = TRON_ADDRESS_PREFIX; + memcpy(out->to + 1, word + 12, 20); + memcpy(out->trc20_amount, data + 4 + 32, 32); + return true; +} + +/* Parse Contract { type=1, parameter=2 (Any) }; enum type and the Any + * type_url must agree, otherwise refuse. */ +static TronTxType tron_parseContract(const uint8_t* buf, size_t len, + TronParsedTx* out) { + size_t pos = 0; + uint64_t ctype = 0; + bool has_type = false; + const uint8_t* value = NULL; + size_t value_len = 0; + const uint8_t* type_url = NULL; + size_t type_url_len = 0; + + while (pos < len) { + uint32_t field; + uint8_t wire; + if (!pb_read_key(buf, len, &pos, &field, &wire)) return TRON_TX_UNVERIFIED; + if (field == TRON_CONTRACT_TYPE && wire == 0) { + if (!pb_read_varint(buf, len, &pos, &ctype) || has_type) + return TRON_TX_UNVERIFIED; + has_type = true; + } else if (field == TRON_CONTRACT_PARAMETER && wire == 2) { + const uint8_t* any; + size_t any_len; + if (!pb_read_bytes(buf, len, &pos, &any, &any_len) || value) + return TRON_TX_UNVERIFIED; + size_t apos = 0; + while (apos < any_len) { + uint32_t afield; + uint8_t awire; + if (!pb_read_key(any, any_len, &apos, &afield, &awire)) + return TRON_TX_UNVERIFIED; + if (afield == TRON_ANY_TYPE_URL && awire == 2) { + if (type_url || + !pb_read_bytes(any, any_len, &apos, &type_url, &type_url_len)) + return TRON_TX_UNVERIFIED; + } else if (afield == TRON_ANY_VALUE && awire == 2) { + if (value || !pb_read_bytes(any, any_len, &apos, &value, &value_len)) + return TRON_TX_UNVERIFIED; + } else { + return TRON_TX_UNVERIFIED; + } + } + if (!value) return TRON_TX_UNVERIFIED; + } else { + /* Permission_id (multisig), provider, ContractName, unknown: refuse. */ + return TRON_TX_UNVERIFIED; + } + } + if (!has_type || !value || !type_url) return TRON_TX_UNVERIFIED; + + /* type_url ends with "/protocol."; require agreement with enum */ + const char* expect_suffix; + if (ctype == TRON_CT_TRANSFER_CONTRACT) { + expect_suffix = "/protocol.TransferContract"; + } else if (ctype == TRON_CT_TRIGGER_SMART_CONTRACT) { + expect_suffix = "/protocol.TriggerSmartContract"; + } else { + return TRON_TX_UNVERIFIED; + } + size_t suffix_len = strlen(expect_suffix); + if (type_url_len < suffix_len || memcmp(type_url + type_url_len - suffix_len, + expect_suffix, suffix_len) != 0) { + return TRON_TX_UNVERIFIED; + } + + if (ctype == TRON_CT_TRANSFER_CONTRACT) { + return tron_parseTransferContract(value, value_len, out) + ? TRON_TX_TRANSFER + : TRON_TX_UNVERIFIED; + } + return tron_parseTriggerSmartContract(value, value_len, out) + ? TRON_TX_TRC20_TRANSFER + : TRON_TX_UNVERIFIED; +} + +TronTxType tron_parseRawTx(const uint8_t* raw, size_t len, TronParsedTx* out) { + memset(out, 0, sizeof(*out)); + if (!raw || len == 0) return TRON_TX_UNVERIFIED; + + size_t pos = 0; + const uint8_t* contract = NULL; + size_t contract_len = 0; + + while (pos < len) { + uint32_t field; + uint8_t wire; + if (!pb_read_key(raw, len, &pos, &field, &wire)) goto unverified; + switch (field) { + case TRON_RAW_REF_BLOCK_BYTES: + case TRON_RAW_REF_BLOCK_HASH: + if (wire != 2 || !pb_skip(raw, len, &pos, wire)) goto unverified; + break; + case TRON_RAW_REF_BLOCK_NUM: + case TRON_RAW_EXPIRATION: + case TRON_RAW_TIMESTAMP: + if (wire != 0 || !pb_skip(raw, len, &pos, wire)) goto unverified; + break; + case TRON_RAW_DATA: { + const uint8_t* bp; + size_t bl; + if (wire != 2 || out->memo || + !pb_read_bytes(raw, len, &pos, &bp, &bl) || bl > UINT16_MAX) + goto unverified; + out->memo = bp; + out->memo_len = (uint16_t)bl; + break; + } + case TRON_RAW_CONTRACT: + /* exactly one contract may be displayed truthfully */ + if (wire != 2 || contract || + !pb_read_bytes(raw, len, &pos, &contract, &contract_len)) + goto unverified; + break; + case TRON_RAW_FEE_LIMIT: { + uint64_t v; + if (wire != 0 || out->has_fee_limit || + !pb_read_varint(raw, len, &pos, &v) || v > INT64_MAX) + goto unverified; + out->fee_limit = v; + out->has_fee_limit = true; + break; + } + default: + /* auths, scripts, future fields: can change meaning — refuse. */ + goto unverified; + } + } + + if (!contract) goto unverified; + out->type = tron_parseContract(contract, contract_len, out); + if (out->type == TRON_TX_UNVERIFIED) goto unverified; + return out->type; + +unverified: + /* Preserve nothing from a failed parse except the classification. */ + memset(out, 0, sizeof(*out)); + out->type = TRON_TX_UNVERIFIED; + return TRON_TX_UNVERIFIED; +} + /** * Sign a TRON transaction with secp256k1 */ diff --git a/lib/firmware/zcash.c b/lib/firmware/zcash.c new file mode 100644 index 000000000..c84ef1e3b --- /dev/null +++ b/lib/firmware/zcash.c @@ -0,0 +1,1133 @@ +/* + * This file is part of the KeepKey project. + * + * Copyright (C) 2025 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. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include "keepkey/firmware/zcash.h" + +#include +#include + +#include "trezor/crypto/aes/aes.h" +#include "trezor/crypto/bignum.h" +#include "trezor/crypto/blake2b.h" +#include "trezor/crypto/hasher.h" +#include "trezor/crypto/memzero.h" +#include "trezor/crypto/pallas.h" +#include "trezor/crypto/pallas_sinsemilla.h" +#include "trezor/crypto/pallas_swu.h" +#include "trezor/crypto/redpallas.h" +#include "trezor/crypto/zcash_zip316.h" + +/* + * ZIP-32 Orchard key derivation. + * + * Master key: + * I = BLAKE2b-512("ZcashIP32Orchard", seed) + * sk = I[0..32], chain_code = I[32..64] + * + * Child derivation (hardened only): + * I = BLAKE2b-512("ZcashIP32Orchard", chain_code, + * 0x11 || sk || i_be) + * where 0x11 indicates hardened derivation with Orchard, + * and i_be is the 4-byte big-endian child index with the hardened bit set. + * + * From the spending key sk, subkeys are derived using PRF^expand: + * PRF^expand(sk, t) = BLAKE2b-512("Zcash_ExpandSeed", sk || t) + * + * ask = ToScalar(PRF^expand(sk, [0x06])) + * nk = ToBase(PRF^expand(sk, [0x07])) + * rivk = ToScalar(PRF^expand(sk, [0x08])) + * + * ToScalar: interpret 64 bytes as LE integer, reduce mod order + * ToBase: interpret 64 bytes as LE integer, reduce mod prime + */ + +/* + * BLAKE2b-512 with personalization "ZcashIP32Orchard" — master key only. + * Used for: I = BLAKE2b-512("ZcashIP32Orchard", seed) + * NOT used for child derivation (which uses PRF^expand). + */ +static void zip32_orchard_master(const uint8_t* seed, size_t seed_len, + uint8_t out[64]) { + BLAKE2B_CTX ctx; + blake2b_InitPersonal(&ctx, 64, "ZcashIP32Orchard", 16); + blake2b_Update(&ctx, seed, seed_len); + blake2b_Final(&ctx, out, 64); +} + +/* PRF^expand(sk, t) = BLAKE2b-512("Zcash_ExpandSeed", sk || t) */ +static void prf_expand(const uint8_t sk[32], const uint8_t* t, size_t t_len, + uint8_t out[64]) { + BLAKE2B_CTX ctx; + blake2b_InitPersonal(&ctx, 64, "Zcash_ExpandSeed", 16); + blake2b_Update(&ctx, sk, 32); + blake2b_Update(&ctx, t, t_len); + blake2b_Final(&ctx, out, 64); +} + +/* + * 2^256 mod q (Pallas scalar field order), little-endian. + * q = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001 + * R = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF992C350BE34205675B2B3E9CFFFFFFFD + * Verified: R + 3*q == 2^256. + */ +static const uint8_t two_256_mod_q[32] = { + 0xfd, 0xff, 0xff, 0xff, 0x9c, 0x3e, 0x2b, 0x5b, 0x67, 0x05, 0x42, + 0xe3, 0x0b, 0x35, 0x2c, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, +}; + +/* + * 2^256 mod p (Pallas base field prime), little-endian. + * p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001 + * R = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF992C350BE41914AD34786D38FFFFFFFD + * Verified: R + 3*p == 2^256. + */ +static const uint8_t two_256_mod_p[32] = { + 0xfd, 0xff, 0xff, 0xff, 0x38, 0x6d, 0x78, 0x34, 0xad, 0x14, 0x19, + 0xe4, 0x0b, 0x35, 0x2c, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, +}; + +/* + * ToScalar: reduce a 512-bit LE integer mod Pallas scalar order. + * + * Uses wide reduction matching the orchard crate's from_uniform_bytes: + * result = (lo + hi * 2^256) mod q + * where lo = input[0..31], hi = input[32..63] (little-endian). + */ +static void to_scalar(const uint8_t input[64], uint8_t output[32]) { + bignum256 lo, hi, t256, result; + + bn_read_le(input, &lo); + pallas_mod_q(&lo); + + bn_read_le(input + 32, &hi); + pallas_mod_q(&hi); + + bn_read_le(two_256_mod_q, &t256); + + /* result = hi * (2^256 mod q) mod q */ + bn_copy(&hi, &result); + pallas_mul_mod_q(&result, &t256); + + /* result = result + lo mod q */ + pallas_add_mod_q(&result, &lo); + + bn_write_le(&result, output); + + memzero(&lo, sizeof(lo)); + memzero(&hi, sizeof(hi)); + memzero(&result, sizeof(result)); +} + +/* + * ToBase: reduce a 512-bit LE integer mod Pallas base field prime. + * + * Uses wide reduction: + * result = (lo + hi * 2^256) mod p + * where lo = input[0..31], hi = input[32..63] (little-endian). + */ +static void to_base(const uint8_t input[64], uint8_t output[32]) { + bignum256 lo, hi, t256, result; + + bn_read_le(input, &lo); + pallas_mod_p(&lo); + + bn_read_le(input + 32, &hi); + pallas_mod_p(&hi); + + bn_read_le(two_256_mod_p, &t256); + + /* result = hi * (2^256 mod p) mod p */ + bn_copy(&hi, &result); + pallas_mul_mod_p(&result, &t256); + + /* result = result + lo mod p */ + bignum256 sum; + pallas_add_mod_p(&result, &lo, &sum); + bn_copy(&sum, &result); + memzero(&sum, sizeof(sum)); + + bn_write_le(&result, output); + + memzero(&lo, sizeof(lo)); + memzero(&hi, sizeof(hi)); + memzero(&result, sizeof(result)); +} + +/* Hardened child index */ +#define ZIP32_HARDENED 0x80000000 + +/* + * ZIP-32 Orchard diversifiers use FF1-AES256 over an 88-bit binary numeral + * string. Parameters are fixed by the Zcash protocol: + * + * radix = 2, minlen = maxlen = n = 88, tweak = "", rounds = 10 + * + * The input and output byte arrays are LEBS2OSP encodings of the 88-bit + * strings, but FF1's NUM/STR operations interpret each half in numeral-string + * order. Keep the bit-order conversion explicit to avoid silently turning this + * into a radix-256 construction, which would be a different permutation. + */ +#define ZCASH_FF1_BITS 88 +#define ZCASH_FF1_HALF_BITS 44 +#define ZCASH_FF1_MASK44 ((UINT64_C(1) << ZCASH_FF1_HALF_BITS) - 1) + +static uint8_t bit_get_le(const uint8_t* bytes, uint32_t bit) { + return (bytes[bit >> 3] >> (bit & 7)) & 1; +} + +static void bit_set_le(uint8_t* bytes, uint32_t bit, uint8_t value) { + if (value) { + bytes[bit >> 3] |= (uint8_t)(1u << (bit & 7)); + } +} + +static uint64_t ff1_bits_to_num(const uint8_t bits[11], uint32_t offset, + uint32_t len) { + uint64_t n = 0; + for (uint32_t i = 0; i < len; i++) { + n = (n << 1) | bit_get_le(bits, offset + i); + } + return n; +} + +static void ff1_num_to_bits(uint64_t n, uint8_t bits[11], uint32_t offset, + uint32_t len) { + for (uint32_t i = 0; i < len; i++) { + uint32_t shift = len - 1 - i; + bit_set_le(bits, offset + i, (uint8_t)((n >> shift) & 1)); + } +} + +static void ff1_store_be48(uint64_t n, uint8_t out[6]) { + for (int i = 5; i >= 0; i--) { + out[i] = (uint8_t)(n & 0xff); + n >>= 8; + } +} + +static bool aes256_encrypt_block(const aes_encrypt_ctx* ctx, + const uint8_t in[16], uint8_t out[16]) { + return aes_encrypt(in, out, ctx) == EXIT_SUCCESS; +} + +static bool ff1_round_y_mod_2_44(const aes_encrypt_ctx* ctx, uint8_t round, + uint64_t b, uint64_t* y_mod) { + static const uint8_t P[16] = { + 0x01, 0x02, 0x01, 0x00, 0x00, 0x02, 0x0a, 0x2c, + 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, + }; + + uint8_t q[16] = {0}; + uint8_t y[16]; + uint8_t block[16]; + uint8_t r[16]; + + /* + * Q = T || [0]^{(-t-b-1) mod 16} || [i]_1 || [NUM(B)]_b + * Here t = 0 and b = ceil(44 / 8) = 6, so padding is 9 bytes. + */ + q[9] = round; + ff1_store_be48(b, q + 10); + + /* PRF(P || Q) = CBC-MAC_AES(P || Q), IV = 0. */ + if (!aes256_encrypt_block(ctx, P, y)) return false; + for (int i = 0; i < 16; i++) { + block[i] = y[i] ^ q[i]; + } + if (!aes256_encrypt_block(ctx, block, r)) return false; + + /* + * d = 4 * ceil(6 / 4) + 4 = 12, so S is the first 12 bytes of R. + * We only need NUM(S) modulo 2^44, i.e. the low 44 bits of R[0..11]. + */ + uint64_t low48 = 0; + for (int i = 6; i < 12; i++) { + low48 = (low48 << 8) | r[i]; + } + *y_mod = low48 & ZCASH_FF1_MASK44; + + memzero(q, sizeof(q)); + memzero(y, sizeof(y)); + memzero(block, sizeof(block)); + memzero(r, sizeof(r)); + return true; +} + +bool zcash_orchard_derive_diversifier(const uint8_t dk[32], + const uint8_t index_le[11], + uint8_t diversifier_out[11]) { + if (!dk || !index_le || !diversifier_out) return false; + + aes_encrypt_ctx ctx; + if (aes_encrypt_key256(dk, &ctx) != EXIT_SUCCESS) { + memzero(&ctx, sizeof(ctx)); + return false; + } + + uint64_t A = + ff1_bits_to_num(index_le, 0, ZCASH_FF1_HALF_BITS) & ZCASH_FF1_MASK44; + uint64_t B = + ff1_bits_to_num(index_le, ZCASH_FF1_HALF_BITS, ZCASH_FF1_HALF_BITS) & + ZCASH_FF1_MASK44; + + for (uint8_t round = 0; round < 10; round++) { + uint64_t y; + if (!ff1_round_y_mod_2_44(&ctx, round, B, &y)) { + memzero(&ctx, sizeof(ctx)); + return false; + } + uint64_t C = (A + y) & ZCASH_FF1_MASK44; + A = B; + B = C; + } + + memset(diversifier_out, 0, 11); + ff1_num_to_bits(A, diversifier_out, 0, ZCASH_FF1_HALF_BITS); + ff1_num_to_bits(B, diversifier_out, ZCASH_FF1_HALF_BITS, ZCASH_FF1_HALF_BITS); + + memzero(&ctx, sizeof(ctx)); + return true; +} + +static bool orchard_diversify_point(const uint8_t diversifier[11], + curve_point* gd) { + if (!diversifier || !gd) return false; + static const char domain[] = "z.cash:Orchard-gd"; + + if (pallas_group_hash(domain, diversifier, 11, gd) != 0) { + return false; + } + + if (pallas_point_is_identity(gd)) { + if (pallas_group_hash(domain, NULL, 0, gd) != 0 || + pallas_point_is_identity(gd)) { + memzero(gd, sizeof(*gd)); + return false; + } + } + + return true; +} + +bool zcash_orchard_diversify_hash(const uint8_t diversifier[11], + uint8_t gd_out[32]) { + if (!gd_out) return false; + + curve_point gd; + if (!orchard_diversify_point(diversifier, &gd)) { + return false; + } + + pallas_point_encode(&gd, gd_out); + memzero(&gd, sizeof(gd)); + return true; +} + +bool zcash_orchard_derive_transmission_key(const uint8_t ivk[32], + const uint8_t diversifier[11], + uint8_t gd_out[32], + uint8_t pkd_out[32]) { + if (!ivk || !pkd_out) return false; + + bignum256 ivk_scalar; + bn_read_le(ivk, &ivk_scalar); + bn_normalize(&ivk_scalar); + if (bn_is_zero(&ivk_scalar) || !bn_is_less(&ivk_scalar, &pallas_prime)) { + memzero(&ivk_scalar, sizeof(ivk_scalar)); + return false; + } + + curve_point gd; + if (!orchard_diversify_point(diversifier, &gd)) { + memzero(&ivk_scalar, sizeof(ivk_scalar)); + return false; + } + + curve_point pkd; + pallas_point_mult(&ivk_scalar, &gd, &pkd); + if (pallas_point_is_identity(&pkd)) { + memzero(&ivk_scalar, sizeof(ivk_scalar)); + memzero(&gd, sizeof(gd)); + memzero(&pkd, sizeof(pkd)); + return false; + } + + if (gd_out) { + pallas_point_encode(&gd, gd_out); + } + pallas_point_encode(&pkd, pkd_out); + + memzero(&ivk_scalar, sizeof(ivk_scalar)); + memzero(&gd, sizeof(gd)); + memzero(&pkd, sizeof(pkd)); + return true; +} + +bool zcash_orchard_derive_ivk(const uint8_t ak[32], const uint8_t nk[32], + const uint8_t rivk[32], uint8_t ivk_out[32]) { + if (!ak || !nk || !rivk || !ivk_out) return false; + if ((ak[31] & 0x80) != 0) return false; + + if (pallas_sinsemilla_commit_ivk(ak, nk, rivk, ivk_out) != 0) { + return false; + } + + bignum256 ivk; + bn_read_le(ivk_out, &ivk); + bn_normalize(&ivk); + bool ok = !bn_is_zero(&ivk) && bn_is_less(&ivk, &pallas_prime); + memzero(&ivk, sizeof(ivk)); + if (!ok) { + memzero(ivk_out, 32); + } + return ok; +} + +bool zcash_orchard_derive_receiver(const uint8_t ak[32], const uint8_t nk[32], + const uint8_t rivk[32], const uint8_t dk[32], + const uint8_t index_le[11], + uint8_t receiver_out[43]) { + if (!receiver_out) return false; + + uint8_t diversifier[11]; + uint8_t ivk[32]; + uint8_t pkd[32]; + bool ok = zcash_orchard_derive_diversifier(dk, index_le, diversifier) && + zcash_orchard_derive_ivk(ak, nk, rivk, ivk) && + zcash_orchard_derive_transmission_key(ivk, diversifier, NULL, pkd); + + if (ok) { + memcpy(receiver_out, diversifier, sizeof(diversifier)); + memcpy(receiver_out + sizeof(diversifier), pkd, sizeof(pkd)); + } else { + memzero(receiver_out, 43); + } + + memzero(diversifier, sizeof(diversifier)); + memzero(ivk, sizeof(ivk)); + memzero(pkd, sizeof(pkd)); + return ok; +} + +bool zcash_orchard_derive_unified_address(const ZcashOrchardKeys* keys, + const uint8_t index_le[11], + const char* hrp, char* address_out, + size_t address_out_len) { + if (!keys || !index_le || !hrp || !address_out) return false; + + bignum256 ask_scalar; + curve_point ak_point; + bignum256 ak_x; + uint8_t ak[32]; + uint8_t receiver[43]; + + bn_read_le(keys->ask, &ask_scalar); + redpallas_scalar_mult_spendauth_G(&ask_scalar, &ak_point); + bn_copy(&ak_point.x, &ak_x); + bn_write_le(&ak_x, ak); + + bool ok = zcash_orchard_derive_receiver(ak, keys->nk, keys->rivk, keys->dk, + index_le, receiver); + if (ok) { + ok = zcash_zip316_encode_orchard_unified_address(hrp, receiver, address_out, + address_out_len) == 0; + } + if (!ok && address_out_len > 0) { + address_out[0] = '\0'; + } + + memzero(&ask_scalar, sizeof(ask_scalar)); + memzero(&ak_point, sizeof(ak_point)); + memzero(&ak_x, sizeof(ak_x)); + memzero(ak, sizeof(ak)); + memzero(receiver, sizeof(receiver)); + return ok; +} + +bool zcash_orchard_receiver_to_unified_address( + const uint8_t receiver[ZCASH_ORCHARD_RAW_RECEIVER_SIZE], const char* hrp, + char* address_out, size_t address_out_len) { + if (!receiver || !hrp || !address_out) return false; + return zcash_zip316_encode_orchard_unified_address(hrp, receiver, address_out, + address_out_len) == 0; +} + +static bool zcash_pack_orchard_note_commit_msg(const uint8_t receiver[43], + uint64_t value, + const uint8_t rho[32], + const uint8_t psi[32], + uint8_t msg[136]) { + memset(msg, 0, 136); + + /* bits 0..255: repr_P(g_d) */ + curve_point gd; + if (!orchard_diversify_point(receiver, &gd)) { + memzero(&gd, sizeof(gd)); + return false; + } + pallas_point_encode(&gd, msg); + memzero(&gd, sizeof(gd)); + + /* bits 256..511: repr_P(pk_d) */ + memcpy(msg + 32, receiver + 11, 32); + + /* bits 512..575: I2LEBSP_64(value) */ + for (int i = 0; i < 8; i++) { + msg[64 + i] = (uint8_t)((value >> (8 * i)) & 0xff); + } + + /* bits 576..830: I2LEBSP_255(rho) */ + memcpy(msg + 72, rho, 31); + msg[103] = rho[31] & 0x7f; + + /* bits 831..1085: I2LEBSP_255(psi), packed at bit offset 831. */ + uint8_t psi255[32]; + memcpy(psi255, psi, 32); + psi255[31] &= 0x7f; + for (int i = 0; i < 32; i++) { + msg[103 + i] |= (uint8_t)(psi255[i] << 7); + msg[104 + i] |= (uint8_t)(psi255[i] >> 1); + } + memzero(psi255, sizeof(psi255)); + return true; +} + +bool zcash_orchard_compute_cmx( + const uint8_t receiver[ZCASH_ORCHARD_RAW_RECEIVER_SIZE], uint64_t value, + const uint8_t rho[32], const uint8_t rseed[32], uint8_t cmx_out[32]) { + if (!receiver || !rho || !rseed || !cmx_out) return false; + + uint8_t msg[136]; + uint8_t prf_in[33]; + uint8_t prf_out[64]; + uint8_t rcm[32]; + uint8_t psi[32]; + curve_point q, r; + bool ok = false; + + memcpy(prf_in + 1, rho, 32); + + prf_in[0] = 0x05; + prf_expand(rseed, prf_in, sizeof(prf_in), prf_out); + to_scalar(prf_out, rcm); + + prf_in[0] = 0x09; + prf_expand(rseed, prf_in, sizeof(prf_in), prf_out); + to_base(prf_out, psi); + + ok = zcash_pack_orchard_note_commit_msg(receiver, value, rho, psi, msg) && + pallas_group_hash("z.cash:SinsemillaQ", + (const uint8_t*)"z.cash:Orchard-NoteCommit-M", + strlen("z.cash:Orchard-NoteCommit-M"), &q) == 0 && + pallas_group_hash("z.cash:Orchard-NoteCommit-r", NULL, 0, &r) == 0 && + pallas_sinsemilla_short_commit(&q, &r, msg, 1086, rcm, cmx_out) == 0; + + if (!ok) { + memzero(cmx_out, 32); + } + + memzero(msg, sizeof(msg)); + memzero(prf_in, sizeof(prf_in)); + memzero(prf_out, sizeof(prf_out)); + memzero(rcm, sizeof(rcm)); + memzero(psi, sizeof(psi)); + memzero(&q, sizeof(q)); + memzero(&r, sizeof(r)); + return ok; +} + +bool zcash_derive_orchard_keys(const uint8_t* seed, uint32_t seed_len, + uint32_t account, ZcashOrchardKeys* keys) { + uint8_t I[64]; + uint8_t sk[32], chain_code[32]; + + /* Step 1: Master key from seed + * I = BLAKE2b-512("ZcashIP32Orchard", seed) */ + zip32_orchard_master(seed, seed_len, I); + memcpy(sk, I, 32); + memcpy(chain_code, I + 32, 32); + + /* Step 2: Derive path m_orchard / 32' / 133' / account' + * + * CKDOrchard child derivation (ZIP-32 hardened-only): + * I = PRF^expand(chain_code, [0x81] || sk || I2LEOSP32(index)) + * + * PRF^expand(sk, t) = BLAKE2b-512("Zcash_ExpandSeed", sk || t) + * + * So: I = BLAKE2b-512("Zcash_ExpandSeed", + * chain_code || 0x81 || sk || index_le) + */ + const uint32_t path[3] = { + 32 | ZIP32_HARDENED, /* Purpose (Orchard) */ + 133 | ZIP32_HARDENED, /* Coin type (Zcash) */ + account | ZIP32_HARDENED /* Account */ + }; + + for (int i = 0; i < 3; i++) { + /* Build PRF^expand input: [0x81] || sk || I2LEOSP32(index) */ + uint8_t child_input[1 + 32 + 4]; + child_input[0] = 0x81; /* ORCHARD_ZIP32_CHILD domain separator */ + memcpy(child_input + 1, sk, 32); + /* Little-endian index (I2LEOSP32) */ + uint32_t idx = path[i]; + child_input[33] = idx & 0xff; + child_input[34] = (idx >> 8) & 0xff; + child_input[35] = (idx >> 16) & 0xff; + child_input[36] = (idx >> 24) & 0xff; + + /* PRF^expand(chain_code, child_input) */ + prf_expand(chain_code, child_input, sizeof(child_input), I); + memcpy(sk, I, 32); + memcpy(chain_code, I + 32, 32); + + memzero(child_input, sizeof(child_input)); + } + + /* Step 3: Derive subkeys from final spending key */ + memcpy(keys->sk, sk, 32); + + uint8_t expanded[64]; + + /* ask = ToScalar(PRF^expand(sk, [0x06])) */ + uint8_t t_ask = 0x06; + prf_expand(sk, &t_ask, 1, expanded); + to_scalar(expanded, keys->ask); + uint8_t ak_bytes[32]; + + /* + * Zcash spec (§ 4.2.3): If [ask]*G_spendauth has odd y (ỹ = 1), + * negate ask so that the resulting ak always has ỹ = 0. + * This matches the orchard crate's SpendAuthorizingKey::from() behavior. + */ + { + bignum256 ask_test; + bn_read_le(keys->ask, &ask_test); + curve_point ak_test; + redpallas_scalar_mult_spendauth_G(&ask_test, &ak_test); + bignum256 ak_x; + bn_copy(&ak_test.x, &ak_x); + bn_write_le(&ak_x, ak_bytes); + if (bn_is_odd(&ak_test.y)) { + /* ask = order - ask (negate mod q) */ + bignum256 ask_val, neg_ask; + bn_read_le(keys->ask, &ask_val); + bn_subtract(&pallas_order, &ask_val, &neg_ask); + bn_write_le(&neg_ask, keys->ask); + memzero(&neg_ask, sizeof(neg_ask)); + memzero(&ask_val, sizeof(ask_val)); + } + memzero(&ask_test, sizeof(ask_test)); + memzero(&ak_test, sizeof(ak_test)); + memzero(&ak_x, sizeof(ak_x)); + } + + /* nk = ToBase(PRF^expand(sk, [0x07])) */ + uint8_t t_nk = 0x07; + prf_expand(sk, &t_nk, 1, expanded); + to_base(expanded, keys->nk); + + /* rivk = ToScalar(PRF^expand(sk, [0x08])) */ + uint8_t t_rivk = 0x08; + prf_expand(sk, &t_rivk, 1, expanded); + to_scalar(expanded, keys->rivk); + + /* + * dk = truncate_32(PRF^expand(rivk, [0x82] || I2LEOSP_256(ak) + * || I2LEOSP_256(nk))) + */ + uint8_t dk_input[1 + 32 + 32]; + dk_input[0] = 0x82; + memcpy(dk_input + 1, ak_bytes, 32); + memcpy(dk_input + 33, keys->nk, 32); + prf_expand(keys->rivk, dk_input, sizeof(dk_input), expanded); + memcpy(keys->dk, expanded, 32); + + /* Clean up */ + memzero(I, sizeof(I)); + memzero(sk, sizeof(sk)); + memzero(chain_code, sizeof(chain_code)); + memzero(expanded, sizeof(expanded)); + memzero(ak_bytes, sizeof(ak_bytes)); + memzero(dk_input, sizeof(dk_input)); + + return true; +} + +bool zcash_compute_shielded_sighash(const uint8_t header_digest[32], + const uint8_t transparent_digest[32], + const uint8_t sapling_digest[32], + const uint8_t orchard_digest[32], + uint32_t branch_id, + uint8_t sighash_out[32]) { + Hasher h; + uint8_t personal[16]; + + memcpy(personal, "ZcashTxHash_", 12); + memcpy(personal + 12, &branch_id, 4); + + hasher_InitParam(&h, HASHER_BLAKE2B_PERSONAL, personal, 16); + hasher_Update(&h, header_digest, 32); + hasher_Update(&h, transparent_digest, 32); + hasher_Update(&h, sapling_digest, 32); + hasher_Update(&h, orchard_digest, 32); + hasher_Final(&h, sighash_out); + + return true; +} + +static void zcash_write_u32_le(uint32_t value, uint8_t out[4]) { + out[0] = (uint8_t)(value & 0xff); + out[1] = (uint8_t)((value >> 8) & 0xff); + out[2] = (uint8_t)((value >> 16) & 0xff); + out[3] = (uint8_t)((value >> 24) & 0xff); +} + +static void zcash_write_u64_le(uint64_t value, uint8_t out[8]) { + for (size_t i = 0; i < 8; i++) { + out[i] = (uint8_t)((value >> (8 * i)) & 0xff); + } +} + +static size_t zcash_write_compact_size(size_t value, uint8_t out[9]) { + if (value < 253) { + out[0] = (uint8_t)value; + return 1; + } + + if (value <= 0xffff) { + out[0] = 0xfd; + out[1] = (uint8_t)(value & 0xff); + out[2] = (uint8_t)((value >> 8) & 0xff); + return 3; + } + + if (value <= 0xffffffff) { + out[0] = 0xfe; + out[1] = (uint8_t)(value & 0xff); + out[2] = (uint8_t)((value >> 8) & 0xff); + out[3] = (uint8_t)((value >> 16) & 0xff); + out[4] = (uint8_t)((value >> 24) & 0xff); + return 5; + } + + out[0] = 0xff; + uint64_t v = (uint64_t)value; + for (size_t i = 0; i < 8; i++) { + out[i + 1] = (uint8_t)((v >> (8 * i)) & 0xff); + } + return 9; +} + +static void zcash_blake2b_personal_256(const char personal[16], + const uint8_t* data, size_t data_len, + uint8_t digest_out[32]) { + BLAKE2B_CTX ctx; + blake2b_InitPersonal(&ctx, 32, personal, 16); + if (data_len > 0) { + blake2b_Update(&ctx, data, data_len); + } + blake2b_Final(&ctx, digest_out, 32); +} + +bool zcash_compute_header_digest(uint32_t version, uint32_t version_group_id, + uint32_t branch_id, uint32_t lock_time, + uint32_t expiry_height, + uint8_t digest_out[32]) { + if (!digest_out) return false; + + uint8_t header[20]; + zcash_write_u32_le(version | 0x80000000u, header); + zcash_write_u32_le(version_group_id, header + 4); + zcash_write_u32_le(branch_id, header + 8); + zcash_write_u32_le(lock_time, header + 12); + zcash_write_u32_le(expiry_height, header + 16); + + zcash_blake2b_personal_256("ZTxIdHeadersHash", header, sizeof(header), + digest_out); + memzero(header, sizeof(header)); + return true; +} + +static bool zcash_validate_transparent_digest_info( + const ZcashTransparentInputDigestInfo* inputs, size_t n_inputs, + const ZcashTransparentOutputDigestInfo* outputs, size_t n_outputs) { + if (n_inputs > 0 && !inputs) return false; + if (n_outputs > 0 && !outputs) return false; + + for (size_t i = 0; i < n_inputs; i++) { + if (!inputs[i].prevout_txid || + (inputs[i].script_pubkey_size > 0 && !inputs[i].script_pubkey)) { + return false; + } + } + + for (size_t i = 0; i < n_outputs; i++) { + if (outputs[i].script_pubkey_size > 0 && !outputs[i].script_pubkey) { + return false; + } + } + + return true; +} + +static void zcash_hash_transparent_prevouts( + const ZcashTransparentInputDigestInfo* inputs, size_t n_inputs, + uint8_t digest_out[32]) { + BLAKE2B_CTX ctx; + uint8_t le[4]; + blake2b_InitPersonal(&ctx, 32, "ZTxIdPrevoutHash", 16); + for (size_t i = 0; i < n_inputs; i++) { + blake2b_Update(&ctx, inputs[i].prevout_txid, 32); + zcash_write_u32_le(inputs[i].prevout_index, le); + blake2b_Update(&ctx, le, sizeof(le)); + } + blake2b_Final(&ctx, digest_out, 32); + memzero(le, sizeof(le)); +} + +static void zcash_hash_transparent_sequences( + const ZcashTransparentInputDigestInfo* inputs, size_t n_inputs, + uint8_t digest_out[32]) { + BLAKE2B_CTX ctx; + uint8_t le[4]; + blake2b_InitPersonal(&ctx, 32, "ZTxIdSequencHash", 16); + for (size_t i = 0; i < n_inputs; i++) { + zcash_write_u32_le(inputs[i].sequence, le); + blake2b_Update(&ctx, le, sizeof(le)); + } + blake2b_Final(&ctx, digest_out, 32); + memzero(le, sizeof(le)); +} + +static void zcash_hash_transparent_amounts( + const ZcashTransparentInputDigestInfo* inputs, size_t n_inputs, + uint8_t digest_out[32]) { + BLAKE2B_CTX ctx; + uint8_t le[8]; + blake2b_InitPersonal(&ctx, 32, "ZTxTrAmountsHash", 16); + for (size_t i = 0; i < n_inputs; i++) { + zcash_write_u64_le(inputs[i].value, le); + blake2b_Update(&ctx, le, sizeof(le)); + } + blake2b_Final(&ctx, digest_out, 32); + memzero(le, sizeof(le)); +} + +static void zcash_hash_transparent_scripts( + const ZcashTransparentInputDigestInfo* inputs, size_t n_inputs, + uint8_t digest_out[32]) { + BLAKE2B_CTX ctx; + uint8_t compact_size[9]; + blake2b_InitPersonal(&ctx, 32, "ZTxTrScriptsHash", 16); + for (size_t i = 0; i < n_inputs; i++) { + size_t compact_size_len = + zcash_write_compact_size(inputs[i].script_pubkey_size, compact_size); + blake2b_Update(&ctx, compact_size, compact_size_len); + if (inputs[i].script_pubkey_size > 0) { + blake2b_Update(&ctx, inputs[i].script_pubkey, + inputs[i].script_pubkey_size); + } + } + blake2b_Final(&ctx, digest_out, 32); + memzero(compact_size, sizeof(compact_size)); +} + +static void zcash_hash_transparent_outputs( + const ZcashTransparentOutputDigestInfo* outputs, size_t n_outputs, + uint8_t digest_out[32]) { + BLAKE2B_CTX ctx; + uint8_t le[8]; + uint8_t compact_size[9]; + blake2b_InitPersonal(&ctx, 32, "ZTxIdOutputsHash", 16); + for (size_t i = 0; i < n_outputs; i++) { + zcash_write_u64_le(outputs[i].value, le); + blake2b_Update(&ctx, le, sizeof(le)); + size_t compact_size_len = + zcash_write_compact_size(outputs[i].script_pubkey_size, compact_size); + blake2b_Update(&ctx, compact_size, compact_size_len); + if (outputs[i].script_pubkey_size > 0) { + blake2b_Update(&ctx, outputs[i].script_pubkey, + outputs[i].script_pubkey_size); + } + } + blake2b_Final(&ctx, digest_out, 32); + memzero(le, sizeof(le)); + memzero(compact_size, sizeof(compact_size)); +} + +static bool zcash_hash_transparent_input( + const ZcashTransparentInputDigestInfo* input, uint8_t digest_out[32]) { + if (!input) return false; + + BLAKE2B_CTX ctx; + uint8_t le4[4]; + uint8_t le8[8]; + uint8_t compact_size[9]; + blake2b_InitPersonal(&ctx, 32, "Zcash___TxInHash", 16); + blake2b_Update(&ctx, input->prevout_txid, 32); + zcash_write_u32_le(input->prevout_index, le4); + blake2b_Update(&ctx, le4, sizeof(le4)); + zcash_write_u64_le(input->value, le8); + blake2b_Update(&ctx, le8, sizeof(le8)); + size_t compact_size_len = + zcash_write_compact_size(input->script_pubkey_size, compact_size); + blake2b_Update(&ctx, compact_size, compact_size_len); + if (input->script_pubkey_size > 0) { + blake2b_Update(&ctx, input->script_pubkey, input->script_pubkey_size); + } + zcash_write_u32_le(input->sequence, le4); + blake2b_Update(&ctx, le4, sizeof(le4)); + blake2b_Final(&ctx, digest_out, 32); + memzero(le4, sizeof(le4)); + memzero(le8, sizeof(le8)); + memzero(compact_size, sizeof(compact_size)); + return true; +} + +bool zcash_compute_transparent_digest( + const ZcashTransparentInputDigestInfo* inputs, size_t n_inputs, + const ZcashTransparentOutputDigestInfo* outputs, size_t n_outputs, + uint8_t digest_out[32]) { + if (!digest_out || !zcash_validate_transparent_digest_info( + inputs, n_inputs, outputs, n_outputs)) { + return false; + } + + if (n_inputs == 0 && n_outputs == 0) { + zcash_blake2b_personal_256("ZTxIdTranspaHash", NULL, 0, digest_out); + return true; + } + + uint8_t prevouts_digest[32], sequence_digest[32], outputs_digest[32]; + zcash_hash_transparent_prevouts(inputs, n_inputs, prevouts_digest); + zcash_hash_transparent_sequences(inputs, n_inputs, sequence_digest); + zcash_hash_transparent_outputs(outputs, n_outputs, outputs_digest); + + BLAKE2B_CTX ctx; + blake2b_InitPersonal(&ctx, 32, "ZTxIdTranspaHash", 16); + blake2b_Update(&ctx, prevouts_digest, 32); + blake2b_Update(&ctx, sequence_digest, 32); + blake2b_Update(&ctx, outputs_digest, 32); + blake2b_Final(&ctx, digest_out, 32); + + memzero(prevouts_digest, sizeof(prevouts_digest)); + memzero(sequence_digest, sizeof(sequence_digest)); + memzero(outputs_digest, sizeof(outputs_digest)); + return true; +} + +/* ZIP-244 §4.9 / §4.10b: transparent_sig_digest for Orchard spend + * authorization. + * + * When n_inputs > 0, the Orchard sighash uses the S.2 form: + * BLAKE2b("ZTxIdTranspaHash", + * hash_type(0x01) || prevouts || amounts || scripts || sequences || + * outputs || empty_txin_digest) + * where empty_txin_digest = BLAKE2b("Zcash___TxInHash", ""). + * + * When n_inputs == 0 (deshield / private-send), falls back to T.1 form + * (no hash_type, amounts, scripts, or txin digest) — same as txid form. + * + * This differs from zcash_compute_transparent_sighash_digest which uses a + * per-input txin_sig_digest for transparent ECDSA signatures. + */ +bool zcash_compute_orchard_transparent_sig_digest( + const ZcashTransparentInputDigestInfo* inputs, size_t n_inputs, + const ZcashTransparentOutputDigestInfo* outputs, size_t n_outputs, + uint8_t digest_out[32]) { + if (!digest_out || !zcash_validate_transparent_digest_info( + inputs, n_inputs, outputs, n_outputs)) { + return false; + } + + /* Empty-vin case (deshield, private): T.1 form is correct per §4.10b. */ + if (n_inputs == 0) { + return zcash_compute_transparent_digest(inputs, n_inputs, outputs, + n_outputs, digest_out); + } + + /* Non-empty vin (shield): S.2 form with empty txin_sig_digest. */ + const uint8_t sighash_type = 0x01; /* SIGHASH_ALL */ + uint8_t prevouts_digest[32], amounts_digest[32], scripts_digest[32]; + uint8_t sequence_digest[32], outputs_digest[32], empty_txin_digest[32]; + + zcash_hash_transparent_prevouts(inputs, n_inputs, prevouts_digest); + zcash_hash_transparent_amounts(inputs, n_inputs, amounts_digest); + zcash_hash_transparent_scripts(inputs, n_inputs, scripts_digest); + zcash_hash_transparent_sequences(inputs, n_inputs, sequence_digest); + zcash_hash_transparent_outputs(outputs, n_outputs, outputs_digest); + + /* Empty txin_sig_digest: BLAKE2b("Zcash___TxInHash", "") */ + zcash_blake2b_personal_256("Zcash___TxInHash", NULL, 0, empty_txin_digest); + + BLAKE2B_CTX ctx; + blake2b_InitPersonal(&ctx, 32, "ZTxIdTranspaHash", 16); + blake2b_Update(&ctx, &sighash_type, 1); + blake2b_Update(&ctx, prevouts_digest, 32); + blake2b_Update(&ctx, amounts_digest, 32); + blake2b_Update(&ctx, scripts_digest, 32); + blake2b_Update(&ctx, sequence_digest, 32); + blake2b_Update(&ctx, outputs_digest, 32); + blake2b_Update(&ctx, empty_txin_digest, 32); + blake2b_Final(&ctx, digest_out, 32); + + memzero(prevouts_digest, sizeof(prevouts_digest)); + memzero(amounts_digest, sizeof(amounts_digest)); + memzero(scripts_digest, sizeof(scripts_digest)); + memzero(sequence_digest, sizeof(sequence_digest)); + memzero(outputs_digest, sizeof(outputs_digest)); + memzero(empty_txin_digest, sizeof(empty_txin_digest)); + return true; +} + +bool zcash_compute_transparent_sighash_digest( + const ZcashTransparentInputDigestInfo* inputs, size_t n_inputs, + const ZcashTransparentOutputDigestInfo* outputs, size_t n_outputs, + uint32_t signable_input_index, uint8_t sighash_type, + uint8_t digest_out[32]) { + if (!digest_out || !zcash_validate_transparent_digest_info( + inputs, n_inputs, outputs, n_outputs)) { + return false; + } + + if (sighash_type != 0x01 || signable_input_index >= n_inputs) { + return false; + } + + uint8_t prevouts_digest[32], amounts_digest[32], scripts_digest[32]; + uint8_t sequence_digest[32], outputs_digest[32], txin_sig_digest[32]; + zcash_hash_transparent_prevouts(inputs, n_inputs, prevouts_digest); + zcash_hash_transparent_amounts(inputs, n_inputs, amounts_digest); + zcash_hash_transparent_scripts(inputs, n_inputs, scripts_digest); + zcash_hash_transparent_sequences(inputs, n_inputs, sequence_digest); + zcash_hash_transparent_outputs(outputs, n_outputs, outputs_digest); + + zcash_hash_transparent_input(&inputs[signable_input_index], txin_sig_digest); + + BLAKE2B_CTX ctx; + blake2b_InitPersonal(&ctx, 32, "ZTxIdTranspaHash", 16); + blake2b_Update(&ctx, &sighash_type, 1); + blake2b_Update(&ctx, prevouts_digest, 32); + blake2b_Update(&ctx, amounts_digest, 32); + blake2b_Update(&ctx, scripts_digest, 32); + blake2b_Update(&ctx, sequence_digest, 32); + blake2b_Update(&ctx, outputs_digest, 32); + blake2b_Update(&ctx, txin_sig_digest, 32); + blake2b_Final(&ctx, digest_out, 32); + + memzero(prevouts_digest, sizeof(prevouts_digest)); + memzero(amounts_digest, sizeof(amounts_digest)); + memzero(scripts_digest, sizeof(scripts_digest)); + memzero(sequence_digest, sizeof(sequence_digest)); + memzero(outputs_digest, sizeof(outputs_digest)); + memzero(txin_sig_digest, sizeof(txin_sig_digest)); + return true; +} + +ZcashPCZTSigningRequestStatus zcash_pczt_signing_request_status( + const ZcashPCZTSigningRequestMeta* meta) { + if (!meta || !meta->has_header_digest || !meta->has_orchard_digest) { + return ZCASH_PCZT_SIGNING_REQUEST_MISSING_TX_DIGESTS; + } + + if (meta->header_digest_size != 32 || meta->orchard_digest_size != 32) { + return ZCASH_PCZT_SIGNING_REQUEST_INVALID_DIGEST_SIZE; + } + + if (meta->has_transparent_digest && meta->transparent_digest_size != 32) { + return ZCASH_PCZT_SIGNING_REQUEST_INVALID_DIGEST_SIZE; + } + + (void)meta->sapling_digest_size; + if (meta->has_sapling_digest) { + return ZCASH_PCZT_SIGNING_REQUEST_UNSUPPORTED_SAPLING_COMPONENT; + } + + if (!meta->has_header_fields) { + return ZCASH_PCZT_SIGNING_REQUEST_MISSING_HEADER_FIELDS; + } + + if ((meta->n_transparent_inputs > 0 || meta->n_transparent_outputs > 0) && + (!meta->has_transparent_digest || meta->transparent_digest_size != 32)) { + return ZCASH_PCZT_SIGNING_REQUEST_MISSING_TRANSPARENT_DIGEST; + } + + if (!meta->has_orchard_flags || meta->orchard_flags > 0xff || + !meta->has_orchard_value_balance || !meta->has_orchard_anchor || + meta->orchard_anchor_size != 32) { + return ZCASH_PCZT_SIGNING_REQUEST_MISSING_ORCHARD_METADATA; + } + + return ZCASH_PCZT_SIGNING_REQUEST_OK; +} + +bool zcash_pczt_signing_request_is_clear( + const ZcashPCZTSigningRequestMeta* meta) { + return zcash_pczt_signing_request_status(meta) == + ZCASH_PCZT_SIGNING_REQUEST_OK; +} + +/* + * ZIP-32 §6.1 seed fingerprint: + * + * SeedFingerprint := BLAKE2b-256( + * "Zcash_HD_Seed_FP", I2LEBSP_8(len(seed)) || seed) + * + * The 1-byte length prefix domain-separates seeds of different lengths that + * happen to share a prefix. + * + * Trivial seeds (all-zero, all-0xFF) and seeds outside [32, 252] bytes are + * rejected — these are nominally seeds but provide no security and are + * almost certainly bugs in the caller. + */ +bool zcash_seed_fingerprint_request_valid(bool present, size_t size) { + return !present || size == 32; +} + +bool zcash_calculate_seed_fingerprint(const uint8_t* seed, uint32_t seed_len, + uint8_t fingerprint_out[32]) { + if (!seed || !fingerprint_out) return false; + if (seed_len < 32 || seed_len > 252) return false; + + bool all_zero = true; + bool all_ff = true; + for (uint32_t i = 0; i < seed_len; i++) { + if (seed[i] != 0x00) all_zero = false; + if (seed[i] != 0xFF) all_ff = false; + if (!all_zero && !all_ff) break; + } + if (all_zero || all_ff) return false; + + BLAKE2B_CTX ctx; + if (blake2b_InitPersonal(&ctx, 32, "Zcash_HD_Seed_FP", 16) != 0) { + return false; + } + uint8_t len_byte = (uint8_t)seed_len; + blake2b_Update(&ctx, &len_byte, 1); + blake2b_Update(&ctx, seed, seed_len); + if (blake2b_Final(&ctx, fingerprint_out, 32) != 0) { + memzero(&ctx, sizeof(ctx)); + return false; + } + + memzero(&ctx, sizeof(ctx)); + return true; +} diff --git a/lib/rand/rng.c b/lib/rand/rng.c index 57c8c75b9..9e61f3e82 100644 --- a/lib/rand/rng.c +++ b/lib/rand/rng.c @@ -27,6 +27,14 @@ #include #endif +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN /* exclude winsock.h — it declares \ + shutdown(SOCKET,int) */ +#include +#include +#include +#endif + void reset_rng(void) { #ifndef EMULATOR /* disable RNG */ @@ -77,20 +85,46 @@ uint32_t random32(void) { } last = new; return new; +#elif defined(_WIN32) + /* Windows has no POSIX random(); use the system CSPRNG (stronger than the + * macOS/Linux emulator's random() PRNG anyway). Resolves via the bcrypt link + * on kkemulator_dylib (tools/emulator/CMakeLists.txt). */ + uint32_t v = 0; + if (BCryptGenRandom(NULL, (PUCHAR)&v, (ULONG)sizeof(v), + BCRYPT_USE_SYSTEM_PREFERRED_RNG) != 0) { + abort(); + } + return v; #else return random(); #endif } +#if defined(EMULATOR) && !defined(__APPLE__) +/* trezor-crypto declares random_buffer() as a weak symbol so platforms can + * supply their own. GNU/MinGW ld will NOT extract a weak definition from a + * static archive to satisfy a strong reference (fsm.c/reset.c/storage.c), + * which breaks the Linux .so and Windows .dll links. Provide a strong + * definition here — identical to trezor-crypto's, built on our random32(). + * macOS ld64 resolves the weak one fine, so it's left untouched there. */ +void random_buffer(uint8_t *buf, size_t len) { + uint32_t r = 0; + for (size_t i = 0; i < len; i++) { + if (i % 4 == 0) r = random32(); + buf[i] = (r >> ((i % 4) * 8)) & 0xff; + } +} +#endif + // I miss C++ templates sooo bad. -#define RANDOM_PERMUTE(BUFF, COUNT) \ - do { \ - for (size_t i = (COUNT)-1; i >= 1; i--) { \ - size_t j = random_uniform(i + 1); \ - typeof(*(BUFF)) t = (BUFF)[j]; \ - (BUFF)[j] = (BUFF)[i]; \ - (BUFF)[i] = t; \ - } \ +#define RANDOM_PERMUTE(BUFF, COUNT) \ + do { \ + for (size_t i = (COUNT) - 1; i >= 1; i--) { \ + size_t j = random_uniform(i + 1); \ + typeof(*(BUFF)) t = (BUFF)[j]; \ + (BUFF)[j] = (BUFF)[i]; \ + (BUFF)[i] = t; \ + } \ } while (0) void random_permute_char(char *str, size_t len) { RANDOM_PERMUTE(str, len); } diff --git a/lib/transport/CMakeLists.txt b/lib/transport/CMakeLists.txt index d42d3e113..c8dd5c0ac 100644 --- a/lib/transport/CMakeLists.txt +++ b/lib/transport/CMakeLists.txt @@ -18,6 +18,8 @@ set(protoc_pb_sources ${DEVICE_PROTOCOL}/messages-solana.proto ${DEVICE_PROTOCOL}/messages-tron.proto ${DEVICE_PROTOCOL}/messages-ton.proto + ${DEVICE_PROTOCOL}/messages-zcash.proto + ${DEVICE_PROTOCOL}/messages-hive.proto ${DEVICE_PROTOCOL}/messages.proto) set(protoc_pb_options @@ -35,6 +37,8 @@ set(protoc_pb_options ${CMAKE_SOURCE_DIR}/include/keepkey/transport/messages-solana.options ${CMAKE_SOURCE_DIR}/include/keepkey/transport/messages-tron.options ${CMAKE_SOURCE_DIR}/include/keepkey/transport/messages-ton.options + ${CMAKE_SOURCE_DIR}/include/keepkey/transport/messages-zcash.options + ${CMAKE_SOURCE_DIR}/include/keepkey/transport/messages-hive.options ${CMAKE_SOURCE_DIR}/include/keepkey/transport/messages.options) set(protoc_c_sources @@ -52,6 +56,8 @@ set(protoc_c_sources ${CMAKE_BINARY_DIR}/lib/transport/messages-solana.pb.c ${CMAKE_BINARY_DIR}/lib/transport/messages-tron.pb.c ${CMAKE_BINARY_DIR}/lib/transport/messages-ton.pb.c + ${CMAKE_BINARY_DIR}/lib/transport/messages-zcash.pb.c + ${CMAKE_BINARY_DIR}/lib/transport/messages-hive.pb.c ${CMAKE_BINARY_DIR}/lib/transport/messages.pb.c) set(protoc_c_headers @@ -69,6 +75,8 @@ set(protoc_c_headers ${CMAKE_BINARY_DIR}/include/messages-solana.pb.h ${CMAKE_BINARY_DIR}/include/messages-tron.pb.h ${CMAKE_BINARY_DIR}/include/messages-ton.pb.h + ${CMAKE_BINARY_DIR}/include/messages-zcash.pb.h + ${CMAKE_BINARY_DIR}/include/messages-hive.pb.h ${CMAKE_BINARY_DIR}/include/messages.pb.h) set(protoc_pb_sources_moved @@ -86,6 +94,8 @@ set(protoc_pb_sources_moved ${CMAKE_BINARY_DIR}/lib/transport/messages-solana.proto ${CMAKE_BINARY_DIR}/lib/transport/messages-tron.proto ${CMAKE_BINARY_DIR}/lib/transport/messages-ton.proto + ${CMAKE_BINARY_DIR}/lib/transport/messages-zcash.proto + ${CMAKE_BINARY_DIR}/lib/transport/messages-hive.proto ${CMAKE_BINARY_DIR}/lib/transport/messages.proto) add_custom_command( @@ -163,6 +173,14 @@ add_custom_command( ${PROTOC_BINARY} -I. -I/usr/include --plugin=nanopb=${NANOPB_DIR}/generator/protoc-gen-nanopb "--nanopb_out=-f messages-ton.options:." messages-ton.proto + COMMAND + ${PROTOC_BINARY} -I. -I/usr/include + --plugin=nanopb=${NANOPB_DIR}/generator/protoc-gen-nanopb + "--nanopb_out=-f messages-zcash.options:." messages-zcash.proto + COMMAND + ${PROTOC_BINARY} -I. -I/usr/include + --plugin=nanopb=${NANOPB_DIR}/generator/protoc-gen-nanopb + "--nanopb_out=-f messages-hive.options:." messages-hive.proto COMMAND ${PROTOC_BINARY} -I. -I/usr/include --plugin=nanopb=${NANOPB_DIR}/generator/protoc-gen-nanopb diff --git a/scripts/build/docker/device/release.sh b/scripts/build/docker/device/release.sh index 18cfe53dc..50fbc9d4c 100755 --- a/scripts/build/docker/device/release.sh +++ b/scripts/build/docker/device/release.sh @@ -7,13 +7,18 @@ IMAGETAG=kktech/firmware:v15 docker image inspect $IMAGETAG > /dev/null || docker pull $IMAGETAG +# Extra cmake flags pass straight through. The only alternate release product +# is bitcoin-only: ./release.sh -DKK_BITCOIN_ONLY=ON +EXTRA_CMAKE_FLAGS="$*" + docker run -t \ -v $(pwd):/root/keepkey-firmware:z \ $IMAGETAG /bin/sh -c "\ mkdir /root/build && cd /root/build && \ cmake -C /root/keepkey-firmware/cmake/caches/device.cmake /root/keepkey-firmware \ -DCMAKE_BUILD_TYPE=MinSizeRel \ - -DCMAKE_COLOR_MAKEFILE=ON &&\ + -DCMAKE_COLOR_MAKEFILE=ON \ + ${EXTRA_CMAKE_FLAGS} &&\ make && \ mkdir -p /root/keepkey-firmware/bin && \ cp -r /root/build /root/keepkey-firmware/bin/ && \ diff --git a/scripts/emulator/python-keepkey-tests.sh b/scripts/emulator/python-keepkey-tests.sh index 28b122fc9..bbbce7519 100755 --- a/scripts/emulator/python-keepkey-tests.sh +++ b/scripts/emulator/python-keepkey-tests.sh @@ -41,9 +41,14 @@ echo "=== End diagnostic ===" # expression for every test with non-empty screenshot expectations. Adding screenshots # to a test in SECTIONS automatically includes it here — no manual filter maintenance. echo "=== Phase 1: Report-driven screenshot capture ===" -# Detect firmware version from CMakeLists if not set in env +# Detect firmware version from CMakeLists if not set in env. +# NOTE: grep -oE (POSIX ERE), NOT -oP — this runs in the Alpine/busybox +# python-keepkey container where grep has no -P (PCRE). With -P grep errored +# and the version silently fell back to 7.14.0, so every 7.15.0 section +# (Hive, EVM clear-signing) was excluded from screenshot capture. if [ -z "$FW_VERSION" ]; then - FW_VERSION=$(sed -n '/^project/,/)/p' /kkemu/CMakeLists.txt | grep -oP '\d+\.\d+\.\d+' || echo "7.14.0") + FW_VERSION=$(sed -n '/^project/,/)/p' /kkemu/CMakeLists.txt | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1) + [ -z "$FW_VERSION" ] && FW_VERSION="7.14.0" echo "Detected FW_VERSION=$FW_VERSION from CMakeLists.txt" fi export FW_VERSION diff --git a/tools/check_sram_budget.py b/tools/check_sram_budget.py new file mode 100644 index 000000000..8481a2348 --- /dev/null +++ b/tools/check_sram_budget.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python3 +"""SRAM budget gate for ARM firmware builds. + +Fails CI when the runtime stack/heap reserve — the gap between the end of +static allocation (_ebss) and the top-of-RAM stack (_stack) — drops below the +per-variant budget, or when the largest single stack frame (-fstack-usage) +leaves less than the configured margin inside that reserve. + +Why this exists: RC7's privacy-enabled build shipped with an 11,232-byte gap +while msg_write() carried a 12,416-byte automatic TrezorFrameBuffer — every +USB response overwrote static memory, hard-faulting on boot. The linker also +ASSERTs a 16 KiB floor (tools/firmware/keepkey.ld); this script is the +observability + frame-margin half of that gate. + +Usage: + check_sram_budget.py --elf bin/...firmware.keepkey.elf \ + --su-tar bin/stack-usage.tgz --budgets tools/sram-budgets.json \ + --variant full +""" + +import argparse +import json +import sys +import tarfile + +from elftools.elf.elffile import ELFFile # pip install pyelftools + + +def read_symbols(elf_path): + with open(elf_path, "rb") as f: + elf = ELFFile(f) + symtab = elf.get_section_by_name(".symtab") + if symtab is None: + sys.exit(f"ERROR: {elf_path} has no .symtab") + wanted = {} + for sym in symtab.iter_symbols(): + if sym.name in ("_ebss", "_stack"): + wanted[sym.name] = sym["st_value"] + missing = {"_ebss", "_stack"} - set(wanted) + if missing: + sys.exit(f"ERROR: {elf_path} missing symbols: {sorted(missing)}") + return wanted + + +def largest_frames(su_tar_path, top_n=15): + """Parse GCC -fstack-usage records from a tar of .su files. + + Record format: ":::\t\t" + """ + frames = [] + with tarfile.open(su_tar_path, "r:*") as tar: + for member in tar: + if not member.name.endswith(".su") or not member.isfile(): + continue + data = tar.extractfile(member).read().decode("utf-8", "replace") + for line in data.splitlines(): + parts = line.rsplit("\t", 2) + if len(parts) != 3: + continue + loc, size, qual = parts + try: + frames.append((int(size), loc.split("/")[-1], qual)) + except ValueError: + continue + frames.sort(reverse=True) + return frames[:top_n] + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--elf", required=True) + ap.add_argument("--su-tar", required=True) + ap.add_argument("--budgets", required=True) + ap.add_argument("--variant", required=True) + args = ap.parse_args() + + budgets = json.load(open(args.budgets)) + reserve_min = budgets.get("variants", {}).get(args.variant, {}).get( + "reserve_min", budgets["reserve_min"]) + frame_margin = budgets.get("variants", {}).get(args.variant, {}).get( + "frame_margin", budgets["frame_margin"]) + + syms = read_symbols(args.elf) + gap = syms["_stack"] - syms["_ebss"] + + frames = largest_frames(args.su_tar) + if not frames: + # An empty .su archive means -fstack-usage generation broke (or the + # tar glob went stale). Treating it as "largest frame = 0" would let + # the margin check false-pass — fail loudly instead. + sys.exit("ERROR: no -fstack-usage records found in " + f"{args.su_tar} — stack-usage generation is broken; " + "refusing to pass the frame-margin gate without data") + largest = frames[0][0] + + print(f"SRAM budget report — variant: {args.variant}") + print(f" _ebss = 0x{syms['_ebss']:08x}") + print(f" _stack = 0x{syms['_stack']:08x}") + print(f" stack/heap reserve (gap) = {gap:,} B " + f"(budget: >= {reserve_min:,} B)") + print(f" largest stack frame = {largest:,} B " + f"(gap - largest must be >= {frame_margin:,} B)") + print(" top stack frames (-fstack-usage):") + for size, loc, qual in frames: + print(f" {size:7,} B {qual:14s} {loc}") + + failed = False + if gap < reserve_min: + print(f"::error::SRAM gate: reserve {gap:,} B < budget " + f"{reserve_min:,} B for {args.variant}") + failed = True + if gap - largest < frame_margin: + print(f"::error::SRAM gate: reserve minus largest frame " + f"({gap:,} - {largest:,} = {gap - largest:,} B) < margin " + f"{frame_margin:,} B for {args.variant}") + failed = True + + if failed: + sys.exit(1) + print("SRAM budget gate: PASS") + + +if __name__ == "__main__": + main() diff --git a/tools/emulator/CMakeLists.txt b/tools/emulator/CMakeLists.txt index 63b80bd88..9f14af996 100644 --- a/tools/emulator/CMakeLists.txt +++ b/tools/emulator/CMakeLists.txt @@ -21,21 +21,43 @@ if(${KK_EMULATOR}) SecAESSTM32 kkrand) - # Standalone emulator binary (uses UDP sockets) - add_executable(kkemu ${sources}) + # Standalone emulator binary — UDP sockets on :11044/:11045 (used by firmware + # CI: python-keepkey UDP tests + OLED screenshots). NOT built on Windows: it + # depends on BSD sockets + signal(); the vault never uses it — the vault loads + # the dylib/DLL below instead. + if(NOT WIN32) + add_executable(kkemu ${sources}) - # Add linker flags for ARM64 Mac compatibility - if(APPLE AND CMAKE_SYSTEM_PROCESSOR MATCHES "arm64") - target_link_options(kkemu PRIVATE "-Wl,-no_fixup_chains") - endif() + # Add linker flags for ARM64 Mac compatibility + if(APPLE AND CMAKE_SYSTEM_PROCESSOR MATCHES "arm64") + target_link_options(kkemu PRIVATE "-Wl,-no_fixup_chains") + endif() - target_link_libraries(kkemu ${FIRMWARE_LIBS} kkemulator) + target_link_libraries(kkemu ${FIRMWARE_LIBS} kkemulator) + endif() - # Shared library (ring buffers, no sockets) for in-process FFI (vault) + # Shared library (ring buffers, no sockets) for in-process FFI — this is what + # the vault loads via bun:ffi (libkkemu.dylib on macOS, .so on Linux, .dll on + # Windows). if(KK_BUILD_DYLIB) - target_link_libraries(kkemulator_dylib ${FIRMWARE_LIBS}) - if(APPLE AND CMAKE_SYSTEM_PROCESSOR MATCHES "arm64") - target_link_options(kkemulator_dylib PRIVATE "-Wl,-no_fixup_chains") + if(WIN32) + # kkrand and trezorcrypto cross-reference each other (random32 / + # random_uniform). GNU/MinGW ld resolves static archives left-to-right in + # a single pass, so wrap FIRMWARE_LIBS in a linker group. Use the raw + # --start-group/--end-group flags rather than the LINK_GROUP genex: the + # genex needs CMake >= 3.24, but this repo's cmake_minimum_required is + # 3.7.2. macOS ld64 is multi-pass and needs neither. + # Also: MinGW exports nothing from a DLL by default (unlike Mach-O/ELF), + # so export the kkemu_* FFI entry points; and link the Windows CSPRNG + # (bcrypt, BCryptGenRandom) used by setup.c / rng.c on _WIN32. + target_link_libraries(kkemulator_dylib + -Wl,--start-group ${FIRMWARE_LIBS} -Wl,--end-group bcrypt) + target_link_options(kkemulator_dylib PRIVATE "-Wl,--export-all-symbols") + else() + target_link_libraries(kkemulator_dylib ${FIRMWARE_LIBS}) + if(APPLE AND CMAKE_SYSTEM_PROCESSOR MATCHES "arm64") + target_link_options(kkemulator_dylib PRIVATE "-Wl,-no_fixup_chains") + endif() endif() endif() endif() diff --git a/tools/firmware/CMakeLists.txt b/tools/firmware/CMakeLists.txt index 18c50e411..3c91156e6 100644 --- a/tools/firmware/CMakeLists.txt +++ b/tools/firmware/CMakeLists.txt @@ -13,8 +13,10 @@ if(NOT ${KK_EMULATOR}) set(linker_script ${CMAKE_CURRENT_SOURCE_DIR}/keepkey.ld) + # Link map for the CI SRAM report/artifact (pairs with the .ld's 16 KiB + # stack-reserve ASSERT and the -fstack-usage frame report). set(CMAKE_EXE_LINKER_FLAGS - "${CMAKE_EXE_LINKER_FLAGS} -T${linker_script} -L${CMAKE_BINARY_DIR}/lib") + "${CMAKE_EXE_LINKER_FLAGS} -T${linker_script} -L${CMAKE_BINARY_DIR}/lib -Wl,-Map=${CMAKE_BINARY_DIR}/bin/firmware.keepkey.map,--cref") set(LINK_FLAGS kkfirmware diff --git a/tools/firmware/keepkey.ld b/tools/firmware/keepkey.ld index 964b43676..9538bc4cd 100644 --- a/tools/firmware/keepkey.ld +++ b/tools/firmware/keepkey.ld @@ -71,3 +71,13 @@ _buttonusr_isr = _comram_end - 4; _data_size = SIZEOF(.data); _codelen = SIZEOF(.text) + SIZEOF(.data) + SIZEOF(.ARM.exidx) + SIZEOF(.version); + +/* Runtime SRAM gate: everything between the end of static allocation (.bss) + * and the top-of-RAM stack is the ONLY memory the running firmware has for + * call frames. RC7's privacy-enabled build shipped with an 11.2 KB gap while + * msg_write() put a 12.4 KB frame on the stack — a guaranteed boot-path + * overwrite of static memory. Never again: require a 16 KiB reserve at link + * time, for every variant. (Initial limit — replace with measured worst-case + * high-water + margin once the -fstack-usage CI reporting has data.) */ +ASSERT((_stack - _ebss) >= 0x4000, + "Insufficient runtime SRAM: require 16 KiB stack/heap reserve between _ebss and _stack"); diff --git a/tools/sram-budgets.json b/tools/sram-budgets.json new file mode 100644 index 000000000..f5b5b2277 --- /dev/null +++ b/tools/sram-budgets.json @@ -0,0 +1,9 @@ +{ + "_comment": "Per-product SRAM budgets enforced by tools/check_sram_budget.py in CI (and a 16 KiB linker ASSERT in tools/firmware/keepkey.ld). reserve_min = minimum bytes between _ebss and _stack; frame_margin = minimum bytes left after subtracting the largest -fstack-usage frame from the reserve. Initial limits chosen after the RC7 privacy-enabled overflow (11,232 B gap vs a 12,416 B msg_write frame); replace with measured worst-case high-water + margin once hardware instrumentation reports real numbers. Any change to these budgets, and any single-commit SRAM increase above 256 B, needs explicit review.", + "reserve_min": 16384, + "frame_margin": 4096, + "variants": { + "full": {}, + "bitcoin-only": {} + } +} diff --git a/unittests/crypto/CMakeLists.txt b/unittests/crypto/CMakeLists.txt index 782549f28..7c9898e38 100644 --- a/unittests/crypto/CMakeLists.txt +++ b/unittests/crypto/CMakeLists.txt @@ -22,3 +22,19 @@ target_link_libraries(crypto-unit kkrand trezorcrypto kktransport) + +# Orchard/Pallas engine + its unit test only exist when privacy is built in. +if(${KK_ZCASH_PRIVACY}) + add_executable(zcash-crypto-unit + ../firmware/zcash.cpp + ${CMAKE_SOURCE_DIR}/lib/firmware/zcash.c) + target_include_directories(zcash-crypto-unit PRIVATE + ${CMAKE_SOURCE_DIR}/include + ${CMAKE_SOURCE_DIR}/lib/firmware + ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-firmware/crypto + ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-firmware/crypto/ed25519-donna) + target_link_libraries(zcash-crypto-unit + gtest_main + trezorcrypto + kkrand) +endif() diff --git a/unittests/firmware/CMakeLists.txt b/unittests/firmware/CMakeLists.txt index 647d72571..f2c47a261 100644 --- a/unittests/firmware/CMakeLists.txt +++ b/unittests/firmware/CMakeLists.txt @@ -1,15 +1,40 @@ set(sources - coins.cpp - cosmos.cpp - eos.cpp - ethereum.cpp - nano.cpp + app_confirm.cpp recovery.cpp - ripple.cpp storage.cpp usb_rx.cpp u2f.cpp) +# Coin/token unit tests exercise handlers/helpers that are compiled out of the +# bitcoin-only firmware (ethereum_address_checksum, tokenByTicker, ...), so they +# only build against a full-feature firmware. coins.cpp asserts the multi-chain +# coin+token table. +if(NOT ${KK_BITCOIN_ONLY}) + list(APPEND sources + authenticator.cpp + binance.cpp + coins.cpp + cosmos.cpp + eip712.cpp + eos.cpp + ethereum.cpp + hive.cpp + mayachain.cpp + nano.cpp + osmosis.cpp + ripple.cpp + signed_metadata.cpp + solana.cpp + thorchain.cpp + tron.cpp) +endif() + +# zcash.cpp exercises the Orchard engine (lib/firmware/zcash.c), which is only +# compiled into kkfirmware when the privacy flag is on. +if(${KK_ZCASH_PRIVACY}) + list(APPEND sources zcash.cpp) +endif() + include_directories( ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/lib/firmware diff --git a/unittests/firmware/app_confirm.cpp b/unittests/firmware/app_confirm.cpp new file mode 100644 index 000000000..fdec4316d --- /dev/null +++ b/unittests/firmware/app_confirm.cpp @@ -0,0 +1,42 @@ +extern "C" { +#include "keepkey/firmware/app_confirm.h" +} + +#include "gtest/gtest.h" + +TEST(AppConfirm, MultilineAsciiMessageUsesTextMode) { + static const char message[] = + "Welcome to DegenQuest!\n" + "\n" + "Sign this message to authenticate your wallet.\n" + "\n" + "This request will not trigger a blockchain transaction or cost any gas " + "fees.\n" + "\n" + "Nonce: d2d8d32b-a7fc-4129-a60b-e0664f0b2169"; + + ASSERT_EQ(193U, sizeof(message) - 1); + EXPECT_TRUE(confirm_bytes_is_text(reinterpret_cast(message), + sizeof(message) - 1)); +} + +TEST(AppConfirm, UnsafeControlsAndBinaryBytesUseHexMode) { + static const uint8_t spaces[] = {' ', ' ', ' '}; + static const uint8_t blank_lines[] = {'\n', '\n'}; + static const uint8_t nul[] = {'a', 0x00, 'b'}; + static const uint8_t tab[] = {'a', '\t', 'b'}; + static const uint8_t carriage_return[] = {'a', '\r', 'b'}; + static const uint8_t escape[] = {'a', 0x1b, 'b'}; + static const uint8_t del[] = {'a', 0x7f, 'b'}; + static const uint8_t utf8[] = {0xc3, 0xa9}; + + EXPECT_FALSE(confirm_bytes_is_text(spaces, sizeof(spaces))); + EXPECT_FALSE(confirm_bytes_is_text(blank_lines, sizeof(blank_lines))); + EXPECT_FALSE(confirm_bytes_is_text(nul, sizeof(nul))); + EXPECT_FALSE(confirm_bytes_is_text(tab, sizeof(tab))); + EXPECT_FALSE(confirm_bytes_is_text(carriage_return, sizeof(carriage_return))); + EXPECT_FALSE(confirm_bytes_is_text(escape, sizeof(escape))); + EXPECT_FALSE(confirm_bytes_is_text(del, sizeof(del))); + EXPECT_FALSE(confirm_bytes_is_text(utf8, sizeof(utf8))); + EXPECT_FALSE(confirm_bytes_is_text(nullptr, 1)); +} diff --git a/unittests/firmware/authenticator.cpp b/unittests/firmware/authenticator.cpp new file mode 100644 index 000000000..e5615cb61 --- /dev/null +++ b/unittests/firmware/authenticator.cpp @@ -0,0 +1,111 @@ +extern "C" { +#include + +#include "trezor/crypto/sha2.h" +#include "keepkey/firmware/authenticator.h" +#include "keepkey/firmware/storage.h" + +void setup(void); +} + +#include "gtest/gtest.h" + +// Shared emulator confirmation driver from thorchain.cpp. +bool kkconfirm_preload(int nYes, int nNo); +int kkconfirm_drain(void); + +static void ensure_auth_storage_initialized(void) { + static bool initialized = false; + if (!initialized) { + setup(); + storage_init(); + initialized = true; + } +} + +TEST(Authenticator, WipeCancellationFailsClosed) { + ensure_auth_storage_initialized(); + ASSERT_TRUE(kkconfirm_preload(0, 1)); + EXPECT_EQ(AUTH_CANCELLED, wipeAuthData()); + EXPECT_EQ(0, kkconfirm_drain()); +} + +TEST(Authenticator, AddAndRemoveCancellationFailsClosed) { + ensure_auth_storage_initialized(); + ASSERT_TRUE(kkconfirm_preload(1, 0)); + EXPECT_EQ(NOERR, wipeAuthData()); + EXPECT_EQ(0, kkconfirm_drain()); + + char cancelled_add[] = "example:alice:JBSWY3DPEHPK3PXPJBSWY3DPEHPK3PXP"; + ASSERT_TRUE(kkconfirm_preload(0, 1)); + EXPECT_EQ(AUTH_CANCELLED, addAuthAccount(cancelled_add)); + EXPECT_EQ(0, kkconfirm_drain()); + + char account[DOMAIN_SIZE + ACCOUNT_SIZE + 2] = {0}; + EXPECT_EQ(NOACC, getAuthAccount("0", account)); + + char accepted_add[] = "example:alice:JBSWY3DPEHPK3PXPJBSWY3DPEHPK3PXP"; + ASSERT_TRUE(kkconfirm_preload(2, 0)); + EXPECT_EQ(NOERR, addAuthAccount(accepted_add)); + EXPECT_EQ(0, kkconfirm_drain()); + + char cancelled_remove[] = "example:alice"; + ASSERT_TRUE(kkconfirm_preload(0, 1)); + EXPECT_EQ(AUTH_CANCELLED, removeAuthAccount(cancelled_remove)); + EXPECT_EQ(0, kkconfirm_drain()); + EXPECT_EQ(NOERR, getAuthAccount("0", account)); + EXPECT_STREQ("example:alice", account); + + ASSERT_TRUE(kkconfirm_preload(1, 0)); + EXPECT_EQ(NOERR, wipeAuthData()); + EXPECT_EQ(0, kkconfirm_drain()); +} + +TEST(Authenticator, RejectsAmbiguousDisplayFieldsBeforeMutation) { + char long_domain[] = "domain-is-too-long:alice:JBSWY3DPEHPK3PXP"; + EXPECT_EQ(TOKERR, addAuthAccount(long_domain)); + + char control_domain[] = "bad\ndomain:alice:JBSWY3DPEHPK3PXP"; + EXPECT_EQ(TOKERR, addAuthAccount(control_domain)); + + char long_account[] = "example:account-is-too-long:JBSWY3DPEHPK3PXP"; + EXPECT_EQ(TOKERR, addAuthAccount(long_account)); + + char remove_long[] = "example:account-is-too-long"; + EXPECT_EQ(TOKERR, removeAuthAccount(remove_long)); + + char remove_control[] = "example:bad\naccount"; + EXPECT_EQ(TOKERR, removeAuthAccount(remove_control)); +} + +TEST(Authenticator, RejectsWeakAndDuplicateSecrets) { + ensure_auth_storage_initialized(); + ASSERT_TRUE(kkconfirm_preload(1, 0)); + EXPECT_EQ(NOERR, wipeAuthData()); + EXPECT_EQ(0, kkconfirm_drain()); + + char weak[] = "example:weak:MY"; + EXPECT_EQ(BADSECRET, addAuthAccount(weak)); + + // The final invalid block fails after earlier blocks have decoded; the + // implementation must still take its cleanup path. + char partially_decoded[] = "example:invalid:JBSWY3DPEHPK3PXPJBSWY3DPEHPK3PX!"; + EXPECT_EQ(BADSECRET, addAuthAccount(partially_decoded)); + + char first[] = "example:alice:JBSWY3DPEHPK3PXPJBSWY3DPEHPK3PXP"; + ASSERT_TRUE(kkconfirm_preload(2, 0)); + EXPECT_EQ(NOERR, addAuthAccount(first)); + EXPECT_EQ(0, kkconfirm_drain()); + + char duplicate[] = "example:alice:KRSXG5DSNFXGOIDBKRSXG5DSNFXGOIDB"; + EXPECT_EQ(DUPLICATE, addAuthAccount(duplicate)); + + char account[DOMAIN_SIZE + ACCOUNT_SIZE + 2] = {0}; + EXPECT_EQ(NOACC, getAuthAccount("1", account)); + + char remove[] = "example:alice"; + ASSERT_TRUE(kkconfirm_preload(1, 0)); + EXPECT_EQ(NOERR, removeAuthAccount(remove)); + EXPECT_EQ(0, kkconfirm_drain()); + EXPECT_EQ(NOACC, getAuthAccount("0", account)); +} diff --git a/unittests/firmware/binance.cpp b/unittests/firmware/binance.cpp new file mode 100644 index 000000000..66789e3a7 --- /dev/null +++ b/unittests/firmware/binance.cpp @@ -0,0 +1,83 @@ +extern "C" { +#include "keepkey/transport/interface.h" +#include "keepkey/firmware/binance.h" +} + +#include "gtest/gtest.h" + +#include +#include "trezor/crypto/secp256k1.h" + +static BinanceTransferMsg transfer(const char* denom, int64_t amount) { + BinanceTransferMsg msg = {}; + msg.inputs_count = 1; + msg.outputs_count = 1; + msg.inputs[0].coins_count = 1; + msg.outputs[0].coins_count = 1; + msg.inputs[0].has_address = true; + msg.outputs[0].has_address = true; + strcpy(msg.inputs[0].address, "tbnb1hgm0p7khfk85zpz5v0j8wnej3a90w709zzlffd"); + strcpy(msg.outputs[0].address, "tbnb1ss57e8sa7xnwq030k2ctr775uac9gjzglqhvpy"); + msg.inputs[0].coins[0].has_amount = true; + msg.outputs[0].coins[0].has_amount = true; + msg.inputs[0].coins[0].amount = amount; + msg.outputs[0].coins[0].amount = amount; + msg.inputs[0].coins[0].has_denom = true; + msg.outputs[0].coins[0].has_denom = true; + strcpy(msg.inputs[0].coins[0].denom, denom); + strcpy(msg.outputs[0].coins[0].denom, denom); + return msg; +} + +TEST(Binance, DenomBoundsAndGrammar) { + EXPECT_TRUE(binance_isValidDenom("BNB")); + EXPECT_TRUE(binance_isValidDenom("RUNE-B1A")); + EXPECT_TRUE(binance_isValidDenom("ABCDEFGH-123")); + EXPECT_TRUE(binance_isValidDenom("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")); + EXPECT_FALSE(binance_isValidDenom("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")); + EXPECT_FALSE(binance_isValidDenom("bnb")); + EXPECT_FALSE(binance_isValidDenom("BNB\"")); + EXPECT_FALSE(binance_isValidDenom("BN B")); + EXPECT_FALSE(binance_isValidDenom("")); +} + +TEST(Binance, TransferValidationFailsClosed) { + BinanceTransferMsg msg = transfer("RUNE-B1A", 1000000000); + EXPECT_TRUE(binance_validateTransfer(&msg)); + + msg = transfer("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 1000000000); + EXPECT_TRUE(binance_validateTransfer(&msg)); + + msg = transfer("BNB", 0); + EXPECT_FALSE(binance_validateTransfer(&msg)); + msg = transfer("BNB", -1); + EXPECT_FALSE(binance_validateTransfer(&msg)); + + msg = transfer("BNB", 1); + msg.outputs[0].coins[0].amount = 2; + EXPECT_FALSE(binance_validateTransfer(&msg)); + + msg = transfer("BNB", 1); + msg.outputs[0].coins[0].has_denom = false; + EXPECT_FALSE(binance_validateTransfer(&msg)); +} + +TEST(Binance, SigningSessionRequiresCanonicalEnvelopeState) { + HDNode node = {}; + node.curve = &secp256k1_info; + BinanceSignTx envelope = {}; + EXPECT_FALSE(binance_signTxInit(&node, &envelope)); + EXPECT_FALSE(binance_signingIsInited()); + + envelope.has_msg_count = true; + envelope.msg_count = 1; + envelope.has_account_number = true; + envelope.has_chain_id = true; + strcpy(envelope.chain_id, "Binance-Chain-Nile"); + envelope.has_sequence = true; + envelope.has_source = true; + EXPECT_TRUE(binance_signTxInit(&node, &envelope)); + EXPECT_TRUE(binance_signingIsInited()); + EXPECT_FALSE(binance_signingIsFinished()); + binance_signAbort(); +} diff --git a/unittests/firmware/coins.cpp b/unittests/firmware/coins.cpp index c11a59bd6..5f4a5f631 100644 --- a/unittests/firmware/coins.cpp +++ b/unittests/firmware/coins.cpp @@ -75,6 +75,17 @@ TEST(Coins, TableSanity) { if (!coin.has_contract_address) continue; + // Pre-existing (not 7.x-release related): these legacy coins[] entries are + // display-only leftovers whose ERC20 entries were dropped from the generated + // token table years ago (dead/migrated tokens). Named allowlist so a *new* + // missing token still fails this sanity check. + static const char *const kLegacyNoTokenEntry[] = { + "QTUM", "BNB", "ZIL", "GTO", "IOST", "CMT", "MCO", "ODEM"}; + bool legacy = false; + for (const char *t : kLegacyNoTokenEntry) + if (strcmp(coin.coin_shortcut, t) == 0) { legacy = true; break; } + if (legacy) continue; + const TokenType *token; if (!tokenByTicker(1, coin.coin_shortcut, &token)) { EXPECT_TRUE(false) << "Can't uniquely find " << coin.coin_shortcut; diff --git a/unittests/firmware/cosmos.cpp b/unittests/firmware/cosmos.cpp index d150fda34..96d565285 100644 --- a/unittests/firmware/cosmos.cpp +++ b/unittests/firmware/cosmos.cpp @@ -3,6 +3,7 @@ extern "C" { #include "keepkey/firmware/cosmos.h" #include "keepkey/firmware/signtx_tendermint.h" #include "keepkey/firmware/tendermint.h" +#include "messages-tendermint.pb.h" #include "trezor/crypto/secp256k1.h" } @@ -54,10 +55,14 @@ TEST(Cosmos, CosmosSignTx) { true, 0, // sequence true, 1 // msg_count }; - ASSERT_TRUE(tendermint_signTxInit(&node, &msg, sizeof(CosmosSignTx), "uatom")); - - ASSERT_TRUE(tendermint_signTxUpdateMsgSend(100000, "cosmos18vhdczjut44gpsy804crfhnd5nq003nz0nf20v", "cosmos", "uatom", "cosmos-sdk")); + ASSERT_TRUE(tendermint_signTxInit(&node, &msg, sizeof(CosmosSignTx), "uatom", + TENDERMINT_SIGNING_COSMOS)); + EXPECT_TRUE(tendermint_signingIsInited(TENDERMINT_SIGNING_COSMOS)); + EXPECT_FALSE(tendermint_signingIsInited(TENDERMINT_SIGNING_GENERIC)); + ASSERT_TRUE(tendermint_signTxUpdateMsgSend( + 100000, "cosmos18vhdczjut44gpsy804crfhnd5nq003nz0nf20v", "cosmos", + "uatom", "cosmos-sdk")); uint8_t public_key[33]; uint8_t signature[64]; @@ -72,3 +77,38 @@ TEST(Cosmos, CosmosSignTx) { "\x47\x56\x43\xca\x33\xc7\xad\x2c\x8a\x53\x2b\x39", 64) == 0); } + +TEST(Cosmos, TendermintSessionBindsProtocolAndAssetConfiguration) { + HDNode node = {}; + node.curve = &secp256k1_info; + TendermintSignTx msg = {}; + msg.has_account_number = true; + msg.has_chain_id = true; + strcpy(msg.chain_id, "chain-1"); + msg.has_fee_amount = true; + msg.fee_amount = 1; + msg.has_gas = true; + msg.gas = 1; + msg.has_sequence = true; + msg.has_msg_count = true; + msg.msg_count = 1; + msg.has_chain_name = true; + strcpy(msg.chain_name, "Cosmos"); + msg.has_denom = true; + strcpy(msg.denom, "uatom"); + msg.has_message_type_prefix = true; + strcpy(msg.message_type_prefix, "cosmos-sdk"); + + ASSERT_TRUE(tendermint_signTxInit(&node, &msg, sizeof(msg), msg.denom, + TENDERMINT_SIGNING_GENERIC)); + EXPECT_TRUE(tendermint_signingIsInited(TENDERMINT_SIGNING_GENERIC)); + EXPECT_FALSE(tendermint_signingIsInited(TENDERMINT_SIGNING_COSMOS)); + EXPECT_TRUE(tendermint_signingConfigMatches("Cosmos", "uatom", "cosmos-sdk")); + EXPECT_FALSE( + tendermint_signingConfigMatches("Cosmos", "uosmo", "cosmos-sdk")); + EXPECT_FALSE( + tendermint_signingConfigMatches("Osmosis", "uatom", "cosmos-sdk")); + EXPECT_FALSE( + tendermint_signingConfigMatches("Cosmos", "uatom", "other-prefix")); + tendermint_signAbort(); +} diff --git a/unittests/firmware/eip712.cpp b/unittests/firmware/eip712.cpp new file mode 100644 index 000000000..c1c8d4447 --- /dev/null +++ b/unittests/firmware/eip712.cpp @@ -0,0 +1,67 @@ +extern "C" { +#include "keepkey/firmware/eip712.h" +} + +#include "gtest/gtest.h" + +#include + +TEST(EIP712, AddressRequiresCanonicalTwentyByteHex) { + uint8_t encoded[32] = {0}; + ASSERT_EQ(SUCCESS, + encAddress("0x00112233445566778899aabbccddeeff00112233", encoded)); + for (size_t i = 0; i < 12; i++) EXPECT_EQ(0, encoded[i]); + EXPECT_EQ(0x00, encoded[12]); + EXPECT_EQ(0x11, encoded[13]); + EXPECT_EQ(0x33, encoded[31]); + + EXPECT_NE(SUCCESS, encAddress("0x112233", encoded)); + EXPECT_NE(SUCCESS, + encAddress("00112233445566778899aabbccddeeff00112233", encoded)); + EXPECT_NE(SUCCESS, + encAddress("0x00112233445566778899aabbccddeeff0011223g", encoded)); + EXPECT_NE(SUCCESS, encAddress("0x00112233445566778899aabbccddeeff0011223344", + encoded)); +} + +TEST(EIP712, DynamicBytesRequireCompleteHexOctets) { + uint8_t encoded[32] = {0}; + EXPECT_EQ(SUCCESS, encodeBytes("0x", encoded)); + EXPECT_EQ(SUCCESS, encodeBytes("0x00a1FF", encoded)); + EXPECT_NE(SUCCESS, encodeBytes("00a1", encoded)); + EXPECT_NE(SUCCESS, encodeBytes("0x0", encoded)); + EXPECT_NE(SUCCESS, encodeBytes("0x0z", encoded)); +} + +TEST(EIP712, FixedBytesRequireExactDeclaredLength) { + uint8_t encoded[32]; + memset(encoded, 0xa5, sizeof(encoded)); + ASSERT_EQ(SUCCESS, encodeBytesN("bytes4", "0x0011aAff", encoded)); + EXPECT_EQ(0x00, encoded[0]); + EXPECT_EQ(0x11, encoded[1]); + EXPECT_EQ(0xaa, encoded[2]); + EXPECT_EQ(0xff, encoded[3]); + for (size_t i = 4; i < sizeof(encoded); i++) EXPECT_EQ(0, encoded[i]); + + EXPECT_NE(SUCCESS, encodeBytesN("bytes4", "0x0011aa", encoded)); + EXPECT_NE(SUCCESS, encodeBytesN("bytes4", "0x0011aaff00", encoded)); + EXPECT_NE(SUCCESS, encodeBytesN("bytes0", "0x", encoded)); + EXPECT_NE(SUCCESS, encodeBytesN("bytes33", "0x", encoded)); + EXPECT_NE(SUCCESS, encodeBytesN("bytes4x", "0x0011aaff", encoded)); +} + +TEST(EIP712, MissingTypedValueFailsWithoutDereferencingNull) { + char types_json[] = + "{\"types\":{\"Mail\":[{\"name\":\"from\",\"type\":\"address\"}," + "{\"name\":\"note\",\"type\":\"string\"}]}}"; + char values_json[] = "{\"message\":{\"note\":\"hello\"}}"; + json_t type_nodes[16] = {}; + json_t value_nodes[8] = {}; + const json_t* types = json_create(types_json, type_nodes, 16); + const json_t* values = json_create(values_json, value_nodes, 8); + ASSERT_NE(nullptr, types); + ASSERT_NE(nullptr, values); + + uint8_t hash[32] = {}; + EXPECT_EQ(JSON_TYPE_WNOVAL, encode(types, values, "Mail", hash)); +} diff --git a/unittests/firmware/eos.cpp b/unittests/firmware/eos.cpp index c15f220e1..b1e61a48e 100644 --- a/unittests/firmware/eos.cpp +++ b/unittests/firmware/eos.cpp @@ -7,6 +7,23 @@ extern "C" { #include +TEST(EOS, UnknownActionsRequireAdvancedMode) { + EXPECT_FALSE(eos_unknownActionPolicyAllows(false)); + EXPECT_TRUE(eos_unknownActionPolicyAllows(true)); +} + +TEST(EOS, NewAccountCannotDowngradeToUnknownAction) { + EosActionCommon common = {}; + common.has_account = true; + common.account = EOS_eosio; + common.has_name = true; + common.name = EOS_NewAccount; + EXPECT_TRUE(eos_isSupportedAction(&common)); + + common.account = 0x1111111111111111ULL; + EXPECT_FALSE(eos_isSupportedAction(&common)); +} + TEST(EOS, FormatNameVec) { struct { uint64_t value; diff --git a/unittests/firmware/ethereum.cpp b/unittests/firmware/ethereum.cpp index f8329a416..83e67af23 100644 --- a/unittests/firmware/ethereum.cpp +++ b/unittests/firmware/ethereum.cpp @@ -1,11 +1,19 @@ extern "C" { +#include "keepkey/firmware/ethereum.h" +#include "keepkey/firmware/ethereum_contracts/zxappliquid.h" +#include "keepkey/firmware/ethereum_contracts/zxliquidtx.h" +#include "keepkey/firmware/ethereum_tokens.h" #include "trezor/crypto/address.h" } #include "gtest/gtest.h" +#include #include +bool kkconfirm_preload(int nYes, int nNo); +int kkconfirm_drain(void); + static uint8_t bin_from_ascii(char c) { if ('a' <= c && c <= 'f') return c - 'a' + 0xa; @@ -16,7 +24,7 @@ static uint8_t bin_from_ascii(char c) { __builtin_unreachable(); } -static void test_checksum(const std::string &addr) { +static void test_checksum(const std::string& addr) { uint8_t addr_bin[20]; for (size_t i = 0; i < addr.size(); i += 2) { addr_bin[i / 2] = bin_from_ascii(addr[i + 1]) | bin_from_ascii(addr[i]) @@ -38,3 +46,209 @@ TEST(Ethereum, AddressChecksum) { test_checksum("dbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB"); test_checksum("D1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb"); } + +TEST(Ethereum, TypedHashSigningRequiresAdvancedMode) { + EXPECT_FALSE(ethereum_typed_hash_policy_allows(false)); + EXPECT_TRUE(ethereum_typed_hash_policy_allows(true)); +} + +TEST(Ethereum, DomainOnlyPrimaryTypeRequiresExactMatch) { + EXPECT_TRUE(ethereum_eip712_is_domain_primary_type("EIP712Domain")); + EXPECT_FALSE(ethereum_eip712_is_domain_primary_type("EIP")); + EXPECT_FALSE(ethereum_eip712_is_domain_primary_type("EIP712Domain[]")); + EXPECT_FALSE(ethereum_eip712_is_domain_primary_type("")); + EXPECT_FALSE(ethereum_eip712_is_domain_primary_type(nullptr)); +} + +static const uint8_t DAI_MAINNET_ADDRESS[20] = { + 0x6b, 0x17, 0x54, 0x74, 0xe8, 0x90, 0x94, 0xc4, 0x4d, 0xa9, + 0x8b, 0x95, 0x4e, 0xed, 0xea, 0xc4, 0x95, 0x27, 0x1d, 0x0f}; +static const uint8_t USDC_MAINNET_ADDRESS[20] = { + 0xa0, 0xb8, 0x69, 0x91, 0xc6, 0x21, 0x8b, 0x36, 0xc1, 0xd1, + 0x9d, 0x4a, 0x2e, 0x9e, 0xb0, 0xce, 0x36, 0x06, 0xeb, 0x48}; + +static EthereumSignTx liquidity_tx( + bool known_token, bool add = true, + const uint8_t* token_address = DAI_MAINNET_ADDRESS) { + EthereumSignTx msg; + memset(&msg, 0, sizeof(msg)); + msg.has_chain_id = true; + msg.chain_id = 1; + msg.has_to = true; + msg.to.size = 20; + memcpy(msg.to.bytes, UNISWAP_ROUTER_ADDRESS, 20); + msg.has_data_initial_chunk = true; + msg.data_initial_chunk.size = 4 + 6 * 32; + memcpy(msg.data_initial_chunk.bytes, + add ? "\xf3\x05\xd7\x19" : "\x02\x75\x1c\xec", 4); + + const TokenType* token = tokenByChainAddress(1, token_address); + EXPECT_NE(UnknownToken, token); + if (token == UnknownToken) return msg; + uint8_t unknown[20]; + memset(unknown, 0xa5, sizeof(unknown)); + memcpy( + msg.data_initial_chunk.bytes + 4 + 32 - 20, + known_token ? reinterpret_cast(token->address) : unknown, + 20); + + // Token desired/minimum and native minimum. + msg.data_initial_chunk.bytes[4 + 2 * 32 - 1] = 1; + msg.data_initial_chunk.bytes[4 + 3 * 32 - 1] = 1; + msg.data_initial_chunk.bytes[4 + 4 * 32 - 1] = 1; + // Recipient and deadline. + memset(msg.data_initial_chunk.bytes + 4 + 5 * 32 - 20, 0x11, 20); + msg.data_initial_chunk.bytes[4 + 6 * 32 - 1] = 1; + msg.has_value = true; + if (add) { + msg.value.size = 1; + msg.value.bytes[0] = 1; + } + return msg; +} + +static void set_word_u64(EthereumSignTx& msg, size_t word, uint64_t value) { + uint8_t* out = msg.data_initial_chunk.bytes + 4 + word * 32; + memset(out, 0, 32); + for (size_t i = 0; i < 8; i++) { + out[31 - i] = static_cast(value); + value >>= 8; + } +} + +static EthereumSignTx approve_liquidity_tx() { + EthereumSignTx msg; + memset(&msg, 0, sizeof(msg)); + msg.has_chain_id = true; + msg.chain_id = 1; + msg.has_to = true; + msg.to.size = 20; + // Canonical mainnet DAI/WETH Uniswap V2 pair. + const uint8_t pair[20] = {0xa4, 0x78, 0xc2, 0x97, 0x5a, 0xb1, 0xea, + 0x89, 0xe8, 0x19, 0x68, 0x11, 0xf5, 0x1a, + 0x7b, 0x7a, 0xde, 0x33, 0xeb, 0x11}; + memcpy(msg.to.bytes, pair, sizeof(pair)); + msg.has_data_initial_chunk = true; + msg.data_initial_chunk.size = 4 + 2 * 32; + memcpy(msg.data_initial_chunk.bytes, "\x09\x5e\xa7\xb3", 4); + memcpy(msg.data_initial_chunk.bytes + 4 + 12, UNISWAP_ROUTER_ADDRESS, 20); + msg.data_initial_chunk.bytes[4 + 2 * 32 - 1] = 1; + msg.has_value = true; + return msg; +} + +TEST(Ethereum, LiquiditySelectorChecksDeclaredCalldataLength) { + EthereumSignTx msg; + memset(&msg, 0, sizeof(msg)); + msg.has_to = true; + msg.to.size = 20; + memcpy(msg.to.bytes, UNISWAP_ROUTER_ADDRESS, 20); + msg.has_data_initial_chunk = true; + msg.data_initial_chunk.size = 3; + memcpy(msg.data_initial_chunk.bytes, "\xf3\x05\xd7", 3); + EXPECT_FALSE(zx_isZxLiquidTx(&msg)); + + msg.data_initial_chunk.size = 4; + memcpy(msg.data_initial_chunk.bytes, "\x09\x5e\xa7\xb3", 4); + EXPECT_FALSE(zx_isZxApproveLiquid(&msg)); + + msg.data_initial_chunk.size = 4 + 2 * 32 + 1; + memcpy(msg.data_initial_chunk.bytes, "\x09\x5e\xa7\xb3", 4); + memcpy(msg.data_initial_chunk.bytes + 4 + 32 - 20, UNISWAP_ROUTER_ADDRESS, + 20); + EXPECT_FALSE(zx_isZxApproveLiquid(&msg)); + + msg.data_initial_chunk.size = 4 + 6 * 32 + 1; + memcpy(msg.data_initial_chunk.bytes, "\xf3\x05\xd7\x19", 4); + EXPECT_FALSE(zx_isZxLiquidTx(&msg)); +} + +TEST(Ethereum, LiquidityCancellationFailsClosed) { + EthereumSignTx msg = liquidity_tx(true); + ASSERT_TRUE(kkconfirm_preload(0, 1)); + EXPECT_FALSE(zx_confirmZxLiquidTx(msg.data_initial_chunk.size, &msg)); + EXPECT_EQ(0, kkconfirm_drain()); +} + +TEST(Ethereum, LiquidityRejectsUnknownTokenBeforeConfirmation) { + EthereumSignTx msg = liquidity_tx(false); + EXPECT_FALSE(zx_confirmZxLiquidTx(msg.data_initial_chunk.size, &msg)); +} + +TEST(Ethereum, LiquidityClearSigningIsMainnetOnly) { + EthereumSignTx msg = liquidity_tx(true); + EXPECT_TRUE(zx_isZxLiquidTx(&msg)); + + msg.chain_id = 137; + EXPECT_FALSE(zx_isZxLiquidTx(&msg)); + msg.chain_id = 1; + msg.has_chain_id = false; + EXPECT_FALSE(zx_isZxLiquidTx(&msg)); +} + +TEST(Ethereum, LiquidityRejectsTruncatedDeadlineAndNoncanonicalAddresses) { + EthereumSignTx msg = liquidity_tx(true); + msg.data_initial_chunk.bytes[4 + 5 * 32] = 1; + EXPECT_FALSE(zx_isZxLiquidTx(&msg)); + EXPECT_FALSE(zx_confirmZxLiquidTx(msg.data_initial_chunk.size, &msg)); + + msg = liquidity_tx(true); + msg.data_initial_chunk.bytes[4] = 1; + EXPECT_FALSE(zx_isZxLiquidTx(&msg)); + + msg = liquidity_tx(true); + msg.data_initial_chunk.bytes[4 + 4 * 32] = 1; + EXPECT_FALSE(zx_isZxLiquidTx(&msg)); +} + +TEST(Ethereum, RemoveLiquidityRejectsNativeValue) { + EthereumSignTx msg = liquidity_tx(true, false); + EXPECT_TRUE(zx_isZxLiquidTx(&msg)); + msg.value.size = 1; + msg.value.bytes[0] = 1; + EXPECT_FALSE(zx_isZxLiquidTx(&msg)); +} + +TEST(Ethereum, RemoveLiquidityFormatsPrimaryAmountAsLpTokens) { + EthereumSignTx add = liquidity_tx(true, true, USDC_MAINNET_ADDRESS); + set_word_u64(add, 1, UINT64_C(1000000000000000000)); + char formatted[96]; + ASSERT_TRUE( + zx_formatZxLiquidityPrimaryAmount(&add, formatted, sizeof(formatted))); + EXPECT_STREQ("1000000000000 USDC", formatted); + + EthereumSignTx remove = liquidity_tx(true, false, USDC_MAINNET_ADDRESS); + set_word_u64(remove, 1, UINT64_C(1000000000000000000)); + ASSERT_TRUE( + zx_formatZxLiquidityPrimaryAmount(&remove, formatted, sizeof(formatted))); + EXPECT_STREQ("1 LP", formatted); +} + +TEST(Ethereum, LiquidityFormatsFullUint256WithoutBlankConfirmation) { + EthereumSignTx msg = liquidity_tx(true); + memset(msg.data_initial_chunk.bytes + 4 + 32, 0xff, 32); + char formatted[96]; + ASSERT_TRUE( + zx_formatZxLiquidityPrimaryAmount(&msg, formatted, sizeof(formatted))); + EXPECT_GT(strlen(formatted), 32u); + + ASSERT_TRUE(kkconfirm_preload(0, 1)); + EXPECT_FALSE(zx_confirmZxLiquidTx(msg.data_initial_chunk.size, &msg)); + EXPECT_EQ(0, kkconfirm_drain()); +} + +TEST(Ethereum, LpApprovalRequiresMainnetDerivedPairAndCanonicalSpender) { + EthereumSignTx msg = approve_liquidity_tx(); + EXPECT_TRUE(zx_isZxApproveLiquid(&msg)); + + msg.to.bytes[0] ^= 1; + EXPECT_FALSE(zx_isZxApproveLiquid(&msg)); + + msg = approve_liquidity_tx(); + msg.chain_id = 137; + EXPECT_FALSE(zx_isZxApproveLiquid(&msg)); + + msg = approve_liquidity_tx(); + msg.data_initial_chunk.bytes[4] = 1; + EXPECT_FALSE(zx_isZxApproveLiquid(&msg)); +} diff --git a/unittests/firmware/hive.cpp b/unittests/firmware/hive.cpp new file mode 100644 index 000000000..4a90cdba0 --- /dev/null +++ b/unittests/firmware/hive.cpp @@ -0,0 +1,983 @@ +extern "C" { +#include "keepkey/board/font.h" +#include "keepkey/board/layout.h" +#include "keepkey/firmware/hive.h" +} + +#include "gtest/gtest.h" + +#include +#include +#include +#include + +namespace { + +void append_varint(std::vector& out, uint32_t value) { + do { + uint8_t byte = static_cast(value & 0x7f); + value >>= 7; + if (value != 0) byte |= 0x80; + out.push_back(byte); + } while (value != 0); +} + +void append_u16_le(std::vector& out, uint16_t value) { + out.push_back(static_cast(value)); + out.push_back(static_cast(value >> 8)); +} + +void append_u32_le(std::vector& out, uint32_t value) { + for (int i = 0; i < 4; i++) { + out.push_back(static_cast(value >> (8 * i))); + } +} + +void append_string(std::vector& out, const std::string& value) { + append_varint(out, static_cast(value.size())); + out.insert(out.end(), value.begin(), value.end()); +} + +std::string slice(const uint8_t* value, uint16_t len) { + return std::string(reinterpret_cast(value), len); +} + +std::vector comment_tx(const std::string& parent_author, + const std::string& parent_permlink, + const std::string& author, + const std::string& permlink, + const std::string& title, + const std::string& body, + const std::string& json_metadata) { + std::vector tx; + append_u16_le(tx, 12345); + append_u32_le(tx, 67890); + append_u32_le(tx, 1700000000); + append_varint(tx, 1); + append_varint(tx, HIVE_OP_COMMENT); + append_string(tx, parent_author); + append_string(tx, parent_permlink); + append_string(tx, author); + append_string(tx, permlink); + append_string(tx, title); + append_string(tx, body); + append_string(tx, json_metadata); + append_varint(tx, 0); + return tx; +} + +// Call sites pass DISPLAY symbols ("HIVE"/"HBD") because that is what the test +// is about; this helper writes what the chain actually serializes. Verified +// against hived itself via condenser_api.get_transaction_hex — see +// Hive.SerializationMatchesHived. +std::string wire_symbol(const std::string& display) { + if (display == "HIVE") return "STEEM"; + if (display == "HBD") return "SBD"; + return display; +} + +void append_asset(std::vector& out, int64_t amount, uint8_t precision, + const std::string& symbol) { + const std::string wire = wire_symbol(symbol); + uint64_t raw = static_cast(amount); + for (int i = 0; i < 8; i++) { + out.push_back(static_cast(raw >> (8 * i))); + } + out.push_back(precision); + for (size_t i = 0; i < 7; i++) { + out.push_back(i < wire.size() ? static_cast(wire[i]) : 0); + } +} + +// Wrap already-serialized ops in the 10-byte TaPoS header, op count and the +// empty extensions varint that hive_parseOperations expects. +std::vector wrap_ops(const std::vector>& ops) { + std::vector tx; + append_u16_le(tx, 12345); + append_u32_le(tx, 67890); + append_u32_le(tx, 1700000000); + append_varint(tx, static_cast(ops.size())); + for (const std::vector& op : ops) { + tx.insert(tx.end(), op.begin(), op.end()); + } + append_varint(tx, 0); + return tx; +} + +std::vector limit_order_create_op( + const std::string& owner, uint32_t orderid, int64_t sell, + const std::string& sell_symbol, int64_t receive, + const std::string& receive_symbol, bool fill_or_kill, uint32_t expiration) { + std::vector op; + append_varint(op, HIVE_OP_LIMIT_ORDER_CREATE); + append_string(op, owner); + append_u32_le(op, orderid); + append_asset(op, sell, 3, sell_symbol); + append_asset(op, receive, 3, receive_symbol); + op.push_back(fill_or_kill ? 1 : 0); + append_u32_le(op, expiration); + return op; +} + +// A limit order priced in VESTS at its CORRECT precision (6), so the +// rejection comes from the symbol whitelist rather than the precision check. +std::vector limit_order_vests_op() { + std::vector op; + append_varint(op, HIVE_OP_LIMIT_ORDER_CREATE); + append_string(op, "alice"); + append_u32_le(op, 1); + append_asset(op, 100, 6, "VESTS"); + append_asset(op, 100, 3, "HBD"); + op.push_back(0); + append_u32_le(op, 1); + return op; +} + +// transfer_to_vesting with a caller-chosen symbol/precision, so the asset +// validator can be probed with values a correct host would never send. +std::vector power_up_op(int64_t amount, uint8_t precision, + const std::string& symbol) { + std::vector op; + append_varint(op, HIVE_OP_TRANSFER_TO_VESTING); + append_string(op, "alice"); + append_string(op, "bob"); + append_asset(op, amount, precision, symbol); + return op; +} + +std::vector comment_op(const std::string& author, + const std::string& permlink) { + std::vector op; + append_varint(op, HIVE_OP_COMMENT); + append_string(op, ""); + append_string(op, "hive-100"); + append_string(op, author); + append_string(op, permlink); + append_string(op, "Title"); + append_string(op, "Body"); + append_string(op, "{}"); + return op; +} + +// beneficiaries: (account, basis-point weight) pairs; empty = no extension. +std::vector comment_options_op( + const std::string& author, const std::string& permlink, + const std::vector>& beneficiaries) { + std::vector op; + append_varint(op, HIVE_OP_COMMENT_OPTIONS); + append_string(op, author); + append_string(op, permlink); + append_asset(op, 1000000, 3, "HBD"); + append_u16_le(op, 10000); + op.push_back(1); + op.push_back(1); + if (beneficiaries.empty()) { + append_varint(op, 0); + } else { + append_varint(op, 1); + append_varint(op, 0); + append_varint(op, static_cast(beneficiaries.size())); + for (const auto& b : beneficiaries) { + append_string(op, b.first); + append_u16_le(op, b.second); + } + } + return op; +} + +std::vector account_update2_op(const std::string& json_metadata, + const std::string& posting_metadata, + bool authority_present) { + std::vector op; + append_varint(op, HIVE_OP_ACCOUNT_UPDATE2); + append_string(op, "alice"); + op.push_back(authority_present ? 1 : 0); + op.push_back(0); + op.push_back(0); + op.push_back(0); + append_string(op, json_metadata); + append_string(op, posting_metadata); + append_varint(op, 0); + return op; +} + +std::vector custom_json_op( + const std::vector& active_auths, + const std::vector& posting_auths, const std::string& id, + const std::string& json) { + std::vector op; + append_varint(op, HIVE_OP_CUSTOM_JSON); + append_varint(op, static_cast(active_auths.size())); + for (const std::string& auth : active_auths) append_string(op, auth); + append_varint(op, static_cast(posting_auths.size())); + for (const std::string& auth : posting_auths) append_string(op, auth); + append_string(op, id); + append_string(op, json); + return op; +} + +} // namespace + +TEST(Hive, Slip48PathValidation) { + uint32_t path[5] = {HIVE_SLIP48_PURPOSE, HIVE_SLIP48_NETWORK, + HIVE_ROLE_ACTIVE, 0x80000007u, 0x80000000u}; + + EXPECT_TRUE(hive_slip48_path_valid(path, 5)); + EXPECT_TRUE(hive_slip48_path_valid_for_role(path, 5, HIVE_ROLE_ACTIVE)); + EXPECT_FALSE(hive_slip48_path_valid_for_role(path, 5, HIVE_ROLE_OWNER)); + EXPECT_FALSE(hive_slip48_path_valid(path, 4)); + + path[0] = 0x8000002cu; + EXPECT_FALSE(hive_slip48_path_valid(path, 5)); + path[0] = HIVE_SLIP48_PURPOSE; + path[1] = 0x8000003cu; + EXPECT_FALSE(hive_slip48_path_valid(path, 5)); + path[1] = HIVE_SLIP48_NETWORK; + path[2] = 0x80000002u; + EXPECT_FALSE(hive_slip48_path_valid(path, 5)); + path[2] = HIVE_ROLE_ACTIVE; + path[3] = 7; + EXPECT_FALSE(hive_slip48_path_valid(path, 5)); + path[3] = 0x80000007u; + path[4] = 0; + EXPECT_FALSE(hive_slip48_path_valid(path, 5)); +} + +TEST(Hive, CommentParserRetainsEveryDisplayedField) { + std::vector tx = comment_tx( + "parent-author", "parent-permlink", "reply-author", "reply-permlink", + "Reply title", "Complete reply body", "{\"tags\":[\"keepkey\"]}"); + + HiveParsedTx parsed; + ASSERT_EQ(nullptr, hive_parseOperations(tx.data(), tx.size(), &parsed)); + ASSERT_EQ(1, parsed.num_ops); + const HiveTxOp& op = parsed.ops[0]; + EXPECT_FALSE(op.is_top_level); + EXPECT_EQ("reply-author", slice(op.acct, op.acct_len)); + EXPECT_EQ("parent-author", slice(op.parent_author, op.parent_author_len)); + EXPECT_EQ("parent-permlink", + slice(op.parent_permlink, op.parent_permlink_len)); + EXPECT_EQ("reply-permlink", slice(op.permlink, op.permlink_len)); + EXPECT_EQ("Reply title", slice(op.target, op.target_len)); + EXPECT_EQ("Complete reply body", slice(op.detail, op.detail_len)); + EXPECT_EQ("{\"tags\":[\"keepkey\"]}", + slice(op.json_metadata, op.json_metadata_len)); +} + +// Message signing is restricted to printable ASCII so a message can never be a +// binary transaction preimage (chain_id || serialized_tx) on any chain id. +TEST(Hive, MessagePrintableAcceptsAsciiRejectsBinary) { + const char* login = "keepkey-login-challenge:1700000000"; + EXPECT_TRUE(hive_message_is_printable(reinterpret_cast(login), + strlen(login))); + + // Empty message is trivially printable. + EXPECT_TRUE( + hive_message_is_printable(reinterpret_cast(""), 0)); + + // Any non-printable byte (control char / high bit) is refused. + const uint8_t withNul[] = {'h', 'i', 0x00, 'x'}; + EXPECT_FALSE(hive_message_is_printable(withNul, sizeof(withNul))); + const uint8_t highBit[] = {'o', 'k', 0x80}; + EXPECT_FALSE(hive_message_is_printable(highBit, sizeof(highBit))); + + // The oracle vector: a "message" that begins with the binary mainnet chain id + // (beeab0de00...) followed by a serialized tx. The leading 0xbe/0xea/0x00 + // bytes are non-printable, so this can never be signed as a message. + const uint8_t chainIdPrefixed[] = {0xbe, 0xea, 0xb0, 0xde, 0x00, + 0x00, 0x00, 't', 'x'}; + EXPECT_FALSE( + hive_message_is_printable(chainIdPrefixed, sizeof(chainIdPrefixed))); +} + +TEST(Hive, TopLevelCommentRetainsCategoryAndEmptyTitle) { + std::vector tx = comment_tx("", "hive-123456", "post-author", + "post-permlink", "", "Post body", "{}"); + + HiveParsedTx parsed; + ASSERT_EQ(nullptr, hive_parseOperations(tx.data(), tx.size(), &parsed)); + const HiveTxOp& op = parsed.ops[0]; + EXPECT_TRUE(op.is_top_level); + EXPECT_EQ(0, op.parent_author_len); + EXPECT_EQ("hive-123456", slice(op.parent_permlink, op.parent_permlink_len)); + EXPECT_EQ("post-permlink", slice(op.permlink, op.permlink_len)); + EXPECT_EQ(0, op.target_len); + EXPECT_EQ("{}", slice(op.json_metadata, op.json_metadata_len)); +} + +TEST(Hive, RejectsNonCanonicalVarints) { + std::vector op; + append_varint(op, HIVE_OP_VOTE); + append_string(op, "alice"); + append_string(op, "bob"); + append_string(op, "post"); + append_u16_le(op, 10000); + + HiveParsedTx parsed; + + // Operation count 1 encoded as 0x81 0x00 instead of canonical 0x01. + std::vector overlong_count = wrap_ops({op}); + overlong_count[10] = 0x81; + overlong_count.insert(overlong_count.begin() + 11, 0x00); + EXPECT_NE(nullptr, hive_parseOperations(overlong_count.data(), + overlong_count.size(), &parsed)); + + // The voter string length 5 encoded as 0x85 0x00. + std::vector overlong_string = wrap_ops({op}); + overlong_string[12] = 0x85; + overlong_string.insert(overlong_string.begin() + 13, 0x00); + EXPECT_NE(nullptr, hive_parseOperations(overlong_string.data(), + overlong_string.size(), &parsed)); +} + +TEST(Hive, RejectsAccountNamesThatCanSpoofTheDisplay) { + HiveParsedTx parsed; + const std::vector invalid = { + "al\nice", std::string("ali\0ce", 6), "Alice", "alice-", ".alice", "a"}; + for (const std::string& account : invalid) { + std::vector op; + append_varint(op, HIVE_OP_TRANSFER_TO_SAVINGS); + append_string(op, account); + append_string(op, "bob"); + append_asset(op, 1000, 3, "HIVE"); + append_string(op, ""); + std::vector tx = wrap_ops({op}); + EXPECT_NE(nullptr, hive_parseOperations(tx.data(), tx.size(), &parsed)); + } +} + +TEST(Hive, CustomJsonRetainsAndBoundsEveryAuthorization) { + HiveParsedTx parsed; + std::vector tx = + wrap_ops({custom_json_op({}, {"alice", "bob", "carol"}, "follow", "[]")}); + ASSERT_EQ(nullptr, hive_parseOperations(tx.data(), tx.size(), &parsed)); + const HiveTxOp& op = parsed.ops[0]; + ASSERT_EQ(3, op.n_auths); + EXPECT_EQ("alice", slice(op.auth_acct[0], op.auth_acct_len[0])); + EXPECT_EQ("bob", slice(op.auth_acct[1], op.auth_acct_len[1])); + EXPECT_EQ("carol", slice(op.auth_acct[2], op.auth_acct_len[2])); + EXPECT_FALSE(parsed.needs_active); + + std::vector too_many = wrap_ops({custom_json_op( + {}, {"alice", "bob", "carol", "dave", "erin"}, "follow", "[]")}); + EXPECT_NE(nullptr, + hive_parseOperations(too_many.data(), too_many.size(), &parsed)); + + std::vector unsorted = + wrap_ops({custom_json_op({}, {"bob", "alice"}, "follow", "[]")}); + EXPECT_NE(nullptr, + hive_parseOperations(unsorted.data(), unsorted.size(), &parsed)); + + std::vector duplicate = + wrap_ops({custom_json_op({}, {"alice", "alice"}, "follow", "[]")}); + EXPECT_NE(nullptr, + hive_parseOperations(duplicate.data(), duplicate.size(), &parsed)); +} + +TEST(Hive, DisplayPaginationUsesRenderedBodyRows) { + const std::string payload = + "%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%"; + ASSERT_GT(calc_str_line(get_body_font(), payload.c_str(), BODY_WIDTH), + BODY_ROWS); + + std::string reconstructed; + size_t offset = 0; + unsigned pages = 0; + while (offset < payload.size()) { + size_t take = calc_str_page(get_body_font(), payload.data() + offset, + payload.size() - offset, BODY_WIDTH, BODY_ROWS); + ASSERT_GT(take, 0u); + const std::string page = payload.substr(offset, take); + EXPECT_LE(calc_str_line(get_body_font(), page.c_str(), BODY_WIDTH), + BODY_ROWS); + reconstructed += page; + offset += take; + pages++; + } + + EXPECT_GT(pages, 1u); + EXPECT_EQ(payload, reconstructed); +} + +// ── Phase-3 op table ──────────────────────────────────────────────────────── + +// The op that started this: a HIVE->HBD internal-market swap. Every field the +// approval screen shows must survive the parse. +TEST(Hive, LimitOrderCreateRetainsEveryDisplayedField) { + std::vector tx = wrap_ops({limit_order_create_op( + "alice", 42, 1500, "HIVE", 400, "HBD", true, 1700003600)}); + + HiveParsedTx parsed; + ASSERT_EQ(nullptr, hive_parseOperations(tx.data(), tx.size(), &parsed)); + ASSERT_EQ(1, parsed.num_ops); + const HiveTxOp& op = parsed.ops[0]; + EXPECT_EQ(HIVE_OP_LIMIT_ORDER_CREATE, op.op_type); + EXPECT_EQ("alice", slice(op.acct, op.acct_len)); + EXPECT_EQ(42u, op.req_id); + EXPECT_EQ(1700003600u, op.expiration); + EXPECT_TRUE(op.flag); // fill_or_kill + ASSERT_EQ(2, op.n_assets); + EXPECT_EQ(1500u, hive_assetAmount(op.assets[0])); + EXPECT_STREQ("HIVE", hive_assetSymbol(op.assets[0])); + EXPECT_EQ(3, hive_assetPrecision(op.assets[0])); + EXPECT_EQ(400u, hive_assetAmount(op.assets[1])); + EXPECT_STREQ("HBD", hive_assetSymbol(op.assets[1])); + // Trading needs the active key. + EXPECT_TRUE(parsed.needs_active); +} + +TEST(Hive, LimitOrderRejectsDegenerateOrders) { + HiveParsedTx parsed; + + // A same-symbol pair is a no-op trade on screen but still burns the fill. + std::vector same = wrap_ops( + {limit_order_create_op("alice", 1, 100, "HIVE", 100, "HIVE", false, 1)}); + EXPECT_NE(nullptr, hive_parseOperations(same.data(), same.size(), &parsed)); + + std::vector zero_sell = wrap_ops( + {limit_order_create_op("alice", 1, 0, "HIVE", 100, "HBD", false, 1)}); + EXPECT_NE(nullptr, + hive_parseOperations(zero_sell.data(), zero_sell.size(), &parsed)); + + std::vector zero_recv = wrap_ops( + {limit_order_create_op("alice", 1, 100, "HIVE", 0, "HBD", false, 1)}); + EXPECT_NE(nullptr, + hive_parseOperations(zero_recv.data(), zero_recv.size(), &parsed)); + + // VESTS never trades on the internal market. + std::vector vests = wrap_ops({limit_order_vests_op()}); + EXPECT_NE(nullptr, hive_parseOperations(vests.data(), vests.size(), &parsed)); +} + +TEST(Hive, LimitOrderCancelParses) { + std::vector op; + append_varint(op, HIVE_OP_LIMIT_ORDER_CANCEL); + append_string(op, "alice"); + append_u32_le(op, 42); + std::vector tx = wrap_ops({op}); + + HiveParsedTx parsed; + ASSERT_EQ(nullptr, hive_parseOperations(tx.data(), tx.size(), &parsed)); + EXPECT_EQ("alice", slice(parsed.ops[0].acct, parsed.ops[0].acct_len)); + EXPECT_EQ(42u, parsed.ops[0].req_id); + EXPECT_TRUE(parsed.needs_active); +} + +// The asset validator is what stops a host from moving the decimal point or +// swapping a ~2000x-more-valuable symbol behind an identical-looking number. +TEST(Hive, AssetValidatorPinsSymbolAndPrecision) { + HiveParsedTx parsed; + + std::vector ok = wrap_ops({power_up_op(1000, 3, "HIVE")}); + EXPECT_EQ(nullptr, hive_parseOperations(ok.data(), ok.size(), &parsed)); + + // transfer_to_vesting is HIVE-only; HBD and VESTS are out of the whitelist. + std::vector hbd = wrap_ops({power_up_op(1000, 3, "HBD")}); + EXPECT_NE(nullptr, hive_parseOperations(hbd.data(), hbd.size(), &parsed)); + std::vector vests = wrap_ops({power_up_op(1000, 6, "VESTS")}); + EXPECT_NE(nullptr, hive_parseOperations(vests.data(), vests.size(), &parsed)); + + // Right symbol, wrong precision: 1000 would render as 0.001 vs 1.000. + std::vector prec = wrap_ops({power_up_op(1000, 6, "HIVE")}); + EXPECT_NE(nullptr, hive_parseOperations(prec.data(), prec.size(), &parsed)); + + // A negative int64 would print as an enormous positive number. + std::vector negative = wrap_ops({power_up_op(-1000, 3, "HIVE")}); + EXPECT_NE(nullptr, + hive_parseOperations(negative.data(), negative.size(), &parsed)); + + // Unknown symbol, and a longer symbol sharing an accepted prefix. + std::vector unknown = wrap_ops({power_up_op(1000, 3, "SBD")}); + EXPECT_NE(nullptr, + hive_parseOperations(unknown.data(), unknown.size(), &parsed)); + std::vector prefixed = wrap_ops({power_up_op(1000, 3, "HIVEX")}); + EXPECT_NE(nullptr, + hive_parseOperations(prefixed.data(), prefixed.size(), &parsed)); +} + +// Zero is a real instruction for some ops and nonsense for others; the parser +// must not apply one blanket rule. +TEST(Hive, ZeroAmountSemanticsDifferPerOp) { + HiveParsedTx parsed; + + // Zero HIVE power-up: nothing to do, reject. + std::vector power_up = wrap_ops({power_up_op(0, 3, "HIVE")}); + EXPECT_NE(nullptr, + hive_parseOperations(power_up.data(), power_up.size(), &parsed)); + + // Zero VESTS withdraw_vesting: cancels an in-progress power-down, accept. + std::vector stop_pd; + { + std::vector op; + append_varint(op, HIVE_OP_WITHDRAW_VESTING); + append_string(op, "alice"); + append_asset(op, 0, 6, "VESTS"); + stop_pd = wrap_ops({op}); + } + EXPECT_EQ(nullptr, + hive_parseOperations(stop_pd.data(), stop_pd.size(), &parsed)); + + // Zero VESTS delegation: removes an existing delegation, accept. + std::vector undelegate; + { + std::vector op; + append_varint(op, HIVE_OP_DELEGATE_VESTING_SHARES); + append_string(op, "alice"); + append_string(op, "bob"); + append_asset(op, 0, 6, "VESTS"); + undelegate = wrap_ops({op}); + } + EXPECT_EQ(nullptr, hive_parseOperations(undelegate.data(), undelegate.size(), + &parsed)); + + // claim_reward_balance with all three at zero: nothing to claim, reject. + std::vector empty_claim; + { + std::vector op; + append_varint(op, HIVE_OP_CLAIM_REWARD_BALANCE); + append_string(op, "alice"); + append_asset(op, 0, 3, "HIVE"); + append_asset(op, 0, 3, "HBD"); + append_asset(op, 0, 6, "VESTS"); + empty_claim = wrap_ops({op}); + } + EXPECT_NE(nullptr, hive_parseOperations(empty_claim.data(), + empty_claim.size(), &parsed)); +} + +TEST(Hive, ClaimRewardBalanceKeepsAssetOrder) { + std::vector op; + append_varint(op, HIVE_OP_CLAIM_REWARD_BALANCE); + append_string(op, "alice"); + append_asset(op, 1234, 3, "HIVE"); + append_asset(op, 5678, 3, "HBD"); + append_asset(op, 90123456, 6, "VESTS"); + std::vector tx = wrap_ops({op}); + + HiveParsedTx parsed; + ASSERT_EQ(nullptr, hive_parseOperations(tx.data(), tx.size(), &parsed)); + ASSERT_EQ(3, parsed.ops[0].n_assets); + EXPECT_EQ(1234u, hive_assetAmount(parsed.ops[0].assets[0])); + EXPECT_STREQ("HIVE", hive_assetSymbol(parsed.ops[0].assets[0])); + EXPECT_EQ(5678u, hive_assetAmount(parsed.ops[0].assets[1])); + EXPECT_STREQ("HBD", hive_assetSymbol(parsed.ops[0].assets[1])); + EXPECT_EQ(90123456u, hive_assetAmount(parsed.ops[0].assets[2])); + EXPECT_STREQ("VESTS", hive_assetSymbol(parsed.ops[0].assets[2])); + // Claiming rewards is a posting-tier action. + EXPECT_FALSE(parsed.needs_active); +} + +// SECURITY: comment_options redirects a post's payout. Detached from its +// comment it could retarget a post the user published earlier and is not +// reviewing on screen. +TEST(Hive, CommentOptionsMustBindToItsComment) { + HiveParsedTx parsed; + + std::vector alone = + wrap_ops({comment_options_op("alice", "my-post", {})}); + EXPECT_NE(nullptr, hive_parseOperations(alone.data(), alone.size(), &parsed)); + + std::vector wrong_permlink = + wrap_ops({comment_op("alice", "my-post"), + comment_options_op("alice", "other-post", {})}); + EXPECT_NE(nullptr, hive_parseOperations(wrong_permlink.data(), + wrong_permlink.size(), &parsed)); + + std::vector wrong_author = + wrap_ops({comment_op("alice", "my-post"), + comment_options_op("mallory", "my-post", {})}); + EXPECT_NE(nullptr, hive_parseOperations(wrong_author.data(), + wrong_author.size(), &parsed)); + + std::vector ok = + wrap_ops({comment_op("alice", "my-post"), + comment_options_op("alice", "my-post", {})}); + ASSERT_EQ(nullptr, hive_parseOperations(ok.data(), ok.size(), &parsed)); + EXPECT_EQ(2, parsed.num_ops); + EXPECT_EQ(10000, parsed.ops[1].weight); // percent_hbd + EXPECT_FALSE(parsed.needs_active); +} + +TEST(Hive, CommentOptionsBeneficiaryRules) { + HiveParsedTx parsed; + + std::vector ok = + wrap_ops({comment_op("alice", "my-post"), + comment_options_op("alice", "my-post", + {{"aaron", 1000}, {"zoe", 500}})}); + ASSERT_EQ(nullptr, hive_parseOperations(ok.data(), ok.size(), &parsed)); + ASSERT_EQ(2, parsed.ops[1].n_benef); + EXPECT_EQ("aaron", slice(parsed.ops[1].benef_acct[0], + parsed.ops[1].benef_acct_len[0])); + EXPECT_EQ(1000, parsed.ops[1].benef_weight[0]); + EXPECT_EQ("zoe", slice(parsed.ops[1].benef_acct[1], + parsed.ops[1].benef_acct_len[1])); + + // hived requires strictly ascending names; unsorted is rejected on-chain. + std::vector unsorted = + wrap_ops({comment_op("alice", "my-post"), + comment_options_op("alice", "my-post", + {{"zoe", 500}, {"aaron", 1000}})}); + EXPECT_NE(nullptr, + hive_parseOperations(unsorted.data(), unsorted.size(), &parsed)); + + // Duplicates are the same violation. + std::vector duped = + wrap_ops({comment_op("alice", "my-post"), + comment_options_op("alice", "my-post", + {{"aaron", 500}, {"aaron", 500}})}); + EXPECT_NE(nullptr, hive_parseOperations(duped.data(), duped.size(), &parsed)); + + // Weights may not add up to more than 100%. + std::vector overweight = + wrap_ops({comment_op("alice", "my-post"), + comment_options_op("alice", "my-post", + {{"aaron", 6000}, {"zoe", 5000}})}); + EXPECT_NE(nullptr, hive_parseOperations(overweight.data(), overweight.size(), + &parsed)); +} + +// SECURITY: account_update2 can rotate account keys. Only the profile-metadata +// form is in the table — the op-9/10 exclusion applied field-level. +TEST(Hive, AccountUpdate2RejectsAuthorityChanges) { + HiveParsedTx parsed; + + std::vector authority = + wrap_ops({account_update2_op("{\"profile\":{}}", "", true)}); + EXPECT_NE(nullptr, + hive_parseOperations(authority.data(), authority.size(), &parsed)); + + std::vector empty = wrap_ops({account_update2_op("", "", false)}); + EXPECT_NE(nullptr, hive_parseOperations(empty.data(), empty.size(), &parsed)); + + // json_metadata is an active-key field. + std::vector active = + wrap_ops({account_update2_op("{\"profile\":{}}", "", false)}); + ASSERT_EQ(nullptr, + hive_parseOperations(active.data(), active.size(), &parsed)); + EXPECT_TRUE(parsed.needs_active); + + // posting_json_metadata alone stays on the posting tier. + std::vector posting = + wrap_ops({account_update2_op("", "{\"profile\":{}}", false)}); + ASSERT_EQ(nullptr, + hive_parseOperations(posting.data(), posting.size(), &parsed)); + EXPECT_FALSE(parsed.needs_active); +} + +TEST(Hive, SavingsWithdrawRetainsDisplayedFields) { + std::vector op; + append_varint(op, HIVE_OP_TRANSFER_FROM_SAVINGS); + append_string(op, "alice"); + append_u32_le(op, 7); + append_string(op, "bob"); + append_asset(op, 2500, 3, "HBD"); + append_string(op, "rent"); + std::vector tx = wrap_ops({op}); + + HiveParsedTx parsed; + ASSERT_EQ(nullptr, hive_parseOperations(tx.data(), tx.size(), &parsed)); + // request_id sits BETWEEN from and to on the wire — the easiest field-order + // bug to make in this op, and the one that would swap displayed accounts. + EXPECT_EQ("alice", slice(parsed.ops[0].acct, parsed.ops[0].acct_len)); + EXPECT_EQ(7u, parsed.ops[0].req_id); + EXPECT_EQ("bob", slice(parsed.ops[0].target, parsed.ops[0].target_len)); + EXPECT_EQ("rent", slice(parsed.ops[0].detail, parsed.ops[0].detail_len)); + EXPECT_EQ(2500u, hive_assetAmount(parsed.ops[0].assets[0])); + EXPECT_TRUE(parsed.needs_active); +} + +TEST(Hive, SavingsDepositRetainsDisplayedFields) { + std::vector op; + append_varint(op, HIVE_OP_TRANSFER_TO_SAVINGS); + append_string(op, "alice"); + append_string(op, "bob"); + append_asset(op, 1500, 3, "HIVE"); + append_string(op, ""); + std::vector tx = wrap_ops({op}); + + HiveParsedTx parsed; + ASSERT_EQ(nullptr, hive_parseOperations(tx.data(), tx.size(), &parsed)); + EXPECT_EQ("alice", slice(parsed.ops[0].acct, parsed.ops[0].acct_len)); + EXPECT_EQ("bob", slice(parsed.ops[0].target, parsed.ops[0].target_len)); + EXPECT_EQ(0, parsed.ops[0].detail_len); // empty memo is legal + EXPECT_EQ(1500u, hive_assetAmount(parsed.ops[0].assets[0])); +} + +// An empty `to` means "power up to self" on Hive, not a malformed field. +TEST(Hive, PowerUpAcceptsEmptyDestination) { + std::vector op; + append_varint(op, HIVE_OP_TRANSFER_TO_VESTING); + append_string(op, "alice"); + append_string(op, ""); + append_asset(op, 1000, 3, "HIVE"); + std::vector tx = wrap_ops({op}); + + HiveParsedTx parsed; + ASSERT_EQ(nullptr, hive_parseOperations(tx.data(), tx.size(), &parsed)); + EXPECT_EQ(0, parsed.ops[0].target_len); +} + +// Truncating any op body by one byte must be refused, never partially parsed: +// the signature covers the whole buffer, so a short read would mean signing +// bytes the device never looked at. +TEST(Hive, TruncatedOpBodiesRejected) { + std::vector> bodies; + bodies.push_back( + limit_order_create_op("alice", 1, 100, "HIVE", 50, "HBD", false, 9)); + bodies.push_back(power_up_op(1000, 3, "HIVE")); + { + std::vector op; + append_varint(op, HIVE_OP_CLAIM_REWARD_BALANCE); + append_string(op, "alice"); + append_asset(op, 1, 3, "HIVE"); + append_asset(op, 1, 3, "HBD"); + append_asset(op, 1, 6, "VESTS"); + bodies.push_back(op); + } + { + std::vector op; + append_varint(op, HIVE_OP_TRANSFER_FROM_SAVINGS); + append_string(op, "alice"); + append_u32_le(op, 7); + append_string(op, "bob"); + append_asset(op, 2500, 3, "HBD"); + append_string(op, "memo"); + bodies.push_back(op); + } + + HiveParsedTx parsed; + for (const std::vector& body : bodies) { + ASSERT_EQ(nullptr, hive_parseOperations(wrap_ops({body}).data(), + wrap_ops({body}).size(), &parsed)); + for (size_t cut = 1; cut < body.size(); cut++) { + std::vector truncated(body.begin(), body.end() - cut); + std::vector tx = wrap_ops({truncated}); + EXPECT_NE(nullptr, hive_parseOperations(tx.data(), tx.size(), &parsed)) + << "op type " << (unsigned)body[0] << " truncated by " << cut; + } + } +} + +TEST(Hive, CommentOptionsExtensionShapeRejected) { + HiveParsedTx parsed; + const std::vector comment = comment_op("alice", "my-post"); + + // More than one extension could split beneficiaries past a per-extension cap. + { + std::vector op; + append_varint(op, HIVE_OP_COMMENT_OPTIONS); + append_string(op, "alice"); + append_string(op, "my-post"); + append_asset(op, 1000000, 3, "HBD"); + append_u16_le(op, 10000); + op.push_back(1); + op.push_back(1); + append_varint(op, 2); + std::vector tx = wrap_ops({comment, op}); + EXPECT_NE(nullptr, hive_parseOperations(tx.data(), tx.size(), &parsed)); + } + // Only comment_payout_beneficiaries (tag 0) is in the table. + { + std::vector op; + append_varint(op, HIVE_OP_COMMENT_OPTIONS); + append_string(op, "alice"); + append_string(op, "my-post"); + append_asset(op, 1000000, 3, "HBD"); + append_u16_le(op, 10000); + op.push_back(1); + op.push_back(1); + append_varint(op, 1); + append_varint(op, 1); // tag != 0 + std::vector tx = wrap_ops({comment, op}); + EXPECT_NE(nullptr, hive_parseOperations(tx.data(), tx.size(), &parsed)); + } + // Zero beneficiaries in a present extension is malformed, not "none". + { + std::vector tx = + wrap_ops({comment, comment_options_op("alice", "my-post", {})}); + ASSERT_EQ(nullptr, hive_parseOperations(tx.data(), tx.size(), &parsed)); + std::vector op; + append_varint(op, HIVE_OP_COMMENT_OPTIONS); + append_string(op, "alice"); + append_string(op, "my-post"); + append_asset(op, 1000000, 3, "HBD"); + append_u16_le(op, 10000); + op.push_back(1); + op.push_back(1); + append_varint(op, 1); + append_varint(op, 0); + append_varint(op, 0); // n_benef = 0 + std::vector bad = wrap_ops({comment, op}); + EXPECT_NE(nullptr, hive_parseOperations(bad.data(), bad.size(), &parsed)); + } +} + +TEST(Hive, AccountUpdate2RejectsNonEmptyExtensions) { + std::vector op; + append_varint(op, HIVE_OP_ACCOUNT_UPDATE2); + append_string(op, "alice"); + for (int i = 0; i < 4; i++) op.push_back(0); + append_string(op, "{\"profile\":{}}"); + append_string(op, ""); + append_varint(op, 1); // extensions must be empty + std::vector tx = wrap_ops({op}); + + HiveParsedTx parsed; + EXPECT_NE(nullptr, hive_parseOperations(tx.data(), tx.size(), &parsed)); +} + +// Graphene bools are one byte; anything but 0/1 is a host serializer bug. +TEST(Hive, RejectsNonCanonicalBool) { + // limit_order_create's fill_or_kill byte, set to 2. + std::vector op; + append_varint(op, HIVE_OP_LIMIT_ORDER_CREATE); + append_string(op, "alice"); + append_u32_le(op, 1); + append_asset(op, 100, 3, "HIVE"); + append_asset(op, 50, 3, "HBD"); + op.push_back(2); + append_u32_le(op, 9); + std::vector tx = wrap_ops({op}); + + HiveParsedTx parsed; + EXPECT_NE(nullptr, hive_parseOperations(tx.data(), tx.size(), &parsed)); +} + +TEST(Hive, MixedTierOpsRejected) { + // vote is posting-tier, convert is active-tier; one signature cannot + // satisfy both post-HF28. + std::vector vote; + append_varint(vote, HIVE_OP_VOTE); + append_string(vote, "alice"); + append_string(vote, "bob"); + append_string(vote, "a-post"); + append_u16_le(vote, 10000); + + std::vector convert; + append_varint(convert, HIVE_OP_CONVERT); + append_string(convert, "alice"); + append_u32_le(convert, 1); + append_asset(convert, 1000, 3, "HBD"); + + std::vector tx = wrap_ops({vote, convert}); + HiveParsedTx parsed; + EXPECT_NE(nullptr, hive_parseOperations(tx.data(), tx.size(), &parsed)); +} + +TEST(Hive, ExcludedAndUnknownOpsStillRejected) { + HiveParsedTx parsed; + + // Ops 2/9/10 keep their dedicated message types — never fold them in. + for (uint32_t excluded : {static_cast(HIVE_OP_TRANSFER), + static_cast(HIVE_OP_ACCOUNT_CREATE), + static_cast(HIVE_OP_ACCOUNT_UPDATE)}) { + std::vector op; + append_varint(op, excluded); + append_string(op, "alice"); + std::vector tx = wrap_ops({op}); + EXPECT_NE(nullptr, hive_parseOperations(tx.data(), tx.size(), &parsed)); + } + + // Anything outside the table is refused; there is no blind-sign fallback. + // 49 = recurrent_transfer, a real op deliberately not in the table. + std::vector unknown; + append_varint(unknown, 49); + append_string(unknown, "alice"); + std::vector tx = wrap_ops({unknown}); + EXPECT_NE(nullptr, hive_parseOperations(tx.data(), tx.size(), &parsed)); +} + +// Trailing bytes after a well-formed op must not be silently accepted: the +// signature covers them, so what the device displays would be a subset of +// what it signs. +TEST(Hive, TrailingBytesRejected) { + std::vector tx = wrap_ops( + {limit_order_create_op("alice", 1, 100, "HIVE", 50, "HBD", false, 1)}); + tx.push_back(0xff); + + HiveParsedTx parsed; + EXPECT_NE(nullptr, hive_parseOperations(tx.data(), tx.size(), &parsed)); +} + +// --------------------------------------------------------------------------- +// Golden vectors produced by hived itself: +// +// curl -X POST https://api.hive.blog -H 'Content-Type: application/json' \ +// -d '{"jsonrpc":"2.0","method":"condenser_api.get_transaction_hex", +// "params":[],"id":1}' +// +// These exist because our serializer and this parser were byte-exact mirrors +// of EACH OTHER while both disagreed with the chain: we wrote "HIVE"/"HBD" +// where hived writes "STEEM"/"SBD". Two wrongs cancelled and every test +// passed, but the device signed bytes hived could not validate — it reported +// "missing required active authority", because signature recovery over +// different bytes yields a key in no authority. A vector the chain generated +// is the only kind that can catch that class of bug. +// --------------------------------------------------------------------------- + +std::vector from_hex(const std::string& hex) { + std::vector out; + for (size_t i = 0; i + 1 < hex.size(); i += 2) { + out.push_back( + static_cast(std::stoul(hex.substr(i, 2), nullptr, 16))); + } + return out; +} + +// Header shared by both vectors below: ref_block_num 4660 / prefix 0xdeadbeef +// (0/0 for the second) and expiration 2021-01-14T02:19:44. +// +// get_transaction_hex serializes a full transaction, so its output ends with a +// varint count of the `signatures` array. The device is handed the digest +// preimage, which stops after the extensions varint — so the trailing "00" +// from hived's hex is dropped in the goldens below. Everything before it must +// match byte for byte. +TEST(Hive, SerializationMatchesHivedLimitOrderCreate) { + const std::string golden = + "3412efbeadde40aaff5f010505616c6963652a000000dc05000000000000035354" + "45454d00009001000000000000035342440000000001b0f5536500"; + + std::vector tx; + append_u16_le(tx, 4660); + append_u32_le(tx, 0xdeadbeef); + append_u32_le(tx, 0x5fffaa40); + append_varint(tx, 1); + std::vector op = limit_order_create_op("alice", 42, 1500, "HIVE", + 400, "HBD", true, 0x6553f5b0); + tx.insert(tx.end(), op.begin(), op.end()); + append_varint(tx, 0); // extensions + + EXPECT_EQ(from_hex(golden), tx); + + // and the parser accepts what the chain produces + HiveParsedTx parsed; + ASSERT_EQ(nullptr, hive_parseOperations(tx.data(), tx.size(), &parsed)); + EXPECT_STREQ("HIVE", hive_assetSymbol(parsed.ops[0].assets[0])); + EXPECT_STREQ("HBD", hive_assetSymbol(parsed.ops[0].assets[1])); +} + +TEST(Hive, SerializationMatchesHivedClaimRewardBalance) { + const std::string golden = + "00000000000040aaff5f012705616c696365e8030000000000000353544545" + "4d0000d0070000000000000353424400000000c0c62d0000000000065645535453" + "000000"; + + std::vector tx; + append_u16_le(tx, 0); + append_u32_le(tx, 0); + append_u32_le(tx, 0x5fffaa40); + append_varint(tx, 1); + append_varint(tx, HIVE_OP_CLAIM_REWARD_BALANCE); + append_string(tx, "alice"); + append_asset(tx, 1000, 3, "HIVE"); + append_asset(tx, 2000, 3, "HBD"); + append_asset(tx, 3000000, 6, "VESTS"); + append_varint(tx, 0); // extensions + + EXPECT_EQ(from_hex(golden), tx); + + HiveParsedTx parsed; + ASSERT_EQ(nullptr, hive_parseOperations(tx.data(), tx.size(), &parsed)); + EXPECT_STREQ("VESTS", hive_assetSymbol(parsed.ops[0].assets[2])); +} diff --git a/unittests/firmware/mayachain.cpp b/unittests/firmware/mayachain.cpp index 8a319a610..cf17b29c2 100644 --- a/unittests/firmware/mayachain.cpp +++ b/unittests/firmware/mayachain.cpp @@ -7,6 +7,13 @@ extern "C" { #include "gtest/gtest.h" #include +#include + +// confirm() auto-accept driver, defined in thorchain.cpp (same binary). +// kkconfirm_preload(nYes, nNo) queues nYes accepted confirm screens then +// nNo rejected ones; kkconfirm_drain() == 0 proves the exact screen count. +bool kkconfirm_preload(int nYes, int nNo); +int kkconfirm_drain(void); TEST(Mayachain, MayachainGetAddress) { HDNode node = { @@ -56,19 +63,176 @@ TEST(Mayachain, MayachainSignTx) { ASSERT_TRUE(mayachain_signTxInit(&node, &msg)); ASSERT_TRUE(mayachain_signTxUpdateMsgSend( - 100, "maya1g9el7lzjwh9yun2c4jjzhy09j98vkhfxfqkl5k")); + 100, "maya1g9el7lzjwh9yun2c4jjzhy09j98vkhfxfqkl5k", "cacao")); uint8_t public_key[33]; uint8_t signature[64]; ASSERT_TRUE(mayachain_signTxFinalize(public_key, signature)); + // Expected value recomputed independently (python-ecdsa, RFC6979/secp256k1, + // low-s) over the exact sign-doc JSON this fixture produces: + // {"account_number":"6359","chain_id":"mayachain-mainnet-v1","fee": + // {"amount":[{"amount":"3000","denom":"cacao"}],"gas":"200000"},"memo": + // "","msgs":[{"type":"mayachain/MsgSend","value":{"amount":[{"amount": + // "100","denom":"cacao"}],"from_address": + // "maya1ls33ayg26kmltw7jjy55p32ghjna09zp7z4etj","to_address": + // "maya1g9el7lzjwh9yun2c4jjzhy09j98vkhfxfqkl5k"}}],"sequence":"19"} + // The bytes recorded when this file was written never matched: the file + // was not in the unit build (see 28c74a0e) so the vector was never + // validated, and it did not verify against this fixture's key/JSON. EXPECT_TRUE( memcmp(signature, - (uint8_t *)"\x8a\x91\x43\x54\xca\xe7\x45\x30\x0e\xfb\x88\xee\xdd" - "\xac\xc0\xb5\xa3\x3d\x18\xb1\xe6\x54\x26\x70\x8f\x93" - "\x69\x67\xd5\x21\x84\xbb\x6b\x58\x3d\xe3\x21\xd0\x3e" - "\x26\xb2\xd8\x00\x7d\x81\x84\x34\x82\x5a\xfa\xa2\x80" - "\x54\x88\x90\xc6\xec\xf0\x3b\xf5\x33\x0f\x3e\x9a", + (uint8_t *)"\xdf\x2f\x66\x37\x03\x08\x32\xd2\xce\x87\xfe\x47\x8d" + "\xdf\xe6\xd8\x21\xd2\x6b\x03\x8b\x44\xfa\xc8\x98\xe6" + "\xdf\x79\xe3\xfd\x10\x5d\x40\x3f\x05\x0d\x00\xad\xf9" + "\x7d\x3e\xd3\xa7\x3d\xa6\x9b\x19\x74\x0c\x6a\xbc\xf6" + "\x94\x09\x57\x29\xa3\xf0\xc3\x62\xc9\xf0\xfa\x71", 64) == 0); +} + +// Denom validation: only [a-z0-9./\-] is allowed; anything else is rejected +TEST(Mayachain, MayachainDenomValidation) { + EXPECT_TRUE(mayachain_isValidDenom("cacao")); + EXPECT_TRUE(mayachain_isValidDenom("maya")); + EXPECT_TRUE(mayachain_isValidDenom("eth.eth")); + EXPECT_TRUE(mayachain_isValidDenom("btc/btc")); + EXPECT_TRUE(mayachain_isValidDenom("cross-chain")); + + EXPECT_FALSE(mayachain_isValidDenom("")); // empty → caller "cacao" + EXPECT_FALSE(mayachain_isValidDenom("CACAO")); // uppercase rejected + EXPECT_FALSE(mayachain_isValidDenom("cacao\"")); // quote injection + EXPECT_FALSE(mayachain_isValidDenom("cacao\\n")); // backslash injection + EXPECT_FALSE(mayachain_isValidDenom(" cacao")); // leading space + EXPECT_FALSE(mayachain_isValidDenom("ca cao")); // embedded space +} + +// The signer function itself must reject an invalid denom — not merely +// rely on the FSM caller to pre-validate — so it stays safe if reused or +// called directly. Empty denom must still default to "cacao" and succeed. +TEST(Mayachain, MayachainSignTxUpdateMsgSendRejectsInvalidDenom) { + HDNode node = { + 0, + 0, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0xb9, 0x9a, 0x39, 0x3a, 0x5a, 0x53, 0x0d, 0x90, 0xef, 0x6e, 0x46, + 0x4e, 0x8e, 0x2f, 0x2b, 0x8b, 0x5c, 0x64, 0xa7, 0x97, 0x29, 0xcd, + 0x60, 0x3b, 0x1f, 0xba, 0x33, 0x81, 0x7d, 0x1a, 0x75, 0xa1}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + &secp256k1_info}; + hdnode_fill_public_key(&node); + + const MayachainSignTx msg = { + 5, {0x80000000 | 44, 0x80000000 | 931, 0x80000000, 0, 0}, + true, 6359, + true, "mayachain-mainnet-v1", + true, 3000, + true, 200000, + true, "", + true, 19, + true, 1}; + + ASSERT_TRUE(mayachain_signTxInit(&node, &msg)); + EXPECT_FALSE(mayachain_signTxUpdateMsgSend( + 100, "maya1g9el7lzjwh9yun2c4jjzhy09j98vkhfxfqkl5k", "cacao\"")); + + ASSERT_TRUE(mayachain_signTxInit(&node, &msg)); + EXPECT_TRUE(mayachain_signTxUpdateMsgSend( + 100, "maya1g9el7lzjwh9yun2c4jjzhy09j98vkhfxfqkl5k", "")); +} + +/* ===================================================================== * + * mayachain_parseConfirmMemo — swap-memo clear-signing. + * Mirrors the thorchain.cpp memo tests; see kkconfirm_preload docs there. + * ===================================================================== */ + +static bool parseMayaMemo(const char *memo, size_t size) { + return mayachain_parseConfirmMemo(memo, size); +} +static bool parseMayaMemo(const char *memo) { + return parseMayaMemo(memo, strlen(memo) + 1); +} + +// Classic full-form swap memo = 4 screens (4th is the affiliate fee screen) +TEST(Mayachain, MemoSwapFullFormShowsAffiliate) { + ASSERT_TRUE(kkconfirm_preload(4, 0)); + EXPECT_TRUE(parseMayaMemo( + "SWAP:ETH.USDT-0xdac17f958d2ee523a2206206994597c13d831ec7:" + "0x41e5560054824ea6b0732e656e3ad64e20e94e45:420:kk:75")); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// No '.' in the asset field (no chain.asset pair): raw-memo fallback +TEST(Mayachain, MemoSwapNoChainAssetPair) { + ASSERT_TRUE(kkconfirm_preload(0, 0)); + EXPECT_FALSE(parseMayaMemo("=:e:0xdest:0/1/0:kk:75")); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// Empty limit must NOT shift the affiliate into the limit slot: 4 screens +TEST(Mayachain, MemoSwapEmptyLimitDoesNotShift) { + ASSERT_TRUE(kkconfirm_preload(4, 0)); + EXPECT_TRUE(parseMayaMemo("=:ETH.ETH:0xdest::kk:75")); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// No affiliate: exactly the 3 historical screens +TEST(Mayachain, MemoSwapNoAffiliate) { + ASSERT_TRUE(kkconfirm_preload(3, 0)); + EXPECT_TRUE(parseMayaMemo("SWAP:ETH.ETH:0xdest:420")); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// ADD with a pool address: 2 screens (unchanged behavior) +TEST(Mayachain, MemoAddWithPool) { + ASSERT_TRUE(kkconfirm_preload(2, 0)); + EXPECT_TRUE( + parseMayaMemo("ADD:BTC.BTC:maya1g9el7lzjwh9yun2c4jjzhy09j98vkhfxfqkl5k")); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// WITHDRAW with basis points: 1 screen; without: malformed +TEST(Mayachain, MemoWithdraw) { + ASSERT_TRUE(kkconfirm_preload(1, 0)); + EXPECT_TRUE(parseMayaMemo("WITHDRAW:BTC.BTC:5000")); + EXPECT_FALSE(parseMayaMemo("wd:BTC.BTC")); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// Garbage / oversized memos fall back to raw-memo confirmation +// BTC OP_RETURN passes RAW memo bytes with no NUL and size = byte count. +// Every byte must survive the copy — the historical off-by-one dropped +// the last char (1-char affiliate vanished: 3 screens instead of 4). +TEST(Mayachain, MemoRawBytesNoNulKeepsLastChar) { + ASSERT_TRUE(kkconfirm_preload(4, 0)); + const char raw[] = "=:ETH.ETH:0xdest:420:k"; + EXPECT_TRUE(parseMayaMemo(raw, sizeof(raw) - 1)); /* no NUL counted */ + EXPECT_EQ(0, kkconfirm_drain()); +} + +// A raw memo that fills the internal buffer's entire documented capacity +// (size == 256, the parser's own <=256 contract) must ALSO keep its last +// byte — this is the boundary the copy-length clamp missed. +TEST(Mayachain, MemoExactBufferCapacityKeepsLastChar) { + const std::string prefix = "=:ETH.ETH:0x"; + const std::string suffix = ":420:k"; // 1-char affiliate as the last byte + std::string memo = prefix + std::string(256 - prefix.size() - suffix.size(), + 'd') + + suffix; + ASSERT_EQ(memo.size(), 256u); + + ASSERT_TRUE(kkconfirm_preload(4, 0)); + EXPECT_TRUE(parseMayaMemo(memo.c_str(), memo.size())); /* no NUL counted */ + EXPECT_EQ(0, kkconfirm_drain()); +} + +TEST(Mayachain, MemoGarbageAndOversized) { + ASSERT_TRUE(kkconfirm_preload(0, 0)); + EXPECT_FALSE(parseMayaMemo("hello world")); + EXPECT_FALSE(parseMayaMemo("SWAP:ETH.ETH:0xdest:420", 257)); + EXPECT_EQ(0, kkconfirm_drain()); } \ No newline at end of file diff --git a/unittests/firmware/osmosis.cpp b/unittests/firmware/osmosis.cpp new file mode 100644 index 000000000..b08f129fc --- /dev/null +++ b/unittests/firmware/osmosis.cpp @@ -0,0 +1,158 @@ +extern "C" { +// interface.h first: it is what neutralises the `delete` field in +// messages.pb.h, which is a keyword in C++. +#include "keepkey/transport/interface.h" +#include "keepkey/board/util.h" +#include "keepkey/firmware/app_confirm.h" +#include "keepkey/firmware/osmosis.h" +#include "trezor/crypto/secp256k1.h" +} + +#include "gtest/gtest.h" + +#include + +bool kkconfirm_preload(int nYes, int nNo); +int kkconfirm_drain(void); + +static std::string fmt(const char *value, const char *denom) { + char out[OSMOSIS_AMOUNT_STR_LEN] = {0}; + EXPECT_TRUE(osmosis_formatAmount(out, sizeof(out), value, denom)); + return std::string(out); +} + +TEST(Osmosis, FormatAmountScalesUosmo) { + EXPECT_EQ(fmt("1500000", "uosmo"), "1.500000 OSMO"); + EXPECT_EQ(fmt("1000000", "uosmo"), "1.000000 OSMO"); + EXPECT_EQ(fmt("0", "uosmo"), "0.000000 OSMO"); + // Sub-unit amounts keep every digit rather than collapsing to zero. + EXPECT_EQ(fmt("500", "uosmo"), "0.000500 OSMO"); + EXPECT_EQ(fmt("1", "uosmo"), "0.000001 OSMO"); +} + +/* + * The reason this formatter exists. A float carries ~7 significant decimal + * digits, so the old atof() + "%.6f" path rendered large amounts rounded on + * the screen the user approves — 123456789.123456 OSMO came out as + * 123456792.000000. Integer formatting is exact at any magnitude. + */ +TEST(Osmosis, FormatAmountIsExactBeyondFloatPrecision) { + EXPECT_EQ(fmt("123456789123456", "uosmo"), "123456789.123456 OSMO"); + EXPECT_EQ(fmt("999999999999999", "uosmo"), "999999999.999999 OSMO"); + EXPECT_EQ(fmt("18446744073709551615", "uosmo"), "18446744073709.551615 OSMO"); +} + +TEST(Osmosis, FormatAmountLeavesUnknownDenomsAlone) { + // The device does not know the precision of an arbitrary denom, so the + // base-unit integer is shown verbatim — never scaled by a guess. + EXPECT_EQ(fmt("1500000", "uatom"), "1500000 uatom"); + EXPECT_EQ( + fmt("42", "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA6"), + "42 ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA6"); + // "uosmo" must match exactly — a lookalike denom is not OSMO. + EXPECT_EQ(fmt("1500000", "uosmox"), "1500000 uosmox"); +} + +TEST(Osmosis, FormatAmountRejectsNoncanonicalOrOutOfSchemaValues) { + const char *invalid[] = {"", + "01", + "+1", + "-1", + " 1", + "1 ", + "0x1", + "1a", + "18446744073709551616", + "123456789012345678901234567890123"}; + for (const char *value : invalid) { + char out[OSMOSIS_AMOUNT_STR_LEN] = "unchanged"; + EXPECT_FALSE(osmosis_formatAmount(out, sizeof(out), value, "uosmo")); + EXPECT_STREQ(out, ""); + } + + char out[OSMOSIS_AMOUNT_STR_LEN] = {0}; + EXPECT_FALSE(osmosis_formatAmount(out, sizeof(out), "1", "bad denom")); + EXPECT_FALSE(osmosis_formatAmount(out, sizeof(out), "1", "bad\"denom")); + EXPECT_FALSE(osmosis_formatAmount( + out, sizeof(out), "1", + "ibc/12345678901234567890123456789012345678901234567890123456789012345")); + EXPECT_FALSE(osmosis_formatAmount(out, 4, "1", "uosmo")); +} + +TEST(Osmosis, BaseToPrecisionPreservesMaxLpAmountAndCanary) { + struct { + uint8_t out[34]; + uint8_t canary; + } guarded = {{0}, 0xa5}; + const char value[] = "12345678901234567890123456789012"; + + ASSERT_EQ(0, base_to_precision(guarded.out, (const uint8_t *)value, + sizeof(guarded.out), strlen(value), 18)); + EXPECT_STREQ((const char *)guarded.out, "12345678901234.567890123456789012"); + EXPECT_EQ(guarded.canary, 0xa5); +} + +TEST(Osmosis, BaseToPrecisionRejectsTruncationAndNoncanonicalValues) { + uint8_t out[34] = {0}; + const char max_value[] = "12345678901234567890123456789012"; + EXPECT_LT(base_to_precision(out, (const uint8_t *)max_value, sizeof(out) - 1, + strlen(max_value), 18), + 0); + EXPECT_LT(base_to_precision(out, (const uint8_t *)"01", sizeof(out), 2, 18), + 0); + EXPECT_LT(base_to_precision(out, (const uint8_t *)"1x", sizeof(out), 2, 18), + 0); +} + +TEST(Osmosis, MaxSwapAssetsAreRendererPagedCompletely) { + const char denom[] = + "ibc/1234567890123456789012345678901234567890123456789012345678901234"; + static_assert(sizeof(denom) - 1 == OSMOSIS_MAX_DENOM_LEN, + "fixture must exercise the schema maximum"); + char token[OSMOSIS_AMOUNT_STR_LEN] = {0}; + ASSERT_TRUE(osmosis_formatAmount(token, sizeof(token), + "12345678901234567890123456789012", denom)); + + // The old combined sentence required more than the OLED's three rows. Each + // 101-character asset now gets its own measured page, so both signed values + // are fully accepted in exactly two independent confirmations. + ASSERT_TRUE(kkconfirm_preload(2, 0)); + EXPECT_TRUE(confirm_bytes(ButtonRequestType_ButtonRequest_Other, "Swap Input", + (const uint8_t *)token, strlen(token))); + EXPECT_TRUE(confirm_bytes(ButtonRequestType_ButtonRequest_Other, + "Minimum Output", (const uint8_t *)token, + strlen(token))); + EXPECT_EQ(0, kkconfirm_drain()); +} + +TEST(Osmosis, MsgSendSignsCanonicalNonNativeDenomination) { + HDNode node = { + 0, + 0, + {0}, + {0xb9, 0x9a, 0x39, 0x3a, 0x5a, 0x53, 0x0d, 0x90, 0xef, 0x6e, 0x46, + 0x4e, 0x8e, 0x2f, 0x2b, 0x8b, 0x5c, 0x64, 0xa7, 0x97, 0x29, 0xcd, + 0x8b, 0x6c, 0x69, 0x5c, 0x71, 0x72, 0x03, 0x02, 0xf1, 0x76}, + {0}, + {0}, + &secp256k1_info}; + hdnode_fill_public_key(&node); + + OsmosisSignTx msg = {}; + msg.account_number = 0; + msg.has_chain_id = true; + strlcpy(msg.chain_id, "osmosis-1", sizeof(msg.chain_id)); + msg.fee_amount = 800; + msg.gas = 290000; + msg.has_memo = true; + msg.sequence = 0; + msg.msg_count = 1; + ASSERT_TRUE(osmosis_signTxInit(&node, &msg)); + + const char denom[] = + "ibc/1234567890123456789012345678901234567890123456789012345678901234"; + static_assert(sizeof(denom) - 1 == OSMOSIS_MAX_DENOM_LEN, + "fixture must exercise the schema maximum"); + EXPECT_TRUE(osmosis_signTxUpdateMsgSend( + "7", "osmo1rs7fckgznkaxs4sq02pexwjgar43p5wnkx9s92", denom)); +} diff --git a/unittests/firmware/signed_metadata.cpp b/unittests/firmware/signed_metadata.cpp new file mode 100644 index 000000000..b580ad0dd --- /dev/null +++ b/unittests/firmware/signed_metadata.cpp @@ -0,0 +1,1551 @@ +/* + * Unit tests for the EVM clear-signing ("Insight") signed-metadata module. + * + * Phase 1 ships with NO built-in verification keys: every signer is loaded + * at runtime (signed_metadata_store_signer, + * reached in production through the user-confirmed LoadClearsignSigner FSM + * handler). The fixture loads the CI test key (02e3b3015c...ab5107) into + * slot 3 with alias "CI Test"; all vectors are signed in-process with the + * matching private key (f6d19e15...068a260) and embed key_id=3. + * + * No OLED/button I/O is exercised: signed_metadata_process() and + * signed_metadata_matches_tx() never draw, and signed_metadata_confirm() is + * only called on its no-I/O early-return guards. The relied-path enforce truth + * table is tested through the pure, exported signed_metadata_enforce_decision() + * (see SECTION 2), since relied_on_metadata is only set inside confirm()'s + * interactive tail. + */ + +extern "C" { +#include "messages-ethereum.pb.h" /* full EthereumSignTx definition */ +#include "keepkey/board/draw.h" /* draw_bitmap_mono_rle (icon decoder) */ +#include "keepkey/board/layout.h" /* LEFT_MARGIN_WITH_ICON */ +#include "keepkey/firmware/signed_metadata.h" +#include "keepkey/firmware/solana.h" /* SolanaTokenInfo, solana_token_info_trusted */ +#include "trezor/crypto/ecdsa.h" +#include "trezor/crypto/secp256k1.h" +#include "trezor/crypto/sha2.h" +} + +#include "gtest/gtest.h" + +#include +#include +#include +#include +#include + +namespace { + +/* Test signing key. Its compressed pubkey is loaded into slot 3 by the fixture. + */ +const uint8_t TEST_PRIV[32] = {0xf6, 0xd1, 0x9e, 0x15, 0xa4, 0x38, 0x5f, 0x03, + 0xb7, 0x8b, 0x5a, 0x1e, 0x16, 0x14, 0xe7, 0xd9, + 0xa1, 0x04, 0xd8, 0x1f, 0x73, 0x24, 0x49, 0x87, + 0x56, 0xe5, 0x71, 0x90, 0x40, 0x68, 0xa2, 0x60}; + +/* Compressed pubkey of TEST_PRIV; loaded into slot 3 by the fixture. */ +const uint8_t EXPECTED_SLOT3_PUB[33] = { + 0x02, 0xe3, 0xb3, 0x01, 0x5c, 0x47, 0xdd, 0xca, 0xab, 0xe4, 0xf8, + 0xe8, 0x72, 0xf1, 0xed, 0x8f, 0x09, 0xca, 0x14, 0x5a, 0x8d, 0x81, + 0x77, 0x0d, 0x92, 0x21, 0x3d, 0x56, 0xda, 0x31, 0xab, 0x51, 0x07}; + +const uint8_t TEST_KEY_ID = 3; + +/* Deterministic, opaque test data. Only internal consistency matters. */ +const uint8_t CONTRACT_A[20] = {0xa0, 0xb8, 0x69, 0x91, 0xc6, 0x21, 0x8b, + 0x36, 0xc1, 0xd1, 0x9d, 0x4a, 0x2e, 0x9e, + 0xb0, 0xce, 0x36, 0x06, 0xeb, 0x48}; +const uint8_t CONTRACT_B[20] = {0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}; +const uint8_t SEL_TRANSFER[4] = {0xa9, 0x05, 0x9c, 0xbb}; +const uint8_t SEL_APPROVE[4] = {0x09, 0x5e, 0xa7, 0xb3}; +const uint8_t TX_HASH[32] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20}; +const uint8_t RECIPIENT[20] = {0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, + 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, + 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53}; +const uint8_t AMOUNT32[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0x03, 0xe8}; + +/* ---- byte writers ------------------------------------------------------- */ + +void put_u8(std::vector& v, uint8_t x) { v.push_back(x); } +void put_be16(std::vector& v, uint16_t x) { + v.push_back((uint8_t)(x >> 8)); + v.push_back((uint8_t)(x & 0xff)); +} +void put_be32(std::vector& v, uint32_t x) { + v.push_back((uint8_t)(x >> 24)); + v.push_back((uint8_t)(x >> 16)); + v.push_back((uint8_t)(x >> 8)); + v.push_back((uint8_t)(x & 0xff)); +} +void put_bytes(std::vector& v, const uint8_t* b, size_t n) { + v.insert(v.end(), b, b + n); +} + +/* ---- metadata builder --------------------------------------------------- */ + +struct Arg { + std::string name; + uint8_t format; + std::vector value; + int value_len_override; // -1 => use value.size() +}; + +Arg mk_arg(const std::string& name, uint8_t format, const uint8_t* value, + size_t value_len) { + Arg a; + a.name = name; + a.format = format; + a.value.assign(value, value + value_len); + a.value_len_override = -1; + return a; +} + +struct Spec { + uint8_t version; + uint32_t chain_id; + std::vector contract; + std::vector selector; + std::vector tx_hash; + std::string method; + std::vector args; + uint8_t classification; + uint32_t timestamp; + uint8_t key_id; + int method_len_override; // -1 => use method.size() + int num_args_override; // -1 => use args.size() +}; + +/* Canonical VERIFIED metadata: transfer(to:ADDRESS, amount:AMOUNT) on chain 1. + */ +Spec base_spec() { + Spec s; + s.version = 0x01; + s.chain_id = 1; + s.contract.assign(CONTRACT_A, CONTRACT_A + 20); + s.selector.assign(SEL_TRANSFER, SEL_TRANSFER + 4); + s.tx_hash.assign(TX_HASH, TX_HASH + 32); + s.method = "transfer"; + s.args.push_back(mk_arg("to", ARG_FORMAT_ADDRESS, RECIPIENT, 20)); + s.args.push_back(mk_arg("amount", ARG_FORMAT_AMOUNT, AMOUNT32, 32)); + s.classification = METADATA_VERIFIED; + s.timestamp = 0; + s.key_id = TEST_KEY_ID; + s.method_len_override = -1; + s.num_args_override = -1; + return s; +} + +/* Serialize the signed region (version .. key_id), exactly matching + * parse_metadata_binary() / serialize_metadata(). */ +std::vector build_body(const Spec& s) { + std::vector b; + put_u8(b, s.version); + put_be32(b, s.chain_id); + put_bytes(b, s.contract.data(), s.contract.size()); + put_bytes(b, s.selector.data(), s.selector.size()); + put_bytes(b, s.tx_hash.data(), s.tx_hash.size()); + + uint16_t mlen = s.method_len_override >= 0 ? (uint16_t)s.method_len_override + : (uint16_t)s.method.size(); + put_be16(b, mlen); + put_bytes(b, (const uint8_t*)s.method.data(), s.method.size()); + + uint8_t na = s.num_args_override >= 0 ? (uint8_t)s.num_args_override + : (uint8_t)s.args.size(); + put_u8(b, na); + for (const Arg& a : s.args) { + put_u8(b, (uint8_t)a.name.size()); + put_bytes(b, (const uint8_t*)a.name.data(), a.name.size()); + put_u8(b, a.format); + uint16_t vl = a.value_len_override >= 0 ? (uint16_t)a.value_len_override + : (uint16_t)a.value.size(); + put_be16(b, vl); + put_bytes(b, a.value.data(), a.value.size()); + } + + put_u8(b, s.classification); + put_be32(b, s.timestamp); + put_u8(b, s.key_id); + return b; +} + +/* sha256(body) -> ecdsa sign with TEST_PRIV -> append sig(64) + recovery(1). + * Mirrors signed_metadata_process(): signed_len = payload_len - 64 - 1. */ +std::vector sign_body(std::vector body) { + uint8_t digest[32]; + sha256_Raw(body.data(), body.size(), digest); + uint8_t sig[64]; + uint8_t pby = 0; + int rc = ecdsa_sign_digest(&secp256k1, TEST_PRIV, digest, sig, &pby, NULL); + EXPECT_EQ(rc, 0); + body.insert(body.end(), sig, sig + 64); + body.push_back((uint8_t)(27 + pby)); + return body; +} + +std::vector base_blob() { return sign_body(build_body(base_spec())); } + +void make_msg(EthereumSignTx* msg, const uint8_t contract[20], + const uint8_t* data, size_t data_len, bool has_chain, + uint32_t chain) { + memset(msg, 0, sizeof(*msg)); + msg->has_to = true; + msg->to.size = 20; + memcpy(msg->to.bytes, contract, 20); + msg->has_data_initial_chunk = true; + msg->data_initial_chunk.size = (pb_size_t)data_len; + memcpy(msg->data_initial_chunk.bytes, data, data_len); + msg->has_chain_id = has_chain; + msg->chain_id = chain; +} + +/* A standard transfer() calldata chunk that matches base_spec(). */ +void make_matching_msg(EthereumSignTx* msg) { + uint8_t data[68]; + memcpy(data, SEL_TRANSFER, 4); + memset(data + 4, 0, sizeof(data) - 4); + make_msg(msg, CONTRACT_A, data, sizeof(data), /*has_chain=*/true, 1); +} + +const char* TEST_ALIAS = "CI Test"; + +class SignedMetadataTest : public ::testing::Test { + protected: + void SetUp() override { + signed_metadata_clear_signers(); + signed_metadata_store_signer(TEST_KEY_ID, EXPECTED_SLOT3_PUB, TEST_ALIAS, + NULL, 0, 0, 0, false); + } + void TearDown() override { signed_metadata_clear_signers(); } + + void ExpectMalformed(const std::vector& blob, uint8_t key_id) { + EXPECT_EQ(signed_metadata_process(blob.data(), blob.size(), key_id), + METADATA_MALFORMED); + EXPECT_FALSE(signed_metadata_available()); + EXPECT_EQ(signed_metadata_get(), nullptr); + } +}; + +/* ===================================================================== * + * signed_metadata_process — happy path via a runtime-loaded signer + * ===================================================================== */ + +TEST_F(SignedMetadataTest, DerivedPubkeyMatchesSlot3) { + uint8_t pub[33]; + ecdsa_get_public_key33(&secp256k1, TEST_PRIV, pub); + EXPECT_EQ(memcmp(pub, EXPECTED_SLOT3_PUB, sizeof(pub)), 0) + << "TEST_PRIV must derive the loaded slot-3 test pubkey"; +} + +TEST_F(SignedMetadataTest, ValidVerifiedSlot3) { + std::vector blob = base_blob(); + EXPECT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_VERIFIED); + EXPECT_TRUE(signed_metadata_available()); + const SignedMetadata* m = signed_metadata_get(); + ASSERT_NE(m, nullptr); + EXPECT_EQ(m->classification, METADATA_VERIFIED); + EXPECT_EQ(m->chain_id, 1u); + EXPECT_STREQ(m->method_name, "transfer"); + EXPECT_EQ(m->num_args, 2); + EXPECT_EQ(memcmp(m->contract_address, CONTRACT_A, 20), 0); + EXPECT_EQ(memcmp(m->selector, SEL_TRANSFER, 4), 0); + EXPECT_EQ(memcmp(m->tx_hash, TX_HASH, 32), 0); + EXPECT_EQ(m->key_id, TEST_KEY_ID); +} + +TEST_F(SignedMetadataTest, ValidOpaqueClassification) { + Spec s = base_spec(); + s.classification = METADATA_OPAQUE; // 0 + std::vector blob = sign_body(build_body(s)); + EXPECT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_OPAQUE); + EXPECT_TRUE(signed_metadata_available()); // available, but not VERIFIED + EXPECT_NE(signed_metadata_get(), nullptr); +} + +TEST_F(SignedMetadataTest, SelfDeclaredMalformedWithValidSignature) { + /* A trusted signer can self-declare MALFORMED(2). Signature verifies, so + * process() returns MALFORMED but leaves the (inert) metadata available. It + * must never be displayed or relied upon. */ + Spec s = base_spec(); + s.classification = METADATA_MALFORMED; // 2 + std::vector blob = sign_body(build_body(s)); + EXPECT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_MALFORMED); + EXPECT_TRUE(signed_metadata_available()); + EXPECT_NE(signed_metadata_get(), nullptr); + + EthereumSignTx msg; + make_matching_msg(&msg); + EXPECT_FALSE(signed_metadata_matches_tx(&msg)); // gated on VERIFIED + EXPECT_FALSE(signed_metadata_confirm()); // gated on VERIFIED +} + +/* ===================================================================== * + * signed_metadata_process — key-slot guards + * ===================================================================== */ + +TEST_F(SignedMetadataTest, KeyIdOutOfRange) { + ExpectMalformed(base_blob(), /*key_id=*/4); // >= METADATA_MAX_KEYS +} + +TEST_F(SignedMetadataTest, EmptyRotationSlot) { + Spec s = base_spec(); + s.key_id = 1; // slot 1: no built-in key, nothing loaded + ExpectMalformed(sign_body(build_body(s)), /*key_id=*/1); +} + +TEST_F(SignedMetadataTest, NullPayload) { + EXPECT_EQ(signed_metadata_process(nullptr, 200, TEST_KEY_ID), + METADATA_MALFORMED); + EXPECT_FALSE(signed_metadata_available()); + EXPECT_EQ(signed_metadata_get(), nullptr); +} + +TEST_F(SignedMetadataTest, EmbeddedKeyIdMismatch) { + Spec s = base_spec(); + s.key_id = 2; // embedded != protocol key_id (3) + ExpectMalformed(sign_body(build_body(s)), /*key_id=*/3); +} + +TEST_F(SignedMetadataTest, SignatureVerificationFails) { + std::vector blob = base_blob(); + blob[146] ^= 0x01; // flip first signature byte (sig starts after 146B body) + ExpectMalformed(blob, TEST_KEY_ID); +} + +/* ===================================================================== * + * signed_metadata_process — length guards + * ===================================================================== */ + +TEST_F(SignedMetadataTest, PayloadShorterThan65) { + std::vector blob = base_blob(); + blob.resize(64); // process() early guard: payload_len < 65 + ExpectMalformed(blob, TEST_KEY_ID); +} + +TEST_F(SignedMetadataTest, PayloadBetween65And135) { + std::vector blob = base_blob(); + blob.resize(100); // passes <65 guard, fails parser <136 minimum + ExpectMalformed(blob, TEST_KEY_ID); +} + +TEST_F(SignedMetadataTest, TrailingByteAfterRecovery) { + std::vector blob = base_blob(); + blob.push_back(0x00); // cursor != end + ExpectMalformed(blob, TEST_KEY_ID); +} + +TEST_F(SignedMetadataTest, MissingRecoveryByte) { + std::vector blob = base_blob(); + blob.pop_back(); // truncated tail: read recovery fails + ExpectMalformed(blob, TEST_KEY_ID); +} + +/* ===================================================================== * + * parse_metadata_binary — field guards (all re-signed so the PARSE guard, + * not the signature check, is what rejects the blob) + * ===================================================================== */ + +TEST_F(SignedMetadataTest, BadVersion) { + Spec s = base_spec(); + s.version = 0x02; + ExpectMalformed(sign_body(build_body(s)), TEST_KEY_ID); +} + +TEST_F(SignedMetadataTest, EmptyMethodName) { + Spec s = base_spec(); + s.method = ""; // 2-byte length prefix == 0 + ExpectMalformed(sign_body(build_body(s)), TEST_KEY_ID); +} + +TEST_F(SignedMetadataTest, MethodNameTooLong) { + Spec s = base_spec(); + s.method = std::string(65, 'A'); // > METADATA_MAX_METHOD_LEN (64) + ExpectMalformed(sign_body(build_body(s)), TEST_KEY_ID); +} + +TEST_F(SignedMetadataTest, MethodNameLengthOverrun) { + /* Length prefix claims 64 but only "transfer" (8B) is the method; the read + * consumes downstream bytes and parsing misaligns -> MALFORMED. The clean + * read_string short-read guard is unreachable under the >=136 floor (after + * the 63-byte fixed prefix at least 73 bytes always remain), so this pins + * the observable contract rather than a specific internal branch. The + * corrupted signature byte makes rejection deterministic even in the + * vanishingly unlikely event the misaligned parse re-aligns to the end. */ + Spec s = base_spec(); + s.method_len_override = 64; + std::vector blob = sign_body(build_body(s)); + blob[blob.size() - 2] ^= 0xFF; // ensure verify cannot pass + ExpectMalformed(blob, TEST_KEY_ID); +} + +TEST_F(SignedMetadataTest, NumArgsTooMany) { + Spec s = base_spec(); + s.num_args_override = 9; // > METADATA_MAX_ARGS (8) + ExpectMalformed(sign_body(build_body(s)), TEST_KEY_ID); +} + +TEST_F(SignedMetadataTest, ArgNameEmpty) { + Spec s = base_spec(); + s.args[0] = mk_arg("", ARG_FORMAT_ADDRESS, RECIPIENT, 20); // name_len == 0 + ExpectMalformed(sign_body(build_body(s)), TEST_KEY_ID); +} + +TEST_F(SignedMetadataTest, ArgNameTooLong) { + Spec s = base_spec(); + std::string long_name(33, 'x'); // > METADATA_MAX_ARG_NAME_LEN (32) + s.args[0] = mk_arg(long_name, ARG_FORMAT_ADDRESS, RECIPIENT, 20); + ExpectMalformed(sign_body(build_body(s)), TEST_KEY_ID); +} + +TEST_F(SignedMetadataTest, ArgFormatOutOfRange) { + Spec s = base_spec(); + s.args[0].format = 6; // > ARG_FORMAT_TOKEN_AMOUNT (5) + ExpectMalformed(sign_body(build_body(s)), TEST_KEY_ID); +} + +/* ---- ARG_FORMAT_STRING (attested printable label) ----------------------- */ + +TEST_F(SignedMetadataTest, StringArgAccepted) { + Spec s = base_spec(); + const char* label = "Uniswap V2"; + s.args[0] = mk_arg("protocol", ARG_FORMAT_STRING, (const uint8_t*)label, + strlen(label)); + std::vector blob = sign_body(build_body(s)); + ASSERT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_VERIFIED); + const SignedMetadata* m = signed_metadata_get(); + ASSERT_NE(m, nullptr); + EXPECT_EQ(m->args[0].format, ARG_FORMAT_STRING); + EXPECT_EQ(memcmp(m->args[0].value, label, strlen(label)), 0); +} + +TEST_F(SignedMetadataTest, StringArgRejectsUnprintableAndPercent) { + const uint8_t nl[] = {'a', '\n', 'b'}; + Spec s = base_spec(); + s.args[0] = mk_arg("protocol", ARG_FORMAT_STRING, nl, sizeof(nl)); + ExpectMalformed(sign_body(build_body(s)), TEST_KEY_ID); + + const uint8_t pct[] = {'a', '%', 's'}; + Spec s2 = base_spec(); + s2.args[0] = mk_arg("protocol", ARG_FORMAT_STRING, pct, sizeof(pct)); + ExpectMalformed(sign_body(build_body(s2)), TEST_KEY_ID); + + Spec s3 = base_spec(); + s3.args[0] = mk_arg("protocol", ARG_FORMAT_STRING, pct, 0); // empty string + ExpectMalformed(sign_body(build_body(s3)), TEST_KEY_ID); +} + +/* ---- ARG_FORMAT_TOKEN_AMOUNT (decimals + symbol + amount) --------------- */ + +std::vector token_amount_value(uint8_t decimals, + const std::string& symbol, + const std::vector& amount) { + std::vector v; + v.push_back(decimals); + v.push_back((uint8_t)symbol.size()); + v.insert(v.end(), symbol.begin(), symbol.end()); + v.insert(v.end(), amount.begin(), amount.end()); + return v; +} + +TEST_F(SignedMetadataTest, TokenAmountAccepted) { + /* 1.00 USDC: 1000000 raw, 6 decimals */ + std::vector amt = {0x0F, 0x42, 0x40}; + std::vector val = token_amount_value(6, "USDC", amt); + Spec s = base_spec(); + s.args[1] = mk_arg("amount", ARG_FORMAT_TOKEN_AMOUNT, val.data(), val.size()); + std::vector blob = sign_body(build_body(s)); + ASSERT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_VERIFIED); + const SignedMetadata* m = signed_metadata_get(); + ASSERT_NE(m, nullptr); + EXPECT_EQ(m->args[1].format, ARG_FORMAT_TOKEN_AMOUNT); + EXPECT_EQ(m->args[1].value_len, val.size()); +} + +TEST_F(SignedMetadataTest, TokenAmountUnlimited32BytesAccepted) { + /* UNLIMITED approve: 32 x 0xFF + symbol -> value_len 38 (> old 32 cap) */ + std::vector amt(32, 0xFF); + std::vector val = token_amount_value(6, "USDC", amt); + EXPECT_EQ(val.size(), 38u); // 1+1+4+32 + Spec s = base_spec(); + s.args[1] = mk_arg("amount", ARG_FORMAT_TOKEN_AMOUNT, val.data(), val.size()); + std::vector blob = sign_body(build_body(s)); + EXPECT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_VERIFIED); +} + +TEST_F(SignedMetadataTest, TokenAmountRejectsBadLayout) { + Spec s = base_spec(); + /* symbol chars outside [A-Za-z0-9] */ + std::vector bad_sym = token_amount_value(6, "US-C", {0x01}); + s.args[1] = + mk_arg("amount", ARG_FORMAT_TOKEN_AMOUNT, bad_sym.data(), bad_sym.size()); + ExpectMalformed(sign_body(build_body(s)), TEST_KEY_ID); + + /* decimals > 36 */ + Spec s2 = base_spec(); + std::vector bad_dec = token_amount_value(37, "USDC", {0x01}); + s2.args[1] = + mk_arg("amount", ARG_FORMAT_TOKEN_AMOUNT, bad_dec.data(), bad_dec.size()); + ExpectMalformed(sign_body(build_body(s2)), TEST_KEY_ID); + + /* symbol_len runs past the value (no amount bytes left) */ + Spec s3 = base_spec(); + std::vector no_amt = {6, 4, 'U', 'S', 'D', 'C'}; + s3.args[1] = + mk_arg("amount", ARG_FORMAT_TOKEN_AMOUNT, no_amt.data(), no_amt.size()); + ExpectMalformed(sign_body(build_body(s3)), TEST_KEY_ID); + + /* legacy formats must NOT accept the larger 44-byte cap */ + Spec s4 = base_spec(); + std::vector big(40, 0xAB); + s4.args[1] = mk_arg("amount", ARG_FORMAT_AMOUNT, big.data(), big.size()); + ExpectMalformed(sign_body(build_body(s4)), TEST_KEY_ID); +} + +TEST_F(SignedMetadataTest, ArgValueTooLong) { + Spec s = base_spec(); + uint8_t big[33] = {0}; + s.args[0] = mk_arg("to", ARG_FORMAT_BYTES, big, 33); // > 32 + ExpectMalformed(sign_body(build_body(s)), TEST_KEY_ID); +} + +TEST_F(SignedMetadataTest, ArgValueLengthOverrun) { + /* value_len prefix claims 32 but only 4 value bytes follow; the read eats + * into the fixed tail and parsing misaligns -> MALFORMED. As with the method + * case, the read_bytes short-read guard is dominated by the >=71-byte fixed + * tail, so this asserts the observable MALFORMED outcome. */ + Spec s = base_spec(); + uint8_t four[4] = {0xde, 0xad, 0xbe, 0xef}; + Arg a = mk_arg("amount", ARG_FORMAT_AMOUNT, four, 4); + a.value_len_override = 32; + s.args[1] = a; + std::vector blob = sign_body(build_body(s)); + blob[blob.size() - 2] ^= 0xFF; // ensure verify cannot pass + ExpectMalformed(blob, TEST_KEY_ID); +} + +TEST_F(SignedMetadataTest, ClassificationOutOfRange) { + Spec s = base_spec(); + s.classification = 3; // > 2 + ExpectMalformed(sign_body(build_body(s)), TEST_KEY_ID); +} + +/* ===================================================================== * + * signed_metadata_matches_tx — display gate + * ===================================================================== */ + +TEST_F(SignedMetadataTest, MatchesTxAllBindingsMatch) { + std::vector blob = base_blob(); + ASSERT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_VERIFIED); + EthereumSignTx msg; + make_matching_msg(&msg); + EXPECT_TRUE(signed_metadata_matches_tx(&msg)); +} + +TEST_F(SignedMetadataTest, MatchesTxNotAvailable) { + signed_metadata_clear(); + EthereumSignTx msg; + make_matching_msg(&msg); + EXPECT_FALSE(signed_metadata_matches_tx(&msg)); +} + +TEST_F(SignedMetadataTest, MatchesTxNullMsg) { + std::vector blob = base_blob(); + ASSERT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_VERIFIED); + EXPECT_FALSE(signed_metadata_matches_tx(nullptr)); +} + +TEST_F(SignedMetadataTest, MatchesTxNotVerifiedClassification) { + Spec s = base_spec(); + s.classification = METADATA_OPAQUE; + std::vector blob = sign_body(build_body(s)); + ASSERT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_OPAQUE); + EthereumSignTx msg; + make_matching_msg(&msg); + EXPECT_FALSE(signed_metadata_matches_tx(&msg)); +} + +TEST_F(SignedMetadataTest, MatchesTxWrongToSize) { + std::vector blob = base_blob(); + ASSERT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_VERIFIED); + EthereumSignTx msg; + make_matching_msg(&msg); + msg.to.size = 19; // not 20 (e.g. contract-create has 0) + EXPECT_FALSE(signed_metadata_matches_tx(&msg)); +} + +TEST_F(SignedMetadataTest, MatchesTxDataTooShortForSelector) { + std::vector blob = base_blob(); + ASSERT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_VERIFIED); + EthereumSignTx msg; + make_matching_msg(&msg); + msg.data_initial_chunk.size = 3; // < 4 + EXPECT_FALSE(signed_metadata_matches_tx(&msg)); +} + +TEST_F(SignedMetadataTest, MatchesTxWrongContract) { + std::vector blob = base_blob(); + ASSERT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_VERIFIED); + uint8_t data[68]; + memcpy(data, SEL_TRANSFER, 4); + memset(data + 4, 0, sizeof(data) - 4); + EthereumSignTx msg; + make_msg(&msg, CONTRACT_B, data, sizeof(data), true, 1); + EXPECT_FALSE(signed_metadata_matches_tx(&msg)); +} + +TEST_F(SignedMetadataTest, MatchesTxWrongSelector) { + std::vector blob = base_blob(); + ASSERT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_VERIFIED); + uint8_t data[68]; + memcpy(data, SEL_APPROVE, 4); // approve, not transfer + memset(data + 4, 0, sizeof(data) - 4); + EthereumSignTx msg; + make_msg(&msg, CONTRACT_A, data, sizeof(data), true, 1); + EXPECT_FALSE(signed_metadata_matches_tx(&msg)); +} + +TEST_F(SignedMetadataTest, MatchesTxWrongChainId) { + std::vector blob = base_blob(); + ASSERT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_VERIFIED); + uint8_t data[68]; + memcpy(data, SEL_TRANSFER, 4); + memset(data + 4, 0, sizeof(data) - 4); + + EthereumSignTx wrong_chain; + make_msg(&wrong_chain, CONTRACT_A, data, sizeof(data), true, 137); + EXPECT_FALSE(signed_metadata_matches_tx(&wrong_chain)); + + EthereumSignTx no_chain; + make_msg(&no_chain, CONTRACT_A, data, sizeof(data), false, + 0); // treated as 0 + EXPECT_FALSE(signed_metadata_matches_tx(&no_chain)); +} + +/* ===================================================================== * + * signed_metadata_confirm — no-I/O early guards + * ===================================================================== */ + +TEST_F(SignedMetadataTest, ConfirmNotAvailable) { + signed_metadata_clear(); + EXPECT_FALSE(signed_metadata_confirm()); +} + +TEST_F(SignedMetadataTest, ConfirmNotVerified) { + Spec s = base_spec(); + s.classification = METADATA_OPAQUE; + std::vector blob = sign_body(build_body(s)); + ASSERT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_OPAQUE); + EXPECT_FALSE(signed_metadata_confirm()); +} + +/* ===================================================================== * + * signed_metadata_enforce — module-level not-relied path (reachable + * without confirm()'s interactive tail) and clear() reset + * ===================================================================== */ + +TEST_F(SignedMetadataTest, EnforceNotReliedAlwaysAllows) { + std::vector blob = base_blob(); + ASSERT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_VERIFIED); + ASSERT_FALSE(signed_metadata_relied()); // process() never sets relied + + uint8_t wrong[32]; + memcpy(wrong, TX_HASH, 32); + wrong[0] ^= 0xFF; + EXPECT_TRUE(signed_metadata_enforce(TX_HASH)); + EXPECT_TRUE(signed_metadata_enforce(wrong)); + EXPECT_TRUE(signed_metadata_enforce(nullptr)); +} + +TEST_F(SignedMetadataTest, ClearResetsAllState) { + std::vector blob = base_blob(); + ASSERT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_VERIFIED); + ASSERT_TRUE(signed_metadata_available()); + + signed_metadata_clear(); + EXPECT_FALSE(signed_metadata_available()); + EXPECT_FALSE(signed_metadata_relied()); + EXPECT_EQ(signed_metadata_get(), nullptr); + EXPECT_TRUE(signed_metadata_enforce(TX_HASH)); // not relied +} + +/* ===================================================================== * + * Runtime signer loading — the phase-1 trust path + * ===================================================================== */ + +TEST_F(SignedMetadataTest, NoSignerLoadedRejects) { + signed_metadata_clear_signers(); // undo the fixture's load + ExpectMalformed(base_blob(), TEST_KEY_ID); +} + +TEST_F(SignedMetadataTest, FromLoadedSignerTracksMetadata) { + EXPECT_FALSE(signed_metadata_from_loaded_signer()); // nothing processed + std::vector blob = base_blob(); + ASSERT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_VERIFIED); + EXPECT_TRUE(signed_metadata_from_loaded_signer()); + signed_metadata_clear(); + EXPECT_FALSE(signed_metadata_from_loaded_signer()); +} + +TEST_F(SignedMetadataTest, ClearSignersDropsKeyAndMetadata) { + std::vector blob = base_blob(); + ASSERT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_VERIFIED); + signed_metadata_clear_signers(); + EXPECT_FALSE(signed_metadata_available()); + EXPECT_EQ(signed_metadata_get(), nullptr); + ExpectMalformed(blob, TEST_KEY_ID); // the key itself is gone too +} + +TEST_F(SignedMetadataTest, StoreSignerReplacementInvalidatesOldKey) { + std::vector blob = base_blob(); + ASSERT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_VERIFIED); + + uint8_t priv2[32]; + memcpy(priv2, TEST_PRIV, sizeof(priv2)); + priv2[31] ^= 0x5a; // a different valid scalar + uint8_t pub2[33]; + ecdsa_get_public_key33(&secp256k1, priv2, pub2); + signed_metadata_store_signer(TEST_KEY_ID, pub2, "Replacement", NULL, 0, 0, 0, + false); + + /* Replacing a signer drops metadata the old one verified... */ + EXPECT_FALSE(signed_metadata_available()); + /* ...and the old key no longer verifies anything. */ + ExpectMalformed(blob, TEST_KEY_ID); +} + +/* ---- signed_metadata_signer_valid (pure) ------------------------------ */ + +/* + * ── Identity-icon decoder hardening ──────────────────────────────────────── + * + * The clearsign identity icon is HOST-SUPPLIED and is rendered on the trust + * screen, so the decoder is an attack surface reachable before the user has + * approved anything. Regression guards for two review findings: + * + * (1) A 0x80 (n = -128) packet is undecodable: draw_bitmap_mono_rle's counter + * is int8_t, so -(-128) wraps back to -128 and breaks its `> 0` invariant. + * Under NDEBUG the assert is compiled out and decoding proceeded with a + * negative counter (signed-overflow UB). Must fail closed instead. + * (2) icon_width must not exceed LEFT_MARGIN_WITH_ICON: text starts at x=40 + * and the icon is drawn AFTER the text, so a wider icon overwrites the + * alias / fingerprint / "NOT verified by KeepKey" warning. + */ +namespace { + +struct IconCanvas { + uint8_t buf[64 * 256]; + Canvas canvas; + IconCanvas() { + memset(buf, 0, sizeof(buf)); + canvas.buffer = buf; + canvas.width = 256; + canvas.height = 64; + canvas.dirty = false; + } +}; + +bool decode_icon(const std::vector& data, uint16_t w, uint16_t h, + IconCanvas* ic) { + Image img; + img.w = w; + img.h = h; + img.length = (uint32_t)data.size(); + img.data = data.data(); + AnimationFrame frame; + frame.x = 0; + frame.y = 0; + frame.duration = 0; + frame.color = 100; /* value*100/100 => data bytes land verbatim */ + frame.image = &img; + return draw_bitmap_mono_rle(&ic->canvas, &frame, /*erase=*/false); +} + +} // namespace + +TEST(SignedMetadataIcon, GoldenVectorDecodes) { + /* The vector published in messages-ethereum.proto: 03 FF FF 00 (w=2,h=2). */ + IconCanvas ic; + ASSERT_TRUE(decode_icon({0x03, 0xFF, 0xFF, 0x00}, 2, 2, &ic)); + EXPECT_EQ(ic.buf[0 * 256 + 0], 0xFF); + EXPECT_EQ(ic.buf[0 * 256 + 1], 0xFF); + EXPECT_EQ(ic.buf[1 * 256 + 0], 0xFF); + EXPECT_EQ(ic.buf[1 * 256 + 1], 0x00); +} + +TEST(SignedMetadataIcon, LiteralOf128IsRejected) { + /* n = 0x80 = -128. Spec-valid under the old doc, undecodable in fact: + * previously asserted (debug) or decoded with a negative counter (NDEBUG). */ + std::vector data; + data.push_back(0x80); + for (int i = 0; i < 128; i++) data.push_back(0xAA); + IconCanvas ic; + EXPECT_FALSE(decode_icon(data, 128, 1, &ic)); +} + +TEST(SignedMetadataIcon, ZeroCountIsRejected) { + /* n == 0 leaves both counters at 0 and hits the same broken invariant. */ + IconCanvas ic; + EXPECT_FALSE(decode_icon({0x00, 0xFF}, 1, 1, &ic)); +} + +TEST(SignedMetadataIcon, MaxLiteralOf127Decodes) { + /* The boundary that IS valid: n = -127 (0x81). */ + std::vector data; + data.push_back(0x81); + for (int i = 0; i < 127; i++) data.push_back((uint8_t)i); + IconCanvas ic; + ASSERT_TRUE(decode_icon(data, 127, 1, &ic)); + EXPECT_EQ(ic.buf[0], 0x00); + EXPECT_EQ(ic.buf[126], 126); +} + +TEST(SignedMetadataIcon, MaxRunOf127Decodes) { + std::vector data{0x7F, 0x5A}; + IconCanvas ic; + ASSERT_TRUE(decode_icon(data, 127, 1, &ic)); + EXPECT_EQ(ic.buf[0], 0x5A); + EXPECT_EQ(ic.buf[126], 0x5A); +} + +TEST(SignedMetadataIcon, TruncatedStreamIsRejected) { + IconCanvas ic; + EXPECT_FALSE(decode_icon({0x08, 0xFF}, 4, 4, &ic)); /* claims 8, has 2 */ +} + +/* ── Exact-validation guards (review round 2) ────────────────────────────── + * The render path is lenient by construction: it fills the canvas and stops, + * so it cannot reject a final run that straddles the image or trailing packets. + * Callers gate on the validator, so the validator must be exact. */ + +TEST(SignedMetadataIcon, StraddlingRunIsRejected) { + /* 05 FF for a 2x2: a RUN of 5 into a 4-pixel image. The draw loop would fill + * 4 and report success; the stream is not well-formed. */ + EXPECT_FALSE(draw_bitmap_mono_rle_valid((const uint8_t*)"\x05\xFF", 2, 2, 2)); + IconCanvas ic; + EXPECT_FALSE(decode_icon({0x05, 0xFF}, 2, 2, &ic)); +} + +TEST(SignedMetadataIcon, TrailingPacketsAreRejected) { + /* Exactly fills 2x2, then carries an unread packet. */ + EXPECT_FALSE( + draw_bitmap_mono_rle_valid((const uint8_t*)"\x04\xFF\x01\xAA", 4, 2, 2)); +} + +TEST(SignedMetadataIcon, TruncatedLiteralBodyIsRejected) { + /* n = -3 promises 3 value bytes, only 2 present. */ + EXPECT_FALSE( + draw_bitmap_mono_rle_valid((const uint8_t*)"\xFD\x01\x02", 3, 3, 1)); +} + +TEST(SignedMetadataIcon, MissingRunValueByteIsRejected) { + EXPECT_FALSE(draw_bitmap_mono_rle_valid((const uint8_t*)"\x04", 1, 4, 1)); +} + +TEST(SignedMetadataIcon, ValidatorAcceptsExactStreams) { + /* The golden vector, and the valid boundaries. */ + EXPECT_TRUE( + draw_bitmap_mono_rle_valid((const uint8_t*)"\x03\xFF\xFF\x00", 4, 2, 2)); + EXPECT_TRUE( + draw_bitmap_mono_rle_valid((const uint8_t*)"\x7F\x5A", 2, 127, 1)); + std::vector lit; + lit.push_back(0x81); + for (int i = 0; i < 127; i++) lit.push_back((uint8_t)i); + EXPECT_TRUE( + draw_bitmap_mono_rle_valid(lit.data(), (uint32_t)lit.size(), 127, 1)); +} + +TEST(SignedMetadataIcon, ValidatorRejectsUndecodableAndZeroCounts) { + std::vector lit128; + lit128.push_back(0x80); + for (int i = 0; i < 128; i++) lit128.push_back(0xAA); + EXPECT_FALSE(draw_bitmap_mono_rle_valid(lit128.data(), + (uint32_t)lit128.size(), 128, 1)); + EXPECT_FALSE(draw_bitmap_mono_rle_valid((const uint8_t*)"\x00\xFF", 2, 1, 1)); + /* The 1x1 accept-and-persist case: 80 FF was previously stored despite never + * rendering, because only size+dims were checked at the trust boundary. */ + EXPECT_FALSE(draw_bitmap_mono_rle_valid((const uint8_t*)"\x80\xFF", 2, 1, 1)); +} + +TEST(SignedMetadataIcon, ValidatorRejectsDegenerateGeometry) { + EXPECT_FALSE(draw_bitmap_mono_rle_valid((const uint8_t*)"\x01\xFF", 2, 0, 1)); + EXPECT_FALSE(draw_bitmap_mono_rle_valid((const uint8_t*)"\x01\xFF", 2, 1, 0)); + EXPECT_FALSE(draw_bitmap_mono_rle_valid(NULL, 0, 1, 1)); +} + +TEST(SignedMetadataIcon, IconColumnCapIsNarrowerThanTheIconHeight) { + /* The width cap is the 40px text column, NOT the 64px height. A 64px-wide + * icon at x=0 would span into the text that begins at x=40 and, because the + * icon is drawn after the text, erase the "NOT verified" warning. */ + EXPECT_EQ(LEFT_MARGIN_WITH_ICON, 40); + EXPECT_LT(LEFT_MARGIN_WITH_ICON, 64); +} + +TEST(SignedMetadataSignerValid, AcceptsValidCompressedKeyAllSlots) { + for (uint8_t slot = 0; slot < METADATA_MAX_KEYS; slot++) { + EXPECT_TRUE( + signed_metadata_signer_valid(slot, EXPECTED_SLOT3_PUB, 33, "CI Test")) + << "slot " << (int)slot; + } +} + +TEST(SignedMetadataSignerValid, RejectsKeyIdOutOfRange) { + EXPECT_FALSE(signed_metadata_signer_valid(METADATA_MAX_KEYS, + EXPECTED_SLOT3_PUB, 33, "CI Test")); +} + +TEST(SignedMetadataSignerValid, RejectsWrongPubkeyLength) { + EXPECT_FALSE( + signed_metadata_signer_valid(0, EXPECTED_SLOT3_PUB, 32, "CI Test")); + EXPECT_FALSE( + signed_metadata_signer_valid(0, EXPECTED_SLOT3_PUB, 65, "CI Test")); + EXPECT_FALSE(signed_metadata_signer_valid(0, nullptr, 33, "CI Test")); +} + +TEST(SignedMetadataSignerValid, RejectsNonCompressedPrefix) { + /* 0x04 would make ecdsa_read_pubkey read 65 bytes from a 33-byte buffer — + * the prefix guard must reject it before the parser ever runs. */ + uint8_t bad[33]; + memcpy(bad, EXPECTED_SLOT3_PUB, sizeof(bad)); + bad[0] = 0x04; + EXPECT_FALSE(signed_metadata_signer_valid(0, bad, 33, "CI Test")); + bad[0] = 0x00; // the "empty slot" sentinel must never load as a key + EXPECT_FALSE(signed_metadata_signer_valid(0, bad, 33, "CI Test")); +} + +TEST(SignedMetadataSignerValid, RejectsBadAlias) { + EXPECT_FALSE( + signed_metadata_signer_valid(0, EXPECTED_SLOT3_PUB, 33, nullptr)); + EXPECT_FALSE(signed_metadata_signer_valid(0, EXPECTED_SLOT3_PUB, 33, "")); + std::string too_long(METADATA_ALIAS_MAX_LEN + 1, 'a'); + EXPECT_FALSE(signed_metadata_signer_valid(0, EXPECTED_SLOT3_PUB, 33, + too_long.c_str())); + std::string max_len(METADATA_ALIAS_MAX_LEN, 'a'); + EXPECT_TRUE( + signed_metadata_signer_valid(0, EXPECTED_SLOT3_PUB, 33, max_len.c_str())); + /* Realistic aliases (letters/digits/space/-/_) are accepted. */ + EXPECT_TRUE( + signed_metadata_signer_valid(0, EXPECTED_SLOT3_PUB, 33, "Pioneer")); + EXPECT_TRUE( + signed_metadata_signer_valid(0, EXPECTED_SLOT3_PUB, 33, "KeepKey Swap")); + EXPECT_TRUE( + signed_metadata_signer_valid(0, EXPECTED_SLOT3_PUB, 33, "my-signer_1")); + /* Rendered inside quotes on the trust screen — control chars, '%', and + * semantic-injection punctuation (quote breakout, "." / "(" appending a + * false "verified by KeepKey." claim) are all rejected. */ + EXPECT_FALSE(signed_metadata_signer_valid(0, EXPECTED_SLOT3_PUB, 33, "a\nb")); + EXPECT_FALSE(signed_metadata_signer_valid(0, EXPECTED_SLOT3_PUB, 33, "a%sb")); + EXPECT_FALSE(signed_metadata_signer_valid(0, EXPECTED_SLOT3_PUB, 33, + "a\x7f" + "b")); + EXPECT_FALSE(signed_metadata_signer_valid(0, EXPECTED_SLOT3_PUB, 33, + "x' verified by KeepKey. Safe (")); + EXPECT_FALSE( + signed_metadata_signer_valid(0, EXPECTED_SLOT3_PUB, 33, "safe.KeepKey")); + EXPECT_FALSE( + signed_metadata_signer_valid(0, EXPECTED_SLOT3_PUB, 33, "trust(me)")); +} + +/* ---- signed_metadata_pubkey_fingerprint -------------------------------- */ + +TEST(SignedMetadataFingerprint, IsSha256Prefix) { + char fp[METADATA_FINGERPRINT_LEN]; + signed_metadata_pubkey_fingerprint(EXPECTED_SLOT3_PUB, fp); + + uint8_t digest[32]; + sha256_Raw(EXPECTED_SLOT3_PUB, 33, digest); + char expected[METADATA_FINGERPRINT_LEN]; + snprintf(expected, sizeof(expected), "%02X%02X%02X%02X", digest[0], digest[1], + digest[2], digest[3]); + EXPECT_STREQ(fp, expected); +} + +/* ===================================================================== * + * signed_metadata_enforce_decision — pure enforce truth table (SECTION 2). + * Exercises the relied==true cases that confirm()'s OLED/button I/O makes + * unreachable from the module-state API in a unit test. + * ===================================================================== */ + +TEST(SignedMetadataEnforce, NotReliedAlwaysAllow) { + uint8_t h[32] = {0}; + uint8_t hw[32] = {1}; + EXPECT_TRUE( + signed_metadata_enforce_decision(false, true, METADATA_VERIFIED, h, h)); + EXPECT_TRUE(signed_metadata_enforce_decision(false, false, METADATA_OPAQUE, + nullptr, nullptr)); + EXPECT_TRUE( + signed_metadata_enforce_decision(false, true, METADATA_VERIFIED, h, hw)); +} + +TEST(SignedMetadataEnforce, ReliedHashMatches) { + uint8_t h[32]; + memcpy(h, TX_HASH, 32); + EXPECT_TRUE( + signed_metadata_enforce_decision(true, true, METADATA_VERIFIED, h, h)); +} + +TEST(SignedMetadataEnforce, ReliedHashMismatch) { + uint8_t stored[32]; + memcpy(stored, TX_HASH, 32); + uint8_t got[32]; + memcpy(got, TX_HASH, 32); + got[0] ^= 0x01; + EXPECT_FALSE(signed_metadata_enforce_decision(true, true, METADATA_VERIFIED, + stored, got)); +} + +TEST(SignedMetadataEnforce, ReliedHashNull) { + uint8_t stored[32]; + memcpy(stored, TX_HASH, 32); + EXPECT_FALSE(signed_metadata_enforce_decision(true, true, METADATA_VERIFIED, + stored, nullptr)); +} + +TEST(SignedMetadataEnforce, ReliedNotAvailable) { + uint8_t h[32]; + memcpy(h, TX_HASH, 32); + EXPECT_FALSE( + signed_metadata_enforce_decision(true, false, METADATA_VERIFIED, h, h)); +} + +TEST(SignedMetadataEnforce, ReliedNotVerified) { + uint8_t h[32]; + memcpy(h, TX_HASH, 32); + EXPECT_FALSE( + signed_metadata_enforce_decision(true, true, METADATA_OPAQUE, h, h)); + EXPECT_FALSE( + signed_metadata_enforce_decision(true, true, METADATA_MALFORMED, h, h)); +} + +TEST(SignedMetadataEnforce, ReliedStoredHashNull) { + uint8_t h[32]; + memcpy(h, TX_HASH, 32); + EXPECT_FALSE(signed_metadata_enforce_decision(true, true, METADATA_VERIFIED, + nullptr, h)); +} + +/* ===================================================================== * + * SECTION 3 — v2 static-schema blobs + on-device calldata decode + * + * v2 carries NO tx_hash and NO argument values. The blob attests only the + * static schema (chainId, contract, selector, method, per-arg name + display + * format [+ static decimals/symbol]); the device decodes the actual argument + * values from the calldata it is about to sign. These tests drive the full + * parse -> verify -> signed_metadata_matches_tx (which decodes) path and check + * the decoded MetadataArg values, plus the malformed/rejection cases. + * ===================================================================== */ + +struct V2Arg { + std::string name; + uint8_t format; + uint8_t decimals; /* TOKEN_AMOUNT only */ + std::string symbol; /* TOKEN_AMOUNT only */ +}; + +V2Arg v2_addr(const std::string& name) { + return V2Arg{name, ARG_FORMAT_ADDRESS, 0, ""}; +} +V2Arg v2_token(const std::string& name, uint8_t decimals, + const std::string& symbol) { + return V2Arg{name, ARG_FORMAT_TOKEN_AMOUNT, decimals, symbol}; +} + +struct V2Spec { + uint32_t chain_id; + std::vector contract; + std::vector selector; + std::string method; + std::vector args; + uint8_t classification; + uint8_t key_id; + int num_args_override; // -1 => use args.size() +}; + +V2Spec v2_base_spec() { + V2Spec s; + s.chain_id = 1; + s.contract.assign(CONTRACT_A, CONTRACT_A + 20); + s.selector.assign(SEL_TRANSFER, SEL_TRANSFER + 4); + s.method = "transfer"; + s.args.push_back(v2_addr("to")); + s.args.push_back(v2_token("amount", 6, "USDC")); + s.classification = METADATA_VERIFIED; + s.key_id = TEST_KEY_ID; + s.num_args_override = -1; + return s; +} + +std::vector build_v2_body(const V2Spec& s) { + std::vector b; + put_u8(b, METADATA_VERSION_SCHEMA); + put_be32(b, s.chain_id); + put_bytes(b, s.contract.data(), s.contract.size()); + put_bytes(b, s.selector.data(), s.selector.size()); + put_be16(b, (uint16_t)s.method.size()); + put_bytes(b, (const uint8_t*)s.method.data(), s.method.size()); + put_u8(b, s.num_args_override >= 0 ? (uint8_t)s.num_args_override + : (uint8_t)s.args.size()); + for (const V2Arg& a : s.args) { + put_u8(b, (uint8_t)a.name.size()); + put_bytes(b, (const uint8_t*)a.name.data(), a.name.size()); + put_u8(b, a.format); + if (a.format == ARG_FORMAT_TOKEN_AMOUNT) { + put_u8(b, a.decimals); + put_u8(b, (uint8_t)a.symbol.size()); + put_bytes(b, (const uint8_t*)a.symbol.data(), a.symbol.size()); + } + } + put_u8(b, s.classification); + put_be32(b, 0); // timestamp + put_u8(b, s.key_id); + return b; +} + +std::vector v2_base_blob() { + return sign_body(build_v2_body(v2_base_spec())); +} + +/* ABI calldata: selector + one 32-byte head word per arg. */ +void put_addr_word(std::vector& d, const uint8_t addr[20]) { + for (int i = 0; i < 12; i++) d.push_back(0); + d.insert(d.end(), addr, addr + 20); +} + +/* Canonical transfer(to=RECIPIENT, amount=AMOUNT32) calldata (4 + 64 = 68). */ +std::vector v2_transfer_calldata() { + std::vector d(SEL_TRANSFER, SEL_TRANSFER + 4); + put_addr_word(d, RECIPIENT); + d.insert(d.end(), AMOUNT32, AMOUNT32 + 32); + return d; +} + +void make_v2_msg(EthereumSignTx* msg, const uint8_t contract[20], + const std::vector& data, bool has_len, + uint32_t data_length) { + memset(msg, 0, sizeof(*msg)); + msg->has_to = true; + msg->to.size = 20; + memcpy(msg->to.bytes, contract, 20); + msg->has_data_initial_chunk = true; + msg->data_initial_chunk.size = (pb_size_t)data.size(); + memcpy(msg->data_initial_chunk.bytes, data.data(), data.size()); + msg->has_chain_id = true; + msg->chain_id = 1; + msg->has_data_length = has_len; + msg->data_length = has_len ? data_length : 0; +} + +/* Happy path: parse+verify a v2 blob, then matches_tx decodes the args from the + * transfer calldata and populates stored_metadata. */ +TEST_F(SignedMetadataTest, V2SchemaDecodesTransferArgs) { + std::vector blob = v2_base_blob(); + EXPECT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_VERIFIED); + EXPECT_TRUE(signed_metadata_available()); + + const SignedMetadata* md = signed_metadata_get(); + ASSERT_NE(md, nullptr); + EXPECT_EQ(md->version, METADATA_VERSION_SCHEMA); + EXPECT_EQ(md->num_args, 2); + EXPECT_EQ(md->args[0].value_len, 0); // undecoded before matches_tx + + EthereumSignTx msg; + std::vector data = v2_transfer_calldata(); + make_v2_msg(&msg, CONTRACT_A, data, /*has_len=*/true, (uint32_t)data.size()); + EXPECT_TRUE(signed_metadata_matches_tx(&msg)); + + EXPECT_EQ(md->args[0].format, ARG_FORMAT_ADDRESS); + EXPECT_EQ(md->args[0].value_len, 20); + EXPECT_EQ(memcmp(md->args[0].value, RECIPIENT, 20), 0); + + EXPECT_EQ(md->args[1].format, ARG_FORMAT_TOKEN_AMOUNT); + EXPECT_EQ(md->args[1].value_len, 2 + 4 + 32); + EXPECT_EQ(md->args[1].value[0], 6); // decimals + EXPECT_EQ(md->args[1].value[1], 4); // symlen + EXPECT_EQ(memcmp(md->args[1].value + 2, "USDC", 4), 0); + EXPECT_EQ(memcmp(md->args[1].value + 6, AMOUNT32, 32), 0); +} + +/* THE v2 drain preventer: a v2 schema commits to calldata only — never to + * msg->value — and a v2 match suppresses ethereum.c's native-value confirm + * screen. A payable method could then clear-sign an arbitrary ETH transfer + * whose value is never shown. Any nonzero native value must therefore refuse + * the v2 match and fall to the blind-sign gate. (v1 is safe: tx_hash covers + * value.) */ +TEST_F(SignedMetadataTest, V2SchemaRejectsNonzeroNativeValue) { + std::vector blob = v2_base_blob(); + ASSERT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_VERIFIED); + + EthereumSignTx msg; + std::vector data = v2_transfer_calldata(); + make_v2_msg(&msg, CONTRACT_A, data, /*has_len=*/true, (uint32_t)data.size()); + msg.has_value = true; + msg.value.size = 1; + msg.value.bytes[0] = 0x01; // 1 wei is enough — any nonzero value refuses + EXPECT_FALSE(signed_metadata_matches_tx(&msg)); + + /* Same tx with zero value clear-signs — proving the refusal above is the + * value guard, not some other binding. */ + msg.value.size = 0; + msg.has_value = false; + EXPECT_TRUE(signed_metadata_matches_tx(&msg)); +} + +/* Relay solver swap: selector 0x02d5f05f(token address, amount, requestId) — + * three fixed single words, EXACTLY the shape pulled from real relay traffic + * (100-byte calldata: 4 + 3*32, zero remainder, verified across 22 live + * samples). Proves a v2 static schema clear-signs a relay swap: the device + * decodes token+amount+id from the very calldata it is about to sign — no + * tx_hash, no per-tx online signer, schema signed once offline. This is the + * "add a new service via a signed payload" path for a NON-native contract + * (relay is not in ethereum_contractHandled). */ +TEST_F(SignedMetadataTest, V2SchemaDecodesRelaySolverArgs) { + const uint8_t RELAY_SOLVER[20] = {0x4c, 0xd0, 0x0e, 0x38, 0x76, 0x22, 0xc3, + 0x5b, 0xdd, 0xb9, 0xb4, 0x96, 0x2c, 0x13, + 0x64, 0x62, 0x33, 0x8b, 0xc3, 0x31}; + const uint8_t SEL_RELAY[4] = {0x02, 0xd5, 0xf0, 0x5f}; + uint8_t REQ_ID[32] = {0}; // requestId 0x...cd7c from a real sample + REQ_ID[30] = 0xcd; + REQ_ID[31] = 0x7c; + + V2Spec s = v2_base_spec(); + s.contract.assign(RELAY_SOLVER, RELAY_SOLVER + 20); + s.selector.assign(SEL_RELAY, SEL_RELAY + 4); + s.method = "relaySwap"; + s.args.clear(); + s.args.push_back(v2_addr("token")); + s.args.push_back(v2_token("amount", 6, "USDC")); + s.args.push_back(V2Arg{"requestId", ARG_FORMAT_AMOUNT, 0, ""}); + + std::vector blob = sign_body(build_v2_body(s)); + EXPECT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_VERIFIED); + + const SignedMetadata* md = signed_metadata_get(); + ASSERT_NE(md, nullptr); + EXPECT_EQ(md->version, METADATA_VERSION_SCHEMA); + EXPECT_EQ(md->num_args, 3); + + // Real relay calldata: selector + token(USDC=CONTRACT_A) + amount + + // requestId. + std::vector data(SEL_RELAY, SEL_RELAY + 4); + put_addr_word(data, CONTRACT_A); + data.insert(data.end(), AMOUNT32, AMOUNT32 + 32); + data.insert(data.end(), REQ_ID, REQ_ID + 32); + EXPECT_EQ(data.size(), 100u); + + EthereumSignTx msg; + make_v2_msg(&msg, RELAY_SOLVER, data, /*has_len=*/true, + (uint32_t)data.size()); + EXPECT_TRUE(signed_metadata_matches_tx(&msg)); + + // token → full 20-byte USDC address (never truncated). + EXPECT_EQ(md->args[0].format, ARG_FORMAT_ADDRESS); + EXPECT_EQ(md->args[0].value_len, 20); + EXPECT_EQ(memcmp(md->args[0].value, CONTRACT_A, 20), 0); + + // amount → TOKEN_AMOUNT [decimals=6, "USDC", 32-byte amount]. + EXPECT_EQ(md->args[1].format, ARG_FORMAT_TOKEN_AMOUNT); + EXPECT_EQ(md->args[1].value[0], 6); + EXPECT_EQ(md->args[1].value[1], 4); + EXPECT_EQ(memcmp(md->args[1].value + 2, "USDC", 4), 0); + EXPECT_EQ(memcmp(md->args[1].value + 6, AMOUNT32, 32), 0); + + // requestId → raw 32-byte AMOUNT word. + EXPECT_EQ(md->args[2].format, ARG_FORMAT_AMOUNT); + EXPECT_EQ(md->args[2].value_len, 32); + EXPECT_EQ(memcmp(md->args[2].value, REQ_ID, 32), 0); +} + +/* has_data_length omitted but the initial chunk IS the whole calldata: allowed. + */ +TEST_F(SignedMetadataTest, V2AcceptsNoDataLengthWhenChunkComplete) { + std::vector blob = v2_base_blob(); + ASSERT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_VERIFIED); + EthereumSignTx msg; + std::vector data = v2_transfer_calldata(); + make_v2_msg(&msg, CONTRACT_A, data, /*has_len=*/false, 0); + EXPECT_TRUE(signed_metadata_matches_tx(&msg)); +} + +/* Reject when the tx claims MORE calldata than the schema accounts for. */ +TEST_F(SignedMetadataTest, V2RejectsExtraCalldataLength) { + std::vector blob = v2_base_blob(); + ASSERT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_VERIFIED); + EthereumSignTx msg; + std::vector data = v2_transfer_calldata(); // 68 bytes + make_v2_msg(&msg, CONTRACT_A, data, /*has_len=*/true, 100); + EXPECT_FALSE(signed_metadata_matches_tx(&msg)); +} + +/* Reject a partial initial chunk (rest would stream later). */ +TEST_F(SignedMetadataTest, V2RejectsPartialInitialChunk) { + std::vector blob = v2_base_blob(); + ASSERT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_VERIFIED); + EthereumSignTx msg; + std::vector data = v2_transfer_calldata(); + data.resize(40); // selector + partial first word + make_v2_msg(&msg, CONTRACT_A, data, /*has_len=*/true, 68); + EXPECT_FALSE(signed_metadata_matches_tx(&msg)); +} + +/* Reject an ABI address word with non-zero high bytes. */ +TEST_F(SignedMetadataTest, V2RejectsDirtyAddressWord) { + std::vector blob = v2_base_blob(); + ASSERT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_VERIFIED); + EthereumSignTx msg; + std::vector data = v2_transfer_calldata(); + data[4] = 0x01; // first (should-be-zero) byte of the address word + make_v2_msg(&msg, CONTRACT_A, data, /*has_len=*/true, (uint32_t)data.size()); + EXPECT_FALSE(signed_metadata_matches_tx(&msg)); +} + +/* Wrong selector in calldata -> matches_tx fails before decode. */ +TEST_F(SignedMetadataTest, V2RejectsSelectorMismatch) { + std::vector blob = v2_base_blob(); + ASSERT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_VERIFIED); + EthereumSignTx msg; + std::vector data = v2_transfer_calldata(); + memcpy(data.data(), SEL_APPROVE, 4); + make_v2_msg(&msg, CONTRACT_A, data, /*has_len=*/true, (uint32_t)data.size()); + EXPECT_FALSE(signed_metadata_matches_tx(&msg)); +} + +/* An unsupported display format (dynamic types out of scope) -> MALFORMED. */ +TEST_F(SignedMetadataTest, V2RejectsUnsupportedFormat) { + V2Spec s = v2_base_spec(); + s.args[1] = V2Arg{"data", ARG_FORMAT_BYTES, 0, ""}; + std::vector blob = sign_body(build_v2_body(s)); + ExpectMalformed(blob, TEST_KEY_ID); +} + +/* Tampered v2 body must fail the signature check. */ +TEST_F(SignedMetadataTest, V2RejectsTamperedBody) { + std::vector blob = v2_base_blob(); + blob[5] ^= 0xFF; // flip a contract-address byte in the signed region + ExpectMalformed(blob, TEST_KEY_ID); +} + +/* Zero-arg v2 schema (selector-only call): valid, decodes nothing. */ +TEST_F(SignedMetadataTest, V2ZeroArgsSelectorOnly) { + V2Spec s = v2_base_spec(); + s.args.clear(); + s.method = "poke"; + std::vector blob = sign_body(build_v2_body(s)); + ASSERT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_VERIFIED); + EthereumSignTx msg; + std::vector data(SEL_TRANSFER, SEL_TRANSFER + 4); + make_v2_msg(&msg, CONTRACT_A, data, /*has_len=*/true, 4); + EXPECT_TRUE(signed_metadata_matches_tx(&msg)); + EXPECT_EQ(signed_metadata_get()->num_args, 0); +} + +/* matches_tx() must be idempotent: a second call decodes to the same values + * (regression for the TOKEN_AMOUNT prefix that used to grow on each call). */ +TEST_F(SignedMetadataTest, V2MatchesTxIsIdempotent) { + std::vector blob = v2_base_blob(); + ASSERT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_VERIFIED); + EthereumSignTx msg; + std::vector data = v2_transfer_calldata(); + make_v2_msg(&msg, CONTRACT_A, data, /*has_len=*/true, (uint32_t)data.size()); + + EXPECT_TRUE(signed_metadata_matches_tx(&msg)); + const SignedMetadata* md = signed_metadata_get(); + uint16_t len_addr = md->args[0].value_len, len_tok = md->args[1].value_len; + + EXPECT_TRUE(signed_metadata_matches_tx(&msg)); // second call + EXPECT_EQ(md->args[0].value_len, len_addr); + EXPECT_EQ(md->args[1].value_len, len_tok); + EXPECT_EQ(md->args[1].value_len, 2 + 4 + 32); + EXPECT_EQ(memcmp(md->args[0].value, RECIPIENT, 20), 0); + EXPECT_EQ(memcmp(md->args[1].value + 6, AMOUNT32, 32), 0); +} + +/* The v2 decode flag must reflect ONLY the latest matches_tx() call: a + * successful decode followed by a mismatching tx must leave it false, so a + * stale "decoded" proof can never survive into enforce. */ +TEST_F(SignedMetadataTest, V2SchemaDecodedFlagNotStaleAfterMismatch) { + std::vector blob = v2_base_blob(); + ASSERT_EQ(signed_metadata_process(blob.data(), blob.size(), TEST_KEY_ID), + METADATA_VERIFIED); + EXPECT_FALSE(signed_metadata_schema_decoded()); // not decoded yet + + EthereumSignTx ok; + std::vector data = v2_transfer_calldata(); + make_v2_msg(&ok, CONTRACT_A, data, /*has_len=*/true, (uint32_t)data.size()); + ASSERT_TRUE(signed_metadata_matches_tx(&ok)); + EXPECT_TRUE(signed_metadata_schema_decoded()); // decoded this tx + + /* Now a tx that fails an EARLY binding (wrong contract) — before the decode + * branch. The flag must be cleared, not left over from the match above. */ + EthereumSignTx bad; + make_v2_msg(&bad, CONTRACT_B, data, /*has_len=*/true, (uint32_t)data.size()); + EXPECT_FALSE(signed_metadata_matches_tx(&bad)); + EXPECT_FALSE(signed_metadata_schema_decoded()); +} + +/* ---- v2 enforce truth table (pure, no I/O) ------------------------------ */ +/* Signature: (relied, available, decoded, classification). */ + +TEST(SignedMetadataEnforceSchema, NotReliedAlwaysAllow) { + EXPECT_TRUE(signed_metadata_enforce_schema_decision(false, true, true, + METADATA_VERIFIED)); + EXPECT_TRUE(signed_metadata_enforce_schema_decision(false, false, false, + METADATA_OPAQUE)); +} + +TEST(SignedMetadataEnforceSchema, ReliedVerifiedDecodedAllow) { + EXPECT_TRUE(signed_metadata_enforce_schema_decision(true, true, true, + METADATA_VERIFIED)); +} + +TEST(SignedMetadataEnforceSchema, ReliedButNotDecodedFails) { + /* The core hardening: relied + available + VERIFIED but decode never ran. */ + EXPECT_FALSE(signed_metadata_enforce_schema_decision(true, true, false, + METADATA_VERIFIED)); +} + +TEST(SignedMetadataEnforceSchema, ReliedButUnavailableOrUnverifiedFails) { + EXPECT_FALSE(signed_metadata_enforce_schema_decision(true, false, true, + METADATA_VERIFIED)); + EXPECT_FALSE(signed_metadata_enforce_schema_decision(true, true, true, + METADATA_OPAQUE)); + EXPECT_FALSE(signed_metadata_enforce_schema_decision(true, true, true, + METADATA_MALFORMED)); +} + +// Generic attestation primitive (used by the Solana signed-token-definition +// path): a valid signature from a loaded signer verifies; tampering, an +// unloaded key_id, or a wrong signature length are all rejected. +TEST(SignedMetadataAttestation, VerifiesValidRejectsTampered) { + signed_metadata_clear_signers(); + signed_metadata_store_signer(TEST_KEY_ID, EXPECTED_SLOT3_PUB, TEST_ALIAS, + nullptr, 0, 0, 0, false); + + const uint8_t data[] = "KeepKeySolanaTokenDef/1|mint|decimals|USDC"; + const size_t len = sizeof(data) - 1; + uint8_t digest[32]; + sha256_Raw(data, len, digest); + uint8_t sig[64]; + uint8_t pby; + ASSERT_EQ( + 0, ecdsa_sign_digest(&secp256k1, TEST_PRIV, digest, sig, &pby, nullptr)); + + EXPECT_TRUE(signed_metadata_verify_attestation(TEST_KEY_ID, data, len, sig, + sizeof(sig))); + + std::vector bad(data, data + len); + bad[0] ^= 0x01; + EXPECT_FALSE(signed_metadata_verify_attestation(TEST_KEY_ID, bad.data(), len, + sig, sizeof(sig))); + EXPECT_FALSE(signed_metadata_verify_attestation((uint8_t)(TEST_KEY_ID + 1), + data, len, sig, sizeof(sig))); + EXPECT_FALSE( + signed_metadata_verify_attestation(TEST_KEY_ID, data, len, sig, 63)); + + signed_metadata_clear_signers(); +} + +// End-to-end test of the production Solana token-definition path: builds the +// exact domain-separated preimage solana_token_info_trusted() reconstructs, +// signs it, and checks acceptance + every rejection branch. +TEST(SolanaTokenDef, TrustedOnlyWithValidAttestation) { + signed_metadata_clear_signers(); + signed_metadata_store_signer(TEST_KEY_ID, EXPECTED_SLOT3_PUB, TEST_ALIAS, + nullptr, 0, 0, 0, false); + + SolanaTokenInfo ti; + memset(&ti, 0, sizeof(ti)); + ti.has_mint = true; + ti.mint.size = 32; + memset(ti.mint.bytes, 0xAB, 32); + ti.has_symbol = true; + strcpy(ti.symbol, "USDC"); + ti.has_decimals = true; + ti.decimals = 6; + ti.has_signer_key_id = true; + ti.signer_key_id = TEST_KEY_ID; + + // Canonical preimage: tag || mint(32) || decimals(le32) || symbol. + std::vector pre; + const char* tag = "KeepKeySolanaTokenDef/1"; + pre.insert(pre.end(), tag, tag + strlen(tag)); + pre.insert(pre.end(), ti.mint.bytes, ti.mint.bytes + 32); + pre.push_back(6); + pre.push_back(0); + pre.push_back(0); + pre.push_back(0); + pre.insert(pre.end(), ti.symbol, ti.symbol + strlen(ti.symbol)); + + uint8_t digest[32]; + sha256_Raw(pre.data(), pre.size(), digest); + uint8_t sig[64]; + uint8_t pby; + ASSERT_EQ( + 0, ecdsa_sign_digest(&secp256k1, TEST_PRIV, digest, sig, &pby, nullptr)); + ti.has_signature = true; + ti.signature.size = 64; + memcpy(ti.signature.bytes, sig, 64); + + EXPECT_TRUE(solana_token_info_trusted(&ti)); + + // Attested-tuple disagreement: a different decimals no longer matches the + // sig. + ti.decimals = 9; + EXPECT_FALSE(solana_token_info_trusted(&ti)); + ti.decimals = 6; + EXPECT_TRUE(solana_token_info_trusted(&ti)); + + // Corrupted signature. + ti.signature.bytes[10] ^= 0x40; + EXPECT_FALSE(solana_token_info_trusted(&ti)); + ti.signature.bytes[10] ^= 0x40; + + // Out-of-range signer slot (256 would narrow to slot 0 without the guard). + ti.signer_key_id = 256; + EXPECT_FALSE(solana_token_info_trusted(&ti)); + ti.signer_key_id = TEST_KEY_ID; + + // No attestation -> not trusted (the caller falls back to unsigned display). + ti.has_signature = false; + EXPECT_FALSE(solana_token_info_trusted(&ti)); + + signed_metadata_clear_signers(); +} + +} // namespace diff --git a/unittests/firmware/solana.cpp b/unittests/firmware/solana.cpp index 36ccef252..978cf3943 100644 --- a/unittests/firmware/solana.cpp +++ b/unittests/firmware/solana.cpp @@ -225,14 +225,138 @@ TEST(Solana, ParseSPLTokenTransfer) { raw[pos++] = 0x00; SolanaParsedTx tx; - EXPECT_EQ(solana_inspectTx(raw, pos, &tx), SOL_TX_REVIEW_VERIFIED); - ASSERT_TRUE(solana_parseTx(raw, pos, &tx)); + /* Unchecked SPL Transfer carries no signed mint (the token being moved is not + * provable), so the transaction is now OPAQUE — it requires AdvancedMode + * blind-signing rather than clear-signing. The instruction is still parsed. + */ + EXPECT_EQ(solana_inspectTx(raw, pos, &tx), SOL_TX_REVIEW_OPAQUE); EXPECT_EQ(tx.num_instructions, 1); EXPECT_EQ(tx.instructions[0].type, SOL_INSTR_TOKEN_TRANSFER); EXPECT_EQ(tx.instructions[0].amount, 1000000ULL); } +TEST(Solana, Token2022TransferCheckedIsOpaque) { + /* A Token-2022 TransferChecked can invoke an undisclosed transfer hook / fee, + * so it must NOT clear-sign (only legacy SPL Token TransferChecked does). */ + uint8_t raw[512]; + size_t pos = 0; + raw[pos++] = 1; + raw[pos++] = 0; + raw[pos++] = 1; + raw[pos++] = 5; /* source, mint, dest, authority, token-2022 program */ + memset(raw + pos, 0x11, 32); + pos += 32; + memset(raw + pos, 0x22, 32); + pos += 32; + memset(raw + pos, 0x33, 32); + pos += 32; + memset(raw + pos, 0x44, 32); + pos += 32; + memcpy(raw + pos, SOL_TOKEN_2022_PROGRAM, 32); + pos += 32; + memset(raw + pos, 0xBB, 32); + pos += 32; + raw[pos++] = 1; /* 1 instruction */ + raw[pos++] = 4; /* program index = token-2022 */ + raw[pos++] = 4; /* 4 accounts */ + raw[pos++] = 0; + raw[pos++] = 1; + raw[pos++] = 2; + raw[pos++] = 3; + raw[pos++] = 10; /* data length */ + raw[pos++] = 12; /* TransferChecked */ + raw[pos++] = 0x40; + raw[pos++] = 0x42; + raw[pos++] = 0x0F; + raw[pos++] = 0x00; + raw[pos++] = 0x00; + raw[pos++] = 0x00; + raw[pos++] = 0x00; + raw[pos++] = 0x00; + raw[pos++] = 6; /* decimals */ + + SolanaParsedTx tx; + EXPECT_EQ(solana_inspectTx(raw, pos, &tx), SOL_TX_REVIEW_OPAQUE); +} + +/* Helper: build a Vote UpdateValidatorIdentity tx with the given instruction + * data length (4 = canonical; >4 = trailing bytes). Accounts: vote(0), + * new-validator(1), authority(2), vote-program. */ +static size_t build_vote_update_validator(uint8_t* raw, uint16_t data_len) { + size_t pos = 0; + raw[pos++] = 1; + raw[pos++] = 0; + raw[pos++] = 1; + raw[pos++] = 4; + memset(raw + pos, 0x11, 32); + pos += 32; /* vote account (idx 0) */ + memset(raw + pos, 0x22, 32); + pos += 32; /* new validator (idx 1) */ + memset(raw + pos, 0x33, 32); + pos += 32; /* authority (idx 2) */ + memcpy(raw + pos, SOL_VOTE_PROGRAM, 32); + pos += 32; + memset(raw + pos, 0xBB, 32); + pos += 32; /* blockhash */ + raw[pos++] = 1; + raw[pos++] = 3; /* program index = vote */ + raw[pos++] = 3; /* 3 accounts */ + raw[pos++] = 0; + raw[pos++] = 1; + raw[pos++] = 2; + raw[pos++] = (uint8_t)data_len; + raw[pos++] = 4; /* UpdateValidatorIdentity discriminator (le32) */ + raw[pos++] = 0; + raw[pos++] = 0; + raw[pos++] = 0; + for (uint16_t i = 4; i < data_len; i++) raw[pos++] = 0x77; /* trailing */ + return pos; +} + +TEST(Solana, VoteUpdateValidatorReadsAccountNotData) { + uint8_t raw[512]; + size_t pos = build_vote_update_validator(raw, 4); /* canonical */ + SolanaParsedTx tx; + EXPECT_EQ(solana_inspectTx(raw, pos, &tx), SOL_TX_REVIEW_VERIFIED); + EXPECT_EQ(tx.instructions[0].type, SOL_INSTR_VOTE_UPDATE_VALIDATOR); + /* The new validator must be account index 1 (0x22..), never fabricated data. + */ + uint8_t expected[32]; + memset(expected, 0x22, 32); + EXPECT_EQ(0, memcmp(tx.instructions[0].extra, expected, 32)); +} + +TEST(Solana, VoteUpdateValidatorRejectsTrailingBytes) { + uint8_t raw[512]; + /* 4-byte discriminator + 32 fabricated bytes — used to be displayed as a + * fake validator; now non-canonical, so the tx is opaque (blind-sign only). + */ + size_t pos = build_vote_update_validator(raw, 36); + SolanaParsedTx tx; + EXPECT_EQ(solana_inspectTx(raw, pos, &tx), SOL_TX_REVIEW_OPAQUE); +} + +TEST(Solana, PriorityFeeOverflowSafe) { + uint64_t fee = 0; + /* The wrap-to-zero case: price=UINT64_MAX, limit=1. A naive + * (price*limit + 999999)/1e6 wraps to 0; the real fee is 18446.744073710 SOL + * (= 18446744073710 lamports) and must be shown, not hidden. */ + EXPECT_TRUE(solana_priority_fee_lamports(UINT64_MAX, 1, &fee)); + EXPECT_EQ(fee, 18446744073710ULL); + + /* Typical fee: 1000 micro-lamports/CU * 200000 CU / 1e6 = 200 lamports. */ + EXPECT_TRUE(solana_priority_fee_lamports(1000, 200000, &fee)); + EXPECT_EQ(fee, 200ULL); + + /* Sub-lamport fee rounds UP (fees are charged even for one CU). */ + EXPECT_TRUE(solana_priority_fee_lamports(1, 1, &fee)); + EXPECT_EQ(fee, 1ULL); + + /* A fee that truly exceeds u64 lamports is rejected, never saturated. */ + EXPECT_FALSE(solana_priority_fee_lamports(UINT64_MAX, UINT64_MAX, &fee)); +} + TEST(Solana, ParseAssociatedTokenAccountCreate) { uint8_t raw[512]; size_t pos = 0; @@ -480,15 +604,27 @@ TEST(Solana, RejectsExcessInstructions) { memset(raw + pos, 0xBB, 32); pos += 32; - /* 9 instructions (exceeds limit of 8) */ + /* 9 instructions (exceeds limit of 8), each minimal but well-formed: + * program_idx + zero account indices + zero data bytes */ raw[pos++] = 9; + for (int i = 0; i < 9; i++) { + raw[pos++] = 1; /* program = account 1 */ + raw[pos++] = 0; /* no account indices */ + raw[pos++] = 0; /* no data */ + } SolanaParsedTx tx; EXPECT_EQ(solana_inspectTx(raw, pos, &tx), SOL_TX_REVIEW_OPAQUE); EXPECT_FALSE(solana_parseTx(raw, pos, &tx)); + + /* A claimed instruction count with truncated bodies is malformed */ + uint8_t truncated[256]; + memcpy(truncated, raw, pos - 27); + EXPECT_EQ(solana_inspectTx(truncated, pos - 27, &tx), + SOL_TX_REVIEW_MALFORMED); } -TEST(Solana, VersionedMessageIsOpaque) { +TEST(Solana, VersionedMessageNoLookupTablesIsVerified) { uint8_t raw[256]; size_t pos = 0; @@ -529,12 +665,20 @@ TEST(Solana, VersionedMessageIsOpaque) { raw[pos++] = 0; /* zero lookup tables */ + /* A v0 message whose instructions touch only static accounts is as + * verifiable as a legacy message — swap providers build these. */ SolanaParsedTx tx; - EXPECT_EQ(solana_inspectTx(raw, pos, &tx), SOL_TX_REVIEW_OPAQUE); - EXPECT_FALSE(solana_parseTx(raw, pos, &tx)); + EXPECT_EQ(solana_inspectTx(raw, pos, &tx), SOL_TX_REVIEW_VERIFIED); + EXPECT_TRUE(solana_parseTx(raw, pos, &tx)); + ASSERT_EQ(tx.num_instructions, 1); + EXPECT_EQ(tx.instructions[0].type, SOL_INSTR_SYSTEM_TRANSFER); + EXPECT_EQ(tx.instructions[0].lamports, 1000000000ULL); + uint8_t expected_to[32]; + memset(expected_to, 0x22, 32); + EXPECT_EQ(memcmp(tx.instructions[0].to, expected_to, 32), 0); } -TEST(Solana, VersionedMessageWithLookupTableIsOpaque) { +TEST(Solana, VersionedMessageWithUnreferencedLookupTableIsVerified) { uint8_t raw[256]; size_t pos = 0; @@ -582,11 +726,127 @@ TEST(Solana, VersionedMessageWithLookupTableIsOpaque) { raw[pos++] = 1; raw[pos++] = 2; + /* Table attached but no instruction reaches into it: every displayed + * field is decoded from static accounts, so it stays verifiable. */ + SolanaParsedTx tx; + EXPECT_EQ(solana_inspectTx(raw, pos, &tx), SOL_TX_REVIEW_VERIFIED); + EXPECT_TRUE(solana_parseTx(raw, pos, &tx)); +} + +TEST(Solana, VersionedInstructionUsingLookupAccountIsOpaque) { + uint8_t raw[256]; + size_t pos = 0; + + raw[pos++] = 0x80; /* v0 prefix */ + raw[pos++] = 1; + raw[pos++] = 0; + raw[pos++] = 1; + + raw[pos++] = 3; /* static accounts */ + memset(raw + pos, 0x11, 32); + pos += 32; + memset(raw + pos, 0x22, 32); + pos += 32; + memset(raw + pos, 0x00, 32); + pos += 32; + + memset(raw + pos, 0xBB, 32); + pos += 32; + + raw[pos++] = 1; /* instructions */ + raw[pos++] = 2; /* program = system (static) */ + raw[pos++] = 2; + raw[pos++] = 0; + raw[pos++] = 3; /* index 3 = first lookup-table account */ + raw[pos++] = 12; + raw[pos++] = 2; + raw[pos++] = 0; + raw[pos++] = 0; + raw[pos++] = 0; + raw[pos++] = 0x00; + raw[pos++] = 0xCA; + raw[pos++] = 0x9A; + raw[pos++] = 0x3B; + raw[pos++] = 0x00; + raw[pos++] = 0x00; + raw[pos++] = 0x00; + raw[pos++] = 0x00; + + raw[pos++] = 1; /* one lookup table */ + memset(raw + pos, 0x55, 32); + pos += 32; + raw[pos++] = 1; + raw[pos++] = 0; + raw[pos++] = 0; + + /* The recipient lives in a lookup table the device cannot resolve — + * must be opaque (blind-signable under AdvancedMode), NOT malformed, + * and NEVER verified. */ SolanaParsedTx tx; EXPECT_EQ(solana_inspectTx(raw, pos, &tx), SOL_TX_REVIEW_OPAQUE); EXPECT_FALSE(solana_parseTx(raw, pos, &tx)); } +TEST(Solana, MemoBodyCaptured) { + /* Legacy tx: system transfer + memo instruction (THORChain-style swap + * memo). The parser must expose the memo bytes for display. */ + const char* memo = "=:ETH.ETH:0x1234:0/1/0:kk:75"; + uint8_t raw[512]; + size_t pos = 0; + + raw[pos++] = 1; + raw[pos++] = 0; + raw[pos++] = 2; /* system + memo programs readonly */ + + raw[pos++] = 4; /* accounts: sender, recipient, system, memo */ + memset(raw + pos, 0x11, 32); + pos += 32; + memset(raw + pos, 0x22, 32); + pos += 32; + memset(raw + pos, 0x00, 32); /* system program */ + pos += 32; + memcpy(raw + pos, SOL_MEMO_PROGRAM, 32); + pos += 32; + + memset(raw + pos, 0xBB, 32); /* blockhash */ + pos += 32; + + raw[pos++] = 2; /* two instructions */ + + /* transfer */ + raw[pos++] = 2; + raw[pos++] = 2; + raw[pos++] = 0; + raw[pos++] = 1; + raw[pos++] = 12; + raw[pos++] = 2; + raw[pos++] = 0; + raw[pos++] = 0; + raw[pos++] = 0; + raw[pos++] = 0x00; + raw[pos++] = 0xCA; + raw[pos++] = 0x9A; + raw[pos++] = 0x3B; + raw[pos++] = 0x00; + raw[pos++] = 0x00; + raw[pos++] = 0x00; + raw[pos++] = 0x00; + + /* memo */ + raw[pos++] = 3; /* program = memo */ + raw[pos++] = 0; /* no accounts */ + raw[pos++] = (uint8_t)strlen(memo); + memcpy(raw + pos, memo, strlen(memo)); + pos += strlen(memo); + + SolanaParsedTx tx; + EXPECT_EQ(solana_inspectTx(raw, pos, &tx), SOL_TX_REVIEW_VERIFIED); + ASSERT_EQ(tx.num_instructions, 2); + EXPECT_EQ(tx.instructions[1].type, SOL_INSTR_MEMO); + ASSERT_EQ(tx.instructions[1].data_len, strlen(memo)); + EXPECT_EQ(memcmp(tx.instructions[1].data, memo, strlen(memo)), 0); +} + TEST(Solana, MalformedVersionedLookupTableRejects) { uint8_t raw[256]; size_t pos = 0; @@ -616,3 +876,98 @@ TEST(Solana, MalformedVersionedLookupTableRejects) { EXPECT_EQ(solana_inspectTx(raw, pos, &tx), SOL_TX_REVIEW_MALFORMED); EXPECT_FALSE(solana_parseTx(raw, pos, &tx)); } + +/* ===================================================================== + * Review-round-12 regression tests: the forced-opaque set and the + * canonical-shape guards. A future refactor that silently drops any of + * these gates fails here, not in the field. + * ===================================================================== */ + +/* Build a single-instruction tx over `program`, with `n_accounts` distinct + * accounts fed to the instruction, plus a fee-payer signer and the program + * account. instr_data holds the opcode + operands. Returns the byte length. */ +static size_t build_single_instr_tx(uint8_t* raw, const uint8_t* program, + int n_accounts, const uint8_t* instr_data, + uint8_t data_len) { + size_t pos = 0; + raw[pos++] = 1; /* num_required_sigs */ + raw[pos++] = 0; /* num_readonly_signed */ + raw[pos++] = 1; /* num_readonly_unsigned (program) */ + const int total_accts = n_accounts + 1 /* program */; + raw[pos++] = (uint8_t)total_accts; /* compact-u16 account count */ + for (int i = 0; i < n_accounts; i++) { /* instruction accounts */ + memset(raw + pos, 0x11 + i, 32); + pos += 32; + } + memcpy(raw + pos, program, 32); /* program account (last) */ + pos += 32; + memset(raw + pos, 0xBB, 32); /* recent blockhash */ + pos += 32; + raw[pos++] = 1; /* 1 instruction */ + raw[pos++] = (uint8_t)n_accounts; /* program index (last account) */ + raw[pos++] = (uint8_t)n_accounts; /* account-index count */ + for (int i = 0; i < n_accounts; i++) { /* account indices 0..n-1 */ + raw[pos++] = (uint8_t)i; + } + raw[pos++] = data_len; + memcpy(raw + pos, instr_data, data_len); + pos += data_len; + return pos; +} + +/* Legacy SPL TransferChecked with the canonical 10-byte data (opcode + amount + * + decimals) and all four accounts clear-signs. */ +TEST(Solana, TransferCheckedCanonicalIsVerified) { + uint8_t d[10] = { + SOL_TOKEN_TRANSFER_CHECKED_IX, 0x40, 0x42, 0x0F, 0, 0, 0, 0, 6}; + uint8_t raw[512]; + size_t pos = build_single_instr_tx(raw, SOL_TOKEN_PROGRAM, 4, d, sizeof(d)); + SolanaParsedTx tx; + EXPECT_EQ(solana_inspectTx(raw, pos, &tx), SOL_TX_REVIEW_VERIFIED); +} + +/* A 9-byte TransferChecked (no decimals byte) is non-canonical: it must NOT + * classify VERIFIED (which would skip the mint screen) — force opaque. */ +TEST(Solana, TransferCheckedShortDataIsOpaque) { + uint8_t d[9] = {SOL_TOKEN_TRANSFER_CHECKED_IX, 0x40, 0x42, 0x0F, 0, 0, 0, 0}; + uint8_t raw[512]; + size_t pos = build_single_instr_tx(raw, SOL_TOKEN_PROGRAM, 4, d, sizeof(d)); + SolanaParsedTx tx; + EXPECT_EQ(solana_inspectTx(raw, pos, &tx), SOL_TX_REVIEW_OPAQUE); +} + +/* A TransferChecked with fewer than 4 accounts would read a zeroed mint / + * destination (displayed as 1111..) — force opaque instead of clear-signing a + * fabricated recipient. */ +TEST(Solana, TransferCheckedShortAccountsIsOpaque) { + uint8_t d[10] = { + SOL_TOKEN_TRANSFER_CHECKED_IX, 0x40, 0x42, 0x0F, 0, 0, 0, 0, 6}; + uint8_t raw[512]; + size_t pos = build_single_instr_tx(raw, SOL_TOKEN_PROGRAM, 3, d, sizeof(d)); + SolanaParsedTx tx; + EXPECT_EQ(solana_inspectTx(raw, pos, &tx), SOL_TX_REVIEW_OPAQUE); +} + +/* StakeAuthorize needs >= 40 data bytes (type(4) + new-authority(32) + + * role(4)); a 36-byte encoding would read the role word out of bounds, so it + * must not be accepted as a canonical authorize. */ +TEST(Solana, StakeAuthorizeShortDataIsOpaque) { + uint8_t d[36] = {SOL_STAKE_AUTHORIZE_IX, 0, 0, 0}; + memset(d + 4, 0x77, 32); /* new authority, role word missing */ + uint8_t raw[512]; + size_t pos = build_single_instr_tx(raw, SOL_STAKE_PROGRAM, 3, d, sizeof(d)); + SolanaParsedTx tx; + EXPECT_EQ(solana_inspectTx(raw, pos, &tx), SOL_TX_REVIEW_OPAQUE); +} + +/* The same StakeAuthorize with the full 40-byte canonical encoding clear-signs + * (role = staker), proving the rejection above is the length guard. */ +TEST(Solana, StakeAuthorizeCanonicalIsVerified) { + uint8_t d[40] = {SOL_STAKE_AUTHORIZE_IX, 0, 0, 0}; + memset(d + 4, 0x77, 32); /* new authority */ + /* d[36..39] = role 0 (staker), already zero */ + uint8_t raw[512]; + size_t pos = build_single_instr_tx(raw, SOL_STAKE_PROGRAM, 3, d, sizeof(d)); + SolanaParsedTx tx; + EXPECT_EQ(solana_inspectTx(raw, pos, &tx), SOL_TX_REVIEW_VERIFIED); +} diff --git a/unittests/firmware/storage.cpp b/unittests/firmware/storage.cpp index b04af1ebe..1dc4fdb7e 100644 --- a/unittests/firmware/storage.cpp +++ b/unittests/firmware/storage.cpp @@ -497,6 +497,70 @@ TEST(Storage, StorageUpgrade_Normal) { EXPECT_EQ(shadow.storage.pub.policies[1].enabled, true); } +#if !BITCOIN_ONLY +// A seed created under bitcoin-only firmware is stamped in a reserved version +// band. Multi-chain firmware must REFUSE it (SUS_BitcoinOnlyLocked), not load +// it and not silently reset it here -- the seed stays intact in flash until an +// explicit wipe. This is the core anti-downgrade guarantee. +TEST(Storage, BitcoinOnlyBandRefused) { + // storage_fromFlash always reads STORAGE_SECTOR_LEN from `flash` (in the + // firmware it points to a full flash sector), so the buffer must be a full + // sector or the version-17 read below runs off the end. + static char flash[STORAGE_SECTOR_LEN]; + memset(flash, 0, sizeof(flash)); + memcpy(flash, "stor", 4); // STORAGE_MAGIC_STR + uint32_t v = STORAGE_VERSION_BTC_ONLY; + flash[44] = (char)(v & 0xff); + flash[45] = (char)((v >> 8) & 0xff); + flash[46] = (char)((v >> 16) & 0xff); + flash[47] = (char)((v >> 24) & 0xff); + + SessionState session; + memset(&session, 0, sizeof(session)); + ConfigFlash shadow; + EXPECT_EQ(storage_fromFlash(&session, &shadow, flash), SUS_BitcoinOnlyLocked); + + // A normal (below-band) version is still handled as before. + flash[44] = 17; + flash[45] = flash[46] = flash[47] = 0; + EXPECT_NE(storage_fromFlash(&session, &shadow, flash), SUS_BitcoinOnlyLocked); +} +#endif + +#if BITCOIN_ONLY +// On bitcoin-only firmware, an in-band wallet stamped at an OLDER underlying +// version (which is exactly what an existing wallet looks like after a +// STORAGE_VERSION bump) must still load and migrate — never be refused, which +// would lock the user out of their own wallet. A NEWER in-band version is +// refused (downgrade guard), never wiped. +TEST(Storage, BitcoinOnlyBandMigrates) { + static char flash[STORAGE_SECTOR_LEN]; + SessionState session; + ConfigFlash shadow; + + // Older in-band version (underlying < STORAGE_VERSION): migrate, not refuse. + memset(flash, 0, sizeof(flash)); + memcpy(flash, "stor", 4); + uint32_t older = STORAGE_VERSION_BTC_ONLY_BASE + (STORAGE_VERSION - 1); + memcpy(flash + 44, &older, + 4); // test host is little-endian, matches read_u32_le + memset(&session, 0, sizeof(session)); + EXPECT_NE(storage_fromFlash(&session, &shadow, flash), SUS_BitcoinOnlyLocked); + + // Our own current in-band version: loads (not refused). + uint32_t current = STORAGE_VERSION_BTC_ONLY; + memcpy(flash + 44, ¤t, 4); + memset(&session, 0, sizeof(session)); + EXPECT_NE(storage_fromFlash(&session, &shadow, flash), SUS_BitcoinOnlyLocked); + + // A newer in-band version than this firmware understands: refuse. + uint32_t newer = STORAGE_VERSION_BTC_ONLY_BASE + (STORAGE_VERSION + 1); + memcpy(flash + 44, &newer, 4); + memset(&session, 0, sizeof(session)); + EXPECT_EQ(storage_fromFlash(&session, &shadow, flash), SUS_BitcoinOnlyLocked); +} +#endif + TEST(Storage, StorageRoundTrip) { ConfigFlash start; memset(&start, 0xAB, sizeof(start)); @@ -556,6 +620,7 @@ TEST(Storage, StorageRoundTrip) { printf("\n"); #endif + // clang-format off const uint8_t expected_flash[] = { 0x73, 0x74, 0x6f, 0x72, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, @@ -653,7 +718,7 @@ TEST(Storage, StorageRoundTrip) { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0xe4, 0x8d, 0xfe, 0xcf, 0xd0, 0x54, 0x71, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0xe4, 0x8d, 0xfe, 0xcf, 0xd0, 0x54, 0x71, 0x50, 0xcb, 0x12, 0x84, 0xfa, 0x5f, 0xbf, 0xcb, 0x09, 0xca, 0x00, 0xf1, 0x37, 0xe4, 0x8f, 0x5e, 0xf9, 0x81, 0x57, 0x26, 0xb6, 0x7b, 0x8e, 0x03, 0x44, 0x9a, 0x2a, 0x7c, 0xf4, 0x3c, 0x79, 0x87, 0x5d, 0x26, 0xae, 0x9b, 0x4b, 0xb4, 0xd2, 0xc4, 0x67, 0x97, 0xe7, 0x6b, 0x6c, 0x4c, 0xbe, 0x68, @@ -719,6 +784,7 @@ TEST(Storage, StorageRoundTrip) { 0x7c, 0x20, 0x50, 0x7c, 0x85, 0xc1, 0x44, 0xaa, 0xfb, 0xf8, 0xeb, 0x20, 0x16, 0x8d, 0x72, 0x8c, 0xd2, 0xbe, 0xc2, 0xea, 0x44, 0xed, 0x7b, 0x94, 0x21, 0x00, }; + // clang-format on // If storage isn't correct, let's get an idea of where the failure is for (int i=0; ipresent = true; + a->key_id = 1; + for (int i = 0; i < 33; i++) a->pubkey[i] = (uint8_t)(i + 1); + strcpy(a->alias, "CI Test"); + a->icon_w = 48; + a->icon_h = 48; + a->icon_len = 120; + for (int i = 0; i < a->icon_len; i++) a->icon[i] = (uint8_t)(0xF0 ^ i); + + // Identity 1: text-only (no icon). + ClearsignIdentity *b = &start.storage.pub.clearsign_identities[1]; + memset(b, 0, sizeof(*b)); + b->present = true; + b->key_id = 2; + for (int i = 0; i < 33; i++) b->pubkey[i] = (uint8_t)(0x80 + i); + strcpy(b->alias, "Pioneer Insight"); + + std::vector flash(3480, 0); + storage_writeV18((char *)&flash[0], flash.size(), &start); + + ConfigFlash end; + memset(&end, 0x00, sizeof(end)); + storage_readV18(&end, (const char *)&flash[0], flash.size()); + + for (int k = 0; k < PERSISTENT_IDENTITY_COUNT; k++) { + const ClearsignIdentity *s = &start.storage.pub.clearsign_identities[k]; + const ClearsignIdentity *r = &end.storage.pub.clearsign_identities[k]; + ASSERT_EQ(s->present, r->present) << "present " << k; + ASSERT_EQ(s->key_id, r->key_id) << "key_id " << k; + ASSERT_EQ(0, memcmp(s->pubkey, r->pubkey, 33)) << "pubkey " << k; + ASSERT_STREQ(s->alias, r->alias) << "alias " << k; + ASSERT_EQ(s->icon_w, r->icon_w) << "icon_w " << k; + ASSERT_EQ(s->icon_h, r->icon_h) << "icon_h " << k; + ASSERT_EQ(s->icon_len, r->icon_len) << "icon_len " << k; + ASSERT_EQ(0, memcmp(s->icon, r->icon, CLEARSIGN_ICON_MAX)) << "icon " << k; + } + + // A corrupt on-flash icon_len (> CLEARSIGN_ICON_MAX) must clamp to 0 on read + // so downstream renderers never index past the icon buffer. Identity 0's + // icon_len lives at flash[44 + 2525 + 69] (present, key_id, pubkey[33], + // alias[32], icon_w, icon_h => 69). + const size_t id0_icon_len_off = 44 + 1501 + V17_ENCSEC_SIZE + 69; + flash[id0_icon_len_off] = 0xFF; + flash[id0_icon_len_off + 1] = 0xFF; + ConfigFlash corrupt; + memset(&corrupt, 0x00, sizeof(corrupt)); + storage_readV18(&corrupt, (const char *)&flash[0], flash.size()); + ASSERT_EQ(0, corrupt.storage.pub.clearsign_identities[0].icon_len); +} diff --git a/unittests/firmware/thorchain.cpp b/unittests/firmware/thorchain.cpp index 4fa8faa8f..aa2a338ec 100644 --- a/unittests/firmware/thorchain.cpp +++ b/unittests/firmware/thorchain.cpp @@ -1,12 +1,111 @@ extern "C" { +#include "keepkey/board/messages.h" +#include "keepkey/board/usb.h" #include "keepkey/firmware/coins.h" +#include "keepkey/firmware/app_confirm.h" +#include "keepkey/firmware/ethereum_contracts/thortx.h" +#include "keepkey/firmware/fsm.h" #include "keepkey/firmware/thorchain.h" #include "keepkey/firmware/tendermint.h" +#include "messages-ethereum.pb.h" #include "trezor/crypto/secp256k1.h" + +// From keepkey_board.h, which we can't include here: its shutdown(void) +// declaration clashes with sys/socket.h's shutdown(int, int). +void kk_board_init(void); } #include "gtest/gtest.h" #include +#include +#include + +#include +#include +#include + +/* + * confirm() auto-accept driver for unit tests. + * + * In the emulator/unittest build (always DEBUG_LINK), confirm_helper() + * busy-polls the emulator's UDP "usb" port for tiny messages and returns + * once it has seen a ButtonAck plus a DebugLinkDecision. Each confirm + * screen therefore consumes exactly one ButtonAck + one DebugLinkDecision + * from the socket queue. Preloading exactly N accept pairs before invoking + * the code under test auto-accepts exactly N screens, and + * kkconfirm_drain() == 0 afterwards proves exactly N screens were shown + * (fewer screens leave packets queued; more screens would hang the test). + * + * These helpers have external linkage so mayachain.cpp can share the + * one-time board/usb initialization. + */ + +static bool kkconfirm_sendTiny(uint16_t msgId, const uint8_t* payload, + uint8_t len) { + static int fd = -1; + if (fd < 0) fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (fd < 0) return false; + + uint8_t frame[64] = {0}; + frame[0] = '?'; + frame[1] = '#'; + frame[2] = '#'; + frame[3] = msgId >> 8; + frame[4] = msgId & 0xff; + frame[8] = len; // bytes 5..7 are the high bits of the big-endian size + if (len) memcpy(&frame[9], payload, len); + + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(11044); // emulator main "usb" port + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + return sendto(fd, frame, sizeof(frame), 0, (struct sockaddr*)&addr, + sizeof(addr)) == (ssize_t)sizeof(frame); +} + +// Queue nYes accepted screens followed by nNo rejected screens. +bool kkconfirm_preload(int nYes, int nNo) { + static bool initialized = false; + if (!initialized) { + kk_board_init(); // canvas + runnable queues for confirm's draw path + fsm_init(); // registers the usb rx callback + message maps + usbInit(""); // binds the emulator UDP ports + initialized = true; + } + + static const uint8_t yes[] = {0x08, 0x01}; // DebugLinkDecision.yes_no + static const uint8_t no[] = {0x08, 0x00}; + for (int i = 0; i < nYes + nNo; i++) { + if (!kkconfirm_sendTiny(MessageType_MessageType_ButtonAck, NULL, 0)) + return false; + const uint8_t* decision = (i < nYes) ? yes : no; + if (!kkconfirm_sendTiny(MessageType_MessageType_DebugLinkDecision, decision, + 2)) + return false; + } + return true; +} + +// Consume and count any tiny messages left in the queue. +int kkconfirm_drain(void) { + uint8_t buf[MSG_TINY_BFR_SZ]; + int n = 0; + for (;;) { + // volatile: 0xFFFF (MSG_TINY_TYPE_ERROR) is outside the MessageType + // enum range, so an unguarded comparison is a tautology the compiler + // may fold away. + volatile uint16_t id = (uint16_t)check_for_tiny_msg(buf); + if (id == MSG_TINY_TYPE_ERROR) break; + n++; + } + return n; +} + +// Vectors computed with the trezor-crypto library directly (see +// unittests/firmware/thorchain.cpp notes). The test file was previously +// absent from CMakeLists.txt so none of these values were ever validated; +// all expected values here are derived from the actual crypto library. TEST(Thorchain, ThorchainGetAddress) { HDNode node = { @@ -24,51 +123,520 @@ TEST(Thorchain, ThorchainGetAddress) { &secp256k1_info}; char addr[46]; ASSERT_TRUE(tendermint_getAddress(&node, "thor", addr)); - EXPECT_EQ(std::string("thor1am058pdux3hyulcmfgj4m3hhrlfn8nzm88u80q"), addr); + EXPECT_EQ(std::string("thor1am058pdux3hyulcmfgj4m3hhrlfn8nzmpq9u6l"), addr); } -TEST(Thorchain, ThorchainSignTx) { - HDNode node = { - 0, - 0, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0x04, 0xde, 0xc0, 0xcc, 0x01, 0x3c, 0xd8, 0xab, 0x70, 0x87, 0xca, - 0x14, 0x96, 0x0b, 0x76, 0x8c, 0x3d, 0x83, 0x45, 0x24, 0x48, 0xaa, - 0x00, 0x64, 0xda, 0xe6, 0xfb, 0x04, 0xb5, 0xd9, 0x34, 0x76}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - &secp256k1_info}; +// Shared fixtures +static const HDNode kSignNode = { + 0, + 0, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0x04, 0xde, 0xc0, 0xcc, 0x01, 0x3c, 0xd8, 0xab, 0x70, 0x87, 0xca, + 0x14, 0x96, 0x0b, 0x76, 0x8c, 0x3d, 0x83, 0x45, 0x24, 0x48, 0xaa, + 0x00, 0x64, 0xda, 0xe6, 0xfb, 0x04, 0xb5, 0xd9, 0x34, 0x76}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + &secp256k1_info}; + +static const ThorchainSignTx kSignTx = { + 5, {0x80000000 | 44, 0x80000000 | 931, 0x80000000, 0, 0}, + true, 0, + true, "thorchain", + true, 5000, + true, 200000, + true, "", + true, 0, + true, 1}; + +static const char* kToAddr = "thor18vhdczjut44gpsy804crfhnd5nq003nz0nf20v"; + +// Denom validation: only [a-z0-9./\-] is allowed; anything else is rejected +TEST(Thorchain, ThorchainDenomValidation) { + EXPECT_TRUE(thorchain_isValidDenom("rune")); + EXPECT_TRUE(thorchain_isValidDenom("tcy")); + EXPECT_TRUE(thorchain_isValidDenom("rujira")); + EXPECT_TRUE(thorchain_isValidDenom("eth.eth")); + EXPECT_TRUE(thorchain_isValidDenom("btc/btc")); + EXPECT_TRUE(thorchain_isValidDenom("cross-chain")); + + EXPECT_FALSE(thorchain_isValidDenom("")); // empty → caller uses "rune" + EXPECT_FALSE(thorchain_isValidDenom("RUNE")); // uppercase rejected + EXPECT_FALSE(thorchain_isValidDenom("rune\"")); // quote injection + EXPECT_FALSE(thorchain_isValidDenom("rune\\n")); // backslash injection + EXPECT_FALSE(thorchain_isValidDenom(" rune")); // leading space + EXPECT_FALSE(thorchain_isValidDenom("ru ne")); // embedded space +} + +// Invalid denom must cause thorchain_signTxUpdateMsgSend to return false +TEST(Thorchain, ThorchainSignTxInvalidDenom) { + HDNode node = kSignNode; hdnode_fill_public_key(&node); - const ThorchainSignTx msg = { - 5, {0x80000000 | 44, 0x80000000 | 931, 0x80000000, 0, 0}, // address_n - true, 0, // account_number - true, "thorchain", // chain_id - true, 5000, // fee_amount - true, 200000, // gas - true, "", // memo - true, 0, // sequence - true, 1 // msg_count - }; - ASSERT_TRUE(thorchain_signTxInit(&node, &msg)); + ASSERT_TRUE(thorchain_signTxInit(&node, &kSignTx)); + // Quote-injection attempt must be rejected at the signing layer + EXPECT_FALSE(thorchain_signTxUpdateMsgSend(100000, kToAddr, + "rune\",\"from_address\":\"evil")); + thorchain_signAbort(); +} + +/* ===================================================================== * + * thorchain_parseConfirmMemo — swap-memo clear-signing. + * Screen counts are asserted exactly: kkconfirm_preload(N, 0) accepts N + * screens and kkconfirm_drain() == 0 proves N screens were shown. + * ===================================================================== */ + +static bool parseMemo(const char* memo, size_t size) { + return thorchain_parseConfirmMemo(memo, size); +} +static bool parseMemo(const char* memo) { + return parseMemo(memo, strlen(memo) + 1); +} + +// Classic full-form swap memo: asset + dest + limit + affiliate + fee bps +// = 4 screens (the 4th is the new affiliate fee screen) +TEST(Thorchain, MemoSwapFullFormShowsAffiliate) { + ASSERT_TRUE(kkconfirm_preload(4, 0)); + EXPECT_TRUE( + parseMemo("SWAP:ETH.USDT-0xdac17f958d2ee523a2206206994597c13d831ec7:" + "0x41e5560054824ea6b0732e656e3ad64e20e94e45:420:kk:75")); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// Abbreviated asset with no '.' (no chain.asset pair) is not parseable +// thorchain data: raw-memo fallback +TEST(Thorchain, MemoSwapNoChainAssetPair) { + ASSERT_TRUE(kkconfirm_preload(0, 0)); + EXPECT_FALSE(parseMemo("=:e:0xdest:0/1/0:kk:75")); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// Empty limit field must NOT shift the affiliate into the limit slot: it +// must still take 4 screens (limit "none" + separate affiliate screen). +// The old strtok tokenizer collapsed the empty field and displayed the +// affiliate ("kk") as the limit in 3 screens. +TEST(Thorchain, MemoSwapEmptyLimitDoesNotShift) { + ASSERT_TRUE(kkconfirm_preload(4, 0)); + EXPECT_TRUE(parseMemo("=:ETH.ETH:0xdest::kk:75")); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// No affiliate: exactly the 3 historical screens, no affiliate screen +TEST(Thorchain, MemoSwapNoAffiliate) { + ASSERT_TRUE(kkconfirm_preload(3, 0)); + EXPECT_TRUE(parseMemo("SWAP:ETH.ETH:0xdest:420")); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// Affiliate present but fee absent: affiliate screen still shows (fee "0") +TEST(Thorchain, MemoSwapAffiliateNoFee) { + ASSERT_TRUE(kkconfirm_preload(4, 0)); + EXPECT_TRUE(parseMemo("SWAP:ETH.ETH:0xdest:420:kk")); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// Missing dest and limit: still 3 screens ("self" / "none") +TEST(Thorchain, MemoSwapMinimal) { + ASSERT_TRUE(kkconfirm_preload(3, 0)); + EXPECT_TRUE(parseMemo("SWAP:ETH.ETH")); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// Rejecting a screen aborts the whole confirmation +TEST(Thorchain, MemoSwapRejectPropagates) { + ASSERT_TRUE(kkconfirm_preload(2, 1)); + EXPECT_FALSE(parseMemo("SWAP:ETH.ETH:0xdest:420")); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// ADD with a pool address: 2 screens (unchanged behavior) +TEST(Thorchain, MemoAddWithPool) { + ASSERT_TRUE(kkconfirm_preload(2, 0)); + EXPECT_TRUE( + parseMemo("ADD:BTC.BTC:thor18vhdczjut44gpsy804crfhnd5nq003nz0nf20v")); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// ADD without a pool address: 1 screen (unchanged behavior) +TEST(Thorchain, MemoAddWithoutPool) { + ASSERT_TRUE(kkconfirm_preload(1, 0)); + EXPECT_TRUE(parseMemo("+:BTC.BTC")); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// WITHDRAW with basis points: 1 screen (unchanged behavior) +TEST(Thorchain, MemoWithdraw) { + ASSERT_TRUE(kkconfirm_preload(1, 0)); + EXPECT_TRUE(parseMemo("WITHDRAW:BTC.BTC:5000")); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// WITHDRAW without basis points is malformed (unchanged behavior) +TEST(Thorchain, MemoWithdrawMissingBps) { + ASSERT_TRUE(kkconfirm_preload(0, 0)); + EXPECT_FALSE(parseMemo("wd:BTC.BTC")); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// Garbage memos fall back to raw-memo confirmation +TEST(Thorchain, MemoGarbage) { + ASSERT_TRUE(kkconfirm_preload(0, 0)); + EXPECT_FALSE(parseMemo("hello world")); + EXPECT_FALSE(parseMemo("NOTATHING:ETH.ETH:0xdest")); + EXPECT_FALSE(parseMemo("")); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// BTC OP_RETURN passes RAW memo bytes with no NUL and size = byte count +// (transaction.c). Every byte must survive the copy: dropping the last +// character turns affiliate "kk" into "k" — or a fee of 75 bps into 7. +// This memo's affiliate is 1 char, so the historical off-by-one would +// lose it entirely and show only 3 screens instead of 4. +TEST(Thorchain, MemoRawBytesNoNulKeepsLastChar) { + ASSERT_TRUE(kkconfirm_preload(4, 0)); + const char raw[] = "=:ETH.ETH:0xdest:420:k"; + EXPECT_TRUE(parseMemo(raw, sizeof(raw) - 1)); /* no NUL counted */ + EXPECT_EQ(0, kkconfirm_drain()); +} - ASSERT_TRUE(thorchain_signTxUpdateMsgSend( - 100000, "thor18vhdczjut44gpsy804crfhnd5nq003nz0nf20v")); +// A raw memo that fills the internal buffer's entire documented capacity +// (size == 256, the parser's own <=256 contract) must ALSO keep its last +// byte — this is the boundary the copy-length clamp missed. +TEST(Thorchain, MemoExactBufferCapacityKeepsLastChar) { + const std::string prefix = "=:ETH.ETH:0x"; + const std::string suffix = ":420:k"; // 1-char affiliate as the last byte + std::string memo = + prefix + std::string(256 - prefix.size() - suffix.size(), 'd') + suffix; + ASSERT_EQ(memo.size(), 256u); - uint8_t public_key[33]; - uint8_t signature[64]; + ASSERT_TRUE(kkconfirm_preload(4, 0)); + EXPECT_TRUE(parseMemo(memo.c_str(), memo.size())); /* no NUL counted */ + EXPECT_EQ(0, kkconfirm_drain()); +} + +// Oversized input (> 256) is rejected outright +TEST(Thorchain, MemoOversized) { + ASSERT_TRUE(kkconfirm_preload(0, 0)); + EXPECT_FALSE(parseMemo("SWAP:ETH.ETH:0xdest:420", 257)); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// Symmetric withdraw: pool + basis points on a single screen. +TEST(Thorchain, MemoWithdrawSymmetric) { + ASSERT_TRUE(kkconfirm_preload(1, 0)); + EXPECT_TRUE(parseMemo("WITHDRAW:BTC.BTC:10000")); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// Asymmetric withdraw: the 4th field selects a SINGLE-SIDED payout asset — +// it directs money, so it gets its own screen instead of signing unseen with +// screens identical to the symmetric form. +TEST(Thorchain, MemoWithdrawAsymmetricShowsPayoutAsset) { + ASSERT_TRUE(kkconfirm_preload(2, 0)); + EXPECT_TRUE(parseMemo("-:BTC.BTC:10000:THOR.RUNE")); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// Rejecting the payout-asset screen aborts the withdrawal. +TEST(Thorchain, MemoWithdrawAsymmetricRejectPropagates) { + ASSERT_TRUE(kkconfirm_preload(1, 1)); // approve summary, reject asset + EXPECT_FALSE(parseMemo("wd:BTC.BTC:5000:BTC.BTC")); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// More fields than any withdraw grammar defines cannot be labeled and must +// not be hidden — mirrors the SWAP (>9) and ADD (>5) caps. +TEST(Thorchain, MemoWithdrawTooManyFieldsRejected) { + ASSERT_TRUE(kkconfirm_preload(0, 0)); + EXPECT_FALSE(parseMemo("WITHDRAW:BTC.BTC:10000:THOR.RUNE:extra")); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// DEX-aggregator swap: aggregator addr, final token and min-out are all +// router-executed and must be shown — asset/chain + dest + limit + affiliate + +// aggregator + final + min = 7 screens (none hidden). +TEST(Thorchain, MemoSwapAggregatorShowsAllFields) { + ASSERT_TRUE(kkconfirm_preload(7, 0)); + EXPECT_TRUE(parseMemo( + "SWAP:ETH.ETH:0xdest:420:kk:75:0xaggregator:0xfinaltoken:1000")); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// A '|' outbound-memo suffix (MinAmountOut|OUTBOUND_MEMO) is forwarded to the +// outbound contract and can contain ':' our split would scatter. It must be +// disclosed in full: swap header + the fully-paged raw memo = 2 screens here +// (memo < one page). Nothing falls back to blind-signing. +TEST(Thorchain, MemoSwapPipeOutboundIsFullyPaged) { + ASSERT_TRUE(kkconfirm_preload(2, 0)); + const char memo[] = "=:ETH.ETH:0xdest|OUT:0xfinal:1"; // ':' after the pipe + EXPECT_TRUE(parseMemo(memo, strlen(memo))); // no NUL in the paged bytes + EXPECT_EQ(0, kkconfirm_drain()); +} - ASSERT_TRUE(thorchain_signTxFinalize(public_key, signature)); +// More fields than any swap grammar defines (>9) is structure we cannot label; +// refuse it rather than sign an undisplayed tail. Rejected before any screen. +TEST(Thorchain, MemoSwapTooManyFieldsRejected) { + ASSERT_TRUE(kkconfirm_preload(0, 0)); + EXPECT_FALSE(parseMemo("SWAP:ETH.ETH:a:b:c:d:e:f:g:h")); + EXPECT_EQ(0, kkconfirm_drain()); +} +// ADD:POOL:PAIREDADDR:AFFILIATE:FEE — affiliate + fee must not be hidden: +// add asset + pool + affiliate-fee = 3 screens. +TEST(Thorchain, MemoAddShowsAffiliateAndFee) { + ASSERT_TRUE(kkconfirm_preload(3, 0)); EXPECT_TRUE( - memcmp(signature, - (uint8_t *)"\x41\x99\x66\x30\x08\xef\xea\x75\x93\x56\x35\xe6\x1a" - "\x11\xdf\xa3\x3c\xeb\xeb\x91\xc1\xca\xed\xc6\x0e\x5e" - "\xef\x3c\xa2\xc0\x1f\x83\x48\x08\x36\xe6\x21\x89\x51" - "\x14\x36\x64\x7f\xac\x5a\xbd\xc2\x9f\x54\xae\x3d\x7e" - "\x47\x56\x43\xca\x33\xc7\xad\x2c\x8a\x53\x2b\x39", - 64) == 0); + parseMemo("ADD:BTC.BTC:thor18vhdczjut44gpsy804crfhnd5nq003nz0nf20v" + ":affil:50")); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// ADD with more than its 5 defined fields is refused (no hidden tail). +TEST(Thorchain, MemoAddTooManyFieldsRejected) { + ASSERT_TRUE(kkconfirm_preload(0, 0)); + EXPECT_FALSE(parseMemo("ADD:BTC.BTC:pool:affil:50:extra")); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// The full-memo pager is the authoritative disclosure the native THOR/MAYA +// handlers page after their structured summary. A short ASCII memo is one page. +TEST(Thorchain, FullMemoShortAsciiIsOnePage) { + const char memo[] = "=:ETH.ETH:0xdest:420:kk:75"; + ASSERT_TRUE(kkconfirm_preload(1, 0)); + EXPECT_TRUE(thorchain_confirm_full_memo("Memo", memo, strlen(memo))); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// Page breaks use measured rendered rows, including word-wrap behavior. +TEST(Thorchain, FullMemoLongAsciiPagesAll) { + const char memo[] = + "%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%"; + ASSERT_TRUE(kkconfirm_preload(2, 0)); + EXPECT_TRUE(thorchain_confirm_full_memo("Memo", memo, strlen(memo))); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// Rejecting any page aborts the whole disclosure (so the handler aborts +// signing). +TEST(Thorchain, FullMemoRejectPropagates) { + const char memo[] = + "%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%"; + ASSERT_TRUE(kkconfirm_preload(1, 1)); // approve page 1, reject page 2 + EXPECT_FALSE(thorchain_confirm_full_memo("Memo", memo, strlen(memo))); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// Non-printable memo bytes are disclosed in complete renderer-measured hex +// pages, never hidden behind a byte-count summary. +TEST(Thorchain, FullMemoBinaryPagesAsHex) { + char memo[100]; + memset(memo, 0x01, sizeof(memo)); + ASSERT_TRUE(kkconfirm_preload(2, 0)); + EXPECT_TRUE(thorchain_confirm_full_memo("Memo", memo, sizeof(memo))); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// An empty memo must show a single "(empty)" screen — not fall through to the +// hex branch, which would pass an uninitialized buffer to %s. +TEST(Thorchain, FullMemoEmptyShowsEmpty) { + ASSERT_TRUE(kkconfirm_preload(1, 0)); + EXPECT_TRUE(thorchain_confirm_full_memo("Memo", "", 0)); + EXPECT_EQ(0, kkconfirm_drain()); +} + +// Renderer-aware paging must split the exact 69-byte word-wrap exploit from +// the second-pass audit. A byte-count pager treated this as one screen even +// though the OLED renderer placed the final signed word on a fourth row. +TEST(Confirmation, ExactLengthPagerMeasuresRenderedRows) { + const char payload[] = + "%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%"; + ASSERT_TRUE(kkconfirm_preload(2, 0)); + EXPECT_TRUE(confirm_bytes(ButtonRequestType_ButtonRequest_SignMessage, + "Signed Message", (const uint8_t*)payload, + strlen(payload))); + EXPECT_EQ(0, kkconfirm_drain()); +} + +TEST(Confirmation, ExactLengthPagerRejectPropagates) { + const char payload[] = + "%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%"; + ASSERT_TRUE(kkconfirm_preload(1, 1)); + EXPECT_FALSE(confirm_bytes(ButtonRequestType_ButtonRequest_SignMessage, + "Signed Message", (const uint8_t*)payload, + strlen(payload))); + EXPECT_EQ(0, kkconfirm_drain()); +} + +/* ===================================================================== + * thor_isThorchainTx — chain-scoped router pin. + * + * A THORChain deposit uses a DIFFERENT router address on every EVM chain, + * so the pin must match on (chain_id, address) together. Before this was + * chain-scoped, only Ethereum-mainnet deposits ever matched and an + * Avalanche deposit fell into the blind-sign gate (the AVAX->ETH bug). + * ===================================================================== */ + +// Lowercase-hex 40-char router -> 20 raw bytes. +static void hex20(const char* hex, uint8_t out[20]) { + for (int i = 0; i < 20; i++) { + auto nib = [](char c) -> int { + return c <= '9' ? c - '0' : (c | 0x20) - 'a' + 10; + }; + out[i] = (uint8_t)((nib(hex[i * 2]) << 4) | nib(hex[i * 2 + 1])); + } +} + +static void make_deposit_msg(EthereumSignTx* msg, const uint8_t to[20], + const uint8_t* data, size_t data_len, + uint32_t chain_id, bool has_chain) { + memset(msg, 0, sizeof(*msg)); + msg->has_to = true; + msg->to.size = 20; + memcpy(msg->to.bytes, to, 20); + msg->has_data_initial_chunk = true; + msg->data_initial_chunk.size = (pb_size_t)data_len; + memcpy(msg->data_initial_chunk.bytes, data, data_len); + msg->has_chain_id = has_chain; + msg->chain_id = chain_id; +} + +static const char* THOR_ETH_ROUTER = "d37bbe5744d730a1d98d8dc97c42f0ca46ad7146"; +static const char* THOR_AVAX_ROUTER = + "00dc6100103bc402d490aee3f9a5560cbd91f1d4"; +static const uint8_t DEPOSIT_WITH_EXPIRY[4] = {0x44, 0xbc, 0x93, 0x7b}; + +TEST(Thorchain, IsThorchainTxEthRouterOnEthereum) { + uint8_t to[20]; + hex20(THOR_ETH_ROUTER, to); + EthereumSignTx msg; + make_deposit_msg(&msg, to, DEPOSIT_WITH_EXPIRY, 4, 1, true); + EXPECT_TRUE(thor_isThorchainTx(&msg)); +} + +TEST(Thorchain, IsThorchainTxAvaxRouterOnAvalanche) { + uint8_t to[20]; + hex20(THOR_AVAX_ROUTER, to); + EthereumSignTx msg; + make_deposit_msg(&msg, to, DEPOSIT_WITH_EXPIRY, 4, 43114, true); + EXPECT_TRUE(thor_isThorchainTx(&msg)); // the AVAX->ETH bug fix +} + +// The AVAX router on the Ethereum chain (or vice versa) must NOT match — the +// pin is (chain, address) together, so a router borrowed onto the wrong chain +// can't inherit the trusted deposit UX. +TEST(Thorchain, IsThorchainTxRejectsRouterOnWrongChain) { + uint8_t avax[20], eth[20]; + hex20(THOR_AVAX_ROUTER, avax); + hex20(THOR_ETH_ROUTER, eth); + EthereumSignTx msg; + make_deposit_msg(&msg, avax, DEPOSIT_WITH_EXPIRY, 4, 1, true); + EXPECT_FALSE(thor_isThorchainTx(&msg)); // AVAX router, ETH chain + make_deposit_msg(&msg, eth, DEPOSIT_WITH_EXPIRY, 4, 43114, true); + EXPECT_FALSE(thor_isThorchainTx(&msg)); // ETH router, AVAX chain +} + +// A chain with no pinned THORChain router never clear-signs (falls to blind +// sign), even with a real deposit selector to some address. +TEST(Thorchain, IsThorchainTxRejectsUnpinnedChain) { + uint8_t to[20]; + hex20(THOR_ETH_ROUTER, to); + EthereumSignTx msg; + make_deposit_msg(&msg, to, DEPOSIT_WITH_EXPIRY, 4, 137 /*polygon*/, true); + EXPECT_FALSE(thor_isThorchainTx(&msg)); +} + +// A tx with NO chain_id at all gets no router: ethereum.c defaults an absent +// chain_id to mainnet for hashing, but an identity pin must never be +// inherited from a default the host merely omitted. +TEST(Thorchain, IsThorchainTxRejectsMissingChainId) { + uint8_t to[20]; + hex20(THOR_ETH_ROUTER, to); + EthereumSignTx msg; + make_deposit_msg(&msg, to, DEPOSIT_WITH_EXPIRY, 4, 0, false); + EXPECT_FALSE(thor_isThorchainTx(&msg)); +} + +// A random contract carrying the deposit selector must not match — this is the +// drain-vector guard the pin exists for. +TEST(Thorchain, IsThorchainTxRejectsUnpinnedAddress) { + uint8_t to[20]; + hex20("00000000000000000000000000000000deadbeef", to); + EthereumSignTx msg; + make_deposit_msg(&msg, to, DEPOSIT_WITH_EXPIRY, 4, 43114, true); + EXPECT_FALSE(thor_isThorchainTx(&msg)); +} + +/* ===================================================================== + * thor_confirmThorTx on the Avalanche router — the full confirm path + * (router label, vault, native amount, structured memo, raw memo pages) + * runs for a non-mainnet deposit, and the exact-end memo bounds hold. + * ===================================================================== */ + +// Assemble a canonical depositWithExpiry(address,address,uint256,string, +// uint256) calldata. declared_len overrides the ABI memo-length word so the +// adversarial case (length says more than is present) can be exercised. +static std::vector build_thor_deposit(const uint8_t vault[20], + const std::string& memo, + uint32_t declared_len) { + std::vector d(DEPOSIT_WITH_EXPIRY, DEPOSIT_WITH_EXPIRY + 4); + auto push_word = [&](const uint8_t* w) { d.insert(d.end(), w, w + 32); }; + auto push_u = [&](uint64_t v) { + uint8_t w[32] = {0}; + for (int i = 0; i < 8; i++) w[31 - i] = (uint8_t)((v >> (8 * i)) & 0xff); + push_word(w); + }; + uint8_t vw[32] = {0}; + memcpy(vw + 12, vault, 20); + push_word(vw); // word0: vault + push_u(0); // word1: asset = native (address zero) + push_u(1000000000ULL); // word2: amount (router-ignored hint for native) + push_u(0xa0); // word3: memo offset (canonical for expiry variant) + push_u(1893456000ULL); // word4: expiry + push_u(declared_len); // word5: memo length + d.insert(d.end(), memo.begin(), memo.end()); + while (d.size() % 32 != 4) d.push_back(0); // pad memo to a 32-byte boundary + return d; +} + +// A 67-byte memo (longer than the once-hardcoded 64) must display in full +// through the memo screens, not silently truncate its trailing fields — on the +// AVALANCHE router, proving the whole confirm path is chain-scoped. +TEST(Thorchain, ConfirmThorTxAvaxLongMemoDecodesFully) { + uint8_t vault[20]; + hex20("15a18266c5331ac3a7f6bc5cdf25bcc55561b4fa", vault); + const std::string memo = + "=:ETH.ETH:0x141D9959cAe3853b035000490C03991eB70Fc4aC:323935:keep:30"; + ASSERT_EQ(memo.size(), 67u); + auto data = build_thor_deposit(vault, memo, (uint32_t)memo.size()); + + uint8_t avax[20]; + hex20(THOR_AVAX_ROUTER, avax); + EthereumSignTx msg; + make_deposit_msg(&msg, avax, data.data(), data.size(), 43114, true); + + ASSERT_TRUE(kkconfirm_preload(12, 0)); // generous; extras drain below + EXPECT_TRUE(thor_confirmThorTx((uint32_t)data.size(), &msg)); + kkconfirm_drain(); +} + +// A memo-length word claiming more bytes than are present must be REJECTED — +// otherwise the router would execute a longer memo than the device displayed +// (display-vs-execute divergence). Fail closed -> blind-sign path. +TEST(Thorchain, ConfirmThorTxRejectsOverlongDeclaredMemo) { + uint8_t vault[20]; + hex20("15a18266c5331ac3a7f6bc5cdf25bcc55561b4fa", vault); + const std::string memo = "=:ETH.ETH:0xdest:0:keep:30"; + // Declare 200 bytes while only ~26 (padded to 32) are present. + auto data = build_thor_deposit(vault, memo, 200); + + uint8_t avax[20]; + hex20(THOR_AVAX_ROUTER, avax); + EthereumSignTx msg; + make_deposit_msg(&msg, avax, data.data(), data.size(), 43114, true); + + ASSERT_TRUE(kkconfirm_preload(12, 0)); + EXPECT_FALSE(thor_confirmThorTx((uint32_t)data.size(), &msg)); + kkconfirm_drain(); } diff --git a/unittests/firmware/tron.cpp b/unittests/firmware/tron.cpp new file mode 100644 index 000000000..cfc77e6e6 --- /dev/null +++ b/unittests/firmware/tron.cpp @@ -0,0 +1,495 @@ +extern "C" { +#include "keepkey/firmware/tron.h" +} + +#include "gtest/gtest.h" +#include +#include + +/* ------------------------------------------------------------------ */ +/* Minimal protobuf wire-format writer for building raw_data vectors */ +/* ------------------------------------------------------------------ */ + +namespace { + +void putVarint(std::vector& out, uint64_t v) { + while (v >= 0x80) { + out.push_back(static_cast(v) | 0x80); + v >>= 7; + } + out.push_back(static_cast(v)); +} + +void putKey(std::vector& out, uint32_t field, uint8_t wire) { + putVarint(out, (static_cast(field) << 3) | wire); +} + +void putVarintField(std::vector& out, uint32_t field, uint64_t v) { + putKey(out, field, 0); + putVarint(out, v); +} + +void putBytesField(std::vector& out, uint32_t field, + const std::vector& bytes) { + putKey(out, field, 2); + putVarint(out, bytes.size()); + out.insert(out.end(), bytes.begin(), bytes.end()); +} + +void putStringField(std::vector& out, uint32_t field, + const char* str) { + putBytesField(out, field, + std::vector(str, str + strlen(str))); +} + +/* A 10-byte varint whose final byte's payload has bits above bit 0 set. + * Bytes 1-9 are all-zero-payload continuations, so the "value" this would + * decode to (if truncation were allowed) is 2 << 63, silently dropped by + * a naive shift. A correct reader must reject this outright rather than + * accept some truncated value. */ +void putOverlongVarintValue(std::vector& out) { + for (int i = 0; i < 9; i++) out.push_back(0x80); + out.push_back(0x02); +} + +void putOverlongVarintField(std::vector& out, uint32_t field) { + putKey(out, field, 0); + putOverlongVarintValue(out); +} + +std::vector tronAddr(uint8_t fill) { + std::vector a(21, fill); + a[0] = 0x41; + return a; +} + +/* protocol.TransferContract { owner=1, to=2, amount=3 } */ +std::vector transferContractValue(const std::vector& owner, + const std::vector& to, + uint64_t amount) { + std::vector v; + putBytesField(v, 1, owner); + putBytesField(v, 2, to); + putVarintField(v, 3, amount); + return v; +} + +/* TRC-20 transfer(address,uint256) calldata */ +std::vector trc20Calldata(const std::vector& to21, + uint64_t amount, bool tronStylePrefix) { + std::vector d = {0xa9, 0x05, 0x9c, 0xbb}; + /* address word */ + for (int i = 0; i < 11; i++) d.push_back(0); + d.push_back(tronStylePrefix ? 0x41 : 0x00); + d.insert(d.end(), to21.begin() + 1, to21.end()); /* low 20 bytes */ + /* amount word: big-endian uint256 */ + for (int i = 0; i < 24; i++) d.push_back(0); + for (int i = 7; i >= 0; i--) + d.push_back(static_cast(amount >> (8 * i))); + return d; +} + +/* protocol.TriggerSmartContract { owner=1, contract=2, call_value=3, data=4 } */ +std::vector triggerContractValue(const std::vector& owner, + const std::vector& contract, + const std::vector& data) { + std::vector v; + putBytesField(v, 1, owner); + putBytesField(v, 2, contract); + putBytesField(v, 4, data); + return v; +} + +/* Transaction.Contract { type=1, parameter=2 (Any{type_url=1, value=2}) } */ +std::vector contractMsg(uint64_t type, const char* type_url, + const std::vector& value) { + std::vector any; + putStringField(any, 1, type_url); + putBytesField(any, 2, value); + + std::vector c; + putVarintField(c, 1, type); + putBytesField(c, 2, any); + return c; +} + +/* Transaction.raw with typical TronGrid framing */ +std::vector rawTx(const std::vector& contract, + const char* memo, uint64_t fee_limit) { + std::vector raw; + putBytesField(raw, 1, {0xab, 0xcd}); /* ref_block_bytes */ + putBytesField(raw, 4, std::vector(8, 0x5a)); /* ref_block_hash */ + putVarintField(raw, 8, 1750000000000ULL); /* expiration */ + if (memo) putStringField(raw, 10, memo); + putBytesField(raw, 11, contract); + putVarintField(raw, 14, 1749999000000ULL); /* timestamp */ + if (fee_limit) putVarintField(raw, 18, fee_limit); + return raw; +} + +const char* TRANSFER_URL = "type.googleapis.com/protocol.TransferContract"; +const char* TRIGGER_URL = "type.googleapis.com/protocol.TriggerSmartContract"; + +} // namespace + +TEST(Tron, ParseNativeTransfer) { + auto owner = tronAddr(0x11); + auto to = tronAddr(0x22); + auto raw = rawTx(contractMsg(1, TRANSFER_URL, + transferContractValue(owner, to, 1000000)), + nullptr, 0); + + TronParsedTx parsed; + EXPECT_EQ(tron_parseRawTx(raw.data(), raw.size(), &parsed), + TRON_TX_TRANSFER); + EXPECT_EQ(memcmp(parsed.owner, owner.data(), 21), 0); + EXPECT_EQ(memcmp(parsed.to, to.data(), 21), 0); + EXPECT_EQ(parsed.amount, 1000000u); + EXPECT_FALSE(parsed.has_fee_limit); + EXPECT_EQ(parsed.memo_len, 0); +} + +TEST(Tron, ParseNativeTransferWithSwapMemo) { + const char* memo = "=:ETH.ETH:0x41e5560054824ea6b0732e656e3ad64e20e94e45:0/1/0:kk:75"; + auto raw = rawTx(contractMsg(1, TRANSFER_URL, + transferContractValue(tronAddr(0x11), + tronAddr(0x22), 5000000)), + memo, 0); + + TronParsedTx parsed; + EXPECT_EQ(tron_parseRawTx(raw.data(), raw.size(), &parsed), + TRON_TX_TRANSFER); + ASSERT_EQ(parsed.memo_len, strlen(memo)); + EXPECT_EQ(memcmp(parsed.memo, memo, parsed.memo_len), 0); +} + +TEST(Tron, ParseTrc20Transfer) { + auto owner = tronAddr(0x11); + auto to = tronAddr(0x22); + auto token = tronAddr(0x33); + for (bool tronStyle : {false, true}) { + auto raw = rawTx( + contractMsg(31, TRIGGER_URL, + triggerContractValue( + owner, token, trc20Calldata(to, 123456789, tronStyle))), + nullptr, 100000000 /* 100 TRX fee_limit */); + + TronParsedTx parsed; + EXPECT_EQ(tron_parseRawTx(raw.data(), raw.size(), &parsed), + TRON_TX_TRC20_TRANSFER); + EXPECT_EQ(memcmp(parsed.owner, owner.data(), 21), 0); + EXPECT_EQ(memcmp(parsed.to, to.data(), 21), 0); + EXPECT_EQ(memcmp(parsed.contract, token.data(), 21), 0); + EXPECT_TRUE(parsed.has_fee_limit); + EXPECT_EQ(parsed.fee_limit, 100000000u); + + char amount[90]; + ASSERT_TRUE(tron_formatTrc20Amount(parsed.trc20_amount, amount, + sizeof(amount))); + EXPECT_STREQ(amount, "123456789"); + } +} + +TEST(Tron, ParseTrc20TransferWithMemo) { + /* Vault splices THORChain swap memos into raw_data.data for TRC-20 swaps */ + const char* memo = "=:e:0x1234:0:kk:75"; + auto raw = rawTx(contractMsg(31, TRIGGER_URL, + triggerContractValue( + tronAddr(0x11), tronAddr(0x33), + trc20Calldata(tronAddr(0x22), 42, false))), + memo, 30000000); + + TronParsedTx parsed; + EXPECT_EQ(tron_parseRawTx(raw.data(), raw.size(), &parsed), + TRON_TX_TRC20_TRANSFER); + ASSERT_EQ(parsed.memo_len, strlen(memo)); + EXPECT_EQ(memcmp(parsed.memo, memo, parsed.memo_len), 0); +} + +TEST(Tron, RejectWrongSelector) { + auto data = trc20Calldata(tronAddr(0x22), 42, false); + data[0] = 0x09; /* approve(address,uint256) = 0x095ea7b3... not transfer */ + auto raw = rawTx(contractMsg(31, TRIGGER_URL, + triggerContractValue(tronAddr(0x11), + tronAddr(0x33), data)), + nullptr, 0); + + TronParsedTx parsed; + EXPECT_EQ(tron_parseRawTx(raw.data(), raw.size(), &parsed), + TRON_TX_UNVERIFIED); +} + +TEST(Tron, RejectDirtyAddressWord) { + auto data = trc20Calldata(tronAddr(0x22), 42, false); + data[4 + 3] = 0x01; /* junk in the high bytes of the address word */ + auto raw = rawTx(contractMsg(31, TRIGGER_URL, + triggerContractValue(tronAddr(0x11), + tronAddr(0x33), data)), + nullptr, 0); + + TronParsedTx parsed; + EXPECT_EQ(tron_parseRawTx(raw.data(), raw.size(), &parsed), + TRON_TX_UNVERIFIED); +} + +TEST(Tron, RejectCalldataLengthMismatch) { + auto data = trc20Calldata(tronAddr(0x22), 42, false); + data.push_back(0x00); /* trailing byte — could smuggle params */ + auto raw = rawTx(contractMsg(31, TRIGGER_URL, + triggerContractValue(tronAddr(0x11), + tronAddr(0x33), data)), + nullptr, 0); + + TronParsedTx parsed; + EXPECT_EQ(tron_parseRawTx(raw.data(), raw.size(), &parsed), + TRON_TX_UNVERIFIED); +} + +TEST(Tron, RejectNonzeroCallValue) { + auto value = triggerContractValue(tronAddr(0x11), tronAddr(0x33), + trc20Calldata(tronAddr(0x22), 42, false)); + std::vector withCallValue; + putBytesField(withCallValue, 1, tronAddr(0x11)); + putBytesField(withCallValue, 2, tronAddr(0x33)); + putVarintField(withCallValue, 3, 7 /* nonzero TRX attached */); + putBytesField(withCallValue, 4, trc20Calldata(tronAddr(0x22), 42, false)); + auto raw = rawTx(contractMsg(31, TRIGGER_URL, withCallValue), nullptr, 0); + + TronParsedTx parsed; + EXPECT_EQ(tron_parseRawTx(raw.data(), raw.size(), &parsed), + TRON_TX_UNVERIFIED); + + /* zero call_value explicitly present is fine */ + std::vector zeroCallValue; + putBytesField(zeroCallValue, 1, tronAddr(0x11)); + putBytesField(zeroCallValue, 2, tronAddr(0x33)); + putVarintField(zeroCallValue, 3, 0); + putBytesField(zeroCallValue, 4, trc20Calldata(tronAddr(0x22), 42, false)); + raw = rawTx(contractMsg(31, TRIGGER_URL, zeroCallValue), nullptr, 0); + EXPECT_EQ(tron_parseRawTx(raw.data(), raw.size(), &parsed), + TRON_TX_TRC20_TRANSFER); +} + +TEST(Tron, RejectTrc10Fields) { + std::vector v; + putBytesField(v, 1, tronAddr(0x11)); + putBytesField(v, 2, tronAddr(0x33)); + putBytesField(v, 4, trc20Calldata(tronAddr(0x22), 42, false)); + putVarintField(v, 5, 1000001); /* call_token_value / token_id territory */ + auto raw = rawTx(contractMsg(31, TRIGGER_URL, v), nullptr, 0); + + TronParsedTx parsed; + EXPECT_EQ(tron_parseRawTx(raw.data(), raw.size(), &parsed), + TRON_TX_UNVERIFIED); +} + +TEST(Tron, RejectMultipleContracts) { + auto contract = contractMsg( + 1, TRANSFER_URL, + transferContractValue(tronAddr(0x11), tronAddr(0x22), 1)); + std::vector raw; + putBytesField(raw, 11, contract); + putBytesField(raw, 11, contract); + + TronParsedTx parsed; + EXPECT_EQ(tron_parseRawTx(raw.data(), raw.size(), &parsed), + TRON_TX_UNVERIFIED); +} + +TEST(Tron, RejectUnknownTopLevelField) { + auto raw = rawTx(contractMsg(1, TRANSFER_URL, + transferContractValue(tronAddr(0x11), + tronAddr(0x22), 1)), + nullptr, 0); + putBytesField(raw, 9, {0x01}); /* auths — permission delegation */ + + TronParsedTx parsed; + EXPECT_EQ(tron_parseRawTx(raw.data(), raw.size(), &parsed), + TRON_TX_UNVERIFIED); +} + +TEST(Tron, RejectExtraFieldInTransferContract) { + auto value = transferContractValue(tronAddr(0x11), tronAddr(0x22), 1); + putVarintField(value, 4, 99); + auto raw = rawTx(contractMsg(1, TRANSFER_URL, value), nullptr, 0); + + TronParsedTx parsed; + EXPECT_EQ(tron_parseRawTx(raw.data(), raw.size(), &parsed), + TRON_TX_UNVERIFIED); +} + +TEST(Tron, RejectPermissionId) { + std::vector any; + putStringField(any, 1, TRANSFER_URL); + putBytesField(any, 2, + transferContractValue(tronAddr(0x11), tronAddr(0x22), 1)); + std::vector c; + putVarintField(c, 1, 1); + putBytesField(c, 2, any); + putVarintField(c, 5, 2); /* Permission_id — multisig account slot */ + auto raw = rawTx(c, nullptr, 0); + + TronParsedTx parsed; + EXPECT_EQ(tron_parseRawTx(raw.data(), raw.size(), &parsed), + TRON_TX_UNVERIFIED); +} + +TEST(Tron, RejectDuplicateAnyFields) { + /* Two type_urls in the Any wrapper — last-wins ambiguity, refuse. */ + std::vector any; + putStringField(any, 1, TRIGGER_URL); + putStringField(any, 1, TRANSFER_URL); + putBytesField(any, 2, + transferContractValue(tronAddr(0x11), tronAddr(0x22), 1)); + std::vector c; + putVarintField(c, 1, 1); + putBytesField(c, 2, any); + auto raw = rawTx(c, nullptr, 0); + + TronParsedTx parsed; + EXPECT_EQ(tron_parseRawTx(raw.data(), raw.size(), &parsed), + TRON_TX_UNVERIFIED); + + /* Two value fields likewise */ + std::vector any2; + putStringField(any2, 1, TRANSFER_URL); + putBytesField(any2, 2, + transferContractValue(tronAddr(0x11), tronAddr(0x22), 1)); + putBytesField(any2, 2, + transferContractValue(tronAddr(0x11), tronAddr(0x33), 2)); + std::vector c2; + putVarintField(c2, 1, 1); + putBytesField(c2, 2, any2); + raw = rawTx(c2, nullptr, 0); + EXPECT_EQ(tron_parseRawTx(raw.data(), raw.size(), &parsed), + TRON_TX_UNVERIFIED); +} + +TEST(Tron, RejectTypeUrlEnumMismatch) { + /* enum says TransferContract, Any says TriggerSmartContract */ + auto raw = rawTx(contractMsg(1, TRIGGER_URL, + transferContractValue(tronAddr(0x11), + tronAddr(0x22), 1)), + nullptr, 0); + + TronParsedTx parsed; + EXPECT_EQ(tron_parseRawTx(raw.data(), raw.size(), &parsed), + TRON_TX_UNVERIFIED); +} + +TEST(Tron, RejectBadOwnerAddress) { + auto owner = tronAddr(0x11); + owner[0] = 0x42; /* wrong network prefix */ + auto raw = rawTx(contractMsg(1, TRANSFER_URL, + transferContractValue(owner, tronAddr(0x22), 1)), + nullptr, 0); + + TronParsedTx parsed; + EXPECT_EQ(tron_parseRawTx(raw.data(), raw.size(), &parsed), + TRON_TX_UNVERIFIED); +} + +TEST(Tron, RejectOverlongKeyVarint) { + /* The very first varint of raw_data is a field key. An overlong + * (overflowing) key varint must not be silently truncated into some + * other field number. */ + std::vector raw; + putOverlongVarintValue(raw); + + TronParsedTx parsed; + EXPECT_EQ(tron_parseRawTx(raw.data(), raw.size(), &parsed), + TRON_TX_UNVERIFIED); +} + +TEST(Tron, RejectOverlongLengthVarint) { + /* A valid key (field 11, length-delimited) followed by an overlong + * length varint — must not be truncated into some in-bounds length. */ + std::vector raw; + putKey(raw, 11, 2); + putOverlongVarintValue(raw); + + TronParsedTx parsed; + EXPECT_EQ(tron_parseRawTx(raw.data(), raw.size(), &parsed), + TRON_TX_UNVERIFIED); +} + +TEST(Tron, RejectOverlongAmountVarint) { + /* TransferContract.amount (field 3) encoded as an overlong varint. */ + std::vector value; + putBytesField(value, 1, tronAddr(0x11)); + putBytesField(value, 2, tronAddr(0x22)); + putOverlongVarintField(value, 3); + auto raw = rawTx(contractMsg(1, TRANSFER_URL, value), nullptr, 0); + + TronParsedTx parsed; + EXPECT_EQ(tron_parseRawTx(raw.data(), raw.size(), &parsed), + TRON_TX_UNVERIFIED); +} + +TEST(Tron, RejectOverlongFeeLimitVarint) { + /* Top-level fee_limit (field 18) encoded as an overlong varint. */ + auto raw = rawTx(contractMsg(1, TRANSFER_URL, + transferContractValue(tronAddr(0x11), + tronAddr(0x22), 1)), + nullptr, 0); + putOverlongVarintField(raw, 18); + + TronParsedTx parsed; + EXPECT_EQ(tron_parseRawTx(raw.data(), raw.size(), &parsed), + TRON_TX_UNVERIFIED); +} + +TEST(Tron, RejectTruncated) { + /* Build with the contract as the LAST field: any truncation then either + * cuts into a field (parse failure) or drops the contract entirely — + * both must be UNVERIFIED. (Truncation at a field boundary that only + * drops benign trailing fields like timestamp is legal protobuf and + * stays verified — that case is exercised by the parse tests above.) */ + std::vector raw; + putBytesField(raw, 1, {0xab, 0xcd}); + putVarintField(raw, 8, 1750000000000ULL); + putBytesField(raw, 11, + contractMsg(1, TRANSFER_URL, + transferContractValue(tronAddr(0x11), + tronAddr(0x22), 1000000))); + TronParsedTx sanity; + ASSERT_EQ(tron_parseRawTx(raw.data(), raw.size(), &sanity), + TRON_TX_TRANSFER); + + for (size_t cut = 1; cut < raw.size(); cut++) { + TronParsedTx parsed; + EXPECT_EQ(tron_parseRawTx(raw.data(), raw.size() - cut, &parsed), + TRON_TX_UNVERIFIED) + << "cut=" << cut; + } + + TronParsedTx parsed; + EXPECT_EQ(tron_parseRawTx(nullptr, 0, &parsed), TRON_TX_UNVERIFIED); +} + +TEST(Tron, FormatTrc20AmountUint256) { + uint8_t amount[32] = {0}; + amount[31] = 0x01; + char buf[90]; + ASSERT_TRUE(tron_formatTrc20Amount(amount, buf, sizeof(buf))); + EXPECT_STREQ(buf, "1"); + + /* 10^18 — an 18-decimals token unit */ + uint8_t big[32] = {0}; + const uint64_t e18 = 1000000000000000000ULL; + for (int i = 0; i < 8; i++) + big[24 + i] = static_cast(e18 >> (8 * (7 - i))); + ASSERT_TRUE(tron_formatTrc20Amount(big, buf, sizeof(buf))); + EXPECT_STREQ(buf, "1000000000000000000"); +} + +TEST(Tron, AddressFromBytes) { + /* Base58Check of 41 + 20 bytes must round-trip through the display helper */ + uint8_t addr[21]; + memset(addr, 0x11, sizeof(addr)); + addr[0] = 0x41; + char out[64]; + ASSERT_TRUE(tron_addressFromBytes(addr, out, sizeof(out))); + EXPECT_EQ(out[0], 'T'); /* mainnet addresses render as T... */ + EXPECT_GE(strlen(out), 33u); +} diff --git a/unittests/firmware/zcash.cpp b/unittests/firmware/zcash.cpp new file mode 100644 index 000000000..2d8f43e7f --- /dev/null +++ b/unittests/firmware/zcash.cpp @@ -0,0 +1,1757 @@ +extern "C" { +#include "keepkey/firmware/zcash.h" +#include "trezor/crypto/bignum.h" +#include "trezor/crypto/blake2b.h" +#include "trezor/crypto/memzero.h" +#include "trezor/crypto/pallas.h" +#include "trezor/crypto/pallas_sinsemilla.h" +#include "trezor/crypto/pallas_swu.h" +#include "trezor/crypto/redpallas.h" +#include "trezor/crypto/zcash_zip316.h" +} + +#include "gtest/gtest.h" +#include + +/* ── Pallas curve constants ──────────────────────────────────────── */ + +/* Pallas base field prime p (LE) */ +static const uint8_t PALLAS_P_LE[32] = { + 0x01, 0x00, 0x00, 0x00, 0xed, 0x30, 0x2d, 0x99, 0x1b, 0xf9, 0x4c, + 0x09, 0xfc, 0x98, 0x46, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +}; + +/* Pallas scalar field order q (LE) */ +static const uint8_t PALLAS_Q_LE[32] = { + 0x01, 0x00, 0x00, 0x00, 0x21, 0xeb, 0x46, 0x8c, 0xdd, 0xa8, 0x94, + 0x09, 0xfc, 0x98, 0x46, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +}; + +/* Sinsemilla primitive vectors generated with sinsemilla 0.1.0. */ +static const uint8_t SINSEMILLA_COMMIT_IVK_Q_X[32] = { + 0xf2, 0x82, 0x0f, 0x79, 0x92, 0x2f, 0xcb, 0x6b, 0x32, 0xa2, 0x28, + 0x51, 0x24, 0xcc, 0x1b, 0x42, 0xfa, 0x41, 0xa2, 0x5a, 0xb8, 0x81, + 0xcc, 0x7d, 0x11, 0xc8, 0xa9, 0x4a, 0xf1, 0x0c, 0xbc, 0x05, +}; + +static const uint8_t SINSEMILLA_COMMIT_IVK_Q_Y[32] = { + 0xbe, 0xde, 0xad, 0xcf, 0xce, 0xe5, 0x5a, 0xbe, 0xf1, 0xa5, 0x6d, + 0xc9, 0x1d, 0x35, 0xc4, 0x46, 0x4b, 0x05, 0xde, 0x20, 0x46, 0x07, + 0x59, 0xef, 0xe6, 0xbe, 0x1a, 0xd4, 0xf6, 0x4c, 0x01, 0x1b, +}; + +static const uint8_t SINSEMILLA_COMMIT_IVK_R_X[32] = { + 0x18, 0xa1, 0xf8, 0x5f, 0x6e, 0x48, 0x23, 0x98, 0xc7, 0xed, 0x1a, + 0xd3, 0xe2, 0x7f, 0x95, 0x02, 0x48, 0x89, 0x80, 0x40, 0x0a, 0x29, + 0x34, 0x16, 0x4e, 0x13, 0x70, 0x50, 0xcd, 0x2c, 0xa2, 0x25, +}; + +static const uint8_t SINSEMILLA_COMMIT_IVK_R_Y[32] = { + 0xa9, 0xdd, 0x7f, 0xe3, 0xb3, 0x93, 0xe7, 0x3f, 0xc7, 0xa6, 0x58, + 0x1b, 0xfb, 0x42, 0x44, 0x6b, 0x94, 0x57, 0x4b, 0x28, 0xc4, 0x90, + 0xc8, 0xc2, 0xeb, 0xfa, 0xa2, 0x66, 0x99, 0xd2, 0xcf, 0x29, +}; + +static const uint8_t SINSEMILLA_MSG_ONE_BIT[1] = {0x01}; +static const uint8_t SINSEMILLA_MSG_TEN_BITS[2] = {0xa5, 0x02}; +static const uint8_t SINSEMILLA_MSG_TWENTY_THREE_BITS[3] = {0x5a, 0xc3, 0x3f}; + +static const uint8_t SINSEMILLA_ZERO_BLIND[32] = {0}; +static const uint8_t SINSEMILLA_NONZERO_BLIND[32] = { + 0x21, 0x43, 0x65, 0x87, 0xa9, 0xcb, 0xed, 0x0f, 0x10, 0x32, 0x54, + 0x76, 0x98, 0xba, 0xdc, 0xfe, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, + 0xcd, 0xef, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, +}; + +#define SINSEMILLA_EMPTY_HASH_POINT SINSEMILLA_COMMIT_IVK_Q_X +#define SINSEMILLA_EMPTY_HASH SINSEMILLA_COMMIT_IVK_Q_X + +static const uint8_t SINSEMILLA_ONE_BIT_HASH_POINT[32] = { + 0xa6, 0x59, 0xf2, 0xb8, 0xa8, 0x92, 0xba, 0x43, 0x86, 0xca, 0x91, + 0x01, 0x6d, 0x68, 0xa8, 0xa4, 0xd2, 0x51, 0x38, 0x55, 0xaf, 0x29, + 0x15, 0x90, 0xd8, 0x2c, 0x50, 0xb9, 0x02, 0x26, 0x94, 0xb2, +}; + +static const uint8_t SINSEMILLA_ONE_BIT_HASH[32] = { + 0xa6, 0x59, 0xf2, 0xb8, 0xa8, 0x92, 0xba, 0x43, 0x86, 0xca, 0x91, + 0x01, 0x6d, 0x68, 0xa8, 0xa4, 0xd2, 0x51, 0x38, 0x55, 0xaf, 0x29, + 0x15, 0x90, 0xd8, 0x2c, 0x50, 0xb9, 0x02, 0x26, 0x94, 0x32, +}; + +static const uint8_t SINSEMILLA_TEN_BITS_HASH_POINT[32] = { + 0x16, 0xad, 0xea, 0x6c, 0xce, 0x33, 0x1c, 0xb2, 0x5c, 0xcb, 0x62, + 0x3e, 0x55, 0x61, 0x96, 0x98, 0x2c, 0xbb, 0xa0, 0x30, 0x18, 0xd9, + 0x49, 0x53, 0x5b, 0x4a, 0x56, 0x3b, 0x05, 0x73, 0x04, 0x85, +}; + +static const uint8_t SINSEMILLA_TEN_BITS_HASH[32] = { + 0x16, 0xad, 0xea, 0x6c, 0xce, 0x33, 0x1c, 0xb2, 0x5c, 0xcb, 0x62, + 0x3e, 0x55, 0x61, 0x96, 0x98, 0x2c, 0xbb, 0xa0, 0x30, 0x18, 0xd9, + 0x49, 0x53, 0x5b, 0x4a, 0x56, 0x3b, 0x05, 0x73, 0x04, 0x05, +}; + +static const uint8_t SINSEMILLA_TWENTY_THREE_BITS_HASH_POINT[32] = { + 0x1b, 0x2f, 0x70, 0x0a, 0x30, 0xc4, 0x5a, 0x5e, 0x7f, 0x98, 0x6e, + 0x13, 0xf9, 0xe8, 0xec, 0x5e, 0x95, 0xc9, 0xb1, 0xf0, 0x77, 0x3b, + 0x76, 0x39, 0x81, 0xbb, 0x59, 0x9a, 0x2e, 0xd7, 0xab, 0xb5, +}; + +static const uint8_t SINSEMILLA_TWENTY_THREE_BITS_HASH[32] = { + 0x1b, 0x2f, 0x70, 0x0a, 0x30, 0xc4, 0x5a, 0x5e, 0x7f, 0x98, 0x6e, + 0x13, 0xf9, 0xe8, 0xec, 0x5e, 0x95, 0xc9, 0xb1, 0xf0, 0x77, 0x3b, + 0x76, 0x39, 0x81, 0xbb, 0x59, 0x9a, 0x2e, 0xd7, 0xab, 0x35, +}; + +static const uint8_t SINSEMILLA_TWENTY_THREE_BITS_COMMIT_POINT[32] = { + 0x38, 0x2f, 0xe5, 0xd4, 0x2a, 0xe2, 0x0b, 0x82, 0x21, 0x6f, 0x86, + 0xb5, 0xba, 0xd0, 0xa4, 0xce, 0x14, 0x8a, 0x5f, 0x1a, 0x8e, 0xae, + 0xc0, 0x30, 0x67, 0xae, 0xaa, 0x2c, 0x67, 0xdd, 0xc1, 0x0a, +}; + +#define SINSEMILLA_TWENTY_THREE_BITS_SHORT_COMMIT \ + SINSEMILLA_TWENTY_THREE_BITS_COMMIT_POINT + +/* F4Jumble vectors from f4jumble 0.1.1 / zcash-test-vectors. */ +static const uint8_t F4JUMBLE_48_NORMAL[48] = { + 0x5d, 0x7a, 0x8f, 0x73, 0x9a, 0x2d, 0x9e, 0x94, 0x5b, 0x0c, 0xe1, 0x52, + 0xa8, 0x04, 0x9e, 0x29, 0x4c, 0x4d, 0x6e, 0x66, 0xb1, 0x64, 0x93, 0x9d, + 0xaf, 0xfa, 0x2e, 0xf6, 0xee, 0x69, 0x21, 0x48, 0x1c, 0xdd, 0x86, 0xb3, + 0xcc, 0x43, 0x18, 0xd9, 0x61, 0x4f, 0xc8, 0x20, 0x90, 0x5d, 0x04, 0x2b, +}; + +static const uint8_t F4JUMBLE_48_JUMBLED[48] = { + 0x03, 0x04, 0xd0, 0x29, 0x14, 0x1b, 0x99, 0x5d, 0xa5, 0x38, 0x7c, 0x12, + 0x59, 0x70, 0x67, 0x35, 0x04, 0xd6, 0xc7, 0x64, 0xd9, 0x1e, 0xa6, 0xc0, + 0x82, 0x12, 0x37, 0x70, 0xc7, 0x13, 0x9c, 0xcd, 0x88, 0xee, 0x27, 0x36, + 0x8c, 0xd0, 0xc0, 0x92, 0x1a, 0x04, 0x44, 0xc8, 0xe5, 0x85, 0x8d, 0x22, +}; + +static const uint8_t F4JUMBLE_64_NORMAL[64] = { + 0xb1, 0xef, 0x9c, 0xa3, 0xf2, 0x49, 0x88, 0xc7, 0xb3, 0x53, 0x42, + 0x01, 0xcf, 0xb1, 0xcd, 0x8d, 0xbf, 0x69, 0xb8, 0x25, 0x0c, 0x18, + 0xef, 0x41, 0x29, 0x4c, 0xa9, 0x79, 0x93, 0xdb, 0x54, 0x6c, 0x1f, + 0xe0, 0x1f, 0x7e, 0x9c, 0x8e, 0x36, 0xd6, 0xa5, 0xe2, 0x9d, 0x4e, + 0x30, 0xa7, 0x35, 0x94, 0xbf, 0x50, 0x98, 0x42, 0x1c, 0x69, 0x37, + 0x8a, 0xf1, 0xe4, 0x0f, 0x64, 0xe1, 0x25, 0x94, 0x6f, +}; + +static const uint8_t F4JUMBLE_64_JUMBLED[64] = { + 0x52, 0x71, 0xfa, 0x33, 0x21, 0xf3, 0xad, 0xbc, 0xfb, 0x07, 0x51, + 0x96, 0x88, 0x3d, 0x54, 0x2b, 0x43, 0x8e, 0xc6, 0x33, 0x91, 0x76, + 0x53, 0x7d, 0xaf, 0x85, 0x98, 0x41, 0xfe, 0x6a, 0x56, 0x22, 0x2b, + 0xff, 0x76, 0xd1, 0x66, 0x2b, 0x55, 0x09, 0xa9, 0xe1, 0x07, 0x9e, + 0x44, 0x6e, 0xee, 0xdd, 0x2e, 0x68, 0x3c, 0x31, 0xaa, 0xe3, 0xee, + 0x18, 0x51, 0xd7, 0x95, 0x43, 0x28, 0x52, 0x6b, 0xe1, +}; + +/* Compare two 32-byte LE values: return -1 if a < b, 0 if equal, 1 if a > b */ +static int cmp_le256(const uint8_t a[32], const uint8_t b[32]) { + for (int i = 31; i >= 0; i--) { + if (a[i] < b[i]) return -1; + if (a[i] > b[i]) return 1; + } + return 0; +} + +/* ── Reference Test Vectors ──────────────────────────────────────── */ + +/* + * Mnemonic: "all all all all all all all all all all all all" + * BIP-39 seed (PBKDF2, no passphrase), 64 bytes: + */ +static const uint8_t SEED_ALL[64] = { + 0xc7, 0x6c, 0x4a, 0xc4, 0xf4, 0xe4, 0xa0, 0x0d, 0x6b, 0x27, 0x4d, + 0x5c, 0x39, 0xc7, 0x00, 0xbb, 0x4a, 0x7d, 0xdc, 0x04, 0xfb, 0xc6, + 0xf7, 0x8e, 0x85, 0xca, 0x75, 0x00, 0x7b, 0x5b, 0x49, 0x5f, 0x74, + 0xa9, 0x04, 0x3e, 0xeb, 0x77, 0xbd, 0xd5, 0x3a, 0xa6, 0xfc, 0x3a, + 0x0e, 0x31, 0x46, 0x22, 0x70, 0x31, 0x6f, 0xa0, 0x4b, 0x8c, 0x19, + 0x11, 0x4c, 0x87, 0x98, 0x70, 0x6c, 0xd0, 0x2a, 0xc8, +}; + +/* + * Expected FVK for "all" mnemonic, account 0. + * Generated by the orchard Rust crate (authoritative ZIP-32). + */ +static const uint8_t EXPECTED_AK_ALL_0[32] = { + 0x05, 0x7a, 0xb0, 0x51, 0xd4, 0xfb, 0xb0, 0x20, 0x5d, 0x28, 0x64, + 0x8b, 0xac, 0xbc, 0x64, 0x71, 0xb5, 0x33, 0x47, 0x6c, 0x27, 0xbe, + 0xca, 0x33, 0xe5, 0xb9, 0xf5, 0x11, 0xd8, 0x55, 0x67, 0x2b, +}; + +static const uint8_t EXPECTED_NK_ALL_0[32] = { + 0x34, 0xa3, 0x5a, 0x0b, 0xda, 0x50, 0x27, 0x3b, 0x03, 0x19, 0xaf, + 0xa7, 0xa7, 0x0f, 0x86, 0xb6, 0xb1, 0x62, 0xeb, 0x31, 0x1d, 0x26, + 0x3d, 0x8f, 0x63, 0x21, 0xde, 0xf0, 0x02, 0x28, 0xba, 0x25, +}; + +static const uint8_t EXPECTED_RIVK_ALL_0[32] = { + 0x46, 0xbd, 0x2b, 0xd5, 0xe6, 0xec, 0xa5, 0xef, 0x03, 0xe1, 0x8c, + 0xd7, 0x65, 0x95, 0x51, 0x9e, 0xa9, 0x67, 0x06, 0xc5, 0x82, 0x6a, + 0x93, 0xba, 0x4d, 0xca, 0x94, 0x7d, 0x71, 0x1a, 0x7c, 0x0a, +}; + +static const uint8_t EXPECTED_IVK_ALL_0[32] = { + 0xa8, 0xe2, 0xea, 0x36, 0x48, 0x8b, 0x9e, 0xb4, 0x61, 0x47, 0x60, + 0x5b, 0xa1, 0x50, 0x40, 0x37, 0xd0, 0x88, 0x1e, 0x98, 0x1b, 0x6e, + 0x58, 0x47, 0xb9, 0xf5, 0xc1, 0xbe, 0xb5, 0xd0, 0x43, 0x35, +}; + +static const uint8_t EXPECTED_DK_ALL_0[32] = { + 0xe8, 0x52, 0xed, 0xd7, 0x82, 0xd6, 0xeb, 0x92, 0x12, 0x82, 0x21, + 0x9b, 0x8a, 0x9c, 0x38, 0x0e, 0x03, 0xfc, 0xc4, 0x76, 0x60, 0xfe, + 0x67, 0xaf, 0x1b, 0xa4, 0x77, 0x80, 0x2b, 0xb0, 0x6c, 0xe7, +}; + +static const uint8_t EXPECTED_DIVERSIFIER_ALL_0[11] = { + 0xda, 0x97, 0x30, 0x31, 0x63, 0x4a, 0x89, 0x38, 0xad, 0x1c, 0x48, +}; + +/* FF1-AES256 Orchard diversifier vectors generated with zcash-test-vectors. + * Parameters: radix = 2, n = 88, tweak = "", rounds = 10. + * Inputs and outputs are LEBS2OSP_88 byte encodings. + */ +struct OrchardFf1Vector { + uint8_t dk[32]; + uint8_t index[11]; + uint8_t diversifier[11]; +}; + +static const OrchardFf1Vector ORCHARD_FF1_VECTORS[] = { + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xdc, 0xe7, 0x7e, 0xbc, 0xec, 0x0a, 0x26, 0xaf, 0xd6, 0x99, 0x8c}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x63, 0x73, 0x8a, 0xa5, 0xf7, 0xbe, 0x22, 0xe1, 0xac, 0xdc, 0x0b}}, + {{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xd7, 0x39, 0xcc, 0xc2, 0xb8, 0x4d, 0x5d, 0x1a, 0xe5, 0x4a, 0x95}}, + {{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a}, + {0xc8, 0xff, 0x0b, 0x01, 0x96, 0x01, 0x30, 0x12, 0x76, 0x38, 0xc7}}, +}; + +static const uint8_t XMD_ABC_96[96] = { + 0x48, 0x50, 0x5e, 0x62, 0xfe, 0x0c, 0xe6, 0x64, 0xb6, 0x80, 0xf1, 0xf9, + 0xe6, 0x37, 0x43, 0x91, 0xa6, 0x09, 0x57, 0x5e, 0x53, 0x5c, 0xfd, 0x55, + 0xea, 0xd4, 0x49, 0xa4, 0x18, 0x43, 0xc7, 0x0d, 0x65, 0x3a, 0x08, 0x5d, + 0x09, 0xb1, 0x9f, 0x3f, 0x8d, 0x4d, 0x0a, 0xe4, 0x4f, 0x6a, 0xcf, 0x48, + 0xca, 0xfd, 0xb2, 0x8b, 0x8e, 0xea, 0x01, 0xe3, 0x6a, 0xf4, 0xf5, 0xfc, + 0xda, 0xcc, 0xf1, 0x45, 0x2a, 0x87, 0xc0, 0x8c, 0xc1, 0x0c, 0x9a, 0x03, + 0x7f, 0x3f, 0x03, 0x69, 0xf6, 0xb0, 0x43, 0xfb, 0xfc, 0x59, 0x81, 0xb6, + 0x0d, 0x50, 0xd7, 0xbd, 0x00, 0x4a, 0x59, 0x71, 0x3b, 0x1e, 0xcc, 0x25, +}; + +static const uint8_t SWU_0_X_LE[32] = { + 0x6e, 0x09, 0x9b, 0x51, 0x33, 0x34, 0xca, 0x85, 0xf4, 0x27, 0xa7, + 0xde, 0x25, 0x25, 0xf4, 0xf5, 0x8a, 0x9a, 0x12, 0x39, 0xb3, 0x95, + 0x52, 0xe2, 0x52, 0x6c, 0xf5, 0x34, 0xa5, 0xa6, 0xc1, 0x28, +}; + +static const uint8_t SWU_0_Y_LE[32] = { + 0x8d, 0xae, 0xc5, 0x6a, 0xee, 0xa1, 0x4f, 0x08, 0xc7, 0xb7, 0x07, + 0x02, 0x27, 0x9c, 0xd2, 0x15, 0xd3, 0x3f, 0x08, 0x27, 0x09, 0x7f, + 0x7d, 0x3c, 0xc6, 0x53, 0x66, 0xee, 0x8b, 0x65, 0xfc, 0x3b, +}; + +static const uint8_t SWU_0_Z_LE[32] = { + 0x36, 0xef, 0xcd, 0xd8, 0x0c, 0x25, 0x5f, 0x8a, 0x6f, 0x74, 0x7d, + 0xda, 0x72, 0x54, 0x11, 0x5d, 0x9d, 0xa1, 0x34, 0x85, 0x31, 0xb1, + 0x57, 0x41, 0x10, 0xdc, 0x16, 0x04, 0xa1, 0x3b, 0x4b, 0x05, +}; + +static const uint8_t SWU_1_X_LE[32] = { + 0x05, 0x15, 0x56, 0xa3, 0xa5, 0xb9, 0x13, 0x79, 0x83, 0x80, 0x82, + 0x06, 0x71, 0xb0, 0x64, 0x6d, 0x85, 0xa1, 0x26, 0xc0, 0x67, 0xe9, + 0xf5, 0x4a, 0x53, 0x76, 0xe8, 0x57, 0x59, 0xba, 0x0c, 0x01, +}; + +static const uint8_t SWU_1_Y_LE[32] = { + 0x81, 0x9c, 0xcc, 0x5d, 0x51, 0x6d, 0xfa, 0x76, 0xe9, 0x78, 0x80, + 0xb0, 0xd6, 0x14, 0x75, 0x54, 0x6a, 0xf4, 0xeb, 0x65, 0xa0, 0x65, + 0x6e, 0x7d, 0x8e, 0x11, 0xd3, 0x9c, 0x1f, 0xc6, 0x2f, 0x06, +}; + +static const uint8_t SWU_1_Z_LE[32] = { + 0x88, 0x36, 0xa7, 0x29, 0x9a, 0xbc, 0x75, 0x7c, 0x3a, 0x75, 0xe1, + 0x3d, 0x62, 0xf5, 0xcf, 0x5c, 0x60, 0x93, 0x77, 0x3e, 0x52, 0x4e, + 0x1c, 0x10, 0xc3, 0x50, 0x12, 0x31, 0x8c, 0xcb, 0x86, 0x3f, +}; + +static const uint8_t HASH_ZCASH_TEST_TRANS_RIGHTS[32] = { + 0xd3, 0x6b, 0x0b, 0x64, 0x9b, 0x5c, 0x69, 0x36, 0x02, 0x7a, 0x18, + 0x0f, 0x7d, 0x25, 0x40, 0x23, 0x95, 0x6f, 0xc2, 0x88, 0x3d, 0xdf, + 0x23, 0xff, 0xc3, 0xc8, 0xfd, 0x1f, 0xa3, 0xcd, 0x18, 0x18, +}; + +static const uint8_t ORCHARD_GD_EMPTY[32] = { + 0x3f, 0x90, 0xd3, 0xe5, 0x80, 0xd5, 0x6a, 0x66, 0x2b, 0x27, 0x36, + 0x91, 0xd8, 0xd1, 0xe3, 0x34, 0x75, 0x30, 0x83, 0xe9, 0xbf, 0x4c, + 0x17, 0x2e, 0x7d, 0xae, 0xfc, 0x0f, 0x06, 0x08, 0xcf, 0x97, +}; + +static const uint8_t ORCHARD_GD_ALL_ACCOUNT0_J0[32] = { + 0x26, 0x8e, 0xd9, 0xf9, 0x01, 0xfd, 0xb4, 0xe9, 0xb3, 0xf0, 0x70, + 0xd9, 0x5f, 0x1b, 0x8d, 0x98, 0x35, 0x3c, 0xb8, 0xa2, 0x02, 0xac, + 0x1c, 0x97, 0xbd, 0xb1, 0x26, 0x9f, 0x85, 0x93, 0xd6, 0x30, +}; + +static const uint8_t ORCHARD_GD_FF1_ZERO_ZERO[32] = { + 0xa4, 0x58, 0x99, 0x84, 0x3c, 0xde, 0x1f, 0xaf, 0x52, 0x42, 0x6e, + 0x27, 0xd4, 0x17, 0x96, 0xb5, 0x2a, 0xaf, 0x39, 0xf1, 0x47, 0x9c, + 0xe0, 0x69, 0xd7, 0xa9, 0xda, 0x4e, 0xef, 0xc3, 0xf8, 0x3d, +}; + +/* Orchard ivk/d/g_d/pk_d vectors generated with orchard 0.12.0. */ +struct OrchardReceiverVector { + uint8_t ivk[32]; + uint8_t diversifier[11]; + uint8_t gd[32]; + uint8_t pkd[32]; +}; + +static const OrchardReceiverVector ORCHARD_RECEIVER_VECTORS[] = { + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xd8, 0xe1, 0x01, 0x7d, 0x45, 0x32, 0xab, 0x65, 0xe0, 0xe5, 0x38}, + {0x7d, 0x70, 0x35, 0xca, 0x4a, 0x40, 0x9d, 0xe0, 0x65, 0x40, 0xdf, + 0xd1, 0x6e, 0x8c, 0x2d, 0xd9, 0xa9, 0x34, 0xee, 0x17, 0xfa, 0xfb, + 0x8e, 0xd0, 0xd7, 0x85, 0x6d, 0x16, 0x1c, 0x9a, 0x02, 0x2b}, + {0x7d, 0x70, 0x35, 0xca, 0x4a, 0x40, 0x9d, 0xe0, 0x65, 0x40, 0xdf, + 0xd1, 0x6e, 0x8c, 0x2d, 0xd9, 0xa9, 0x34, 0xee, 0x17, 0xfa, 0xfb, + 0x8e, 0xd0, 0xd7, 0x85, 0x6d, 0x16, 0x1c, 0x9a, 0x02, 0x2b}}, + {{0x42, 0x7a, 0x1d, 0xb3, 0x94, 0x6f, 0x20, 0xe5, 0x88, 0x30, 0xc2, + 0x91, 0x76, 0x11, 0x5d, 0x04, 0xf8, 0xbc, 0x9a, 0x21, 0x0e, 0x73, + 0xd5, 0x4c, 0x06, 0x9b, 0xa8, 0x17, 0x2e, 0x45, 0x00, 0x10}, + {0xe3, 0x63, 0x1b, 0x5e, 0xdd, 0x66, 0x95, 0xf0, 0xf0, 0x0d, 0x8d}, + {0xe7, 0xb6, 0x5d, 0xda, 0x4b, 0xc5, 0x39, 0xc0, 0xf4, 0x0c, 0x6a, + 0xdf, 0xaa, 0x41, 0xaa, 0x11, 0xd2, 0xf5, 0x27, 0xc8, 0x8a, 0xd0, + 0x10, 0xec, 0xb5, 0xe3, 0x8c, 0xbe, 0x38, 0x18, 0xdd, 0x31}, + {0x36, 0xc5, 0x49, 0x3f, 0x2b, 0x53, 0xaf, 0x23, 0x7b, 0x86, 0x5a, + 0xe1, 0x17, 0xc3, 0x05, 0x14, 0x8b, 0x78, 0xb2, 0x10, 0x84, 0x7c, + 0x86, 0xa5, 0xce, 0x24, 0xfa, 0x12, 0xa9, 0x1f, 0xf5, 0x87}}, + {{0xfe, 0xff, 0xff, 0xff, 0x38, 0x6d, 0x78, 0x34, 0xad, 0x14, 0x19, + 0xe4, 0x0b, 0x35, 0x2c, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f}, + {0x65, 0x92, 0x89, 0x70, 0xbe, 0x78, 0x36, 0x96, 0xe0, 0x2f, 0xd1}, + {0xc9, 0xb4, 0xb5, 0x0a, 0x61, 0x9d, 0xc3, 0x4c, 0x60, 0xd4, 0xa8, + 0x30, 0x0d, 0x56, 0x60, 0x12, 0x77, 0xd7, 0x02, 0xa7, 0x5e, 0xb5, + 0xcf, 0xe1, 0x77, 0x22, 0xa7, 0x1d, 0xb7, 0x3f, 0x36, 0x32}, + {0x17, 0xcb, 0x58, 0x55, 0x9a, 0xf4, 0xd2, 0xcc, 0x6e, 0x1f, 0x24, + 0xa7, 0xe5, 0xab, 0x4c, 0x83, 0x33, 0x3c, 0x25, 0x16, 0xd3, 0x64, + 0x00, 0x6f, 0x9c, 0xee, 0x24, 0x70, 0x3c, 0xe4, 0xfc, 0xba}}, +}; + +/* Orchard ak/nk/rivk -> ivk vectors generated with orchard 0.12.0. */ +struct OrchardIvkVector { + uint8_t ak[32]; + uint8_t nk[32]; + uint8_t rivk[32]; + uint8_t ivk[32]; +}; + +static const OrchardIvkVector ORCHARD_IVK_VECTORS[] = { + {{0x87, 0x77, 0xe2, 0x15, 0x10, 0x1d, 0xf4, 0x5a, 0xa4, 0x68, 0xbb, + 0x10, 0xb2, 0xf9, 0x3f, 0xfe, 0x08, 0xa2, 0xf7, 0x9e, 0xbf, 0xf0, + 0x95, 0xaa, 0xeb, 0x74, 0x73, 0xc7, 0x71, 0x34, 0x96, 0x21}, + {0xbb, 0xca, 0x15, 0x2c, 0xfb, 0xf9, 0x81, 0x18, 0x19, 0xcc, 0x62, + 0x44, 0x34, 0xd1, 0x23, 0x75, 0x77, 0xc1, 0x38, 0x05, 0xcc, 0x3d, + 0xed, 0x44, 0x4e, 0x75, 0x5a, 0x6b, 0x78, 0xfa, 0xcd, 0x16}, + {0x8c, 0xa7, 0xfb, 0xba, 0x26, 0x47, 0x0f, 0xea, 0x0b, 0x10, 0xd3, + 0x0d, 0xb2, 0x73, 0x66, 0xec, 0x65, 0x04, 0x0c, 0x72, 0xa0, 0x9a, + 0xd8, 0x42, 0x58, 0x88, 0xef, 0x26, 0xf1, 0xc0, 0x79, 0x3f}, + {0xa1, 0xf8, 0x75, 0x87, 0x29, 0x73, 0xea, 0x49, 0x2d, 0xe3, 0xbe, + 0x5c, 0xce, 0xcf, 0xe5, 0x56, 0x79, 0x10, 0x24, 0x4c, 0xb6, 0x02, + 0x99, 0x4c, 0x58, 0x00, 0xf6, 0x8c, 0x64, 0x38, 0xb9, 0x1b}}, + {{0x6e, 0xbb, 0x83, 0x3c, 0x1d, 0x2f, 0x84, 0x33, 0x08, 0x0a, 0xbc, + 0xea, 0xbe, 0x47, 0x90, 0x60, 0x97, 0xf9, 0x06, 0x78, 0xd6, 0x03, + 0xf5, 0x77, 0xd0, 0x48, 0x6c, 0x91, 0x11, 0x73, 0x7b, 0x07}, + {0xf2, 0x26, 0xa3, 0xf8, 0x79, 0xeb, 0xe2, 0x1a, 0xbf, 0xaf, 0xcc, + 0xb6, 0xc5, 0x21, 0xca, 0x74, 0x9e, 0x63, 0xac, 0x17, 0xfd, 0x2c, + 0xd1, 0x78, 0x70, 0xaa, 0x72, 0xde, 0x12, 0xd8, 0x33, 0x0d}, + {0x04, 0x7c, 0x00, 0xab, 0x5e, 0x0f, 0xec, 0xa6, 0x1a, 0x46, 0x18, + 0x58, 0xbb, 0x0b, 0x15, 0xd5, 0x5f, 0x29, 0x76, 0x3a, 0x0a, 0x28, + 0x28, 0x25, 0xac, 0xeb, 0xd5, 0x86, 0x98, 0x93, 0x7d, 0x24}, + {0xa1, 0x75, 0x8f, 0x83, 0xad, 0xbd, 0x24, 0x89, 0x87, 0xc3, 0x6b, + 0xbf, 0x52, 0x41, 0xc1, 0x29, 0x9e, 0xfa, 0x96, 0xf2, 0x4c, 0x8c, + 0xfb, 0xb5, 0x51, 0x17, 0x23, 0x90, 0x9c, 0xc1, 0xe2, 0x02}}, + {{0xa4, 0x1c, 0xc0, 0xc3, 0x80, 0x0f, 0xf8, 0x9a, 0x88, 0xd7, 0xae, + 0x02, 0xff, 0x33, 0x6f, 0xdb, 0xd5, 0xbc, 0xe8, 0x9d, 0x9e, 0x8d, + 0xd4, 0xeb, 0x27, 0x8b, 0x4c, 0xd5, 0xc3, 0x7e, 0xc7, 0x20}, + {0x41, 0x5e, 0x75, 0x22, 0x27, 0xcb, 0x69, 0x65, 0x2e, 0x2a, 0xfa, + 0x94, 0x81, 0x6f, 0x63, 0x0d, 0xce, 0xc1, 0xac, 0xdf, 0x3c, 0x3f, + 0xb0, 0x2e, 0x1e, 0x6b, 0x04, 0x6e, 0x12, 0xa4, 0x31, 0x11}, + {0x92, 0x76, 0xa5, 0xb7, 0x55, 0xa1, 0x54, 0x63, 0xab, 0x59, 0xf0, + 0xe7, 0x22, 0x1f, 0x65, 0x80, 0x65, 0x7c, 0x05, 0x3f, 0xdb, 0x74, + 0x40, 0x12, 0xb3, 0xc1, 0x64, 0x8c, 0x75, 0x78, 0xd1, 0x22}, + {0xa8, 0x4f, 0x85, 0xd1, 0x57, 0xba, 0x71, 0x66, 0x5b, 0x31, 0x0b, + 0xd2, 0x12, 0x15, 0xad, 0x58, 0x82, 0x3b, 0x29, 0x8f, 0x44, 0x98, + 0xd5, 0x0d, 0x63, 0xad, 0xc9, 0x4d, 0x34, 0xeb, 0x93, 0x0a}}, +}; + +/* Orchard raw receiver vectors generated with orchard 0.12.0. */ +struct OrchardReceiverAssemblyVector { + const uint8_t* ak; + const uint8_t* nk; + const uint8_t* rivk; + const uint8_t* dk; + uint8_t index[11]; + uint8_t receiver[43]; +}; + +static const uint8_t ORCHARD_ASSEMBLY_DK_2[32] = { + 0x6c, 0x50, 0x3c, 0x95, 0x19, 0x0a, 0x74, 0x1d, 0x5f, 0x54, 0x87, + 0x59, 0xeb, 0x46, 0x4a, 0xa5, 0x36, 0x3b, 0xcd, 0xbc, 0x91, 0xa6, + 0x98, 0x7b, 0xd0, 0x7f, 0x67, 0x7b, 0x37, 0x59, 0xc2, 0x08, +}; + +static const uint8_t ORCHARD_ASSEMBLY_DK_3[32] = { + 0x41, 0xb7, 0x06, 0x56, 0xe2, 0x02, 0xaa, 0xcd, 0x0d, 0x92, 0x3b, + 0x7c, 0x95, 0xc0, 0xfc, 0x17, 0xa2, 0x13, 0xaf, 0x97, 0x3a, 0xd4, + 0xf8, 0x3f, 0xeb, 0x47, 0xdd, 0xf8, 0x3b, 0xb1, 0x68, 0xe4, +}; + +static const OrchardReceiverAssemblyVector ORCHARD_RECEIVER_ASSEMBLY_VECTORS[] = + { + {EXPECTED_AK_ALL_0, + EXPECTED_NK_ALL_0, + EXPECTED_RIVK_ALL_0, + EXPECTED_DK_ALL_0, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xda, 0x97, 0x30, 0x31, 0x63, 0x4a, 0x89, 0x38, 0xad, 0x1c, 0x48, + 0x0f, 0x97, 0x87, 0x80, 0x69, 0x3e, 0xc7, 0x70, 0x9b, 0xa5, 0xca, + 0xf5, 0x8d, 0x8a, 0x7e, 0xb9, 0x45, 0x58, 0x6c, 0xbe, 0xd6, 0x45, + 0x52, 0x0f, 0x17, 0x38, 0x74, 0x37, 0xbc, 0xfd, 0xc2, 0x16}}, + {EXPECTED_AK_ALL_0, + EXPECTED_NK_ALL_0, + EXPECTED_RIVK_ALL_0, + EXPECTED_DK_ALL_0, + {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xbb, 0x0c, 0x08, 0xc2, 0x0f, 0x07, 0x8f, 0x59, 0x89, 0x39, 0x1c, + 0x36, 0x91, 0xb8, 0x97, 0xea, 0xcf, 0x28, 0x9a, 0x02, 0x02, 0x2f, + 0x45, 0xb3, 0xb1, 0x3f, 0x5f, 0xa1, 0xaa, 0xd5, 0x95, 0x9f, 0xaa, + 0x29, 0x01, 0x56, 0xc2, 0x40, 0xb8, 0xae, 0x1c, 0x07, 0x25}}, + {ORCHARD_IVK_VECTORS[1].ak, + ORCHARD_IVK_VECTORS[1].nk, + ORCHARD_IVK_VECTORS[1].rivk, + ORCHARD_ASSEMBLY_DK_2, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x45, 0x59, 0x02, 0x9c, 0x0b, 0x5d, 0xbf, 0x94, 0x1c, 0x5a, 0xd1, + 0x81, 0xa5, 0xfe, 0x8f, 0x45, 0xb3, 0x46, 0x30, 0xf2, 0x9d, 0x0c, + 0x8d, 0xd8, 0xdc, 0x1c, 0xc3, 0x57, 0x33, 0x86, 0xf4, 0x16, 0xcb, + 0x32, 0x41, 0x33, 0x15, 0x6d, 0x72, 0x3d, 0xf5, 0xe6, 0x2d}}, + {ORCHARD_IVK_VECTORS[2].ak, + ORCHARD_IVK_VECTORS[2].nk, + ORCHARD_IVK_VECTORS[2].rivk, + ORCHARD_ASSEMBLY_DK_3, + {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xcb, 0xd5, 0xfc, 0x34, 0xc7, 0x26, 0x1d, 0x3f, 0xdb, 0x23, 0xd2, + 0xb8, 0x14, 0xad, 0xcb, 0xfc, 0x2d, 0x8e, 0x17, 0x2c, 0x79, 0xee, + 0x8e, 0x2e, 0x3f, 0xe7, 0xd8, 0xb1, 0xda, 0xd5, 0xb6, 0x67, 0x8e, + 0x22, 0x6c, 0xa7, 0xa3, 0x99, 0x6b, 0x1e, 0x62, 0x4f, 0x35}}, +}; + +/* Orchard-only unified address vectors generated with zcash_address 0.10.1. */ +static const char ORCHARD_ONLY_UA_MAINNET_0[] = + "u1uzslnccvrw4r2y2kgjz7fm477xcnzge9z45scm4e6l6c63ren0ru29teedxw5vxu7c8xch" + "p3ec2pu3wkgldc5zphwtm4w3fchcwrl26c"; +static const char ORCHARD_ONLY_UA_TESTNET_0[] = + "utest1deyej6qvxfnewfhgdc987fgpq407u374vzvtvgjuv86vj0gs9tcej04hk7nr5msm5fzg" + "335j70mddjnqj48zjsj5zl2362w4zcd2ks8c"; +static const char ORCHARD_ONLY_UA_MAINNET_1[] = + "u19whtuck5ry2d53xa348ecvfgsudtk8vt2qexe9w50lzwkzxx3lxcn60ztjfe2m33e0jz4xd" + "4kxe3yhz65xq9jzvjcrtjrhvrf5mzat26"; +static const char ORCHARD_ONLY_UA_TESTNET_1[] = + "utest1ff5jzt4pr5hzgz8688052pjtq0plzk3va9hgssprp3ps2lluhy3u6ej7eh3njfgqp3" + "ar4lm8muxu352nmuqt2c5n92w4ngf44qwtjl0p"; + +/* ── ZIP-32 Derivation Tests ─────────────────────────────────────── */ + +TEST(Zcash, DeriveOrchardKeys_ReferenceVector_Account0) { + /* + * Reference vector test: derive keys from known "all" mnemonic seed + * and compare against values from the orchard Rust crate. + */ + ZcashOrchardKeys keys; + ASSERT_TRUE(zcash_derive_orchard_keys(SEED_ALL, 64, 0, &keys)); + + /* nk must match reference */ + EXPECT_TRUE(memcmp(keys.nk, EXPECTED_NK_ALL_0, 32) == 0) + << "nk mismatch for all-mnemonic account 0"; + + /* rivk must match reference */ + EXPECT_TRUE(memcmp(keys.rivk, EXPECTED_RIVK_ALL_0, 32) == 0) + << "rivk mismatch for all-mnemonic account 0"; + + uint8_t ivk[32]; + ASSERT_TRUE( + zcash_orchard_derive_ivk(EXPECTED_AK_ALL_0, keys.nk, keys.rivk, ivk)); + EXPECT_TRUE(memcmp(ivk, EXPECTED_IVK_ALL_0, 32) == 0) + << "ivk mismatch for all-mnemonic account 0"; + + EXPECT_TRUE(memcmp(keys.dk, EXPECTED_DK_ALL_0, 32) == 0) + << "dk mismatch for all-mnemonic account 0"; + + uint8_t diversifier[11]; + uint8_t index0[11] = {0}; + ASSERT_TRUE(zcash_orchard_derive_diversifier(keys.dk, index0, diversifier)); + EXPECT_TRUE(memcmp(diversifier, EXPECTED_DIVERSIFIER_ALL_0, 11) == 0) + << "default diversifier mismatch for all-mnemonic account 0"; + + /* Compute ak = [ask]*G and verify against reference */ + bignum256 ask_scalar; + bn_read_le(keys.ask, &ask_scalar); + curve_point ak_point; + redpallas_scalar_mult_spendauth_G(&ask_scalar, &ak_point); + + uint8_t ak_bytes[32]; + bignum256 x_copy; + bn_copy(&ak_point.x, &x_copy); + bn_write_le(&x_copy, ak_bytes); + EXPECT_EQ(ak_bytes[31] & 0x80, 0) + << "ak sign bit must be 0 after ask normalization"; + + EXPECT_TRUE(memcmp(ak_bytes, EXPECTED_AK_ALL_0, 32) == 0) + << "ak mismatch for all-mnemonic account 0"; + + memzero(diversifier, sizeof(diversifier)); + memzero(ivk, sizeof(ivk)); + memzero(&keys, sizeof(keys)); +} + +TEST(Zcash, DeriveOrchardKeys_DifferentAccounts) { + ZcashOrchardKeys keys0, keys1; + ASSERT_TRUE(zcash_derive_orchard_keys(SEED_ALL, 64, 0, &keys0)); + ASSERT_TRUE(zcash_derive_orchard_keys(SEED_ALL, 64, 1, &keys1)); + + /* Different accounts must produce different spending keys */ + EXPECT_TRUE(memcmp(keys0.sk, keys1.sk, 32) != 0) + << "Account 0 and 1 must have different sk"; + EXPECT_TRUE(memcmp(keys0.ask, keys1.ask, 32) != 0) + << "Account 0 and 1 must have different ask"; + EXPECT_TRUE(memcmp(keys0.nk, keys1.nk, 32) != 0) + << "Account 0 and 1 must have different nk"; + + memzero(&keys0, sizeof(keys0)); + memzero(&keys1, sizeof(keys1)); +} + +TEST(Zcash, DeriveOrchardKeys_DifferentSeeds) { + /* Use a different seed (all zeros) */ + uint8_t zero_seed[64]; + memset(zero_seed, 0, sizeof(zero_seed)); + + ZcashOrchardKeys keys_all, keys_zero; + ASSERT_TRUE(zcash_derive_orchard_keys(SEED_ALL, 64, 0, &keys_all)); + ASSERT_TRUE(zcash_derive_orchard_keys(zero_seed, 64, 0, &keys_zero)); + + EXPECT_TRUE(memcmp(keys_all.sk, keys_zero.sk, 32) != 0) + << "Different seeds must produce different sk"; + + memzero(&keys_all, sizeof(keys_all)); + memzero(&keys_zero, sizeof(keys_zero)); +} + +TEST(Zcash, DeriveOrchardKeys_Deterministic) { + ZcashOrchardKeys keys1, keys2; + ASSERT_TRUE(zcash_derive_orchard_keys(SEED_ALL, 64, 0, &keys1)); + ASSERT_TRUE(zcash_derive_orchard_keys(SEED_ALL, 64, 0, &keys2)); + + EXPECT_TRUE(memcmp(keys1.sk, keys2.sk, 32) == 0); + EXPECT_TRUE(memcmp(keys1.ask, keys2.ask, 32) == 0); + EXPECT_TRUE(memcmp(keys1.nk, keys2.nk, 32) == 0); + EXPECT_TRUE(memcmp(keys1.rivk, keys2.rivk, 32) == 0); + EXPECT_TRUE(memcmp(keys1.dk, keys2.dk, 32) == 0); + + memzero(&keys1, sizeof(keys1)); + memzero(&keys2, sizeof(keys2)); +} + +TEST(Zcash, DeriveOrchardKeys_DerivesDiversifierKey) { + ZcashOrchardKeys keys0, keys1; + ASSERT_TRUE(zcash_derive_orchard_keys(SEED_ALL, 64, 0, &keys0)); + ASSERT_TRUE(zcash_derive_orchard_keys(SEED_ALL, 64, 1, &keys1)); + + uint8_t zero[32] = {0}; + EXPECT_TRUE(memcmp(keys0.dk, zero, 32) != 0) + << "Diversifier key must be populated"; + EXPECT_TRUE(memcmp(keys0.dk, keys1.dk, 32) != 0) + << "Different accounts must produce different diversifier keys"; + + memzero(&keys0, sizeof(keys0)); + memzero(&keys1, sizeof(keys1)); +} + +TEST(Zcash, OrchardDiversifier_FF1ReferenceVectors) { + for (const auto& tv : ORCHARD_FF1_VECTORS) { + uint8_t actual[11]; + ASSERT_TRUE(zcash_orchard_derive_diversifier(tv.dk, tv.index, actual)); + EXPECT_TRUE(memcmp(actual, tv.diversifier, sizeof(actual)) == 0); + memzero(actual, sizeof(actual)); + } +} + +TEST(Zcash, OrchardDiversifier_DeterministicAndDistinct) { + const uint8_t index0[11] = {0}; + const uint8_t index1[11] = {1}; + uint8_t d0[11], d0_again[11], d1[11]; + + ASSERT_TRUE( + zcash_orchard_derive_diversifier(ORCHARD_FF1_VECTORS[2].dk, index0, d0)); + ASSERT_TRUE(zcash_orchard_derive_diversifier(ORCHARD_FF1_VECTORS[2].dk, + index0, d0_again)); + ASSERT_TRUE( + zcash_orchard_derive_diversifier(ORCHARD_FF1_VECTORS[2].dk, index1, d1)); + + EXPECT_TRUE(memcmp(d0, d0_again, sizeof(d0)) == 0); + EXPECT_TRUE(memcmp(d0, d1, sizeof(d0)) != 0); + + memzero(d0, sizeof(d0)); + memzero(d0_again, sizeof(d0_again)); + memzero(d1, sizeof(d1)); +} + +TEST(Zcash, ExpandMessageXmdBlake2b_ReferenceVector) { + const uint8_t msg[] = {'a', 'b', 'c'}; + const uint8_t dst[] = "z.cash:test-pallas_XMD:BLAKE2b_SSWU_RO_"; + uint8_t out[96]; + + ASSERT_EQ(pallas_expand_message_xmd_blake2b( + msg, sizeof(msg), dst, sizeof(dst) - 1, out, sizeof(out)), + 0); + EXPECT_TRUE(memcmp(out, XMD_ABC_96, sizeof(out)) == 0); +} + +static void expect_bn_le(const bignum256* value, const uint8_t expected[32]) { + uint8_t actual[32]; + bignum256 tmp; + bn_copy(value, &tmp); + bn_write_le(&tmp, actual); + EXPECT_TRUE(memcmp(actual, expected, 32) == 0); + memzero(actual, sizeof(actual)); + memzero(&tmp, sizeof(tmp)); +} + +static void load_curve_point_from_xy(const uint8_t x[32], const uint8_t y[32], + curve_point* out) { + bn_read_le(x, &out->x); + bn_read_le(y, &out->y); + bn_normalize(&out->x); + bn_normalize(&out->y); +} + +TEST(Zcash, PallasSimpleSwu_ReferenceVectors) { + uint8_t u0[32] = {0}; + uint8_t u1[32] = {0}; + u1[0] = 1; + + pallas_jacobian_point p0, p1; + ASSERT_EQ(pallas_map_to_curve_simple_swu(u0, &p0), 0); + ASSERT_EQ(pallas_map_to_curve_simple_swu(u1, &p1), 0); + + expect_bn_le(&p0.x, SWU_0_X_LE); + expect_bn_le(&p0.y, SWU_0_Y_LE); + expect_bn_le(&p0.z, SWU_0_Z_LE); + expect_bn_le(&p1.x, SWU_1_X_LE); + expect_bn_le(&p1.y, SWU_1_Y_LE); + expect_bn_le(&p1.z, SWU_1_Z_LE); + + memzero(&p0, sizeof(p0)); + memzero(&p1, sizeof(p1)); +} + +TEST(Zcash, PallasGroupHash_ReferenceVector) { + const uint8_t msg[] = "Trans rights now!"; + curve_point p; + uint8_t encoded[32]; + + ASSERT_EQ(pallas_group_hash("z.cash:test", msg, sizeof(msg) - 1, &p), 0); + pallas_point_encode(&p, encoded); + EXPECT_TRUE(memcmp(encoded, HASH_ZCASH_TEST_TRANS_RIGHTS, sizeof(encoded)) == + 0); + + memzero(&p, sizeof(p)); + memzero(encoded, sizeof(encoded)); +} + +struct SinsemillaPrimitiveVector { + const uint8_t* msg; + size_t msg_bits; + const uint8_t* blind; + const uint8_t* hash_point; + const uint8_t* hash; + const uint8_t* commit_point; + const uint8_t* short_commit; +}; + +TEST(Zcash, SinsemillaPrimitives_ReferenceVectors) { + const SinsemillaPrimitiveVector vectors[] = { + {nullptr, 0, SINSEMILLA_ZERO_BLIND, SINSEMILLA_EMPTY_HASH_POINT, + SINSEMILLA_EMPTY_HASH, SINSEMILLA_EMPTY_HASH_POINT, + SINSEMILLA_EMPTY_HASH}, + {SINSEMILLA_MSG_ONE_BIT, 1, SINSEMILLA_ZERO_BLIND, + SINSEMILLA_ONE_BIT_HASH_POINT, SINSEMILLA_ONE_BIT_HASH, + SINSEMILLA_ONE_BIT_HASH_POINT, SINSEMILLA_ONE_BIT_HASH}, + {SINSEMILLA_MSG_TEN_BITS, 10, SINSEMILLA_ZERO_BLIND, + SINSEMILLA_TEN_BITS_HASH_POINT, SINSEMILLA_TEN_BITS_HASH, + SINSEMILLA_TEN_BITS_HASH_POINT, SINSEMILLA_TEN_BITS_HASH}, + {SINSEMILLA_MSG_TWENTY_THREE_BITS, 23, SINSEMILLA_NONZERO_BLIND, + SINSEMILLA_TWENTY_THREE_BITS_HASH_POINT, + SINSEMILLA_TWENTY_THREE_BITS_HASH, + SINSEMILLA_TWENTY_THREE_BITS_COMMIT_POINT, + SINSEMILLA_TWENTY_THREE_BITS_SHORT_COMMIT}, + }; + + curve_point q, r; + load_curve_point_from_xy(SINSEMILLA_COMMIT_IVK_Q_X, SINSEMILLA_COMMIT_IVK_Q_Y, + &q); + load_curve_point_from_xy(SINSEMILLA_COMMIT_IVK_R_X, SINSEMILLA_COMMIT_IVK_R_Y, + &r); + + for (const auto& vector : vectors) { + curve_point hash_point, commit_point; + uint8_t encoded[32]; + uint8_t hash[32]; + uint8_t short_commit[32]; + + ASSERT_EQ(pallas_sinsemilla_hash_to_point(&q, vector.msg, vector.msg_bits, + &hash_point), + 0); + pallas_point_encode(&hash_point, encoded); + EXPECT_TRUE(memcmp(encoded, vector.hash_point, sizeof(encoded)) == 0); + + ASSERT_EQ(pallas_sinsemilla_hash(&q, vector.msg, vector.msg_bits, hash), 0); + EXPECT_TRUE(memcmp(hash, vector.hash, sizeof(hash)) == 0); + + ASSERT_EQ(pallas_sinsemilla_commit(&q, &r, vector.msg, vector.msg_bits, + vector.blind, &commit_point), + 0); + pallas_point_encode(&commit_point, encoded); + EXPECT_TRUE(memcmp(encoded, vector.commit_point, sizeof(encoded)) == 0); + + ASSERT_EQ( + pallas_sinsemilla_short_commit(&q, &r, vector.msg, vector.msg_bits, + vector.blind, short_commit), + 0); + EXPECT_TRUE( + memcmp(short_commit, vector.short_commit, sizeof(short_commit)) == 0); + + memzero(&hash_point, sizeof(hash_point)); + memzero(&commit_point, sizeof(commit_point)); + memzero(encoded, sizeof(encoded)); + memzero(hash, sizeof(hash)); + memzero(short_commit, sizeof(short_commit)); + } + + memzero(&q, sizeof(q)); + memzero(&r, sizeof(r)); +} + +TEST(Zcash, SinsemillaPrimitives_RejectInvalidInputs) { + curve_point q, r, out; + load_curve_point_from_xy(SINSEMILLA_COMMIT_IVK_Q_X, SINSEMILLA_COMMIT_IVK_Q_Y, + &q); + load_curve_point_from_xy(SINSEMILLA_COMMIT_IVK_R_X, SINSEMILLA_COMMIT_IVK_R_Y, + &r); + + EXPECT_EQ( + pallas_sinsemilla_hash_to_point(&q, SINSEMILLA_MSG_ONE_BIT, + PALLAS_SINSEMILLA_MAX_BITS + 1, &out), + -1); + + curve_point identity = {}; + EXPECT_EQ(pallas_sinsemilla_hash_to_point(&identity, SINSEMILLA_MSG_ONE_BIT, + 1, &out), + -1); + EXPECT_EQ(pallas_sinsemilla_commit(&q, &identity, SINSEMILLA_MSG_ONE_BIT, 1, + SINSEMILLA_ZERO_BLIND, &out), + -1); + EXPECT_EQ(pallas_sinsemilla_commit(&q, &r, SINSEMILLA_MSG_ONE_BIT, 1, + PALLAS_Q_LE, &out), + -1); + + memzero(&q, sizeof(q)); + memzero(&r, sizeof(r)); + memzero(&out, sizeof(out)); + memzero(&identity, sizeof(identity)); +} + +TEST(Zcash, Zip316F4Jumble_ReferenceVectors) { + uint8_t buf48[sizeof(F4JUMBLE_48_NORMAL)]; + memcpy(buf48, F4JUMBLE_48_NORMAL, sizeof(buf48)); + ASSERT_EQ(zcash_zip316_f4jumble(buf48, sizeof(buf48)), 0); + EXPECT_TRUE(memcmp(buf48, F4JUMBLE_48_JUMBLED, sizeof(buf48)) == 0); + ASSERT_EQ(zcash_zip316_f4jumble_inv(buf48, sizeof(buf48)), 0); + EXPECT_TRUE(memcmp(buf48, F4JUMBLE_48_NORMAL, sizeof(buf48)) == 0); + + uint8_t buf64[sizeof(F4JUMBLE_64_NORMAL)]; + memcpy(buf64, F4JUMBLE_64_NORMAL, sizeof(buf64)); + ASSERT_EQ(zcash_zip316_f4jumble(buf64, sizeof(buf64)), 0); + EXPECT_TRUE(memcmp(buf64, F4JUMBLE_64_JUMBLED, sizeof(buf64)) == 0); + ASSERT_EQ(zcash_zip316_f4jumble_inv(buf64, sizeof(buf64)), 0); + EXPECT_TRUE(memcmp(buf64, F4JUMBLE_64_NORMAL, sizeof(buf64)) == 0); + + memzero(buf48, sizeof(buf48)); + memzero(buf64, sizeof(buf64)); +} + +TEST(Zcash, Zip316F4Jumble_RejectsInvalidLengths) { + uint8_t too_short[ZCASH_ZIP316_F4JUMBLE_MIN_LEN - 1] = {0}; + EXPECT_EQ(zcash_zip316_f4jumble(too_short, sizeof(too_short)), -1); + EXPECT_EQ(zcash_zip316_f4jumble_inv(too_short, sizeof(too_short)), -1); + EXPECT_EQ(zcash_zip316_f4jumble(nullptr, ZCASH_ZIP316_F4JUMBLE_MIN_LEN), -1); +} + +TEST(Zcash, Zip316OrchardOnlyUnifiedAddress_ReferenceVectors) { + char address[ZCASH_ZIP316_ORCHARD_ONLY_MAX_ADDRESS_SIZE]; + + ASSERT_EQ(zcash_zip316_encode_orchard_unified_address( + "u", ORCHARD_RECEIVER_ASSEMBLY_VECTORS[0].receiver, address, + sizeof(address)), + 0); + EXPECT_STREQ(address, ORCHARD_ONLY_UA_MAINNET_0); + + ASSERT_EQ(zcash_zip316_encode_orchard_unified_address( + "utest", ORCHARD_RECEIVER_ASSEMBLY_VECTORS[0].receiver, address, + sizeof(address)), + 0); + EXPECT_STREQ(address, ORCHARD_ONLY_UA_TESTNET_0); + + ASSERT_EQ(zcash_zip316_encode_orchard_unified_address( + "u", ORCHARD_RECEIVER_ASSEMBLY_VECTORS[1].receiver, address, + sizeof(address)), + 0); + EXPECT_STREQ(address, ORCHARD_ONLY_UA_MAINNET_1); + + ASSERT_EQ(zcash_zip316_encode_orchard_unified_address( + "utest", ORCHARD_RECEIVER_ASSEMBLY_VECTORS[1].receiver, address, + sizeof(address)), + 0); + EXPECT_STREQ(address, ORCHARD_ONLY_UA_TESTNET_1); + + memzero(address, sizeof(address)); +} + +TEST(Zcash, Zip316OrchardOnlyUnifiedAddress_RejectsInvalidInputs) { + char address[ZCASH_ZIP316_ORCHARD_ONLY_MAX_ADDRESS_SIZE]; + char too_small[16]; + char long_hrp[ZCASH_ZIP316_PADDING_LEN + 2]; + memset(long_hrp, 'a', sizeof(long_hrp) - 1); + long_hrp[sizeof(long_hrp) - 1] = 0; + + EXPECT_EQ(zcash_zip316_encode_orchard_unified_address( + "u", ORCHARD_RECEIVER_ASSEMBLY_VECTORS[0].receiver, too_small, + sizeof(too_small)), + -1); + EXPECT_EQ(zcash_zip316_encode_orchard_unified_address( + long_hrp, ORCHARD_RECEIVER_ASSEMBLY_VECTORS[0].receiver, + address, sizeof(address)), + -1); + EXPECT_EQ(zcash_zip316_encode_orchard_unified_address( + "U", ORCHARD_RECEIVER_ASSEMBLY_VECTORS[0].receiver, address, + sizeof(address)), + -1); + + memzero(address, sizeof(address)); + memzero(too_small, sizeof(too_small)); + memzero(long_hrp, sizeof(long_hrp)); +} + +TEST(Zcash, OrchardUnifiedAddress_FromDerivedKeys) { + ZcashOrchardKeys keys; + ASSERT_TRUE(zcash_derive_orchard_keys(SEED_ALL, 64, 0, &keys)); + + char address[ZCASH_ZIP316_ORCHARD_ONLY_MAX_ADDRESS_SIZE]; + const uint8_t index0[11] = {0}; + const uint8_t index1[11] = {1}; + + ASSERT_TRUE(zcash_orchard_derive_unified_address(&keys, index0, "u", address, + sizeof(address))); + EXPECT_STREQ(address, ORCHARD_ONLY_UA_MAINNET_0); + + ASSERT_TRUE(zcash_orchard_derive_unified_address(&keys, index0, "utest", + address, sizeof(address))); + EXPECT_STREQ(address, ORCHARD_ONLY_UA_TESTNET_0); + + ASSERT_TRUE(zcash_orchard_derive_unified_address(&keys, index1, "u", address, + sizeof(address))); + EXPECT_STREQ(address, ORCHARD_ONLY_UA_MAINNET_1); + + ASSERT_TRUE(zcash_orchard_derive_unified_address(&keys, index1, "utest", + address, sizeof(address))); + EXPECT_STREQ(address, ORCHARD_ONLY_UA_TESTNET_1); + + memzero(address, sizeof(address)); + memzero(&keys, sizeof(keys)); +} + +TEST(Zcash, OrchardUnifiedAddress_RejectsInvalidInputs) { + ZcashOrchardKeys keys; + ASSERT_TRUE(zcash_derive_orchard_keys(SEED_ALL, 64, 0, &keys)); + + char address[ZCASH_ZIP316_ORCHARD_ONLY_MAX_ADDRESS_SIZE]; + char too_small[16]; + const uint8_t index0[11] = {0}; + + EXPECT_FALSE(zcash_orchard_derive_unified_address(nullptr, index0, "u", + address, sizeof(address))); + EXPECT_FALSE(zcash_orchard_derive_unified_address(&keys, nullptr, "u", + address, sizeof(address))); + EXPECT_FALSE(zcash_orchard_derive_unified_address(&keys, index0, nullptr, + address, sizeof(address))); + EXPECT_FALSE(zcash_orchard_derive_unified_address(&keys, index0, "u", nullptr, + sizeof(address))); + EXPECT_FALSE(zcash_orchard_derive_unified_address( + &keys, index0, "u", too_small, sizeof(too_small))); + + memzero(address, sizeof(address)); + memzero(too_small, sizeof(too_small)); + memzero(&keys, sizeof(keys)); +} + +TEST(Zcash, OrchardNoteCommitment_KnownVector) { + const uint8_t recipient[ZCASH_ORCHARD_RAW_RECEIVER_SIZE] = { + 0x3c, 0x15, 0x0e, 0x60, 0x98, 0xb8, 0x61, 0x71, 0x6c, 0xc7, 0xf6, + 0x28, 0x35, 0xf6, 0x9f, 0xeb, 0x30, 0x21, 0x93, 0xc9, 0x26, 0x60, + 0x44, 0x4f, 0x26, 0x62, 0x4f, 0xd1, 0x3e, 0x00, 0xea, 0x7a, 0xc7, + 0x74, 0xcd, 0x55, 0x07, 0x4d, 0x63, 0x67, 0xef, 0xef, 0x37}; + const uint64_t value = 12345678; + const uint8_t rho[32] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, + 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, + 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00}; + const uint8_t rseed[32] = {0xca, 0xfe, 0xba, 0xbe, 0xde, 0xad, 0xbe, 0xef, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}; + const uint8_t expected_cmx[32] = { + 0x02, 0xde, 0xfb, 0x39, 0xc8, 0xf2, 0xe1, 0xec, 0xc9, 0x45, 0x18, + 0x93, 0x73, 0xcf, 0x2a, 0x8e, 0x21, 0xd4, 0xe1, 0x54, 0x39, 0x8e, + 0xfa, 0x16, 0x21, 0xd5, 0xfb, 0x98, 0x9e, 0x1d, 0xeb, 0x36}; + + uint8_t cmx[32]; + ASSERT_TRUE(zcash_orchard_compute_cmx(recipient, value, rho, rseed, cmx)); + EXPECT_TRUE(memcmp(cmx, expected_cmx, sizeof(cmx)) == 0); + + uint8_t tampered[ZCASH_ORCHARD_RAW_RECEIVER_SIZE]; + memcpy(tampered, recipient, sizeof(tampered)); + tampered[0] ^= 0x01; + ASSERT_TRUE(zcash_orchard_compute_cmx(tampered, value, rho, rseed, cmx)); + EXPECT_TRUE(memcmp(cmx, expected_cmx, sizeof(cmx)) != 0); + + memzero(cmx, sizeof(cmx)); + memzero(tampered, sizeof(tampered)); +} + +TEST(Zcash, OrchardReceiverToUnifiedAddress_KnownVector) { + const uint8_t recipient[ZCASH_ORCHARD_RAW_RECEIVER_SIZE] = { + 0x3c, 0x15, 0x0e, 0x60, 0x98, 0xb8, 0x61, 0x71, 0x6c, 0xc7, 0xf6, + 0x28, 0x35, 0xf6, 0x9f, 0xeb, 0x30, 0x21, 0x93, 0xc9, 0x26, 0x60, + 0x44, 0x4f, 0x26, 0x62, 0x4f, 0xd1, 0x3e, 0x00, 0xea, 0x7a, 0xc7, + 0x74, 0xcd, 0x55, 0x07, 0x4d, 0x63, 0x67, 0xef, 0xef, 0x37}; + char address[ZCASH_ORCHARD_UNIFIED_ADDRESS_SIZE]; + + ASSERT_TRUE(zcash_orchard_receiver_to_unified_address(recipient, "u", address, + sizeof(address))); + EXPECT_STREQ(address, + "u1ut4h93zg5670tyqss7tneru3t7h6dk62r9hhyxyrpv3nwwe9dnyj5l0ruwygf" + "74gp5f3zklj5xly4h8h54un3asugt9mn6gwfqsq3wq7"); + + EXPECT_FALSE( + zcash_orchard_receiver_to_unified_address(recipient, "u", address, 16)); + memzero(address, sizeof(address)); +} + +TEST(Zcash, OrchardDiversifyHash_ReferenceVectors) { + uint8_t gd[32]; + ASSERT_TRUE(zcash_orchard_diversify_hash(EXPECTED_DIVERSIFIER_ALL_0, gd)); + EXPECT_TRUE(memcmp(gd, ORCHARD_GD_ALL_ACCOUNT0_J0, sizeof(gd)) == 0); + + ASSERT_TRUE( + zcash_orchard_diversify_hash(ORCHARD_FF1_VECTORS[0].diversifier, gd)); + EXPECT_TRUE(memcmp(gd, ORCHARD_GD_FF1_ZERO_ZERO, sizeof(gd)) == 0); + + curve_point empty; + ASSERT_EQ(pallas_group_hash("z.cash:Orchard-gd", NULL, 0, &empty), 0); + pallas_point_encode(&empty, gd); + EXPECT_TRUE(memcmp(gd, ORCHARD_GD_EMPTY, sizeof(gd)) == 0); + + memzero(gd, sizeof(gd)); + memzero(&empty, sizeof(empty)); +} + +TEST(Zcash, OrchardTransmissionKey_ReferenceVectors) { + for (const auto& vector : ORCHARD_RECEIVER_VECTORS) { + uint8_t gd[32]; + uint8_t pkd[32]; + ASSERT_TRUE(zcash_orchard_derive_transmission_key( + vector.ivk, vector.diversifier, gd, pkd)); + EXPECT_TRUE(memcmp(gd, vector.gd, sizeof(gd)) == 0); + EXPECT_TRUE(memcmp(pkd, vector.pkd, sizeof(pkd)) == 0); + + uint8_t pkd_without_gd[32]; + ASSERT_TRUE(zcash_orchard_derive_transmission_key( + vector.ivk, vector.diversifier, nullptr, pkd_without_gd)); + EXPECT_TRUE(memcmp(pkd_without_gd, vector.pkd, sizeof(pkd_without_gd)) == + 0); + + memzero(gd, sizeof(gd)); + memzero(pkd, sizeof(pkd)); + memzero(pkd_without_gd, sizeof(pkd_without_gd)); + } +} + +TEST(Zcash, OrchardTransmissionKey_RejectsZeroIvk) { + uint8_t zero_ivk[32] = {0}; + uint8_t gd[32]; + uint8_t pkd[32]; + EXPECT_FALSE(zcash_orchard_derive_transmission_key( + zero_ivk, ORCHARD_RECEIVER_VECTORS[0].diversifier, gd, pkd)); +} + +TEST(Zcash, OrchardIvk_ReferenceVectors) { + for (const auto& vector : ORCHARD_IVK_VECTORS) { + uint8_t ivk[32]; + ASSERT_TRUE( + zcash_orchard_derive_ivk(vector.ak, vector.nk, vector.rivk, ivk)); + EXPECT_TRUE(memcmp(ivk, vector.ivk, sizeof(ivk)) == 0); + memzero(ivk, sizeof(ivk)); + } +} + +TEST(Zcash, OrchardIvk_RejectsInvalidAkEncoding) { + uint8_t bad_ak[32]; + memcpy(bad_ak, ORCHARD_IVK_VECTORS[0].ak, sizeof(bad_ak)); + bad_ak[31] |= 0x80; + + uint8_t ivk[32]; + EXPECT_FALSE(zcash_orchard_derive_ivk(bad_ak, ORCHARD_IVK_VECTORS[0].nk, + ORCHARD_IVK_VECTORS[0].rivk, ivk)); + memzero(bad_ak, sizeof(bad_ak)); + memzero(ivk, sizeof(ivk)); +} + +TEST(Zcash, OrchardReceiver_ReferenceVectors) { + for (const auto& vector : ORCHARD_RECEIVER_ASSEMBLY_VECTORS) { + uint8_t receiver[43]; + ASSERT_TRUE(zcash_orchard_derive_receiver( + vector.ak, vector.nk, vector.rivk, vector.dk, vector.index, receiver)); + EXPECT_TRUE(memcmp(receiver, vector.receiver, sizeof(receiver)) == 0); + memzero(receiver, sizeof(receiver)); + } +} + +TEST(Zcash, OrchardReceiver_RejectsInvalidAkEncoding) { + uint8_t bad_ak[32]; + memcpy(bad_ak, ORCHARD_RECEIVER_ASSEMBLY_VECTORS[0].ak, sizeof(bad_ak)); + bad_ak[31] |= 0x80; + + uint8_t receiver[43]; + EXPECT_FALSE(zcash_orchard_derive_receiver( + bad_ak, ORCHARD_RECEIVER_ASSEMBLY_VECTORS[0].nk, + ORCHARD_RECEIVER_ASSEMBLY_VECTORS[0].rivk, + ORCHARD_RECEIVER_ASSEMBLY_VECTORS[0].dk, + ORCHARD_RECEIVER_ASSEMBLY_VECTORS[0].index, receiver)); + memzero(bad_ak, sizeof(bad_ak)); + memzero(receiver, sizeof(receiver)); +} + +/* ── Field Range Tests ───────────────────────────────────────────── */ + +TEST(Zcash, DeriveOrchardKeys_FieldRanges) { + /* Test multiple accounts to increase coverage of edge cases */ + for (uint32_t account = 0; account < 5; account++) { + ZcashOrchardKeys keys; + ASSERT_TRUE(zcash_derive_orchard_keys(SEED_ALL, 64, account, &keys)); + + /* nk must be < Pallas base field prime p */ + EXPECT_LT(cmp_le256(keys.nk, PALLAS_P_LE), 0) + << "nk must be < p for account " << account; + + /* rivk must be < Pallas scalar field order q */ + EXPECT_LT(cmp_le256(keys.rivk, PALLAS_Q_LE), 0) + << "rivk must be < q for account " << account; + + /* ask must be < Pallas scalar field order q */ + EXPECT_LT(cmp_le256(keys.ask, PALLAS_Q_LE), 0) + << "ask must be < q for account " << account; + + /* ask must be nonzero (astronomically unlikely, but verify) */ + uint8_t zero[32] = {0}; + EXPECT_TRUE(memcmp(keys.ask, zero, 32) != 0) + << "ask must be nonzero for account " << account; + + memzero(&keys, sizeof(keys)); + } +} + +TEST(Zcash, AkSignBit_AlwaysClear) { + /* + * For every account, compute ak = [ask]*G and verify the sign bit + * is always clear. This is the invariant that the ask negation + * in zcash_derive_orchard_keys() is supposed to enforce. + */ + for (uint32_t account = 0; account < 10; account++) { + ZcashOrchardKeys keys; + ASSERT_TRUE(zcash_derive_orchard_keys(SEED_ALL, 64, account, &keys)); + + bignum256 ask_scalar; + bn_read_le(keys.ask, &ask_scalar); + curve_point ak_point; + redpallas_scalar_mult_spendauth_G(&ask_scalar, &ak_point); + + /* Check y parity: must be even (sign bit = 0) */ + EXPECT_FALSE(bn_is_odd(&ak_point.y)) + << "ak y-coordinate must be even for account " << account; + + /* Check serialized sign bit */ + uint8_t ak_bytes[32]; + bignum256 x_copy; + bn_copy(&ak_point.x, &x_copy); + bn_write_le(&x_copy, ak_bytes); + + EXPECT_EQ(ak_bytes[31] & 0x80, 0) + << "ak sign bit must be clear for account " << account; + + memzero(&keys, sizeof(keys)); + } +} + +/* ── PCZT Signing Policy Tests ───────────────────────────────────── */ + +static ZcashPCZTSigningRequestMeta clear_pczt_meta(void) { + ZcashPCZTSigningRequestMeta meta = {}; + meta.has_header_digest = true; + meta.header_digest_size = 32; + meta.has_orchard_digest = true; + meta.orchard_digest_size = 32; + meta.has_orchard_flags = true; + meta.has_orchard_value_balance = true; + meta.has_orchard_anchor = true; + meta.orchard_anchor_size = 32; + meta.has_header_fields = true; + meta.n_transparent_inputs = 0; + meta.n_transparent_outputs = 0; + return meta; +} + +TEST(Zcash, PCZTSigningPolicy_AcceptsVerifiedShieldedOnlyRequest) { + ZcashPCZTSigningRequestMeta meta = clear_pczt_meta(); + + EXPECT_EQ(zcash_pczt_signing_request_status(&meta), + ZCASH_PCZT_SIGNING_REQUEST_OK); + EXPECT_TRUE(zcash_pczt_signing_request_is_clear(&meta)); +} + +TEST(Zcash, PCZTSigningPolicy_RejectsMissingTransactionDigests) { + ZcashPCZTSigningRequestMeta meta = clear_pczt_meta(); + + meta.has_header_digest = false; + EXPECT_EQ(zcash_pczt_signing_request_status(&meta), + ZCASH_PCZT_SIGNING_REQUEST_MISSING_TX_DIGESTS); + EXPECT_FALSE(zcash_pczt_signing_request_is_clear(&meta)); + + meta = clear_pczt_meta(); + meta.orchard_digest_size = 31; + EXPECT_EQ(zcash_pczt_signing_request_status(&meta), + ZCASH_PCZT_SIGNING_REQUEST_INVALID_DIGEST_SIZE); + EXPECT_FALSE(zcash_pczt_signing_request_is_clear(&meta)); +} + +TEST(Zcash, PCZTSigningPolicy_RejectsMissingPlaintextHeaderFields) { + ZcashPCZTSigningRequestMeta meta = clear_pczt_meta(); + + meta.has_header_fields = false; + EXPECT_EQ(zcash_pczt_signing_request_status(&meta), + ZCASH_PCZT_SIGNING_REQUEST_MISSING_HEADER_FIELDS); + EXPECT_FALSE(zcash_pczt_signing_request_is_clear(&meta)); +} + +TEST(Zcash, PCZTSigningPolicy_RejectsMissingOrchardMetadata) { + ZcashPCZTSigningRequestMeta meta = clear_pczt_meta(); + + meta.has_orchard_anchor = false; + EXPECT_EQ(zcash_pczt_signing_request_status(&meta), + ZCASH_PCZT_SIGNING_REQUEST_MISSING_ORCHARD_METADATA); + EXPECT_FALSE(zcash_pczt_signing_request_is_clear(&meta)); + + meta = clear_pczt_meta(); + meta.has_orchard_flags = false; + EXPECT_EQ(zcash_pczt_signing_request_status(&meta), + ZCASH_PCZT_SIGNING_REQUEST_MISSING_ORCHARD_METADATA); + EXPECT_FALSE(zcash_pczt_signing_request_is_clear(&meta)); +} + +TEST(Zcash, PCZTSigningPolicy_RejectsInvalidOptionalDigests) { + ZcashPCZTSigningRequestMeta meta = clear_pczt_meta(); + + meta.has_transparent_digest = true; + meta.transparent_digest_size = 31; + EXPECT_EQ(zcash_pczt_signing_request_status(&meta), + ZCASH_PCZT_SIGNING_REQUEST_INVALID_DIGEST_SIZE); + EXPECT_FALSE(zcash_pczt_signing_request_is_clear(&meta)); +} + +TEST(Zcash, PCZTSigningPolicy_RejectsSaplingComponent) { + ZcashPCZTSigningRequestMeta meta = clear_pczt_meta(); + + meta.has_sapling_digest = true; + meta.sapling_digest_size = 32; + EXPECT_EQ(zcash_pczt_signing_request_status(&meta), + ZCASH_PCZT_SIGNING_REQUEST_UNSUPPORTED_SAPLING_COMPONENT); + EXPECT_FALSE(zcash_pczt_signing_request_is_clear(&meta)); +} + +TEST(Zcash, PCZTSigningPolicy_RejectsTransparentComponentsWithoutDigest) { + ZcashPCZTSigningRequestMeta meta = clear_pczt_meta(); + meta.n_transparent_inputs = 1; + + EXPECT_EQ(zcash_pczt_signing_request_status(&meta), + ZCASH_PCZT_SIGNING_REQUEST_MISSING_TRANSPARENT_DIGEST); + EXPECT_FALSE(zcash_pczt_signing_request_is_clear(&meta)); + + meta.has_transparent_digest = true; + meta.transparent_digest_size = 32; + EXPECT_EQ(zcash_pczt_signing_request_status(&meta), + ZCASH_PCZT_SIGNING_REQUEST_OK); + EXPECT_TRUE(zcash_pczt_signing_request_is_clear(&meta)); + + meta = clear_pczt_meta(); + meta.n_transparent_outputs = 1; + EXPECT_EQ(zcash_pczt_signing_request_status(&meta), + ZCASH_PCZT_SIGNING_REQUEST_MISSING_TRANSPARENT_DIGEST); + EXPECT_FALSE(zcash_pczt_signing_request_is_clear(&meta)); + + meta.has_transparent_digest = true; + meta.transparent_digest_size = 32; + EXPECT_EQ(zcash_pczt_signing_request_status(&meta), + ZCASH_PCZT_SIGNING_REQUEST_OK); + EXPECT_TRUE(zcash_pczt_signing_request_is_clear(&meta)); +} + +static const uint8_t ZIP244_EXPECTED_HEADER_DIGEST[32] = { + 0x44, 0x4b, 0xe9, 0x38, 0x88, 0x1d, 0xc9, 0xf2, 0x0a, 0xed, 0x88, + 0x0c, 0x3a, 0x05, 0x94, 0xe5, 0xc1, 0x22, 0x3e, 0xff, 0xc5, 0x75, + 0xef, 0x05, 0xda, 0xae, 0xe3, 0x45, 0x1b, 0xa2, 0xf4, 0x93}; + +static const uint8_t ZIP244_EXPECTED_EMPTY_TRANSPARENT_DIGEST[32] = { + 0xc3, 0x3f, 0x2e, 0x95, 0x70, 0x5f, 0xaa, 0xb3, 0x5f, 0x8d, 0x53, + 0x3f, 0xa6, 0x1e, 0x95, 0xc3, 0xb7, 0xaa, 0xba, 0x07, 0x76, 0xb8, + 0x74, 0xa9, 0xf7, 0x4f, 0xc1, 0x27, 0x84, 0x37, 0x6a, 0x59}; + +static const uint8_t ZIP244_EXPECTED_TRANSPARENT_DIGEST[32] = { + 0xfa, 0xe5, 0x37, 0x7f, 0xa9, 0x3c, 0xc0, 0xc3, 0x1d, 0x30, 0x39, + 0x42, 0x21, 0x57, 0xce, 0x4b, 0x9e, 0x7b, 0x12, 0x57, 0x00, 0x9f, + 0x15, 0x90, 0xe1, 0x62, 0x95, 0x62, 0x55, 0xbb, 0x2e, 0x84}; + +static const uint8_t ZIP244_EXPECTED_TRANSPARENT_SIGHASH_0[32] = { + 0x37, 0xa9, 0xc4, 0xec, 0x61, 0x87, 0x07, 0x20, 0x5b, 0xcb, 0x47, + 0x7b, 0xea, 0x4f, 0xda, 0x6d, 0x61, 0x01, 0x62, 0xea, 0xaa, 0x5c, + 0x9f, 0x33, 0xe5, 0x59, 0x69, 0x02, 0x6e, 0x47, 0x6f, 0x23}; + +static const uint8_t ZIP244_EXPECTED_TRANSPARENT_SIGHASH_1[32] = { + 0x29, 0x4d, 0xb7, 0xaa, 0xf1, 0x65, 0x37, 0x4e, 0x02, 0xda, 0xe1, + 0x6f, 0xf3, 0xdd, 0x97, 0x78, 0x8f, 0x4f, 0x5e, 0x2d, 0xc4, 0xe1, + 0xb3, 0xf6, 0x62, 0x73, 0x9e, 0xd3, 0x5b, 0x82, 0x08, 0x2f}; + +static const uint8_t ZIP244_P2PKH_SCRIPT_11[25] = { + 0x76, 0xa9, 0x14, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x88, 0xac}; + +static const uint8_t ZIP244_P2SH_SCRIPT_22[23] = { + 0xa9, 0x14, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x87}; + +static const uint8_t ZIP244_P2PKH_SCRIPT_33[25] = { + 0x76, 0xa9, 0x14, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x88, 0xac}; + +static const uint8_t ZIP244_P2SH_SCRIPT_44[23] = { + 0xa9, 0x14, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x87}; + +static void fill_zip244_txids(uint8_t txid0[32], uint8_t txid1[32]) { + for (size_t i = 0; i < 32; i++) { + txid0[i] = (uint8_t)i; + txid1[i] = (uint8_t)(i + 32); + } +} + +static void make_zip244_transparent_fixture( + ZcashTransparentInputDigestInfo inputs[2], + ZcashTransparentOutputDigestInfo outputs[2], uint8_t txid0[32], + uint8_t txid1[32]) { + fill_zip244_txids(txid0, txid1); + + inputs[0].prevout_txid = txid0; + inputs[0].prevout_index = 2; + inputs[0].sequence = 0xfffffffe; + inputs[0].value = 1234567890ULL; + inputs[0].script_pubkey = ZIP244_P2PKH_SCRIPT_11; + inputs[0].script_pubkey_size = sizeof(ZIP244_P2PKH_SCRIPT_11); + + inputs[1].prevout_txid = txid1; + inputs[1].prevout_index = 7; + inputs[1].sequence = 0xfffffffd; + inputs[1].value = 987654321ULL; + inputs[1].script_pubkey = ZIP244_P2SH_SCRIPT_22; + inputs[1].script_pubkey_size = sizeof(ZIP244_P2SH_SCRIPT_22); + + outputs[0].value = 2000000000ULL; + outputs[0].script_pubkey = ZIP244_P2PKH_SCRIPT_33; + outputs[0].script_pubkey_size = sizeof(ZIP244_P2PKH_SCRIPT_33); + + outputs[1].value = 1111111ULL; + outputs[1].script_pubkey = ZIP244_P2SH_SCRIPT_44; + outputs[1].script_pubkey_size = sizeof(ZIP244_P2SH_SCRIPT_44); +} + +TEST(Zcash, ComputeHeaderDigest_FromPlaintextFields) { + uint8_t digest[32] = {0}; + + ASSERT_TRUE(zcash_compute_header_digest(5, 0x26a7270a, 0xc2d6d0b4, 123456, + 987654, digest)); + EXPECT_TRUE(memcmp(digest, ZIP244_EXPECTED_HEADER_DIGEST, 32) == 0); +} + +TEST(Zcash, ComputeTransparentDigest_DistinctFromPerInputSighash) { + ZcashTransparentInputDigestInfo inputs[2] = {}; + ZcashTransparentOutputDigestInfo outputs[2] = {}; + uint8_t txid0[32], txid1[32]; + make_zip244_transparent_fixture(inputs, outputs, txid0, txid1); + + uint8_t digest[32] = {0}; + uint8_t sighash0[32] = {0}; + uint8_t sighash1[32] = {0}; + + ASSERT_TRUE(zcash_compute_transparent_digest(inputs, 2, outputs, 2, digest)); + ASSERT_TRUE(zcash_compute_transparent_sighash_digest(inputs, 2, outputs, 2, 0, + 0x01, sighash0)); + ASSERT_TRUE(zcash_compute_transparent_sighash_digest(inputs, 2, outputs, 2, 1, + 0x01, sighash1)); + + EXPECT_TRUE(memcmp(digest, ZIP244_EXPECTED_TRANSPARENT_DIGEST, 32) == 0); + EXPECT_TRUE(memcmp(sighash0, ZIP244_EXPECTED_TRANSPARENT_SIGHASH_0, 32) == 0); + EXPECT_TRUE(memcmp(sighash1, ZIP244_EXPECTED_TRANSPARENT_SIGHASH_1, 32) == 0); + EXPECT_TRUE(memcmp(digest, sighash0, 32) != 0); + EXPECT_TRUE(memcmp(sighash0, sighash1, 32) != 0); +} + +TEST(Zcash, ComputeTransparentDigest_EmptyBundle) { + uint8_t digest[32] = {0}; + + ASSERT_TRUE(zcash_compute_transparent_digest(NULL, 0, NULL, 0, digest)); + EXPECT_TRUE(memcmp(digest, ZIP244_EXPECTED_EMPTY_TRANSPARENT_DIGEST, 32) == + 0); +} + +TEST(Zcash, ComputeTransparentSighash_RejectsUnsupportedRequest) { + ZcashTransparentInputDigestInfo inputs[2] = {}; + ZcashTransparentOutputDigestInfo outputs[2] = {}; + uint8_t txid0[32], txid1[32], digest[32]; + make_zip244_transparent_fixture(inputs, outputs, txid0, txid1); + + EXPECT_FALSE(zcash_compute_transparent_sighash_digest(inputs, 2, outputs, 2, + 2, 0x01, digest)); + EXPECT_FALSE(zcash_compute_transparent_sighash_digest(inputs, 2, outputs, 2, + 0, 0x02, digest)); +} + +TEST(Zcash, ComputeTransparentSighash_CommitsToOutputScriptAndValue) { + ZcashTransparentInputDigestInfo inputs[2] = {}; + ZcashTransparentOutputDigestInfo outputs[2] = {}; + uint8_t txid0[32], txid1[32]; + make_zip244_transparent_fixture(inputs, outputs, txid0, txid1); + + uint8_t original[32] = {0}; + uint8_t changed_script[32] = {0}; + uint8_t changed_value[32] = {0}; + + ASSERT_TRUE(zcash_compute_transparent_sighash_digest(inputs, 2, outputs, 2, 0, + 0x01, original)); + + outputs[0].script_pubkey = ZIP244_P2SH_SCRIPT_44; + outputs[0].script_pubkey_size = sizeof(ZIP244_P2SH_SCRIPT_44); + ASSERT_TRUE(zcash_compute_transparent_sighash_digest(inputs, 2, outputs, 2, 0, + 0x01, changed_script)); + EXPECT_TRUE(memcmp(original, changed_script, 32) != 0); + + outputs[0].script_pubkey = ZIP244_P2PKH_SCRIPT_33; + outputs[0].script_pubkey_size = sizeof(ZIP244_P2PKH_SCRIPT_33); + outputs[0].value++; + ASSERT_TRUE(zcash_compute_transparent_sighash_digest(inputs, 2, outputs, 2, 0, + 0x01, changed_value)); + EXPECT_TRUE(memcmp(original, changed_value, 32) != 0); +} + +/* ── Sighash Computation Tests ───────────────────────────────────── */ + +TEST(Zcash, ComputeShieldedSighash_Deterministic) { + uint8_t header[32], transparent[32], sapling[32], orchard[32]; + memset(header, 0x01, 32); + memset(transparent, 0x02, 32); + memset(sapling, 0x03, 32); + memset(orchard, 0x04, 32); + + uint32_t branch_id = 0x37519621; /* NU5 */ + + uint8_t sighash1[32], sighash2[32]; + ASSERT_TRUE(zcash_compute_shielded_sighash(header, transparent, sapling, + orchard, branch_id, sighash1)); + ASSERT_TRUE(zcash_compute_shielded_sighash(header, transparent, sapling, + orchard, branch_id, sighash2)); + + EXPECT_TRUE(memcmp(sighash1, sighash2, 32) == 0) + << "Sighash must be deterministic"; +} + +TEST(Zcash, ComputeShieldedSighash_DifferentInputs) { + uint8_t header[32], transparent[32], sapling[32], orchard[32]; + memset(header, 0x01, 32); + memset(transparent, 0x02, 32); + memset(sapling, 0x03, 32); + memset(orchard, 0x04, 32); + + uint32_t branch_id = 0x37519621; + uint8_t sighash_a[32], sighash_b[32]; + + ASSERT_TRUE(zcash_compute_shielded_sighash(header, transparent, sapling, + orchard, branch_id, sighash_a)); + + /* Change one byte in the orchard digest */ + orchard[0] ^= 0xff; + ASSERT_TRUE(zcash_compute_shielded_sighash(header, transparent, sapling, + orchard, branch_id, sighash_b)); + + EXPECT_TRUE(memcmp(sighash_a, sighash_b, 32) != 0) + << "Different orchard digests must produce different sighashes"; +} + +TEST(Zcash, ComputeShieldedSighash_DifferentBranchId) { + uint8_t header[32], transparent[32], sapling[32], orchard[32]; + memset(header, 0x01, 32); + memset(transparent, 0x02, 32); + memset(sapling, 0x03, 32); + memset(orchard, 0x04, 32); + + uint8_t sighash_nu5[32], sighash_nu6[32]; + + ASSERT_TRUE(zcash_compute_shielded_sighash(header, transparent, sapling, + orchard, 0x37519621, sighash_nu5)); + ASSERT_TRUE(zcash_compute_shielded_sighash(header, transparent, sapling, + orchard, 0xC4D97411, sighash_nu6)); + + EXPECT_TRUE(memcmp(sighash_nu5, sighash_nu6, 32) != 0) + << "Different branch IDs must produce different sighashes"; +} + +TEST(Zcash, ComputeShieldedSighash_KnownVector) { + /* + * ZIP-244 sighash test vector. + * + * The sighash personalization is "ZcashTxHash_" || branch_id_LE. + * For NU5 (branch_id = 0x37519621): + * personalization = "ZcashTxHash_" || 0x21965137 + * + * Input: BLAKE2b-256(personalization, header || transparent || sapling || + * orchard) where each digest is 32 bytes of zeros. + */ + uint8_t header[32] = {0}; + uint8_t transparent[32] = {0}; + uint8_t sapling[32] = {0}; + uint8_t orchard[32] = {0}; + uint32_t branch_id = 0x37519621; + + uint8_t sighash[32]; + ASSERT_TRUE(zcash_compute_shielded_sighash(header, transparent, sapling, + orchard, branch_id, sighash)); + + /* + * Independently verified: BLAKE2b-256 with personalization + * "ZcashTxHash_\x21\x96\x51\x37" over 128 zero bytes. + * + * This is a self-consistency check — the value was computed by + * running the same BLAKE2b-256 offline. If the sighash function + * changes its algorithm, this test will catch it. + */ + uint8_t expected[32]; + BLAKE2B_CTX ctx; + uint8_t personal[16]; + memcpy(personal, "ZcashTxHash_", 12); + memcpy(personal + 12, &branch_id, 4); + blake2b_InitPersonal(&ctx, 32, personal, 16); + blake2b_Update(&ctx, header, 32); + blake2b_Update(&ctx, transparent, 32); + blake2b_Update(&ctx, sapling, 32); + blake2b_Update(&ctx, orchard, 32); + blake2b_Final(&ctx, expected, 32); + + EXPECT_TRUE(memcmp(sighash, expected, 32) == 0) + << "Sighash must match direct BLAKE2b computation"; +} + +/* ── RedPallas Signing Smoke Test ────────────────────────────────── */ + +TEST(Zcash, RedPallasSign_ProducesVerifiableSignature) { + ZcashOrchardKeys keys; + ASSERT_TRUE(zcash_derive_orchard_keys(SEED_ALL, 64, 0, &keys)); + + /* Construct a fake sighash and alpha */ + uint8_t sighash[32]; + memset(sighash, 0xAB, 32); + + uint8_t alpha[32]; + memset(alpha, 0x01, 32); + /* Ensure alpha is a valid scalar (< q) */ + alpha[31] = 0x00; + + uint8_t signature[64]; + int ret = redpallas_sign_digest(keys.ask, alpha, sighash, signature); + EXPECT_EQ(ret, 0) << "RedPallas signing must succeed"; + + /* Signature must be nonzero */ + uint8_t zero[64] = {0}; + EXPECT_TRUE(memcmp(signature, zero, 64) != 0) << "Signature must be nonzero"; + + /* + * Verify the signature against the randomized verification key rk. + * rk = [ask + alpha]*G_spendauth (Pallas SpendAuth basepoint) + */ + bignum256 ask_scalar, alpha_scalar, rk_scalar; + bn_read_le(keys.ask, &ask_scalar); + bn_read_le(alpha, &alpha_scalar); + + /* rk_scalar = ask + alpha mod q */ + bn_copy(&ask_scalar, &rk_scalar); + pallas_add_mod_q(&rk_scalar, &alpha_scalar); + + curve_point rk_point; + redpallas_scalar_mult_spendauth_G(&rk_scalar, &rk_point); + + /* Serialize rk as Pallas point (LE x-coord + sign bit) */ + uint8_t rk_bytes[32]; + bignum256 rk_x; + bn_copy(&rk_point.x, &rk_x); + bn_write_le(&rk_x, rk_bytes); + if (bn_is_odd(&rk_point.y)) { + rk_bytes[31] |= 0x80; + } + + /* Verify: redpallas_verify_digest(rk, sighash, sig) == 0 */ + EXPECT_EQ(redpallas_verify_digest(rk_bytes, sighash, signature), 0) + << "Signature must verify against rk = [ask+alpha]*G"; + + /* Verify fails with wrong sighash */ + uint8_t wrong_sighash[32]; + memset(wrong_sighash, 0xCC, 32); + EXPECT_NE(redpallas_verify_digest(rk_bytes, wrong_sighash, signature), 0) + << "Signature must NOT verify with wrong sighash"; + + memzero(&keys, sizeof(keys)); +} + +TEST(Zcash, RedPallasSign_MultipleCallsSucceed) { + /* + * RedPallas uses randomized nonces — signatures are intentionally + * non-deterministic. Verify that multiple calls all succeed and + * produce valid (nonzero) 64-byte signatures. + */ + ZcashOrchardKeys keys; + ASSERT_TRUE(zcash_derive_orchard_keys(SEED_ALL, 64, 0, &keys)); + + uint8_t sighash[32]; + memset(sighash, 0xCD, 32); + uint8_t alpha[32]; + memset(alpha, 0x02, 32); + alpha[31] = 0x00; + + uint8_t zero[64] = {0}; + for (int i = 0; i < 3; i++) { + uint8_t sig[64]; + ASSERT_EQ(redpallas_sign_digest(keys.ask, alpha, sighash, sig), 0) + << "Signing must succeed on call " << i; + EXPECT_TRUE(memcmp(sig, zero, 64) != 0) + << "Signature must be nonzero on call " << i; + } + + memzero(&keys, sizeof(keys)); +} + +TEST(Zcash, RedPallasSign_DifferentSighash) { + ZcashOrchardKeys keys; + ASSERT_TRUE(zcash_derive_orchard_keys(SEED_ALL, 64, 0, &keys)); + + uint8_t alpha[32]; + memset(alpha, 0x01, 32); + alpha[31] = 0x00; + + uint8_t sighash_a[32], sighash_b[32]; + memset(sighash_a, 0xAA, 32); + memset(sighash_b, 0xBB, 32); + + uint8_t sig_a[64], sig_b[64]; + ASSERT_EQ(redpallas_sign_digest(keys.ask, alpha, sighash_a, sig_a), 0); + ASSERT_EQ(redpallas_sign_digest(keys.ask, alpha, sighash_b, sig_b), 0); + + EXPECT_TRUE(memcmp(sig_a, sig_b, 64) != 0) + << "Different sighash must produce different signatures"; + + memzero(&keys, sizeof(keys)); +} + +/* ─── Seed Fingerprint (ZIP-32 §6.1) ─────────────────────────────── */ + +/* Reference vector: matches keystone3-firmware + * rust/keystore/src/algorithms/zcash/mod.rs test_keystore_derive_zcash_ufvk + * Seed: 000102...1f (32 bytes) + * Fingerprint: deff604c246710f7176dead02aa746f2fd8d5389f7072556dcb555fdbe5e3ae3 + */ +TEST(Zcash, SeedFingerprint_ReferenceVector) { + uint8_t seed[32]; + for (int i = 0; i < 32; i++) seed[i] = (uint8_t)i; + + uint8_t expected[32] = { + 0xde, 0xff, 0x60, 0x4c, 0x24, 0x67, 0x10, 0xf7, 0x17, 0x6d, 0xea, + 0xd0, 0x2a, 0xa7, 0x46, 0xf2, 0xfd, 0x8d, 0x53, 0x89, 0xf7, 0x07, + 0x25, 0x56, 0xdc, 0xb5, 0x55, 0xfd, 0xbe, 0x5e, 0x3a, 0xe3, + }; + + uint8_t fp[32]; + ASSERT_TRUE(zcash_calculate_seed_fingerprint(seed, 32, fp)); + EXPECT_EQ(memcmp(fp, expected, 32), 0); +} + +TEST(Zcash, SeedFingerprintRequestRequiresExactSizeWhenPresent) { + EXPECT_TRUE(zcash_seed_fingerprint_request_valid(false, 0)); + EXPECT_TRUE(zcash_seed_fingerprint_request_valid(true, 32)); + EXPECT_FALSE(zcash_seed_fingerprint_request_valid(true, 0)); + EXPECT_FALSE(zcash_seed_fingerprint_request_valid(true, 31)); + EXPECT_FALSE(zcash_seed_fingerprint_request_valid(true, 33)); +} + +TEST(Zcash, SeedFingerprint_RejectAllZero) { + uint8_t seed[32] = {0}; + uint8_t fp[32]; + EXPECT_FALSE(zcash_calculate_seed_fingerprint(seed, 32, fp)); +} + +TEST(Zcash, SeedFingerprint_RejectAllFF) { + uint8_t seed[32]; + memset(seed, 0xFF, 32); + uint8_t fp[32]; + EXPECT_FALSE(zcash_calculate_seed_fingerprint(seed, 32, fp)); +} + +TEST(Zcash, SeedFingerprint_RejectShortSeed) { + uint8_t seed[31]; + for (int i = 0; i < 31; i++) seed[i] = (uint8_t)(i + 1); + uint8_t fp[32]; + EXPECT_FALSE(zcash_calculate_seed_fingerprint(seed, 31, fp)); +} + +TEST(Zcash, SeedFingerprint_RejectLongSeed) { + uint8_t seed[253]; + for (int i = 0; i < 253; i++) seed[i] = (uint8_t)(i & 0xFF); + uint8_t fp[32]; + EXPECT_FALSE(zcash_calculate_seed_fingerprint(seed, 253, fp)); +} + +TEST(Zcash, SeedFingerprint_DeterministicAcrossCalls) { + uint8_t seed[64]; + for (int i = 0; i < 64; i++) seed[i] = (uint8_t)(0xAA ^ i); + + uint8_t fp_a[32], fp_b[32]; + ASSERT_TRUE(zcash_calculate_seed_fingerprint(seed, 64, fp_a)); + ASSERT_TRUE(zcash_calculate_seed_fingerprint(seed, 64, fp_b)); + EXPECT_EQ(memcmp(fp_a, fp_b, 32), 0); +} + +TEST(Zcash, SeedFingerprint_DiffersForDifferentSeeds) { + uint8_t seed_a[64]; + uint8_t seed_b[64]; + for (int i = 0; i < 64; i++) { + seed_a[i] = (uint8_t)i; + seed_b[i] = (uint8_t)(i + 1); + } + + uint8_t fp_a[32], fp_b[32]; + ASSERT_TRUE(zcash_calculate_seed_fingerprint(seed_a, 64, fp_a)); + ASSERT_TRUE(zcash_calculate_seed_fingerprint(seed_b, 64, fp_b)); + EXPECT_NE(memcmp(fp_a, fp_b, 32), 0); +} + +/* ===================================================================== * + * zcash_compute_orchard_transparent_sig_digest — ZIP-244 S.2/T.1 + * + * This is the site of the historical shield-fix (S.2 vs T.1 selection by + * vin count). It had no test caller, so a refactor could silently swap the + * two forms. These lock in: (a) empty-vin -> T.1 (equals the standalone + * transparent digest), (b) non-empty-vin -> S.2 (distinct from T.1 and + * stable), and (c) validation refusal on malformed info. + * ===================================================================== */ + +// A P2PKH-shaped script_pubkey (25 bytes) for the fixtures. +static const uint8_t kScriptPubkey[25] = { + 0x76, 0xa9, 0x14, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0x10, 0x11, 0x12, 0x13, 0x88, 0xac}; +static const uint8_t kPrevoutTxid[32] = { + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, + 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, + 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00}; + +// Empty vin (deshield): the Orchard transparent-sig digest is the T.1 form, +// which is exactly zcash_compute_transparent_digest over the same components. +TEST(Zcash, OrchardTransparentSigDigest_EmptyVinMatchesT1) { + ZcashTransparentOutputDigestInfo out = {/*value=*/50000, kScriptPubkey, + sizeof(kScriptPubkey)}; + + uint8_t s2_digest[32], t1_digest[32]; + ASSERT_TRUE(zcash_compute_orchard_transparent_sig_digest(nullptr, 0, &out, 1, + s2_digest)); + ASSERT_TRUE(zcash_compute_transparent_digest(nullptr, 0, &out, 1, t1_digest)); + EXPECT_EQ(memcmp(s2_digest, t1_digest, 32), 0); +} + +// Non-empty vin (shield): the S.2 form is used and MUST differ from the T.1 +// form over the identical inputs/outputs (the whole point of the shield fix), +// and it must be deterministic. +TEST(Zcash, OrchardTransparentSigDigest_NonEmptyVinIsS2NotT1) { + ZcashTransparentInputDigestInfo in = { + kPrevoutTxid, /*prevout_index=*/0, /*sequence=*/0xffffffff, + /*value=*/100000, kScriptPubkey, sizeof(kScriptPubkey)}; + ZcashTransparentOutputDigestInfo out = {/*value=*/50000, kScriptPubkey, + sizeof(kScriptPubkey)}; + + uint8_t s2_digest[32], t1_digest[32], s2_again[32]; + ASSERT_TRUE( + zcash_compute_orchard_transparent_sig_digest(&in, 1, &out, 1, s2_digest)); + ASSERT_TRUE(zcash_compute_transparent_digest(&in, 1, &out, 1, t1_digest)); + ASSERT_TRUE( + zcash_compute_orchard_transparent_sig_digest(&in, 1, &out, 1, s2_again)); + EXPECT_NE(memcmp(s2_digest, t1_digest, 32), 0); // S.2 != T.1 (the fix) + EXPECT_EQ(memcmp(s2_digest, s2_again, 32), 0); // deterministic +} + +// Malformed digest info (a nonzero script with a NULL pointer) is refused. +TEST(Zcash, OrchardTransparentSigDigest_RejectsMalformedInfo) { + ZcashTransparentOutputDigestInfo bad = {/*value=*/1, + /*script_pubkey=*/nullptr, + /*script_pubkey_size=*/25}; + uint8_t digest[32]; + EXPECT_FALSE(zcash_compute_orchard_transparent_sig_digest(nullptr, 0, &bad, 1, + digest)); +} From cb68d070189346ebeeb258efd28968866abfd1ac Mon Sep 17 00:00:00 2001 From: highlander Date: Sat, 25 Jul 2026 14:23:30 -0300 Subject: [PATCH 02/22] security(crypto): vendor audited trezor-crypto for rc18 Remove the trezor-firmware submodule dependency and vendor the audited crypto subtree with applicable upstream security backports, regression coverage, provenance documentation, and firmware cache clearing. --- .github/workflows/ci.yml | 44 +- .github/workflows/release.yml | 2 - .gitmodules | 3 - CMakeLists.txt | 4 +- deps/crypto/CMakeLists.txt | 138 +- deps/crypto/trezor-crypto/.gitignore | 9 + deps/crypto/trezor-crypto/AUTHORS | 2 + deps/crypto/trezor-crypto/CONTRIBUTORS | 16 + deps/crypto/trezor-crypto/KEEPKEY_VENDOR.md | 65 + deps/crypto/trezor-crypto/LICENSE | 22 + deps/crypto/trezor-crypto/Makefile | 138 + deps/crypto/trezor-crypto/README.md | 45 + .../trezor-crypto/SECURITY_BACKPORTS.md | 81 + deps/crypto/trezor-crypto/address.c | 91 + deps/crypto/trezor-crypto/address.h | 40 + deps/crypto/trezor-crypto/aes/aes.h | 226 + deps/crypto/trezor-crypto/aes/aes_modes.c | 957 ++ deps/crypto/trezor-crypto/aes/aescrypt.c | 307 + deps/crypto/trezor-crypto/aes/aeskey.c | 560 + deps/crypto/trezor-crypto/aes/aesopt.h | 789 ++ deps/crypto/trezor-crypto/aes/aestab.c | 417 + deps/crypto/trezor-crypto/aes/aestab.h | 173 + deps/crypto/trezor-crypto/aes/aestst.c | 182 + deps/crypto/trezor-crypto/aes/aestst.h | 85 + deps/crypto/trezor-crypto/base32.c | 241 + deps/crypto/trezor-crypto/base32.h | 44 + deps/crypto/trezor-crypto/base58.c | 274 + deps/crypto/trezor-crypto/base58.h | 53 + deps/crypto/trezor-crypto/bignum.c | 1833 ++++ deps/crypto/trezor-crypto/bignum.h | 166 + deps/crypto/trezor-crypto/bip32.c | 1045 ++ deps/crypto/trezor-crypto/bip32.h | 157 + deps/crypto/trezor-crypto/bip39.c | 323 + deps/crypto/trezor-crypto/bip39.h | 62 + deps/crypto/trezor-crypto/bip39_english.c | 4125 +++++++ deps/crypto/trezor-crypto/bip39_english.h | 24 + deps/crypto/trezor-crypto/blake256.c | 234 + deps/crypto/trezor-crypto/blake256.h | 53 + deps/crypto/trezor-crypto/blake2_common.h | 25 + deps/crypto/trezor-crypto/blake2b.c | 324 + deps/crypto/trezor-crypto/blake2b.h | 41 + deps/crypto/trezor-crypto/blake2s.c | 318 + deps/crypto/trezor-crypto/blake2s.h | 41 + deps/crypto/trezor-crypto/cash_addr.c | 193 + deps/crypto/trezor-crypto/cash_addr.h | 80 + .../chacha20poly1305/chacha20poly1305.c | 60 + .../chacha20poly1305/chacha20poly1305.h | 19 + .../chacha20poly1305/chacha_merged.c | 252 + .../chacha20poly1305/ecrypt-config.h | 316 + .../chacha20poly1305/ecrypt-machine.h | 49 + .../chacha20poly1305/ecrypt-portable.h | 275 + .../chacha20poly1305/ecrypt-sync.h | 290 + .../chacha20poly1305/ecrypt-types.h | 53 + .../chacha20poly1305/poly1305-donna-32.h | 218 + .../chacha20poly1305/poly1305-donna.c | 179 + .../chacha20poly1305/poly1305-donna.h | 19 + .../trezor-crypto/chacha20poly1305/rfc7539.c | 48 + .../trezor-crypto/chacha20poly1305/rfc7539.h | 10 + deps/crypto/trezor-crypto/chacha_drbg.c | 126 + deps/crypto/trezor-crypto/chacha_drbg.h | 54 + deps/crypto/trezor-crypto/check_mem.h | 30 + deps/crypto/trezor-crypto/curves.c | 39 + deps/crypto/trezor-crypto/curves.h | 44 + deps/crypto/trezor-crypto/ecdsa.c | 1265 +++ deps/crypto/trezor-crypto/ecdsa.h | 128 + .../trezor-crypto/ed25519-donna/README.md | 183 + .../ed25519-donna/curve25519-donna-32bit.c | 681 ++ .../ed25519-donna/curve25519-donna-32bit.h | 79 + .../ed25519-donna/curve25519-donna-helpers.c | 66 + .../ed25519-donna/curve25519-donna-helpers.h | 22 + .../curve25519-donna-scalarmult-base.c | 67 + .../curve25519-donna-scalarmult-base.h | 8 + .../ed25519-donna/ed25519-blake2b.c | 8 + .../ed25519-donna/ed25519-blake2b.h | 21 + .../ed25519-donna-32bit-tables.c | 63 + .../ed25519-donna-32bit-tables.h | 17 + .../ed25519-donna-basepoint-table.c | 261 + .../ed25519-donna-basepoint-table.h | 2 + .../ed25519-donna/ed25519-donna-impl-base.c | 751 ++ .../ed25519-donna/ed25519-donna-impl-base.h | 104 + .../ed25519-donna/ed25519-donna-portable.h | 24 + .../ed25519-donna/ed25519-donna.h | 52 + .../ed25519-hash-custom-blake2b.h | 23 + .../ed25519-hash-custom-keccak.h | 23 + .../ed25519-donna/ed25519-hash-custom-sha3.h | 23 + .../ed25519-donna/ed25519-hash-custom.h | 23 + .../ed25519-donna/ed25519-keccak.c | 8 + .../ed25519-donna/ed25519-keccak.h | 21 + .../ed25519-donna/ed25519-sha3.c | 8 + .../ed25519-donna/ed25519-sha3.h | 21 + .../trezor-crypto/ed25519-donna/ed25519.c | 377 + .../trezor-crypto/ed25519-donna/ed25519.h | 49 + .../ed25519-donna/modm-donna-32bit.c | 517 + .../ed25519-donna/modm-donna-32bit.h | 80 + deps/crypto/trezor-crypto/fuzzer/README.md | 67 + deps/crypto/trezor-crypto/fuzzer/fuzzer.c | 416 + deps/crypto/trezor-crypto/groestl.c | 787 ++ deps/crypto/trezor-crypto/groestl.h | 95 + deps/crypto/trezor-crypto/groestl_internal.h | 509 + deps/crypto/trezor-crypto/gui/.gitignore | 4 + deps/crypto/trezor-crypto/gui/gui.pro | 34 + deps/crypto/trezor-crypto/gui/main.cpp | 10 + deps/crypto/trezor-crypto/gui/mainwindow.cpp | 78 + deps/crypto/trezor-crypto/gui/mainwindow.h | 27 + deps/crypto/trezor-crypto/gui/mainwindow.ui | 161 + deps/crypto/trezor-crypto/hasher.c | 156 + deps/crypto/trezor-crypto/hasher.h | 86 + deps/crypto/trezor-crypto/hmac.c | 176 + deps/crypto/trezor-crypto/hmac.h | 60 + deps/crypto/trezor-crypto/hmac_drbg.c | 130 + deps/crypto/trezor-crypto/hmac_drbg.h | 43 + deps/crypto/trezor-crypto/memzero.c | 75 + deps/crypto/trezor-crypto/memzero.h | 8 + deps/crypto/trezor-crypto/monero/base58.c | 247 + deps/crypto/trezor-crypto/monero/base58.h | 43 + deps/crypto/trezor-crypto/monero/int-util.h | 77 + deps/crypto/trezor-crypto/monero/monero.h | 21 + .../crypto/trezor-crypto/monero/range_proof.c | 115 + .../crypto/trezor-crypto/monero/range_proof.h | 31 + deps/crypto/trezor-crypto/monero/serialize.c | 53 + deps/crypto/trezor-crypto/monero/serialize.h | 15 + deps/crypto/trezor-crypto/monero/xmr.c | 143 + deps/crypto/trezor-crypto/monero/xmr.h | 76 + deps/crypto/trezor-crypto/nano.c | 155 + deps/crypto/trezor-crypto/nano.h | 52 + deps/crypto/trezor-crypto/nem.c | 507 + deps/crypto/trezor-crypto/nem.h | 156 + deps/crypto/trezor-crypto/nist256p1.c | 69 + deps/crypto/trezor-crypto/nist256p1.h | 35 + deps/crypto/trezor-crypto/nist256p1.table | 1664 +++ deps/crypto/trezor-crypto/options.h | 99 + deps/crypto/trezor-crypto/pallas.c | 805 ++ deps/crypto/trezor-crypto/pallas.h | 107 + deps/crypto/trezor-crypto/pallas_sinsemilla.c | 274 + deps/crypto/trezor-crypto/pallas_sinsemilla.h | 66 + .../trezor-crypto/pallas_sinsemilla_table.inc | 1026 ++ deps/crypto/trezor-crypto/pallas_swu.c | 712 ++ deps/crypto/trezor-crypto/pallas_swu.h | 41 + deps/crypto/trezor-crypto/pbkdf2.c | 179 + deps/crypto/trezor-crypto/pbkdf2.h | 66 + deps/crypto/trezor-crypto/rand.c | 81 + deps/crypto/trezor-crypto/rand.h | 37 + deps/crypto/trezor-crypto/rc4.c | 56 + deps/crypto/trezor-crypto/rc4.h | 37 + deps/crypto/trezor-crypto/redpallas.c | 357 + deps/crypto/trezor-crypto/redpallas.h | 85 + deps/crypto/trezor-crypto/rfc6979.c | 62 + deps/crypto/trezor-crypto/rfc6979.h | 41 + deps/crypto/trezor-crypto/ripemd160.c | 343 + deps/crypto/trezor-crypto/ripemd160.h | 22 + deps/crypto/trezor-crypto/schnorr.c | 215 + deps/crypto/trezor-crypto/schnorr.h | 36 + deps/crypto/trezor-crypto/script.c | 66 + deps/crypto/trezor-crypto/script.h | 31 + deps/crypto/trezor-crypto/secp256k1.c | 94 + deps/crypto/trezor-crypto/secp256k1.h | 38 + deps/crypto/trezor-crypto/secp256k1.table | 1664 +++ deps/crypto/trezor-crypto/segwit_addr.c | 209 + deps/crypto/trezor-crypto/segwit_addr.h | 116 + deps/crypto/trezor-crypto/setup.py | 39 + deps/crypto/trezor-crypto/sha2.c | 1283 +++ deps/crypto/trezor-crypto/sha2.h | 116 + deps/crypto/trezor-crypto/sha3.c | 399 + deps/crypto/trezor-crypto/sha3.h | 89 + deps/crypto/trezor-crypto/shamir.c | 335 + deps/crypto/trezor-crypto/shamir.h | 70 + deps/crypto/trezor-crypto/slip39.c | 151 + deps/crypto/trezor-crypto/slip39.h | 39 + deps/crypto/trezor-crypto/slip39_wordlist.h | 1246 +++ .../crypto/trezor-crypto/tests/test_bignum.py | 1032 ++ deps/crypto/trezor-crypto/tests/test_check.c | 9514 +++++++++++++++++ .../trezor-crypto/tests/test_check_cardano.h | 468 + .../trezor-crypto/tests/test_check_cashaddr.h | 68 + .../trezor-crypto/tests/test_check_monero.h | 1180 ++ .../trezor-crypto/tests/test_check_nano.h | 111 + .../trezor-crypto/tests/test_check_segwit.h | 149 + .../crypto/trezor-crypto/tests/test_curves.py | 353 + .../crypto/trezor-crypto/tests/test_openssl.c | 143 + deps/crypto/trezor-crypto/tests/test_speed.c | 233 + .../trezor-crypto/tests/test_wycheproof.py | 721 ++ deps/crypto/trezor-crypto/tools/.gitignore | 3 + deps/crypto/trezor-crypto/tools/README.md | 54 + .../trezor-crypto/tools/bip39bruteforce.c | 100 + deps/crypto/trezor-crypto/tools/mktable.c | 69 + .../trezor-crypto/tools/nem_test_vectors.erb | 18 + .../trezor-crypto/tools/nem_test_vectors.rb | 126 + deps/crypto/trezor-crypto/tools/xpubaddrgen.c | 48 + deps/crypto/trezor-crypto/zcash_zip316.c | 271 + deps/crypto/trezor-crypto/zcash_zip316.h | 37 + deps/crypto/trezor-firmware | 1 - include/trezor/crypto | 2 +- lib/firmware/fsm_msg_solana.h | 3 +- lib/firmware/solana.c | 5 +- lib/firmware/storage.c | 6 + lib/firmware/ton.c | 4 +- unittests/crypto/CMakeLists.txt | 4 +- 196 files changed, 52847 insertions(+), 97 deletions(-) create mode 100644 deps/crypto/trezor-crypto/.gitignore create mode 100644 deps/crypto/trezor-crypto/AUTHORS create mode 100644 deps/crypto/trezor-crypto/CONTRIBUTORS create mode 100644 deps/crypto/trezor-crypto/KEEPKEY_VENDOR.md create mode 100644 deps/crypto/trezor-crypto/LICENSE create mode 100644 deps/crypto/trezor-crypto/Makefile create mode 100644 deps/crypto/trezor-crypto/README.md create mode 100644 deps/crypto/trezor-crypto/SECURITY_BACKPORTS.md create mode 100644 deps/crypto/trezor-crypto/address.c create mode 100644 deps/crypto/trezor-crypto/address.h create mode 100644 deps/crypto/trezor-crypto/aes/aes.h create mode 100644 deps/crypto/trezor-crypto/aes/aes_modes.c create mode 100644 deps/crypto/trezor-crypto/aes/aescrypt.c create mode 100644 deps/crypto/trezor-crypto/aes/aeskey.c create mode 100644 deps/crypto/trezor-crypto/aes/aesopt.h create mode 100644 deps/crypto/trezor-crypto/aes/aestab.c create mode 100644 deps/crypto/trezor-crypto/aes/aestab.h create mode 100644 deps/crypto/trezor-crypto/aes/aestst.c create mode 100644 deps/crypto/trezor-crypto/aes/aestst.h create mode 100644 deps/crypto/trezor-crypto/base32.c create mode 100644 deps/crypto/trezor-crypto/base32.h create mode 100644 deps/crypto/trezor-crypto/base58.c create mode 100644 deps/crypto/trezor-crypto/base58.h create mode 100644 deps/crypto/trezor-crypto/bignum.c create mode 100644 deps/crypto/trezor-crypto/bignum.h create mode 100644 deps/crypto/trezor-crypto/bip32.c create mode 100644 deps/crypto/trezor-crypto/bip32.h create mode 100644 deps/crypto/trezor-crypto/bip39.c create mode 100644 deps/crypto/trezor-crypto/bip39.h create mode 100644 deps/crypto/trezor-crypto/bip39_english.c create mode 100644 deps/crypto/trezor-crypto/bip39_english.h create mode 100644 deps/crypto/trezor-crypto/blake256.c create mode 100644 deps/crypto/trezor-crypto/blake256.h create mode 100644 deps/crypto/trezor-crypto/blake2_common.h create mode 100644 deps/crypto/trezor-crypto/blake2b.c create mode 100644 deps/crypto/trezor-crypto/blake2b.h create mode 100644 deps/crypto/trezor-crypto/blake2s.c create mode 100644 deps/crypto/trezor-crypto/blake2s.h create mode 100644 deps/crypto/trezor-crypto/cash_addr.c create mode 100644 deps/crypto/trezor-crypto/cash_addr.h create mode 100644 deps/crypto/trezor-crypto/chacha20poly1305/chacha20poly1305.c create mode 100644 deps/crypto/trezor-crypto/chacha20poly1305/chacha20poly1305.h create mode 100644 deps/crypto/trezor-crypto/chacha20poly1305/chacha_merged.c create mode 100644 deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-config.h create mode 100644 deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-machine.h create mode 100644 deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-portable.h create mode 100644 deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-sync.h create mode 100644 deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-types.h create mode 100644 deps/crypto/trezor-crypto/chacha20poly1305/poly1305-donna-32.h create mode 100644 deps/crypto/trezor-crypto/chacha20poly1305/poly1305-donna.c create mode 100644 deps/crypto/trezor-crypto/chacha20poly1305/poly1305-donna.h create mode 100644 deps/crypto/trezor-crypto/chacha20poly1305/rfc7539.c create mode 100644 deps/crypto/trezor-crypto/chacha20poly1305/rfc7539.h create mode 100644 deps/crypto/trezor-crypto/chacha_drbg.c create mode 100644 deps/crypto/trezor-crypto/chacha_drbg.h create mode 100644 deps/crypto/trezor-crypto/check_mem.h create mode 100644 deps/crypto/trezor-crypto/curves.c create mode 100644 deps/crypto/trezor-crypto/curves.h create mode 100644 deps/crypto/trezor-crypto/ecdsa.c create mode 100644 deps/crypto/trezor-crypto/ecdsa.h create mode 100644 deps/crypto/trezor-crypto/ed25519-donna/README.md create mode 100644 deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-32bit.c create mode 100644 deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-32bit.h create mode 100644 deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-helpers.c create mode 100644 deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-helpers.h create mode 100644 deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-scalarmult-base.c create mode 100644 deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-scalarmult-base.h create mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-blake2b.c create mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-blake2b.h create mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-32bit-tables.c create mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-32bit-tables.h create mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-basepoint-table.c create mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-basepoint-table.h create mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-impl-base.c create mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-impl-base.h create mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-portable.h create mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna.h create mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom-blake2b.h create mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom-keccak.h create mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom-sha3.h create mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom.h create mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-keccak.c create mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-keccak.h create mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-sha3.c create mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-sha3.h create mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519.c create mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519.h create mode 100644 deps/crypto/trezor-crypto/ed25519-donna/modm-donna-32bit.c create mode 100644 deps/crypto/trezor-crypto/ed25519-donna/modm-donna-32bit.h create mode 100644 deps/crypto/trezor-crypto/fuzzer/README.md create mode 100644 deps/crypto/trezor-crypto/fuzzer/fuzzer.c create mode 100644 deps/crypto/trezor-crypto/groestl.c create mode 100644 deps/crypto/trezor-crypto/groestl.h create mode 100644 deps/crypto/trezor-crypto/groestl_internal.h create mode 100644 deps/crypto/trezor-crypto/gui/.gitignore create mode 100644 deps/crypto/trezor-crypto/gui/gui.pro create mode 100644 deps/crypto/trezor-crypto/gui/main.cpp create mode 100644 deps/crypto/trezor-crypto/gui/mainwindow.cpp create mode 100644 deps/crypto/trezor-crypto/gui/mainwindow.h create mode 100644 deps/crypto/trezor-crypto/gui/mainwindow.ui create mode 100644 deps/crypto/trezor-crypto/hasher.c create mode 100644 deps/crypto/trezor-crypto/hasher.h create mode 100644 deps/crypto/trezor-crypto/hmac.c create mode 100644 deps/crypto/trezor-crypto/hmac.h create mode 100644 deps/crypto/trezor-crypto/hmac_drbg.c create mode 100644 deps/crypto/trezor-crypto/hmac_drbg.h create mode 100644 deps/crypto/trezor-crypto/memzero.c create mode 100644 deps/crypto/trezor-crypto/memzero.h create mode 100644 deps/crypto/trezor-crypto/monero/base58.c create mode 100644 deps/crypto/trezor-crypto/monero/base58.h create mode 100644 deps/crypto/trezor-crypto/monero/int-util.h create mode 100644 deps/crypto/trezor-crypto/monero/monero.h create mode 100644 deps/crypto/trezor-crypto/monero/range_proof.c create mode 100644 deps/crypto/trezor-crypto/monero/range_proof.h create mode 100644 deps/crypto/trezor-crypto/monero/serialize.c create mode 100644 deps/crypto/trezor-crypto/monero/serialize.h create mode 100644 deps/crypto/trezor-crypto/monero/xmr.c create mode 100644 deps/crypto/trezor-crypto/monero/xmr.h create mode 100644 deps/crypto/trezor-crypto/nano.c create mode 100644 deps/crypto/trezor-crypto/nano.h create mode 100644 deps/crypto/trezor-crypto/nem.c create mode 100644 deps/crypto/trezor-crypto/nem.h create mode 100644 deps/crypto/trezor-crypto/nist256p1.c create mode 100644 deps/crypto/trezor-crypto/nist256p1.h create mode 100644 deps/crypto/trezor-crypto/nist256p1.table create mode 100644 deps/crypto/trezor-crypto/options.h create mode 100644 deps/crypto/trezor-crypto/pallas.c create mode 100644 deps/crypto/trezor-crypto/pallas.h create mode 100644 deps/crypto/trezor-crypto/pallas_sinsemilla.c create mode 100644 deps/crypto/trezor-crypto/pallas_sinsemilla.h create mode 100644 deps/crypto/trezor-crypto/pallas_sinsemilla_table.inc create mode 100644 deps/crypto/trezor-crypto/pallas_swu.c create mode 100644 deps/crypto/trezor-crypto/pallas_swu.h create mode 100644 deps/crypto/trezor-crypto/pbkdf2.c create mode 100644 deps/crypto/trezor-crypto/pbkdf2.h create mode 100644 deps/crypto/trezor-crypto/rand.c create mode 100644 deps/crypto/trezor-crypto/rand.h create mode 100644 deps/crypto/trezor-crypto/rc4.c create mode 100644 deps/crypto/trezor-crypto/rc4.h create mode 100644 deps/crypto/trezor-crypto/redpallas.c create mode 100644 deps/crypto/trezor-crypto/redpallas.h create mode 100644 deps/crypto/trezor-crypto/rfc6979.c create mode 100644 deps/crypto/trezor-crypto/rfc6979.h create mode 100644 deps/crypto/trezor-crypto/ripemd160.c create mode 100644 deps/crypto/trezor-crypto/ripemd160.h create mode 100644 deps/crypto/trezor-crypto/schnorr.c create mode 100644 deps/crypto/trezor-crypto/schnorr.h create mode 100644 deps/crypto/trezor-crypto/script.c create mode 100644 deps/crypto/trezor-crypto/script.h create mode 100644 deps/crypto/trezor-crypto/secp256k1.c create mode 100644 deps/crypto/trezor-crypto/secp256k1.h create mode 100644 deps/crypto/trezor-crypto/secp256k1.table create mode 100644 deps/crypto/trezor-crypto/segwit_addr.c create mode 100644 deps/crypto/trezor-crypto/segwit_addr.h create mode 100755 deps/crypto/trezor-crypto/setup.py create mode 100644 deps/crypto/trezor-crypto/sha2.c create mode 100644 deps/crypto/trezor-crypto/sha2.h create mode 100644 deps/crypto/trezor-crypto/sha3.c create mode 100644 deps/crypto/trezor-crypto/sha3.h create mode 100644 deps/crypto/trezor-crypto/shamir.c create mode 100644 deps/crypto/trezor-crypto/shamir.h create mode 100644 deps/crypto/trezor-crypto/slip39.c create mode 100644 deps/crypto/trezor-crypto/slip39.h create mode 100644 deps/crypto/trezor-crypto/slip39_wordlist.h create mode 100755 deps/crypto/trezor-crypto/tests/test_bignum.py create mode 100644 deps/crypto/trezor-crypto/tests/test_check.c create mode 100644 deps/crypto/trezor-crypto/tests/test_check_cardano.h create mode 100644 deps/crypto/trezor-crypto/tests/test_check_cashaddr.h create mode 100644 deps/crypto/trezor-crypto/tests/test_check_monero.h create mode 100644 deps/crypto/trezor-crypto/tests/test_check_nano.h create mode 100644 deps/crypto/trezor-crypto/tests/test_check_segwit.h create mode 100755 deps/crypto/trezor-crypto/tests/test_curves.py create mode 100644 deps/crypto/trezor-crypto/tests/test_openssl.c create mode 100644 deps/crypto/trezor-crypto/tests/test_speed.c create mode 100755 deps/crypto/trezor-crypto/tests/test_wycheproof.py create mode 100644 deps/crypto/trezor-crypto/tools/.gitignore create mode 100644 deps/crypto/trezor-crypto/tools/README.md create mode 100644 deps/crypto/trezor-crypto/tools/bip39bruteforce.c create mode 100644 deps/crypto/trezor-crypto/tools/mktable.c create mode 100644 deps/crypto/trezor-crypto/tools/nem_test_vectors.erb create mode 100755 deps/crypto/trezor-crypto/tools/nem_test_vectors.rb create mode 100644 deps/crypto/trezor-crypto/tools/xpubaddrgen.c create mode 100644 deps/crypto/trezor-crypto/zcash_zip316.c create mode 100644 deps/crypto/trezor-crypto/zcash_zip316.h delete mode 160000 deps/crypto/trezor-firmware diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4f433560c..adc1b2d94 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,6 +5,7 @@ # Stage 1: GATE (seconds, no Docker) # ├─ lint-format clang-format diff check # ├─ static-analysis cppcheck static analysis +# ├─ crypto-tests vendored trezor-crypto vectors + ASan/UBSan # ├─ secret-scan gitleaks credential detection # └─ check-submodules verify all deps present # @@ -122,7 +123,7 @@ jobs: --inline-suppr \ --suppressions-list=.cppcheck-suppressions \ -I include \ - -I deps/crypto/trezor-firmware/crypto \ + -I deps/crypto/trezor-crypto \ -I deps/device-protocol \ -DSTM32F2=1 \ -DUSE_ETHEREUM=1 \ @@ -190,7 +191,6 @@ jobs: run: | echo "Checking required submodule declarations..." REQUIRED=( - "deps/crypto/trezor-firmware" "deps/device-protocol" "deps/python-keepkey" "deps/googletest" @@ -208,13 +208,41 @@ jobs: done [ "$FAILED" = "0" ] || exit 1 + crypto-tests: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + + - name: Install crypto test dependencies + run: sudo apt-get update && sudo apt-get install -y check libssl-dev pkg-config + + - name: Run optimized crypto suite + working-directory: deps/crypto/trezor-crypto + run: | + make clean + make VALGRIND=0 tests/test_check + ./tests/test_check + + - name: Run crypto suite with ASan and UBSan + working-directory: deps/crypto/trezor-crypto + run: | + make clean + make CC='gcc -fsanitize=address,undefined' VALGRIND=0 \ + OPTFLAGS='-O1 -g -fno-omit-frame-pointer' tests/test_check + ASAN_OPTIONS=detect_leaks=0:halt_on_error=1 \ + UBSAN_OPTIONS=halt_on_error=1 ./tests/test_check + # ═══════════════════════════════════════════════════════════ # STAGE 2: BUILD — compile only after gate passes # ═══════════════════════════════════════════════════════════ build-emulator: name: build-emulator${{ matrix.label }} - needs: [lint-format, static-analysis, check-submodules, secret-scan] + needs: [lint-format, static-analysis, check-submodules, secret-scan, crypto-tests] runs-on: ubuntu-latest timeout-minutes: 15 strategy: @@ -237,7 +265,6 @@ jobs: - name: Init submodules run: | - git submodule update --init deps/crypto/trezor-firmware git submodule update --init deps/device-protocol git submodule update --init --recursive deps/python-keepkey git submodule update --init deps/googletest @@ -284,7 +311,7 @@ jobs: build-arm-firmware: name: build-arm-firmware${{ matrix.label }} - needs: [lint-format, static-analysis, check-submodules, secret-scan] + needs: [lint-format, static-analysis, check-submodules, secret-scan, crypto-tests] runs-on: ubuntu-latest timeout-minutes: 15 strategy: @@ -305,7 +332,6 @@ jobs: - name: Init submodules run: | - git submodule update --init deps/crypto/trezor-firmware git submodule update --init deps/device-protocol git submodule update --init --recursive deps/python-keepkey git submodule update --init deps/googletest @@ -448,7 +474,7 @@ jobs: retention-days: 30 python-integration-tests: - needs: [lint-format, static-analysis, check-submodules, secret-scan] + needs: [lint-format, static-analysis, check-submodules, secret-scan, crypto-tests] runs-on: ubuntu-latest timeout-minutes: 30 steps: @@ -459,7 +485,6 @@ jobs: - name: Init submodules run: | - git submodule update --init deps/crypto/trezor-firmware git submodule update --init deps/device-protocol git submodule update --init --recursive deps/python-keepkey git submodule update --init deps/googletest @@ -553,7 +578,7 @@ jobs: # fsm_msgDebugLinkGetState is excluded from the build and any # read_layout() call hangs the test). python-dylib-tests: - needs: [lint-format, static-analysis, check-submodules, secret-scan] + needs: [lint-format, static-analysis, check-submodules, secret-scan, crypto-tests] runs-on: macos-latest timeout-minutes: 25 steps: @@ -564,7 +589,6 @@ jobs: - name: Init submodules run: | - git submodule update --init deps/crypto/trezor-firmware git submodule update --init deps/device-protocol git submodule update --init --recursive deps/python-keepkey git submodule update --init deps/qrenc/QR-Code-generator diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5603f459b..dffe07f07 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -96,7 +96,6 @@ jobs: - name: Init required submodules run: | - git submodule update --init deps/crypto/trezor-firmware git submodule update --init deps/device-protocol git submodule update --init --recursive deps/python-keepkey git submodule update --init deps/googletest @@ -202,7 +201,6 @@ jobs: - name: Init required submodules run: | - git submodule update --init deps/crypto/trezor-firmware git submodule update --init deps/device-protocol git submodule update --init --recursive deps/python-keepkey git submodule update --init deps/googletest diff --git a/.gitmodules b/.gitmodules index b8d6fe804..873868109 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,9 +2,6 @@ path = deps/device-protocol url = https://github.com/keepkey/device-protocol.git branch = up/release-protocol -[submodule "deps/trezor-firmware"] -path = deps/crypto/trezor-firmware -url = https://github.com/keepkey/trezor-firmware.git [submodule "googletest"] path = deps/googletest url = https://github.com/google/googletest.git diff --git a/CMakeLists.txt b/CMakeLists.txt index a2d8d7979..be14c23c2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,10 +69,10 @@ if(NOT EXISTS ${CMAKE_SOURCE_DIR}/deps/googletest/CMakeLists.txt) "googletest missing. Need to 'git submodule update --init --recursive") endif() -if(NOT EXISTS ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-firmware/crypto/Makefile) +if(NOT EXISTS ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-crypto/Makefile) message( FATAL_ERROR - " trezor-crypto missing. Need to 'git submodule update --init --recursive" + " vendored trezor-crypto missing from deps/crypto/trezor-crypto" ) endif() diff --git a/deps/crypto/CMakeLists.txt b/deps/crypto/CMakeLists.txt index 47ca306f2..8df7775cc 100644 --- a/deps/crypto/CMakeLists.txt +++ b/deps/crypto/CMakeLists.txt @@ -1,86 +1,86 @@ set(sources - trezor-firmware/crypto/bip39.c - trezor-firmware/crypto/bip39_english.c - trezor-firmware/crypto/hmac.c - trezor-firmware/crypto/hmac_drbg.c - trezor-firmware/crypto/sha2.c - trezor-firmware/crypto/base32.c - trezor-firmware/crypto/hasher.c - #trezor-firmware/crypto/tools/bip39bruteforce.c - #trezor-firmware/crypto/tools/mktable.c - #trezor-firmware/crypto/tools/xpubaddrgen.c - trezor-firmware/crypto/rand.c - trezor-firmware/crypto/rc4.c - trezor-firmware/crypto/blake256.c - trezor-firmware/crypto/cash_addr.c - trezor-firmware/crypto/curves.c - trezor-firmware/crypto/rfc6979.c - trezor-firmware/crypto/ed25519-donna/curve25519-donna-scalarmult-base.c - trezor-firmware/crypto/ed25519-donna/ed25519-donna-32bit-tables.c - trezor-firmware/crypto/ed25519-donna/ed25519.c - trezor-firmware/crypto/ed25519-donna/curve25519-donna-helpers.c - trezor-firmware/crypto/ed25519-donna/ed25519-blake2b.c - trezor-firmware/crypto/ed25519-donna/ed25519-keccak.c - trezor-firmware/crypto/ed25519-donna/ed25519-sha3.c - trezor-firmware/crypto/ed25519-donna/ed25519-donna-basepoint-table.c - trezor-firmware/crypto/ed25519-donna/modm-donna-32bit.c - trezor-firmware/crypto/ed25519-donna/curve25519-donna-32bit.c - trezor-firmware/crypto/ed25519-donna/ed25519-donna-impl-base.c - trezor-firmware/crypto/nem.c - trezor-firmware/crypto/nano.c - #trezor-firmware/crypto/tests/test_check.c - #trezor-firmware/crypto/tests/test_openssl.c - #trezor-firmware/crypto/tests/test_speed.c - trezor-firmware/crypto/secp256k1.c - trezor-firmware/crypto/bignum.c - trezor-firmware/crypto/segwit_addr.c - trezor-firmware/crypto/ripemd160.c - trezor-firmware/crypto/groestl.c - trezor-firmware/crypto/nist256p1.c - #trezor-firmware/crypto/monero/serialize.c - #trezor-firmware/crypto/monero/range_proof.c - #trezor-firmware/crypto/monero/xmr.c - #trezor-firmware/crypto/monero/base58.c - trezor-firmware/crypto/memzero.c - trezor-firmware/crypto/blake2b.c - trezor-firmware/crypto/script.c - trezor-firmware/crypto/bip32.c - trezor-firmware/crypto/address.c - trezor-firmware/crypto/blake2s.c - trezor-firmware/crypto/sha3.c - trezor-firmware/crypto/base58.c - trezor-firmware/crypto/ecdsa.c - trezor-firmware/crypto/pbkdf2.c - trezor-firmware/crypto/aes/aeskey.c - trezor-firmware/crypto/aes/aescrypt.c - trezor-firmware/crypto/aes/aes_modes.c - #trezor-firmware/crypto/aes/aestst.c - trezor-firmware/crypto/aes/aestab.c) + trezor-crypto/bip39.c + trezor-crypto/bip39_english.c + trezor-crypto/hmac.c + trezor-crypto/hmac_drbg.c + trezor-crypto/sha2.c + trezor-crypto/base32.c + trezor-crypto/hasher.c + #trezor-crypto/tools/bip39bruteforce.c + #trezor-crypto/tools/mktable.c + #trezor-crypto/tools/xpubaddrgen.c + trezor-crypto/rand.c + trezor-crypto/rc4.c + trezor-crypto/blake256.c + trezor-crypto/cash_addr.c + trezor-crypto/curves.c + trezor-crypto/rfc6979.c + trezor-crypto/ed25519-donna/curve25519-donna-scalarmult-base.c + trezor-crypto/ed25519-donna/ed25519-donna-32bit-tables.c + trezor-crypto/ed25519-donna/ed25519.c + trezor-crypto/ed25519-donna/curve25519-donna-helpers.c + trezor-crypto/ed25519-donna/ed25519-blake2b.c + trezor-crypto/ed25519-donna/ed25519-keccak.c + trezor-crypto/ed25519-donna/ed25519-sha3.c + trezor-crypto/ed25519-donna/ed25519-donna-basepoint-table.c + trezor-crypto/ed25519-donna/modm-donna-32bit.c + trezor-crypto/ed25519-donna/curve25519-donna-32bit.c + trezor-crypto/ed25519-donna/ed25519-donna-impl-base.c + trezor-crypto/nem.c + trezor-crypto/nano.c + #trezor-crypto/tests/test_check.c + #trezor-crypto/tests/test_openssl.c + #trezor-crypto/tests/test_speed.c + trezor-crypto/secp256k1.c + trezor-crypto/bignum.c + trezor-crypto/segwit_addr.c + trezor-crypto/ripemd160.c + trezor-crypto/groestl.c + trezor-crypto/nist256p1.c + #trezor-crypto/monero/serialize.c + #trezor-crypto/monero/range_proof.c + #trezor-crypto/monero/xmr.c + #trezor-crypto/monero/base58.c + trezor-crypto/memzero.c + trezor-crypto/blake2b.c + trezor-crypto/script.c + trezor-crypto/bip32.c + trezor-crypto/address.c + trezor-crypto/blake2s.c + trezor-crypto/sha3.c + trezor-crypto/base58.c + trezor-crypto/ecdsa.c + trezor-crypto/pbkdf2.c + trezor-crypto/aes/aeskey.c + trezor-crypto/aes/aescrypt.c + trezor-crypto/aes/aes_modes.c + #trezor-crypto/aes/aestst.c + trezor-crypto/aes/aestab.c) # Pallas/Orchard curve arithmetic (~2.4k LOC) -- only the Zcash shielded engine # uses it. Excluded from the default and bitcoin-only images. if(${KK_ZCASH_PRIVACY}) list(APPEND sources - trezor-firmware/crypto/pallas.c - trezor-firmware/crypto/pallas_sinsemilla.c - trezor-firmware/crypto/pallas_swu.c - trezor-firmware/crypto/redpallas.c - trezor-firmware/crypto/zcash_zip316.c) + trezor-crypto/pallas.c + trezor-crypto/pallas_sinsemilla.c + trezor-crypto/pallas_swu.c + trezor-crypto/redpallas.c + trezor-crypto/zcash_zip316.c) endif() # Clang 5.0 in the docker image (kktech/firmware:v7) is missing # , which breaks these. Until they're needed, we'll just elide # them. - #trezor-firmware/crypto/chacha20poly1305/chacha_merged.c - #trezor-firmware/crypto/chacha20poly1305/rfc7539.c - #trezor-firmware/crypto/chacha20poly1305/poly1305-donna.c - #trezor-firmware/crypto/chacha20poly1305/chacha20poly1305.c + #trezor-crypto/chacha20poly1305/chacha_merged.c + #trezor-crypto/chacha20poly1305/rfc7539.c + #trezor-crypto/chacha20poly1305/poly1305-donna.c + #trezor-crypto/chacha20poly1305/chacha20poly1305.c include_directories( - ${CMAKE_CURRENT_SOURCE_DIR}/trezor-firmware/crypto - ${CMAKE_CURRENT_SOURCE_DIR}/trezor-firmware/ - ${CMAKE_CURRENT_SOURCE_DIR}/trezor-firmware/crypto/ed25519-donna + ${CMAKE_CURRENT_SOURCE_DIR}/trezor-crypto + ${CMAKE_CURRENT_SOURCE_DIR}/trezor-crypto/ + ${CMAKE_CURRENT_SOURCE_DIR}/trezor-crypto/ed25519-donna ${OPENSSL_INCLUDE_DIR}) diff --git a/deps/crypto/trezor-crypto/.gitignore b/deps/crypto/trezor-crypto/.gitignore new file mode 100644 index 000000000..5037519b3 --- /dev/null +++ b/deps/crypto/trezor-crypto/.gitignore @@ -0,0 +1,9 @@ +*.d +*.exe +*.o +*.os +tests/aestst +tests/libtrezor-crypto.so +tests/test_check +tests/test_openssl +tests/test_speed diff --git a/deps/crypto/trezor-crypto/AUTHORS b/deps/crypto/trezor-crypto/AUTHORS new file mode 100644 index 000000000..51c9bdab0 --- /dev/null +++ b/deps/crypto/trezor-crypto/AUTHORS @@ -0,0 +1,2 @@ +Tomas Dzetkulic +Pavol Rusnak diff --git a/deps/crypto/trezor-crypto/CONTRIBUTORS b/deps/crypto/trezor-crypto/CONTRIBUTORS new file mode 100644 index 000000000..300b9788d --- /dev/null +++ b/deps/crypto/trezor-crypto/CONTRIBUTORS @@ -0,0 +1,16 @@ +Tomas Dzetkulic +Pavol Rusnak +Jochen Hoenicke +Dustin Laurence +Ondrej Mikle +Roman Zeyde +Alex Beregszaszi +netanelkl +Jan Pochyla +Ondrej Mikle +Josh Billings +Adam Mackler +Oleg Andreev +mog +John Dvorak +Christian Reitter diff --git a/deps/crypto/trezor-crypto/KEEPKEY_VENDOR.md b/deps/crypto/trezor-crypto/KEEPKEY_VENDOR.md new file mode 100644 index 000000000..f863e94f7 --- /dev/null +++ b/deps/crypto/trezor-crypto/KEEPKEY_VENDOR.md @@ -0,0 +1,65 @@ +# KeepKey vendored trezor-crypto + +This directory is a direct, in-tree firmware dependency. It replaces the +`deps/crypto/trezor-firmware` submodule so that a KeepKey release no longer +depends on an unrelated Trezor monorepo fork. + +## Provenance + +- Previous RC18 crypto pin: `keepkey/trezor-firmware@0837875b9f5ce29f5d29f2a8ad3798787bd25b61` +- Vendoring baseline: `keepkey/trezor-firmware@56f404e452bc7738cd3b3e14454dfecb25c083bf` +- Upstream audit reference: `trezor/trezor-firmware@90e07df6c8b85ff3dc41f502de9dfff21493671b` +- Audit date: 2026-07-25 +- License: MIT; see `LICENSE` + +The vendoring baseline contains the KeepKey AES-small-tables and +Orchard/Pallas work. The source in this directory additionally contains the +security backports and KeepKey adaptations recorded in +`SECURITY_BACKPORTS.md`. + +The complete `crypto/` subtree is retained, including its tests. No Trezor +Core, Legacy firmware, Python client, storage implementation, CI, or other +monorepo component is vendored. + +## Updating + +Do not merge the current Trezor monorepo into this directory for version +optics. Audit crypto changes explicitly: + +1. Fetch `https://github.com/trezor/trezor-firmware.git`. +2. Review `git log --no-merges ..upstream/main -- crypto`. +3. Classify each correctness or security change for the KeepKey build and + document the decision in `SECURITY_BACKPORTS.md`. +4. Apply applicable changes to an isolated crypto worktree, preserving + upstream commit IDs in commit messages. +5. Run the standalone optimized and sanitizer suites below. +6. Replace this directory from the tested worktree and run both full firmware + variants before opening a PR. + +The upstream monorepo had diverged by 7,996 commits and 5,494 files at this +audit point. A mechanical merge was possible but was not treated as a +security review. + +## Standalone verification + +On macOS with Homebrew `check` installed: + +```sh +make clean +make VALGRIND=0 \ + OPTFLAGS='-O3 -g -I/opt/homebrew/include -Wno-error=unterminated-string-initialization' \ + tests/test_check +./tests/test_check +``` + +ASan and UBSan: + +```sh +make clean +make CC='clang -fsanitize=address,undefined' VALGRIND=0 \ + OPTFLAGS='-O1 -g -fno-omit-frame-pointer -I/opt/homebrew/include -Wno-error=unterminated-string-initialization -Wno-error=deprecated-declarations' \ + tests/test_check +ASAN_OPTIONS=halt_on_error=1 UBSAN_OPTIONS=halt_on_error=1 ./tests/test_check +``` + +The vendoring audit passed 158 checks in both configurations. diff --git a/deps/crypto/trezor-crypto/LICENSE b/deps/crypto/trezor-crypto/LICENSE new file mode 100644 index 000000000..1ea1df703 --- /dev/null +++ b/deps/crypto/trezor-crypto/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2013 Tomas Dzetkulic +Copyright (c) 2013 Pavol Rusnak + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/deps/crypto/trezor-crypto/Makefile b/deps/crypto/trezor-crypto/Makefile new file mode 100644 index 000000000..6c8fc9427 --- /dev/null +++ b/deps/crypto/trezor-crypto/Makefile @@ -0,0 +1,138 @@ +ifeq ($(FUZZER),1) +CC ?= clang +LD ?= $(CC) + +SANFLAGS += -fsanitize=fuzzer + +CFLAGS += $(SANFLAGS) +LDFLAGS += $(SANFLAGS) +endif + +CC ?= gcc + +OPTFLAGS ?= -O3 -g + +CFLAGS += $(OPTFLAGS) \ + -std=gnu99 \ + -W \ + -Wall \ + -Wextra \ + -Wimplicit-function-declaration \ + -Wredundant-decls \ + -Wstrict-prototypes \ + -Wundef \ + -Wshadow \ + -Wpointer-arith \ + -Wformat \ + -Wreturn-type \ + -Wsign-compare \ + -Wmultichar \ + -Wformat-nonliteral \ + -Winit-self \ + -Wuninitialized \ + -Wformat-security \ + -Wno-missing-braces \ + -Werror + +VALGRIND ?= 1 + +CFLAGS += -I. +CFLAGS += -DVALGRIND=$(VALGRIND) +CFLAGS += -DUSE_ETHEREUM=1 +CFLAGS += -DUSE_GRAPHENE=1 +CFLAGS += -DUSE_KECCAK=1 +CFLAGS += -DUSE_MONERO=1 +CFLAGS += -DUSE_NEM=1 +CFLAGS += -DUSE_CARDANO=1 +CFLAGS += -DUSE_NANO=1 +CFLAGS += $(shell pkg-config --cflags openssl) + +# disable certain optimizations and features when small footprint is required +ifdef SMALL +CFLAGS += -DUSE_PRECOMPUTED_CP=0 +endif + +SRCS = bignum.c ecdsa.c curves.c secp256k1.c nist256p1.c rand.c hmac.c bip32.c bip39.c bip39_english.c pbkdf2.c base58.c base32.c +SRCS += address.c +SRCS += script.c +SRCS += ripemd160.c +SRCS += sha2.c +SRCS += sha3.c +SRCS += hasher.c +SRCS += aes/aescrypt.c aes/aeskey.c aes/aestab.c aes/aes_modes.c +SRCS += ed25519-donna/curve25519-donna-32bit.c ed25519-donna/curve25519-donna-helpers.c ed25519-donna/modm-donna-32bit.c +SRCS += ed25519-donna/ed25519-donna-basepoint-table.c ed25519-donna/ed25519-donna-32bit-tables.c ed25519-donna/ed25519-donna-impl-base.c +SRCS += ed25519-donna/ed25519.c ed25519-donna/curve25519-donna-scalarmult-base.c ed25519-donna/ed25519-sha3.c ed25519-donna/ed25519-keccak.c +SRCS += ed25519-donna/ed25519-blake2b.c +SRCS += monero/base58.c +SRCS += monero/serialize.c +SRCS += monero/xmr.c +SRCS += monero/range_proof.c +SRCS += blake256.c +SRCS += blake2b.c blake2s.c +SRCS += chacha_drbg.c +SRCS += groestl.c +SRCS += chacha20poly1305/chacha20poly1305.c chacha20poly1305/chacha_merged.c chacha20poly1305/poly1305-donna.c chacha20poly1305/rfc7539.c +SRCS += rc4.c +SRCS += nem.c +SRCS += nano.c +SRCS += segwit_addr.c cash_addr.c +SRCS += zcash_zip316.c +SRCS += memzero.c +SRCS += shamir.c +SRCS += hmac_drbg.c +SRCS += rfc6979.c +SRCS += slip39.c +SRCS += schnorr.c + +OBJS = $(SRCS:.c=.o) + +TESTLIBS = $(shell pkg-config --libs check) -lpthread -lm +TESTSSLLIBS = $(shell pkg-config --libs openssl) + +all: tools tests + +%.o: %.c %.h options.h + $(CC) $(CFLAGS) -o $@ -c $< + +tests: tests/test_check tests/test_openssl tests/test_speed tests/libtrezor-crypto.so tests/aestst + +tests/aestst: aes/aestst.o aes/aescrypt.o aes/aeskey.o aes/aestab.o + $(CC) $^ -o $@ + +tests/test_check.o: tests/test_check_cardano.h tests/test_check_nano.h tests/test_check_monero.h tests/test_check_cashaddr.h tests/test_check_segwit.h + +tests/test_check: tests/test_check.o $(OBJS) + $(CC) tests/test_check.o $(OBJS) $(TESTLIBS) -o tests/test_check + +tests/test_speed: tests/test_speed.o $(OBJS) + $(CC) tests/test_speed.o $(OBJS) -o tests/test_speed + +tests/test_openssl: tests/test_openssl.o $(OBJS) + $(CC) tests/test_openssl.o $(OBJS) $(TESTSSLLIBS) -o tests/test_openssl + +tests/libtrezor-crypto.so: $(SRCS) + $(CC) $(CFLAGS) -DAES_128 -DAES_192 -fPIC -shared $(SRCS) -o tests/libtrezor-crypto.so + +tools: tools/xpubaddrgen tools/mktable tools/bip39bruteforce + +tools/xpubaddrgen: tools/xpubaddrgen.o $(OBJS) + $(CC) tools/xpubaddrgen.o $(OBJS) -o tools/xpubaddrgen + +tools/mktable: tools/mktable.o $(OBJS) + $(CC) tools/mktable.o $(OBJS) -o tools/mktable + +tools/bip39bruteforce: tools/bip39bruteforce.o $(OBJS) + $(CC) tools/bip39bruteforce.o $(OBJS) -o tools/bip39bruteforce + +fuzzer: fuzzer/fuzzer.o $(OBJS) + $(CC) $(CFLAGS) fuzzer/fuzzer.o $(OBJS) -o fuzzer/fuzzer + +clean: + rm -f *.o aes/*.o chacha20poly1305/*.o ed25519-donna/*.o monero/*.o + rm -f tests/*.o tests/test_check tests/test_speed tests/test_openssl tests/libtrezor-crypto.so tests/aestst + rm -f tools/*.o tools/xpubaddrgen tools/mktable tools/bip39bruteforce + rm -f fuzzer/*.o fuzzer/fuzzer + +clean-fuzzer: clean + rm -f crash-* fuzz-*.log slow-unit-* timeout-* diff --git a/deps/crypto/trezor-crypto/README.md b/deps/crypto/trezor-crypto/README.md new file mode 100644 index 000000000..50d9198a1 --- /dev/null +++ b/deps/crypto/trezor-crypto/README.md @@ -0,0 +1,45 @@ +# trezor-crypto + +[![Build Status](https://travis-ci.org/trezor/trezor-crypto.svg?branch=master)](https://travis-ci.org/trezor/trezor-crypto) [![gitter](https://badges.gitter.im/trezor/community.svg)](https://gitter.im/trezor/community) + +Heavily optimized cryptography algorithms for embedded devices. + +These include: +- AES/Rijndael encryption/decryption +- Big Number (256 bit) Arithmetics +- BIP32 Hierarchical Deterministic Wallets +- BIP39 Mnemonic code +- ECDSA signing/verifying (supports secp256k1 and nist256p1 curves, + uses RFC6979 for deterministic signatures) +- ECDSA public key derivation +- Schnorr (BCH variant) signing/verifying +- Base32 (RFC4648 and custom alphabets) +- Base58 address representation +- Ed25519 signing/verifying (also SHA3 and Keccak variants) +- ECDH using secp256k1, nist256p1 and Curve25519 +- HMAC-SHA256 and HMAC-SHA512 +- PBKDF2 +- RIPEMD-160 +- SHA1 +- SHA2-256/SHA2-512 +- SHA3/Keccak +- BLAKE2s/BLAKE2b +- Chacha20-Poly1305 +- unit tests (using Check - check.sf.net; in test_check.c) +- tests against OpenSSL (in test_openssl.c) +- integrated Wycheproof tests + +Distibuted under MIT License. + +## Some parts of the library come from external sources: + +- AES: https://github.com/BrianGladman/aes +- Base58: https://github.com/luke-jr/libbase58 +- BLAKE2s/BLAKE2b: https://github.com/BLAKE2/BLAKE2 +- RIPEMD-160: https://github.com/ARMmbed/mbedtls +- SHA1/SHA2: http://www.aarongifford.com/computers/sha.html +- SHA3: https://github.com/rhash/RHash +- Curve25519: https://github.com/agl/curve25519-donna +- Ed25519: https://github.com/floodyberry/ed25519-donna +- Chacha20: https://github.com/wg/c20p1305 +- Poly1305: https://github.com/floodyberry/poly1305-donna diff --git a/deps/crypto/trezor-crypto/SECURITY_BACKPORTS.md b/deps/crypto/trezor-crypto/SECURITY_BACKPORTS.md new file mode 100644 index 000000000..47844c487 --- /dev/null +++ b/deps/crypto/trezor-crypto/SECURITY_BACKPORTS.md @@ -0,0 +1,81 @@ +# RC18 crypto security triage + +This file records the security-relevant delta applied after baseline +`56f404e452bc7738cd3b3e14454dfecb25c083bf`. + +## Applied upstream changes + +| Upstream commit | KeepKey disposition | +| --- | --- | +| `15bb085509263a2586b914363b095e1e62255816` | Propagate invalid public-child derivation failures. | +| `5d03110a4287d2cdb0820d07d04e71a79d445014` | Handle invalid ECDSA private-key and zero-digest edge cases. | +| `34621a6b6d340a42e917cad346ec527c94066712` | Tighten private-key validity checks. | +| `307d166383614a8fa6ebee90ee10c469dfa697d1` | Clean Ed25519 stack intermediates. | +| `f96e737ef540665ff8df0e5d46a3ad0e2d7f67f9` | Remove alignment-dependent SHA3 undefined behavior. | +| `4882648dad1e29b635568abe52251285fb56bdb1` | Reject a recovered ECDSA point at infinity. | +| `8baf1ca79f107da2c25348df7f429e2f147dd939` | Prevent an out-of-bounds read in `ecdsa_sig_to_der`. | +| `10bc747dc6dae3620dce73df37a55009bbfc87ed` | Correct Ed25519 argument types. | +| `4827969cc8411f38d4b10916658d2aa665ca555d` | Harden SHA function declarations. | +| `d1d3558d02732979c00c96c5e7b91e6560149e61` | Correct constant-time assertions and casts. | +| `d6fdadf6730727c26d0644d84faaa562cf75f4d3` | Remove zero-length Groestl/SHA3 undefined behavior. | +| `f4d0dd9807ec3d50483dd589455235569a1a63c6` | Initialize Ed25519 locals; adapted for KeepKey Cardano APIs. | +| `8e8f1afa8566cd5c7f89e4154163e6b9f6c9bee4` | Enforce strict DER signature decoding. | +| `1e53a84cfc22405d2a67295954cbb33ca0c336ca` | Zero-initialize AES stack contexts. | +| `3b49e5400db4c92490a259c363f257617cb017ff` | Remove secret-dependent Ed25519 memory access. | +| `ecc38f267f91dffdb8afaaea8d5e5853be72df21` | Use constant-time Ed25519 conditional moves. | +| `2ce1e6ba7dbe5bbaeeb336fff0a038e59cb40ef8` | Add BIP32/BIP39 cache clearing APIs. | +| `477cbb365a29c23df766fd8f128cc5b73ed04bb6` | Wipe HDNode deserialization scratch data. | +| `09e55d8c9cb255eaa0463a8aa58f5dca1ed17644` | Clean NEM AES contexts. | +| `26914ff4962812695a2abf49f06e268606a7a7e2` | Prevent fixed-size BIP32 cache-path overflow. | +| `ea542943fced278c3563f068c2aa63dda0d1705e` | Reject BIP32 depth overflow. | +| `865ca5f0a9534ca64f41a1d508983029b55c9b7b` | Correct SLIP-10/25519 fingerprints. | +| `3da9c6bbb9910ce7f8fc29f9c5da758dbb50cb9c` | Reject public CKD for 25519 curves. | +| `bddd38b47d920559e50aa50c82eab62a8f6510ca` | Wipe ECDSA signing intermediates. | +| `9b1c06205c41811abe7de81d9e50abd22613f0b3` | Make BIP39 word processing constant-time. | +| `13e6c4f55d3a54678d140ecd9b06205d5115881d` | Bound CashAddr HRP and output writes. | +| `ea5886026fac93f2a7544f425fa0480d6e896220` | Pass the curve into RFC6979 initialization. | +| `53d522a1fd6f391fe48de8accecae308e9754f09` | Reduce RFC6979 digests modulo the curve order. | +| `fa5e7feda66f2b64d8d2976f9110456a1f86989b` | Remove CoSi nonce bias. | +| `48db49fa67eb4b51a30dff394e27cbea6803dbf1` | Wipe CoSi secrets on early returns. | +| `892f3e348dacb6c7b9880bc697234a78aaf6d80a` | Remove caller-supplied Ed25519 public keys from signing APIs. | + +## KeepKey-specific corrections + +- Preserve the existing `mnemonic_find_word` API while using a fixed-size, + constant-time word lookup and wiping checksum intermediates. +- Reject an invalid/null-curve node in `hdnode_private_ckd_cached`; the legacy + implementation incorrectly returned success. +- Deserialize into a fresh output `HDNode` without first requiring that + uninitialized output to be valid, and reject an unknown curve safely. +- Calculate 25519 fingerprints without mutating a cached public key. +- Apply the hardened Ed25519 signing API to the KeepKey Nano/Blake2b variant + and all firmware call sites. +- Clear BIP32 and BIP39 global caches on session clear and storage reset. + +## Reviewed but not applied + +- `a5f7c19` insecure platform-independent LCG: not active in production. + KeepKey defines `RAND_PLATFORM_INDEPENDENT=0` and supplies hardware + `random32`; host tests use their own platform source. +- `b1bee00` BIP39 word-boundary read: the KeepKey word list already carried a + sentinel, and the constant-time BIP39 rewrite above supersedes this path. +- `dfb7295` migration of crypto globals to stack: deferred because the legacy + embedded target has strict stack limits. Existing static secret + intermediates are explicitly wiped, and the new cache-clear APIs are called + at the firmware session boundary. +- Broad feature, architecture, generated-file, Rust/Python/Core, and toolchain + changes outside the compiled KeepKey crypto surface were not backported. + +## Regression coverage + +The standalone suite includes focused tests for: + +- zero-valued DER signature components; +- recovered point-at-infinity rejection; +- BIP32 cache paths deeper than `BIP32_CACHE_MAXDEPTH`; +- private and public BIP32 depth overflow; +- RFC6979 digest reduction/deterministic signatures; +- the hardened Ed25519, Cardano, and CoSi APIs; +- the complete pre-existing crypto vector suite. + +Result: 158/158 checks pass under the optimized build and under ASan+UBSan. diff --git a/deps/crypto/trezor-crypto/address.c b/deps/crypto/trezor-crypto/address.c new file mode 100644 index 000000000..8f3aa9734 --- /dev/null +++ b/deps/crypto/trezor-crypto/address.c @@ -0,0 +1,91 @@ +/** + * Copyright (c) 2016 Daira Hopwood + * Copyright (c) 2016 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "address.h" +#include "bignum.h" + +size_t address_prefix_bytes_len(uint32_t address_type) { + if (address_type <= 0xFF) return 1; + if (address_type <= 0xFFFF) return 2; + if (address_type <= 0xFFFFFF) return 3; + return 4; +} + +void address_write_prefix_bytes(uint32_t address_type, uint8_t *out) { + if (address_type > 0xFFFFFF) *(out++) = address_type >> 24; + if (address_type > 0xFFFF) *(out++) = (address_type >> 16) & 0xFF; + if (address_type > 0xFF) *(out++) = (address_type >> 8) & 0xFF; + *(out++) = address_type & 0xFF; +} + +bool address_check_prefix(const uint8_t *addr, uint32_t address_type) { + if (address_type <= 0xFF) { + return address_type == (uint32_t)(addr[0]); + } + if (address_type <= 0xFFFF) { + return address_type == (((uint32_t)addr[0] << 8) | ((uint32_t)addr[1])); + } + if (address_type <= 0xFFFFFF) { + return address_type == (((uint32_t)addr[0] << 16) | + ((uint32_t)addr[1] << 8) | ((uint32_t)addr[2])); + } + return address_type == + (((uint32_t)addr[0] << 24) | ((uint32_t)addr[1] << 16) | + ((uint32_t)addr[2] << 8) | ((uint32_t)addr[3])); +} + +#if USE_ETHEREUM +#include "sha3.h" + +void ethereum_address_checksum(const uint8_t *addr, char *address, bool rskip60, + uint32_t chain_id) { + const char *hex = "0123456789abcdef"; + for (int i = 0; i < 20; i++) { + address[i * 2] = hex[(addr[i] >> 4) & 0xF]; + address[i * 2 + 1] = hex[addr[i] & 0xF]; + } + address[40] = 0; + + SHA3_CTX ctx = {0}; + uint8_t hash[32] = {0}; + keccak_256_Init(&ctx); + if (rskip60) { + char prefix[16] = {0}; + int prefix_size = bn_format_uint64(chain_id, NULL, "0x", 0, 0, false, + prefix, sizeof(prefix)); + keccak_Update(&ctx, (const uint8_t *)prefix, prefix_size); + } + keccak_Update(&ctx, (const uint8_t *)address, 40); + keccak_Final(&ctx, hash); + + for (int i = 0; i < 20; i++) { + if (hash[i] & 0x80 && address[i * 2] >= 'a' && address[i * 2] <= 'f') { + address[i * 2] -= 0x20; + } + if (hash[i] & 0x08 && address[i * 2 + 1] >= 'a' && + address[i * 2 + 1] <= 'f') { + address[i * 2 + 1] -= 0x20; + } + } +} +#endif diff --git a/deps/crypto/trezor-crypto/address.h b/deps/crypto/trezor-crypto/address.h new file mode 100644 index 000000000..8147f2c35 --- /dev/null +++ b/deps/crypto/trezor-crypto/address.h @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2016 Daira Hopwood + * Copyright (c) 2016 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __ADDRESS_H__ +#define __ADDRESS_H__ + +#include +#include +#include +#include "options.h" + +size_t address_prefix_bytes_len(uint32_t address_type); +void address_write_prefix_bytes(uint32_t address_type, uint8_t *out); +bool address_check_prefix(const uint8_t *addr, uint32_t address_type); +#if USE_ETHEREUM +void ethereum_address_checksum(const uint8_t *addr, char *address, bool rskip60, + uint32_t chain_id); +#endif + +#endif diff --git a/deps/crypto/trezor-crypto/aes/aes.h b/deps/crypto/trezor-crypto/aes/aes.h new file mode 100644 index 000000000..878943b57 --- /dev/null +++ b/deps/crypto/trezor-crypto/aes/aes.h @@ -0,0 +1,226 @@ +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 02/08/2018 + + This file contains the definitions required to use AES in C. See aesopt.h + for optimisation details. +*/ + +#ifndef _AES_H +#define _AES_H + +#include +#include + +#define VOID_RETURN void +#define INT_RETURN int +#define ALIGN_OFFSET(x,n) (((intptr_t)(x)) & ((n) - 1)) +#define ALIGN_FLOOR(x,n) ((uint8_t*)(x) - ( ((intptr_t)(x)) & ((n) - 1))) +#define ALIGN_CEIL(x,n) ((uint8_t*)(x) + (-((intptr_t)(x)) & ((n) - 1))) + +#if defined(__cplusplus) +extern "C" +{ +#endif + +// #define AES_128 /* if a fast 128 bit key scheduler is needed */ +// #define AES_192 /* if a fast 192 bit key scheduler is needed */ +#define AES_256 /* if a fast 256 bit key scheduler is needed */ +// #define AES_VAR /* if variable key size scheduler is needed */ +#if 1 +# define AES_MODES /* if support is needed for modes in the C code */ +#endif /* (these will use AES_NI if it is present) */ +#if 0 /* add this to make direct calls to the AES_NI */ +# /* implemented CBC and CTR modes available */ +# define ADD_AESNI_MODE_CALLS +#endif + +/* The following must also be set in assembler files if being used */ + +#define AES_ENCRYPT /* if support for encryption is needed */ +#define AES_DECRYPT /* if support for decryption is needed */ + +#define AES_BLOCK_SIZE_P2 4 /* AES block size as a power of 2 */ +#define AES_BLOCK_SIZE (1 << AES_BLOCK_SIZE_P2) /* AES block size */ +#define N_COLS 4 /* the number of columns in the state */ + +/* The key schedule length is 11, 13 or 15 16-byte blocks for 128, */ +/* 192 or 256-bit keys respectively. That is 176, 208 or 240 bytes */ +/* or 44, 52 or 60 32-bit words. */ + +#if defined( AES_VAR ) || defined( AES_256 ) +#define KS_LENGTH 60 +#elif defined( AES_192 ) +#define KS_LENGTH 52 +#else +#define KS_LENGTH 44 +#endif + +#define AES_RETURN INT_RETURN + +/* the character array 'inf' in the following structures is used */ +/* to hold AES context information. This AES code uses cx->inf.b[0] */ +/* to hold the number of rounds multiplied by 16. The other three */ +/* elements can be used by code that implements additional modes */ + +typedef union +{ uint32_t l; + uint8_t b[4]; +} aes_inf; + +#ifdef _MSC_VER +# pragma warning( disable : 4324 ) +#endif + +#if defined(_MSC_VER) && defined(_WIN64) +#define ALIGNED_(x) __declspec(align(x)) +#elif defined(__GNUC__) && defined(__x86_64__) +#define ALIGNED_(x) __attribute__ ((aligned(x))) +#else +#define ALIGNED_(x) +#endif + +typedef struct ALIGNED_(16) +{ uint32_t ks[KS_LENGTH]; + aes_inf inf; +} aes_encrypt_ctx; + +typedef struct ALIGNED_(16) +{ uint32_t ks[KS_LENGTH]; + aes_inf inf; +} aes_decrypt_ctx; + +#ifdef _MSC_VER +# pragma warning( default : 4324 ) +#endif + +/* This routine must be called before first use if non-static */ +/* tables are being used */ + +AES_RETURN aes_init(void); + +/* Key lengths in the range 16 <= key_len <= 32 are given in bytes, */ +/* those in the range 128 <= key_len <= 256 are given in bits */ + +#if defined( AES_ENCRYPT ) + +#if defined( AES_128 ) || defined( AES_VAR) +AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]); +#endif + +#if defined( AES_192 ) || defined( AES_VAR) +AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]); +#endif + +#if defined( AES_256 ) || defined( AES_VAR) +AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]); +#endif + +#if defined( AES_VAR ) +AES_RETURN aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1]); +#endif + +AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1]); + +#endif + +#if defined( AES_DECRYPT ) + +#if defined( AES_128 ) || defined( AES_VAR) +AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]); +#endif + +#if defined( AES_192 ) || defined( AES_VAR) +AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]); +#endif + +#if defined( AES_256 ) || defined( AES_VAR) +AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]); +#endif + +#if defined( AES_VAR ) +AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1]); +#endif + +AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1]); + +#endif + +#if defined( AES_MODES ) + +/* Multiple calls to the following subroutines for multiple block */ +/* ECB, CBC, CFB, OFB and CTR mode encryption can be used to handle */ +/* long messages incrementally provided that the context AND the iv */ +/* are preserved between all such calls. For the ECB and CBC modes */ +/* each individual call within a series of incremental calls must */ +/* process only full blocks (i.e. len must be a multiple of 16) but */ +/* the CFB, OFB and CTR mode calls can handle multiple incremental */ +/* calls of any length. Each mode is reset when a new AES key is */ +/* set but ECB needs no reset and CBC can be reset without setting */ +/* a new key by setting a new IV value. To reset CFB, OFB and CTR */ +/* without setting the key, aes_mode_reset() must be called and the */ +/* IV must be set. NOTE: All these calls update the IV on exit so */ +/* this has to be reset if a new operation with the same IV as the */ +/* previous one is required (or decryption follows encryption with */ +/* the same IV array). */ + +AES_RETURN aes_test_alignment_detection(unsigned int n); + +AES_RETURN aes_ecb_encrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, const aes_encrypt_ctx cx[1]); + +AES_RETURN aes_ecb_decrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, const aes_decrypt_ctx cx[1]); + +AES_RETURN aes_cbc_encrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, const aes_encrypt_ctx cx[1]); + +AES_RETURN aes_cbc_decrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, const aes_decrypt_ctx cx[1]); + +AES_RETURN aes_mode_reset(aes_encrypt_ctx cx[1]); + +AES_RETURN aes_cfb_encrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, aes_encrypt_ctx cx[1]); + +AES_RETURN aes_cfb_decrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, aes_encrypt_ctx cx[1]); + +#define aes_ofb_encrypt aes_ofb_crypt +#define aes_ofb_decrypt aes_ofb_crypt + +AES_RETURN aes_ofb_crypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, aes_encrypt_ctx cx[1]); + +typedef void cbuf_inc(unsigned char *cbuf); + +#define aes_ctr_encrypt aes_ctr_crypt +#define aes_ctr_decrypt aes_ctr_crypt + +AES_RETURN aes_ctr_crypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx cx[1]); + +void aes_ctr_cbuf_inc(unsigned char *cbuf); + +#endif + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/deps/crypto/trezor-crypto/aes/aes_modes.c b/deps/crypto/trezor-crypto/aes/aes_modes.c new file mode 100644 index 000000000..b89283d0f --- /dev/null +++ b/deps/crypto/trezor-crypto/aes/aes_modes.c @@ -0,0 +1,957 @@ +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 + + These subroutines implement multiple block AES modes for ECB, CBC, CFB, + OFB and CTR encryption, The code provides support for the VIA Advanced + Cryptography Engine (ACE). + + NOTE: In the following subroutines, the AES contexts (ctx) must be + 16 byte aligned if VIA ACE is being used +*/ + +#include +#include +#include + +#include "aesopt.h" + +#if defined( AES_MODES ) +#if defined(__cplusplus) +extern "C" +{ +#endif + +#if defined( _MSC_VER ) && ( _MSC_VER > 800 ) +#pragma intrinsic(memcpy) +#endif + +#define BFR_BLOCKS 8 + +/* These values are used to detect long word alignment in order to */ +/* speed up some buffer operations. This facility may not work on */ +/* some machines so this define can be commented out if necessary */ + +#define FAST_BUFFER_OPERATIONS + +#define lp32(x) ((uint32_t*)(x)) + +#if defined( USE_VIA_ACE_IF_PRESENT ) + +#include "aes_via_ace.h" + +#pragma pack(16) + +aligned_array(unsigned long, enc_gen_table, 12, 16) = NEH_ENC_GEN_DATA; +aligned_array(unsigned long, enc_load_table, 12, 16) = NEH_ENC_LOAD_DATA; +aligned_array(unsigned long, enc_hybrid_table, 12, 16) = NEH_ENC_HYBRID_DATA; +aligned_array(unsigned long, dec_gen_table, 12, 16) = NEH_DEC_GEN_DATA; +aligned_array(unsigned long, dec_load_table, 12, 16) = NEH_DEC_LOAD_DATA; +aligned_array(unsigned long, dec_hybrid_table, 12, 16) = NEH_DEC_HYBRID_DATA; + +/* NOTE: These control word macros must only be used after */ +/* a key has been set up because they depend on key size */ +/* See the VIA ACE documentation for key type information */ +/* and aes_via_ace.h for non-default NEH_KEY_TYPE values */ + +#ifndef NEH_KEY_TYPE +# define NEH_KEY_TYPE NEH_HYBRID +#endif + +#if NEH_KEY_TYPE == NEH_LOAD +#define kd_adr(c) ((uint8_t*)(c)->ks) +#elif NEH_KEY_TYPE == NEH_GENERATE +#define kd_adr(c) ((uint8_t*)(c)->ks + (c)->inf.b[0]) +#elif NEH_KEY_TYPE == NEH_HYBRID +#define kd_adr(c) ((uint8_t*)(c)->ks + ((c)->inf.b[0] == 160 ? 160 : 0)) +#else +#error no key type defined for VIA ACE +#endif + +#else + +#define aligned_array(type, name, no, stride) type name[no] +#define aligned_auto(type, name, no, stride) type name[no] + +#endif + +#if defined( _MSC_VER ) && _MSC_VER > 1200 + +#define via_cwd(cwd, ty, dir, len) \ + unsigned long* cwd = (dir##_##ty##_table + ((len - 128) >> 4)) + +#else + +#define via_cwd(cwd, ty, dir, len) \ + aligned_auto(unsigned long, cwd, 4, 16); \ + cwd[1] = cwd[2] = cwd[3] = 0; \ + cwd[0] = neh_##dir##_##ty##_key(len) + +#endif + +/* test the code for detecting and setting pointer alignment */ + +AES_RETURN aes_test_alignment_detection(unsigned int n) /* 4 <= n <= 16 */ +{ uint8_t p[16] = {0}; + uint32_t i = 0, count_eq = 0, count_neq = 0; + + if(n < 4 || n > 16) + return EXIT_FAILURE; + + for(i = 0; i < n; ++i) + { + uint8_t *qf = ALIGN_FLOOR(p + i, n), + *qh = ALIGN_CEIL(p + i, n); + + if(qh == qf) + ++count_eq; + else if(qh == qf + n) + ++count_neq; + else + return EXIT_FAILURE; + } + return (count_eq != 1 || count_neq != n - 1 ? EXIT_FAILURE : EXIT_SUCCESS); +} + +AES_RETURN aes_mode_reset(aes_encrypt_ctx ctx[1]) +{ + ctx->inf.b[2] = 0; + return EXIT_SUCCESS; +} + +AES_RETURN aes_ecb_encrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, const aes_encrypt_ctx ctx[1]) +{ int nb = len >> AES_BLOCK_SIZE_P2; + + if(len & (AES_BLOCK_SIZE - 1)) + return EXIT_FAILURE; + +#if defined( USE_VIA_ACE_IF_PRESENT ) + + if(ctx->inf.b[1] == 0xff) + { uint8_t *ksp = (uint8_t*)(ctx->ks); + via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); + + if(ALIGN_OFFSET( ctx, 16 )) + return EXIT_FAILURE; + + if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 )) + { + via_ecb_op5(ksp, cwd, ibuf, obuf, nb); + } + else + { aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); + uint8_t *ip = NULL, *op = NULL; + + while(nb) + { + int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); + + ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); + op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); + + if(ip != ibuf) + memcpy(buf, ibuf, m * AES_BLOCK_SIZE); + + via_ecb_op5(ksp, cwd, ip, op, m); + + if(op != obuf) + memcpy(obuf, buf, m * AES_BLOCK_SIZE); + + ibuf += m * AES_BLOCK_SIZE; + obuf += m * AES_BLOCK_SIZE; + nb -= m; + } + } + + return EXIT_SUCCESS; + } + +#endif + +#if !defined( ASSUME_VIA_ACE_PRESENT ) + while(nb--) + { + if(aes_encrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } +#endif + return EXIT_SUCCESS; +} + +AES_RETURN aes_ecb_decrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, const aes_decrypt_ctx ctx[1]) +{ int nb = len >> AES_BLOCK_SIZE_P2; + + if(len & (AES_BLOCK_SIZE - 1)) + return EXIT_FAILURE; + +#if defined( USE_VIA_ACE_IF_PRESENT ) + + if(ctx->inf.b[1] == 0xff) + { uint8_t *ksp = kd_adr(ctx); + via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192); + + if(ALIGN_OFFSET( ctx, 16 )) + return EXIT_FAILURE; + + if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 )) + { + via_ecb_op5(ksp, cwd, ibuf, obuf, nb); + } + else + { aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); + uint8_t *ip = NULL, *op = NULL; + + while(nb) + { + int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); + + ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); + op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); + + if(ip != ibuf) + memcpy(buf, ibuf, m * AES_BLOCK_SIZE); + + via_ecb_op5(ksp, cwd, ip, op, m); + + if(op != obuf) + memcpy(obuf, buf, m * AES_BLOCK_SIZE); + + ibuf += m * AES_BLOCK_SIZE; + obuf += m * AES_BLOCK_SIZE; + nb -= m; + } + } + + return EXIT_SUCCESS; + } + +#endif + +#if !defined( ASSUME_VIA_ACE_PRESENT ) + while(nb--) + { + if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } +#endif + return EXIT_SUCCESS; +} + +AES_RETURN aes_cbc_encrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, const aes_encrypt_ctx ctx[1]) +{ int nb = len >> AES_BLOCK_SIZE_P2; + + if(len & (AES_BLOCK_SIZE - 1)) + return EXIT_FAILURE; + +#if defined( USE_VIA_ACE_IF_PRESENT ) + + if(ctx->inf.b[1] == 0xff) + { uint8_t *ksp = (uint8_t*)(ctx->ks), *ivp = iv; + aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16); + via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); + + if(ALIGN_OFFSET( ctx, 16 )) + return EXIT_FAILURE; + + if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */ + { + ivp = liv; + memcpy(liv, iv, AES_BLOCK_SIZE); + } + + if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ) && !ALIGN_OFFSET( iv, 16 )) + { + via_cbc_op7(ksp, cwd, ibuf, obuf, nb, ivp, ivp); + } + else + { aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); + uint8_t *ip = NULL, *op = NULL; + + while(nb) + { + int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); + + ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); + op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); + + if(ip != ibuf) + memcpy(buf, ibuf, m * AES_BLOCK_SIZE); + + via_cbc_op7(ksp, cwd, ip, op, m, ivp, ivp); + + if(op != obuf) + memcpy(obuf, buf, m * AES_BLOCK_SIZE); + + ibuf += m * AES_BLOCK_SIZE; + obuf += m * AES_BLOCK_SIZE; + nb -= m; + } + } + + if(iv != ivp) + memcpy(iv, ivp, AES_BLOCK_SIZE); + + return EXIT_SUCCESS; + } + +#endif + +#if !defined( ASSUME_VIA_ACE_PRESENT ) +# ifdef FAST_BUFFER_OPERATIONS + if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( iv, 4 )) + while(nb--) + { + lp32(iv)[0] ^= lp32(ibuf)[0]; + lp32(iv)[1] ^= lp32(ibuf)[1]; + lp32(iv)[2] ^= lp32(ibuf)[2]; + lp32(iv)[3] ^= lp32(ibuf)[3]; + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + memcpy(obuf, iv, AES_BLOCK_SIZE); + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } + else +# endif + while(nb--) + { + iv[ 0] ^= ibuf[ 0]; iv[ 1] ^= ibuf[ 1]; + iv[ 2] ^= ibuf[ 2]; iv[ 3] ^= ibuf[ 3]; + iv[ 4] ^= ibuf[ 4]; iv[ 5] ^= ibuf[ 5]; + iv[ 6] ^= ibuf[ 6]; iv[ 7] ^= ibuf[ 7]; + iv[ 8] ^= ibuf[ 8]; iv[ 9] ^= ibuf[ 9]; + iv[10] ^= ibuf[10]; iv[11] ^= ibuf[11]; + iv[12] ^= ibuf[12]; iv[13] ^= ibuf[13]; + iv[14] ^= ibuf[14]; iv[15] ^= ibuf[15]; + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + memcpy(obuf, iv, AES_BLOCK_SIZE); + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } +#endif + return EXIT_SUCCESS; +} + +AES_RETURN aes_cbc_decrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, const aes_decrypt_ctx ctx[1]) +{ unsigned char tmp[AES_BLOCK_SIZE] = {0}; + int nb = len >> AES_BLOCK_SIZE_P2; + + if(len & (AES_BLOCK_SIZE - 1)) + return EXIT_FAILURE; + +#if defined( USE_VIA_ACE_IF_PRESENT ) + + if(ctx->inf.b[1] == 0xff) + { uint8_t *ksp = kd_adr(ctx), *ivp = iv; + aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16); + via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192); + + if(ALIGN_OFFSET( ctx, 16 )) + return EXIT_FAILURE; + + if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */ + { + ivp = liv; + memcpy(liv, iv, AES_BLOCK_SIZE); + } + + if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ) && !ALIGN_OFFSET( iv, 16 )) + { + via_cbc_op6(ksp, cwd, ibuf, obuf, nb, ivp); + } + else + { aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); + uint8_t *ip = NULL, *op = NULL; + + while(nb) + { + int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); + + ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); + op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); + + if(ip != ibuf) + memcpy(buf, ibuf, m * AES_BLOCK_SIZE); + + via_cbc_op6(ksp, cwd, ip, op, m, ivp); + + if(op != obuf) + memcpy(obuf, buf, m * AES_BLOCK_SIZE); + + ibuf += m * AES_BLOCK_SIZE; + obuf += m * AES_BLOCK_SIZE; + nb -= m; + } + } + + if(iv != ivp) + memcpy(iv, ivp, AES_BLOCK_SIZE); + + return EXIT_SUCCESS; + } +#endif + +#if !defined( ASSUME_VIA_ACE_PRESENT ) +# ifdef FAST_BUFFER_OPERATIONS + if(!ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 )) + while(nb--) + { + memcpy(tmp, ibuf, AES_BLOCK_SIZE); + if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + lp32(obuf)[0] ^= lp32(iv)[0]; + lp32(obuf)[1] ^= lp32(iv)[1]; + lp32(obuf)[2] ^= lp32(iv)[2]; + lp32(obuf)[3] ^= lp32(iv)[3]; + memcpy(iv, tmp, AES_BLOCK_SIZE); + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } + else +# endif + while(nb--) + { + memcpy(tmp, ibuf, AES_BLOCK_SIZE); + if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + obuf[ 0] ^= iv[ 0]; obuf[ 1] ^= iv[ 1]; + obuf[ 2] ^= iv[ 2]; obuf[ 3] ^= iv[ 3]; + obuf[ 4] ^= iv[ 4]; obuf[ 5] ^= iv[ 5]; + obuf[ 6] ^= iv[ 6]; obuf[ 7] ^= iv[ 7]; + obuf[ 8] ^= iv[ 8]; obuf[ 9] ^= iv[ 9]; + obuf[10] ^= iv[10]; obuf[11] ^= iv[11]; + obuf[12] ^= iv[12]; obuf[13] ^= iv[13]; + obuf[14] ^= iv[14]; obuf[15] ^= iv[15]; + memcpy(iv, tmp, AES_BLOCK_SIZE); + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } +#endif + return EXIT_SUCCESS; +} + +AES_RETURN aes_cfb_encrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, aes_encrypt_ctx ctx[1]) +{ int cnt = 0, b_pos = (int)ctx->inf.b[2], nb = 0; + + if(b_pos) /* complete any partial block */ + { + while(b_pos < AES_BLOCK_SIZE && cnt < len) + { + *obuf++ = (iv[b_pos++] ^= *ibuf++); + cnt++; + } + + b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); + } + + if((nb = (len - cnt) >> AES_BLOCK_SIZE_P2) != 0) /* process whole blocks */ + { +#if defined( USE_VIA_ACE_IF_PRESENT ) + + if(ctx->inf.b[1] == 0xff) + { int m = 0; + uint8_t *ksp = (uint8_t*)(ctx->ks), *ivp = iv; + aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16); + via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); + + if(ALIGN_OFFSET( ctx, 16 )) + return EXIT_FAILURE; + + if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */ + { + ivp = liv; + memcpy(liv, iv, AES_BLOCK_SIZE); + } + + if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 )) + { + via_cfb_op7(ksp, cwd, ibuf, obuf, nb, ivp, ivp); + ibuf += nb * AES_BLOCK_SIZE; + obuf += nb * AES_BLOCK_SIZE; + cnt += nb * AES_BLOCK_SIZE; + } + else /* input, output or both are unaligned */ + { aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); + uint8_t *ip = NULL, *op = NULL; + + while(nb) + { + m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m; + + ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); + op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); + + if(ip != ibuf) + memcpy(buf, ibuf, m * AES_BLOCK_SIZE); + + via_cfb_op7(ksp, cwd, ip, op, m, ivp, ivp); + + if(op != obuf) + memcpy(obuf, buf, m * AES_BLOCK_SIZE); + + ibuf += m * AES_BLOCK_SIZE; + obuf += m * AES_BLOCK_SIZE; + cnt += m * AES_BLOCK_SIZE; + } + } + + if(ivp != iv) + memcpy(iv, ivp, AES_BLOCK_SIZE); + } +#else +# ifdef FAST_BUFFER_OPERATIONS + if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 )) + while(cnt + AES_BLOCK_SIZE <= len) + { + assert(b_pos == 0); + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + lp32(obuf)[0] = lp32(iv)[0] ^= lp32(ibuf)[0]; + lp32(obuf)[1] = lp32(iv)[1] ^= lp32(ibuf)[1]; + lp32(obuf)[2] = lp32(iv)[2] ^= lp32(ibuf)[2]; + lp32(obuf)[3] = lp32(iv)[3] ^= lp32(ibuf)[3]; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + cnt += AES_BLOCK_SIZE; + } + else +# endif + while(cnt + AES_BLOCK_SIZE <= len) + { + assert(b_pos == 0); + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + obuf[ 0] = iv[ 0] ^= ibuf[ 0]; obuf[ 1] = iv[ 1] ^= ibuf[ 1]; + obuf[ 2] = iv[ 2] ^= ibuf[ 2]; obuf[ 3] = iv[ 3] ^= ibuf[ 3]; + obuf[ 4] = iv[ 4] ^= ibuf[ 4]; obuf[ 5] = iv[ 5] ^= ibuf[ 5]; + obuf[ 6] = iv[ 6] ^= ibuf[ 6]; obuf[ 7] = iv[ 7] ^= ibuf[ 7]; + obuf[ 8] = iv[ 8] ^= ibuf[ 8]; obuf[ 9] = iv[ 9] ^= ibuf[ 9]; + obuf[10] = iv[10] ^= ibuf[10]; obuf[11] = iv[11] ^= ibuf[11]; + obuf[12] = iv[12] ^= ibuf[12]; obuf[13] = iv[13] ^= ibuf[13]; + obuf[14] = iv[14] ^= ibuf[14]; obuf[15] = iv[15] ^= ibuf[15]; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + cnt += AES_BLOCK_SIZE; + } +#endif + } + + while(cnt < len) + { + if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + + while(cnt < len && b_pos < AES_BLOCK_SIZE) + { + *obuf++ = (iv[b_pos++] ^= *ibuf++); + cnt++; + } + + b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); + } + + ctx->inf.b[2] = (uint8_t)b_pos; + return EXIT_SUCCESS; +} + +AES_RETURN aes_cfb_decrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, aes_encrypt_ctx ctx[1]) +{ int cnt = 0, b_pos = (int)ctx->inf.b[2], nb = 0; + + if(b_pos) /* complete any partial block */ + { uint8_t t = 0; + + while(b_pos < AES_BLOCK_SIZE && cnt < len) + { + t = *ibuf++; + *obuf++ = t ^ iv[b_pos]; + iv[b_pos++] = t; + cnt++; + } + + b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); + } + + if((nb = (len - cnt) >> AES_BLOCK_SIZE_P2) != 0) /* process whole blocks */ + { +#if defined( USE_VIA_ACE_IF_PRESENT ) + + if(ctx->inf.b[1] == 0xff) + { int m = 0; + uint8_t *ksp = (uint8_t*)(ctx->ks), *ivp = iv; + aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16); + via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192); + + if(ALIGN_OFFSET( ctx, 16 )) + return EXIT_FAILURE; + + if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */ + { + ivp = liv; + memcpy(liv, iv, AES_BLOCK_SIZE); + } + + if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 )) + { + via_cfb_op6(ksp, cwd, ibuf, obuf, nb, ivp); + ibuf += nb * AES_BLOCK_SIZE; + obuf += nb * AES_BLOCK_SIZE; + cnt += nb * AES_BLOCK_SIZE; + } + else /* input, output or both are unaligned */ + { aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); + uint8_t *ip = NULL, *op = NULL; + + while(nb) + { + m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m; + + ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); + op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); + + if(ip != ibuf) /* input buffer is not aligned */ + memcpy(buf, ibuf, m * AES_BLOCK_SIZE); + + via_cfb_op6(ksp, cwd, ip, op, m, ivp); + + if(op != obuf) /* output buffer is not aligned */ + memcpy(obuf, buf, m * AES_BLOCK_SIZE); + + ibuf += m * AES_BLOCK_SIZE; + obuf += m * AES_BLOCK_SIZE; + cnt += m * AES_BLOCK_SIZE; + } + } + + if(ivp != iv) + memcpy(iv, ivp, AES_BLOCK_SIZE); + } +#else +# ifdef FAST_BUFFER_OPERATIONS + if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) &&!ALIGN_OFFSET( iv, 4 )) + while(cnt + AES_BLOCK_SIZE <= len) + { uint32_t t = 0; + + assert(b_pos == 0); + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + t = lp32(ibuf)[0], lp32(obuf)[0] = t ^ lp32(iv)[0], lp32(iv)[0] = t; + t = lp32(ibuf)[1], lp32(obuf)[1] = t ^ lp32(iv)[1], lp32(iv)[1] = t; + t = lp32(ibuf)[2], lp32(obuf)[2] = t ^ lp32(iv)[2], lp32(iv)[2] = t; + t = lp32(ibuf)[3], lp32(obuf)[3] = t ^ lp32(iv)[3], lp32(iv)[3] = t; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + cnt += AES_BLOCK_SIZE; + } + else +# endif + while(cnt + AES_BLOCK_SIZE <= len) + { uint8_t t = 0; + + assert(b_pos == 0); + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + t = ibuf[ 0], obuf[ 0] = t ^ iv[ 0], iv[ 0] = t; + t = ibuf[ 1], obuf[ 1] = t ^ iv[ 1], iv[ 1] = t; + t = ibuf[ 2], obuf[ 2] = t ^ iv[ 2], iv[ 2] = t; + t = ibuf[ 3], obuf[ 3] = t ^ iv[ 3], iv[ 3] = t; + t = ibuf[ 4], obuf[ 4] = t ^ iv[ 4], iv[ 4] = t; + t = ibuf[ 5], obuf[ 5] = t ^ iv[ 5], iv[ 5] = t; + t = ibuf[ 6], obuf[ 6] = t ^ iv[ 6], iv[ 6] = t; + t = ibuf[ 7], obuf[ 7] = t ^ iv[ 7], iv[ 7] = t; + t = ibuf[ 8], obuf[ 8] = t ^ iv[ 8], iv[ 8] = t; + t = ibuf[ 9], obuf[ 9] = t ^ iv[ 9], iv[ 9] = t; + t = ibuf[10], obuf[10] = t ^ iv[10], iv[10] = t; + t = ibuf[11], obuf[11] = t ^ iv[11], iv[11] = t; + t = ibuf[12], obuf[12] = t ^ iv[12], iv[12] = t; + t = ibuf[13], obuf[13] = t ^ iv[13], iv[13] = t; + t = ibuf[14], obuf[14] = t ^ iv[14], iv[14] = t; + t = ibuf[15], obuf[15] = t ^ iv[15], iv[15] = t; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + cnt += AES_BLOCK_SIZE; + } +#endif + } + + while(cnt < len) + { uint8_t t = 0; + + if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + + while(cnt < len && b_pos < AES_BLOCK_SIZE) + { + t = *ibuf++; + *obuf++ = t ^ iv[b_pos]; + iv[b_pos++] = t; + cnt++; + } + + b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); + } + + ctx->inf.b[2] = (uint8_t)b_pos; + return EXIT_SUCCESS; +} + +AES_RETURN aes_ofb_crypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, aes_encrypt_ctx ctx[1]) +{ int cnt = 0, b_pos = (int)ctx->inf.b[2], nb = 0; + + if(b_pos) /* complete any partial block */ + { + while(b_pos < AES_BLOCK_SIZE && cnt < len) + { + *obuf++ = iv[b_pos++] ^ *ibuf++; + cnt++; + } + + b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); + } + + if((nb = (len - cnt) >> AES_BLOCK_SIZE_P2) != 0) /* process whole blocks */ + { +#if defined( USE_VIA_ACE_IF_PRESENT ) + + if(ctx->inf.b[1] == 0xff) + { int m = 0; + uint8_t *ksp = (uint8_t*)(ctx->ks), *ivp = iv; + aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16); + via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); + + if(ALIGN_OFFSET( ctx, 16 )) + return EXIT_FAILURE; + + if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */ + { + ivp = liv; + memcpy(liv, iv, AES_BLOCK_SIZE); + } + + if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 )) + { + via_ofb_op6(ksp, cwd, ibuf, obuf, nb, ivp); + ibuf += nb * AES_BLOCK_SIZE; + obuf += nb * AES_BLOCK_SIZE; + cnt += nb * AES_BLOCK_SIZE; + } + else /* input, output or both are unaligned */ + { aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); + uint8_t *ip = NULL, *op = NULL; + + while(nb) + { + m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m; + + ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); + op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); + + if(ip != ibuf) + memcpy(buf, ibuf, m * AES_BLOCK_SIZE); + + via_ofb_op6(ksp, cwd, ip, op, m, ivp); + + if(op != obuf) + memcpy(obuf, buf, m * AES_BLOCK_SIZE); + + ibuf += m * AES_BLOCK_SIZE; + obuf += m * AES_BLOCK_SIZE; + cnt += m * AES_BLOCK_SIZE; + } + } + + if(ivp != iv) + memcpy(iv, ivp, AES_BLOCK_SIZE); + } +#else +# ifdef FAST_BUFFER_OPERATIONS + if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 )) + while(cnt + AES_BLOCK_SIZE <= len) + { + assert(b_pos == 0); + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + lp32(obuf)[0] = lp32(iv)[0] ^ lp32(ibuf)[0]; + lp32(obuf)[1] = lp32(iv)[1] ^ lp32(ibuf)[1]; + lp32(obuf)[2] = lp32(iv)[2] ^ lp32(ibuf)[2]; + lp32(obuf)[3] = lp32(iv)[3] ^ lp32(ibuf)[3]; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + cnt += AES_BLOCK_SIZE; + } + else +# endif + while(cnt + AES_BLOCK_SIZE <= len) + { + assert(b_pos == 0); + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + obuf[ 0] = iv[ 0] ^ ibuf[ 0]; obuf[ 1] = iv[ 1] ^ ibuf[ 1]; + obuf[ 2] = iv[ 2] ^ ibuf[ 2]; obuf[ 3] = iv[ 3] ^ ibuf[ 3]; + obuf[ 4] = iv[ 4] ^ ibuf[ 4]; obuf[ 5] = iv[ 5] ^ ibuf[ 5]; + obuf[ 6] = iv[ 6] ^ ibuf[ 6]; obuf[ 7] = iv[ 7] ^ ibuf[ 7]; + obuf[ 8] = iv[ 8] ^ ibuf[ 8]; obuf[ 9] = iv[ 9] ^ ibuf[ 9]; + obuf[10] = iv[10] ^ ibuf[10]; obuf[11] = iv[11] ^ ibuf[11]; + obuf[12] = iv[12] ^ ibuf[12]; obuf[13] = iv[13] ^ ibuf[13]; + obuf[14] = iv[14] ^ ibuf[14]; obuf[15] = iv[15] ^ ibuf[15]; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + cnt += AES_BLOCK_SIZE; + } +#endif + } + + while(cnt < len) + { + if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + + while(cnt < len && b_pos < AES_BLOCK_SIZE) + { + *obuf++ = iv[b_pos++] ^ *ibuf++; + cnt++; + } + + b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); + } + + ctx->inf.b[2] = (uint8_t)b_pos; + return EXIT_SUCCESS; +} + +#define BFR_LENGTH (BFR_BLOCKS * AES_BLOCK_SIZE) + +AES_RETURN aes_ctr_crypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx ctx[1]) +{ unsigned char *ip = NULL; + int i = 0, blen = 0, b_pos = (int)(ctx->inf.b[2]); + +#if defined( USE_VIA_ACE_IF_PRESENT ) + aligned_auto(uint8_t, buf, BFR_LENGTH, 16); + if(ctx->inf.b[1] == 0xff && ALIGN_OFFSET( ctx, 16 )) + return EXIT_FAILURE; +#else + uint8_t buf[BFR_LENGTH] = {0}; +#endif + + if(b_pos) + { + memcpy(buf, cbuf, AES_BLOCK_SIZE); + if(aes_ecb_encrypt(buf, buf, AES_BLOCK_SIZE, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + + while(b_pos < AES_BLOCK_SIZE && len) + { + *obuf++ = *ibuf++ ^ buf[b_pos++]; + --len; + } + + if(len) + ctr_inc(cbuf), b_pos = 0; + } + + while(len) + { + blen = (len > BFR_LENGTH ? BFR_LENGTH : len), len -= blen; + + for(i = 0, ip = buf; i < (blen >> AES_BLOCK_SIZE_P2); ++i) + { + memcpy(ip, cbuf, AES_BLOCK_SIZE); + ctr_inc(cbuf); + ip += AES_BLOCK_SIZE; + } + + if(blen & (AES_BLOCK_SIZE - 1)) + memcpy(ip, cbuf, AES_BLOCK_SIZE), i++; + +#if defined( USE_VIA_ACE_IF_PRESENT ) + if(ctx->inf.b[1] == 0xff) + { + via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); + via_ecb_op5((ctx->ks), cwd, buf, buf, i); + } + else +#endif + if(aes_ecb_encrypt(buf, buf, i * AES_BLOCK_SIZE, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + + i = 0; ip = buf; +# ifdef FAST_BUFFER_OPERATIONS + if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( ip, 4 )) + while(i + AES_BLOCK_SIZE <= blen) + { + lp32(obuf)[0] = lp32(ibuf)[0] ^ lp32(ip)[0]; + lp32(obuf)[1] = lp32(ibuf)[1] ^ lp32(ip)[1]; + lp32(obuf)[2] = lp32(ibuf)[2] ^ lp32(ip)[2]; + lp32(obuf)[3] = lp32(ibuf)[3] ^ lp32(ip)[3]; + i += AES_BLOCK_SIZE; + ip += AES_BLOCK_SIZE; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } + else +#endif + while(i + AES_BLOCK_SIZE <= blen) + { + obuf[ 0] = ibuf[ 0] ^ ip[ 0]; obuf[ 1] = ibuf[ 1] ^ ip[ 1]; + obuf[ 2] = ibuf[ 2] ^ ip[ 2]; obuf[ 3] = ibuf[ 3] ^ ip[ 3]; + obuf[ 4] = ibuf[ 4] ^ ip[ 4]; obuf[ 5] = ibuf[ 5] ^ ip[ 5]; + obuf[ 6] = ibuf[ 6] ^ ip[ 6]; obuf[ 7] = ibuf[ 7] ^ ip[ 7]; + obuf[ 8] = ibuf[ 8] ^ ip[ 8]; obuf[ 9] = ibuf[ 9] ^ ip[ 9]; + obuf[10] = ibuf[10] ^ ip[10]; obuf[11] = ibuf[11] ^ ip[11]; + obuf[12] = ibuf[12] ^ ip[12]; obuf[13] = ibuf[13] ^ ip[13]; + obuf[14] = ibuf[14] ^ ip[14]; obuf[15] = ibuf[15] ^ ip[15]; + i += AES_BLOCK_SIZE; + ip += AES_BLOCK_SIZE; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } + + while(i++ < blen) + *obuf++ = *ibuf++ ^ ip[b_pos++]; + } + + ctx->inf.b[2] = (uint8_t)b_pos; + return EXIT_SUCCESS; +} + +void aes_ctr_cbuf_inc(unsigned char *cbuf) +{ + int i = AES_BLOCK_SIZE - 1; + while (i >= 0) { + cbuf[i]++; + if (cbuf[i]) return; // if there was no overflow + i--; + } +} + +#if defined(__cplusplus) +} +#endif +#endif diff --git a/deps/crypto/trezor-crypto/aes/aescrypt.c b/deps/crypto/trezor-crypto/aes/aescrypt.c new file mode 100644 index 000000000..4d0fcdefe --- /dev/null +++ b/deps/crypto/trezor-crypto/aes/aescrypt.c @@ -0,0 +1,307 @@ +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 +*/ + +#include "aesopt.h" +#include "aestab.h" + +#if defined( USE_INTEL_AES_IF_PRESENT ) +# include "aes_ni.h" +#else +/* map names here to provide the external API ('name' -> 'aes_name') */ +# define aes_xi(x) aes_ ## x +#endif + +#if defined(__cplusplus) +extern "C" +{ +#endif + +#define si(y,x,k,c) (s(y,c) = word_in(x, c) ^ (k)[c]) +#define so(y,x,c) word_out(y, c, s(x,c)) + +#if defined(ARRAYS) +#define locals(y,x) x[4] = {0}, y[4] = {0} +#else +#define locals(y,x) x##0=0,x##1=0,x##2=0,x##3=0,y##0=0,y##1=0,y##2=0,y##3=0 +#endif + +#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \ + s(y,2) = s(x,2); s(y,3) = s(x,3); +#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3) +#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3) +#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3) + +#if ( FUNCS_IN_C & ENCRYPTION_IN_C ) + +/* Visual C++ .Net v7.1 provides the fastest encryption code when using + Pentium optimiation with small code but this is poor for decryption + so we need to control this with the following VC++ pragmas +*/ + +#if defined( _MSC_VER ) && !defined( _WIN64 ) && !defined( __clang__ ) +#pragma optimize( "s", on ) +#endif + +/* Given the column (c) of the output state variable, the following + macros give the input state variables which are needed in its + computation for each row (r) of the state. All the alternative + macros give the same end values but expand into different ways + of calculating these values. In particular the complex macro + used for dynamically variable block sizes is designed to expand + to a compile time constant whenever possible but will expand to + conditional clauses on some branches (I am grateful to Frank + Yellin for this construction) +*/ + +#define fwd_var(x,r,c)\ + ( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\ + : r == 1 ? ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))\ + : r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\ + : ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2))) + +#if defined(FT4_SET) +#undef dec_fmvars +#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,n),fwd_var,rf1,c)) +#elif defined(FT1_SET) +#undef dec_fmvars +#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(f,n),fwd_var,rf1,c)) +#else +#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ fwd_mcol(no_table(x,t_use(s,box),fwd_var,rf1,c))) +#endif + +#if defined(FL4_SET) +#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,l),fwd_var,rf1,c)) +#elif defined(FL1_SET) +#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(f,l),fwd_var,rf1,c)) +#else +#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ no_table(x,t_use(s,box),fwd_var,rf1,c)) +#endif + +AES_RETURN aes_xi(encrypt)(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1]) +{ uint32_t locals(b0, b1); + const uint32_t *kp = NULL; +#if defined( dec_fmvars ) + dec_fmvars; /* declare variables for fwd_mcol() if needed */ +#endif + + if(cx->inf.b[0] != 10 * AES_BLOCK_SIZE && cx->inf.b[0] != 12 * AES_BLOCK_SIZE && cx->inf.b[0] != 14 * AES_BLOCK_SIZE) + return EXIT_FAILURE; + + kp = cx->ks; + state_in(b0, in, kp); + +#if (ENC_UNROLL == FULL) + + switch(cx->inf.b[0]) + { + case 14 * AES_BLOCK_SIZE: + round(fwd_rnd, b1, b0, kp + 1 * N_COLS); + round(fwd_rnd, b0, b1, kp + 2 * N_COLS); + kp += 2 * N_COLS; + //-fallthrough + case 12 * AES_BLOCK_SIZE: + round(fwd_rnd, b1, b0, kp + 1 * N_COLS); + round(fwd_rnd, b0, b1, kp + 2 * N_COLS); + kp += 2 * N_COLS; + //-fallthrough + case 10 * AES_BLOCK_SIZE: + round(fwd_rnd, b1, b0, kp + 1 * N_COLS); + round(fwd_rnd, b0, b1, kp + 2 * N_COLS); + round(fwd_rnd, b1, b0, kp + 3 * N_COLS); + round(fwd_rnd, b0, b1, kp + 4 * N_COLS); + round(fwd_rnd, b1, b0, kp + 5 * N_COLS); + round(fwd_rnd, b0, b1, kp + 6 * N_COLS); + round(fwd_rnd, b1, b0, kp + 7 * N_COLS); + round(fwd_rnd, b0, b1, kp + 8 * N_COLS); + round(fwd_rnd, b1, b0, kp + 9 * N_COLS); + round(fwd_lrnd, b0, b1, kp +10 * N_COLS); + //-fallthrough + } + +#else + +#if (ENC_UNROLL == PARTIAL) + { uint32_t rnd = 0; + for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd) + { + kp += N_COLS; + round(fwd_rnd, b1, b0, kp); + kp += N_COLS; + round(fwd_rnd, b0, b1, kp); + } + kp += N_COLS; + round(fwd_rnd, b1, b0, kp); +#else + { uint32_t rnd = 0; + for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd) + { + kp += N_COLS; + round(fwd_rnd, b1, b0, kp); + l_copy(b0, b1); + } +#endif + kp += N_COLS; + round(fwd_lrnd, b0, b1, kp); + } +#endif + + state_out(out, b0); + return EXIT_SUCCESS; +} + +#endif + +#if ( FUNCS_IN_C & DECRYPTION_IN_C) + +/* Visual C++ .Net v7.1 provides the fastest encryption code when using + Pentium optimiation with small code but this is poor for decryption + so we need to control this with the following VC++ pragmas +*/ + +#if defined( _MSC_VER ) && !defined( _WIN64 ) && !defined( __clang__ ) +#pragma optimize( "t", on ) +#endif + +/* Given the column (c) of the output state variable, the following + macros give the input state variables which are needed in its + computation for each row (r) of the state. All the alternative + macros give the same end values but expand into different ways + of calculating these values. In particular the complex macro + used for dynamically variable block sizes is designed to expand + to a compile time constant whenever possible but will expand to + conditional clauses on some branches (I am grateful to Frank + Yellin for this construction) +*/ + +#define inv_var(x,r,c)\ + ( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\ + : r == 1 ? ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2))\ + : r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\ + : ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))) + +#if defined(IT4_SET) +#undef dec_imvars +#define inv_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,n),inv_var,rf1,c)) +#elif defined(IT1_SET) +#undef dec_imvars +#define inv_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(i,n),inv_var,rf1,c)) +#else +#define inv_rnd(y,x,k,c) (s(y,c) = inv_mcol((k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c))) +#endif + +#if defined(IL4_SET) +#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,l),inv_var,rf1,c)) +#elif defined(IL1_SET) +#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(i,l),inv_var,rf1,c)) +#else +#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c)) +#endif + +/* This code can work with the decryption key schedule in the */ +/* order that is used for encrytpion (where the 1st decryption */ +/* round key is at the high end ot the schedule) or with a key */ +/* schedule that has been reversed to put the 1st decryption */ +/* round key at the low end of the schedule in memory (when */ +/* AES_REV_DKS is defined) */ + +#ifdef AES_REV_DKS +#define key_ofs 0 +#define rnd_key(n) (kp + n * N_COLS) +#else +#define key_ofs 1 +#define rnd_key(n) (kp - n * N_COLS) +#endif + +AES_RETURN aes_xi(decrypt)(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1]) +{ uint32_t locals(b0, b1); +#if defined( dec_imvars ) + dec_imvars; /* declare variables for inv_mcol() if needed */ +#endif + const uint32_t *kp = NULL; + + if(cx->inf.b[0] != 10 * AES_BLOCK_SIZE && cx->inf.b[0] != 12 * AES_BLOCK_SIZE && cx->inf.b[0] != 14 * AES_BLOCK_SIZE) + return EXIT_FAILURE; + + kp = cx->ks + (key_ofs ? (cx->inf.b[0] >> 2) : 0); + state_in(b0, in, kp); + +#if (DEC_UNROLL == FULL) + + kp = cx->ks + (key_ofs ? 0 : (cx->inf.b[0] >> 2)); + switch(cx->inf.b[0]) + { + case 14 * AES_BLOCK_SIZE: + round(inv_rnd, b1, b0, rnd_key(-13)); + round(inv_rnd, b0, b1, rnd_key(-12)); + //-fallthrough + case 12 * AES_BLOCK_SIZE: + round(inv_rnd, b1, b0, rnd_key(-11)); + round(inv_rnd, b0, b1, rnd_key(-10)); + //-fallthrough + case 10 * AES_BLOCK_SIZE: + round(inv_rnd, b1, b0, rnd_key(-9)); + round(inv_rnd, b0, b1, rnd_key(-8)); + round(inv_rnd, b1, b0, rnd_key(-7)); + round(inv_rnd, b0, b1, rnd_key(-6)); + round(inv_rnd, b1, b0, rnd_key(-5)); + round(inv_rnd, b0, b1, rnd_key(-4)); + round(inv_rnd, b1, b0, rnd_key(-3)); + round(inv_rnd, b0, b1, rnd_key(-2)); + round(inv_rnd, b1, b0, rnd_key(-1)); + round(inv_lrnd, b0, b1, rnd_key( 0)); + //-fallthrough + } + +#else + +#if (DEC_UNROLL == PARTIAL) + { uint32_t rnd = 0; + for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd) + { + kp = rnd_key(1); + round(inv_rnd, b1, b0, kp); + kp = rnd_key(1); + round(inv_rnd, b0, b1, kp); + } + kp = rnd_key(1); + round(inv_rnd, b1, b0, kp); +#else + { uint32_t rnd = 0; + for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd) + { + kp = rnd_key(1); + round(inv_rnd, b1, b0, kp); + l_copy(b0, b1); + } +#endif + kp = rnd_key(1); + round(inv_lrnd, b0, b1, kp); + } +#endif + + state_out(out, b0); + return EXIT_SUCCESS; +} + +#endif + +#if defined(__cplusplus) +} +#endif diff --git a/deps/crypto/trezor-crypto/aes/aeskey.c b/deps/crypto/trezor-crypto/aes/aeskey.c new file mode 100644 index 000000000..f675d6968 --- /dev/null +++ b/deps/crypto/trezor-crypto/aes/aeskey.c @@ -0,0 +1,560 @@ +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 +*/ + +#include "aesopt.h" +#include "aestab.h" + +#if defined( USE_INTEL_AES_IF_PRESENT ) +# include "aes_ni.h" +#else +/* map names here to provide the external API ('name' -> 'aes_name') */ +# define aes_xi(x) aes_ ## x +#endif + +#ifdef USE_VIA_ACE_IF_PRESENT +# include "aes_via_ace.h" +#endif + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/* Initialise the key schedule from the user supplied key. The key + length can be specified in bytes, with legal values of 16, 24 + and 32, or in bits, with legal values of 128, 192 and 256. These + values correspond with Nk values of 4, 6 and 8 respectively. + + The following macros implement a single cycle in the key + schedule generation process. The number of cycles needed + for each cx->n_col and nk value is: + + nk = 4 5 6 7 8 + ------------------------------ + cx->n_col = 4 10 9 8 7 7 + cx->n_col = 5 14 11 10 9 9 + cx->n_col = 6 19 15 12 11 11 + cx->n_col = 7 21 19 16 13 14 + cx->n_col = 8 29 23 19 17 14 +*/ + +#if defined( REDUCE_CODE_SIZE ) +# define ls_box ls_sub + uint32_t ls_sub(const uint32_t t, const uint32_t n); +# define inv_mcol im_sub + uint32_t im_sub(const uint32_t x); +# ifdef ENC_KS_UNROLL +# undef ENC_KS_UNROLL +# endif +# ifdef DEC_KS_UNROLL +# undef DEC_KS_UNROLL +# endif +#endif + +#if (FUNCS_IN_C & ENC_KEYING_IN_C) + +#if defined(AES_128) || defined( AES_VAR ) + +#define ke4(k,i) \ +{ k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; \ + k[4*(i)+5] = ss[1] ^= ss[0]; \ + k[4*(i)+6] = ss[2] ^= ss[1]; \ + k[4*(i)+7] = ss[3] ^= ss[2]; \ +} + +AES_RETURN aes_xi(encrypt_key128)(const unsigned char *key, aes_encrypt_ctx cx[1]) +{ uint32_t ss[4] = {0}; + + cx->ks[0] = ss[0] = word_in(key, 0); + cx->ks[1] = ss[1] = word_in(key, 1); + cx->ks[2] = ss[2] = word_in(key, 2); + cx->ks[3] = ss[3] = word_in(key, 3); + +#ifdef ENC_KS_UNROLL + ke4(cx->ks, 0); ke4(cx->ks, 1); + ke4(cx->ks, 2); ke4(cx->ks, 3); + ke4(cx->ks, 4); ke4(cx->ks, 5); + ke4(cx->ks, 6); ke4(cx->ks, 7); + ke4(cx->ks, 8); +#else + { uint32_t i = 0; + for(i = 0; i < 9; ++i) + ke4(cx->ks, i); + } +#endif + ke4(cx->ks, 9); + cx->inf.l = 0; + cx->inf.b[0] = 10 * AES_BLOCK_SIZE; + +#ifdef USE_VIA_ACE_IF_PRESENT + if(VIA_ACE_AVAILABLE) + cx->inf.b[1] = 0xff; +#endif + return EXIT_SUCCESS; +} + +#endif + +#if defined(AES_192) || defined( AES_VAR ) + +#define kef6(k,i) \ +{ k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; \ + k[6*(i)+ 7] = ss[1] ^= ss[0]; \ + k[6*(i)+ 8] = ss[2] ^= ss[1]; \ + k[6*(i)+ 9] = ss[3] ^= ss[2]; \ +} + +#define ke6(k,i) \ +{ kef6(k,i); \ + k[6*(i)+10] = ss[4] ^= ss[3]; \ + k[6*(i)+11] = ss[5] ^= ss[4]; \ +} + +AES_RETURN aes_xi(encrypt_key192)(const unsigned char *key, aes_encrypt_ctx cx[1]) +{ uint32_t ss[6] = {0}; + + cx->ks[0] = ss[0] = word_in(key, 0); + cx->ks[1] = ss[1] = word_in(key, 1); + cx->ks[2] = ss[2] = word_in(key, 2); + cx->ks[3] = ss[3] = word_in(key, 3); + cx->ks[4] = ss[4] = word_in(key, 4); + cx->ks[5] = ss[5] = word_in(key, 5); + +#ifdef ENC_KS_UNROLL + ke6(cx->ks, 0); ke6(cx->ks, 1); + ke6(cx->ks, 2); ke6(cx->ks, 3); + ke6(cx->ks, 4); ke6(cx->ks, 5); + ke6(cx->ks, 6); +#else + { uint32_t i = 0; + for(i = 0; i < 7; ++i) + ke6(cx->ks, i); + } +#endif + kef6(cx->ks, 7); + cx->inf.l = 0; + cx->inf.b[0] = 12 * AES_BLOCK_SIZE; + +#ifdef USE_VIA_ACE_IF_PRESENT + if(VIA_ACE_AVAILABLE) + cx->inf.b[1] = 0xff; +#endif + return EXIT_SUCCESS; +} + +#endif + +#if defined(AES_256) || defined( AES_VAR ) + +#define kef8(k,i) \ +{ k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; \ + k[8*(i)+ 9] = ss[1] ^= ss[0]; \ + k[8*(i)+10] = ss[2] ^= ss[1]; \ + k[8*(i)+11] = ss[3] ^= ss[2]; \ +} + +#define ke8(k,i) \ +{ kef8(k,i); \ + k[8*(i)+12] = ss[4] ^= ls_box(ss[3],0); \ + k[8*(i)+13] = ss[5] ^= ss[4]; \ + k[8*(i)+14] = ss[6] ^= ss[5]; \ + k[8*(i)+15] = ss[7] ^= ss[6]; \ +} + +AES_RETURN aes_xi(encrypt_key256)(const unsigned char *key, aes_encrypt_ctx cx[1]) +{ uint32_t ss[8] = {0}; + + cx->ks[0] = ss[0] = word_in(key, 0); + cx->ks[1] = ss[1] = word_in(key, 1); + cx->ks[2] = ss[2] = word_in(key, 2); + cx->ks[3] = ss[3] = word_in(key, 3); + cx->ks[4] = ss[4] = word_in(key, 4); + cx->ks[5] = ss[5] = word_in(key, 5); + cx->ks[6] = ss[6] = word_in(key, 6); + cx->ks[7] = ss[7] = word_in(key, 7); + +#ifdef ENC_KS_UNROLL + ke8(cx->ks, 0); ke8(cx->ks, 1); + ke8(cx->ks, 2); ke8(cx->ks, 3); + ke8(cx->ks, 4); ke8(cx->ks, 5); +#else + { uint32_t i = 0; + for(i = 0; i < 6; ++i) + ke8(cx->ks, i); + } +#endif + kef8(cx->ks, 6); + cx->inf.l = 0; + cx->inf.b[0] = 14 * AES_BLOCK_SIZE; + +#ifdef USE_VIA_ACE_IF_PRESENT + if(VIA_ACE_AVAILABLE) + cx->inf.b[1] = 0xff; +#endif + return EXIT_SUCCESS; +} + +#endif + +#endif + +#if (FUNCS_IN_C & DEC_KEYING_IN_C) + +/* this is used to store the decryption round keys */ +/* in forward or reverse order */ + +#ifdef AES_REV_DKS +#define v(n,i) ((n) - (i) + 2 * ((i) & 3)) +#else +#define v(n,i) (i) +#endif + +#if DEC_ROUND == NO_TABLES +#define ff(x) (x) +#else +#define ff(x) inv_mcol(x) +#if defined( dec_imvars ) +#define d_vars dec_imvars +#endif +#endif + +#if defined(AES_128) || defined( AES_VAR ) + +#define k4e(k,i) \ +{ k[v(40,(4*(i))+4)] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; \ + k[v(40,(4*(i))+5)] = ss[1] ^= ss[0]; \ + k[v(40,(4*(i))+6)] = ss[2] ^= ss[1]; \ + k[v(40,(4*(i))+7)] = ss[3] ^= ss[2]; \ +} + +#if 1 + +#define kdf4(k,i) \ +{ ss[0] = ss[0] ^ ss[2] ^ ss[1] ^ ss[3]; \ + ss[1] = ss[1] ^ ss[3]; \ + ss[2] = ss[2] ^ ss[3]; \ + ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; \ + ss[i % 4] ^= ss[4]; \ + ss[4] ^= k[v(40,(4*(i)))]; k[v(40,(4*(i))+4)] = ff(ss[4]); \ + ss[4] ^= k[v(40,(4*(i))+1)]; k[v(40,(4*(i))+5)] = ff(ss[4]); \ + ss[4] ^= k[v(40,(4*(i))+2)]; k[v(40,(4*(i))+6)] = ff(ss[4]); \ + ss[4] ^= k[v(40,(4*(i))+3)]; k[v(40,(4*(i))+7)] = ff(ss[4]); \ +} + +#define kd4(k,i) \ +{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; \ + ss[i % 4] ^= ss[4]; ss[4] = ff(ss[4]); \ + k[v(40,(4*(i))+4)] = ss[4] ^= k[v(40,(4*(i)))]; \ + k[v(40,(4*(i))+5)] = ss[4] ^= k[v(40,(4*(i))+1)]; \ + k[v(40,(4*(i))+6)] = ss[4] ^= k[v(40,(4*(i))+2)]; \ + k[v(40,(4*(i))+7)] = ss[4] ^= k[v(40,(4*(i))+3)]; \ +} + +#define kdl4(k,i) \ +{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; ss[i % 4] ^= ss[4]; \ + k[v(40,(4*(i))+4)] = (ss[0] ^= ss[1]) ^ ss[2] ^ ss[3]; \ + k[v(40,(4*(i))+5)] = ss[1] ^ ss[3]; \ + k[v(40,(4*(i))+6)] = ss[0]; \ + k[v(40,(4*(i))+7)] = ss[1]; \ +} + +#else + +#define kdf4(k,i) \ +{ ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[v(40,(4*(i))+ 4)] = ff(ss[0]); \ + ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ff(ss[1]); \ + ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ff(ss[2]); \ + ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ff(ss[3]); \ +} + +#define kd4(k,i) \ +{ ss[4] = ls_box(ss[3],3) ^ t_use(r,c)[i]; \ + ss[0] ^= ss[4]; ss[4] = ff(ss[4]); k[v(40,(4*(i))+ 4)] = ss[4] ^= k[v(40,(4*(i)))]; \ + ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ss[4] ^= k[v(40,(4*(i))+ 1)]; \ + ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ss[4] ^= k[v(40,(4*(i))+ 2)]; \ + ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ss[4] ^= k[v(40,(4*(i))+ 3)]; \ +} + +#define kdl4(k,i) \ +{ ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[v(40,(4*(i))+ 4)] = ss[0]; \ + ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ss[1]; \ + ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ss[2]; \ + ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ss[3]; \ +} + +#endif + +AES_RETURN aes_xi(decrypt_key128)(const unsigned char *key, aes_decrypt_ctx cx[1]) +{ uint32_t ss[5] = {0}; +#if defined( d_vars ) + d_vars; +#endif + + cx->ks[v(40,(0))] = ss[0] = word_in(key, 0); + cx->ks[v(40,(1))] = ss[1] = word_in(key, 1); + cx->ks[v(40,(2))] = ss[2] = word_in(key, 2); + cx->ks[v(40,(3))] = ss[3] = word_in(key, 3); + +#ifdef DEC_KS_UNROLL + kdf4(cx->ks, 0); kd4(cx->ks, 1); + kd4(cx->ks, 2); kd4(cx->ks, 3); + kd4(cx->ks, 4); kd4(cx->ks, 5); + kd4(cx->ks, 6); kd4(cx->ks, 7); + kd4(cx->ks, 8); kdl4(cx->ks, 9); +#else + { uint32_t i = 0; + for(i = 0; i < 10; ++i) + k4e(cx->ks, i); +#if !(DEC_ROUND == NO_TABLES) + for(i = N_COLS; i < 10 * N_COLS; ++i) + cx->ks[i] = inv_mcol(cx->ks[i]); +#endif + } +#endif + cx->inf.l = 0; + cx->inf.b[0] = 10 * AES_BLOCK_SIZE; + +#ifdef USE_VIA_ACE_IF_PRESENT + if(VIA_ACE_AVAILABLE) + cx->inf.b[1] = 0xff; +#endif + return EXIT_SUCCESS; +} + +#endif + +#if defined(AES_192) || defined( AES_VAR ) + +#define k6ef(k,i) \ +{ k[v(48,(6*(i))+ 6)] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; \ + k[v(48,(6*(i))+ 7)] = ss[1] ^= ss[0]; \ + k[v(48,(6*(i))+ 8)] = ss[2] ^= ss[1]; \ + k[v(48,(6*(i))+ 9)] = ss[3] ^= ss[2]; \ +} + +#define k6e(k,i) \ +{ k6ef(k,i); \ + k[v(48,(6*(i))+10)] = ss[4] ^= ss[3]; \ + k[v(48,(6*(i))+11)] = ss[5] ^= ss[4]; \ +} + +#define kdf6(k,i) \ +{ ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[v(48,(6*(i))+ 6)] = ff(ss[0]); \ + ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ff(ss[1]); \ + ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ff(ss[2]); \ + ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ff(ss[3]); \ + ss[4] ^= ss[3]; k[v(48,(6*(i))+10)] = ff(ss[4]); \ + ss[5] ^= ss[4]; k[v(48,(6*(i))+11)] = ff(ss[5]); \ +} + +#define kd6(k,i) \ +{ ss[6] = ls_box(ss[5],3) ^ t_use(r,c)[i]; \ + ss[0] ^= ss[6]; ss[6] = ff(ss[6]); k[v(48,(6*(i))+ 6)] = ss[6] ^= k[v(48,(6*(i)))]; \ + ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ss[6] ^= k[v(48,(6*(i))+ 1)]; \ + ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ss[6] ^= k[v(48,(6*(i))+ 2)]; \ + ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ss[6] ^= k[v(48,(6*(i))+ 3)]; \ + ss[4] ^= ss[3]; k[v(48,(6*(i))+10)] = ss[6] ^= k[v(48,(6*(i))+ 4)]; \ + ss[5] ^= ss[4]; k[v(48,(6*(i))+11)] = ss[6] ^= k[v(48,(6*(i))+ 5)]; \ +} + +#define kdl6(k,i) \ +{ ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[v(48,(6*(i))+ 6)] = ss[0]; \ + ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ss[1]; \ + ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ss[2]; \ + ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ss[3]; \ +} + +AES_RETURN aes_xi(decrypt_key192)(const unsigned char *key, aes_decrypt_ctx cx[1]) +{ uint32_t ss[7] = {0}; +#if defined( d_vars ) + d_vars; +#endif + + cx->ks[v(48,(0))] = ss[0] = word_in(key, 0); + cx->ks[v(48,(1))] = ss[1] = word_in(key, 1); + cx->ks[v(48,(2))] = ss[2] = word_in(key, 2); + cx->ks[v(48,(3))] = ss[3] = word_in(key, 3); + +#ifdef DEC_KS_UNROLL + ss[4] = word_in(key, 4); + ss[5] = word_in(key, 5); + cx->ks[v(48,(4))] = ff(ss[4]); + cx->ks[v(48,(5))] = ff(ss[5]); + kdf6(cx->ks, 0); kd6(cx->ks, 1); + kd6(cx->ks, 2); kd6(cx->ks, 3); + kd6(cx->ks, 4); kd6(cx->ks, 5); + kd6(cx->ks, 6); kdl6(cx->ks, 7); +#else + cx->ks[v(48,(4))] = ss[4] = word_in(key, 4); + cx->ks[v(48,(5))] = ss[5] = word_in(key, 5); + { uint32_t i = 0; + + for(i = 0; i < 7; ++i) + k6e(cx->ks, i); + k6ef(cx->ks, 7); +#if !(DEC_ROUND == NO_TABLES) + for(i = N_COLS; i < 12 * N_COLS; ++i) + cx->ks[i] = inv_mcol(cx->ks[i]); +#endif + } +#endif + cx->inf.l = 0; + cx->inf.b[0] = 12 * AES_BLOCK_SIZE; + +#ifdef USE_VIA_ACE_IF_PRESENT + if(VIA_ACE_AVAILABLE) + cx->inf.b[1] = 0xff; +#endif + return EXIT_SUCCESS; +} + +#endif + +#if defined(AES_256) || defined( AES_VAR ) + +#define k8ef(k,i) \ +{ k[v(56,(8*(i))+ 8)] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; \ + k[v(56,(8*(i))+ 9)] = ss[1] ^= ss[0]; \ + k[v(56,(8*(i))+10)] = ss[2] ^= ss[1]; \ + k[v(56,(8*(i))+11)] = ss[3] ^= ss[2]; \ +} + +#define k8e(k,i) \ +{ k8ef(k,i); \ + k[v(56,(8*(i))+12)] = ss[4] ^= ls_box(ss[3],0); \ + k[v(56,(8*(i))+13)] = ss[5] ^= ss[4]; \ + k[v(56,(8*(i))+14)] = ss[6] ^= ss[5]; \ + k[v(56,(8*(i))+15)] = ss[7] ^= ss[6]; \ +} + +#define kdf8(k,i) \ +{ ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[v(56,(8*(i))+ 8)] = ff(ss[0]); \ + ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ff(ss[1]); \ + ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ff(ss[2]); \ + ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ff(ss[3]); \ + ss[4] ^= ls_box(ss[3],0); k[v(56,(8*(i))+12)] = ff(ss[4]); \ + ss[5] ^= ss[4]; k[v(56,(8*(i))+13)] = ff(ss[5]); \ + ss[6] ^= ss[5]; k[v(56,(8*(i))+14)] = ff(ss[6]); \ + ss[7] ^= ss[6]; k[v(56,(8*(i))+15)] = ff(ss[7]); \ +} + +#define kd8(k,i) \ +{ ss[8] = ls_box(ss[7],3) ^ t_use(r,c)[i]; \ + ss[0] ^= ss[8]; ss[8] = ff(ss[8]); k[v(56,(8*(i))+ 8)] = ss[8] ^= k[v(56,(8*(i)))]; \ + ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ss[8] ^= k[v(56,(8*(i))+ 1)]; \ + ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ss[8] ^= k[v(56,(8*(i))+ 2)]; \ + ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[8] ^= k[v(56,(8*(i))+ 3)]; \ + ss[8] = ls_box(ss[3],0); \ + ss[4] ^= ss[8]; ss[8] = ff(ss[8]); k[v(56,(8*(i))+12)] = ss[8] ^= k[v(56,(8*(i))+ 4)]; \ + ss[5] ^= ss[4]; k[v(56,(8*(i))+13)] = ss[8] ^= k[v(56,(8*(i))+ 5)]; \ + ss[6] ^= ss[5]; k[v(56,(8*(i))+14)] = ss[8] ^= k[v(56,(8*(i))+ 6)]; \ + ss[7] ^= ss[6]; k[v(56,(8*(i))+15)] = ss[8] ^= k[v(56,(8*(i))+ 7)]; \ +} + +#define kdl8(k,i) \ +{ ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[v(56,(8*(i))+ 8)] = ss[0]; \ + ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ss[1]; \ + ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ss[2]; \ + ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[3]; \ +} + +AES_RETURN aes_xi(decrypt_key256)(const unsigned char *key, aes_decrypt_ctx cx[1]) +{ uint32_t ss[9] = {0}; +#if defined( d_vars ) + d_vars; +#endif + + cx->ks[v(56,(0))] = ss[0] = word_in(key, 0); + cx->ks[v(56,(1))] = ss[1] = word_in(key, 1); + cx->ks[v(56,(2))] = ss[2] = word_in(key, 2); + cx->ks[v(56,(3))] = ss[3] = word_in(key, 3); + +#ifdef DEC_KS_UNROLL + ss[4] = word_in(key, 4); + ss[5] = word_in(key, 5); + ss[6] = word_in(key, 6); + ss[7] = word_in(key, 7); + cx->ks[v(56,(4))] = ff(ss[4]); + cx->ks[v(56,(5))] = ff(ss[5]); + cx->ks[v(56,(6))] = ff(ss[6]); + cx->ks[v(56,(7))] = ff(ss[7]); + kdf8(cx->ks, 0); kd8(cx->ks, 1); + kd8(cx->ks, 2); kd8(cx->ks, 3); + kd8(cx->ks, 4); kd8(cx->ks, 5); + kdl8(cx->ks, 6); +#else + cx->ks[v(56,(4))] = ss[4] = word_in(key, 4); + cx->ks[v(56,(5))] = ss[5] = word_in(key, 5); + cx->ks[v(56,(6))] = ss[6] = word_in(key, 6); + cx->ks[v(56,(7))] = ss[7] = word_in(key, 7); + { uint32_t i = 0; + + for(i = 0; i < 6; ++i) + k8e(cx->ks, i); + k8ef(cx->ks, 6); +#if !(DEC_ROUND == NO_TABLES) + for(i = N_COLS; i < 14 * N_COLS; ++i) + cx->ks[i] = inv_mcol(cx->ks[i]); +#endif + } +#endif + cx->inf.l = 0; + cx->inf.b[0] = 14 * AES_BLOCK_SIZE; + +#ifdef USE_VIA_ACE_IF_PRESENT + if(VIA_ACE_AVAILABLE) + cx->inf.b[1] = 0xff; +#endif + return EXIT_SUCCESS; +} + +#endif + +#endif + +#if defined( AES_VAR ) + +AES_RETURN aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1]) +{ + switch(key_len) + { + case 16: case 128: return aes_encrypt_key128(key, cx); + case 24: case 192: return aes_encrypt_key192(key, cx); + case 32: case 256: return aes_encrypt_key256(key, cx); + default: return EXIT_FAILURE; + } +} + +AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1]) +{ + switch(key_len) + { + case 16: case 128: return aes_decrypt_key128(key, cx); + case 24: case 192: return aes_decrypt_key192(key, cx); + case 32: case 256: return aes_decrypt_key256(key, cx); + default: return EXIT_FAILURE; + } +} + +#endif + +#if defined(__cplusplus) +} +#endif diff --git a/deps/crypto/trezor-crypto/aes/aesopt.h b/deps/crypto/trezor-crypto/aes/aesopt.h new file mode 100644 index 000000000..d8dca1b3b --- /dev/null +++ b/deps/crypto/trezor-crypto/aes/aesopt.h @@ -0,0 +1,789 @@ +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 + + This file contains the compilation options for AES (Rijndael) and code + that is common across encryption, key scheduling and table generation. + + OPERATION + + These source code files implement the AES algorithm Rijndael designed by + Joan Daemen and Vincent Rijmen. This version is designed for the standard + block size of 16 bytes and for key sizes of 128, 192 and 256 bits (16, 24 + and 32 bytes). + + This version is designed for flexibility and speed using operations on + 32-bit words rather than operations on bytes. It can be compiled with + either big or little endian internal byte order but is faster when the + native byte order for the processor is used. + + THE CIPHER INTERFACE + + The cipher interface is implemented as an array of bytes in which lower + AES bit sequence indexes map to higher numeric significance within bytes. + + uint8_t (an unsigned 8-bit type) + uint32_t (an unsigned 32-bit type) + struct aes_encrypt_ctx (structure for the cipher encryption context) + struct aes_decrypt_ctx (structure for the cipher decryption context) + AES_RETURN the function return type + + C subroutine calls: + + AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]); + AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]); + AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]); + AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, + const aes_encrypt_ctx cx[1]); + + AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]); + AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]); + AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]); + AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, + const aes_decrypt_ctx cx[1]); + + IMPORTANT NOTE: If you are using this C interface with dynamic tables make sure that + you call aes_init() before AES is used so that the tables are initialised. + + C++ aes class subroutines: + + Class AESencrypt for encryption + + Constructors: + AESencrypt(void) + AESencrypt(const unsigned char *key) - 128 bit key + Members: + AES_RETURN key128(const unsigned char *key) + AES_RETURN key192(const unsigned char *key) + AES_RETURN key256(const unsigned char *key) + AES_RETURN encrypt(const unsigned char *in, unsigned char *out) const + + Class AESdecrypt for encryption + Constructors: + AESdecrypt(void) + AESdecrypt(const unsigned char *key) - 128 bit key + Members: + AES_RETURN key128(const unsigned char *key) + AES_RETURN key192(const unsigned char *key) + AES_RETURN key256(const unsigned char *key) + AES_RETURN decrypt(const unsigned char *in, unsigned char *out) const +*/ + +#if !defined( _AESOPT_H ) +#define _AESOPT_H + +#if defined( __cplusplus ) +#include "aescpp.h" +#else +#include "aes.h" +#endif + +/* PLATFORM SPECIFIC INCLUDES */ + +#define IS_BIG_ENDIAN 4321 +#define IS_LITTLE_ENDIAN 1234 +#define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN + +/* CONFIGURATION - THE USE OF DEFINES + + Later in this section there are a number of defines that control the + operation of the code. In each section, the purpose of each define is + explained so that the relevant form can be included or excluded by + setting either 1's or 0's respectively on the branches of the related + #if clauses. The following local defines should not be changed. +*/ + +#define ENCRYPTION_IN_C 1 +#define DECRYPTION_IN_C 2 +#define ENC_KEYING_IN_C 4 +#define DEC_KEYING_IN_C 8 + +#define NO_TABLES 0 +#define ONE_TABLE 1 +#define FOUR_TABLES 4 +#define NONE 0 +#define PARTIAL 1 +#define FULL 2 + +/* --- START OF USER CONFIGURED OPTIONS --- */ + +/* 1. BYTE ORDER WITHIN 32 BIT WORDS + + The fundamental data processing units in Rijndael are 8-bit bytes. The + input, output and key input are all enumerated arrays of bytes in which + bytes are numbered starting at zero and increasing to one less than the + number of bytes in the array in question. This enumeration is only used + for naming bytes and does not imply any adjacency or order relationship + from one byte to another. When these inputs and outputs are considered + as bit sequences, bits 8*n to 8*n+7 of the bit sequence are mapped to + byte[n] with bit 8n+i in the sequence mapped to bit 7-i within the byte. + In this implementation bits are numbered from 0 to 7 starting at the + numerically least significant end of each byte (bit n represents 2^n). + + However, Rijndael can be implemented more efficiently using 32-bit + words by packing bytes into words so that bytes 4*n to 4*n+3 are placed + into word[n]. While in principle these bytes can be assembled into words + in any positions, this implementation only supports the two formats in + which bytes in adjacent positions within words also have adjacent byte + numbers. This order is called big-endian if the lowest numbered bytes + in words have the highest numeric significance and little-endian if the + opposite applies. + + This code can work in either order irrespective of the order used by the + machine on which it runs. Normally the internal byte order will be set + to the order of the processor on which the code is to be run but this + define can be used to reverse this in special situations + + WARNING: Assembler code versions rely on PLATFORM_BYTE_ORDER being set. + This define will hence be redefined later (in section 4) if necessary +*/ + +#if 1 +# define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER +#elif 0 +# define ALGORITHM_BYTE_ORDER IS_LITTLE_ENDIAN +#elif 0 +# define ALGORITHM_BYTE_ORDER IS_BIG_ENDIAN +#else +# error The algorithm byte order is not defined +#endif + +/* 2. Intel AES AND VIA ACE SUPPORT */ + +#if defined( __GNUC__ ) && defined( __i386__ ) && !defined(__BEOS__) \ + || defined( _WIN32 ) && defined( _M_IX86 ) && !(defined( _WIN64 ) \ + || defined( _WIN32_WCE ) || defined( _MSC_VER ) && ( _MSC_VER <= 800 )) +# define VIA_ACE_POSSIBLE +#endif + +/* AESNI is supported by all Windows x64 compilers, but for Linux/GCC + we have to test for SSE 2, SSE 3, and AES to before enabling it; */ +#if !defined( INTEL_AES_POSSIBLE ) +# if defined( _WIN64 ) && defined( _MSC_VER ) \ + || defined( __GNUC__ ) && defined( __x86_64__ ) && \ + defined( __SSE2__ ) && defined( __SSE3__ ) && \ + defined( __AES__ ) +# define INTEL_AES_POSSIBLE +# endif +#endif + +/* Define this option if support for the Intel AESNI is required + If USE_INTEL_AES_IF_PRESENT is defined then AESNI will be used + if it is detected (both present and enabled). + + AESNI uses a decryption key schedule with the first decryption + round key at the high end of the key scedule with the following + round keys at lower positions in memory. So AES_REV_DKS must NOT + be defined when AESNI will be used. Although it is unlikely that + assembler code will be used with an AESNI build, if it is then + AES_REV_DKS must NOT be defined when the assembler files are + built (the definition of USE_INTEL_AES_IF_PRESENT in the assembler + code files must match that here if they are used). +*/ + +#if 0 && defined( INTEL_AES_POSSIBLE ) && !defined( USE_INTEL_AES_IF_PRESENT ) +# define USE_INTEL_AES_IF_PRESENT +#endif + +/* Define this option if support for the VIA ACE is required. This uses + inline assembler instructions and is only implemented for the Microsoft, + Intel and GCC compilers. If VIA ACE is known to be present, then defining + ASSUME_VIA_ACE_PRESENT will remove the ordinary encryption/decryption + code. If USE_VIA_ACE_IF_PRESENT is defined then VIA ACE will be used if + it is detected (both present and enabled) but the normal AES code will + also be present. + + When VIA ACE is to be used, all AES encryption contexts MUST be 16 byte + aligned; other input/output buffers do not need to be 16 byte aligned + but there are very large performance gains if this can be arranged. + VIA ACE also requires the decryption key schedule to be in reverse + order (which later checks below ensure). + + AES_REV_DKS must be set for assembler code used with a VIA ACE build +*/ + +#if 0 && defined( VIA_ACE_POSSIBLE ) && !defined( USE_VIA_ACE_IF_PRESENT ) +# define USE_VIA_ACE_IF_PRESENT +#endif + +#if 0 && defined( VIA_ACE_POSSIBLE ) && !defined( ASSUME_VIA_ACE_PRESENT ) +# define ASSUME_VIA_ACE_PRESENT +# endif + +/* 3. ASSEMBLER SUPPORT + + This define (which can be on the command line) enables the use of the + assembler code routines for encryption, decryption and key scheduling + as follows: + + ASM_X86_V1C uses the assembler (aes_x86_v1.asm) with large tables for + encryption and decryption and but with key scheduling in C + ASM_X86_V2 uses assembler (aes_x86_v2.asm) with compressed tables for + encryption, decryption and key scheduling + ASM_X86_V2C uses assembler (aes_x86_v2.asm) with compressed tables for + encryption and decryption and but with key scheduling in C + ASM_AMD64_C uses assembler (aes_amd64.asm) with compressed tables for + encryption and decryption and but with key scheduling in C + + Change one 'if 0' below to 'if 1' to select the version or define + as a compilation option. +*/ + +#if 0 && !defined( ASM_X86_V1C ) +# define ASM_X86_V1C +#elif 0 && !defined( ASM_X86_V2 ) +# define ASM_X86_V2 +#elif 0 && !defined( ASM_X86_V2C ) +# define ASM_X86_V2C +#elif 0 && !defined( ASM_AMD64_C ) +# define ASM_AMD64_C +#endif + +#if defined( __i386 ) || defined( _M_IX86 ) +# define A32_ +#elif defined( __x86_64__ ) || defined( _M_X64 ) +# define A64_ +#endif + +#if (defined ( ASM_X86_V1C ) || defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )) \ + && !defined( A32_ ) || defined( ASM_AMD64_C ) && !defined( A64_ ) +# error Assembler code is only available for x86 and AMD64 systems +#endif + +/* 4. FAST INPUT/OUTPUT OPERATIONS. + + On some machines it is possible to improve speed by transferring the + bytes in the input and output arrays to and from the internal 32-bit + variables by addressing these arrays as if they are arrays of 32-bit + words. On some machines this will always be possible but there may + be a large performance penalty if the byte arrays are not aligned on + the normal word boundaries. On other machines this technique will + lead to memory access errors when such 32-bit word accesses are not + properly aligned. The option SAFE_IO avoids such problems but will + often be slower on those machines that support misaligned access + (especially so if care is taken to align the input and output byte + arrays on 32-bit word boundaries). If SAFE_IO is not defined it is + assumed that access to byte arrays as if they are arrays of 32-bit + words will not cause problems when such accesses are misaligned. +*/ +#if 1 && !defined( _MSC_VER ) +# define SAFE_IO +#endif + +/* 5. LOOP UNROLLING + + The code for encryption and decrytpion cycles through a number of rounds + that can be implemented either in a loop or by expanding the code into a + long sequence of instructions, the latter producing a larger program but + one that will often be much faster. The latter is called loop unrolling. + There are also potential speed advantages in expanding two iterations in + a loop with half the number of iterations, which is called partial loop + unrolling. The following options allow partial or full loop unrolling + to be set independently for encryption and decryption +*/ +#if 1 +# define ENC_UNROLL FULL +#elif 0 +# define ENC_UNROLL PARTIAL +#else +# define ENC_UNROLL NONE +#endif + +#if 1 +# define DEC_UNROLL FULL +#elif 0 +# define DEC_UNROLL PARTIAL +#else +# define DEC_UNROLL NONE +#endif + +#if 1 +# define ENC_KS_UNROLL +#endif + +#if 1 +# define DEC_KS_UNROLL +#endif + +/* 6. FAST FINITE FIELD OPERATIONS + + If this section is included, tables are used to provide faster finite + field arithmetic (this has no effect if STATIC_TABLES is defined). +*/ +#if 1 +# define FF_TABLES +#endif + +/* 7. INTERNAL STATE VARIABLE FORMAT + + The internal state of Rijndael is stored in a number of local 32-bit + word varaibles which can be defined either as an array or as individual + names variables. Include this section if you want to store these local + varaibles in arrays. Otherwise individual local variables will be used. +*/ +#if 1 +# define ARRAYS +#endif + +/* 8. FIXED OR DYNAMIC TABLES + + When this section is included the tables used by the code are compiled + statically into the binary file. Otherwise the subroutine aes_init() + must be called to compute them before the code is first used. +*/ +#if 1 && !(defined( _MSC_VER ) && ( _MSC_VER <= 800 )) +# define STATIC_TABLES +#endif + +/* 9. MASKING OR CASTING FROM LONGER VALUES TO BYTES + + In some systems it is better to mask longer values to extract bytes + rather than using a cast. This option allows this choice. +*/ +#if 0 +# define to_byte(x) ((uint8_t)(x)) +#else +# define to_byte(x) ((x) & 0xff) +#endif + +/* 10. TABLE ALIGNMENT + + On some sytsems speed will be improved by aligning the AES large lookup + tables on particular boundaries. This define should be set to a power of + two giving the desired alignment. It can be left undefined if alignment + is not needed. This option is specific to the Microsft VC++ compiler - + it seems to sometimes cause trouble for the VC++ version 6 compiler. +*/ + +#if 1 && defined( _MSC_VER ) && ( _MSC_VER >= 1300 ) +# define TABLE_ALIGN 32 +#endif + +/* 11. REDUCE CODE AND TABLE SIZE + + This replaces some expanded macros with function calls if AES_ASM_V2 or + AES_ASM_V2C are defined +*/ + +#if 1 && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )) +# define REDUCE_CODE_SIZE +#endif + +/* 12. TABLE OPTIONS + + This cipher proceeds by repeating in a number of cycles known as 'rounds' + which are implemented by a round function which can optionally be speeded + up using tables. The basic tables are each 256 32-bit words, with either + one or four tables being required for each round function depending on + how much speed is required. The encryption and decryption round functions + are different and the last encryption and decrytpion round functions are + different again making four different round functions in all. + + This means that: + 1. Normal encryption and decryption rounds can each use either 0, 1 + or 4 tables and table spaces of 0, 1024 or 4096 bytes each. + 2. The last encryption and decryption rounds can also use either 0, 1 + or 4 tables and table spaces of 0, 1024 or 4096 bytes each. + + Include or exclude the appropriate definitions below to set the number + of tables used by this implementation. + + Defining AES_SMALL_TABLES selects ONE_TABLE for every round function, + shrinking the five lookup tables from 4096 to 1024 bytes each (15,360 + bytes of flash reclaimed) at a modest cycle cost per round. Intended + for ROM-constrained firmware variants; the default remains FOUR_TABLES. +*/ + +#if defined( AES_SMALL_TABLES ) /* set tables for the normal encryption round */ +# define ENC_ROUND ONE_TABLE +#elif 1 +# define ENC_ROUND FOUR_TABLES +#else +# define ENC_ROUND NO_TABLES +#endif + +#if defined( AES_SMALL_TABLES ) /* set tables for the last encryption round */ +# define LAST_ENC_ROUND ONE_TABLE +#elif 1 +# define LAST_ENC_ROUND FOUR_TABLES +#else +# define LAST_ENC_ROUND NO_TABLES +#endif + +#if defined( AES_SMALL_TABLES ) /* set tables for the normal decryption round */ +# define DEC_ROUND ONE_TABLE +#elif 1 +# define DEC_ROUND FOUR_TABLES +#else +# define DEC_ROUND NO_TABLES +#endif + +#if defined( AES_SMALL_TABLES ) /* set tables for the last decryption round */ +# define LAST_DEC_ROUND ONE_TABLE +#elif 1 +# define LAST_DEC_ROUND FOUR_TABLES +#else +# define LAST_DEC_ROUND NO_TABLES +#endif + +/* The decryption key schedule can be speeded up with tables in the same + way that the round functions can. Include or exclude the following + defines to set this requirement. +*/ +#if defined( AES_SMALL_TABLES ) +# define KEY_SCHED ONE_TABLE +#elif 1 +# define KEY_SCHED FOUR_TABLES +#else +# define KEY_SCHED NO_TABLES +#endif + +/* ---- END OF USER CONFIGURED OPTIONS ---- */ + +/* VIA ACE support is only available for VC++ and GCC */ + +#if !defined( _MSC_VER ) && !defined( __GNUC__ ) +# if defined( ASSUME_VIA_ACE_PRESENT ) +# undef ASSUME_VIA_ACE_PRESENT +# endif +# if defined( USE_VIA_ACE_IF_PRESENT ) +# undef USE_VIA_ACE_IF_PRESENT +# endif +#endif + +#if defined( ASSUME_VIA_ACE_PRESENT ) && !defined( USE_VIA_ACE_IF_PRESENT ) +# define USE_VIA_ACE_IF_PRESENT +#endif + +/* define to reverse decryption key schedule */ +#if 1 || defined( USE_VIA_ACE_IF_PRESENT ) && !defined ( AES_REV_DKS ) +# define AES_REV_DKS +#endif + +/* Intel AESNI uses a decryption key schedule in the encryption order */ +#if defined( USE_INTEL_AES_IF_PRESENT ) && defined ( AES_REV_DKS ) +# undef AES_REV_DKS +#endif + +/* Assembler support requires the use of platform byte order */ + +#if ( defined( ASM_X86_V1C ) || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) ) \ + && (ALGORITHM_BYTE_ORDER != PLATFORM_BYTE_ORDER) +# undef ALGORITHM_BYTE_ORDER +# define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER +#endif + +/* In this implementation the columns of the state array are each held in + 32-bit words. The state array can be held in various ways: in an array + of words, in a number of individual word variables or in a number of + processor registers. The following define maps a variable name x and + a column number c to the way the state array variable is to be held. + The first define below maps the state into an array x[c] whereas the + second form maps the state into a number of individual variables x0, + x1, etc. Another form could map individual state colums to machine + register names. +*/ + +#if defined( ARRAYS ) +# define s(x,c) x[c] +#else +# define s(x,c) x##c +#endif + +/* This implementation provides subroutines for encryption, decryption + and for setting the three key lengths (separately) for encryption + and decryption. Since not all functions are needed, masks are set + up here to determine which will be implemented in C +*/ + +#if !defined( AES_ENCRYPT ) +# define EFUNCS_IN_C 0 +#elif defined( ASSUME_VIA_ACE_PRESENT ) || defined( ASM_X86_V1C ) \ + || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) +# define EFUNCS_IN_C ENC_KEYING_IN_C +#elif !defined( ASM_X86_V2 ) +# define EFUNCS_IN_C ( ENCRYPTION_IN_C | ENC_KEYING_IN_C ) +#else +# define EFUNCS_IN_C 0 +#endif + +#if !defined( AES_DECRYPT ) +# define DFUNCS_IN_C 0 +#elif defined( ASSUME_VIA_ACE_PRESENT ) || defined( ASM_X86_V1C ) \ + || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) +# define DFUNCS_IN_C DEC_KEYING_IN_C +#elif !defined( ASM_X86_V2 ) +# define DFUNCS_IN_C ( DECRYPTION_IN_C | DEC_KEYING_IN_C ) +#else +# define DFUNCS_IN_C 0 +#endif + +#define FUNCS_IN_C ( EFUNCS_IN_C | DFUNCS_IN_C ) + +/* END OF CONFIGURATION OPTIONS */ + +#define RC_LENGTH (5 * (AES_BLOCK_SIZE / 4 - 2)) + +/* Disable or report errors on some combinations of options */ + +#if ENC_ROUND == NO_TABLES && LAST_ENC_ROUND != NO_TABLES +# undef LAST_ENC_ROUND +# define LAST_ENC_ROUND NO_TABLES +#elif ENC_ROUND == ONE_TABLE && LAST_ENC_ROUND == FOUR_TABLES +# undef LAST_ENC_ROUND +# define LAST_ENC_ROUND ONE_TABLE +#endif + +#if ENC_ROUND == NO_TABLES && ENC_UNROLL != NONE +# undef ENC_UNROLL +# define ENC_UNROLL NONE +#endif + +#if DEC_ROUND == NO_TABLES && LAST_DEC_ROUND != NO_TABLES +# undef LAST_DEC_ROUND +# define LAST_DEC_ROUND NO_TABLES +#elif DEC_ROUND == ONE_TABLE && LAST_DEC_ROUND == FOUR_TABLES +# undef LAST_DEC_ROUND +# define LAST_DEC_ROUND ONE_TABLE +#endif + +#if DEC_ROUND == NO_TABLES && DEC_UNROLL != NONE +# undef DEC_UNROLL +# define DEC_UNROLL NONE +#endif + +#if defined( bswap32 ) +# define aes_sw32 bswap32 +#elif defined( bswap_32 ) +# define aes_sw32 bswap_32 +#else +# define brot(x,n) (((uint32_t)(x) << n) | ((uint32_t)(x) >> (32 - n))) +# define aes_sw32(x) ((brot((x),8) & 0x00ff00ff) | (brot((x),24) & 0xff00ff00)) +#endif + +/* upr(x,n): rotates bytes within words by n positions, moving bytes to + higher index positions with wrap around into low positions + ups(x,n): moves bytes by n positions to higher index positions in + words but without wrap around + bval(x,n): extracts a byte from a word + + WARNING: The definitions given here are intended only for use with + unsigned variables and with shift counts that are compile + time constants +*/ + +#if ( ALGORITHM_BYTE_ORDER == IS_LITTLE_ENDIAN ) +# define upr(x,n) (((uint32_t)(x) << (8 * (n))) | ((uint32_t)(x) >> (32 - 8 * (n)))) +# define ups(x,n) ((uint32_t) (x) << (8 * (n))) +# define bval(x,n) to_byte((x) >> (8 * (n))) +# define bytes2word(b0, b1, b2, b3) \ + (((uint32_t)(b3) << 24) | ((uint32_t)(b2) << 16) | ((uint32_t)(b1) << 8) | (b0)) +#endif + +#if ( ALGORITHM_BYTE_ORDER == IS_BIG_ENDIAN ) +# define upr(x,n) (((uint32_t)(x) >> (8 * (n))) | ((uint32_t)(x) << (32 - 8 * (n)))) +# define ups(x,n) ((uint32_t) (x) >> (8 * (n))) +# define bval(x,n) to_byte((x) >> (24 - 8 * (n))) +# define bytes2word(b0, b1, b2, b3) \ + (((uint32_t)(b0) << 24) | ((uint32_t)(b1) << 16) | ((uint32_t)(b2) << 8) | (b3)) +#endif + +#if defined( SAFE_IO ) +# define word_in(x,c) bytes2word(((const uint8_t*)(x)+4*c)[0], ((const uint8_t*)(x)+4*c)[1], \ + ((const uint8_t*)(x)+4*c)[2], ((const uint8_t*)(x)+4*c)[3]) +# define word_out(x,c,v) { ((uint8_t*)(x)+4*c)[0] = bval(v,0); ((uint8_t*)(x)+4*c)[1] = bval(v,1); \ + ((uint8_t*)(x)+4*c)[2] = bval(v,2); ((uint8_t*)(x)+4*c)[3] = bval(v,3); } +#elif ( ALGORITHM_BYTE_ORDER == PLATFORM_BYTE_ORDER ) +# define word_in(x,c) (*((uint32_t*)(x)+(c))) +# define word_out(x,c,v) (*((uint32_t*)(x)+(c)) = (v)) +#else +# define word_in(x,c) aes_sw32(*((uint32_t*)(x)+(c))) +# define word_out(x,c,v) (*((uint32_t*)(x)+(c)) = aes_sw32(v)) +#endif + +/* the finite field modular polynomial and elements */ + +#define WPOLY 0x011b +#define BPOLY 0x1b + +/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */ + +#define gf_c1 0x80808080 +#define gf_c2 0x7f7f7f7f +#define gf_mulx(x) ((((x) & gf_c2) << 1) ^ ((((x) & gf_c1) >> 7) * BPOLY)) + +/* The following defines provide alternative definitions of gf_mulx that might + give improved performance if a fast 32-bit multiply is not available. Note + that a temporary variable u needs to be defined where gf_mulx is used. + +#define gf_mulx(x) (u = (x) & gf_c1, u |= (u >> 1), ((x) & gf_c2) << 1) ^ ((u >> 3) | (u >> 6)) +#define gf_c4 (0x01010101 * BPOLY) +#define gf_mulx(x) (u = (x) & gf_c1, ((x) & gf_c2) << 1) ^ ((u - (u >> 7)) & gf_c4) +*/ + +/* Work out which tables are needed for the different options */ + +#if defined( ASM_X86_V1C ) +# if defined( ENC_ROUND ) +# undef ENC_ROUND +# endif +# define ENC_ROUND FOUR_TABLES +# if defined( LAST_ENC_ROUND ) +# undef LAST_ENC_ROUND +# endif +# define LAST_ENC_ROUND FOUR_TABLES +# if defined( DEC_ROUND ) +# undef DEC_ROUND +# endif +# define DEC_ROUND FOUR_TABLES +# if defined( LAST_DEC_ROUND ) +# undef LAST_DEC_ROUND +# endif +# define LAST_DEC_ROUND FOUR_TABLES +# if defined( KEY_SCHED ) +# undef KEY_SCHED +# define KEY_SCHED FOUR_TABLES +# endif +#endif + +#if ( FUNCS_IN_C & ENCRYPTION_IN_C ) || defined( ASM_X86_V1C ) +# if ENC_ROUND == ONE_TABLE +# define FT1_SET +# elif ENC_ROUND == FOUR_TABLES +# define FT4_SET +# else +# define SBX_SET +# endif +# if LAST_ENC_ROUND == ONE_TABLE +# define FL1_SET +# elif LAST_ENC_ROUND == FOUR_TABLES +# define FL4_SET +# elif !defined( SBX_SET ) +# define SBX_SET +# endif +#endif + +#if ( FUNCS_IN_C & DECRYPTION_IN_C ) || defined( ASM_X86_V1C ) +# if DEC_ROUND == ONE_TABLE +# define IT1_SET +# elif DEC_ROUND == FOUR_TABLES +# define IT4_SET +# else +# define ISB_SET +# endif +# if LAST_DEC_ROUND == ONE_TABLE +# define IL1_SET +# elif LAST_DEC_ROUND == FOUR_TABLES +# define IL4_SET +# elif !defined(ISB_SET) +# define ISB_SET +# endif +#endif + +#if !(defined( REDUCE_CODE_SIZE ) && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C ))) +# if ((FUNCS_IN_C & ENC_KEYING_IN_C) || (FUNCS_IN_C & DEC_KEYING_IN_C)) +# if KEY_SCHED == ONE_TABLE +# if !defined( FL1_SET ) && !defined( FL4_SET ) +# define LS1_SET +# endif +# elif KEY_SCHED == FOUR_TABLES +# if !defined( FL4_SET ) +# define LS4_SET +# endif +# elif !defined( SBX_SET ) +# define SBX_SET +# endif +# endif +# if (FUNCS_IN_C & DEC_KEYING_IN_C) +# if KEY_SCHED == ONE_TABLE +# define IM1_SET +# elif KEY_SCHED == FOUR_TABLES +# define IM4_SET +# elif !defined( SBX_SET ) +# define SBX_SET +# endif +# endif +#endif + +/* generic definitions of Rijndael macros that use tables */ + +#define no_table(x,box,vf,rf,c) bytes2word( \ + box[bval(vf(x,0,c),rf(0,c))], \ + box[bval(vf(x,1,c),rf(1,c))], \ + box[bval(vf(x,2,c),rf(2,c))], \ + box[bval(vf(x,3,c),rf(3,c))]) + +#define one_table(x,op,tab,vf,rf,c) \ + ( tab[bval(vf(x,0,c),rf(0,c))] \ + ^ op(tab[bval(vf(x,1,c),rf(1,c))],1) \ + ^ op(tab[bval(vf(x,2,c),rf(2,c))],2) \ + ^ op(tab[bval(vf(x,3,c),rf(3,c))],3)) + +#define four_tables(x,tab,vf,rf,c) \ + ( tab[0][bval(vf(x,0,c),rf(0,c))] \ + ^ tab[1][bval(vf(x,1,c),rf(1,c))] \ + ^ tab[2][bval(vf(x,2,c),rf(2,c))] \ + ^ tab[3][bval(vf(x,3,c),rf(3,c))]) + +#define vf1(x,r,c) (x) +#define rf1(r,c) (r) +#define rf2(r,c) ((8+r-c)&3) + +/* perform forward and inverse column mix operation on four bytes in long word x in */ +/* parallel. NOTE: x must be a simple variable, NOT an expression in these macros. */ + +#if !(defined( REDUCE_CODE_SIZE ) && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C ))) + +#if defined( FM4_SET ) /* not currently used */ +# define fwd_mcol(x) four_tables(x,t_use(f,m),vf1,rf1,0) +#elif defined( FM1_SET ) /* not currently used */ +# define fwd_mcol(x) one_table(x,upr,t_use(f,m),vf1,rf1,0) +#else +# define dec_fmvars uint32_t g2 +# define fwd_mcol(x) (g2 = gf_mulx(x), g2 ^ upr((x) ^ g2, 3) ^ upr((x), 2) ^ upr((x), 1)) +#endif + +#if defined( IM4_SET ) +# define inv_mcol(x) four_tables(x,t_use(i,m),vf1,rf1,0) +#elif defined( IM1_SET ) +# define inv_mcol(x) one_table(x,upr,t_use(i,m),vf1,rf1,0) +#else +# define dec_imvars uint32_t g2, g4, g9 +# define inv_mcol(x) (g2 = gf_mulx(x), g4 = gf_mulx(g2), g9 = (x) ^ gf_mulx(g4), g4 ^= g9, \ + (x) ^ g2 ^ g4 ^ upr(g2 ^ g9, 3) ^ upr(g4, 2) ^ upr(g9, 1)) +#endif + +#if defined( FL4_SET ) +# define ls_box(x,c) four_tables(x,t_use(f,l),vf1,rf2,c) +#elif defined( LS4_SET ) +# define ls_box(x,c) four_tables(x,t_use(l,s),vf1,rf2,c) +#elif defined( FL1_SET ) +# define ls_box(x,c) one_table(x,upr,t_use(f,l),vf1,rf2,c) +#elif defined( LS1_SET ) +# define ls_box(x,c) one_table(x,upr,t_use(l,s),vf1,rf2,c) +#else +# define ls_box(x,c) no_table(x,t_use(s,box),vf1,rf2,c) +#endif + +#endif + +#if defined( ASM_X86_V1C ) && defined( AES_DECRYPT ) && !defined( ISB_SET ) +# define ISB_SET +#endif + +#endif diff --git a/deps/crypto/trezor-crypto/aes/aestab.c b/deps/crypto/trezor-crypto/aes/aestab.c new file mode 100644 index 000000000..5e5dc1deb --- /dev/null +++ b/deps/crypto/trezor-crypto/aes/aestab.c @@ -0,0 +1,417 @@ +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 +*/ + +#define DO_TABLES + +#include "aes.h" +#include "aesopt.h" + +#if defined(STATIC_TABLES) + +#define sb_data(w) {\ + w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\ + w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\ + w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\ + w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\ + w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\ + w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\ + w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\ + w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\ + w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\ + w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\ + w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\ + w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\ + w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\ + w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\ + w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\ + w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\ + w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\ + w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\ + w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\ + w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\ + w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\ + w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\ + w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\ + w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\ + w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\ + w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\ + w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\ + w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\ + w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\ + w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\ + w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\ + w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) } + +#define isb_data(w) {\ + w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38),\ + w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb),\ + w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87),\ + w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), w(0xde), w(0xe9), w(0xcb),\ + w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d),\ + w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e),\ + w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2),\ + w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25),\ + w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16),\ + w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92),\ + w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda),\ + w(0x5e), w(0x15), w(0x46), w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84),\ + w(0x90), w(0xd8), w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a),\ + w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06),\ + w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02),\ + w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), w(0x6b),\ + w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea),\ + w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73),\ + w(0x96), w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85),\ + w(0xe2), w(0xf9), w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e),\ + w(0x47), w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89),\ + w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b),\ + w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), w(0x20),\ + w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), w(0x5a), w(0xf4),\ + w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), w(0x31),\ + w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f),\ + w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d),\ + w(0x2d), w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef),\ + w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0),\ + w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61),\ + w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), w(0xd6), w(0x26),\ + w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), w(0x21), w(0x0c), w(0x7d) } + +#define mm_data(w) {\ + w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07),\ + w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f),\ + w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), w(0x16), w(0x17),\ + w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), w(0x1d), w(0x1e), w(0x1f),\ + w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), w(0x25), w(0x26), w(0x27),\ + w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f),\ + w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37),\ + w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f),\ + w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47),\ + w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f),\ + w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57),\ + w(0x58), w(0x59), w(0x5a), w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f),\ + w(0x60), w(0x61), w(0x62), w(0x63), w(0x64), w(0x65), w(0x66), w(0x67),\ + w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f),\ + w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77),\ + w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), w(0x7f),\ + w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87),\ + w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f),\ + w(0x90), w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97),\ + w(0x98), w(0x99), w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f),\ + w(0xa0), w(0xa1), w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7),\ + w(0xa8), w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf),\ + w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), w(0xb7),\ + w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), w(0xbe), w(0xbf),\ + w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), w(0xc7),\ + w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf),\ + w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7),\ + w(0xd8), w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf),\ + w(0xe0), w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7),\ + w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef),\ + w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), w(0xf6), w(0xf7),\ + w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), w(0xfd), w(0xfe), w(0xff) } + +#define rc_data(w) {\ + w(0x01), w(0x02), w(0x04), w(0x08), w(0x10),w(0x20), w(0x40), w(0x80),\ + w(0x1b), w(0x36) } + +#define h0(x) (x) + +#define w0(p) bytes2word(p, 0, 0, 0) +#define w1(p) bytes2word(0, p, 0, 0) +#define w2(p) bytes2word(0, 0, p, 0) +#define w3(p) bytes2word(0, 0, 0, p) + +#define u0(p) bytes2word(f2(p), p, p, f3(p)) +#define u1(p) bytes2word(f3(p), f2(p), p, p) +#define u2(p) bytes2word(p, f3(p), f2(p), p) +#define u3(p) bytes2word(p, p, f3(p), f2(p)) + +#define v0(p) bytes2word(fe(p), f9(p), fd(p), fb(p)) +#define v1(p) bytes2word(fb(p), fe(p), f9(p), fd(p)) +#define v2(p) bytes2word(fd(p), fb(p), fe(p), f9(p)) +#define v3(p) bytes2word(f9(p), fd(p), fb(p), fe(p)) + +#endif + +#if defined(STATIC_TABLES) || !defined(FF_TABLES) + +#define f2(x) ((x<<1) ^ (((x>>7) & 1) * WPOLY)) +#define f4(x) ((x<<2) ^ (((x>>6) & 1) * WPOLY) ^ (((x>>6) & 2) * WPOLY)) +#define f8(x) ((x<<3) ^ (((x>>5) & 1) * WPOLY) ^ (((x>>5) & 2) * WPOLY) \ + ^ (((x>>5) & 4) * WPOLY)) +#define f3(x) (f2(x) ^ x) +#define f9(x) (f8(x) ^ x) +#define fb(x) (f8(x) ^ f2(x) ^ x) +#define fd(x) (f8(x) ^ f4(x) ^ x) +#define fe(x) (f8(x) ^ f4(x) ^ f2(x)) + +#else + +#define f2(x) ((x) ? pow[log[x] + 0x19] : 0) +#define f3(x) ((x) ? pow[log[x] + 0x01] : 0) +#define f9(x) ((x) ? pow[log[x] + 0xc7] : 0) +#define fb(x) ((x) ? pow[log[x] + 0x68] : 0) +#define fd(x) ((x) ? pow[log[x] + 0xee] : 0) +#define fe(x) ((x) ? pow[log[x] + 0xdf] : 0) + +#endif + +#include "aestab.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + +#if defined(STATIC_TABLES) + +/* implemented in case of wrong call for fixed tables */ + +AES_RETURN aes_init(void) +{ + return EXIT_SUCCESS; +} + +#else /* Generate the tables for the dynamic table option */ + +#if defined(FF_TABLES) + +#define gf_inv(x) ((x) ? pow[ 255 - log[x]] : 0) + +#else + +/* It will generally be sensible to use tables to compute finite + field multiplies and inverses but where memory is scarse this + code might sometimes be better. But it only has effect during + initialisation so its pretty unimportant in overall terms. +*/ + +/* return 2 ^ (n - 1) where n is the bit number of the highest bit + set in x with x in the range 1 < x < 0x00000200. This form is + used so that locals within fi can be bytes rather than words +*/ + +static uint8_t hibit(const uint32_t x) +{ uint8_t r = (uint8_t)((x >> 1) | (x >> 2)); + + r |= (r >> 2); + r |= (r >> 4); + return (r + 1) >> 1; +} + +/* return the inverse of the finite field element x */ + +static uint8_t gf_inv(const uint8_t x) +{ uint8_t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0; + + if(x < 2) + return x; + + for( ; ; ) + { + if(n1) + while(n2 >= n1) /* divide polynomial p2 by p1 */ + { + n2 /= n1; /* shift smaller polynomial left */ + p2 ^= (p1 * n2) & 0xff; /* and remove from larger one */ + v2 ^= v1 * n2; /* shift accumulated value and */ + n2 = hibit(p2); /* add into result */ + } + else + return v1; + + if(n2) /* repeat with values swapped */ + while(n1 >= n2) + { + n1 /= n2; + p1 ^= p2 * n1; + v1 ^= v2 * n1; + n1 = hibit(p1); + } + else + return v2; + } +} + +#endif + +/* The forward and inverse affine transformations used in the S-box */ +uint8_t fwd_affine(const uint8_t x) +{ uint32_t w = x; + w ^= (w << 1) ^ (w << 2) ^ (w << 3) ^ (w << 4); + return 0x63 ^ ((w ^ (w >> 8)) & 0xff); +} + +uint8_t inv_affine(const uint8_t x) +{ uint32_t w = x; + w = (w << 1) ^ (w << 3) ^ (w << 6); + return 0x05 ^ ((w ^ (w >> 8)) & 0xff); +} + +static int init = 0; + +AES_RETURN aes_init(void) +{ uint32_t i = 0, w = 0; + +#if defined(FF_TABLES) + + uint8_t pow[512] = {0}, log[256] = {0}; + + if(init) + return EXIT_SUCCESS; + /* log and power tables for GF(2^8) finite field with + WPOLY as modular polynomial - the simplest primitive + root is 0x03, used here to generate the tables + */ + + i = 0; w = 1; + do + { + pow[i] = (uint8_t)w; + pow[i + 255] = (uint8_t)w; + log[w] = (uint8_t)i++; + w ^= (w << 1) ^ (w & 0x80 ? WPOLY : 0); + } + while (w != 1); + +#else + if(init) + return EXIT_SUCCESS; +#endif + + for(i = 0, w = 1; i < RC_LENGTH; ++i) + { + t_set(r,c)[i] = bytes2word(w, 0, 0, 0); + w = f2(w); + } + + for(i = 0; i < 256; ++i) + { uint8_t b = 0; + + b = fwd_affine(gf_inv((uint8_t)i)); + w = bytes2word(f2(b), b, b, f3(b)); + +#if defined( SBX_SET ) + t_set(s,box)[i] = b; +#endif + +#if defined( FT1_SET ) /* tables for a normal encryption round */ + t_set(f,n)[i] = w; +#endif +#if defined( FT4_SET ) + t_set(f,n)[0][i] = w; + t_set(f,n)[1][i] = upr(w,1); + t_set(f,n)[2][i] = upr(w,2); + t_set(f,n)[3][i] = upr(w,3); +#endif + w = bytes2word(b, 0, 0, 0); + +#if defined( FL1_SET ) /* tables for last encryption round (may also */ + t_set(f,l)[i] = w; /* be used in the key schedule) */ +#endif +#if defined( FL4_SET ) + t_set(f,l)[0][i] = w; + t_set(f,l)[1][i] = upr(w,1); + t_set(f,l)[2][i] = upr(w,2); + t_set(f,l)[3][i] = upr(w,3); +#endif + +#if defined( LS1_SET ) /* table for key schedule if t_set(f,l) above is*/ + t_set(l,s)[i] = w; /* not of the required form */ +#endif +#if defined( LS4_SET ) + t_set(l,s)[0][i] = w; + t_set(l,s)[1][i] = upr(w,1); + t_set(l,s)[2][i] = upr(w,2); + t_set(l,s)[3][i] = upr(w,3); +#endif + + b = gf_inv(inv_affine((uint8_t)i)); + w = bytes2word(fe(b), f9(b), fd(b), fb(b)); + +#if defined( IM1_SET ) /* tables for the inverse mix column operation */ + t_set(i,m)[b] = w; +#endif +#if defined( IM4_SET ) + t_set(i,m)[0][b] = w; + t_set(i,m)[1][b] = upr(w,1); + t_set(i,m)[2][b] = upr(w,2); + t_set(i,m)[3][b] = upr(w,3); +#endif + +#if defined( ISB_SET ) + t_set(i,box)[i] = b; +#endif +#if defined( IT1_SET ) /* tables for a normal decryption round */ + t_set(i,n)[i] = w; +#endif +#if defined( IT4_SET ) + t_set(i,n)[0][i] = w; + t_set(i,n)[1][i] = upr(w,1); + t_set(i,n)[2][i] = upr(w,2); + t_set(i,n)[3][i] = upr(w,3); +#endif + w = bytes2word(b, 0, 0, 0); +#if defined( IL1_SET ) /* tables for last decryption round */ + t_set(i,l)[i] = w; +#endif +#if defined( IL4_SET ) + t_set(i,l)[0][i] = w; + t_set(i,l)[1][i] = upr(w,1); + t_set(i,l)[2][i] = upr(w,2); + t_set(i,l)[3][i] = upr(w,3); +#endif + } + init = 1; + return EXIT_SUCCESS; +} + +/* + Automatic code initialisation (suggested by by Henrik S. Gaßmann) + based on code provided by Joe Lowe and placed in the public domain at: + http://stackoverflow.com/questions/1113409/attribute-constructor-equivalent-in-vc +*/ + +#ifdef _MSC_VER + +#pragma section(".CRT$XCU", read) + +__declspec(allocate(".CRT$XCU")) void (__cdecl *aes_startup)(void) = aes_init; + +#elif defined(__GNUC__) + +static void aes_startup(void) __attribute__((constructor)); + +static void aes_startup(void) +{ + aes_init(); +} + +#else + +#pragma message( "dynamic tables must be initialised manually on your system" ) + +#endif + +#endif + +#if defined(__cplusplus) +} +#endif diff --git a/deps/crypto/trezor-crypto/aes/aestab.h b/deps/crypto/trezor-crypto/aes/aestab.h new file mode 100644 index 000000000..8fe32d180 --- /dev/null +++ b/deps/crypto/trezor-crypto/aes/aestab.h @@ -0,0 +1,173 @@ +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 + + This file contains the code for declaring the tables needed to implement + AES. The file aesopt.h is assumed to be included before this header file. + If there are no global variables, the definitions here can be used to put + the AES tables in a structure so that a pointer can then be added to the + AES context to pass them to the AES routines that need them. If this + facility is used, the calling program has to ensure that this pointer is + managed appropriately. In particular, the value of the t_dec(in,it) item + in the table structure must be set to zero in order to ensure that the + tables are initialised. In practice the three code sequences in aeskey.c + that control the calls to aes_init() and the aes_init() routine itself will + have to be changed for a specific implementation. If global variables are + available it will generally be preferable to use them with the precomputed + STATIC_TABLES option that uses static global tables. + + The following defines can be used to control the way the tables + are defined, initialised and used in embedded environments that + require special features for these purposes + + the 't_dec' construction is used to declare fixed table arrays + the 't_set' construction is used to set fixed table values + the 't_use' construction is used to access fixed table values + + 256 byte tables: + + t_xxx(s,box) => forward S box + t_xxx(i,box) => inverse S box + + 256 32-bit word OR 4 x 256 32-bit word tables: + + t_xxx(f,n) => forward normal round + t_xxx(f,l) => forward last round + t_xxx(i,n) => inverse normal round + t_xxx(i,l) => inverse last round + t_xxx(l,s) => key schedule table + t_xxx(i,m) => key schedule table + + Other variables and tables: + + t_xxx(r,c) => the rcon table +*/ + +#if !defined( _AESTAB_H ) +#define _AESTAB_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#define t_dec(m,n) t_##m##n +#define t_set(m,n) t_##m##n +#define t_use(m,n) t_##m##n + +#if defined(STATIC_TABLES) +# if !defined( __GNUC__ ) && (defined( __MSDOS__ ) || defined( __WIN16__ )) +/* make tables far data to avoid using too much DGROUP space (PG) */ +# define CONST const far +# else +# define CONST const +# endif +#else +# define CONST +#endif + +#if defined(DO_TABLES) +# define EXTERN +#else +# define EXTERN extern +#endif + +#if defined(_MSC_VER) && defined(TABLE_ALIGN) +#define ALIGN __declspec(align(TABLE_ALIGN)) +#else +#define ALIGN +#endif + +#if defined( __WATCOMC__ ) && ( __WATCOMC__ >= 1100 ) +# define XP_DIR __cdecl +#else +# define XP_DIR +#endif + +#if defined(DO_TABLES) && defined(STATIC_TABLES) +#define d_1(t,n,b,e) EXTERN ALIGN CONST XP_DIR t n[256] = b(e) +#define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256] = { b(e), b(f), b(g), b(h) } +EXTERN ALIGN CONST uint32_t t_dec(r,c)[RC_LENGTH] = rc_data(w0); +#else +#define d_1(t,n,b,e) EXTERN ALIGN CONST XP_DIR t n[256] +#define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256] +EXTERN ALIGN CONST uint32_t t_dec(r,c)[RC_LENGTH]; +#endif + +#if defined( SBX_SET ) + d_1(uint8_t, t_dec(s,box), sb_data, h0); +#endif +#if defined( ISB_SET ) + d_1(uint8_t, t_dec(i,box), isb_data, h0); +#endif + +#if defined( FT1_SET ) + d_1(uint32_t, t_dec(f,n), sb_data, u0); +#endif +#if defined( FT4_SET ) + d_4(uint32_t, t_dec(f,n), sb_data, u0, u1, u2, u3); +#endif + +#if defined( FL1_SET ) + d_1(uint32_t, t_dec(f,l), sb_data, w0); +#endif +#if defined( FL4_SET ) + d_4(uint32_t, t_dec(f,l), sb_data, w0, w1, w2, w3); +#endif + +#if defined( IT1_SET ) + d_1(uint32_t, t_dec(i,n), isb_data, v0); +#endif +#if defined( IT4_SET ) + d_4(uint32_t, t_dec(i,n), isb_data, v0, v1, v2, v3); +#endif + +#if defined( IL1_SET ) + d_1(uint32_t, t_dec(i,l), isb_data, w0); +#endif +#if defined( IL4_SET ) + d_4(uint32_t, t_dec(i,l), isb_data, w0, w1, w2, w3); +#endif + +#if defined( LS1_SET ) +#if defined( FL1_SET ) +#undef LS1_SET +#else + d_1(uint32_t, t_dec(l,s), sb_data, w0); +#endif +#endif + +#if defined( LS4_SET ) +#if defined( FL4_SET ) +#undef LS4_SET +#else + d_4(uint32_t, t_dec(l,s), sb_data, w0, w1, w2, w3); +#endif +#endif + +#if defined( IM1_SET ) + d_1(uint32_t, t_dec(i,m), mm_data, v0); +#endif +#if defined( IM4_SET ) + d_4(uint32_t, t_dec(i,m), mm_data, v0, v1, v2, v3); +#endif + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/deps/crypto/trezor-crypto/aes/aestst.c b/deps/crypto/trezor-crypto/aes/aestst.c new file mode 100644 index 000000000..90a8714a9 --- /dev/null +++ b/deps/crypto/trezor-crypto/aes/aestst.c @@ -0,0 +1,182 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The redistribution and use of this software (with or without changes) + is allowed without the payment of fees or royalties provided that: + + 1. source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + 2. binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation; + + 3. the name of the copyright holder is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 20/12/2007 +*/ + +// Correct Output (for variable block size - AES_BLOCK_SIZE undefined): + +// lengths: block = 16 bytes, key = 16 bytes +// key = 2b7e151628aed2a6abf7158809cf4f3c +// input = 3243f6a8885a308d313198a2e0370734 +// encrypt = 3925841d02dc09fbdc118597196a0b32 +// decrypt = 3243f6a8885a308d313198a2e0370734 + +// lengths: block = 16 bytes, key = 24 bytes +// key = 2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da5 +// input = 3243f6a8885a308d313198a2e0370734 +// encrypt = f9fb29aefc384a250340d833b87ebc00 +// decrypt = 3243f6a8885a308d313198a2e0370734 + +// lengths: block = 16 bytes, key = 32 bytes +// key = 2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d9045190cfe +// input = 3243f6a8885a308d313198a2e0370734 +// encrypt = 1a6e6c2c662e7da6501ffb62bc9e93f3 +// decrypt = 3243f6a8885a308d313198a2e0370734 + +#include +#include + +#include "aes.h" +#include "aestst.h" + +void out_state(long s0, long s1, long s2, long s3) +{ + printf("\n%08lx%08lx%08lx%08lx", s0, s1, s2, s3); +} + +void oblk(char m[], unsigned char v[], unsigned long n) +{ unsigned long i; + + printf("\n%s", m); + + for(i = 0; i < n; ++i) + printf("%02x", v[i]); +} + +void message(const char *s) { printf("%s", s); } + +unsigned char pih[32] = // hex digits of pi +{ + 0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, + 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34, + 0x4a, 0x40, 0x93, 0x82, 0x22, 0x99, 0xf3, 0x1d, + 0x00, 0x82, 0xef, 0xa9, 0x8e, 0xc4, 0xe6, 0xc8 +}; + +unsigned char exh[32] = // hex digits of e +{ + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c, + 0x76, 0x2e, 0x71, 0x60, 0xf3, 0x8b, 0x4d, 0xa5, + 0x6a, 0x78, 0x4d, 0x90, 0x45, 0x19, 0x0c, 0xfe +}; + +unsigned char res[3][32] = +{ + { 0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, + 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32 + }, + { 0xf9, 0xfb, 0x29, 0xae, 0xfc, 0x38, 0x4a, 0x25, + 0x03, 0x40, 0xd8, 0x33, 0xb8, 0x7e, 0xbc, 0x00 + }, + { 0x1a, 0x6e, 0x6c, 0x2c, 0x66, 0x2e, 0x7d, 0xa6, + 0x50, 0x1f, 0xfb, 0x62, 0xbc, 0x9e, 0x93, 0xf3 + } +}; + +void cycles(volatile uint64_t *rtn) +{ +#if defined( _MSCVER ) + __asm // read the Pentium Time Stamp Counter + { cpuid + rdtsc + mov ecx,rtn + mov [ecx],eax + mov [ecx+4],edx + cpuid + } +#elif defined( __GNUC__ ) +#if defined(__aarch64__) + __asm__ __volatile__("mrs %0, cntvct_el0": "=r" (*rtn)); +#else + __asm__ __volatile__("rdtsc": "=A" (*rtn)); +#endif +#endif +} + +int main(void) +{ unsigned char out[32], ret[32], err = 0; + f_ectx alge[1]; + f_dctx algd[1]; + + aes_init(); + + message("\nRun tests for the AES algorithm"); + + memset(&alge, 0, sizeof(aes_encrypt_ctx)); + memset(&algd, 0, sizeof(aes_decrypt_ctx)); + +#if defined( AES_128 ) + memset(out, 0xcc, 16); memset(ret, 0xcc, 16); + printf("\n\n// lengths: block = 16, bytes, key = 16 bytes"); + f_enc_key128(alge, exh); + oblk("// key = ", exh, 16); + oblk("// input = ", pih, 16); + do_enc(alge, pih, out, 1); + oblk("// encrypt = ", out, 16); + if(memcmp(out, res[0], 16)) { message (" error"); err += 1; } + f_dec_key128(algd, exh); + do_dec(algd, out, ret, 1); + oblk("// decrypt = ", ret, 16); + if(memcmp(ret, pih, 16)) { message (" error"); err += 2; } +#endif + +#if defined( AES_192 ) + memset(out, 0xcc, 16); memset(ret, 0xcc, 16); + printf("\n\n// lengths: block = 16, bytes, key = 24 bytes"); + f_enc_key192(alge, exh); + oblk("// key = ", exh, 24); + oblk("// input = ", pih, 16); + do_enc(alge, pih, out, 1); + oblk("// encrypt = ", out, 16); + if(memcmp(out, res[1], 16)) { message (" error"); err += 4; } + f_dec_key192(algd, exh); + do_dec(algd, out, ret, 1); + oblk("// decrypt = ", ret, 16); + if(memcmp(ret, pih, 16)) { message (" error"); err += 8; } +#endif + +#if defined( AES_256 ) + memset(out, 0xcc, 16); memset(ret, 0xcc, 16); + printf("\n\n// lengths: block = 16, bytes, key = 32 bytes"); + f_enc_key256(alge, exh); + oblk("// key = ", exh, 32); + oblk("// input = ", pih, 16); + do_enc(alge, pih, out, 1); + oblk("// encrypt = ", out, 16); + if(memcmp(out, res[2], 16)) { message (" error"); err += 16; } + f_dec_key256(algd, exh); + do_dec(algd, out, ret, 1); + oblk("// decrypt = ", ret, 16); + if(memcmp(ret, pih, 16)) { message (" error"); err += 32; } +#endif + + if(!err) + message("\n\nThese values are all correct\n\n"); + else + message("\n\nSome values are in error\n\n"); + + return 0; +} diff --git a/deps/crypto/trezor-crypto/aes/aestst.h b/deps/crypto/trezor-crypto/aes/aestst.h new file mode 100644 index 000000000..3c5461c3c --- /dev/null +++ b/deps/crypto/trezor-crypto/aes/aestst.h @@ -0,0 +1,85 @@ +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 +*/ + +// The following definitions are required for testing only, They are not needed +// for AES (Rijndael) implementation. They are used to allow C, C++ and DLL +// data access and subroutine calls to be expressed in the same form in the +// testing code. + +#ifndef AESTST_H +#define AESTST_H + +#define f_info(x) (x)->inf.b[2] +#define f_ectx aes_encrypt_ctx +#define f_enc_key128(a,b) aes_encrypt_key128((b),(a)) +#define f_enc_key192(a,b) aes_encrypt_key192((b),(a)) +#define f_enc_key256(a,b) aes_encrypt_key256((b),(a)) +#define f_enc_key(a,b,c) aes_encrypt_key((b),(c),(a)) +#define f_enc_blk(a,b,c) aes_encrypt((b),(c),(a)) + +#define f_dctx aes_decrypt_ctx +#define f_dec_key128(a,b) aes_decrypt_key128((b),(a)) +#define f_dec_key192(a,b) aes_decrypt_key192((b),(a)) +#define f_dec_key256(a,b) aes_decrypt_key256((b),(a)) +#define f_dec_key(a,b,c) aes_decrypt_key((b),(c),(a)) +#define f_dec_blk(a,b,c) aes_decrypt((b),(c),(a)) + +#define f_talign(a,b) aes_test_alignment_detection(b) +#define f_mode_reset(a) aes_mode_reset(a) +#define f_ecb_enc(a,b,c,d) aes_ecb_encrypt((b),(c),(d),(a)) +#define f_ecb_dec(a,b,c,d) aes_ecb_decrypt((b),(c),(d),(a)) +#define f_cbc_enc(a,b,c,d,e) aes_cbc_encrypt((b),(c),(d),(e),(a)) +#define f_cbc_dec(a,b,c,d,e) aes_cbc_decrypt((b),(c),(d),(e),(a)) +#define f_cfb_enc(a,b,c,d,e) aes_cfb_encrypt((b),(c),(d),(e),(a)) +#define f_cfb_dec(a,b,c,d,e) aes_cfb_decrypt((b),(c),(d),(e),(a)) +#define f_ofb_cry(a,b,c,d,e) aes_ofb_crypt((b),(c),(d),(e),(a)) +#define f_ctr_cry(a,b,c,d,e,f) aes_ctr_crypt((b),(c),(d),(e),(f),(a)) + +#define ek_name128 "aes_encrypt_key128" +#define ek_name192 "aes_encrypt_key192" +#define ek_name256 "aes_encrypt_key256" +#define ek_name "aes_encrypt_key" +#define eb_name "aes_encrypt" + +#define dk_name128 "aes_decrypt_key128" +#define dk_name192 "aes_decrypt_key192" +#define dk_name256 "aes_decrypt_key256" +#define dk_name "aes_decrypt_key" +#define db_name "aes_decrypt" + +#define eres_name "aes_mode_reset" +#define ecbe_name "aes_ecb_encrypt" +#define ecbd_name "aes_ecb_decrypt" +#define cbce_name "aes_cbc_encrypt" +#define cbcd_name "aes_cbc_decrypt" +#define cfbe_name "aes_cfb_encrypt" +#define cfbd_name "aes_cfb_decrypt" +#define ofb_name "aes_ofb_crypt" +#define ctr_name "aes_ctr_crypt" + +#ifndef AES_N_BLOCK +#define do_enc(a,b,c,d) f_enc_blk(a, b, c) +#define do_dec(a,b,c,d) f_dec_blk(a, b, c) +#else +#define do_enc(a,b,c,d) f_ecb_enc(a, b, c, 1) +#define do_dec(a,b,c,d) f_ecb_dec(a, b, c, 1) +#endif + +#endif diff --git a/deps/crypto/trezor-crypto/base32.c b/deps/crypto/trezor-crypto/base32.c new file mode 100644 index 000000000..ef9b76bec --- /dev/null +++ b/deps/crypto/trezor-crypto/base32.c @@ -0,0 +1,241 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, E1PRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "base32.h" + +#include + +const char *BASE32_ALPHABET_RFC4648 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ23456789"; + +static inline void base32_5to8(const uint8_t *in, uint8_t length, uint8_t *out); +static inline bool base32_8to5(const uint8_t *in, uint8_t length, uint8_t *out, + const char *alphabet); +static inline void base32_8to5_raw(const uint8_t *in, uint8_t length, + uint8_t *out); + +static inline int base32_encode_character(uint8_t decoded, + const char *alphabet); +static inline int base32_decode_character(char encoded, const char *alphabet); + +char *base32_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen, + const char *alphabet) { + size_t length = base32_encoded_length(inlen); + if (outlen <= length) { + return NULL; + } + + base32_encode_unsafe(in, inlen, (uint8_t *)out); + + for (size_t i = 0; i < length; i++) { + int ret = base32_encode_character(out[i], alphabet); + + if (ret == -1) { + return false; + } else { + out[i] = ret; + } + } + + out[length] = '\0'; + return &out[length]; +} + +uint8_t *base32_decode(const char *in, size_t inlen, uint8_t *out, + size_t outlen, const char *alphabet) { + size_t length = base32_decoded_length(inlen); + if (outlen < length) { + return NULL; + } + + if (!base32_decode_unsafe((uint8_t *)in, inlen, (uint8_t *)out, alphabet)) { + return NULL; + } + + return &out[length]; +} + +void base32_encode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out) { + uint8_t remainder = inlen % 5; + size_t limit = inlen - remainder; + + size_t i = 0, j = 0; + for (i = 0, j = 0; i < limit; i += 5, j += 8) { + base32_5to8(&in[i], 5, &out[j]); + } + + if (remainder) base32_5to8(&in[i], remainder, &out[j]); +} + +bool base32_decode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out, + const char *alphabet) { + uint8_t remainder = inlen % 8; + size_t limit = inlen - remainder; + + size_t i = 0, j = 0; + for (i = 0, j = 0; i < limit; i += 8, j += 5) { + if (!base32_8to5(&in[i], 8, &out[j], alphabet)) { + return false; + } + } + + if (remainder && !base32_8to5(&in[i], remainder, &out[j], alphabet)) { + return false; + } + + return true; +} + +size_t base32_encoded_length(size_t inlen) { + uint8_t remainder = inlen % 5; + + return (inlen / 5) * 8 + (remainder * 8 + 4) / 5; +} + +size_t base32_decoded_length(size_t inlen) { + uint8_t remainder = inlen % 8; + + return (inlen / 8) * 5 + (remainder * 5) / 8; +} + +void base32_5to8(const uint8_t *in, uint8_t length, uint8_t *out) { + if (length >= 1) { + out[0] = (in[0] >> 3); + out[1] = (in[0] & 7) << 2; + } + + if (length >= 2) { + out[1] |= (in[1] >> 6); + out[2] = (in[1] >> 1) & 31; + out[3] = (in[1] & 1) << 4; + } + + if (length >= 3) { + out[3] |= (in[2] >> 4); + out[4] = (in[2] & 15) << 1; + } + + if (length >= 4) { + out[4] |= (in[3] >> 7); + out[5] = (in[3] >> 2) & 31; + out[6] = (in[3] & 3) << 3; + } + + if (length >= 5) { + out[6] |= (in[4] >> 5); + out[7] = (in[4] & 31); + } +} + +bool base32_8to5(const uint8_t *in, uint8_t length, uint8_t *out, + const char *alphabet) { + if (length == 1 || length == 3 || length == 6 || length > 8) { + return false; + } + + if (alphabet) { + uint8_t decoded[length]; + memset(decoded, 0, sizeof(decoded)); + + for (size_t i = 0; i < length; i++) { + int ret = base32_decode_character(in[i], alphabet); + + if (ret == -1) { + return false; + } else { + decoded[i] = ret; + } + } + + base32_8to5_raw(decoded, length, out); + } else { + base32_8to5_raw(in, length, out); + } + + return true; +} + +void base32_8to5_raw(const uint8_t *in, uint8_t length, uint8_t *out) { + if (length >= 2) { + out[0] = (in[0] << 3); + out[0] |= (in[1] >> 2); + } + + if (length >= 4) { + out[1] = (in[1] & 3) << 6; + out[1] |= (in[2] << 1); + out[1] |= (in[3] >> 4); + } + + if (length >= 5) { + out[2] = (in[3] & 15) << 4; + out[2] |= (in[4] >> 1); + } + + if (length >= 7) { + out[3] = (in[4] & 1) << 7; + out[3] |= (in[5] << 2); + out[3] |= (in[6] >> 3); + } + + if (length >= 8) { + out[4] = (in[6] & 7) << 5; + out[4] |= (in[7] & 31); + } +} + +int base32_encode_character(uint8_t decoded, const char *alphabet) { + if (decoded >> 5) { + return -1; + } + + if (alphabet == BASE32_ALPHABET_RFC4648) { + if (decoded < 26) { + return 'A' + decoded; + } else { + return '2' - 26 + decoded; + } + } + + return alphabet[decoded]; +} + +int base32_decode_character(char encoded, const char *alphabet) { + if (alphabet == BASE32_ALPHABET_RFC4648) { + if (encoded >= 'A' && encoded <= 'Z') { + return encoded - 'A'; + } else if (encoded >= 'a' && encoded <= 'z') { + return encoded - 'a'; + } else if (encoded >= '2' && encoded <= '7') { + return encoded - '2' + 26; + } else { + return -1; + } + } + + const char *occurrence = strchr(alphabet, encoded); + + if (occurrence) { + return occurrence - alphabet; + } else { + return -1; + } +} diff --git a/deps/crypto/trezor-crypto/base32.h b/deps/crypto/trezor-crypto/base32.h new file mode 100644 index 000000000..8b5cc8513 --- /dev/null +++ b/deps/crypto/trezor-crypto/base32.h @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BASE32_H__ +#define __BASE32_H__ + +#include +#include +#include + +extern const char *BASE32_ALPHABET_RFC4648; + +char *base32_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen, + const char *alphabet); +void base32_encode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out); + +uint8_t *base32_decode(const char *in, size_t inlen, uint8_t *out, + size_t outlen, const char *alphabet); +bool base32_decode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out, + const char *alphabet); + +size_t base32_encoded_length(size_t inlen); +size_t base32_decoded_length(size_t inlen); + +#endif diff --git a/deps/crypto/trezor-crypto/base58.c b/deps/crypto/trezor-crypto/base58.c new file mode 100644 index 000000000..faa763501 --- /dev/null +++ b/deps/crypto/trezor-crypto/base58.c @@ -0,0 +1,274 @@ +/** + * Copyright (c) 2012-2014 Luke Dashjr + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "base58.h" +#include +#include +#include "memzero.h" +#include "ripemd160.h" +#include "sha2.h" + +const char b58digits_ordered[] = + "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; +const int8_t b58digits_map[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, + 8, -1, -1, -1, -1, -1, -1, -1, 9, 10, 11, 12, 13, 14, 15, 16, -1, 17, 18, + 19, 20, 21, -1, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, + -1, -1, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, -1, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, -1, -1, -1, +}; + +typedef uint64_t b58_maxint_t; +typedef uint32_t b58_almostmaxint_t; +#define b58_almostmaxint_bits (sizeof(b58_almostmaxint_t) * 8) +static const b58_almostmaxint_t b58_almostmaxint_mask = + ((((b58_maxint_t)1) << b58_almostmaxint_bits) - 1); + +// Decodes a null-terminated Base58 string `b58` to binary and writes the result +// at the end of the buffer `bin` of size `*binszp`. On success `*binszp` is set +// to the number of valid bytes at the end of the buffer. +bool b58tobin(void *bin, size_t *binszp, const char *b58) { + size_t binsz = *binszp; + + if (binsz == 0) { + return false; + } + + const unsigned char *b58u = (const unsigned char *)b58; + unsigned char *binu = bin; + size_t outisz = + (binsz + sizeof(b58_almostmaxint_t) - 1) / sizeof(b58_almostmaxint_t); + b58_almostmaxint_t outi[outisz]; + b58_maxint_t t = 0; + b58_almostmaxint_t c = 0; + size_t i = 0, j = 0; + uint8_t bytesleft = binsz % sizeof(b58_almostmaxint_t); + b58_almostmaxint_t zeromask = + bytesleft ? (b58_almostmaxint_mask << (bytesleft * 8)) : 0; + unsigned zerocount = 0; + + size_t b58sz = strlen(b58); + + memzero(outi, sizeof(outi)); + + // Leading zeros, just count + for (i = 0; i < b58sz && b58u[i] == '1'; ++i) ++zerocount; + + for (; i < b58sz; ++i) { + if (b58u[i] & 0x80) + // High-bit set on invalid digit + return false; + if (b58digits_map[b58u[i]] == -1) + // Invalid base58 digit + return false; + c = (unsigned)b58digits_map[b58u[i]]; + for (j = outisz; j--;) { + t = ((b58_maxint_t)outi[j]) * 58 + c; + c = t >> b58_almostmaxint_bits; + outi[j] = t & b58_almostmaxint_mask; + } + if (c) + // Output number too big (carry to the next int32) + return false; + if (outi[0] & zeromask) + // Output number too big (last int32 filled too far) + return false; + } + + j = 0; + if (bytesleft) { + for (i = bytesleft; i > 0; --i) { + *(binu++) = (outi[0] >> (8 * (i - 1))) & 0xff; + } + ++j; + } + + for (; j < outisz; ++j) { + for (i = sizeof(*outi); i > 0; --i) { + *(binu++) = (outi[j] >> (8 * (i - 1))) & 0xff; + } + } + + // locate the most significant byte + binu = bin; + for (i = 0; i < binsz; ++i) { + if (binu[i]) break; + } + + // prepend the correct number of null-bytes + if (zerocount > i) { + /* result too large */ + return false; + } + *binszp = binsz - i + zerocount; + + return true; +} + +int b58check(const void *bin, size_t binsz, HasherType hasher_type, + const char *base58str) { + unsigned char buf[32] = {0}; + const uint8_t *binc = bin; + unsigned i = 0; + if (binsz < 4) return -4; + hasher_Raw(hasher_type, bin, binsz - 4, buf); + if (memcmp(&binc[binsz - 4], buf, 4)) return -1; + + // Check number of zeros is correct AFTER verifying checksum (to avoid + // possibility of accessing base58str beyond the end) + for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i) { + } // Just finding the end of zeros, nothing to do in loop + if (binc[i] == '\0' || base58str[i] == '1') return -3; + + return binc[0]; +} + +bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz) { + const uint8_t *bin = data; + int carry = 0; + size_t i = 0, j = 0, high = 0, zcount = 0; + size_t size = 0; + + while (zcount < binsz && !bin[zcount]) ++zcount; + + size = (binsz - zcount) * 138 / 100 + 1; + uint8_t buf[size]; + memzero(buf, size); + + for (i = zcount, high = size - 1; i < binsz; ++i, high = j) { + for (carry = bin[i], j = size - 1; (j > high) || carry; --j) { + carry += 256 * buf[j]; + buf[j] = carry % 58; + carry /= 58; + if (!j) { + // Otherwise j wraps to maxint which is > high + break; + } + } + } + + for (j = 0; j < size && !buf[j]; ++j) + ; + + if (*b58sz <= zcount + size - j) { + *b58sz = zcount + size - j + 1; + return false; + } + + if (zcount) memset(b58, '1', zcount); + for (i = zcount; j < size; ++i, ++j) b58[i] = b58digits_ordered[buf[j]]; + b58[i] = '\0'; + *b58sz = i + 1; + + return true; +} + +int base58_encode_check(const uint8_t *data, int datalen, + HasherType hasher_type, char *str, int strsize) { + if (datalen > 128) { + return 0; + } + uint8_t buf[datalen + 32]; + memset(buf, 0, sizeof(buf)); + uint8_t *hash = buf + datalen; + memcpy(buf, data, datalen); + hasher_Raw(hasher_type, data, datalen, hash); + size_t res = strsize; + bool success = b58enc(str, &res, buf, datalen + 4); + memzero(buf, sizeof(buf)); + return success ? res : 0; +} + +int base58_decode_check(const char *str, HasherType hasher_type, uint8_t *data, + int datalen) { + if (datalen > 128) { + return 0; + } + uint8_t d[datalen + 4]; + memset(d, 0, sizeof(d)); + size_t res = datalen + 4; + if (b58tobin(d, &res, str) != true) { + return 0; + } + uint8_t *nd = d + datalen + 4 - res; + if (b58check(nd, res, hasher_type, str) < 0) { + return 0; + } + memcpy(data, nd, res - 4); + return res - 4; +} + +#if USE_GRAPHENE +int b58gphcheck(const void *bin, size_t binsz, const char *base58str) { + unsigned char buf[32] = {0}; + const uint8_t *binc = bin; + unsigned i = 0; + if (binsz < 4) return -4; + ripemd160(bin, binsz - 4, buf); // No double SHA256, but a single RIPEMD160 + if (memcmp(&binc[binsz - 4], buf, 4)) return -1; + + // Check number of zeros is correct AFTER verifying checksum (to avoid + // possibility of accessing base58str beyond the end) + for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i) { + } // Just finding the end of zeros, nothing to do in loop + if (binc[i] == '\0' || base58str[i] == '1') return -3; + + return binc[0]; +} + +int base58gph_encode_check(const uint8_t *data, int datalen, char *str, + int strsize) { + if (datalen > 128) { + return 0; + } + uint8_t buf[datalen + 32]; + memset(buf, 0, sizeof(buf)); + uint8_t *hash = buf + datalen; + memcpy(buf, data, datalen); + ripemd160(data, datalen, hash); // No double SHA256, but a single RIPEMD160 + size_t res = strsize; + bool success = b58enc(str, &res, buf, datalen + 4); + memzero(buf, sizeof(buf)); + return success ? res : 0; +} + +int base58gph_decode_check(const char *str, uint8_t *data, int datalen) { + if (datalen > 128) { + return 0; + } + uint8_t d[datalen + 4]; + memset(d, 0, sizeof(d)); + size_t res = datalen + 4; + if (b58tobin(d, &res, str) != true) { + return 0; + } + uint8_t *nd = d + datalen + 4 - res; + if (b58gphcheck(nd, res, str) < 0) { + return 0; + } + memcpy(data, nd, res - 4); + return res - 4; +} +#endif diff --git a/deps/crypto/trezor-crypto/base58.h b/deps/crypto/trezor-crypto/base58.h new file mode 100644 index 000000000..97cb54e60 --- /dev/null +++ b/deps/crypto/trezor-crypto/base58.h @@ -0,0 +1,53 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BASE58_H__ +#define __BASE58_H__ + +#include +#include +#include "hasher.h" +#include "options.h" + +extern const char b58digits_ordered[]; +extern const int8_t b58digits_map[]; + +int base58_encode_check(const uint8_t *data, int len, HasherType hasher_type, + char *str, int strsize); +int base58_decode_check(const char *str, HasherType hasher_type, uint8_t *data, + int datalen); + +// Private +bool b58tobin(void *bin, size_t *binszp, const char *b58); +int b58check(const void *bin, size_t binsz, HasherType hasher_type, + const char *base58str); +bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz); + +#if USE_GRAPHENE +int base58gph_encode_check(const uint8_t *data, int datalen, char *str, + int strsize); +int base58gph_decode_check(const char *str, uint8_t *data, int datalen); +int b58gphcheck(const void *bin, size_t binsz, const char *base58str); +#endif + +#endif diff --git a/deps/crypto/trezor-crypto/bignum.c b/deps/crypto/trezor-crypto/bignum.c new file mode 100644 index 000000000..e2bb9a129 --- /dev/null +++ b/deps/crypto/trezor-crypto/bignum.c @@ -0,0 +1,1833 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * Copyright (c) 2015 Jochen Hoenicke + * Copyright (c) 2016 Alex Beregszaszi + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "bignum.h" + +#include +#include +#include +#include + +#include "memzero.h" +#include "script.h" + +/* + This library implements 256-bit numbers arithmetic. + + An unsigned 256-bit number is represented by a bignum256 structure, that is an + array of nine 32-bit values called limbs. Limbs are digits of the number in + the base 2**29 representation in the little endian order. This means that + bignum256 x; + represents the value + sum([x[i] * 2**(29*i) for i in range(9)). + + A limb of a bignum256 is *normalized* iff it's less than 2**29. + A bignum256 is *normalized* iff every its limb is normalized. + A number is *fully reduced modulo p* iff it is less than p. + A number is *partly reduced modulo p* iff is is less than 2*p. + The number p is usually a prime number such that 2^256 - 2^224 <= p <= 2^256. + + All functions except bn_fast_mod expect that all their bignum256 inputs are + normalized. (The function bn_fast_mod allows the input number to have the + most significant limb unnormalized). All bignum256 outputs of all functions + are guaranteed to be normalized. + + A number can be partly reduced with bn_fast_mod, a partly reduced number can + be fully reduced with bn_mod. + + A function has *constant control flow with regard to its argument* iff the + order in which instructions of the function are executed doesn't depend on the + value of the argument. + A function has *constant memory access flow with regard to its argument* iff + the memory addresses that are acessed and the order in which they are accessed + don't depend on the value of the argument. + A function *has contant control (memory access) flow* iff it has constant + control (memory access) flow with regard to all its arguments. + + The following function has contant control flow with regard to its arugment + n, however is doesn't have constant memory access flow with regard to it: + void (int n, int *a) } + a[0] = 0; + a[n] = 0; // memory address reveals the value of n + } + + Unless stated otherwise all functions are supposed to have both constant + control flow and constant memory access flow. + */ + +#define BN_MAX_DECIMAL_DIGITS \ + 79 // floor(log(2**(LIMBS * BITS_PER_LIMB), 10)) + 1 + +// out_number = (bignum256) in_number +// Assumes in_number is a raw bigendian 256-bit number +// Guarantees out_number is normalized +void bn_read_be(const uint8_t *in_number, bignum256 *out_number) { + uint32_t temp = 0; + + for (int i = 0; i < BN_LIMBS - 1; i++) { + uint32_t limb = read_be(in_number + (BN_LIMBS - 2 - i) * 4); + + temp |= limb << (BN_EXTRA_BITS * i); + out_number->val[i] = temp & BN_LIMB_MASK; + + temp = limb >> (32 - BN_EXTRA_BITS * (i + 1)); + } + + out_number->val[BN_LIMBS - 1] = temp; +} + +// out_number = (256BE) in_number +// Assumes in_number < 2**256 +// Guarantess out_number is a raw bigendian 256-bit number +void bn_write_be(const bignum256 *in_number, uint8_t *out_number) { + uint32_t temp = in_number->val[BN_LIMBS - 1]; + for (int i = BN_LIMBS - 2; i >= 0; i--) { + uint32_t limb = in_number->val[i]; + + temp = (temp << (BN_BITS_PER_LIMB - BN_EXTRA_BITS * i)) | + (limb >> (BN_EXTRA_BITS * i)); + write_be(out_number + (BN_LIMBS - 2 - i) * 4, temp); + + temp = limb; + } +} + +// out_number = (bignum256) in_number +// Assumes in_number is a raw little endian 256-bit number +// Guarantees out_number is normalized +void bn_read_le(const uint8_t *in_number, bignum256 *out_number) { + uint32_t temp = 0; + for (int i = 0; i < BN_LIMBS - 1; i++) { + uint32_t limb = read_le(in_number + i * 4); + + temp |= limb << (BN_EXTRA_BITS * i); + out_number->val[i] = temp & BN_LIMB_MASK; + temp = limb >> (32 - BN_EXTRA_BITS * (i + 1)); + } + + out_number->val[BN_LIMBS - 1] = temp; +} + +// out_number = (256LE) in_number +// Assumes in_number < 2**256 +// Guarantess out_number is a raw little endian 256-bit number +void bn_write_le(const bignum256 *in_number, uint8_t *out_number) { + uint32_t temp = in_number->val[BN_LIMBS - 1]; + + for (int i = BN_LIMBS - 2; i >= 0; i--) { + uint32_t limb = in_number->val[i]; + temp = (temp << (BN_BITS_PER_LIMB - BN_EXTRA_BITS * i)) | + (limb >> (BN_EXTRA_BITS * i)); + write_le(out_number + i * 4, temp); + temp = limb; + } +} + +// out_number = (bignum256) in_number +// Guarantees out_number is normalized +void bn_read_uint32(uint32_t in_number, bignum256 *out_number) { + out_number->val[0] = in_number & BN_LIMB_MASK; + out_number->val[1] = in_number >> BN_BITS_PER_LIMB; + for (uint32_t i = 2; i < BN_LIMBS; i++) out_number->val[i] = 0; +} + +// out_number = (bignum256) in_number +// Guarantees out_number is normalized +void bn_read_uint64(uint64_t in_number, bignum256 *out_number) { + out_number->val[0] = in_number & BN_LIMB_MASK; + out_number->val[1] = (in_number >>= BN_BITS_PER_LIMB) & BN_LIMB_MASK; + out_number->val[2] = in_number >> BN_BITS_PER_LIMB; + for (uint32_t i = 3; i < BN_LIMBS; i++) out_number->val[i] = 0; +} + +// Returns the bitsize of x +// Assumes x is normalized +// The function doesn't have neither constant control flow nor constant memory +// access flow +int bn_bitcount(const bignum256 *x) { + for (int i = BN_LIMBS - 1; i >= 0; i--) { + uint32_t limb = x->val[i]; + if (limb != 0) { + // __builtin_clz returns the number of leading zero bits starting at the + // most significant bit position + return i * BN_BITS_PER_LIMB + (32 - __builtin_clz(limb)); + } + } + return 0; +} + +// Returns the number of decimal digits of x; if x is 0, returns 1 +// Assumes x is normalized +// The function doesn't have neither constant control flow nor constant memory +// access flow +unsigned int bn_digitcount(const bignum256 *x) { + bignum256 val = {0}; + bn_copy(x, &val); + + unsigned int digits = 1; + for (unsigned int i = 0; i < BN_MAX_DECIMAL_DIGITS; i += 3) { + uint32_t limb = 0; + + bn_divmod1000(&val, &limb); + + if (limb >= 100) { + digits = i + 3; + } else if (limb >= 10) { + digits = i + 2; + } else if (limb >= 1) { + digits = i + 1; + } + } + + memzero(&val, sizeof(val)); + + return digits; +} + +// x = 0 +// Guarantees x is normalized +void bn_zero(bignum256 *x) { + for (int i = 0; i < BN_LIMBS; i++) { + x->val[i] = 0; + } +} + +// x = 1 +// Guarantees x is normalized +void bn_one(bignum256 *x) { + x->val[0] = 1; + for (int i = 1; i < BN_LIMBS; i++) { + x->val[i] = 0; + } +} + +// Returns x == 0 +// Assumes x is normalized +int bn_is_zero(const bignum256 *x) { + uint32_t result = 0; + for (int i = 0; i < BN_LIMBS; i++) { + result |= x->val[i]; + } + return !result; +} + +// Returns x == 1 +// Assumes x is normalized +int bn_is_one(const bignum256 *x) { + uint32_t result = x->val[0] ^ 1; + for (int i = 1; i < BN_LIMBS; i++) { + result |= x->val[i]; + } + return !result; +} + +// Returns x < y +// Assumes x, y are normalized +int bn_is_less(const bignum256 *x, const bignum256 *y) { + uint32_t res1 = 0; + uint32_t res2 = 0; + for (int i = BN_LIMBS - 1; i >= 0; i--) { + res1 = (res1 << 1) | (x->val[i] < y->val[i]); + res2 = (res2 << 1) | (x->val[i] > y->val[i]); + } + return res1 > res2; +} + +// Returns x == y +// Assumes x, y are normalized +int bn_is_equal(const bignum256 *x, const bignum256 *y) { + uint32_t result = 0; + for (int i = 0; i < BN_LIMBS; i++) { + result |= x->val[i] ^ y->val[i]; + } + return !result; +} + +// res = cond if truecase else falsecase +// Assumes cond is either 0 or 1 +// Works properly even if &res == &truecase or &res == &falsecase or +// &truecase == &falsecase or &res == &truecase == &falsecase +void bn_cmov(bignum256 *res, volatile uint32_t cond, const bignum256 *truecase, + const bignum256 *falsecase) { + // Intentional use of bitwise OR operator to ensure constant-time + assert((int)(cond == 1) | (int)(cond == 0)); + + uint32_t tmask = -cond; // tmask = 0xFFFFFFFF if cond else 0x00000000 + uint32_t fmask = ~tmask; // fmask = 0x00000000 if cond else 0xFFFFFFFF + + for (int i = 0; i < BN_LIMBS; i++) { + res->val[i] = (truecase->val[i] & tmask) | (falsecase->val[i] & fmask); + } +} + +// x = -x % prime if cond else x, +// Explicitly x = (3 * prime - x if x > prime else 2 * prime - x) if cond else +// else (x if x > prime else x + prime) +// Assumes x is normalized and partly reduced +// Assumes cond is either 1 or 0 +// Guarantees x is normalized +// Assumes prime is normalized and +// 0 < prime < 2**260 == 2**(BITS_PER_LIMB * LIMBS - 1) +void bn_cnegate(volatile uint32_t cond, bignum256 *x, const bignum256 *prime) { + // Intentional use of bitwise OR operator to ensure constant time + assert((int)(cond == 1) | (int)(cond == 0)); + + uint32_t tmask = -cond; // tmask = 0xFFFFFFFF if cond else 0x00000000 + uint32_t fmask = ~tmask; // fmask = 0x00000000 if cond else 0xFFFFFFFF + + bn_mod(x, prime); + // x < prime + + uint32_t acc1 = 1; + uint32_t acc2 = 0; + + for (int i = 0; i < BN_LIMBS; i++) { + acc1 += (BN_BASE - 1) + 2 * prime->val[i] - x->val[i]; + // acc1 neither overflows 32 bits nor underflows 0 + // Proof: + // acc1 + (BASE - 1) + 2 * prime[i] - x[i] + // >= (BASE - 1) - x >= (2**BITS_PER_LIMB - 1) - (2**BITS_PER_LIMB - 1) + // == 0 + // acc1 + (BASE - 1) + 2 * prime[i] - x[i] + // <= acc1 + (BASE - 1) + 2 * prime[i] + // <= (2**(32 - BITS_PER_LIMB) - 1) + 2 * (2**BITS_PER_LIMB - 1) + + // (2**BITS_PER_LIMB - 1) + // == 7 + 3 * 2**29 < 2**32 + + acc2 += prime->val[i] + x->val[i]; + // acc2 doesn't overflow 32 bits + // Proof: + // acc2 + prime[i] + x[i] + // <= 2**(32 - BITS_PER_LIMB) - 1 + 2 * (2**BITS_PER_LIMB - 1) + // == 2**(32 - BITS_PER_LIMB) + 2**(BITS_PER_LIMB + 1) - 2 + // == 2**30 + 5 < 2**32 + + // x = acc1 & LIMB_MASK if cond else acc2 & LIMB_MASK + x->val[i] = ((acc1 & tmask) | (acc2 & fmask)) & BN_LIMB_MASK; + + acc1 >>= BN_BITS_PER_LIMB; + // acc1 <= 7 == 2**(32 - BITS_PER_LIMB) - 1 + // acc1 == 2**(BITS_PER_LIMB * (i + 1)) + 2 * prime[:i + 1] - x[:i + 1] + // >> BITS_PER_LIMB * (i + 1) + + acc2 >>= BN_BITS_PER_LIMB; + // acc2 <= 7 == 2**(32 - BITS_PER_LIMB) - 1 + // acc2 == prime[:i + 1] + x[:i + 1] >> BITS_PER_LIMB * (i + 1) + } + + // assert(acc1 == 1); // assert prime <= 2**260 + // assert(acc2 == 0); + + // clang-format off + // acc1 == 1 + // Proof: + // acc1 == 2**(BITS_PER_LIMB * LIMBS) + 2 * prime[:LIMBS] - x[:LIMBS] >> BITS_PER_LIMB * LIMBS + // == 2**(BITS_PER_LIMB * LIMBS) + 2 * prime - x >> BITS_PER_LIMB * LIMBS + // <= 2**(BITS_PER_LIMB * LIMBS) + 2 * prime >> BITS_PER_LIMB * LIMBS + // <= 2**(BITS_PER_LIMB * LIMBS) + 2 * (2**(BITS_PER_LIMB * LIMBS - 1) - 1) >> BITS_PER_LIMB * LIMBS + // <= 2**(BITS_PER_LIMB * LIMBS) + 2**(BITS_PER_LIMB * LIMBS) - 2 >> BITS_PER_LIMB * LIMBS + // == 1 + + // acc1 == 2**(BITS_PER_LIMB * LIMBS) + 2 * prime[:LIMBS] - x[:LIMBS] >> BITS_PER_LIMB * LIMBS + // == 2**(BITS_PER_LIMB * LIMBS) + 2 * prime - x >> BITS_PER_LIMB * LIMBS + // >= 2**(BITS_PER_LIMB * LIMBS) + 0 >> BITS_PER_LIMB * LIMBS + // == 1 + + // acc2 == 0 + // Proof: + // acc2 == prime[:LIMBS] + x[:LIMBS] >> BITS_PER_LIMB * LIMBS + // == prime + x >> BITS_PER_LIMB * LIMBS + // <= 2 * prime - 1 >> BITS_PER_LIMB * LIMBS + // <= 2 * (2**(BITS_PER_LIMB * LIMBS - 1) - 1) - 1 >> 261 + // == 2**(BITS_PER_LIMB * LIMBS) - 3 >> BITS_PER_LIMB * LIMBS + // == 0 + // clang-format on +} + +// x <<= 1 +// Assumes x is normalized, x < 2**260 == 2**(LIMBS*BITS_PER_LIMB - 1) +// Guarantees x is normalized +void bn_lshift(bignum256 *x) { + for (int i = BN_LIMBS - 1; i > 0; i--) { + x->val[i] = ((x->val[i] << 1) & BN_LIMB_MASK) | + (x->val[i - 1] >> (BN_BITS_PER_LIMB - 1)); + } + x->val[0] = (x->val[0] << 1) & BN_LIMB_MASK; +} + +// x >>= 1, i.e. x = floor(x/2) +// Assumes x is normalized +// Guarantees x is normalized +// If x is partly reduced (fully reduced) modulo prime, +// guarantess x will be partly reduced (fully reduced) modulo prime +void bn_rshift(bignum256 *x) { + for (int i = 0; i < BN_LIMBS - 1; i++) { + x->val[i] = + (x->val[i] >> 1) | ((x->val[i + 1] & 1) << (BN_BITS_PER_LIMB - 1)); + } + x->val[BN_LIMBS - 1] >>= 1; +} + +// Sets i-th least significant bit (counting from zero) +// Assumes x is normalized and 0 <= i < 261 == LIMBS*BITS_PER_LIMB +// Guarantees x is normalized +// The function has constant control flow but not constant memory access flow +// with regard to i +void bn_setbit(bignum256 *x, uint16_t i) { + assert(i < BN_LIMBS * BN_BITS_PER_LIMB); + x->val[i / BN_BITS_PER_LIMB] |= (1u << (i % BN_BITS_PER_LIMB)); +} + +// clears i-th least significant bit (counting from zero) +// Assumes x is normalized and 0 <= i < 261 == LIMBS*BITS_PER_LIMB +// Guarantees x is normalized +// The function has constant control flow but not constant memory access flow +// with regard to i +void bn_clearbit(bignum256 *x, uint16_t i) { + assert(i < BN_LIMBS * BN_BITS_PER_LIMB); + x->val[i / BN_BITS_PER_LIMB] &= ~(1u << (i % BN_BITS_PER_LIMB)); +} + +// returns i-th least significant bit (counting from zero) +// Assumes x is normalized and 0 <= i < 261 == LIMBS*BITS_PER_LIMB +// The function has constant control flow but not constant memory access flow +// with regard to i +uint32_t bn_testbit(const bignum256 *x, uint16_t i) { + assert(i < BN_LIMBS * BN_BITS_PER_LIMB); + return (x->val[i / BN_BITS_PER_LIMB] >> (i % BN_BITS_PER_LIMB)) & 1; +} + +// res = x ^ y +// Assumes x, y are normalized +// Guarantees res is normalized +// Works properly even if &res == &x or &res == &y or &res == &x == &y +void bn_xor(bignum256 *res, const bignum256 *x, const bignum256 *y) { + for (int i = 0; i < BN_LIMBS; i++) { + res->val[i] = x->val[i] ^ y->val[i]; + } +} + +// x = x / 2 % prime +// Explicitly x = x / 2 if is_even(x) else (x + prime) / 2 +// Assumes x is normalized, x + prime < 261 == LIMBS * BITS_PER_LIMB +// Guarantees x is normalized +// If x is partly reduced (fully reduced) modulo prime, +// guarantess x will be partly reduced (fully reduced) modulo prime +// Assumes prime is an odd number and normalized +void bn_mult_half(bignum256 *x, const bignum256 *prime) { + // x = x / 2 if is_even(x) else (x + prime) / 2 + + uint32_t x_is_odd_mask = + -(x->val[0] & 1); // x_is_odd_mask = 0xFFFFFFFF if is_odd(x) else 0 + + uint32_t acc = (x->val[0] + (prime->val[0] & x_is_odd_mask)) >> 1; + // acc < 2**BITS_PER_LIMB + // Proof: + // acc == x[0] + prime[0] & x_is_odd_mask >> 1 + // <= (2**(BITS_PER_LIMB) - 1) + (2**(BITS_PER_LIMB) - 1) >> 1 + // == 2**(BITS_PER_LIMB + 1) - 2 >> 1 + // < 2**(BITS_PER_LIMB) + + for (int i = 0; i < BN_LIMBS - 1; i++) { + uint32_t temp = (x->val[i + 1] + (prime->val[i + 1] & x_is_odd_mask)); + // temp < 2**(BITS_PER_LIMB + 1) + // Proof: + // temp == x[i + 1] + val[i + 1] & x_is_odd_mask + // <= (2**(BITS_PER_LIMB) - 1) + (2**(BITS_PER_LIMB) - 1) + // < 2**(BITS_PER_LIMB + 1) + + acc += (temp & 1) << (BN_BITS_PER_LIMB - 1); + // acc doesn't overflow 32 bits + // Proof: + // acc + (temp & 1 << BITS_PER_LIMB - 1) + // <= 2**(BITS_PER_LIMB + 1) + 2**(BITS_PER_LIMB - 1) + // <= 2**30 + 2**28 < 2**32 + + x->val[i] = acc & BN_LIMB_MASK; + acc >>= BN_BITS_PER_LIMB; + acc += temp >> 1; + // acc < 2**(BITS_PER_LIMB + 1) + // Proof: + // acc + (temp >> 1) + // <= (2**(32 - BITS_PER_LIMB) - 1) + (2**(BITS_PER_LIMB + 1) - 1 >> 1) + // == 7 + 2**(BITS_PER_LIMB) - 1 < 2**(BITS_PER_LIMB + 1) + + // acc == x[:i+2]+(prime[:i+2] & x_is_odd_mask) >> BITS_PER_LIMB * (i+1) + } + x->val[BN_LIMBS - 1] = acc; + + // assert(acc >> BITS_PER_LIMB == 0); + // acc >> BITS_PER_LIMB == 0 + // Proof: + // acc + // == x[:LIMBS] + (prime[:LIMBS] & x_is_odd_mask) >> BITS_PER_LIMB*LIMBS + // == x + (prime & x_is_odd_mask) >> BITS_PER_LIMB * LIMBS + // <= x + prime >> BITS_PER_LIMB * LIMBS + // <= 2**(BITS_PER_LIMB * LIMBS) - 1 >> BITS_PER_LIMB * LIMBS + // == 0 +} + +// x = x * k % prime +// Assumes x is normalized, 0 <= k <= 8 = 2**(32 - BITS_PER_LIMB) +// Assumes prime is normalized and 2^256 - 2^224 <= prime <= 2^256 +// Guarantees x is normalized and partly reduced modulo prime +void bn_mult_k(bignum256 *x, uint8_t k, const bignum256 *prime) { + assert(k <= 8); + + for (int i = 0; i < BN_LIMBS; i++) { + x->val[i] = k * x->val[i]; + // x[i] doesn't overflow 32 bits + // k * x[i] <= 2**(32 - BITS_PER_LIMB) * (2**BITS_PER_LIMB - 1) + // < 2**(32 - BITS_PER_LIMB) * 2**BITS_PER_LIMB == 2**32 + } + + bn_fast_mod(x, prime); +} + +// Reduces partly reduced x modulo prime +// Explicitly x = x if x < prime else x - prime +// Assumes x is partly reduced modulo prime +// Guarantees x is fully reduced modulo prime +// Assumes prime is nonzero and normalized +void bn_mod(bignum256 *x, const bignum256 *prime) { + uint32_t x_less_prime = bn_is_less(x, prime); + + bignum256 temp = {0}; + bn_subtract(x, prime, &temp); + bn_cmov(x, x_less_prime, x, &temp); + + memzero(&temp, sizeof(temp)); +} + +// Auxiliary function for bn_multiply +// res = k * x +// Assumes k and x are normalized +// Guarantees res is normalized 18 digit little endian number in base 2**29 +void bn_multiply_long(const bignum256 *k, const bignum256 *x, + uint32_t res[2 * BN_LIMBS]) { + // Uses long multiplication in base 2**29, see + // https://en.wikipedia.org/wiki/Multiplication_algorithm#Long_multiplication + + uint64_t acc = 0; + + // compute lower half + for (int i = 0; i < BN_LIMBS; i++) { + for (int j = 0; j <= i; j++) { + acc += k->val[j] * (uint64_t)x->val[i - j]; + // acc doesn't overflow 64 bits + // Proof: + // acc <= acc + sum([k[j] * x[i-j] for j in range(i)]) + // <= (2**(64 - BITS_PER_LIMB) - 1) + + // LIMBS * (2**BITS_PER_LIMB - 1) * (2**BITS_PER_LIMB - 1) + // == (2**35 - 1) + 9 * (2**29 - 1) * (2**29 - 1) + // <= 2**35 + 9 * 2**58 < 2**64 + } + + res[i] = acc & BN_LIMB_MASK; + acc >>= BN_BITS_PER_LIMB; + // acc <= 2**35 - 1 == 2**(64 - BITS_PER_LIMB) - 1 + } + + // compute upper half + for (int i = BN_LIMBS; i < 2 * BN_LIMBS - 1; i++) { + for (int j = i - BN_LIMBS + 1; j < BN_LIMBS; j++) { + acc += k->val[j] * (uint64_t)x->val[i - j]; + // acc doesn't overflow 64 bits + // Proof: + // acc <= acc + sum([k[j] * x[i-j] for j in range(i)]) + // <= (2**(64 - BITS_PER_LIMB) - 1) + // LIMBS * (2**BITS_PER_LIMB - 1) * (2**BITS_PER_LIMB - 1) + // == (2**35 - 1) + 9 * (2**29 - 1) * (2**29 - 1) + // <= 2**35 + 9 * 2**58 < 2**64 + } + + res[i] = acc & (BN_BASE - 1); + acc >>= BN_BITS_PER_LIMB; + // acc < 2**35 == 2**(64 - BITS_PER_LIMB) + } + + res[2 * BN_LIMBS - 1] = acc; +} + +// Auxiliary function for bn_multiply +// Assumes 0 <= d <= 8 == LIMBS - 1 +// Assumes res is normalized and res < 2**(256 + 29*d + 31) +// Guarantess res in normalized and res < 2 * prime * 2**(29*d) +// Assumes prime is normalized, 2**256 - 2**224 <= prime <= 2**256 +void bn_multiply_reduce_step(uint32_t res[2 * BN_LIMBS], const bignum256 *prime, + uint32_t d) { + // clang-format off + // Computes res = res - (res // 2**(256 + BITS_PER_LIMB * d)) * prime * 2**(BITS_PER_LIMB * d) + + // res - (res // 2**(256 + BITS_PER_LIMB * d)) * prime * 2**(BITS_PER_LIMB * d) < 2 * prime * 2**(BITS_PER_LIMB * d) + // Proof: + // res - res // (2**(256 + BITS_PER_LIMB * d)) * 2**(BITS_PER_LIMB * d) * prime + // == res - res // (2**(256 + BITS_PER_LIMB * d)) * 2**(BITS_PER_LIMB * d) * (2**256 - (2**256 - prime)) + // == res - res // (2**(256 + BITS_PER_LIMB * d)) * 2**(BITS_PER_LIMB * d) * 2**256 + res // (2**(256 + BITS_PER_LIMB * d)) * 2**(BITS_PER_LIMB * d) * (2**256 - prime) + // == (res % 2**(256 + BITS_PER_LIMB * d)) + res // (2**256 + BITS_PER_LIMB * d) * 2**(BITS_PER_LIMB * d) * (2**256 - prime) + // <= (2**(256 + 29*d + 31) % 2**(256 + 29*d)) + (2**(256 + 29*d + 31) - 1) / (2**256 + 29*d) * 2**(29*d) * (2**256 - prime) + // <= 2**(256 + 29*d) + 2**(256 + 29*d + 31) / (2**256 + 29*d) * 2**(29*d) * (2**256 - prime) + // == 2**(256 + 29*d) + 2**31 * 2**(29*d) * (2**256 - prime) + // == 2**(29*d) * (2**256 + 2**31 * (2*256 - prime)) + // <= 2**(29*d) * (2**256 + 2**31 * 2*224) + // <= 2**(29*d) * (2**256 + 2**255) + // <= 2**(29*d) * 2 * (2**256 - 2**224) + // <= 2 * prime * 2**(29*d) + // clang-format on + + uint32_t coef = + (res[d + BN_LIMBS - 1] >> (256 - (BN_LIMBS - 1) * BN_BITS_PER_LIMB)) + + (res[d + BN_LIMBS] << ((BN_LIMBS * BN_BITS_PER_LIMB) - 256)); + + // coef == res // 2**(256 + BITS_PER_LIMB * d) + + // coef < 2**31 + // Proof: + // coef == res // 2**(256 + BITS_PER_LIMB * d) + // < 2**(256 + 29 * d + 31) // 2**(256 + 29 * d) + // == 2**31 + + const int shift = 31; + uint64_t acc = 1ull << shift; + + for (int i = 0; i < BN_LIMBS; i++) { + acc += (((uint64_t)(BN_BASE - 1)) << shift) + res[d + i] - + prime->val[i] * (uint64_t)coef; + // acc neither overflow 64 bits nor underflow zero + // Proof: + // acc + ((BASE - 1) << shift) + res[d + i] - prime[i] * coef + // >= ((BASE - 1) << shift) - prime[i] * coef + // == 2**shift * (2**BITS_PER_LIMB - 1) - (2**BITS_PER_LIMB - 1) * + // (2**31 - 1) + // == (2**shift - 2**31 + 1) * (2**BITS_PER_LIMB - 1) + // == (2**31 - 2**31 + 1) * (2**29 - 1) + // == 2**29 - 1 > 0 + // acc + ((BASE - 1) << shift) + res[d + i] - prime[i] * coef + // <= acc + ((BASE - 1) << shift) + res[d+i] + // <= (2**(64 - BITS_PER_LIMB) - 1) + 2**shift * (2**BITS_PER_LIMB - 1) + // + (2*BITS_PER_LIMB - 1) + // == (2**(64 - BITS_PER_LIMB) - 1) + (2**shift + 1) * + // (2**BITS_PER_LIMB - 1) + // == (2**35 - 1) + (2**31 + 1) * (2**29 - 1) + // <= 2**35 + 2**60 + 2**29 < 2**64 + + res[d + i] = acc & BN_LIMB_MASK; + acc >>= BN_BITS_PER_LIMB; + // acc <= 2**(64 - BITS_PER_LIMB) - 1 == 2**35 - 1 + + // acc == (1 << BITS_PER_LIMB * (i + 1) + shift) + res[d : d + i + 1] + // - coef * prime[:i + 1] >> BITS_PER_LIMB * (i + 1) + } + + // acc += (((uint64_t)(BASE - 1)) << shift) + res[d + LIMBS]; + // acc >>= BITS_PER_LIMB; + // assert(acc <= 1ul << shift); + + // clang-format off + // acc == 1 << shift + // Proof: + // acc + // == (1 << BITS_PER_LIMB * (LIMBS + 1) + shift) + res[d : d + LIMBS + 1] - coef * prime[:LIMBS] >> BITS_PER_LIMB * (LIMBS + 1) + // == (1 << BITS_PER_LIMB * (LIMBS + 1) + shift) + res[d : d + LIMBS + 1] - coef * prime >> BITS_PER_LIMB * (LIMBS + 1) + + // == (1 << BITS_PER_LIMB * (LIMBS + 1) + shift) + (res[d : d + LIMBS + 1] - coef * prime) >> BITS_PER_LIMB * (LIMBS + 1) + // <= (1 << BITS_PER_LIMB * (LIMBS + 1) + shift) + (res[:d] + BASE**d * res[d : d + LIMBS + 1] - BASE**d * coef * prime)//BASE**d >> BITS_PER_LIMB * (LIMBS + 1) + // <= (1 << BITS_PER_LIMB * (LIMBS + 1) + shift) + (res - BASE**d * coef * prime) // BASE**d >> BITS_PER_LIMB * (LIMBS + 1) + // == (1 << BITS_PER_LIMB * (LIMBS + 1) + shift) + (2 * prime * BASE**d) // BASE**d >> BITS_PER_LIMB * (LIMBS + 1) + // <= (1 << 321) + 2 * 2**256 >> 290 + // == 1 << 31 == 1 << shift + + // == (1 << BITS_PER_LIMB * (LIMBS + 1) + shift) + res[d : d + LIMBS + 1] - coef * prime[:LIMBS + 1] >> BITS_PER_LIMB * (LIMBS + 1) + // >= (1 << BITS_PER_LIMB * (LIMBS + 1) + shift) + 0 >> BITS_PER_LIMB * (LIMBS + 1) + // == 1 << shift + // clang-format on + + res[d + BN_LIMBS] = 0; +} + +// Auxiliary function for bn_multiply +// Partly reduces res and stores both in x and res +// Assumes res in normalized and res < 2**519 +// Guarantees x is normalized and partly reduced modulo prime +// Assumes prime is normalized, 2**256 - 2**224 <= prime <= 2**256 +void bn_multiply_reduce(bignum256 *x, uint32_t res[2 * BN_LIMBS], + const bignum256 *prime) { + for (int i = BN_LIMBS - 1; i >= 0; i--) { + // res < 2**(256 + 29*i + 31) + // Proof: + // if i == LIMBS - 1: + // res < 2**519 + // == 2**(256 + 29 * 8 + 31) + // == 2**(256 + 29 * (LIMBS - 1) + 31) + // else: + // res < 2 * prime * 2**(29 * (i + 1)) + // <= 2**256 * 2**(29*i + 29) < 2**(256 + 29*i + 31) + bn_multiply_reduce_step(res, prime, i); + } + + for (int i = 0; i < BN_LIMBS; i++) { + x->val[i] = res[i]; + } +} + +// x = k * x % prime +// Assumes k, x are normalized, k * x < 2**519 +// Guarantees x is normalized and partly reduced modulo prime +// Assumes prime is normalized, 2**256 - 2**224 <= prime <= 2**256 +void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime) { + uint32_t res[2 * BN_LIMBS] = {0}; + + bn_multiply_long(k, x, res); + bn_multiply_reduce(x, res, prime); + + memzero(res, sizeof(res)); +} + +// Partly reduces x modulo prime +// Assumes limbs of x except the last (the most significant) one are normalized +// Assumes prime is normalized and 2^256 - 2^224 <= prime <= 2^256 +// Guarantees x is normalized and partly reduced modulo prime +void bn_fast_mod(bignum256 *x, const bignum256 *prime) { + // Computes x = x - (x // 2**256) * prime + + // x < 2**((LIMBS - 1) * BITS_PER_LIMB + 32) == 2**264 + + // x - (x // 2**256) * prime < 2 * prime + // Proof: + // x - (x // 2**256) * prime + // == x - (x // 2**256) * (2**256 - (2**256 - prime)) + // == x - ((x // 2**256) * 2**256) + (x // 2**256) * (2**256 - prime) + // == (x % prime) + (x // 2**256) * (2**256 - prime) + // <= prime - 1 + (2**264 // 2**256) * (2**256 - prime) + // <= 2**256 + 2**8 * 2**224 == 2**256 + 2**232 + // < 2 * (2**256 - 2**224) + // <= 2 * prime + + // x - (x // 2**256 - 1) * prime < 2 * prime + // Proof: + // x - (x // 2**256) * prime + prime + // == x - (x // 2**256) * (2**256 - (2**256 - prime)) + prime + // == x - ((x//2**256) * 2**256) + (x//2**256) * (2**256 - prime) + prime + // == (x % prime) + (x // 2**256) * (2**256 - prime) + prime + // <= 2 * prime - 1 + (2**264 // 2**256) * (2**256 - prime) + // <= 2 * prime + 2**8 * 2**224 == 2**256 + 2**232 + 2**256 - 2**224 + // < 2 * (2**256 - 2**224) + // <= 2 * prime + + uint32_t coef = + x->val[BN_LIMBS - 1] >> (256 - ((BN_LIMBS - 1) * BN_BITS_PER_LIMB)); + + // clang-format off + // coef == x // 2**256 + // 0 <= coef < 2**((LIMBS - 1) * BITS_PER_LIMB + 32 - 256) == 256 + // Proof: + //* Let x[[a : b] be the number consisting of a-th to (b-1)-th bit of the number x. + // x[LIMBS - 1] >> (256 - ((LIMBS - 1) * BITS_PER_LIMB)) + // == x[[(LIMBS - 1) * BITS_PER_LIMB : (LIMBS - 1) * BITS_PER_LIMB + 32]] >> (256 - ((LIMBS - 1) * BITS_PER_LIMB)) + // == x[[256 - ((LIMBS - 1) * BITS_PER_LIMB) + (LIMBS - 1) * BITS_PER_LIMB : (LIMBS - 1) * BITS_PER_LIMB + 32]] + // == x[[256 : (LIMBS - 1) * BITS_PER_LIMB + 32]] + // == x[[256 : 264]] == x // 2**256 + // clang-format on + + const int shift = 8; + uint64_t acc = 1ull << shift; + + for (int i = 0; i < BN_LIMBS; i++) { + acc += (((uint64_t)(BN_BASE - 1)) << shift) + x->val[i] - + prime->val[i] * (uint64_t)coef; + // acc neither overflows 64 bits nor underflows 0 + // Proof: + // acc + (BASE - 1 << shift) + x[i] - prime[i] * coef + // >= (BASE - 1 << shift) - prime[i] * coef + // >= 2**shift * (2**BITS_PER_LIMB - 1) - (2**BITS_PER_LIMB - 1) * 255 + // == (2**shift - 255) * (2**BITS_PER_LIMB - 1) + // == (2**8 - 255) * (2**29 - 1) == 2**29 - 1 >= 0 + // acc + (BASE - 1 << shift) + x[i] - prime[i] * coef + // <= acc + ((BASE - 1) << shift) + x[i] + // <= (2**(64 - BITS_PER_LIMB) - 1) + 2**shift * (2**BITS_PER_LIMB - 1) + // + (2**32 - 1) + // == (2**35 - 1) + 2**8 * (2**29 - 1) + 2**32 + // < 2**35 + 2**37 + 2**32 < 2**64 + + x->val[i] = acc & BN_LIMB_MASK; + acc >>= BN_BITS_PER_LIMB; + // acc <= 2**(64 - BITS_PER_LIMB) - 1 == 2**35 - 1 + + // acc == (1 << BITS_PER_LIMB * (i + 1) + shift) + x[:i + 1] + // - coef * prime[:i + 1] >> BITS_PER_LIMB * (i + 1) + } + + // assert(acc == 1 << shift); + + // clang-format off + // acc == 1 << shift + // Proof: + // acc + // == (1 << BITS_PER_LIMB * LIMBS + shift) + x[:LIMBS] - coef * prime[:LIMBS] >> BITS_PER_LIMB * LIMBS + // == (1 << BITS_PER_LIMB * LIMBS + shift) + (x - coef * prime) >> BITS_PER_LIMB * LIMBS + // <= (1 << BITS_PER_LIMB * LIMBS + shift) + (2 * prime) >> BITS_PER_LIMB * LIMBS + // <= (1 << BITS_PER_LIMB * LIMBS + shift) + 2 * 2**256 >> BITS_PER_LIMB * LIMBS + // <= 2**269 + 2**257 >> 2**261 + // <= 1 << 8 == 1 << shift + + // acc + // == (1 << BITS_PER_LIMB * LIMBS + shift) + x[:LIMBS] - coef * prime[:LIMBS] >> BITS_PER_LIMB * LIMBS + // >= (1 << BITS_PER_LIMB * LIMBS + shift) + 0 >> BITS_PER_LIMB * LIMBS + // == (1 << BITS_PER_LIMB * LIMBS + shift) + 0 >> BITS_PER_LIMB * LIMBS + // <= 1 << 8 == 1 << shift + // clang-format on +} + +// res = x**e % prime +// Assumes both x and e are normalized, x < 2**259 +// Guarantees res is normalized and partly reduced modulo prime +// Works properly even if &x == &res +// Assumes prime is normalized, 2**256 - 2**224 <= prime <= 2**256 +// The function doesn't have neither constant control flow nor constant memory +// access flow with regard to e +void bn_power_mod(const bignum256 *x, const bignum256 *e, + const bignum256 *prime, bignum256 *res) { + // Uses iterative right-to-left exponentiation by squaring, see + // https://en.wikipedia.org/wiki/Modular_exponentiation#Right-to-left_binary_method + + bignum256 acc = {0}; + bn_copy(x, &acc); + + bn_one(res); + for (int i = 0; i < BN_LIMBS; i++) { + uint32_t limb = e->val[i]; + + for (int j = 0; j < BN_BITS_PER_LIMB; j++) { + // Break if the following bits of the last limb are zero + if (i == BN_LIMBS - 1 && limb == 0) break; + + if (limb & 1) + // acc * res < 2**519 + // Proof: + // acc * res <= max(2**259 - 1, 2 * prime) * (2 * prime) + // == max(2**259 - 1, 2**257) * 2**257 < 2**259 * 2**257 + // == 2**516 < 2**519 + bn_multiply(&acc, res, prime); + + limb >>= 1; + // acc * acc < 2**519 + // Proof: + // acc * acc <= max(2**259 - 1, 2 * prime)**2 + // <= (2**259)**2 == 2**518 < 2**519 + bn_multiply(&acc, &acc, prime); + } + // acc == x**(e[:i + 1]) % prime + } + + memzero(&acc, sizeof(acc)); +} + +// x = sqrt(x) % prime +// Explicitly x = x**((prime+1)/4) % prime +// The other root is -sqrt(x) +// Assumes x is normalized, x < 2**259 and quadratic residuum mod prime +// Assumes prime is a prime number, prime % 4 == 3, it is normalized and +// 2**256 - 2**224 <= prime <= 2**256 +// Guarantees x is normalized and fully reduced modulo prime +// The function doesn't have neither constant control flow nor constant memory +// access flow with regard to prime +void bn_sqrt(bignum256 *x, const bignum256 *prime) { + // Uses the Lagrange formula for the primes of the special form, see + // http://en.wikipedia.org/wiki/Quadratic_residue#Prime_or_prime_power_modulus + // If prime % 4 == 3, then sqrt(x) % prime == x**((prime+1)//4) % prime + + assert(prime->val[BN_LIMBS - 1] % 4 == 3); + + // e = (prime + 1) // 4 + bignum256 e = {0}; + bn_copy(prime, &e); + bn_addi(&e, 1); + bn_rshift(&e); + bn_rshift(&e); + + bn_power_mod(x, &e, prime, x); + bn_mod(x, prime); + + memzero(&e, sizeof(e)); +} + +// a = 1/a % 2**n +// Assumes a is odd, 1 <= n <= 32 +// The function doesn't have neither constant control flow nor constant memory +// access flow with regard to n +uint32_t inverse_mod_power_two(uint32_t a, uint32_t n) { + // Uses "Explicit Quadratic Modular inverse modulo 2" from section 3.3 of "On + // Newton-Raphson iteration for multiplicative inverses modulo prime powers" + // by Jean-Guillaume Dumas, see + // https://arxiv.org/pdf/1209.6626.pdf + + // 1/a % 2**n + // = (2-a) * product([1 + (a-1)**(2**i) for i in range(1, floor(log2(n)))]) + + uint32_t acc = 2 - a; + uint32_t f = a - 1; + + // mask = (1 << n) - 1 + uint32_t mask = n == 32 ? 0xFFFFFFFF : (1u << n) - 1; + + for (uint32_t i = 1; i < n; i <<= 1) { + f = (f * f) & mask; + acc = (acc * (1 + f)) & mask; + } + + return acc; +} + +// x = (x / 2**BITS_PER_LIMB) % prime +// Assumes both x and prime are normalized +// Assumes prime is an odd number and normalized +// Guarantees x is normalized +// If x is partly reduced (fully reduced) modulo prime, +// guarantess x will be partly reduced (fully reduced) modulo prime +void bn_divide_base(bignum256 *x, const bignum256 *prime) { + // Uses an explicit formula for the modular inverse of power of two + // (x / 2**n) % prime == (x + ((-x / prime) % 2**n) * prime) // 2**n + // Proof: + // (x + ((-x / prime) % 2**n) * prime) % 2**n + // == (x - x / prime * prime) % 2**n + // == 0 + // (x + ((-1 / prime) % 2**n) * prime) % prime + // == x + // if x < prime: + // (x + ((-x / prime) % 2**n) * prime) // 2**n + // <= ((prime - 1) + (2**n - 1) * prime) / 2**n + // == (2**n * prime - 1) / 2**n == prime - 1 / 2**n < prime + // if x < 2 * prime: + // (x + ((-x / prime) % 2**n) * prime) // 2**n + // <= ((2 * prime - 1) + (2**n - 1) * prime) / 2**n + // == (2**n * prime + prime - 1) / 2**n + // == prime + (prime - 1) / 2**n < 2 * prime + + // m = (-x / prime) % 2**BITS_PER_LIMB + uint32_t m = (x->val[0] * (BN_BASE - inverse_mod_power_two( + prime->val[0], BN_BITS_PER_LIMB))) & + BN_LIMB_MASK; + // m < 2**BITS_PER_LIMB + + uint64_t acc = x->val[0] + (uint64_t)m * prime->val[0]; + acc >>= BN_BITS_PER_LIMB; + + for (int i = 1; i < BN_LIMBS; i++) { + acc = acc + x->val[i] + (uint64_t)m * prime->val[i]; + // acc does not overflow 64 bits + // acc == acc + x + m * prime + // <= 2**(64 - BITS_PER_LIMB) + 2**(BITS_PER_LIMB) + // 2**(BITS_PER_LIMB) * 2**(BITS_PER_LIMB) + // <= 2**(2 * BITS_PER_LIMB) + 2**(64 - BITS_PER_LIMB) + + // 2**(BITS_PER_LIMB) + // <= 2**58 + 2**35 + 2**29 < 2**64 + + x->val[i - 1] = acc & BN_LIMB_MASK; + acc >>= BN_BITS_PER_LIMB; + // acc < 2**35 == 2**(64 - BITS_PER_LIMB) + + // acc == x[:i + 1] + m * prime[:i + 1] >> BITS_PER_LIMB * (i + 1) + } + + x->val[BN_LIMBS - 1] = acc; + + assert(acc >> BN_BITS_PER_LIMB == 0); + + // clang-format off + // acc >> BITS_PER_LIMB == 0 + // Proof: + // acc >> BITS_PER_LIMB + // == (x[:LIMB] + m * prime[:LIMB] >> BITS_PER_LIMB * LIMBS) >> BITS_PER_LIMB * (LIMBS + 1) + // == x + m * prime >> BITS_PER_LIMB * (LIMBS + 1) + // <= (2**(BITS_PER_LIMB * LIMBS) - 1) + (2**BITS_PER_LIMB - 1) * (2**(BITS_PER_LIMB * LIMBS) - 1) >> BITS_PER_LIMB * (LIMBS + 1) + // == 2**(BITS_PER_LIMB * LIMBS) - 1 + 2**(BITS_PER_LIMB * (LIMBS + 1)) - 2**(BITS_PER_LIMB * LIMBS) - 2**BITS_PER_LIMB + 1 >> BITS_PER_LIMB * (LIMBS + 1) + // == 2**(BITS_PER_LIMB * (LIMBS + 1)) - 2**BITS_PER_LIMB >> BITS_PER_LIMB * (LIMBS + 1) + // == 0 + // clang-format on +} + +#if !USE_INVERSE_FAST +// x = 1/x % prime if x != 0 else 0 +// Assumes x is normalized +// Assumes prime is a prime number +// Guarantees x is normalized and fully reduced modulo prime +// Assumes prime is normalized, 2**256 - 2**224 <= prime <= 2**256 +// The function doesn't have neither constant control flow nor constant memory +// access flow with regard to prime +static void bn_inverse_slow(bignum256 *x, const bignum256 *prime) { + // Uses formula 1/x % prime == x**(prime - 2) % prime + // See https://en.wikipedia.org/wiki/Fermat%27s_little_theorem + + bn_fast_mod(x, prime); + + // e = prime - 2 + bignum256 e = {0}; + bn_read_uint32(2, &e); + bn_subtract(prime, &e, &e); + + bn_power_mod(x, &e, prime, x); + bn_mod(x, prime); + + memzero(&e, sizeof(e)); +} +#endif + +#if false +// x = 1/x % prime if x != 0 else 0 +// Assumes x is is_normalized +// Assumes GCD(x, prime) = 1 +// Guarantees x is normalized and fully reduced modulo prime +// Assumes prime is odd, normalized, 2**256 - 2**224 <= prime <= 2**256 +// The function doesn't have neither constant control flow nor constant memory +// access flow with regard to prime and x +static void bn_inverse_fast(bignum256 *x, const bignum256 *prime) { + // "The Almost Montgomery Inverse" from the section 3 of "Constant Time + // Modular Inversion" by Joppe W. Bos + // See http://www.joppebos.com/files/CTInversion.pdf + + /* + u = prime + v = x & prime + s = 1 + r = 0 + + k = 0 + while v != 1: + k += 1 + if is_even(u): + u = u // 2 + s = 2 * s + elif is_even(v): + v = v // 2 + r = 2 * r + elif v < u: + u = (u - v) // 2 + r = r + s + s = 2 * s + else: + v = (v - u) // 2 + s = r + s + r = 2 * r + + s = (s / 2**k) % prime + return s + */ + + if (bn_is_zero(x)) return; + + bn_fast_mod(x, prime); + bn_mod(x, prime); + + bignum256 u = {0}, v = {0}, r = {0}, s = {0}; + bn_copy(prime, &u); + bn_copy(x, &v); + bn_one(&s); + bn_zero(&r); + + int k = 0; + while (!bn_is_one(&v)) { + if ((u.val[0] & 1) == 0) { + bn_rshift(&u); + bn_lshift(&s); + } else if ((v.val[0] & 1) == 0) { + bn_rshift(&v); + bn_lshift(&r); + } else if (bn_is_less(&v, &u)) { + bn_subtract(&u, &v, &u); + bn_rshift(&u); + bn_add(&r, &s); + bn_lshift(&s); + } else { + bn_subtract(&v, &u, &v); + bn_rshift(&v); + bn_add(&s, &r); + bn_lshift(&r); + } + k += 1; + assert(!bn_is_zero(&v)); // assert GCD(x, prime) == 1 + } + + // s = s / 2**(k // BITS_PER_LIMB * BITS_PER_LIMB) + for (int i = 0; i < k / BITS_PER_LIMB; i++) { + bn_divide_base(&s, prime); + } + + // s = s / 2**(k % BITS_PER_LIMB) + for (int i = 0; i < k % BN_BITS_PER_LIMB; i++) { + bn_mult_half(&s, prime); + } + + bn_copy(&s, x); + + memzero(&u, sizeof(u)); + memzero(&v, sizeof(v)); + memzero(&r, sizeof(r)); + memzero(&s, sizeof(s)); +} +#endif + +#if USE_INVERSE_FAST +// x = 1/x % prime if x != 0 else 0 +// Assumes x is is_normalized +// Assumes GCD(x, prime) = 1 +// Guarantees x is normalized and fully reduced modulo prime +// Assumes prime is odd, normalized, 2**256 - 2**224 <= prime <= 2**256 +// The function has constant control flow but not constant memory access flow +// with regard to prime and x +static void bn_inverse_fast(bignum256 *x, const bignum256 *prime) { + // Custom constant time version of "The Almost Montgomery Inverse" from the + // section 3 of "Constant Time Modular Inversion" by Joppe W. Bos + // See http://www.joppebos.com/files/CTInversion.pdf + + /* + u = prime + v = x % prime + s = 1 + r = 0 + + k = 0 + while v != 1: + k += 1 + if is_even(u): # b1 + u = u // 2 + s = 2 * s + elif is_even(v): # b2 + v = v // 2 + r = 2 * r + elif v < u: # b3 + u = (u - v) // 2 + r = r + s + s = 2 * s + else: # b4 + v = (v - u) // 2 + s = r + s + r = 2 * r + + s = (s / 2**k) % prime + return s + */ + + bn_fast_mod(x, prime); + bn_mod(x, prime); + + bignum256 u = {0}, v = {0}, r = {0}, s = {0}; + bn_copy(prime, &u); + bn_copy(x, &v); + bn_one(&s); + bn_zero(&r); + + bignum256 zero = {0}; + bn_zero(&zero); + + int k = 0; + + int finished = 0, u_even = 0, v_even = 0, v_less_u = 0, b1 = 0, b2 = 0, + b3 = 0, b4 = 0; + finished = 0; + + for (int i = 0; i < 2 * BN_LIMBS * BN_BITS_PER_LIMB; i++) { + finished = finished | -bn_is_one(&v); + u_even = -bn_is_even(&u); + v_even = -bn_is_even(&v); + v_less_u = -bn_is_less(&v, &u); + + b1 = ~finished & u_even; + b2 = ~finished & ~b1 & v_even; + b3 = ~finished & ~b1 & ~b2 & v_less_u; + b4 = ~finished & ~b1 & ~b2 & ~b3; + +// The ternary operator for pointers with constant control flow +// BN_INVERSE_FAST_TERNARY(c, t, f) = t if c else f +// Very nasty hack, sorry for that +#define BN_INVERSE_FAST_TERNARY(c, t, f) \ + ((void *)(((c) & (uintptr_t)(t)) | (~(c) & (uintptr_t)(f)))) + + bn_subtract(BN_INVERSE_FAST_TERNARY(b3, &u, &v), + BN_INVERSE_FAST_TERNARY( + b3 | b4, BN_INVERSE_FAST_TERNARY(b3, &v, &u), &zero), + BN_INVERSE_FAST_TERNARY(b3, &u, &v)); + + bn_add(BN_INVERSE_FAST_TERNARY(b3, &r, &s), + BN_INVERSE_FAST_TERNARY(b3 | b4, BN_INVERSE_FAST_TERNARY(b3, &s, &r), + &zero)); + bn_rshift(BN_INVERSE_FAST_TERNARY(b1 | b3, &u, &v)); + bn_lshift(BN_INVERSE_FAST_TERNARY(b1 | b3, &s, &r)); + + k = k - ~finished; + } + + // s = s / 2**(k // BITS_PER_LIMB * BITS_PER_LIMB) + for (int i = 0; i < 2 * BN_LIMBS; i++) { + // s = s / 2**BITS_PER_LIMB % prime if i < k // BITS_PER_LIMB else s + bn_copy(&s, &r); + bn_divide_base(&r, prime); + bn_cmov(&s, i < k / BN_BITS_PER_LIMB, &r, &s); + } + + // s = s / 2**(k % BITS_PER_LIMB) + for (int i = 0; i < BN_BITS_PER_LIMB; i++) { + // s = s / 2 % prime if i < k % BITS_PER_LIMB else s + bn_copy(&s, &r); + bn_mult_half(&r, prime); + bn_cmov(&s, i < k % BN_BITS_PER_LIMB, &r, &s); + } + + bn_cmov(x, bn_is_zero(x), x, &s); + + memzero(&u, sizeof(u)); + memzero(&v, sizeof(v)); + memzero(&r, sizeof(s)); + memzero(&s, sizeof(s)); +} +#endif + +#if false +// x = 1/x % prime if x != 0 else 0 +// Assumes x is is_normalized +// Assumes GCD(x, prime) = 1 +// Guarantees x is normalized and fully reduced modulo prime +// Assumes prime is odd, normalized, 2**256 - 2**224 <= prime <= 2**256 +static void bn_inverse_fast(bignum256 *x, const bignum256 *prime) { + // Custom constant time version of "The Almost Montgomery Inverse" from the + // section 3 of "Constant Time Modular Inversion" by Joppe W. Bos + // See http://www.joppebos.com/files/CTInversion.pdf + + /* + u = prime + v = x % prime + s = 1 + r = 0 + + k = 0 + while v != 1: + k += 1 + if is_even(u): # b1 + u = u // 2 + s = 2 * s + elif is_even(v): # b2 + v = v // 2 + r = 2 * r + elif v < u: # b3 + u = (u - v) // 2 + r = r + s + s = 2 * s + else: # b4 + v = (v - u) // 2 + s = r + s + r = 2 * r + + s = (s / 2**k) % prime + return s + */ + + bn_fast_mod(x, prime); + bn_mod(x, prime); + + bignum256 u = {0}, v = {0}, r = {0}, s = {0}; + bn_copy(prime, &u); + bn_copy(x, &v); + bn_one(&s); + bn_zero(&r); + + bignum256 zero = {0}; + bn_zero(&zero); + + int k = 0; + + uint32_t finished = 0, u_even = 0, v_even = 0, v_less_u = 0, b1 = 0, b2 = 0, + b3 = 0, b4 = 0; + finished = 0; + + bignum256 u_half = {0}, v_half = {0}, u_minus_v_half = {0}, v_minus_u_half = {0}, r_plus_s = {0}, r_twice = {0}, s_twice = {0}; + for (int i = 0; i < 2 * BN_LIMBS * BN_BITS_PER_LIMB; i++) { + finished = finished | bn_is_one(&v); + u_even = bn_is_even(&u); + v_even = bn_is_even(&v); + v_less_u = bn_is_less(&v, &u); + + b1 = (finished ^ 1) & u_even; + b2 = (finished ^ 1) & (b1 ^ 1) & v_even; + b3 = (finished ^ 1) & (b1 ^ 1) & (b2 ^ 1) & v_less_u; + b4 = (finished ^ 1) & (b1 ^ 1) & (b2 ^ 1) & (b3 ^ 1); + + // u_half = u // 2 + bn_copy(&u, &u_half); + bn_rshift(&u_half); + + // v_half = v // 2 + bn_copy(&v, &v_half); + bn_rshift(&v_half); + + // u_minus_v_half = (u - v) // 2 + bn_subtract(&u, &v, &u_minus_v_half); + bn_rshift(&u_minus_v_half); + + // v_minus_u_half = (v - u) // 2 + bn_subtract(&v, &u, &v_minus_u_half); + bn_rshift(&v_minus_u_half); + + // r_plus_s = r + s + bn_copy(&r, &r_plus_s); + bn_add(&r_plus_s, &s); + + // r_twice = 2 * r + bn_copy(&r, &r_twice); + bn_lshift(&r_twice); + + // s_twice = 2 * s + bn_copy(&s, &s_twice); + bn_lshift(&s_twice); + + bn_cmov(&u, b1, &u_half, &u); + bn_cmov(&u, b3, &u_minus_v_half, &u); + + bn_cmov(&v, b2, &v_half, &v); + bn_cmov(&v, b4, &v_minus_u_half, &v); + + bn_cmov(&r, b2 | b4, &r_twice, &r); + bn_cmov(&r, b3, &r_plus_s, &r); + + bn_cmov(&s, b1 | b3, &s_twice, &s); + bn_cmov(&s, b4, &r_plus_s, &s); + + k = k + (finished ^ 1); + } + + // s = s / 2**(k // BITS_PER_LIMB * BITS_PER_LIMB) + for (int i = 0; i < 2 * BN_LIMBS; i++) { + // s = s / 2**BITS_PER_LIMB % prime if i < k // BITS_PER_LIMB else s + bn_copy(&s, &r); + bn_divide_base(&r, prime); + bn_cmov(&s, i < k / BITS_PER_LIMB, &r, &s); + } + + // s = s / 2**(k % BITS_PER_LIMB) + for (int i = 0; i < BN_BITS_PER_LIMB; i++) { + // s = s / 2 % prime if i < k % BITS_PER_LIMB else s + bn_copy(&s, &r); + bn_mult_half(&r, prime); + bn_cmov(&s, i < k % BN_BITS_PER_LIMB, &r, &s); + } + + bn_cmov(x, bn_is_zero(x), x, &s); + + memzero(&u, sizeof(u)); + memzero(&v, sizeof(v)); + memzero(&r, sizeof(r)); + memzero(&s, sizeof(s)); + memzero(&u_half, sizeof(u_half)); + memzero(&v_half, sizeof(v_half)); + memzero(&u_minus_v_half, sizeof(u_minus_v_half)); + memzero(&v_minus_u_half, sizeof(v_minus_u_half)); + memzero(&r_twice, sizeof(r_twice)); + memzero(&s_twice, sizeof(s_twice)); + memzero(&r_plus_s, sizeof(r_plus_s)); +} +#endif + +// Normalizes x +// Assumes x < 2**261 == 2**(LIMBS * BITS_PER_LIMB) +// Guarantees x is normalized +void bn_normalize(bignum256 *x) { + uint32_t acc = 0; + + for (int i = 0; i < BN_LIMBS; i++) { + acc += x->val[i]; + // acc doesn't overflow 32 bits + // Proof: + // acc + x[i] + // <= (2**(32 - BITS_PER_LIMB) - 1) + (2**BITS_PER_LIMB - 1) + // == 7 + 2**29 - 1 < 2**32 + + x->val[i] = acc & BN_LIMB_MASK; + acc >>= (BN_BITS_PER_LIMB); + // acc <= 7 == 2**(32 - BITS_PER_LIMB) - 1 + } +} + +// x = x + y +// Assumes x, y are normalized, x + y < 2**(LIMBS*BITS_PER_LIMB) == 2**261 +// Guarantees x is normalized +// Works properly even if &x == &y +void bn_add(bignum256 *x, const bignum256 *y) { + uint32_t acc = 0; + for (int i = 0; i < BN_LIMBS; i++) { + acc += x->val[i] + y->val[i]; + // acc doesn't overflow 32 bits + // Proof: + // acc + x[i] + y[i] + // <= (2**(32 - BITS_PER_LIMB) - 1) + 2 * (2**BITS_PER_LIMB - 1) + // == (2**(32 - BITS_PER_LIMB) - 1) + 2**(BITS_PER_LIMB + 1) - 2 + // == 7 + 2**30 - 2 < 2**32 + + x->val[i] = acc & BN_LIMB_MASK; + acc >>= BN_BITS_PER_LIMB; + // acc <= 7 == 2**(32 - BITS_PER_LIMB) - 1 + + // acc == x[:i + 1] + y[:i + 1] >> BITS_PER_LIMB * (i + 1) + } + + // assert(acc == 0); // assert x + y < 2**261 + // acc == 0 + // Proof: + // acc == x[:LIMBS] + y[:LIMBS] >> LIMBS * BITS_PER_LIMB + // == x + y >> LIMBS * BITS_PER_LIMB + // <= 2**(LIMBS * BITS_PER_LIMB) - 1 >> LIMBS * BITS_PER_LIMB == 0 +} + +// x = x + y % prime +// Assumes x, y are normalized +// Guarantees x is normalized and partly reduced modulo prime +// Assumes prime is normalized and 2^256 - 2^224 <= prime <= 2^256 +void bn_addmod(bignum256 *x, const bignum256 *y, const bignum256 *prime) { + for (int i = 0; i < BN_LIMBS; i++) { + x->val[i] += y->val[i]; + // x[i] doesn't overflow 32 bits + // Proof: + // x[i] + y[i] + // <= 2 * (2**BITS_PER_LIMB - 1) + // == 2**30 - 2 < 2**32 + } + + bn_fast_mod(x, prime); +} + +// x = x + y +// Assumes x is normalized +// Assumes y <= 2**32 - 2**29 == 2**32 - 2**BITS_PER_LIMB and +// x + y < 2**261 == 2**(LIMBS * BITS_PER_LIMB) +// Guarantees x is normalized +void bn_addi(bignum256 *x, uint32_t y) { + // assert(y <= 3758096384); // assert y <= 2**32 - 2**29 + uint32_t acc = y; + + for (int i = 0; i < BN_LIMBS; i++) { + acc += x->val[i]; + // acc doesn't overflow 32 bits + // Proof: + // if i == 0: + // acc + x[i] == y + x[0] + // <= (2**32 - 2**BITS_PER_LIMB) + (2**BITS_PER_LIMB - 1) + // == 2**32 - 1 < 2**32 + // else: + // acc + x[i] + // <= (2**(32 - BITS_PER_LIMB) - 1) + (2**BITS_PER_LIMB - 1) + // == 7 + 2**29 - 1 < 2**32 + + x->val[i] = acc & BN_LIMB_MASK; + acc >>= (BN_BITS_PER_LIMB); + // acc <= 7 == 2**(32 - BITS_PER_LIMB) - 1 + + // acc == x[:i + 1] + y >> BITS_PER_LIMB * (i + 1) + } + + // assert(acc == 0); // assert x + y < 2**261 + // acc == 0 + // Proof: + // acc == x[:LIMBS] + y << LIMBS * BITS_PER_LIMB + // == x + y << LIMBS * BITS_PER_LIMB + // <= 2**(LIMBS + BITS_PER_LIMB) - 1 << LIMBS * BITS_PER_LIMB + // == 0 +} + +// x = x - y % prime +// Explicitly x = x + prime - y +// Assumes x, y are normalized +// Assumes y < prime[0], x + prime - y < 2**261 == 2**(LIMBS * BITS_PER_LIMB) +// Guarantees x is normalized +// If x is fully reduced modulo prime, +// guarantess x will be partly reduced modulo prime +// Assumes prime is nonzero and normalized +void bn_subi(bignum256 *x, uint32_t y, const bignum256 *prime) { + assert(y < prime->val[0]); + + // x = x + prime - y + + uint32_t acc = -y; + for (int i = 0; i < BN_LIMBS; i++) { + acc += x->val[i] + prime->val[i]; + // acc neither overflows 32 bits nor underflows 0 + // Proof: + // acc + x[i] + prime[i] + // <= (2**(32 - BITS_PER_LIMB) - 1) + 2 * (2**BITS_PER_LIMB - 1) + // <= 7 + 2**30 - 2 < 2**32 + // acc + x[i] + prime[i] + // >= -y + prime[0] >= 0 + + x->val[i] = acc & BN_LIMB_MASK; + acc >>= BN_BITS_PER_LIMB; + // acc <= 7 == 2**(32 - BITS_PER_LIMB) - 1 + + // acc == x[:i + 1] + prime[:i + 1] - y >> BITS_PER_LIMB * (i + 1) + } + + // assert(acc == 0); // assert x + prime - y < 2**261 + // acc == 0 + // Proof: + // acc == x[:LIMBS] + prime[:LIMBS] - y >> BITS_PER_LIMB * LIMBS + // == x + prime - y >> BITS_PER_LIMB * LIMBS + // <= 2**(LIMBS * BITS_PER_LIMB) - 1 >> BITS_PER_LIMB * LIMBS == 0 +} + +// res = x - y % prime +// Explicitly res = x + (2 * prime - y) +// Assumes x, y are normalized, y is partly reduced +// Assumes x + 2 * prime - y < 2**261 == 2**(BITS_PER_LIMB * LIMBS) +// Guarantees res is normalized +// Assumes prime is nonzero and normalized +void bn_subtractmod(const bignum256 *x, const bignum256 *y, bignum256 *res, + const bignum256 *prime) { + // res = x + (2 * prime - y) + + uint32_t acc = 1; + + for (int i = 0; i < BN_LIMBS; i++) { + acc += (BN_BASE - 1) + x->val[i] + 2 * prime->val[i] - y->val[i]; + // acc neither overflows 32 bits nor underflows 0 + // Proof: + // acc + (BASE - 1) + x[i] + 2 * prime[i] - y[i] + // >= (BASE - 1) - y[i] + // == (2**BITS_PER_LIMB - 1) - (2**BITS_PER_LIMB - 1) == 0 + // acc + (BASE - 1) + x[i] + 2 * prime[i] - y[i] + // <= acc + (BASE - 1) + x[i] + 2 * prime[i] + // <= (2**(32 - BITS_PER_LIMB) - 1) + (2**BITS_PER_LIMB - 1) + + // (2**BITS_PER_LIMB - 1) + 2 * (2**BITS_PER_LIMB - 1) + // <= (2**(32 - BITS_PER_LIMB) - 1) + 4 * (2**BITS_PER_LIMB - 1) + // == 7 + 4 * 2**29 - 4 == 2**31 + 3 < 2**32 + + res->val[i] = acc & (BN_BASE - 1); + acc >>= BN_BITS_PER_LIMB; + // acc <= 7 == 2**(32 - BITS_PER_LIMB) - 1 + + // acc == 2**(BITS_PER_LIMB * (i + 1)) + x[:i+1] - y[:i+1] + 2*prime[:i+1] + // >> BITS_PER_LIMB * (i+1) + } + + // assert(acc == 1); // assert x + 2 * prime - y < 2**261 + + // clang-format off + // acc == 1 + // Proof: + // acc == 2**(BITS_PER_LIMB * LIMBS) + x[:LIMBS] - y[:LIMBS] + 2 * prime[:LIMBS] >> BITS_PER_LIMB * LIMBS + // == 2**(BITS_PER_LIMB * LIMBS) + x - y + 2 * prime >> BITS_PER_LIMB * LIMBS + // == 2**(BITS_PER_LIMB * LIMBS) + x + (2 * prime - y) >> BITS_PER_LIMB * LIMBS + // <= 2**(BITS_PER_LIMB * LIMBS) + 2**(BITS_PER_LIMB * LIMBS) - 1 >> BITS_PER_LIMB * LIMBS + // <= 2 * 2**(BITS_PER_LIMB * LIMBS) - 1 >> BITS_PER_LIMB * LIMBS + // == 1 + + // acc == 2**(BITS_PER_LIMB * LIMBS) + x[:LIMBS] - y[:LIMBS] + 2 * prime[:LIMBS] >> BITS_PER_LIMB * LIMBS + // == 2**(BITS_PER_LIMB * LIMBS) + x - y + 2 * prime >> BITS_PER_LIMB * LIMBS + // == 2**(BITS_PER_LIMB * LIMBS) + x + (2 * prime - y) >> BITS_PER_LIMB * LIMBS + // >= 2**(BITS_PER_LIMB * LIMBS) + 0 + 1 >> BITS_PER_LIMB * LIMBS + // == 1 + // clang-format on +} + +// res = x - y +// Assumes x, y are normalized and x >= y +// Guarantees res is normalized +// Works properly even if &x == &y or &x == &res or &y == &res or +// &x == &y == &res +void bn_subtract(const bignum256 *x, const bignum256 *y, bignum256 *res) { + uint32_t acc = 1; + for (int i = 0; i < BN_LIMBS; i++) { + acc += (BN_BASE - 1) + x->val[i] - y->val[i]; + // acc neither overflows 32 bits nor underflows 0 + // Proof: + // acc + (BASE - 1) + x[i] - y[i] + // >= (BASE - 1) - y == (2**BITS_PER_LIMB - 1) - (2**BITS_PER_LIMB - 1) + // == 0 + // acc + (BASE - 1) + x[i] - y[i] + // <= acc + (BASE - 1) + x[i] + // <= (2**(32 - BITS_PER_LIMB) - 1) + (2**BITS_PER_LIMB - 1) + + // (2**BITS_PER_LIMB - 1) + // == 7 + 2 * 2**29 < 2 **32 + + res->val[i] = acc & BN_LIMB_MASK; + acc >>= BN_BITS_PER_LIMB; + // acc <= 7 == 2**(32 - BITS_PER_LIMB) - 1 + + // acc == 2**(BITS_PER_LIMB * (i + 1)) + x[:i + 1] - y[:i + 1] + // >> BITS_PER_LIMB * (i + 1) + } + + // assert(acc == 1); // assert x >= y + + // clang-format off + // acc == 1 + // Proof: + // acc == 2**(BITS_PER_LIMB * LIMBS) + x[:LIMBS] - y[:LIMBS] >> BITS_PER_LIMB * LIMBS + // == 2**(BITS_PER_LIMB * LIMBS) + x - y >> BITS_PER_LIMB * LIMBS + // == 2**(BITS_PER_LIMB * LIMBS) + x >> BITS_PER_LIMB * LIMBS + // <= 2**(BITS_PER_LIMB * LIMBS) + 2**(BITS_PER_LIMB * LIMBS) - 1 >> BITS_PER_LIMB * LIMBS + // <= 2 * 2**(BITS_PER_LIMB * LIMBS) - 1 >> BITS_PER_LIMB * LIMBS + // == 1 + + // acc == 2**(BITS_PER_LIMB * LIMBS) + x[:LIMBS] - y[:LIMBS] >> BITS_PER_LIMB * LIMBS + // == 2**(BITS_PER_LIMB * LIMBS) + x - y >> BITS_PER_LIMB * LIMBS + // >= 2**(BITS_PER_LIMB * LIMBS) >> BITS_PER_LIMB * LIMBS + // == 1 +} + +// q = x // d, r = x % d +// Assumes x is normalized, 1 <= d <= 61304 +// Guarantees q is normalized +void bn_long_division(bignum256 *x, uint32_t d, bignum256 *q, uint32_t *r) { + assert(1 <= d && d < 61304); + + uint32_t acc = 0; + + *r = x->val[BN_LIMBS - 1] % d; + q->val[BN_LIMBS - 1] = x->val[BN_LIMBS - 1] / d; + + for (int i = BN_LIMBS - 2; i >= 0; i--) { + acc = *r * (BN_BASE % d) + x->val[i]; + // acc doesn't overflow 32 bits + // Proof: + // r * (BASE % d) + x[i] + // <= (d - 1) * (d - 1) + (2**BITS_PER_LIMB - 1) + // == d**2 - 2*d + 2**BITS_PER_LIMB + // == 61304**2 - 2 * 61304 + 2**29 + // == 3758057808 + 2**29 < 2**32 + + q->val[i] = *r * (BN_BASE / d) + (acc / d); + // q[i] doesn't overflow 32 bits + // Proof: + // r * (BASE // d) + (acc // d) + // <= (d - 1) * (2**BITS_PER_LIMB / d) + + // ((d**2 - 2*d + 2**BITS_PER_LIMB) / d) + // <= (d - 1) * (2**BITS_PER_LIMB / d) + (d - 2 + 2**BITS_PER_LIMB / d) + // == (d - 1 + 1) * (2**BITS_PER_LIMB / d) + d - 2 + // == 2**BITS_PER_LIMB + d - 2 <= 2**29 + 61304 < 2**32 + + // q[i] == (r * BASE + x[i]) // d + // Proof: + // q[i] == r * (BASE // d) + (acc // d) + // == r * (BASE // d) + (r * (BASE % d) + x[i]) // d + // == (r * d * (BASE // d) + r * (BASE % d) + x[i]) // d + // == (r * (d * (BASE // d) + (BASE % d)) + x[i]) // d + // == (r * BASE + x[i]) // d + + // q[i] < 2**BITS_PER_LIMB + // Proof: + // q[i] == (r * BASE + x[i]) // d + // <= ((d - 1) * 2**BITS_PER_LIMB + (2**BITS_PER_LIMB - 1)) / d + // == (d * 2**BITS_PER_LIMB - 1) / d == 2**BITS_PER_LIMB - 1 / d + // < 2**BITS_PER_LIMB + + *r = acc % d; + // r == (r * BASE + x[i]) % d + // Proof: + // r == acc % d == (r * (BASE % d) + x[i]) % d + // == (r * BASE + x[i]) % d + + // x[:i] == q[:i] * d + r + } +} + +// x = x // 58, r = x % 58 +// Assumes x is normalized +// Guarantees x is normalized +void bn_divmod58(bignum256 *x, uint32_t *r) { bn_long_division(x, 58, x, r); } + +// x = x // 1000, r = x % 1000 +// Assumes x is normalized +// Guarantees x is normalized +void bn_divmod1000(bignum256 *x, uint32_t *r) { + bn_long_division(x, 1000, x, r); +} + +// x = x // 10, r = x % 10 +// Assumes x is normalized +// Guarantees x is normalized +void bn_divmod10(bignum256 *x, uint32_t *r) { bn_long_division(x, 10, x, r); } + +// Formats amount +// Assumes amount is normalized +// Assumes prefix and suffix are null-terminated strings +// Assumes output is an array of length output_length +// The function doesn't have neither constant control flow nor constant memory +// access flow with regard to any its argument +size_t bn_format(const bignum256 *amount, const char *prefix, const char *suffix, unsigned int decimals, int exponent, bool trailing, char *output, size_t output_length) { + +/* + Python prototype of the function: + + def format(amount, prefix, suffix, decimals, exponent, trailing): + if exponent >= 0: + amount *= 10 ** exponent + else: + amount //= 10 ** (-exponent) + + d = pow(10, decimals) + + if decimals: + output = "%d.%0*d" % (amount // d, decimals, amount % d) + if not trailing: + output = output.rstrip("0").rstrip(".") + else: + output = "%d" % (amount // d) + + return prefix + output + suffix +*/ + +// Auxiliary macro for bn_format +// If enough space adds one character to output starting from the end +#define BN_FORMAT_ADD_OUTPUT_CHAR(c) \ + { \ + --position; \ + if (output <= position && position < output + output_length) { \ + *position = (c); \ + } else { \ + memset(output, '\0', output_length); \ + return 0; \ + } \ + } + + bignum256 temp = {0}; + bn_copy(amount, &temp); + uint32_t digit = 0; + + char *position = output + output_length; + + // Add string ending character + BN_FORMAT_ADD_OUTPUT_CHAR('\0'); + + // Add suffix + size_t suffix_length = suffix ? strlen(suffix) : 0; + for (int i = suffix_length - 1; i >= 0; --i) + BN_FORMAT_ADD_OUTPUT_CHAR(suffix[i]) + + // amount //= 10**exponent + for (; exponent < 0; ++exponent) { + // if temp == 0, there is no need to divide it by 10 anymore + if (bn_is_zero(&temp)) { + exponent = 0; + break; + } + bn_divmod10(&temp, &digit); + } + + // exponent >= 0 && decimals >= 0 + + bool fractional_part = false; // is fractional-part of amount present + + { // Add fractional-part digits of amount + // Add trailing zeroes + unsigned int trailing_zeros = decimals < (unsigned int) exponent ? decimals : (unsigned int) exponent; + // When casting a negative int to unsigned int, UINT_MAX is added to the int before + // Since exponent >= 0, the value remains unchanged + decimals -= trailing_zeros; + exponent -= trailing_zeros; + + if (trailing && trailing_zeros) { + fractional_part = true; + for (; trailing_zeros > 0; --trailing_zeros) + BN_FORMAT_ADD_OUTPUT_CHAR('0') + } + + // exponent == 0 || decimals == 0 + + // Add significant digits and leading zeroes + for (; decimals > 0; --decimals) { + bn_divmod10(&temp, &digit); + + if (fractional_part || digit || trailing) { + fractional_part = true; + BN_FORMAT_ADD_OUTPUT_CHAR('0' + digit) + } + else if (bn_is_zero(&temp)) { + // We break since the remaining digits are zeroes and fractional_part == trailing == false + decimals = 0; + break; + } + } + // decimals == 0 + } + + if (fractional_part) { + BN_FORMAT_ADD_OUTPUT_CHAR('.') + } + + { // Add integer-part digits of amount + // Add trailing zeroes + if (!bn_is_zero(&temp)) { + for (; exponent > 0; --exponent) { + BN_FORMAT_ADD_OUTPUT_CHAR('0') + } + } + // decimals == 0 && exponent == 0 + + // Add significant digits + do { + bn_divmod10(&temp, &digit); + BN_FORMAT_ADD_OUTPUT_CHAR('0' + digit) + } while (!bn_is_zero(&temp)); + } + + // Add prefix + size_t prefix_length = prefix ? strlen(prefix) : 0; + for (int i = prefix_length - 1; i >= 0; --i) + BN_FORMAT_ADD_OUTPUT_CHAR(prefix[i]) + + // Move formatted amount to the start of output + int length = output - position + output_length; + memmove(output, position, length); + return length - 1; +} + +#if USE_BN_PRINT +// Prints x in hexadecimal +// Assumes x is normalized and x < 2**256 +void bn_print(const bignum256 *x) { + printf("%06x", x->val[8]); + printf("%08x", ((x->val[7] << 3) | (x->val[6] >> 26))); + printf("%07x", ((x->val[6] << 2) | (x->val[5] >> 27)) & 0x0FFFFFFF); + printf("%07x", ((x->val[5] << 1) | (x->val[4] >> 28)) & 0x0FFFFFFF); + printf("%07x", x->val[4] & 0x0FFFFFFF); + printf("%08x", ((x->val[3] << 3) | (x->val[2] >> 26))); + printf("%07x", ((x->val[2] << 2) | (x->val[1] >> 27)) & 0x0FFFFFFF); + printf("%07x", ((x->val[1] << 1) | (x->val[0] >> 28)) & 0x0FFFFFFF); + printf("%07x", x->val[0] & 0x0FFFFFFF); +} + +// Prints comma separated list of limbs of x +void bn_print_raw(const bignum256 *x) { + for (int i = 0; i < BN_LIMBS - 1; i++) { + printf("0x%08x, ", x->val[i]); + } + printf("0x%08x", x->val[BN_LIMBS - 1]); +} +#endif + +#if USE_INVERSE_FAST +void bn_inverse(bignum256 *x, const bignum256 *prime) { + bn_inverse_fast(x, prime); +} +#else +void bn_inverse(bignum256 *x, const bignum256 *prime) { + bn_inverse_slow(x, prime); +} +#endif diff --git a/deps/crypto/trezor-crypto/bignum.h b/deps/crypto/trezor-crypto/bignum.h new file mode 100644 index 000000000..fcae2f773 --- /dev/null +++ b/deps/crypto/trezor-crypto/bignum.h @@ -0,0 +1,166 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * Copyright (c) 2016 Alex Beregszaszi + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BIGNUM_H__ +#define __BIGNUM_H__ + +#include +#include +#include + +#include "options.h" + +#define BN_LIMBS 9 +#define BN_BITS_PER_LIMB 29 +#define BN_BASE (1u << BN_BITS_PER_LIMB) +#define BN_LIMB_MASK ((1u << BN_BITS_PER_LIMB) - 1) +#define BN_EXTRA_BITS (32 - BN_BITS_PER_LIMB) +#define BN_BITS_LAST_LIMB (256 - (BN_LIMBS - 1) * BN_BITS_PER_LIMB) + +// Represents the number sum([val[i] * 2**(29*i) for i in range(9)) +typedef struct { + uint32_t val[BN_LIMBS]; +} bignum256; + +static inline uint32_t read_be(const uint8_t *data) { + return (((uint32_t)data[0]) << 24) | (((uint32_t)data[1]) << 16) | + (((uint32_t)data[2]) << 8) | (((uint32_t)data[3])); +} + +static inline void write_be(uint8_t *data, uint32_t x) { + data[0] = x >> 24; + data[1] = x >> 16; + data[2] = x >> 8; + data[3] = x; +} + +static inline uint32_t read_le(const uint8_t *data) { + return (((uint32_t)data[3]) << 24) | (((uint32_t)data[2]) << 16) | + (((uint32_t)data[1]) << 8) | (((uint32_t)data[0])); +} + +static inline void write_le(uint8_t *data, uint32_t x) { + data[3] = x >> 24; + data[2] = x >> 16; + data[1] = x >> 8; + data[0] = x; +} + +void bn_read_be(const uint8_t *in_number, bignum256 *out_number); +void bn_write_be(const bignum256 *in_number, uint8_t *out_number); +void bn_read_le(const uint8_t *in_number, bignum256 *out_number); +void bn_write_le(const bignum256 *in_number, uint8_t *out_number); +void bn_read_uint32(uint32_t in_number, bignum256 *out_number); +void bn_read_uint64(uint64_t in_number, bignum256 *out_number); +int bn_bitcount(const bignum256 *x); +unsigned int bn_digitcount(const bignum256 *x); +void bn_zero(bignum256 *x); +void bn_one(bignum256 *x); +int bn_is_zero(const bignum256 *x); +int bn_is_one(const bignum256 *x); +int bn_is_less(const bignum256 *x, const bignum256 *y); +int bn_is_equal(const bignum256 *x, const bignum256 *y); +void bn_cmov(bignum256 *res, volatile uint32_t cond, const bignum256 *truecase, + const bignum256 *falsecase); +void bn_cnegate(volatile uint32_t cond, bignum256 *x, const bignum256 *prime); +void bn_lshift(bignum256 *x); +void bn_rshift(bignum256 *x); +void bn_setbit(bignum256 *x, uint16_t i); +void bn_clearbit(bignum256 *x, uint16_t i); +uint32_t bn_testbit(const bignum256 *x, uint16_t i); +void bn_xor(bignum256 *res, const bignum256 *x, const bignum256 *y); +void bn_mult_half(bignum256 *x, const bignum256 *prime); +void bn_mult_k(bignum256 *x, uint8_t k, const bignum256 *prime); +void bn_mod(bignum256 *x, const bignum256 *prime); +void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime); +void bn_fast_mod(bignum256 *x, const bignum256 *prime); +void bn_power_mod(const bignum256 *x, const bignum256 *e, + const bignum256 *prime, bignum256 *res); +void bn_sqrt(bignum256 *x, const bignum256 *prime); +uint32_t inverse_mod_power_two(uint32_t a, uint32_t n); +void bn_divide_base(bignum256 *x, const bignum256 *prime); +void bn_normalize(bignum256 *x); +void bn_add(bignum256 *x, const bignum256 *y); +void bn_addmod(bignum256 *x, const bignum256 *y, const bignum256 *prime); +void bn_addi(bignum256 *x, uint32_t y); +void bn_subi(bignum256 *x, uint32_t y, const bignum256 *prime); +void bn_subtractmod(const bignum256 *x, const bignum256 *y, bignum256 *res, + const bignum256 *prime); +void bn_subtract(const bignum256 *x, const bignum256 *y, bignum256 *res); +void bn_long_division(bignum256 *x, uint32_t d, bignum256 *q, uint32_t *r); +void bn_divmod58(bignum256 *x, uint32_t *r); +void bn_divmod1000(bignum256 *x, uint32_t *r); +void bn_inverse(bignum256 *x, const bignum256 *prime); +size_t bn_format(const bignum256 *amount, const char *prefix, + const char *suffix, unsigned int decimals, int exponent, + bool trailing, char *output, size_t output_length); + +// Returns (uint32_t) in_number +// Assumes in_number < 2**32 +// Assumes in_number is normalized +static inline uint32_t bn_write_uint32(const bignum256 *in_number) { + return in_number->val[0] | (in_number->val[1] << BN_BITS_PER_LIMB); +} + +// Returns (uint64_t) in_number +// Assumes in_number < 2**64 +// Assumes in_number is normalized +static inline uint64_t bn_write_uint64(const bignum256 *in_number) { + uint64_t acc; + acc = in_number->val[2]; + acc <<= BN_BITS_PER_LIMB; + acc |= in_number->val[1]; + acc <<= BN_BITS_PER_LIMB; + acc |= in_number->val[0]; + return acc; +} + +// y = x +static inline void bn_copy(const bignum256 *x, bignum256 *y) { *y = *x; } + +// Returns x % 2 == 0 +static inline int bn_is_even(const bignum256 *x) { + return (x->val[0] & 1) == 0; +} + +// Returns x % 2 == 0 +static inline int bn_is_odd(const bignum256 *x) { return (x->val[0] & 1) == 1; } + +static inline size_t bn_format_uint64(uint64_t amount, const char *prefix, + const char *suffix, unsigned int decimals, + int exponent, bool trailing, char *output, + size_t output_length) { + bignum256 bn_amount; + bn_read_uint64(amount, &bn_amount); + + return bn_format(&bn_amount, prefix, suffix, decimals, exponent, trailing, + output, output_length); +} + +#if USE_BN_PRINT +void bn_print(const bignum256 *x); +void bn_print_raw(const bignum256 *x); +#endif + +#endif diff --git a/deps/crypto/trezor-crypto/bip32.c b/deps/crypto/trezor-crypto/bip32.c new file mode 100644 index 000000000..66f8fd9e6 --- /dev/null +++ b/deps/crypto/trezor-crypto/bip32.c @@ -0,0 +1,1045 @@ +/** + * Copyright (c) 2013-2016 Tomas Dzetkulic + * Copyright (c) 2013-2016 Pavol Rusnak + * Copyright (c) 2015-2016 Jochen Hoenicke + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +#include "aes/aes.h" +#include "address.h" +#include "bignum.h" +#include "hmac.h" +#include "ecdsa.h" +#include "bip32.h" +#include "sha2.h" +#include "sha3.h" +#include "base58.h" +#include "curves.h" +#include "secp256k1.h" +#include "nist256p1.h" +#include "ed25519-donna/ed25519.h" +#if USE_NANO +#include "ed25519-donna/ed25519-blake2b.h" +#endif +#include "ed25519-donna/ed25519-sha3.h" +#if USE_KECCAK +#include "ed25519-donna/ed25519-keccak.h" +#endif +#if USE_NEM +#include "nem.h" +#endif +#if USE_CARDANO +#include "pbkdf2.h" +#endif +#include "memzero.h" + +#define CARDANO_MAX_NODE_DEPTH 1048576 + +const curve_info ed25519_info = { + .bip32_name = "ed25519 seed", + .params = NULL, + .hasher_base58 = HASHER_SHA2D, + .hasher_sign = HASHER_SHA2D, + .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_script = HASHER_SHA2, +}; + +const curve_info ed25519_cardano_info = { + .bip32_name = "ed25519 cardano seed", + .params = NULL, + .hasher_base58 = HASHER_SHA2D, + .hasher_sign = HASHER_SHA2D, + .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_script = HASHER_SHA2, +}; + +#if USE_NANO +const curve_info ed25519_blake2b_nano_info = { + .bip32_name = "ed25519 seed", + .params = NULL, + .hasher_base58 = HASHER_SHA2D, + .hasher_sign = HASHER_SHA2D, + .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_script = HASHER_SHA2, +}; +#endif + +const curve_info ed25519_sha3_info = { + .bip32_name = "ed25519-sha3 seed", + .params = NULL, + .hasher_base58 = HASHER_SHA2D, + .hasher_sign = HASHER_SHA2D, + .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_script = HASHER_SHA2, +}; + +#if USE_KECCAK +const curve_info ed25519_keccak_info = { + .bip32_name = "ed25519-keccak seed", + .params = NULL, + .hasher_base58 = HASHER_SHA2D, + .hasher_sign = HASHER_SHA2D, + .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_script = HASHER_SHA2, +}; +#endif + +const curve_info curve25519_info = { + .bip32_name = "curve25519 seed", + .params = NULL, + .hasher_base58 = HASHER_SHA2D, + .hasher_sign = HASHER_SHA2D, + .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_script = HASHER_SHA2, +}; + +bool hdnode_is_valid(const HDNode* node) { + return node && node->curve; +} + +int hdnode_from_xpub(uint32_t depth, uint32_t child_num, + const uint8_t *chain_code, const uint8_t *public_key, + const char *curve, HDNode *out) { + const curve_info *info = get_curve_by_name(curve); + if (info == 0) { + return 0; + } + if (public_key[0] != 0x02 && public_key[0] != 0x03) { // invalid pubkey + return 0; + } + out->curve = info; + out->depth = depth; + out->child_num = child_num; + memcpy(out->chain_code, chain_code, 32); + memzero(out->private_key, 32); + memzero(out->private_key_extension, 32); + memcpy(out->public_key, public_key, 33); + return 1; +} + +int hdnode_from_xprv(uint32_t depth, uint32_t child_num, + const uint8_t *chain_code, const uint8_t *private_key, + const char *curve, HDNode *out) { + bool failed = false; + const curve_info *info = get_curve_by_name(curve); + if (info == 0) { + failed = true; + } else if (info->params) { + bignum256 a = {0}; + bn_read_be(private_key, &a); + if (bn_is_zero(&a)) { // == 0 + failed = true; + } else { + if (!bn_is_less(&a, &info->params->order)) { // >= order + failed = true; + } + } + memzero(&a, sizeof(a)); + } + + if (failed) { + return 0; + } + + out->curve = info; + out->depth = depth; + out->child_num = child_num; + memcpy(out->chain_code, chain_code, 32); + memcpy(out->private_key, private_key, 32); + memzero(out->public_key, sizeof(out->public_key)); + memzero(out->private_key_extension, sizeof(out->private_key_extension)); + return 1; +} + +int hdnode_from_seed(const uint8_t *seed, int seed_len, const char *curve, + HDNode *out) { + static CONFIDENTIAL uint8_t I[32 + 32]; + memzero(out, sizeof(HDNode)); + out->depth = 0; + out->child_num = 0; + out->curve = get_curve_by_name(curve); + if (out->curve == 0) { + return 0; + } + static CONFIDENTIAL HMAC_SHA512_CTX ctx; + hmac_sha512_Init(&ctx, (const uint8_t *)out->curve->bip32_name, + strlen(out->curve->bip32_name)); + hmac_sha512_Update(&ctx, seed, seed_len); + hmac_sha512_Final(&ctx, I); + + if (out->curve->params) { + bignum256 a = {0}; + while (true) { + bn_read_be(I, &a); + if (!bn_is_zero(&a) // != 0 + && bn_is_less(&a, &out->curve->params->order)) { // < order + break; + } + hmac_sha512_Init(&ctx, (const uint8_t *)out->curve->bip32_name, + strlen(out->curve->bip32_name)); + hmac_sha512_Update(&ctx, I, sizeof(I)); + hmac_sha512_Final(&ctx, I); + } + memzero(&a, sizeof(a)); + } + memcpy(out->private_key, I, 32); + memcpy(out->chain_code, I + 32, 32); + memzero(out->public_key, sizeof(out->public_key)); + memzero(I, sizeof(I)); + return 1; +} + +uint32_t hdnode_fingerprint(HDNode *node) { + if (!hdnode_is_valid(node)) return 0; + + uint8_t digest[32] = {0}; + uint8_t public_key[33] = {0}; + uint32_t fingerprint = 0; + + hdnode_fill_public_key(node); + memcpy(public_key, node->public_key, sizeof(public_key)); + if (public_key[0] == 0x01) { + // SLIP-10 fingerprints Ed25519 and Curve25519 keys with a 0x00 prefix. + public_key[0] = 0x00; + } + hasher_Raw(node->curve->hasher_pubkey, public_key, sizeof(public_key), + digest); + fingerprint = ((uint32_t)digest[0] << 24) + (digest[1] << 16) + + (digest[2] << 8) + digest[3]; + memzero(public_key, sizeof(public_key)); + memzero(digest, sizeof(digest)); + return fingerprint; +} + +int hdnode_private_ckd(HDNode *inout, uint32_t i) { + if (!hdnode_is_valid(inout)) return 0; + if (inout->depth == UINT32_MAX) return 0; + + static CONFIDENTIAL uint8_t data[1 + 32 + 4]; + static CONFIDENTIAL uint8_t I[32 + 32]; + static CONFIDENTIAL bignum256 a, b; + + if (i & 0x80000000) { // private derivation + data[0] = 0; + memcpy(data + 1, inout->private_key, 32); + } else { // public derivation + if (!inout->curve->params) { + return 0; + } + hdnode_fill_public_key(inout); + memcpy(data, inout->public_key, 33); + } + write_be(data + 33, i); + + bn_read_be(inout->private_key, &a); + + static CONFIDENTIAL HMAC_SHA512_CTX ctx; + hmac_sha512_Init(&ctx, inout->chain_code, 32); + hmac_sha512_Update(&ctx, data, sizeof(data)); + hmac_sha512_Final(&ctx, I); + + if (inout->curve->params) { + while (true) { + bool failed = false; + bn_read_be(I, &b); + if (!bn_is_less(&b, &inout->curve->params->order)) { // >= order + failed = true; + } else { + bn_add(&b, &a); + bn_mod(&b, &inout->curve->params->order); + if (bn_is_zero(&b)) { + failed = true; + } + } + + if (!failed) { + bn_write_be(&b, inout->private_key); + break; + } + + data[0] = 1; + memcpy(data + 1, I + 32, 32); + hmac_sha512_Init(&ctx, inout->chain_code, 32); + hmac_sha512_Update(&ctx, data, sizeof(data)); + hmac_sha512_Final(&ctx, I); + } + } else { + memcpy(inout->private_key, I, 32); + } + + memcpy(inout->chain_code, I + 32, 32); + inout->depth++; + inout->child_num = i; + memzero(inout->public_key, sizeof(inout->public_key)); + + // making sure to wipe our memory + memzero(&a, sizeof(a)); + memzero(&b, sizeof(b)); + memzero(I, sizeof(I)); + memzero(data, sizeof(data)); + return 1; +} + +#if USE_CARDANO +static void scalar_multiply8(const uint8_t *src, int bytes, uint8_t *dst) { + uint8_t prev_acc = 0; + for (int i = 0; i < bytes; i++) { + dst[i] = (src[i] << 3) + (prev_acc & 0x7); + prev_acc = src[i] >> 5; + } + dst[bytes] = src[bytes - 1] >> 5; +} + +static void scalar_add_256bits(const uint8_t *src1, const uint8_t *src2, + uint8_t *dst) { + uint16_t r = 0; + for (int i = 0; i < 32; i++) { + r = r + (uint16_t)src1[i] + (uint16_t)src2[i]; + dst[i] = r & 0xff; + r >>= 8; + } +} + +int hdnode_private_ckd_cardano(HDNode *inout, uint32_t index) { + if (!hdnode_is_valid(inout)) return 0; + + if (inout->depth >= CARDANO_MAX_NODE_DEPTH) { + return 0; + } + + // checks for hardened/non-hardened derivation, keysize 32 means we are + // dealing with public key and thus non-h, keysize 64 is for private key + int keysize = 32; + if (index & 0x80000000) { + keysize = 64; + } + + static CONFIDENTIAL uint8_t data[1 + 64 + 4]; + static CONFIDENTIAL uint8_t z[32 + 32]; + static CONFIDENTIAL uint8_t priv_key[64]; + static CONFIDENTIAL uint8_t res_key[64]; + + write_le(data + keysize + 1, index); + + memcpy(priv_key, inout->private_key, 32); + memcpy(priv_key + 32, inout->private_key_extension, 32); + + if (keysize == 64) { // private derivation + data[0] = 0; + memcpy(data + 1, inout->private_key, 32); + memcpy(data + 1 + 32, inout->private_key_extension, 32); + } else { // public derivation + hdnode_fill_public_key(inout); + data[0] = 2; + memcpy(data + 1, inout->public_key + 1, 32); + } + + static CONFIDENTIAL HMAC_SHA512_CTX ctx; + hmac_sha512_Init(&ctx, inout->chain_code, 32); + hmac_sha512_Update(&ctx, data, 1 + keysize + 4); + hmac_sha512_Final(&ctx, z); + + static CONFIDENTIAL uint8_t zl8[32]; + memzero(zl8, 32); + + /* get 8 * Zl */ + scalar_multiply8(z, 28, zl8); + /* Kl = 8*Zl + parent(K)l */ + scalar_add_256bits(zl8, priv_key, res_key); + + /* Kr = Zr + parent(K)r */ + scalar_add_256bits(z + 32, priv_key + 32, res_key + 32); + + memcpy(inout->private_key, res_key, 32); + memcpy(inout->private_key_extension, res_key + 32, 32); + + if (keysize == 64) { + data[0] = 1; + } else { + data[0] = 3; + } + hmac_sha512_Init(&ctx, inout->chain_code, 32); + hmac_sha512_Update(&ctx, data, 1 + keysize + 4); + hmac_sha512_Final(&ctx, z); + + memcpy(inout->chain_code, z + 32, 32); + inout->depth++; + inout->child_num = index; + memzero(inout->public_key, sizeof(inout->public_key)); + + // making sure to wipe our memory + memzero(z, sizeof(z)); + memzero(data, sizeof(data)); + memzero(priv_key, sizeof(priv_key)); + memzero(res_key, sizeof(res_key)); + return 1; +} + +static int hdnode_from_secret_cardano(const uint8_t *k, + const uint8_t *chain_code, HDNode *out) { + memzero(out, sizeof(HDNode)); + out->depth = 0; + out->child_num = 0; + out->curve = &ed25519_cardano_info; + memcpy(out->private_key, k, 32); + memcpy(out->private_key_extension, k + 32, 32); + memcpy(out->chain_code, chain_code, 32); + + out->private_key[0] &= 0xf8; + out->private_key[31] &= 0x1f; + out->private_key[31] |= 0x40; + + out->public_key[0] = 0; + hdnode_fill_public_key(out); + + return 1; +} + +// Derives the root Cardano HDNode from a master secret, aka seed, as defined in +// SLIP-0023. +int hdnode_from_seed_cardano(const uint8_t *seed, int seed_len, HDNode *out) { + static CONFIDENTIAL uint8_t I[SHA512_DIGEST_LENGTH]; + static CONFIDENTIAL uint8_t k[SHA512_DIGEST_LENGTH]; + static CONFIDENTIAL HMAC_SHA512_CTX ctx; + + hmac_sha512_Init(&ctx, (const uint8_t *)ED25519_CARDANO_NAME, + strlen(ED25519_CARDANO_NAME)); + hmac_sha512_Update(&ctx, seed, seed_len); + hmac_sha512_Final(&ctx, I); + + sha512_Raw(I, 32, k); + + int ret = hdnode_from_secret_cardano(k, I + 32, out); + + memzero(I, sizeof(I)); + memzero(k, sizeof(k)); + memzero(&ctx, sizeof(ctx)); + return ret; +} + +// Derives the root Cardano HDNode from a passphrase and the entropy encoded in +// a BIP-0039 mnemonic using the Icarus derivation scheme, aka V2 derivation +// scheme. +int hdnode_from_entropy_cardano_icarus(const uint8_t *pass, int pass_len, + const uint8_t *entropy, int entropy_len, + HDNode *out) { + static CONFIDENTIAL uint8_t secret[96]; + pbkdf2_hmac_sha512(pass, pass_len, entropy, entropy_len, 4096, secret, 96); + + int ret = hdnode_from_secret_cardano(secret, secret + 64, out); + memzero(secret, sizeof(secret)); + return ret; +} +#endif + +int hdnode_public_ckd_cp(const ecdsa_curve *curve, const curve_point *parent, + const uint8_t *parent_chain_code, uint32_t i, + curve_point *child, uint8_t *child_chain_code) { + uint8_t data[(1 + 32) + 4] = {0}; + uint8_t I[32 + 32] = {0}; + bignum256 c = {0}; + + if (i & 0x80000000) { // private derivation + return 0; + } + + data[0] = 0x02 | (parent->y.val[0] & 0x01); + bn_write_be(&parent->x, data + 1); + write_be(data + 33, i); + + while (true) { + hmac_sha512(parent_chain_code, 32, data, sizeof(data), I); + bn_read_be(I, &c); + if (bn_is_less(&c, &curve->order)) { // < order + scalar_multiply(curve, &c, child); // b = c * G + point_add(curve, parent, child); // b = a + b + if (!point_is_infinity(child)) { + if (child_chain_code) { + memcpy(child_chain_code, I + 32, 32); + } + + // Wipe all stack data. + memzero(data, sizeof(data)); + memzero(I, sizeof(I)); + memzero(&c, sizeof(c)); + return 1; + } + } + + data[0] = 1; + memcpy(data + 1, I + 32, 32); + } +} + +int hdnode_public_ckd(HDNode *inout, uint32_t i) { + if (!hdnode_is_valid(inout)) return 0; + if (inout->depth == UINT32_MAX) return 0; + if (!inout->curve->params) { + // SLIP-10 does not define public child derivation for 25519 curves. + return 0; + } + + curve_point parent = {0}, child = {0}; + + if (!ecdsa_read_pubkey(inout->curve->params, inout->public_key, &parent)) { + return 0; + } + if (!hdnode_public_ckd_cp(inout->curve->params, &parent, inout->chain_code, i, + &child, inout->chain_code)) { + return 0; + } + memzero(inout->private_key, 32); + inout->depth++; + inout->child_num = i; + inout->public_key[0] = 0x02 | (child.y.val[0] & 0x01); + bn_write_be(&child.x, inout->public_key + 1); + + // Wipe all stack data. + memzero(&parent, sizeof(parent)); + memzero(&child, sizeof(child)); + + return 1; +} + +void hdnode_public_ckd_address_optimized(const curve_point *pub, + const uint8_t *chain_code, uint32_t i, + uint32_t version, + HasherType hasher_pubkey, + HasherType hasher_base58, char *addr, + int addrsize, int addrformat) { + uint8_t child_pubkey[33] = {0}; + curve_point b = {0}; + + hdnode_public_ckd_cp(&secp256k1, pub, chain_code, i, &b, NULL); + child_pubkey[0] = 0x02 | (b.y.val[0] & 0x01); + bn_write_be(&b.x, child_pubkey + 1); + + switch (addrformat) { + case 1: // Segwit-in-P2SH + ecdsa_get_address_segwit_p2sh(child_pubkey, version, hasher_pubkey, + hasher_base58, addr, addrsize); + break; + default: // normal address + ecdsa_get_address(child_pubkey, version, hasher_pubkey, hasher_base58, + addr, addrsize); + break; + } +} + +#if USE_BIP32_CACHE +static bool private_ckd_cache_root_set = false; +static CONFIDENTIAL HDNode private_ckd_cache_root; +static int private_ckd_cache_index = 0; + +static CONFIDENTIAL struct { + bool set; + size_t depth; + uint32_t i[BIP32_CACHE_MAXDEPTH]; + HDNode node; +} private_ckd_cache[BIP32_CACHE_SIZE]; + +void bip32_cache_clear(void) { + private_ckd_cache_root_set = false; + private_ckd_cache_index = 0; + memzero(&private_ckd_cache_root, sizeof(private_ckd_cache_root)); + memzero(private_ckd_cache, sizeof(private_ckd_cache)); +} + +int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count, + uint32_t *fingerprint) { + if (!hdnode_is_valid(inout)) return 0; + + if (i_count == 0) { + // no way how to compute parent fingerprint + return 1; + } + if (i_count == 1 || i_count - 1 > BIP32_CACHE_MAXDEPTH) { + // when parent is uncacheable just derive the node and return + for (size_t k = 0; k < i_count - 1; k++) { + if (hdnode_private_ckd(inout, i[k]) == 0) return 0; + } + if (fingerprint) { + *fingerprint = hdnode_fingerprint(inout); + } + if (hdnode_private_ckd(inout, i[i_count - 1]) == 0) return 0; + return 1; + } + + bool found = false; + // if root is not set or not the same + if (!private_ckd_cache_root_set || + memcmp(&private_ckd_cache_root, inout, sizeof(HDNode)) != 0) { + // clear the cache + private_ckd_cache_index = 0; + memzero(private_ckd_cache, sizeof(private_ckd_cache)); + // setup new root + memcpy(&private_ckd_cache_root, inout, sizeof(HDNode)); + private_ckd_cache_root_set = true; + } else { + // try to find parent + int j = 0; + for (j = 0; j < BIP32_CACHE_SIZE; j++) { + if (private_ckd_cache[j].set && + private_ckd_cache[j].depth == i_count - 1 && + memcmp(private_ckd_cache[j].i, i, (i_count - 1) * sizeof(uint32_t)) == + 0 && + private_ckd_cache[j].node.curve == inout->curve) { + memcpy(inout, &(private_ckd_cache[j].node), sizeof(HDNode)); + found = true; + break; + } + } + } + + // else derive parent + if (!found) { + size_t k = 0; + for (k = 0; k < i_count - 1; k++) { + if (hdnode_private_ckd(inout, i[k]) == 0) return 0; + } + // and save it + memzero(&(private_ckd_cache[private_ckd_cache_index]), + sizeof(private_ckd_cache[private_ckd_cache_index])); + private_ckd_cache[private_ckd_cache_index].set = true; + private_ckd_cache[private_ckd_cache_index].depth = i_count - 1; + memcpy(private_ckd_cache[private_ckd_cache_index].i, i, + (i_count - 1) * sizeof(uint32_t)); + memcpy(&(private_ckd_cache[private_ckd_cache_index].node), inout, + sizeof(HDNode)); + private_ckd_cache_index = (private_ckd_cache_index + 1) % BIP32_CACHE_SIZE; + } + + if (fingerprint) { + *fingerprint = hdnode_fingerprint(inout); + } + if (hdnode_private_ckd(inout, i[i_count - 1]) == 0) return 0; + + return 1; +} +#endif + +void hdnode_get_address_raw(HDNode *node, uint32_t version, uint8_t *addr_raw) { + if (!hdnode_is_valid(node)) return; + + hdnode_fill_public_key(node); + ecdsa_get_address_raw(node->public_key, version, node->curve->hasher_pubkey, + addr_raw); +} + +void hdnode_get_address(HDNode *node, uint32_t version, char *addr, + int addrsize) { + if (!hdnode_is_valid(node)) return; + + hdnode_fill_public_key(node); + ecdsa_get_address(node->public_key, version, node->curve->hasher_pubkey, + node->curve->hasher_base58, addr, addrsize); +} + +void hdnode_fill_public_key(HDNode *node) { + if (!hdnode_is_valid(node)) return; + + if (node->public_key[0] != 0) return; + +#if USE_BIP32_25519_CURVES + if (node->curve->params) { + ecdsa_get_public_key33(node->curve->params, node->private_key, + node->public_key); + } else { + node->public_key[0] = 1; + if (node->curve == &ed25519_info) { + ed25519_publickey(node->private_key, node->public_key + 1); +#if USE_NANO + } else if (node->curve == &ed25519_blake2b_nano_info) { + ed25519_publickey_blake2b(node->private_key, node->public_key + 1); +#endif + } else if (node->curve == &ed25519_sha3_info) { + ed25519_publickey_sha3(node->private_key, node->public_key + 1); +#if USE_KECCAK + } else if (node->curve == &ed25519_keccak_info) { + ed25519_publickey_keccak(node->private_key, node->public_key + 1); +#endif + } else if (node->curve == &curve25519_info) { + curve25519_scalarmult_basepoint(node->public_key + 1, node->private_key); +#if USE_CARDANO + } else if (node->curve == &ed25519_cardano_info) { + ed25519_publickey_ext(node->private_key, node->private_key_extension, + node->public_key + 1); +#endif + } + } +#else + + ecdsa_get_public_key33(node->curve->params, node->private_key, + node->public_key); +#endif +} + +#if USE_ETHEREUM +int hdnode_get_ethereum_pubkeyhash(const HDNode *node, uint8_t *pubkeyhash) { + if (!hdnode_is_valid(node)) return 0; + + uint8_t buf[65] = {0}; + SHA3_CTX ctx = {0}; + + /* get uncompressed public key */ + ecdsa_get_public_key65(node->curve->params, node->private_key, buf); + + /* compute sha3 of x and y coordinate without 04 prefix */ + sha3_256_Init(&ctx); + sha3_Update(&ctx, buf + 1, 64); + keccak_Final(&ctx, buf); + + /* result are the least significant 160 bits */ + memcpy(pubkeyhash, buf + 12, 20); + + return 1; +} +#endif + +#if USE_NEM +int hdnode_get_nem_address(HDNode *node, uint8_t version, char *address) { + if (!hdnode_is_valid(node)) return 0; + + if (node->curve != &ed25519_keccak_info) { + return 0; + } + + hdnode_fill_public_key(node); + return nem_get_address(&node->public_key[1], version, address); +} + +int hdnode_get_nem_shared_key(const HDNode *node, + const ed25519_public_key peer_public_key, + const uint8_t *salt, ed25519_public_key mul, + uint8_t *shared_key) { + if (!hdnode_is_valid(node)) return 0; + + if (node->curve != &ed25519_keccak_info) { + return 0; + } + + // sizeof(ed25519_public_key) == SHA3_256_DIGEST_LENGTH + if (mul == NULL) mul = shared_key; + + if (ed25519_scalarmult_keccak(mul, node->private_key, peer_public_key)) { + return 0; + } + + for (size_t i = 0; i < 32; i++) { + shared_key[i] = mul[i] ^ salt[i]; + } + + keccak_256(shared_key, 32, shared_key); + return 1; +} + +int hdnode_nem_encrypt(const HDNode *node, const ed25519_public_key public_key, + const uint8_t *iv_immut, const uint8_t *salt, + const uint8_t *payload, size_t size, uint8_t *buffer) { + if (!hdnode_is_valid(node)) return 0; + + uint8_t last_block[AES_BLOCK_SIZE] = {0}; + uint8_t remainder = size % AES_BLOCK_SIZE; + + // Round down to last whole block + size -= remainder; + // Copy old last block + memcpy(last_block, &payload[size], remainder); + // Pad new last block with number of missing bytes + memset(&last_block[remainder], AES_BLOCK_SIZE - remainder, + AES_BLOCK_SIZE - remainder); + + // the IV gets mutated, so we make a copy not to touch the original + uint8_t iv[AES_BLOCK_SIZE] = {0}; + memcpy(iv, iv_immut, AES_BLOCK_SIZE); + + uint8_t shared_key[SHA3_256_DIGEST_LENGTH] = {0}; + if (!hdnode_get_nem_shared_key(node, public_key, salt, NULL, shared_key)) { + return 0; + } + + aes_encrypt_ctx ctx = {0}; + + int succ = 0; + int ret = aes_encrypt_key256(shared_key, &ctx); + memzero(shared_key, sizeof(shared_key)); + + if (ret != EXIT_SUCCESS) { + goto cleanup; + } + + if (aes_cbc_encrypt(payload, buffer, size, iv, &ctx) != EXIT_SUCCESS) { + goto cleanup; + } + + if (aes_cbc_encrypt(last_block, &buffer[size], sizeof(last_block), iv, + &ctx) != EXIT_SUCCESS) { + goto cleanup; + } + + succ = 1; +cleanup: + memzero(&ctx, sizeof(ctx)); + return succ; +} + +int hdnode_nem_decrypt(const HDNode *node, const ed25519_public_key public_key, + uint8_t *iv, const uint8_t *salt, const uint8_t *payload, + size_t size, uint8_t *buffer) { + if (!hdnode_is_valid(node)) return 0; + + uint8_t shared_key[SHA3_256_DIGEST_LENGTH] = {0}; + + if (!hdnode_get_nem_shared_key(node, public_key, salt, NULL, shared_key)) { + return 0; + } + + aes_decrypt_ctx ctx = {0}; + + int succ = 0; + int ret = aes_decrypt_key256(shared_key, &ctx); + memzero(shared_key, sizeof(shared_key)); + + if (ret != EXIT_SUCCESS) { + goto cleanup; + } + + if (aes_cbc_decrypt(payload, buffer, size, iv, &ctx) != EXIT_SUCCESS) { + goto cleanup; + } + + succ = 1; +cleanup: + memzero(&ctx, sizeof(ctx)); + return succ; +} +#endif + +// msg is a data to be signed +// msg_len is the message length +int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, + HasherType hasher_sign, uint8_t *sig, uint8_t *pby, + int (*is_canonical)(uint8_t by, uint8_t sig[64])) { + if (!hdnode_is_valid(node)) return 1; + + if (node->curve->params) { + return ecdsa_sign(node->curve->params, hasher_sign, node->private_key, msg, + msg_len, sig, pby, is_canonical); + } else if (node->curve == &curve25519_info) { + return 1; // signatures are not supported + } else { + if (node->curve == &ed25519_info) { + ed25519_sign(msg, msg_len, node->private_key, sig); +#if USE_NANO + } else if (node->curve == &ed25519_blake2b_nano_info) { + ed25519_sign_blake2b(msg, msg_len, node->private_key, sig); +#endif + } else if (node->curve == &ed25519_sha3_info) { + ed25519_sign_sha3(msg, msg_len, node->private_key, sig); +#if USE_KECCAK + } else if (node->curve == &ed25519_keccak_info) { + ed25519_sign_keccak(msg, msg_len, node->private_key, sig); +#endif + } else { + return 1; // unknown or unsupported curve + } + return 0; + } +} + +int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, + uint8_t *pby, + int (*is_canonical)(uint8_t by, uint8_t sig[64])) { + if (!hdnode_is_valid(node)) return 1; + + if (node->curve->params) { + return ecdsa_sign_digest(node->curve->params, node->private_key, digest, + sig, pby, is_canonical); + } else if (node->curve == &curve25519_info) { + return 1; // signatures are not supported + } else { + return hdnode_sign(node, digest, 32, 0, sig, pby, is_canonical); + } +} + +int hdnode_get_shared_key(const HDNode *node, const uint8_t *peer_public_key, + uint8_t *session_key, int *result_size) { + if (!hdnode_is_valid(node)) return 1; + + // Use elliptic curve Diffie-Helman to compute shared session key + if (node->curve->params) { + if (ecdh_multiply(node->curve->params, node->private_key, peer_public_key, + session_key) != 0) { + return 1; + } + *result_size = 65; + return 0; + } else if (node->curve == &curve25519_info) { + session_key[0] = 0x04; + if (peer_public_key[0] != 0x40) { + return 1; // Curve25519 public key should start with 0x40 byte. + } + curve25519_scalarmult(session_key + 1, node->private_key, + peer_public_key + 1); + *result_size = 33; + return 0; + } else { + *result_size = 0; + return 1; // ECDH is not supported + } +} + +static int hdnode_serialize(const HDNode *node, uint32_t fingerprint, + uint32_t version, bool use_private, char *str, + int strsize) { + if (!hdnode_is_valid(node)) return 0; + + uint8_t node_data[78] = {0}; + write_be(node_data, version); + node_data[4] = node->depth; + write_be(node_data + 5, fingerprint); + write_be(node_data + 9, node->child_num); + memcpy(node_data + 13, node->chain_code, 32); + if (use_private) { + node_data[45] = 0; + memcpy(node_data + 46, node->private_key, 32); + } else { + memcpy(node_data + 45, node->public_key, 33); + } + int ret = base58_encode_check(node_data, sizeof(node_data), + node->curve->hasher_base58, str, strsize); + memzero(node_data, sizeof(node_data)); + return ret; +} + +int hdnode_serialize_public(const HDNode *node, uint32_t fingerprint, + uint32_t version, char *str, int strsize) { + return hdnode_serialize(node, fingerprint, version, false, str, strsize); +} + +int hdnode_serialize_private(const HDNode *node, uint32_t fingerprint, + uint32_t version, char *str, int strsize) { + return hdnode_serialize(node, fingerprint, version, true, str, strsize); +} + +// check for validity of curve point in case of public data not performed +static int hdnode_deserialize(const char *str, uint32_t version, + bool use_private, const char *curve, HDNode *node, + uint32_t *fingerprint) { + int ret = 0; + uint8_t node_data[78] = {0}; + memzero(node, sizeof(HDNode)); + node->curve = get_curve_by_name(curve); + if (!node->curve) { + ret = -1; + goto cleanup; + } + if (base58_decode_check(str, node->curve->hasher_base58, node_data, + sizeof(node_data)) != sizeof(node_data)) { + ret = -1; + goto cleanup; + } + uint32_t ver = read_be(node_data); + if (ver != version) { + ret = -3; // invalid version + goto cleanup; + } + if (use_private) { + // invalid data + if (node_data[45]) { + ret = -2; + goto cleanup; + } + memcpy(node->private_key, node_data + 46, 32); + memzero(node->public_key, sizeof(node->public_key)); + } else { + memzero(node->private_key, sizeof(node->private_key)); + memcpy(node->public_key, node_data + 45, 33); + } + node->depth = node_data[4]; + if (fingerprint) { + *fingerprint = read_be(node_data + 5); + } + node->child_num = read_be(node_data + 9); + memcpy(node->chain_code, node_data + 13, 32); + +cleanup: + memzero(node_data, sizeof(node_data)); + return ret; +} + +int hdnode_deserialize_public(const char *str, uint32_t version, + const char *curve, HDNode *node, + uint32_t *fingerprint) { + return hdnode_deserialize(str, version, false, curve, node, fingerprint); +} + +int hdnode_deserialize_private(const char *str, uint32_t version, + const char *curve, HDNode *node, + uint32_t *fingerprint) { + return hdnode_deserialize(str, version, true, curve, node, fingerprint); +} + +const curve_info *get_curve_by_name(const char *curve_name) { + if (curve_name == 0) { + return 0; + } + if (strcmp(curve_name, SECP256K1_NAME) == 0) { + return &secp256k1_info; + } + if (strcmp(curve_name, SECP256K1_DECRED_NAME) == 0) { + return &secp256k1_decred_info; + } + if (strcmp(curve_name, SECP256K1_GROESTL_NAME) == 0) { + return &secp256k1_groestl_info; + } + if (strcmp(curve_name, SECP256K1_SMART_NAME) == 0) { + return &secp256k1_smart_info; + } + if (strcmp(curve_name, NIST256P1_NAME) == 0) { + return &nist256p1_info; + } + if (strcmp(curve_name, ED25519_NAME) == 0) { + return &ed25519_info; + } + if (strcmp(curve_name, ED25519_CARDANO_NAME) == 0) { + return &ed25519_cardano_info; + } +#if USE_NANO + if (strcmp(curve_name, ED25519_BLAKE2B_NANO_NAME) == 0) { + return &ed25519_blake2b_nano_info; + } +#endif + if (strcmp(curve_name, ED25519_SHA3_NAME) == 0) { + return &ed25519_sha3_info; + } +#if USE_KECCAK + if (strcmp(curve_name, ED25519_KECCAK_NAME) == 0) { + return &ed25519_keccak_info; + } +#endif + if (strcmp(curve_name, CURVE25519_NAME) == 0) { + return &curve25519_info; + } + return 0; +} diff --git a/deps/crypto/trezor-crypto/bip32.h b/deps/crypto/trezor-crypto/bip32.h new file mode 100644 index 000000000..06d6f8001 --- /dev/null +++ b/deps/crypto/trezor-crypto/bip32.h @@ -0,0 +1,157 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BIP32_H__ +#define __BIP32_H__ + +#include +#include +#include +#include "ecdsa.h" +#include "ed25519-donna/ed25519.h" +#include "options.h" + +// Maximum length of a Base58Check-encoded extended public or private key. +#define XPUB_MAXLEN 112 + +// Maximum length of a Base58Check-encoded address. +#define ADDRESS_MAXLEN 39 + +typedef struct { + const char *bip32_name; // string for generating BIP32 xprv from seed + const ecdsa_curve *params; // ecdsa curve parameters, null for ed25519 + + HasherType hasher_base58; + HasherType hasher_sign; + HasherType hasher_pubkey; + HasherType hasher_script; +} curve_info; + +typedef struct { + uint32_t depth; + uint32_t child_num; + uint8_t chain_code[32]; + + uint8_t private_key[32]; + uint8_t private_key_extension[32]; + + uint8_t public_key[33]; + const curve_info *curve; +} HDNode; + +int hdnode_from_xpub(uint32_t depth, uint32_t child_num, + const uint8_t *chain_code, const uint8_t *public_key, + const char *curve, HDNode *out); + +int hdnode_from_xprv(uint32_t depth, uint32_t child_num, + const uint8_t *chain_code, const uint8_t *private_key, + const char *curve, HDNode *out); + +int hdnode_from_seed(const uint8_t *seed, int seed_len, const char *curve, + HDNode *out); + +#define hdnode_private_ckd_prime(X, I) \ + hdnode_private_ckd((X), ((I) | 0x80000000)) + +int hdnode_private_ckd(HDNode *inout, uint32_t i); + +#if USE_CARDANO +int hdnode_private_ckd_cardano(HDNode *inout, uint32_t i); +int hdnode_from_seed_cardano(const uint8_t *seed, int seed_len, HDNode *out); +int hdnode_from_entropy_cardano_icarus(const uint8_t *pass, int pass_len, + const uint8_t *seed, int seed_len, + HDNode *out); +#endif + +int hdnode_public_ckd_cp(const ecdsa_curve *curve, const curve_point *parent, + const uint8_t *parent_chain_code, uint32_t i, + curve_point *child, uint8_t *child_chain_code); + +int hdnode_public_ckd(HDNode *inout, uint32_t i); + +void hdnode_public_ckd_address_optimized(const curve_point *pub, + const uint8_t *chain_code, uint32_t i, + uint32_t version, + HasherType hasher_pubkey, + HasherType hasher_base58, char *addr, + int addrsize, int addrformat); + +#if USE_BIP32_CACHE +void bip32_cache_clear(void); +int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count, + uint32_t *fingerprint); +#endif + +uint32_t hdnode_fingerprint(HDNode *node); + +void hdnode_fill_public_key(HDNode *node); + +#if USE_ETHEREUM +int hdnode_get_ethereum_pubkeyhash(const HDNode *node, uint8_t *pubkeyhash); +#endif + +#if USE_NEM +int hdnode_get_nem_address(HDNode *node, uint8_t version, char *address); +int hdnode_get_nem_shared_key(const HDNode *node, + const ed25519_public_key peer_public_key, + const uint8_t *salt, ed25519_public_key mul, + uint8_t *shared_key); +int hdnode_nem_encrypt(const HDNode *node, const ed25519_public_key public_key, + const uint8_t *iv, const uint8_t *salt, + const uint8_t *payload, size_t size, uint8_t *buffer); +int hdnode_nem_decrypt(const HDNode *node, const ed25519_public_key public_key, + uint8_t *iv, const uint8_t *salt, const uint8_t *payload, + size_t size, uint8_t *buffer); +#endif + +int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, + HasherType hasher_sign, uint8_t *sig, uint8_t *pby, + int (*is_canonical)(uint8_t by, uint8_t sig[64])); +int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, + uint8_t *pby, + int (*is_canonical)(uint8_t by, uint8_t sig[64])); + +int hdnode_get_shared_key(const HDNode *node, const uint8_t *peer_public_key, + uint8_t *session_key, int *result_size); + +int hdnode_serialize_public(const HDNode *node, uint32_t fingerprint, + uint32_t version, char *str, int strsize); + +int hdnode_serialize_private(const HDNode *node, uint32_t fingerprint, + uint32_t version, char *str, int strsize); + +int hdnode_deserialize_public(const char *str, uint32_t version, + const char *curve, HDNode *node, + uint32_t *fingerprint); + +int hdnode_deserialize_private(const char *str, uint32_t version, + const char *curve, HDNode *node, + uint32_t *fingerprint); + +void hdnode_get_address_raw(HDNode *node, uint32_t version, uint8_t *addr_raw); +void hdnode_get_address(HDNode *node, uint32_t version, char *addr, + int addrsize); + +const curve_info *get_curve_by_name(const char *curve_name); + +#endif diff --git a/deps/crypto/trezor-crypto/bip39.c b/deps/crypto/trezor-crypto/bip39.c new file mode 100644 index 000000000..44074e1fa --- /dev/null +++ b/deps/crypto/trezor-crypto/bip39.c @@ -0,0 +1,323 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +#include "bip39.h" +#include "bip39_english.h" +#include "hmac.h" +#include "memzero.h" +#include "options.h" +#include "pbkdf2.h" +#include "rand.h" +#include "sha2.h" + +#if USE_BIP39_CACHE + +static int bip39_cache_index = 0; + +static CONFIDENTIAL struct { + bool set; + char mnemonic[256]; + char passphrase[64]; + uint8_t seed[512 / 8]; +} bip39_cache[BIP39_CACHE_SIZE]; + +void bip39_cache_clear(void) { + memzero(bip39_cache, sizeof(bip39_cache)); + bip39_cache_index = 0; +} + +#endif + +const char *mnemonic_generate(int strength) { + if (strength % 32 || strength < 128 || strength > 256) { + return 0; + } + uint8_t data[32] = {0}; + random_buffer(data, 32); + const char *r = mnemonic_from_data(data, strength / 8); + memzero(data, sizeof(data)); + return r; +} + +static CONFIDENTIAL char mnemo[24 * 10]; + +const char *mnemonic_from_data(const uint8_t *data, int len) { + if (len % 4 || len < 16 || len > 32) { + return 0; + } + + uint8_t bits[32 + 1] = {0}; + + sha256_Raw(data, len, bits); + // checksum + bits[len] = bits[0]; + // data + memcpy(bits, data, len); + + int mlen = len * 3 / 4; + + int i = 0, j = 0, idx = 0; + char *p = mnemo; + for (i = 0; i < mlen; i++) { + idx = 0; + for (j = 0; j < 11; j++) { + idx <<= 1; + idx += (bits[(i * 11 + j) / 8] & (1 << (7 - ((i * 11 + j) % 8)))) > 0; + } + strcpy(p, wordlist[idx]); + p += strlen(wordlist[idx]); + *p = (i < mlen - 1) ? ' ' : 0; + p++; + } + memzero(bits, sizeof(bits)); + + return mnemo; +} + +void mnemonic_clear(void) { memzero(mnemo, sizeof(mnemo)); } + +typedef struct { + int index; + size_t length; +} found_word; + +static bool constant_time_memeq(const void *s1, const void *s2, size_t n) { + const unsigned char *p1 = s1; + const unsigned char *p2 = s2; + unsigned int diff = 0; + for (size_t i = 0; i < n; i++) { + diff |= p1[i] ^ p2[i]; + } + return diff == 0; +} + +static found_word mnemonic_find_word_constant_time(const char *word) { + int result_index = -1; + size_t result_length = 0; + + for (int i = 0; i < BIP39_WORDS; i++) { + const char *dict_word = wordlist[i]; + size_t dict_word_len = strlen(dict_word); + bool is_match = + constant_time_memeq(word, dict_word, dict_word_len + 1); + int match_mask = -((int)is_match); + result_index = (match_mask & i) | (~match_mask & result_index); + result_length = + ((size_t)match_mask & dict_word_len) | + ((size_t)~match_mask & result_length); + } + + return (found_word){.index = result_index, .length = result_length}; +} + +int mnemonic_to_bits(const char *mnemonic_orig, uint8_t *bits) { + if (!mnemonic_orig || !bits) { + return 0; + } + + char mnemonic[BIP39_MAX_MNEMONIC_LEN + BIP39_MAX_WORD_LEN + 1] = {0}; + uint8_t result[32 + 1] = {0}; + int result_bits = 0; + + size_t mnemonic_len = strlen(mnemonic_orig); + if (mnemonic_len > BIP39_MAX_MNEMONIC_LEN) { + goto cleanup; + } + + uint32_t word_count = 0; + for (size_t i = 0; i < mnemonic_len; i++) { + bool is_space = mnemonic_orig[i] == ' '; + int space_mask = -((int)is_space) & ' '; + mnemonic[i] = mnemonic_orig[i] ^ space_mask; + word_count += is_space; + } + word_count++; + + if (word_count < 12 || word_count > 24 || (word_count % 3)) { + goto cleanup; + } + + uint32_t bit_count = 0; + size_t word_offset = 0; + while (word_offset < mnemonic_len) { + found_word found = + mnemonic_find_word_constant_time(&mnemonic[word_offset]); + word_offset += found.length + 1; + if (found.index < 0) { + goto cleanup; + } + + for (uint32_t bit_in_index = 0; bit_in_index < BIP39_BITS_PER_WORD; + bit_in_index++) { + uint32_t secret_bit = + ((uint32_t)found.index >> + (BIP39_BITS_PER_WORD - 1 - bit_in_index)) & + 1; + uint32_t mask = 0U - secret_bit; + result[bit_count / 8] |= + (uint8_t)((1U << (7 - (bit_count % 8))) & mask); + bit_count++; + } + } + + if (bit_count != word_count * BIP39_BITS_PER_WORD) { + goto cleanup; + } + + memcpy(bits, result, sizeof(result)); + result_bits = (int)bit_count; + +cleanup: + memzero(result, sizeof(result)); + memzero(mnemonic, sizeof(mnemonic)); + return result_bits; +} + +int mnemonic_check(const char *mnemonic) { + uint8_t bits[32 + 1] = {0}; + int mnemonic_bits_len = mnemonic_to_bits(mnemonic, bits); + int result = 0; + if (mnemonic_bits_len != (12 * BIP39_BITS_PER_WORD) && + mnemonic_bits_len != (18 * BIP39_BITS_PER_WORD) && + mnemonic_bits_len != (24 * BIP39_BITS_PER_WORD)) { + goto cleanup; + } + int words = mnemonic_bits_len / BIP39_BITS_PER_WORD; + + uint8_t checksum = bits[words * 4 / 3]; + sha256_Raw(bits, words * 4 / 3, bits); + if (words == 12) { + result = (bits[0] & 0xF0) == (checksum & 0xF0); + } else if (words == 18) { + result = (bits[0] & 0xFC) == (checksum & 0xFC); + } else if (words == 24) { + result = bits[0] == checksum; + } + +cleanup: + memzero(bits, sizeof(bits)); + return result; +} + +int mnemonic_find_word(const char *word) { + if (!word) { + return -1; + } + + char word_buffer[BIP39_MAX_WORD_LEN + 1] = {0}; + size_t word_len = strnlen(word, sizeof(word_buffer)); + if (word_len > BIP39_MAX_WORD_LEN) { + return -1; + } + memcpy(word_buffer, word, word_len); + found_word found = mnemonic_find_word_constant_time(word_buffer); + memzero(word_buffer, sizeof(word_buffer)); + return found.index; +} + +// passphrase must be at most 256 characters otherwise it would be truncated +void mnemonic_to_seed(const char *mnemonic, const char *passphrase, + uint8_t seed[512 / 8], + void (*progress_callback)(uint32_t current, + uint32_t total)) { + int mnemoniclen = strlen(mnemonic); + int passphraselen = strnlen(passphrase, 256); +#if USE_BIP39_CACHE + // check cache + if (mnemoniclen < 256 && passphraselen < 64) { + for (int i = 0; i < BIP39_CACHE_SIZE; i++) { + if (!bip39_cache[i].set) continue; + if (strcmp(bip39_cache[i].mnemonic, mnemonic) != 0) continue; + if (strcmp(bip39_cache[i].passphrase, passphrase) != 0) continue; + // found the correct entry + memcpy(seed, bip39_cache[i].seed, 512 / 8); + return; + } + } +#endif + uint8_t salt[8 + 256] = {0}; + memcpy(salt, "mnemonic", 8); + memcpy(salt + 8, passphrase, passphraselen); + static CONFIDENTIAL PBKDF2_HMAC_SHA512_CTX pctx; + pbkdf2_hmac_sha512_Init(&pctx, (const uint8_t *)mnemonic, mnemoniclen, salt, + passphraselen + 8, 1); + if (progress_callback) { + progress_callback(0, BIP39_PBKDF2_ROUNDS); + } + for (int i = 0; i < 16; i++) { + pbkdf2_hmac_sha512_Update(&pctx, BIP39_PBKDF2_ROUNDS / 16); + if (progress_callback) { + progress_callback((i + 1) * BIP39_PBKDF2_ROUNDS / 16, + BIP39_PBKDF2_ROUNDS); + } + } + pbkdf2_hmac_sha512_Final(&pctx, seed); + memzero(salt, sizeof(salt)); +#if USE_BIP39_CACHE + // store to cache + if (mnemoniclen < 256 && passphraselen < 64) { + bip39_cache[bip39_cache_index].set = true; + strcpy(bip39_cache[bip39_cache_index].mnemonic, mnemonic); + strcpy(bip39_cache[bip39_cache_index].passphrase, passphrase); + memcpy(bip39_cache[bip39_cache_index].seed, seed, 512 / 8); + bip39_cache_index = (bip39_cache_index + 1) % BIP39_CACHE_SIZE; + } +#endif +} + +const char *mnemonic_complete_word(const char *prefix, int len) { + // we need to perform linear search, + // because we want to return the first match + for (const char *const *w = wordlist; *w != 0; w++) { + if (strncmp(*w, prefix, len) == 0) { + return *w; + } + } + return NULL; +} + +const char *mnemonic_get_word(int index) { + if (index >= 0 && index < BIP39_WORDS) { + return wordlist[index]; + } else { + return NULL; + } +} + +uint32_t mnemonic_word_completion_mask(const char *prefix, int len) { + if (len <= 0) { + return 0x3ffffff; // all letters (bits 1-26 set) + } + uint32_t res = 0; + for (const char *const *w = wordlist; *w != 0; w++) { + const char *word = *w; + if (strncmp(word, prefix, len) == 0 && word[len] >= 'a' && + word[len] <= 'z') { + res |= 1 << (word[len] - 'a'); + } + } + return res; +} diff --git a/deps/crypto/trezor-crypto/bip39.h b/deps/crypto/trezor-crypto/bip39.h new file mode 100644 index 000000000..ab1e57fad --- /dev/null +++ b/deps/crypto/trezor-crypto/bip39.h @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BIP39_H__ +#define __BIP39_H__ + +#include +#include +#include + +#include "options.h" + +#define BIP39_WORDS 2048 +#define BIP39_PBKDF2_ROUNDS 2048 +#define BIP39_MAX_WORD_LEN 8 +#define BIP39_MAX_MNEMONIC_LEN (24 * BIP39_MAX_WORD_LEN + 23) +#define BIP39_BITS_PER_WORD 11 + +#if USE_BIP39_CACHE +void bip39_cache_clear(void); +#endif + +const char *mnemonic_generate(int strength); // strength in bits +const char *mnemonic_from_data(const uint8_t *data, int len); +void mnemonic_clear(void); + +int mnemonic_check(const char *mnemonic); + +int mnemonic_to_bits(const char *mnemonic, uint8_t *bits); + +// passphrase must be at most 256 characters otherwise it would be truncated +void mnemonic_to_seed(const char *mnemonic, const char *passphrase, + uint8_t seed[512 / 8], + void (*progress_callback)(uint32_t current, + uint32_t total)); + +int mnemonic_find_word(const char *word); +const char *mnemonic_complete_word(const char *prefix, int len); +const char *mnemonic_get_word(int index); +uint32_t mnemonic_word_completion_mask(const char *prefix, int len); + +#endif diff --git a/deps/crypto/trezor-crypto/bip39_english.c b/deps/crypto/trezor-crypto/bip39_english.c new file mode 100644 index 000000000..82b404699 --- /dev/null +++ b/deps/crypto/trezor-crypto/bip39_english.c @@ -0,0 +1,4125 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +const char * const wordlist[2048 + 1] = { +#ifndef BIP39_WORDLIST_PADDED +"abandon", +"ability", +"able", +"about", +"above", +"absent", +"absorb", +"abstract", +"absurd", +"abuse", +"access", +"accident", +"account", +"accuse", +"achieve", +"acid", +"acoustic", +"acquire", +"across", +"act", +"action", +"actor", +"actress", +"actual", +"adapt", +"add", +"addict", +"address", +"adjust", +"admit", +"adult", +"advance", +"advice", +"aerobic", +"affair", +"afford", +"afraid", +"again", +"age", +"agent", +"agree", +"ahead", +"aim", +"air", +"airport", +"aisle", +"alarm", +"album", +"alcohol", +"alert", +"alien", +"all", +"alley", +"allow", +"almost", +"alone", +"alpha", +"already", +"also", +"alter", +"always", +"amateur", +"amazing", +"among", +"amount", +"amused", +"analyst", +"anchor", +"ancient", +"anger", +"angle", +"angry", +"animal", +"ankle", +"announce", +"annual", +"another", +"answer", +"antenna", +"antique", +"anxiety", +"any", +"apart", +"apology", +"appear", +"apple", +"approve", +"april", +"arch", +"arctic", +"area", +"arena", +"argue", +"arm", +"armed", +"armor", +"army", +"around", +"arrange", +"arrest", +"arrive", +"arrow", +"art", +"artefact", +"artist", +"artwork", +"ask", +"aspect", +"assault", +"asset", +"assist", +"assume", +"asthma", +"athlete", +"atom", +"attack", +"attend", +"attitude", +"attract", +"auction", +"audit", +"august", +"aunt", +"author", +"auto", +"autumn", +"average", +"avocado", +"avoid", +"awake", +"aware", +"away", +"awesome", +"awful", +"awkward", +"axis", +"baby", +"bachelor", +"bacon", +"badge", +"bag", +"balance", +"balcony", +"ball", +"bamboo", +"banana", +"banner", +"bar", +"barely", +"bargain", +"barrel", +"base", +"basic", +"basket", +"battle", +"beach", +"bean", +"beauty", +"because", +"become", +"beef", +"before", +"begin", +"behave", +"behind", +"believe", +"below", +"belt", +"bench", +"benefit", +"best", +"betray", +"better", +"between", +"beyond", +"bicycle", +"bid", +"bike", +"bind", +"biology", +"bird", +"birth", +"bitter", +"black", +"blade", +"blame", +"blanket", +"blast", +"bleak", +"bless", +"blind", +"blood", +"blossom", +"blouse", +"blue", +"blur", +"blush", +"board", +"boat", +"body", +"boil", +"bomb", +"bone", +"bonus", +"book", +"boost", +"border", +"boring", +"borrow", +"boss", +"bottom", +"bounce", +"box", +"boy", +"bracket", +"brain", +"brand", +"brass", +"brave", +"bread", +"breeze", +"brick", +"bridge", +"brief", +"bright", +"bring", +"brisk", +"broccoli", +"broken", +"bronze", +"broom", +"brother", +"brown", +"brush", +"bubble", +"buddy", +"budget", +"buffalo", +"build", +"bulb", +"bulk", +"bullet", +"bundle", +"bunker", +"burden", +"burger", +"burst", +"bus", +"business", +"busy", +"butter", +"buyer", +"buzz", +"cabbage", +"cabin", +"cable", +"cactus", +"cage", +"cake", +"call", +"calm", +"camera", +"camp", +"can", +"canal", +"cancel", +"candy", +"cannon", +"canoe", +"canvas", +"canyon", +"capable", +"capital", +"captain", +"car", +"carbon", +"card", +"cargo", +"carpet", +"carry", +"cart", +"case", +"cash", +"casino", +"castle", +"casual", +"cat", +"catalog", +"catch", +"category", +"cattle", +"caught", +"cause", +"caution", +"cave", +"ceiling", +"celery", +"cement", +"census", +"century", +"cereal", +"certain", +"chair", +"chalk", +"champion", +"change", +"chaos", +"chapter", +"charge", +"chase", +"chat", +"cheap", +"check", +"cheese", +"chef", +"cherry", +"chest", +"chicken", +"chief", +"child", +"chimney", +"choice", +"choose", +"chronic", +"chuckle", +"chunk", +"churn", +"cigar", +"cinnamon", +"circle", +"citizen", +"city", +"civil", +"claim", +"clap", +"clarify", +"claw", +"clay", +"clean", +"clerk", +"clever", +"click", +"client", +"cliff", +"climb", +"clinic", +"clip", +"clock", +"clog", +"close", +"cloth", +"cloud", +"clown", +"club", +"clump", +"cluster", +"clutch", +"coach", +"coast", +"coconut", +"code", +"coffee", +"coil", +"coin", +"collect", +"color", +"column", +"combine", +"come", +"comfort", +"comic", +"common", +"company", +"concert", +"conduct", +"confirm", +"congress", +"connect", +"consider", +"control", +"convince", +"cook", +"cool", +"copper", +"copy", +"coral", +"core", +"corn", +"correct", +"cost", +"cotton", +"couch", +"country", +"couple", +"course", +"cousin", +"cover", +"coyote", +"crack", +"cradle", +"craft", +"cram", +"crane", +"crash", +"crater", +"crawl", +"crazy", +"cream", +"credit", +"creek", +"crew", +"cricket", +"crime", +"crisp", +"critic", +"crop", +"cross", +"crouch", +"crowd", +"crucial", +"cruel", +"cruise", +"crumble", +"crunch", +"crush", +"cry", +"crystal", +"cube", +"culture", +"cup", +"cupboard", +"curious", +"current", +"curtain", +"curve", +"cushion", +"custom", +"cute", +"cycle", +"dad", +"damage", +"damp", +"dance", +"danger", +"daring", +"dash", +"daughter", +"dawn", +"day", +"deal", +"debate", +"debris", +"decade", +"december", +"decide", +"decline", +"decorate", +"decrease", +"deer", +"defense", +"define", +"defy", +"degree", +"delay", +"deliver", +"demand", +"demise", +"denial", +"dentist", +"deny", +"depart", +"depend", +"deposit", +"depth", +"deputy", +"derive", +"describe", +"desert", +"design", +"desk", +"despair", +"destroy", +"detail", +"detect", +"develop", +"device", +"devote", +"diagram", +"dial", +"diamond", +"diary", +"dice", +"diesel", +"diet", +"differ", +"digital", +"dignity", +"dilemma", +"dinner", +"dinosaur", +"direct", +"dirt", +"disagree", +"discover", +"disease", +"dish", +"dismiss", +"disorder", +"display", +"distance", +"divert", +"divide", +"divorce", +"dizzy", +"doctor", +"document", +"dog", +"doll", +"dolphin", +"domain", +"donate", +"donkey", +"donor", +"door", +"dose", +"double", +"dove", +"draft", +"dragon", +"drama", +"drastic", +"draw", +"dream", +"dress", +"drift", +"drill", +"drink", +"drip", +"drive", +"drop", +"drum", +"dry", +"duck", +"dumb", +"dune", +"during", +"dust", +"dutch", +"duty", +"dwarf", +"dynamic", +"eager", +"eagle", +"early", +"earn", +"earth", +"easily", +"east", +"easy", +"echo", +"ecology", +"economy", +"edge", +"edit", +"educate", +"effort", +"egg", +"eight", +"either", +"elbow", +"elder", +"electric", +"elegant", +"element", +"elephant", +"elevator", +"elite", +"else", +"embark", +"embody", +"embrace", +"emerge", +"emotion", +"employ", +"empower", +"empty", +"enable", +"enact", +"end", +"endless", +"endorse", +"enemy", +"energy", +"enforce", +"engage", +"engine", +"enhance", +"enjoy", +"enlist", +"enough", +"enrich", +"enroll", +"ensure", +"enter", +"entire", +"entry", +"envelope", +"episode", +"equal", +"equip", +"era", +"erase", +"erode", +"erosion", +"error", +"erupt", +"escape", +"essay", +"essence", +"estate", +"eternal", +"ethics", +"evidence", +"evil", +"evoke", +"evolve", +"exact", +"example", +"excess", +"exchange", +"excite", +"exclude", +"excuse", +"execute", +"exercise", +"exhaust", +"exhibit", +"exile", +"exist", +"exit", +"exotic", +"expand", +"expect", +"expire", +"explain", +"expose", +"express", +"extend", +"extra", +"eye", +"eyebrow", +"fabric", +"face", +"faculty", +"fade", +"faint", +"faith", +"fall", +"false", +"fame", +"family", +"famous", +"fan", +"fancy", +"fantasy", +"farm", +"fashion", +"fat", +"fatal", +"father", +"fatigue", +"fault", +"favorite", +"feature", +"february", +"federal", +"fee", +"feed", +"feel", +"female", +"fence", +"festival", +"fetch", +"fever", +"few", +"fiber", +"fiction", +"field", +"figure", +"file", +"film", +"filter", +"final", +"find", +"fine", +"finger", +"finish", +"fire", +"firm", +"first", +"fiscal", +"fish", +"fit", +"fitness", +"fix", +"flag", +"flame", +"flash", +"flat", +"flavor", +"flee", +"flight", +"flip", +"float", +"flock", +"floor", +"flower", +"fluid", +"flush", +"fly", +"foam", +"focus", +"fog", +"foil", +"fold", +"follow", +"food", +"foot", +"force", +"forest", +"forget", +"fork", +"fortune", +"forum", +"forward", +"fossil", +"foster", +"found", +"fox", +"fragile", +"frame", +"frequent", +"fresh", +"friend", +"fringe", +"frog", +"front", +"frost", +"frown", +"frozen", +"fruit", +"fuel", +"fun", +"funny", +"furnace", +"fury", +"future", +"gadget", +"gain", +"galaxy", +"gallery", +"game", +"gap", +"garage", +"garbage", +"garden", +"garlic", +"garment", +"gas", +"gasp", +"gate", +"gather", +"gauge", +"gaze", +"general", +"genius", +"genre", +"gentle", +"genuine", +"gesture", +"ghost", +"giant", +"gift", +"giggle", +"ginger", +"giraffe", +"girl", +"give", +"glad", +"glance", +"glare", +"glass", +"glide", +"glimpse", +"globe", +"gloom", +"glory", +"glove", +"glow", +"glue", +"goat", +"goddess", +"gold", +"good", +"goose", +"gorilla", +"gospel", +"gossip", +"govern", +"gown", +"grab", +"grace", +"grain", +"grant", +"grape", +"grass", +"gravity", +"great", +"green", +"grid", +"grief", +"grit", +"grocery", +"group", +"grow", +"grunt", +"guard", +"guess", +"guide", +"guilt", +"guitar", +"gun", +"gym", +"habit", +"hair", +"half", +"hammer", +"hamster", +"hand", +"happy", +"harbor", +"hard", +"harsh", +"harvest", +"hat", +"have", +"hawk", +"hazard", +"head", +"health", +"heart", +"heavy", +"hedgehog", +"height", +"hello", +"helmet", +"help", +"hen", +"hero", +"hidden", +"high", +"hill", +"hint", +"hip", +"hire", +"history", +"hobby", +"hockey", +"hold", +"hole", +"holiday", +"hollow", +"home", +"honey", +"hood", +"hope", +"horn", +"horror", +"horse", +"hospital", +"host", +"hotel", +"hour", +"hover", +"hub", +"huge", +"human", +"humble", +"humor", +"hundred", +"hungry", +"hunt", +"hurdle", +"hurry", +"hurt", +"husband", +"hybrid", +"ice", +"icon", +"idea", +"identify", +"idle", +"ignore", +"ill", +"illegal", +"illness", +"image", +"imitate", +"immense", +"immune", +"impact", +"impose", +"improve", +"impulse", +"inch", +"include", +"income", +"increase", +"index", +"indicate", +"indoor", +"industry", +"infant", +"inflict", +"inform", +"inhale", +"inherit", +"initial", +"inject", +"injury", +"inmate", +"inner", +"innocent", +"input", +"inquiry", +"insane", +"insect", +"inside", +"inspire", +"install", +"intact", +"interest", +"into", +"invest", +"invite", +"involve", +"iron", +"island", +"isolate", +"issue", +"item", +"ivory", +"jacket", +"jaguar", +"jar", +"jazz", +"jealous", +"jeans", +"jelly", +"jewel", +"job", +"join", +"joke", +"journey", +"joy", +"judge", +"juice", +"jump", +"jungle", +"junior", +"junk", +"just", +"kangaroo", +"keen", +"keep", +"ketchup", +"key", +"kick", +"kid", +"kidney", +"kind", +"kingdom", +"kiss", +"kit", +"kitchen", +"kite", +"kitten", +"kiwi", +"knee", +"knife", +"knock", +"know", +"lab", +"label", +"labor", +"ladder", +"lady", +"lake", +"lamp", +"language", +"laptop", +"large", +"later", +"latin", +"laugh", +"laundry", +"lava", +"law", +"lawn", +"lawsuit", +"layer", +"lazy", +"leader", +"leaf", +"learn", +"leave", +"lecture", +"left", +"leg", +"legal", +"legend", +"leisure", +"lemon", +"lend", +"length", +"lens", +"leopard", +"lesson", +"letter", +"level", +"liar", +"liberty", +"library", +"license", +"life", +"lift", +"light", +"like", +"limb", +"limit", +"link", +"lion", +"liquid", +"list", +"little", +"live", +"lizard", +"load", +"loan", +"lobster", +"local", +"lock", +"logic", +"lonely", +"long", +"loop", +"lottery", +"loud", +"lounge", +"love", +"loyal", +"lucky", +"luggage", +"lumber", +"lunar", +"lunch", +"luxury", +"lyrics", +"machine", +"mad", +"magic", +"magnet", +"maid", +"mail", +"main", +"major", +"make", +"mammal", +"man", +"manage", +"mandate", +"mango", +"mansion", +"manual", +"maple", +"marble", +"march", +"margin", +"marine", +"market", +"marriage", +"mask", +"mass", +"master", +"match", +"material", +"math", +"matrix", +"matter", +"maximum", +"maze", +"meadow", +"mean", +"measure", +"meat", +"mechanic", +"medal", +"media", +"melody", +"melt", +"member", +"memory", +"mention", +"menu", +"mercy", +"merge", +"merit", +"merry", +"mesh", +"message", +"metal", +"method", +"middle", +"midnight", +"milk", +"million", +"mimic", +"mind", +"minimum", +"minor", +"minute", +"miracle", +"mirror", +"misery", +"miss", +"mistake", +"mix", +"mixed", +"mixture", +"mobile", +"model", +"modify", +"mom", +"moment", +"monitor", +"monkey", +"monster", +"month", +"moon", +"moral", +"more", +"morning", +"mosquito", +"mother", +"motion", +"motor", +"mountain", +"mouse", +"move", +"movie", +"much", +"muffin", +"mule", +"multiply", +"muscle", +"museum", +"mushroom", +"music", +"must", +"mutual", +"myself", +"mystery", +"myth", +"naive", +"name", +"napkin", +"narrow", +"nasty", +"nation", +"nature", +"near", +"neck", +"need", +"negative", +"neglect", +"neither", +"nephew", +"nerve", +"nest", +"net", +"network", +"neutral", +"never", +"news", +"next", +"nice", +"night", +"noble", +"noise", +"nominee", +"noodle", +"normal", +"north", +"nose", +"notable", +"note", +"nothing", +"notice", +"novel", +"now", +"nuclear", +"number", +"nurse", +"nut", +"oak", +"obey", +"object", +"oblige", +"obscure", +"observe", +"obtain", +"obvious", +"occur", +"ocean", +"october", +"odor", +"off", +"offer", +"office", +"often", +"oil", +"okay", +"old", +"olive", +"olympic", +"omit", +"once", +"one", +"onion", +"online", +"only", +"open", +"opera", +"opinion", +"oppose", +"option", +"orange", +"orbit", +"orchard", +"order", +"ordinary", +"organ", +"orient", +"original", +"orphan", +"ostrich", +"other", +"outdoor", +"outer", +"output", +"outside", +"oval", +"oven", +"over", +"own", +"owner", +"oxygen", +"oyster", +"ozone", +"pact", +"paddle", +"page", +"pair", +"palace", +"palm", +"panda", +"panel", +"panic", +"panther", +"paper", +"parade", +"parent", +"park", +"parrot", +"party", +"pass", +"patch", +"path", +"patient", +"patrol", +"pattern", +"pause", +"pave", +"payment", +"peace", +"peanut", +"pear", +"peasant", +"pelican", +"pen", +"penalty", +"pencil", +"people", +"pepper", +"perfect", +"permit", +"person", +"pet", +"phone", +"photo", +"phrase", +"physical", +"piano", +"picnic", +"picture", +"piece", +"pig", +"pigeon", +"pill", +"pilot", +"pink", +"pioneer", +"pipe", +"pistol", +"pitch", +"pizza", +"place", +"planet", +"plastic", +"plate", +"play", +"please", +"pledge", +"pluck", +"plug", +"plunge", +"poem", +"poet", +"point", +"polar", +"pole", +"police", +"pond", +"pony", +"pool", +"popular", +"portion", +"position", +"possible", +"post", +"potato", +"pottery", +"poverty", +"powder", +"power", +"practice", +"praise", +"predict", +"prefer", +"prepare", +"present", +"pretty", +"prevent", +"price", +"pride", +"primary", +"print", +"priority", +"prison", +"private", +"prize", +"problem", +"process", +"produce", +"profit", +"program", +"project", +"promote", +"proof", +"property", +"prosper", +"protect", +"proud", +"provide", +"public", +"pudding", +"pull", +"pulp", +"pulse", +"pumpkin", +"punch", +"pupil", +"puppy", +"purchase", +"purity", +"purpose", +"purse", +"push", +"put", +"puzzle", +"pyramid", +"quality", +"quantum", +"quarter", +"question", +"quick", +"quit", +"quiz", +"quote", +"rabbit", +"raccoon", +"race", +"rack", +"radar", +"radio", +"rail", +"rain", +"raise", +"rally", +"ramp", +"ranch", +"random", +"range", +"rapid", +"rare", +"rate", +"rather", +"raven", +"raw", +"razor", +"ready", +"real", +"reason", +"rebel", +"rebuild", +"recall", +"receive", +"recipe", +"record", +"recycle", +"reduce", +"reflect", +"reform", +"refuse", +"region", +"regret", +"regular", +"reject", +"relax", +"release", +"relief", +"rely", +"remain", +"remember", +"remind", +"remove", +"render", +"renew", +"rent", +"reopen", +"repair", +"repeat", +"replace", +"report", +"require", +"rescue", +"resemble", +"resist", +"resource", +"response", +"result", +"retire", +"retreat", +"return", +"reunion", +"reveal", +"review", +"reward", +"rhythm", +"rib", +"ribbon", +"rice", +"rich", +"ride", +"ridge", +"rifle", +"right", +"rigid", +"ring", +"riot", +"ripple", +"risk", +"ritual", +"rival", +"river", +"road", +"roast", +"robot", +"robust", +"rocket", +"romance", +"roof", +"rookie", +"room", +"rose", +"rotate", +"rough", +"round", +"route", +"royal", +"rubber", +"rude", +"rug", +"rule", +"run", +"runway", +"rural", +"sad", +"saddle", +"sadness", +"safe", +"sail", +"salad", +"salmon", +"salon", +"salt", +"salute", +"same", +"sample", +"sand", +"satisfy", +"satoshi", +"sauce", +"sausage", +"save", +"say", +"scale", +"scan", +"scare", +"scatter", +"scene", +"scheme", +"school", +"science", +"scissors", +"scorpion", +"scout", +"scrap", +"screen", +"script", +"scrub", +"sea", +"search", +"season", +"seat", +"second", +"secret", +"section", +"security", +"seed", +"seek", +"segment", +"select", +"sell", +"seminar", +"senior", +"sense", +"sentence", +"series", +"service", +"session", +"settle", +"setup", +"seven", +"shadow", +"shaft", +"shallow", +"share", +"shed", +"shell", +"sheriff", +"shield", +"shift", +"shine", +"ship", +"shiver", +"shock", +"shoe", +"shoot", +"shop", +"short", +"shoulder", +"shove", +"shrimp", +"shrug", +"shuffle", +"shy", +"sibling", +"sick", +"side", +"siege", +"sight", +"sign", +"silent", +"silk", +"silly", +"silver", +"similar", +"simple", +"since", +"sing", +"siren", +"sister", +"situate", +"six", +"size", +"skate", +"sketch", +"ski", +"skill", +"skin", +"skirt", +"skull", +"slab", +"slam", +"sleep", +"slender", +"slice", +"slide", +"slight", +"slim", +"slogan", +"slot", +"slow", +"slush", +"small", +"smart", +"smile", +"smoke", +"smooth", +"snack", +"snake", +"snap", +"sniff", +"snow", +"soap", +"soccer", +"social", +"sock", +"soda", +"soft", +"solar", +"soldier", +"solid", +"solution", +"solve", +"someone", +"song", +"soon", +"sorry", +"sort", +"soul", +"sound", +"soup", +"source", +"south", +"space", +"spare", +"spatial", +"spawn", +"speak", +"special", +"speed", +"spell", +"spend", +"sphere", +"spice", +"spider", +"spike", +"spin", +"spirit", +"split", +"spoil", +"sponsor", +"spoon", +"sport", +"spot", +"spray", +"spread", +"spring", +"spy", +"square", +"squeeze", +"squirrel", +"stable", +"stadium", +"staff", +"stage", +"stairs", +"stamp", +"stand", +"start", +"state", +"stay", +"steak", +"steel", +"stem", +"step", +"stereo", +"stick", +"still", +"sting", +"stock", +"stomach", +"stone", +"stool", +"story", +"stove", +"strategy", +"street", +"strike", +"strong", +"struggle", +"student", +"stuff", +"stumble", +"style", +"subject", +"submit", +"subway", +"success", +"such", +"sudden", +"suffer", +"sugar", +"suggest", +"suit", +"summer", +"sun", +"sunny", +"sunset", +"super", +"supply", +"supreme", +"sure", +"surface", +"surge", +"surprise", +"surround", +"survey", +"suspect", +"sustain", +"swallow", +"swamp", +"swap", +"swarm", +"swear", +"sweet", +"swift", +"swim", +"swing", +"switch", +"sword", +"symbol", +"symptom", +"syrup", +"system", +"table", +"tackle", +"tag", +"tail", +"talent", +"talk", +"tank", +"tape", +"target", +"task", +"taste", +"tattoo", +"taxi", +"teach", +"team", +"tell", +"ten", +"tenant", +"tennis", +"tent", +"term", +"test", +"text", +"thank", +"that", +"theme", +"then", +"theory", +"there", +"they", +"thing", +"this", +"thought", +"three", +"thrive", +"throw", +"thumb", +"thunder", +"ticket", +"tide", +"tiger", +"tilt", +"timber", +"time", +"tiny", +"tip", +"tired", +"tissue", +"title", +"toast", +"tobacco", +"today", +"toddler", +"toe", +"together", +"toilet", +"token", +"tomato", +"tomorrow", +"tone", +"tongue", +"tonight", +"tool", +"tooth", +"top", +"topic", +"topple", +"torch", +"tornado", +"tortoise", +"toss", +"total", +"tourist", +"toward", +"tower", +"town", +"toy", +"track", +"trade", +"traffic", +"tragic", +"train", +"transfer", +"trap", +"trash", +"travel", +"tray", +"treat", +"tree", +"trend", +"trial", +"tribe", +"trick", +"trigger", +"trim", +"trip", +"trophy", +"trouble", +"truck", +"true", +"truly", +"trumpet", +"trust", +"truth", +"try", +"tube", +"tuition", +"tumble", +"tuna", +"tunnel", +"turkey", +"turn", +"turtle", +"twelve", +"twenty", +"twice", +"twin", +"twist", +"two", +"type", +"typical", +"ugly", +"umbrella", +"unable", +"unaware", +"uncle", +"uncover", +"under", +"undo", +"unfair", +"unfold", +"unhappy", +"uniform", +"unique", +"unit", +"universe", +"unknown", +"unlock", +"until", +"unusual", +"unveil", +"update", +"upgrade", +"uphold", +"upon", +"upper", +"upset", +"urban", +"urge", +"usage", +"use", +"used", +"useful", +"useless", +"usual", +"utility", +"vacant", +"vacuum", +"vague", +"valid", +"valley", +"valve", +"van", +"vanish", +"vapor", +"various", +"vast", +"vault", +"vehicle", +"velvet", +"vendor", +"venture", +"venue", +"verb", +"verify", +"version", +"very", +"vessel", +"veteran", +"viable", +"vibrant", +"vicious", +"victory", +"video", +"view", +"village", +"vintage", +"violin", +"virtual", +"virus", +"visa", +"visit", +"visual", +"vital", +"vivid", +"vocal", +"voice", +"void", +"volcano", +"volume", +"vote", +"voyage", +"wage", +"wagon", +"wait", +"walk", +"wall", +"walnut", +"want", +"warfare", +"warm", +"warrior", +"wash", +"wasp", +"waste", +"water", +"wave", +"way", +"wealth", +"weapon", +"wear", +"weasel", +"weather", +"web", +"wedding", +"weekend", +"weird", +"welcome", +"west", +"wet", +"whale", +"what", +"wheat", +"wheel", +"when", +"where", +"whip", +"whisper", +"wide", +"width", +"wife", +"wild", +"will", +"win", +"window", +"wine", +"wing", +"wink", +"winner", +"winter", +"wire", +"wisdom", +"wise", +"wish", +"witness", +"wolf", +"woman", +"wonder", +"wood", +"wool", +"word", +"work", +"world", +"worry", +"worth", +"wrap", +"wreck", +"wrestle", +"wrist", +"write", +"wrong", +"yard", +"year", +"yellow", +"you", +"young", +"youth", +"zebra", +"zero", +"zone", +"zoo", +#else +"abandon\0", +"ability\0", +"able\0\0\0\0", +"about\0\0\0", +"above\0\0\0", +"absent\0\0", +"absorb\0\0", +"abstract", +"absurd\0\0", +"abuse\0\0\0", +"access\0\0", +"accident", +"account\0", +"accuse\0\0", +"achieve\0", +"acid\0\0\0\0", +"acoustic", +"acquire\0", +"across\0\0", +"act\0\0\0\0\0", +"action\0\0", +"actor\0\0\0", +"actress\0", +"actual\0\0", +"adapt\0\0\0", +"add\0\0\0\0\0", +"addict\0\0", +"address\0", +"adjust\0\0", +"admit\0\0\0", +"adult\0\0\0", +"advance\0", +"advice\0\0", +"aerobic\0", +"affair\0\0", +"afford\0\0", +"afraid\0\0", +"again\0\0\0", +"age\0\0\0\0\0", +"agent\0\0\0", +"agree\0\0\0", +"ahead\0\0\0", +"aim\0\0\0\0\0", +"air\0\0\0\0\0", +"airport\0", +"aisle\0\0\0", +"alarm\0\0\0", +"album\0\0\0", +"alcohol\0", +"alert\0\0\0", +"alien\0\0\0", +"all\0\0\0\0\0", +"alley\0\0\0", +"allow\0\0\0", +"almost\0\0", +"alone\0\0\0", +"alpha\0\0\0", +"already\0", +"also\0\0\0\0", +"alter\0\0\0", +"always\0\0", +"amateur\0", +"amazing\0", +"among\0\0\0", +"amount\0\0", +"amused\0\0", +"analyst\0", +"anchor\0\0", +"ancient\0", +"anger\0\0\0", +"angle\0\0\0", +"angry\0\0\0", +"animal\0\0", +"ankle\0\0\0", +"announce", +"annual\0\0", +"another\0", +"answer\0\0", +"antenna\0", +"antique\0", +"anxiety\0", +"any\0\0\0\0\0", +"apart\0\0\0", +"apology\0", +"appear\0\0", +"apple\0\0\0", +"approve\0", +"april\0\0\0", +"arch\0\0\0\0", +"arctic\0\0", +"area\0\0\0\0", +"arena\0\0\0", +"argue\0\0\0", +"arm\0\0\0\0\0", +"armed\0\0\0", +"armor\0\0\0", +"army\0\0\0\0", +"around\0\0", +"arrange\0", +"arrest\0\0", +"arrive\0\0", +"arrow\0\0\0", +"art\0\0\0\0\0", +"artefact", +"artist\0\0", +"artwork\0", +"ask\0\0\0\0\0", +"aspect\0\0", +"assault\0", +"asset\0\0\0", +"assist\0\0", +"assume\0\0", +"asthma\0\0", +"athlete\0", +"atom\0\0\0\0", +"attack\0\0", +"attend\0\0", +"attitude", +"attract\0", +"auction\0", +"audit\0\0\0", +"august\0\0", +"aunt\0\0\0\0", +"author\0\0", +"auto\0\0\0\0", +"autumn\0\0", +"average\0", +"avocado\0", +"avoid\0\0\0", +"awake\0\0\0", +"aware\0\0\0", +"away\0\0\0\0", +"awesome\0", +"awful\0\0\0", +"awkward\0", +"axis\0\0\0\0", +"baby\0\0\0\0", +"bachelor", +"bacon\0\0\0", +"badge\0\0\0", +"bag\0\0\0\0\0", +"balance\0", +"balcony\0", +"ball\0\0\0\0", +"bamboo\0\0", +"banana\0\0", +"banner\0\0", +"bar\0\0\0\0\0", +"barely\0\0", +"bargain\0", +"barrel\0\0", +"base\0\0\0\0", +"basic\0\0\0", +"basket\0\0", +"battle\0\0", +"beach\0\0\0", +"bean\0\0\0\0", +"beauty\0\0", +"because\0", +"become\0\0", +"beef\0\0\0\0", +"before\0\0", +"begin\0\0\0", +"behave\0\0", +"behind\0\0", +"believe\0", +"below\0\0\0", +"belt\0\0\0\0", +"bench\0\0\0", +"benefit\0", +"best\0\0\0\0", +"betray\0\0", +"better\0\0", +"between\0", +"beyond\0\0", +"bicycle\0", +"bid\0\0\0\0\0", +"bike\0\0\0\0", +"bind\0\0\0\0", +"biology\0", +"bird\0\0\0\0", +"birth\0\0\0", +"bitter\0\0", +"black\0\0\0", +"blade\0\0\0", +"blame\0\0\0", +"blanket\0", +"blast\0\0\0", +"bleak\0\0\0", +"bless\0\0\0", +"blind\0\0\0", +"blood\0\0\0", +"blossom\0", +"blouse\0\0", +"blue\0\0\0\0", +"blur\0\0\0\0", +"blush\0\0\0", +"board\0\0\0", +"boat\0\0\0\0", +"body\0\0\0\0", +"boil\0\0\0\0", +"bomb\0\0\0\0", +"bone\0\0\0\0", +"bonus\0\0\0", +"book\0\0\0\0", +"boost\0\0\0", +"border\0\0", +"boring\0\0", +"borrow\0\0", +"boss\0\0\0\0", +"bottom\0\0", +"bounce\0\0", +"box\0\0\0\0\0", +"boy\0\0\0\0\0", +"bracket\0", +"brain\0\0\0", +"brand\0\0\0", +"brass\0\0\0", +"brave\0\0\0", +"bread\0\0\0", +"breeze\0\0", +"brick\0\0\0", +"bridge\0\0", +"brief\0\0\0", +"bright\0\0", +"bring\0\0\0", +"brisk\0\0\0", +"broccoli", +"broken\0\0", +"bronze\0\0", +"broom\0\0\0", +"brother\0", +"brown\0\0\0", +"brush\0\0\0", +"bubble\0\0", +"buddy\0\0\0", +"budget\0\0", +"buffalo\0", +"build\0\0\0", +"bulb\0\0\0\0", +"bulk\0\0\0\0", +"bullet\0\0", +"bundle\0\0", +"bunker\0\0", +"burden\0\0", +"burger\0\0", +"burst\0\0\0", +"bus\0\0\0\0\0", +"business", +"busy\0\0\0\0", +"butter\0\0", +"buyer\0\0\0", +"buzz\0\0\0\0", +"cabbage\0", +"cabin\0\0\0", +"cable\0\0\0", +"cactus\0\0", +"cage\0\0\0\0", +"cake\0\0\0\0", +"call\0\0\0\0", +"calm\0\0\0\0", +"camera\0\0", +"camp\0\0\0\0", +"can\0\0\0\0\0", +"canal\0\0\0", +"cancel\0\0", +"candy\0\0\0", +"cannon\0\0", +"canoe\0\0\0", +"canvas\0\0", +"canyon\0\0", +"capable\0", +"capital\0", +"captain\0", +"car\0\0\0\0\0", +"carbon\0\0", +"card\0\0\0\0", +"cargo\0\0\0", +"carpet\0\0", +"carry\0\0\0", +"cart\0\0\0\0", +"case\0\0\0\0", +"cash\0\0\0\0", +"casino\0\0", +"castle\0\0", +"casual\0\0", +"cat\0\0\0\0\0", +"catalog\0", +"catch\0\0\0", +"category", +"cattle\0\0", +"caught\0\0", +"cause\0\0\0", +"caution\0", +"cave\0\0\0\0", +"ceiling\0", +"celery\0\0", +"cement\0\0", +"census\0\0", +"century\0", +"cereal\0\0", +"certain\0", +"chair\0\0\0", +"chalk\0\0\0", +"champion", +"change\0\0", +"chaos\0\0\0", +"chapter\0", +"charge\0\0", +"chase\0\0\0", +"chat\0\0\0\0", +"cheap\0\0\0", +"check\0\0\0", +"cheese\0\0", +"chef\0\0\0\0", +"cherry\0\0", +"chest\0\0\0", +"chicken\0", +"chief\0\0\0", +"child\0\0\0", +"chimney\0", +"choice\0\0", +"choose\0\0", +"chronic\0", +"chuckle\0", +"chunk\0\0\0", +"churn\0\0\0", +"cigar\0\0\0", +"cinnamon", +"circle\0\0", +"citizen\0", +"city\0\0\0\0", +"civil\0\0\0", +"claim\0\0\0", +"clap\0\0\0\0", +"clarify\0", +"claw\0\0\0\0", +"clay\0\0\0\0", +"clean\0\0\0", +"clerk\0\0\0", +"clever\0\0", +"click\0\0\0", +"client\0\0", +"cliff\0\0\0", +"climb\0\0\0", +"clinic\0\0", +"clip\0\0\0\0", +"clock\0\0\0", +"clog\0\0\0\0", +"close\0\0\0", +"cloth\0\0\0", +"cloud\0\0\0", +"clown\0\0\0", +"club\0\0\0\0", +"clump\0\0\0", +"cluster\0", +"clutch\0\0", +"coach\0\0\0", +"coast\0\0\0", +"coconut\0", +"code\0\0\0\0", +"coffee\0\0", +"coil\0\0\0\0", +"coin\0\0\0\0", +"collect\0", +"color\0\0\0", +"column\0\0", +"combine\0", +"come\0\0\0\0", +"comfort\0", +"comic\0\0\0", +"common\0\0", +"company\0", +"concert\0", +"conduct\0", +"confirm\0", +"congress", +"connect\0", +"consider", +"control\0", +"convince", +"cook\0\0\0\0", +"cool\0\0\0\0", +"copper\0\0", +"copy\0\0\0\0", +"coral\0\0\0", +"core\0\0\0\0", +"corn\0\0\0\0", +"correct\0", +"cost\0\0\0\0", +"cotton\0\0", +"couch\0\0\0", +"country\0", +"couple\0\0", +"course\0\0", +"cousin\0\0", +"cover\0\0\0", +"coyote\0\0", +"crack\0\0\0", +"cradle\0\0", +"craft\0\0\0", +"cram\0\0\0\0", +"crane\0\0\0", +"crash\0\0\0", +"crater\0\0", +"crawl\0\0\0", +"crazy\0\0\0", +"cream\0\0\0", +"credit\0\0", +"creek\0\0\0", +"crew\0\0\0\0", +"cricket\0", +"crime\0\0\0", +"crisp\0\0\0", +"critic\0\0", +"crop\0\0\0\0", +"cross\0\0\0", +"crouch\0\0", +"crowd\0\0\0", +"crucial\0", +"cruel\0\0\0", +"cruise\0\0", +"crumble\0", +"crunch\0\0", +"crush\0\0\0", +"cry\0\0\0\0\0", +"crystal\0", +"cube\0\0\0\0", +"culture\0", +"cup\0\0\0\0\0", +"cupboard", +"curious\0", +"current\0", +"curtain\0", +"curve\0\0\0", +"cushion\0", +"custom\0\0", +"cute\0\0\0\0", +"cycle\0\0\0", +"dad\0\0\0\0\0", +"damage\0\0", +"damp\0\0\0\0", +"dance\0\0\0", +"danger\0\0", +"daring\0\0", +"dash\0\0\0\0", +"daughter", +"dawn\0\0\0\0", +"day\0\0\0\0\0", +"deal\0\0\0\0", +"debate\0\0", +"debris\0\0", +"decade\0\0", +"december", +"decide\0\0", +"decline\0", +"decorate", +"decrease", +"deer\0\0\0\0", +"defense\0", +"define\0\0", +"defy\0\0\0\0", +"degree\0\0", +"delay\0\0\0", +"deliver\0", +"demand\0\0", +"demise\0\0", +"denial\0\0", +"dentist\0", +"deny\0\0\0\0", +"depart\0\0", +"depend\0\0", +"deposit\0", +"depth\0\0\0", +"deputy\0\0", +"derive\0\0", +"describe", +"desert\0\0", +"design\0\0", +"desk\0\0\0\0", +"despair\0", +"destroy\0", +"detail\0\0", +"detect\0\0", +"develop\0", +"device\0\0", +"devote\0\0", +"diagram\0", +"dial\0\0\0\0", +"diamond\0", +"diary\0\0\0", +"dice\0\0\0\0", +"diesel\0\0", +"diet\0\0\0\0", +"differ\0\0", +"digital\0", +"dignity\0", +"dilemma\0", +"dinner\0\0", +"dinosaur", +"direct\0\0", +"dirt\0\0\0\0", +"disagree", +"discover", +"disease\0", +"dish\0\0\0\0", +"dismiss\0", +"disorder", +"display\0", +"distance", +"divert\0\0", +"divide\0\0", +"divorce\0", +"dizzy\0\0\0", +"doctor\0\0", +"document", +"dog\0\0\0\0\0", +"doll\0\0\0\0", +"dolphin\0", +"domain\0\0", +"donate\0\0", +"donkey\0\0", +"donor\0\0\0", +"door\0\0\0\0", +"dose\0\0\0\0", +"double\0\0", +"dove\0\0\0\0", +"draft\0\0\0", +"dragon\0\0", +"drama\0\0\0", +"drastic\0", +"draw\0\0\0\0", +"dream\0\0\0", +"dress\0\0\0", +"drift\0\0\0", +"drill\0\0\0", +"drink\0\0\0", +"drip\0\0\0\0", +"drive\0\0\0", +"drop\0\0\0\0", +"drum\0\0\0\0", +"dry\0\0\0\0\0", +"duck\0\0\0\0", +"dumb\0\0\0\0", +"dune\0\0\0\0", +"during\0\0", +"dust\0\0\0\0", +"dutch\0\0\0", +"duty\0\0\0\0", +"dwarf\0\0\0", +"dynamic\0", +"eager\0\0\0", +"eagle\0\0\0", +"early\0\0\0", +"earn\0\0\0\0", +"earth\0\0\0", +"easily\0\0", +"east\0\0\0\0", +"easy\0\0\0\0", +"echo\0\0\0\0", +"ecology\0", +"economy\0", +"edge\0\0\0\0", +"edit\0\0\0\0", +"educate\0", +"effort\0\0", +"egg\0\0\0\0\0", +"eight\0\0\0", +"either\0\0", +"elbow\0\0\0", +"elder\0\0\0", +"electric", +"elegant\0", +"element\0", +"elephant", +"elevator", +"elite\0\0\0", +"else\0\0\0\0", +"embark\0\0", +"embody\0\0", +"embrace\0", +"emerge\0\0", +"emotion\0", +"employ\0\0", +"empower\0", +"empty\0\0\0", +"enable\0\0", +"enact\0\0\0", +"end\0\0\0\0\0", +"endless\0", +"endorse\0", +"enemy\0\0\0", +"energy\0\0", +"enforce\0", +"engage\0\0", +"engine\0\0", +"enhance\0", +"enjoy\0\0\0", +"enlist\0\0", +"enough\0\0", +"enrich\0\0", +"enroll\0\0", +"ensure\0\0", +"enter\0\0\0", +"entire\0\0", +"entry\0\0\0", +"envelope", +"episode\0", +"equal\0\0\0", +"equip\0\0\0", +"era\0\0\0\0\0", +"erase\0\0\0", +"erode\0\0\0", +"erosion\0", +"error\0\0\0", +"erupt\0\0\0", +"escape\0\0", +"essay\0\0\0", +"essence\0", +"estate\0\0", +"eternal\0", +"ethics\0\0", +"evidence", +"evil\0\0\0\0", +"evoke\0\0\0", +"evolve\0\0", +"exact\0\0\0", +"example\0", +"excess\0\0", +"exchange", +"excite\0\0", +"exclude\0", +"excuse\0\0", +"execute\0", +"exercise", +"exhaust\0", +"exhibit\0", +"exile\0\0\0", +"exist\0\0\0", +"exit\0\0\0\0", +"exotic\0\0", +"expand\0\0", +"expect\0\0", +"expire\0\0", +"explain\0", +"expose\0\0", +"express\0", +"extend\0\0", +"extra\0\0\0", +"eye\0\0\0\0\0", +"eyebrow\0", +"fabric\0\0", +"face\0\0\0\0", +"faculty\0", +"fade\0\0\0\0", +"faint\0\0\0", +"faith\0\0\0", +"fall\0\0\0\0", +"false\0\0\0", +"fame\0\0\0\0", +"family\0\0", +"famous\0\0", +"fan\0\0\0\0\0", +"fancy\0\0\0", +"fantasy\0", +"farm\0\0\0\0", +"fashion\0", +"fat\0\0\0\0\0", +"fatal\0\0\0", +"father\0\0", +"fatigue\0", +"fault\0\0\0", +"favorite", +"feature\0", +"february", +"federal\0", +"fee\0\0\0\0\0", +"feed\0\0\0\0", +"feel\0\0\0\0", +"female\0\0", +"fence\0\0\0", +"festival", +"fetch\0\0\0", +"fever\0\0\0", +"few\0\0\0\0\0", +"fiber\0\0\0", +"fiction\0", +"field\0\0\0", +"figure\0\0", +"file\0\0\0\0", +"film\0\0\0\0", +"filter\0\0", +"final\0\0\0", +"find\0\0\0\0", +"fine\0\0\0\0", +"finger\0\0", +"finish\0\0", +"fire\0\0\0\0", +"firm\0\0\0\0", +"first\0\0\0", +"fiscal\0\0", +"fish\0\0\0\0", +"fit\0\0\0\0\0", +"fitness\0", +"fix\0\0\0\0\0", +"flag\0\0\0\0", +"flame\0\0\0", +"flash\0\0\0", +"flat\0\0\0\0", +"flavor\0\0", +"flee\0\0\0\0", +"flight\0\0", +"flip\0\0\0\0", +"float\0\0\0", +"flock\0\0\0", +"floor\0\0\0", +"flower\0\0", +"fluid\0\0\0", +"flush\0\0\0", +"fly\0\0\0\0\0", +"foam\0\0\0\0", +"focus\0\0\0", +"fog\0\0\0\0\0", +"foil\0\0\0\0", +"fold\0\0\0\0", +"follow\0\0", +"food\0\0\0\0", +"foot\0\0\0\0", +"force\0\0\0", +"forest\0\0", +"forget\0\0", +"fork\0\0\0\0", +"fortune\0", +"forum\0\0\0", +"forward\0", +"fossil\0\0", +"foster\0\0", +"found\0\0\0", +"fox\0\0\0\0\0", +"fragile\0", +"frame\0\0\0", +"frequent", +"fresh\0\0\0", +"friend\0\0", +"fringe\0\0", +"frog\0\0\0\0", +"front\0\0\0", +"frost\0\0\0", +"frown\0\0\0", +"frozen\0\0", +"fruit\0\0\0", +"fuel\0\0\0\0", +"fun\0\0\0\0\0", +"funny\0\0\0", +"furnace\0", +"fury\0\0\0\0", +"future\0\0", +"gadget\0\0", +"gain\0\0\0\0", +"galaxy\0\0", +"gallery\0", +"game\0\0\0\0", +"gap\0\0\0\0\0", +"garage\0\0", +"garbage\0", +"garden\0\0", +"garlic\0\0", +"garment\0", +"gas\0\0\0\0\0", +"gasp\0\0\0\0", +"gate\0\0\0\0", +"gather\0\0", +"gauge\0\0\0", +"gaze\0\0\0\0", +"general\0", +"genius\0\0", +"genre\0\0\0", +"gentle\0\0", +"genuine\0", +"gesture\0", +"ghost\0\0\0", +"giant\0\0\0", +"gift\0\0\0\0", +"giggle\0\0", +"ginger\0\0", +"giraffe\0", +"girl\0\0\0\0", +"give\0\0\0\0", +"glad\0\0\0\0", +"glance\0\0", +"glare\0\0\0", +"glass\0\0\0", +"glide\0\0\0", +"glimpse\0", +"globe\0\0\0", +"gloom\0\0\0", +"glory\0\0\0", +"glove\0\0\0", +"glow\0\0\0\0", +"glue\0\0\0\0", +"goat\0\0\0\0", +"goddess\0", +"gold\0\0\0\0", +"good\0\0\0\0", +"goose\0\0\0", +"gorilla\0", +"gospel\0\0", +"gossip\0\0", +"govern\0\0", +"gown\0\0\0\0", +"grab\0\0\0\0", +"grace\0\0\0", +"grain\0\0\0", +"grant\0\0\0", +"grape\0\0\0", +"grass\0\0\0", +"gravity\0", +"great\0\0\0", +"green\0\0\0", +"grid\0\0\0\0", +"grief\0\0\0", +"grit\0\0\0\0", +"grocery\0", +"group\0\0\0", +"grow\0\0\0\0", +"grunt\0\0\0", +"guard\0\0\0", +"guess\0\0\0", +"guide\0\0\0", +"guilt\0\0\0", +"guitar\0\0", +"gun\0\0\0\0\0", +"gym\0\0\0\0\0", +"habit\0\0\0", +"hair\0\0\0\0", +"half\0\0\0\0", +"hammer\0\0", +"hamster\0", +"hand\0\0\0\0", +"happy\0\0\0", +"harbor\0\0", +"hard\0\0\0\0", +"harsh\0\0\0", +"harvest\0", +"hat\0\0\0\0\0", +"have\0\0\0\0", +"hawk\0\0\0\0", +"hazard\0\0", +"head\0\0\0\0", +"health\0\0", +"heart\0\0\0", +"heavy\0\0\0", +"hedgehog", +"height\0\0", +"hello\0\0\0", +"helmet\0\0", +"help\0\0\0\0", +"hen\0\0\0\0\0", +"hero\0\0\0\0", +"hidden\0\0", +"high\0\0\0\0", +"hill\0\0\0\0", +"hint\0\0\0\0", +"hip\0\0\0\0\0", +"hire\0\0\0\0", +"history\0", +"hobby\0\0\0", +"hockey\0\0", +"hold\0\0\0\0", +"hole\0\0\0\0", +"holiday\0", +"hollow\0\0", +"home\0\0\0\0", +"honey\0\0\0", +"hood\0\0\0\0", +"hope\0\0\0\0", +"horn\0\0\0\0", +"horror\0\0", +"horse\0\0\0", +"hospital", +"host\0\0\0\0", +"hotel\0\0\0", +"hour\0\0\0\0", +"hover\0\0\0", +"hub\0\0\0\0\0", +"huge\0\0\0\0", +"human\0\0\0", +"humble\0\0", +"humor\0\0\0", +"hundred\0", +"hungry\0\0", +"hunt\0\0\0\0", +"hurdle\0\0", +"hurry\0\0\0", +"hurt\0\0\0\0", +"husband\0", +"hybrid\0\0", +"ice\0\0\0\0\0", +"icon\0\0\0\0", +"idea\0\0\0\0", +"identify", +"idle\0\0\0\0", +"ignore\0\0", +"ill\0\0\0\0\0", +"illegal\0", +"illness\0", +"image\0\0\0", +"imitate\0", +"immense\0", +"immune\0\0", +"impact\0\0", +"impose\0\0", +"improve\0", +"impulse\0", +"inch\0\0\0\0", +"include\0", +"income\0\0", +"increase", +"index\0\0\0", +"indicate", +"indoor\0\0", +"industry", +"infant\0\0", +"inflict\0", +"inform\0\0", +"inhale\0\0", +"inherit\0", +"initial\0", +"inject\0\0", +"injury\0\0", +"inmate\0\0", +"inner\0\0\0", +"innocent", +"input\0\0\0", +"inquiry\0", +"insane\0\0", +"insect\0\0", +"inside\0\0", +"inspire\0", +"install\0", +"intact\0\0", +"interest", +"into\0\0\0\0", +"invest\0\0", +"invite\0\0", +"involve\0", +"iron\0\0\0\0", +"island\0\0", +"isolate\0", +"issue\0\0\0", +"item\0\0\0\0", +"ivory\0\0\0", +"jacket\0\0", +"jaguar\0\0", +"jar\0\0\0\0\0", +"jazz\0\0\0\0", +"jealous\0", +"jeans\0\0\0", +"jelly\0\0\0", +"jewel\0\0\0", +"job\0\0\0\0\0", +"join\0\0\0\0", +"joke\0\0\0\0", +"journey\0", +"joy\0\0\0\0\0", +"judge\0\0\0", +"juice\0\0\0", +"jump\0\0\0\0", +"jungle\0\0", +"junior\0\0", +"junk\0\0\0\0", +"just\0\0\0\0", +"kangaroo", +"keen\0\0\0\0", +"keep\0\0\0\0", +"ketchup\0", +"key\0\0\0\0\0", +"kick\0\0\0\0", +"kid\0\0\0\0\0", +"kidney\0\0", +"kind\0\0\0\0", +"kingdom\0", +"kiss\0\0\0\0", +"kit\0\0\0\0\0", +"kitchen\0", +"kite\0\0\0\0", +"kitten\0\0", +"kiwi\0\0\0\0", +"knee\0\0\0\0", +"knife\0\0\0", +"knock\0\0\0", +"know\0\0\0\0", +"lab\0\0\0\0\0", +"label\0\0\0", +"labor\0\0\0", +"ladder\0\0", +"lady\0\0\0\0", +"lake\0\0\0\0", +"lamp\0\0\0\0", +"language", +"laptop\0\0", +"large\0\0\0", +"later\0\0\0", +"latin\0\0\0", +"laugh\0\0\0", +"laundry\0", +"lava\0\0\0\0", +"law\0\0\0\0\0", +"lawn\0\0\0\0", +"lawsuit\0", +"layer\0\0\0", +"lazy\0\0\0\0", +"leader\0\0", +"leaf\0\0\0\0", +"learn\0\0\0", +"leave\0\0\0", +"lecture\0", +"left\0\0\0\0", +"leg\0\0\0\0\0", +"legal\0\0\0", +"legend\0\0", +"leisure\0", +"lemon\0\0\0", +"lend\0\0\0\0", +"length\0\0", +"lens\0\0\0\0", +"leopard\0", +"lesson\0\0", +"letter\0\0", +"level\0\0\0", +"liar\0\0\0\0", +"liberty\0", +"library\0", +"license\0", +"life\0\0\0\0", +"lift\0\0\0\0", +"light\0\0\0", +"like\0\0\0\0", +"limb\0\0\0\0", +"limit\0\0\0", +"link\0\0\0\0", +"lion\0\0\0\0", +"liquid\0\0", +"list\0\0\0\0", +"little\0\0", +"live\0\0\0\0", +"lizard\0\0", +"load\0\0\0\0", +"loan\0\0\0\0", +"lobster\0", +"local\0\0\0", +"lock\0\0\0\0", +"logic\0\0\0", +"lonely\0\0", +"long\0\0\0\0", +"loop\0\0\0\0", +"lottery\0", +"loud\0\0\0\0", +"lounge\0\0", +"love\0\0\0\0", +"loyal\0\0\0", +"lucky\0\0\0", +"luggage\0", +"lumber\0\0", +"lunar\0\0\0", +"lunch\0\0\0", +"luxury\0\0", +"lyrics\0\0", +"machine\0", +"mad\0\0\0\0\0", +"magic\0\0\0", +"magnet\0\0", +"maid\0\0\0\0", +"mail\0\0\0\0", +"main\0\0\0\0", +"major\0\0\0", +"make\0\0\0\0", +"mammal\0\0", +"man\0\0\0\0\0", +"manage\0\0", +"mandate\0", +"mango\0\0\0", +"mansion\0", +"manual\0\0", +"maple\0\0\0", +"marble\0\0", +"march\0\0\0", +"margin\0\0", +"marine\0\0", +"market\0\0", +"marriage", +"mask\0\0\0\0", +"mass\0\0\0\0", +"master\0\0", +"match\0\0\0", +"material", +"math\0\0\0\0", +"matrix\0\0", +"matter\0\0", +"maximum\0", +"maze\0\0\0\0", +"meadow\0\0", +"mean\0\0\0\0", +"measure\0", +"meat\0\0\0\0", +"mechanic", +"medal\0\0\0", +"media\0\0\0", +"melody\0\0", +"melt\0\0\0\0", +"member\0\0", +"memory\0\0", +"mention\0", +"menu\0\0\0\0", +"mercy\0\0\0", +"merge\0\0\0", +"merit\0\0\0", +"merry\0\0\0", +"mesh\0\0\0\0", +"message\0", +"metal\0\0\0", +"method\0\0", +"middle\0\0", +"midnight", +"milk\0\0\0\0", +"million\0", +"mimic\0\0\0", +"mind\0\0\0\0", +"minimum\0", +"minor\0\0\0", +"minute\0\0", +"miracle\0", +"mirror\0\0", +"misery\0\0", +"miss\0\0\0\0", +"mistake\0", +"mix\0\0\0\0\0", +"mixed\0\0\0", +"mixture\0", +"mobile\0\0", +"model\0\0\0", +"modify\0\0", +"mom\0\0\0\0\0", +"moment\0\0", +"monitor\0", +"monkey\0\0", +"monster\0", +"month\0\0\0", +"moon\0\0\0\0", +"moral\0\0\0", +"more\0\0\0\0", +"morning\0", +"mosquito", +"mother\0\0", +"motion\0\0", +"motor\0\0\0", +"mountain", +"mouse\0\0\0", +"move\0\0\0\0", +"movie\0\0\0", +"much\0\0\0\0", +"muffin\0\0", +"mule\0\0\0\0", +"multiply", +"muscle\0\0", +"museum\0\0", +"mushroom", +"music\0\0\0", +"must\0\0\0\0", +"mutual\0\0", +"myself\0\0", +"mystery\0", +"myth\0\0\0\0", +"naive\0\0\0", +"name\0\0\0\0", +"napkin\0\0", +"narrow\0\0", +"nasty\0\0\0", +"nation\0\0", +"nature\0\0", +"near\0\0\0\0", +"neck\0\0\0\0", +"need\0\0\0\0", +"negative", +"neglect\0", +"neither\0", +"nephew\0\0", +"nerve\0\0\0", +"nest\0\0\0\0", +"net\0\0\0\0\0", +"network\0", +"neutral\0", +"never\0\0\0", +"news\0\0\0\0", +"next\0\0\0\0", +"nice\0\0\0\0", +"night\0\0\0", +"noble\0\0\0", +"noise\0\0\0", +"nominee\0", +"noodle\0\0", +"normal\0\0", +"north\0\0\0", +"nose\0\0\0\0", +"notable\0", +"note\0\0\0\0", +"nothing\0", +"notice\0\0", +"novel\0\0\0", +"now\0\0\0\0\0", +"nuclear\0", +"number\0\0", +"nurse\0\0\0", +"nut\0\0\0\0\0", +"oak\0\0\0\0\0", +"obey\0\0\0\0", +"object\0\0", +"oblige\0\0", +"obscure\0", +"observe\0", +"obtain\0\0", +"obvious\0", +"occur\0\0\0", +"ocean\0\0\0", +"october\0", +"odor\0\0\0\0", +"off\0\0\0\0\0", +"offer\0\0\0", +"office\0\0", +"often\0\0\0", +"oil\0\0\0\0\0", +"okay\0\0\0\0", +"old\0\0\0\0\0", +"olive\0\0\0", +"olympic\0", +"omit\0\0\0\0", +"once\0\0\0\0", +"one\0\0\0\0\0", +"onion\0\0\0", +"online\0\0", +"only\0\0\0\0", +"open\0\0\0\0", +"opera\0\0\0", +"opinion\0", +"oppose\0\0", +"option\0\0", +"orange\0\0", +"orbit\0\0\0", +"orchard\0", +"order\0\0\0", +"ordinary", +"organ\0\0\0", +"orient\0\0", +"original", +"orphan\0\0", +"ostrich\0", +"other\0\0\0", +"outdoor\0", +"outer\0\0\0", +"output\0\0", +"outside\0", +"oval\0\0\0\0", +"oven\0\0\0\0", +"over\0\0\0\0", +"own\0\0\0\0\0", +"owner\0\0\0", +"oxygen\0\0", +"oyster\0\0", +"ozone\0\0\0", +"pact\0\0\0\0", +"paddle\0\0", +"page\0\0\0\0", +"pair\0\0\0\0", +"palace\0\0", +"palm\0\0\0\0", +"panda\0\0\0", +"panel\0\0\0", +"panic\0\0\0", +"panther\0", +"paper\0\0\0", +"parade\0\0", +"parent\0\0", +"park\0\0\0\0", +"parrot\0\0", +"party\0\0\0", +"pass\0\0\0\0", +"patch\0\0\0", +"path\0\0\0\0", +"patient\0", +"patrol\0\0", +"pattern\0", +"pause\0\0\0", +"pave\0\0\0\0", +"payment\0", +"peace\0\0\0", +"peanut\0\0", +"pear\0\0\0\0", +"peasant\0", +"pelican\0", +"pen\0\0\0\0\0", +"penalty\0", +"pencil\0\0", +"people\0\0", +"pepper\0\0", +"perfect\0", +"permit\0\0", +"person\0\0", +"pet\0\0\0\0\0", +"phone\0\0\0", +"photo\0\0\0", +"phrase\0\0", +"physical", +"piano\0\0\0", +"picnic\0\0", +"picture\0", +"piece\0\0\0", +"pig\0\0\0\0\0", +"pigeon\0\0", +"pill\0\0\0\0", +"pilot\0\0\0", +"pink\0\0\0\0", +"pioneer\0", +"pipe\0\0\0\0", +"pistol\0\0", +"pitch\0\0\0", +"pizza\0\0\0", +"place\0\0\0", +"planet\0\0", +"plastic\0", +"plate\0\0\0", +"play\0\0\0\0", +"please\0\0", +"pledge\0\0", +"pluck\0\0\0", +"plug\0\0\0\0", +"plunge\0\0", +"poem\0\0\0\0", +"poet\0\0\0\0", +"point\0\0\0", +"polar\0\0\0", +"pole\0\0\0\0", +"police\0\0", +"pond\0\0\0\0", +"pony\0\0\0\0", +"pool\0\0\0\0", +"popular\0", +"portion\0", +"position", +"possible", +"post\0\0\0\0", +"potato\0\0", +"pottery\0", +"poverty\0", +"powder\0\0", +"power\0\0\0", +"practice", +"praise\0\0", +"predict\0", +"prefer\0\0", +"prepare\0", +"present\0", +"pretty\0\0", +"prevent\0", +"price\0\0\0", +"pride\0\0\0", +"primary\0", +"print\0\0\0", +"priority", +"prison\0\0", +"private\0", +"prize\0\0\0", +"problem\0", +"process\0", +"produce\0", +"profit\0\0", +"program\0", +"project\0", +"promote\0", +"proof\0\0\0", +"property", +"prosper\0", +"protect\0", +"proud\0\0\0", +"provide\0", +"public\0\0", +"pudding\0", +"pull\0\0\0\0", +"pulp\0\0\0\0", +"pulse\0\0\0", +"pumpkin\0", +"punch\0\0\0", +"pupil\0\0\0", +"puppy\0\0\0", +"purchase", +"purity\0\0", +"purpose\0", +"purse\0\0\0", +"push\0\0\0\0", +"put\0\0\0\0\0", +"puzzle\0\0", +"pyramid\0", +"quality\0", +"quantum\0", +"quarter\0", +"question", +"quick\0\0\0", +"quit\0\0\0\0", +"quiz\0\0\0\0", +"quote\0\0\0", +"rabbit\0\0", +"raccoon\0", +"race\0\0\0\0", +"rack\0\0\0\0", +"radar\0\0\0", +"radio\0\0\0", +"rail\0\0\0\0", +"rain\0\0\0\0", +"raise\0\0\0", +"rally\0\0\0", +"ramp\0\0\0\0", +"ranch\0\0\0", +"random\0\0", +"range\0\0\0", +"rapid\0\0\0", +"rare\0\0\0\0", +"rate\0\0\0\0", +"rather\0\0", +"raven\0\0\0", +"raw\0\0\0\0\0", +"razor\0\0\0", +"ready\0\0\0", +"real\0\0\0\0", +"reason\0\0", +"rebel\0\0\0", +"rebuild\0", +"recall\0\0", +"receive\0", +"recipe\0\0", +"record\0\0", +"recycle\0", +"reduce\0\0", +"reflect\0", +"reform\0\0", +"refuse\0\0", +"region\0\0", +"regret\0\0", +"regular\0", +"reject\0\0", +"relax\0\0\0", +"release\0", +"relief\0\0", +"rely\0\0\0\0", +"remain\0\0", +"remember", +"remind\0\0", +"remove\0\0", +"render\0\0", +"renew\0\0\0", +"rent\0\0\0\0", +"reopen\0\0", +"repair\0\0", +"repeat\0\0", +"replace\0", +"report\0\0", +"require\0", +"rescue\0\0", +"resemble", +"resist\0\0", +"resource", +"response", +"result\0\0", +"retire\0\0", +"retreat\0", +"return\0\0", +"reunion\0", +"reveal\0\0", +"review\0\0", +"reward\0\0", +"rhythm\0\0", +"rib\0\0\0\0\0", +"ribbon\0\0", +"rice\0\0\0\0", +"rich\0\0\0\0", +"ride\0\0\0\0", +"ridge\0\0\0", +"rifle\0\0\0", +"right\0\0\0", +"rigid\0\0\0", +"ring\0\0\0\0", +"riot\0\0\0\0", +"ripple\0\0", +"risk\0\0\0\0", +"ritual\0\0", +"rival\0\0\0", +"river\0\0\0", +"road\0\0\0\0", +"roast\0\0\0", +"robot\0\0\0", +"robust\0\0", +"rocket\0\0", +"romance\0", +"roof\0\0\0\0", +"rookie\0\0", +"room\0\0\0\0", +"rose\0\0\0\0", +"rotate\0\0", +"rough\0\0\0", +"round\0\0\0", +"route\0\0\0", +"royal\0\0\0", +"rubber\0\0", +"rude\0\0\0\0", +"rug\0\0\0\0\0", +"rule\0\0\0\0", +"run\0\0\0\0\0", +"runway\0\0", +"rural\0\0\0", +"sad\0\0\0\0\0", +"saddle\0\0", +"sadness\0", +"safe\0\0\0\0", +"sail\0\0\0\0", +"salad\0\0\0", +"salmon\0\0", +"salon\0\0\0", +"salt\0\0\0\0", +"salute\0\0", +"same\0\0\0\0", +"sample\0\0", +"sand\0\0\0\0", +"satisfy\0", +"satoshi\0", +"sauce\0\0\0", +"sausage\0", +"save\0\0\0\0", +"say\0\0\0\0\0", +"scale\0\0\0", +"scan\0\0\0\0", +"scare\0\0\0", +"scatter\0", +"scene\0\0\0", +"scheme\0\0", +"school\0\0", +"science\0", +"scissors", +"scorpion", +"scout\0\0\0", +"scrap\0\0\0", +"screen\0\0", +"script\0\0", +"scrub\0\0\0", +"sea\0\0\0\0\0", +"search\0\0", +"season\0\0", +"seat\0\0\0\0", +"second\0\0", +"secret\0\0", +"section\0", +"security", +"seed\0\0\0\0", +"seek\0\0\0\0", +"segment\0", +"select\0\0", +"sell\0\0\0\0", +"seminar\0", +"senior\0\0", +"sense\0\0\0", +"sentence", +"series\0\0", +"service\0", +"session\0", +"settle\0\0", +"setup\0\0\0", +"seven\0\0\0", +"shadow\0\0", +"shaft\0\0\0", +"shallow\0", +"share\0\0\0", +"shed\0\0\0\0", +"shell\0\0\0", +"sheriff\0", +"shield\0\0", +"shift\0\0\0", +"shine\0\0\0", +"ship\0\0\0\0", +"shiver\0\0", +"shock\0\0\0", +"shoe\0\0\0\0", +"shoot\0\0\0", +"shop\0\0\0\0", +"short\0\0\0", +"shoulder", +"shove\0\0\0", +"shrimp\0\0", +"shrug\0\0\0", +"shuffle\0", +"shy\0\0\0\0\0", +"sibling\0", +"sick\0\0\0\0", +"side\0\0\0\0", +"siege\0\0\0", +"sight\0\0\0", +"sign\0\0\0\0", +"silent\0\0", +"silk\0\0\0\0", +"silly\0\0\0", +"silver\0\0", +"similar\0", +"simple\0\0", +"since\0\0\0", +"sing\0\0\0\0", +"siren\0\0\0", +"sister\0\0", +"situate\0", +"six\0\0\0\0\0", +"size\0\0\0\0", +"skate\0\0\0", +"sketch\0\0", +"ski\0\0\0\0\0", +"skill\0\0\0", +"skin\0\0\0\0", +"skirt\0\0\0", +"skull\0\0\0", +"slab\0\0\0\0", +"slam\0\0\0\0", +"sleep\0\0\0", +"slender\0", +"slice\0\0\0", +"slide\0\0\0", +"slight\0\0", +"slim\0\0\0\0", +"slogan\0\0", +"slot\0\0\0\0", +"slow\0\0\0\0", +"slush\0\0\0", +"small\0\0\0", +"smart\0\0\0", +"smile\0\0\0", +"smoke\0\0\0", +"smooth\0\0", +"snack\0\0\0", +"snake\0\0\0", +"snap\0\0\0\0", +"sniff\0\0\0", +"snow\0\0\0\0", +"soap\0\0\0\0", +"soccer\0\0", +"social\0\0", +"sock\0\0\0\0", +"soda\0\0\0\0", +"soft\0\0\0\0", +"solar\0\0\0", +"soldier\0", +"solid\0\0\0", +"solution", +"solve\0\0\0", +"someone\0", +"song\0\0\0\0", +"soon\0\0\0\0", +"sorry\0\0\0", +"sort\0\0\0\0", +"soul\0\0\0\0", +"sound\0\0\0", +"soup\0\0\0\0", +"source\0\0", +"south\0\0\0", +"space\0\0\0", +"spare\0\0\0", +"spatial\0", +"spawn\0\0\0", +"speak\0\0\0", +"special\0", +"speed\0\0\0", +"spell\0\0\0", +"spend\0\0\0", +"sphere\0\0", +"spice\0\0\0", +"spider\0\0", +"spike\0\0\0", +"spin\0\0\0\0", +"spirit\0\0", +"split\0\0\0", +"spoil\0\0\0", +"sponsor\0", +"spoon\0\0\0", +"sport\0\0\0", +"spot\0\0\0\0", +"spray\0\0\0", +"spread\0\0", +"spring\0\0", +"spy\0\0\0\0\0", +"square\0\0", +"squeeze\0", +"squirrel", +"stable\0\0", +"stadium\0", +"staff\0\0\0", +"stage\0\0\0", +"stairs\0\0", +"stamp\0\0\0", +"stand\0\0\0", +"start\0\0\0", +"state\0\0\0", +"stay\0\0\0\0", +"steak\0\0\0", +"steel\0\0\0", +"stem\0\0\0\0", +"step\0\0\0\0", +"stereo\0\0", +"stick\0\0\0", +"still\0\0\0", +"sting\0\0\0", +"stock\0\0\0", +"stomach\0", +"stone\0\0\0", +"stool\0\0\0", +"story\0\0\0", +"stove\0\0\0", +"strategy", +"street\0\0", +"strike\0\0", +"strong\0\0", +"struggle", +"student\0", +"stuff\0\0\0", +"stumble\0", +"style\0\0\0", +"subject\0", +"submit\0\0", +"subway\0\0", +"success\0", +"such\0\0\0\0", +"sudden\0\0", +"suffer\0\0", +"sugar\0\0\0", +"suggest\0", +"suit\0\0\0\0", +"summer\0\0", +"sun\0\0\0\0\0", +"sunny\0\0\0", +"sunset\0\0", +"super\0\0\0", +"supply\0\0", +"supreme\0", +"sure\0\0\0\0", +"surface\0", +"surge\0\0\0", +"surprise", +"surround", +"survey\0\0", +"suspect\0", +"sustain\0", +"swallow\0", +"swamp\0\0\0", +"swap\0\0\0\0", +"swarm\0\0\0", +"swear\0\0\0", +"sweet\0\0\0", +"swift\0\0\0", +"swim\0\0\0\0", +"swing\0\0\0", +"switch\0\0", +"sword\0\0\0", +"symbol\0\0", +"symptom\0", +"syrup\0\0\0", +"system\0\0", +"table\0\0\0", +"tackle\0\0", +"tag\0\0\0\0\0", +"tail\0\0\0\0", +"talent\0\0", +"talk\0\0\0\0", +"tank\0\0\0\0", +"tape\0\0\0\0", +"target\0\0", +"task\0\0\0\0", +"taste\0\0\0", +"tattoo\0\0", +"taxi\0\0\0\0", +"teach\0\0\0", +"team\0\0\0\0", +"tell\0\0\0\0", +"ten\0\0\0\0\0", +"tenant\0\0", +"tennis\0\0", +"tent\0\0\0\0", +"term\0\0\0\0", +"test\0\0\0\0", +"text\0\0\0\0", +"thank\0\0\0", +"that\0\0\0\0", +"theme\0\0\0", +"then\0\0\0\0", +"theory\0\0", +"there\0\0\0", +"they\0\0\0\0", +"thing\0\0\0", +"this\0\0\0\0", +"thought\0", +"three\0\0\0", +"thrive\0\0", +"throw\0\0\0", +"thumb\0\0\0", +"thunder\0", +"ticket\0\0", +"tide\0\0\0\0", +"tiger\0\0\0", +"tilt\0\0\0\0", +"timber\0\0", +"time\0\0\0\0", +"tiny\0\0\0\0", +"tip\0\0\0\0\0", +"tired\0\0\0", +"tissue\0\0", +"title\0\0\0", +"toast\0\0\0", +"tobacco\0", +"today\0\0\0", +"toddler\0", +"toe\0\0\0\0\0", +"together", +"toilet\0\0", +"token\0\0\0", +"tomato\0\0", +"tomorrow", +"tone\0\0\0\0", +"tongue\0\0", +"tonight\0", +"tool\0\0\0\0", +"tooth\0\0\0", +"top\0\0\0\0\0", +"topic\0\0\0", +"topple\0\0", +"torch\0\0\0", +"tornado\0", +"tortoise", +"toss\0\0\0\0", +"total\0\0\0", +"tourist\0", +"toward\0\0", +"tower\0\0\0", +"town\0\0\0\0", +"toy\0\0\0\0\0", +"track\0\0\0", +"trade\0\0\0", +"traffic\0", +"tragic\0\0", +"train\0\0\0", +"transfer", +"trap\0\0\0\0", +"trash\0\0\0", +"travel\0\0", +"tray\0\0\0\0", +"treat\0\0\0", +"tree\0\0\0\0", +"trend\0\0\0", +"trial\0\0\0", +"tribe\0\0\0", +"trick\0\0\0", +"trigger\0", +"trim\0\0\0\0", +"trip\0\0\0\0", +"trophy\0\0", +"trouble\0", +"truck\0\0\0", +"true\0\0\0\0", +"truly\0\0\0", +"trumpet\0", +"trust\0\0\0", +"truth\0\0\0", +"try\0\0\0\0\0", +"tube\0\0\0\0", +"tuition\0", +"tumble\0\0", +"tuna\0\0\0\0", +"tunnel\0\0", +"turkey\0\0", +"turn\0\0\0\0", +"turtle\0\0", +"twelve\0\0", +"twenty\0\0", +"twice\0\0\0", +"twin\0\0\0\0", +"twist\0\0\0", +"two\0\0\0\0\0", +"type\0\0\0\0", +"typical\0", +"ugly\0\0\0\0", +"umbrella", +"unable\0\0", +"unaware\0", +"uncle\0\0\0", +"uncover\0", +"under\0\0\0", +"undo\0\0\0\0", +"unfair\0\0", +"unfold\0\0", +"unhappy\0", +"uniform\0", +"unique\0\0", +"unit\0\0\0\0", +"universe", +"unknown\0", +"unlock\0\0", +"until\0\0\0", +"unusual\0", +"unveil\0\0", +"update\0\0", +"upgrade\0", +"uphold\0\0", +"upon\0\0\0\0", +"upper\0\0\0", +"upset\0\0\0", +"urban\0\0\0", +"urge\0\0\0\0", +"usage\0\0\0", +"use\0\0\0\0\0", +"used\0\0\0\0", +"useful\0\0", +"useless\0", +"usual\0\0\0", +"utility\0", +"vacant\0\0", +"vacuum\0\0", +"vague\0\0\0", +"valid\0\0\0", +"valley\0\0", +"valve\0\0\0", +"van\0\0\0\0\0", +"vanish\0\0", +"vapor\0\0\0", +"various\0", +"vast\0\0\0\0", +"vault\0\0\0", +"vehicle\0", +"velvet\0\0", +"vendor\0\0", +"venture\0", +"venue\0\0\0", +"verb\0\0\0\0", +"verify\0\0", +"version\0", +"very\0\0\0\0", +"vessel\0\0", +"veteran\0", +"viable\0\0", +"vibrant\0", +"vicious\0", +"victory\0", +"video\0\0\0", +"view\0\0\0\0", +"village\0", +"vintage\0", +"violin\0\0", +"virtual\0", +"virus\0\0\0", +"visa\0\0\0\0", +"visit\0\0\0", +"visual\0\0", +"vital\0\0\0", +"vivid\0\0\0", +"vocal\0\0\0", +"voice\0\0\0", +"void\0\0\0\0", +"volcano\0", +"volume\0\0", +"vote\0\0\0\0", +"voyage\0\0", +"wage\0\0\0\0", +"wagon\0\0\0", +"wait\0\0\0\0", +"walk\0\0\0\0", +"wall\0\0\0\0", +"walnut\0\0", +"want\0\0\0\0", +"warfare\0", +"warm\0\0\0\0", +"warrior\0", +"wash\0\0\0\0", +"wasp\0\0\0\0", +"waste\0\0\0", +"water\0\0\0", +"wave\0\0\0\0", +"way\0\0\0\0\0", +"wealth\0\0", +"weapon\0\0", +"wear\0\0\0\0", +"weasel\0\0", +"weather\0", +"web\0\0\0\0\0", +"wedding\0", +"weekend\0", +"weird\0\0\0", +"welcome\0", +"west\0\0\0\0", +"wet\0\0\0\0\0", +"whale\0\0\0", +"what\0\0\0\0", +"wheat\0\0\0", +"wheel\0\0\0", +"when\0\0\0\0", +"where\0\0\0", +"whip\0\0\0\0", +"whisper\0", +"wide\0\0\0\0", +"width\0\0\0", +"wife\0\0\0\0", +"wild\0\0\0\0", +"will\0\0\0\0", +"win\0\0\0\0\0", +"window\0\0", +"wine\0\0\0\0", +"wing\0\0\0\0", +"wink\0\0\0\0", +"winner\0\0", +"winter\0\0", +"wire\0\0\0\0", +"wisdom\0\0", +"wise\0\0\0\0", +"wish\0\0\0\0", +"witness\0", +"wolf\0\0\0\0", +"woman\0\0\0", +"wonder\0\0", +"wood\0\0\0\0", +"wool\0\0\0\0", +"word\0\0\0\0", +"work\0\0\0\0", +"world\0\0\0", +"worry\0\0\0", +"worth\0\0\0", +"wrap\0\0\0\0", +"wreck\0\0\0", +"wrestle\0", +"wrist\0\0\0", +"write\0\0\0", +"wrong\0\0\0", +"yard\0\0\0\0", +"year\0\0\0\0", +"yellow\0\0", +"you\0\0\0\0\0", +"young\0\0\0", +"youth\0\0\0", +"zebra\0\0\0", +"zero\0\0\0\0", +"zone\0\0\0\0", +"zoo\0\0\0\0\0", +#endif +0, +}; diff --git a/deps/crypto/trezor-crypto/bip39_english.h b/deps/crypto/trezor-crypto/bip39_english.h new file mode 100644 index 000000000..69dc38f59 --- /dev/null +++ b/deps/crypto/trezor-crypto/bip39_english.h @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +extern const char * const wordlist[2048 + 1]; diff --git a/deps/crypto/trezor-crypto/blake256.c b/deps/crypto/trezor-crypto/blake256.c new file mode 100644 index 000000000..a7cb843c1 --- /dev/null +++ b/deps/crypto/trezor-crypto/blake256.c @@ -0,0 +1,234 @@ +/* + BLAKE reference C implementation + + Copyright (c) 2012 Jean-Philippe Aumasson + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along with + this software. If not, see . + */ +#include "blake256.h" + +#include + +#define U8TO32_BIG(p) \ + (((uint32_t)((p)[0]) << 24) | ((uint32_t)((p)[1]) << 16) | \ + ((uint32_t)((p)[2]) << 8) | ((uint32_t)((p)[3]) )) + +#define U32TO8_BIG(p, v) \ + (p)[0] = (uint8_t)((v) >> 24); (p)[1] = (uint8_t)((v) >> 16); \ + (p)[2] = (uint8_t)((v) >> 8); (p)[3] = (uint8_t)((v) ); + +static const uint8_t sigma[][16] = +{ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, + {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 }, + {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 }, + {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 }, + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 }, + {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, + {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } +}; + +static const uint32_t u256[16] = +{ + 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, + 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, + 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, + 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917 +}; + +static const uint8_t padding[129] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static void blake256_compress( BLAKE256_CTX *S, const uint8_t *block ) +{ + uint32_t v[16] = {0}, m[16] = {0}, i = 0; +#define ROT(x,n) (((x)<<(32-n))|( (x)>>(n))) +#define G(a,b,c,d,e) \ + v[a] += (m[sigma[i][e]] ^ u256[sigma[i][e+1]]) + v[b]; \ + v[d] = ROT( v[d] ^ v[a],16); \ + v[c] += v[d]; \ + v[b] = ROT( v[b] ^ v[c],12); \ + v[a] += (m[sigma[i][e+1]] ^ u256[sigma[i][e]])+v[b]; \ + v[d] = ROT( v[d] ^ v[a], 8); \ + v[c] += v[d]; \ + v[b] = ROT( v[b] ^ v[c], 7); + + for( i = 0; i < 16; ++i ) m[i] = U8TO32_BIG( block + i * 4 ); + + for( i = 0; i < 8; ++i ) v[i] = S->h[i]; + + v[ 8] = S->s[0] ^ u256[0]; + v[ 9] = S->s[1] ^ u256[1]; + v[10] = S->s[2] ^ u256[2]; + v[11] = S->s[3] ^ u256[3]; + v[12] = u256[4]; + v[13] = u256[5]; + v[14] = u256[6]; + v[15] = u256[7]; + + /* don't xor t when the block is only padding */ + if ( !S->nullt ) + { + v[12] ^= S->t[0]; + v[13] ^= S->t[0]; + v[14] ^= S->t[1]; + v[15] ^= S->t[1]; + } + + for( i = 0; i < 14; ++i ) + { + /* column step */ + G( 0, 4, 8, 12, 0 ); + G( 1, 5, 9, 13, 2 ); + G( 2, 6, 10, 14, 4 ); + G( 3, 7, 11, 15, 6 ); + /* diagonal step */ + G( 0, 5, 10, 15, 8 ); + G( 1, 6, 11, 12, 10 ); + G( 2, 7, 8, 13, 12 ); + G( 3, 4, 9, 14, 14 ); + } + + for( i = 0; i < 16; ++i ) S->h[i % 8] ^= v[i]; + + for( i = 0; i < 8 ; ++i ) S->h[i] ^= S->s[i % 4]; +} + + +void blake256_Init( BLAKE256_CTX *S ) +{ + S->h[0] = 0x6a09e667; + S->h[1] = 0xbb67ae85; + S->h[2] = 0x3c6ef372; + S->h[3] = 0xa54ff53a; + S->h[4] = 0x510e527f; + S->h[5] = 0x9b05688c; + S->h[6] = 0x1f83d9ab; + S->h[7] = 0x5be0cd19; + S->t[0] = S->t[1] = S->buflen = S->nullt = 0; + S->s[0] = S->s[1] = S->s[2] = S->s[3] = 0; +} + + +void blake256_Update( BLAKE256_CTX *S, const uint8_t *in, size_t inlen ) +{ + size_t left = S->buflen; + size_t fill = 64 - left; + + /* data left and data received fill a block */ + if( left && ( inlen >= fill ) ) + { + memcpy( ( void * ) ( S->buf + left ), ( void * ) in, fill ); + S->t[0] += 512; + + if ( S->t[0] == 0 ) S->t[1]++; + + blake256_compress( S, S->buf ); + in += fill; + inlen -= fill; + left = 0; + } + + /* compress blocks of data received */ + while( inlen >= 64 ) + { + S->t[0] += 512; + + if ( S->t[0] == 0 ) S->t[1]++; + + blake256_compress( S, in ); + in += 64; + inlen -= 64; + } + + /* store any data left */ + if( inlen > 0 ) + { + memcpy( ( void * ) ( S->buf + left ), \ + ( void * ) in, ( size_t ) inlen ); + } + S->buflen = left + inlen; +} + + +void blake256_Final( BLAKE256_CTX *S, uint8_t *out ) +{ + uint8_t msglen[8] = {0}, zo = 0x01, oo = 0x81; + uint32_t lo = S->t[0] + ( S->buflen << 3 ), hi = S->t[1]; + + /* support for hashing more than 2^32 bits */ + if ( lo < ( S->buflen << 3 ) ) hi++; + + U32TO8_BIG( msglen + 0, hi ); + U32TO8_BIG( msglen + 4, lo ); + + if ( S->buflen == 55 ) /* one padding byte */ + { + S->t[0] -= 8; + blake256_Update( S, &oo, 1 ); + } + else + { + if ( S->buflen < 55 ) /* enough space to fill the block */ + { + if ( !S->buflen ) S->nullt = 1; + + S->t[0] -= 440 - ( S->buflen << 3 ); + blake256_Update( S, padding, 55 - S->buflen ); + } + else /* need 2 compressions */ + { + S->t[0] -= 512 - ( S->buflen << 3 ); + blake256_Update( S, padding, 64 - S->buflen ); + S->t[0] -= 440; + blake256_Update( S, padding + 1, 55 ); + S->nullt = 1; + } + + blake256_Update( S, &zo, 1 ); + S->t[0] -= 8; + } + + S->t[0] -= 64; + blake256_Update( S, msglen, 8 ); + U32TO8_BIG( out + 0, S->h[0] ); + U32TO8_BIG( out + 4, S->h[1] ); + U32TO8_BIG( out + 8, S->h[2] ); + U32TO8_BIG( out + 12, S->h[3] ); + U32TO8_BIG( out + 16, S->h[4] ); + U32TO8_BIG( out + 20, S->h[5] ); + U32TO8_BIG( out + 24, S->h[6] ); + U32TO8_BIG( out + 28, S->h[7] ); +} + + +void blake256( const uint8_t *in, size_t inlen, uint8_t *out ) +{ + BLAKE256_CTX S = {0}; + blake256_Init( &S ); + blake256_Update( &S, in, inlen ); + blake256_Final( &S, out ); +} diff --git a/deps/crypto/trezor-crypto/blake256.h b/deps/crypto/trezor-crypto/blake256.h new file mode 100644 index 000000000..2c68ae2ef --- /dev/null +++ b/deps/crypto/trezor-crypto/blake256.h @@ -0,0 +1,53 @@ +// Copyright (c) 2014-2017, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#ifndef __BLAKE256_H__ +#define __BLAKE256_H__ + +#include +#include + +#define BLAKE256_DIGEST_LENGTH 32 +#define BLAKE256_BLOCK_LENGTH 64 + +typedef struct { + uint32_t h[8], s[4], t[2]; + size_t buflen; + uint8_t nullt; + uint8_t buf[64]; +} BLAKE256_CTX; + +void blake256_Init(BLAKE256_CTX *); +void blake256_Update(BLAKE256_CTX *, const uint8_t *, size_t); +void blake256_Final(BLAKE256_CTX *, uint8_t *); + +void blake256(const uint8_t *, size_t, uint8_t *); + +#endif /* __BLAKE256_H__ */ diff --git a/deps/crypto/trezor-crypto/blake2_common.h b/deps/crypto/trezor-crypto/blake2_common.h new file mode 100644 index 000000000..0a7a3ad91 --- /dev/null +++ b/deps/crypto/trezor-crypto/blake2_common.h @@ -0,0 +1,25 @@ +static inline uint32_t load32(const void *src) { + uint32_t w; + memcpy(&w, src, sizeof w); + return w; +} + +static inline uint64_t load64(const void *src) { + uint64_t w; + memcpy(&w, src, sizeof w); + return w; +} + +static inline void store16(void *dst, uint16_t w) { memcpy(dst, &w, sizeof w); } + +static inline void store32(void *dst, uint32_t w) { memcpy(dst, &w, sizeof w); } + +static inline void store64(void *dst, uint64_t w) { memcpy(dst, &w, sizeof w); } + +static inline uint32_t rotr32(const uint32_t w, const unsigned c) { + return (w >> c) | (w << (32 - c)); +} + +static inline uint64_t rotr64(const uint64_t w, const unsigned c) { + return (w >> c) | (w << (64 - c)); +} diff --git a/deps/crypto/trezor-crypto/blake2b.c b/deps/crypto/trezor-crypto/blake2b.c new file mode 100644 index 000000000..f0832c359 --- /dev/null +++ b/deps/crypto/trezor-crypto/blake2b.c @@ -0,0 +1,324 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ + +#include + +#include "blake2b.h" +#include "blake2_common.h" +#include "memzero.h" + +typedef struct blake2b_param__ +{ + uint8_t digest_length; /* 1 */ + uint8_t key_length; /* 2 */ + uint8_t fanout; /* 3 */ + uint8_t depth; /* 4 */ + uint32_t leaf_length; /* 8 */ + uint32_t node_offset; /* 12 */ + uint32_t xof_length; /* 16 */ + uint8_t node_depth; /* 17 */ + uint8_t inner_length; /* 18 */ + uint8_t reserved[14]; /* 32 */ + uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */ + uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */ +} __attribute__((packed)) blake2b_param; + +static const uint64_t blake2b_IV[8] = +{ + 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL +}; + +static const uint8_t blake2b_sigma[12][16] = +{ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } +}; + + +static void blake2b_set_lastnode( blake2b_state *S ) +{ + S->f[1] = (uint64_t)-1; +} + +/* Some helper functions, not necessarily useful */ +static int blake2b_is_lastblock( const blake2b_state *S ) +{ + return S->f[0] != 0; +} + +static void blake2b_set_lastblock( blake2b_state *S ) +{ + if( S->last_node ) blake2b_set_lastnode( S ); + + S->f[0] = (uint64_t)-1; +} + +static void blake2b_increment_counter( blake2b_state *S, const uint64_t inc ) +{ + S->t[0] += inc; + S->t[1] += ( S->t[0] < inc ); +} + +static void blake2b_init0( blake2b_state *S ) +{ + size_t i = 0; + memzero( S, sizeof( blake2b_state ) ); + + for( i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i]; +} + +/* init xors IV with input parameter block */ +int blake2b_init_param( blake2b_state *S, const blake2b_param *P ) +{ + const uint8_t *p = ( const uint8_t * )( P ); + size_t i = 0; + + blake2b_init0( S ); + + /* IV XOR ParamBlock */ + for( i = 0; i < 8; ++i ) + S->h[i] ^= load64( p + sizeof( S->h[i] ) * i ); + + S->outlen = P->digest_length; + return 0; +} + + +/* Sequential blake2b initialization */ +int blake2b_Init( blake2b_state *S, size_t outlen ) +{ + blake2b_param P[1] = {0}; + + if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store32( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + memzero( P->reserved, sizeof( P->reserved ) ); + memzero( P->salt, sizeof( P->salt ) ); + memzero( P->personal, sizeof( P->personal ) ); + return blake2b_init_param( S, P ); +} + +int blake2b_InitPersonal( blake2b_state *S, size_t outlen, const void *personal, size_t personal_len) +{ + blake2b_param P[1] = {0}; + + if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1; + if ( ( !personal ) || ( personal_len != BLAKE2B_PERSONALBYTES ) ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store32( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + memzero( P->reserved, sizeof( P->reserved ) ); + memzero( P->salt, sizeof( P->salt ) ); + memcpy( P->personal, personal, BLAKE2B_PERSONALBYTES ); + return blake2b_init_param( S, P ); +} + +int blake2b_InitKey( blake2b_state *S, size_t outlen, const void *key, size_t keylen ) +{ + blake2b_param P[1] = {0}; + + if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1; + + if ( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = (uint8_t)keylen; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store32( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + memzero( P->reserved, sizeof( P->reserved ) ); + memzero( P->salt, sizeof( P->salt ) ); + memzero( P->personal, sizeof( P->personal ) ); + + if( blake2b_init_param( S, P ) < 0 ) return -1; + + { + uint8_t block[BLAKE2B_BLOCKBYTES] = {0}; + memzero( block, BLAKE2B_BLOCKBYTES ); + memcpy( block, key, keylen ); + blake2b_Update( S, block, BLAKE2B_BLOCKBYTES ); + memzero( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */ + } + return 0; +} + +#define G(r,i,a,b,c,d) \ + do { \ + a = a + b + m[blake2b_sigma[r][2*i+0]]; \ + d = rotr64(d ^ a, 32); \ + c = c + d; \ + b = rotr64(b ^ c, 24); \ + a = a + b + m[blake2b_sigma[r][2*i+1]]; \ + d = rotr64(d ^ a, 16); \ + c = c + d; \ + b = rotr64(b ^ c, 63); \ + } while(0) + +#define ROUND(r) \ + do { \ + G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ + G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ + G(r,2,v[ 2],v[ 6],v[10],v[14]); \ + G(r,3,v[ 3],v[ 7],v[11],v[15]); \ + G(r,4,v[ 0],v[ 5],v[10],v[15]); \ + G(r,5,v[ 1],v[ 6],v[11],v[12]); \ + G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ + G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \ + } while(0) + +static void blake2b_compress( blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES] ) +{ + uint64_t m[16] = {0}; + uint64_t v[16] = {0}; + size_t i = 0; + + for( i = 0; i < 16; ++i ) { + m[i] = load64( block + i * sizeof( m[i] ) ); + } + + for( i = 0; i < 8; ++i ) { + v[i] = S->h[i]; + } + + v[ 8] = blake2b_IV[0]; + v[ 9] = blake2b_IV[1]; + v[10] = blake2b_IV[2]; + v[11] = blake2b_IV[3]; + v[12] = blake2b_IV[4] ^ S->t[0]; + v[13] = blake2b_IV[5] ^ S->t[1]; + v[14] = blake2b_IV[6] ^ S->f[0]; + v[15] = blake2b_IV[7] ^ S->f[1]; + + ROUND( 0 ); + ROUND( 1 ); + ROUND( 2 ); + ROUND( 3 ); + ROUND( 4 ); + ROUND( 5 ); + ROUND( 6 ); + ROUND( 7 ); + ROUND( 8 ); + ROUND( 9 ); + ROUND( 10 ); + ROUND( 11 ); + + for( i = 0; i < 8; ++i ) { + S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; + } +} + +#undef G +#undef ROUND + +int blake2b_Update( blake2b_state *S, const void *pin, size_t inlen ) +{ + const unsigned char * in = (const unsigned char *)pin; + if( inlen > 0 ) + { + size_t left = S->buflen; + size_t fill = BLAKE2B_BLOCKBYTES - left; + if( inlen > fill ) + { + S->buflen = 0; + memcpy( S->buf + left, in, fill ); /* Fill buffer */ + blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES ); + blake2b_compress( S, S->buf ); /* Compress */ + in += fill; inlen -= fill; + while(inlen > BLAKE2B_BLOCKBYTES) { + blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); + blake2b_compress( S, in ); + in += BLAKE2B_BLOCKBYTES; + inlen -= BLAKE2B_BLOCKBYTES; + } + } + memcpy( S->buf + S->buflen, in, inlen ); + S->buflen += inlen; + } + return 0; +} + +int blake2b_Final( blake2b_state *S, void *out, size_t outlen ) +{ + uint8_t buffer[BLAKE2B_OUTBYTES] = {0}; + size_t i = 0; + + if( out == NULL || outlen < S->outlen ) + return -1; + + if( blake2b_is_lastblock( S ) ) + return -1; + + blake2b_increment_counter( S, S->buflen ); + blake2b_set_lastblock( S ); + memzero( S->buf + S->buflen, BLAKE2B_BLOCKBYTES - S->buflen ); /* Padding */ + blake2b_compress( S, S->buf ); + + for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */ + store64( buffer + sizeof( S->h[i] ) * i, S->h[i] ); + + memcpy( out, buffer, S->outlen ); + memzero(buffer, sizeof(buffer)); + return 0; +} + +int blake2b(const uint8_t *msg, uint32_t msg_len, void *out, size_t outlen) +{ + BLAKE2B_CTX ctx; + if (0 != blake2b_Init(&ctx, outlen)) return -1; + if (0 != blake2b_Update(&ctx, msg, msg_len)) return -1; + if (0 != blake2b_Final(&ctx, out, outlen)) return -1; + return 0; +} + +int blake2b_Key(const uint8_t *msg, uint32_t msg_len, const void *key, size_t keylen, void *out, size_t outlen) +{ + BLAKE2B_CTX ctx; + if (0 != blake2b_InitKey(&ctx, outlen, key, keylen)) return -1; + if (0 != blake2b_Update(&ctx, msg, msg_len)) return -1; + if (0 != blake2b_Final(&ctx, out, outlen)) return -1; + return 0; +} diff --git a/deps/crypto/trezor-crypto/blake2b.h b/deps/crypto/trezor-crypto/blake2b.h new file mode 100644 index 000000000..1a43e92d1 --- /dev/null +++ b/deps/crypto/trezor-crypto/blake2b.h @@ -0,0 +1,41 @@ +#ifndef __BLAKE2B_H__ +#define __BLAKE2B_H__ + +#include +#include + +enum blake2b_constant +{ + BLAKE2B_BLOCKBYTES = 128, + BLAKE2B_OUTBYTES = 64, + BLAKE2B_KEYBYTES = 64, + BLAKE2B_SALTBYTES = 16, + BLAKE2B_PERSONALBYTES = 16 +}; + +typedef struct __blake2b_state +{ + uint64_t h[8]; + uint64_t t[2]; + uint64_t f[2]; + uint8_t buf[BLAKE2B_BLOCKBYTES]; + size_t buflen; + size_t outlen; + uint8_t last_node; +} blake2b_state; + +#define BLAKE2B_CTX blake2b_state +#define BLAKE2B_BLOCK_LENGTH BLAKE2B_BLOCKBYTES +#define BLAKE2B_DIGEST_LENGTH BLAKE2B_OUTBYTES +#define BLAKE2B_KEY_LENGTH BLAKE2B_KEYBYTES + +int blake2b_Init(blake2b_state *S, size_t outlen); +int blake2b_InitKey(blake2b_state *S, size_t outlen, const void *key, size_t keylen); +int blake2b_InitPersonal(blake2b_state *S, size_t outlen, const void *personal, size_t personal_len); +int blake2b_Update(blake2b_state *S, const void *pin, size_t inlen); +int blake2b_Final(blake2b_state *S, void *out, size_t outlen); + +int blake2b(const uint8_t *msg, uint32_t msg_len, void *out, size_t outlen); +int blake2b_Key(const uint8_t *msg, uint32_t msg_len, const void *key, size_t keylen, void *out, size_t outlen); + +#endif diff --git a/deps/crypto/trezor-crypto/blake2s.c b/deps/crypto/trezor-crypto/blake2s.c new file mode 100644 index 000000000..2c060a637 --- /dev/null +++ b/deps/crypto/trezor-crypto/blake2s.c @@ -0,0 +1,318 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ + +#include + +#include "blake2s.h" +#include "blake2_common.h" +#include "memzero.h" + +typedef struct blake2s_param__ +{ + uint8_t digest_length; /* 1 */ + uint8_t key_length; /* 2 */ + uint8_t fanout; /* 3 */ + uint8_t depth; /* 4 */ + uint32_t leaf_length; /* 8 */ + uint32_t node_offset; /* 12 */ + uint16_t xof_length; /* 14 */ + uint8_t node_depth; /* 15 */ + uint8_t inner_length; /* 16 */ + /* uint8_t reserved[0]; */ + uint8_t salt[BLAKE2S_SALTBYTES]; /* 24 */ + uint8_t personal[BLAKE2S_PERSONALBYTES]; /* 32 */ +} __attribute__((packed)) blake2s_param; + +static const uint32_t blake2s_IV[8] = +{ + 0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL, + 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL +}; + +static const uint8_t blake2s_sigma[10][16] = +{ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , +}; + +static void blake2s_set_lastnode( blake2s_state *S ) +{ + S->f[1] = (uint32_t)-1; +} + +/* Some helper functions, not necessarily useful */ +static int blake2s_is_lastblock( const blake2s_state *S ) +{ + return S->f[0] != 0; +} + +static void blake2s_set_lastblock( blake2s_state *S ) +{ + if( S->last_node ) blake2s_set_lastnode( S ); + + S->f[0] = (uint32_t)-1; +} + +static void blake2s_increment_counter( blake2s_state *S, const uint32_t inc ) +{ + S->t[0] += inc; + S->t[1] += ( S->t[0] < inc ); +} + +static void blake2s_init0( blake2s_state *S ) +{ + size_t i = 0; + memzero( S, sizeof( blake2s_state ) ); + + for( i = 0; i < 8; ++i ) S->h[i] = blake2s_IV[i]; +} + +/* init2 xors IV with input parameter block */ +int blake2s_init_param( blake2s_state *S, const blake2s_param *P ) +{ + const unsigned char *p = ( const unsigned char * )( P ); + size_t i = 0; + + blake2s_init0( S ); + + /* IV XOR ParamBlock */ + for( i = 0; i < 8; ++i ) + S->h[i] ^= load32( &p[i * 4] ); + + S->outlen = P->digest_length; + return 0; +} + + +/* Sequential blake2s initialization */ +int blake2s_Init( blake2s_state *S, size_t outlen ) +{ + blake2s_param P[1] = {0}; + + if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store16( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + /* memzero(P->reserved, sizeof(P->reserved) ); */ + memzero( P->salt, sizeof( P->salt ) ); + memzero( P->personal, sizeof( P->personal ) ); + return blake2s_init_param( S, P ); +} + +int blake2s_InitPersonal( blake2s_state *S, size_t outlen, const void *personal, size_t personal_len) +{ + blake2s_param P[1] = {0}; + + if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1; + if ( ( !personal ) || ( personal_len != BLAKE2S_PERSONALBYTES ) ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store16( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + /* memzero(P->reserved, sizeof(P->reserved) ); */ + memzero( P->salt, sizeof( P->salt ) ); + memcpy( P->personal, personal, BLAKE2S_PERSONALBYTES ); + return blake2s_init_param( S, P ); +} + + +int blake2s_InitKey( blake2s_state *S, size_t outlen, const void *key, size_t keylen ) +{ + blake2s_param P[1] = {0}; + + if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1; + + if ( !key || !keylen || keylen > BLAKE2S_KEYBYTES ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = (uint8_t)keylen; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store16( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + /* memzero(P->reserved, sizeof(P->reserved) ); */ + memzero( P->salt, sizeof( P->salt ) ); + memzero( P->personal, sizeof( P->personal ) ); + + if( blake2s_init_param( S, P ) < 0 ) return -1; + + { + uint8_t block[BLAKE2S_BLOCKBYTES] = {0}; + memzero( block, BLAKE2S_BLOCKBYTES ); + memcpy( block, key, keylen ); + blake2s_Update( S, block, BLAKE2S_BLOCKBYTES ); + memzero( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */ + } + return 0; +} + +#define G(r,i,a,b,c,d) \ + do { \ + a = a + b + m[blake2s_sigma[r][2*i+0]]; \ + d = rotr32(d ^ a, 16); \ + c = c + d; \ + b = rotr32(b ^ c, 12); \ + a = a + b + m[blake2s_sigma[r][2*i+1]]; \ + d = rotr32(d ^ a, 8); \ + c = c + d; \ + b = rotr32(b ^ c, 7); \ + } while(0) + +#define ROUND(r) \ + do { \ + G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ + G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ + G(r,2,v[ 2],v[ 6],v[10],v[14]); \ + G(r,3,v[ 3],v[ 7],v[11],v[15]); \ + G(r,4,v[ 0],v[ 5],v[10],v[15]); \ + G(r,5,v[ 1],v[ 6],v[11],v[12]); \ + G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ + G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \ + } while(0) + +static void blake2s_compress( blake2s_state *S, const uint8_t in[BLAKE2S_BLOCKBYTES] ) +{ + uint32_t m[16] = {0}; + uint32_t v[16] = {0}; + size_t i = 0; + + for( i = 0; i < 16; ++i ) { + m[i] = load32( in + i * sizeof( m[i] ) ); + } + + for( i = 0; i < 8; ++i ) { + v[i] = S->h[i]; + } + + v[ 8] = blake2s_IV[0]; + v[ 9] = blake2s_IV[1]; + v[10] = blake2s_IV[2]; + v[11] = blake2s_IV[3]; + v[12] = S->t[0] ^ blake2s_IV[4]; + v[13] = S->t[1] ^ blake2s_IV[5]; + v[14] = S->f[0] ^ blake2s_IV[6]; + v[15] = S->f[1] ^ blake2s_IV[7]; + + ROUND( 0 ); + ROUND( 1 ); + ROUND( 2 ); + ROUND( 3 ); + ROUND( 4 ); + ROUND( 5 ); + ROUND( 6 ); + ROUND( 7 ); + ROUND( 8 ); + ROUND( 9 ); + + for( i = 0; i < 8; ++i ) { + S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; + } +} + +#undef G +#undef ROUND + +int blake2s_Update( blake2s_state *S, const void *pin, size_t inlen ) +{ + const unsigned char * in = (const unsigned char *)pin; + if( inlen > 0 ) + { + size_t left = S->buflen; + size_t fill = BLAKE2S_BLOCKBYTES - left; + if( inlen > fill ) + { + S->buflen = 0; + memcpy( S->buf + left, in, fill ); /* Fill buffer */ + blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES ); + blake2s_compress( S, S->buf ); /* Compress */ + in += fill; inlen -= fill; + while(inlen > BLAKE2S_BLOCKBYTES) { + blake2s_increment_counter(S, BLAKE2S_BLOCKBYTES); + blake2s_compress( S, in ); + in += BLAKE2S_BLOCKBYTES; + inlen -= BLAKE2S_BLOCKBYTES; + } + } + memcpy( S->buf + S->buflen, in, inlen ); + S->buflen += inlen; + } + return 0; +} + +int blake2s_Final( blake2s_state *S, void *out, size_t outlen ) +{ + uint8_t buffer[BLAKE2S_OUTBYTES] = {0}; + size_t i = 0; + + if( out == NULL || outlen < S->outlen ) + return -1; + + if( blake2s_is_lastblock( S ) ) + return -1; + + blake2s_increment_counter( S, ( uint32_t )S->buflen ); + blake2s_set_lastblock( S ); + memzero( S->buf + S->buflen, BLAKE2S_BLOCKBYTES - S->buflen ); /* Padding */ + blake2s_compress( S, S->buf ); + + for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */ + store32( buffer + sizeof( S->h[i] ) * i, S->h[i] ); + + memcpy( out, buffer, outlen ); + memzero(buffer, sizeof(buffer)); + return 0; +} + +int blake2s(const uint8_t *msg, uint32_t msg_len, void *out, size_t outlen) +{ + BLAKE2S_CTX ctx; + if (0 != blake2s_Init(&ctx, outlen)) return -1; + if (0 != blake2s_Update(&ctx, msg, msg_len)) return -1; + if (0 != blake2s_Final(&ctx, out, outlen)) return -1; + return 0; +} + +int blake2s_Key(const uint8_t *msg, uint32_t msg_len, const void *key, size_t keylen, void *out, size_t outlen) +{ + BLAKE2S_CTX ctx; + if (0 != blake2s_InitKey(&ctx, outlen, key, keylen)) return -1; + if (0 != blake2s_Update(&ctx, msg, msg_len)) return -1; + if (0 != blake2s_Final(&ctx, out, outlen)) return -1; + return 0; +} diff --git a/deps/crypto/trezor-crypto/blake2s.h b/deps/crypto/trezor-crypto/blake2s.h new file mode 100644 index 000000000..57991bc91 --- /dev/null +++ b/deps/crypto/trezor-crypto/blake2s.h @@ -0,0 +1,41 @@ +#ifndef __BLAKE2S_H__ +#define __BLAKE2S_H__ + +#include +#include + +enum blake2s_constant +{ + BLAKE2S_BLOCKBYTES = 64, + BLAKE2S_OUTBYTES = 32, + BLAKE2S_KEYBYTES = 32, + BLAKE2S_SALTBYTES = 8, + BLAKE2S_PERSONALBYTES = 8 +}; + +typedef struct __blake2s_state +{ + uint32_t h[8]; + uint32_t t[2]; + uint32_t f[2]; + uint8_t buf[BLAKE2S_BLOCKBYTES]; + uint32_t buflen; + uint8_t outlen; + uint8_t last_node; +} blake2s_state; + +#define BLAKE2S_CTX blake2s_state +#define BLAKE2S_BLOCK_LENGTH BLAKE2S_BLOCKBYTES +#define BLAKE2S_DIGEST_LENGTH BLAKE2S_OUTBYTES +#define BLAKE2S_KEY_LENGTH BLAKE2S_KEYBYTES + +int blake2s_Init(blake2s_state *S, size_t outlen); +int blake2s_InitKey(blake2s_state *S, size_t outlen, const void *key, size_t keylen); +int blake2s_InitPersonal(blake2s_state *S, size_t outlen, const void *personal, size_t personal_len); +int blake2s_Update(blake2s_state *S, const void *pin, size_t inlen); +int blake2s_Final(blake2s_state *S, void *out, size_t outlen); + +int blake2s(const uint8_t *msg, uint32_t msg_len, void *out, size_t outlen); +int blake2s_Key(const uint8_t *msg, uint32_t msg_len, const void *key, size_t keylen, void *out, size_t outlen); + +#endif diff --git a/deps/crypto/trezor-crypto/cash_addr.c b/deps/crypto/trezor-crypto/cash_addr.c new file mode 100644 index 000000000..1057e7ef6 --- /dev/null +++ b/deps/crypto/trezor-crypto/cash_addr.c @@ -0,0 +1,193 @@ +/* Copyright (c) 2017 Jochen Hoenicke + * based on code Copyright (c) 2017 Peter Wuille + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include + +#include "cash_addr.h" + +#define MAX_CASHADDR_LEN 129 +#define MAX_BASE32_SIZE 104 +#define MAX_PROG_SIZE 65 +#define MAX_HRP_LEN 20 +#define CHECKSUM_SIZE 8 + +uint64_t cashaddr_polymod_step(uint64_t pre) { + uint8_t b = pre >> 35; + return ((pre & 0x7FFFFFFFFULL) << 5) ^ (-((b >> 0) & 1) & 0x98f2bc8e61ULL) ^ + (-((b >> 1) & 1) & 0x79b76d99e2ULL) ^ + (-((b >> 2) & 1) & 0xf33e5fb3c4ULL) ^ + (-((b >> 3) & 1) & 0xae2eabe2a8ULL) ^ + (-((b >> 4) & 1) & 0x1e4f43e470ULL); +} + +static const char* charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; + +static const int8_t charset_rev[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 15, -1, 10, 17, 21, 20, 26, 30, 7, + 5, -1, -1, -1, -1, -1, -1, -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, + 31, 27, 19, -1, 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, + -1, -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, 1, 0, + 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1}; + +int cash_encode(char* output, const char* hrp, const uint8_t* data, + size_t data_size) { + uint64_t chk = 1; + size_t i = 0; + while (hrp[i] != 0) { + int ch = hrp[i]; + if (ch < 33 || ch > 126) { + return 0; + } + *(output++) = ch; + chk = cashaddr_polymod_step(chk) ^ (ch & 0x1f); + ++i; + if (i > MAX_HRP_LEN) { + return 0; + } + } + if (i + 1 + data_size + CHECKSUM_SIZE > MAX_CASHADDR_LEN) { + return 0; + } + chk = cashaddr_polymod_step(chk); + *(output++) = ':'; + for (i = 0; i < data_size; ++i) { + if (*data >> 5) return 0; + chk = cashaddr_polymod_step(chk) ^ (*data); + *(output++) = charset[*(data++)]; + } + for (i = 0; i < CHECKSUM_SIZE; ++i) { + chk = cashaddr_polymod_step(chk); + } + chk ^= 1; + for (i = 0; i < CHECKSUM_SIZE; ++i) { + *(output++) = charset[(chk >> ((CHECKSUM_SIZE - 1 - i) * 5)) & 0x1f]; + } + *output = 0; + return 1; +} + +int cash_decode(char* hrp, uint8_t* data, size_t* data_size, + const char* input) { + uint64_t chk = 1; + size_t i = 0; + size_t input_len = strlen(input); + size_t hrp_len = 0; + int have_lower = 0, have_upper = 0; + if (input_len < CHECKSUM_SIZE || input_len > MAX_CASHADDR_LEN) { + return 0; + } + *data_size = 0; + while (*data_size < input_len && input[(input_len - 1) - *data_size] != ':') { + ++(*data_size); + } + hrp_len = input_len - (1 + *data_size); + if (1 + *data_size >= input_len || hrp_len > MAX_HRP_LEN || + *data_size < CHECKSUM_SIZE || + *data_size > CHECKSUM_SIZE + MAX_BASE32_SIZE) { + return 0; + } + // subtract checksum + *(data_size) -= CHECKSUM_SIZE; + for (i = 0; i < hrp_len; ++i) { + int ch = input[i]; + if (ch < 33 || ch > 126) { + return 0; + } + if (ch >= 'a' && ch <= 'z') { + have_lower = 1; + } else if (ch >= 'A' && ch <= 'Z') { + have_upper = 1; + ch = (ch - 'A') + 'a'; + } + hrp[i] = ch; + chk = cashaddr_polymod_step(chk) ^ (ch & 0x1f); + } + hrp[i] = 0; + chk = cashaddr_polymod_step(chk); + ++i; + while (i < input_len) { + int v = (input[i] & 0x80) ? -1 : charset_rev[(int)input[i]]; + if (input[i] >= 'a' && input[i] <= 'z') have_lower = 1; + if (input[i] >= 'A' && input[i] <= 'Z') have_upper = 1; + if (v == -1) { + return 0; + } + chk = cashaddr_polymod_step(chk) ^ v; + if (i + CHECKSUM_SIZE < input_len) { + data[i - (1 + hrp_len)] = v; + } + ++i; + } + if (have_lower && have_upper) { + return 0; + } + return chk == 1; +} + +static int convert_bits(uint8_t* out, size_t* outlen, int outbits, + const uint8_t* in, size_t inlen, int inbits, int pad) { + uint32_t val = 0; + int bits = 0; + uint32_t maxv = (((uint32_t)1) << outbits) - 1; + while (inlen--) { + val = (val << inbits) | *(in++); + bits += inbits; + while (bits >= outbits) { + bits -= outbits; + out[(*outlen)++] = (val >> bits) & maxv; + } + } + if (pad) { + if (bits) { + out[(*outlen)++] = (val << (outbits - bits)) & maxv; + } + } else if (((val << (outbits - bits)) & maxv) || bits >= inbits) { + return 0; + } + return 1; +} + +int cash_addr_encode(char* output, const char* hrp, const uint8_t* prog, + size_t prog_size) { + uint8_t base32[MAX_BASE32_SIZE] = {0}; + size_t base32size = 0; + if (prog_size < 2 || prog_size > MAX_PROG_SIZE) return 0; + convert_bits(base32, &base32size, 5, prog, prog_size, 8, 1); + return cash_encode(output, hrp, base32, base32size); +} + +int cash_addr_decode(uint8_t* prog, size_t* prog_size, const char* hrp, + const char* addr) { + uint8_t data[MAX_BASE32_SIZE] = {0}; + char hrp_actual[MAX_HRP_LEN + 1] = {0}; + size_t data_size = 0; + if (!cash_decode(hrp_actual, data, &data_size, addr)) return 0; + if (data_size == 0 || data_size > MAX_BASE32_SIZE) return 0; + if (strncmp(hrp, hrp_actual, MAX_HRP_LEN + 1) != 0) return 0; + *prog_size = 0; + if (!convert_bits(prog, prog_size, 8, data, data_size, 5, 0)) return 0; + if (*prog_size < 2 || *prog_size > MAX_PROG_SIZE) return 0; + return 1; +} diff --git a/deps/crypto/trezor-crypto/cash_addr.h b/deps/crypto/trezor-crypto/cash_addr.h new file mode 100644 index 000000000..5f27edb85 --- /dev/null +++ b/deps/crypto/trezor-crypto/cash_addr.h @@ -0,0 +1,80 @@ +/* Copyright (c) 2017 Jochen Hoenicke, Pieter Wuille + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef _CASH_ADDR_H_ +#define _CASH_ADDR_H_ 1 + +#include + +/** Encode a Cashaddr address + * + * Out: output: Pointer to a buffer of size min(114 + strlen(hrp), 130) + * that will be updated to contain the null-terminated + * address. + * In: hrp: Pointer to the null-terminated human readable part to use + * (chain/network specific). + * prog: Data bytes for the hash (between 21 and 65 bytes). + * prog_size: Number of data bytes in prog. + * Returns 1 if successful. + */ +int cash_addr_encode(char *output, const char *hrp, const uint8_t *prog, + size_t prog_size); + +/** Decode a CashAddr address + * + * Out: prog: Pointer to a buffer of size 65 that will be updated to + * contain the witness program bytes. + * prog_size: Pointer to a size_t that will be updated to contain the + * length of bytes in prog. + * In: hrp: Pointer to the null-terminated human readable part that is + * expected (chain/network specific). + * addr: Pointer to the null-terminated address. + * Returns 1 if successful. + */ +int cash_addr_decode(uint8_t *prog, size_t *prog_size, const char *hrp, + const char *addr); + +/** Encode a Cash string + * + * Out: output: Pointer to a buffer of size strlen(hrp) + data_size + 10 that + * will be updated to contain the null-terminated Cash string. + * In: hrp: Pointer to the null-terminated human readable part. + * data: Pointer to an array of 5-bit values. + * data_size: Length of the data array. + * Returns 1 if successful. + */ +int cash_encode(char *output, const char *hrp, const uint8_t *data, + size_t data_size); + +/** Decode a Cash string + * + * Out: hrp: Pointer to a buffer of size strlen(input) - 6. Will be + * updated to contain the null-terminated human readable part. + * data: Pointer to a buffer of size strlen(input) - 8 that will + * hold the encoded 5-bit data values. + * data_size: Pointer to a size_t that will be updated to be the number + * of entries in data. + * In: input: Pointer to a null-terminated Cash string. + * Returns 1 if succesful. + */ +int cash_decode(char *hrp, uint8_t *data, size_t *data_size, const char *input); + +#endif diff --git a/deps/crypto/trezor-crypto/chacha20poly1305/chacha20poly1305.c b/deps/crypto/trezor-crypto/chacha20poly1305/chacha20poly1305.c new file mode 100644 index 000000000..4012dd056 --- /dev/null +++ b/deps/crypto/trezor-crypto/chacha20poly1305/chacha20poly1305.c @@ -0,0 +1,60 @@ +// Implementations of the XChaCha20 + Poly1305 and ChaCha20 + Poly1305 +// AEAD constructions with a goal of simplicity and correctness rather +// than performance. + +#include "chacha20poly1305.h" +#include "ecrypt-portable.h" + +void hchacha20(ECRYPT_ctx *x,u8 *c); + +// Initialize the XChaCha20 + Poly1305 context for encryption or decryption +// using a 32 byte key and 24 byte nonce. The key and the first 16 bytes of +// the nonce are used as input to HChaCha20 to derive the Chacha20 key. +void xchacha20poly1305_init(chacha20poly1305_ctx *ctx, const uint8_t key[32], const uint8_t nonce[24]) { + unsigned char subkey[32] = {0}; + unsigned char block0[64] = {0}; + ECRYPT_ctx tmp = {0}; + + // Generate the Chacha20 key by applying HChaCha20 to the + // original key and the first 16 bytes of the nonce. + ECRYPT_keysetup(&tmp, key, 256, 16); + tmp.input[12] = U8TO32_LITTLE(nonce + 0); + tmp.input[13] = U8TO32_LITTLE(nonce + 4); + tmp.input[14] = U8TO32_LITTLE(nonce + 8); + tmp.input[15] = U8TO32_LITTLE(nonce + 12); + hchacha20(&tmp, subkey); + + // Initialize Chacha20 with the newly generated key and + // the last 8 bytes of the nonce. + ECRYPT_keysetup(&ctx->chacha20, subkey, 256, 16); + ECRYPT_ivsetup(&ctx->chacha20, nonce+16); + + // Encrypt 64 bytes of zeros and use the first 32 bytes + // as the Poly1305 key. + ECRYPT_encrypt_bytes(&ctx->chacha20, block0, block0, 64); + poly1305_init(&ctx->poly1305, block0); +} + +// Encrypt n bytes of plaintext where n must be evenly divisible by the +// Chacha20 blocksize of 64, except for the final n bytes of plaintext. +void chacha20poly1305_encrypt(chacha20poly1305_ctx *ctx, const uint8_t *in, uint8_t *out, size_t n) { + ECRYPT_encrypt_bytes(&ctx->chacha20, in, out, n); + poly1305_update(&ctx->poly1305, out, n); +} + +// Decrypt n bytes of ciphertext where n must be evenly divisible by the +// Chacha20 blocksize of 64, except for the final n bytes of ciphertext. +void chacha20poly1305_decrypt(chacha20poly1305_ctx *ctx, const uint8_t *in, uint8_t *out, size_t n) { + poly1305_update(&ctx->poly1305, in, n); + ECRYPT_encrypt_bytes(&ctx->chacha20, in, out, n); +} + +// Include authenticated data in the Poly1305 MAC. +void chacha20poly1305_auth(chacha20poly1305_ctx *ctx, const uint8_t *in, size_t n) { + poly1305_update(&ctx->poly1305, in, n); +} + +// Compute NaCl secretbox-style Poly1305 MAC. +void chacha20poly1305_finish(chacha20poly1305_ctx *ctx, uint8_t mac[16]) { + poly1305_finish(&ctx->poly1305, mac); +} diff --git a/deps/crypto/trezor-crypto/chacha20poly1305/chacha20poly1305.h b/deps/crypto/trezor-crypto/chacha20poly1305/chacha20poly1305.h new file mode 100644 index 000000000..1f501f12e --- /dev/null +++ b/deps/crypto/trezor-crypto/chacha20poly1305/chacha20poly1305.h @@ -0,0 +1,19 @@ +#ifndef CHACHA20POLY1305_H +#define CHACHA20POLY1305_H + +#include +#include "ecrypt-sync.h" +#include "poly1305-donna.h" + +typedef struct { + ECRYPT_ctx chacha20; + poly1305_context poly1305; +} chacha20poly1305_ctx; + +void xchacha20poly1305_init(chacha20poly1305_ctx *ctx, const uint8_t key[32], const uint8_t nonce[24]); +void chacha20poly1305_encrypt(chacha20poly1305_ctx *ctx, const uint8_t *in, uint8_t *out, size_t n); +void chacha20poly1305_decrypt(chacha20poly1305_ctx *ctx, const uint8_t *in, uint8_t *out, size_t n); +void chacha20poly1305_auth(chacha20poly1305_ctx *ctx, const uint8_t *in, size_t n); +void chacha20poly1305_finish(chacha20poly1305_ctx *ctx, uint8_t mac[16]); + +#endif // CHACHA20POLY1305_H diff --git a/deps/crypto/trezor-crypto/chacha20poly1305/chacha_merged.c b/deps/crypto/trezor-crypto/chacha20poly1305/chacha_merged.c new file mode 100644 index 000000000..f5c37fa8a --- /dev/null +++ b/deps/crypto/trezor-crypto/chacha20poly1305/chacha_merged.c @@ -0,0 +1,252 @@ +/* +chacha-merged.c version 20080118 +D. J. Bernstein +Public domain. +*/ + +#include "ecrypt-sync.h" +#include "ecrypt-portable.h" + +#define ROTATE(v,c) (ROTL32(v,c)) +#define XOR(v,w) ((v) ^ (w)) +#define PLUS(v,w) (U32V((v) + (w))) +#define PLUSONE(v) (PLUS((v),1)) + +#define QUARTERROUND(a,b,c,d) \ + a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ + a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); + +void ECRYPT_init(void) +{ + return; +} + +static const char sigma[16] = "expand 32-byte k"; +static const char tau[16] = "expand 16-byte k"; + +void ECRYPT_keysetup(ECRYPT_ctx *x,const u8 *k,u32 kbits,u32 ivbits) +{ + (void)ivbits; + const char *constants = (const char *)0; + + x->input[4] = U8TO32_LITTLE(k + 0); + x->input[5] = U8TO32_LITTLE(k + 4); + x->input[6] = U8TO32_LITTLE(k + 8); + x->input[7] = U8TO32_LITTLE(k + 12); + if (kbits == 256) { /* recommended */ + k += 16; + constants = sigma; + } else { /* kbits == 128 */ + constants = tau; + } + x->input[8] = U8TO32_LITTLE(k + 0); + x->input[9] = U8TO32_LITTLE(k + 4); + x->input[10] = U8TO32_LITTLE(k + 8); + x->input[11] = U8TO32_LITTLE(k + 12); + x->input[0] = U8TO32_LITTLE(constants + 0); + x->input[1] = U8TO32_LITTLE(constants + 4); + x->input[2] = U8TO32_LITTLE(constants + 8); + x->input[3] = U8TO32_LITTLE(constants + 12); +} + +void ECRYPT_ivsetup(ECRYPT_ctx *x,const u8 *iv) +{ + x->input[12] = 0; + x->input[13] = 0; + x->input[14] = U8TO32_LITTLE(iv + 0); + x->input[15] = U8TO32_LITTLE(iv + 4); +} + +void ECRYPT_ctrsetup(ECRYPT_ctx *x,const u8 *ctr) +{ + x->input[12] = U8TO32_LITTLE(ctr + 0); + x->input[13] = U8TO32_LITTLE(ctr + 4); +} + +void ECRYPT_encrypt_bytes(ECRYPT_ctx *x,const u8 *m,u8 *c,u32 bytes) +{ + u32 x0 = 0, x1 = 0, x2 = 0, x3 = 0, x4 = 0, x5 = 0, x6 = 0, x7 = 0, x8 = 0, x9 = 0, x10 = 0, x11 = 0, x12 = 0, x13 = 0, x14 = 0, x15 = 0; + u32 j0 = 0, j1 = 0, j2 = 0, j3 = 0, j4 = 0, j5 = 0, j6 = 0, j7 = 0, j8 = 0, j9 = 0, j10 = 0, j11 = 0, j12 = 0, j13 = 0, j14 = 0, j15 = 0; + u8 *ctarget = 0; + u8 tmp[64] = {0}; + int i = 0; + + if (!bytes) return; + + j0 = x->input[0]; + j1 = x->input[1]; + j2 = x->input[2]; + j3 = x->input[3]; + j4 = x->input[4]; + j5 = x->input[5]; + j6 = x->input[6]; + j7 = x->input[7]; + j8 = x->input[8]; + j9 = x->input[9]; + j10 = x->input[10]; + j11 = x->input[11]; + j12 = x->input[12]; + j13 = x->input[13]; + j14 = x->input[14]; + j15 = x->input[15]; + + for (;;) { + if (bytes < 64) { + for (i = 0;i < (int)bytes;++i) tmp[i] = m[i]; + m = tmp; + ctarget = c; + c = tmp; + } + x0 = j0; + x1 = j1; + x2 = j2; + x3 = j3; + x4 = j4; + x5 = j5; + x6 = j6; + x7 = j7; + x8 = j8; + x9 = j9; + x10 = j10; + x11 = j11; + x12 = j12; + x13 = j13; + x14 = j14; + x15 = j15; + for (i = 20;i > 0;i -= 2) { + QUARTERROUND( x0, x4, x8,x12) + QUARTERROUND( x1, x5, x9,x13) + QUARTERROUND( x2, x6,x10,x14) + QUARTERROUND( x3, x7,x11,x15) + QUARTERROUND( x0, x5,x10,x15) + QUARTERROUND( x1, x6,x11,x12) + QUARTERROUND( x2, x7, x8,x13) + QUARTERROUND( x3, x4, x9,x14) + } + x0 = PLUS(x0,j0); + x1 = PLUS(x1,j1); + x2 = PLUS(x2,j2); + x3 = PLUS(x3,j3); + x4 = PLUS(x4,j4); + x5 = PLUS(x5,j5); + x6 = PLUS(x6,j6); + x7 = PLUS(x7,j7); + x8 = PLUS(x8,j8); + x9 = PLUS(x9,j9); + x10 = PLUS(x10,j10); + x11 = PLUS(x11,j11); + x12 = PLUS(x12,j12); + x13 = PLUS(x13,j13); + x14 = PLUS(x14,j14); + x15 = PLUS(x15,j15); + + x0 = XOR(x0,U8TO32_LITTLE(m + 0)); + x1 = XOR(x1,U8TO32_LITTLE(m + 4)); + x2 = XOR(x2,U8TO32_LITTLE(m + 8)); + x3 = XOR(x3,U8TO32_LITTLE(m + 12)); + x4 = XOR(x4,U8TO32_LITTLE(m + 16)); + x5 = XOR(x5,U8TO32_LITTLE(m + 20)); + x6 = XOR(x6,U8TO32_LITTLE(m + 24)); + x7 = XOR(x7,U8TO32_LITTLE(m + 28)); + x8 = XOR(x8,U8TO32_LITTLE(m + 32)); + x9 = XOR(x9,U8TO32_LITTLE(m + 36)); + x10 = XOR(x10,U8TO32_LITTLE(m + 40)); + x11 = XOR(x11,U8TO32_LITTLE(m + 44)); + x12 = XOR(x12,U8TO32_LITTLE(m + 48)); + x13 = XOR(x13,U8TO32_LITTLE(m + 52)); + x14 = XOR(x14,U8TO32_LITTLE(m + 56)); + x15 = XOR(x15,U8TO32_LITTLE(m + 60)); + + j12 = PLUSONE(j12); + if (!j12) { + j13 = PLUSONE(j13); + /* stopping at 2^70 bytes per nonce is user's responsibility */ + } + + U32TO8_LITTLE(c + 0,x0); + U32TO8_LITTLE(c + 4,x1); + U32TO8_LITTLE(c + 8,x2); + U32TO8_LITTLE(c + 12,x3); + U32TO8_LITTLE(c + 16,x4); + U32TO8_LITTLE(c + 20,x5); + U32TO8_LITTLE(c + 24,x6); + U32TO8_LITTLE(c + 28,x7); + U32TO8_LITTLE(c + 32,x8); + U32TO8_LITTLE(c + 36,x9); + U32TO8_LITTLE(c + 40,x10); + U32TO8_LITTLE(c + 44,x11); + U32TO8_LITTLE(c + 48,x12); + U32TO8_LITTLE(c + 52,x13); + U32TO8_LITTLE(c + 56,x14); + U32TO8_LITTLE(c + 60,x15); + + if (bytes <= 64) { + if (bytes < 64) { + for (i = 0;i < (int)bytes;++i) ctarget[i] = c[i]; + } + x->input[12] = j12; + x->input[13] = j13; + return; + } + bytes -= 64; + c += 64; + m += 64; + } +} + +void ECRYPT_decrypt_bytes(ECRYPT_ctx *x,const u8 *c,u8 *m,u32 bytes) +{ + ECRYPT_encrypt_bytes(x,c,m,bytes); +} + +void ECRYPT_keystream_bytes(ECRYPT_ctx *x,u8 *stream,u32 bytes) +{ + u32 i = 0; + for (i = 0;i < bytes;++i) stream[i] = 0; + ECRYPT_encrypt_bytes(x,stream,stream,bytes); +} + +void hchacha20(ECRYPT_ctx *x,u8 *c) +{ + u32 x0 = 0, x1 = 0, x2 = 0, x3 = 0, x4 = 0, x5 = 0, x6 = 0, x7 = 0, x8 = 0, x9 = 0, x10 = 0, x11 = 0, x12 = 0, x13 = 0, x14 = 0, x15 = 0; + int i = 0; + + x0 = x->input[0]; + x1 = x->input[1]; + x2 = x->input[2]; + x3 = x->input[3]; + x4 = x->input[4]; + x5 = x->input[5]; + x6 = x->input[6]; + x7 = x->input[7]; + x8 = x->input[8]; + x9 = x->input[9]; + x10 = x->input[10]; + x11 = x->input[11]; + x12 = x->input[12]; + x13 = x->input[13]; + x14 = x->input[14]; + x15 = x->input[15]; + + for (i = 20;i > 0;i -= 2) { + QUARTERROUND( x0, x4, x8,x12) + QUARTERROUND( x1, x5, x9,x13) + QUARTERROUND( x2, x6,x10,x14) + QUARTERROUND( x3, x7,x11,x15) + QUARTERROUND( x0, x5,x10,x15) + QUARTERROUND( x1, x6,x11,x12) + QUARTERROUND( x2, x7, x8,x13) + QUARTERROUND( x3, x4, x9,x14) + } + + U32TO8_LITTLE(c + 0,x0); + U32TO8_LITTLE(c + 4,x1); + U32TO8_LITTLE(c + 8,x2); + U32TO8_LITTLE(c + 12,x3); + U32TO8_LITTLE(c + 16,x12); + U32TO8_LITTLE(c + 20,x13); + U32TO8_LITTLE(c + 24,x14); + U32TO8_LITTLE(c + 28,x15); +} diff --git a/deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-config.h b/deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-config.h new file mode 100644 index 000000000..0749df730 --- /dev/null +++ b/deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-config.h @@ -0,0 +1,316 @@ +/* ecrypt-config.h */ + +/* *** Normally, it should not be necessary to edit this file. *** */ + +#ifndef ECRYPT_CONFIG +#define ECRYPT_CONFIG + +/* ------------------------------------------------------------------------- */ + +/* Guess the endianness of the target architecture. */ + +/* + * The LITTLE endian machines: + */ +#if defined(__ultrix) /* Older MIPS */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(__alpha) /* Alpha */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(i386) /* x86 (gcc) */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(__i386) /* x86 (gcc) */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(__x86_64) /* x86_64 (gcc) */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(_M_IX86) /* x86 (MSC, Borland) */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(_MSC_VER) /* x86 (surely MSC) */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(__INTEL_COMPILER) /* x86 (surely Intel compiler icl.exe) */ +#define ECRYPT_LITTLE_ENDIAN + +/* + * The BIG endian machines: + */ +#elif defined(__sparc) /* Newer Sparc's */ +#define ECRYPT_BIG_ENDIAN +#elif defined(__powerpc__) /* PowerPC */ +#define ECRYPT_BIG_ENDIAN +#elif defined(__ppc__) /* PowerPC */ +#define ECRYPT_BIG_ENDIAN +#elif defined(__hppa) /* HP-PA */ +#define ECRYPT_BIG_ENDIAN + +/* + * Finally machines with UNKNOWN endianness: + */ +#elif defined (_AIX) /* RS6000 */ +#define ECRYPT_UNKNOWN +#elif defined(__aux) /* 68K */ +#define ECRYPT_UNKNOWN +#elif defined(__dgux) /* 88K (but P6 in latest boxes) */ +#define ECRYPT_UNKNOWN +#elif defined(__sgi) /* Newer MIPS */ +#define ECRYPT_UNKNOWN +#else /* Any other processor */ +#define ECRYPT_UNKNOWN +#endif + +/* ------------------------------------------------------------------------- */ + +/* + * Find minimal-width types to store 8-bit, 16-bit, 32-bit, and 64-bit + * integers. + * + * Note: to enable 64-bit types on 32-bit compilers, it might be + * necessary to switch from ISO C90 mode to ISO C99 mode (e.g., gcc + * -std=c99), or to allow compiler-specific extensions. + */ + +#include + +/* --- check char --- */ + +#if (UCHAR_MAX / 0xFU > 0xFU) +#ifndef I8T +#define I8T char +#define U8C(v) (v##U) + +#if (UCHAR_MAX == 0xFFU) +#define ECRYPT_I8T_IS_BYTE +#endif + +#endif + +#if (UCHAR_MAX / 0xFFU > 0xFFU) +#ifndef I16T +#define I16T char +#define U16C(v) (v##U) +#endif + +#if (UCHAR_MAX / 0xFFFFU > 0xFFFFU) +#ifndef I32T +#define I32T char +#define U32C(v) (v##U) +#endif + +#if (UCHAR_MAX / 0xFFFFFFFFU > 0xFFFFFFFFU) +#ifndef I64T +#define I64T char +#define U64C(v) (v##U) +#define ECRYPT_NATIVE64 +#endif + +#endif +#endif +#endif +#endif + +/* --- check short --- */ + +#if (USHRT_MAX / 0xFU > 0xFU) +#ifndef I8T +#define I8T short +#define U8C(v) (v##U) + +#if (USHRT_MAX == 0xFFU) +#define ECRYPT_I8T_IS_BYTE +#endif + +#endif + +#if (USHRT_MAX / 0xFFU > 0xFFU) +#ifndef I16T +#define I16T short +#define U16C(v) (v##U) +#endif + +#if (USHRT_MAX / 0xFFFFU > 0xFFFFU) +#ifndef I32T +#define I32T short +#define U32C(v) (v##U) +#endif + +#if (USHRT_MAX / 0xFFFFFFFFU > 0xFFFFFFFFU) +#ifndef I64T +#define I64T short +#define U64C(v) (v##U) +#define ECRYPT_NATIVE64 +#endif + +#endif +#endif +#endif +#endif + +/* --- check int --- */ + +#if (UINT_MAX / 0xFU > 0xFU) +#ifndef I8T +#define I8T int +#define U8C(v) (v##U) + +#if (ULONG_MAX == 0xFFU) +#define ECRYPT_I8T_IS_BYTE +#endif + +#endif + +#if (UINT_MAX / 0xFFU > 0xFFU) +#ifndef I16T +#define I16T int +#define U16C(v) (v##U) +#endif + +#if (UINT_MAX / 0xFFFFU > 0xFFFFU) +#ifndef I32T +#define I32T int +#define U32C(v) (v##U) +#endif + +#if (UINT_MAX / 0xFFFFFFFFU > 0xFFFFFFFFU) +#ifndef I64T +#define I64T int +#define U64C(v) (v##U) +#define ECRYPT_NATIVE64 +#endif + +#endif +#endif +#endif +#endif + +/* --- check long --- */ + +#if (ULONG_MAX / 0xFUL > 0xFUL) +#ifndef I8T +#define I8T long +#define U8C(v) (v##UL) + +#if (ULONG_MAX == 0xFFUL) +#define ECRYPT_I8T_IS_BYTE +#endif + +#endif + +#if (ULONG_MAX / 0xFFUL > 0xFFUL) +#ifndef I16T +#define I16T long +#define U16C(v) (v##UL) +#endif + +#if (ULONG_MAX / 0xFFFFUL > 0xFFFFUL) +#ifndef I32T +#define I32T long +#define U32C(v) (v##UL) +#endif + +#if (ULONG_MAX / 0xFFFFFFFFUL > 0xFFFFFFFFUL) +#ifndef I64T +#define I64T long +#define U64C(v) (v##UL) +#define ECRYPT_NATIVE64 +#endif + +#endif +#endif +#endif +#endif + +/* --- check long long --- */ + +#ifdef ULLONG_MAX + +#if (ULLONG_MAX / 0xFULL > 0xFULL) +#ifndef I8T +#define I8T long long +#define U8C(v) (v##ULL) + +#if (ULLONG_MAX == 0xFFULL) +#define ECRYPT_I8T_IS_BYTE +#endif + +#endif + +#if (ULLONG_MAX / 0xFFULL > 0xFFULL) +#ifndef I16T +#define I16T long long +#define U16C(v) (v##ULL) +#endif + +#if (ULLONG_MAX / 0xFFFFULL > 0xFFFFULL) +#ifndef I32T +#define I32T long long +#define U32C(v) (v##ULL) +#endif + +#if (ULLONG_MAX / 0xFFFFFFFFULL > 0xFFFFFFFFULL) +#ifndef I64T +#define I64T long long +#define U64C(v) (v##ULL) +#endif + +#endif +#endif +#endif +#endif + +#endif + +/* --- check __int64 --- */ + +#if !defined(__STDC__) && defined(_UI64_MAX) + +#ifndef I64T +#define I64T __int64 +#define U64C(v) (v##ui64) +#endif + +#endif + +/* --- if platform doesn't announce anything, use most common choices --- */ + +#ifndef I8T +#define I8T char +#define U8C(v) (v##U) +#endif +#ifndef I16T +#define I16T short +#define U16C(v) (v##U) +#endif +#ifndef I32T +#define I32T int +#define U32C(v) (v##U) +#endif +#ifndef I64T +#define I64T long long +#define U64C(v) (v##ULL) +#endif + +/* ------------------------------------------------------------------------- */ + +/* find the largest type on this platform (used for alignment) */ + +#if defined(__SSE__) || (defined(_MSC_VER) && (_MSC_VER >= 1300)) + +#include +#define MAXT __m128 + +#elif defined(__MMX__) + +#include +#define MAXT __m64 + +#elif defined(__ALTIVEC__) + +#define MAXT __vector int + +#else + +#define MAXT long + +#endif + +/* ------------------------------------------------------------------------- */ + +#endif diff --git a/deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-machine.h b/deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-machine.h new file mode 100644 index 000000000..d006bedec --- /dev/null +++ b/deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-machine.h @@ -0,0 +1,49 @@ +/* ecrypt-machine.h */ + +/* + * This file is included by 'ecrypt-portable.h'. It allows to override + * the default macros for specific platforms. Please carefully check + * the machine code generated by your compiler (with optimisations + * turned on) before deciding to edit this file. + */ + +/* ------------------------------------------------------------------------- */ + +#if (defined(ECRYPT_DEFAULT_ROT) && !defined(ECRYPT_MACHINE_ROT)) + +#define ECRYPT_MACHINE_ROT + +#if (defined(WIN32) && defined(_MSC_VER)) + +#undef ROTL32 +#undef ROTR32 +#undef ROTL64 +#undef ROTR64 + +#include + +#pragma intrinsic(_lrotl) /* compile rotations "inline" */ +#pragma intrinsic(_lrotr) + +#define ROTL32(v, n) _lrotl(v, n) +#define ROTR32(v, n) _lrotr(v, n) +#define ROTL64(v, n) _rotl64(v, n) +#define ROTR64(v, n) _rotr64(v, n) + +#endif + +#endif + +/* ------------------------------------------------------------------------- */ + +#if (defined(ECRYPT_DEFAULT_SWAP) && !defined(ECRYPT_MACHINE_SWAP)) + +#define ECRYPT_MACHINE_SWAP + +/* + * If you want to overwrite the default swap macros, put it here. And so on. + */ + +#endif + +/* ------------------------------------------------------------------------- */ diff --git a/deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-portable.h b/deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-portable.h new file mode 100644 index 000000000..e5276d846 --- /dev/null +++ b/deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-portable.h @@ -0,0 +1,275 @@ +/* ecrypt-portable.h */ + +/* + * WARNING: the conversions defined below are implemented as macros, + * and should be used carefully. They should NOT be used with + * parameters which perform some action. E.g., the following two lines + * are not equivalent: + * + * 1) ++x; y = ROTL32(x, n); + * 2) y = ROTL32(++x, n); + */ + +/* + * *** Please do not edit this file. *** + * + * The default macros can be overridden for specific architectures by + * editing 'ecrypt-machine.h'. + */ + +#ifndef ECRYPT_PORTABLE +#define ECRYPT_PORTABLE + +#include "ecrypt-config.h" +#include "ecrypt-types.h" + +/* ------------------------------------------------------------------------- */ + +/* + * The following macros are used to obtain exact-width results. + */ + +#define U8V(v) ((u8)(v) & U8C(0xFF)) +#define U16V(v) ((u16)(v) & U16C(0xFFFF)) +#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) +#define U64V(v) ((u64)(v) & U64C(0xFFFFFFFFFFFFFFFF)) + +/* ------------------------------------------------------------------------- */ + +/* + * The following macros return words with their bits rotated over n + * positions to the left/right. + */ + +#define ECRYPT_DEFAULT_ROT + +#define ROTL8(v, n) \ + (U8V((v) << (n)) | ((v) >> (8 - (n)))) + +#define ROTL16(v, n) \ + (U16V((v) << (n)) | ((v) >> (16 - (n)))) + +#define ROTL32(v, n) \ + (U32V((v) << (n)) | ((v) >> (32 - (n)))) + +#define ROTL64(v, n) \ + (U64V((v) << (n)) | ((v) >> (64 - (n)))) + +#define ROTR8(v, n) ROTL8(v, 8 - (n)) +#define ROTR16(v, n) ROTL16(v, 16 - (n)) +#define ROTR32(v, n) ROTL32(v, 32 - (n)) +#define ROTR64(v, n) ROTL64(v, 64 - (n)) + +#include "ecrypt-machine.h" + +/* ------------------------------------------------------------------------- */ + +/* + * The following macros return a word with bytes in reverse order. + */ + +#define ECRYPT_DEFAULT_SWAP + +#define SWAP16(v) \ + ROTL16(v, 8) + +#define SWAP32(v) \ + ((ROTL32(v, 8) & U32C(0x00FF00FF)) | \ + (ROTL32(v, 24) & U32C(0xFF00FF00))) + +#ifdef ECRYPT_NATIVE64 +#define SWAP64(v) \ + ((ROTL64(v, 8) & U64C(0x000000FF000000FF)) | \ + (ROTL64(v, 24) & U64C(0x0000FF000000FF00)) | \ + (ROTL64(v, 40) & U64C(0x00FF000000FF0000)) | \ + (ROTL64(v, 56) & U64C(0xFF000000FF000000))) +#else +#define SWAP64(v) \ + (((u64)SWAP32(U32V(v)) << 32) | (u64)SWAP32(U32V(v >> 32))) +#endif + +#include "ecrypt-machine.h" + +#define ECRYPT_DEFAULT_WTOW + +#ifdef ECRYPT_LITTLE_ENDIAN +#define U16TO16_LITTLE(v) (v) +#define U32TO32_LITTLE(v) (v) +#define U64TO64_LITTLE(v) (v) + +#define U16TO16_BIG(v) SWAP16(v) +#define U32TO32_BIG(v) SWAP32(v) +#define U64TO64_BIG(v) SWAP64(v) +#endif + +#ifdef ECRYPT_BIG_ENDIAN +#define U16TO16_LITTLE(v) SWAP16(v) +#define U32TO32_LITTLE(v) SWAP32(v) +#define U64TO64_LITTLE(v) SWAP64(v) + +#define U16TO16_BIG(v) (v) +#define U32TO32_BIG(v) (v) +#define U64TO64_BIG(v) (v) +#endif + +#include "ecrypt-machine.h" + +/* + * The following macros load words from an array of bytes with + * different types of endianness, and vice versa. + */ + +#define ECRYPT_DEFAULT_BTOW + +#if (!defined(ECRYPT_UNKNOWN) && defined(ECRYPT_I8T_IS_BYTE)) + +#define U8TO16_LITTLE(p) U16TO16_LITTLE(((u16*)(p))[0]) +#define U8TO32_LITTLE(p) U32TO32_LITTLE(((u32*)(p))[0]) +#define U8TO64_LITTLE(p) U64TO64_LITTLE(((u64*)(p))[0]) + +#define U8TO16_BIG(p) U16TO16_BIG(((u16*)(p))[0]) +#define U8TO32_BIG(p) U32TO32_BIG(((u32*)(p))[0]) +#define U8TO64_BIG(p) U64TO64_BIG(((u64*)(p))[0]) + +#define U16TO8_LITTLE(p, v) (((u16*)(p))[0] = U16TO16_LITTLE(v)) +#define U32TO8_LITTLE(p, v) (((u32*)(p))[0] = U32TO32_LITTLE(v)) +#define U64TO8_LITTLE(p, v) (((u64*)(p))[0] = U64TO64_LITTLE(v)) + +#define U16TO8_BIG(p, v) (((u16*)(p))[0] = U16TO16_BIG(v)) +#define U32TO8_BIG(p, v) (((u32*)(p))[0] = U32TO32_BIG(v)) +#define U64TO8_BIG(p, v) (((u64*)(p))[0] = U64TO64_BIG(v)) + +#else + +#define U8TO16_LITTLE(p) \ + (((u16)((p)[0]) ) | \ + ((u16)((p)[1]) << 8)) + +#define U8TO32_LITTLE(p) \ + (((u32)((p)[0]) ) | \ + ((u32)((p)[1]) << 8) | \ + ((u32)((p)[2]) << 16) | \ + ((u32)((p)[3]) << 24)) + +#ifdef ECRYPT_NATIVE64 +#define U8TO64_LITTLE(p) \ + (((u64)((p)[0]) ) | \ + ((u64)((p)[1]) << 8) | \ + ((u64)((p)[2]) << 16) | \ + ((u64)((p)[3]) << 24) | \ + ((u64)((p)[4]) << 32) | \ + ((u64)((p)[5]) << 40) | \ + ((u64)((p)[6]) << 48) | \ + ((u64)((p)[7]) << 56)) +#else +#define U8TO64_LITTLE(p) \ + ((u64)U8TO32_LITTLE(p) | ((u64)U8TO32_LITTLE((p) + 4) << 32)) +#endif + +#define U8TO16_BIG(p) \ + (((u16)((p)[0]) << 8) | \ + ((u16)((p)[1]) )) + +#define U8TO32_BIG(p) \ + (((u32)((p)[0]) << 24) | \ + ((u32)((p)[1]) << 16) | \ + ((u32)((p)[2]) << 8) | \ + ((u32)((p)[3]) )) + +#ifdef ECRYPT_NATIVE64 +#define U8TO64_BIG(p) \ + (((u64)((p)[0]) << 56) | \ + ((u64)((p)[1]) << 48) | \ + ((u64)((p)[2]) << 40) | \ + ((u64)((p)[3]) << 32) | \ + ((u64)((p)[4]) << 24) | \ + ((u64)((p)[5]) << 16) | \ + ((u64)((p)[6]) << 8) | \ + ((u64)((p)[7]) )) +#else +#define U8TO64_BIG(p) \ + (((u64)U8TO32_BIG(p) << 32) | (u64)U8TO32_BIG((p) + 4)) +#endif + +#define U16TO8_LITTLE(p, v) \ + do { \ + (p)[0] = U8V((v) ); \ + (p)[1] = U8V((v) >> 8); \ + } while (0) + +#define U32TO8_LITTLE(p, v) \ + do { \ + (p)[0] = U8V((v) ); \ + (p)[1] = U8V((v) >> 8); \ + (p)[2] = U8V((v) >> 16); \ + (p)[3] = U8V((v) >> 24); \ + } while (0) + +#ifdef ECRYPT_NATIVE64 +#define U64TO8_LITTLE(p, v) \ + do { \ + (p)[0] = U8V((v) ); \ + (p)[1] = U8V((v) >> 8); \ + (p)[2] = U8V((v) >> 16); \ + (p)[3] = U8V((v) >> 24); \ + (p)[4] = U8V((v) >> 32); \ + (p)[5] = U8V((v) >> 40); \ + (p)[6] = U8V((v) >> 48); \ + (p)[7] = U8V((v) >> 56); \ + } while (0) +#else +#define U64TO8_LITTLE(p, v) \ + do { \ + U32TO8_LITTLE((p), U32V((v) )); \ + U32TO8_LITTLE((p) + 4, U32V((v) >> 32)); \ + } while (0) +#endif + +#define U16TO8_BIG(p, v) \ + do { \ + (p)[0] = U8V((v) ); \ + (p)[1] = U8V((v) >> 8); \ + } while (0) + +#define U32TO8_BIG(p, v) \ + do { \ + (p)[0] = U8V((v) >> 24); \ + (p)[1] = U8V((v) >> 16); \ + (p)[2] = U8V((v) >> 8); \ + (p)[3] = U8V((v) ); \ + } while (0) + +#ifdef ECRYPT_NATIVE64 +#define U64TO8_BIG(p, v) \ + do { \ + (p)[0] = U8V((v) >> 56); \ + (p)[1] = U8V((v) >> 48); \ + (p)[2] = U8V((v) >> 40); \ + (p)[3] = U8V((v) >> 32); \ + (p)[4] = U8V((v) >> 24); \ + (p)[5] = U8V((v) >> 16); \ + (p)[6] = U8V((v) >> 8); \ + (p)[7] = U8V((v) ); \ + } while (0) +#else +#define U64TO8_BIG(p, v) \ + do { \ + U32TO8_BIG((p), U32V((v) >> 32)); \ + U32TO8_BIG((p) + 4, U32V((v) )); \ + } while (0) +#endif + +#endif + +#include "ecrypt-machine.h" + +/* ------------------------------------------------------------------------- */ + +#define AT_LEAST_ONE(n) (((n) < 1) ? 1 : (n)) + +#define ALIGN(t, v, n) \ + union { t b[n]; MAXT l[AT_LEAST_ONE(n * sizeof(t) / sizeof(MAXT))]; } v + +/* ------------------------------------------------------------------------- */ + +#endif diff --git a/deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-sync.h b/deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-sync.h new file mode 100644 index 000000000..efce9dde2 --- /dev/null +++ b/deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-sync.h @@ -0,0 +1,290 @@ +#define ECRYPT_VARIANT 1 +#define ECRYPT_API +/* ecrypt-sync.h */ + +/* + * Header file for synchronous stream ciphers without authentication + * mechanism. + * + * *** Please only edit parts marked with "[edit]". *** + */ + +#ifndef ECRYPT_SYNC +#define ECRYPT_SYNC + +#include "ecrypt-types.h" + +/* ------------------------------------------------------------------------- */ + +/* Cipher parameters */ + +/* + * The name of your cipher. + */ +#define ECRYPT_NAME "ChaCha20" +#define ECRYPT_PROFILE "_____" + +/* + * Specify which key and IV sizes are supported by your cipher. A user + * should be able to enumerate the supported sizes by running the + * following code: + * + * for (i = 0; ECRYPT_KEYSIZE(i) <= ECRYPT_MAXKEYSIZE; ++i) + * { + * keysize = ECRYPT_KEYSIZE(i); + * + * ... + * } + * + * All sizes are in bits. + */ + +#define ECRYPT_MAXKEYSIZE 256 /* [edit] */ +#define ECRYPT_KEYSIZE(i) (128 + (i)*128) /* [edit] */ + +#define ECRYPT_MAXIVSIZE 64 /* [edit] */ +#define ECRYPT_IVSIZE(i) (64 + (i)*64) /* [edit] */ + +/* ------------------------------------------------------------------------- */ + +/* Data structures */ + +/* + * ECRYPT_ctx is the structure containing the representation of the + * internal state of your cipher. + */ + +typedef struct +{ + u32 input[16]; /* could be compressed */ + /* + * [edit] + * + * Put here all state variable needed during the encryption process. + */ +} ECRYPT_ctx; + +/* ------------------------------------------------------------------------- */ + +/* Mandatory functions */ + +/* + * Key and message independent initialization. This function will be + * called once when the program starts (e.g., to build expanded S-box + * tables). + */ +void ECRYPT_init(void); + +/* + * Key setup. It is the user's responsibility to select the values of + * keysize and ivsize from the set of supported values specified + * above. + */ +void ECRYPT_keysetup( + ECRYPT_ctx* ctx, + const u8* key, + u32 keysize, /* Key size in bits. */ + u32 ivsize); /* IV size in bits. */ + +/* + * IV setup. After having called ECRYPT_keysetup(), the user is + * allowed to call ECRYPT_ivsetup() different times in order to + * encrypt/decrypt different messages with the same key but different + * IV's. ECRYPT_ivsetup() also sets block counter to zero. + */ +void ECRYPT_ivsetup( + ECRYPT_ctx* ctx, + const u8* iv); + +/* + * Block counter setup. It is used only for special purposes, + * since block counter is usually initialized with ECRYPT_ivsetup. + * ECRYPT_ctrsetup has to be called after ECRYPT_ivsetup. + */ +void ECRYPT_ctrsetup( + ECRYPT_ctx* ctx, + const u8* ctr); + +/* + * Encryption/decryption of arbitrary length messages. + * + * For efficiency reasons, the API provides two types of + * encrypt/decrypt functions. The ECRYPT_encrypt_bytes() function + * (declared here) encrypts byte strings of arbitrary length, while + * the ECRYPT_encrypt_blocks() function (defined later) only accepts + * lengths which are multiples of ECRYPT_BLOCKLENGTH. + * + * The user is allowed to make multiple calls to + * ECRYPT_encrypt_blocks() to incrementally encrypt a long message, + * but he is NOT allowed to make additional encryption calls once he + * has called ECRYPT_encrypt_bytes() (unless he starts a new message + * of course). For example, this sequence of calls is acceptable: + * + * ECRYPT_keysetup(); + * + * ECRYPT_ivsetup(); + * ECRYPT_encrypt_blocks(); + * ECRYPT_encrypt_blocks(); + * ECRYPT_encrypt_bytes(); + * + * ECRYPT_ivsetup(); + * ECRYPT_encrypt_blocks(); + * ECRYPT_encrypt_blocks(); + * + * ECRYPT_ivsetup(); + * ECRYPT_encrypt_bytes(); + * + * The following sequence is not: + * + * ECRYPT_keysetup(); + * ECRYPT_ivsetup(); + * ECRYPT_encrypt_blocks(); + * ECRYPT_encrypt_bytes(); + * ECRYPT_encrypt_blocks(); + */ + +void ECRYPT_encrypt_bytes( + ECRYPT_ctx* ctx, + const u8* plaintext, + u8* ciphertext, + u32 msglen); /* Message length in bytes. */ + +void ECRYPT_decrypt_bytes( + ECRYPT_ctx* ctx, + const u8* ciphertext, + u8* plaintext, + u32 msglen); /* Message length in bytes. */ + +/* ------------------------------------------------------------------------- */ + +/* Optional features */ + +/* + * For testing purposes it can sometimes be useful to have a function + * which immediately generates keystream without having to provide it + * with a zero plaintext. If your cipher cannot provide this function + * (e.g., because it is not strictly a synchronous cipher), please + * reset the ECRYPT_GENERATES_KEYSTREAM flag. + */ + +#define ECRYPT_GENERATES_KEYSTREAM +#ifdef ECRYPT_GENERATES_KEYSTREAM + +void ECRYPT_keystream_bytes( + ECRYPT_ctx* ctx, + u8* keystream, + u32 length); /* Length of keystream in bytes. */ + +#endif + +/* ------------------------------------------------------------------------- */ + +/* Optional optimizations */ + +/* + * By default, the functions in this section are implemented using + * calls to functions declared above. However, you might want to + * implement them differently for performance reasons. + */ + +/* + * All-in-one encryption/decryption of (short) packets. + * + * The default definitions of these functions can be found in + * "ecrypt-sync.c". If you want to implement them differently, please + * undef the ECRYPT_USES_DEFAULT_ALL_IN_ONE flag. + */ +#define ECRYPT_USES_DEFAULT_ALL_IN_ONE /* [edit] */ + +void ECRYPT_encrypt_packet( + ECRYPT_ctx* ctx, + const u8* iv, + const u8* plaintext, + u8* ciphertext, + u32 msglen); + +void ECRYPT_decrypt_packet( + ECRYPT_ctx* ctx, + const u8* iv, + const u8* ciphertext, + u8* plaintext, + u32 msglen); + +/* + * Encryption/decryption of blocks. + * + * By default, these functions are defined as macros. If you want to + * provide a different implementation, please undef the + * ECRYPT_USES_DEFAULT_BLOCK_MACROS flag and implement the functions + * declared below. + */ + +#define ECRYPT_BLOCKLENGTH 64 /* [edit] */ + +#define ECRYPT_USES_DEFAULT_BLOCK_MACROS /* [edit] */ +#ifdef ECRYPT_USES_DEFAULT_BLOCK_MACROS + +#define ECRYPT_encrypt_blocks(ctx, plaintext, ciphertext, blocks) \ + ECRYPT_encrypt_bytes(ctx, plaintext, ciphertext, \ + (blocks) * ECRYPT_BLOCKLENGTH) + +#define ECRYPT_decrypt_blocks(ctx, ciphertext, plaintext, blocks) \ + ECRYPT_decrypt_bytes(ctx, ciphertext, plaintext, \ + (blocks) * ECRYPT_BLOCKLENGTH) + +#ifdef ECRYPT_GENERATES_KEYSTREAM + +#define ECRYPT_keystream_blocks(ctx, keystream, blocks) \ + ECRYPT_keystream_bytes(ctx, keystream, \ + (blocks) * ECRYPT_BLOCKLENGTH) + +#endif + +#else + +void ECRYPT_encrypt_blocks( + ECRYPT_ctx* ctx, + const u8* plaintext, + u8* ciphertext, + u32 blocks); /* Message length in blocks. */ + +void ECRYPT_decrypt_blocks( + ECRYPT_ctx* ctx, + const u8* ciphertext, + u8* plaintext, + u32 blocks); /* Message length in blocks. */ + +#ifdef ECRYPT_GENERATES_KEYSTREAM + +void ECRYPT_keystream_blocks( + ECRYPT_ctx* ctx, + const u8* keystream, + u32 blocks); /* Keystream length in blocks. */ + +#endif + +#endif + +/* + * If your cipher can be implemented in different ways, you can use + * the ECRYPT_VARIANT parameter to allow the user to choose between + * them at compile time (e.g., gcc -DECRYPT_VARIANT=3 ...). Please + * only use this possibility if you really think it could make a + * significant difference and keep the number of variants + * (ECRYPT_MAXVARIANT) as small as possible (definitely not more than + * 10). Note also that all variants should have exactly the same + * external interface (i.e., the same ECRYPT_BLOCKLENGTH, etc.). + */ +#define ECRYPT_MAXVARIANT 1 /* [edit] */ + +#ifndef ECRYPT_VARIANT +#define ECRYPT_VARIANT 1 +#endif + +#if (ECRYPT_VARIANT > ECRYPT_MAXVARIANT) +#error this variant does not exist +#endif + +/* ------------------------------------------------------------------------- */ + +#endif diff --git a/deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-types.h b/deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-types.h new file mode 100644 index 000000000..e608e220a --- /dev/null +++ b/deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-types.h @@ -0,0 +1,53 @@ +/* ecrypt-types.h */ + +/* + * *** Please do not edit this file. *** + * + * The default macros can be overridden for specific architectures by + * editing 'ecrypt-machine.h'. + */ + +#ifndef ECRYPT_TYPES +#define ECRYPT_TYPES + +#include "ecrypt-config.h" + +/* ------------------------------------------------------------------------- */ + +/* + * The following types are defined (if available): + * + * u8: unsigned integer type, at least 8 bits + * u16: unsigned integer type, at least 16 bits + * u32: unsigned integer type, at least 32 bits + * u64: unsigned integer type, at least 64 bits + * + * s8, s16, s32, s64 -> signed counterparts of u8, u16, u32, u64 + * + * The selection of minimum-width integer types is taken care of by + * 'ecrypt-config.h'. Note: to enable 64-bit types on 32-bit + * compilers, it might be necessary to switch from ISO C90 mode to ISO + * C99 mode (e.g., gcc -std=c99). + */ + +#ifdef I8T +typedef signed I8T s8; +typedef unsigned I8T u8; +#endif + +#ifdef I16T +typedef signed I16T s16; +typedef unsigned I16T u16; +#endif + +#ifdef I32T +typedef signed I32T s32; +typedef unsigned I32T u32; +#endif + +#ifdef I64T +typedef signed I64T s64; +typedef unsigned I64T u64; +#endif + +#endif diff --git a/deps/crypto/trezor-crypto/chacha20poly1305/poly1305-donna-32.h b/deps/crypto/trezor-crypto/chacha20poly1305/poly1305-donna-32.h new file mode 100644 index 000000000..eab8acdbf --- /dev/null +++ b/deps/crypto/trezor-crypto/chacha20poly1305/poly1305-donna-32.h @@ -0,0 +1,218 @@ +/* + poly1305 implementation using 32 bit * 32 bit = 64 bit multiplication and 64 bit addition +*/ + +#if defined(_MSC_VER) + #define POLY1305_NOINLINE __declspec(noinline) +#elif defined(__GNUC__) + #define POLY1305_NOINLINE __attribute__((noinline)) +#else + #define POLY1305_NOINLINE +#endif + +#define poly1305_block_size 16 + +/* 17 + sizeof(size_t) + 14*sizeof(unsigned long) */ +typedef struct poly1305_state_internal_t { + unsigned long r[5]; + unsigned long h[5]; + unsigned long pad[4]; + size_t leftover; + unsigned char buffer[poly1305_block_size]; + unsigned char final; +} poly1305_state_internal_t; + +/* interpret four 8 bit unsigned integers as a 32 bit unsigned integer in little endian */ +static unsigned long +U8TO32(const unsigned char *p) { + return + (((unsigned long)(p[0] & 0xff) ) | + ((unsigned long)(p[1] & 0xff) << 8) | + ((unsigned long)(p[2] & 0xff) << 16) | + ((unsigned long)(p[3] & 0xff) << 24)); +} + +/* store a 32 bit unsigned integer as four 8 bit unsigned integers in little endian */ +static void +U32TO8(unsigned char *p, unsigned long v) { + p[0] = (v ) & 0xff; + p[1] = (v >> 8) & 0xff; + p[2] = (v >> 16) & 0xff; + p[3] = (v >> 24) & 0xff; +} + +void +poly1305_init(poly1305_context *ctx, const unsigned char key[32]) { + poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; + + /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ + st->r[0] = (U8TO32(&key[ 0]) ) & 0x3ffffff; + st->r[1] = (U8TO32(&key[ 3]) >> 2) & 0x3ffff03; + st->r[2] = (U8TO32(&key[ 6]) >> 4) & 0x3ffc0ff; + st->r[3] = (U8TO32(&key[ 9]) >> 6) & 0x3f03fff; + st->r[4] = (U8TO32(&key[12]) >> 8) & 0x00fffff; + + /* h = 0 */ + st->h[0] = 0; + st->h[1] = 0; + st->h[2] = 0; + st->h[3] = 0; + st->h[4] = 0; + + /* save pad for later */ + st->pad[0] = U8TO32(&key[16]); + st->pad[1] = U8TO32(&key[20]); + st->pad[2] = U8TO32(&key[24]); + st->pad[3] = U8TO32(&key[28]); + + st->leftover = 0; + st->final = 0; +} + +static void +poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t bytes) { + const unsigned long hibit = (st->final) ? 0 : (1UL << 24); /* 1 << 128 */ + unsigned long r0,r1,r2,r3,r4; + unsigned long s1,s2,s3,s4; + unsigned long h0,h1,h2,h3,h4; + unsigned long long d0,d1,d2,d3,d4; + unsigned long c; + + r0 = st->r[0]; + r1 = st->r[1]; + r2 = st->r[2]; + r3 = st->r[3]; + r4 = st->r[4]; + + s1 = r1 * 5; + s2 = r2 * 5; + s3 = r3 * 5; + s4 = r4 * 5; + + h0 = st->h[0]; + h1 = st->h[1]; + h2 = st->h[2]; + h3 = st->h[3]; + h4 = st->h[4]; + + while (bytes >= poly1305_block_size) { + /* h += m[i] */ + h0 += (U8TO32(m+ 0) ) & 0x3ffffff; + h1 += (U8TO32(m+ 3) >> 2) & 0x3ffffff; + h2 += (U8TO32(m+ 6) >> 4) & 0x3ffffff; + h3 += (U8TO32(m+ 9) >> 6) & 0x3ffffff; + h4 += (U8TO32(m+12) >> 8) | hibit; + + /* h *= r */ + d0 = ((unsigned long long)h0 * r0) + ((unsigned long long)h1 * s4) + ((unsigned long long)h2 * s3) + ((unsigned long long)h3 * s2) + ((unsigned long long)h4 * s1); + d1 = ((unsigned long long)h0 * r1) + ((unsigned long long)h1 * r0) + ((unsigned long long)h2 * s4) + ((unsigned long long)h3 * s3) + ((unsigned long long)h4 * s2); + d2 = ((unsigned long long)h0 * r2) + ((unsigned long long)h1 * r1) + ((unsigned long long)h2 * r0) + ((unsigned long long)h3 * s4) + ((unsigned long long)h4 * s3); + d3 = ((unsigned long long)h0 * r3) + ((unsigned long long)h1 * r2) + ((unsigned long long)h2 * r1) + ((unsigned long long)h3 * r0) + ((unsigned long long)h4 * s4); + d4 = ((unsigned long long)h0 * r4) + ((unsigned long long)h1 * r3) + ((unsigned long long)h2 * r2) + ((unsigned long long)h3 * r1) + ((unsigned long long)h4 * r0); + + /* (partial) h %= p */ + c = (unsigned long)(d0 >> 26); h0 = (unsigned long)d0 & 0x3ffffff; + d1 += c; c = (unsigned long)(d1 >> 26); h1 = (unsigned long)d1 & 0x3ffffff; + d2 += c; c = (unsigned long)(d2 >> 26); h2 = (unsigned long)d2 & 0x3ffffff; + d3 += c; c = (unsigned long)(d3 >> 26); h3 = (unsigned long)d3 & 0x3ffffff; + d4 += c; c = (unsigned long)(d4 >> 26); h4 = (unsigned long)d4 & 0x3ffffff; + h0 += c * 5; c = (h0 >> 26); h0 = h0 & 0x3ffffff; + h1 += c; + + m += poly1305_block_size; + bytes -= poly1305_block_size; + } + + st->h[0] = h0; + st->h[1] = h1; + st->h[2] = h2; + st->h[3] = h3; + st->h[4] = h4; +} + +POLY1305_NOINLINE void +poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) { + poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; + unsigned long h0,h1,h2,h3,h4,c; + unsigned long g0,g1,g2,g3,g4; + unsigned long long f; + unsigned long mask; + + /* process the remaining block */ + if (st->leftover) { + size_t i = st->leftover; + st->buffer[i++] = 1; + for (; i < poly1305_block_size; i++) + st->buffer[i] = 0; + st->final = 1; + poly1305_blocks(st, st->buffer, poly1305_block_size); + } + + /* fully carry h */ + h0 = st->h[0]; + h1 = st->h[1]; + h2 = st->h[2]; + h3 = st->h[3]; + h4 = st->h[4]; + + c = h1 >> 26; h1 = h1 & 0x3ffffff; + h2 += c; c = h2 >> 26; h2 = h2 & 0x3ffffff; + h3 += c; c = h3 >> 26; h3 = h3 & 0x3ffffff; + h4 += c; c = h4 >> 26; h4 = h4 & 0x3ffffff; + h0 += c * 5; c = h0 >> 26; h0 = h0 & 0x3ffffff; + h1 += c; + + /* compute h + -p */ + g0 = h0 + 5; c = g0 >> 26; g0 &= 0x3ffffff; + g1 = h1 + c; c = g1 >> 26; g1 &= 0x3ffffff; + g2 = h2 + c; c = g2 >> 26; g2 &= 0x3ffffff; + g3 = h3 + c; c = g3 >> 26; g3 &= 0x3ffffff; + g4 = h4 + c - (1UL << 26); + + /* select h if h < p, or h + -p if h >= p */ + mask = (g4 >> ((sizeof(unsigned long) * 8) - 1)) - 1; + g0 &= mask; + g1 &= mask; + g2 &= mask; + g3 &= mask; + g4 &= mask; + mask = ~mask; + h0 = (h0 & mask) | g0; + h1 = (h1 & mask) | g1; + h2 = (h2 & mask) | g2; + h3 = (h3 & mask) | g3; + h4 = (h4 & mask) | g4; + + /* h = h % (2^128) */ + h0 = ((h0 ) | (h1 << 26)) & 0xffffffff; + h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff; + h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff; + h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff; + + /* mac = (h + pad) % (2^128) */ + f = (unsigned long long)h0 + st->pad[0] ; h0 = (unsigned long)f; + f = (unsigned long long)h1 + st->pad[1] + (f >> 32); h1 = (unsigned long)f; + f = (unsigned long long)h2 + st->pad[2] + (f >> 32); h2 = (unsigned long)f; + f = (unsigned long long)h3 + st->pad[3] + (f >> 32); h3 = (unsigned long)f; + + U32TO8(mac + 0, h0); + U32TO8(mac + 4, h1); + U32TO8(mac + 8, h2); + U32TO8(mac + 12, h3); + + /* zero out the state */ + st->h[0] = 0; + st->h[1] = 0; + st->h[2] = 0; + st->h[3] = 0; + st->h[4] = 0; + st->r[0] = 0; + st->r[1] = 0; + st->r[2] = 0; + st->r[3] = 0; + st->r[4] = 0; + st->pad[0] = 0; + st->pad[1] = 0; + st->pad[2] = 0; + st->pad[3] = 0; +} diff --git a/deps/crypto/trezor-crypto/chacha20poly1305/poly1305-donna.c b/deps/crypto/trezor-crypto/chacha20poly1305/poly1305-donna.c new file mode 100644 index 000000000..bb6e7a3ec --- /dev/null +++ b/deps/crypto/trezor-crypto/chacha20poly1305/poly1305-donna.c @@ -0,0 +1,179 @@ +#include "poly1305-donna.h" +#include "poly1305-donna-32.h" + +void +poly1305_update(poly1305_context *ctx, const unsigned char *m, size_t bytes) { + poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; + size_t i = 0; + + /* handle leftover */ + if (st->leftover) { + size_t want = (poly1305_block_size - st->leftover); + if (want > bytes) + want = bytes; + for (i = 0; i < want; i++) + st->buffer[st->leftover + i] = m[i]; + bytes -= want; + m += want; + st->leftover += want; + if (st->leftover < poly1305_block_size) + return; + poly1305_blocks(st, st->buffer, poly1305_block_size); + st->leftover = 0; + } + + /* process full blocks */ + if (bytes >= poly1305_block_size) { + size_t want = (bytes & ~(poly1305_block_size - 1)); + poly1305_blocks(st, m, want); + m += want; + bytes -= want; + } + + /* store leftover */ + if (bytes) { + for (i = 0; i < bytes; i++) + st->buffer[st->leftover + i] = m[i]; + st->leftover += bytes; + } +} + +void +poly1305_auth(unsigned char mac[16], const unsigned char *m, size_t bytes, const unsigned char key[32]) { + poly1305_context ctx = {0}; + poly1305_init(&ctx, key); + poly1305_update(&ctx, m, bytes); + poly1305_finish(&ctx, mac); +} + +int +poly1305_verify(const unsigned char mac1[16], const unsigned char mac2[16]) { + size_t i = 0; + unsigned int dif = 0; + for (i = 0; i < 16; i++) + dif |= (mac1[i] ^ mac2[i]); + dif = (dif - 1) >> ((sizeof(unsigned int) * 8) - 1); + return (dif & 1); +} + + +/* test a few basic operations */ +int +poly1305_power_on_self_test(void) { + /* example from nacl */ + static const unsigned char nacl_key[32] = { + 0xee,0xa6,0xa7,0x25,0x1c,0x1e,0x72,0x91, + 0x6d,0x11,0xc2,0xcb,0x21,0x4d,0x3c,0x25, + 0x25,0x39,0x12,0x1d,0x8e,0x23,0x4e,0x65, + 0x2d,0x65,0x1f,0xa4,0xc8,0xcf,0xf8,0x80, + }; + + static const unsigned char nacl_msg[131] = { + 0x8e,0x99,0x3b,0x9f,0x48,0x68,0x12,0x73, + 0xc2,0x96,0x50,0xba,0x32,0xfc,0x76,0xce, + 0x48,0x33,0x2e,0xa7,0x16,0x4d,0x96,0xa4, + 0x47,0x6f,0xb8,0xc5,0x31,0xa1,0x18,0x6a, + 0xc0,0xdf,0xc1,0x7c,0x98,0xdc,0xe8,0x7b, + 0x4d,0xa7,0xf0,0x11,0xec,0x48,0xc9,0x72, + 0x71,0xd2,0xc2,0x0f,0x9b,0x92,0x8f,0xe2, + 0x27,0x0d,0x6f,0xb8,0x63,0xd5,0x17,0x38, + 0xb4,0x8e,0xee,0xe3,0x14,0xa7,0xcc,0x8a, + 0xb9,0x32,0x16,0x45,0x48,0xe5,0x26,0xae, + 0x90,0x22,0x43,0x68,0x51,0x7a,0xcf,0xea, + 0xbd,0x6b,0xb3,0x73,0x2b,0xc0,0xe9,0xda, + 0x99,0x83,0x2b,0x61,0xca,0x01,0xb6,0xde, + 0x56,0x24,0x4a,0x9e,0x88,0xd5,0xf9,0xb3, + 0x79,0x73,0xf6,0x22,0xa4,0x3d,0x14,0xa6, + 0x59,0x9b,0x1f,0x65,0x4c,0xb4,0x5a,0x74, + 0xe3,0x55,0xa5 + }; + + static const unsigned char nacl_mac[16] = { + 0xf3,0xff,0xc7,0x70,0x3f,0x94,0x00,0xe5, + 0x2a,0x7d,0xfb,0x4b,0x3d,0x33,0x05,0xd9 + }; + + /* generates a final value of (2^130 - 2) == 3 */ + static const unsigned char wrap_key[32] = { + 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + }; + + static const unsigned char wrap_msg[16] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff + }; + + static const unsigned char wrap_mac[16] = { + 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + }; + + /* + mac of the macs of messages of length 0 to 256, where the key and messages + have all their values set to the length + */ + static const unsigned char total_key[32] = { + 0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0xff,0xfe,0xfd,0xfc,0xfb,0xfa,0xf9, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff + }; + + static const unsigned char total_mac[16] = { + 0x64,0xaf,0xe2,0xe8,0xd6,0xad,0x7b,0xbd, + 0xd2,0x87,0xf9,0x7c,0x44,0x62,0x3d,0x39 + }; + + poly1305_context ctx = {0}; + poly1305_context total_ctx = {0}; + unsigned char all_key[32] = {0}; + unsigned char all_msg[256] = {0}; + unsigned char mac[16] = {0}; + size_t i = 0, j = 0; + int result = 1; + + for (i = 0; i < sizeof(mac); i++) + mac[i] = 0; + poly1305_auth(mac, nacl_msg, sizeof(nacl_msg), nacl_key); + result &= poly1305_verify(nacl_mac, mac); + + for (i = 0; i < sizeof(mac); i++) + mac[i] = 0; + poly1305_init(&ctx, nacl_key); + poly1305_update(&ctx, nacl_msg + 0, 32); + poly1305_update(&ctx, nacl_msg + 32, 64); + poly1305_update(&ctx, nacl_msg + 96, 16); + poly1305_update(&ctx, nacl_msg + 112, 8); + poly1305_update(&ctx, nacl_msg + 120, 4); + poly1305_update(&ctx, nacl_msg + 124, 2); + poly1305_update(&ctx, nacl_msg + 126, 1); + poly1305_update(&ctx, nacl_msg + 127, 1); + poly1305_update(&ctx, nacl_msg + 128, 1); + poly1305_update(&ctx, nacl_msg + 129, 1); + poly1305_update(&ctx, nacl_msg + 130, 1); + poly1305_finish(&ctx, mac); + result &= poly1305_verify(nacl_mac, mac); + + for (i = 0; i < sizeof(mac); i++) + mac[i] = 0; + poly1305_auth(mac, wrap_msg, sizeof(wrap_msg), wrap_key); + result &= poly1305_verify(wrap_mac, mac); + + poly1305_init(&total_ctx, total_key); + for (i = 0; i < 256; i++) { + /* set key and message to 'i,i,i..' */ + for (j = 0; j < sizeof(all_key); j++) + all_key[j] = i; + for (j = 0; j < i; j++) + all_msg[j] = i; + poly1305_auth(mac, all_msg, i, all_key); + poly1305_update(&total_ctx, mac, 16); + } + poly1305_finish(&total_ctx, mac); + result &= poly1305_verify(total_mac, mac); + + return result; +} diff --git a/deps/crypto/trezor-crypto/chacha20poly1305/poly1305-donna.h b/deps/crypto/trezor-crypto/chacha20poly1305/poly1305-donna.h new file mode 100644 index 000000000..39b7a8f5e --- /dev/null +++ b/deps/crypto/trezor-crypto/chacha20poly1305/poly1305-donna.h @@ -0,0 +1,19 @@ +#ifndef POLY1305_DONNA_H +#define POLY1305_DONNA_H + +#include + +typedef struct poly1305_context { + size_t aligner; + unsigned char opaque[136]; +} poly1305_context; + +void poly1305_init(poly1305_context *ctx, const unsigned char key[32]); +void poly1305_update(poly1305_context *ctx, const unsigned char *m, size_t bytes); +void poly1305_finish(poly1305_context *ctx, unsigned char mac[16]); +void poly1305_auth(unsigned char mac[16], const unsigned char *m, size_t bytes, const unsigned char key[32]); + +int poly1305_verify(const unsigned char mac1[16], const unsigned char mac2[16]); +int poly1305_power_on_self_test(void); + +#endif /* POLY1305_DONNA_H */ diff --git a/deps/crypto/trezor-crypto/chacha20poly1305/rfc7539.c b/deps/crypto/trezor-crypto/chacha20poly1305/rfc7539.c new file mode 100644 index 000000000..94e5f0b23 --- /dev/null +++ b/deps/crypto/trezor-crypto/chacha20poly1305/rfc7539.c @@ -0,0 +1,48 @@ +// Implementation of the ChaCha20 + Poly1305 AEAD construction +// as described in RFC 7539. + +#include +#include "rfc7539.h" +#include "ecrypt-portable.h" + +// Initialize the ChaCha20 + Poly1305 context for encryption or decryption +// using a 32 byte key and 12 byte nonce as in the RFC 7539 style. +void rfc7539_init(chacha20poly1305_ctx *ctx, const uint8_t key[32], const uint8_t nonce[12]) { + unsigned char block0[64] = {0}; + + ECRYPT_keysetup(&ctx->chacha20, key, 256, 16); + ctx->chacha20.input[12] = 0; + ctx->chacha20.input[13] = U8TO32_LITTLE(nonce + 0); + ctx->chacha20.input[14] = U8TO32_LITTLE(nonce + 4); + ctx->chacha20.input[15] = U8TO32_LITTLE(nonce + 8); + + // Encrypt 64 bytes of zeros and use the first 32 bytes + // as the Poly1305 key. + ECRYPT_encrypt_bytes(&ctx->chacha20, block0, block0, 64); + poly1305_init(&ctx->poly1305, block0); +} + +// Include authenticated data in the Poly1305 MAC using the RFC 7539 +// style with 16 byte padding. This must only be called once and prior +// to encryption or decryption. +void rfc7539_auth(chacha20poly1305_ctx *ctx, const uint8_t *in, size_t n) { + uint8_t padding[16] = {0}; + poly1305_update(&ctx->poly1305, in, n); + if (n % 16 != 0) + poly1305_update(&ctx->poly1305, padding, 16 - n%16); +} + +// Compute RFC 7539-style Poly1305 MAC. +void rfc7539_finish(chacha20poly1305_ctx *ctx, int64_t alen, int64_t plen, uint8_t mac[16]) { + uint8_t padding[16] = {0}; + uint8_t lengths[16] = {0}; + + memcpy(lengths, &alen, sizeof(int64_t)); + memcpy(lengths + 8, &plen, sizeof(int64_t)); + + if (plen % 16 != 0) + poly1305_update(&ctx->poly1305, padding, 16 - plen%16); + poly1305_update(&ctx->poly1305, lengths, 16); + + poly1305_finish(&ctx->poly1305, mac); +} diff --git a/deps/crypto/trezor-crypto/chacha20poly1305/rfc7539.h b/deps/crypto/trezor-crypto/chacha20poly1305/rfc7539.h new file mode 100644 index 000000000..75e3d1d7e --- /dev/null +++ b/deps/crypto/trezor-crypto/chacha20poly1305/rfc7539.h @@ -0,0 +1,10 @@ +#ifndef RFC7539_H +#define RFC7539_H + +#include "chacha20poly1305.h" + +void rfc7539_init(chacha20poly1305_ctx *ctx, const uint8_t key[32], const uint8_t nonce[12]); +void rfc7539_auth(chacha20poly1305_ctx *ctx, const uint8_t *in, size_t n); +void rfc7539_finish(chacha20poly1305_ctx *ctx, int64_t alen, int64_t plen, uint8_t mac[16]); + +#endif // RFC7539_H diff --git a/deps/crypto/trezor-crypto/chacha_drbg.c b/deps/crypto/trezor-crypto/chacha_drbg.c new file mode 100644 index 000000000..663b1a355 --- /dev/null +++ b/deps/crypto/trezor-crypto/chacha_drbg.c @@ -0,0 +1,126 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "chacha_drbg.h" + +#include +#include +#include + +#include "chacha20poly1305/ecrypt-portable.h" +#include "memzero.h" +#include "sha2.h" + +#define CHACHA_DRBG_KEY_LENGTH 32 +#define CHACHA_DRBG_COUNTER_LENGTH 8 +#define CHACHA_DRBG_IV_LENGTH 8 +#define CHACHA_DRBG_SEED_LENGTH \ + (CHACHA_DRBG_KEY_LENGTH + CHACHA_DRBG_COUNTER_LENGTH + CHACHA_DRBG_IV_LENGTH) + +#define MAX(a, b) (a) > (b) ? (a) : (b) + +static void derivation_function(const uint8_t *input1, size_t input1_length, + const uint8_t *input2, size_t input2_length, + uint8_t *output, size_t output_length) { + // Implementation of Hash_df from NIST SP 800-90A + uint32_t block_count = (output_length - 1) / SHA256_DIGEST_LENGTH + 1; + size_t partial_block_length = output_length % SHA256_DIGEST_LENGTH; + assert(block_count <= 255); + + uint32_t output_length_bits = output_length * 8; +#if BYTE_ORDER == LITTLE_ENDIAN + REVERSE32(output_length_bits, output_length_bits); +#endif + + SHA256_CTX ctx = {0}; + + for (uint8_t counter = 1; counter <= block_count; counter++) { + sha256_Init(&ctx); + sha256_Update(&ctx, &counter, sizeof(counter)); + sha256_Update(&ctx, (uint8_t *)&output_length_bits, + sizeof(output_length_bits)); + sha256_Update(&ctx, input1, input1_length); + sha256_Update(&ctx, input2, input2_length); + + if (counter != block_count || partial_block_length == 0) { + sha256_Final(&ctx, output); + output += SHA256_DIGEST_LENGTH; + } else { // last block is partial + uint8_t digest[SHA256_DIGEST_LENGTH] = {0}; + sha256_Final(&ctx, digest); + memcpy(output, digest, partial_block_length); + memzero(digest, sizeof(digest)); + } + } + + memzero(&ctx, sizeof(ctx)); +} + +void chacha_drbg_init(CHACHA_DRBG_CTX *ctx, const uint8_t *entropy, + size_t entropy_length, const uint8_t *nonce, + size_t nonce_length) { + uint8_t buffer[MAX(CHACHA_DRBG_KEY_LENGTH, CHACHA_DRBG_IV_LENGTH)] = {0}; + ECRYPT_keysetup(&ctx->chacha_ctx, buffer, CHACHA_DRBG_KEY_LENGTH * 8, + CHACHA_DRBG_IV_LENGTH * 8); + ECRYPT_ivsetup(&ctx->chacha_ctx, buffer); + + chacha_drbg_reseed(ctx, entropy, entropy_length, nonce, nonce_length); +} + +static void chacha_drbg_update(CHACHA_DRBG_CTX *ctx, + const uint8_t data[CHACHA_DRBG_SEED_LENGTH]) { + uint8_t seed[CHACHA_DRBG_SEED_LENGTH] = {0}; + + if (data) + ECRYPT_encrypt_bytes(&ctx->chacha_ctx, data, seed, CHACHA_DRBG_SEED_LENGTH); + else + ECRYPT_keystream_bytes(&ctx->chacha_ctx, seed, CHACHA_DRBG_SEED_LENGTH); + + ECRYPT_keysetup(&ctx->chacha_ctx, seed, CHACHA_DRBG_KEY_LENGTH * 8, + CHACHA_DRBG_IV_LENGTH * 8); + + ECRYPT_ivsetup(&ctx->chacha_ctx, + seed + CHACHA_DRBG_KEY_LENGTH + CHACHA_DRBG_COUNTER_LENGTH); + + ECRYPT_ctrsetup(&ctx->chacha_ctx, seed + CHACHA_DRBG_KEY_LENGTH); + + memzero(seed, sizeof(seed)); +} + +void chacha_drbg_generate(CHACHA_DRBG_CTX *ctx, uint8_t *output, + size_t output_length) { + assert(output_length < 65536); + assert(ctx->reseed_counter + 1 != 0); + + ECRYPT_keystream_bytes(&ctx->chacha_ctx, output, output_length); + chacha_drbg_update(ctx, NULL); + ctx->reseed_counter++; +} + +void chacha_drbg_reseed(CHACHA_DRBG_CTX *ctx, const uint8_t *entropy, + size_t entropy_length, const uint8_t *additional_input, + size_t additional_input_length) { + uint8_t seed[CHACHA_DRBG_SEED_LENGTH] = {0}; + derivation_function(entropy, entropy_length, additional_input, + additional_input_length, seed, sizeof(seed)); + chacha_drbg_update(ctx, seed); + memzero(seed, sizeof(seed)); + + ctx->reseed_counter = 1; +} diff --git a/deps/crypto/trezor-crypto/chacha_drbg.h b/deps/crypto/trezor-crypto/chacha_drbg.h new file mode 100644 index 000000000..83e2d0b42 --- /dev/null +++ b/deps/crypto/trezor-crypto/chacha_drbg.h @@ -0,0 +1,54 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __CHACHA_DRBG__ +#define __CHACHA_DRBG__ + +#include "chacha20poly1305/chacha20poly1305.h" +#include "sha2.h" + +// A very fast deterministic random bit generator based on CTR_DRBG in NIST SP +// 800-90A. Chacha is used instead of a block cipher in the counter mode, SHA256 +// is used as a derivation function. The highest supported security strength is +// at least 256 bits. Reseeding is left up to caller. + +// Length of inputs of chacha_drbg_init (entropy and nonce) or +// chacha_drbg_reseed (entropy and additional_input) that fill exactly +// block_count blocks of hash function in derivation_function. There is no need +// the input to have this length, it's just an optimalization. +#define CHACHA_DRBG_OPTIMAL_RESEED_LENGTH(block_count) \ + ((block_count)*SHA256_BLOCK_LENGTH - 1 - 4 - 9) +// 1 = sizeof(counter), 4 = sizeof(output_length) in +// derivation_function, 9 is length of SHA256 padding of message +// aligned to bytes + +typedef struct _CHACHA_DRBG_CTX { + ECRYPT_ctx chacha_ctx; + uint32_t reseed_counter; +} CHACHA_DRBG_CTX; + +void chacha_drbg_init(CHACHA_DRBG_CTX *ctx, const uint8_t *entropy, + size_t entropy_length, const uint8_t *nonce, + size_t nonce_length); +void chacha_drbg_generate(CHACHA_DRBG_CTX *ctx, uint8_t *output, + size_t output_length); +void chacha_drbg_reseed(CHACHA_DRBG_CTX *ctx, const uint8_t *entropy, + size_t entropy_length, const uint8_t *additional_input, + size_t additional_input_length); +#endif // __CHACHA_DRBG__ diff --git a/deps/crypto/trezor-crypto/check_mem.h b/deps/crypto/trezor-crypto/check_mem.h new file mode 100644 index 000000000..be8a43cd6 --- /dev/null +++ b/deps/crypto/trezor-crypto/check_mem.h @@ -0,0 +1,30 @@ +#ifndef CHECK_MEM_H +#define CHECK_MEM_H + +#if CHECK_MAJOR_VERSION == 0 && CHECK_MINOR_VERSION < 11 + +#define _ck_assert_mem(X, Y, L, OP) do { \ + const char* _ck_x = (const char*)(void*)(X); \ + const char* _ck_y = (const char*)(void*)(Y); \ + size_t _ck_l = (L); \ + char _ck_x_str[129]; \ + char _ck_y_str[129]; \ + static char _ck_hexdigits[] = "0123456789abcdef"; \ + size_t _ck_i; \ + for (_ck_i = 0; _ck_i < ((_ck_l > 64) ? 64 : _ck_l); _ck_i++) { \ + _ck_x_str[_ck_i * 2 ] = _ck_hexdigits[(_ck_x[_ck_i] >> 4) & 0xF]; \ + _ck_y_str[_ck_i * 2 ] = _ck_hexdigits[(_ck_y[_ck_i] >> 4) & 0xF]; \ + _ck_x_str[_ck_i * 2 + 1] = _ck_hexdigits[_ck_x[_ck_i] & 0xF]; \ + _ck_y_str[_ck_i * 2 + 1] = _ck_hexdigits[_ck_y[_ck_i] & 0xF]; \ + } \ + _ck_x_str[_ck_i * 2] = 0; \ + _ck_y_str[_ck_i * 2] = 0; \ + ck_assert_msg(0 OP memcmp(_ck_y, _ck_x, _ck_l), \ + "Assertion '"#X#OP#Y"' failed: "#X"==\"%s\", "#Y"==\"%s\"", _ck_x_str, _ck_y_str); \ +} while (0) +#define ck_assert_mem_eq(X, Y, L) _ck_assert_mem(X, Y, L, ==) +#define ck_assert_mem_ne(X, Y, L) _ck_assert_mem(X, Y, L, !=) + +#endif + +#endif diff --git a/deps/crypto/trezor-crypto/curves.c b/deps/crypto/trezor-crypto/curves.c new file mode 100644 index 000000000..64cb0dffd --- /dev/null +++ b/deps/crypto/trezor-crypto/curves.c @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2016 Jochen Hoenicke + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "curves.h" + +const char SECP256K1_NAME[] = "secp256k1"; +const char SECP256K1_DECRED_NAME[] = "secp256k1-decred"; +const char SECP256K1_GROESTL_NAME[] = "secp256k1-groestl"; +const char SECP256K1_SMART_NAME[] = "secp256k1-smart"; +const char NIST256P1_NAME[] = "nist256p1"; +const char ED25519_NAME[] = "ed25519"; +const char ED25519_CARDANO_NAME[] = "ed25519 cardano seed"; +#if USE_NANO +const char ED25519_BLAKE2B_NANO_NAME[] = "ed25519-blake2b-nano"; +#endif +const char ED25519_SHA3_NAME[] = "ed25519-sha3"; +#if USE_KECCAK +const char ED25519_KECCAK_NAME[] = "ed25519-keccak"; +#endif +const char CURVE25519_NAME[] = "curve25519"; diff --git a/deps/crypto/trezor-crypto/curves.h b/deps/crypto/trezor-crypto/curves.h new file mode 100644 index 000000000..e6e2c4045 --- /dev/null +++ b/deps/crypto/trezor-crypto/curves.h @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2016 Jochen Hoenicke + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __CURVES_H__ +#define __CURVES_H__ + +#include "options.h" + +extern const char SECP256K1_NAME[]; +extern const char SECP256K1_DECRED_NAME[]; +extern const char SECP256K1_GROESTL_NAME[]; +extern const char SECP256K1_SMART_NAME[]; +extern const char NIST256P1_NAME[]; +extern const char ED25519_NAME[]; +extern const char ED25519_CARDANO_NAME[]; +#if USE_NANO +extern const char ED25519_BLAKE2B_NANO_NAME[]; +#endif +extern const char ED25519_SHA3_NAME[]; +#if USE_KECCAK +extern const char ED25519_KECCAK_NAME[]; +#endif +extern const char CURVE25519_NAME[]; + +#endif diff --git a/deps/crypto/trezor-crypto/ecdsa.c b/deps/crypto/trezor-crypto/ecdsa.c new file mode 100644 index 000000000..0349719f2 --- /dev/null +++ b/deps/crypto/trezor-crypto/ecdsa.c @@ -0,0 +1,1265 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * Copyright (c) 2015 Jochen Hoenicke + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "address.h" +#include "base58.h" +#include "bignum.h" +#include "ecdsa.h" +#include "hmac.h" +#include "memzero.h" +#include "rand.h" +#include "rfc6979.h" +#include "secp256k1.h" + +// Set cp2 = cp1 +void point_copy(const curve_point *cp1, curve_point *cp2) { *cp2 = *cp1; } + +// cp2 = cp1 + cp2 +void point_add(const ecdsa_curve *curve, const curve_point *cp1, + curve_point *cp2) { + bignum256 lambda = {0}, inv = {0}, xr = {0}, yr = {0}; + + if (point_is_infinity(cp1)) { + return; + } + if (point_is_infinity(cp2)) { + point_copy(cp1, cp2); + return; + } + if (point_is_equal(cp1, cp2)) { + point_double(curve, cp2); + return; + } + if (point_is_negative_of(cp1, cp2)) { + point_set_infinity(cp2); + return; + } + + // lambda = (y2 - y1) / (x2 - x1) + bn_subtractmod(&(cp2->x), &(cp1->x), &inv, &curve->prime); + bn_inverse(&inv, &curve->prime); + bn_subtractmod(&(cp2->y), &(cp1->y), &lambda, &curve->prime); + bn_multiply(&inv, &lambda, &curve->prime); + + // xr = lambda^2 - x1 - x2 + xr = lambda; + bn_multiply(&xr, &xr, &curve->prime); + yr = cp1->x; + bn_addmod(&yr, &(cp2->x), &curve->prime); + bn_subtractmod(&xr, &yr, &xr, &curve->prime); + bn_fast_mod(&xr, &curve->prime); + bn_mod(&xr, &curve->prime); + + // yr = lambda (x1 - xr) - y1 + bn_subtractmod(&(cp1->x), &xr, &yr, &curve->prime); + bn_multiply(&lambda, &yr, &curve->prime); + bn_subtractmod(&yr, &(cp1->y), &yr, &curve->prime); + bn_fast_mod(&yr, &curve->prime); + bn_mod(&yr, &curve->prime); + + cp2->x = xr; + cp2->y = yr; +} + +// cp = cp + cp +void point_double(const ecdsa_curve *curve, curve_point *cp) { + bignum256 lambda = {0}, xr = {0}, yr = {0}; + + if (point_is_infinity(cp)) { + return; + } + if (bn_is_zero(&(cp->y))) { + point_set_infinity(cp); + return; + } + + // lambda = (3 x^2 + a) / (2 y) + lambda = cp->y; + bn_mult_k(&lambda, 2, &curve->prime); + bn_fast_mod(&lambda, &curve->prime); + bn_mod(&lambda, &curve->prime); + bn_inverse(&lambda, &curve->prime); + + xr = cp->x; + bn_multiply(&xr, &xr, &curve->prime); + bn_mult_k(&xr, 3, &curve->prime); + bn_subi(&xr, -curve->a, &curve->prime); + bn_multiply(&xr, &lambda, &curve->prime); + + // xr = lambda^2 - 2*x + xr = lambda; + bn_multiply(&xr, &xr, &curve->prime); + yr = cp->x; + bn_lshift(&yr); + bn_subtractmod(&xr, &yr, &xr, &curve->prime); + bn_fast_mod(&xr, &curve->prime); + bn_mod(&xr, &curve->prime); + + // yr = lambda (x - xr) - y + bn_subtractmod(&(cp->x), &xr, &yr, &curve->prime); + bn_multiply(&lambda, &yr, &curve->prime); + bn_subtractmod(&yr, &(cp->y), &yr, &curve->prime); + bn_fast_mod(&yr, &curve->prime); + bn_mod(&yr, &curve->prime); + + cp->x = xr; + cp->y = yr; +} + +// set point to internal representation of point at infinity +void point_set_infinity(curve_point *p) { + bn_zero(&(p->x)); + bn_zero(&(p->y)); +} + +// return true iff p represent point at infinity +// both coords are zero in internal representation +int point_is_infinity(const curve_point *p) { + return bn_is_zero(&(p->x)) && bn_is_zero(&(p->y)); +} + +// return true iff both points are equal +int point_is_equal(const curve_point *p, const curve_point *q) { + return bn_is_equal(&(p->x), &(q->x)) && bn_is_equal(&(p->y), &(q->y)); +} + +// returns true iff p == -q +// expects p and q be valid points on curve other than point at infinity +int point_is_negative_of(const curve_point *p, const curve_point *q) { + // if P == (x, y), then -P would be (x, -y) on this curve + if (!bn_is_equal(&(p->x), &(q->x))) { + return 0; + } + + // we shouldn't hit this for a valid point + if (bn_is_zero(&(p->y))) { + return 0; + } + + return !bn_is_equal(&(p->y), &(q->y)); +} + +typedef struct jacobian_curve_point { + bignum256 x, y, z; +} jacobian_curve_point; + +// generate random K for signing/side-channel noise +static void generate_k_random(bignum256 *k, const bignum256 *prime) { + do { + int i = 0; + for (i = 0; i < 8; i++) { + k->val[i] = random32() & ((1u << BN_BITS_PER_LIMB) - 1); + } + k->val[8] = random32() & ((1u << BN_BITS_LAST_LIMB) - 1); + // check that k is in range and not zero. + } while (bn_is_zero(k) || !bn_is_less(k, prime)); +} + +void curve_to_jacobian(const curve_point *p, jacobian_curve_point *jp, + const bignum256 *prime) { + // randomize z coordinate + generate_k_random(&jp->z, prime); + + jp->x = jp->z; + bn_multiply(&jp->z, &jp->x, prime); + // x = z^2 + jp->y = jp->x; + bn_multiply(&jp->z, &jp->y, prime); + // y = z^3 + + bn_multiply(&p->x, &jp->x, prime); + bn_multiply(&p->y, &jp->y, prime); +} + +void jacobian_to_curve(const jacobian_curve_point *jp, curve_point *p, + const bignum256 *prime) { + p->y = jp->z; + bn_inverse(&p->y, prime); + // p->y = z^-1 + p->x = p->y; + bn_multiply(&p->x, &p->x, prime); + // p->x = z^-2 + bn_multiply(&p->x, &p->y, prime); + // p->y = z^-3 + bn_multiply(&jp->x, &p->x, prime); + // p->x = jp->x * z^-2 + bn_multiply(&jp->y, &p->y, prime); + // p->y = jp->y * z^-3 + bn_mod(&p->x, prime); + bn_mod(&p->y, prime); +} + +void point_jacobian_add(const curve_point *p1, jacobian_curve_point *p2, + const ecdsa_curve *curve) { + bignum256 r = {0}, h = {0}, r2 = {0}; + bignum256 hcby = {0}, hsqx = {0}; + bignum256 xz = {0}, yz = {0}, az = {0}; + int is_doubling = 0; + const bignum256 *prime = &curve->prime; + int a = curve->a; + + assert(-3 <= a && a <= 0); + + /* First we bring p1 to the same denominator: + * x1' := x1 * z2^2 + * y1' := y1 * z2^3 + */ + /* + * lambda = ((y1' - y2)/z2^3) / ((x1' - x2)/z2^2) + * = (y1' - y2) / (x1' - x2) z2 + * x3/z3^2 = lambda^2 - (x1' + x2)/z2^2 + * y3/z3^3 = 1/2 lambda * (2x3/z3^2 - (x1' + x2)/z2^2) + (y1'+y2)/z2^3 + * + * For the special case x1=x2, y1=y2 (doubling) we have + * lambda = 3/2 ((x2/z2^2)^2 + a) / (y2/z2^3) + * = 3/2 (x2^2 + a*z2^4) / y2*z2) + * + * to get rid of fraction we write lambda as + * lambda = r / (h*z2) + * with r = is_doubling ? 3/2 x2^2 + az2^4 : (y1 - y2) + * h = is_doubling ? y1+y2 : (x1 - x2) + * + * With z3 = h*z2 (the denominator of lambda) + * we get x3 = lambda^2*z3^2 - (x1' + x2)/z2^2*z3^2 + * = r^2 - h^2 * (x1' + x2) + * and y3 = 1/2 r * (2x3 - h^2*(x1' + x2)) + h^3*(y1' + y2) + */ + + /* h = x1 - x2 + * r = y1 - y2 + * x3 = r^2 - h^3 - 2*h^2*x2 + * y3 = r*(h^2*x2 - x3) - h^3*y2 + * z3 = h*z2 + */ + + xz = p2->z; + bn_multiply(&xz, &xz, prime); // xz = z2^2 + yz = p2->z; + bn_multiply(&xz, &yz, prime); // yz = z2^3 + + if (a != 0) { + az = xz; + bn_multiply(&az, &az, prime); // az = z2^4 + bn_mult_k(&az, -a, prime); // az = -az2^4 + } + + bn_multiply(&p1->x, &xz, prime); // xz = x1' = x1*z2^2; + h = xz; + bn_subtractmod(&h, &p2->x, &h, prime); + bn_fast_mod(&h, prime); + // h = x1' - x2; + + bn_add(&xz, &p2->x); + // xz = x1' + x2 + + // check for h == 0 % prime. Note that h never normalizes to + // zero, since h = x1' + 2*prime - x2 > 0 and a positive + // multiple of prime is always normalized to prime by + // bn_fast_mod. + is_doubling = bn_is_equal(&h, prime); + + bn_multiply(&p1->y, &yz, prime); // yz = y1' = y1*z2^3; + bn_subtractmod(&yz, &p2->y, &r, prime); + // r = y1' - y2; + + bn_add(&yz, &p2->y); + // yz = y1' + y2 + + r2 = p2->x; + bn_multiply(&r2, &r2, prime); + bn_mult_k(&r2, 3, prime); + + if (a != 0) { + // subtract -a z2^4, i.e, add a z2^4 + bn_subtractmod(&r2, &az, &r2, prime); + } + bn_cmov(&r, is_doubling, &r2, &r); + bn_cmov(&h, is_doubling, &yz, &h); + + // hsqx = h^2 + hsqx = h; + bn_multiply(&hsqx, &hsqx, prime); + + // hcby = h^3 + hcby = h; + bn_multiply(&hsqx, &hcby, prime); + + // hsqx = h^2 * (x1 + x2) + bn_multiply(&xz, &hsqx, prime); + + // hcby = h^3 * (y1 + y2) + bn_multiply(&yz, &hcby, prime); + + // z3 = h*z2 + bn_multiply(&h, &p2->z, prime); + + // x3 = r^2 - h^2 (x1 + x2) + p2->x = r; + bn_multiply(&p2->x, &p2->x, prime); + bn_subtractmod(&p2->x, &hsqx, &p2->x, prime); + bn_fast_mod(&p2->x, prime); + + // y3 = 1/2 (r*(h^2 (x1 + x2) - 2x3) - h^3 (y1 + y2)) + bn_subtractmod(&hsqx, &p2->x, &p2->y, prime); + bn_subtractmod(&p2->y, &p2->x, &p2->y, prime); + bn_multiply(&r, &p2->y, prime); + bn_subtractmod(&p2->y, &hcby, &p2->y, prime); + bn_mult_half(&p2->y, prime); + bn_fast_mod(&p2->y, prime); +} + +void point_jacobian_double(jacobian_curve_point *p, const ecdsa_curve *curve) { + bignum256 az4 = {0}, m = {0}, msq = {0}, ysq = {0}, xysq = {0}; + const bignum256 *prime = &curve->prime; + + assert(-3 <= curve->a && curve->a <= 0); + /* usual algorithm: + * + * lambda = (3((x/z^2)^2 + a) / 2y/z^3) = (3x^2 + az^4)/2yz + * x3/z3^2 = lambda^2 - 2x/z^2 + * y3/z3^3 = lambda * (x/z^2 - x3/z3^2) - y/z^3 + * + * to get rid of fraction we set + * m = (3 x^2 + az^4) / 2 + * Hence, + * lambda = m / yz = m / z3 + * + * With z3 = yz (the denominator of lambda) + * we get x3 = lambda^2*z3^2 - 2*x/z^2*z3^2 + * = m^2 - 2*xy^2 + * and y3 = (lambda * (x/z^2 - x3/z3^2) - y/z^3) * z3^3 + * = m * (xy^2 - x3) - y^4 + */ + + /* m = (3*x^2 + a z^4) / 2 + * x3 = m^2 - 2*xy^2 + * y3 = m*(xy^2 - x3) - 8y^4 + * z3 = y*z + */ + + m = p->x; + bn_multiply(&m, &m, prime); + bn_mult_k(&m, 3, prime); + + az4 = p->z; + bn_multiply(&az4, &az4, prime); + bn_multiply(&az4, &az4, prime); + bn_mult_k(&az4, -curve->a, prime); + bn_subtractmod(&m, &az4, &m, prime); + bn_mult_half(&m, prime); + + // msq = m^2 + msq = m; + bn_multiply(&msq, &msq, prime); + // ysq = y^2 + ysq = p->y; + bn_multiply(&ysq, &ysq, prime); + // xysq = xy^2 + xysq = p->x; + bn_multiply(&ysq, &xysq, prime); + + // z3 = yz + bn_multiply(&p->y, &p->z, prime); + + // x3 = m^2 - 2*xy^2 + p->x = xysq; + bn_lshift(&p->x); + bn_fast_mod(&p->x, prime); + bn_subtractmod(&msq, &p->x, &p->x, prime); + bn_fast_mod(&p->x, prime); + + // y3 = m*(xy^2 - x3) - y^4 + bn_subtractmod(&xysq, &p->x, &p->y, prime); + bn_multiply(&m, &p->y, prime); + bn_multiply(&ysq, &ysq, prime); + bn_subtractmod(&p->y, &ysq, &p->y, prime); + bn_fast_mod(&p->y, prime); +} + +// res = k * p +// returns 0 on success +int point_multiply(const ecdsa_curve *curve, const bignum256 *k, + const curve_point *p, curve_point *res) { + // this algorithm is loosely based on + // Katsuyuki Okeya and Tsuyoshi Takagi, The Width-w NAF Method Provides + // Small Memory and Fast Elliptic Scalar Multiplications Secure against + // Side Channel Attacks. + if (!bn_is_less(k, &curve->order)) { + return 1; + } + + int i = 0, j = 0; + static CONFIDENTIAL bignum256 a; + uint32_t *aptr = NULL; + uint32_t abits = 0; + int ashift = 0; + uint32_t is_even = (k->val[0] & 1) - 1; + uint32_t bits = {0}, sign = {0}, nsign = {0}; + static CONFIDENTIAL jacobian_curve_point jres; + curve_point pmult[8] = {0}; + const bignum256 *prime = &curve->prime; + + // is_even = 0xffffffff if k is even, 0 otherwise. + + // add 2^256. + // make number odd: subtract curve->order if even + uint32_t tmp = 1; + uint32_t is_non_zero = 0; + for (j = 0; j < 8; j++) { + is_non_zero |= k->val[j]; + tmp += (BN_BASE - 1) + k->val[j] - (curve->order.val[j] & is_even); + a.val[j] = tmp & (BN_BASE - 1); + tmp >>= BN_BITS_PER_LIMB; + } + is_non_zero |= k->val[j]; + a.val[j] = tmp + 0xffffff + k->val[j] - (curve->order.val[j] & is_even); + assert((a.val[0] & 1) != 0); + + // special case 0*p: just return zero. We don't care about constant time. + if (!is_non_zero) { + point_set_infinity(res); + return 1; + } + + // Now a = k + 2^256 (mod curve->order) and a is odd. + // + // The idea is to bring the new a into the form. + // sum_{i=0..64} a[i] 16^i, where |a[i]| < 16 and a[i] is odd. + // a[0] is odd, since a is odd. If a[i] would be even, we can + // add 1 to it and subtract 16 from a[i-1]. Afterwards, + // a[64] = 1, which is the 2^256 that we added before. + // + // Since k = a - 2^256 (mod curve->order), we can compute + // k*p = sum_{i=0..63} a[i] 16^i * p + // + // We compute |a[i]| * p in advance for all possible + // values of |a[i]| * p. pmult[i] = (2*i+1) * p + // We compute p, 3*p, ..., 15*p and store it in the table pmult. + // store p^2 temporarily in pmult[7] + pmult[7] = *p; + point_double(curve, &pmult[7]); + // compute 3*p, etc by repeatedly adding p^2. + pmult[0] = *p; + for (i = 1; i < 8; i++) { + pmult[i] = pmult[7]; + point_add(curve, &pmult[i - 1], &pmult[i]); + } + + // now compute res = sum_{i=0..63} a[i] * 16^i * p step by step, + // starting with i = 63. + // initialize jres = |a[63]| * p. + // Note that a[i] = a>>(4*i) & 0xf if (a&0x10) != 0 + // and - (16 - (a>>(4*i) & 0xf)) otherwise. We can compute this as + // ((a ^ (((a >> 4) & 1) - 1)) & 0xf) >> 1 + // since a is odd. + aptr = &a.val[8]; + abits = *aptr; + ashift = 256 - (BN_BITS_PER_LIMB * 8) - 4; + bits = abits >> ashift; + sign = (bits >> 4) - 1; + bits ^= sign; + bits &= 15; + curve_to_jacobian(&pmult[bits >> 1], &jres, prime); + for (i = 62; i >= 0; i--) { + // sign = sign(a[i+1]) (0xffffffff for negative, 0 for positive) + // invariant jres = (-1)^sign sum_{j=i+1..63} (a[j] * 16^{j-i-1} * p) + // abits >> (ashift - 4) = lowbits(a >> (i*4)) + + point_jacobian_double(&jres, curve); + point_jacobian_double(&jres, curve); + point_jacobian_double(&jres, curve); + point_jacobian_double(&jres, curve); + + // get lowest 5 bits of a >> (i*4). + ashift -= 4; + if (ashift < 0) { + // the condition only depends on the iteration number and + // leaks no private information to a side-channel. + bits = abits << (-ashift); + abits = *(--aptr); + ashift += BN_BITS_PER_LIMB; + bits |= abits >> ashift; + } else { + bits = abits >> ashift; + } + bits &= 31; + nsign = (bits >> 4) - 1; + bits ^= nsign; + bits &= 15; + + // negate last result to make signs of this round and the + // last round equal. + bn_cnegate((sign ^ nsign) & 1, &jres.z, prime); + + // add odd factor + point_jacobian_add(&pmult[bits >> 1], &jres, curve); + sign = nsign; + } + bn_cnegate(sign & 1, &jres.z, prime); + jacobian_to_curve(&jres, res, prime); + memzero(&a, sizeof(a)); + memzero(&jres, sizeof(jres)); + + return 0; +} + +#if USE_PRECOMPUTED_CP + +// res = k * G +// k must be a normalized number with 0 <= k < curve->order +// returns 0 on success +int scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, + curve_point *res) { + if (!bn_is_less(k, &curve->order)) { + return 1; + } + + int i = {0}, j = {0}; + static CONFIDENTIAL bignum256 a; + uint32_t is_even = (k->val[0] & 1) - 1; + uint32_t lowbits = 0; + static CONFIDENTIAL jacobian_curve_point jres; + const bignum256 *prime = &curve->prime; + + // is_even = 0xffffffff if k is even, 0 otherwise. + + // add 2^256. + // make number odd: subtract curve->order if even + uint32_t tmp = 1; + uint32_t is_non_zero = 0; + for (j = 0; j < 8; j++) { + is_non_zero |= k->val[j]; + tmp += (BN_BASE - 1) + k->val[j] - (curve->order.val[j] & is_even); + a.val[j] = tmp & (BN_BASE - 1); + tmp >>= BN_BITS_PER_LIMB; + } + is_non_zero |= k->val[j]; + a.val[j] = tmp + 0xffffff + k->val[j] - (curve->order.val[j] & is_even); + assert((a.val[0] & 1) != 0); + + // special case 0*G: just return zero. We don't care about constant time. + if (!is_non_zero) { + point_set_infinity(res); + return 0; + } + + // Now a = k + 2^256 (mod curve->order) and a is odd. + // + // The idea is to bring the new a into the form. + // sum_{i=0..64} a[i] 16^i, where |a[i]| < 16 and a[i] is odd. + // a[0] is odd, since a is odd. If a[i] would be even, we can + // add 1 to it and subtract 16 from a[i-1]. Afterwards, + // a[64] = 1, which is the 2^256 that we added before. + // + // Since k = a - 2^256 (mod curve->order), we can compute + // k*G = sum_{i=0..63} a[i] 16^i * G + // + // We have a big table curve->cp that stores all possible + // values of |a[i]| 16^i * G. + // curve->cp[i][j] = (2*j+1) * 16^i * G + + // now compute res = sum_{i=0..63} a[i] * 16^i * G step by step. + // initial res = |a[0]| * G. Note that a[0] = a & 0xf if (a&0x10) != 0 + // and - (16 - (a & 0xf)) otherwise. We can compute this as + // ((a ^ (((a >> 4) & 1) - 1)) & 0xf) >> 1 + // since a is odd. + lowbits = a.val[0] & ((1 << 5) - 1); + lowbits ^= (lowbits >> 4) - 1; + lowbits &= 15; + curve_to_jacobian(&curve->cp[0][lowbits >> 1], &jres, prime); + for (i = 1; i < 64; i++) { + // invariant res = sign(a[i-1]) sum_{j=0..i-1} (a[j] * 16^j * G) + + // shift a by 4 places. + for (j = 0; j < 8; j++) { + a.val[j] = + (a.val[j] >> 4) | ((a.val[j + 1] & 0xf) << (BN_BITS_PER_LIMB - 4)); + } + a.val[j] >>= 4; + // a = old(a)>>(4*i) + // a is even iff sign(a[i-1]) = -1 + + lowbits = a.val[0] & ((1 << 5) - 1); + lowbits ^= (lowbits >> 4) - 1; + lowbits &= 15; + // negate last result to make signs of this round and the + // last round equal. + bn_cnegate(~lowbits & 1, &jres.y, prime); + + // add odd factor + point_jacobian_add(&curve->cp[i][lowbits >> 1], &jres, curve); + } + bn_cnegate(~(a.val[0] >> 4) & 1, &jres.y, prime); + jacobian_to_curve(&jres, res, prime); + memzero(&a, sizeof(a)); + memzero(&jres, sizeof(jres)); + + return 0; +} + +#else + +int scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, + curve_point *res) { + return point_multiply(curve, k, &curve->G, res); +} + +#endif + +int ecdh_multiply(const ecdsa_curve *curve, const uint8_t *priv_key, + const uint8_t *pub_key, uint8_t *session_key) { + curve_point point = {0}; + if (!ecdsa_read_pubkey(curve, pub_key, &point)) { + return 1; + } + + bignum256 k = {0}; + bn_read_be(priv_key, &k); + if (bn_is_zero(&k) || !bn_is_less(&k, &curve->order)) { + // Invalid private key. + memzero(&k, sizeof(k)); + return 2; + } + + point_multiply(curve, &k, &point, &point); + memzero(&k, sizeof(k)); + + session_key[0] = 0x04; + bn_write_be(&point.x, session_key + 1); + bn_write_be(&point.y, session_key + 33); + memzero(&point, sizeof(point)); + + return 0; +} + +// msg is a data to be signed +// msg_len is the message length +int ecdsa_sign(const ecdsa_curve *curve, HasherType hasher_sign, + const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, + uint8_t *sig, uint8_t *pby, + int (*is_canonical)(uint8_t by, uint8_t sig[64])) { + uint8_t hash[32] = {0}; + hasher_Raw(hasher_sign, msg, msg_len, hash); + int res = ecdsa_sign_digest(curve, priv_key, hash, sig, pby, is_canonical); + memzero(hash, sizeof(hash)); + return res; +} + +// uses secp256k1 curve +// priv_key is a 32 byte big endian stored number +// sig is 64 bytes long array for the signature +// digest is 32 bytes of digest +// is_canonical is an optional function that checks if the signature +// conforms to additional coin-specific rules. +int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, + const uint8_t *digest, uint8_t *sig, uint8_t *pby, + int (*is_canonical)(uint8_t by, uint8_t sig[64])) { + int ret = -1; + int i = 0; + curve_point R = {0}; + bignum256 k = {0}, z = {0}, randk = {0}, s = {0}; + uint8_t by; // signature recovery byte + +#if USE_RFC6979 + rfc6979_state rng = {0}; + init_rfc6979(priv_key, digest, curve, &rng); +#endif + + bn_read_be(digest, &z); + if (bn_is_zero(&z)) { + // The probability of the digest being all-zero by chance is infinitesimal, + // so this is most likely an indication of a bug. Furthermore, the signature + // has no value, because in this case it can be easily forged for any public + // key, see ecdsa_verify_digest(). + ret = 1; + goto cleanup; + } + + for (i = 0; i < 10000; i++) { +#if USE_RFC6979 + // generate K deterministically + generate_k_rfc6979(&k, &rng); + // if k is too big or too small, we don't like it + if (bn_is_zero(&k) || !bn_is_less(&k, &curve->order)) { + continue; + } +#else + // generate random number k + generate_k_random(&k, &curve->order); +#endif + + // compute k*G + scalar_multiply(curve, &k, &R); + by = R.y.val[0] & 1; + // r = (rx mod n) + if (!bn_is_less(&R.x, &curve->order)) { + bn_subtract(&R.x, &curve->order, &R.x); + by |= 2; + } + // if r is zero, we retry + if (bn_is_zero(&R.x)) { + continue; + } + + bn_read_be(priv_key, &s); + if (bn_is_zero(&s) || !bn_is_less(&s, &curve->order)) { + // Invalid private key. + ret = 2; + goto cleanup; + } + + // randomize operations to counter side-channel attacks + generate_k_random(&randk, &curve->order); + bn_multiply(&randk, &k, &curve->order); // k*rand + bn_inverse(&k, &curve->order); // (k*rand)^-1 + bn_multiply(&R.x, &s, &curve->order); // R.x*priv + bn_add(&s, &z); // R.x*priv + z + bn_multiply(&k, &s, &curve->order); // (k*rand)^-1 (R.x*priv + z) + bn_multiply(&randk, &s, &curve->order); // k^-1 (R.x*priv + z) + bn_mod(&s, &curve->order); + // if s is zero, we retry + if (bn_is_zero(&s)) { + continue; + } + + // if S > order/2 => S = -S + if (bn_is_less(&curve->order_half, &s)) { + bn_subtract(&curve->order, &s, &s); + by ^= 1; + } + // we are done, R.x and s is the result signature + bn_write_be(&R.x, sig); + bn_write_be(&s, sig + 32); + + // check if the signature is acceptable or retry + if (is_canonical && !is_canonical(by, sig)) { + continue; + } + + if (pby) { + *pby = by; + } + ret = 0; + goto cleanup; + } + + // Too many retries without a valid signature + // -> fail with an error +cleanup: + memzero(&R, sizeof(R)); + memzero(&k, sizeof(k)); + memzero(&randk, sizeof(randk)); + memzero(&z, sizeof(z)); + memzero(&s, sizeof(s)); +#if USE_RFC6979 + memzero(&rng, sizeof(rng)); +#endif + return ret; +} + +// returns 0 on success +int ecdsa_get_public_key33(const ecdsa_curve *curve, const uint8_t *priv_key, + uint8_t *pub_key) { + curve_point R = {0}; + bignum256 k = {0}; + + bn_read_be(priv_key, &k); + if (bn_is_zero(&k) || !bn_is_less(&k, &curve->order)) { + // Invalid private key. + memzero(&k, sizeof(k)); + memzero(pub_key, 33); + return -1; + } + + // compute k*G + if (scalar_multiply(curve, &k, &R) != 0) { + memzero(&k, sizeof(k)); + return 1; + } + pub_key[0] = 0x02 | (R.y.val[0] & 0x01); + bn_write_be(&R.x, pub_key + 1); + memzero(&R, sizeof(R)); + memzero(&k, sizeof(k)); + return 0; +} + +// returns 0 on success +int ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key, + uint8_t *pub_key) { + curve_point R = {0}; + bignum256 k = {0}; + + bn_read_be(priv_key, &k); + if (bn_is_zero(&k) || !bn_is_less(&k, &curve->order)) { + // Invalid private key. + memzero(&k, sizeof(k)); + memzero(pub_key, 65); + return -1; + } + + // compute k*G + if (scalar_multiply(curve, &k, &R) != 0) { + memzero(&k, sizeof(k)); + return 1; + } + pub_key[0] = 0x04; + bn_write_be(&R.x, pub_key + 1); + bn_write_be(&R.y, pub_key + 33); + memzero(&R, sizeof(R)); + memzero(&k, sizeof(k)); + return 0; +} + +int ecdsa_uncompress_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, + uint8_t *uncompressed) { + curve_point pub = {0}; + + if (!ecdsa_read_pubkey(curve, pub_key, &pub)) { + return 0; + } + + uncompressed[0] = 4; + bn_write_be(&pub.x, uncompressed + 1); + bn_write_be(&pub.y, uncompressed + 33); + + return 1; +} + +void ecdsa_get_pubkeyhash(const uint8_t *pub_key, HasherType hasher_pubkey, + uint8_t *pubkeyhash) { + uint8_t h[HASHER_DIGEST_LENGTH] = {0}; + if (pub_key[0] == 0x04) { // uncompressed format + hasher_Raw(hasher_pubkey, pub_key, 65, h); + } else if (pub_key[0] == 0x00) { // point at infinity + hasher_Raw(hasher_pubkey, pub_key, 1, h); + } else { // expecting compressed format + hasher_Raw(hasher_pubkey, pub_key, 33, h); + } + memcpy(pubkeyhash, h, 20); + memzero(h, sizeof(h)); +} + +void ecdsa_get_address_raw(const uint8_t *pub_key, uint32_t version, + HasherType hasher_pubkey, uint8_t *addr_raw) { + size_t prefix_len = address_prefix_bytes_len(version); + address_write_prefix_bytes(version, addr_raw); + ecdsa_get_pubkeyhash(pub_key, hasher_pubkey, addr_raw + prefix_len); +} + +void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, + HasherType hasher_pubkey, HasherType hasher_base58, + char *addr, int addrsize) { + uint8_t raw[MAX_ADDR_RAW_SIZE] = {0}; + size_t prefix_len = address_prefix_bytes_len(version); + ecdsa_get_address_raw(pub_key, version, hasher_pubkey, raw); + base58_encode_check(raw, 20 + prefix_len, hasher_base58, addr, addrsize); + // not as important to clear this one, but we might as well + memzero(raw, sizeof(raw)); +} + +void ecdsa_get_address_segwit_p2sh_raw(const uint8_t *pub_key, uint32_t version, + HasherType hasher_pubkey, + uint8_t *addr_raw) { + uint8_t buf[32 + 2] = {0}; + buf[0] = 0; // version byte + buf[1] = 20; // push 20 bytes + ecdsa_get_pubkeyhash(pub_key, hasher_pubkey, buf + 2); + size_t prefix_len = address_prefix_bytes_len(version); + address_write_prefix_bytes(version, addr_raw); + hasher_Raw(hasher_pubkey, buf, 22, addr_raw + prefix_len); +} + +void ecdsa_get_address_segwit_p2sh(const uint8_t *pub_key, uint32_t version, + HasherType hasher_pubkey, + HasherType hasher_base58, char *addr, + int addrsize) { + uint8_t raw[MAX_ADDR_RAW_SIZE] = {0}; + size_t prefix_len = address_prefix_bytes_len(version); + ecdsa_get_address_segwit_p2sh_raw(pub_key, version, hasher_pubkey, raw); + base58_encode_check(raw, prefix_len + 20, hasher_base58, addr, addrsize); + memzero(raw, sizeof(raw)); +} + +void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, + HasherType hasher_base58, char *wif, int wifsize) { + uint8_t wif_raw[MAX_WIF_RAW_SIZE] = {0}; + size_t prefix_len = address_prefix_bytes_len(version); + address_write_prefix_bytes(version, wif_raw); + memcpy(wif_raw + prefix_len, priv_key, 32); + wif_raw[prefix_len + 32] = 0x01; + base58_encode_check(wif_raw, prefix_len + 32 + 1, hasher_base58, wif, + wifsize); + // private keys running around our stack can cause trouble + memzero(wif_raw, sizeof(wif_raw)); +} + +int ecdsa_address_decode(const char *addr, uint32_t version, + HasherType hasher_base58, uint8_t *out) { + if (!addr) return 0; + int prefix_len = address_prefix_bytes_len(version); + return base58_decode_check(addr, hasher_base58, out, 20 + prefix_len) == + 20 + prefix_len && + address_check_prefix(out, version); +} + +void compress_coords(const curve_point *cp, uint8_t *compressed) { + compressed[0] = bn_is_odd(&cp->y) ? 0x03 : 0x02; + bn_write_be(&cp->x, compressed + 1); +} + +void uncompress_coords(const ecdsa_curve *curve, uint8_t odd, + const bignum256 *x, bignum256 *y) { + // y^2 = x^3 + a*x + b + memcpy(y, x, sizeof(bignum256)); // y is x + bn_multiply(x, y, &curve->prime); // y is x^2 + bn_subi(y, -curve->a, &curve->prime); // y is x^2 + a + bn_multiply(x, y, &curve->prime); // y is x^3 + ax + bn_add(y, &curve->b); // y is x^3 + ax + b + bn_sqrt(y, &curve->prime); // y = sqrt(y) + if ((odd & 0x01) != (y->val[0] & 1)) { + bn_subtract(&curve->prime, y, y); // y = -y + } +} + +int ecdsa_read_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, + curve_point *pub) { + if (!curve) { + curve = &secp256k1; + } + if (pub_key[0] == 0x04) { + bn_read_be(pub_key + 1, &(pub->x)); + bn_read_be(pub_key + 33, &(pub->y)); + return ecdsa_validate_pubkey(curve, pub); + } + if (pub_key[0] == 0x02 || pub_key[0] == 0x03) { // compute missing y coords + bn_read_be(pub_key + 1, &(pub->x)); + uncompress_coords(curve, pub_key[0], &(pub->x), &(pub->y)); + return ecdsa_validate_pubkey(curve, pub); + } + // error + return 0; +} + +// Verifies that: +// - pub is not the point at infinity. +// - pub->x and pub->y are in range [0,p-1]. +// - pub is on the curve. +// We assume that all curves using this code have cofactor 1, so there is no +// need to verify that pub is a scalar multiple of G. +int ecdsa_validate_pubkey(const ecdsa_curve *curve, const curve_point *pub) { + bignum256 y_2 = {0}, x3_ax_b = {0}; + + if (point_is_infinity(pub)) { + return 0; + } + + if (!bn_is_less(&(pub->x), &curve->prime) || + !bn_is_less(&(pub->y), &curve->prime)) { + return 0; + } + + memcpy(&y_2, &(pub->y), sizeof(bignum256)); + memcpy(&x3_ax_b, &(pub->x), sizeof(bignum256)); + + // y^2 + bn_multiply(&(pub->y), &y_2, &curve->prime); + bn_mod(&y_2, &curve->prime); + + // x^3 + ax + b + bn_multiply(&(pub->x), &x3_ax_b, &curve->prime); // x^2 + bn_subi(&x3_ax_b, -curve->a, &curve->prime); // x^2 + a + bn_multiply(&(pub->x), &x3_ax_b, &curve->prime); // x^3 + ax + bn_addmod(&x3_ax_b, &curve->b, &curve->prime); // x^3 + ax + b + bn_mod(&x3_ax_b, &curve->prime); + + if (!bn_is_equal(&x3_ax_b, &y_2)) { + return 0; + } + + return 1; +} + +// uses secp256k1 curve +// pub_key - 65 bytes uncompressed key +// signature - 64 bytes signature +// msg is a data that was signed +// msg_len is the message length + +int ecdsa_verify(const ecdsa_curve *curve, HasherType hasher_sign, + const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, + uint32_t msg_len) { + uint8_t hash[32] = {0}; + hasher_Raw(hasher_sign, msg, msg_len, hash); + int res = ecdsa_verify_digest(curve, pub_key, sig, hash); + memzero(hash, sizeof(hash)); + return res; +} + +// Compute public key from signature and recovery id. +// returns 0 if the key is successfully recovered +int ecdsa_recover_pub_from_sig(const ecdsa_curve *curve, uint8_t *pub_key, + const uint8_t *sig, const uint8_t *digest, + int recid) { + bignum256 r = {0}, s = {0}, e = {0}; + curve_point cp = {0}, cp2 = {0}; + + // read r and s + bn_read_be(sig, &r); + bn_read_be(sig + 32, &s); + if (!bn_is_less(&r, &curve->order) || bn_is_zero(&r)) { + return 1; + } + if (!bn_is_less(&s, &curve->order) || bn_is_zero(&s)) { + return 1; + } + // cp = R = k * G (k is secret nonce when signing) + memcpy(&cp.x, &r, sizeof(bignum256)); + if (recid & 2) { + bn_add(&cp.x, &curve->order); + if (!bn_is_less(&cp.x, &curve->prime)) { + return 1; + } + } + // compute y from x + uncompress_coords(curve, recid & 1, &cp.x, &cp.y); + if (!ecdsa_validate_pubkey(curve, &cp)) { + return 1; + } + // e = -digest + bn_read_be(digest, &e); + bn_mod(&e, &curve->order); + bn_subtract(&curve->order, &e, &e); + // r = r^-1 + bn_inverse(&r, &curve->order); + // e = -digest * r^-1 + bn_multiply(&r, &e, &curve->order); + bn_mod(&e, &curve->order); + // s = s * r^-1 + bn_multiply(&r, &s, &curve->order); + bn_mod(&s, &curve->order); + // cp = s * r^-1 * k * G + point_multiply(curve, &s, &cp, &cp); + // cp2 = -digest * r^-1 * G + scalar_multiply(curve, &e, &cp2); + // cp = (s * r^-1 * k - digest * r^-1) * G = Pub + point_add(curve, &cp2, &cp); + // The point at infinity is not considered to be a valid public key. + if (point_is_infinity(&cp)) { + return 1; + } + pub_key[0] = 0x04; + bn_write_be(&cp.x, pub_key + 1); + bn_write_be(&cp.y, pub_key + 33); + return 0; +} + +// returns 0 if verification succeeded +int ecdsa_verify_digest(const ecdsa_curve *curve, const uint8_t *pub_key, + const uint8_t *sig, const uint8_t *digest) { + curve_point pub = {0}, res = {0}; + bignum256 r = {0}, s = {0}, z = {0}; + int result = 0; + + if (!ecdsa_read_pubkey(curve, pub_key, &pub)) { + result = 1; + } + + if (result == 0) { + bn_read_be(sig, &r); + bn_read_be(sig + 32, &s); + bn_read_be(digest, &z); + if (bn_is_zero(&r) || bn_is_zero(&s) || (!bn_is_less(&r, &curve->order)) || + (!bn_is_less(&s, &curve->order))) { + result = 2; + } + if (bn_is_zero(&z)) { + // The digest was all-zero. The probability of this happening by chance is + // infinitesimal, but it could be induced by a fault injection. In this + // case the signature (r,s) can be forged by taking r := (t * Q).x mod n + // and s := r * t^-1 mod n for any t in [1, n-1]. We fail verification, + // because there is no guarantee that the signature was created by the + // owner of the private key. + result = 3; + } + } + + if (result == 0) { + bn_inverse(&s, &curve->order); // s = s^-1 + bn_multiply(&s, &z, &curve->order); // z = z * s [u1 = z * s^-1 mod n] + bn_mod(&z, &curve->order); + } + + if (result == 0) { + bn_multiply(&r, &s, &curve->order); // s = r * s [u2 = r * s^-1 mod n] + bn_mod(&s, &curve->order); + scalar_multiply(curve, &z, &res); // res = z * G [= u1 * G] + point_multiply(curve, &s, &pub, &pub); // pub = s * pub [= u2 * Q] + point_add(curve, &pub, &res); // res = pub + res [R = u1 * G + u2 * Q] + if (point_is_infinity(&res)) { + // R == Infinity + result = 4; + } + } + + if (result == 0) { + bn_mod(&(res.x), &curve->order); + if (!bn_is_equal(&res.x, &r)) { + // R.x != r + // signature does not match + result = 5; + } + } + + memzero(&pub, sizeof(pub)); + memzero(&res, sizeof(res)); + memzero(&r, sizeof(r)); + memzero(&s, sizeof(s)); + memzero(&z, sizeof(z)); + + // all OK + return result; +} + +int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der) { + int i = 0; + uint8_t *p = der, *len = NULL, *len1 = NULL, *len2 = NULL; + *p = 0x30; + p++; // sequence + *p = 0x00; + len = p; + p++; // len(sequence) + + *p = 0x02; + p++; // integer + *p = 0x00; + len1 = p; + p++; // len(integer) + + // process R + i = 0; + while (i < 31 && sig[i] == 0) { + i++; + } // skip leading zeroes + if (sig[i] >= 0x80) { // put zero in output if MSB set + *p = 0x00; + p++; + *len1 = *len1 + 1; + } + while (i < 32) { // copy bytes to output + *p = sig[i]; + p++; + *len1 = *len1 + 1; + i++; + } + + *p = 0x02; + p++; // integer + *p = 0x00; + len2 = p; + p++; // len(integer) + + // process S + i = 32; + while (i < 63 && sig[i] == 0) { + i++; + } // skip leading zeroes + if (sig[i] >= 0x80) { // put zero in output if MSB set + *p = 0x00; + p++; + *len2 = *len2 + 1; + } + while (i < 64) { // copy bytes to output + *p = sig[i]; + p++; + *len2 = *len2 + 1; + i++; + } + + *len = *len1 + *len2 + 4; + return *len + 2; +} + +// Parse a DER-encoded signature. We check whether the encoded integers satisfy +// DER requirements regarding leading zeros. +int ecdsa_sig_from_der(const uint8_t *der, size_t der_len, uint8_t sig[64]) { + memzero(sig, 64); + + // Check sequence header. + if (der_len < 2 || der_len > 72 || der[0] != 0x30 || der[1] != der_len - 2) { + return 1; + } + + // Read two DER-encoded integers. + size_t pos = 2; + for (int i = 0; i < 2; ++i) { + // Check integer header. + if (der_len < pos + 2 || der[pos] != 0x02) { + return 1; + } + + // Locate the integer. + size_t int_len = der[pos + 1]; + pos += 2; + if (pos + int_len > der_len) { + return 1; + } + + // Positive integers must not start with an octet that has bit 8 set to 1. + if (int_len == 0 || der[pos] > 0x7f) { + return 1; + } + + // Skip a possible leading null octet. + if (int_len > 1 && der[pos] == 0x00) { + int_len--; + pos++; + + // Check that integer uses the shortest possible encoding. + if (der[pos] < 0x80) { + return 1; + } + } + + // Copy the integer to the output, making sure it fits. + if (int_len > 32) { + return 1; + } + memcpy(sig + 32 * (i + 1) - int_len, der + pos, int_len); + + // Move on to the next one. + pos += int_len; + } + + // Check that there are no trailing elements in the sequence. + if (pos != der_len) { + return 1; + } + + return 0; +} diff --git a/deps/crypto/trezor-crypto/ecdsa.h b/deps/crypto/trezor-crypto/ecdsa.h new file mode 100644 index 000000000..7b951d236 --- /dev/null +++ b/deps/crypto/trezor-crypto/ecdsa.h @@ -0,0 +1,128 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __ECDSA_H__ +#define __ECDSA_H__ + +#include +#include "bignum.h" +#include "hasher.h" +#include "options.h" + +// curve point x and y +typedef struct { + bignum256 x, y; +} curve_point; + +typedef struct { + bignum256 prime; // prime order of the finite field + curve_point G; // initial curve point + bignum256 order; // order of G + bignum256 order_half; // order of G divided by 2 + int a; // coefficient 'a' of the elliptic curve + bignum256 b; // coefficient 'b' of the elliptic curve + +#if USE_PRECOMPUTED_CP + const curve_point cp[64][8]; +#endif + +} ecdsa_curve; + +// 4 byte prefix + 40 byte data (segwit) +// 1 byte prefix + 64 byte data (cashaddr) +#define MAX_ADDR_RAW_SIZE 65 +// bottle neck is cashaddr +// segwit is at most 90 characters plus NUL separator +// cashaddr: human readable prefix + 1 separator + 104 data + 8 checksum + 1 NUL +// we choose 130 as maximum (including NUL character) +#define MAX_ADDR_SIZE 130 +// 4 byte prefix + 32 byte privkey + 1 byte compressed marker +#define MAX_WIF_RAW_SIZE (4 + 32 + 1) +// (4 + 32 + 1 + 4 [checksum]) * 8 / log2(58) plus NUL. +#define MAX_WIF_SIZE (57) + +void point_copy(const curve_point *cp1, curve_point *cp2); +void point_add(const ecdsa_curve *curve, const curve_point *cp1, + curve_point *cp2); +void point_double(const ecdsa_curve *curve, curve_point *cp); +int point_multiply(const ecdsa_curve *curve, const bignum256 *k, + const curve_point *p, curve_point *res); +void point_set_infinity(curve_point *p); +int point_is_infinity(const curve_point *p); +int point_is_equal(const curve_point *p, const curve_point *q); +int point_is_negative_of(const curve_point *p, const curve_point *q); +int scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, + curve_point *res); +int ecdh_multiply(const ecdsa_curve *curve, const uint8_t *priv_key, + const uint8_t *pub_key, uint8_t *session_key); +void compress_coords(const curve_point *cp, uint8_t *compressed); +void uncompress_coords(const ecdsa_curve *curve, uint8_t odd, + const bignum256 *x, bignum256 *y); +int ecdsa_uncompress_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, + uint8_t *uncompressed); + +int ecdsa_sign(const ecdsa_curve *curve, HasherType hasher_sign, + const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, + uint8_t *sig, uint8_t *pby, + int (*is_canonical)(uint8_t by, uint8_t sig[64])); +int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, + const uint8_t *digest, uint8_t *sig, uint8_t *pby, + int (*is_canonical)(uint8_t by, uint8_t sig[64])); +int ecdsa_get_public_key33(const ecdsa_curve *curve, const uint8_t *priv_key, + uint8_t *pub_key); +int ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key, + uint8_t *pub_key); +void ecdsa_get_pubkeyhash(const uint8_t *pub_key, HasherType hasher_pubkey, + uint8_t *pubkeyhash); +void ecdsa_get_address_raw(const uint8_t *pub_key, uint32_t version, + HasherType hasher_pubkey, uint8_t *addr_raw); +void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, + HasherType hasher_pubkey, HasherType hasher_base58, + char *addr, int addrsize); +void ecdsa_get_address_segwit_p2sh_raw(const uint8_t *pub_key, uint32_t version, + HasherType hasher_pubkey, + uint8_t *addr_raw); +void ecdsa_get_address_segwit_p2sh(const uint8_t *pub_key, uint32_t version, + HasherType hasher_pubkey, + HasherType hasher_base58, char *addr, + int addrsize); +void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, + HasherType hasher_base58, char *wif, int wifsize); + +int ecdsa_address_decode(const char *addr, uint32_t version, + HasherType hasher_base58, uint8_t *out); +int ecdsa_read_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, + curve_point *pub); +int ecdsa_validate_pubkey(const ecdsa_curve *curve, const curve_point *pub); +int ecdsa_verify(const ecdsa_curve *curve, HasherType hasher_sign, + const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, + uint32_t msg_len); +int ecdsa_verify_digest(const ecdsa_curve *curve, const uint8_t *pub_key, + const uint8_t *sig, const uint8_t *digest); +int ecdsa_recover_pub_from_sig(const ecdsa_curve *curve, uint8_t *pub_key, + const uint8_t *sig, const uint8_t *digest, + int recid); +int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der); +int ecdsa_sig_from_der(const uint8_t *der, size_t der_len, uint8_t sig[64]); + +#endif diff --git a/deps/crypto/trezor-crypto/ed25519-donna/README.md b/deps/crypto/trezor-crypto/ed25519-donna/README.md new file mode 100644 index 000000000..73eadf8db --- /dev/null +++ b/deps/crypto/trezor-crypto/ed25519-donna/README.md @@ -0,0 +1,183 @@ +[ed25519](https://ed25519.cr.yp.to) is an +[Elliptic Curve Digital Signature Algortithm](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm), +developed by [Dan Bernstein](https://cr.yp.to/djb.html), +[Niels Duif](https://www.nielsduif.nl), +[Tanja Lange](https://hyperelliptic.org/tanja), +[Peter Schwabe](https://cryptojedi.org/peter), +and [Bo-Yin Yang](https://www.iis.sinica.edu.tw/pages/byyang). + +This project provides performant, portable 32-bit & 64-bit implementations. All implementations are +of course constant time in regard to secret data. + +#### Performance + +SSE2 code and benches have not been updated yet. I will do those next. + +Compilers versions are gcc 4.6.3, icc 13.1.1, clang 3.4-1~exp1. + +Batch verification time (in parentheses) is the average time per 1 verification in a batch of 64 signatures. Counts are in thousands of cycles. + +Note that SSE2 performance may be less impressive on AMD & older CPUs with slower SSE ops! + +Visual Studio performance for `ge25519_scalarmult_base_niels` will lag behind a bit until optimized assembler versions of `ge25519_scalarmult_base_choose_niels` +are made. + +##### E5200 @ 2.5ghz, march=core2 + + + + + + + + + + + +
ImplementationSigngcciccclangVerifygcciccclang
ed25519-donna 64bit 100k110k137k327k (144k) 342k (163k) 422k (194k)
amd64-64-24k 102k 355k (158k)
ed25519-donna-sse2 64bit108k111k116k353k (155k) 345k (154k) 360k (161k)
amd64-51-32k 116k 380k (175k)
ed25519-donna-sse2 32bit147k147k156k380k (178k) 381k (173k) 430k (192k)
ed25519-donna 32bit 597k335k380k1693k (720k)1052k (453k)1141k (493k)
+ +##### E3-1270 @ 3.4ghz, march=corei7-avx + + + + + + + + + + + +
ImplementationSigngcciccclangVerifygcciccclang
amd64-64-24k 68k 225k (104k)
ed25519-donna 64bit 71k 75k 90k226k (105k) 226k (112k) 277k (125k)
amd64-51-32k 72k 218k (107k)
ed25519-donna-sse2 64bit 79k 82k 92k252k (122k) 259k (124k) 282k (131k)
ed25519-donna-sse2 32bit 94k 95k103k296k (146k) 294k (137k) 306k (147k)
ed25519-donna 32bit 525k299k316k1502k (645k)959k (418k) 954k (416k)
+ +#### Compilation + +No configuration is needed **if you are compiling against OpenSSL**. + +##### Hash Options + +If you are not compiling aginst OpenSSL, you will need a hash function. + +To use a simple/**slow** implementation of SHA-512, use `-DED25519_REFHASH` when compiling `ed25519.c`. +This should never be used except to verify the code works when OpenSSL is not available. + +To use a custom hash function, use `-DED25519_CUSTOMHASH` when compiling `ed25519.c` and put your +custom hash implementation in ed25519-hash-custom.h. The hash must have a 512bit digest and implement + + struct ed25519_hash_context; + + void ed25519_hash_init(ed25519_hash_context *ctx); + void ed25519_hash_update(ed25519_hash_context *ctx, const uint8_t *in, size_t inlen); + void ed25519_hash_final(ed25519_hash_context *ctx, uint8_t *hash); + void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen); + +##### Random Options + +If you are not compiling aginst OpenSSL, you will need a random function for batch verification. + +To use a custom random function, use `-DED25519_CUSTOMRANDOM` when compiling `ed25519.c` and put your +custom hash implementation in ed25519-randombytes-custom.h. The random function must implement: + + void ED25519_FN(ed25519_randombytes_unsafe) (void *p, size_t len); + +Use `-DED25519_TEST` when compiling `ed25519.c` to use a deterministically seeded, non-thread safe CSPRNG +variant of Bob Jenkins [ISAAC](https://en.wikipedia.org/wiki/ISAAC_%28cipher%29) + +##### Minor options + +Use `-DED25519_INLINE_ASM` to disable the use of custom assembler routines and instead rely on portable C. + +Use `-DED25519_FORCE_32BIT` to force the use of 32 bit routines even when compiling for 64 bit. + +##### 32-bit + + gcc ed25519.c -m32 -O3 -c + +##### 64-bit + + gcc ed25519.c -m64 -O3 -c + +##### SSE2 + + gcc ed25519.c -m32 -O3 -c -DED25519_SSE2 -msse2 + gcc ed25519.c -m64 -O3 -c -DED25519_SSE2 + +clang and icc are also supported + + +#### Usage + +To use the code, link against `ed25519.o -mbits` and: + + #include "ed25519.h" + +Add `-lssl -lcrypto` when using OpenSSL (Some systems don't need -lcrypto? It might be trial and error). + +To generate a private key, simply generate 32 bytes from a secure +cryptographic source: + + ed25519_secret_key sk; + randombytes(sk, sizeof(ed25519_secret_key)); + +To generate a public key: + + ed25519_public_key pk; + ed25519_publickey(sk, pk); + +To sign a message: + + ed25519_signature sig; + ed25519_sign(message, message_len, sk, pk, signature); + +To verify a signature: + + int valid = ed25519_sign_open(message, message_len, pk, signature) == 0; + +To batch verify signatures: + + const unsigned char *mp[num] = {message1, message2..} + size_t ml[num] = {message_len1, message_len2..} + const unsigned char *pkp[num] = {pk1, pk2..} + const unsigned char *sigp[num] = {signature1, signature2..} + int valid[num] + + /* valid[i] will be set to 1 if the individual signature was valid, 0 otherwise */ + int all_valid = ed25519_sign_open_batch(mp, ml, pkp, sigp, num, valid) == 0; + +**Note**: Batch verification uses `ed25519_randombytes_unsafe`, implemented in +`ed25519-randombytes.h`, to generate random scalars for the verification code. +The default implementation now uses OpenSSLs `RAND_bytes`. + +Unlike the [SUPERCOP](https://bench.cr.yp.to/supercop.html) version, signatures are +not appended to messages, and there is no need for padding in front of messages. +Additionally, the secret key does not contain a copy of the public key, so it is +32 bytes instead of 64 bytes, and the public key must be provided to the signing +function. + +##### Curve25519 + +Curve25519 public keys can be generated thanks to +[Adam Langley](https://www.imperialviolet.org/2013/05/10/fastercurve25519.html) +leveraging Ed25519's precomputed basepoint scalar multiplication. + + curved25519_key sk, pk; + randombytes(sk, sizeof(curved25519_key)); + curved25519_scalarmult_basepoint(pk, sk); + +Note the name is curved25519, a combination of curve and ed25519, to prevent +name clashes. Performance is slightly faster than short message ed25519 +signing due to both using the same code for the scalar multiply. + +#### Testing + +Fuzzing against reference implemenations is now available. See [fuzz/README](fuzz/README.md). + +Building `ed25519.c` with `-DED25519_TEST` and linking with `test.c` will run basic sanity tests +and benchmark each function. `test-batch.c` has been incorporated in to `test.c`. + +`test-internals.c` is standalone and built the same way as `ed25519.c`. It tests the math primitives +with extreme values to ensure they function correctly. SSE2 is now supported. + +#### Papers + +[Available on the Ed25519 website](https://ed25519.cr.yp.to/papers.html) diff --git a/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-32bit.c b/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-32bit.c new file mode 100644 index 000000000..5a09710be --- /dev/null +++ b/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-32bit.c @@ -0,0 +1,681 @@ +/* + Public domain by Andrew M. + See: https://github.com/floodyberry/curve25519-donna + + 32 bit integer curve25519 implementation +*/ + +#include "ed25519-donna.h" + +static const uint32_t reduce_mask_25 = (1 << 25) - 1; +static const uint32_t reduce_mask_26 = (1 << 26) - 1; + +/* out = in */ +void curve25519_copy(bignum25519 out, const bignum25519 in) { + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = in[3]; + out[4] = in[4]; + out[5] = in[5]; + out[6] = in[6]; + out[7] = in[7]; + out[8] = in[8]; + out[9] = in[9]; +} + +/* out = a + b */ +void curve25519_add(bignum25519 out, const bignum25519 a, const bignum25519 b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + out[4] = a[4] + b[4]; + out[5] = a[5] + b[5]; + out[6] = a[6] + b[6]; + out[7] = a[7] + b[7]; + out[8] = a[8] + b[8]; + out[9] = a[9] + b[9]; +} + +void curve25519_add_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) { + uint32_t c = 0; + out[0] = a[0] + b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; + out[1] = a[1] + b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; + out[2] = a[2] + b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; + out[3] = a[3] + b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; + out[4] = a[4] + b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; + out[5] = a[5] + b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; + out[6] = a[6] + b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; + out[7] = a[7] + b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; + out[8] = a[8] + b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; + out[9] = a[9] + b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +void curve25519_add_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) { + uint32_t c = 0; + out[0] = a[0] + b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; + out[1] = a[1] + b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; + out[2] = a[2] + b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; + out[3] = a[3] + b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; + out[4] = a[4] + b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; + out[5] = a[5] + b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; + out[6] = a[6] + b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; + out[7] = a[7] + b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; + out[8] = a[8] + b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; + out[9] = a[9] + b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +/* multiples of p */ +static const uint32_t twoP0 = 0x07ffffda; +static const uint32_t twoP13579 = 0x03fffffe; +static const uint32_t twoP2468 = 0x07fffffe; +static const uint32_t fourP0 = 0x0fffffb4; +static const uint32_t fourP13579 = 0x07fffffc; +static const uint32_t fourP2468 = 0x0ffffffc; + +/* out = a - b */ +void curve25519_sub(bignum25519 out, const bignum25519 a, const bignum25519 b) { + uint32_t c = 0; + out[0] = twoP0 + a[0] - b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; + out[1] = twoP13579 + a[1] - b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; + out[2] = twoP2468 + a[2] - b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; + out[3] = twoP13579 + a[3] - b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; + out[4] = twoP2468 + a[4] - b[4] + c; + out[5] = twoP13579 + a[5] - b[5] ; + out[6] = twoP2468 + a[6] - b[6] ; + out[7] = twoP13579 + a[7] - b[7] ; + out[8] = twoP2468 + a[8] - b[8] ; + out[9] = twoP13579 + a[9] - b[9] ; +} + +/* out = in * scalar */ +void curve25519_scalar_product(bignum25519 out, const bignum25519 in, const uint32_t scalar) { + uint64_t a = 0; + uint32_t c = 0; + a = mul32x32_64(in[0], scalar); out[0] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); + a = mul32x32_64(in[1], scalar) + c; out[1] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); + a = mul32x32_64(in[2], scalar) + c; out[2] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); + a = mul32x32_64(in[3], scalar) + c; out[3] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); + a = mul32x32_64(in[4], scalar) + c; out[4] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); + a = mul32x32_64(in[5], scalar) + c; out[5] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); + a = mul32x32_64(in[6], scalar) + c; out[6] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); + a = mul32x32_64(in[7], scalar) + c; out[7] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); + a = mul32x32_64(in[8], scalar) + c; out[8] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); + a = mul32x32_64(in[9], scalar) + c; out[9] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); + out[0] += c * 19; +} + +/* out = a - b, where a is the result of a basic op (add,sub) */ +void curve25519_sub_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) { + uint32_t c = 0; + out[0] = fourP0 + a[0] - b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; + out[1] = fourP13579 + a[1] - b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; + out[2] = fourP2468 + a[2] - b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; + out[3] = fourP13579 + a[3] - b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; + out[4] = fourP2468 + a[4] - b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; + out[5] = fourP13579 + a[5] - b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; + out[6] = fourP2468 + a[6] - b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; + out[7] = fourP13579 + a[7] - b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; + out[8] = fourP2468 + a[8] - b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; + out[9] = fourP13579 + a[9] - b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +void curve25519_sub_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) { + uint32_t c = 0; + out[0] = fourP0 + a[0] - b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; + out[1] = fourP13579 + a[1] - b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; + out[2] = fourP2468 + a[2] - b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; + out[3] = fourP13579 + a[3] - b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; + out[4] = fourP2468 + a[4] - b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; + out[5] = fourP13579 + a[5] - b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; + out[6] = fourP2468 + a[6] - b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; + out[7] = fourP13579 + a[7] - b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; + out[8] = fourP2468 + a[8] - b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; + out[9] = fourP13579 + a[9] - b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +/* out = -a */ +void curve25519_neg(bignum25519 out, const bignum25519 a) { + uint32_t c = 0; + out[0] = twoP0 - a[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; + out[1] = twoP13579 - a[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; + out[2] = twoP2468 - a[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; + out[3] = twoP13579 - a[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; + out[4] = twoP2468 - a[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; + out[5] = twoP13579 - a[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; + out[6] = twoP2468 - a[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; + out[7] = twoP13579 - a[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; + out[8] = twoP2468 - a[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; + out[9] = twoP13579 - a[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +/* out = a * b */ +#define curve25519_mul_noinline curve25519_mul +void curve25519_mul(bignum25519 out, const bignum25519 a, const bignum25519 b) { + uint32_t r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0, r6 = 0, r7 = 0, r8 = 0, r9 = 0; + uint32_t s0 = 0, s1 = 0, s2 = 0, s3 = 0, s4 = 0, s5 = 0, s6 = 0, s7 = 0, s8 = 0, s9 = 0; + uint64_t m0 = 0, m1 = 0, m2 = 0, m3 = 0, m4 = 0, m5 = 0, m6 = 0, m7 = 0, m8 = 0, m9 = 0, c = 0; + uint32_t p = 0; + + r0 = b[0]; + r1 = b[1]; + r2 = b[2]; + r3 = b[3]; + r4 = b[4]; + r5 = b[5]; + r6 = b[6]; + r7 = b[7]; + r8 = b[8]; + r9 = b[9]; + + s0 = a[0]; + s1 = a[1]; + s2 = a[2]; + s3 = a[3]; + s4 = a[4]; + s5 = a[5]; + s6 = a[6]; + s7 = a[7]; + s8 = a[8]; + s9 = a[9]; + + m1 = mul32x32_64(r0, s1) + mul32x32_64(r1, s0); + m3 = mul32x32_64(r0, s3) + mul32x32_64(r1, s2) + mul32x32_64(r2, s1) + mul32x32_64(r3, s0); + m5 = mul32x32_64(r0, s5) + mul32x32_64(r1, s4) + mul32x32_64(r2, s3) + mul32x32_64(r3, s2) + mul32x32_64(r4, s1) + mul32x32_64(r5, s0); + m7 = mul32x32_64(r0, s7) + mul32x32_64(r1, s6) + mul32x32_64(r2, s5) + mul32x32_64(r3, s4) + mul32x32_64(r4, s3) + mul32x32_64(r5, s2) + mul32x32_64(r6, s1) + mul32x32_64(r7, s0); + m9 = mul32x32_64(r0, s9) + mul32x32_64(r1, s8) + mul32x32_64(r2, s7) + mul32x32_64(r3, s6) + mul32x32_64(r4, s5) + mul32x32_64(r5, s4) + mul32x32_64(r6, s3) + mul32x32_64(r7, s2) + mul32x32_64(r8, s1) + mul32x32_64(r9, s0); + + r1 *= 2; + r3 *= 2; + r5 *= 2; + r7 *= 2; + + m0 = mul32x32_64(r0, s0); + m2 = mul32x32_64(r0, s2) + mul32x32_64(r1, s1) + mul32x32_64(r2, s0); + m4 = mul32x32_64(r0, s4) + mul32x32_64(r1, s3) + mul32x32_64(r2, s2) + mul32x32_64(r3, s1) + mul32x32_64(r4, s0); + m6 = mul32x32_64(r0, s6) + mul32x32_64(r1, s5) + mul32x32_64(r2, s4) + mul32x32_64(r3, s3) + mul32x32_64(r4, s2) + mul32x32_64(r5, s1) + mul32x32_64(r6, s0); + m8 = mul32x32_64(r0, s8) + mul32x32_64(r1, s7) + mul32x32_64(r2, s6) + mul32x32_64(r3, s5) + mul32x32_64(r4, s4) + mul32x32_64(r5, s3) + mul32x32_64(r6, s2) + mul32x32_64(r7, s1) + mul32x32_64(r8, s0); + + r1 *= 19; + r2 *= 19; + r3 = (r3 / 2) * 19; + r4 *= 19; + r5 = (r5 / 2) * 19; + r6 *= 19; + r7 = (r7 / 2) * 19; + r8 *= 19; + r9 *= 19; + + m1 += (mul32x32_64(r9, s2) + mul32x32_64(r8, s3) + mul32x32_64(r7, s4) + mul32x32_64(r6, s5) + mul32x32_64(r5, s6) + mul32x32_64(r4, s7) + mul32x32_64(r3, s8) + mul32x32_64(r2, s9)); + m3 += (mul32x32_64(r9, s4) + mul32x32_64(r8, s5) + mul32x32_64(r7, s6) + mul32x32_64(r6, s7) + mul32x32_64(r5, s8) + mul32x32_64(r4, s9)); + m5 += (mul32x32_64(r9, s6) + mul32x32_64(r8, s7) + mul32x32_64(r7, s8) + mul32x32_64(r6, s9)); + m7 += (mul32x32_64(r9, s8) + mul32x32_64(r8, s9)); + + r3 *= 2; + r5 *= 2; + r7 *= 2; + r9 *= 2; + + m0 += (mul32x32_64(r9, s1) + mul32x32_64(r8, s2) + mul32x32_64(r7, s3) + mul32x32_64(r6, s4) + mul32x32_64(r5, s5) + mul32x32_64(r4, s6) + mul32x32_64(r3, s7) + mul32x32_64(r2, s8) + mul32x32_64(r1, s9)); + m2 += (mul32x32_64(r9, s3) + mul32x32_64(r8, s4) + mul32x32_64(r7, s5) + mul32x32_64(r6, s6) + mul32x32_64(r5, s7) + mul32x32_64(r4, s8) + mul32x32_64(r3, s9)); + m4 += (mul32x32_64(r9, s5) + mul32x32_64(r8, s6) + mul32x32_64(r7, s7) + mul32x32_64(r6, s8) + mul32x32_64(r5, s9)); + m6 += (mul32x32_64(r9, s7) + mul32x32_64(r8, s8) + mul32x32_64(r7, s9)); + m8 += (mul32x32_64(r9, s9)); + + r0 = (uint32_t)m0 & reduce_mask_26; c = (m0 >> 26); + m1 += c; r1 = (uint32_t)m1 & reduce_mask_25; c = (m1 >> 25); + m2 += c; r2 = (uint32_t)m2 & reduce_mask_26; c = (m2 >> 26); + m3 += c; r3 = (uint32_t)m3 & reduce_mask_25; c = (m3 >> 25); + m4 += c; r4 = (uint32_t)m4 & reduce_mask_26; c = (m4 >> 26); + m5 += c; r5 = (uint32_t)m5 & reduce_mask_25; c = (m5 >> 25); + m6 += c; r6 = (uint32_t)m6 & reduce_mask_26; c = (m6 >> 26); + m7 += c; r7 = (uint32_t)m7 & reduce_mask_25; c = (m7 >> 25); + m8 += c; r8 = (uint32_t)m8 & reduce_mask_26; c = (m8 >> 26); + m9 += c; r9 = (uint32_t)m9 & reduce_mask_25; p = (uint32_t)(m9 >> 25); + m0 = r0 + mul32x32_64(p,19); r0 = (uint32_t)m0 & reduce_mask_26; p = (uint32_t)(m0 >> 26); + r1 += p; + + out[0] = r0; + out[1] = r1; + out[2] = r2; + out[3] = r3; + out[4] = r4; + out[5] = r5; + out[6] = r6; + out[7] = r7; + out[8] = r8; + out[9] = r9; +} + +/* out = in * in */ +void curve25519_square(bignum25519 out, const bignum25519 in) { + uint32_t r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0, r6 = 0, r7 = 0, r8 = 0, r9 = 0; + uint32_t d6 = 0, d7 = 0, d8 = 0, d9 = 0; + uint64_t m0 = 0, m1 = 0, m2 = 0, m3 = 0, m4 = 0, m5 = 0, m6 = 0, m7 = 0, m8 = 0, m9 = 0, c = 0; + uint32_t p = 0; + + r0 = in[0]; + r1 = in[1]; + r2 = in[2]; + r3 = in[3]; + r4 = in[4]; + r5 = in[5]; + r6 = in[6]; + r7 = in[7]; + r8 = in[8]; + r9 = in[9]; + + m0 = mul32x32_64(r0, r0); + r0 *= 2; + m1 = mul32x32_64(r0, r1); + m2 = mul32x32_64(r0, r2) + mul32x32_64(r1, r1 * 2); + r1 *= 2; + m3 = mul32x32_64(r0, r3) + mul32x32_64(r1, r2 ); + m4 = mul32x32_64(r0, r4) + mul32x32_64(r1, r3 * 2) + mul32x32_64(r2, r2); + r2 *= 2; + m5 = mul32x32_64(r0, r5) + mul32x32_64(r1, r4 ) + mul32x32_64(r2, r3); + m6 = mul32x32_64(r0, r6) + mul32x32_64(r1, r5 * 2) + mul32x32_64(r2, r4) + mul32x32_64(r3, r3 * 2); + r3 *= 2; + m7 = mul32x32_64(r0, r7) + mul32x32_64(r1, r6 ) + mul32x32_64(r2, r5) + mul32x32_64(r3, r4 ); + m8 = mul32x32_64(r0, r8) + mul32x32_64(r1, r7 * 2) + mul32x32_64(r2, r6) + mul32x32_64(r3, r5 * 2) + mul32x32_64(r4, r4 ); + m9 = mul32x32_64(r0, r9) + mul32x32_64(r1, r8 ) + mul32x32_64(r2, r7) + mul32x32_64(r3, r6 ) + mul32x32_64(r4, r5 * 2); + + d6 = r6 * 19; + d7 = r7 * 2 * 19; + d8 = r8 * 19; + d9 = r9 * 2 * 19; + + m0 += (mul32x32_64(d9, r1 ) + mul32x32_64(d8, r2 ) + mul32x32_64(d7, r3 ) + mul32x32_64(d6, r4 * 2) + mul32x32_64(r5, r5 * 2 * 19)); + m1 += (mul32x32_64(d9, r2 / 2) + mul32x32_64(d8, r3 ) + mul32x32_64(d7, r4 ) + mul32x32_64(d6, r5 * 2)); + m2 += (mul32x32_64(d9, r3 ) + mul32x32_64(d8, r4 * 2) + mul32x32_64(d7, r5 * 2) + mul32x32_64(d6, r6 )); + m3 += (mul32x32_64(d9, r4 ) + mul32x32_64(d8, r5 * 2) + mul32x32_64(d7, r6 )); + m4 += (mul32x32_64(d9, r5 * 2) + mul32x32_64(d8, r6 * 2) + mul32x32_64(d7, r7 )); + m5 += (mul32x32_64(d9, r6 ) + mul32x32_64(d8, r7 * 2)); + m6 += (mul32x32_64(d9, r7 * 2) + mul32x32_64(d8, r8 )); + m7 += (mul32x32_64(d9, r8 )); + m8 += (mul32x32_64(d9, r9 )); + + r0 = (uint32_t)m0 & reduce_mask_26; c = (m0 >> 26); + m1 += c; r1 = (uint32_t)m1 & reduce_mask_25; c = (m1 >> 25); + m2 += c; r2 = (uint32_t)m2 & reduce_mask_26; c = (m2 >> 26); + m3 += c; r3 = (uint32_t)m3 & reduce_mask_25; c = (m3 >> 25); + m4 += c; r4 = (uint32_t)m4 & reduce_mask_26; c = (m4 >> 26); + m5 += c; r5 = (uint32_t)m5 & reduce_mask_25; c = (m5 >> 25); + m6 += c; r6 = (uint32_t)m6 & reduce_mask_26; c = (m6 >> 26); + m7 += c; r7 = (uint32_t)m7 & reduce_mask_25; c = (m7 >> 25); + m8 += c; r8 = (uint32_t)m8 & reduce_mask_26; c = (m8 >> 26); + m9 += c; r9 = (uint32_t)m9 & reduce_mask_25; p = (uint32_t)(m9 >> 25); + m0 = r0 + mul32x32_64(p,19); r0 = (uint32_t)m0 & reduce_mask_26; p = (uint32_t)(m0 >> 26); + r1 += p; + + out[0] = r0; + out[1] = r1; + out[2] = r2; + out[3] = r3; + out[4] = r4; + out[5] = r5; + out[6] = r6; + out[7] = r7; + out[8] = r8; + out[9] = r9; +} + +/* out = in ^ (2 * count) */ +void curve25519_square_times(bignum25519 out, const bignum25519 in, int count) { + uint32_t r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0, r6 = 0, r7 = 0, r8 = 0, r9 = 0; + uint32_t d6 = 0, d7 = 0, d8 = 0, d9 = 0; + uint64_t m0 = 0, m1 = 0, m2 = 0, m3 = 0, m4 = 0, m5 = 0, m6 = 0, m7 = 0, m8 = 0, m9 = 0, c = 0; + uint32_t p = 0; + + r0 = in[0]; + r1 = in[1]; + r2 = in[2]; + r3 = in[3]; + r4 = in[4]; + r5 = in[5]; + r6 = in[6]; + r7 = in[7]; + r8 = in[8]; + r9 = in[9]; + + do { + m0 = mul32x32_64(r0, r0); + r0 *= 2; + m1 = mul32x32_64(r0, r1); + m2 = mul32x32_64(r0, r2) + mul32x32_64(r1, r1 * 2); + r1 *= 2; + m3 = mul32x32_64(r0, r3) + mul32x32_64(r1, r2 ); + m4 = mul32x32_64(r0, r4) + mul32x32_64(r1, r3 * 2) + mul32x32_64(r2, r2); + r2 *= 2; + m5 = mul32x32_64(r0, r5) + mul32x32_64(r1, r4 ) + mul32x32_64(r2, r3); + m6 = mul32x32_64(r0, r6) + mul32x32_64(r1, r5 * 2) + mul32x32_64(r2, r4) + mul32x32_64(r3, r3 * 2); + r3 *= 2; + m7 = mul32x32_64(r0, r7) + mul32x32_64(r1, r6 ) + mul32x32_64(r2, r5) + mul32x32_64(r3, r4 ); + m8 = mul32x32_64(r0, r8) + mul32x32_64(r1, r7 * 2) + mul32x32_64(r2, r6) + mul32x32_64(r3, r5 * 2) + mul32x32_64(r4, r4 ); + m9 = mul32x32_64(r0, r9) + mul32x32_64(r1, r8 ) + mul32x32_64(r2, r7) + mul32x32_64(r3, r6 ) + mul32x32_64(r4, r5 * 2); + + d6 = r6 * 19; + d7 = r7 * 2 * 19; + d8 = r8 * 19; + d9 = r9 * 2 * 19; + + m0 += (mul32x32_64(d9, r1 ) + mul32x32_64(d8, r2 ) + mul32x32_64(d7, r3 ) + mul32x32_64(d6, r4 * 2) + mul32x32_64(r5, r5 * 2 * 19)); + m1 += (mul32x32_64(d9, r2 / 2) + mul32x32_64(d8, r3 ) + mul32x32_64(d7, r4 ) + mul32x32_64(d6, r5 * 2)); + m2 += (mul32x32_64(d9, r3 ) + mul32x32_64(d8, r4 * 2) + mul32x32_64(d7, r5 * 2) + mul32x32_64(d6, r6 )); + m3 += (mul32x32_64(d9, r4 ) + mul32x32_64(d8, r5 * 2) + mul32x32_64(d7, r6 )); + m4 += (mul32x32_64(d9, r5 * 2) + mul32x32_64(d8, r6 * 2) + mul32x32_64(d7, r7 )); + m5 += (mul32x32_64(d9, r6 ) + mul32x32_64(d8, r7 * 2)); + m6 += (mul32x32_64(d9, r7 * 2) + mul32x32_64(d8, r8 )); + m7 += (mul32x32_64(d9, r8 )); + m8 += (mul32x32_64(d9, r9 )); + + r0 = (uint32_t)m0 & reduce_mask_26; c = (m0 >> 26); + m1 += c; r1 = (uint32_t)m1 & reduce_mask_25; c = (m1 >> 25); + m2 += c; r2 = (uint32_t)m2 & reduce_mask_26; c = (m2 >> 26); + m3 += c; r3 = (uint32_t)m3 & reduce_mask_25; c = (m3 >> 25); + m4 += c; r4 = (uint32_t)m4 & reduce_mask_26; c = (m4 >> 26); + m5 += c; r5 = (uint32_t)m5 & reduce_mask_25; c = (m5 >> 25); + m6 += c; r6 = (uint32_t)m6 & reduce_mask_26; c = (m6 >> 26); + m7 += c; r7 = (uint32_t)m7 & reduce_mask_25; c = (m7 >> 25); + m8 += c; r8 = (uint32_t)m8 & reduce_mask_26; c = (m8 >> 26); + m9 += c; r9 = (uint32_t)m9 & reduce_mask_25; p = (uint32_t)(m9 >> 25); + m0 = r0 + mul32x32_64(p,19); r0 = (uint32_t)m0 & reduce_mask_26; p = (uint32_t)(m0 >> 26); + r1 += p; + } while (--count); + + out[0] = r0; + out[1] = r1; + out[2] = r2; + out[3] = r3; + out[4] = r4; + out[5] = r5; + out[6] = r6; + out[7] = r7; + out[8] = r8; + out[9] = r9; +} + +/* Take a little-endian, 32-byte number and expand it into polynomial form */ +void curve25519_expand(bignum25519 out, const unsigned char in[32]) { + uint32_t x0 = 0, x1 = 0, x2 = 0, x3 = 0, x4 = 0, x5 = 0, x6 = 0, x7 = 0; + #define F(s) \ + ((((uint32_t)in[s + 0]) ) | \ + (((uint32_t)in[s + 1]) << 8) | \ + (((uint32_t)in[s + 2]) << 16) | \ + (((uint32_t)in[s + 3]) << 24)) + x0 = F(0); + x1 = F(4); + x2 = F(8); + x3 = F(12); + x4 = F(16); + x5 = F(20); + x6 = F(24); + x7 = F(28); + #undef F + + out[0] = ( x0 ) & reduce_mask_26; + out[1] = ((((uint64_t)x1 << 32) | x0) >> 26) & reduce_mask_25; + out[2] = ((((uint64_t)x2 << 32) | x1) >> 19) & reduce_mask_26; + out[3] = ((((uint64_t)x3 << 32) | x2) >> 13) & reduce_mask_25; + out[4] = (( x3) >> 6) & reduce_mask_26; + out[5] = ( x4 ) & reduce_mask_25; + out[6] = ((((uint64_t)x5 << 32) | x4) >> 25) & reduce_mask_26; + out[7] = ((((uint64_t)x6 << 32) | x5) >> 19) & reduce_mask_25; + out[8] = ((((uint64_t)x7 << 32) | x6) >> 12) & reduce_mask_26; + out[9] = (( x7) >> 6) & reduce_mask_25; /* ignore the top bit */ +} + +/* Take a fully reduced polynomial form number and contract it into a + * little-endian, 32-byte array + */ +void curve25519_contract(unsigned char out[32], const bignum25519 in) { + bignum25519 f = {0}; + curve25519_copy(f, in); + + #define carry_pass() \ + f[1] += f[0] >> 26; f[0] &= reduce_mask_26; \ + f[2] += f[1] >> 25; f[1] &= reduce_mask_25; \ + f[3] += f[2] >> 26; f[2] &= reduce_mask_26; \ + f[4] += f[3] >> 25; f[3] &= reduce_mask_25; \ + f[5] += f[4] >> 26; f[4] &= reduce_mask_26; \ + f[6] += f[5] >> 25; f[5] &= reduce_mask_25; \ + f[7] += f[6] >> 26; f[6] &= reduce_mask_26; \ + f[8] += f[7] >> 25; f[7] &= reduce_mask_25; \ + f[9] += f[8] >> 26; f[8] &= reduce_mask_26; + + #define carry_pass_full() \ + carry_pass() \ + f[0] += 19 * (f[9] >> 25); f[9] &= reduce_mask_25; + + #define carry_pass_final() \ + carry_pass() \ + f[9] &= reduce_mask_25; + + carry_pass_full() + carry_pass_full() + + /* now t is between 0 and 2^255-1, properly carried. */ + /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ + f[0] += 19; + carry_pass_full() + + /* now between 19 and 2^255-1 in both cases, and offset by 19. */ + f[0] += (reduce_mask_26 + 1) - 19; + f[1] += (reduce_mask_25 + 1) - 1; + f[2] += (reduce_mask_26 + 1) - 1; + f[3] += (reduce_mask_25 + 1) - 1; + f[4] += (reduce_mask_26 + 1) - 1; + f[5] += (reduce_mask_25 + 1) - 1; + f[6] += (reduce_mask_26 + 1) - 1; + f[7] += (reduce_mask_25 + 1) - 1; + f[8] += (reduce_mask_26 + 1) - 1; + f[9] += (reduce_mask_25 + 1) - 1; + + /* now between 2^255 and 2^256-20, and offset by 2^255. */ + carry_pass_final() + + #undef carry_pass + #undef carry_full + #undef carry_final + + f[1] <<= 2; + f[2] <<= 3; + f[3] <<= 5; + f[4] <<= 6; + f[6] <<= 1; + f[7] <<= 3; + f[8] <<= 4; + f[9] <<= 6; + + #define F(i, s) \ + out[s+0] |= (unsigned char )(f[i] & 0xff); \ + out[s+1] = (unsigned char )((f[i] >> 8) & 0xff); \ + out[s+2] = (unsigned char )((f[i] >> 16) & 0xff); \ + out[s+3] = (unsigned char )((f[i] >> 24) & 0xff); + + out[0] = 0; + out[16] = 0; + F(0,0); + F(1,3); + F(2,6); + F(3,9); + F(4,12); + F(5,16); + F(6,19); + F(7,22); + F(8,25); + F(9,28); + #undef F +} + +/* if (iswap) swap(a, b) */ +void curve25519_swap_conditional(bignum25519 a, bignum25519 b, uint32_t iswap) { + const uint32_t swap = (uint32_t)(-(int32_t)iswap); + uint32_t x0 = 0, x1 = 0, x2 = 0, x3 = 0, x4 = 0, x5 = 0, x6 = 0, x7 = 0, x8 = 0, x9 = 0; + + x0 = swap & (a[0] ^ b[0]); a[0] ^= x0; b[0] ^= x0; + x1 = swap & (a[1] ^ b[1]); a[1] ^= x1; b[1] ^= x1; + x2 = swap & (a[2] ^ b[2]); a[2] ^= x2; b[2] ^= x2; + x3 = swap & (a[3] ^ b[3]); a[3] ^= x3; b[3] ^= x3; + x4 = swap & (a[4] ^ b[4]); a[4] ^= x4; b[4] ^= x4; + x5 = swap & (a[5] ^ b[5]); a[5] ^= x5; b[5] ^= x5; + x6 = swap & (a[6] ^ b[6]); a[6] ^= x6; b[6] ^= x6; + x7 = swap & (a[7] ^ b[7]); a[7] ^= x7; b[7] ^= x7; + x8 = swap & (a[8] ^ b[8]); a[8] ^= x8; b[8] ^= x8; + x9 = swap & (a[9] ^ b[9]); a[9] ^= x9; b[9] ^= x9; +} + +void curve25519_set(bignum25519 r, uint32_t x){ + r[0] = x & reduce_mask_26; x >>= 26; + r[1] = x & reduce_mask_25; + r[2] = 0; + r[3] = 0; + r[4] = 0; + r[5] = 0; + r[6] = 0; + r[7] = 0; + r[8] = 0; + r[9] = 0; +} + +void curve25519_set_d(bignum25519 r){ + curve25519_copy(r, ge25519_ecd); +} + +void curve25519_set_2d(bignum25519 r){ + curve25519_copy(r, ge25519_ec2d); +} + +void curve25519_set_sqrtneg1(bignum25519 r){ + curve25519_copy(r, ge25519_sqrtneg1); +} + +int curve25519_isnegative(const bignum25519 f) { + unsigned char s[32] = {0}; + curve25519_contract(s, f); + return s[0] & 1; +} + +int curve25519_isnonzero(const bignum25519 f) { + unsigned char s[32] = {0}; + curve25519_contract(s, f); + return ((((int) (s[0] | s[1] | s[2] | s[3] | s[4] | s[5] | s[6] | s[7] | s[8] | + s[9] | s[10] | s[11] | s[12] | s[13] | s[14] | s[15] | s[16] | s[17] | + s[18] | s[19] | s[20] | s[21] | s[22] | s[23] | s[24] | s[25] | s[26] | + s[27] | s[28] | s[29] | s[30] | s[31]) - 1) >> 8) + 1) & 0x1; +} + +void curve25519_reduce(bignum25519 out, const bignum25519 in) { + uint32_t c = 0; + out[0] = in[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; + out[1] = in[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; + out[2] = in[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; + out[3] = in[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; + out[4] = in[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; + out[5] = in[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; + out[6] = in[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; + out[7] = in[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; + out[8] = in[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; + out[9] = in[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +void curve25519_divpowm1(bignum25519 r, const bignum25519 u, const bignum25519 v) { + bignum25519 v3={0}, uv7={0}, t0={0}, t1={0}, t2={0}; + int i = 0; + + curve25519_square(v3, v); + curve25519_mul(v3, v3, v); /* v3 = v^3 */ + curve25519_square(uv7, v3); + curve25519_mul(uv7, uv7, v); + curve25519_mul(uv7, uv7, u); /* uv7 = uv^7 */ + + /*fe_pow22523(uv7, uv7);*/ + /* From fe_pow22523.c */ + + curve25519_square(t0, uv7); + curve25519_square(t1, t0); + curve25519_square(t1, t1); + curve25519_mul(t1, uv7, t1); + curve25519_mul(t0, t0, t1); + curve25519_square(t0, t0); + curve25519_mul(t0, t1, t0); + curve25519_square(t1, t0); + for (i = 0; i < 4; ++i) { + curve25519_square(t1, t1); + } + curve25519_mul(t0, t1, t0); + curve25519_square(t1, t0); + for (i = 0; i < 9; ++i) { + curve25519_square(t1, t1); + } + curve25519_mul(t1, t1, t0); + curve25519_square(t2, t1); + for (i = 0; i < 19; ++i) { + curve25519_square(t2, t2); + } + curve25519_mul(t1, t2, t1); + for (i = 0; i < 10; ++i) { + curve25519_square(t1, t1); + } + curve25519_mul(t0, t1, t0); + curve25519_square(t1, t0); + for (i = 0; i < 49; ++i) { + curve25519_square(t1, t1); + } + curve25519_mul(t1, t1, t0); + curve25519_square(t2, t1); + for (i = 0; i < 99; ++i) { + curve25519_square(t2, t2); + } + curve25519_mul(t1, t2, t1); + for (i = 0; i < 50; ++i) { + curve25519_square(t1, t1); + } + curve25519_mul(t0, t1, t0); + curve25519_square(t0, t0); + curve25519_square(t0, t0); + curve25519_mul(t0, t0, uv7); + + /* End fe_pow22523.c */ + /* t0 = (uv^7)^((q-5)/8) */ + curve25519_mul(t0, t0, v3); + curve25519_mul(r, t0, u); /* u^(m+1)v^(-(m+1)) */ +} + +void curve25519_expand_reduce(bignum25519 out, const unsigned char in[32]) { + uint32_t x0 = 0, x1 = 0, x2 = 0, x3 = 0, x4 = 0, x5 = 0, x6 = 0, x7 = 0; +#define F(s) \ + ((((uint32_t)in[s + 0]) ) | \ + (((uint32_t)in[s + 1]) << 8) | \ + (((uint32_t)in[s + 2]) << 16) | \ + (((uint32_t)in[s + 3]) << 24)) + x0 = F(0); + x1 = F(4); + x2 = F(8); + x3 = F(12); + x4 = F(16); + x5 = F(20); + x6 = F(24); + x7 = F(28); +#undef F + + out[0] = ( x0 ) & reduce_mask_26; + out[1] = ((((uint64_t)x1 << 32) | x0) >> 26) & reduce_mask_25; + out[2] = ((((uint64_t)x2 << 32) | x1) >> 19) & reduce_mask_26; + out[3] = ((((uint64_t)x3 << 32) | x2) >> 13) & reduce_mask_25; + out[4] = (( x3) >> 6) & reduce_mask_26; + out[5] = ( x4 ) & reduce_mask_25; + out[6] = ((((uint64_t)x5 << 32) | x4) >> 25) & reduce_mask_26; + out[7] = ((((uint64_t)x6 << 32) | x5) >> 19) & reduce_mask_25; + out[8] = ((((uint64_t)x7 << 32) | x6) >> 12) & reduce_mask_26; + out[9] = (( x7) >> 6); // & reduce_mask_25; /* ignore the top bit */ + out[0] += 19 * (out[9] >> 25); + out[9] &= reduce_mask_25; +} diff --git a/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-32bit.h b/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-32bit.h new file mode 100644 index 000000000..87bea94f9 --- /dev/null +++ b/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-32bit.h @@ -0,0 +1,79 @@ +/* + Public domain by Andrew M. + See: https://github.com/floodyberry/curve25519-donna + + 32 bit integer curve25519 implementation +*/ + +typedef uint32_t bignum25519[10]; + +/* out = in */ +void curve25519_copy(bignum25519 out, const bignum25519 in); + +/* out = a + b */ +void curve25519_add(bignum25519 out, const bignum25519 a, const bignum25519 b); + +void curve25519_add_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b); + +void curve25519_add_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b); + +/* out = a - b */ +void curve25519_sub(bignum25519 out, const bignum25519 a, const bignum25519 b); + +/* out = in * scalar */ +void curve25519_scalar_product(bignum25519 out, const bignum25519 in, const uint32_t scalar); + +/* out = a - b, where a is the result of a basic op (add,sub) */ +void curve25519_sub_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b); + +void curve25519_sub_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b); + +/* out = -a */ +void curve25519_neg(bignum25519 out, const bignum25519 a); + +/* out = a * b */ +#define curve25519_mul_noinline curve25519_mul +void curve25519_mul(bignum25519 out, const bignum25519 a, const bignum25519 b); + +/* out = in * in */ +void curve25519_square(bignum25519 out, const bignum25519 in); + +/* out = in ^ (2 * count) */ +void curve25519_square_times(bignum25519 out, const bignum25519 in, int count); + +/* Take a little-endian, 32-byte number and expand it into polynomial form */ +void curve25519_expand(bignum25519 out, const unsigned char in[32]); + +/* Take a fully reduced polynomial form number and contract it into a + * little-endian, 32-byte array + */ +void curve25519_contract(unsigned char out[32], const bignum25519 in); + +/* if (iswap) swap(a, b) */ +void curve25519_swap_conditional(bignum25519 a, bignum25519 b, uint32_t iswap); + +/* uint32_t to Zmod(2^255-19) */ +void curve25519_set(bignum25519 r, uint32_t x); + +/* set d */ +void curve25519_set_d(bignum25519 r); + +/* set 2d */ +void curve25519_set_2d(bignum25519 r); + +/* set sqrt(-1) */ +void curve25519_set_sqrtneg1(bignum25519 r); + +/* constant time Zmod(2^255-19) negative test */ +int curve25519_isnegative(const bignum25519 f); + +/* constant time Zmod(2^255-19) non-zero test */ +int curve25519_isnonzero(const bignum25519 f); + +/* reduce Zmod(2^255-19) */ +void curve25519_reduce(bignum25519 r, const bignum25519 in); + +void curve25519_divpowm1(bignum25519 r, const bignum25519 u, const bignum25519 v); + +/* Zmod(2^255-19) from byte array to bignum25519 expansion with modular reduction */ +void curve25519_expand_reduce(bignum25519 out, const unsigned char in[32]); diff --git a/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-helpers.c b/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-helpers.c new file mode 100644 index 000000000..b18500aab --- /dev/null +++ b/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-helpers.c @@ -0,0 +1,66 @@ +/* + Public domain by Andrew M. + See: https://github.com/floodyberry/curve25519-donna + + Curve25519 implementation agnostic helpers +*/ + +#include "ed25519-donna.h" + +/* + * In: b = 2^5 - 2^0 + * Out: b = 2^250 - 2^0 + */ +void curve25519_pow_two5mtwo0_two250mtwo0(bignum25519 b) { + bignum25519 ALIGN(16) t0 = {0}, c = {0}; + + /* 2^5 - 2^0 */ /* b */ + /* 2^10 - 2^5 */ curve25519_square_times(t0, b, 5); + /* 2^10 - 2^0 */ curve25519_mul_noinline(b, t0, b); + /* 2^20 - 2^10 */ curve25519_square_times(t0, b, 10); + /* 2^20 - 2^0 */ curve25519_mul_noinline(c, t0, b); + /* 2^40 - 2^20 */ curve25519_square_times(t0, c, 20); + /* 2^40 - 2^0 */ curve25519_mul_noinline(t0, t0, c); + /* 2^50 - 2^10 */ curve25519_square_times(t0, t0, 10); + /* 2^50 - 2^0 */ curve25519_mul_noinline(b, t0, b); + /* 2^100 - 2^50 */ curve25519_square_times(t0, b, 50); + /* 2^100 - 2^0 */ curve25519_mul_noinline(c, t0, b); + /* 2^200 - 2^100 */ curve25519_square_times(t0, c, 100); + /* 2^200 - 2^0 */ curve25519_mul_noinline(t0, t0, c); + /* 2^250 - 2^50 */ curve25519_square_times(t0, t0, 50); + /* 2^250 - 2^0 */ curve25519_mul_noinline(b, t0, b); +} + +/* + * z^(p - 2) = z(2^255 - 21) + */ +void curve25519_recip(bignum25519 out, const bignum25519 z) { + bignum25519 ALIGN(16) a = {0}, t0 = {0}, b = {0}; + + /* 2 */ curve25519_square_times(a, z, 1); /* a = 2 */ + /* 8 */ curve25519_square_times(t0, a, 2); + /* 9 */ curve25519_mul_noinline(b, t0, z); /* b = 9 */ + /* 11 */ curve25519_mul_noinline(a, b, a); /* a = 11 */ + /* 22 */ curve25519_square_times(t0, a, 1); + /* 2^5 - 2^0 = 31 */ curve25519_mul_noinline(b, t0, b); + /* 2^250 - 2^0 */ curve25519_pow_two5mtwo0_two250mtwo0(b); + /* 2^255 - 2^5 */ curve25519_square_times(b, b, 5); + /* 2^255 - 21 */ curve25519_mul_noinline(out, b, a); +} + +/* + * z^((p-5)/8) = z^(2^252 - 3) + */ +void curve25519_pow_two252m3(bignum25519 two252m3, const bignum25519 z) { + bignum25519 ALIGN(16) b,c,t0; + + /* 2 */ curve25519_square_times(c, z, 1); /* c = 2 */ + /* 8 */ curve25519_square_times(t0, c, 2); /* t0 = 8 */ + /* 9 */ curve25519_mul_noinline(b, t0, z); /* b = 9 */ + /* 11 */ curve25519_mul_noinline(c, b, c); /* c = 11 */ + /* 22 */ curve25519_square_times(t0, c, 1); + /* 2^5 - 2^0 = 31 */ curve25519_mul_noinline(b, t0, b); + /* 2^250 - 2^0 */ curve25519_pow_two5mtwo0_two250mtwo0(b); + /* 2^252 - 2^2 */ curve25519_square_times(b, b, 2); + /* 2^252 - 3 */ curve25519_mul_noinline(two252m3, b, z); +} diff --git a/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-helpers.h b/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-helpers.h new file mode 100644 index 000000000..62fde9099 --- /dev/null +++ b/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-helpers.h @@ -0,0 +1,22 @@ +/* + Public domain by Andrew M. + See: https://github.com/floodyberry/curve25519-donna + + Curve25519 implementation agnostic helpers +*/ + +/* + * In: b = 2^5 - 2^0 + * Out: b = 2^250 - 2^0 + */ +void curve25519_pow_two5mtwo0_two250mtwo0(bignum25519 b); + +/* + * z^(p - 2) = z(2^255 - 21) + */ +void curve25519_recip(bignum25519 out, const bignum25519 z); + +/* + * z^((p-5)/8) = z^(2^252 - 3) + */ +void curve25519_pow_two252m3(bignum25519 two252m3, const bignum25519 z); diff --git a/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-scalarmult-base.c b/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-scalarmult-base.c new file mode 100644 index 000000000..85a5d14b3 --- /dev/null +++ b/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-scalarmult-base.c @@ -0,0 +1,67 @@ +#include "ed25519-donna.h" +#include "ed25519.h" + +/* Calculates nQ where Q is the x-coordinate of a point on the curve + * + * mypublic: the packed little endian x coordinate of the resulting curve point + * n: a little endian, 32-byte number + * basepoint: a packed little endian point of the curve + */ + +void curve25519_scalarmult_donna(curve25519_key mypublic, const curve25519_key n, const curve25519_key basepoint) { + bignum25519 nqpqx = {1}, nqpqz = {0}, nqz = {1}, nqx = {0}; + bignum25519 q = {0}, qx = {0}, qpqx = {0}, qqx = {0}, zzz = {0}, zmone = {0}; + size_t bit = 0, lastbit = 0; + int32_t i = 0; + + curve25519_expand(q, basepoint); + curve25519_copy(nqx, q); + + /* bit 255 is always 0, and bit 254 is always 1, so skip bit 255 and + start pre-swapped on bit 254 */ + lastbit = 1; + + /* we are doing bits 254..3 in the loop, but are swapping in bits 253..2 */ + for (i = 253; i >= 2; i--) { + curve25519_add(qx, nqx, nqz); + curve25519_sub(nqz, nqx, nqz); + curve25519_add(qpqx, nqpqx, nqpqz); + curve25519_sub(nqpqz, nqpqx, nqpqz); + curve25519_mul(nqpqx, qpqx, nqz); + curve25519_mul(nqpqz, qx, nqpqz); + curve25519_add(qqx, nqpqx, nqpqz); + curve25519_sub(nqpqz, nqpqx, nqpqz); + curve25519_square(nqpqz, nqpqz); + curve25519_square(nqpqx, qqx); + curve25519_mul(nqpqz, nqpqz, q); + curve25519_square(qx, qx); + curve25519_square(nqz, nqz); + curve25519_mul(nqx, qx, nqz); + curve25519_sub(nqz, qx, nqz); + curve25519_scalar_product(zzz, nqz, 121665); + curve25519_add(zzz, zzz, qx); + curve25519_mul(nqz, nqz, zzz); + + bit = (n[i/8] >> (i & 7)) & 1; + curve25519_swap_conditional(nqx, nqpqx, bit ^ lastbit); + curve25519_swap_conditional(nqz, nqpqz, bit ^ lastbit); + lastbit = bit; + } + + /* the final 3 bits are always zero, so we only need to double */ + for (i = 0; i < 3; i++) { + curve25519_add(qx, nqx, nqz); + curve25519_sub(nqz, nqx, nqz); + curve25519_square(qx, qx); + curve25519_square(nqz, nqz); + curve25519_mul(nqx, qx, nqz); + curve25519_sub(nqz, qx, nqz); + curve25519_scalar_product(zzz, nqz, 121665); + curve25519_add(zzz, zzz, qx); + curve25519_mul(nqz, nqz, zzz); + } + + curve25519_recip(zmone, nqz); + curve25519_mul(nqz, nqx, zmone); + curve25519_contract(mypublic, nqz); +} diff --git a/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-scalarmult-base.h b/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-scalarmult-base.h new file mode 100644 index 000000000..9f3d79895 --- /dev/null +++ b/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-scalarmult-base.h @@ -0,0 +1,8 @@ +/* Calculates nQ where Q is the x-coordinate of a point on the curve + * + * mypublic: the packed little endian x coordinate of the resulting curve point + * n: a little endian, 32-byte number + * basepoint: a packed little endian point of the curve + */ + +void curve25519_scalarmult_donna(curve25519_key mypublic, const curve25519_key n, const curve25519_key basepoint); diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-blake2b.c b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-blake2b.c new file mode 100644 index 000000000..3223c5543 --- /dev/null +++ b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-blake2b.c @@ -0,0 +1,8 @@ +#include + +#include "ed25519-blake2b.h" +#include "ed25519-hash-custom-blake2b.h" + +#define ED25519_SUFFIX _blake2b + +#include "ed25519.c" diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-blake2b.h b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-blake2b.h new file mode 100644 index 000000000..95dc31e80 --- /dev/null +++ b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-blake2b.h @@ -0,0 +1,21 @@ +#ifndef ED25519_BLAKE2B_H +#define ED25519_BLAKE2B_H + +#include "ed25519.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +void ed25519_publickey_blake2b(const ed25519_secret_key sk, ed25519_public_key pk); + +int ed25519_sign_open_blake2b(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS); +void ed25519_sign_blake2b(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, ed25519_signature RS); + +int ed25519_scalarmult_blake2b(ed25519_public_key res, const ed25519_secret_key sk, const ed25519_public_key pk); + +#if defined(__cplusplus) +} +#endif + +#endif // ED25519_BLAKE2B_H diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-32bit-tables.c b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-32bit-tables.c new file mode 100644 index 000000000..fd2236b05 --- /dev/null +++ b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-32bit-tables.c @@ -0,0 +1,63 @@ +#include "ed25519-donna.h" + +const ge25519 ALIGN(16) ge25519_basepoint = { + {0x0325d51a,0x018b5823,0x00f6592a,0x0104a92d,0x01a4b31d,0x01d6dc5c,0x027118fe,0x007fd814,0x013cd6e5,0x0085a4db}, + {0x02666658,0x01999999,0x00cccccc,0x01333333,0x01999999,0x00666666,0x03333333,0x00cccccc,0x02666666,0x01999999}, + {0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000}, + {0x01b7dda3,0x01a2ace9,0x025eadbb,0x0003ba8a,0x0083c27e,0x00abe37d,0x01274732,0x00ccacdd,0x00fd78b7,0x019e1d7c} +}; + +/* + d +*/ + +const bignum25519 ALIGN(16) ge25519_ecd = { + 0x035978a3,0x00d37284,0x03156ebd,0x006a0a0e,0x0001c029,0x0179e898,0x03a03cbb,0x01ce7198,0x02e2b6ff,0x01480db3 +}; + +const bignum25519 ALIGN(16) ge25519_ec2d = { + 0x02b2f159,0x01a6e509,0x022add7a,0x00d4141d,0x00038052,0x00f3d130,0x03407977,0x019ce331,0x01c56dff,0x00901b67 +}; + +/* + sqrt(-1) +*/ + +const bignum25519 ALIGN(16) ge25519_sqrtneg1 = { + 0x020ea0b0,0x0186c9d2,0x008f189d,0x0035697f,0x00bd0c60,0x01fbd7a7,0x02804c9e,0x01e16569,0x0004fc1d,0x00ae0c92 +}; + +const ge25519_niels ALIGN(16) ge25519_niels_sliding_multiples[32] = { + {{0x0340913e,0x000e4175,0x03d673a2,0x002e8a05,0x03f4e67c,0x008f8a09,0x00c21a34,0x004cf4b8,0x01298f81,0x0113f4be},{0x018c3b85,0x0124f1bd,0x01c325f7,0x0037dc60,0x033e4cb7,0x003d42c2,0x01a44c32,0x014ca4e1,0x03a33d4b,0x001f3e74},{0x037aaa68,0x00448161,0x0093d579,0x011e6556,0x009b67a0,0x0143598c,0x01bee5ee,0x00b50b43,0x0289f0c6,0x01bc45ed}}, + {{0x00fcd265,0x0047fa29,0x034faacc,0x01ef2e0d,0x00ef4d4f,0x014bd6bd,0x00f98d10,0x014c5026,0x007555bd,0x00aae456},{0x00ee9730,0x016c2a13,0x017155e4,0x01874432,0x00096a10,0x01016732,0x01a8014f,0x011e9823,0x01b9a80f,0x01e85938},{0x01d0d889,0x01a4cfc3,0x034c4295,0x0110e1ae,0x0162508c,0x00f2db4c,0x0072a2c6,0x0098da2e,0x02f12b9b,0x0168a09a}}, + {{0x0047d6ba,0x0060b0e9,0x0136eff2,0x008a5939,0x03540053,0x0064a087,0x02788e5c,0x00be7c67,0x033eb1b5,0x005529f9},{0x00a5bb33,0x00af1102,0x01a05442,0x001e3af7,0x02354123,0x00bfec44,0x01f5862d,0x00dd7ba3,0x03146e20,0x00a51733},{0x012a8285,0x00f6fc60,0x023f9797,0x003e85ee,0x009c3820,0x01bda72d,0x01b3858d,0x00d35683,0x0296b3bb,0x010eaaf9}}, + {{0x023221b1,0x01cb26aa,0x0074f74d,0x0099ddd1,0x01b28085,0x00192c3a,0x013b27c9,0x00fc13bd,0x01d2e531,0x0075bb75},{0x004ea3bf,0x00973425,0x001a4d63,0x01d59cee,0x01d1c0d4,0x00542e49,0x01294114,0x004fce36,0x029283c9,0x01186fa9},{0x01b8b3a2,0x00db7200,0x00935e30,0x003829f5,0x02cc0d7d,0x0077adf3,0x0220dd2c,0x0014ea53,0x01c6a0f9,0x01ea7eec}}, + {{0x039d8064,0x01885f80,0x00337e6d,0x01b7a902,0x02628206,0x015eb044,0x01e30473,0x0191f2d9,0x011fadc9,0x01270169},{0x02a8632f,0x0199e2a9,0x00d8b365,0x017a8de2,0x02994279,0x0086f5b5,0x0119e4e3,0x01eb39d6,0x0338add7,0x00d2e7b4},{0x0045af1b,0x013a2fe4,0x0245e0d6,0x014538ce,0x038bfe0f,0x01d4cf16,0x037e14c9,0x0160d55e,0x0021b008,0x01cf05c8}}, + {{0x01864348,0x01d6c092,0x0070262b,0x014bb844,0x00fb5acd,0x008deb95,0x003aaab5,0x00eff474,0x00029d5c,0x0062ad66},{0x02802ade,0x01c02122,0x01c4e5f7,0x00781181,0x039767fb,0x01703406,0x0342388b,0x01f5e227,0x022546d8,0x0109d6ab},{0x016089e9,0x00cb317f,0x00949b05,0x01099417,0x000c7ad2,0x011a8622,0x0088ccda,0x01290886,0x022b53df,0x00f71954}}, + {{0x027fbf93,0x01c04ecc,0x01ed6a0d,0x004cdbbb,0x02bbf3af,0x00ad5968,0x01591955,0x0094f3a2,0x02d17602,0x00099e20},{0x02007f6d,0x003088a8,0x03db77ee,0x00d5ade6,0x02fe12ce,0x0107ba07,0x0107097d,0x00482a6f,0x02ec346f,0x008d3f5f},{0x032ea378,0x0028465c,0x028e2a6c,0x018efc6e,0x0090df9a,0x01a7e533,0x039bfc48,0x010c745d,0x03daa097,0x0125ee9b}}, + {{0x028ccf0b,0x00f36191,0x021ac081,0x012154c8,0x034e0a6e,0x01b25192,0x00180403,0x01d7eea1,0x00218d05,0x010ed735},{0x03cfeaa0,0x01b300c4,0x008da499,0x0068c4e1,0x0219230a,0x01f2d4d0,0x02defd60,0x00e565b7,0x017f12de,0x018788a4},{0x03d0b516,0x009d8be6,0x03ddcbb3,0x0071b9fe,0x03ace2bd,0x01d64270,0x032d3ec9,0x01084065,0x0210ae4d,0x01447584}}, + {{0x0020de87,0x00e19211,0x01b68102,0x00b5ac97,0x022873c0,0x01942d25,0x01271394,0x0102073f,0x02fe2482,0x01c69ff9},{0x010e9d81,0x019dbbe5,0x0089f258,0x006e06b8,0x02951883,0x018f1248,0x019b3237,0x00bc7553,0x024ddb85,0x01b4c964},{0x01c8c854,0x0060ae29,0x01406d8e,0x01cff2f9,0x00cff451,0x01778d0c,0x03ac8c41,0x01552e59,0x036559ee,0x011d1b12}}, + {{0x00741147,0x0151b219,0x01092690,0x00e877e6,0x01f4d6bb,0x0072a332,0x01cd3b03,0x00dadff2,0x0097db5e,0x0086598d},{0x01c69a2b,0x01decf1b,0x02c2fa6e,0x013b7c4f,0x037beac8,0x013a16b5,0x028e7bda,0x01f6e8ac,0x01e34fe9,0x01726947},{0x01f10e67,0x003c73de,0x022b7ea2,0x010f32c2,0x03ff776a,0x00142277,0x01d38b88,0x00776138,0x03c60822,0x01201140}}, + {{0x0236d175,0x0008748e,0x03c6476d,0x013f4cdc,0x02eed02a,0x00838a47,0x032e7210,0x018bcbb3,0x00858de4,0x01dc7826},{0x00a37fc7,0x0127b40b,0x01957884,0x011d30ad,0x02816683,0x016e0e23,0x00b76be4,0x012db115,0x02516506,0x0154ce62},{0x00451edf,0x00bd749e,0x03997342,0x01cc2c4c,0x00eb6975,0x01a59508,0x03a516cf,0x00c228ef,0x0168ff5a,0x01697b47}}, + {{0x00527359,0x01783156,0x03afd75c,0x00ce56dc,0x00e4b970,0x001cabe9,0x029e0f6d,0x0188850c,0x0135fefd,0x00066d80},{0x02150e83,0x01448abf,0x02bb0232,0x012bf259,0x033c8268,0x00711e20,0x03fc148f,0x005e0e70,0x017d8bf9,0x0112b2e2},{0x02134b83,0x001a0517,0x0182c3cc,0x00792182,0x0313d799,0x001a3ed7,0x0344547e,0x01f24a0d,0x03de6ad2,0x00543127}}, + {{0x00dca868,0x00618f27,0x015a1709,0x00ddc38a,0x0320fd13,0x0036168d,0x0371ab06,0x01783fc7,0x0391e05f,0x01e29b5d},{0x01471138,0x00fca542,0x00ca31cf,0x01ca7bad,0x0175bfbc,0x01a708ad,0x03bce212,0x01244215,0x0075bb99,0x01acad68},{0x03a0b976,0x01dc12d1,0x011aab17,0x00aba0ba,0x029806cd,0x0142f590,0x018fd8ea,0x01a01545,0x03c4ad55,0x01c971ff}}, + {{0x00d098c0,0x000afdc7,0x006cd230,0x01276af3,0x03f905b2,0x0102994c,0x002eb8a4,0x015cfbeb,0x025f855f,0x01335518},{0x01cf99b2,0x0099c574,0x01a69c88,0x00881510,0x01cd4b54,0x0112109f,0x008abdc5,0x0074647a,0x0277cb1f,0x01e53324},{0x02ac5053,0x01b109b0,0x024b095e,0x016997b3,0x02f26bb6,0x00311021,0x00197885,0x01d0a55a,0x03b6fcc8,0x01c020d5}}, + {{0x02584a34,0x00e7eee0,0x03257a03,0x011e95a3,0x011ead91,0x00536202,0x00b1ce24,0x008516c6,0x03669d6d,0x004ea4a8},{0x00773f01,0x0019c9ce,0x019f6171,0x01d4afde,0x02e33323,0x01ad29b6,0x02ead1dc,0x01ed51a5,0x01851ad0,0x001bbdfa},{0x00577de5,0x00ddc730,0x038b9952,0x00f281ae,0x01d50390,0x0002e071,0x000780ec,0x010d448d,0x01f8a2af,0x00f0a5b7}}, + {{0x031f2541,0x00d34bae,0x0323ff9d,0x003a056d,0x02e25443,0x00a1ad05,0x00d1bee8,0x002f7f8e,0x03007477,0x002a24b1},{0x0114a713,0x01457e76,0x032255d5,0x01cc647f,0x02a4bdef,0x0153d730,0x00118bcf,0x00f755ff,0x013490c7,0x01ea674e},{0x02bda3e8,0x00bb490d,0x00f291ea,0x000abf40,0x01dea321,0x002f9ce0,0x00b2b193,0x00fa54b5,0x0128302f,0x00a19d8b}}, + {{0x022ef5bd,0x01638af3,0x038c6f8a,0x01a33a3d,0x039261b2,0x01bb89b8,0x010bcf9d,0x00cf42a9,0x023d6f17,0x01da1bca},{0x00e35b25,0x000d824f,0x0152e9cf,0x00ed935d,0x020b8460,0x01c7b83f,0x00c969e5,0x01a74198,0x0046a9d9,0x00cbc768},{0x01597c6a,0x0144a99b,0x00a57551,0x0018269c,0x023c464c,0x0009b022,0x00ee39e1,0x0114c7f2,0x038a9ad2,0x01584c17}}, + {{0x03b0c0d5,0x00b30a39,0x038a6ce4,0x01ded83a,0x01c277a6,0x01010a61,0x0346d3eb,0x018d995e,0x02f2c57c,0x000c286b},{0x0092aed1,0x0125e37b,0x027ca201,0x001a6b6b,0x03290f55,0x0047ba48,0x018d916c,0x01a59062,0x013e35d4,0x0002abb1},{0x003ad2aa,0x007ddcc0,0x00c10f76,0x0001590b,0x002cfca6,0x000ed23e,0x00ee4329,0x00900f04,0x01c24065,0x0082fa70}}, + {{0x02025e60,0x003912b8,0x0327041c,0x017e5ee5,0x02c0ecec,0x015a0d1c,0x02b1ce7c,0x0062220b,0x0145067e,0x01a5d931},{0x009673a6,0x00e1f609,0x00927c2a,0x016faa37,0x01650ef0,0x016f63b5,0x03cd40e1,0x003bc38f,0x0361f0ac,0x01d42acc},{0x02f81037,0x008ca0e8,0x017e23d1,0x011debfe,0x01bcbb68,0x002e2563,0x03e8add6,0x000816e5,0x03fb7075,0x0153e5ac}}, + {{0x02b11ecd,0x016bf185,0x008f22ef,0x00e7d2bb,0x0225d92e,0x00ece785,0x00508873,0x017e16f5,0x01fbe85d,0x01e39a0e},{0x01669279,0x017c810a,0x024941f5,0x0023ebeb,0x00eb7688,0x005760f1,0x02ca4146,0x0073cde7,0x0052bb75,0x00f5ffa7},{0x03b8856b,0x00cb7dcd,0x02f14e06,0x001820d0,0x01d74175,0x00e59e22,0x03fba550,0x00484641,0x03350088,0x01c3c9a3}}, + {{0x00dcf355,0x0104481c,0x0022e464,0x01f73fe7,0x00e03325,0x0152b698,0x02ef769a,0x00973663,0x00039b8c,0x0101395b},{0x01805f47,0x019160ec,0x03832cd0,0x008b06eb,0x03d4d717,0x004cb006,0x03a75b8f,0x013b3d30,0x01cfad88,0x01f034d1},{0x0078338a,0x01c7d2e3,0x02bc2b23,0x018b3f05,0x0280d9aa,0x005f3d44,0x0220a95a,0x00eeeb97,0x0362aaec,0x00835d51}}, + {{0x01b9f543,0x013fac4d,0x02ad93ae,0x018ef464,0x0212cdf7,0x01138ba9,0x011583ab,0x019c3d26,0x028790b4,0x00e2e2b6},{0x033bb758,0x01f0dbf1,0x03734bd1,0x0129b1e5,0x02b3950e,0x003bc922,0x01a53ec8,0x018c5532,0x006f3cee,0x00ae3c79},{0x0351f95d,0x0012a737,0x03d596b8,0x017658fe,0x00ace54a,0x008b66da,0x0036c599,0x012a63a2,0x032ceba1,0x00126bac}}, + {{0x03dcfe7e,0x019f4f18,0x01c81aee,0x0044bc2b,0x00827165,0x014f7c13,0x03b430f0,0x00bf96cc,0x020c8d62,0x01471997},{0x01fc7931,0x001f42dd,0x00ba754a,0x005bd339,0x003fbe49,0x016b3930,0x012a159c,0x009f83b0,0x03530f67,0x01e57b85},{0x02ecbd81,0x0096c294,0x01fce4a9,0x017701a5,0x0175047d,0x00ee4a31,0x012686e5,0x008efcd4,0x0349dc54,0x01b3466f}}, + {{0x02179ca3,0x01d86414,0x03f0afd0,0x00305964,0x015c7428,0x0099711e,0x015d5442,0x00c71014,0x01b40b2e,0x01d483cf},{0x01afc386,0x01984859,0x036203ff,0x0045c6a8,0x0020a8aa,0x00990baa,0x03313f10,0x007ceede,0x027429e4,0x017806ce},{0x039357a1,0x0142f8f4,0x0294a7b6,0x00eaccf4,0x0259edb3,0x01311e6e,0x004d326f,0x0130c346,0x01ccef3c,0x01c424b2}}, + {{0x0364918c,0x00148fc0,0x01638a7b,0x01a1fd5b,0x028ad013,0x0081e5a4,0x01a54f33,0x0174e101,0x003d0257,0x003a856c},{0x00051dcf,0x00f62b1d,0x0143d0ad,0x0042adbd,0x000fda90,0x01743ceb,0x0173e5e4,0x017bc749,0x03b7137a,0x0105ce96},{0x00f9218a,0x015b8c7c,0x00e102f8,0x0158d7e2,0x0169a5b8,0x00b2f176,0x018b347a,0x014cfef2,0x0214a4e3,0x017f1595}}, + {{0x006d7ae5,0x0195c371,0x0391e26d,0x0062a7c6,0x003f42ab,0x010dad86,0x024f8198,0x01542b2a,0x0014c454,0x0189c471},{0x0390988e,0x00b8799d,0x02e44912,0x0078e2e6,0x00075654,0x01923eed,0x0040cd72,0x00a37c76,0x0009d466,0x00c8531d},{0x02651770,0x00609d01,0x0286c265,0x0134513c,0x00ee9281,0x005d223c,0x035c760c,0x00679b36,0x0073ecb8,0x016faa50}}, + {{0x02c89be4,0x016fc244,0x02f38c83,0x018beb72,0x02b3ce2c,0x0097b065,0x034f017b,0x01dd957f,0x00148f61,0x00eab357},{0x0343d2f8,0x003398fc,0x011e368e,0x00782a1f,0x00019eea,0x00117b6f,0x0128d0d1,0x01a5e6bb,0x01944f1b,0x012b41e1},{0x03318301,0x018ecd30,0x0104d0b1,0x0038398b,0x03726701,0x019da88c,0x002d9769,0x00a7a681,0x031d9028,0x00ebfc32}}, + {{0x0220405e,0x0171face,0x02d930f8,0x017f6d6a,0x023b8c47,0x0129d5f9,0x02972456,0x00a3a524,0x006f4cd2,0x004439fa},{0x00c53505,0x0190c2fd,0x00507244,0x009930f9,0x01a39270,0x01d327c6,0x0399bc47,0x01cfe13d,0x0332bd99,0x00b33e7d},{0x0203f5e4,0x003627b5,0x00018af8,0x01478581,0x004a2218,0x002e3bb7,0x039384d0,0x0146ea62,0x020b9693,0x0017155f}}, + {{0x03c97e6f,0x00738c47,0x03b5db1f,0x01808fcf,0x01e8fc98,0x01ed25dd,0x01bf5045,0x00eb5c2b,0x0178fe98,0x01b85530},{0x01c20eb0,0x01aeec22,0x030b9eee,0x01b7d07e,0x0187e16f,0x014421fb,0x009fa731,0x0040b6d7,0x00841861,0x00a27fbc},{0x02d69abf,0x0058cdbf,0x0129f9ec,0x013c19ae,0x026c5b93,0x013a7fe7,0x004bb2ba,0x0063226f,0x002a95ca,0x01abefd9}}, + {{0x02f5d2c1,0x00378318,0x03734fb5,0x01258073,0x0263f0f6,0x01ad70e0,0x01b56d06,0x01188fbd,0x011b9503,0x0036d2e1},{0x0113a8cc,0x01541c3e,0x02ac2bbc,0x01d95867,0x01f47459,0x00ead489,0x00ab5b48,0x01db3b45,0x00edb801,0x004b024f},{0x00b8190f,0x011fe4c2,0x00621f82,0x010508d7,0x001a5a76,0x00c7d7fd,0x03aab96d,0x019cd9dc,0x019c6635,0x00ceaa1e}}, + {{0x01085cf2,0x01fd47af,0x03e3f5e1,0x004b3e99,0x01e3d46a,0x0060033c,0x015ff0a8,0x0150cdd8,0x029e8e21,0x008cf1bc},{0x00156cb1,0x003d623f,0x01a4f069,0x00d8d053,0x01b68aea,0x01ca5ab6,0x0316ae43,0x0134dc44,0x001c8d58,0x0084b343},{0x0318c781,0x0135441f,0x03a51a5e,0x019293f4,0x0048bb37,0x013d3341,0x0143151e,0x019c74e1,0x00911914,0x0076ddde}}, + {{0x006bc26f,0x00d48e5f,0x00227bbe,0x00629ea8,0x01ea5f8b,0x0179a330,0x027a1d5f,0x01bf8f8e,0x02d26e2a,0x00c6b65e},{0x01701ab6,0x0051da77,0x01b4b667,0x00a0ce7c,0x038ae37b,0x012ac852,0x03a0b0fe,0x0097c2bb,0x00a017d2,0x01eb8b2a},{0x0120b962,0x0005fb42,0x0353b6fd,0x0061f8ce,0x007a1463,0x01560a64,0x00e0a792,0x01907c92,0x013a6622,0x007b47f1}} +}; diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-32bit-tables.h b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-32bit-tables.h new file mode 100644 index 000000000..f76a832cf --- /dev/null +++ b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-32bit-tables.h @@ -0,0 +1,17 @@ +extern const ge25519 ALIGN(16) ge25519_basepoint; + +/* + d +*/ + +extern const bignum25519 ALIGN(16) ge25519_ecd; + +extern const bignum25519 ALIGN(16) ge25519_ec2d; + +/* + sqrt(-1) +*/ + +extern const bignum25519 ALIGN(16) ge25519_sqrtneg1; + +extern const ge25519_niels ALIGN(16) ge25519_niels_sliding_multiples[32]; diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-basepoint-table.c b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-basepoint-table.c new file mode 100644 index 000000000..cd5d18728 --- /dev/null +++ b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-basepoint-table.c @@ -0,0 +1,261 @@ +#include "ed25519-donna.h" + +/* multiples of the base point in packed {ysubx, xaddy, t2d} form */ +const uint8_t ALIGN(16) ge25519_niels_base_multiples[256][96] = { + {0x3e,0x91,0x40,0xd7,0x05,0x39,0x10,0x9d,0xb3,0xbe,0x40,0xd1,0x05,0x9f,0x39,0xfd,0x09,0x8a,0x8f,0x68,0x34,0x84,0xc1,0xa5,0x67,0x12,0xf8,0x98,0x92,0x2f,0xfd,0x44,0x85,0x3b,0x8c,0xf5,0xc6,0x93,0xbc,0x2f,0x19,0x0e,0x8c,0xfb,0xc6,0x2d,0x93,0xcf,0xc2,0x42,0x3d,0x64,0x98,0x48,0x0b,0x27,0x65,0xba,0xd4,0x33,0x3a,0x9d,0xcf,0x07,0x59,0xbb,0x6f,0x4b,0x67,0x15,0xbd,0xdb,0xea,0xa5,0xa2,0xee,0x00,0x3f,0xe1,0x41,0xfa,0xc6,0x57,0xc9,0x1c,0x9d,0xd4,0xcd,0xca,0xec,0x16,0xaf,0x1f,0xbe,0x0e,0x4f}, + {0xa8,0xd5,0xb4,0x42,0x60,0xa5,0x99,0x8a,0xf6,0xac,0x60,0x4e,0x0c,0x81,0x2b,0x8f,0xaa,0x37,0x6e,0xb1,0x6b,0x23,0x9e,0xe0,0x55,0x25,0xc9,0x69,0xa6,0x95,0xb5,0x6b,0xd7,0x71,0x3c,0x93,0xfc,0xe7,0x24,0x92,0xb5,0xf5,0x0f,0x7a,0x96,0x9d,0x46,0x9f,0x02,0x07,0xd6,0xe1,0x65,0x9a,0xa6,0x5a,0x2e,0x2e,0x7d,0xa8,0x3f,0x06,0x0c,0x59,0x02,0x68,0xd3,0xda,0xaa,0x7e,0x34,0x6e,0x05,0x48,0xee,0x83,0x93,0x59,0xf3,0xba,0x26,0x68,0x07,0xe6,0x10,0xbe,0xca,0x3b,0xb8,0xd1,0x5e,0x16,0x0a,0x4f,0x31,0x49}, + {0x65,0xd2,0xfc,0xa4,0xe8,0x1f,0x61,0x56,0x7d,0xba,0xc1,0xe5,0xfd,0x53,0xd3,0x3b,0xbd,0xd6,0x4b,0x21,0x1a,0xf3,0x31,0x81,0x62,0xda,0x5b,0x55,0x87,0x15,0xb9,0x2a,0x30,0x97,0xee,0x4c,0xa8,0xb0,0x25,0xaf,0x8a,0x4b,0x86,0xe8,0x30,0x84,0x5a,0x02,0x32,0x67,0x01,0x9f,0x02,0x50,0x1b,0xc1,0xf4,0xf8,0x80,0x9a,0x1b,0x4e,0x16,0x7a,0x34,0x48,0x67,0xf1,0xf4,0x11,0xf2,0x9b,0x95,0xf8,0x2d,0xf6,0x17,0x6b,0x4e,0xb8,0x4e,0x2a,0x72,0x5b,0x07,0x6f,0xde,0xd7,0x21,0x2a,0xbb,0x63,0xb9,0x04,0x9a,0x54}, + {0xbf,0x18,0x68,0x05,0x0a,0x05,0xfe,0x95,0xa9,0xfa,0x60,0x56,0x71,0x89,0x7e,0x32,0x73,0x50,0xa0,0x06,0xcd,0xe3,0xe8,0xc3,0x9a,0xa4,0x45,0x74,0x4c,0x3f,0x93,0x27,0x9f,0x09,0xfc,0x8e,0xb9,0x51,0x73,0x28,0x38,0x25,0xfd,0x7d,0xf4,0xc6,0x65,0x67,0x65,0x92,0x0a,0xfb,0x3d,0x8d,0x34,0xca,0x27,0x87,0xe5,0x21,0x03,0x91,0x0e,0x68,0xb0,0x26,0x14,0xe5,0xec,0x45,0x1e,0xbf,0x94,0x0f,0xba,0x6d,0x3d,0xc6,0x2b,0xe3,0xc0,0x52,0xf8,0x8c,0xd5,0x74,0x29,0xe4,0x18,0x4c,0xe6,0xb0,0xb1,0x79,0xf0,0x44}, + {0xba,0xd6,0x47,0xa4,0xc3,0x82,0x91,0x7f,0xb7,0x29,0x27,0x4b,0xd1,0x14,0x00,0xd5,0x87,0xa0,0x64,0xb8,0x1c,0xf1,0x3c,0xe3,0xf3,0x55,0x1b,0xeb,0x73,0x7e,0x4a,0x15,0x33,0xbb,0xa5,0x08,0x44,0xbc,0x12,0xa2,0x02,0xed,0x5e,0xc7,0xc3,0x48,0x50,0x8d,0x44,0xec,0xbf,0x5a,0x0c,0xeb,0x1b,0xdd,0xeb,0x06,0xe2,0x46,0xf1,0xcc,0x45,0x29,0xb3,0x03,0xd0,0xe7,0x79,0xa1,0x32,0xc8,0x7e,0x4d,0x12,0x00,0x0a,0x9d,0x72,0x5f,0xf3,0x8f,0x6d,0x0e,0xa1,0xd4,0xc1,0x62,0x98,0x7a,0xb2,0x38,0x59,0xac,0xb8,0x68}, + {0xa4,0x8c,0x7d,0x7b,0xb6,0x06,0x98,0x49,0x39,0x27,0xd2,0x27,0x84,0xe2,0x5b,0x57,0xb9,0x53,0x45,0x20,0xe7,0x5c,0x08,0xbb,0x84,0x78,0x41,0xae,0x41,0x4c,0xb6,0x38,0x31,0x71,0x15,0x77,0xeb,0xee,0x0c,0x3a,0x88,0xaf,0xc8,0x00,0x89,0x15,0x27,0x9b,0x36,0xa7,0x59,0xda,0x68,0xb6,0x65,0x80,0xbd,0x38,0xcc,0xa2,0xb6,0x7b,0xe5,0x51,0xa4,0xe3,0x9d,0x68,0x91,0xad,0x9d,0x8f,0x37,0x91,0xfb,0xf8,0x28,0x24,0x5f,0x17,0x88,0xb9,0xcf,0x9f,0x32,0xb5,0x0a,0x05,0x9f,0xc0,0x54,0x13,0xa2,0xdf,0x65,0x78}, + {0xb1,0x21,0x32,0xaa,0x9a,0x2c,0x6f,0xba,0xa7,0x23,0xba,0x3b,0x53,0x21,0xa0,0x6c,0x3a,0x2c,0x19,0x92,0x4f,0x76,0xea,0x9d,0xe0,0x17,0x53,0x2e,0x5d,0xdd,0x6e,0x1d,0xbf,0xa3,0x4e,0x94,0xd0,0x5c,0x1a,0x6b,0xd2,0xc0,0x9d,0xb3,0x3a,0x35,0x70,0x74,0x49,0x2e,0x54,0x28,0x82,0x52,0xb2,0x71,0x7e,0x92,0x3c,0x28,0x69,0xea,0x1b,0x46,0x36,0xda,0x0f,0xab,0xac,0x8a,0x7a,0x21,0xc8,0x49,0x35,0x3d,0x54,0xc6,0x28,0xa5,0x68,0x75,0xab,0x13,0x8b,0x5b,0xd0,0x37,0x37,0xbc,0x2c,0x3a,0x62,0xef,0x3c,0x23}, + {0xd9,0x34,0x92,0xf3,0xed,0x5d,0xa7,0xe2,0xf9,0x58,0xb5,0xe1,0x80,0x76,0x3d,0x96,0xfb,0x23,0x3c,0x6e,0xac,0x41,0x27,0x2c,0xc3,0x01,0x0e,0x32,0xa1,0x24,0x90,0x3a,0x8f,0x3e,0xdd,0x04,0x66,0x59,0xb7,0x59,0x2c,0x70,0x88,0xe2,0x77,0x03,0xb3,0x6c,0x23,0xc3,0xd9,0x5e,0x66,0x9c,0x33,0xb1,0x2f,0xe5,0xbc,0x61,0x60,0xe7,0x15,0x09,0x7e,0xa3,0x34,0xa8,0x35,0xe8,0x7d,0xdf,0xea,0x57,0x98,0x68,0xda,0x9c,0xe1,0x8b,0x26,0xb3,0x67,0x71,0x36,0x85,0x11,0x2c,0xc2,0xd5,0xef,0xdb,0xd9,0xb3,0x9e,0x58}, + {0x5e,0x51,0xaa,0x49,0x54,0x63,0x5b,0xed,0x3a,0x82,0xc6,0x0b,0x9f,0xc4,0x65,0xa8,0xc4,0xd1,0x42,0x5b,0xe9,0x1f,0x0c,0x85,0xb9,0x15,0xd3,0x03,0x6f,0x6d,0xd7,0x30,0x1d,0x9c,0x2f,0x63,0x0e,0xdd,0xcc,0x2e,0x15,0x31,0x89,0x76,0x96,0xb6,0xd0,0x51,0x58,0x7a,0x63,0xa8,0x6b,0xb7,0xdf,0x52,0x39,0xef,0x0e,0xa0,0x49,0x7d,0xd3,0x6d,0xc7,0xe4,0x06,0x21,0x17,0x44,0x44,0x6c,0x69,0x7f,0x8d,0x92,0x80,0xd6,0x53,0xfb,0x26,0x3f,0x4d,0x69,0xa4,0x9e,0x73,0xb4,0xb0,0x4b,0x86,0x2e,0x11,0x97,0xc6,0x10}, + {0xde,0x5f,0xbe,0x7d,0x27,0xc4,0x93,0x64,0xa2,0x7e,0xad,0x19,0xad,0x4f,0x5d,0x26,0x90,0x45,0x30,0x46,0xc8,0xdf,0x00,0x0e,0x09,0xfe,0x66,0xed,0xab,0x1c,0xe6,0x25,0x05,0xc8,0x58,0x83,0xa0,0x2a,0xa6,0x0c,0x47,0x42,0x20,0x7a,0xe3,0x4a,0x3d,0x6a,0xdc,0xed,0x11,0x3b,0xa6,0xd3,0x64,0x74,0xef,0x06,0x08,0x55,0xaf,0x9b,0xbf,0x03,0x04,0x66,0x58,0xcc,0x28,0xe1,0x13,0x3f,0x7e,0x74,0x59,0xb4,0xec,0x73,0x58,0x6f,0xf5,0x68,0x12,0xcc,0xed,0x3d,0xb6,0xa0,0x2c,0xe2,0x86,0x45,0x63,0x78,0x6d,0x56}, + {0x34,0x08,0xc1,0x9c,0x9f,0xa4,0x37,0x16,0x51,0xc4,0x9b,0xa8,0xd5,0x56,0x8e,0xbc,0xdb,0xd2,0x7f,0x7f,0x0f,0xec,0xb5,0x1c,0xd9,0x35,0xcc,0x5e,0xca,0x5b,0x97,0x33,0xd0,0x2f,0x5a,0xc6,0x85,0x42,0x05,0xa1,0xc3,0x67,0x16,0xf3,0x2a,0x11,0x64,0x6c,0x58,0xee,0x1a,0x73,0x40,0xe2,0x0a,0x68,0x2a,0xb2,0x93,0x47,0xf3,0xa5,0xfb,0x14,0xd4,0xf7,0x85,0x69,0x16,0x46,0xd7,0x3c,0x57,0x00,0xc8,0xc9,0x84,0x5e,0x3e,0x59,0x1e,0x13,0x61,0x7b,0xb6,0xf2,0xc3,0x2f,0x6c,0x52,0xfc,0x83,0xea,0x9c,0x82,0x14}, + {0xc2,0x95,0xdd,0x97,0x84,0x7b,0x43,0xff,0xa7,0xb5,0x4e,0xaa,0x30,0x4e,0x74,0x6c,0x8b,0xe8,0x85,0x3c,0x61,0x5d,0x0c,0x9e,0x73,0x81,0x75,0x5f,0x1e,0xc7,0xd9,0x2f,0xb8,0xec,0x71,0x4e,0x2f,0x0b,0xe7,0x21,0xe3,0x77,0xa4,0x40,0xb9,0xdd,0x56,0xe6,0x80,0x4f,0x1d,0xce,0xce,0x56,0x65,0xbf,0x7e,0x7b,0x5d,0x53,0xc4,0x3b,0xfc,0x05,0xdd,0xde,0xaf,0x52,0xae,0xb3,0xb8,0x24,0xcf,0x30,0x3b,0xed,0x8c,0x63,0x95,0x34,0x95,0x81,0xbe,0xa9,0x83,0xbc,0xa4,0x33,0x04,0x1f,0x65,0x5c,0x47,0x67,0x37,0x37}, + {0xd9,0xad,0xd1,0x40,0xfd,0x99,0xba,0x2f,0x27,0xd0,0xf4,0x96,0x6f,0x16,0x07,0xb3,0xae,0x3b,0xf0,0x15,0x52,0xf0,0x63,0x43,0x99,0xf9,0x18,0x3b,0x6c,0xa5,0xbe,0x1f,0x90,0x65,0x24,0x14,0xcb,0x95,0x40,0x63,0x35,0x55,0xc1,0x16,0x40,0x14,0x12,0xef,0x60,0xbc,0x10,0x89,0x0c,0x14,0x38,0x9e,0x8c,0x7c,0x90,0x30,0x57,0x90,0xf5,0x6b,0x8a,0x5b,0x41,0xe1,0xf1,0x78,0xa7,0x0f,0x7e,0xa7,0xc3,0xba,0xf7,0x9f,0x40,0x06,0x50,0x9a,0xa2,0x9a,0xb8,0xd7,0x52,0x6f,0x56,0x5a,0x63,0x7a,0xf6,0x1c,0x52,0x02}, + {0x94,0x52,0x9d,0x0a,0x0b,0xee,0x3f,0x51,0x66,0x5a,0xdf,0x0f,0x5c,0xe7,0x98,0x8f,0xce,0x07,0xe1,0xbf,0x88,0x86,0x61,0xd4,0xed,0x2c,0x38,0x71,0x7e,0x0a,0xa0,0x3f,0xe4,0x5e,0x2f,0x77,0x20,0x67,0x14,0xb1,0xce,0x9a,0x07,0x96,0xb1,0x94,0xf8,0xe8,0x4a,0x82,0xac,0x00,0x4d,0x22,0xf8,0x4a,0xc4,0x6c,0xcd,0xf7,0xd9,0x53,0x17,0x00,0x34,0xdb,0x3d,0x96,0x2d,0x23,0x69,0x3c,0x58,0x38,0x97,0xb4,0xda,0x87,0xde,0x1d,0x85,0xf2,0x91,0xa0,0xf9,0xd1,0xd7,0xaa,0xb6,0xed,0x48,0xa0,0x2f,0xfe,0xb5,0x12}, + {0x4d,0xe3,0xfc,0x96,0xc4,0xfb,0xf0,0x71,0xed,0x5b,0xf3,0xad,0x6b,0x82,0xb9,0x73,0x61,0xc5,0x28,0xff,0x61,0x72,0x04,0xd2,0x6f,0x20,0xb1,0x6f,0xf9,0x76,0x9b,0x74,0x92,0x1e,0x6f,0xad,0x26,0x7c,0x2b,0xdf,0x13,0x89,0x4b,0x50,0x23,0xd3,0x66,0x4b,0xc3,0x8b,0x1c,0x75,0xc0,0x9d,0x40,0x8c,0xb8,0xc7,0x96,0x07,0xc2,0x93,0x7e,0x6f,0x05,0xae,0xa6,0xae,0x04,0xf6,0x5a,0x1f,0x99,0x9c,0xe4,0xbe,0xf1,0x51,0x23,0xc1,0x66,0x6b,0xff,0xee,0xb5,0x08,0xa8,0x61,0x51,0x21,0xe0,0x01,0x0f,0xc1,0xce,0x0f}, + {0x44,0x1e,0xfe,0x49,0xa6,0x58,0x4d,0x64,0x7e,0x77,0xad,0x31,0xa2,0xae,0xfc,0x21,0xd2,0xd0,0x7f,0x88,0x5a,0x1c,0x44,0x02,0xf3,0x11,0xc5,0x83,0x71,0xaa,0x01,0x49,0x45,0x4e,0x24,0xc4,0x9d,0xd2,0xf2,0x3d,0x0a,0xde,0xd8,0x93,0x74,0x0e,0x02,0x2b,0x4d,0x21,0x0c,0x82,0x7e,0x06,0xc8,0x6c,0x0a,0xb9,0xea,0x6f,0x16,0x79,0x37,0x41,0xf0,0xf8,0x1a,0x8c,0x54,0xb7,0xb1,0x08,0xb4,0x99,0x62,0x24,0x7c,0x7a,0x0f,0xce,0x39,0xd9,0x06,0x1e,0xf9,0xb0,0x60,0xf7,0x13,0x12,0x6d,0x72,0x7b,0x88,0xbb,0x41}, + {0xbe,0x46,0x43,0x74,0x44,0x7d,0xe8,0x40,0x25,0x2b,0xb5,0x15,0xd4,0xda,0x48,0x1d,0x3e,0x60,0x3b,0xa1,0x18,0x8a,0x3a,0x7c,0xf7,0xbd,0xcd,0x2f,0xc1,0x28,0xb7,0x4e,0xae,0x91,0x66,0x7c,0x59,0x4c,0x23,0x7e,0xc8,0xb4,0x85,0x0a,0x3d,0x9d,0x88,0x64,0xe7,0xfa,0x4a,0x35,0x0c,0xc9,0xe2,0xda,0x1d,0x9e,0x6a,0x0c,0x07,0x1e,0x87,0x0a,0x89,0x89,0xbc,0x4b,0x99,0xb5,0x01,0x33,0x60,0x42,0xdd,0x5b,0x3a,0xae,0x6b,0x73,0x3c,0x9e,0xd5,0x19,0xe2,0xad,0x61,0x0d,0x64,0xd4,0x85,0x26,0x0f,0x30,0xe7,0x3e}, + {0xb7,0xd6,0x7d,0x9e,0xe4,0x55,0xd2,0xf5,0xac,0x1e,0x0b,0x61,0x5c,0x11,0x16,0x80,0xca,0x87,0xe1,0x92,0x5d,0x97,0x99,0x3c,0xc2,0x25,0x91,0x97,0x62,0x57,0x81,0x13,0x18,0x75,0x1e,0x84,0x47,0x79,0xfa,0x43,0xd7,0x46,0x9c,0x63,0x59,0xfa,0xc6,0xe5,0x74,0x2b,0x05,0xe3,0x1d,0x5e,0x06,0xa1,0x30,0x90,0xb8,0xcf,0xa2,0xc6,0x47,0x7d,0xe0,0xd6,0xf0,0x8e,0x14,0xd0,0xda,0x3f,0x3c,0x6f,0x54,0x91,0x9a,0x74,0x3e,0x9d,0x57,0x81,0xbb,0x26,0x10,0x62,0xec,0x71,0x80,0xec,0xc9,0x34,0x8d,0xf5,0x8c,0x14}, + {0x27,0xf0,0x34,0x79,0xf6,0x92,0xa4,0x46,0xa9,0x0a,0x84,0xf6,0xbe,0x84,0x99,0x46,0x54,0x18,0x61,0x89,0x2a,0xbc,0xa1,0x5c,0xd4,0xbb,0x5d,0xbd,0x1e,0xfa,0xf2,0x3f,0x6d,0x75,0xe4,0x9a,0x7d,0x2f,0x57,0xe2,0x7f,0x48,0xf3,0x88,0xbb,0x45,0xc3,0x56,0x8d,0xa8,0x60,0x69,0x6d,0x0b,0xd1,0x9f,0xb9,0xa1,0xae,0x4e,0xad,0xeb,0x8f,0x27,0x66,0x39,0x93,0x8c,0x1f,0x68,0xaa,0xb1,0x98,0x0c,0x29,0x20,0x9c,0x94,0x21,0x8c,0x52,0x3c,0x9d,0x21,0x91,0x52,0x11,0x39,0x7b,0x67,0x9c,0xfe,0x02,0xdd,0x04,0x41}, + {0x2a,0x42,0x24,0x11,0x5e,0xbf,0xb2,0x72,0xb5,0x3a,0xa3,0x98,0x33,0x0c,0xfa,0xa1,0x66,0xb6,0x52,0xfa,0x01,0x61,0xcb,0x94,0xd5,0x53,0xaf,0xaf,0x00,0x3b,0x86,0x2c,0xb8,0x6a,0x09,0xdb,0x06,0x4e,0x21,0x81,0x35,0x4f,0xe4,0x0c,0xc9,0xb6,0xa8,0x21,0xf5,0x2a,0x9e,0x40,0x2a,0xc1,0x24,0x65,0x81,0xa4,0xfc,0x8e,0xa4,0xb5,0x65,0x01,0x76,0x6a,0x84,0xa0,0x74,0xa4,0x90,0xf1,0xc0,0x7c,0x2f,0xcd,0x84,0xf9,0xef,0x12,0x8f,0x2b,0xaa,0x58,0x06,0x29,0x5e,0x69,0xb8,0xc8,0xfe,0xbf,0xd9,0x67,0x1b,0x59}, + {0xfa,0x9b,0xb4,0x80,0x1c,0x0d,0x2f,0x31,0x8a,0xec,0xf3,0xab,0x5e,0x51,0x79,0x59,0x88,0x1c,0xf0,0x9e,0xc0,0x33,0x70,0x72,0xcb,0x7b,0x8f,0xca,0xc7,0x2e,0xe0,0x3d,0x5d,0xb5,0x18,0x9f,0x71,0xb3,0xb9,0x99,0x1e,0x64,0x8c,0xa1,0xfa,0xe5,0x65,0xe4,0xed,0x05,0x9f,0xc2,0x36,0x11,0x08,0x61,0x8b,0x12,0x30,0x70,0x86,0x4f,0x9b,0x48,0xef,0x92,0xeb,0x3a,0x2d,0x10,0x32,0xd2,0x61,0xa8,0x16,0x61,0xb4,0x53,0x62,0xe1,0x24,0xaa,0x0b,0x19,0xe7,0xab,0x7e,0x3d,0xbf,0xbe,0x6c,0x49,0xba,0xfb,0xf5,0x49}, + {0xd4,0xcf,0x5b,0x8a,0x10,0x9a,0x94,0x30,0xeb,0x73,0x64,0xbc,0x70,0xdd,0x40,0xdc,0x1c,0x0d,0x7c,0x30,0xc1,0x94,0xc2,0x92,0x74,0x6e,0xfa,0xcb,0x6d,0xa8,0x04,0x56,0x2e,0x57,0x9c,0x1e,0x8c,0x62,0x5d,0x15,0x41,0x47,0x88,0xc5,0xac,0x86,0x4d,0x8a,0xeb,0x63,0x57,0x51,0xf6,0x52,0xa3,0x91,0x5b,0x51,0x67,0x88,0xc2,0xa6,0xa1,0x06,0xb6,0x64,0x17,0x7c,0xd4,0xd1,0x88,0x72,0x51,0x8b,0x41,0xe0,0x40,0x11,0x54,0x72,0xd1,0xf6,0xac,0x18,0x60,0x1a,0x03,0x9f,0xc6,0x42,0x27,0xfe,0x89,0x9e,0x98,0x20}, + {0x7f,0xcc,0x2d,0x3a,0xfd,0x77,0x97,0x49,0x92,0xd8,0x4f,0xa5,0x2c,0x7c,0x85,0x32,0xa0,0xe3,0x07,0xd2,0x64,0xd8,0x79,0xa2,0x29,0x7e,0xa6,0x0c,0x1d,0xed,0x03,0x04,0x2e,0xec,0xea,0x85,0x8b,0x27,0x74,0x16,0xdf,0x2b,0xcb,0x7a,0x07,0xdc,0x21,0x56,0x5a,0xf4,0xcb,0x61,0x16,0x4c,0x0a,0x64,0xd3,0x95,0x05,0xf7,0x50,0x99,0x0b,0x73,0x52,0xc5,0x4e,0x87,0x35,0x2d,0x4b,0xc9,0x8d,0x6f,0x24,0x98,0xcf,0xc8,0xe6,0xc5,0xce,0x35,0xc0,0x16,0xfa,0x46,0xcb,0xf7,0xcc,0x3d,0x30,0x08,0x43,0x45,0xd7,0x5b}, + {0xc2,0x4c,0xb2,0x28,0x95,0xd1,0x9a,0x7f,0x81,0xc1,0x35,0x63,0x65,0x54,0x6b,0x7f,0x36,0x72,0xc0,0x4f,0x6e,0xb6,0xb8,0x66,0x83,0xad,0x80,0x73,0x00,0x78,0x3a,0x13,0x2a,0x79,0xe7,0x15,0x21,0x93,0xc4,0x85,0xc9,0xdd,0xcd,0xbd,0xa2,0x89,0x4c,0xc6,0x62,0xd7,0xa3,0xad,0xa8,0x3d,0x1e,0x9d,0x2c,0xf8,0x67,0x30,0x12,0xdb,0xb7,0x5b,0xbe,0x62,0xca,0xc6,0x67,0xf4,0x61,0x09,0xee,0x52,0x19,0x21,0xd6,0x21,0xec,0x04,0x70,0x47,0xd5,0x9b,0x77,0x60,0x23,0x18,0xd2,0xe0,0xf0,0x58,0x6d,0xca,0x0d,0x74}, + {0x4e,0xce,0xcf,0x52,0x07,0xee,0x48,0xdf,0xb7,0x08,0xec,0x06,0xf3,0xfa,0xff,0xc3,0xc4,0x59,0x54,0xb9,0x2a,0x0b,0x71,0x05,0x8d,0xa3,0x3e,0x96,0xfa,0x25,0x1d,0x16,0x3c,0x43,0x78,0x04,0x57,0x8c,0x1a,0x23,0x9d,0x43,0x81,0xc2,0x0e,0x27,0xb5,0xb7,0x9f,0x07,0xd9,0xe3,0xea,0x99,0xaa,0xdb,0xd9,0x03,0x2b,0x6c,0x25,0xf5,0x03,0x2c,0x7d,0xa4,0x53,0x7b,0x75,0x18,0x0f,0x79,0x79,0x58,0x0c,0xcf,0x30,0x01,0x7b,0x30,0xf9,0xf7,0x7e,0x25,0x77,0x3d,0x90,0x31,0xaf,0xbb,0x96,0xbd,0xbd,0x68,0x94,0x69}, + {0xcf,0xfe,0xda,0xf4,0x46,0x2f,0x1f,0xbd,0xf7,0xd6,0x7f,0xa4,0x14,0x01,0xef,0x7c,0x7f,0xb3,0x47,0x4a,0xda,0xfd,0x1f,0xd3,0x85,0x57,0x90,0x73,0xa4,0x19,0x52,0x52,0x48,0x19,0xa9,0x6a,0xe6,0x3d,0xdd,0xd8,0xcc,0xd2,0xc0,0x2f,0xc2,0x64,0x50,0x48,0x2f,0xea,0xfd,0x34,0x66,0x24,0x48,0x9b,0x3a,0x2e,0x4a,0x6c,0x4e,0x1c,0x3e,0x29,0xe1,0x12,0x51,0x92,0x4b,0x13,0x6e,0x37,0xa0,0x5d,0xa1,0xdc,0xb5,0x78,0x37,0x70,0x11,0x31,0x1c,0x46,0xaf,0x89,0x45,0xb0,0x23,0x28,0x03,0x7f,0x44,0x5c,0x60,0x5b}, + {0x89,0x7c,0xc4,0x20,0x59,0x80,0x65,0xb9,0xcc,0x8f,0x3b,0x92,0x0c,0x10,0xf0,0xe7,0x77,0xef,0xe2,0x02,0x65,0x25,0x01,0x00,0xee,0xb3,0xae,0xa8,0xce,0x6d,0xa7,0x24,0x4c,0xf0,0xe7,0xf0,0xc6,0xfe,0xe9,0x3b,0x62,0x49,0xe3,0x75,0x9e,0x57,0x6a,0x86,0x1a,0xe6,0x1d,0x1e,0x16,0xef,0x42,0x55,0xd5,0xbd,0x5a,0xcc,0xf4,0xfe,0x12,0x2f,0x40,0xc7,0xc0,0xdf,0xb2,0x22,0x45,0x0a,0x07,0xa4,0xc9,0x40,0x7f,0x6e,0xd0,0x10,0x68,0xf6,0xcf,0x78,0x41,0x14,0xcf,0xc6,0x90,0x37,0xa4,0x18,0x25,0x7b,0x60,0x5e}, + {0x18,0x18,0xdf,0x6c,0x8f,0x1d,0xb3,0x58,0xa2,0x58,0x62,0xc3,0x4f,0xa7,0xcf,0x35,0x6e,0x1d,0xe6,0x66,0x4f,0xff,0xb3,0xe1,0xf7,0xd5,0xcd,0x6c,0xab,0xac,0x67,0x50,0x14,0xcf,0x96,0xa5,0x1c,0x43,0x2c,0xa0,0x00,0xe4,0xd3,0xae,0x40,0x2d,0xc4,0xe3,0xdb,0x26,0x0f,0x2e,0x80,0x26,0x45,0xd2,0x68,0x70,0x45,0x9e,0x13,0x33,0x1f,0x20,0x51,0x9d,0x03,0x08,0x6b,0x7f,0x52,0xfd,0x06,0x00,0x7c,0x01,0x64,0x49,0xb1,0x18,0xa8,0xa4,0x25,0x2e,0xb0,0x0e,0x22,0xd5,0x75,0x03,0x46,0x62,0x88,0xba,0x7c,0x39}, + {0xb2,0x59,0x59,0xf0,0x93,0x30,0xc1,0x30,0x76,0x79,0xa9,0xe9,0x8d,0xa1,0x3a,0xe2,0x26,0x5e,0x1d,0x72,0x91,0xd4,0x2f,0x22,0x3a,0x6c,0x6e,0x76,0x20,0xd3,0x39,0x23,0xe7,0x79,0x13,0xc8,0xfb,0xc3,0x15,0x78,0xf1,0x2a,0xe1,0xdd,0x20,0x94,0x61,0xa6,0xd5,0xfd,0xa8,0x85,0xf8,0xc0,0xa9,0xff,0x52,0xc2,0xe1,0xc1,0x22,0x40,0x1b,0x77,0xa7,0x2f,0x3a,0x51,0x86,0xd9,0x7d,0xd8,0x08,0xcf,0xd4,0xf9,0x71,0x9b,0xac,0xf5,0xb3,0x83,0xa2,0x1e,0x1b,0xc3,0x6b,0xd0,0x76,0x1a,0x97,0x19,0x92,0x18,0x1a,0x33}, + {0xc6,0x80,0x4f,0xfb,0x45,0x6f,0x16,0xf5,0xcf,0x75,0xc7,0x61,0xde,0xc7,0x36,0x9c,0x1c,0xd9,0x41,0x90,0x1b,0xe8,0xd4,0xe3,0x21,0xfe,0xbd,0x83,0x6b,0x7c,0x16,0x31,0xaf,0x72,0x75,0x9d,0x3a,0x2f,0x51,0x26,0x9e,0x4a,0x07,0x68,0x88,0xe2,0xcb,0x5b,0xc4,0xf7,0x80,0x11,0xc1,0xc1,0xed,0x84,0x7b,0xa6,0x49,0xf6,0x9f,0x61,0xc9,0x1a,0x68,0x10,0x4b,0x52,0x42,0x38,0x2b,0xf2,0x87,0xe9,0x9c,0xee,0x3b,0x34,0x68,0x50,0xc8,0x50,0x62,0x4a,0x84,0x71,0x9d,0xfc,0x11,0xb1,0x08,0x1f,0x34,0x36,0x24,0x61}, + {0x8d,0x89,0x4e,0x87,0xdb,0x41,0x9d,0xd9,0x20,0xdc,0x07,0x6c,0xf1,0xa5,0xfe,0x09,0xbc,0x9b,0x0f,0xd0,0x67,0x2c,0x3d,0x79,0x40,0xff,0x5e,0x9e,0x30,0xe2,0xeb,0x46,0x38,0x26,0x2d,0x1a,0xe3,0x49,0x63,0x8b,0x35,0xfd,0xd3,0x9b,0x00,0xb7,0xdf,0x9d,0xa4,0x6b,0xa0,0xa3,0xb8,0xf1,0x8b,0x7f,0x45,0x04,0xd9,0x78,0x31,0xaa,0x22,0x15,0x38,0x49,0x61,0x69,0x53,0x2f,0x38,0x2c,0x10,0x6d,0x2d,0xb7,0x9a,0x40,0xfe,0xda,0x27,0xf2,0x46,0xb6,0x91,0x33,0xc8,0xe8,0x6c,0x30,0x24,0x05,0xf5,0x70,0xfe,0x45}, + {0x8c,0x0b,0x0c,0x96,0xa6,0x75,0x48,0xda,0x20,0x2f,0x0e,0xef,0x76,0xd0,0x68,0x5b,0xd4,0x8f,0x0b,0x3d,0xcf,0x51,0xfb,0x07,0xd4,0x92,0xe3,0xa0,0x23,0x16,0x8d,0x42,0x91,0x14,0x95,0xc8,0x20,0x49,0xf2,0x62,0xa2,0x0c,0x63,0x3f,0xc8,0x07,0xf0,0x05,0xb8,0xd4,0xc9,0xf5,0xd2,0x45,0xbb,0x6f,0x45,0x22,0x7a,0xb5,0x6d,0x9f,0x61,0x16,0xfd,0x08,0xa3,0x01,0x44,0x4a,0x4f,0x08,0xac,0xca,0xa5,0x76,0xc3,0x19,0x22,0xa8,0x7d,0xbc,0xd1,0x43,0x46,0xde,0xb8,0xde,0xc6,0x38,0xbd,0x60,0x2d,0x59,0x81,0x1d}, + {0x5f,0xac,0x0d,0xa6,0x56,0x87,0x36,0x61,0x57,0xdc,0xab,0xeb,0x6a,0x2f,0xe0,0x17,0x7d,0x0f,0xce,0x4c,0x2d,0x3f,0x19,0x7f,0xf0,0xdc,0xec,0x89,0x77,0x4a,0x23,0x20,0xe8,0xc5,0x85,0x7b,0x9f,0xb6,0x65,0x87,0xb2,0xba,0x68,0xd1,0x8b,0x67,0xf0,0x6f,0x9b,0x0f,0x33,0x1d,0x7c,0xe7,0x70,0x3a,0x7c,0x8e,0xaf,0xb0,0x51,0x6d,0x5f,0x3a,0x52,0xb2,0x78,0x71,0xb6,0x0d,0xd2,0x76,0x60,0xd1,0x1e,0xd5,0xf9,0x34,0x1c,0x07,0x70,0x11,0xe4,0xb3,0x20,0x4a,0x2a,0xf6,0x66,0xe3,0xff,0x3c,0x35,0x82,0xd6,0x7c}, + {0xb6,0xfa,0x87,0xd8,0x5b,0xa4,0xe1,0x0b,0x6e,0x3b,0x40,0xba,0x32,0x6a,0x84,0x2a,0x00,0x60,0x6e,0xe9,0x12,0x10,0x92,0xd9,0x43,0x09,0xdc,0x3b,0x86,0xc8,0x38,0x28,0xf3,0xf4,0xac,0x68,0x60,0xcd,0x65,0xa6,0xd3,0xe3,0xd7,0x3c,0x18,0x2d,0xd9,0x42,0xd9,0x25,0x60,0x33,0x9d,0x38,0x59,0x57,0xff,0xd8,0x2c,0x2b,0x3b,0x25,0xf0,0x3e,0x30,0x50,0x46,0x4a,0xcf,0xb0,0x6b,0xd1,0xab,0x77,0xc5,0x15,0x41,0x6b,0x49,0xfa,0x9d,0x41,0xab,0xf4,0x8a,0xae,0xcf,0x82,0x12,0x28,0xa8,0x06,0xa6,0xb8,0xdc,0x21}, + {0xc8,0x9f,0x9d,0x8c,0x46,0x04,0x60,0x5c,0xcb,0xa3,0x2a,0xd4,0x6e,0x09,0x40,0x25,0x9c,0x2f,0xee,0x12,0x4c,0x4d,0x5b,0x12,0xab,0x1d,0xa3,0x94,0x81,0xd0,0xc3,0x0b,0xba,0x31,0x77,0xbe,0xfa,0x00,0x8d,0x9a,0x89,0x18,0x9e,0x62,0x7e,0x60,0x03,0x82,0x7f,0xd9,0xf3,0x43,0x37,0x02,0xcc,0xb2,0x8b,0x67,0x6f,0x6c,0xbf,0x0d,0x84,0x5d,0x8b,0xe1,0x9f,0x30,0x0d,0x38,0x6e,0x70,0xc7,0x65,0xe1,0xb9,0xa6,0x2d,0xb0,0x6e,0xab,0x20,0xae,0x7d,0x99,0xba,0xbb,0x57,0xdd,0x96,0xc1,0x2a,0x23,0x76,0x42,0x3a}, + {0xfa,0x84,0x70,0x8a,0x2c,0x43,0x42,0x4b,0x45,0xe5,0xb9,0xdf,0xe3,0x19,0x8a,0x89,0x5d,0xe4,0x58,0x9c,0x21,0x00,0x9f,0xbe,0xd1,0xeb,0x6d,0xa1,0xce,0x77,0xf1,0x1f,0xcb,0x7e,0x44,0xdb,0x72,0xc1,0xf8,0x3b,0xbd,0x2d,0x28,0xc6,0x1f,0xc4,0xcf,0x5f,0xfe,0x15,0xaa,0x75,0xc0,0xff,0xac,0x80,0xf9,0xa9,0xe1,0x24,0xe8,0xc9,0x70,0x07,0xfd,0xb5,0xb5,0x45,0x9a,0xd9,0x61,0xcf,0x24,0x79,0x3a,0x1b,0xe9,0x84,0x09,0x86,0x89,0x3e,0x3e,0x30,0x19,0x09,0x30,0xe7,0x1e,0x0b,0x50,0x41,0xfd,0x64,0xf2,0x39}, + {0x9c,0xe2,0xe7,0xdb,0x17,0x34,0xad,0xa7,0x9c,0x13,0x9c,0x2b,0x6a,0x37,0x94,0xbd,0xa9,0x7b,0x59,0x93,0x8e,0x1b,0xe9,0xa0,0x40,0x98,0x88,0x68,0x34,0xd7,0x12,0x17,0xe1,0x7b,0x09,0xfe,0xab,0x4a,0x9b,0xd1,0x29,0x19,0xe0,0xdf,0xe1,0xfc,0x6d,0xa4,0xff,0xf1,0xa6,0x2c,0x94,0x08,0xc9,0xc3,0x4e,0xf1,0x35,0x2c,0x27,0x21,0xc6,0x65,0xdd,0x93,0x31,0xce,0xf8,0x89,0x2b,0xe7,0xbb,0xc0,0x25,0xa1,0x56,0x33,0x10,0x4d,0x83,0xfe,0x1c,0x2e,0x3d,0xa9,0x19,0x04,0x72,0xe2,0x9c,0xb1,0x0a,0x80,0xf9,0x22}, + {0xcb,0xf8,0x9e,0x3e,0x8a,0x36,0x5a,0x60,0x15,0x47,0x50,0xa5,0x22,0xc0,0xe9,0xe3,0x8f,0x24,0x24,0x5f,0xb0,0x48,0x3d,0x55,0xe5,0x26,0x76,0x64,0xcd,0x16,0xf4,0x13,0xac,0xfd,0x6e,0x9a,0xdd,0x9f,0x02,0x42,0x41,0x49,0xa5,0x34,0xbe,0xce,0x12,0xb9,0x7b,0xf3,0xbd,0x87,0xb9,0x64,0x0f,0x64,0xb4,0xca,0x98,0x85,0xd3,0xa4,0x71,0x41,0x8c,0x4c,0xc9,0x99,0xaa,0x58,0x27,0xfa,0x07,0xb8,0x00,0xb0,0x6f,0x6f,0x00,0x23,0x92,0x53,0xda,0xad,0xdd,0x91,0xd2,0xfb,0xab,0xd1,0x4b,0x57,0xfa,0x14,0x82,0x50}, + {0x4b,0xfe,0xd6,0x3e,0x15,0x69,0x02,0xc2,0xc4,0x77,0x1d,0x51,0x39,0x67,0x5a,0xa6,0x94,0xaf,0x14,0x2c,0x46,0x26,0xde,0xcb,0x4b,0xa7,0xab,0x6f,0xec,0x60,0xf9,0x22,0xd6,0x03,0xd0,0x53,0xbb,0x15,0x1a,0x46,0x65,0xc9,0xf3,0xbc,0x88,0x28,0x10,0xb2,0x5a,0x3a,0x68,0x6c,0x75,0x76,0xc5,0x27,0x47,0xb4,0x6c,0xc8,0xa4,0x58,0x77,0x3a,0x76,0x50,0xae,0x93,0xf6,0x11,0x81,0x54,0xa6,0x54,0xfd,0x1d,0xdf,0x21,0xae,0x1d,0x65,0x5e,0x11,0xf3,0x90,0x8c,0x24,0x12,0x94,0xf4,0xe7,0x8d,0x5f,0xd1,0x9f,0x5d}, + {0x7f,0x72,0x63,0x6d,0xd3,0x08,0x14,0x03,0x33,0xb5,0xc7,0xd7,0xef,0x9a,0x37,0x6a,0x4b,0xe2,0xae,0xcc,0xc5,0x8f,0xe1,0xa9,0xd3,0xbe,0x8f,0x4f,0x91,0x35,0x2f,0x33,0x1e,0x52,0xd7,0xee,0x2a,0x4d,0x24,0x3f,0x15,0x96,0x2e,0x43,0x28,0x90,0x3a,0x8e,0xd4,0x16,0x9c,0x2e,0x77,0xba,0x64,0xe1,0xd8,0x98,0xeb,0x47,0xfa,0x87,0xc1,0x3b,0x0c,0xc2,0x86,0xea,0x15,0x01,0x47,0x6d,0x25,0xd1,0x46,0x6c,0xcb,0xb7,0x8a,0x99,0x88,0x01,0x66,0x3a,0xb5,0x32,0x78,0xd7,0x03,0xba,0x6f,0x90,0xce,0x81,0x0d,0x45}, + {0x75,0x52,0x20,0xa6,0xa1,0xb6,0x7b,0x6e,0x83,0x8e,0x3c,0x41,0xd7,0x21,0x4f,0xaa,0xb2,0x5c,0x8f,0xe8,0x55,0xd1,0x56,0x6f,0xe1,0x5b,0x34,0xa6,0x4b,0x5d,0xe2,0x2d,0x3f,0x74,0xae,0x1c,0x96,0xd8,0x74,0xd0,0xed,0x63,0x1c,0xee,0xf5,0x18,0x6d,0xf8,0x29,0xed,0xf4,0xe7,0x5b,0xc5,0xbd,0x97,0x08,0xb1,0x3a,0x66,0x79,0xd2,0xba,0x4c,0xcd,0x1f,0xd7,0xa0,0x24,0x90,0xd1,0x80,0xf8,0x8a,0x28,0xfb,0x0a,0xc2,0x25,0xc5,0x19,0x64,0x3a,0x5f,0x4b,0x97,0xa3,0xb1,0x33,0x72,0x00,0xe2,0xef,0xbc,0x7f,0x7d}, + {0x01,0x28,0x6b,0x26,0x6a,0x1e,0xef,0xfa,0x16,0x9f,0x73,0xd5,0xc4,0x68,0x6c,0x86,0x2c,0x76,0x03,0x1b,0xbc,0x2f,0x8a,0xf6,0x8d,0x5a,0xb7,0x87,0x5e,0x43,0x75,0x59,0x94,0x90,0xc2,0xf3,0xc5,0x5d,0x7c,0xcd,0xab,0x05,0x91,0x2a,0x9a,0xa2,0x81,0xc7,0x58,0x30,0x1c,0x42,0x36,0x1d,0xc6,0x80,0xd7,0xd4,0xd8,0xdc,0x96,0xd1,0x9c,0x4f,0x68,0x37,0x7b,0x6a,0xd8,0x97,0x92,0x19,0x63,0x7a,0xd1,0x1a,0x24,0x58,0xd0,0xd0,0x17,0x0c,0x1c,0x5c,0xad,0x9c,0x02,0xba,0x07,0x03,0x7a,0x38,0x84,0xd0,0xcd,0x7c}, + {0x17,0x04,0x26,0x6d,0x2c,0x42,0xa6,0xdc,0xbd,0x40,0x82,0x94,0x50,0x3d,0x15,0xae,0x77,0xc6,0x68,0xfb,0xb4,0xc1,0xc0,0xa9,0x53,0xcf,0xd0,0x61,0xed,0xd0,0x8b,0x42,0x93,0xcc,0x60,0x67,0x18,0x84,0x0c,0x9b,0x99,0x2a,0xb3,0x1a,0x7a,0x00,0xae,0xcd,0x18,0xda,0x0b,0x62,0x86,0xec,0x8d,0xa8,0x44,0xca,0x90,0x81,0x84,0xca,0x93,0x35,0xa7,0x9a,0x84,0x5e,0x9a,0x18,0x13,0x92,0xcd,0xfa,0xd8,0x65,0x35,0xc3,0xd8,0xd4,0xd1,0xbb,0xfd,0x53,0x5b,0x54,0x52,0x8c,0xe6,0x63,0x2d,0xda,0x08,0x83,0x39,0x27}, + {0x13,0xd4,0x5e,0x43,0x28,0x8d,0xc3,0x42,0xc9,0xcc,0x78,0x32,0x60,0xf3,0x50,0xbd,0xef,0x03,0xda,0x79,0x1a,0xab,0x07,0xbb,0x55,0x33,0x8c,0xbe,0xae,0x97,0x95,0x26,0x53,0x24,0x70,0x0a,0x4c,0x0e,0xa1,0xb9,0xde,0x1b,0x7d,0xd5,0x66,0x58,0xa2,0x0f,0xf7,0xda,0x27,0xcd,0xb5,0xd9,0xb9,0xff,0xfd,0x33,0x2c,0x49,0x45,0x29,0x2c,0x57,0xbe,0x30,0xcd,0xd6,0x45,0xc7,0x7f,0xc7,0xfb,0xae,0xba,0xe3,0xd3,0xe8,0xdf,0xe4,0x0c,0xda,0x5d,0xaa,0x30,0x88,0x2c,0xa2,0x80,0xca,0x5b,0xc0,0x98,0x54,0x98,0x7f}, + {0x17,0xe1,0x0b,0x9f,0x88,0xce,0x49,0x38,0x88,0xa2,0x54,0x7b,0x1b,0xad,0x05,0x80,0x1c,0x92,0xfc,0x23,0x9f,0xc3,0xa3,0x3d,0x04,0xf3,0x31,0x0a,0x47,0xec,0xc2,0x76,0x63,0x63,0xbf,0x0f,0x52,0x15,0x56,0xd3,0xa6,0xfb,0x4d,0xcf,0x45,0x5a,0x04,0x08,0xc2,0xa0,0x3f,0x87,0xbc,0x4f,0xc2,0xee,0xe7,0x12,0x9b,0xd6,0x3c,0x65,0xf2,0x30,0x85,0x0c,0xc1,0xaa,0x38,0xc9,0x08,0x8a,0xcb,0x6b,0x27,0xdb,0x60,0x9b,0x17,0x46,0x70,0xac,0x6f,0x0e,0x1e,0xc0,0x20,0xa9,0xda,0x73,0x64,0x59,0xf1,0x73,0x12,0x2f}, + {0x11,0x1e,0xe0,0x8a,0x7c,0xfc,0x39,0x47,0x9f,0xab,0x6a,0x4a,0x90,0x74,0x52,0xfd,0x2e,0x8f,0x72,0x87,0x82,0x8a,0xd9,0x41,0xf2,0x69,0x5b,0xd8,0x2a,0x57,0x9e,0x5d,0xc0,0x0b,0xa7,0x55,0xd7,0x8b,0x48,0x30,0xe7,0x42,0xd4,0xf1,0xa4,0xb5,0xd6,0x06,0x62,0x61,0x59,0xbc,0x9e,0xa6,0xd1,0xea,0x84,0xf7,0xc5,0xed,0x97,0x19,0xac,0x38,0x3b,0xb1,0x51,0xa7,0x17,0xb5,0x66,0x06,0x8c,0x85,0x9b,0x7e,0x86,0x06,0x7d,0x74,0x49,0xde,0x4d,0x45,0x11,0xc0,0xac,0xac,0x9c,0xe6,0xe9,0xbf,0x9c,0xcd,0xdf,0x22}, + {0xd9,0x0c,0x0d,0xc3,0xe0,0xd2,0xdb,0x8d,0x33,0x43,0xbb,0xac,0x5f,0x66,0x8e,0xad,0x1f,0x96,0x2a,0x32,0x8c,0x25,0x6b,0x8f,0xc7,0xc1,0x48,0x54,0xc0,0x16,0x29,0x6b,0xa1,0xe0,0x3b,0x10,0xb4,0x59,0xec,0x56,0x69,0xf9,0x59,0xd2,0xec,0xba,0xe3,0x2e,0x32,0xcd,0xf5,0x13,0x94,0xb2,0x7c,0x79,0x72,0xe4,0xcd,0x24,0x78,0x87,0xe9,0x0f,0x3b,0x91,0xba,0x0a,0xd1,0x34,0xdb,0x7e,0x0e,0xac,0x6d,0x2e,0x82,0xcd,0xa3,0x4e,0x15,0xf8,0x78,0x65,0xff,0x3d,0x08,0x66,0x17,0x0a,0xf0,0x7f,0x30,0x3f,0x30,0x4c}, + {0x85,0x8c,0xb2,0x17,0xd6,0x3b,0x0a,0xd3,0xea,0x3b,0x77,0x39,0xb7,0x77,0xd3,0xc5,0xbf,0x5c,0x6a,0x1e,0x8c,0xe7,0xc6,0xc6,0xc4,0xb7,0x2a,0x8b,0xf7,0xb8,0x61,0x0d,0x00,0x45,0xd9,0x0d,0x58,0x03,0xfc,0x29,0x93,0xec,0xbb,0x6f,0xa4,0x7a,0xd2,0xec,0xf8,0xa7,0xe2,0xc2,0x5f,0x15,0x0a,0x13,0xd5,0xa1,0x06,0xb7,0x1a,0x15,0x6b,0x41,0xb0,0x36,0xc1,0xe9,0xef,0xd7,0xa8,0x56,0x20,0x4b,0xe4,0x58,0xcd,0xe5,0x07,0xbd,0xab,0xe0,0x57,0x1b,0xda,0x2f,0xe6,0xaf,0xd2,0xe8,0x77,0x42,0xf7,0x2a,0x1a,0x19}, + {0x31,0x14,0x3c,0xc5,0x4b,0xf7,0x16,0xce,0xde,0xed,0x72,0x20,0xce,0x25,0x97,0x2b,0xe7,0x3e,0xb2,0xb5,0x6f,0xc3,0xb9,0xb8,0x08,0xc9,0x5c,0x0b,0x45,0x0e,0x2e,0x7e,0xfb,0x0e,0x46,0x4f,0x43,0x2b,0xe6,0x9f,0xd6,0x07,0x36,0xa6,0xd4,0x03,0xd3,0xde,0x24,0xda,0xa0,0xb7,0x0e,0x21,0x52,0xf0,0x93,0x5b,0x54,0x00,0xbe,0x7d,0x7e,0x23,0x30,0xb4,0x01,0x67,0xed,0x75,0x35,0x01,0x10,0xfd,0x0b,0x9f,0xe6,0x94,0x10,0x23,0x22,0x7f,0xe4,0x83,0x15,0x0f,0x32,0x75,0xe3,0x55,0x11,0xb1,0x99,0xa6,0xaf,0x71}, + {0x1d,0xb6,0x53,0x39,0x9b,0x6f,0xce,0x65,0xe6,0x41,0xa1,0xaf,0xea,0x39,0x58,0xc6,0xfe,0x59,0xf7,0xa9,0xfd,0x5f,0x43,0x0f,0x8e,0xc2,0xb1,0xc2,0xe9,0x42,0x11,0x02,0xd6,0x50,0x3b,0x47,0x1c,0x3c,0x42,0xea,0x10,0xef,0x38,0x3b,0x1f,0x7a,0xe8,0x51,0x95,0xbe,0xc9,0xb2,0x5f,0xbf,0x84,0x9b,0x1c,0x9a,0xf8,0x78,0xbc,0x1f,0x73,0x00,0x80,0x18,0xf8,0x48,0x18,0xc7,0x30,0xe4,0x19,0xc1,0xce,0x5e,0x22,0x0c,0x96,0xbf,0xe3,0x15,0xba,0x6b,0x83,0xe0,0xda,0xb6,0x08,0x58,0xe1,0x47,0x33,0x6f,0x4d,0x4c}, + {0xc9,0x1f,0x7d,0xc1,0xcf,0xec,0xf7,0x18,0x14,0x3c,0x40,0x51,0xa6,0xf5,0x75,0x6c,0xdf,0x0c,0xee,0xf7,0x2b,0x71,0xde,0xdb,0x22,0x7a,0xe4,0xa7,0xaa,0xdd,0x3f,0x19,0x70,0x19,0x8f,0x98,0xfc,0xdd,0x0c,0x2f,0x1b,0xf5,0xb9,0xb0,0x27,0x62,0x91,0x6b,0xbe,0x76,0x91,0x77,0xc4,0xb6,0xc7,0x6e,0xa8,0x9f,0x8f,0xa8,0x00,0x95,0xbf,0x38,0x6f,0x87,0xe8,0x37,0x3c,0xc9,0xd2,0x1f,0x2c,0x46,0xd1,0x18,0x5a,0x1e,0xf6,0xa2,0x76,0x12,0x24,0x39,0x82,0xf5,0x80,0x50,0x69,0x49,0x0d,0xbf,0x9e,0xb9,0x6f,0x6a}, + {0xeb,0x55,0x08,0x56,0xbb,0xc1,0x46,0x6a,0x9d,0xf0,0x93,0xf8,0x38,0xbb,0x16,0x24,0xc1,0xac,0x71,0x8f,0x37,0x11,0x1d,0xd7,0xea,0x96,0x18,0xa3,0x14,0x69,0xf7,0x75,0xc6,0x23,0xe4,0xb6,0xb5,0x22,0xb1,0xee,0x8e,0xff,0x86,0xf2,0x10,0x70,0x9d,0x93,0x8c,0x5d,0xcf,0x1d,0x83,0x2a,0xa9,0x90,0x10,0xeb,0xc5,0x42,0x9f,0xda,0x6f,0x13,0xd1,0xbd,0x05,0xa3,0xb1,0xdf,0x4c,0xf9,0x08,0x2c,0xf8,0x9f,0x9d,0x4b,0x36,0x0f,0x8a,0x58,0xbb,0xc3,0xa5,0xd8,0x87,0x2a,0xba,0xdc,0xe8,0x0b,0x51,0x83,0x21,0x02}, + {0x14,0x2d,0xad,0x5e,0x38,0x66,0xf7,0x4a,0x30,0x58,0x7c,0xca,0x80,0xd8,0x8e,0xa0,0x3d,0x1e,0x21,0x10,0xe6,0xa6,0x13,0x0d,0x03,0x6c,0x80,0x7b,0xe1,0x1c,0x07,0x6a,0x7f,0x7a,0x30,0x43,0x01,0x71,0x5a,0x9d,0x5f,0xa4,0x7d,0xc4,0x9e,0xde,0x63,0xb0,0xd3,0x7a,0x92,0xbe,0x52,0xfe,0xbb,0x22,0x6c,0x42,0x40,0xfd,0x41,0xc4,0x87,0x13,0xf8,0x8a,0x97,0x87,0xd1,0xc3,0xd3,0xb5,0x13,0x44,0x0e,0x7f,0x3d,0x5a,0x2b,0x72,0xa0,0x7c,0x47,0xbb,0x48,0x48,0x7b,0x0d,0x92,0xdc,0x1e,0xaf,0x6a,0xb2,0x71,0x31}, + {0xa8,0x4c,0x56,0x97,0x90,0x31,0x2f,0xa9,0x19,0xe1,0x75,0x22,0x4c,0xb8,0x7b,0xff,0x50,0x51,0x87,0xa4,0x37,0xfe,0x55,0x4f,0x5a,0x83,0xf0,0x3c,0x87,0xd4,0x1f,0x22,0xd1,0x47,0x8a,0xb2,0xd8,0xb7,0x0d,0xa6,0xf1,0xa4,0x70,0x17,0xd6,0x14,0xbf,0xa6,0x58,0xbd,0xdd,0x53,0x93,0xf8,0xa1,0xd4,0xe9,0x43,0x42,0x34,0x63,0x4a,0x51,0x6c,0x41,0x63,0x15,0x3a,0x4f,0x20,0x22,0x23,0x2d,0x03,0x0a,0xba,0xe9,0xe0,0x73,0xfb,0x0e,0x03,0x0f,0x41,0x4c,0xdd,0xe0,0xfc,0xaa,0x4a,0x92,0xfb,0x96,0xa5,0xda,0x48}, + {0xc7,0x9c,0xa5,0x5c,0x66,0x8e,0xca,0x6e,0xa0,0xac,0x38,0x2e,0x4b,0x25,0x47,0xa8,0xce,0x17,0x1e,0xd2,0x08,0xc7,0xaf,0x31,0xf7,0x4a,0xd8,0xca,0xfc,0xd6,0x6d,0x67,0x93,0x97,0x4c,0xc8,0x5d,0x1d,0xf6,0x14,0x06,0x82,0x41,0xef,0xe3,0xf9,0x41,0x99,0xac,0x77,0x62,0x34,0x8f,0xb8,0xf5,0xcd,0xa9,0x79,0x8a,0x0e,0xfa,0x37,0xc8,0x58,0x58,0x90,0xfc,0x96,0x85,0x68,0xf9,0x0c,0x1b,0xa0,0x56,0x7b,0xf3,0xbb,0xdc,0x1d,0x6a,0xd6,0x35,0x49,0x7d,0xe7,0xc2,0xdc,0x0a,0x7f,0xa5,0xc6,0xf2,0x73,0x4f,0x1c}, + {0xbb,0xa0,0x5f,0x30,0xbd,0x4f,0x7a,0x0e,0xad,0x63,0xc6,0x54,0xe0,0x4c,0x9d,0x82,0x48,0x38,0xe3,0x2f,0x83,0xc3,0x21,0xf4,0x42,0x4c,0xf6,0x1b,0x0d,0xc8,0x5a,0x79,0x84,0x34,0x7c,0xfc,0x6e,0x70,0x6e,0xb3,0x61,0xcf,0xc1,0xc3,0xb4,0xc9,0xdf,0x73,0xe5,0xc7,0x1c,0x78,0xc9,0x79,0x1d,0xeb,0x5c,0x67,0xaf,0x7d,0xdb,0x9a,0x45,0x70,0xb3,0x2b,0xb4,0x91,0x49,0xdb,0x91,0x1b,0xca,0xdc,0x02,0x4b,0x23,0x96,0x26,0x57,0xdc,0x78,0x8c,0x1f,0xe5,0x9e,0xdf,0x9f,0xd3,0x1f,0xe2,0x8c,0x84,0x62,0xe1,0x5f}, + {0x1a,0x96,0x94,0xe1,0x4f,0x21,0x59,0x4e,0x4f,0xcd,0x71,0x0d,0xc7,0x7d,0xbe,0x49,0x2d,0xf2,0x50,0x3b,0xd2,0xcf,0x00,0x93,0x32,0x72,0x91,0xfc,0x46,0xd4,0x89,0x47,0x08,0xb2,0x7c,0x5d,0x2d,0x85,0x79,0x28,0xe7,0xf2,0x7d,0x68,0x70,0xdd,0xde,0xb8,0x91,0x78,0x68,0x21,0xab,0xff,0x0b,0xdc,0x35,0xaa,0x7d,0x67,0x43,0xc0,0x44,0x2b,0x8e,0xb7,0x4e,0x07,0xab,0x87,0x1c,0x1a,0x67,0xf4,0xda,0x99,0x8e,0xd1,0xc6,0xfa,0x67,0x90,0x4f,0x48,0xcd,0xbb,0xac,0x3e,0xe4,0xa4,0xb9,0x2b,0xef,0x2e,0xc5,0x60}, + {0xf1,0x8b,0xfd,0x3b,0xbc,0x89,0x5d,0x0b,0x1a,0x55,0xf3,0xc9,0x37,0x92,0x6b,0xb0,0xf5,0x28,0x30,0xd5,0xb0,0x16,0x4c,0x0e,0xab,0xca,0xcf,0x2c,0x31,0x9c,0xbc,0x10,0x11,0x6d,0xae,0x7c,0xc2,0xc5,0x2b,0x70,0xab,0x8c,0xa4,0x54,0x9b,0x69,0xc7,0x44,0xb2,0x2e,0x49,0xba,0x56,0x40,0xbc,0xef,0x6d,0x67,0xb6,0xd9,0x48,0x72,0xd7,0x70,0x5b,0xa0,0xc2,0x3e,0x4b,0xe8,0x8a,0xaa,0xe0,0x81,0x17,0xed,0xf4,0x9e,0x69,0x98,0xd1,0x85,0x8e,0x70,0xe4,0x13,0x45,0x79,0x13,0xf4,0x76,0xa9,0xd3,0x5b,0x75,0x63}, + {0x53,0x08,0xd1,0x2a,0x3e,0xa0,0x5f,0xb5,0x69,0x35,0xe6,0x9e,0x90,0x75,0x6f,0x35,0x90,0xb8,0x69,0xbe,0xfd,0xf1,0xf9,0x9f,0x84,0x6f,0xc1,0x8b,0xc4,0xc1,0x8c,0x0d,0xb7,0xac,0xf1,0x97,0x18,0x10,0xc7,0x3d,0xd8,0xbb,0x65,0xc1,0x5e,0x7d,0xda,0x5d,0x0f,0x02,0xa1,0x0f,0x9c,0x5b,0x8e,0x50,0x56,0x2a,0xc5,0x37,0x17,0x75,0x63,0x27,0xa9,0x19,0xb4,0x6e,0xd3,0x02,0x94,0x02,0xa5,0x60,0xb4,0x77,0x7e,0x4e,0xb4,0xf0,0x56,0x49,0x3c,0xd4,0x30,0x62,0xa8,0xcf,0xe7,0x66,0xd1,0x7a,0x8a,0xdd,0xc2,0x70}, + {0x0e,0xec,0x6f,0x9f,0x50,0x94,0x61,0x65,0x8d,0x51,0xc6,0x46,0xa9,0x7e,0x2e,0xee,0x5c,0x9b,0xe0,0x67,0xf3,0xc1,0x33,0x97,0x95,0x84,0x94,0x63,0x63,0xac,0x0f,0x2e,0x13,0x7e,0xed,0xb8,0x7d,0x96,0xd4,0x91,0x7a,0x81,0x76,0xd7,0x0a,0x2f,0x25,0x74,0x64,0x25,0x85,0x0d,0xe0,0x82,0x09,0xe4,0xe5,0x3c,0xa5,0x16,0x38,0x61,0xb8,0x32,0x64,0xcd,0x48,0xe4,0xbe,0xf7,0xe7,0x79,0xd0,0x86,0x78,0x08,0x67,0x3a,0xc8,0x6a,0x2e,0xdb,0xe4,0xa0,0xd9,0xd4,0x9f,0xf8,0x41,0x4f,0x5a,0x73,0x5c,0x21,0x79,0x41}, + {0x2a,0xed,0xdc,0xd7,0xe7,0x94,0x70,0x8c,0x70,0x9c,0xd3,0x47,0xc3,0x8a,0xfb,0x97,0x02,0xd9,0x06,0xa9,0x33,0xe0,0x3b,0xe1,0x76,0x9d,0xd9,0x0c,0xa3,0x44,0x03,0x70,0x34,0xcd,0x6b,0x28,0xb9,0x33,0xae,0xe4,0xdc,0xd6,0x9d,0x55,0xb6,0x7e,0xef,0xb7,0x1f,0x8e,0xd3,0xb3,0x1f,0x14,0x8b,0x27,0x86,0xc2,0x41,0x22,0x66,0x85,0xfa,0x31,0xf4,0x22,0x36,0x2e,0x42,0x6c,0x82,0xaf,0x2d,0x50,0x33,0x98,0x87,0x29,0x20,0xc1,0x23,0x91,0x38,0x2b,0xe1,0xb7,0xc1,0x9b,0x89,0x24,0x95,0xa9,0x12,0x23,0xbb,0x24}, + {0xc3,0x67,0xde,0x32,0x17,0xed,0xa8,0xb1,0x48,0x49,0x1b,0x46,0x18,0x94,0xb4,0x3c,0xd2,0xbc,0xcf,0x76,0x43,0x43,0xbd,0x8e,0x08,0x80,0x18,0x1e,0x87,0x3e,0xee,0x0f,0x6b,0x5c,0xf8,0xf5,0x2a,0x0c,0xf8,0x41,0x94,0x67,0xfa,0x04,0xc3,0x84,0x72,0x68,0xad,0x1b,0xba,0xa3,0x99,0xdf,0x45,0x89,0x16,0x5d,0xeb,0xff,0xf9,0x2a,0x1d,0x0d,0xdf,0x1e,0x62,0x32,0xa1,0x8a,0xda,0xa9,0x79,0x65,0x22,0x59,0xa1,0x22,0xb8,0x30,0x93,0xc1,0x9a,0xa7,0x7b,0x19,0x04,0x40,0x76,0x1d,0x53,0x18,0x97,0xd7,0xac,0x16}, + {0x3d,0x1d,0x9b,0x2d,0xaf,0x72,0xdf,0x72,0x5a,0x24,0x32,0xa4,0x36,0x2a,0x46,0x63,0x37,0x96,0xb3,0x16,0x79,0xa0,0xce,0x3e,0x09,0x23,0x30,0xb9,0xf6,0x0e,0x3e,0x12,0xad,0xb6,0x87,0x78,0xc5,0xc6,0x59,0xc9,0xba,0xfe,0x90,0x5f,0xad,0x9e,0xe1,0x94,0x04,0xf5,0x42,0xa3,0x62,0x4e,0xe2,0x16,0x00,0x17,0x16,0x18,0x4b,0xd3,0x4e,0x16,0x9a,0xe6,0x2f,0x19,0x4c,0xd9,0x7e,0x48,0x13,0x15,0x91,0x3a,0xea,0x2c,0xae,0x61,0x27,0xde,0xa4,0xb9,0xd3,0xf6,0x7b,0x87,0xeb,0xf3,0x73,0x10,0xc6,0x0f,0xda,0x78}, + {0x6a,0xc6,0x2b,0xe5,0x28,0x5d,0xf1,0x5b,0x8e,0x1a,0xf0,0x70,0x18,0xe3,0x47,0x2c,0xdd,0x8b,0xc2,0x06,0xbc,0xaf,0x19,0x24,0x3a,0x17,0x6b,0x25,0xeb,0xde,0x25,0x2d,0x94,0x3a,0x0c,0x68,0xf1,0x80,0x9f,0xa2,0xe6,0xe7,0xe9,0x1a,0x15,0x7e,0xf7,0x71,0x73,0x79,0x01,0x48,0x58,0xf1,0x00,0x11,0xdd,0x8d,0xb3,0x16,0xb3,0xa4,0x4a,0x05,0xb8,0x7c,0x26,0x19,0x8d,0x46,0xc8,0xdf,0xaf,0x4d,0xe5,0x66,0x9c,0x78,0x28,0x0b,0x17,0xec,0x6e,0x66,0x2a,0x1d,0xeb,0x2a,0x60,0xa7,0x7d,0xab,0xa6,0x10,0x46,0x13}, + {0xfe,0xb0,0xf6,0x8d,0xc7,0x8e,0x13,0x51,0x1b,0xf5,0x75,0xe5,0x89,0xda,0x97,0x53,0xb9,0xf1,0x7a,0x71,0x1d,0x7a,0x20,0x09,0x50,0xd6,0x20,0x2b,0xba,0xfd,0x02,0x21,0x15,0xf5,0xd1,0x77,0xe7,0x65,0x2a,0xcd,0xf1,0x60,0xaa,0x8f,0x87,0x91,0x89,0x54,0xe5,0x06,0xbc,0xda,0xbc,0x3b,0xb7,0xb1,0xfb,0xc9,0x7c,0xa9,0xcb,0x78,0x48,0x65,0xa1,0xe6,0x5c,0x05,0x05,0xe4,0x9e,0x96,0x29,0xad,0x51,0x12,0x68,0xa7,0xbc,0x36,0x15,0xa4,0x7d,0xaa,0x17,0xf5,0x1a,0x3a,0xba,0xb2,0xec,0x29,0xdb,0x25,0xd7,0x0a}, + {0x57,0x24,0x4e,0x83,0xb1,0x67,0x42,0xdc,0xc5,0x1b,0xce,0x70,0xb5,0x44,0x75,0xb6,0xd7,0x5e,0xd1,0xf7,0x0b,0x7a,0xf0,0x1a,0x50,0x36,0xa0,0x71,0xfb,0xcf,0xef,0x4a,0x85,0x6f,0x05,0x9b,0x0c,0xbc,0xc7,0xfe,0xd7,0xff,0xf5,0xe7,0x68,0x52,0x7d,0x53,0xfa,0xae,0x12,0x43,0x62,0xc6,0xaf,0x77,0xd9,0x9f,0x39,0x02,0x53,0x5f,0x67,0x4f,0x1e,0x17,0x15,0x04,0x36,0x36,0x2d,0xc3,0x3b,0x48,0x98,0x89,0x11,0xef,0x2b,0xcd,0x10,0x51,0x94,0xd0,0xad,0x6e,0x0a,0x87,0x61,0x65,0xa8,0xa2,0x72,0xbb,0xcc,0x0b}, + {0xc8,0xa9,0xb1,0xea,0x2f,0x96,0x5e,0x18,0xcd,0x7d,0x14,0x65,0x35,0xe6,0xe7,0x86,0xf2,0x6d,0x5b,0xbb,0x31,0xe0,0x92,0xb0,0x3e,0xb7,0xd6,0x59,0xab,0xf0,0x24,0x40,0x96,0x12,0xfe,0x50,0x4c,0x5e,0x6d,0x18,0x7e,0x9f,0xe8,0xfe,0x82,0x7b,0x39,0xe0,0xb0,0x31,0x70,0x50,0xc5,0xf6,0xc7,0x3b,0xc2,0x37,0x8f,0x10,0x69,0xfd,0x78,0x66,0xc2,0x63,0x68,0x63,0x31,0xfa,0x86,0x15,0xf2,0x33,0x2d,0x57,0x48,0x8c,0xf6,0x07,0xfc,0xae,0x9e,0x78,0x9f,0xcc,0x73,0x4f,0x01,0x47,0xad,0x8e,0x10,0xe2,0x42,0x2d}, + {0x9b,0xd2,0xdf,0x94,0x15,0x13,0xf5,0x97,0x6a,0x4c,0x3f,0x31,0x5d,0x98,0x55,0x61,0x10,0x50,0x45,0x08,0x07,0x3f,0xa1,0xeb,0x22,0xd3,0xd2,0xb8,0x08,0x26,0x6b,0x67,0x93,0x75,0x53,0x0f,0x0d,0x7b,0x71,0x21,0x4c,0x06,0x1e,0x13,0x0b,0x69,0x4e,0x91,0x9f,0xe0,0x2a,0x75,0xae,0x87,0xb6,0x1b,0x6e,0x3c,0x42,0x9b,0xa7,0xf3,0x0b,0x42,0x47,0x2b,0x5b,0x1c,0x65,0xba,0x38,0x81,0x80,0x1b,0x1b,0x31,0xec,0xb6,0x71,0x86,0xb0,0x35,0x31,0xbc,0xb1,0x0c,0xff,0x7b,0xe0,0xf1,0x0c,0x9c,0xfa,0x2f,0x5d,0x74}, + {0xbd,0xc8,0xc9,0x2b,0x1e,0x5a,0x52,0xbf,0x81,0x9d,0x47,0x26,0x08,0x26,0x5b,0xea,0xdb,0x55,0x01,0xdf,0x0e,0xc7,0x11,0xd5,0xd0,0xf5,0x0c,0x96,0xeb,0x3c,0xe2,0x1a,0x6a,0x4e,0xd3,0x21,0x57,0xdf,0x36,0x60,0xd0,0xb3,0x7b,0x99,0x27,0x88,0xdb,0xb1,0xfa,0x6a,0x75,0xc8,0xc3,0x09,0xc2,0xd3,0x39,0xc8,0x1d,0x4c,0xe5,0x5b,0xe1,0x06,0x4a,0x99,0x32,0x19,0x87,0x5d,0x72,0x5b,0xb0,0xda,0xb1,0xce,0xb5,0x1c,0x35,0x32,0x05,0xca,0xb7,0xda,0x49,0x15,0xc4,0x7d,0xf7,0xc1,0x8e,0x27,0x61,0xd8,0xde,0x58}, + {0x5c,0xc5,0x66,0xf2,0x93,0x37,0x17,0xd8,0x49,0x4e,0x45,0xcc,0xc5,0x76,0xc9,0xc8,0xa8,0xc3,0x26,0xbc,0xf8,0x82,0xe3,0x5c,0xf9,0xf6,0x85,0x54,0xe8,0x9d,0xf3,0x2f,0xa8,0xc9,0xc2,0xb6,0xa8,0x5b,0xfb,0x2d,0x8c,0x59,0x2c,0xf5,0x8e,0xef,0xee,0x48,0x73,0x15,0x2d,0xf1,0x07,0x91,0x80,0x33,0xd8,0x5b,0x1d,0x53,0x6b,0x69,0xba,0x08,0x7a,0xc5,0xef,0xc3,0xee,0x3e,0xed,0x77,0x11,0x48,0xff,0xd4,0x17,0x55,0xe0,0x04,0xcb,0x71,0xa6,0xf1,0x3f,0x7a,0x3d,0xea,0x54,0xfe,0x7c,0x94,0xb4,0x33,0x06,0x12}, + {0x42,0x00,0x61,0x91,0x78,0x98,0x94,0x0b,0xe8,0xfa,0xeb,0xec,0x3c,0xb1,0xe7,0x4e,0xc0,0xa4,0xf0,0x94,0x95,0x73,0xbe,0x70,0x85,0x91,0xd5,0xb4,0x99,0x0a,0xd3,0x35,0x0a,0x10,0x12,0x49,0x47,0x31,0xbd,0x82,0x06,0xbe,0x6f,0x7e,0x6d,0x7b,0x23,0xde,0xc6,0x79,0xea,0x11,0x19,0x76,0x1e,0xe1,0xde,0x3b,0x39,0xcb,0xe3,0x3b,0x43,0x07,0xf4,0x97,0xe9,0x5c,0xc0,0x44,0x79,0xff,0xa3,0x51,0x5c,0xb0,0xe4,0x3d,0x5d,0x57,0x7c,0x84,0x76,0x5a,0xfd,0x81,0x33,0x58,0x9f,0xda,0xf6,0x7a,0xde,0x3e,0x87,0x2d}, + {0x09,0x34,0x37,0x43,0x64,0x31,0x7a,0x15,0xd9,0x81,0xaa,0xf4,0xee,0xb7,0xb8,0xfa,0x06,0x48,0xa6,0xf5,0xe6,0xfe,0x93,0xb0,0xb6,0xa7,0x7f,0x70,0x54,0x36,0x77,0x2e,0x81,0xf9,0x5d,0x4e,0xe1,0x02,0x62,0xaa,0xf5,0xe1,0x15,0x50,0x17,0x59,0x0d,0xa2,0x6c,0x1d,0xe2,0xba,0xd3,0x75,0xa2,0x18,0x53,0x02,0x60,0x01,0x8a,0x61,0x43,0x05,0xc1,0x23,0x4c,0x97,0xf4,0xbd,0xea,0x0d,0x93,0x46,0xce,0x9d,0x25,0x0a,0x6f,0xaa,0x2c,0xba,0x9a,0xa2,0xb8,0x2c,0x20,0x04,0x0d,0x96,0x07,0x2d,0x36,0x43,0x14,0x4b}, + {0x7a,0x1f,0x6e,0xb6,0xc7,0xb7,0xc4,0xcc,0x7e,0x2f,0x0c,0xf5,0x25,0x7e,0x15,0x44,0x1c,0xaf,0x3e,0x71,0xfc,0x6d,0xf0,0x3e,0xf7,0x63,0xda,0x52,0x67,0x44,0x2f,0x58,0xcb,0x9c,0x52,0x1c,0xe9,0x54,0x7c,0x96,0xfb,0x35,0xc6,0x64,0x92,0x26,0xf6,0x30,0x65,0x19,0x12,0x78,0xf4,0xaf,0x47,0x27,0x5c,0x6f,0xf6,0xea,0x18,0x84,0x03,0x17,0xe4,0x4c,0x32,0x20,0xd3,0x7b,0x31,0xc6,0xc4,0x8b,0x48,0xa4,0xe8,0x42,0x10,0xa8,0x64,0x13,0x5a,0x4e,0x8b,0xf1,0x1e,0xb2,0xc9,0x8d,0xa2,0xcd,0x4b,0x1c,0x2a,0x0c}, + {0x47,0x04,0x1f,0x6f,0xd0,0xc7,0x4d,0xd2,0x59,0xc0,0x87,0xdb,0x3e,0x9e,0x26,0xb2,0x8f,0xd2,0xb2,0xfb,0x72,0x02,0x5b,0xd1,0x77,0x48,0xf6,0xc6,0xd1,0x8b,0x55,0x7c,0x45,0x69,0xbd,0x69,0x48,0x81,0xc4,0xed,0x22,0x8d,0x1c,0xbe,0x7d,0x90,0x6d,0x0d,0xab,0xc5,0x5c,0xd5,0x12,0xd2,0x3b,0xc6,0x83,0xdc,0x14,0xa3,0x30,0x9b,0x6a,0x5a,0x3d,0x46,0x96,0xd3,0x24,0x15,0xec,0xd0,0xf0,0x24,0x5a,0xc3,0x8a,0x62,0xbb,0x12,0xa4,0x5f,0xbc,0x1c,0x79,0x3a,0x0c,0xa5,0xc3,0xaf,0xfb,0x0a,0xca,0xa5,0x04,0x04}, + {0xd6,0x43,0xa7,0x0a,0x07,0x40,0x1f,0x8c,0xe8,0x5e,0x26,0x5b,0xcb,0xd0,0xba,0xcc,0xde,0xd2,0x8f,0x66,0x6b,0x04,0x4b,0x57,0x33,0x96,0xdd,0xca,0xfd,0x5b,0x39,0x46,0xd1,0x6f,0x41,0x2a,0x1b,0x9e,0xbc,0x62,0x8b,0x59,0x50,0xe3,0x28,0xf7,0xc6,0xb5,0x67,0x69,0x5d,0x3d,0xd8,0x3f,0x34,0x04,0x98,0xee,0xf8,0xe7,0x16,0x75,0x52,0x39,0x9c,0x9a,0x5d,0x1a,0x2d,0xdb,0x7f,0x11,0x2a,0x5c,0x00,0xd1,0xbc,0x45,0x77,0x9c,0xea,0x6f,0xd5,0x54,0xf1,0xbe,0xd4,0xef,0x16,0xd0,0x22,0xe8,0x29,0x9a,0x57,0x76}, + {0x17,0x2a,0xc0,0x49,0x7e,0x8e,0xb6,0x45,0x7f,0xa3,0xa9,0xbc,0xa2,0x51,0xcd,0x23,0x1b,0x4c,0x22,0xec,0x11,0x5f,0xd6,0x3e,0xb1,0xbd,0x05,0x9e,0xdc,0x84,0xa3,0x43,0xf2,0x34,0xb4,0x52,0x13,0xb5,0x3c,0x33,0xe1,0x80,0xde,0x93,0x49,0x28,0x32,0xd8,0xce,0x35,0x0d,0x75,0x87,0x28,0x51,0xb5,0xc1,0x77,0x27,0x2a,0xbb,0x14,0xc5,0x02,0x45,0xb6,0xf1,0x8b,0xda,0xd5,0x4b,0x68,0x53,0x4b,0xb5,0xf6,0x7e,0xd3,0x8b,0xfb,0x53,0xd2,0xb0,0xa9,0xd7,0x16,0x39,0x31,0x59,0x80,0x54,0x61,0x09,0x92,0x60,0x11}, + {0xaa,0xcf,0xda,0x29,0x69,0x16,0x4d,0xb4,0x8f,0x59,0x13,0x84,0x4c,0x9f,0x52,0xda,0x59,0x55,0x3d,0x45,0xca,0x63,0xef,0xe9,0x0b,0x8e,0x69,0xc5,0x5b,0x12,0x1e,0x35,0xcd,0x4d,0x9b,0x36,0x16,0x56,0x38,0x7a,0x63,0x35,0x5c,0x65,0xa7,0x2c,0xc0,0x75,0x21,0x80,0xf1,0xd4,0xf9,0x1b,0xc2,0x7d,0x42,0xe0,0xe6,0x91,0x74,0x7d,0x63,0x2f,0xbe,0x7b,0xf6,0x1a,0x46,0x9b,0xb4,0xd4,0x61,0x89,0xab,0xc8,0x7a,0x03,0x03,0xd6,0xfb,0x99,0xa6,0xf9,0x9f,0xe1,0xde,0x71,0x9a,0x2a,0xce,0xe7,0x06,0x2d,0x18,0x7f}, + {0xec,0x68,0x01,0xab,0x64,0x8e,0x7c,0x7a,0x43,0xc5,0xed,0x15,0x55,0x4a,0x5a,0xcb,0xda,0x0e,0xcd,0x47,0xd3,0x19,0x55,0x09,0xb0,0x93,0x3e,0x34,0x8c,0xac,0xd4,0x67,0x22,0x75,0x21,0x8e,0x72,0x4b,0x45,0x09,0xd8,0xb8,0x84,0xd4,0xf4,0xe8,0x58,0xaa,0x3c,0x90,0x46,0x7f,0x4d,0x25,0x58,0xd3,0x17,0x52,0x1c,0x24,0x43,0xc0,0xac,0x44,0x77,0x57,0x7a,0x4f,0xbb,0x6b,0x7d,0x1c,0xe1,0x13,0x83,0x91,0xd4,0xfe,0x35,0x8b,0x84,0x46,0x6b,0xc9,0xc6,0xa1,0xdc,0x4a,0xbd,0x71,0xad,0x12,0x83,0x1c,0x6d,0x55}, + {0x82,0x39,0x8d,0x0c,0xe3,0x40,0xef,0x17,0x34,0xfa,0xa3,0x15,0x3e,0x07,0xf7,0x31,0x6e,0x64,0x73,0x07,0xcb,0xf3,0x21,0x4f,0xff,0x4e,0x82,0x1d,0x6d,0x6c,0x6c,0x74,0x21,0xe8,0x1b,0xb1,0x56,0x67,0xf0,0x81,0xdd,0xf3,0xa3,0x10,0x23,0xf8,0xaf,0x0f,0x5d,0x46,0x99,0x6a,0x55,0xd0,0xb2,0xf8,0x05,0x7f,0x8c,0xcc,0x38,0xbe,0x7a,0x09,0xa4,0x2d,0xa5,0x7e,0x87,0xc9,0x49,0x0c,0x43,0x1d,0xdc,0x9b,0x55,0x69,0x43,0x4c,0xd2,0xeb,0xcc,0xf7,0x09,0x38,0x2c,0x02,0xbd,0x84,0xee,0x4b,0xa3,0x14,0x7e,0x57}, + {0x0a,0x3b,0xa7,0x61,0xac,0x68,0xe2,0xf0,0xf5,0xa5,0x91,0x37,0x10,0xfa,0xfa,0xf2,0xe9,0x00,0x6d,0x6b,0x82,0x3e,0xe1,0xc1,0x42,0x8f,0xd7,0x6f,0xe9,0x7e,0xfa,0x60,0x2b,0xd7,0x4d,0xbd,0xbe,0xce,0xfe,0x94,0x11,0x22,0x0f,0x06,0xda,0x4f,0x6a,0xf4,0xff,0xd1,0xc8,0xc0,0x77,0x59,0x4a,0x12,0x95,0x92,0x00,0xfb,0xb8,0x04,0x53,0x70,0xc6,0x6e,0x29,0x4d,0x35,0x1d,0x3d,0xb6,0xd8,0x31,0xad,0x5f,0x3e,0x05,0xc3,0xf3,0xec,0x42,0xbd,0xb4,0x8c,0x95,0x0b,0x67,0xfd,0x53,0x63,0xa1,0x0c,0x8e,0x39,0x21}, + {0xf3,0x33,0x2b,0x38,0x8a,0x05,0xf5,0x89,0xb4,0xc0,0x48,0xad,0x0b,0xba,0xe2,0x5a,0x6e,0xb3,0x3d,0xa5,0x03,0xb5,0x93,0x8f,0xe6,0x32,0xa2,0x95,0x9d,0xed,0xa3,0x5a,0x01,0x56,0xb7,0xb4,0xf9,0xaa,0x98,0x27,0x72,0xad,0x8d,0x5c,0x13,0x72,0xac,0x5e,0x23,0xa0,0xb7,0x61,0x61,0xaa,0xce,0xd2,0x4e,0x7d,0x8f,0xe9,0x84,0xb2,0xbf,0x1b,0x61,0x65,0xd9,0xc7,0xe9,0x77,0x67,0x65,0x36,0x80,0xc7,0x72,0x54,0x12,0x2b,0xcb,0xee,0x6e,0x50,0xd9,0x99,0x32,0x05,0x65,0xcc,0x57,0x89,0x5e,0x4e,0xe1,0x07,0x4a}, + {0x99,0xf9,0x0d,0x98,0xcb,0x12,0xe4,0x4e,0x71,0xc7,0x6e,0x3c,0x6f,0xd7,0x15,0xa3,0xfd,0x77,0x5c,0x92,0xde,0xed,0xa5,0xbb,0x02,0x34,0x31,0x1d,0x39,0xac,0x0b,0x3f,0x9b,0xa4,0x77,0xc4,0xcd,0x58,0x0b,0x24,0x17,0xf0,0x47,0x64,0xde,0xda,0x38,0xfd,0xad,0x6a,0xc8,0xa7,0x32,0x8d,0x92,0x19,0x81,0xa0,0xaf,0x84,0xed,0x7a,0xaf,0x50,0xe5,0x5b,0xf6,0x15,0x01,0xde,0x4f,0x6e,0xb2,0x09,0x61,0x21,0x21,0x26,0x98,0x29,0xd9,0xd6,0xad,0x0b,0x81,0x05,0x02,0x78,0x06,0xd0,0xeb,0xba,0x16,0xa3,0x21,0x19}, + {0xfc,0x70,0xb8,0xdf,0x7e,0x2f,0x42,0x89,0xbd,0xb3,0x76,0x4f,0xeb,0x6b,0x29,0x2c,0xf7,0x4d,0xc2,0x36,0xd4,0xf1,0x38,0x07,0xb0,0xae,0x73,0xe2,0x41,0xdf,0x58,0x64,0x8b,0xc1,0xf3,0xd9,0x9a,0xad,0x5a,0xd7,0x9c,0xc1,0xb1,0x60,0xef,0x0e,0x6a,0x56,0xd9,0x0e,0x5c,0x25,0xac,0x0b,0x9a,0x3e,0xf5,0xc7,0x62,0xa0,0xec,0x9d,0x04,0x7b,0x83,0x44,0x44,0x35,0x7a,0xe3,0xcb,0xdc,0x93,0xbe,0xed,0x0f,0x33,0x79,0x88,0x75,0x87,0xdd,0xc5,0x12,0xc3,0x04,0x60,0x78,0x64,0x0e,0x95,0xc2,0xcb,0xdc,0x93,0x60}, + {0x6d,0x70,0xe0,0x85,0x85,0x9a,0xf3,0x1f,0x33,0x39,0xe7,0xb3,0xd8,0xa5,0xd0,0x36,0x3b,0x45,0x8f,0x71,0xe1,0xf2,0xb9,0x43,0x7c,0xa9,0x27,0x48,0x08,0xea,0xd1,0x57,0x4b,0x03,0x84,0x60,0xbe,0xee,0xde,0x6b,0x54,0xb8,0x0f,0x78,0xb6,0xc2,0x99,0x31,0x95,0x06,0x2d,0xb6,0xab,0x76,0x33,0x97,0x90,0x7d,0x64,0x8b,0xc9,0x80,0x31,0x6e,0x71,0xb0,0x28,0xa1,0xe7,0xb6,0x7a,0xee,0xaa,0x8b,0xa8,0x93,0x6d,0x59,0xc1,0xa4,0x30,0x61,0x21,0xb2,0x82,0xde,0xb4,0xf7,0x18,0xbd,0x97,0xdd,0x9d,0x99,0x3e,0x36}, + {0xc4,0x1f,0xee,0x35,0xc1,0x43,0xa8,0x96,0xcf,0xc8,0xe4,0x08,0x55,0xb3,0x6e,0x97,0x30,0xd3,0x8c,0xb5,0x01,0x68,0x2f,0xb4,0x2b,0x05,0x3a,0x69,0x78,0x9b,0xee,0x48,0xc6,0xae,0x4b,0xe2,0xdc,0x48,0x18,0x2f,0x60,0xaf,0xbc,0xba,0x55,0x72,0x9b,0x76,0x31,0xe9,0xef,0x3c,0x6e,0x3c,0xcb,0x90,0x55,0xb3,0xf9,0xc6,0x9b,0x97,0x1f,0x23,0xc6,0xf3,0x2a,0xcc,0x4b,0xde,0x31,0x5c,0x1f,0x8d,0x20,0xfe,0x30,0xb0,0x4b,0xb0,0x66,0xb4,0x4f,0xc1,0x09,0x70,0x8d,0xb7,0x13,0x24,0x79,0x08,0x9b,0xfa,0x9b,0x07}, + {0xf4,0x0d,0x30,0xda,0x51,0x3a,0x90,0xe3,0xb0,0x5a,0xa9,0x3d,0x23,0x64,0x39,0x84,0x80,0x64,0x35,0x0b,0x2d,0xf1,0x3c,0xed,0x94,0x71,0x81,0x84,0xf6,0x77,0x8c,0x03,0x45,0x42,0xd5,0xa2,0x80,0xed,0xc9,0xf3,0x52,0x39,0xf6,0x77,0x78,0x8b,0xa0,0x0a,0x75,0x54,0x08,0xd1,0x63,0xac,0x6d,0xd7,0x6b,0x63,0x70,0x94,0x15,0xfb,0xf4,0x1e,0xec,0x7b,0x16,0x5b,0xe6,0x5e,0x4e,0x85,0xc2,0xcd,0xd0,0x96,0x42,0x0a,0x59,0x59,0x99,0x21,0x10,0x98,0x34,0xdf,0xb2,0x72,0x56,0xff,0x0b,0x4a,0x2a,0xe9,0x5e,0x57}, + {0xcf,0x2f,0x18,0x8a,0x90,0x80,0xc0,0xd4,0xbd,0x9d,0x48,0x99,0xc2,0x70,0xe1,0x30,0xde,0x33,0xf7,0x52,0x57,0xbd,0xba,0x05,0x00,0xfd,0xd3,0x2c,0x11,0xe7,0xd4,0x43,0x01,0xd8,0xa4,0x0a,0x45,0xbc,0x46,0x5d,0xd8,0xb9,0x33,0xa5,0x27,0x12,0xaf,0xc3,0xc2,0x06,0x89,0x2b,0x26,0x3b,0x9e,0x38,0x1b,0x58,0x2f,0x38,0x7e,0x1e,0x0a,0x20,0xc5,0x3a,0xf9,0xea,0x67,0xb9,0x8d,0x51,0xc0,0x52,0x66,0x05,0x9b,0x98,0xbc,0x71,0xf5,0x97,0x71,0x56,0xd9,0x85,0x2b,0xfe,0x38,0x4e,0x1e,0x65,0x52,0xca,0x0e,0x05}, + {0x9c,0x0c,0x3f,0x45,0xde,0x1a,0x43,0xc3,0x9b,0x3b,0x70,0xff,0x5e,0x04,0xf5,0xe9,0x3d,0x7b,0x84,0xed,0xc9,0x7a,0xd9,0xfc,0xc6,0xf4,0x58,0x1c,0xc2,0xe6,0x0e,0x4b,0xea,0x68,0xe6,0x60,0x76,0x39,0xac,0x97,0x97,0xb4,0x3a,0x15,0xfe,0xbb,0x19,0x9b,0x9f,0xa7,0xec,0x34,0xb5,0x79,0xb1,0x4c,0x57,0xae,0x31,0xa1,0x9f,0xc0,0x51,0x61,0x96,0x5d,0xf0,0xfd,0x0d,0x5c,0xf5,0x3a,0x7a,0xee,0xb4,0x2a,0xe0,0x2e,0x26,0xdd,0x09,0x17,0x17,0x12,0x87,0xbb,0xb2,0x11,0x0b,0x03,0x0f,0x80,0xfa,0x24,0xef,0x1f}, + {0x96,0x31,0xa7,0x1a,0xfb,0x53,0xd6,0x37,0x18,0x64,0xd7,0x3f,0x30,0x95,0x94,0x0f,0xb2,0x17,0x3a,0xfb,0x09,0x0b,0x20,0xad,0x3e,0x61,0xc8,0x2f,0x29,0x49,0x4d,0x54,0x86,0x6b,0x97,0x30,0xf5,0xaf,0xd2,0x22,0x04,0x46,0xd2,0xc2,0x06,0xb8,0x90,0x8d,0xe5,0xba,0xe5,0x4d,0x6c,0x89,0xa1,0xdc,0x17,0x0c,0x34,0xc8,0xe6,0x5f,0x00,0x28,0x88,0x86,0x52,0x34,0x9f,0xba,0xef,0x6a,0xa1,0x7d,0x10,0x25,0x94,0xff,0x1b,0x5c,0x36,0x4b,0xd9,0x66,0xcd,0xbb,0x5b,0xf7,0xfa,0x6d,0x31,0x0f,0x93,0x72,0xe4,0x72}, + {0x4f,0x08,0x81,0x97,0x8c,0x20,0x95,0x26,0xe1,0x0e,0x45,0x23,0x0b,0x2a,0x50,0xb1,0x02,0xde,0xef,0x03,0xa6,0xae,0x9d,0xfd,0x4c,0xa3,0x33,0x27,0x8c,0x2e,0x9d,0x5a,0x27,0x76,0x2a,0xd3,0x35,0xf6,0xf3,0x07,0xf0,0x66,0x65,0x5f,0x86,0x4d,0xaa,0x7a,0x50,0x44,0xd0,0x28,0x97,0xe7,0x85,0x3c,0x38,0x64,0xe0,0x0f,0x00,0x7f,0xee,0x1f,0xe5,0xf7,0xdb,0x03,0xda,0x05,0x53,0x76,0xbd,0xcd,0x34,0x14,0x49,0xf2,0xda,0xa4,0xec,0x88,0x4a,0xd2,0xcd,0xd5,0x4a,0x7b,0x43,0x05,0x04,0xee,0x51,0x40,0xf9,0x00}, + {0xb2,0x30,0xd3,0xc3,0x23,0x6b,0x35,0x8d,0x06,0x1b,0x47,0xb0,0x9b,0x8b,0x1c,0xf2,0x3c,0xb8,0x42,0x6e,0x6c,0x31,0x6c,0xb3,0x0d,0xb1,0xea,0x8b,0x7e,0x9c,0xd7,0x07,0x53,0x97,0xaf,0x07,0xbb,0x93,0xef,0xd7,0xa7,0x66,0xb7,0x3d,0xcf,0xd0,0x3e,0x58,0xc5,0x1e,0x0b,0x6e,0xbf,0x98,0x69,0xce,0x52,0x04,0xd4,0x5d,0xd2,0xff,0xb7,0x47,0x12,0xdd,0x08,0xbc,0x9c,0xfb,0xfb,0x87,0x9b,0xc2,0xee,0xe1,0x3a,0x6b,0x06,0x8a,0xbf,0xc1,0x1f,0xdb,0x2b,0x24,0x57,0x0d,0xb6,0x4b,0xa6,0x5e,0xa3,0x20,0x35,0x1c}, + {0x4a,0xa3,0xcb,0xbc,0xa6,0x53,0xd2,0x80,0x9b,0x21,0x38,0x38,0xa1,0xc3,0x61,0x3e,0x96,0xe3,0x82,0x98,0x01,0xb6,0xc3,0x90,0x6f,0xe6,0x0e,0x5d,0x77,0x05,0x3d,0x1c,0x59,0xc0,0x6b,0x21,0x40,0x6f,0xa8,0xcd,0x7e,0xd8,0xbc,0x12,0x1d,0x23,0xbb,0x1f,0x90,0x09,0xc7,0x17,0x9e,0x6a,0x95,0xb4,0x55,0x2e,0xd1,0x66,0x3b,0x0c,0x75,0x38,0x1a,0xe5,0x22,0x94,0x40,0xf1,0x2e,0x69,0x71,0xf6,0x5d,0x2b,0x3c,0xc7,0xc0,0xcb,0x29,0xe0,0x4c,0x74,0xe7,0x4f,0x01,0x21,0x7c,0x48,0x30,0xd3,0xc7,0xe2,0x21,0x06}, + {0x8d,0x83,0x59,0x82,0xcc,0x60,0x98,0xaf,0xdc,0x9a,0x9f,0xc6,0xc1,0x48,0xea,0x90,0x30,0x1e,0x58,0x65,0x37,0x48,0x26,0x65,0xbc,0xa5,0xd3,0x7b,0x09,0xd6,0x07,0x00,0xf3,0xf0,0xdb,0xb0,0x96,0x17,0xae,0xb7,0x96,0xe1,0x7c,0xe1,0xb9,0xaf,0xdf,0x54,0xb4,0xa3,0xaa,0xe9,0x71,0x30,0x92,0x25,0x9d,0x2e,0x00,0xa1,0x9c,0x58,0x8e,0x5d,0x4b,0xa9,0x42,0x08,0x95,0x1d,0xbf,0xc0,0x3e,0x2e,0x8f,0x58,0x63,0xc3,0xd3,0xb2,0xef,0xe2,0x51,0xbb,0x38,0x14,0x96,0x0a,0x86,0xbf,0x1c,0x3c,0x78,0xd7,0x83,0x15}, + {0xe1,0x7a,0xa2,0x5d,0xef,0xa2,0xee,0xec,0x74,0x01,0x67,0x55,0x14,0x3a,0x7c,0x59,0x7a,0x16,0x09,0x66,0x12,0x2a,0xa6,0xc9,0x70,0x8f,0xed,0x81,0x2e,0x5f,0x2a,0x25,0xc7,0x28,0x9d,0xcc,0x04,0x47,0x03,0x90,0x8f,0xc5,0x2c,0xf7,0x9e,0x67,0x1b,0x1d,0x26,0x87,0x5b,0xbe,0x5f,0x2b,0xe1,0x16,0x0a,0x58,0xc5,0x83,0x4e,0x06,0x58,0x49,0x0d,0xe8,0x66,0x50,0x26,0x94,0x28,0x0d,0x6b,0x8c,0x7c,0x30,0x85,0xf7,0xc3,0xfc,0xfd,0x12,0x11,0x0c,0x78,0xda,0x53,0x1b,0x88,0xb3,0x43,0xd8,0x0b,0x17,0x9c,0x07}, + {0xff,0x6f,0xfa,0x64,0xe4,0xec,0x06,0x05,0x23,0xe5,0x05,0x62,0x1e,0x43,0xe3,0xbe,0x42,0xea,0xb8,0x51,0x24,0x42,0x79,0x35,0x00,0xfb,0xc9,0x4a,0xe3,0x05,0xec,0x6d,0x56,0xd0,0xd5,0xc0,0x50,0xcd,0xd6,0xcd,0x3b,0x57,0x03,0xbb,0x6d,0x68,0xf7,0x9a,0x48,0xef,0xc3,0xf3,0x3f,0x72,0xa6,0x3c,0xcc,0x8a,0x7b,0x31,0xd7,0xc0,0x68,0x67,0xb3,0xc1,0x55,0xf1,0xe5,0x25,0xb6,0x94,0x91,0x7b,0x7b,0x99,0xa7,0xf3,0x7b,0x41,0x00,0x26,0x6b,0x6d,0xdc,0xbd,0x2c,0xc2,0xf4,0x52,0xcd,0xdd,0x14,0x5e,0x44,0x51}, + {0x51,0x49,0x14,0x3b,0x4b,0x2b,0x50,0x57,0xb3,0xbc,0x4b,0x44,0x6b,0xff,0x67,0x8e,0xdb,0x85,0x63,0x16,0x27,0x69,0xbd,0xb8,0xc8,0x95,0x92,0xe3,0x31,0x6f,0x18,0x13,0x55,0xa4,0xbe,0x2b,0xab,0x47,0x31,0x89,0x29,0x91,0x07,0x92,0x4f,0xa2,0x53,0x8c,0xa7,0xf7,0x30,0xbe,0x48,0xf9,0x49,0x4b,0x3d,0xd4,0x4f,0x6e,0x08,0x90,0xe9,0x12,0x2e,0xbb,0xdf,0x7f,0xb3,0x96,0x0c,0xf1,0xf9,0xea,0x1c,0x12,0x5e,0x93,0x9a,0x9f,0x3f,0x98,0x5b,0x3a,0xc4,0x36,0x11,0xdf,0xaf,0x99,0x3e,0x5d,0xf0,0xe3,0xb2,0x77}, + {0xde,0xc4,0x2e,0x9c,0xc5,0xa9,0x6f,0x29,0xcb,0xf3,0x84,0x4f,0xbf,0x61,0x8b,0xbc,0x08,0xf9,0xa8,0x17,0xd9,0x06,0x77,0x1c,0x5d,0x25,0xd3,0x7a,0xfc,0x95,0xb7,0x63,0xa4,0xb0,0xdd,0x12,0x9c,0x63,0x98,0xd5,0x6b,0x86,0x24,0xc0,0x30,0x9f,0xd1,0xa5,0x60,0xe4,0xfc,0x58,0x03,0x2f,0x7c,0xd1,0x8a,0x5e,0x09,0x2e,0x15,0x95,0xa1,0x07,0xc8,0x5f,0x9e,0x38,0x02,0x8f,0x36,0xa8,0x3b,0xe4,0x8d,0xcf,0x02,0x3b,0x43,0x90,0x43,0x26,0x41,0xc5,0x5d,0xfd,0xa1,0xaf,0x37,0x01,0x2f,0x03,0x3d,0xe8,0x8f,0x3e}, + {0x94,0xa2,0x70,0x05,0xb9,0x15,0x8b,0x2f,0x49,0x45,0x08,0x67,0x70,0x42,0xf2,0x94,0x84,0xfd,0xbb,0x61,0xe1,0x5a,0x1c,0xde,0x07,0x40,0xac,0x7f,0x79,0x3b,0xba,0x75,0x3c,0xd1,0xef,0xe8,0x8d,0x4c,0x70,0x08,0x31,0x37,0xe0,0x33,0x8e,0x1a,0xc5,0xdf,0xe3,0xcd,0x60,0x12,0xa5,0x5d,0x9d,0xa5,0x86,0x8c,0x25,0xa6,0x99,0x08,0xd6,0x22,0x96,0xd1,0xcd,0x70,0xc0,0xdb,0x39,0x62,0x9a,0x8a,0x7d,0x6c,0x8b,0x8a,0xfe,0x60,0x60,0x12,0x40,0xeb,0xbc,0x47,0x88,0xb3,0x5e,0x9e,0x77,0x87,0x7b,0xd0,0x04,0x09}, + {0x9c,0x91,0xba,0xdd,0xd4,0x1f,0xce,0xb4,0xaa,0x8d,0x4c,0xc7,0x3e,0xdb,0x31,0xcf,0x51,0xcc,0x86,0xad,0x63,0xcc,0x63,0x2c,0x07,0xde,0x1d,0xbc,0x3f,0x14,0xe2,0x43,0xb9,0x40,0xf9,0x48,0x66,0x2d,0x32,0xf4,0x39,0x0c,0x2d,0xbd,0x0c,0x2f,0x95,0x06,0x31,0xf9,0x81,0xa0,0xad,0x97,0x76,0x16,0x6c,0x2a,0xf7,0xba,0xce,0xaa,0x40,0x62,0xa0,0x95,0xa2,0x5b,0x9c,0x74,0x34,0xf8,0x5a,0xd2,0x37,0xca,0x5b,0x7c,0x94,0xd6,0x6a,0x31,0xc9,0xe7,0xa7,0x3b,0xf1,0x66,0xac,0x0c,0xb4,0x8d,0x23,0xaf,0xbd,0x56}, + {0xeb,0x33,0x35,0xf5,0xe3,0xb9,0x2a,0x36,0x40,0x3d,0xb9,0x6e,0xd5,0x68,0x85,0x33,0x72,0x55,0x5a,0x1d,0x52,0x14,0x0e,0x9e,0x18,0x13,0x74,0x83,0x6d,0xa8,0x24,0x1d,0xb2,0x3b,0x9d,0xc1,0x6c,0xd3,0x10,0x13,0xb9,0x86,0x23,0x62,0xb7,0x6b,0x2a,0x06,0x5c,0x4f,0xa1,0xd7,0x91,0x85,0x9b,0x7c,0x54,0x57,0x1e,0x7e,0x50,0x31,0xaa,0x03,0x1f,0xce,0xd4,0xff,0x48,0x76,0xec,0xf4,0x1c,0x8c,0xac,0x54,0xf0,0xea,0x45,0xe0,0x7c,0x35,0x09,0x1d,0x82,0x25,0xd2,0x88,0x59,0x48,0xeb,0x9a,0xdc,0x61,0xb2,0x43}, + {0xbb,0x79,0xbb,0x88,0x19,0x1e,0x5b,0xe5,0x9d,0x35,0x7a,0xc1,0x7d,0xd0,0x9e,0xa0,0x33,0xea,0x3d,0x60,0xe2,0x2e,0x2c,0xb0,0xc2,0x6b,0x27,0x5b,0xcf,0x55,0x60,0x32,0x64,0x13,0x95,0x6c,0x8b,0x3d,0x51,0x19,0x7b,0xf4,0x0b,0x00,0x26,0x71,0xfe,0x94,0x67,0x95,0x4f,0xd5,0xdd,0x10,0x8d,0x02,0x64,0x09,0x94,0x42,0xe2,0xd5,0xb4,0x02,0xf2,0x8d,0xd1,0x28,0xcb,0x55,0xa1,0xb4,0x08,0xe5,0x6c,0x18,0x46,0x46,0xcc,0xea,0x89,0x43,0x82,0x6c,0x93,0xf4,0x9c,0xc4,0x10,0x34,0x5d,0xae,0x09,0xc8,0xa6,0x27}, + {0x88,0xb1,0x0d,0x1f,0xcd,0xeb,0xa6,0x8b,0xe8,0x5b,0x5a,0x67,0x3a,0xd7,0xd3,0x37,0x5a,0x58,0xf5,0x15,0xa3,0xdf,0x2e,0xf2,0x7e,0xa1,0x60,0xff,0x74,0x71,0xb6,0x2c,0x54,0x69,0x3d,0xc4,0x0a,0x27,0x2c,0xcd,0xb2,0xca,0x66,0x6a,0x57,0x3e,0x4a,0xdd,0x6c,0x03,0xd7,0x69,0x24,0x59,0xfa,0x79,0x99,0x25,0x8c,0x3d,0x60,0x03,0x15,0x22,0xd0,0xe1,0x0b,0x39,0xf9,0xcd,0xee,0x59,0xf1,0xe3,0x8c,0x72,0x44,0x20,0x42,0xa9,0xf4,0xf0,0x94,0x7a,0x66,0x1c,0x89,0x82,0x36,0xf4,0x90,0x38,0xb7,0xf4,0x1d,0x7b}, + {0x24,0xa2,0xb2,0xb3,0xe0,0xf2,0x92,0xe4,0x60,0x11,0x55,0x2b,0x06,0x9e,0x6c,0x7c,0x0e,0x7b,0x7f,0x0d,0xe2,0x8f,0xeb,0x15,0x92,0x59,0xfc,0x58,0x26,0xef,0xfc,0x61,0x8c,0xf5,0xf8,0x07,0x18,0x22,0x2e,0x5f,0xd4,0x09,0x94,0xd4,0x9f,0x5c,0x55,0xe3,0x30,0xa6,0xb6,0x1f,0x8d,0xa8,0xaa,0xb2,0x3d,0xe0,0x52,0xd3,0x45,0x82,0x69,0x68,0x7a,0x18,0x18,0x2a,0x85,0x5d,0xb1,0xdb,0xd7,0xac,0xdd,0x86,0xd3,0xaa,0xe4,0xf3,0x82,0xc4,0xf6,0x0f,0x81,0xe2,0xba,0x44,0xcf,0x01,0xaf,0x3d,0x47,0x4c,0xcf,0x46}, + {0xf9,0xe5,0xc4,0x9e,0xed,0x25,0x65,0x42,0x03,0x33,0x90,0x16,0x01,0xda,0x5e,0x0e,0xdc,0xca,0xe5,0xcb,0xf2,0xa7,0xb1,0x72,0x40,0x5f,0xeb,0x14,0xcd,0x7b,0x38,0x29,0x40,0x81,0x49,0xf1,0xa7,0x6e,0x3c,0x21,0x54,0x48,0x2b,0x39,0xf8,0x7e,0x1e,0x7c,0xba,0xce,0x29,0x56,0x8c,0xc3,0x88,0x24,0xbb,0xc5,0x8c,0x0d,0xe5,0xaa,0x65,0x10,0x57,0x0d,0x20,0xdf,0x25,0x45,0x2c,0x1c,0x4a,0x67,0xca,0xbf,0xd6,0x2d,0x3b,0x5c,0x30,0x40,0x83,0xe1,0xb1,0xe7,0x07,0x0a,0x16,0xe7,0x1c,0x4f,0xe6,0x98,0xa1,0x69}, + {0xbc,0x78,0x1a,0xd9,0xe0,0xb2,0x62,0x90,0x67,0x96,0x50,0xc8,0x9c,0x88,0xc9,0x47,0xb8,0x70,0x50,0x40,0x66,0x4a,0xf5,0x9d,0xbf,0xa1,0x93,0x24,0xa9,0xe6,0x69,0x73,0xed,0xca,0xc5,0xdc,0x34,0x44,0x01,0xe1,0x33,0xfb,0x84,0x3c,0x96,0x5d,0xed,0x47,0xe7,0xa0,0x86,0xed,0x76,0x95,0x01,0x70,0xe4,0xf9,0x67,0xd2,0x7b,0x69,0xb2,0x25,0x64,0x68,0x98,0x13,0xfb,0x3f,0x67,0x9d,0xb8,0xc7,0x5d,0x41,0xd9,0xfb,0xa5,0x3c,0x5e,0x3b,0x27,0xdf,0x3b,0xcc,0x4e,0xe0,0xd2,0x4c,0x4e,0xb5,0x3d,0x68,0x20,0x14}, + {0x97,0xd1,0x9d,0x24,0x1e,0xbd,0x78,0xb4,0x02,0xc1,0x58,0x5e,0x00,0x35,0x0c,0x62,0x5c,0xac,0xba,0xcc,0x2f,0xd3,0x02,0xfb,0x2d,0xa7,0x08,0xf5,0xeb,0x3b,0xb6,0x60,0xd0,0x5a,0xcc,0xc1,0x6f,0xbb,0xee,0x34,0x8b,0xac,0x46,0x96,0xe9,0x0c,0x1b,0x6a,0x53,0xde,0x6b,0xa6,0x49,0xda,0xb0,0xd3,0xc1,0x81,0xd0,0x61,0x41,0x3b,0xe8,0x31,0x4f,0x2b,0x06,0x9e,0x12,0xc7,0xe8,0x97,0xd8,0x0a,0x32,0x29,0x4f,0x8f,0xe4,0x49,0x3f,0x68,0x18,0x6f,0x4b,0xe1,0xec,0x5b,0x17,0x03,0x55,0x2d,0xb6,0x1e,0xcf,0x55}, + {0x58,0x3d,0xc2,0x65,0x10,0x10,0x79,0x58,0x9c,0x81,0x94,0x50,0x6d,0x08,0x9d,0x8b,0xa7,0x5f,0xc5,0x12,0xa9,0x2f,0x40,0xe2,0xd4,0x91,0x08,0x57,0x64,0x65,0x9a,0x66,0x52,0x8c,0xf5,0x7d,0xe3,0xb5,0x76,0x30,0x36,0xcc,0x99,0xe7,0xdd,0xb9,0x3a,0xd7,0x20,0xee,0x13,0x49,0xe3,0x1c,0x83,0xbd,0x33,0x01,0xba,0x62,0xaa,0xfb,0x56,0x1a,0xec,0xc9,0x9d,0x5c,0x50,0x6b,0x3e,0x94,0x1a,0x37,0x7c,0xa7,0xbb,0x57,0x25,0x30,0x51,0x76,0x34,0x41,0x56,0xae,0x73,0x98,0x5c,0x8a,0xc5,0x99,0x67,0x83,0xc4,0x13}, + {0xb9,0xe1,0xb3,0x5a,0x46,0x5d,0x3a,0x42,0x61,0x3f,0xf1,0xc7,0x87,0xc1,0x13,0xfc,0xb6,0xb9,0xb5,0xec,0x64,0x36,0xf8,0x19,0x07,0xb6,0x37,0xa6,0x93,0x0c,0xf8,0x66,0x80,0xd0,0x8b,0x5d,0x6a,0xfb,0xdc,0xc4,0x42,0x48,0x1a,0x57,0xec,0xc4,0xeb,0xde,0x65,0x53,0xe5,0xb8,0x83,0xe8,0xb2,0xd4,0x27,0xb8,0xe5,0xc8,0x7d,0xc8,0xbd,0x50,0x11,0xe1,0xdf,0x6e,0x83,0x37,0x6d,0x60,0xd9,0xab,0x11,0xf0,0x15,0x3e,0x35,0x32,0x96,0x3b,0xb7,0x25,0xc3,0x3a,0xb0,0x64,0xae,0xd5,0x5f,0x72,0x44,0x64,0xd5,0x1d}, + {0x7d,0x12,0x62,0x33,0xf8,0x7f,0xa4,0x8f,0x15,0x7c,0xcd,0x71,0xc4,0x6a,0x9f,0xbc,0x8b,0x0c,0x22,0x49,0x43,0x45,0x71,0x6e,0x2e,0x73,0x9f,0x21,0x12,0x59,0x64,0x0e,0x9a,0xc8,0xba,0x08,0x00,0xe6,0x97,0xc2,0xe0,0xc3,0xe1,0xea,0x11,0xea,0x4c,0x7d,0x7c,0x97,0xe7,0x9f,0xe1,0x8b,0xe3,0xf3,0xcd,0x05,0xa3,0x63,0x0f,0x45,0x3a,0x3a,0x27,0x46,0x39,0xd8,0x31,0x2f,0x8f,0x07,0x10,0xa5,0x94,0xde,0x83,0x31,0x9d,0x38,0x80,0x6f,0x99,0x17,0x6d,0x6c,0xe3,0xd1,0x7b,0xa8,0xa9,0x93,0x93,0x8d,0x8c,0x31}, + {0x19,0xfe,0xff,0x2a,0x03,0x5d,0x74,0xf2,0x66,0xdb,0x24,0x7f,0x49,0x3c,0x9f,0x0c,0xef,0x98,0x85,0xba,0xe3,0xd3,0x98,0xbc,0x14,0x53,0x1d,0x9a,0x67,0x7c,0x4c,0x22,0x98,0xd3,0x1d,0xab,0x29,0x9e,0x66,0x5d,0x3b,0x9e,0x2d,0x34,0x58,0x16,0x92,0xfc,0xcd,0x73,0x59,0xf3,0xfd,0x1d,0x85,0x55,0xf6,0x0a,0x95,0x25,0xc3,0x41,0x9a,0x50,0xe9,0x25,0xf9,0xa6,0xdc,0x6e,0xc0,0xbd,0x33,0x1f,0x1b,0x64,0xf4,0xf3,0x3e,0x79,0x89,0x3e,0x83,0x9d,0x80,0x12,0xec,0x82,0x89,0x13,0xa1,0x28,0x23,0xf0,0xbf,0x05}, + {0x0b,0xe0,0xca,0x23,0x70,0x13,0x32,0x36,0x59,0xcf,0xac,0xd1,0x0a,0xcf,0x4a,0x54,0x88,0x1c,0x1a,0xd2,0x49,0x10,0x74,0x96,0xa7,0x44,0x2a,0xfa,0xc3,0x8c,0x0b,0x78,0xe4,0x12,0xc5,0x0d,0xdd,0xa0,0x81,0x68,0xfe,0xfa,0xa5,0x44,0xc8,0x0d,0xe7,0x4f,0x40,0x52,0x4a,0x8f,0x6b,0x8e,0x74,0x1f,0xea,0xa3,0x01,0xee,0xcd,0x77,0x62,0x57,0x5f,0x30,0x4f,0x23,0xbc,0x8a,0xf3,0x1e,0x08,0xde,0x05,0x14,0xbd,0x7f,0x57,0x9a,0x0d,0x2a,0xe6,0x34,0x14,0xa5,0x82,0x5e,0xa1,0xb7,0x71,0x62,0x72,0x18,0xf4,0x5f}, + {0x9d,0xdb,0x89,0x17,0x0c,0x08,0x8e,0x39,0xf5,0x78,0xe7,0xf3,0x25,0x20,0x60,0xa7,0x5d,0x03,0xbd,0x06,0x4c,0x89,0x98,0xfa,0xbe,0x66,0xa9,0x25,0xdc,0x03,0x6a,0x10,0x40,0x95,0xb6,0x13,0xe8,0x47,0xdb,0xe5,0xe1,0x10,0x26,0x43,0x3b,0x2a,0x5d,0xf3,0x76,0x12,0x78,0x38,0xe9,0x26,0x1f,0xac,0x69,0xcb,0xa0,0xa0,0x8c,0xdb,0xd4,0x29,0xd0,0x53,0x33,0x33,0xaf,0x0a,0xad,0xd9,0xe5,0x09,0xd3,0xac,0xa5,0x9d,0x66,0x38,0xf0,0xf7,0x88,0xc8,0x8a,0x65,0x57,0x3c,0xfa,0xbe,0x2c,0x05,0x51,0x8a,0xb3,0x4a}, + {0x93,0xd5,0x68,0x67,0x25,0x2b,0x7c,0xda,0x13,0xca,0x22,0x44,0x57,0xc0,0xc1,0x98,0x1d,0xce,0x0a,0xca,0xd5,0x0b,0xa8,0xf1,0x90,0xa6,0x88,0xc0,0xad,0xd1,0xcd,0x29,0x9c,0xc0,0xdd,0x5f,0xef,0xd1,0xcf,0xd6,0xce,0x5d,0x57,0xf7,0xfd,0x3e,0x2b,0xe8,0xc2,0x34,0x16,0x20,0x5d,0x6b,0xd5,0x25,0x9b,0x2b,0xed,0x04,0xbb,0xc6,0x41,0x30,0x48,0xe1,0x56,0xd9,0xf9,0xf2,0xf2,0x0f,0x2e,0x6b,0x35,0x9f,0x75,0x97,0xe7,0xad,0x5c,0x02,0x6c,0x5f,0xbb,0x98,0x46,0x1a,0x7b,0x9a,0x04,0x14,0x68,0xbd,0x4b,0x10}, + {0x67,0xed,0xf1,0x68,0x31,0xfd,0xf0,0x51,0xc2,0x3b,0x6f,0xd8,0xcd,0x1d,0x81,0x2c,0xde,0xf2,0xd2,0x04,0x43,0x5c,0xdc,0x44,0x49,0x71,0x2a,0x09,0x57,0xcc,0xe8,0x5b,0x63,0xf1,0x7f,0xd6,0x5f,0x9a,0x5d,0xa9,0x81,0x56,0xc7,0x4c,0x9d,0xe6,0x2b,0xe9,0x57,0xf2,0x20,0xde,0x4c,0x02,0xf8,0xb7,0xf5,0x2d,0x07,0xfb,0x20,0x2a,0x4f,0x20,0x79,0xb0,0xeb,0x30,0x3d,0x3b,0x14,0xc8,0x30,0x2e,0x65,0xbd,0x5a,0x15,0x89,0x75,0x31,0x5c,0x6d,0x8f,0x31,0x3c,0x3c,0x65,0x1f,0x16,0x79,0xc2,0x17,0xfb,0x70,0x25}, + {0x75,0x15,0xb6,0x2c,0x7f,0x36,0xfa,0x3e,0x6c,0x02,0xd6,0x1c,0x76,0x6f,0xf9,0xf5,0x62,0x25,0xb5,0x65,0x2a,0x14,0xc7,0xe8,0xcd,0x0a,0x03,0x53,0xea,0x65,0xcb,0x3d,0x5a,0x24,0xb8,0x0b,0x55,0xa9,0x2e,0x19,0xd1,0x50,0x90,0x8f,0xa8,0xfb,0xe6,0xc8,0x35,0xc9,0xa4,0x88,0x2d,0xea,0x86,0x79,0x68,0x86,0x01,0xde,0x91,0x5f,0x1c,0x24,0xaa,0x6c,0xde,0x40,0x29,0x17,0xd8,0x28,0x3a,0x73,0xd9,0x22,0xf0,0x2c,0xbf,0x8f,0xd1,0x01,0x5b,0x23,0xdd,0xfc,0xd7,0x16,0xe5,0xf0,0xcd,0x5f,0xdd,0x0e,0x42,0x08}, + {0x4a,0xfa,0x62,0x83,0xab,0x20,0xff,0xcd,0x6e,0x3e,0x1a,0xe2,0xd4,0x18,0xe1,0x57,0x2b,0xe6,0x39,0xfc,0x17,0x96,0x17,0xe3,0xfd,0x69,0x17,0xbc,0xef,0x53,0x9a,0x0d,0xce,0x10,0xf4,0x04,0x4e,0xc3,0x58,0x03,0x85,0x06,0x6e,0x27,0x5a,0x5b,0x13,0xb6,0x21,0x15,0xb9,0xeb,0xc7,0x70,0x96,0x5d,0x9c,0x88,0xdb,0x21,0xf3,0x54,0xd6,0x04,0xd5,0xb5,0xbd,0xdd,0x16,0xc1,0x7d,0x5e,0x2d,0xdd,0xa5,0x8d,0xb6,0xde,0x54,0x29,0x92,0xa2,0x34,0x33,0x17,0x08,0xb6,0x1c,0xd7,0x1a,0x99,0x18,0x26,0x4f,0x7a,0x4a}, + {0x95,0x5f,0xb1,0x5f,0x02,0x18,0xa7,0xf4,0x8f,0x1b,0x5c,0x6b,0x34,0x5f,0xf6,0x3d,0x12,0x11,0xe0,0x00,0x85,0xf0,0xfc,0xcd,0x48,0x18,0xd3,0xdd,0x4c,0x0c,0xb5,0x11,0x4b,0x2a,0x37,0xaf,0x91,0xb2,0xc3,0x24,0xf2,0x47,0x81,0x71,0x70,0x82,0xda,0x93,0xf2,0x9e,0x89,0x86,0x64,0x85,0x84,0xdd,0x33,0xee,0xe0,0x23,0x42,0x31,0x96,0x4a,0xd6,0xff,0xa4,0x08,0x44,0x27,0xe8,0xa6,0xd9,0x76,0x15,0x9c,0x7e,0x17,0x8e,0x73,0xf2,0xb3,0x02,0x3d,0xb6,0x48,0x33,0x77,0x51,0xcc,0x6b,0xce,0x4d,0xce,0x4b,0x4f}, + {0x84,0x25,0x24,0xe2,0x5a,0xce,0x1f,0xa7,0x9e,0x8a,0xf5,0x92,0x56,0x72,0xea,0x26,0xf4,0x3c,0xea,0x1c,0xd7,0x09,0x1a,0xd2,0xe6,0x01,0x1c,0xb7,0x14,0xdd,0xfc,0x73,0x6f,0x0b,0x9d,0xc4,0x6e,0x61,0xe2,0x30,0x17,0x23,0xec,0xca,0x8f,0x71,0x56,0xe4,0xa6,0x4f,0x6b,0xf2,0x9b,0x40,0xeb,0x48,0x37,0x5f,0x59,0x61,0xe5,0xce,0x42,0x30,0x41,0xac,0x9b,0x44,0x79,0x70,0x7e,0x42,0x0a,0x31,0xe2,0xbc,0x6d,0xe3,0x5a,0x85,0x7c,0x1a,0x84,0x5f,0x21,0x76,0xae,0x4c,0xd6,0xe1,0x9c,0x9a,0x0c,0x74,0x9e,0x38}, + {0xce,0xb9,0xdc,0x34,0xae,0xb3,0xfc,0x64,0xad,0xd0,0x48,0xe3,0x23,0x03,0x50,0x97,0x1b,0x38,0xc6,0x62,0x7d,0xf0,0xb3,0x45,0x88,0x67,0x5a,0x46,0x79,0x53,0x54,0x61,0x28,0xac,0x0e,0x57,0xf6,0x78,0xbd,0xc9,0xe1,0x9c,0x91,0x27,0x32,0x0b,0x5b,0xe5,0xed,0x91,0x9b,0xa1,0xab,0x3e,0xfc,0x65,0x90,0x36,0x26,0xd6,0xe5,0x25,0xc4,0x25,0x6e,0xde,0xd7,0xf1,0xa6,0x06,0x3e,0x3f,0x08,0x23,0x06,0x8e,0x27,0x76,0xf9,0x3e,0x77,0x6c,0x8a,0x4e,0x26,0xf6,0x14,0x8c,0x59,0x47,0x48,0x15,0x89,0xa0,0x39,0x65}, + {0x73,0xf7,0xd2,0xc3,0x74,0x1f,0xd2,0xe9,0x45,0x68,0xc4,0x25,0x41,0x54,0x50,0xc1,0x33,0x9e,0xb9,0xf9,0xe8,0x5c,0x4e,0x62,0x6c,0x18,0xcd,0xc5,0xaa,0xe4,0xc5,0x11,0x19,0x4a,0xbb,0x14,0xd4,0xdb,0xc4,0xdd,0x8e,0x4f,0x42,0x98,0x3c,0xbc,0xb2,0x19,0x69,0x71,0xca,0x36,0xd7,0x9f,0xa8,0x48,0x90,0xbd,0x19,0xf0,0x0e,0x32,0x65,0x0f,0xc6,0xe0,0xfd,0xca,0xb1,0xd1,0x86,0xd4,0x81,0x51,0x3b,0x16,0xe3,0xe6,0x3f,0x4f,0x9a,0x93,0xf2,0xfa,0x0d,0xaf,0xa8,0x59,0x2a,0x07,0x33,0xec,0xbd,0xc7,0xab,0x4c}, + {0x2e,0x0a,0x9c,0x08,0x24,0x96,0x9e,0x23,0x38,0x47,0xfe,0x3a,0xc0,0xc4,0x48,0xc7,0x2a,0xa1,0x4f,0x76,0x2a,0xed,0xdb,0x17,0x82,0x85,0x1c,0x32,0xf0,0x93,0x9b,0x63,0x89,0xd2,0x78,0x3f,0x8f,0x78,0x8f,0xc0,0x9f,0x4d,0x40,0xa1,0x2c,0xa7,0x30,0xfe,0x9d,0xcc,0x65,0xcf,0xfc,0x8b,0x77,0xf2,0x21,0x20,0xcb,0x5a,0x16,0x98,0xe4,0x7e,0xc3,0xa1,0x11,0x91,0xe3,0x08,0xd5,0x7b,0x89,0x74,0x90,0x80,0xd4,0x90,0x2b,0x2b,0x19,0xfd,0x72,0xae,0xc2,0xae,0xd2,0xe7,0xa6,0x02,0xb6,0x85,0x3c,0x49,0xdf,0x0e}, + {0x68,0x5a,0x9b,0x59,0x58,0x81,0xcc,0xae,0x0e,0xe2,0xad,0xeb,0x0f,0x4f,0x57,0xea,0x07,0x7f,0xb6,0x22,0x74,0x1d,0xe4,0x4f,0xb4,0x4f,0x9d,0x01,0xe3,0x92,0x3b,0x40,0x13,0x41,0x76,0x84,0xd2,0xc4,0x67,0x67,0x35,0xf8,0xf5,0xf7,0x3f,0x40,0x90,0xa0,0xde,0xbe,0xe6,0xca,0xfa,0xcf,0x8f,0x1c,0x69,0xa3,0xdf,0xd1,0x54,0x0c,0xc0,0x04,0xf8,0x5c,0x46,0x8b,0x81,0x2f,0xc2,0x4d,0xf8,0xef,0x80,0x14,0x5a,0xf3,0xa0,0x71,0x57,0xd6,0xc7,0x04,0xad,0xbf,0xe8,0xae,0xf4,0x76,0x61,0xb2,0x2a,0xb1,0x5b,0x35}, + {0xf4,0xbb,0x93,0x74,0xcc,0x64,0x1e,0xa7,0xc3,0xb0,0xa3,0xec,0xd9,0x84,0xbd,0xe5,0x85,0xe7,0x05,0xfa,0x0c,0xc5,0x6b,0x0a,0x12,0xc3,0x2e,0x18,0x32,0x81,0x9b,0x0f,0x18,0x73,0x8c,0x5a,0xc7,0xda,0x01,0xa3,0x11,0xaa,0xce,0xb3,0x9d,0x03,0x90,0xed,0x2d,0x3f,0xae,0x3b,0xbf,0x7c,0x07,0x6f,0x8e,0xad,0x52,0xe0,0xf8,0xea,0x18,0x75,0x32,0x6c,0x7f,0x1b,0xc4,0x59,0x88,0xa4,0x98,0x32,0x38,0xf4,0xbc,0x60,0x2d,0x0f,0xd9,0xd1,0xb1,0xc9,0x29,0xa9,0x15,0x18,0xc4,0x55,0x17,0xbb,0x1b,0x87,0xc3,0x47}, + {0x48,0x4f,0xec,0x71,0x97,0x53,0x44,0x51,0x6e,0x5d,0x8c,0xc9,0x7d,0xb1,0x05,0xf8,0x6b,0xc6,0xc3,0x47,0x1a,0xc1,0x62,0xf7,0xdc,0x99,0x46,0x76,0x85,0x9b,0xb8,0x00,0xb0,0x66,0x50,0xc8,0x50,0x5d,0xe6,0xfb,0xb0,0x99,0xa2,0xb3,0xb0,0xc4,0xec,0x62,0xe0,0xe8,0x1a,0x44,0xea,0x54,0x37,0xe5,0x5f,0x8d,0xd4,0xe8,0x2c,0xa0,0xfe,0x08,0xd0,0xea,0xde,0x68,0x76,0xdd,0x4d,0x82,0x23,0x5d,0x68,0x4b,0x20,0x45,0x64,0xc8,0x65,0xd6,0x89,0x5d,0xcd,0xcf,0x14,0xb5,0x37,0xd5,0x75,0x4f,0xa7,0x29,0x38,0x47}, + {0x18,0xc4,0x79,0x46,0x75,0xda,0xd2,0x82,0xf0,0x8d,0x61,0xb2,0xd8,0xd7,0x3b,0xe6,0x0a,0xeb,0x47,0xac,0x24,0xef,0x5e,0x35,0xb4,0xc6,0x33,0x48,0x4c,0x68,0x78,0x20,0xc9,0x02,0x39,0xad,0x3a,0x53,0xd9,0x23,0x8f,0x58,0x03,0xef,0xce,0xdd,0xc2,0x64,0xb4,0x2f,0xe1,0xcf,0x90,0x73,0x25,0x15,0x90,0xd3,0xe4,0x44,0x4d,0x8b,0x66,0x6c,0x0c,0x82,0x78,0x7a,0x21,0xcf,0x48,0x3b,0x97,0x3e,0x27,0x81,0xb2,0x0a,0x6a,0xf7,0x7b,0xed,0x8e,0x8c,0xa7,0x65,0x6c,0xa9,0x3f,0x43,0x8a,0x4f,0x05,0xa6,0x11,0x74}, + {0x6d,0xc8,0x9d,0xb9,0x32,0x9d,0x65,0x4d,0x15,0xf1,0x3a,0x60,0x75,0xdc,0x4c,0x04,0x88,0xe4,0xc2,0xdc,0x2c,0x71,0x4c,0xb3,0xff,0x34,0x81,0xfb,0x74,0x65,0x13,0x7c,0xb4,0x75,0xb1,0x18,0x3d,0xe5,0x9a,0x57,0x02,0xa1,0x92,0xf3,0x59,0x31,0x71,0x68,0xf5,0x35,0xef,0x1e,0xba,0xec,0x55,0x84,0x8f,0x39,0x8c,0x45,0x72,0xa8,0xc9,0x1e,0x9b,0x50,0xa2,0x00,0xd4,0xa4,0xe6,0xb8,0xb4,0x82,0xc8,0x0b,0x02,0xd7,0x81,0x9b,0x61,0x75,0x95,0xf1,0x9b,0xcc,0xe7,0x57,0x60,0x64,0xcd,0xc7,0xa5,0x88,0xdd,0x3a}, + {0xf2,0xdc,0x35,0xb6,0x70,0x57,0x89,0xab,0xbc,0x1f,0x6c,0xf6,0x6c,0xef,0xdf,0x02,0x87,0xd1,0xb6,0xbe,0x68,0x02,0x53,0x85,0x74,0x9e,0x87,0xcc,0xfc,0x29,0x99,0x24,0x46,0x30,0x39,0x59,0xd4,0x98,0xc2,0x85,0xec,0x59,0xf6,0x5f,0x98,0x35,0x7e,0x8f,0x3a,0x6e,0xf6,0xf2,0x2a,0xa2,0x2c,0x1d,0x20,0xa7,0x06,0xa4,0x31,0x11,0xba,0x61,0x29,0x90,0x95,0x16,0xf1,0xa0,0xd0,0xa3,0x89,0xbd,0x7e,0xba,0x6c,0x6b,0x3b,0x02,0x07,0x33,0x78,0x26,0x3e,0x5a,0xf1,0x7b,0xe7,0xec,0xd8,0xbb,0x0c,0x31,0x20,0x56}, + {0x43,0xd6,0x34,0x49,0x43,0x93,0x89,0x52,0xf5,0x22,0x12,0xa5,0x06,0xf8,0xdb,0xb9,0x22,0x1c,0xf4,0xc3,0x8f,0x87,0x6d,0x8f,0x30,0x97,0x9d,0x4d,0x2a,0x6a,0x67,0x37,0xd6,0x85,0xe2,0x77,0xf4,0xb5,0x46,0x66,0x93,0x61,0x8f,0x6c,0x67,0xff,0xe8,0x40,0xdd,0x94,0xb5,0xab,0x11,0x73,0xec,0xa6,0x4d,0xec,0x8c,0x65,0xf3,0x46,0xc8,0x7e,0xc7,0x2e,0xa2,0x1d,0x3f,0x8f,0x5e,0x9b,0x13,0xcd,0x01,0x6c,0x77,0x1d,0x0f,0x13,0xb8,0x9f,0x98,0xa2,0xcf,0x8f,0x4c,0x21,0xd5,0x9d,0x9b,0x39,0x23,0xf7,0xaa,0x6d}, + {0x47,0xbe,0x3d,0xeb,0x62,0x75,0x3a,0x5f,0xb8,0xa0,0xbd,0x8e,0x54,0x38,0xea,0xf7,0x99,0x72,0x74,0x45,0x31,0xe5,0xc3,0x00,0x51,0xd5,0x27,0x16,0xe7,0xe9,0x04,0x13,0xa2,0x8e,0xad,0xac,0xbf,0x04,0x3b,0x58,0x84,0xe8,0x8b,0x14,0xe8,0x43,0xb7,0x29,0xdb,0xc5,0x10,0x08,0x3b,0x58,0x1e,0x2b,0xaa,0xbb,0xb3,0x8e,0xe5,0x49,0x54,0x2b,0xfe,0x9c,0xdc,0x6a,0xd2,0x14,0x98,0x78,0x0b,0xdd,0x48,0x8b,0x3f,0xab,0x1b,0x3c,0x0a,0xc6,0x79,0xf9,0xff,0xe1,0x0f,0xda,0x93,0xd6,0x2d,0x7c,0x2d,0xde,0x68,0x44}, + {0x9e,0x46,0x19,0x94,0x5e,0x35,0xbb,0x51,0x54,0xc7,0xdd,0x23,0x4c,0xdc,0xe6,0x33,0x62,0x99,0x7f,0x44,0xd6,0xb6,0xa5,0x93,0x63,0xbd,0x44,0xfb,0x6f,0x7c,0xce,0x6c,0xce,0x07,0x63,0xf8,0xc6,0xd8,0x9a,0x4b,0x28,0x0c,0x5d,0x43,0x31,0x35,0x11,0x21,0x2c,0x77,0x7a,0x65,0xc5,0x66,0xa8,0xd4,0x52,0x73,0x24,0x63,0x7e,0x42,0xa6,0x5d,0xca,0x22,0xac,0xde,0x88,0xc6,0x94,0x1a,0xf8,0x1f,0xae,0xbb,0xf7,0x6e,0x06,0xb9,0x0f,0x58,0x59,0x8d,0x38,0x8c,0xad,0x88,0xa8,0x2c,0x9f,0xe7,0xbf,0x9a,0xf2,0x58}, + {0x68,0x3e,0xe7,0x8d,0xab,0xcf,0x0e,0xe9,0xa5,0x76,0x7e,0x37,0x9f,0x6f,0x03,0x54,0x82,0x59,0x01,0xbe,0x0b,0x5b,0x49,0xf0,0x36,0x1e,0xf4,0xa7,0xc4,0x29,0x76,0x57,0xf6,0xcd,0x0e,0x71,0xbf,0x64,0x5a,0x4b,0x3c,0x29,0x2c,0x46,0x38,0xe5,0x4c,0xb1,0xb9,0x3a,0x0b,0xd5,0x56,0xd0,0x43,0x36,0x70,0x48,0x5b,0x18,0x24,0x37,0xf9,0x6a,0x88,0xa8,0xc6,0x09,0x45,0x02,0x20,0x32,0x73,0x89,0x55,0x4b,0x13,0x36,0xe0,0xd2,0x9f,0x28,0x33,0x3c,0x23,0x36,0xe2,0x83,0x8f,0xc1,0xae,0x0c,0xbb,0x25,0x1f,0x70}, + {0xed,0x6c,0x61,0xe4,0xf8,0xb0,0xa8,0xc3,0x7d,0xa8,0x25,0x9e,0x0e,0x66,0x00,0xf7,0x9c,0xa5,0xbc,0xf4,0x1f,0x06,0xe3,0x61,0xe9,0x0b,0xc4,0xbd,0xbf,0x92,0x0c,0x2e,0x13,0xc1,0xbe,0x7c,0xd9,0xf6,0x18,0x9d,0xe4,0xdb,0xbf,0x74,0xe6,0x06,0x4a,0x84,0xd6,0x60,0x4e,0xac,0x22,0xb5,0xf5,0x20,0x51,0x5e,0x95,0x50,0xc0,0x5b,0x0a,0x72,0x35,0x5a,0x80,0x9b,0x43,0x09,0x3f,0x0c,0xfc,0xab,0x42,0x62,0x37,0x8b,0x4e,0xe8,0x46,0x93,0x22,0x5c,0xf3,0x17,0x14,0x69,0xec,0xf0,0x4e,0x14,0xbb,0x9c,0x9b,0x0e}, + {0xad,0x20,0x57,0xfb,0x8f,0xd4,0xba,0xfb,0x0e,0x0d,0xf9,0xdb,0x6b,0x91,0x81,0xee,0xbf,0x43,0x55,0x63,0x52,0x31,0x81,0xd4,0xd8,0x7b,0x33,0x3f,0xeb,0x04,0x11,0x22,0xee,0xbe,0xb1,0x5d,0xd5,0x9b,0xee,0x8d,0xb9,0x3f,0x72,0x0a,0x37,0xab,0xc3,0xc9,0x91,0xd7,0x68,0x1c,0xbf,0xf1,0xa8,0x44,0xde,0x3c,0xfd,0x1c,0x19,0x44,0x6d,0x36,0x14,0x8c,0xbc,0xf2,0x43,0x17,0x3c,0x9e,0x3b,0x6c,0x85,0xb5,0xfc,0x26,0xda,0x2e,0x97,0xfb,0xa7,0x68,0x0e,0x2f,0xb8,0xcc,0x44,0x32,0x59,0xbc,0xe6,0xa4,0x67,0x41}, + {0x00,0x27,0xf6,0x76,0x28,0x9d,0x3b,0x64,0xeb,0x68,0x76,0x0e,0x40,0x9d,0x1d,0x5d,0x84,0x06,0xfc,0x21,0x03,0x43,0x4b,0x1b,0x6a,0x24,0x55,0x22,0x7e,0xbb,0x38,0x79,0xee,0x8f,0xce,0xf8,0x65,0x26,0xbe,0xc2,0x2c,0xd6,0x80,0xe8,0x14,0xff,0x67,0xe9,0xee,0x4e,0x36,0x2f,0x7e,0x6e,0x2e,0xf1,0xf6,0xd2,0x7e,0xcb,0x70,0x33,0xb3,0x34,0xcc,0xd6,0x81,0x86,0xee,0x91,0xc5,0xcd,0x53,0xa7,0x85,0xed,0x9c,0x10,0x02,0xce,0x83,0x88,0x80,0x58,0xc1,0x85,0x74,0xed,0xe4,0x65,0xfe,0x2d,0x6e,0xfc,0x76,0x11}, + {0x9b,0x61,0x9c,0x5b,0xd0,0x6c,0xaf,0xb4,0x80,0x84,0xa5,0xb2,0xf4,0xc9,0xdf,0x2d,0xc4,0x4d,0xe9,0xeb,0x02,0xa5,0x4f,0x3d,0x34,0x5f,0x7d,0x67,0x4c,0x3a,0xfc,0x08,0xb8,0x0e,0x77,0x49,0x89,0xe2,0x90,0xdb,0xa3,0x40,0xf4,0xac,0x2a,0xcc,0xfb,0x98,0x9b,0x87,0xd7,0xde,0xfe,0x4f,0x35,0x21,0xb6,0x06,0x69,0xf2,0x54,0x3e,0x6a,0x1f,0xea,0x34,0x07,0xd3,0x99,0xc1,0xa4,0x60,0xd6,0x5c,0x16,0x31,0xb6,0x85,0xc0,0x40,0x95,0x82,0x59,0xf7,0x23,0x3e,0x33,0xe2,0xd1,0x00,0xb9,0x16,0x01,0xad,0x2f,0x4f}, + {0x54,0x4e,0xae,0x94,0x41,0xb2,0xbe,0x44,0x6c,0xef,0x57,0x18,0x51,0x1c,0x54,0x5f,0x98,0x04,0x8d,0x36,0x2d,0x6b,0x1e,0xa6,0xab,0xf7,0x2e,0x97,0xa4,0x84,0x54,0x44,0x38,0xb6,0x3b,0xb7,0x1d,0xd9,0x2c,0x96,0x08,0x9c,0x12,0xfc,0xaa,0x77,0x05,0xe6,0x89,0x16,0xb6,0xf3,0x39,0x9b,0x61,0x6f,0x81,0xee,0x44,0x29,0x5f,0x99,0x51,0x34,0x7c,0x7d,0xea,0x9f,0xd0,0xfc,0x52,0x91,0xf6,0x5c,0x93,0xb0,0x94,0x6c,0x81,0x4a,0x40,0x5c,0x28,0x47,0xaa,0x9a,0x8e,0x25,0xb7,0x93,0x28,0x04,0xa6,0x9c,0xb8,0x10}, + {0x9c,0x28,0x18,0x97,0x49,0x47,0x59,0x3d,0x26,0x3f,0x53,0x24,0xc5,0xf8,0xeb,0x12,0x15,0xef,0xc3,0x14,0xcb,0xbf,0x62,0x02,0x8e,0x51,0xb7,0x77,0xd5,0x78,0xb8,0x20,0x6e,0xf0,0x45,0x5a,0xbe,0x41,0x39,0x75,0x65,0x5f,0x9c,0x6d,0xed,0xae,0x7c,0xd0,0xb6,0x51,0xff,0x72,0x9c,0x6b,0x77,0x11,0xa9,0x4d,0x0d,0xef,0xd9,0xd1,0xd2,0x17,0x6a,0x3e,0x3f,0x07,0x18,0xaf,0xf2,0x27,0x69,0x10,0x52,0xd7,0x19,0xe5,0x3f,0xfd,0x22,0x00,0xa6,0x3c,0x2c,0xb7,0xe3,0x22,0xa7,0xc6,0x65,0xcc,0x63,0x4f,0x21,0x72}, + {0x93,0xa6,0x07,0x53,0x40,0x7f,0xe3,0xb4,0x95,0x67,0x33,0x2f,0xd7,0x14,0xa7,0xab,0x99,0x10,0x76,0x73,0xa7,0xd0,0xfb,0xd6,0xc9,0xcb,0x71,0x81,0xc5,0x48,0xdf,0x5f,0xc9,0x29,0x3b,0xf4,0xb9,0xb7,0x9d,0x1d,0x75,0x8f,0x51,0x4f,0x4a,0x82,0x05,0xd6,0xc4,0x9d,0x2f,0x31,0xbd,0x72,0xc0,0xf2,0xb0,0x45,0x15,0x5a,0x85,0xac,0x24,0x1f,0xaa,0x05,0x95,0x8e,0x32,0x08,0xd6,0x24,0xee,0x20,0x14,0x0c,0xd1,0xc1,0x48,0x47,0xa2,0x25,0xfb,0x06,0x5c,0xe4,0xff,0xc7,0xe6,0x95,0xe3,0x2a,0x9e,0x73,0xba,0x00}, + {0xd6,0x90,0x87,0x5c,0xde,0x98,0x2e,0x59,0xdf,0xa2,0xc2,0x45,0xd3,0xb7,0xbf,0xe5,0x22,0x99,0xb4,0xf9,0x60,0x3b,0x5a,0x11,0xf3,0x78,0xad,0x67,0x3e,0x3a,0x28,0x03,0x26,0xbb,0x88,0xea,0xf5,0x26,0x44,0xae,0xfb,0x3b,0x97,0x84,0xd9,0x79,0x06,0x36,0x50,0x4e,0x69,0x26,0x0c,0x03,0x9f,0x5c,0x26,0xd2,0x18,0xd5,0xe7,0x7d,0x29,0x72,0x39,0xb9,0x0c,0xbe,0xc7,0x1d,0x24,0x48,0x80,0x30,0x63,0x8b,0x4d,0x9b,0xf1,0x32,0x08,0x93,0x28,0x02,0x0d,0xc9,0xdf,0xd3,0x45,0x19,0x27,0x46,0x68,0x29,0xe1,0x05}, + {0x5a,0x49,0x9c,0x2d,0xb3,0xee,0x82,0xba,0x7c,0xb9,0x2b,0xf1,0xfc,0xc8,0xef,0xce,0xe0,0xd1,0xb5,0x93,0xae,0xab,0x2d,0xb0,0x9b,0x8d,0x69,0x13,0x9c,0x0c,0xc0,0x39,0x50,0x45,0x2c,0x24,0xc8,0xbb,0xbf,0xad,0xd9,0x81,0x30,0xd0,0xec,0x0c,0xc8,0xbc,0x92,0xdf,0xc8,0xf5,0xa6,0x66,0x35,0x84,0x4c,0xce,0x58,0x82,0xd3,0x25,0xcf,0x78,0x68,0x9d,0x48,0x31,0x8e,0x6b,0xae,0x15,0x87,0xf0,0x2b,0x9c,0xab,0x1c,0x85,0xaa,0x05,0xfa,0x4e,0xf0,0x97,0x5a,0xa7,0xc9,0x32,0xf8,0x3f,0x6b,0x07,0x52,0x6b,0x00}, + {0x1c,0x78,0x95,0x9d,0xe1,0xcf,0xe0,0x29,0xe2,0x10,0x63,0x96,0x18,0xdf,0x81,0xb6,0x39,0x6b,0x51,0x70,0xd3,0x39,0xdf,0x57,0x22,0x61,0xc7,0x3b,0x44,0xe3,0x57,0x4d,0x2d,0x08,0xce,0xb9,0x16,0x7e,0xcb,0xf5,0x29,0xbc,0x7a,0x41,0x4c,0xf1,0x07,0x34,0xab,0xa7,0xf4,0x2b,0xce,0x6b,0xb3,0xd4,0xce,0x75,0x9f,0x1a,0x56,0xe9,0xe2,0x7d,0xcb,0x5e,0xa5,0xb6,0xf4,0xd4,0x70,0xde,0x99,0xdb,0x85,0x5d,0x7f,0x52,0x01,0x48,0x81,0x9a,0xee,0xd3,0x40,0xc4,0xc9,0xdb,0xed,0x29,0x60,0x1a,0xaf,0x90,0x2a,0x6b}, + {0x97,0x1e,0xe6,0x9a,0xfc,0xf4,0x23,0x69,0xd1,0x5f,0x3f,0xe0,0x1d,0x28,0x35,0x57,0x2d,0xd1,0xed,0xe6,0x43,0xae,0x64,0xa7,0x4a,0x3e,0x2d,0xd1,0xe9,0xf4,0xd8,0x5f,0x0a,0xd8,0xb2,0x5b,0x24,0xf3,0xeb,0x77,0x9b,0x07,0xb9,0x2f,0x47,0x1b,0x30,0xd8,0x33,0x73,0xee,0x4c,0xf2,0xe6,0x47,0xc6,0x09,0x21,0x6c,0x27,0xc8,0x12,0x58,0x46,0xd9,0x62,0x10,0x2a,0xb2,0xbe,0x43,0x4d,0x16,0xdc,0x31,0x38,0x75,0xfb,0x65,0x70,0xd7,0x68,0x29,0xde,0x7b,0x4a,0x0d,0x18,0x90,0x67,0xb1,0x1c,0x2b,0x2c,0xb3,0x05}, + {0xfd,0xa8,0x4d,0xd2,0xcc,0x5e,0xc0,0xc8,0x83,0xef,0xdf,0x05,0xac,0x1a,0xcf,0xa1,0x61,0xcd,0xf9,0x7d,0xf2,0xef,0xbe,0xdb,0x99,0x1e,0x47,0x7b,0xa3,0x56,0x55,0x3b,0x95,0x81,0xd5,0x7a,0x2c,0xa4,0xfc,0xf7,0xcc,0xf3,0x33,0x43,0x6e,0x28,0x14,0x32,0x9d,0x97,0x0b,0x34,0x0d,0x9d,0xc2,0xb6,0xe1,0x07,0x73,0x56,0x48,0x1a,0x77,0x31,0x82,0xd4,0x4d,0xe1,0x24,0xc5,0xb0,0x32,0xb6,0xa4,0x2b,0x1a,0x54,0x51,0xb3,0xed,0xf3,0x5a,0x2b,0x28,0x48,0x60,0xd1,0xa3,0xeb,0x36,0x73,0x7a,0xd2,0x79,0xc0,0x4f}, + {0x7f,0x2f,0xbf,0x89,0xb0,0x38,0xc9,0x51,0xa7,0xe9,0xdf,0x02,0x65,0xbd,0x97,0x24,0x53,0xe4,0x80,0x78,0x9c,0xc0,0xff,0xff,0x92,0x8e,0xf9,0xca,0xce,0x67,0x45,0x12,0x0d,0xc5,0x86,0x0c,0x44,0x8b,0x34,0xdc,0x51,0xe6,0x94,0xcc,0xc9,0xcb,0x37,0x13,0xb9,0x3c,0x3e,0x64,0x4d,0xf7,0x22,0x64,0x08,0xcd,0xe3,0xba,0xc2,0x70,0x11,0x24,0xb4,0x73,0xc4,0x0a,0x86,0xab,0xf9,0x3f,0x35,0xe4,0x13,0x01,0xee,0x1d,0x91,0xf0,0xaf,0xc4,0xc6,0xeb,0x60,0x50,0xe7,0x4a,0x0d,0x00,0x87,0x6c,0x96,0x12,0x86,0x3f}, + {0xde,0x0d,0x2a,0x78,0xc9,0x0c,0x9a,0x55,0x85,0x83,0x71,0xea,0xb2,0xcd,0x1d,0x55,0x8c,0x23,0xef,0x31,0x5b,0x86,0x62,0x7f,0x3d,0x61,0x73,0x79,0x76,0xa7,0x4a,0x50,0x13,0x8d,0x04,0x36,0xfa,0xfc,0x18,0x9c,0xdd,0x9d,0x89,0x73,0xb3,0x9d,0x15,0x29,0xaa,0xd0,0x92,0x9f,0x0b,0x35,0x9f,0xdc,0xd4,0x19,0x8a,0x87,0xee,0x7e,0xf5,0x26,0xb1,0xef,0x87,0x56,0xd5,0x2c,0xab,0x0c,0x7b,0xf1,0x7a,0x24,0x62,0xd1,0x80,0x51,0x67,0x24,0x5a,0x4f,0x34,0x5a,0xc1,0x85,0x69,0x30,0xba,0x9d,0x3d,0x94,0x41,0x40}, + {0x96,0xcc,0xeb,0x43,0xba,0xee,0xc0,0xc3,0xaf,0x9c,0xea,0x26,0x9c,0x9c,0x74,0x8d,0xc6,0xcc,0x77,0x1c,0xee,0x95,0xfa,0xd9,0x0f,0x34,0x84,0x76,0xd9,0xa1,0x20,0x14,0xdd,0xaa,0x6c,0xa2,0x43,0x77,0x21,0x4b,0xce,0xb7,0x8a,0x64,0x24,0xb4,0xa6,0x47,0xe3,0xc9,0xfb,0x03,0x7a,0x4f,0x1d,0xcb,0x19,0xd0,0x00,0x98,0x42,0x31,0xd9,0x12,0x4f,0x59,0x37,0xd3,0x99,0x77,0xc6,0x00,0x7b,0xa4,0x3a,0xb2,0x40,0x51,0x3c,0x5e,0x95,0xf3,0x5f,0xe3,0x54,0x28,0x18,0x44,0x12,0xa0,0x59,0x43,0x31,0x92,0x4f,0x1b}, + {0x51,0x09,0x15,0x89,0x9d,0x10,0x5c,0x3e,0x6a,0x69,0xe9,0x2d,0x91,0xfa,0xce,0x39,0x20,0x30,0x5f,0x97,0x3f,0xe4,0xea,0x20,0xae,0x2d,0x13,0x7f,0x2a,0x57,0x9b,0x23,0xb1,0x66,0x98,0xa4,0x30,0x30,0xcf,0x33,0x59,0x48,0x5f,0x21,0xd2,0x73,0x1f,0x25,0xf6,0xf4,0xde,0x51,0x40,0xaa,0x82,0xab,0xf6,0x23,0x9a,0x6f,0xd5,0x91,0xf1,0x5f,0x68,0x90,0x2d,0xac,0x33,0xd4,0x9e,0x81,0x23,0x85,0xc9,0x5f,0x79,0xab,0x83,0x28,0x3d,0xeb,0x93,0x55,0x80,0x72,0x45,0xef,0xcb,0x36,0x8f,0x75,0x6a,0x52,0x0c,0x02}, + {0xbc,0xdb,0xd8,0x9e,0xf8,0x34,0x98,0x77,0x6c,0xa4,0x7c,0xdc,0xf9,0xaa,0xf2,0xc8,0x74,0xb0,0xe1,0xa3,0xdc,0x4c,0x52,0xa9,0x77,0x38,0x31,0x15,0x46,0xcc,0xaa,0x02,0x89,0xcc,0x42,0xf0,0x59,0xef,0x31,0xe9,0xb6,0x4b,0x12,0x8e,0x9d,0x9c,0x58,0x2c,0x97,0x59,0xc7,0xae,0x8a,0xe1,0xc8,0xad,0x0c,0xc5,0x02,0x56,0x0a,0xfe,0x2c,0x45,0xdf,0x77,0x78,0x64,0xa0,0xf7,0xa0,0x86,0x9f,0x7c,0x60,0x0e,0x27,0x64,0xc4,0xbb,0xc9,0x11,0xfb,0xf1,0x25,0xea,0x17,0xab,0x7b,0x87,0x4b,0x30,0x7b,0x7d,0xfb,0x4c}, + {0xfe,0x75,0x9b,0xb8,0x6c,0x3d,0xb4,0x72,0x80,0xdc,0x6a,0x9c,0xd9,0x94,0xc6,0x54,0x9f,0x4c,0xe3,0x3e,0x37,0xaa,0xc3,0xb8,0x64,0x53,0x07,0x39,0x2b,0x62,0xb4,0x14,0x12,0xef,0x89,0x97,0xc2,0x99,0x86,0xe2,0x0d,0x19,0x57,0xdf,0x71,0xcd,0x6e,0x2b,0xd0,0x70,0xc9,0xec,0x57,0xc8,0x43,0xc3,0xc5,0x3a,0x4d,0x43,0xbc,0x4c,0x1d,0x5b,0x26,0x9f,0x0a,0xcc,0x15,0x26,0xfb,0xb6,0xe5,0xcc,0x8d,0xb8,0x2b,0x0e,0x4f,0x3a,0x05,0xa7,0x69,0x33,0x8b,0x49,0x01,0x13,0xd1,0x2d,0x59,0x58,0x12,0xf7,0x98,0x2f}, + {0x56,0x9e,0x0f,0xb5,0x4c,0xa7,0x94,0x0c,0x20,0x13,0x8e,0x8e,0xa9,0xf4,0x1f,0x5b,0x67,0x0f,0x30,0x82,0x21,0xcc,0x2a,0x9a,0xf9,0xaa,0x06,0xd8,0x49,0xe2,0x6a,0x3a,0x01,0xa7,0x54,0x4f,0x44,0xae,0x12,0x2e,0xde,0xd7,0xcb,0xa9,0xf0,0x3e,0xfe,0xfc,0xe0,0x5d,0x83,0x75,0x0d,0x89,0xbf,0xce,0x54,0x45,0x61,0xe7,0xe9,0x62,0x80,0x1d,0x5a,0x7c,0x90,0xa9,0x85,0xda,0x7a,0x65,0x62,0x0f,0xb9,0x91,0xb5,0xa8,0x0e,0x1a,0xe9,0xb4,0x34,0xdf,0xfb,0x1d,0x0e,0x8d,0xf3,0x5f,0xf2,0xae,0xe8,0x8c,0x8b,0x29}, + {0xb2,0x0c,0xf7,0xef,0x53,0x79,0x92,0x2a,0x76,0x70,0x15,0x79,0x2a,0xc9,0x89,0x4b,0x6a,0xcf,0xa7,0x30,0x7a,0x45,0x18,0x94,0x85,0xe4,0x5c,0x4d,0x40,0xa8,0xb8,0x34,0xde,0x65,0x21,0x0a,0xea,0x72,0x7a,0x83,0xf6,0x79,0xcf,0x0b,0xb4,0x07,0xab,0x3f,0x70,0xae,0x38,0x77,0xc7,0x36,0x16,0x52,0xdc,0xd7,0xa7,0x03,0x18,0x27,0xa6,0x6b,0x35,0x33,0x69,0x83,0xb5,0xec,0x6e,0xc2,0xfd,0xfe,0xb5,0x63,0xdf,0x13,0xa8,0xd5,0x73,0x25,0xb2,0xa4,0x9a,0xaa,0x93,0xa2,0x6a,0x1c,0x5e,0x46,0xdd,0x2b,0xd6,0x71}, + {0x80,0xdf,0x78,0xd3,0x28,0xcc,0x33,0x65,0xb4,0xa4,0x0f,0x0a,0x79,0x43,0xdb,0xf6,0x5a,0xda,0x01,0xf7,0xf9,0x5f,0x64,0xe3,0xa4,0x2b,0x17,0xf3,0x17,0xf3,0xd5,0x74,0xf5,0x5e,0xf7,0xb1,0xda,0xb5,0x2d,0xcd,0xf5,0x65,0xb0,0x16,0xcf,0x95,0x7f,0xd7,0x85,0xf0,0x49,0x3f,0xea,0x1f,0x57,0x14,0x3d,0x2b,0x2b,0x26,0x21,0x36,0x33,0x1c,0x81,0xca,0xd9,0x67,0x54,0xe5,0x6f,0xa8,0x37,0x8c,0x29,0x2b,0x75,0x7c,0x8b,0x39,0x3b,0x62,0xac,0xe3,0x92,0x08,0x6d,0xda,0x8c,0xd9,0xe9,0x47,0x45,0xcc,0xeb,0x4a}, + {0xc9,0x01,0x6d,0x27,0x1b,0x07,0xf0,0x12,0x70,0x8c,0xc4,0x86,0xc5,0xba,0xb8,0xe7,0xa9,0xfb,0xd6,0x71,0x9b,0x12,0x08,0x53,0x92,0xb7,0x3d,0x5a,0xf9,0xfb,0x88,0x5d,0x10,0xb6,0x54,0x73,0x9e,0x8d,0x40,0x0b,0x6e,0x5b,0xa8,0x5b,0x53,0x32,0x6b,0x80,0x07,0xa2,0x58,0x4a,0x03,0x3a,0xe6,0xdb,0x2c,0xdf,0xa1,0xc9,0xdd,0xd9,0x3b,0x17,0xdf,0x72,0x58,0xfe,0x1e,0x0f,0x50,0x2b,0xc1,0x18,0x39,0xd4,0x2e,0x58,0xd6,0x58,0xe0,0x3a,0x67,0xc9,0x8e,0x27,0xed,0xe6,0x19,0xa3,0x9e,0xb1,0x13,0xcd,0xe1,0x06}, + {0x23,0x6f,0x16,0x6f,0x51,0xad,0xd0,0x40,0xbe,0x6a,0xab,0x1f,0x93,0x32,0x8e,0x11,0x8e,0x08,0x4d,0xa0,0x14,0x5e,0xe3,0x3f,0x66,0x62,0xe1,0x26,0x35,0x60,0x80,0x30,0x53,0x03,0x5b,0x9e,0x62,0xaf,0x2b,0x47,0x47,0x04,0x8d,0x27,0x90,0x0b,0xaa,0x3b,0x27,0xbf,0x43,0x96,0x46,0x5f,0x78,0x0c,0x13,0x7b,0x83,0x8d,0x1a,0x6a,0x3a,0x7f,0x0b,0x80,0x3d,0x5d,0x39,0x44,0xe6,0xf7,0xf6,0xed,0x01,0xc9,0x55,0xd5,0xa8,0x95,0x39,0x63,0x2c,0x59,0x30,0x78,0xcd,0x68,0x7e,0x30,0x51,0x2e,0xed,0xfd,0xd0,0x30}, + {0xb3,0x33,0x12,0xf2,0x1a,0x4d,0x59,0xe0,0x9c,0x4d,0xcc,0xf0,0x8e,0xe7,0xdb,0x1b,0x77,0x9a,0x49,0x8f,0x7f,0x18,0x65,0x69,0x68,0x98,0x09,0x2c,0x20,0x14,0x92,0x0a,0x50,0x47,0xb8,0x68,0x1e,0x97,0xb4,0x9c,0xcf,0xbb,0x64,0x66,0x29,0x72,0x95,0xa0,0x2b,0x41,0xfa,0x72,0x26,0xe7,0x8d,0x5c,0xd9,0x89,0xc5,0x51,0x43,0x08,0x15,0x46,0x2e,0xa0,0xb9,0xae,0xc0,0x19,0x90,0xbc,0xae,0x4c,0x03,0x16,0x0d,0x11,0xc7,0x55,0xec,0x32,0x99,0x65,0x01,0xf5,0x6d,0x0e,0xfe,0x5d,0xca,0x95,0x28,0x0d,0xca,0x3b}, + {0xa4,0x62,0x5d,0x3c,0xbc,0x31,0xf0,0x40,0x60,0x7a,0xf0,0xcf,0x3e,0x8b,0xfc,0x19,0x45,0xb5,0x0f,0x13,0xa2,0x3d,0x18,0x98,0xcd,0x13,0x8f,0xae,0xdd,0xde,0x31,0x56,0xbf,0x01,0xcc,0x9e,0xb6,0x8e,0x68,0x9c,0x6f,0x89,0x44,0xa6,0xad,0x83,0xbc,0xf0,0xe2,0x9f,0x7a,0x5f,0x5f,0x95,0x2d,0xca,0x41,0x82,0xf2,0x8d,0x03,0xb4,0xa8,0x4e,0x02,0xd2,0xca,0xf1,0x0a,0x46,0xed,0x2a,0x83,0xee,0x8c,0xa4,0x05,0x53,0x30,0x46,0x5f,0x1a,0xf1,0x49,0x45,0x77,0x21,0x91,0x63,0xa4,0x2c,0x54,0x30,0x09,0xce,0x24}, + {0x06,0xc1,0x06,0xfd,0xf5,0x90,0xe8,0x1f,0xf2,0x10,0x88,0x5d,0x35,0x68,0xc4,0xb5,0x3e,0xaf,0x8c,0x6e,0xfe,0x08,0x78,0x82,0x4b,0xd7,0x06,0x8a,0xc2,0xe3,0xd4,0x41,0x85,0x0b,0xf3,0xfd,0x55,0xa1,0xcf,0x3f,0xa4,0x2e,0x37,0x36,0x8e,0x16,0xf7,0xd2,0x44,0xf8,0x92,0x64,0xde,0x64,0xe0,0xb2,0x80,0x42,0x4f,0x32,0xa7,0x28,0x99,0x54,0x2e,0x1a,0xee,0x63,0xa7,0x32,0x6e,0xf2,0xea,0xfd,0x5f,0xd2,0xb7,0xe4,0x91,0xae,0x69,0x4d,0x7f,0xd1,0x3b,0xd3,0x3b,0xbc,0x6a,0xff,0xdc,0xc0,0xde,0x66,0x1b,0x49}, + {0xa7,0x32,0xea,0xc7,0x3d,0xb1,0xf5,0x98,0x98,0xdb,0x16,0x7e,0xcc,0xf8,0xd5,0xe3,0x47,0xd9,0xf8,0xcb,0x52,0xbf,0x0a,0xac,0xac,0xe4,0x5e,0xc8,0xd0,0x38,0xf3,0x08,0xa1,0x64,0xda,0xd0,0x8e,0x4a,0xf0,0x75,0x4b,0x28,0xe2,0x67,0xaf,0x2c,0x22,0xed,0xa4,0x7b,0x7b,0x1f,0x79,0xa3,0x34,0x82,0x67,0x8b,0x01,0xb7,0xb0,0xb8,0xf6,0x4c,0xbd,0x73,0x1a,0x99,0x21,0xa8,0x83,0xc3,0x7a,0x0c,0x32,0xdf,0x01,0xbc,0x27,0xab,0x63,0x70,0x77,0x84,0x1b,0x33,0x3d,0xc1,0x99,0x8a,0x07,0xeb,0x82,0x4a,0x0d,0x53}, + {0x25,0x48,0xf9,0xe1,0x30,0x36,0x4c,0x00,0x5a,0x53,0xab,0x8c,0x26,0x78,0x2d,0x7e,0x8b,0xff,0x84,0xcc,0x23,0x23,0x48,0xc7,0xb9,0x70,0x17,0x10,0x3f,0x75,0xea,0x65,0x9e,0xbf,0x9a,0x6c,0x45,0x73,0x69,0x6d,0x80,0xa8,0x00,0x49,0xfc,0xb2,0x7f,0x25,0x50,0xb8,0xcf,0xc8,0x12,0xf4,0xac,0x2b,0x5b,0xbd,0xbf,0x0c,0xe0,0xe7,0xb3,0x0d,0x63,0x63,0x09,0xe2,0x3e,0xfc,0x66,0x3d,0x6b,0xcb,0xb5,0x61,0x7f,0x2c,0xd6,0x81,0x1a,0x3b,0x44,0x13,0x42,0x04,0xbe,0x0f,0xdb,0xa1,0xe1,0x21,0x19,0xec,0xa4,0x02}, + {0xa2,0xb8,0x24,0x3b,0x9a,0x25,0xe6,0x5c,0xb8,0xa0,0xaf,0x45,0xcc,0x7a,0x57,0xb8,0x37,0x70,0xa0,0x8b,0xe8,0xe6,0xcb,0xcc,0xbf,0x09,0x78,0x12,0x51,0x3c,0x14,0x3d,0x5f,0x79,0xcf,0xf1,0x62,0x61,0xc8,0xf5,0xf2,0x57,0xee,0x26,0x19,0x86,0x8c,0x11,0x78,0x35,0x06,0x1c,0x85,0x24,0x21,0x17,0xcf,0x7f,0x06,0xec,0x5d,0x2b,0xd1,0x36,0x57,0x45,0x15,0x79,0x91,0x27,0x6d,0x12,0x0a,0x3a,0x78,0xfc,0x5c,0x8f,0xe4,0xd5,0xac,0x9b,0x17,0xdf,0xe8,0xb6,0xbd,0x36,0x59,0x28,0xa8,0x5b,0x88,0x17,0xf5,0x2e}, + {0xdc,0xae,0x58,0x8c,0x4e,0x97,0x37,0x46,0xa4,0x41,0xf0,0xab,0xfb,0x22,0xef,0xb9,0x8a,0x71,0x80,0xe9,0x56,0xd9,0x85,0xe1,0xa6,0xa8,0x43,0xb1,0xfa,0x78,0x1b,0x2f,0x51,0x2f,0x5b,0x30,0xfb,0xbf,0xee,0x96,0xb8,0x96,0x95,0x88,0xad,0x38,0xf9,0xd3,0x25,0xdd,0xd5,0x46,0xc7,0x2d,0xf5,0xf0,0x95,0x00,0x3a,0xbb,0x90,0x82,0x96,0x57,0x01,0xe1,0x20,0x0a,0x43,0xb8,0x1a,0xf7,0x47,0xec,0xf0,0x24,0x8d,0x65,0x93,0xf3,0xd1,0xee,0xe2,0x6e,0xa8,0x09,0x75,0xcf,0xe1,0xa3,0x2a,0xdc,0x35,0x3e,0xc4,0x7d}, + {0xc3,0xd9,0x7d,0x88,0x65,0x66,0x96,0x85,0x55,0x53,0xb0,0x4b,0x31,0x9b,0x0f,0xc9,0xb1,0x79,0x20,0xef,0xf8,0x8d,0xe0,0xc6,0x2f,0xc1,0x8c,0x75,0x16,0x20,0xf7,0x7e,0x18,0x97,0x3e,0x27,0x5c,0x2a,0x78,0x5a,0x94,0xfd,0x4e,0x5e,0x99,0xc6,0x76,0x35,0x3e,0x7d,0x23,0x1f,0x05,0xd8,0x2e,0x0f,0x99,0x0a,0xd5,0x82,0x1d,0xb8,0x4f,0x04,0xd9,0xe3,0x07,0xa9,0xc5,0x18,0xdf,0xc1,0x59,0x63,0x4c,0xce,0x1d,0x37,0xb3,0x57,0x49,0xbb,0x01,0xb2,0x34,0x45,0x70,0xca,0x2e,0xdd,0x30,0x9c,0x3f,0x82,0x79,0x7f}, + {0xe8,0x13,0xb5,0xa3,0x39,0xd2,0x34,0x83,0xd8,0xa8,0x1f,0xb9,0xd4,0x70,0x36,0xc1,0x33,0xbd,0x90,0xf5,0x36,0x41,0xb5,0x12,0xb4,0xd9,0x84,0xd7,0x73,0x03,0x4e,0x0a,0xba,0x87,0xf5,0x68,0xf0,0x1f,0x9c,0x6a,0xde,0xc8,0x50,0x00,0x4e,0x89,0x27,0x08,0xe7,0x5b,0xed,0x7d,0x55,0x99,0xbf,0x3c,0xf0,0xd6,0x06,0x1c,0x43,0xb0,0xa9,0x64,0x19,0x29,0x7d,0x5b,0xa1,0xd6,0xb3,0x2e,0x35,0x82,0x3a,0xd5,0xa0,0xf6,0xb4,0xb0,0x47,0x5d,0xa4,0x89,0x43,0xce,0x56,0x71,0x6c,0x34,0x18,0xce,0x0a,0x7d,0x1a,0x07}, + {0x0b,0xba,0x87,0xc8,0xaa,0x2d,0x07,0xd3,0xee,0x62,0xa5,0xbf,0x05,0x29,0x26,0x01,0x8b,0x76,0xef,0xc0,0x02,0x30,0x54,0xcf,0x9c,0x7e,0xea,0x46,0x71,0xcc,0x3b,0x2c,0x31,0x44,0xe1,0x20,0x52,0x35,0x0c,0xcc,0x41,0x51,0xb1,0x09,0x07,0x95,0x65,0x0d,0x36,0x5f,0x9d,0x20,0x1b,0x62,0xf5,0x9a,0xd3,0x55,0x77,0x61,0xf7,0xbc,0x69,0x7c,0x5f,0x29,0xe8,0x04,0xeb,0xd7,0xf0,0x07,0x7d,0xf3,0x50,0x2f,0x25,0x18,0xdb,0x10,0xd7,0x98,0x17,0x17,0xa3,0xa9,0x51,0xe9,0x1d,0xa5,0xac,0x22,0x73,0x9a,0x5a,0x6f}, + {0xc5,0xc6,0x41,0x2f,0x0c,0x00,0xa1,0x8b,0x9b,0xfb,0xfe,0x0c,0xc1,0x79,0x9f,0xc4,0x9f,0x1c,0xc5,0x3c,0x70,0x47,0xfa,0x4e,0xca,0xaf,0x47,0xe1,0xa2,0x21,0x4e,0x49,0xbe,0x44,0xd9,0xa3,0xeb,0xd4,0x29,0xe7,0x9e,0xaf,0x78,0x80,0x40,0x09,0x9e,0x8d,0x03,0x9c,0x86,0x47,0x7a,0x56,0x25,0x45,0x24,0x3b,0x8d,0xee,0x80,0x96,0xab,0x02,0x9a,0x0d,0xe5,0xdd,0x85,0x8a,0xa4,0xef,0x49,0xa2,0xb9,0x0f,0x4e,0x22,0x9a,0x21,0xd9,0xf6,0x1e,0xd9,0x1d,0x1f,0x09,0xfa,0x34,0xbb,0x46,0xea,0xcb,0x76,0x5d,0x6b}, + {0x94,0xd9,0x0c,0xec,0x6c,0x55,0x57,0x88,0xba,0x1d,0xd0,0x5c,0x6f,0xdc,0x72,0x64,0x77,0xb4,0x42,0x8f,0x14,0x69,0x01,0xaf,0x54,0x73,0x27,0x85,0xf6,0x33,0xe3,0x0a,0x22,0x25,0x78,0x1e,0x17,0x41,0xf9,0xe0,0xd3,0x36,0x69,0x03,0x74,0xae,0xe6,0xf1,0x46,0xc7,0xfc,0xd0,0xa2,0x3e,0x8b,0x40,0x3e,0x31,0xdd,0x03,0x9c,0x86,0xfb,0x16,0x62,0x09,0xb6,0x33,0x97,0x19,0x8e,0x28,0x33,0xe1,0xab,0xd8,0xb4,0x72,0xfc,0x24,0x3e,0xd0,0x91,0x09,0xed,0xf7,0x11,0x48,0x75,0xd0,0x70,0x8f,0x8b,0xe3,0x81,0x3f}, + {0xfe,0xaf,0xd9,0x7e,0xcc,0x0f,0x91,0x7f,0x4b,0x87,0x65,0x24,0xa1,0xb8,0x5c,0x54,0x04,0x47,0x0c,0x4b,0xd2,0x7e,0x39,0xa8,0x93,0x09,0xf5,0x04,0xc1,0x0f,0x51,0x50,0x24,0xc8,0x17,0x5f,0x35,0x7f,0xdb,0x0a,0xa4,0x99,0x42,0xd7,0xc3,0x23,0xb9,0x74,0xf7,0xea,0xf8,0xcb,0x8b,0x3e,0x7c,0xd5,0x3d,0xdc,0xde,0x4c,0xd3,0xe2,0xd3,0x0a,0x9d,0x24,0x6e,0x33,0xc5,0x0f,0x0c,0x6f,0xd9,0xcf,0x31,0xc3,0x19,0xde,0x5e,0x74,0x1c,0xfe,0xee,0x09,0x00,0xfd,0xd6,0xf2,0xbe,0x1e,0xfa,0xf0,0x8b,0x15,0x7c,0x12}, + {0xa2,0x79,0x98,0x2e,0x42,0x7c,0x19,0xf6,0x47,0x36,0xca,0x52,0xd4,0xdd,0x4a,0xa4,0xcb,0xac,0x4e,0x4b,0xc1,0x3f,0x41,0x9b,0x68,0x4f,0xef,0x07,0x7d,0xf8,0x4e,0x35,0x74,0xb9,0x51,0xae,0xc4,0x8f,0xa2,0xde,0x96,0xfe,0x4d,0x74,0xd3,0x73,0x99,0x1d,0xa8,0x48,0x38,0x87,0x0b,0x68,0x40,0x62,0x95,0xdf,0x67,0xd1,0x79,0x24,0xd8,0x4e,0x75,0xd9,0xc5,0x60,0x22,0xb5,0xe3,0xfe,0xb8,0xb0,0x41,0xeb,0xfc,0x2e,0x35,0x50,0x3c,0x65,0xf6,0xa9,0x30,0xac,0x08,0x88,0x6d,0x23,0x39,0x05,0xd2,0x92,0x2d,0x30}, + {0x3d,0x28,0xa4,0xbc,0xa2,0xc1,0x13,0x78,0xd9,0x3d,0x86,0xa1,0x91,0xf0,0x62,0xed,0x86,0xfa,0x68,0xc2,0xb8,0xbc,0xc7,0xae,0x4c,0xae,0x1c,0x6f,0xb7,0xd3,0xe5,0x10,0x77,0xf1,0xe0,0xe4,0xb6,0x6f,0xbc,0x2d,0x93,0x6a,0xbd,0xa4,0x29,0xbf,0xe1,0x04,0xe8,0xf6,0x7a,0x78,0xd4,0x66,0x19,0x5e,0x60,0xd0,0x26,0xb4,0x5e,0x5f,0xdc,0x0e,0x67,0x8e,0xda,0x53,0xd6,0xbf,0x53,0x54,0x41,0xf6,0xa9,0x24,0xec,0x1e,0xdc,0xe9,0x23,0x8a,0x57,0x03,0x3b,0x26,0x87,0xbf,0x72,0xba,0x1c,0x36,0x51,0x6c,0xb4,0x45}, + {0xa1,0x7f,0x4f,0x31,0xbf,0x2a,0x40,0xa9,0x50,0xf4,0x8c,0x8e,0xdc,0xf1,0x57,0xe2,0x84,0xbe,0xa8,0x23,0x4b,0xd5,0xbb,0x1d,0x3b,0x71,0xcb,0x6d,0xa3,0xbf,0x77,0x21,0xe4,0xe3,0x7f,0x8a,0xdd,0x4d,0x9d,0xce,0x30,0x0e,0x62,0x76,0x56,0x64,0x13,0xab,0x58,0x99,0x0e,0xb3,0x7b,0x4f,0x59,0x4b,0xdf,0x29,0x12,0x32,0xef,0x0a,0x1c,0x5c,0x8f,0xdb,0x79,0xfa,0xbc,0x1b,0x08,0x37,0xb3,0x59,0x5f,0xc2,0x1e,0x81,0x48,0x60,0x87,0x24,0x83,0x9c,0x65,0x76,0x7a,0x08,0xbb,0xb5,0x8a,0x7d,0x38,0x19,0xe6,0x4a}, + {0x2e,0xa3,0x44,0x53,0xaa,0xf6,0xdb,0x8d,0x78,0x40,0x1b,0xb4,0xb4,0xea,0x88,0x7d,0x60,0x0d,0x13,0x4a,0x97,0xeb,0xb0,0x5e,0x03,0x3e,0xbf,0x17,0x1b,0xd9,0x00,0x1a,0x83,0xfb,0x5b,0x98,0x44,0x7e,0x11,0x61,0x36,0x31,0x96,0x71,0x2a,0x46,0xe0,0xfc,0x4b,0x90,0x25,0xd4,0x48,0x34,0xac,0x83,0x64,0x3d,0xa4,0x5b,0xbe,0x5a,0x68,0x75,0xb2,0xf2,0x61,0xeb,0x33,0x09,0x96,0x6e,0x52,0x49,0xff,0xc9,0xa8,0x0f,0x3d,0x54,0x69,0x65,0xf6,0x7a,0x10,0x75,0x72,0xdf,0xaa,0xe6,0xb0,0x23,0xb6,0x29,0x55,0x13}, + {0x18,0xd5,0xd1,0xad,0xd7,0xdb,0xf0,0x18,0x11,0x1f,0xc1,0xcf,0x88,0x78,0x9f,0x97,0x9b,0x75,0x14,0x71,0xf0,0xe1,0x32,0x87,0x01,0x3a,0xca,0x65,0x1a,0xb8,0xb5,0x79,0xfe,0x83,0x2e,0xe2,0xbc,0x16,0xc7,0xf5,0xc1,0x85,0x09,0xe8,0x19,0xeb,0x2b,0xb4,0xae,0x4a,0x25,0x14,0x37,0xa6,0x9d,0xec,0x13,0xa6,0x90,0x15,0x05,0xea,0x72,0x59,0x11,0x78,0x8f,0xdc,0x20,0xac,0xd4,0x0f,0xa8,0x4f,0x4d,0xac,0x94,0xd2,0x9a,0x9a,0x34,0x04,0x36,0xb3,0x64,0x2d,0x1b,0xc0,0xdb,0x3b,0x5f,0x90,0x95,0x9c,0x7e,0x4f}, + {0x2e,0x30,0x81,0x57,0xbc,0x4b,0x67,0x62,0x0f,0xdc,0xad,0x89,0x39,0x0f,0x52,0xd8,0xc6,0xd9,0xfb,0x53,0xae,0x99,0x29,0x8c,0x4c,0x8e,0x63,0x2e,0xd9,0x3a,0x99,0x31,0xfe,0x99,0x52,0x35,0x3d,0x44,0xc8,0x71,0xd7,0xea,0xeb,0xdb,0x1c,0x3b,0xcd,0x8b,0x66,0x94,0xa4,0xf1,0x9e,0x49,0x92,0x80,0xc8,0xad,0x44,0xa1,0xc4,0xee,0x42,0x19,0x92,0x49,0x23,0xae,0x19,0x53,0xac,0x7d,0x92,0x3e,0xea,0x0c,0x91,0x3d,0x1b,0x2c,0x22,0x11,0x3c,0x25,0x94,0xe4,0x3c,0x55,0x75,0xca,0xf9,0x4e,0x31,0x65,0x0a,0x2a}, + {0xc2,0x27,0xf9,0xf7,0x7f,0x93,0xb7,0x2d,0x35,0xa6,0xd0,0x17,0x06,0x1f,0x74,0xdb,0x76,0xaf,0x55,0x11,0xa2,0xf3,0x82,0x59,0xed,0x2d,0x7c,0x64,0x18,0xe2,0xf6,0x4c,0x3a,0x79,0x1c,0x3c,0xcd,0x1a,0x36,0xcf,0x3b,0xbc,0x35,0x5a,0xac,0xbc,0x9e,0x2f,0xab,0xa6,0xcd,0xa8,0xe9,0x60,0xe8,0x60,0x13,0x1a,0xea,0x6d,0x9b,0xc3,0x5d,0x05,0xb6,0x5b,0x8d,0xc2,0x7c,0x22,0x19,0xb1,0xab,0xff,0x4d,0x77,0xbc,0x4e,0xe2,0x07,0x89,0x2c,0xa3,0xe4,0xce,0x78,0x3c,0xa8,0xb6,0x24,0xaa,0x10,0x77,0x30,0x1a,0x12}, + {0x97,0x4a,0x03,0x9f,0x5e,0x5d,0xdb,0xe4,0x2d,0xbc,0x34,0x30,0x09,0xfc,0x53,0xe1,0xb1,0xd3,0x51,0x95,0x91,0x46,0x05,0x46,0x2d,0xe5,0x40,0x7a,0x6c,0xc7,0x3f,0x33,0xc9,0x83,0x74,0xc7,0x3e,0x71,0x59,0xd6,0xaf,0x96,0x2b,0xb8,0x77,0xe0,0xbf,0x88,0xd3,0xbc,0x97,0x10,0x23,0x28,0x9e,0x28,0x9b,0x3a,0xed,0x6c,0x4a,0xb9,0x7b,0x52,0x2e,0x48,0x5b,0x99,0x2a,0x99,0x3d,0x56,0x01,0x38,0x38,0x6e,0x7c,0xd0,0x05,0x34,0xe5,0xd8,0x64,0x2f,0xde,0x35,0x50,0x48,0xf7,0xa9,0xa7,0x20,0x9b,0x06,0x89,0x6b}, + {0x0d,0x22,0x70,0x62,0x41,0xa0,0x2a,0x81,0x4e,0x5b,0x24,0xf9,0xfa,0x89,0x5a,0x99,0x05,0xef,0x72,0x50,0xce,0xc4,0xad,0xff,0x73,0xeb,0x73,0xaa,0x03,0x21,0xbc,0x23,0x77,0xdb,0xc7,0xb5,0x8c,0xfa,0x82,0x40,0x55,0xc1,0x34,0xc7,0xf8,0x86,0x86,0x06,0x7e,0xa5,0xe7,0xf6,0xd9,0xc8,0xe6,0x29,0xcf,0x9b,0x63,0xa7,0x08,0xd3,0x73,0x04,0x05,0x9e,0x58,0x03,0x26,0x79,0xee,0xca,0x92,0xc4,0xdc,0x46,0x12,0x42,0x4b,0x2b,0x4f,0xa9,0x01,0xe6,0x74,0xef,0xa1,0x02,0x1a,0x34,0x04,0xde,0xbf,0x73,0x2f,0x10}, + {0xc6,0x45,0x57,0x7f,0xab,0xb9,0x18,0xeb,0x90,0xc6,0x87,0x57,0xee,0x8a,0x3a,0x02,0xa9,0xaf,0xf7,0x2d,0xda,0x12,0x27,0xb7,0x3d,0x01,0x5c,0xea,0x25,0x7d,0x59,0x36,0x9a,0x1c,0x51,0xb5,0xe0,0xda,0xb4,0xa2,0x06,0xff,0xff,0x2b,0x29,0x60,0xc8,0x7a,0x34,0x42,0x50,0xf5,0x5d,0x37,0x1f,0x98,0x2d,0xa1,0x4e,0xda,0x25,0xd7,0x6b,0x3f,0xac,0x58,0x60,0x10,0x7b,0x8d,0x4d,0x73,0x5f,0x90,0xc6,0x6f,0x9e,0x57,0x40,0xd9,0x2d,0x93,0x02,0x92,0xf9,0xf8,0x66,0x64,0xd0,0xd6,0x60,0xda,0x19,0xcc,0x7e,0x7b}, + {0x0d,0x69,0x5c,0x69,0x3c,0x37,0xc2,0x78,0x6e,0x90,0x42,0x06,0x66,0x2e,0x25,0xdd,0xd2,0x2b,0xe1,0x4a,0x44,0x44,0x1d,0x95,0x56,0x39,0x74,0x01,0x76,0xad,0x35,0x42,0x9b,0xfa,0x7c,0xa7,0x51,0x4a,0xae,0x6d,0x50,0x86,0xa3,0xe7,0x54,0x36,0x26,0x82,0xdb,0x82,0x2d,0x8f,0xcd,0xff,0xbb,0x09,0xba,0xca,0xf5,0x1b,0x66,0xdc,0xbe,0x03,0xf5,0x75,0x89,0x07,0x0d,0xcb,0x58,0x62,0x98,0xf2,0x89,0x91,0x54,0x42,0x29,0x49,0xe4,0x6e,0xe3,0xe2,0x23,0xb4,0xca,0xa0,0xa1,0x66,0xf0,0xcd,0xb0,0xe2,0x7c,0x0e}, + {0xa3,0x85,0x8c,0xc4,0x3a,0x64,0x94,0xc4,0xad,0x39,0x61,0x3c,0xf4,0x1d,0x36,0xfd,0x48,0x4d,0xe9,0x3a,0xdd,0x17,0xdb,0x09,0x4a,0x67,0xb4,0x8f,0x5d,0x0a,0x6e,0x66,0xf9,0x70,0x4b,0xd9,0xdf,0xfe,0xa6,0xfe,0x2d,0xba,0xfc,0xc1,0x51,0xc0,0x30,0xf1,0x89,0xab,0x2f,0x7f,0x7e,0xd4,0x82,0x48,0xb5,0xee,0xec,0x8a,0x13,0x56,0x52,0x61,0x0d,0xcb,0x70,0x48,0x4e,0xf6,0xbb,0x2a,0x6b,0x8b,0x45,0xaa,0xf0,0xbc,0x65,0xcd,0x5d,0x98,0xe8,0x75,0xba,0x4e,0xbe,0x9a,0xe4,0xde,0x14,0xd5,0x10,0xc8,0x0b,0x7f}, + {0x6f,0x13,0xf4,0x26,0xa4,0x6b,0x00,0xb9,0x35,0x30,0xe0,0x57,0x9e,0x36,0x67,0x8d,0x28,0x3c,0x46,0x4f,0xd9,0xdf,0xc8,0xcb,0xf5,0xdb,0xee,0xf8,0xbc,0x8d,0x1f,0x0d,0xa0,0x13,0x72,0x73,0xad,0x9d,0xac,0x83,0x98,0x2e,0xf7,0x2e,0xba,0xf8,0xf6,0x9f,0x57,0x69,0xec,0x43,0xdd,0x2e,0x1e,0x31,0x75,0xab,0xc5,0xde,0x7d,0x90,0x3a,0x1d,0xdc,0x81,0xd0,0x3e,0x31,0x93,0x16,0xba,0x80,0x34,0x1b,0x85,0xad,0x9f,0x32,0x29,0xcb,0x21,0x03,0x03,0x3c,0x01,0x28,0x01,0xe3,0xfd,0x1b,0xa3,0x44,0x1b,0x01,0x00}, + {0x0c,0x6c,0xc6,0x3f,0x6c,0xa0,0xdf,0x3f,0xd2,0x0d,0xd6,0x4d,0x8e,0xe3,0x40,0x5d,0x71,0x4d,0x8e,0x26,0x38,0x8b,0xe3,0x7a,0xe1,0x57,0x83,0x6e,0x91,0x8d,0xc4,0x3a,0x5c,0xa7,0x0a,0x6a,0x69,0x1f,0x56,0x16,0x6a,0xbd,0x52,0x58,0x5c,0x72,0xbf,0xc1,0xad,0x66,0x79,0x9a,0x7f,0xdd,0xa8,0x11,0x26,0x10,0x85,0xd2,0xa2,0x88,0xd9,0x63,0x2e,0x23,0xbd,0xaf,0x53,0x07,0x12,0x00,0x83,0xf6,0xd8,0xfd,0xb8,0xce,0x2b,0xe9,0x91,0x2b,0xe7,0x84,0xb3,0x69,0x16,0xf8,0x66,0xa0,0x68,0x23,0x2b,0xd5,0xfa,0x33}, + {0x16,0x1e,0xe4,0xc5,0xc6,0x49,0x06,0x54,0x35,0x77,0x3f,0x33,0x30,0x64,0xf8,0x0a,0x46,0xe7,0x05,0xf3,0xd2,0xfc,0xac,0xb2,0xa7,0xdc,0x56,0xa2,0x29,0xf4,0xc0,0x16,0xe8,0xcf,0x22,0xc4,0xd0,0xc8,0x2c,0x8d,0xcb,0x3a,0xa1,0x05,0x7b,0x4f,0x2b,0x07,0x6f,0xa5,0xf6,0xec,0xe6,0xb6,0xfe,0xa3,0xe2,0x71,0x0a,0xb9,0xcc,0x55,0xc3,0x3c,0x31,0x91,0x3e,0x90,0x43,0x94,0xb6,0xe9,0xce,0x37,0x56,0x7a,0xcb,0x94,0xa4,0xb8,0x44,0x92,0xba,0xba,0xa4,0xd1,0x7c,0xc8,0x68,0x75,0xae,0x6b,0x42,0xaf,0x1e,0x63}, + {0x9f,0xfe,0x66,0xda,0x10,0x04,0xe9,0xb3,0xa6,0xe5,0x16,0x6c,0x52,0x4b,0xdd,0x85,0x83,0xbf,0xf9,0x1e,0x61,0x97,0x3d,0xbc,0xb5,0x19,0xa9,0x1e,0x8b,0x64,0x99,0x55,0xe8,0x0d,0x70,0xa3,0xb9,0x75,0xd9,0x47,0x52,0x05,0xf8,0xe2,0xfb,0xc5,0x80,0x72,0xe1,0x5d,0xe4,0x32,0x27,0x8f,0x65,0x53,0xb5,0x80,0x5f,0x66,0x7f,0x2c,0x1f,0x43,0x19,0x7b,0x8f,0x85,0x44,0x63,0x02,0xd6,0x4a,0x51,0xea,0xa1,0x2f,0x35,0xab,0x14,0xd7,0xa9,0x90,0x20,0x1a,0x44,0x00,0x89,0x26,0x3b,0x25,0x91,0x5f,0x71,0x04,0x7b}, + {0x43,0xae,0xf6,0xac,0x28,0xbd,0xed,0x83,0xb4,0x7a,0x5c,0x7d,0x8b,0x7c,0x35,0x86,0x44,0x2c,0xeb,0xb7,0x69,0x47,0x40,0xc0,0x3f,0x58,0xf6,0xc2,0xf5,0x7b,0xb3,0x59,0xc6,0xba,0xe6,0xc4,0x80,0xc2,0x76,0xb3,0x0b,0x9b,0x1d,0x6d,0xdd,0xd3,0x0e,0x97,0x44,0xf9,0x0b,0x45,0x58,0x95,0x9a,0xb0,0x23,0xe2,0xcd,0x57,0xfa,0xac,0xd0,0x48,0x71,0xe6,0xab,0x7d,0xe4,0x26,0x0f,0xb6,0x37,0x3a,0x2f,0x62,0x97,0xa1,0xd1,0xf1,0x94,0x03,0x96,0xe9,0x7e,0xce,0x08,0x42,0xdb,0x3b,0x6d,0x33,0x91,0x41,0x23,0x16}, + {0xf6,0x7f,0x26,0xf6,0xde,0x99,0xe4,0xb9,0x43,0x08,0x2c,0x74,0x7b,0xca,0x72,0x77,0xb1,0xf2,0xa4,0xe9,0x3f,0x15,0xa0,0x23,0x06,0x50,0xd0,0xd5,0xec,0xdf,0xdf,0x2c,0x40,0x86,0xf3,0x1f,0xd6,0x9c,0x49,0xdd,0xa0,0x25,0x36,0x06,0xc3,0x9b,0xcd,0x29,0xc3,0x3d,0xd7,0x3d,0x02,0xd8,0xe2,0x51,0x31,0x92,0x3b,0x20,0x7a,0x70,0x25,0x4a,0x6a,0xed,0xf6,0x53,0x8a,0x66,0xb7,0x2a,0xa1,0x70,0xd1,0x1d,0x58,0x42,0x42,0x30,0x61,0x01,0xe2,0x3a,0x4c,0x14,0x00,0x40,0xfc,0x49,0x8e,0x24,0x6d,0x89,0x21,0x57}, + {0xae,0x1b,0x18,0xfd,0x17,0x55,0x6e,0x0b,0xb4,0x63,0xb9,0x2b,0x9f,0x62,0x22,0x90,0x25,0x46,0x06,0x32,0xe9,0xbc,0x09,0x55,0xda,0x13,0x3c,0xf6,0x74,0xdd,0x8e,0x57,0x4e,0xda,0xd0,0xa1,0x91,0x50,0x5d,0x28,0x08,0x3e,0xfe,0xb5,0xa7,0x6f,0xaa,0x4b,0xb3,0x93,0x93,0xe1,0x7c,0x17,0xe5,0x63,0xfd,0x30,0xb0,0xc4,0xaf,0x35,0xc9,0x03,0x3d,0x0c,0x2b,0x49,0xc6,0x76,0x72,0x99,0xfc,0x05,0xe2,0xdf,0xc4,0xc2,0xcc,0x47,0x3c,0x3a,0x62,0xdd,0x84,0x9b,0xd2,0xdc,0xa2,0xc7,0x88,0x02,0x59,0xab,0xc2,0x3e}, + {0xb9,0x7b,0xd8,0xe4,0x7b,0xd2,0xa0,0xa1,0xed,0x1a,0x39,0x61,0xeb,0x4d,0x8b,0xa9,0x83,0x9b,0xcb,0x73,0xd0,0xdd,0xa0,0x99,0xce,0xca,0x0f,0x20,0x5a,0xc2,0xd5,0x2d,0xcb,0xd1,0x32,0xae,0x09,0x3a,0x21,0xa7,0xd5,0xc2,0xf5,0x40,0xdf,0x87,0x2b,0x0f,0x29,0xab,0x1e,0xe8,0xc6,0xa4,0xae,0x0b,0x5e,0xac,0xdb,0x6a,0x6c,0xf6,0x1b,0x0e,0x7e,0x88,0x2c,0x79,0xe9,0xd5,0xab,0xe2,0x5d,0x6d,0x92,0xcb,0x18,0x00,0x02,0x1a,0x1e,0x5f,0xae,0xba,0xcd,0x69,0xba,0xbf,0x5f,0x8f,0xe8,0x5a,0xb3,0x48,0x05,0x73}, + {0xee,0xb8,0xa8,0xcb,0xa3,0x51,0x35,0xc4,0x16,0x5f,0x11,0xb2,0x1d,0x6f,0xa2,0x65,0x50,0x38,0x8c,0xab,0x52,0x4f,0x0f,0x76,0xca,0xb8,0x1d,0x41,0x3b,0x44,0x43,0x30,0x34,0xe3,0xd6,0xa1,0x4b,0x09,0x5b,0x80,0x19,0x3f,0x35,0x09,0x77,0xf1,0x3e,0xbf,0x2b,0x70,0x22,0x06,0xcb,0x06,0x3f,0x42,0xdd,0x45,0x78,0xd8,0x77,0x22,0x5a,0x58,0x62,0x89,0xd4,0x33,0x82,0x5f,0x8a,0xa1,0x7f,0x25,0x78,0xec,0xb5,0xc4,0x98,0x66,0xff,0x41,0x3e,0x37,0xa5,0x6f,0x8e,0xa7,0x1f,0x98,0xef,0x50,0x89,0x27,0x56,0x76}, + {0xc0,0xc8,0x1f,0xd5,0x59,0xcf,0xc3,0x38,0xf2,0xb6,0x06,0x05,0xfd,0xd2,0xed,0x9b,0x8f,0x0e,0x57,0xab,0x9f,0x10,0xbf,0x26,0xa6,0x46,0xb8,0xc1,0xa8,0x60,0x41,0x3f,0x9d,0xcf,0x86,0xea,0xa3,0x73,0x70,0xe1,0xdc,0x5f,0x15,0x07,0xb7,0xfb,0x8c,0x3a,0x8e,0x8a,0x83,0x31,0xfc,0xe7,0x53,0x48,0x16,0xf6,0x13,0xb6,0x84,0xf4,0xbb,0x28,0x7c,0x6c,0x13,0x6f,0x5c,0x2f,0x61,0xf2,0xbe,0x11,0xdd,0xf6,0x07,0xd1,0xea,0xaf,0x33,0x6f,0xde,0x13,0xd2,0x9a,0x7e,0x52,0x5d,0xf7,0x88,0x81,0x35,0xcb,0x79,0x1e}, + {0xf1,0xe3,0xf7,0xee,0xc3,0x36,0x34,0x01,0xf8,0x10,0x9e,0xfe,0x7f,0x6a,0x8b,0x82,0xfc,0xde,0xf9,0xbc,0xe5,0x08,0xf9,0x7f,0x31,0x38,0x3b,0x3a,0x1b,0x95,0xd7,0x65,0x81,0x81,0xe0,0xf5,0xd8,0x53,0xe9,0x77,0xd9,0xde,0x9d,0x29,0x44,0x0c,0xa5,0x84,0xe5,0x25,0x45,0x86,0x0c,0x2d,0x6c,0xdc,0xf4,0xf2,0xd1,0x39,0x2d,0xb5,0x8a,0x47,0x59,0xd1,0x52,0x92,0xd3,0xa4,0xa6,0x66,0x07,0xc8,0x1a,0x87,0xbc,0xe1,0xdd,0xe5,0x6f,0xc9,0xc1,0xa6,0x40,0x6b,0x2c,0xb8,0x14,0x22,0x21,0x1a,0x41,0x7a,0xd8,0x16}, + {0x15,0x62,0x06,0x42,0x5a,0x7e,0xbd,0xb3,0xc1,0x24,0x5a,0x0c,0xcd,0xe3,0x9b,0x87,0xb7,0x94,0xf9,0xd6,0xb1,0x5d,0xc0,0x57,0xa6,0x8c,0xf3,0x65,0x81,0x7c,0xf8,0x28,0x83,0x05,0x4e,0xd5,0xe2,0xd5,0xa4,0xfb,0xfa,0x99,0xbd,0x2e,0xd7,0xaf,0x1f,0xe2,0x8f,0x77,0xe9,0x6e,0x73,0xc2,0x7a,0x49,0xde,0x6d,0x5a,0x7a,0x57,0x0b,0x99,0x1f,0xd6,0xf7,0xe8,0x1b,0xad,0x4e,0x34,0xa3,0x8f,0x79,0xea,0xac,0xeb,0x50,0x1e,0x7d,0x52,0xe0,0x0d,0x52,0x9e,0x56,0xc6,0x77,0x3e,0x6d,0x4d,0x53,0xe1,0x2f,0x88,0x45}, + {0xd6,0x83,0x79,0x75,0x5d,0x34,0x69,0x66,0xa6,0x11,0xaa,0x17,0x11,0xed,0xb6,0x62,0x8f,0x12,0x5e,0x98,0x57,0x18,0xdd,0x7d,0xdd,0xf6,0x26,0xf6,0xb8,0xe5,0x8f,0x68,0xe4,0x6f,0x3c,0x94,0x29,0x99,0xac,0xd8,0xa2,0x92,0x83,0xa3,0x61,0xf1,0xf9,0xb5,0xf3,0x9a,0xc8,0xbe,0x13,0xdb,0x99,0x26,0x74,0xf0,0x05,0xe4,0x3c,0x84,0xcf,0x7d,0xc0,0x32,0x47,0x4a,0x48,0xd6,0x90,0x6c,0x99,0x32,0x56,0xca,0xfd,0x43,0x21,0xd5,0xe1,0xc6,0x5d,0x91,0xc3,0x28,0xbe,0xb3,0x1b,0x19,0x27,0x73,0x7e,0x68,0x39,0x67}, + {0xa6,0x75,0x56,0x38,0x14,0x20,0x78,0xef,0xe8,0xa9,0xfd,0xaa,0x30,0x9f,0x64,0xa2,0xcb,0xa8,0xdf,0x5c,0x50,0xeb,0xd1,0x4c,0xb3,0xc0,0x4d,0x1d,0xba,0x5a,0x11,0x46,0xc0,0x1a,0x0c,0xc8,0x9d,0xcc,0x6d,0xa6,0x36,0xa4,0x38,0x1b,0xf4,0x5c,0xa0,0x97,0xc6,0xd7,0xdb,0x95,0xbe,0xf3,0xeb,0xa7,0xab,0x7d,0x7e,0x8d,0xf6,0xb8,0xa0,0x7d,0x76,0xda,0xb5,0xc3,0x53,0x19,0x0f,0xd4,0x9b,0x9e,0x11,0x21,0x73,0x6f,0xac,0x1d,0x60,0x59,0xb2,0xfe,0x21,0x60,0xcc,0x03,0x4b,0x4b,0x67,0x83,0x7e,0x88,0x5f,0x5a}, + {0x11,0x3d,0xa1,0x70,0xcf,0x01,0x63,0x8f,0xc4,0xd0,0x0d,0x35,0x15,0xb8,0xce,0xcf,0x7e,0xa4,0xbc,0xa4,0xd4,0x97,0x02,0xf7,0x34,0x14,0x4d,0xe4,0x56,0xb6,0x69,0x36,0xb9,0x43,0xa6,0xa0,0xd3,0x28,0x96,0x9e,0x64,0x20,0xc3,0xe6,0x00,0xcb,0xc3,0xb5,0x32,0xec,0x2d,0x7c,0x89,0x02,0x53,0x9b,0x0c,0xc7,0xd1,0xd5,0xe2,0x7a,0xe3,0x43,0x33,0xe1,0xa6,0xed,0x06,0x3f,0x7e,0x38,0xc0,0x3a,0xa1,0x99,0x51,0x1d,0x30,0x67,0x11,0x38,0x26,0x36,0xf8,0xd8,0x5a,0xbd,0xbe,0xe9,0xd5,0x4f,0xcd,0xe6,0x21,0x6a}, + {0x5f,0xe6,0x46,0x30,0x0a,0x17,0xc6,0xf1,0x24,0x35,0xd2,0x00,0x2a,0x2a,0x71,0x58,0x55,0xb7,0x82,0x8c,0x3c,0xbd,0xdb,0x69,0x57,0xff,0x95,0xa1,0xf1,0xf9,0x6b,0x58,0xe3,0xb2,0x99,0x66,0x12,0x29,0x41,0xef,0x01,0x13,0x8d,0x70,0x47,0x08,0xd3,0x71,0xbd,0xb0,0x82,0x11,0xd0,0x32,0x54,0x32,0x36,0x8b,0x1e,0x00,0x07,0x1b,0x37,0x45,0x0b,0x79,0xf8,0x5e,0x8d,0x08,0xdb,0xa6,0xe5,0x37,0x09,0x61,0xdc,0xf0,0x78,0x52,0xb8,0x6e,0xa1,0x61,0xd2,0x49,0x03,0xac,0x79,0x21,0xe5,0x90,0x37,0xb0,0xaf,0x0e}, + {0x2f,0x04,0x48,0x37,0xc1,0x55,0x05,0x96,0x11,0xaa,0x0b,0x82,0xe6,0x41,0x9a,0x21,0x0c,0x6d,0x48,0x73,0x38,0xf7,0x81,0x1c,0x61,0xc6,0x02,0x5a,0x67,0xcc,0x9a,0x30,0x1d,0xae,0x75,0x0f,0x5e,0x80,0x40,0x51,0x30,0xcc,0x62,0x26,0xe3,0xfb,0x02,0xec,0x6d,0x39,0x92,0xea,0x1e,0xdf,0xeb,0x2c,0xb3,0x5b,0x43,0xc5,0x44,0x33,0xae,0x44,0xee,0x43,0xa5,0xbb,0xb9,0x89,0xf2,0x9c,0x42,0x71,0xc9,0x5a,0x9d,0x0e,0x76,0xf3,0xaa,0x60,0x93,0x4f,0xc6,0xe5,0x82,0x1d,0x8f,0x67,0x94,0x7f,0x1b,0x22,0xd5,0x62}, + {0x6d,0x93,0xd0,0x18,0x9c,0x29,0x4c,0x52,0x0c,0x1a,0x0c,0x8a,0x6c,0xb5,0x6b,0xc8,0x31,0x86,0x4a,0xdb,0x2e,0x05,0x75,0xa3,0x62,0x45,0x75,0xbc,0xe4,0xfd,0x0e,0x5c,0x3c,0x7a,0xf7,0x3a,0x26,0xd4,0x85,0x75,0x4d,0x14,0xe9,0xfe,0x11,0x7b,0xae,0xdf,0x3d,0x19,0xf7,0x59,0x80,0x70,0x06,0xa5,0x37,0x20,0x92,0x83,0x53,0x9a,0xf2,0x14,0xf5,0xd7,0xb2,0x25,0xdc,0x7e,0x71,0xdf,0x40,0x30,0xb5,0x99,0xdb,0x70,0xf9,0x21,0x62,0x4c,0xed,0xc3,0xb7,0x34,0x92,0xda,0x3e,0x09,0xee,0x7b,0x5c,0x36,0x72,0x5e}, + {0x7f,0x21,0x71,0x45,0x07,0xfc,0x5b,0x57,0x5b,0xd9,0x94,0x06,0x5d,0x67,0x79,0x37,0x33,0x1e,0x19,0xf4,0xbb,0x37,0x0a,0x9a,0xbc,0xea,0xb4,0x47,0x4c,0x10,0xf1,0x77,0x3e,0xb3,0x08,0x2f,0x06,0x39,0x93,0x7d,0xbe,0x32,0x9f,0xdf,0xe5,0x59,0x96,0x5b,0xfd,0xbd,0x9e,0x1f,0xad,0x3d,0xff,0xac,0xb7,0x49,0x73,0xcb,0x55,0x05,0xb2,0x70,0x4c,0x2c,0x11,0x55,0xc5,0x13,0x51,0xbe,0xcd,0x1f,0x88,0x9a,0x3a,0x42,0x88,0x66,0x47,0x3b,0x50,0x5e,0x85,0x77,0x66,0x44,0x4a,0x40,0x06,0x4a,0x8f,0x39,0x34,0x0e}, + {0xe8,0xbd,0xce,0x3e,0xd9,0x22,0x7d,0xb6,0x07,0x2f,0x82,0x27,0x41,0xe8,0xb3,0x09,0x8d,0x6d,0x5b,0xb0,0x1f,0xa6,0x3f,0x74,0x72,0x23,0x36,0x8a,0x36,0x05,0x54,0x5e,0x28,0x19,0x4b,0x3e,0x09,0x0b,0x93,0x18,0x40,0xf6,0xf3,0x73,0x0e,0xe1,0xe3,0x7d,0x6f,0x5d,0x39,0x73,0xda,0x17,0x32,0xf4,0x3e,0x9c,0x37,0xca,0xd6,0xde,0x8a,0x6f,0x9a,0xb2,0xb7,0xfd,0x3d,0x12,0x40,0xe3,0x91,0xb2,0x1a,0xa2,0xe1,0x97,0x7b,0x48,0x9e,0x94,0xe6,0xfd,0x02,0x7d,0x96,0xf9,0x97,0xde,0xd3,0xc8,0x2e,0xe7,0x0d,0x78}, + {0xbc,0xe7,0x9a,0x08,0x45,0x85,0xe2,0x0a,0x06,0x4d,0x7f,0x1c,0xcf,0xde,0x8d,0x38,0xb8,0x11,0x48,0x0a,0x51,0x15,0xac,0x38,0xe4,0x8c,0x92,0x71,0xf6,0x8b,0xb2,0x0e,0x72,0x27,0xf4,0x00,0xf3,0xea,0x1f,0x67,0xaa,0x41,0x8c,0x2a,0x2a,0xeb,0x72,0x8f,0x92,0x32,0x37,0x97,0xd7,0x7f,0xa1,0x29,0xa6,0x87,0xb5,0x32,0xad,0xc6,0xef,0x1d,0xa7,0x95,0x51,0xef,0x1a,0xbe,0x5b,0xaf,0xed,0x15,0x7b,0x91,0x77,0x12,0x8c,0x14,0x2e,0xda,0xe5,0x7a,0xfb,0xf7,0x91,0x29,0x67,0x28,0xdd,0xf8,0x1b,0x20,0x7d,0x46}, + {0xad,0x4f,0xef,0x74,0x9a,0x91,0xfe,0x95,0xa2,0x08,0xa3,0xf6,0xec,0x7b,0x82,0x3a,0x01,0x7b,0xa4,0x09,0xd3,0x01,0x4e,0x96,0x97,0xc7,0xa3,0x5b,0x4f,0x3c,0xc4,0x71,0xa9,0xe7,0x7a,0x56,0xbd,0xf4,0x1e,0xbc,0xbd,0x98,0x44,0xd6,0xb2,0x4c,0x62,0x3f,0xc8,0x4e,0x1f,0x2c,0xd2,0x64,0x10,0xe4,0x01,0x40,0x38,0xba,0xa5,0xc5,0xf9,0x2e,0xcd,0x74,0x9e,0xfa,0xf6,0x6d,0xfd,0xb6,0x7a,0x26,0xaf,0xe4,0xbc,0x78,0x82,0xf1,0x0e,0x99,0xef,0xf1,0xd0,0xb3,0x55,0x82,0x93,0xf2,0xc5,0x90,0xa3,0x8c,0x75,0x5a}, + {0x95,0x24,0x46,0xd9,0x10,0x27,0xb7,0xa2,0x03,0x50,0x7d,0xd5,0xd2,0xc6,0xa8,0x3a,0xca,0x87,0xb4,0xa0,0xbf,0x00,0xd4,0xe3,0xec,0x72,0xeb,0xb3,0x44,0xe2,0xba,0x2d,0x94,0xdc,0x61,0x1d,0x8b,0x91,0xe0,0x8c,0x66,0x30,0x81,0x9a,0x46,0x36,0xed,0x8d,0xd3,0xaa,0xe8,0xaf,0x29,0xa8,0xe6,0xd4,0x3f,0xd4,0x39,0xf6,0x27,0x80,0x73,0x0a,0xcc,0xe1,0xff,0x57,0x2f,0x4a,0x0f,0x98,0x43,0x98,0x83,0xe1,0x0d,0x0d,0x67,0x00,0xfd,0x15,0xfb,0x49,0x4a,0x3f,0x5c,0x10,0x9c,0xa6,0x26,0x51,0x63,0xca,0x98,0x26}, + {0x78,0xba,0xb0,0x32,0x88,0x31,0x65,0xe7,0x8b,0xff,0x5c,0x92,0xf7,0x31,0x18,0x38,0xcc,0x1f,0x29,0xa0,0x91,0x1b,0xa8,0x08,0x07,0xeb,0xca,0x49,0xcc,0x3d,0xb4,0x1f,0x0e,0xd9,0x3d,0x5e,0x2f,0x70,0x3d,0x2e,0x86,0x53,0xd2,0xe4,0x18,0x09,0x3f,0x9e,0x6a,0xa9,0x4d,0x02,0xf6,0x3e,0x77,0x5e,0x32,0x33,0xfa,0x4a,0x0c,0x4b,0x00,0x3c,0x2b,0xb8,0xf4,0x06,0xac,0x46,0xa9,0x9a,0xf3,0xc4,0x06,0xa8,0xa5,0x84,0xa2,0x1c,0x87,0x47,0xcd,0xc6,0x5f,0x26,0xd3,0x3e,0x17,0xd2,0x1f,0xcd,0x01,0xfd,0x43,0x6b}, + {0x44,0xc5,0x97,0x46,0x4b,0x5d,0xa7,0xc7,0xbf,0xff,0x0f,0xdf,0x48,0xf8,0xfd,0x15,0x5a,0x78,0x46,0xaa,0xeb,0xb9,0x68,0x28,0x14,0xf7,0x52,0x5b,0x10,0xd7,0x68,0x5a,0xf3,0x0e,0x76,0x3e,0x58,0x42,0xc7,0xb5,0x90,0xb9,0x0a,0xee,0xb9,0x52,0xdc,0x75,0x3f,0x92,0x2b,0x07,0xc2,0x27,0x14,0xbf,0xf0,0xd9,0xf0,0x6f,0x2d,0x0b,0x42,0x73,0x06,0x1e,0x85,0x9e,0xcb,0xf6,0x2c,0xaf,0xc4,0x38,0x22,0xc6,0x13,0x39,0x59,0x8f,0x73,0xf3,0xfb,0x99,0x96,0xb8,0x8a,0xda,0x9e,0xbc,0x34,0xea,0x2f,0x63,0xb5,0x3d}, + {0xd8,0xd9,0x5d,0xf7,0x2b,0xee,0x6e,0xf4,0xa5,0x59,0x67,0x39,0xf6,0xb1,0x17,0x0d,0x73,0x72,0x9e,0x49,0x31,0xd1,0xf2,0x1b,0x13,0x5f,0xd7,0x49,0xdf,0x1a,0x32,0x04,0xd5,0x25,0x98,0x82,0xb1,0x90,0x49,0x2e,0x91,0x89,0x9a,0x3e,0x87,0xeb,0xea,0xed,0xf8,0x4a,0x70,0x4c,0x39,0x3d,0xf0,0xee,0x0e,0x2b,0xdf,0x95,0xa4,0x7e,0x19,0x59,0xae,0x5a,0xe5,0xe4,0x19,0x60,0xe1,0x04,0xe9,0x92,0x2f,0x7e,0x7a,0x43,0x7b,0xe7,0xa4,0x9a,0x15,0x6f,0xc1,0x2d,0xce,0xc7,0xc0,0x0c,0xd7,0xf4,0xc1,0xfd,0xea,0x45}, + {0x2b,0xd7,0x45,0x80,0x85,0x01,0x84,0x69,0x51,0x06,0x2f,0xcf,0xa2,0xfa,0x22,0x4c,0xc6,0x2d,0x22,0x6b,0x65,0x36,0x1a,0x94,0xde,0xda,0x62,0x03,0xc8,0xeb,0x5e,0x5a,0xed,0xb1,0xcc,0xcf,0x24,0x46,0x0e,0xb6,0x95,0x03,0x5c,0xbd,0x92,0xc2,0xdb,0x59,0xc9,0x81,0x04,0xdc,0x1d,0x9d,0xa0,0x31,0x40,0xd9,0x56,0x5d,0xea,0xce,0x73,0x3f,0xc6,0x8d,0x4e,0x0a,0xd1,0xbf,0xa7,0xb7,0x39,0xb3,0xc9,0x44,0x7e,0x00,0x57,0xbe,0xfa,0xae,0x57,0x15,0x7f,0x20,0xc1,0x60,0xdb,0x18,0x62,0x26,0x91,0x88,0x05,0x26}, + {0x04,0xff,0x60,0x83,0xa6,0x04,0xf7,0x59,0xf4,0xe6,0x61,0x76,0xde,0x3f,0xd9,0xc3,0x51,0x35,0x87,0x12,0x73,0x2a,0x1b,0x83,0x57,0x5d,0x61,0x4e,0x2e,0x0c,0xad,0x54,0x42,0xe5,0x76,0xc6,0x3c,0x8e,0x81,0x4c,0xad,0xcc,0xce,0x03,0x93,0x2c,0x42,0x5e,0x08,0x9f,0x12,0xb4,0xca,0xcc,0x07,0xec,0xb8,0x43,0x44,0xb2,0x10,0xfa,0xed,0x0d,0x2a,0x52,0x2b,0xb8,0xd5,0x67,0x3b,0xee,0xeb,0xc1,0xa5,0x9f,0x46,0x63,0xf1,0x36,0xd3,0x9f,0xc1,0x6e,0xf2,0xd2,0xb4,0xa5,0x08,0x94,0x7a,0xa7,0xba,0xb2,0xec,0x62}, + {0x3d,0x2b,0x15,0x61,0x52,0x79,0xed,0xe5,0xd1,0xd7,0xdd,0x0e,0x7d,0x35,0x62,0x49,0x71,0x4c,0x6b,0xb9,0xd0,0xc8,0x82,0x74,0xbe,0xd8,0x66,0xa9,0x19,0xf9,0x59,0x2e,0x74,0x28,0xb6,0xaf,0x36,0x28,0x07,0x92,0xa5,0x04,0xe1,0x79,0x85,0x5e,0xcd,0x5f,0x4a,0xa1,0x30,0xc6,0xad,0x01,0xad,0x5a,0x98,0x3f,0x66,0x75,0x50,0x3d,0x91,0x61,0xda,0x31,0x32,0x1a,0x36,0x2d,0xc6,0x0d,0x70,0x02,0x20,0x94,0x32,0x58,0x47,0xfa,0xce,0x94,0x95,0x3f,0x51,0x01,0xd8,0x02,0x5c,0x5d,0xc0,0x31,0xa1,0xc2,0xdb,0x3d}, + {0x4b,0xc5,0x5e,0xce,0xf9,0x0f,0xdc,0x9a,0x0d,0x13,0x2f,0x8c,0x6b,0x2a,0x9c,0x03,0x15,0x95,0xf8,0xf0,0xc7,0x07,0x80,0x02,0x6b,0xb3,0x04,0xac,0x14,0x83,0x96,0x78,0x14,0xbb,0x96,0x27,0xa2,0x57,0xaa,0xf3,0x21,0xda,0x07,0x9b,0xb7,0xba,0x3a,0x88,0x1c,0x39,0xa0,0x31,0x18,0xe2,0x4b,0xe5,0xf9,0x05,0x32,0xd8,0x38,0xfb,0xe7,0x5e,0x8e,0x6a,0x44,0x41,0xcb,0xfd,0x8d,0x53,0xf9,0x37,0x49,0x43,0xa9,0xfd,0xac,0xa5,0x78,0x8c,0x3c,0x26,0x8d,0x90,0xaf,0x46,0x09,0x0d,0xca,0x9b,0x3c,0x63,0xd0,0x61}, + {0x66,0x25,0xdb,0xff,0x35,0x49,0x74,0x63,0xbb,0x68,0x0b,0x78,0x89,0x6b,0xbd,0xc5,0x03,0xec,0x3e,0x55,0x80,0x32,0x1b,0x6f,0xf5,0xd7,0xae,0x47,0xd8,0x5f,0x96,0x6e,0xdf,0x73,0xfc,0xf8,0xbc,0x28,0xa3,0xad,0xfc,0x37,0xf0,0xa6,0x5d,0x69,0x84,0xee,0x09,0xa9,0xc2,0x38,0xdb,0xb4,0x7f,0x63,0xdc,0x7b,0x06,0xf8,0x2d,0xac,0x23,0x5b,0x7b,0x52,0x80,0xee,0x53,0xb9,0xd2,0x9a,0x8d,0x6d,0xde,0xfa,0xaa,0x19,0x8f,0xe8,0xcf,0x82,0x0e,0x15,0x04,0x17,0x71,0x0e,0xdc,0xde,0x95,0xdd,0xb9,0xbb,0xb9,0x79}, + {0xc2,0x26,0x31,0x6a,0x40,0x55,0xb3,0xeb,0x93,0xc3,0xc8,0x68,0xa8,0x83,0x63,0xd2,0x82,0x7a,0xb9,0xe5,0x29,0x64,0x0c,0x6c,0x47,0x21,0xfd,0xc9,0x58,0xf1,0x65,0x50,0x74,0x73,0x9f,0x8e,0xae,0x7d,0x99,0xd1,0x16,0x08,0xbb,0xcf,0xf8,0xa2,0x32,0xa0,0x0a,0x5f,0x44,0x6d,0x12,0xba,0x6c,0xcd,0x34,0xb8,0xcc,0x0a,0x46,0x11,0xa8,0x1b,0x54,0x99,0x42,0x0c,0xfb,0x69,0x81,0x70,0x67,0xcf,0x6e,0xd7,0xac,0x00,0x46,0xe1,0xba,0x45,0xe6,0x70,0x8a,0xb9,0xaa,0x2e,0xf2,0xfa,0xa4,0x58,0x9e,0xf3,0x81,0x39}, + {0x93,0x0a,0x23,0x59,0x75,0x8a,0xfb,0x18,0x5d,0xf4,0xe6,0x60,0x69,0x8f,0x16,0x1d,0xb5,0x3c,0xa9,0x14,0x45,0xa9,0x85,0x3a,0xfd,0xd0,0xac,0x05,0x37,0x08,0xdc,0x38,0xde,0x6f,0xe6,0x6d,0xa5,0xdf,0x45,0xc8,0x3a,0x48,0x40,0x2c,0x00,0xa5,0x52,0xe1,0x32,0xf6,0xb4,0xc7,0x63,0xe1,0xd2,0xe9,0x65,0x1b,0xbc,0xdc,0x2e,0x45,0xf4,0x30,0x40,0x97,0x75,0xc5,0x82,0x27,0x6d,0x85,0xcc,0xbe,0x9c,0xf9,0x69,0x45,0x13,0xfa,0x71,0x4e,0xea,0xc0,0x73,0xfc,0x44,0x88,0x69,0x24,0x3f,0x59,0x1a,0x9a,0x2d,0x63}, + {0xa6,0xcb,0x07,0xb8,0x15,0x6b,0xbb,0xf6,0xd7,0xf0,0x54,0xbc,0xdf,0xc7,0x23,0x18,0x0b,0x67,0x29,0x6e,0x03,0x97,0x1d,0xbb,0x57,0x4a,0xed,0x47,0x88,0xf4,0x24,0x0b,0xa7,0x84,0x0c,0xed,0x11,0xfd,0x09,0xbf,0x3a,0x69,0x9f,0x0d,0x81,0x71,0xf0,0x63,0x79,0x87,0xcf,0x57,0x2d,0x8c,0x90,0x21,0xa2,0x4b,0xf6,0x8a,0xf2,0x7d,0x5a,0x3a,0xc7,0xea,0x1b,0x51,0xbe,0xd4,0xda,0xdc,0xf2,0xcc,0x26,0xed,0x75,0x80,0x53,0xa4,0x65,0x9a,0x5f,0x00,0x9f,0xff,0x9c,0xe1,0x63,0x1f,0x48,0x75,0x44,0xf7,0xfc,0x34}, + {0xca,0x67,0x97,0x78,0x4c,0xe0,0x97,0xc1,0x7d,0x46,0xd9,0x38,0xcb,0x4d,0x71,0xb8,0xa8,0x5f,0xf9,0x83,0x82,0x88,0xde,0x55,0xf7,0x63,0xfa,0x4d,0x16,0xdc,0x3b,0x3d,0x98,0xaa,0xcf,0x78,0xab,0x1d,0xbb,0xa5,0xf2,0x72,0x0b,0x19,0x67,0xa2,0xed,0x5c,0x8e,0x60,0x92,0x0a,0x11,0xc9,0x09,0x93,0xb0,0x74,0xb3,0x2f,0x04,0xa3,0x19,0x01,0x7d,0x17,0xc2,0xe8,0x9c,0xd8,0xa2,0x67,0xc1,0xd0,0x95,0x68,0xf6,0xa5,0x9d,0x66,0xb0,0xa2,0x82,0xb2,0xe5,0x98,0x65,0xf5,0x73,0x0a,0xe2,0xed,0xf1,0x88,0xc0,0x56}, + {0x17,0x6e,0xa8,0x10,0x11,0x3d,0x6d,0x33,0xfa,0xb2,0x75,0x0b,0x32,0x88,0xf3,0xd7,0x88,0x29,0x07,0x25,0x76,0x33,0x15,0xf9,0x87,0x8b,0x10,0x99,0x6b,0x4c,0x67,0x09,0x02,0x8f,0xf3,0x24,0xac,0x5f,0x1b,0x58,0xbd,0x0c,0xe3,0xba,0xfe,0xe9,0x0b,0xa9,0xf0,0x92,0xcf,0x8a,0x02,0x69,0x21,0x9a,0x8f,0x03,0x59,0x83,0xa4,0x7e,0x8b,0x03,0xf8,0x6f,0x31,0x99,0x21,0xf8,0x4e,0x9f,0x4f,0x8d,0xa7,0xea,0x82,0xd2,0x49,0x2f,0x74,0x31,0xef,0x5a,0xab,0xa5,0x71,0x09,0x65,0xeb,0x69,0x59,0x02,0x31,0x5e,0x6e}, + {0xfb,0x93,0xe5,0x87,0xf5,0x62,0x6c,0xb1,0x71,0x3e,0x5d,0xca,0xde,0xed,0x99,0x49,0x6d,0x3e,0xcc,0x14,0xe0,0xc1,0x91,0xb4,0xa8,0xdb,0xa8,0x89,0x47,0x11,0xf5,0x08,0x22,0x62,0x06,0x63,0x0e,0xfb,0x04,0x33,0x3f,0xba,0xac,0x87,0x89,0x06,0x35,0xfb,0xa3,0x61,0x10,0x8c,0x77,0x24,0x19,0xbd,0x20,0x86,0x83,0xd1,0x43,0xad,0x58,0x30,0xd0,0x63,0x76,0xe5,0xfd,0x0f,0x3c,0x32,0x10,0xa6,0x2e,0xa2,0x38,0xdf,0xc3,0x05,0x9a,0x4f,0x99,0xac,0xbd,0x8a,0xc7,0xbd,0x99,0xdc,0xe3,0xef,0xa4,0x9f,0x54,0x26}, + {0xd6,0xf9,0x6b,0x1e,0x46,0x5a,0x1d,0x74,0x81,0xa5,0x77,0x77,0xfc,0xb3,0x05,0x23,0xd9,0xd3,0x74,0x64,0xa2,0x74,0x55,0xd4,0xff,0xe0,0x01,0x64,0xdc,0xe1,0x26,0x19,0x6e,0x66,0x3f,0xaf,0x49,0x85,0x46,0xdb,0xa5,0x0e,0x4a,0xf1,0x04,0xcf,0x7f,0xd7,0x47,0x0c,0xba,0xa4,0xf7,0x3f,0xf2,0x3d,0x85,0x3c,0xce,0x32,0xe1,0xdf,0x10,0x3a,0xa0,0xce,0x17,0xea,0x8a,0x4e,0x7f,0xe0,0xfd,0xc1,0x1f,0x3a,0x46,0x15,0xd5,0x2f,0xf1,0xc0,0xf2,0x31,0xfd,0x22,0x53,0x17,0x15,0x5d,0x1e,0x86,0x1d,0xd0,0xa1,0x1f}, + {0x32,0x98,0x59,0x7d,0x94,0x55,0x80,0xcc,0x20,0x55,0xf1,0x37,0xda,0x56,0x46,0x1e,0x20,0x93,0x05,0x4e,0x74,0xf7,0xf6,0x99,0x33,0xcf,0x75,0x6a,0xbc,0x63,0x35,0x77,0xab,0x94,0xdf,0xd1,0x00,0xac,0xdc,0x38,0xe9,0x0d,0x08,0xd1,0xdd,0x2b,0x71,0x2e,0x62,0xe2,0xd5,0xfd,0x3e,0xe9,0x13,0x7f,0xe5,0x01,0x9a,0xee,0x18,0xed,0xfc,0x73,0xb3,0x9c,0x13,0x63,0x08,0xe9,0xb1,0x06,0xcd,0x3e,0xa0,0xc5,0x67,0xda,0x93,0xa4,0x32,0x89,0x63,0xad,0xc8,0xce,0x77,0x8d,0x44,0x4f,0x86,0x1b,0x70,0x6b,0x42,0x1f}, + {0x01,0x1c,0x91,0x41,0x4c,0x26,0xc9,0xef,0x25,0x2c,0xa2,0x17,0xb8,0xb7,0xa3,0xf1,0x47,0x14,0x0f,0xf3,0x6b,0xda,0x75,0x58,0x90,0xb0,0x31,0x1d,0x27,0xf5,0x1a,0x4e,0x52,0x25,0xa1,0x91,0xc8,0x35,0x7e,0xf1,0x76,0x9c,0x5e,0x57,0x53,0x81,0x6b,0xb7,0x3e,0x72,0x9b,0x0d,0x6f,0x40,0x83,0xfa,0x38,0xe4,0xa7,0x3f,0x1b,0xbb,0x76,0x0b,0x9b,0x93,0x92,0x7f,0xf9,0xc1,0xb8,0x08,0x6e,0xab,0x44,0xd4,0xcb,0x71,0x67,0xbe,0x17,0x80,0xbb,0x99,0x63,0x64,0xe5,0x22,0x55,0xa9,0x72,0xb7,0x1e,0xd6,0x6d,0x7b}, + {0x92,0x3d,0xf3,0x50,0xe8,0xc1,0xad,0xb7,0xcf,0xd5,0x8c,0x60,0x4f,0xfa,0x98,0x79,0xdb,0x5b,0xfc,0x8d,0xbd,0x2d,0x96,0xad,0x4f,0x2f,0x1d,0xaf,0xce,0x9b,0x3e,0x70,0xc7,0xd2,0x01,0xab,0xf9,0xab,0x30,0x57,0x18,0x3b,0x14,0x40,0xdc,0x76,0xfb,0x16,0x81,0xb2,0xcb,0xa0,0x65,0xbe,0x6c,0x86,0xfe,0x6a,0xff,0x9b,0x65,0x9b,0xfa,0x53,0x55,0x54,0x88,0x94,0xe9,0xc8,0x14,0x6c,0xe5,0xd4,0xae,0x65,0x66,0x5d,0x3a,0x84,0xf1,0x5a,0xd6,0xbc,0x3e,0xb7,0x1b,0x18,0x50,0x1f,0xc6,0xc4,0xe5,0x93,0x8d,0x39}, + {0xf3,0x48,0xe2,0x33,0x67,0xd1,0x4b,0x1c,0x5f,0x0a,0xbf,0x15,0x87,0x12,0x9e,0xbd,0x76,0x03,0x0b,0xa1,0xf0,0x8c,0x3f,0xd4,0x13,0x1b,0x19,0xdf,0x5d,0x9b,0xb0,0x53,0xf2,0xe3,0xe7,0xd2,0x60,0x7c,0x87,0xc3,0xb1,0x8b,0x82,0x30,0xa0,0xaa,0x34,0x3b,0x38,0xf1,0x9e,0x73,0xe7,0x26,0x3e,0x28,0x77,0x05,0xc3,0x02,0x90,0x9c,0x9c,0x69,0xcc,0xf1,0x46,0x59,0x23,0xa7,0x06,0xf3,0x7d,0xd9,0xe5,0xcc,0xb5,0x18,0x17,0x92,0x75,0xe9,0xb4,0x81,0x47,0xd2,0xcd,0x28,0x07,0xd9,0xcd,0x6f,0x0c,0xf3,0xca,0x51}, + {0x0a,0xe0,0x74,0x76,0x42,0xa7,0x0b,0xa6,0xf3,0x7b,0x7a,0xa1,0x70,0x85,0x0e,0x63,0xcc,0x24,0x33,0xcf,0x3d,0x56,0x58,0x37,0xaa,0xfd,0x83,0x23,0x29,0xaa,0x04,0x55,0xc7,0x54,0xac,0x18,0x9a,0xf9,0x7a,0x73,0x0f,0xb3,0x1c,0xc5,0xdc,0x78,0x33,0x90,0xc7,0x0c,0xe1,0x4c,0x33,0xbc,0x89,0x2b,0x9a,0xe9,0xf8,0x89,0xc1,0x29,0xae,0x12,0xcf,0x01,0x0d,0x1f,0xcb,0xc0,0x9e,0xa9,0xae,0xf7,0x34,0x3a,0xcc,0xef,0xd1,0x0d,0x22,0x4e,0x9c,0xd0,0x21,0x75,0xca,0x55,0xea,0xa5,0xeb,0x58,0xe9,0x4f,0xd1,0x5f}, + {0x2c,0xab,0x45,0x28,0xdf,0x2d,0xdc,0xb5,0x93,0xe9,0x7f,0x0a,0xb1,0x91,0x94,0x06,0x46,0xe3,0x02,0x40,0xd6,0xf3,0xaa,0x4d,0xd1,0x74,0x64,0x58,0x6e,0xf2,0x3f,0x09,0x8e,0xcb,0x93,0xbf,0x5e,0xfe,0x42,0x3c,0x5f,0x56,0xd4,0x36,0x51,0xa8,0xdf,0xbe,0xe8,0x20,0x42,0x88,0x9e,0x85,0xf0,0xe0,0x28,0xd1,0x25,0x07,0x96,0x3f,0xd7,0x7d,0x29,0x98,0x05,0x68,0xfe,0x24,0x0d,0xb1,0xe5,0x23,0xaf,0xdb,0x72,0x06,0x73,0x75,0x29,0xac,0x57,0xb4,0x3a,0x25,0x67,0x13,0xa4,0x70,0xb4,0x86,0xbc,0xbc,0x59,0x2f}, + {0x5f,0x13,0x17,0x99,0x42,0x7d,0x84,0x83,0xd7,0x03,0x7d,0x56,0x1f,0x91,0x1b,0xad,0xd1,0xaa,0x77,0xbe,0xd9,0x48,0x77,0x7e,0x4a,0xaf,0x51,0x2e,0x2e,0xb4,0x58,0x54,0x01,0xc3,0x91,0xb6,0x60,0xd5,0x41,0x70,0x1e,0xe7,0xd7,0xad,0x3f,0x1b,0x20,0x85,0x85,0x55,0x33,0x11,0x63,0xe1,0xc2,0x16,0xb1,0x28,0x08,0x01,0x3d,0x5e,0xa5,0x2a,0x4f,0x44,0x07,0x0c,0xe6,0x92,0x51,0xed,0x10,0x1d,0x42,0x74,0x2d,0x4e,0xc5,0x42,0x64,0xc8,0xb5,0xfd,0x82,0x4c,0x2b,0x35,0x64,0x86,0x76,0x8a,0x4a,0x00,0xe9,0x13}, + {0xdb,0xce,0x2f,0x83,0x45,0x88,0x9d,0x73,0x63,0xf8,0x6b,0xae,0xc9,0xd6,0x38,0xfa,0xf7,0xfe,0x4f,0xb7,0xca,0x0d,0xbc,0x32,0x5e,0xe4,0xbc,0x14,0x88,0x7e,0x93,0x73,0x7f,0x87,0x3b,0x19,0xc9,0x00,0x2e,0xbb,0x6b,0x50,0xdc,0xe0,0x90,0xa8,0xe3,0xec,0x9f,0x64,0xde,0x36,0xc0,0xb7,0xf3,0xec,0x1a,0x9e,0xde,0x98,0x08,0x04,0x46,0x5f,0x8d,0xf4,0x7b,0x29,0x16,0x71,0x03,0xb9,0x34,0x68,0xf0,0xd4,0x22,0x3b,0xd1,0xa9,0xc6,0xbd,0x96,0x46,0x57,0x15,0x97,0xe1,0x35,0xe8,0xd5,0x91,0xe8,0xa4,0xf8,0x2c}, + {0x67,0x0f,0x11,0x07,0x87,0xfd,0x93,0x6d,0x49,0xb5,0x38,0x7c,0xd3,0x09,0x4c,0xdd,0x86,0x6a,0x73,0xc2,0x4c,0x6a,0xb1,0x7c,0x09,0x2a,0x25,0x58,0x6e,0xbd,0x49,0x20,0xa2,0x6b,0xd0,0x17,0x7e,0x48,0xb5,0x2c,0x6b,0x19,0x50,0x39,0x1c,0x38,0xd2,0x24,0x30,0x8a,0x97,0x85,0x81,0x9c,0x65,0xd7,0xf6,0xa4,0xd6,0x91,0x28,0x7f,0x6f,0x7a,0x49,0xef,0x9a,0x6a,0x8d,0xfd,0x09,0x7d,0x0b,0xb9,0x3d,0x5b,0xbe,0x60,0xee,0xf0,0xd4,0xbf,0x9e,0x51,0x2c,0xb5,0x21,0x4c,0x1d,0x94,0x45,0xc5,0xdf,0xaa,0x11,0x60}, + {0x3c,0xf8,0x95,0xcf,0x6d,0x92,0x67,0x5f,0x71,0x90,0x28,0x71,0x61,0x85,0x7e,0x7c,0x5b,0x7a,0x8f,0x99,0xf3,0xe7,0xa1,0xd6,0xe0,0xf9,0x62,0x0b,0x1b,0xcc,0xc5,0x6f,0x90,0xf8,0xcb,0x02,0xc8,0xd0,0xde,0x63,0xaa,0x6a,0xff,0x0d,0xca,0x98,0xd0,0xfb,0x99,0xed,0xb6,0xb9,0xfd,0x0a,0x4d,0x62,0x1e,0x0b,0x34,0x79,0xb7,0x18,0xce,0x69,0xcb,0x79,0x98,0xb2,0x28,0x55,0xef,0xd1,0x92,0x90,0x7e,0xd4,0x3c,0xae,0x1a,0xdd,0x52,0x23,0x9f,0x18,0x42,0x04,0x7e,0x12,0xf1,0x01,0x71,0xe5,0x3a,0x6b,0x59,0x15}, + {0xa2,0x79,0x91,0x3f,0xd2,0x39,0x27,0x46,0xcf,0xdd,0xd6,0x97,0x31,0x12,0x83,0xff,0x8a,0x14,0xf2,0x53,0xb5,0xde,0x07,0x13,0xda,0x4d,0x5f,0x7b,0x68,0x37,0x22,0x0d,0xca,0x24,0x51,0x7e,0x16,0x31,0xff,0x09,0xdf,0x45,0xc7,0xd9,0x8b,0x15,0xe4,0x0b,0xe5,0x56,0xf5,0x7e,0x22,0x7d,0x2b,0x29,0x38,0xd1,0xb6,0xaf,0x41,0xe2,0xa4,0x3a,0xf5,0x05,0x33,0x2a,0xbf,0x38,0xc1,0x2c,0xc3,0x26,0xe9,0xa2,0x8f,0x3f,0x58,0x48,0xeb,0xd2,0x49,0x55,0xa2,0xb1,0x3a,0x08,0x6c,0xa3,0x87,0x46,0x6e,0xaa,0xfc,0x32}, + {0xf5,0x9a,0x7d,0xc5,0x8d,0x6e,0xc5,0x7b,0xf2,0xbd,0xf0,0x9d,0xed,0xd2,0x0b,0x3e,0xa3,0xe4,0xef,0x22,0xde,0x14,0xc0,0xaa,0x5c,0x6a,0xbd,0xfe,0xce,0xe9,0x27,0x46,0xdf,0xcc,0x87,0x27,0x73,0xa4,0x07,0x32,0xf8,0xe3,0x13,0xf2,0x08,0x19,0xe3,0x17,0x4e,0x96,0x0d,0xf6,0xd7,0xec,0xb2,0xd5,0xe9,0x0b,0x60,0xc2,0x36,0x63,0x6f,0x74,0x1c,0x97,0x6c,0xab,0x45,0xf3,0x4a,0x3f,0x1f,0x73,0x43,0x99,0x72,0xeb,0x88,0xe2,0x6d,0x18,0x44,0x03,0x8a,0x6a,0x59,0x33,0x93,0x62,0xd6,0x7e,0x00,0x17,0x49,0x7b}, + {0x64,0xb0,0x84,0xab,0x5c,0xfb,0x85,0x2d,0x14,0xbc,0xf3,0x89,0xd2,0x10,0x78,0x49,0x0c,0xce,0x15,0x7b,0x44,0xdc,0x6a,0x47,0x7b,0xfd,0x44,0xf8,0x76,0xa3,0x2b,0x12,0xdd,0xa2,0x53,0xdd,0x28,0x1b,0x34,0x54,0x3f,0xfc,0x42,0xdf,0x5b,0x90,0x17,0xaa,0xf4,0xf8,0xd2,0x4d,0xd9,0x92,0xf5,0x0f,0x7d,0xd3,0x8c,0xe0,0x0f,0x62,0x03,0x1d,0x54,0xe5,0xb4,0xa2,0xcd,0x32,0x02,0xc2,0x7f,0x18,0x5d,0x11,0x42,0xfd,0xd0,0x9e,0xd9,0x79,0xd4,0x7d,0xbe,0xb4,0xab,0x2e,0x4c,0xec,0x68,0x2b,0xf5,0x0b,0xc7,0x02}, + {0xbb,0x2f,0x0b,0x5d,0x4b,0xec,0x87,0xa2,0xca,0x82,0x48,0x07,0x90,0x57,0x5c,0x41,0x5c,0x81,0xd0,0xc1,0x1e,0xa6,0x44,0xe0,0xe0,0xf5,0x9e,0x40,0x0a,0x4f,0x33,0x26,0xe1,0x72,0x8d,0x45,0xbf,0x32,0xe5,0xac,0xb5,0x3c,0xb7,0x7c,0xe0,0x68,0xe7,0x5b,0xe7,0xbd,0x8b,0xee,0x94,0x7d,0xcf,0x56,0x03,0x3a,0xb4,0xfe,0xe3,0x97,0x06,0x6b,0xc0,0xa3,0x62,0xdf,0x4a,0xf0,0xc8,0xb6,0x5d,0xa4,0x6d,0x07,0xef,0x00,0xf0,0x3e,0xa9,0xd2,0xf0,0x49,0x58,0xb9,0x9c,0x9c,0xae,0x2f,0x1b,0x44,0x43,0x7f,0xc3,0x1c}, + {0x4f,0x32,0xc7,0x5c,0x5a,0x56,0x8f,0x50,0x22,0xa9,0x06,0xe5,0xc0,0xc4,0x61,0xd0,0x19,0xac,0x45,0x5c,0xdb,0xab,0x18,0xfb,0x4a,0x31,0x80,0x03,0xc1,0x09,0x68,0x6c,0xb9,0xae,0xce,0xc9,0xf1,0x56,0x66,0xd7,0x6a,0x65,0xe5,0x18,0xf8,0x15,0x5b,0x1c,0x34,0x23,0x4c,0x84,0x32,0x28,0xe7,0x26,0x38,0x68,0x19,0x2f,0x77,0x6f,0x34,0x3a,0xc8,0x6a,0xda,0xe2,0x12,0x51,0xd5,0xd2,0xed,0x51,0xe8,0xb1,0x31,0x03,0xbd,0xe9,0x62,0x72,0xc6,0x8e,0xdd,0x46,0x07,0x96,0xd0,0xc5,0xf7,0x6e,0x9f,0x1b,0x91,0x05}, + {0xbb,0x0e,0xdf,0xf5,0x83,0x99,0x33,0xc1,0xac,0x4c,0x2c,0x51,0x8f,0x75,0xf3,0xc0,0xe1,0x98,0xb3,0x0b,0x0a,0x13,0xf1,0x2c,0x62,0x0c,0x27,0xaa,0xf9,0xec,0x3c,0x6b,0xef,0xea,0x2e,0x51,0xf3,0xac,0x49,0x53,0x49,0xcb,0xc1,0x1c,0xd3,0x41,0xc1,0x20,0x8d,0x68,0x9a,0xa9,0x07,0x0c,0x18,0x24,0x17,0x2d,0x4b,0xc6,0xd1,0xf9,0x5e,0x55,0x08,0xbd,0x73,0x3b,0xba,0x70,0xa7,0x36,0x0c,0xbf,0xaf,0xa3,0x08,0xef,0x4a,0x62,0xf2,0x46,0x09,0xb4,0x98,0xff,0x37,0x57,0x9d,0x74,0x81,0x33,0xe1,0x4d,0x5f,0x67}, + {0xfc,0x82,0x17,0x6b,0x03,0x52,0x2c,0x0e,0xb4,0x83,0xad,0x6c,0x81,0x6c,0x81,0x64,0x3e,0x07,0x64,0x69,0xd9,0xbd,0xdc,0xd0,0x20,0xc5,0x64,0x01,0xf7,0x9d,0xd9,0x13,0x1d,0xb3,0xda,0x3b,0xd9,0xf6,0x2f,0xa1,0xfe,0x2d,0x65,0x9d,0x0f,0xd8,0x25,0x07,0x87,0x94,0xbe,0x9a,0xf3,0x4f,0x9c,0x01,0x43,0x3c,0xcd,0x82,0xb8,0x50,0xf4,0x60,0xca,0xc0,0xe5,0x21,0xc3,0x5e,0x4b,0x01,0xa2,0xbf,0x19,0xd7,0xc9,0x69,0xcb,0x4f,0xa0,0x23,0x00,0x75,0x18,0x1c,0x5f,0x4e,0x80,0xac,0xed,0x55,0x9e,0xde,0x06,0x1c}, + {0xe2,0xc4,0x3e,0xa3,0xd6,0x7a,0x0f,0x99,0x8e,0xe0,0x2e,0xbe,0x38,0xf9,0x08,0x66,0x15,0x45,0x28,0x63,0xc5,0x43,0xa1,0x9c,0x0d,0xb6,0x2d,0xec,0x1f,0x8a,0xf3,0x4c,0xaa,0x69,0x6d,0xff,0x40,0x2b,0xd5,0xff,0xbb,0x49,0x40,0xdc,0x18,0x0b,0x53,0x34,0x97,0x98,0x4d,0xa3,0x2f,0x5c,0x4a,0x5e,0x2d,0xba,0x32,0x7d,0x8e,0x6f,0x09,0x78,0xe7,0x5c,0xfa,0x0d,0x65,0xaa,0xaa,0xa0,0x8c,0x47,0xb5,0x48,0x2a,0x9e,0xc4,0xf9,0x5b,0x72,0x03,0x70,0x7d,0xcc,0x09,0x4f,0xbe,0x1a,0x09,0x26,0x3a,0xad,0x3c,0x37}, + {0x7c,0xf5,0xc9,0x82,0x4d,0x63,0x94,0xb2,0x36,0x45,0x93,0x24,0xe1,0xfd,0xcb,0x1f,0x5a,0xdb,0x8c,0x41,0xb3,0x4d,0x9c,0x9e,0xfc,0x19,0x44,0x45,0xd9,0xf3,0x40,0x00,0xad,0xbb,0xdd,0x89,0xfb,0xa8,0xbe,0xf1,0xcb,0xae,0xae,0x61,0xbc,0x2c,0xcb,0x3b,0x9d,0x8d,0x9b,0x1f,0xbb,0xa7,0x58,0x8f,0x86,0xa6,0x12,0x51,0xda,0x7e,0x54,0x21,0xd3,0x86,0x59,0xfd,0x39,0xe9,0xfd,0xde,0x0c,0x38,0x0a,0x51,0x89,0x2c,0x27,0xf4,0xb9,0x19,0x31,0xbb,0x07,0xa4,0x2b,0xb7,0xf4,0x4d,0x25,0x4a,0x33,0x0a,0x55,0x63}, + {0x37,0xcf,0x69,0xb5,0xed,0xd6,0x07,0x65,0xe1,0x2e,0xa5,0x0c,0xb0,0x29,0x84,0x17,0x5d,0xd6,0x6b,0xeb,0x90,0x00,0x7c,0xea,0x51,0x8f,0xf7,0xda,0xc7,0x62,0xea,0x3e,0x49,0x7b,0x54,0x72,0x45,0x58,0xba,0x9b,0xe0,0x08,0xc4,0xe2,0xfa,0xc6,0x05,0xf3,0x8d,0xf1,0x34,0xc7,0x69,0xfa,0xe8,0x60,0x7a,0x76,0x7d,0xaa,0xaf,0x2b,0xa9,0x39,0x4e,0x27,0x93,0xe6,0x13,0xc7,0x24,0x9d,0x75,0xd3,0xdb,0x68,0x77,0x85,0x63,0x5f,0x9a,0xb3,0x8a,0xeb,0x60,0x55,0x52,0x70,0xcd,0xc4,0xc9,0x65,0x06,0x6a,0x43,0x68}, + {0x27,0x3f,0x2f,0x20,0xe8,0x35,0x02,0xbc,0xb0,0x75,0xf9,0x64,0xe2,0x00,0x5c,0xc7,0x16,0x24,0x8c,0xa3,0xd5,0xe9,0xa4,0x91,0xf9,0x89,0xb7,0x8a,0xf6,0xe7,0xb6,0x17,0x7c,0x10,0x20,0xe8,0x17,0xd3,0x56,0x1e,0x65,0xe9,0x0a,0x84,0x44,0x68,0x26,0xc5,0x7a,0xfc,0x0f,0x32,0xc6,0xa1,0xe0,0xc1,0x72,0x14,0x61,0x91,0x9c,0x66,0x73,0x53,0x57,0x52,0x0e,0x9a,0xab,0x14,0x28,0x5d,0xfc,0xb3,0xca,0xc9,0x84,0x20,0x8f,0x90,0xca,0x1e,0x2d,0x5b,0x88,0xf5,0xca,0xaf,0x11,0x7d,0xf8,0x78,0xa6,0xb5,0xb4,0x1c}, + {0x6c,0xfc,0x4a,0x39,0x6b,0xc0,0x64,0xb6,0xb1,0x5f,0xda,0x98,0x24,0xde,0x88,0x0c,0x34,0xd8,0xca,0x4b,0x16,0x03,0x8d,0x4f,0xa2,0x34,0x74,0xde,0x78,0xca,0x0b,0x33,0xe7,0x07,0xa0,0xa2,0x62,0xaa,0x74,0x6b,0xb1,0xc7,0x71,0xf0,0xb0,0xe0,0x11,0xf3,0x23,0xe2,0x0b,0x00,0x38,0xe4,0x07,0x57,0xac,0x6e,0xef,0x82,0x2d,0xfd,0xc0,0x2d,0x4e,0x74,0x19,0x11,0x84,0xff,0x2e,0x98,0x24,0x47,0x07,0x2b,0x96,0x5e,0x69,0xf9,0xfb,0x53,0xc9,0xbf,0x4f,0xc1,0x8a,0xc5,0xf5,0x1c,0x9f,0x36,0x1b,0xbe,0x31,0x3c}, + {0xee,0x8a,0x94,0x08,0x4d,0x86,0xf4,0xb0,0x6f,0x1c,0xba,0x91,0xee,0x19,0xdc,0x07,0x58,0xa1,0xac,0xa6,0xae,0xcd,0x75,0x79,0xbb,0xd4,0x62,0x42,0x13,0x61,0x0b,0x33,0x72,0x42,0xcb,0xf9,0x93,0xbc,0x68,0xc1,0x98,0xdb,0xce,0xc7,0x1f,0x71,0xb8,0xae,0x7a,0x8d,0xac,0x34,0xaa,0x52,0x0e,0x7f,0xbb,0x55,0x7d,0x7e,0x09,0xc1,0xce,0x41,0x8a,0x80,0x6d,0xa2,0xd7,0x19,0x96,0xf7,0x6d,0x15,0x9e,0x1d,0x9e,0xd4,0x1f,0xbb,0x27,0xdf,0xa1,0xdb,0x6c,0xc3,0xd7,0x73,0x7d,0x77,0x28,0x1f,0xd9,0x4c,0xb4,0x26}, + {0x75,0x74,0x38,0x8f,0x47,0x48,0xf0,0x51,0x3c,0xcb,0xbe,0x9c,0xf4,0xbc,0x5d,0xb2,0x55,0x20,0x9f,0xd9,0x44,0x12,0xab,0x9a,0xd6,0xa5,0x10,0x1c,0x6c,0x9e,0x70,0x2c,0x83,0x03,0x73,0x62,0x93,0xf2,0xb7,0xe1,0x2c,0x8a,0xca,0xeb,0xff,0x79,0x52,0x4b,0x14,0x13,0xd4,0xbf,0x8a,0x77,0xfc,0xda,0x0f,0x61,0x72,0x9c,0x14,0x10,0xeb,0x7d,0x7a,0xee,0x66,0x87,0x6a,0xaf,0x62,0xcb,0x0e,0xcd,0x53,0x55,0x04,0xec,0xcb,0x66,0xb5,0xe4,0x0b,0x0f,0x38,0x01,0x80,0x58,0xea,0xe2,0x2c,0xf6,0x9f,0x8e,0xe6,0x08}, + {0xad,0x30,0xc1,0x4b,0x0a,0x50,0xad,0x34,0x9c,0xd4,0x0b,0x3d,0x49,0xdb,0x38,0x8d,0xbe,0x89,0x0a,0x50,0x98,0x3d,0x5c,0xa2,0x09,0x3b,0xba,0xee,0x87,0x3f,0x1f,0x2f,0xf9,0xf2,0xb8,0x0a,0xd5,0x09,0x2d,0x2f,0xdf,0x23,0x59,0xc5,0x8d,0x21,0xb9,0xac,0xb9,0x6c,0x76,0x73,0x26,0x34,0x8f,0x4a,0xf5,0x19,0xf7,0x38,0xd7,0x3b,0xb1,0x4c,0x4a,0xb6,0x15,0xe5,0x75,0x8c,0x84,0xf7,0x38,0x90,0x4a,0xdb,0xba,0x01,0x95,0xa5,0x50,0x1b,0x75,0x3f,0x3f,0x31,0x0d,0xc2,0xe8,0x2e,0xae,0xc0,0x53,0xe3,0xa1,0x19}, + {0xc3,0x05,0xfa,0xba,0x60,0x75,0x1c,0x7d,0x61,0x5e,0xe5,0xc6,0xa0,0xa0,0xe1,0xb3,0x73,0x64,0xd6,0xc0,0x18,0x97,0x52,0xe3,0x86,0x34,0x0c,0xc2,0x11,0x6b,0x54,0x41,0xbd,0xbd,0x96,0xd5,0xcd,0x72,0x21,0xb4,0x40,0xfc,0xee,0x98,0x43,0x45,0xe0,0x93,0xb5,0x09,0x41,0xb4,0x47,0x53,0xb1,0x9f,0x34,0xae,0x66,0x02,0x99,0xd3,0x6b,0x73,0xb4,0xb3,0x34,0x93,0x50,0x2d,0x53,0x85,0x73,0x65,0x81,0x60,0x4b,0x11,0xfd,0x46,0x75,0x83,0x5c,0x42,0x30,0x5f,0x5f,0xcc,0x5c,0xab,0x7f,0xb8,0xa2,0x95,0x22,0x41}, + {0xe9,0xd6,0x7e,0xf5,0x88,0x9b,0xc9,0x19,0x25,0xc8,0xf8,0x6d,0x26,0xcb,0x93,0x53,0x73,0xd2,0x0a,0xb3,0x13,0x32,0xee,0x5c,0x34,0x2e,0x2d,0xb5,0xeb,0x53,0xe1,0x14,0xc6,0xea,0x93,0xe2,0x61,0x52,0x65,0x2e,0xdb,0xac,0x33,0x21,0x03,0x92,0x5a,0x84,0x6b,0x99,0x00,0x79,0xcb,0x75,0x09,0x46,0x80,0xdd,0x5a,0x19,0x8d,0xbb,0x60,0x07,0x8a,0x81,0xe6,0xcd,0x17,0x1a,0x3e,0x41,0x84,0xa0,0x69,0xed,0xa9,0x6d,0x15,0x57,0xb1,0xcc,0xca,0x46,0x8f,0x26,0xbf,0x2c,0xf2,0xc5,0x3a,0xc3,0x9b,0xbe,0x34,0x6b}, + {0xb2,0xc0,0x78,0x3a,0x64,0x2f,0xdf,0xf3,0x7c,0x02,0x2e,0xf2,0x1e,0x97,0x3e,0x4c,0xa3,0xb5,0xc1,0x49,0x5e,0x1c,0x7d,0xec,0x2d,0xdd,0x22,0x09,0x8f,0xc1,0x12,0x20,0xd3,0xf2,0x71,0x65,0x65,0x69,0xfc,0x11,0x7a,0x73,0x0e,0x53,0x45,0xe8,0xc9,0xc6,0x35,0x50,0xfe,0xd4,0xa2,0xe7,0x3a,0xe3,0x0b,0xd3,0x6d,0x2e,0xb6,0xc7,0xb9,0x01,0x29,0x9d,0xc8,0x5a,0xe5,0x55,0x0b,0x88,0x63,0xa7,0xa0,0x45,0x1f,0x24,0x83,0x14,0x1f,0x6c,0xe7,0xc2,0xdf,0xef,0x36,0x3d,0xe8,0xad,0x4b,0x4e,0x78,0x5b,0xaf,0x08}, + {0x33,0x25,0x1f,0x88,0xdc,0x99,0x34,0x28,0xb6,0x23,0x93,0x77,0xda,0x25,0x05,0x9d,0xf4,0x41,0x34,0x67,0xfb,0xdd,0x7a,0x89,0x8d,0x16,0x3a,0x16,0x71,0x9d,0xb7,0x32,0x4b,0x2c,0xcc,0x89,0xd2,0x14,0x73,0xe2,0x8d,0x17,0x87,0xa2,0x11,0xbd,0xe4,0x4b,0xce,0x64,0x33,0xfa,0xd6,0x28,0xd5,0x18,0x6e,0x82,0xd9,0xaf,0xd5,0xc1,0x23,0x64,0x6a,0xb3,0xfc,0xed,0xd9,0xf8,0x85,0xcc,0xf9,0xe5,0x46,0x37,0x8f,0xc2,0xbc,0x22,0xcd,0xd3,0xe5,0xf9,0x38,0xe3,0x9d,0xe4,0xcc,0x2d,0x3e,0xc1,0xfb,0x5e,0x0a,0x48}, + {0x71,0x20,0x62,0x01,0x0b,0xe7,0x51,0x0b,0xc5,0xaf,0x1d,0x8b,0xcf,0x05,0xb5,0x06,0xcd,0xab,0x5a,0xef,0x61,0xb0,0x6b,0x2c,0x31,0xbf,0xb7,0x0c,0x60,0x27,0xaa,0x47,0x1f,0x22,0xce,0x42,0xe4,0x4c,0x61,0xb6,0x28,0x39,0x05,0x4c,0xcc,0x9d,0x19,0x6e,0x03,0xbe,0x1c,0xdc,0xa4,0xb4,0x3f,0x66,0x06,0x8e,0x1c,0x69,0x47,0x1d,0xb3,0x24,0xc3,0xf8,0x15,0xc0,0xed,0x1e,0x54,0x2a,0x7c,0x3f,0x69,0x7c,0x7e,0xfe,0xa4,0x11,0xd6,0x78,0xa2,0x4e,0x13,0x66,0xaf,0xf0,0x94,0xa0,0xdd,0x14,0x5d,0x58,0x5b,0x54}, + {0x0f,0x3a,0xd4,0xa0,0x5e,0x27,0xbf,0x67,0xbe,0xee,0x9b,0x08,0x34,0x8e,0xe6,0xad,0x2e,0xe7,0x79,0xd4,0x4c,0x13,0x89,0x42,0x54,0x54,0xba,0x32,0xc3,0xf9,0x62,0x0f,0xe1,0x21,0xb3,0xe3,0xd0,0xe4,0x04,0x62,0x95,0x1e,0xff,0x28,0x7a,0x63,0xaa,0x3b,0x9e,0xbd,0x99,0x5b,0xfd,0xcf,0x0c,0x0b,0x71,0xd0,0xc8,0x64,0x3e,0xdc,0x22,0x4d,0x39,0x5f,0x3b,0xd6,0x89,0x65,0xb4,0xfc,0x61,0xcf,0xcb,0x57,0x3f,0x6a,0xae,0x5c,0x05,0xfa,0x3a,0x95,0xd2,0xc2,0xba,0xfe,0x36,0x14,0x37,0x36,0x1a,0xa0,0x0f,0x1c}, + {0xff,0x3d,0x94,0x22,0xb6,0x04,0xc6,0xd2,0xa0,0xb3,0xcf,0x44,0xce,0xbe,0x8c,0xbc,0x78,0x86,0x80,0x97,0xf3,0x4f,0x25,0x5d,0xbf,0xa6,0x1c,0x3b,0x4f,0x61,0xa3,0x0f,0x50,0x6a,0x93,0x8c,0x0e,0x2b,0x08,0x69,0xb6,0xc5,0xda,0xc1,0x35,0xa0,0xc9,0xf9,0x34,0xb6,0xdf,0xc4,0x54,0x3e,0xb7,0x6f,0x40,0xc1,0x2b,0x1d,0x9b,0x41,0x05,0x40,0xf0,0x82,0xbe,0xb9,0xbd,0xfe,0x03,0xa0,0x90,0xac,0x44,0x3a,0xaf,0xc1,0x89,0x20,0x8e,0xfa,0x54,0x19,0x91,0x9f,0x49,0xf8,0x42,0xab,0x40,0xef,0x8a,0x21,0xba,0x1f}, + {0x3e,0xf5,0xc8,0xfa,0x48,0x94,0x54,0xab,0x41,0x37,0xa6,0x7b,0x9a,0xe8,0xf6,0x81,0x01,0x5e,0x2b,0x6c,0x7d,0x6c,0xfd,0x74,0x42,0x6e,0xc8,0xa8,0xca,0x3a,0x2e,0x39,0x94,0x01,0x7b,0x3e,0x04,0x57,0x3e,0x4f,0x7f,0xaf,0xda,0x08,0xee,0x3e,0x1d,0xa8,0xf1,0xde,0xdc,0x99,0xab,0xc6,0x39,0xc8,0xd5,0x61,0x77,0xff,0x13,0x5d,0x53,0x6c,0xaf,0x35,0x8a,0x3e,0xe9,0x34,0xbd,0x4c,0x16,0xe8,0x87,0x58,0x44,0x81,0x07,0x2e,0xab,0xb0,0x9a,0xf2,0x76,0x9c,0x31,0x19,0x3b,0xc1,0x0a,0xd5,0xe4,0x7f,0xe1,0x25}, + {0x76,0xf6,0x04,0x1e,0xd7,0x9b,0x28,0x0a,0x95,0x0f,0x42,0xd6,0x52,0x1c,0x8e,0x20,0xab,0x1f,0x69,0x34,0xb0,0xd8,0x86,0x51,0x51,0xb3,0x9f,0x2a,0x44,0x51,0x57,0x25,0xa7,0x21,0xf1,0x76,0xf5,0x7f,0x5f,0x91,0xe3,0x87,0xcd,0x2f,0x27,0x32,0x4a,0xc3,0x26,0xe5,0x1b,0x4d,0xde,0x2f,0xba,0xcc,0x9b,0x89,0x69,0x89,0x8f,0x82,0xba,0x6b,0x01,0x39,0xfe,0x90,0x66,0xbc,0xd1,0xe2,0xd5,0x7a,0x99,0xa0,0x18,0x4a,0xb5,0x4c,0xd4,0x60,0x84,0xaf,0x14,0x69,0x1d,0x97,0xe4,0x7b,0x6b,0x7f,0x4f,0x50,0x9d,0x55}, + {0xd5,0x54,0xeb,0xb3,0x78,0x83,0x73,0xa7,0x7c,0x3c,0x55,0xa5,0x66,0xd3,0x69,0x1d,0xba,0x00,0x28,0xf9,0x62,0xcf,0x26,0x0a,0x17,0x32,0x7e,0x80,0xd5,0x12,0xab,0x01,0xfd,0x66,0xd2,0xf6,0xe7,0x91,0x48,0x9c,0x1b,0x78,0x07,0x03,0x9b,0xa1,0x44,0x07,0x3b,0xe2,0x61,0x60,0x1d,0x8f,0x38,0x88,0x0e,0xd5,0x4b,0x35,0xa3,0xa6,0x3e,0x12,0x96,0x2d,0xe3,0x41,0x90,0x18,0x8d,0x11,0x48,0x58,0x31,0xd8,0xc2,0xe3,0xed,0xb9,0xd9,0x45,0x32,0xd8,0x71,0x42,0xab,0x1e,0x54,0xa1,0x18,0xc9,0xe2,0x61,0x39,0x4a}, + {0xa0,0xbb,0xe6,0xf8,0xe0,0x3b,0xdc,0x71,0x0a,0xe3,0xff,0x7e,0x34,0xf8,0xce,0xd6,0x6a,0x47,0x3a,0xe1,0x5f,0x42,0x92,0xa9,0x63,0xb7,0x1d,0xfb,0xe3,0xbc,0xd6,0x2c,0x1e,0x3f,0x23,0xf3,0x44,0xd6,0x27,0x03,0x16,0xf0,0xfc,0x34,0x0e,0x26,0x9a,0x49,0x79,0xb9,0xda,0xf2,0x16,0xa7,0xb5,0x83,0x1f,0x11,0xd4,0x9b,0xad,0xee,0xac,0x68,0x10,0xc2,0xd7,0xf3,0x0e,0xc9,0xb4,0x38,0x0c,0x04,0xad,0xb7,0x24,0x6e,0x8e,0x30,0x23,0x3e,0xe7,0xb7,0xf1,0xd9,0x60,0x38,0x97,0xf5,0x08,0xb5,0xd5,0x60,0x57,0x59}, + {0x97,0x63,0xaa,0x04,0xe1,0xbf,0x29,0x61,0xcb,0xfc,0xa7,0xa4,0x08,0x00,0x96,0x8f,0x58,0x94,0x90,0x7d,0x89,0xc0,0x8b,0x3f,0xa9,0x91,0xb2,0xdc,0x3e,0xa4,0x9f,0x70,0x90,0x27,0x02,0xfd,0xeb,0xcb,0x2a,0x88,0x60,0x57,0x11,0xc4,0x05,0x33,0xaf,0x89,0xf4,0x73,0x34,0x7d,0xe3,0x92,0xf4,0x65,0x2b,0x5a,0x51,0x54,0xdf,0xc5,0xb2,0x2c,0xca,0x2a,0xfd,0x63,0x8c,0x5d,0x0a,0xeb,0xff,0x4e,0x69,0x2e,0x66,0xc1,0x2b,0xd2,0x3a,0xb0,0xcb,0xf8,0x6e,0xf3,0x23,0x27,0x1f,0x13,0xc8,0xf0,0xec,0x29,0xf0,0x70}, + {0x33,0x3e,0xed,0x2e,0xb3,0x07,0x13,0x46,0xe7,0x81,0x55,0xa4,0x33,0x2f,0x04,0xae,0x66,0x03,0x5f,0x19,0xd3,0x49,0x44,0xc9,0x58,0x48,0x31,0x6c,0x8a,0x5d,0x7d,0x0b,0xb9,0xb0,0x10,0x5e,0xaa,0xaf,0x6a,0x2a,0xa9,0x1a,0x04,0xef,0x70,0xa3,0xf0,0x78,0x1f,0xd6,0x3a,0xaa,0x77,0xfb,0x3e,0x77,0xe1,0xd9,0x4b,0xa7,0xa2,0xa5,0xec,0x44,0x43,0xd5,0x95,0x7b,0x32,0x48,0xd4,0x25,0x1d,0x0f,0x34,0xa3,0x00,0x83,0xd3,0x70,0x2b,0xc5,0xe1,0x60,0x1c,0x53,0x1c,0xde,0xe4,0xe9,0x7d,0x2c,0x51,0x24,0x22,0x27}, + {0x2e,0x34,0xc5,0x49,0xaf,0x92,0xbc,0x1a,0xd0,0xfa,0xe6,0xb2,0x11,0xd8,0xee,0xff,0x29,0x4e,0xc8,0xfc,0x8d,0x8c,0xa2,0xef,0x43,0xc5,0x4c,0xa4,0x18,0xdf,0xb5,0x11,0xfc,0x75,0xa9,0x42,0x8a,0xbb,0x7b,0xbf,0x58,0xa3,0xad,0x96,0x77,0x39,0x5c,0x8c,0x48,0xaa,0xed,0xcd,0x6f,0xc7,0x7f,0xe2,0xa6,0x20,0xbc,0xf6,0xd7,0x5f,0x73,0x19,0x66,0x42,0xc8,0x42,0xd0,0x90,0xab,0xe3,0x7e,0x54,0x19,0x7f,0x0f,0x8e,0x84,0xeb,0xb9,0x97,0xa4,0x65,0xd0,0xa1,0x03,0x25,0x5f,0x89,0xdf,0x91,0x11,0x91,0xef,0x0f} +}; diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-basepoint-table.h b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-basepoint-table.h new file mode 100644 index 000000000..9c0cdfc0c --- /dev/null +++ b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-basepoint-table.h @@ -0,0 +1,2 @@ +/* multiples of the base point in packed {ysubx, xaddy, t2d} form */ +extern const uint8_t ALIGN(16) ge25519_niels_base_multiples[256][96]; diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-impl-base.c b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-impl-base.c new file mode 100644 index 000000000..889710bfc --- /dev/null +++ b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-impl-base.c @@ -0,0 +1,751 @@ +#include +#include "ed25519-donna.h" +#include "memzero.h" + +/* sqrt(x) is such an integer y that 0 <= y <= p - 1, y % 2 = 0, and y^2 = x (mod p). */ +/* d = -121665 / 121666 */ +#if !defined(NDEBUG) +static const bignum25519 ALIGN(16) fe_d = { + 0x35978a3, 0x0d37284, 0x3156ebd, 0x06a0a0e, 0x001c029, 0x179e898, 0x3a03cbb, 0x1ce7198, 0x2e2b6ff, 0x1480db3}; /* d */ +#endif +static const bignum25519 ALIGN(16) fe_sqrtm1 = { + 0x20ea0b0, 0x186c9d2, 0x08f189d, 0x035697f, 0x0bd0c60, 0x1fbd7a7, 0x2804c9e, 0x1e16569, 0x004fc1d, 0x0ae0c92}; /* sqrt(-1) */ +//static const bignum25519 ALIGN(16) fe_d2 = { +// 0x2b2f159, 0x1a6e509, 0x22add7a, 0x0d4141d, 0x0038052, 0x0f3d130, 0x3407977, 0x19ce331, 0x1c56dff, 0x0901b67}; /* 2 * d */ + +/* A = 2 * (1 - d) / (1 + d) = 486662 */ +static const bignum25519 ALIGN(16) fe_ma2 = { + 0x33de3c9, 0x1fff236, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff}; /* -A^2 */ +static const bignum25519 ALIGN(16) fe_ma = { + 0x3f892e7, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff}; /* -A */ +static const bignum25519 ALIGN(16) fe_fffb1 = { + 0x1e3bdff, 0x025a2b3, 0x18e5bab, 0x0ba36ac, 0x0b9afed, 0x004e61c, 0x31d645f, 0x09d1bea, 0x102529e, 0x0063810}; /* sqrt(-2 * A * (A + 2)) */ +static const bignum25519 ALIGN(16) fe_fffb2 = { + 0x383650d, 0x066df27, 0x10405a4, 0x1cfdd48, 0x2b887f2, 0x1e9a041, 0x1d7241f, 0x0612dc5, 0x35fba5d, 0x0cbe787}; /* sqrt(2 * A * (A + 2)) */ +static const bignum25519 ALIGN(16) fe_fffb3 = { + 0x0cfd387, 0x1209e3a, 0x3bad4fc, 0x18ad34d, 0x2ff6c02, 0x0f25d12, 0x15cdfe0, 0x0e208ed, 0x32eb3df, 0x062d7bb}; /* sqrt(-sqrt(-1) * A * (A + 2)) */ +static const bignum25519 ALIGN(16) fe_fffb4 = { + 0x2b39186, 0x14640ed, 0x14930a7, 0x04509fa, 0x3b91bf0, 0x0f7432e, 0x07a443f, 0x17f24d8, 0x031067d, 0x0690fcc}; /* sqrt(sqrt(-1) * A * (A + 2)) */ + + +/* + Timing safe memory compare +*/ +int ed25519_verify(const unsigned char *x, const unsigned char *y, size_t len) { + size_t differentbits = 0; + while (len--) + differentbits |= (*x++ ^ *y++); + return (int) (1 & ((differentbits - 1) >> 8)); +} + +/* + conversions +*/ + +void ge25519_p1p1_to_partial(ge25519 *r, const ge25519_p1p1 *p) { + curve25519_mul(r->x, p->x, p->t); + curve25519_mul(r->y, p->y, p->z); + curve25519_mul(r->z, p->z, p->t); +} + +void ge25519_p1p1_to_full(ge25519 *r, const ge25519_p1p1 *p) { + curve25519_mul(r->x, p->x, p->t); + curve25519_mul(r->y, p->y, p->z); + curve25519_mul(r->z, p->z, p->t); + curve25519_mul(r->t, p->x, p->y); +} + +void ge25519_full_to_pniels(ge25519_pniels *p, const ge25519 *r) { + curve25519_sub(p->ysubx, r->y, r->x); + curve25519_add(p->xaddy, r->y, r->x); + curve25519_copy(p->z, r->z); + curve25519_mul(p->t2d, r->t, ge25519_ec2d); +} + +/* + adding & doubling +*/ + +void ge25519_double_p1p1(ge25519_p1p1 *r, const ge25519 *p) { + bignum25519 a = {0}, b = {0}, c = {0}; + + curve25519_square(a, p->x); + curve25519_square(b, p->y); + curve25519_square(c, p->z); + curve25519_add_reduce(c, c, c); + curve25519_add(r->x, p->x, p->y); + curve25519_square(r->x, r->x); + curve25519_add(r->y, b, a); + curve25519_sub(r->z, b, a); + curve25519_sub_after_basic(r->x, r->x, r->y); + curve25519_sub_after_basic(r->t, c, r->z); +} + +#ifndef ED25519_NO_PRECOMP +void ge25519_nielsadd2_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_niels *q, unsigned char signbit) { + const bignum25519 *qb = (const bignum25519 *)q; + bignum25519 *rb = (bignum25519 *)r; + bignum25519 a = {0}, b = {0}, c = {0}; + + curve25519_sub(a, p->y, p->x); + curve25519_add(b, p->y, p->x); + curve25519_mul(a, a, qb[signbit]); /* x for +, y for - */ + curve25519_mul(r->x, b, qb[signbit^1]); /* y for +, x for - */ + curve25519_add(r->y, r->x, a); + curve25519_sub(r->x, r->x, a); + curve25519_mul(c, p->t, q->t2d); + curve25519_add_reduce(r->t, p->z, p->z); + curve25519_copy(r->z, r->t); + curve25519_add(rb[2+signbit], rb[2+signbit], c); /* z for +, t for - */ + curve25519_sub(rb[2+(signbit^1)], rb[2+(signbit^1)], c); /* t for +, z for - */ +} +#endif + +void ge25519_pnielsadd_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_pniels *q, unsigned char signbit) { + bignum25519 q1, q2 = {0}; + bignum25519 a = {0}, b = {0}, c = {0}; + + curve25519_sub(a, p->y, p->x); + curve25519_add(b, p->y, p->x); + + // a = a * ysubx, r->x = b * xaddy for signbit = 0 + // a = a * xaddy, r->x = b * ysubx for signbit = 1 + curve25519_copy(q1, q->ysubx); + curve25519_copy(q2, q->xaddy); + curve25519_swap_conditional(q1, q2, signbit); + curve25519_mul(a, a, q1); + curve25519_mul(r->x, b, q2); + + curve25519_add(r->y, r->x, a); + curve25519_sub(r->x, r->x, a); + curve25519_mul(c, p->t, q->t2d); + curve25519_mul(r->t, p->z, q->z); + curve25519_add_reduce(r->t, r->t, r->t); + curve25519_copy(r->z, r->t); + + // r->z = r->z + c, r->t = r->t - c for signbit == 0 + // r->z = r->z - c, r->t = r->t + c for signbit == 1 + curve25519_swap_conditional(r->z, r->t, signbit); + curve25519_add(r->z, r->z, c); + curve25519_sub(r->t, r->t, c); + curve25519_swap_conditional(r->z, r->t, signbit); +} + +void ge25519_double_partial(ge25519 *r, const ge25519 *p) { + ge25519_p1p1 t = {0}; + ge25519_double_p1p1(&t, p); + ge25519_p1p1_to_partial(r, &t); +} + +void ge25519_double(ge25519 *r, const ge25519 *p) { + ge25519_p1p1 t = {0}; + ge25519_double_p1p1(&t, p); + ge25519_p1p1_to_full(r, &t); +} + +void ge25519_nielsadd2(ge25519 *r, const ge25519_niels *q) { + bignum25519 a = {0}, b = {0}, c = {0}, e = {0}, f = {0}, g = {0}, h = {0}; + + curve25519_sub(a, r->y, r->x); + curve25519_add(b, r->y, r->x); + curve25519_mul(a, a, q->ysubx); + curve25519_mul(e, b, q->xaddy); + curve25519_add(h, e, a); + curve25519_sub(e, e, a); + curve25519_mul(c, r->t, q->t2d); + curve25519_add(f, r->z, r->z); + curve25519_add_after_basic(g, f, c); + curve25519_sub_after_basic(f, f, c); + curve25519_mul(r->x, e, f); + curve25519_mul(r->y, h, g); + curve25519_mul(r->z, g, f); + curve25519_mul(r->t, e, h); +} + +void ge25519_pnielsadd(ge25519_pniels *r, const ge25519 *p, const ge25519_pniels *q) { + bignum25519 a = {0}, b = {0}, c = {0}, x = {0}, y = {0}, z = {0}, t = {0}; + + curve25519_sub(a, p->y, p->x); + curve25519_add(b, p->y, p->x); + curve25519_mul(a, a, q->ysubx); + curve25519_mul(x, b, q->xaddy); + curve25519_add(y, x, a); + curve25519_sub(x, x, a); + curve25519_mul(c, p->t, q->t2d); + curve25519_mul(t, p->z, q->z); + curve25519_add(t, t, t); + curve25519_add_after_basic(z, t, c); + curve25519_sub_after_basic(t, t, c); + curve25519_mul(r->xaddy, x, t); + curve25519_mul(r->ysubx, y, z); + curve25519_mul(r->z, z, t); + curve25519_mul(r->t2d, x, y); + curve25519_copy(y, r->ysubx); + curve25519_sub(r->ysubx, r->ysubx, r->xaddy); + curve25519_add(r->xaddy, r->xaddy, y); + curve25519_mul(r->t2d, r->t2d, ge25519_ec2d); +} + + +/* + pack & unpack +*/ + +void ge25519_pack(unsigned char r[32], const ge25519 *p) { + bignum25519 tx = {0}, ty = {0}, zi = {0}; + unsigned char parity[32] = {0}; + curve25519_recip(zi, p->z); + curve25519_mul(tx, p->x, zi); + curve25519_mul(ty, p->y, zi); + curve25519_contract(r, ty); + curve25519_contract(parity, tx); + r[31] ^= ((parity[0] & 1) << 7); +} + +int ge25519_unpack_negative_vartime(ge25519 *r, const unsigned char p[32]) { + const unsigned char zero[32] = {0}; + const bignum25519 one = {1}; + unsigned char parity = p[31] >> 7; + unsigned char check[32] = {0}; + bignum25519 t = {0}, root = {0}, num = {0}, den = {0}, d3 = {0}; + + curve25519_expand(r->y, p); + curve25519_copy(r->z, one); + curve25519_square(num, r->y); /* x = y^2 */ + curve25519_mul(den, num, ge25519_ecd); /* den = dy^2 */ + curve25519_sub_reduce(num, num, r->z); /* x = y^1 - 1 */ + curve25519_add(den, den, r->z); /* den = dy^2 + 1 */ + + /* Computation of sqrt(num/den) */ + /* 1.: computation of num^((p-5)/8)*den^((7p-35)/8) = (num*den^7)^((p-5)/8) */ + curve25519_square(t, den); + curve25519_mul(d3, t, den); + curve25519_square(r->x, d3); + curve25519_mul(r->x, r->x, den); + curve25519_mul(r->x, r->x, num); + curve25519_pow_two252m3(r->x, r->x); + + /* 2. computation of r->x = num * den^3 * (num*den^7)^((p-5)/8) */ + curve25519_mul(r->x, r->x, d3); + curve25519_mul(r->x, r->x, num); + + /* 3. Check if either of the roots works: */ + curve25519_square(t, r->x); + curve25519_mul(t, t, den); + curve25519_sub_reduce(root, t, num); + curve25519_contract(check, root); + if (!ed25519_verify(check, zero, 32)) { + curve25519_add_reduce(t, t, num); + curve25519_contract(check, t); + if (!ed25519_verify(check, zero, 32)) + return 0; + curve25519_mul(r->x, r->x, ge25519_sqrtneg1); + } + + curve25519_contract(check, r->x); + if ((check[0] & 1) == parity) { + curve25519_copy(t, r->x); + curve25519_neg(r->x, t); + } + curve25519_mul(r->t, r->x, r->y); + return 1; +} + +/* + scalarmults +*/ + +void ge25519_set_neutral(ge25519 *r) +{ + memzero(r, sizeof(ge25519)); + r->y[0] = 1; + r->z[0] = 1; +} + +#define S1_SWINDOWSIZE 5 +#define S1_TABLE_SIZE (1<<(S1_SWINDOWSIZE-2)) +#ifdef ED25519_NO_PRECOMP +#define S2_SWINDOWSIZE 5 +#else +#define S2_SWINDOWSIZE 7 +#endif +#define S2_TABLE_SIZE (1<<(S2_SWINDOWSIZE-2)) + +/* computes [s1]p1 + [s2]base */ +void ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256modm s1, const bignum256modm s2) { + signed char slide1[256] = {0}, slide2[256] = {0}; + ge25519_pniels pre1[S1_TABLE_SIZE] = {0}; +#ifdef ED25519_NO_PRECOMP + ge25519_pniels pre2[S2_TABLE_SIZE] = {0}; +#endif + ge25519 dp = {0}; + ge25519_p1p1 t = {0}; + int32_t i = 0; + + memzero(&t, sizeof(ge25519_p1p1)); + contract256_slidingwindow_modm(slide1, s1, S1_SWINDOWSIZE); + contract256_slidingwindow_modm(slide2, s2, S2_SWINDOWSIZE); + + ge25519_double(&dp, p1); + ge25519_full_to_pniels(pre1, p1); + for (i = 0; i < S1_TABLE_SIZE - 1; i++) + ge25519_pnielsadd(&pre1[i+1], &dp, &pre1[i]); + +#ifdef ED25519_NO_PRECOMP + ge25519_double(&dp, &ge25519_basepoint); + ge25519_full_to_pniels(pre2, &ge25519_basepoint); + for (i = 0; i < S2_TABLE_SIZE - 1; i++) + ge25519_pnielsadd(&pre2[i+1], &dp, &pre2[i]); +#endif + + ge25519_set_neutral(r); + + i = 255; + while ((i >= 0) && !(slide1[i] | slide2[i])) + i--; + + for (; i >= 0; i--) { + ge25519_double_p1p1(&t, r); + + if (slide1[i]) { + ge25519_p1p1_to_full(r, &t); + ge25519_pnielsadd_p1p1(&t, r, &pre1[abs(slide1[i]) / 2], (unsigned char)slide1[i] >> 7); + } + + if (slide2[i]) { + ge25519_p1p1_to_full(r, &t); +#ifdef ED25519_NO_PRECOMP + ge25519_pnielsadd_p1p1(&t, r, &pre2[abs(slide2[i]) / 2], (unsigned char)slide2[i] >> 7); +#else + ge25519_nielsadd2_p1p1(&t, r, &ge25519_niels_sliding_multiples[abs(slide2[i]) / 2], (unsigned char)slide2[i] >> 7); +#endif + } + + ge25519_p1p1_to_partial(r, &t); + } + curve25519_mul(r->t, t.x, t.y); + memzero(slide1, sizeof(slide1)); + memzero(slide2, sizeof(slide2)); +} + +/* computes [s1]p1 + [s2]p2 */ +#if USE_MONERO +void ge25519_double_scalarmult_vartime2(ge25519 *r, const ge25519 *p1, const bignum256modm s1, const ge25519 *p2, const bignum256modm s2) { + signed char slide1[256] = {0}, slide2[256] = {0}; + ge25519_pniels pre1[S1_TABLE_SIZE] = {0}; + ge25519_pniels pre2[S1_TABLE_SIZE] = {0}; + ge25519 dp = {0}; + ge25519_p1p1 t = {0}; + int32_t i = 0; + + memzero(&t, sizeof(ge25519_p1p1)); + contract256_slidingwindow_modm(slide1, s1, S1_SWINDOWSIZE); + contract256_slidingwindow_modm(slide2, s2, S1_SWINDOWSIZE); + + ge25519_double(&dp, p1); + ge25519_full_to_pniels(pre1, p1); + for (i = 0; i < S1_TABLE_SIZE - 1; i++) + ge25519_pnielsadd(&pre1[i+1], &dp, &pre1[i]); + + ge25519_double(&dp, p2); + ge25519_full_to_pniels(pre2, p2); + for (i = 0; i < S1_TABLE_SIZE - 1; i++) + ge25519_pnielsadd(&pre2[i+1], &dp, &pre2[i]); + + ge25519_set_neutral(r); + + i = 255; + while ((i >= 0) && !(slide1[i] | slide2[i])) + i--; + + for (; i >= 0; i--) { + ge25519_double_p1p1(&t, r); + + if (slide1[i]) { + ge25519_p1p1_to_full(r, &t); + ge25519_pnielsadd_p1p1(&t, r, &pre1[abs(slide1[i]) / 2], (unsigned char)slide1[i] >> 7); + } + + if (slide2[i]) { + ge25519_p1p1_to_full(r, &t); + ge25519_pnielsadd_p1p1(&t, r, &pre2[abs(slide2[i]) / 2], (unsigned char)slide2[i] >> 7); + } + + ge25519_p1p1_to_partial(r, &t); + } + curve25519_mul(r->t, t.x, t.y); + memzero(slide1, sizeof(slide1)); + memzero(slide2, sizeof(slide2)); +} +#endif + +/* + * The following conditional move stuff uses conditional moves. + * I will check on which compilers this works, and provide suitable + * workarounds for those where it doesn't. + * + * This works on gcc 4.x and above with -O3. Don't use -O2, this will + * cause the code to not generate conditional moves. Don't use any -march= + * with less than i686 on x86 + */ +static void ge25519_cmove_stride4(unsigned long * r, unsigned long * p, unsigned long * pos, unsigned long * n, int stride) { + unsigned long x0=r[0], x1=r[1], x2=r[2], x3=r[3], y0 = 0, y1 = 0, y2 = 0, y3 = 0; + for(; p= 0; i--) { + int k=abs(slide1[i]); + ge25519_double_partial(r, r); + ge25519_double_partial(r, r); + ge25519_double_partial(r, r); + ge25519_double_p1p1(&t, r); + ge25519_move_conditional_pniels_array(&pre, pre1, k, 9); + ge25519_p1p1_to_full(r, &t); + ge25519_pnielsadd_p1p1(&t, r, &pre, (unsigned char)slide1[i] >> 7); + ge25519_p1p1_to_partial(r, &t); + } + curve25519_mul(r->t, t.x, t.y); + memzero(slide1, sizeof(slide1)); +} + +void ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b) { + bignum25519 neg = {0}; + uint32_t sign = (uint32_t)((unsigned char)b >> 7); + uint32_t mask = ~(sign - 1); + uint32_t u = (b + mask) ^ mask; + + /* ysubx, xaddy, t2d in packed form. initialize to ysubx = 1, xaddy = 1, t2d = 0 */ + uint8_t packed[96] = {0}; + packed[0] = 1; + packed[32] = 1; + + ge25519_move_conditional_niels_array((ge25519_niels *)packed, &table[pos*8], u-1, 8); + + /* expand in to t */ + curve25519_expand(t->ysubx, packed + 0); + curve25519_expand(t->xaddy, packed + 32); + curve25519_expand(t->t2d , packed + 64); + + /* adjust for sign */ + curve25519_swap_conditional(t->ysubx, t->xaddy, sign); + curve25519_neg(neg, t->t2d); + curve25519_swap_conditional(t->t2d, neg, sign); +} + +/* computes [s]basepoint */ +void ge25519_scalarmult_base_niels(ge25519 *r, const uint8_t basepoint_table[256][96], const bignum256modm s) { + signed char b[64] = {0}; + uint32_t i = 0; + ge25519_niels t = {0}; + + contract256_window4_modm(b, s); + + ge25519_scalarmult_base_choose_niels(&t, basepoint_table, 0, b[1]); + curve25519_sub_reduce(r->x, t.xaddy, t.ysubx); + curve25519_add_reduce(r->y, t.xaddy, t.ysubx); + memzero(r->z, sizeof(bignum25519)); + curve25519_copy(r->t, t.t2d); + r->z[0] = 2; + for (i = 3; i < 64; i += 2) { + ge25519_scalarmult_base_choose_niels(&t, basepoint_table, i / 2, b[i]); + ge25519_nielsadd2(r, &t); + } + ge25519_double_partial(r, r); + ge25519_double_partial(r, r); + ge25519_double_partial(r, r); + ge25519_double(r, r); + ge25519_scalarmult_base_choose_niels(&t, basepoint_table, 0, b[0]); + curve25519_mul(t.t2d, t.t2d, ge25519_ecd); + ge25519_nielsadd2(r, &t); + for(i = 2; i < 64; i += 2) { + ge25519_scalarmult_base_choose_niels(&t, basepoint_table, i / 2, b[i]); + ge25519_nielsadd2(r, &t); + } +} + +int ge25519_check(const ge25519 *r){ + /* return (z % q != 0 and + x * y % q == z * t % q and + (y * y - x * x - z * z - ed25519.d * t * t) % q == 0) + */ + + bignum25519 z={0}, lhs={0}, rhs={0}, tmp={0}, res={0}; + curve25519_reduce(z, r->z); + + curve25519_mul(lhs, r->x, r->y); + curve25519_mul(rhs, r->z, r->t); + curve25519_sub_reduce(lhs, lhs, rhs); + + curve25519_square(res, r->y); + curve25519_square(tmp, r->x); + curve25519_sub_reduce(res, res, tmp); + curve25519_square(tmp, r->z); + curve25519_sub_reduce(res, res, tmp); + curve25519_square(tmp, r->t); + curve25519_mul(tmp, tmp, ge25519_ecd); + curve25519_sub_reduce(res, res, tmp); + + const int c1 = curve25519_isnonzero(z); + const int c2 = curve25519_isnonzero(lhs); + const int c3 = curve25519_isnonzero(res); + return c1 & (c2^0x1) & (c3^0x1); +} + +int ge25519_eq(const ge25519 *a, const ge25519 *b){ + int eq = 1; + bignum25519 t1={0}, t2={0}; + + eq &= ge25519_check(a); + eq &= ge25519_check(b); + + curve25519_mul(t1, a->x, b->z); + curve25519_mul(t2, b->x, a->z); + curve25519_sub_reduce(t1, t1, t2); + eq &= curve25519_isnonzero(t1) ^ 1; + + curve25519_mul(t1, a->y, b->z); + curve25519_mul(t2, b->y, a->z); + curve25519_sub_reduce(t1, t1, t2); + eq &= curve25519_isnonzero(t1) ^ 1; + + return eq; +} + +void ge25519_copy(ge25519 *dst, const ge25519 *src){ + curve25519_copy(dst->x, src->x); + curve25519_copy(dst->y, src->y); + curve25519_copy(dst->z, src->z); + curve25519_copy(dst->t, src->t); +} + +void ge25519_set_base(ge25519 *r){ + ge25519_copy(r, &ge25519_basepoint); +} + +void ge25519_mul8(ge25519 *r, const ge25519 *t) { + ge25519_double_partial(r, t); + ge25519_double_partial(r, r); + ge25519_double(r, r); +} + +void ge25519_neg_partial(ge25519 *r){ + curve25519_neg(r->x, r->x); +} + +void ge25519_neg_full(ge25519 *r){ + curve25519_neg(r->x, r->x); + curve25519_neg(r->t, r->t); +} + +void ge25519_reduce(ge25519 *r, const ge25519 *t){ + curve25519_reduce(r->x, t->x); + curve25519_reduce(r->y, t->y); + curve25519_reduce(r->z, t->z); + curve25519_reduce(r->t, t->t); +} + +void ge25519_norm(ge25519 *r, const ge25519 * t){ + bignum25519 zinv = {0}; + curve25519_recip(zinv, t->z); + curve25519_mul(r->x, t->x, zinv); + curve25519_mul(r->y, t->y, zinv); + curve25519_mul(r->t, r->x, r->y); + curve25519_set(r->z, 1); +} + +void ge25519_add(ge25519 *r, const ge25519 *p, const ge25519 *q, unsigned char signbit) { + ge25519_pniels P_ni = {0}; + ge25519_p1p1 P_11 = {0}; + + ge25519_full_to_pniels(&P_ni, q); + ge25519_pnielsadd_p1p1(&P_11, p, &P_ni, signbit); + ge25519_p1p1_to_full(r, &P_11); +} + +void ge25519_fromfe_frombytes_vartime(ge25519 *r, const unsigned char *s){ + bignum25519 u={0}, v={0}, w={0}, x={0}, y={0}, z={0}; + unsigned char sign = 0; + + curve25519_expand_reduce(u, s); + + curve25519_square(v, u); + curve25519_add_reduce(v, v, v); /* 2 * u^2 */ + curve25519_set(w, 1); + curve25519_add_reduce(w, v, w); /* w = 2 * u^2 + 1 */ + + curve25519_square(x, w); /* w^2 */ + curve25519_mul(y, fe_ma2, v); /* -2 * A^2 * u^2 */ + curve25519_add_reduce(x, x, y); /* x = w^2 - 2 * A^2 * u^2 */ + + curve25519_divpowm1(r->x, w, x); /* (w / x)^(m + 1) */ + curve25519_square(y, r->x); + curve25519_mul(x, y, x); + curve25519_sub_reduce(y, w, x); + curve25519_copy(z, fe_ma); + + if (curve25519_isnonzero(y)) { + curve25519_add_reduce(y, w, x); + if (curve25519_isnonzero(y)) { + goto negative; + } else { + curve25519_mul(r->x, r->x, fe_fffb1); + } + } else { + curve25519_mul(r->x, r->x, fe_fffb2); + } + curve25519_mul(r->x, r->x, u); /* u * sqrt(2 * A * (A + 2) * w / x) */ + curve25519_mul(z, z, v); /* -2 * A * u^2 */ + sign = 0; + goto setsign; +negative: + curve25519_mul(x, x, fe_sqrtm1); + curve25519_sub_reduce(y, w, x); + if (curve25519_isnonzero(y)) { + assert((curve25519_add_reduce(y, w, x), !curve25519_isnonzero(y))); + curve25519_mul(r->x, r->x, fe_fffb3); + } else { + curve25519_mul(r->x, r->x, fe_fffb4); + } + /* r->x = sqrt(A * (A + 2) * w / x) */ + /* z = -A */ + sign = 1; +setsign: + if (curve25519_isnegative(r->x) != sign) { + assert(curve25519_isnonzero(r->x)); + curve25519_neg(r->x, r->x); + } + curve25519_add_reduce(r->z, z, w); + curve25519_sub_reduce(r->y, z, w); + curve25519_mul(r->x, r->x, r->z); + + // Partial form, saving from T coord computation . + // Later is mul8 discarding T anyway. + // rt = ((rx * ry % q) * inv(rz)) % q + // curve25519_mul(x, r->x, r->y); + // curve25519_recip(z, r->z); + // curve25519_mul(r->t, x, z); + +#if !defined(NDEBUG) + { + bignum25519 check_x={0}, check_y={0}, check_iz={0}, check_v={0}; + curve25519_recip(check_iz, r->z); + curve25519_mul(check_x, r->x, check_iz); + curve25519_mul(check_y, r->y, check_iz); + curve25519_square(check_x, check_x); + curve25519_square(check_y, check_y); + curve25519_mul(check_v, check_x, check_y); + curve25519_mul(check_v, fe_d, check_v); + curve25519_add_reduce(check_v, check_v, check_x); + curve25519_sub_reduce(check_v, check_v, check_y); + curve25519_set(check_x, 1); + curve25519_add_reduce(check_v, check_v, check_x); + assert(!curve25519_isnonzero(check_v)); + } +#endif +} + +int ge25519_unpack_vartime(ge25519 *r, const unsigned char *s){ + int res = ge25519_unpack_negative_vartime(r, s); + ge25519_neg_full(r); + return res; +} + +void ge25519_scalarmult_base_wrapper(ge25519 *r, const bignum256modm s){ + ge25519_scalarmult_base_niels(r, ge25519_niels_base_multiples, s); +} diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-impl-base.h b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-impl-base.h new file mode 100644 index 000000000..342a6448a --- /dev/null +++ b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-impl-base.h @@ -0,0 +1,104 @@ +/* + Timing safe memory compare +*/ +int ed25519_verify(const unsigned char *x, const unsigned char *y, size_t len); + +/* + conversions +*/ + +void ge25519_p1p1_to_partial(ge25519 *r, const ge25519_p1p1 *p); + +void ge25519_p1p1_to_full(ge25519 *r, const ge25519_p1p1 *p); + +void ge25519_full_to_pniels(ge25519_pniels *p, const ge25519 *r); + +/* + adding & doubling +*/ + +void ge25519_double_p1p1(ge25519_p1p1 *r, const ge25519 *p); + +#ifndef ED25519_NO_PRECOMP +void ge25519_nielsadd2_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_niels *q, unsigned char signbit); +#endif + +/* computes [s1]p1 + [s2]p2 */ +#if USE_MONERO +void ge25519_double_scalarmult_vartime2(ge25519 *r, const ge25519 *p1, const bignum256modm s1, const ge25519 *p2, const bignum256modm s2); +#endif + +void ge25519_pnielsadd_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_pniels *q, unsigned char signbit); + +void ge25519_double_partial(ge25519 *r, const ge25519 *p); + +void ge25519_double(ge25519 *r, const ge25519 *p); + +void ge25519_nielsadd2(ge25519 *r, const ge25519_niels *q); + +void ge25519_pnielsadd(ge25519_pniels *r, const ge25519 *p, const ge25519_pniels *q); + + +/* + pack & unpack +*/ + +void ge25519_pack(unsigned char r[32], const ge25519 *p); + +int ge25519_unpack_negative_vartime(ge25519 *r, const unsigned char p[32]); + +/* + scalarmults +*/ + +void ge25519_set_neutral(ge25519 *r); + +/* computes [s1]p1 + [s2]base */ +void ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256modm s1, const bignum256modm s2); + +/* computes [s1]p1, constant time */ +void ge25519_scalarmult(ge25519 *r, const ge25519 *p1, const bignum256modm s1); + +void ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b); + +/* computes [s]basepoint */ +void ge25519_scalarmult_base_niels(ge25519 *r, const uint8_t basepoint_table[256][96], const bignum256modm s); + +/* check if r is on curve */ +int ge25519_check(const ge25519 *r); + +/* a == b */ +int ge25519_eq(const ge25519 *a, const ge25519 *b); + +/* copies one point to another */ +void ge25519_copy(ge25519 *dst, const ge25519 *src); + +/* sets B point to r */ +void ge25519_set_base(ge25519 *r); + +/* 8*P */ +void ge25519_mul8(ge25519 *r, const ge25519 *t); + +/* -P */ +void ge25519_neg_partial(ge25519 *r); + +/* -P */ +void ge25519_neg_full(ge25519 *r); + +/* reduce all coords */ +void ge25519_reduce(ge25519 *r, const ge25519 *t); + +/* normalizes coords. (x, y, 1, x*y) */ +void ge25519_norm(ge25519 *r, const ge25519 * t); + +/* Simple addition */ +void ge25519_add(ge25519 *r, const ge25519 *a, const ge25519 *b, unsigned char signbit); + +/* point from bytes, used in H_p() */ +void ge25519_fromfe_frombytes_vartime(ge25519 *r, const unsigned char *s); + +/* point from bytes */ +int ge25519_unpack_vartime(ge25519 *r, const unsigned char *s); + +/* aG, wrapper for niels base mult. */ +void ge25519_scalarmult_base_wrapper(ge25519 *r, const bignum256modm s); diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-portable.h b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-portable.h new file mode 100644 index 000000000..ceeb55741 --- /dev/null +++ b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-portable.h @@ -0,0 +1,24 @@ +#define mul32x32_64(a,b) (((uint64_t)(a))*(b)) + +#include +#include +#include + +#define DONNA_INLINE +#undef ALIGN +#define ALIGN(x) __attribute__((aligned(x))) + +static inline void U32TO8_LE(unsigned char *p, const uint32_t v) { + p[0] = (unsigned char)(v ); + p[1] = (unsigned char)(v >> 8); + p[2] = (unsigned char)(v >> 16); + p[3] = (unsigned char)(v >> 24); +} + +static inline uint32_t U8TO32_LE(const unsigned char *p) { + return + (((uint32_t)(p[0]) ) | + ((uint32_t)(p[1]) << 8) | + ((uint32_t)(p[2]) << 16) | + ((uint32_t)(p[3]) << 24)); +} diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna.h b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna.h new file mode 100644 index 000000000..d3c340227 --- /dev/null +++ b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna.h @@ -0,0 +1,52 @@ +/* + Public domain by Andrew M. + Modified from the amd64-51-30k implementation by + Daniel J. Bernstein + Niels Duif + Tanja Lange + Peter Schwabe + Bo-Yin Yang +*/ + +#ifndef ED25519_DONNA_H +#define ED25519_DONNA_H + +#include "ed25519-donna-portable.h" + +#include "curve25519-donna-32bit.h" + +#include "curve25519-donna-helpers.h" + +#include "modm-donna-32bit.h" + +typedef unsigned char hash_512bits[64]; + +/* + * Arithmetic on the twisted Edwards curve -x^2 + y^2 = 1 + dx^2y^2 + * with d = -(121665/121666) = 37095705934669439343138083508754565189542113879843219016388785533085940283555 + * Base point: (15112221349535400772501151409588531511454012693041857206046113283949847762202,46316835694926478169428394003475163141307993866256225615783033603165251855960); + */ + +typedef struct ge25519_t { + bignum25519 x, y, z, t; +} ge25519; + +typedef struct ge25519_p1p1_t { + bignum25519 x, y, z, t; +} ge25519_p1p1; + +typedef struct ge25519_niels_t { + bignum25519 ysubx, xaddy, t2d; +} ge25519_niels; + +typedef struct ge25519_pniels_t { + bignum25519 ysubx, xaddy, z, t2d; +} ge25519_pniels; + +#include "ed25519-donna-basepoint-table.h" + +#include "ed25519-donna-32bit-tables.h" + +#include "ed25519-donna-impl-base.h" + +#endif diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom-blake2b.h b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom-blake2b.h new file mode 100644 index 000000000..93b60c1d3 --- /dev/null +++ b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom-blake2b.h @@ -0,0 +1,23 @@ +/* + a custom hash must have a 512bit digest and implement: + + struct ed25519_hash_context; + + void ed25519_hash_init(ed25519_hash_context *ctx); + void ed25519_hash_update(ed25519_hash_context *ctx, const uint8_t *in, size_t inlen); + void ed25519_hash_final(ed25519_hash_context *ctx, uint8_t *hash); + void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen); +*/ + +#ifndef ED25519_HASH_CUSTOM +#define ED25519_HASH_CUSTOM + +#include "blake2b.h" + +#define ed25519_hash_context BLAKE2B_CTX +#define ed25519_hash_init(ctx) blake2b_Init(ctx, 64) +#define ed25519_hash_update(ctx, in, inlen) blake2b_Update((ctx), (in), (inlen)) +#define ed25519_hash_final(ctx, hash) blake2b_Final((ctx), (hash), 64) +#define ed25519_hash(hash, in, inlen) blake2b((in), (inlen), (hash), 64) + +#endif // ED25519_HASH_CUSTOM diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom-keccak.h b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom-keccak.h new file mode 100644 index 000000000..4cfe148e5 --- /dev/null +++ b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom-keccak.h @@ -0,0 +1,23 @@ +/* + a custom hash must have a 512bit digest and implement: + + struct ed25519_hash_context; + + void ed25519_hash_init(ed25519_hash_context *ctx); + void ed25519_hash_update(ed25519_hash_context *ctx, const uint8_t *in, size_t inlen); + void ed25519_hash_final(ed25519_hash_context *ctx, uint8_t *hash); + void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen); +*/ + +#ifndef ED25519_HASH_CUSTOM +#define ED25519_HASH_CUSTOM + +#include "sha3.h" + +#define ed25519_hash_context SHA3_CTX +#define ed25519_hash_init(ctx) keccak_512_Init(ctx) +#define ed25519_hash_update(ctx, in, inlen) keccak_Update((ctx), (in), (inlen)) +#define ed25519_hash_final(ctx, hash) keccak_Final((ctx), (hash)) +#define ed25519_hash(hash, in, inlen) keccak_512((in), (inlen), (hash)) + +#endif // ED25519_HASH_CUSTOM diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom-sha3.h b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom-sha3.h new file mode 100644 index 000000000..6d0bd8f23 --- /dev/null +++ b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom-sha3.h @@ -0,0 +1,23 @@ +/* + a custom hash must have a 512bit digest and implement: + + struct ed25519_hash_context; + + void ed25519_hash_init(ed25519_hash_context *ctx); + void ed25519_hash_update(ed25519_hash_context *ctx, const uint8_t *in, size_t inlen); + void ed25519_hash_final(ed25519_hash_context *ctx, uint8_t *hash); + void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen); +*/ + +#ifndef ED25519_HASH_CUSTOM +#define ED25519_HASH_CUSTOM + +#include "sha3.h" + +#define ed25519_hash_context SHA3_CTX +#define ed25519_hash_init(ctx) sha3_512_Init(ctx) +#define ed25519_hash_update(ctx, in, inlen) sha3_Update((ctx), (in), (inlen)) +#define ed25519_hash_final(ctx, hash) sha3_Final((ctx), (hash)) +#define ed25519_hash(hash, in, inlen) sha3_512((in), (inlen), (hash)) + +#endif // ED25519_HASH_CUSTOM diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom.h b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom.h new file mode 100644 index 000000000..5d8236ee0 --- /dev/null +++ b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom.h @@ -0,0 +1,23 @@ +/* + a custom hash must have a 512bit digest and implement: + + struct ed25519_hash_context; + + void ed25519_hash_init(ed25519_hash_context *ctx); + void ed25519_hash_update(ed25519_hash_context *ctx, const uint8_t *in, size_t inlen); + void ed25519_hash_final(ed25519_hash_context *ctx, uint8_t *hash); + void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen); +*/ + +#ifndef ED25519_HASH_CUSTOM +#define ED25519_HASH_CUSTOM + +#include "sha2.h" + +#define ed25519_hash_context SHA512_CTX +#define ed25519_hash_init(ctx) sha512_Init(ctx) +#define ed25519_hash_update(ctx, in, inlen) sha512_Update((ctx), (in), (inlen)) +#define ed25519_hash_final(ctx, hash) sha512_Final((ctx), (hash)) +#define ed25519_hash(hash, in, inlen) sha512_Raw((in), (inlen), (hash)) + +#endif // ED25519_HASH_CUSTOM diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-keccak.c b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-keccak.c new file mode 100644 index 000000000..b109360a7 --- /dev/null +++ b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-keccak.c @@ -0,0 +1,8 @@ +#include + +#include "ed25519-keccak.h" +#include "ed25519-hash-custom-keccak.h" + +#define ED25519_SUFFIX _keccak + +#include "ed25519.c" diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-keccak.h b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-keccak.h new file mode 100644 index 000000000..d40ce7797 --- /dev/null +++ b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-keccak.h @@ -0,0 +1,21 @@ +#ifndef ED25519_KECCAK_H +#define ED25519_KECCAK_H + +#include "ed25519.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +void ed25519_publickey_keccak(const ed25519_secret_key sk, ed25519_public_key pk); + +int ed25519_sign_open_keccak(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS); +void ed25519_sign_keccak(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, ed25519_signature RS); + +int ed25519_scalarmult_keccak(ed25519_public_key res, const ed25519_secret_key sk, const ed25519_public_key pk); + +#if defined(__cplusplus) +} +#endif + +#endif // ED25519_KECCAK_H diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-sha3.c b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-sha3.c new file mode 100644 index 000000000..6a7687d0d --- /dev/null +++ b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-sha3.c @@ -0,0 +1,8 @@ +#include + +#include "ed25519-sha3.h" +#include "ed25519-hash-custom-sha3.h" + +#define ED25519_SUFFIX _sha3 + +#include "ed25519.c" diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-sha3.h b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-sha3.h new file mode 100644 index 000000000..51b764b03 --- /dev/null +++ b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-sha3.h @@ -0,0 +1,21 @@ +#ifndef ED25519_SHA3_H +#define ED25519_SHA3_H + +#include "ed25519.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +void ed25519_publickey_sha3(const ed25519_secret_key sk, ed25519_public_key pk); + +int ed25519_sign_open_sha3(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS); +void ed25519_sign_sha3(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, ed25519_signature RS); + +int ed25519_scalarmult_sha3(ed25519_public_key res, const ed25519_secret_key sk, const ed25519_public_key pk); + +#if defined(__cplusplus) +} +#endif + +#endif // ED25519_SHA3_H diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519.c b/deps/crypto/trezor-crypto/ed25519-donna/ed25519.c new file mode 100644 index 000000000..a90268c3c --- /dev/null +++ b/deps/crypto/trezor-crypto/ed25519-donna/ed25519.c @@ -0,0 +1,377 @@ +/* + Public domain by Andrew M. + + Ed25519 reference implementation using Ed25519-donna +*/ + + +/* define ED25519_SUFFIX to have it appended to the end of each public function */ +#ifdef ED25519_SUFFIX +#define ED25519_FN3(fn,suffix) fn##suffix +#define ED25519_FN2(fn,suffix) ED25519_FN3(fn,suffix) +#define ED25519_FN(fn) ED25519_FN2(fn,ED25519_SUFFIX) +#else +#define ED25519_FN(fn) fn +#endif + +#include "ed25519-donna.h" +#include "ed25519.h" + +#include "ed25519-hash-custom.h" +#include "rand.h" +#include "memzero.h" + +/* + Generates a (extsk[0..31]) and aExt (extsk[32..63]) +*/ +DONNA_INLINE static void +ed25519_extsk(hash_512bits extsk, const ed25519_secret_key sk) { + ed25519_hash(extsk, sk, 32); + extsk[0] &= 248; + extsk[31] &= 127; + extsk[31] |= 64; +} + +static void +ed25519_hram(hash_512bits hram, const ed25519_public_key R, const ed25519_public_key pk, const unsigned char *m, size_t mlen) { + ed25519_hash_context ctx; + ed25519_hash_init(&ctx); + ed25519_hash_update(&ctx, R, 32); + ed25519_hash_update(&ctx, pk, 32); + ed25519_hash_update(&ctx, m, mlen); + ed25519_hash_final(&ctx, hram); +} + +void +ED25519_FN(ed25519_publickey) (const ed25519_secret_key sk, ed25519_public_key pk) { + bignum256modm a = {0}; + ge25519 ALIGN(16) A = {0}; + hash_512bits extsk = {0}; + + ed25519_extsk(extsk, sk); + expand256_modm(a, extsk, 32); + memzero(&extsk, sizeof(extsk)); + + /* A = aB */ + ge25519_scalarmult_base_niels(&A, ge25519_niels_base_multiples, a); + memzero(&a, sizeof(a)); + ge25519_pack(pk, &A); +} + +#if USE_CARDANO +void +ED25519_FN(ed25519_publickey_ext) (const ed25519_secret_key sk, const ed25519_secret_key skext, ed25519_public_key pk) { + bignum256modm a = {0}; + ge25519 ALIGN(16) A = {0}; + hash_512bits extsk = {0}; + + /* we don't stretch the key through hashing first since its already 64 bytes */ + + memcpy(extsk, sk, 32); + memcpy(extsk+32, skext, 32); + expand256_modm(a, extsk, 32); + memzero(&extsk, sizeof(extsk)); + ge25519_scalarmult_base_niels(&A, ge25519_niels_base_multiples, a); + memzero(&a, sizeof(a)); + ge25519_pack(pk, &A); +} +#endif + +void +ED25519_FN(ed25519_cosi_commit) (ed25519_secret_key nonce, ed25519_public_key commitment) { + bignum256modm r = {0}; + ge25519 ALIGN(16) R; + unsigned char extnonce[64] = {0}; + + /* r = random512 mod L */ + random_buffer(extnonce, sizeof(extnonce)); + expand256_modm(r, extnonce, sizeof(extnonce)); + memzero(&extnonce, sizeof(extnonce)); + contract256_modm(nonce, r); + + /* R = rB */ + ge25519_scalarmult_base_niels(&R, ge25519_niels_base_multiples, r); + memzero(&r, sizeof(r)); + ge25519_pack(commitment, &R); +} + +int +ED25519_FN(ed25519_cosi_sign) (const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_secret_key nonce, const ed25519_public_key R, const ed25519_public_key pk, ed25519_cosi_signature sig) { + bignum256modm r = {0}, S = {0}, a = {0}; + hash_512bits extsk = {0}, hram = {0}; + + ed25519_extsk(extsk, sk); + + /* r */ + expand_raw256_modm(r, nonce); + if (!is_reduced256_modm(r)) { + memzero(&extsk, sizeof(extsk)); + memzero(&r, sizeof(r)); + return -1; + } + + /* S = H(R,A,m).. */ + ed25519_hram(hram, R, pk, m, mlen); + expand256_modm(S, hram, 64); + + /* S = H(R,A,m)a */ + expand256_modm(a, extsk, 32); + memzero(&extsk, sizeof(extsk)); + mul256_modm(S, S, a); + memzero(&a, sizeof(a)); + + /* S = (r + H(R,A,m)a) */ + add256_modm(S, S, r); + memzero(&r, sizeof(r)); + + /* S = (r + H(R,A,m)a) mod L */ + contract256_modm(sig, S); + + return 0; +} + +void +ED25519_FN(ed25519_sign) (const unsigned char *m, size_t mlen, const ed25519_secret_key sk, ed25519_signature RS) { + ed25519_hash_context ctx; + bignum256modm r = {0}, S = {0}, a = {0}; + ge25519 ALIGN(16) R = {0}; + ge25519 ALIGN(16) A = {0}; + ed25519_public_key pk = {0}; + hash_512bits extsk = {0}, hashr = {0}, hram = {0}; + + ed25519_extsk(extsk, sk); + + + /* r = H(aExt[32..64], m) */ + ed25519_hash_init(&ctx); + ed25519_hash_update(&ctx, extsk + 32, 32); + ed25519_hash_update(&ctx, m, mlen); + ed25519_hash_final(&ctx, hashr); + expand256_modm(r, hashr, 64); + memzero(&hashr, sizeof(hashr)); + + /* R = rB */ + ge25519_scalarmult_base_niels(&R, ge25519_niels_base_multiples, r); + ge25519_pack(RS, &R); + + /* a = aExt[0..31] */ + expand256_modm(a, extsk, 32); + memzero(&extsk, sizeof(extsk)); + + /* A = aB */ + ge25519_scalarmult_base_niels(&A, ge25519_niels_base_multiples, a); + ge25519_pack(pk, &A); + + /* S = H(R,A,m).. */ + ed25519_hram(hram, RS, pk, m, mlen); + expand256_modm(S, hram, 64); + + /* S = H(R,A,m)a */ + mul256_modm(S, S, a); + memzero(&a, sizeof(a)); + + /* S = (r + H(R,A,m)a) */ + add256_modm(S, S, r); + memzero(&r, sizeof(r)); + + /* S = (r + H(R,A,m)a) mod L */ + contract256_modm(RS + 32, S); +} + +#if USE_CARDANO +void +ED25519_FN(ed25519_sign_ext) (const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_secret_key skext, ed25519_signature RS) { + ed25519_hash_context ctx; + bignum256modm r = {0}, S = {0}, a = {0}; + ge25519 ALIGN(16) R = {0}; + ge25519 ALIGN(16) A = {0}; + ed25519_public_key pk = {0}; + hash_512bits extsk = {0}, hashr = {0}, hram = {0}; + + /* we don't stretch the key through hashing first since its already 64 bytes */ + + memcpy(extsk, sk, 32); + memcpy(extsk+32, skext, 32); + + + /* r = H(aExt[32..64], m) */ + ed25519_hash_init(&ctx); + ed25519_hash_update(&ctx, extsk + 32, 32); + ed25519_hash_update(&ctx, m, mlen); + ed25519_hash_final(&ctx, hashr); + expand256_modm(r, hashr, 64); + memzero(&hashr, sizeof(hashr)); + + /* R = rB */ + ge25519_scalarmult_base_niels(&R, ge25519_niels_base_multiples, r); + ge25519_pack(RS, &R); + + /* a = aExt[0..31] */ + expand256_modm(a, extsk, 32); + memzero(&extsk, sizeof(extsk)); + + /* A = aB */ + ge25519_scalarmult_base_niels(&A, ge25519_niels_base_multiples, a); + ge25519_pack(pk, &A); + + /* S = H(R,A,m).. */ + ed25519_hram(hram, RS, pk, m, mlen); + expand256_modm(S, hram, 64); + + /* S = H(R,A,m)a */ + mul256_modm(S, S, a); + memzero(&a, sizeof(a)); + + /* S = (r + H(R,A,m)a) */ + add256_modm(S, S, r); + memzero(&r, sizeof(r)); + + /* S = (r + H(R,A,m)a) mod L */ + contract256_modm(RS + 32, S); +} +#endif + +int +ED25519_FN(ed25519_sign_open) (const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS) { + ge25519 ALIGN(16) R = {0}, A = {0}; + hash_512bits hash = {0}; + bignum256modm hram = {0}, S = {0}; + unsigned char checkR[32] = {0}; + + if ((RS[63] & 224) || !ge25519_unpack_negative_vartime(&A, pk)) + return -1; + + /* hram = H(R,A,m) */ + ed25519_hram(hash, RS, pk, m, mlen); + expand256_modm(hram, hash, 64); + + /* S */ + expand_raw256_modm(S, RS + 32); + if (!is_reduced256_modm(S)) + return -1; + + /* SB - H(R,A,m)A */ + ge25519_double_scalarmult_vartime(&R, &A, hram, S); + ge25519_pack(checkR, &R); + + /* check that R = SB - H(R,A,m)A */ + return ed25519_verify(RS, checkR, 32) ? 0 : -1; +} + +int +ED25519_FN(ed25519_scalarmult) (ed25519_public_key res, const ed25519_secret_key sk, const ed25519_public_key pk) { + bignum256modm a = {0}; + ge25519 ALIGN(16) A = {0}, P = {0}; + hash_512bits extsk = {0}; + + ed25519_extsk(extsk, sk); + expand256_modm(a, extsk, 32); + memzero(&extsk, sizeof(extsk)); + + if (!ge25519_unpack_negative_vartime(&P, pk)) { + return -1; + } + + ge25519_scalarmult(&A, &P, a); + memzero(&a, sizeof(a)); + curve25519_neg(A.x, A.x); + ge25519_pack(res, &A); + return 0; +} + + +#ifndef ED25519_SUFFIX + +#include "curve25519-donna-scalarmult-base.h" + +int +ed25519_cosi_combine_publickeys(ed25519_public_key res, CONST ed25519_public_key *pks, size_t n) { + size_t i = 0; + ge25519 P = {0}; + ge25519_pniels sump = {0}; + ge25519_p1p1 sump1 = {0}; + + if (n == 1) { + memcpy(res, pks, sizeof(ed25519_public_key)); + return 0; + } + if (!ge25519_unpack_negative_vartime(&P, pks[i++])) { + return -1; + } + ge25519_full_to_pniels(&sump, &P); + while (i < n - 1) { + if (!ge25519_unpack_negative_vartime(&P, pks[i++])) { + return -1; + } + ge25519_pnielsadd(&sump, &P, &sump); + } + if (!ge25519_unpack_negative_vartime(&P, pks[i++])) { + return -1; + } + ge25519_pnielsadd_p1p1(&sump1, &P, &sump, 0); + ge25519_p1p1_to_partial(&P, &sump1); + curve25519_neg(P.x, P.x); + ge25519_pack(res, &P); + return 0; +} + +void +ed25519_cosi_combine_signatures(ed25519_signature res, const ed25519_public_key R, CONST ed25519_cosi_signature *sigs, size_t n) { + bignum256modm s = {0}, t = {0}; + size_t i = 0; + + expand256_modm(s, sigs[i++], 32); + while (i < n) { + expand256_modm(t, sigs[i++], 32); + add256_modm(s, s, t); + } + memcpy(res, R, 32); + contract256_modm(res + 32, s); +} + +/* + Fast Curve25519 basepoint scalar multiplication +*/ +void +curve25519_scalarmult_basepoint(curve25519_key pk, const curve25519_key e) { + curve25519_key ec = {0}; + bignum256modm s = {0}; + bignum25519 ALIGN(16) yplusz = {0}, zminusy = {0}; + ge25519 ALIGN(16) p = {0}; + size_t i = 0; + + /* clamp */ + for (i = 0; i < 32; i++) ec[i] = e[i]; + ec[0] &= 248; + ec[31] &= 127; + ec[31] |= 64; + + expand_raw256_modm(s, ec); + memzero(&ec, sizeof(ec)); + + /* scalar * basepoint */ + ge25519_scalarmult_base_niels(&p, ge25519_niels_base_multiples, s); + memzero(&s, sizeof(s)); + + /* u = (y + z) / (z - y) */ + curve25519_add(yplusz, p.y, p.z); + curve25519_sub(zminusy, p.z, p.y); + curve25519_recip(zminusy, zminusy); + curve25519_mul(yplusz, yplusz, zminusy); + curve25519_contract(pk, yplusz); +} + +void +curve25519_scalarmult(curve25519_key mypublic, const curve25519_key secret, const curve25519_key basepoint) { + curve25519_key e = {0}; + size_t i = 0; + + for (i = 0;i < 32;++i) e[i] = secret[i]; + e[0] &= 0xf8; + e[31] &= 0x7f; + e[31] |= 0x40; + curve25519_scalarmult_donna(mypublic, e, basepoint); + memzero(&e, sizeof(e)); +} + +#endif // ED25519_SUFFIX diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519.h b/deps/crypto/trezor-crypto/ed25519-donna/ed25519.h new file mode 100644 index 000000000..dbe0e35fb --- /dev/null +++ b/deps/crypto/trezor-crypto/ed25519-donna/ed25519.h @@ -0,0 +1,49 @@ +#ifndef ED25519_H +#define ED25519_H + +#include "../options.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +typedef unsigned char ed25519_signature[64]; +typedef unsigned char ed25519_public_key[32]; +typedef unsigned char ed25519_secret_key[32]; + +typedef unsigned char curve25519_key[32]; + +typedef unsigned char ed25519_cosi_signature[32]; + +void ed25519_publickey(const ed25519_secret_key sk, ed25519_public_key pk); +#if USE_CARDANO +void ed25519_publickey_ext(const ed25519_secret_key sk, const ed25519_secret_key skext, ed25519_public_key pk); +#endif + +int ed25519_sign_open(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS); +void ed25519_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, ed25519_signature RS); +#if USE_CARDANO +void ed25519_sign_ext(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_secret_key skext, ed25519_signature RS); +#endif + +int ed25519_scalarmult(ed25519_public_key res, const ed25519_secret_key sk, const ed25519_public_key pk); + +void curve25519_scalarmult(curve25519_key mypublic, const curve25519_key secret, const curve25519_key basepoint); +void curve25519_scalarmult_basepoint(curve25519_key mypublic, const curve25519_key secret); + +#if !defined(__GNUC__) || __GNUC__ > 4 +#define CONST const +#else +#define CONST +#endif + +int ed25519_cosi_combine_publickeys(ed25519_public_key res, CONST ed25519_public_key *pks, size_t n); +void ed25519_cosi_combine_signatures(ed25519_signature res, const ed25519_public_key R, CONST ed25519_cosi_signature *sigs, size_t n); +void ed25519_cosi_commit(ed25519_secret_key nonce, ed25519_public_key commitment); +int ed25519_cosi_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key key, const ed25519_secret_key nonce, const ed25519_public_key R, const ed25519_public_key pk, ed25519_cosi_signature sig); + +#if defined(__cplusplus) +} +#endif + +#endif // ED25519_H diff --git a/deps/crypto/trezor-crypto/ed25519-donna/modm-donna-32bit.c b/deps/crypto/trezor-crypto/ed25519-donna/modm-donna-32bit.c new file mode 100644 index 000000000..4ff735f3f --- /dev/null +++ b/deps/crypto/trezor-crypto/ed25519-donna/modm-donna-32bit.c @@ -0,0 +1,517 @@ +/* + Public domain by Andrew M. +*/ + +#include "ed25519-donna.h" + +/* + Arithmetic modulo the group order n = 2^252 + 27742317777372353535851937790883648493 = 7237005577332262213973186563042994240857116359379907606001950938285454250989 + + k = 32 + b = 1 << 8 = 256 + m = 2^252 + 27742317777372353535851937790883648493 = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed + mu = floor( b^(k*2) / m ) = 0xfffffffffffffffffffffffffffffffeb2106215d086329a7ed9ce5a30a2c131b +*/ + +static const bignum256modm modm_m = { + 0x1cf5d3ed, 0x20498c69, 0x2f79cd65, 0x37be77a8, + 0x00000014, 0x00000000, 0x00000000, 0x00000000, + 0x00001000 +}; + +static const bignum256modm modm_mu = { + 0x0a2c131b, 0x3673968c, 0x06329a7e, 0x01885742, + 0x3fffeb21, 0x3fffffff, 0x3fffffff, 0x3fffffff, + 0x000fffff +}; + +static bignum256modm_element_t +lt_modm(bignum256modm_element_t a, bignum256modm_element_t b) { + return (a - b) >> 31; +} + +/* see HAC, Alg. 14.42 Step 4 */ +void reduce256_modm(bignum256modm r) { + bignum256modm t = {0}; + bignum256modm_element_t b = 0, pb = 0, mask = 0; + + /* t = r - m */ + pb = 0; + pb += modm_m[0]; b = lt_modm(r[0], pb); t[0] = (r[0] - pb + (b << 30)); pb = b; + pb += modm_m[1]; b = lt_modm(r[1], pb); t[1] = (r[1] - pb + (b << 30)); pb = b; + pb += modm_m[2]; b = lt_modm(r[2], pb); t[2] = (r[2] - pb + (b << 30)); pb = b; + pb += modm_m[3]; b = lt_modm(r[3], pb); t[3] = (r[3] - pb + (b << 30)); pb = b; + pb += modm_m[4]; b = lt_modm(r[4], pb); t[4] = (r[4] - pb + (b << 30)); pb = b; + pb += modm_m[5]; b = lt_modm(r[5], pb); t[5] = (r[5] - pb + (b << 30)); pb = b; + pb += modm_m[6]; b = lt_modm(r[6], pb); t[6] = (r[6] - pb + (b << 30)); pb = b; + pb += modm_m[7]; b = lt_modm(r[7], pb); t[7] = (r[7] - pb + (b << 30)); pb = b; + pb += modm_m[8]; b = lt_modm(r[8], pb); t[8] = (r[8] - pb + (b << 16)); + + /* keep r if r was smaller than m */ + mask = b - 1; + r[0] ^= mask & (r[0] ^ t[0]); + r[1] ^= mask & (r[1] ^ t[1]); + r[2] ^= mask & (r[2] ^ t[2]); + r[3] ^= mask & (r[3] ^ t[3]); + r[4] ^= mask & (r[4] ^ t[4]); + r[5] ^= mask & (r[5] ^ t[5]); + r[6] ^= mask & (r[6] ^ t[6]); + r[7] ^= mask & (r[7] ^ t[7]); + r[8] ^= mask & (r[8] ^ t[8]); +} + +/* + Barrett reduction, see HAC, Alg. 14.42 + + Instead of passing in x, pre-process in to q1 and r1 for efficiency +*/ +void barrett_reduce256_modm(bignum256modm r, const bignum256modm q1, const bignum256modm r1) { + bignum256modm q3 = {0}, r2 = {0}; + uint64_t c = 0; + bignum256modm_element_t f = 0, b = 0, pb = 0; + + /* q1 = x >> 248 = 264 bits = 9 30 bit elements + q2 = mu * q1 + q3 = (q2 / 256(32+1)) = q2 / (2^8)^(32+1) = q2 >> 264 */ + c = mul32x32_64(modm_mu[0], q1[7]) + mul32x32_64(modm_mu[1], q1[6]) + mul32x32_64(modm_mu[2], q1[5]) + mul32x32_64(modm_mu[3], q1[4]) + mul32x32_64(modm_mu[4], q1[3]) + mul32x32_64(modm_mu[5], q1[2]) + mul32x32_64(modm_mu[6], q1[1]) + mul32x32_64(modm_mu[7], q1[0]); + c >>= 30; + c += mul32x32_64(modm_mu[0], q1[8]) + mul32x32_64(modm_mu[1], q1[7]) + mul32x32_64(modm_mu[2], q1[6]) + mul32x32_64(modm_mu[3], q1[5]) + mul32x32_64(modm_mu[4], q1[4]) + mul32x32_64(modm_mu[5], q1[3]) + mul32x32_64(modm_mu[6], q1[2]) + mul32x32_64(modm_mu[7], q1[1]) + mul32x32_64(modm_mu[8], q1[0]); + f = (bignum256modm_element_t)c; q3[0] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[1], q1[8]) + mul32x32_64(modm_mu[2], q1[7]) + mul32x32_64(modm_mu[3], q1[6]) + mul32x32_64(modm_mu[4], q1[5]) + mul32x32_64(modm_mu[5], q1[4]) + mul32x32_64(modm_mu[6], q1[3]) + mul32x32_64(modm_mu[7], q1[2]) + mul32x32_64(modm_mu[8], q1[1]); + f = (bignum256modm_element_t)c; q3[0] |= (f << 6) & 0x3fffffff; q3[1] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[2], q1[8]) + mul32x32_64(modm_mu[3], q1[7]) + mul32x32_64(modm_mu[4], q1[6]) + mul32x32_64(modm_mu[5], q1[5]) + mul32x32_64(modm_mu[6], q1[4]) + mul32x32_64(modm_mu[7], q1[3]) + mul32x32_64(modm_mu[8], q1[2]); + f = (bignum256modm_element_t)c; q3[1] |= (f << 6) & 0x3fffffff; q3[2] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[3], q1[8]) + mul32x32_64(modm_mu[4], q1[7]) + mul32x32_64(modm_mu[5], q1[6]) + mul32x32_64(modm_mu[6], q1[5]) + mul32x32_64(modm_mu[7], q1[4]) + mul32x32_64(modm_mu[8], q1[3]); + f = (bignum256modm_element_t)c; q3[2] |= (f << 6) & 0x3fffffff; q3[3] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[4], q1[8]) + mul32x32_64(modm_mu[5], q1[7]) + mul32x32_64(modm_mu[6], q1[6]) + mul32x32_64(modm_mu[7], q1[5]) + mul32x32_64(modm_mu[8], q1[4]); + f = (bignum256modm_element_t)c; q3[3] |= (f << 6) & 0x3fffffff; q3[4] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[5], q1[8]) + mul32x32_64(modm_mu[6], q1[7]) + mul32x32_64(modm_mu[7], q1[6]) + mul32x32_64(modm_mu[8], q1[5]); + f = (bignum256modm_element_t)c; q3[4] |= (f << 6) & 0x3fffffff; q3[5] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[6], q1[8]) + mul32x32_64(modm_mu[7], q1[7]) + mul32x32_64(modm_mu[8], q1[6]); + f = (bignum256modm_element_t)c; q3[5] |= (f << 6) & 0x3fffffff; q3[6] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[7], q1[8]) + mul32x32_64(modm_mu[8], q1[7]); + f = (bignum256modm_element_t)c; q3[6] |= (f << 6) & 0x3fffffff; q3[7] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[8], q1[8]); + f = (bignum256modm_element_t)c; q3[7] |= (f << 6) & 0x3fffffff; q3[8] = (bignum256modm_element_t)(c >> 24); + + /* r1 = (x mod 256^(32+1)) = x mod (2^8)(32+1) = x & ((1 << 264) - 1) + r2 = (q3 * m) mod (256^(32+1)) = (q3 * m) & ((1 << 264) - 1) */ + c = mul32x32_64(modm_m[0], q3[0]); + r2[0] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[1]) + mul32x32_64(modm_m[1], q3[0]); + r2[1] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[2]) + mul32x32_64(modm_m[1], q3[1]) + mul32x32_64(modm_m[2], q3[0]); + r2[2] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[3]) + mul32x32_64(modm_m[1], q3[2]) + mul32x32_64(modm_m[2], q3[1]) + mul32x32_64(modm_m[3], q3[0]); + r2[3] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[4]) + mul32x32_64(modm_m[1], q3[3]) + mul32x32_64(modm_m[2], q3[2]) + mul32x32_64(modm_m[3], q3[1]) + mul32x32_64(modm_m[4], q3[0]); + r2[4] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[5]) + mul32x32_64(modm_m[1], q3[4]) + mul32x32_64(modm_m[2], q3[3]) + mul32x32_64(modm_m[3], q3[2]) + mul32x32_64(modm_m[4], q3[1]) + mul32x32_64(modm_m[5], q3[0]); + r2[5] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[6]) + mul32x32_64(modm_m[1], q3[5]) + mul32x32_64(modm_m[2], q3[4]) + mul32x32_64(modm_m[3], q3[3]) + mul32x32_64(modm_m[4], q3[2]) + mul32x32_64(modm_m[5], q3[1]) + mul32x32_64(modm_m[6], q3[0]); + r2[6] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[7]) + mul32x32_64(modm_m[1], q3[6]) + mul32x32_64(modm_m[2], q3[5]) + mul32x32_64(modm_m[3], q3[4]) + mul32x32_64(modm_m[4], q3[3]) + mul32x32_64(modm_m[5], q3[2]) + mul32x32_64(modm_m[6], q3[1]) + mul32x32_64(modm_m[7], q3[0]); + r2[7] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[8]) + mul32x32_64(modm_m[1], q3[7]) + mul32x32_64(modm_m[2], q3[6]) + mul32x32_64(modm_m[3], q3[5]) + mul32x32_64(modm_m[4], q3[4]) + mul32x32_64(modm_m[5], q3[3]) + mul32x32_64(modm_m[6], q3[2]) + mul32x32_64(modm_m[7], q3[1]) + mul32x32_64(modm_m[8], q3[0]); + r2[8] = (bignum256modm_element_t)(c & 0xffffff); + + /* r = r1 - r2 + if (r < 0) r += (1 << 264) */ + pb = 0; + pb += r2[0]; b = lt_modm(r1[0], pb); r[0] = (r1[0] - pb + (b << 30)); pb = b; + pb += r2[1]; b = lt_modm(r1[1], pb); r[1] = (r1[1] - pb + (b << 30)); pb = b; + pb += r2[2]; b = lt_modm(r1[2], pb); r[2] = (r1[2] - pb + (b << 30)); pb = b; + pb += r2[3]; b = lt_modm(r1[3], pb); r[3] = (r1[3] - pb + (b << 30)); pb = b; + pb += r2[4]; b = lt_modm(r1[4], pb); r[4] = (r1[4] - pb + (b << 30)); pb = b; + pb += r2[5]; b = lt_modm(r1[5], pb); r[5] = (r1[5] - pb + (b << 30)); pb = b; + pb += r2[6]; b = lt_modm(r1[6], pb); r[6] = (r1[6] - pb + (b << 30)); pb = b; + pb += r2[7]; b = lt_modm(r1[7], pb); r[7] = (r1[7] - pb + (b << 30)); pb = b; + pb += r2[8]; b = lt_modm(r1[8], pb); r[8] = (r1[8] - pb + (b << 24)); + + reduce256_modm(r); + reduce256_modm(r); +} + +/* addition modulo m */ +void add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { + bignum256modm_element_t c = 0; + + c = x[0] + y[0]; r[0] = c & 0x3fffffff; c >>= 30; + c += x[1] + y[1]; r[1] = c & 0x3fffffff; c >>= 30; + c += x[2] + y[2]; r[2] = c & 0x3fffffff; c >>= 30; + c += x[3] + y[3]; r[3] = c & 0x3fffffff; c >>= 30; + c += x[4] + y[4]; r[4] = c & 0x3fffffff; c >>= 30; + c += x[5] + y[5]; r[5] = c & 0x3fffffff; c >>= 30; + c += x[6] + y[6]; r[6] = c & 0x3fffffff; c >>= 30; + c += x[7] + y[7]; r[7] = c & 0x3fffffff; c >>= 30; + c += x[8] + y[8]; r[8] = c; + + reduce256_modm(r); +} + +/* -x modulo m */ +void neg256_modm(bignum256modm r, const bignum256modm x) { + bignum256modm_element_t b = 0, pb = 0; + + /* r = m - x */ + pb = 0; + pb += x[0]; b = lt_modm(modm_m[0], pb); r[0] = (modm_m[0] - pb + (b << 30)); pb = b; + pb += x[1]; b = lt_modm(modm_m[1], pb); r[1] = (modm_m[1] - pb + (b << 30)); pb = b; + pb += x[2]; b = lt_modm(modm_m[2], pb); r[2] = (modm_m[2] - pb + (b << 30)); pb = b; + pb += x[3]; b = lt_modm(modm_m[3], pb); r[3] = (modm_m[3] - pb + (b << 30)); pb = b; + pb += x[4]; b = lt_modm(modm_m[4], pb); r[4] = (modm_m[4] - pb + (b << 30)); pb = b; + pb += x[5]; b = lt_modm(modm_m[5], pb); r[5] = (modm_m[5] - pb + (b << 30)); pb = b; + pb += x[6]; b = lt_modm(modm_m[6], pb); r[6] = (modm_m[6] - pb + (b << 30)); pb = b; + pb += x[7]; b = lt_modm(modm_m[7], pb); r[7] = (modm_m[7] - pb + (b << 30)); pb = b; + pb += x[8]; b = lt_modm(modm_m[8], pb); r[8] = (modm_m[8] - pb + (b << 16)); + + // if x==0, reduction is required + reduce256_modm(r); +} + +/* consts for subtraction, > p */ +/* Emilia Kasper trick, https://www.imperialviolet.org/2010/12/04/ecc.html */ +static const uint32_t twoP[] = { + 0x5cf5d3ed, 0x60498c68, 0x6f79cd64, 0x77be77a7, 0x40000013, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xfff}; + +/* subtraction x-y % m */ +void sub256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { + bignum256modm_element_t c = 0; + c = twoP[0] + x[0] - y[0]; r[0] = c & 0x3fffffff; c >>= 30; + c += twoP[1] + x[1] - y[1]; r[1] = c & 0x3fffffff; c >>= 30; + c += twoP[2] + x[2] - y[2]; r[2] = c & 0x3fffffff; c >>= 30; + c += twoP[3] + x[3] - y[3]; r[3] = c & 0x3fffffff; c >>= 30; + c += twoP[4] + x[4] - y[4]; r[4] = c & 0x3fffffff; c >>= 30; + c += twoP[5] + x[5] - y[5]; r[5] = c & 0x3fffffff; c >>= 30; + c += twoP[6] + x[6] - y[6]; r[6] = c & 0x3fffffff; c >>= 30; + c += twoP[7] + x[7] - y[7]; r[7] = c & 0x3fffffff; c >>= 30; + c += twoP[8] + x[8] - y[8]; r[8] = c; + reduce256_modm(r); +} + +/* multiplication modulo m */ +void mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { + bignum256modm r1 = {0}, q1 = {0}; + uint64_t c = 0; + bignum256modm_element_t f = 0; + + /* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1) + q1 = x >> 248 = 264 bits = 9 30 bit elements */ + c = mul32x32_64(x[0], y[0]); + f = (bignum256modm_element_t)c; r1[0] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[1]) + mul32x32_64(x[1], y[0]); + f = (bignum256modm_element_t)c; r1[1] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[2]) + mul32x32_64(x[1], y[1]) + mul32x32_64(x[2], y[0]); + f = (bignum256modm_element_t)c; r1[2] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[3]) + mul32x32_64(x[1], y[2]) + mul32x32_64(x[2], y[1]) + mul32x32_64(x[3], y[0]); + f = (bignum256modm_element_t)c; r1[3] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[4]) + mul32x32_64(x[1], y[3]) + mul32x32_64(x[2], y[2]) + mul32x32_64(x[3], y[1]) + mul32x32_64(x[4], y[0]); + f = (bignum256modm_element_t)c; r1[4] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[5]) + mul32x32_64(x[1], y[4]) + mul32x32_64(x[2], y[3]) + mul32x32_64(x[3], y[2]) + mul32x32_64(x[4], y[1]) + mul32x32_64(x[5], y[0]); + f = (bignum256modm_element_t)c; r1[5] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[6]) + mul32x32_64(x[1], y[5]) + mul32x32_64(x[2], y[4]) + mul32x32_64(x[3], y[3]) + mul32x32_64(x[4], y[2]) + mul32x32_64(x[5], y[1]) + mul32x32_64(x[6], y[0]); + f = (bignum256modm_element_t)c; r1[6] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[7]) + mul32x32_64(x[1], y[6]) + mul32x32_64(x[2], y[5]) + mul32x32_64(x[3], y[4]) + mul32x32_64(x[4], y[3]) + mul32x32_64(x[5], y[2]) + mul32x32_64(x[6], y[1]) + mul32x32_64(x[7], y[0]); + f = (bignum256modm_element_t)c; r1[7] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[8]) + mul32x32_64(x[1], y[7]) + mul32x32_64(x[2], y[6]) + mul32x32_64(x[3], y[5]) + mul32x32_64(x[4], y[4]) + mul32x32_64(x[5], y[3]) + mul32x32_64(x[6], y[2]) + mul32x32_64(x[7], y[1]) + mul32x32_64(x[8], y[0]); + f = (bignum256modm_element_t)c; r1[8] = (f & 0x00ffffff); q1[0] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[1], y[8]) + mul32x32_64(x[2], y[7]) + mul32x32_64(x[3], y[6]) + mul32x32_64(x[4], y[5]) + mul32x32_64(x[5], y[4]) + mul32x32_64(x[6], y[3]) + mul32x32_64(x[7], y[2]) + mul32x32_64(x[8], y[1]); + f = (bignum256modm_element_t)c; q1[0] = (q1[0] | (f << 22)) & 0x3fffffff; q1[1] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[2], y[8]) + mul32x32_64(x[3], y[7]) + mul32x32_64(x[4], y[6]) + mul32x32_64(x[5], y[5]) + mul32x32_64(x[6], y[4]) + mul32x32_64(x[7], y[3]) + mul32x32_64(x[8], y[2]); + f = (bignum256modm_element_t)c; q1[1] = (q1[1] | (f << 22)) & 0x3fffffff; q1[2] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[3], y[8]) + mul32x32_64(x[4], y[7]) + mul32x32_64(x[5], y[6]) + mul32x32_64(x[6], y[5]) + mul32x32_64(x[7], y[4]) + mul32x32_64(x[8], y[3]); + f = (bignum256modm_element_t)c; q1[2] = (q1[2] | (f << 22)) & 0x3fffffff; q1[3] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[4], y[8]) + mul32x32_64(x[5], y[7]) + mul32x32_64(x[6], y[6]) + mul32x32_64(x[7], y[5]) + mul32x32_64(x[8], y[4]); + f = (bignum256modm_element_t)c; q1[3] = (q1[3] | (f << 22)) & 0x3fffffff; q1[4] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[5], y[8]) + mul32x32_64(x[6], y[7]) + mul32x32_64(x[7], y[6]) + mul32x32_64(x[8], y[5]); + f = (bignum256modm_element_t)c; q1[4] = (q1[4] | (f << 22)) & 0x3fffffff; q1[5] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[6], y[8]) + mul32x32_64(x[7], y[7]) + mul32x32_64(x[8], y[6]); + f = (bignum256modm_element_t)c; q1[5] = (q1[5] | (f << 22)) & 0x3fffffff; q1[6] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[7], y[8]) + mul32x32_64(x[8], y[7]); + f = (bignum256modm_element_t)c; q1[6] = (q1[6] | (f << 22)) & 0x3fffffff; q1[7] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[8], y[8]); + f = (bignum256modm_element_t)c; q1[7] = (q1[7] | (f << 22)) & 0x3fffffff; q1[8] = (f >> 8) & 0x3fffff; + + barrett_reduce256_modm(r, q1, r1); +} + +void expand256_modm(bignum256modm out, const unsigned char *in, size_t len) { + unsigned char work[64] = {0}; + bignum256modm_element_t x[16] = {0}; + bignum256modm q1 = {0}; + + memcpy(work, in, len); + x[0] = U8TO32_LE(work + 0); + x[1] = U8TO32_LE(work + 4); + x[2] = U8TO32_LE(work + 8); + x[3] = U8TO32_LE(work + 12); + x[4] = U8TO32_LE(work + 16); + x[5] = U8TO32_LE(work + 20); + x[6] = U8TO32_LE(work + 24); + x[7] = U8TO32_LE(work + 28); + x[8] = U8TO32_LE(work + 32); + x[9] = U8TO32_LE(work + 36); + x[10] = U8TO32_LE(work + 40); + x[11] = U8TO32_LE(work + 44); + x[12] = U8TO32_LE(work + 48); + x[13] = U8TO32_LE(work + 52); + x[14] = U8TO32_LE(work + 56); + x[15] = U8TO32_LE(work + 60); + + /* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1) */ + out[0] = ( x[0]) & 0x3fffffff; + out[1] = ((x[ 0] >> 30) | (x[ 1] << 2)) & 0x3fffffff; + out[2] = ((x[ 1] >> 28) | (x[ 2] << 4)) & 0x3fffffff; + out[3] = ((x[ 2] >> 26) | (x[ 3] << 6)) & 0x3fffffff; + out[4] = ((x[ 3] >> 24) | (x[ 4] << 8)) & 0x3fffffff; + out[5] = ((x[ 4] >> 22) | (x[ 5] << 10)) & 0x3fffffff; + out[6] = ((x[ 5] >> 20) | (x[ 6] << 12)) & 0x3fffffff; + out[7] = ((x[ 6] >> 18) | (x[ 7] << 14)) & 0x3fffffff; + out[8] = ((x[ 7] >> 16) | (x[ 8] << 16)) & 0x00ffffff; + + /* 8*31 = 248 bits, no need to reduce */ + if (len < 32) + return; + + /* q1 = x >> 248 = 264 bits = 9 30 bit elements */ + q1[0] = ((x[ 7] >> 24) | (x[ 8] << 8)) & 0x3fffffff; + q1[1] = ((x[ 8] >> 22) | (x[ 9] << 10)) & 0x3fffffff; + q1[2] = ((x[ 9] >> 20) | (x[10] << 12)) & 0x3fffffff; + q1[3] = ((x[10] >> 18) | (x[11] << 14)) & 0x3fffffff; + q1[4] = ((x[11] >> 16) | (x[12] << 16)) & 0x3fffffff; + q1[5] = ((x[12] >> 14) | (x[13] << 18)) & 0x3fffffff; + q1[6] = ((x[13] >> 12) | (x[14] << 20)) & 0x3fffffff; + q1[7] = ((x[14] >> 10) | (x[15] << 22)) & 0x3fffffff; + q1[8] = ((x[15] >> 8) ); + + barrett_reduce256_modm(out, q1, out); +} + +void expand_raw256_modm(bignum256modm out, const unsigned char in[32]) { + bignum256modm_element_t x[8] = {0}; + + x[0] = U8TO32_LE(in + 0); + x[1] = U8TO32_LE(in + 4); + x[2] = U8TO32_LE(in + 8); + x[3] = U8TO32_LE(in + 12); + x[4] = U8TO32_LE(in + 16); + x[5] = U8TO32_LE(in + 20); + x[6] = U8TO32_LE(in + 24); + x[7] = U8TO32_LE(in + 28); + + out[0] = ( x[0]) & 0x3fffffff; + out[1] = ((x[ 0] >> 30) | (x[ 1] << 2)) & 0x3fffffff; + out[2] = ((x[ 1] >> 28) | (x[ 2] << 4)) & 0x3fffffff; + out[3] = ((x[ 2] >> 26) | (x[ 3] << 6)) & 0x3fffffff; + out[4] = ((x[ 3] >> 24) | (x[ 4] << 8)) & 0x3fffffff; + out[5] = ((x[ 4] >> 22) | (x[ 5] << 10)) & 0x3fffffff; + out[6] = ((x[ 5] >> 20) | (x[ 6] << 12)) & 0x3fffffff; + out[7] = ((x[ 6] >> 18) | (x[ 7] << 14)) & 0x3fffffff; + out[8] = ((x[ 7] >> 16) ) & 0x0000ffff; +} + +int is_reduced256_modm(const bignum256modm in) +{ + int i = 0; + uint32_t res1 = 0; + uint32_t res2 = 0; + for (i = 8; i >= 0; i--) { + res1 = (res1 << 1) | (in[i] < modm_m[i]); + res2 = (res2 << 1) | (in[i] > modm_m[i]); + } + return res1 > res2; +} + +void contract256_modm(unsigned char out[32], const bignum256modm in) { + U32TO8_LE(out + 0, (in[0] ) | (in[1] << 30)); + U32TO8_LE(out + 4, (in[1] >> 2) | (in[2] << 28)); + U32TO8_LE(out + 8, (in[2] >> 4) | (in[3] << 26)); + U32TO8_LE(out + 12, (in[3] >> 6) | (in[4] << 24)); + U32TO8_LE(out + 16, (in[4] >> 8) | (in[5] << 22)); + U32TO8_LE(out + 20, (in[5] >> 10) | (in[6] << 20)); + U32TO8_LE(out + 24, (in[6] >> 12) | (in[7] << 18)); + U32TO8_LE(out + 28, (in[7] >> 14) | (in[8] << 16)); +} + +void contract256_window4_modm(signed char r[64], const bignum256modm in) { + char carry = 0; + signed char *quads = r; + bignum256modm_element_t i = 0, j = 0, v = 0; + + for (i = 0; i < 8; i += 2) { + v = in[i]; + for (j = 0; j < 7; j++) { + *quads++ = (v & 15); + v >>= 4; + } + v |= (in[i+1] << 2); + for (j = 0; j < 8; j++) { + *quads++ = (v & 15); + v >>= 4; + } + } + v = in[8]; + *quads++ = (v & 15); v >>= 4; + *quads++ = (v & 15); v >>= 4; + *quads++ = (v & 15); v >>= 4; + *quads++ = (v & 15); v >>= 4; + + /* making it signed */ + carry = 0; + for(i = 0; i < 63; i++) { + r[i] += carry; + r[i+1] += (r[i] >> 4); + r[i] &= 15; + carry = (r[i] >> 3); + r[i] -= (carry << 4); + } + r[63] += carry; +} + +void contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int windowsize) { + int i = 0, j = 0, k = 0, b = 0; + int m = (1 << (windowsize - 1)) - 1, soplen = 256; + signed char *bits = r; + bignum256modm_element_t v = 0; + + /* first put the binary expansion into r */ + for (i = 0; i < 8; i++) { + v = s[i]; + for (j = 0; j < 30; j++, v >>= 1) + *bits++ = (v & 1); + } + v = s[8]; + for (j = 0; j < 16; j++, v >>= 1) + *bits++ = (v & 1); + + /* Making it sliding window */ + for (j = 0; j < soplen; j++) { + if (!r[j]) + continue; + + for (b = 1; (b < (soplen - j)) && (b <= 6); b++) { + if ((r[j] + (r[j + b] << b)) <= m) { + r[j] += r[j + b] << b; + r[j + b] = 0; + } else if ((r[j] - (r[j + b] << b)) >= -m) { + r[j] -= r[j + b] << b; + for (k = j + b; k < soplen; k++) { + if (!r[k]) { + r[k] = 1; + break; + } + r[k] = 0; + } + } else if (r[j + b]) { + break; + } + } + } +} + +void set256_modm(bignum256modm r, uint64_t v) { + r[0] = (bignum256modm_element_t) (v & 0x3fffffff); v >>= 30; + r[1] = (bignum256modm_element_t) (v & 0x3fffffff); v >>= 30; + r[2] = (bignum256modm_element_t) (v & 0x3fffffff); + r[3] = 0; + r[4] = 0; + r[5] = 0; + r[6] = 0; + r[7] = 0; + r[8] = 0; +} + +int get256_modm(uint64_t * v, const bignum256modm r){ + *v = 0; + int con1 = 0; + +#define NONZ(x) ((((((int64_t)(x)) - 1) >> 32) + 1) & 1) + bignum256modm_element_t c = 0; + c = r[0]; *v += (uint64_t)c & 0x3fffffff; c >>= 30; // 30 + c += r[1]; *v += ((uint64_t)c & 0x3fffffff) << 30; c >>= 30; // 60 + c += r[2]; *v += ((uint64_t)c & 0xf) << 60; con1 |= NONZ(c>>4); c >>= 30; // 64 bits + c += r[3]; con1 |= NONZ(c); c >>= 30; + c += r[4]; con1 |= NONZ(c); c >>= 30; + c += r[5]; con1 |= NONZ(c); c >>= 30; + c += r[6]; con1 |= NONZ(c); c >>= 30; + c += r[7]; con1 |= NONZ(c); c >>= 30; + c += r[8]; con1 |= NONZ(c); c >>= 30; + con1 |= NONZ(c); +#undef NONZ + + return con1 ^ 1; +} + +int eq256_modm(const bignum256modm x, const bignum256modm y){ + size_t differentbits = 0; + int len = bignum256modm_limb_size; + while (len--) { + differentbits |= (*x++ ^ *y++); + } + return (int) (1 & ((differentbits - 1) >> bignum256modm_bits_per_limb)); +} + +int cmp256_modm(const bignum256modm x, const bignum256modm y){ + int len = 2*bignum256modm_limb_size; + uint32_t a_gt = 0; + uint32_t b_gt = 0; + + // 16B chunks + while (len--) { + const uint32_t ln = (const uint32_t) len; + const uint32_t a = (x[ln>>1] >> 16*(ln & 1)) & 0xffff; + const uint32_t b = (y[ln>>1] >> 16*(ln & 1)) & 0xffff; + + const uint32_t limb_a_gt = ((b - a) >> 16) & 1; + const uint32_t limb_b_gt = ((a - b) >> 16) & 1; + a_gt |= limb_a_gt & ~b_gt; + b_gt |= limb_b_gt & ~a_gt; + } + + return a_gt - b_gt; +} + +int iszero256_modm(const bignum256modm x){ + size_t differentbits = 0; + int len = bignum256modm_limb_size; + while (len--) { + differentbits |= (*x++); + } + return (int) (1 & ((differentbits - 1) >> bignum256modm_bits_per_limb)); +} + +void copy256_modm(bignum256modm r, const bignum256modm x){ + r[0] = x[0]; + r[1] = x[1]; + r[2] = x[2]; + r[3] = x[3]; + r[4] = x[4]; + r[5] = x[5]; + r[6] = x[6]; + r[7] = x[7]; + r[8] = x[8]; +} + +int check256_modm(const bignum256modm x){ + int ok = 1; + bignum256modm t={0}, z={0}; + + ok &= iszero256_modm(x) ^ 1; + barrett_reduce256_modm(t, z, x); + ok &= eq256_modm(t, x); + return ok; +} + +void mulsub256_modm(bignum256modm r, const bignum256modm a, const bignum256modm b, const bignum256modm c){ + //(cc - aa * bb) % l + bignum256modm t={0}; + mul256_modm(t, a, b); + sub256_modm(r, c, t); +} + +void muladd256_modm(bignum256modm r, const bignum256modm a, const bignum256modm b, const bignum256modm c){ + //(cc + aa * bb) % l + bignum256modm t={0}; + mul256_modm(t, a, b); + add256_modm(r, c, t); +} diff --git a/deps/crypto/trezor-crypto/ed25519-donna/modm-donna-32bit.h b/deps/crypto/trezor-crypto/ed25519-donna/modm-donna-32bit.h new file mode 100644 index 000000000..98090f2fe --- /dev/null +++ b/deps/crypto/trezor-crypto/ed25519-donna/modm-donna-32bit.h @@ -0,0 +1,80 @@ +/* + Public domain by Andrew M. +*/ + + +/* + Arithmetic modulo the group order n = 2^252 + 27742317777372353535851937790883648493 = 7237005577332262213973186563042994240857116359379907606001950938285454250989 + + k = 32 + b = 1 << 8 = 256 + m = 2^252 + 27742317777372353535851937790883648493 = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed + mu = floor( b^(k*2) / m ) = 0xfffffffffffffffffffffffffffffffeb2106215d086329a7ed9ce5a30a2c131b +*/ + +#define bignum256modm_bits_per_limb 30 +#define bignum256modm_limb_size 9 + +typedef uint32_t bignum256modm_element_t; +typedef bignum256modm_element_t bignum256modm[9]; + +/* see HAC, Alg. 14.42 Step 4 */ +void reduce256_modm(bignum256modm r); + +/* + Barrett reduction, see HAC, Alg. 14.42 + + Instead of passing in x, pre-process in to q1 and r1 for efficiency +*/ +void barrett_reduce256_modm(bignum256modm r, const bignum256modm q1, const bignum256modm r1); + +/* addition modulo m */ +void add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y); + +/* -x modulo m */ +void neg256_modm(bignum256modm r, const bignum256modm x); + +/* subtraction x-y modulo m */ +void sub256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y); + +/* multiplication modulo m */ +void mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y); + +void expand256_modm(bignum256modm out, const unsigned char *in, size_t len); + +void expand_raw256_modm(bignum256modm out, const unsigned char in[32]); + +int is_reduced256_modm(const bignum256modm in); + +void contract256_modm(unsigned char out[32], const bignum256modm in); + +void contract256_window4_modm(signed char r[64], const bignum256modm in); + +void contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int windowsize); + +/* 64bit uint to scalar value */ +void set256_modm(bignum256modm r, uint64_t v); + +/* scalar value to 64bit uint */ +int get256_modm(uint64_t * v, const bignum256modm r); + +/* equality test on two reduced scalar values */ +int eq256_modm(const bignum256modm x, const bignum256modm y); + +/* comparison of two reduced scalar values */ +int cmp256_modm(const bignum256modm x, const bignum256modm y); + +/* scalar null check, has to be reduced */ +int iszero256_modm(const bignum256modm x); + +/* simple copy, no reduction */ +void copy256_modm(bignum256modm r, const bignum256modm x); + +/* check if nonzero && same after reduction */ +int check256_modm(const bignum256modm x); + +/* (cc - aa * bb) % l */ +void mulsub256_modm(bignum256modm r, const bignum256modm a, const bignum256modm b, const bignum256modm c); + +/* (cc + aa * bb) % l */ +void muladd256_modm(bignum256modm r, const bignum256modm a, const bignum256modm b, const bignum256modm c); diff --git a/deps/crypto/trezor-crypto/fuzzer/README.md b/deps/crypto/trezor-crypto/fuzzer/README.md new file mode 100644 index 000000000..e1dbdeb20 --- /dev/null +++ b/deps/crypto/trezor-crypto/fuzzer/README.md @@ -0,0 +1,67 @@ +# trezor-crypto fuzzing +Selected functions can be fuzzed via specific libFuzzer harnesses for increased test coverage and issue detection. + +Note: the following commands are relative to the trezor-crypto main directory. + +## Build + +A modern C compiler with built-in libFuzzer support is required. The build process will use `clang` by default. +Set the `CC=` environment variable if you want to use a special compiler variant. + +```bash +make clean +FUZZER=1 make fuzzer +``` + +### Sanitizers +Recommended: ASAN / UBSAN / MSAN flags for error detection can be specified via the special `SANFLAGS`. + +Examples: + + * `SANFLAGS="-fsanitize=address,undefined"` + * `SANFLAGS="-fsanitize=memory"` + +### Optimizations + +Override `OPTFLAGS` to test the library at different optimization levels or simplify the debugging of detected issues. + +Example: + + * `OPTFLAGS="-O0 -ggdb3"` + +## Operation + +See the [libFuzzer documentation](https://llvm.org/docs/LibFuzzer.html#options) for valid options and usage. Detailed fuzzer usage and relevant considerations are out of scope of this document. + +**Warning**: fuzzing is resource-intensive and can have a negative impact on your system stability. + +Basic fuzzer call: +```bash +./fuzzer/fuzzer +``` + +Here is a more sophisticated multithreading example with a persistent input corpus and other optimizations: +```bash +mkdir fuzzer/fuzzer_corpus +./fuzzer/fuzzer -max_len=2048 -use_value_profile=1 -jobs=16 -timeout=1 -reload=5 -print_pcs=1 -print_funcs=42 fuzzer/fuzzer_corpus +``` + +Hint: for more permanent setups, consider invoking the fuzzer from outside of the source directory to avoid cluttering it with logfiles and crash inputs. + +## Automated fuzzer dictionary generation + +[Dictionaries](https://llvm.org/docs/LibFuzzer.html#dictionaries) are a useful mechanism to augment the capabilities of the fuzzer. Specify them via the `-dict=` flag. + +### Collect interesting strings from the unit tests +``` bash +grep -r -P -o -h "\"\w+\"" tests | sort | uniq > fuzzer_crypto_tests_strings_dictionary1.txt +``` + +## Evaluate source coverage + + 1. build the fuzzer binary with `CFLAGS="-fprofile-instr-generate -fcoverage-mapping"` + 1. run with suitable `-runs=` or `-max_total_time=` limits + 1. convert the recorded data `llvm-profdata merge -output=default.profdata -instr default.profraw` + 1. render the data `llvm-cov show fuzzer/fuzzer -instr-profile=default.profdata -format=html -output-dir=coverage-report` + 1. analyze report at `coverage-report/index.html` + 1. (optional) remove artifacts with `rm default.profraw default.profdata && rm -r coverage-report` diff --git a/deps/crypto/trezor-crypto/fuzzer/fuzzer.c b/deps/crypto/trezor-crypto/fuzzer/fuzzer.c new file mode 100644 index 000000000..3a1e7c1d9 --- /dev/null +++ b/deps/crypto/trezor-crypto/fuzzer/fuzzer.c @@ -0,0 +1,416 @@ +/** + * Copyright (c) 2020 Christian Reitter + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include + +// necessary for the target functions +#include "bignum.h" +#include "ecdsa.h" +#include "hasher.h" +#include "rand.h" + +/* fuzzer input data handling */ +const uint8_t *fuzzer_ptr; +size_t fuzzer_length; + +const uint8_t *fuzzer_input(size_t len) { + if (fuzzer_length < len) { + fuzzer_length = 0; + return NULL; + } + const uint8_t *result = fuzzer_ptr; + fuzzer_length -= len; + fuzzer_ptr += len; + return result; +} + +/* fuzzer state handling */ +void fuzzer_reset_state(void) { + // reset the PRNGs to make individual fuzzer runs deterministic + srand(0); + random_reseed(0); +} + +/* individual fuzzer harness functions */ + +extern size_t bn_format(const bignum256 *amnt, const char *prefix, + const char *suffix, unsigned int decimals, int exponent, + bool trailing, char *out, size_t outlen); +int fuzz_bn_format() { + bignum256 target_bignum; + if (fuzzer_length < sizeof(target_bignum)) { + return 0; + } + + char buf[512]; + int r; + + // mutate the struct contents + memcpy(&target_bignum, fuzzer_ptr, sizeof(target_bignum)); + fuzzer_input(sizeof(target_bignum)); + + uint8_t prefixlen = 0; + if (fuzzer_length < 1) { + return 0; + } + memcpy(&prefixlen, fuzzer_input(1), 1); + char prefix[prefixlen]; + if (prefixlen > 0 && prefixlen <= 128 && prefixlen <= fuzzer_length) { + memcpy(&prefix, fuzzer_input(prefixlen), prefixlen); + // force null termination + prefix[prefixlen - 1] = 0; + } else { + return 0; + } + // TODO fuzzer idea: allow prefix=NULL + + uint8_t suffixlen = 0; + if (fuzzer_length < 1) { + return 0; + } + memcpy(&suffixlen, fuzzer_input(1), 1); + char suffix[suffixlen]; + if (suffixlen > 0 && suffixlen <= 128 && suffixlen <= fuzzer_length) { + memcpy(&suffix, fuzzer_input(suffixlen), suffixlen); + // force null termination + suffix[suffixlen - 1] = 0; + } else { + return 0; + } + // TODO fuzzer idea: allow suffix=NULL + uint32_t decimals = 0; + int32_t exponent = 0; + bool trailing = false; + + if (fuzzer_length >= 9) { + memcpy(&decimals, fuzzer_input(4), 4); + memcpy(&exponent, fuzzer_input(4), 4); + + trailing = (fuzzer_input(1)[0] & 1); + } else { + return 0; + } + + r = bn_format(&target_bignum, prefix, suffix, decimals, exponent, trailing, + buf, sizeof(buf)); + return 0; +} + +extern const char *BASE32_ALPHABET_RFC4648; +extern uint8_t *base32_decode(const char *in, size_t inlen, uint8_t *out, + size_t outlen, const char *alphabet); + +// arbitrarily chosen maximum size +#define BASE32_DECODE_MAX_INPUT_LEN 512 + +int fuzz_base32_decode() { + if (fuzzer_length < 2 || fuzzer_length > BASE32_DECODE_MAX_INPUT_LEN) { + return 0; + } + + char in_buffer[BASE32_DECODE_MAX_INPUT_LEN] = {0}; + uint8_t out_buffer[BASE32_DECODE_MAX_INPUT_LEN] = {0}; + size_t outlen = sizeof(out_buffer); + + // mutate in_buffer + size_t raw_inlen = fuzzer_length; + memcpy(&in_buffer, fuzzer_ptr, raw_inlen); + fuzzer_input(raw_inlen); + + // null-terminate input buffer to prevent issues with strlen() + in_buffer[BASE32_DECODE_MAX_INPUT_LEN - 1] = 0; + size_t inlen = strlen(in_buffer); + + base32_decode(in_buffer, inlen, out_buffer, outlen, BASE32_ALPHABET_RFC4648); + return 0; +} + +extern char *base32_encode(const uint8_t *in, size_t inlen, char *out, + size_t outlen, const char *alphabet); + +// arbitrarily chosen maximum size +#define BASE32_ENCODE_MAX_INPUT_LEN 512 + +int fuzz_base32_encode() { + if (fuzzer_length > BASE32_ENCODE_MAX_INPUT_LEN) { + return 0; + } + + uint8_t in_buffer[BASE32_ENCODE_MAX_INPUT_LEN] = {0}; + char out_buffer[BASE32_ENCODE_MAX_INPUT_LEN] = {0}; + size_t outlen = sizeof(out_buffer); + + // mutate in_buffer + size_t raw_inlen = fuzzer_length; + memcpy(&in_buffer, fuzzer_ptr, raw_inlen); + fuzzer_input(raw_inlen); + + base32_encode(in_buffer, raw_inlen, out_buffer, outlen, + BASE32_ALPHABET_RFC4648); + return 0; +} + +extern int base58_encode_check(const uint8_t *data, int datalen, + HasherType hasher_type, char *str, int strsize); + +// internal limit is 128, try some extra bytes +#define BASE58_ENCODE_MAX_INPUT_LEN 140 + +int fuzz_base58_encode_check() { + if (fuzzer_length > BASE58_ENCODE_MAX_INPUT_LEN) { + return 0; + } + + uint8_t in_buffer[BASE58_ENCODE_MAX_INPUT_LEN] = {0}; + char out_buffer[BASE58_ENCODE_MAX_INPUT_LEN] = {0}; + size_t outlen = sizeof(out_buffer); + + // mutate in_buffer + size_t raw_inlen = fuzzer_length; + memcpy(&in_buffer, fuzzer_ptr, raw_inlen); + fuzzer_input(raw_inlen); + + // run multiple hasher variants for the same input + base58_encode_check(in_buffer, raw_inlen, HASHER_SHA2D, out_buffer, outlen); + base58_encode_check(in_buffer, raw_inlen, HASHER_BLAKED, out_buffer, outlen); + base58_encode_check(in_buffer, raw_inlen, HASHER_GROESTLD_TRUNC, out_buffer, + outlen); + base58_encode_check(in_buffer, raw_inlen, HASHER_SHA3K, out_buffer, outlen); + return 0; +} + +extern int base58_decode_check(const char *str, HasherType hasher_type, + uint8_t *data, int datalen); + +// internal limit is 128, try some extra bytes +#define BASE58_DECODE_MAX_INPUT_LEN 140 + +int fuzz_base58_decode_check() { + if (fuzzer_length > BASE58_DECODE_MAX_INPUT_LEN) { + return 0; + } + + // with null terminator + uint8_t in_buffer[BASE58_DECODE_MAX_INPUT_LEN + 1] = {0}; + uint8_t out_buffer[BASE58_DECODE_MAX_INPUT_LEN] = {0}; + + // mutate in_buffer + size_t raw_inlen = fuzzer_length; + memcpy(&in_buffer, fuzzer_ptr, raw_inlen); + fuzzer_input(raw_inlen); + + // run multiple hasher variants for the same input + base58_decode_check((const char *)in_buffer, HASHER_SHA2D, out_buffer, + MAX_ADDR_RAW_SIZE); + base58_decode_check((const char *)in_buffer, HASHER_BLAKED, out_buffer, + MAX_ADDR_RAW_SIZE); + base58_decode_check((const char *)in_buffer, HASHER_GROESTLD_TRUNC, + out_buffer, MAX_ADDR_RAW_SIZE); + base58_decode_check((const char *)in_buffer, HASHER_SHA3K, out_buffer, + MAX_ADDR_RAW_SIZE); + return 0; +} + +extern int xmr_base58_addr_decode_check(const char *addr, size_t sz, + uint64_t *tag, void *data, + size_t datalen); + +// arbitrarily chosen maximum size +#define XMR_BASE58_ADDR_DECODE_MAX_INPUT_LEN 512 + +int fuzz_xmr_base58_addr_decode_check() { + if (fuzzer_length > XMR_BASE58_ADDR_DECODE_MAX_INPUT_LEN) { + return 0; + } + + char in_buffer[XMR_BASE58_ADDR_DECODE_MAX_INPUT_LEN] = {0}; + char out_buffer[XMR_BASE58_ADDR_DECODE_MAX_INPUT_LEN] = {0}; + size_t outlen = sizeof(out_buffer); + + // mutate in_buffer + size_t raw_inlen = fuzzer_length; + memcpy(&in_buffer, fuzzer_ptr, raw_inlen); + fuzzer_input(raw_inlen); + + uint64_t tag; + xmr_base58_addr_decode_check(in_buffer, raw_inlen, &tag, out_buffer, outlen); + return 0; +} + +extern int xmr_base58_addr_encode_check(uint64_t tag, const uint8_t *data, + size_t binsz, char *b58, size_t b58sz); + +// arbitrarily chosen maximum size +#define XMR_BASE58_ADDR_ENCODE_MAX_INPUT_LEN 512 + +int fuzz_xmr_base58_addr_encode_check() { + uint64_t tag_in; + size_t tag_size = sizeof(tag_in); + if (fuzzer_length < tag_size || + fuzzer_length > XMR_BASE58_ADDR_ENCODE_MAX_INPUT_LEN) { + return 0; + } + + uint8_t in_buffer[XMR_BASE58_ADDR_ENCODE_MAX_INPUT_LEN] = {0}; + char out_buffer[XMR_BASE58_ADDR_ENCODE_MAX_INPUT_LEN] = {0}; + size_t outlen = sizeof(out_buffer); + + // mutate tag_in + memcpy(&tag_in, fuzzer_ptr, tag_size); + fuzzer_input(tag_size); + + // mutate in_buffer + memcpy(&in_buffer, fuzzer_ptr, fuzzer_length); + size_t raw_inlen = fuzzer_length; + fuzzer_input(raw_inlen); + + xmr_base58_addr_encode_check(tag_in, in_buffer, raw_inlen, out_buffer, + outlen); + return 0; +} + +extern int xmr_size_varint(uint64_t num); +extern int xmr_write_varint(uint8_t *buff, size_t buff_size, uint64_t num); +extern int xmr_read_varint(uint8_t *buff, size_t buff_size, uint64_t *val); + +// arbitrarily chosen maximum size +#define XMR_SERIALIZE_VARINT_MAX_INPUT_LEN 128 + +int fuzz_xmr_serialize_varint() { + uint64_t varint_in; + size_t varint_in_size = sizeof(varint_in); + if (fuzzer_length < varint_in_size || + fuzzer_length > XMR_SERIALIZE_VARINT_MAX_INPUT_LEN) { + return 0; + } + + uint8_t in_buffer[XMR_SERIALIZE_VARINT_MAX_INPUT_LEN] = {0}; + uint8_t out_buffer[XMR_SERIALIZE_VARINT_MAX_INPUT_LEN] = {0}; + size_t outlen = sizeof(out_buffer); + uint64_t varint_out = 0; + + // mutate varint_in + memcpy(&varint_in, fuzzer_ptr, varint_in_size); + fuzzer_input(varint_in_size); + + // mutate in_buffer + memcpy(&in_buffer, fuzzer_ptr, fuzzer_length); + size_t raw_inlen = fuzzer_length; + fuzzer_input(raw_inlen); + + // call the actual xmr functions + xmr_size_varint(varint_in); + xmr_write_varint(out_buffer, outlen, varint_in); + xmr_read_varint(in_buffer, raw_inlen, &varint_out); + + return 0; +} + +extern bool nem_validate_address(const char *address, uint8_t network); + +// arbitrarily chosen maximum size +#define NEM_VALIDATE_ADDRESS_MAX_INPUT_LEN 128 + +int fuzz_nem_validate_address() { + if (fuzzer_length < (1 + 1) || + fuzzer_length > NEM_VALIDATE_ADDRESS_MAX_INPUT_LEN) { + return 0; + } + + char in_buffer[NEM_VALIDATE_ADDRESS_MAX_INPUT_LEN] = {0}; + + // TODO potential BUG: is it clearly specified that the address has to be null + // terminated? + in_buffer[NEM_VALIDATE_ADDRESS_MAX_INPUT_LEN - 1] = 0; + + uint8_t network = *fuzzer_ptr; + fuzzer_input(1); + + // mutate the buffer + memcpy(&in_buffer, fuzzer_ptr, fuzzer_length); + size_t raw_inlen = fuzzer_length; + fuzzer_input(raw_inlen); + + nem_validate_address(in_buffer, network); + + return 0; +} + +#define META_HEADER_SIZE 3 + +// main fuzzer entry +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + // reject input that is too short + if (size < META_HEADER_SIZE) { + return 0; + } + + fuzzer_reset_state(); + + uint8_t decision = data[0]; + + // TODO use when necessary + // uint8_t subdecision = data[1]; + + // note: data[2] is reserved for future use + + // assign the fuzzer payload data for the target functions + fuzzer_ptr = data + META_HEADER_SIZE; + fuzzer_length = size - META_HEADER_SIZE; + + switch (decision) { + case 0: + fuzz_bn_format(); + break; + case 1: + fuzz_base32_decode(); + break; + case 2: + fuzz_base32_encode(); + break; + case 3: + fuzz_base58_encode_check(); + break; + case 4: + fuzz_base58_decode_check(); + break; + case 5: + fuzz_xmr_base58_addr_decode_check(); + break; + case 6: + fuzz_xmr_base58_addr_encode_check(); + break; + case 7: + fuzz_xmr_serialize_varint(); + break; + case 8: + fuzz_nem_validate_address(); + break; + default: + // do nothing + break; + } + return 0; +} diff --git a/deps/crypto/trezor-crypto/groestl.c b/deps/crypto/trezor-crypto/groestl.c new file mode 100644 index 000000000..d913c76e0 --- /dev/null +++ b/deps/crypto/trezor-crypto/groestl.c @@ -0,0 +1,787 @@ +/* Groestl hash from https://github.com/Groestlcoin/vanitygen + * Trezor adaptation by Yura Pakhuchiy . */ +/* + * Groestl implementation. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @author Thomas Pornin + */ + +#include +#include + +#include "groestl_internal.h" +#include "groestl.h" +#include "memzero.h" + + +#define C32e(x) ((SPH_C32(x) >> 24) \ + | ((SPH_C32(x) >> 8) & SPH_C32(0x0000FF00)) \ + | ((SPH_C32(x) << 8) & SPH_C32(0x00FF0000)) \ + | ((SPH_C32(x) << 24) & SPH_C32(0xFF000000))) +#define dec32e_aligned sph_dec32le_aligned +#define enc32e sph_enc32le +#define B32_0(x) ((x) & 0xFF) +#define B32_1(x) (((x) >> 8) & 0xFF) +#define B32_2(x) (((x) >> 16) & 0xFF) +#define B32_3(x) ((x) >> 24) + +#define R32u(u, d) SPH_T32(((u) << 16) | ((d) >> 16)) +#define R32d(u, d) SPH_T32(((u) >> 16) | ((d) << 16)) + +#define PC32up(j, r) ((sph_u32)((j) + (r))) +#define PC32dn(j, r) 0 +#define QC32up(j, r) SPH_C32(0xFFFFFFFF) +#define QC32dn(j, r) (((sph_u32)(r) << 24) ^ SPH_T32(~((sph_u32)(j) << 24))) + +#define C64e(x) ((SPH_C64(x) >> 56) \ + | ((SPH_C64(x) >> 40) & SPH_C64(0x000000000000FF00)) \ + | ((SPH_C64(x) >> 24) & SPH_C64(0x0000000000FF0000)) \ + | ((SPH_C64(x) >> 8) & SPH_C64(0x00000000FF000000)) \ + | ((SPH_C64(x) << 8) & SPH_C64(0x000000FF00000000)) \ + | ((SPH_C64(x) << 24) & SPH_C64(0x0000FF0000000000)) \ + | ((SPH_C64(x) << 40) & SPH_C64(0x00FF000000000000)) \ + | ((SPH_C64(x) << 56) & SPH_C64(0xFF00000000000000))) +#define dec64e_aligned sph_dec64le_aligned +#define enc64e sph_enc64le +#define B64_0(x) ((x) & 0xFF) +#define B64_1(x) (((x) >> 8) & 0xFF) +#define B64_2(x) (((x) >> 16) & 0xFF) +#define B64_3(x) (((x) >> 24) & 0xFF) +#define B64_4(x) (((x) >> 32) & 0xFF) +#define B64_5(x) (((x) >> 40) & 0xFF) +#define B64_6(x) (((x) >> 48) & 0xFF) +#define B64_7(x) ((x) >> 56) +#define R64 SPH_ROTL64 +#define PC64(j, r) ((sph_u64)((j) + (r))) +#define QC64(j, r) (((sph_u64)(r) << 56) ^ SPH_T64(~((sph_u64)(j) << 56))) + + +static const sph_u32 T0up[] = { + C32e(0xc632f4a5), C32e(0xf86f9784), C32e(0xee5eb099), C32e(0xf67a8c8d), + C32e(0xffe8170d), C32e(0xd60adcbd), C32e(0xde16c8b1), C32e(0x916dfc54), + C32e(0x6090f050), C32e(0x02070503), C32e(0xce2ee0a9), C32e(0x56d1877d), + C32e(0xe7cc2b19), C32e(0xb513a662), C32e(0x4d7c31e6), C32e(0xec59b59a), + C32e(0x8f40cf45), C32e(0x1fa3bc9d), C32e(0x8949c040), C32e(0xfa689287), + C32e(0xefd03f15), C32e(0xb29426eb), C32e(0x8ece40c9), C32e(0xfbe61d0b), + C32e(0x416e2fec), C32e(0xb31aa967), C32e(0x5f431cfd), C32e(0x456025ea), + C32e(0x23f9dabf), C32e(0x535102f7), C32e(0xe445a196), C32e(0x9b76ed5b), + C32e(0x75285dc2), C32e(0xe1c5241c), C32e(0x3dd4e9ae), C32e(0x4cf2be6a), + C32e(0x6c82ee5a), C32e(0x7ebdc341), C32e(0xf5f30602), C32e(0x8352d14f), + C32e(0x688ce45c), C32e(0x515607f4), C32e(0xd18d5c34), C32e(0xf9e11808), + C32e(0xe24cae93), C32e(0xab3e9573), C32e(0x6297f553), C32e(0x2a6b413f), + C32e(0x081c140c), C32e(0x9563f652), C32e(0x46e9af65), C32e(0x9d7fe25e), + C32e(0x30487828), C32e(0x37cff8a1), C32e(0x0a1b110f), C32e(0x2febc4b5), + C32e(0x0e151b09), C32e(0x247e5a36), C32e(0x1badb69b), C32e(0xdf98473d), + C32e(0xcda76a26), C32e(0x4ef5bb69), C32e(0x7f334ccd), C32e(0xea50ba9f), + C32e(0x123f2d1b), C32e(0x1da4b99e), C32e(0x58c49c74), C32e(0x3446722e), + C32e(0x3641772d), C32e(0xdc11cdb2), C32e(0xb49d29ee), C32e(0x5b4d16fb), + C32e(0xa4a501f6), C32e(0x76a1d74d), C32e(0xb714a361), C32e(0x7d3449ce), + C32e(0x52df8d7b), C32e(0xdd9f423e), C32e(0x5ecd9371), C32e(0x13b1a297), + C32e(0xa6a204f5), C32e(0xb901b868), C32e(0x00000000), C32e(0xc1b5742c), + C32e(0x40e0a060), C32e(0xe3c2211f), C32e(0x793a43c8), C32e(0xb69a2ced), + C32e(0xd40dd9be), C32e(0x8d47ca46), C32e(0x671770d9), C32e(0x72afdd4b), + C32e(0x94ed79de), C32e(0x98ff67d4), C32e(0xb09323e8), C32e(0x855bde4a), + C32e(0xbb06bd6b), C32e(0xc5bb7e2a), C32e(0x4f7b34e5), C32e(0xedd73a16), + C32e(0x86d254c5), C32e(0x9af862d7), C32e(0x6699ff55), C32e(0x11b6a794), + C32e(0x8ac04acf), C32e(0xe9d93010), C32e(0x040e0a06), C32e(0xfe669881), + C32e(0xa0ab0bf0), C32e(0x78b4cc44), C32e(0x25f0d5ba), C32e(0x4b753ee3), + C32e(0xa2ac0ef3), C32e(0x5d4419fe), C32e(0x80db5bc0), C32e(0x0580858a), + C32e(0x3fd3ecad), C32e(0x21fedfbc), C32e(0x70a8d848), C32e(0xf1fd0c04), + C32e(0x63197adf), C32e(0x772f58c1), C32e(0xaf309f75), C32e(0x42e7a563), + C32e(0x20705030), C32e(0xe5cb2e1a), C32e(0xfdef120e), C32e(0xbf08b76d), + C32e(0x8155d44c), C32e(0x18243c14), C32e(0x26795f35), C32e(0xc3b2712f), + C32e(0xbe8638e1), C32e(0x35c8fda2), C32e(0x88c74fcc), C32e(0x2e654b39), + C32e(0x936af957), C32e(0x55580df2), C32e(0xfc619d82), C32e(0x7ab3c947), + C32e(0xc827efac), C32e(0xba8832e7), C32e(0x324f7d2b), C32e(0xe642a495), + C32e(0xc03bfba0), C32e(0x19aab398), C32e(0x9ef668d1), C32e(0xa322817f), + C32e(0x44eeaa66), C32e(0x54d6827e), C32e(0x3bdde6ab), C32e(0x0b959e83), + C32e(0x8cc945ca), C32e(0xc7bc7b29), C32e(0x6b056ed3), C32e(0x286c443c), + C32e(0xa72c8b79), C32e(0xbc813de2), C32e(0x1631271d), C32e(0xad379a76), + C32e(0xdb964d3b), C32e(0x649efa56), C32e(0x74a6d24e), C32e(0x1436221e), + C32e(0x92e476db), C32e(0x0c121e0a), C32e(0x48fcb46c), C32e(0xb88f37e4), + C32e(0x9f78e75d), C32e(0xbd0fb26e), C32e(0x43692aef), C32e(0xc435f1a6), + C32e(0x39dae3a8), C32e(0x31c6f7a4), C32e(0xd38a5937), C32e(0xf274868b), + C32e(0xd5835632), C32e(0x8b4ec543), C32e(0x6e85eb59), C32e(0xda18c2b7), + C32e(0x018e8f8c), C32e(0xb11dac64), C32e(0x9cf16dd2), C32e(0x49723be0), + C32e(0xd81fc7b4), C32e(0xacb915fa), C32e(0xf3fa0907), C32e(0xcfa06f25), + C32e(0xca20eaaf), C32e(0xf47d898e), C32e(0x476720e9), C32e(0x10382818), + C32e(0x6f0b64d5), C32e(0xf0738388), C32e(0x4afbb16f), C32e(0x5cca9672), + C32e(0x38546c24), C32e(0x575f08f1), C32e(0x732152c7), C32e(0x9764f351), + C32e(0xcbae6523), C32e(0xa125847c), C32e(0xe857bf9c), C32e(0x3e5d6321), + C32e(0x96ea7cdd), C32e(0x611e7fdc), C32e(0x0d9c9186), C32e(0x0f9b9485), + C32e(0xe04bab90), C32e(0x7cbac642), C32e(0x712657c4), C32e(0xcc29e5aa), + C32e(0x90e373d8), C32e(0x06090f05), C32e(0xf7f40301), C32e(0x1c2a3612), + C32e(0xc23cfea3), C32e(0x6a8be15f), C32e(0xaebe10f9), C32e(0x69026bd0), + C32e(0x17bfa891), C32e(0x9971e858), C32e(0x3a536927), C32e(0x27f7d0b9), + C32e(0xd9914838), C32e(0xebde3513), C32e(0x2be5ceb3), C32e(0x22775533), + C32e(0xd204d6bb), C32e(0xa9399070), C32e(0x07878089), C32e(0x33c1f2a7), + C32e(0x2decc1b6), C32e(0x3c5a6622), C32e(0x15b8ad92), C32e(0xc9a96020), + C32e(0x875cdb49), C32e(0xaab01aff), C32e(0x50d88878), C32e(0xa52b8e7a), + C32e(0x03898a8f), C32e(0x594a13f8), C32e(0x09929b80), C32e(0x1a233917), + C32e(0x651075da), C32e(0xd7845331), C32e(0x84d551c6), C32e(0xd003d3b8), + C32e(0x82dc5ec3), C32e(0x29e2cbb0), C32e(0x5ac39977), C32e(0x1e2d3311), + C32e(0x7b3d46cb), C32e(0xa8b71ffc), C32e(0x6d0c61d6), C32e(0x2c624e3a) +}; + +static const sph_u32 T0dn[] = { + C32e(0xf497a5c6), C32e(0x97eb84f8), C32e(0xb0c799ee), C32e(0x8cf78df6), + C32e(0x17e50dff), C32e(0xdcb7bdd6), C32e(0xc8a7b1de), C32e(0xfc395491), + C32e(0xf0c05060), C32e(0x05040302), C32e(0xe087a9ce), C32e(0x87ac7d56), + C32e(0x2bd519e7), C32e(0xa67162b5), C32e(0x319ae64d), C32e(0xb5c39aec), + C32e(0xcf05458f), C32e(0xbc3e9d1f), C32e(0xc0094089), C32e(0x92ef87fa), + C32e(0x3fc515ef), C32e(0x267febb2), C32e(0x4007c98e), C32e(0x1ded0bfb), + C32e(0x2f82ec41), C32e(0xa97d67b3), C32e(0x1cbefd5f), C32e(0x258aea45), + C32e(0xda46bf23), C32e(0x02a6f753), C32e(0xa1d396e4), C32e(0xed2d5b9b), + C32e(0x5deac275), C32e(0x24d91ce1), C32e(0xe97aae3d), C32e(0xbe986a4c), + C32e(0xeed85a6c), C32e(0xc3fc417e), C32e(0x06f102f5), C32e(0xd11d4f83), + C32e(0xe4d05c68), C32e(0x07a2f451), C32e(0x5cb934d1), C32e(0x18e908f9), + C32e(0xaedf93e2), C32e(0x954d73ab), C32e(0xf5c45362), C32e(0x41543f2a), + C32e(0x14100c08), C32e(0xf6315295), C32e(0xaf8c6546), C32e(0xe2215e9d), + C32e(0x78602830), C32e(0xf86ea137), C32e(0x11140f0a), C32e(0xc45eb52f), + C32e(0x1b1c090e), C32e(0x5a483624), C32e(0xb6369b1b), C32e(0x47a53ddf), + C32e(0x6a8126cd), C32e(0xbb9c694e), C32e(0x4cfecd7f), C32e(0xbacf9fea), + C32e(0x2d241b12), C32e(0xb93a9e1d), C32e(0x9cb07458), C32e(0x72682e34), + C32e(0x776c2d36), C32e(0xcda3b2dc), C32e(0x2973eeb4), C32e(0x16b6fb5b), + C32e(0x0153f6a4), C32e(0xd7ec4d76), C32e(0xa37561b7), C32e(0x49face7d), + C32e(0x8da47b52), C32e(0x42a13edd), C32e(0x93bc715e), C32e(0xa2269713), + C32e(0x0457f5a6), C32e(0xb86968b9), C32e(0x00000000), C32e(0x74992cc1), + C32e(0xa0806040), C32e(0x21dd1fe3), C32e(0x43f2c879), C32e(0x2c77edb6), + C32e(0xd9b3bed4), C32e(0xca01468d), C32e(0x70ced967), C32e(0xdde44b72), + C32e(0x7933de94), C32e(0x672bd498), C32e(0x237be8b0), C32e(0xde114a85), + C32e(0xbd6d6bbb), C32e(0x7e912ac5), C32e(0x349ee54f), C32e(0x3ac116ed), + C32e(0x5417c586), C32e(0x622fd79a), C32e(0xffcc5566), C32e(0xa7229411), + C32e(0x4a0fcf8a), C32e(0x30c910e9), C32e(0x0a080604), C32e(0x98e781fe), + C32e(0x0b5bf0a0), C32e(0xccf04478), C32e(0xd54aba25), C32e(0x3e96e34b), + C32e(0x0e5ff3a2), C32e(0x19bafe5d), C32e(0x5b1bc080), C32e(0x850a8a05), + C32e(0xec7ead3f), C32e(0xdf42bc21), C32e(0xd8e04870), C32e(0x0cf904f1), + C32e(0x7ac6df63), C32e(0x58eec177), C32e(0x9f4575af), C32e(0xa5846342), + C32e(0x50403020), C32e(0x2ed11ae5), C32e(0x12e10efd), C32e(0xb7656dbf), + C32e(0xd4194c81), C32e(0x3c301418), C32e(0x5f4c3526), C32e(0x719d2fc3), + C32e(0x3867e1be), C32e(0xfd6aa235), C32e(0x4f0bcc88), C32e(0x4b5c392e), + C32e(0xf93d5793), C32e(0x0daaf255), C32e(0x9de382fc), C32e(0xc9f4477a), + C32e(0xef8bacc8), C32e(0x326fe7ba), C32e(0x7d642b32), C32e(0xa4d795e6), + C32e(0xfb9ba0c0), C32e(0xb3329819), C32e(0x6827d19e), C32e(0x815d7fa3), + C32e(0xaa886644), C32e(0x82a87e54), C32e(0xe676ab3b), C32e(0x9e16830b), + C32e(0x4503ca8c), C32e(0x7b9529c7), C32e(0x6ed6d36b), C32e(0x44503c28), + C32e(0x8b5579a7), C32e(0x3d63e2bc), C32e(0x272c1d16), C32e(0x9a4176ad), + C32e(0x4dad3bdb), C32e(0xfac85664), C32e(0xd2e84e74), C32e(0x22281e14), + C32e(0x763fdb92), C32e(0x1e180a0c), C32e(0xb4906c48), C32e(0x376be4b8), + C32e(0xe7255d9f), C32e(0xb2616ebd), C32e(0x2a86ef43), C32e(0xf193a6c4), + C32e(0xe372a839), C32e(0xf762a431), C32e(0x59bd37d3), C32e(0x86ff8bf2), + C32e(0x56b132d5), C32e(0xc50d438b), C32e(0xebdc596e), C32e(0xc2afb7da), + C32e(0x8f028c01), C32e(0xac7964b1), C32e(0x6d23d29c), C32e(0x3b92e049), + C32e(0xc7abb4d8), C32e(0x1543faac), C32e(0x09fd07f3), C32e(0x6f8525cf), + C32e(0xea8fafca), C32e(0x89f38ef4), C32e(0x208ee947), C32e(0x28201810), + C32e(0x64ded56f), C32e(0x83fb88f0), C32e(0xb1946f4a), C32e(0x96b8725c), + C32e(0x6c702438), C32e(0x08aef157), C32e(0x52e6c773), C32e(0xf3355197), + C32e(0x658d23cb), C32e(0x84597ca1), C32e(0xbfcb9ce8), C32e(0x637c213e), + C32e(0x7c37dd96), C32e(0x7fc2dc61), C32e(0x911a860d), C32e(0x941e850f), + C32e(0xabdb90e0), C32e(0xc6f8427c), C32e(0x57e2c471), C32e(0xe583aacc), + C32e(0x733bd890), C32e(0x0f0c0506), C32e(0x03f501f7), C32e(0x3638121c), + C32e(0xfe9fa3c2), C32e(0xe1d45f6a), C32e(0x1047f9ae), C32e(0x6bd2d069), + C32e(0xa82e9117), C32e(0xe8295899), C32e(0x6974273a), C32e(0xd04eb927), + C32e(0x48a938d9), C32e(0x35cd13eb), C32e(0xce56b32b), C32e(0x55443322), + C32e(0xd6bfbbd2), C32e(0x904970a9), C32e(0x800e8907), C32e(0xf266a733), + C32e(0xc15ab62d), C32e(0x6678223c), C32e(0xad2a9215), C32e(0x608920c9), + C32e(0xdb154987), C32e(0x1a4fffaa), C32e(0x88a07850), C32e(0x8e517aa5), + C32e(0x8a068f03), C32e(0x13b2f859), C32e(0x9b128009), C32e(0x3934171a), + C32e(0x75cada65), C32e(0x53b531d7), C32e(0x5113c684), C32e(0xd3bbb8d0), + C32e(0x5e1fc382), C32e(0xcb52b029), C32e(0x99b4775a), C32e(0x333c111e), + C32e(0x46f6cb7b), C32e(0x1f4bfca8), C32e(0x61dad66d), C32e(0x4e583a2c) +}; + +static const sph_u32 T1up[] = { + C32e(0xc6c632f4), C32e(0xf8f86f97), C32e(0xeeee5eb0), C32e(0xf6f67a8c), + C32e(0xffffe817), C32e(0xd6d60adc), C32e(0xdede16c8), C32e(0x91916dfc), + C32e(0x606090f0), C32e(0x02020705), C32e(0xcece2ee0), C32e(0x5656d187), + C32e(0xe7e7cc2b), C32e(0xb5b513a6), C32e(0x4d4d7c31), C32e(0xecec59b5), + C32e(0x8f8f40cf), C32e(0x1f1fa3bc), C32e(0x898949c0), C32e(0xfafa6892), + C32e(0xefefd03f), C32e(0xb2b29426), C32e(0x8e8ece40), C32e(0xfbfbe61d), + C32e(0x41416e2f), C32e(0xb3b31aa9), C32e(0x5f5f431c), C32e(0x45456025), + C32e(0x2323f9da), C32e(0x53535102), C32e(0xe4e445a1), C32e(0x9b9b76ed), + C32e(0x7575285d), C32e(0xe1e1c524), C32e(0x3d3dd4e9), C32e(0x4c4cf2be), + C32e(0x6c6c82ee), C32e(0x7e7ebdc3), C32e(0xf5f5f306), C32e(0x838352d1), + C32e(0x68688ce4), C32e(0x51515607), C32e(0xd1d18d5c), C32e(0xf9f9e118), + C32e(0xe2e24cae), C32e(0xabab3e95), C32e(0x626297f5), C32e(0x2a2a6b41), + C32e(0x08081c14), C32e(0x959563f6), C32e(0x4646e9af), C32e(0x9d9d7fe2), + C32e(0x30304878), C32e(0x3737cff8), C32e(0x0a0a1b11), C32e(0x2f2febc4), + C32e(0x0e0e151b), C32e(0x24247e5a), C32e(0x1b1badb6), C32e(0xdfdf9847), + C32e(0xcdcda76a), C32e(0x4e4ef5bb), C32e(0x7f7f334c), C32e(0xeaea50ba), + C32e(0x12123f2d), C32e(0x1d1da4b9), C32e(0x5858c49c), C32e(0x34344672), + C32e(0x36364177), C32e(0xdcdc11cd), C32e(0xb4b49d29), C32e(0x5b5b4d16), + C32e(0xa4a4a501), C32e(0x7676a1d7), C32e(0xb7b714a3), C32e(0x7d7d3449), + C32e(0x5252df8d), C32e(0xdddd9f42), C32e(0x5e5ecd93), C32e(0x1313b1a2), + C32e(0xa6a6a204), C32e(0xb9b901b8), C32e(0x00000000), C32e(0xc1c1b574), + C32e(0x4040e0a0), C32e(0xe3e3c221), C32e(0x79793a43), C32e(0xb6b69a2c), + C32e(0xd4d40dd9), C32e(0x8d8d47ca), C32e(0x67671770), C32e(0x7272afdd), + C32e(0x9494ed79), C32e(0x9898ff67), C32e(0xb0b09323), C32e(0x85855bde), + C32e(0xbbbb06bd), C32e(0xc5c5bb7e), C32e(0x4f4f7b34), C32e(0xededd73a), + C32e(0x8686d254), C32e(0x9a9af862), C32e(0x666699ff), C32e(0x1111b6a7), + C32e(0x8a8ac04a), C32e(0xe9e9d930), C32e(0x04040e0a), C32e(0xfefe6698), + C32e(0xa0a0ab0b), C32e(0x7878b4cc), C32e(0x2525f0d5), C32e(0x4b4b753e), + C32e(0xa2a2ac0e), C32e(0x5d5d4419), C32e(0x8080db5b), C32e(0x05058085), + C32e(0x3f3fd3ec), C32e(0x2121fedf), C32e(0x7070a8d8), C32e(0xf1f1fd0c), + C32e(0x6363197a), C32e(0x77772f58), C32e(0xafaf309f), C32e(0x4242e7a5), + C32e(0x20207050), C32e(0xe5e5cb2e), C32e(0xfdfdef12), C32e(0xbfbf08b7), + C32e(0x818155d4), C32e(0x1818243c), C32e(0x2626795f), C32e(0xc3c3b271), + C32e(0xbebe8638), C32e(0x3535c8fd), C32e(0x8888c74f), C32e(0x2e2e654b), + C32e(0x93936af9), C32e(0x5555580d), C32e(0xfcfc619d), C32e(0x7a7ab3c9), + C32e(0xc8c827ef), C32e(0xbaba8832), C32e(0x32324f7d), C32e(0xe6e642a4), + C32e(0xc0c03bfb), C32e(0x1919aab3), C32e(0x9e9ef668), C32e(0xa3a32281), + C32e(0x4444eeaa), C32e(0x5454d682), C32e(0x3b3bdde6), C32e(0x0b0b959e), + C32e(0x8c8cc945), C32e(0xc7c7bc7b), C32e(0x6b6b056e), C32e(0x28286c44), + C32e(0xa7a72c8b), C32e(0xbcbc813d), C32e(0x16163127), C32e(0xadad379a), + C32e(0xdbdb964d), C32e(0x64649efa), C32e(0x7474a6d2), C32e(0x14143622), + C32e(0x9292e476), C32e(0x0c0c121e), C32e(0x4848fcb4), C32e(0xb8b88f37), + C32e(0x9f9f78e7), C32e(0xbdbd0fb2), C32e(0x4343692a), C32e(0xc4c435f1), + C32e(0x3939dae3), C32e(0x3131c6f7), C32e(0xd3d38a59), C32e(0xf2f27486), + C32e(0xd5d58356), C32e(0x8b8b4ec5), C32e(0x6e6e85eb), C32e(0xdada18c2), + C32e(0x01018e8f), C32e(0xb1b11dac), C32e(0x9c9cf16d), C32e(0x4949723b), + C32e(0xd8d81fc7), C32e(0xacacb915), C32e(0xf3f3fa09), C32e(0xcfcfa06f), + C32e(0xcaca20ea), C32e(0xf4f47d89), C32e(0x47476720), C32e(0x10103828), + C32e(0x6f6f0b64), C32e(0xf0f07383), C32e(0x4a4afbb1), C32e(0x5c5cca96), + C32e(0x3838546c), C32e(0x57575f08), C32e(0x73732152), C32e(0x979764f3), + C32e(0xcbcbae65), C32e(0xa1a12584), C32e(0xe8e857bf), C32e(0x3e3e5d63), + C32e(0x9696ea7c), C32e(0x61611e7f), C32e(0x0d0d9c91), C32e(0x0f0f9b94), + C32e(0xe0e04bab), C32e(0x7c7cbac6), C32e(0x71712657), C32e(0xcccc29e5), + C32e(0x9090e373), C32e(0x0606090f), C32e(0xf7f7f403), C32e(0x1c1c2a36), + C32e(0xc2c23cfe), C32e(0x6a6a8be1), C32e(0xaeaebe10), C32e(0x6969026b), + C32e(0x1717bfa8), C32e(0x999971e8), C32e(0x3a3a5369), C32e(0x2727f7d0), + C32e(0xd9d99148), C32e(0xebebde35), C32e(0x2b2be5ce), C32e(0x22227755), + C32e(0xd2d204d6), C32e(0xa9a93990), C32e(0x07078780), C32e(0x3333c1f2), + C32e(0x2d2decc1), C32e(0x3c3c5a66), C32e(0x1515b8ad), C32e(0xc9c9a960), + C32e(0x87875cdb), C32e(0xaaaab01a), C32e(0x5050d888), C32e(0xa5a52b8e), + C32e(0x0303898a), C32e(0x59594a13), C32e(0x0909929b), C32e(0x1a1a2339), + C32e(0x65651075), C32e(0xd7d78453), C32e(0x8484d551), C32e(0xd0d003d3), + C32e(0x8282dc5e), C32e(0x2929e2cb), C32e(0x5a5ac399), C32e(0x1e1e2d33), + C32e(0x7b7b3d46), C32e(0xa8a8b71f), C32e(0x6d6d0c61), C32e(0x2c2c624e) +}; + +static const sph_u32 T1dn[] = { + C32e(0xa5f497a5), C32e(0x8497eb84), C32e(0x99b0c799), C32e(0x8d8cf78d), + C32e(0x0d17e50d), C32e(0xbddcb7bd), C32e(0xb1c8a7b1), C32e(0x54fc3954), + C32e(0x50f0c050), C32e(0x03050403), C32e(0xa9e087a9), C32e(0x7d87ac7d), + C32e(0x192bd519), C32e(0x62a67162), C32e(0xe6319ae6), C32e(0x9ab5c39a), + C32e(0x45cf0545), C32e(0x9dbc3e9d), C32e(0x40c00940), C32e(0x8792ef87), + C32e(0x153fc515), C32e(0xeb267feb), C32e(0xc94007c9), C32e(0x0b1ded0b), + C32e(0xec2f82ec), C32e(0x67a97d67), C32e(0xfd1cbefd), C32e(0xea258aea), + C32e(0xbfda46bf), C32e(0xf702a6f7), C32e(0x96a1d396), C32e(0x5bed2d5b), + C32e(0xc25deac2), C32e(0x1c24d91c), C32e(0xaee97aae), C32e(0x6abe986a), + C32e(0x5aeed85a), C32e(0x41c3fc41), C32e(0x0206f102), C32e(0x4fd11d4f), + C32e(0x5ce4d05c), C32e(0xf407a2f4), C32e(0x345cb934), C32e(0x0818e908), + C32e(0x93aedf93), C32e(0x73954d73), C32e(0x53f5c453), C32e(0x3f41543f), + C32e(0x0c14100c), C32e(0x52f63152), C32e(0x65af8c65), C32e(0x5ee2215e), + C32e(0x28786028), C32e(0xa1f86ea1), C32e(0x0f11140f), C32e(0xb5c45eb5), + C32e(0x091b1c09), C32e(0x365a4836), C32e(0x9bb6369b), C32e(0x3d47a53d), + C32e(0x266a8126), C32e(0x69bb9c69), C32e(0xcd4cfecd), C32e(0x9fbacf9f), + C32e(0x1b2d241b), C32e(0x9eb93a9e), C32e(0x749cb074), C32e(0x2e72682e), + C32e(0x2d776c2d), C32e(0xb2cda3b2), C32e(0xee2973ee), C32e(0xfb16b6fb), + C32e(0xf60153f6), C32e(0x4dd7ec4d), C32e(0x61a37561), C32e(0xce49face), + C32e(0x7b8da47b), C32e(0x3e42a13e), C32e(0x7193bc71), C32e(0x97a22697), + C32e(0xf50457f5), C32e(0x68b86968), C32e(0x00000000), C32e(0x2c74992c), + C32e(0x60a08060), C32e(0x1f21dd1f), C32e(0xc843f2c8), C32e(0xed2c77ed), + C32e(0xbed9b3be), C32e(0x46ca0146), C32e(0xd970ced9), C32e(0x4bdde44b), + C32e(0xde7933de), C32e(0xd4672bd4), C32e(0xe8237be8), C32e(0x4ade114a), + C32e(0x6bbd6d6b), C32e(0x2a7e912a), C32e(0xe5349ee5), C32e(0x163ac116), + C32e(0xc55417c5), C32e(0xd7622fd7), C32e(0x55ffcc55), C32e(0x94a72294), + C32e(0xcf4a0fcf), C32e(0x1030c910), C32e(0x060a0806), C32e(0x8198e781), + C32e(0xf00b5bf0), C32e(0x44ccf044), C32e(0xbad54aba), C32e(0xe33e96e3), + C32e(0xf30e5ff3), C32e(0xfe19bafe), C32e(0xc05b1bc0), C32e(0x8a850a8a), + C32e(0xadec7ead), C32e(0xbcdf42bc), C32e(0x48d8e048), C32e(0x040cf904), + C32e(0xdf7ac6df), C32e(0xc158eec1), C32e(0x759f4575), C32e(0x63a58463), + C32e(0x30504030), C32e(0x1a2ed11a), C32e(0x0e12e10e), C32e(0x6db7656d), + C32e(0x4cd4194c), C32e(0x143c3014), C32e(0x355f4c35), C32e(0x2f719d2f), + C32e(0xe13867e1), C32e(0xa2fd6aa2), C32e(0xcc4f0bcc), C32e(0x394b5c39), + C32e(0x57f93d57), C32e(0xf20daaf2), C32e(0x829de382), C32e(0x47c9f447), + C32e(0xacef8bac), C32e(0xe7326fe7), C32e(0x2b7d642b), C32e(0x95a4d795), + C32e(0xa0fb9ba0), C32e(0x98b33298), C32e(0xd16827d1), C32e(0x7f815d7f), + C32e(0x66aa8866), C32e(0x7e82a87e), C32e(0xabe676ab), C32e(0x839e1683), + C32e(0xca4503ca), C32e(0x297b9529), C32e(0xd36ed6d3), C32e(0x3c44503c), + C32e(0x798b5579), C32e(0xe23d63e2), C32e(0x1d272c1d), C32e(0x769a4176), + C32e(0x3b4dad3b), C32e(0x56fac856), C32e(0x4ed2e84e), C32e(0x1e22281e), + C32e(0xdb763fdb), C32e(0x0a1e180a), C32e(0x6cb4906c), C32e(0xe4376be4), + C32e(0x5de7255d), C32e(0x6eb2616e), C32e(0xef2a86ef), C32e(0xa6f193a6), + C32e(0xa8e372a8), C32e(0xa4f762a4), C32e(0x3759bd37), C32e(0x8b86ff8b), + C32e(0x3256b132), C32e(0x43c50d43), C32e(0x59ebdc59), C32e(0xb7c2afb7), + C32e(0x8c8f028c), C32e(0x64ac7964), C32e(0xd26d23d2), C32e(0xe03b92e0), + C32e(0xb4c7abb4), C32e(0xfa1543fa), C32e(0x0709fd07), C32e(0x256f8525), + C32e(0xafea8faf), C32e(0x8e89f38e), C32e(0xe9208ee9), C32e(0x18282018), + C32e(0xd564ded5), C32e(0x8883fb88), C32e(0x6fb1946f), C32e(0x7296b872), + C32e(0x246c7024), C32e(0xf108aef1), C32e(0xc752e6c7), C32e(0x51f33551), + C32e(0x23658d23), C32e(0x7c84597c), C32e(0x9cbfcb9c), C32e(0x21637c21), + C32e(0xdd7c37dd), C32e(0xdc7fc2dc), C32e(0x86911a86), C32e(0x85941e85), + C32e(0x90abdb90), C32e(0x42c6f842), C32e(0xc457e2c4), C32e(0xaae583aa), + C32e(0xd8733bd8), C32e(0x050f0c05), C32e(0x0103f501), C32e(0x12363812), + C32e(0xa3fe9fa3), C32e(0x5fe1d45f), C32e(0xf91047f9), C32e(0xd06bd2d0), + C32e(0x91a82e91), C32e(0x58e82958), C32e(0x27697427), C32e(0xb9d04eb9), + C32e(0x3848a938), C32e(0x1335cd13), C32e(0xb3ce56b3), C32e(0x33554433), + C32e(0xbbd6bfbb), C32e(0x70904970), C32e(0x89800e89), C32e(0xa7f266a7), + C32e(0xb6c15ab6), C32e(0x22667822), C32e(0x92ad2a92), C32e(0x20608920), + C32e(0x49db1549), C32e(0xff1a4fff), C32e(0x7888a078), C32e(0x7a8e517a), + C32e(0x8f8a068f), C32e(0xf813b2f8), C32e(0x809b1280), C32e(0x17393417), + C32e(0xda75cada), C32e(0x3153b531), C32e(0xc65113c6), C32e(0xb8d3bbb8), + C32e(0xc35e1fc3), C32e(0xb0cb52b0), C32e(0x7799b477), C32e(0x11333c11), + C32e(0xcb46f6cb), C32e(0xfc1f4bfc), C32e(0xd661dad6), C32e(0x3a4e583a) +}; + +#define DECL_STATE_SMALL \ + sph_u32 H[16] = {0}; + +#define READ_STATE_SMALL(sc) do { \ + memcpy(H, (sc)->state.narrow, sizeof H); \ + } while (0) + +#define WRITE_STATE_SMALL(sc) do { \ + memcpy((sc)->state.narrow, H, sizeof H); \ + } while (0) + +#define XCAT(x, y) XCAT_(x, y) +#define XCAT_(x, y) x ## y + +#define RSTT(d0, d1, a, b0, b1, b2, b3, b4, b5, b6, b7) do { \ + t[d0] = T0up[B32_0(a[b0])] \ + ^ T1up[B32_1(a[b1])] \ + ^ T2up[B32_2(a[b2])] \ + ^ T3up[B32_3(a[b3])] \ + ^ T0dn[B32_0(a[b4])] \ + ^ T1dn[B32_1(a[b5])] \ + ^ T2dn[B32_2(a[b6])] \ + ^ T3dn[B32_3(a[b7])]; \ + t[d1] = T0dn[B32_0(a[b0])] \ + ^ T1dn[B32_1(a[b1])] \ + ^ T2dn[B32_2(a[b2])] \ + ^ T3dn[B32_3(a[b3])] \ + ^ T0up[B32_0(a[b4])] \ + ^ T1up[B32_1(a[b5])] \ + ^ T2up[B32_2(a[b6])] \ + ^ T3up[B32_3(a[b7])]; \ + } while (0) + +#define ROUND_SMALL_P(a, r) do { \ + sph_u32 t[16]; \ + a[0x0] ^= PC32up(0x00, r); \ + a[0x1] ^= PC32dn(0x00, r); \ + a[0x2] ^= PC32up(0x10, r); \ + a[0x3] ^= PC32dn(0x10, r); \ + a[0x4] ^= PC32up(0x20, r); \ + a[0x5] ^= PC32dn(0x20, r); \ + a[0x6] ^= PC32up(0x30, r); \ + a[0x7] ^= PC32dn(0x30, r); \ + a[0x8] ^= PC32up(0x40, r); \ + a[0x9] ^= PC32dn(0x40, r); \ + a[0xA] ^= PC32up(0x50, r); \ + a[0xB] ^= PC32dn(0x50, r); \ + a[0xC] ^= PC32up(0x60, r); \ + a[0xD] ^= PC32dn(0x60, r); \ + a[0xE] ^= PC32up(0x70, r); \ + a[0xF] ^= PC32dn(0x70, r); \ + RSTT(0x0, 0x1, a, 0x0, 0x2, 0x4, 0x6, 0x9, 0xB, 0xD, 0xF); \ + RSTT(0x2, 0x3, a, 0x2, 0x4, 0x6, 0x8, 0xB, 0xD, 0xF, 0x1); \ + RSTT(0x4, 0x5, a, 0x4, 0x6, 0x8, 0xA, 0xD, 0xF, 0x1, 0x3); \ + RSTT(0x6, 0x7, a, 0x6, 0x8, 0xA, 0xC, 0xF, 0x1, 0x3, 0x5); \ + RSTT(0x8, 0x9, a, 0x8, 0xA, 0xC, 0xE, 0x1, 0x3, 0x5, 0x7); \ + RSTT(0xA, 0xB, a, 0xA, 0xC, 0xE, 0x0, 0x3, 0x5, 0x7, 0x9); \ + RSTT(0xC, 0xD, a, 0xC, 0xE, 0x0, 0x2, 0x5, 0x7, 0x9, 0xB); \ + RSTT(0xE, 0xF, a, 0xE, 0x0, 0x2, 0x4, 0x7, 0x9, 0xB, 0xD); \ + memcpy(a, t, sizeof t); \ + } while (0) + +#define ROUND_SMALL_Q(a, r) do { \ + sph_u32 t[16]; \ + a[0x0] ^= QC32up(0x00, r); \ + a[0x1] ^= QC32dn(0x00, r); \ + a[0x2] ^= QC32up(0x10, r); \ + a[0x3] ^= QC32dn(0x10, r); \ + a[0x4] ^= QC32up(0x20, r); \ + a[0x5] ^= QC32dn(0x20, r); \ + a[0x6] ^= QC32up(0x30, r); \ + a[0x7] ^= QC32dn(0x30, r); \ + a[0x8] ^= QC32up(0x40, r); \ + a[0x9] ^= QC32dn(0x40, r); \ + a[0xA] ^= QC32up(0x50, r); \ + a[0xB] ^= QC32dn(0x50, r); \ + a[0xC] ^= QC32up(0x60, r); \ + a[0xD] ^= QC32dn(0x60, r); \ + a[0xE] ^= QC32up(0x70, r); \ + a[0xF] ^= QC32dn(0x70, r); \ + RSTT(0x0, 0x1, a, 0x2, 0x6, 0xA, 0xE, 0x1, 0x5, 0x9, 0xD); \ + RSTT(0x2, 0x3, a, 0x4, 0x8, 0xC, 0x0, 0x3, 0x7, 0xB, 0xF); \ + RSTT(0x4, 0x5, a, 0x6, 0xA, 0xE, 0x2, 0x5, 0x9, 0xD, 0x1); \ + RSTT(0x6, 0x7, a, 0x8, 0xC, 0x0, 0x4, 0x7, 0xB, 0xF, 0x3); \ + RSTT(0x8, 0x9, a, 0xA, 0xE, 0x2, 0x6, 0x9, 0xD, 0x1, 0x5); \ + RSTT(0xA, 0xB, a, 0xC, 0x0, 0x4, 0x8, 0xB, 0xF, 0x3, 0x7); \ + RSTT(0xC, 0xD, a, 0xE, 0x2, 0x6, 0xA, 0xD, 0x1, 0x5, 0x9); \ + RSTT(0xE, 0xF, a, 0x0, 0x4, 0x8, 0xC, 0xF, 0x3, 0x7, 0xB); \ + memcpy(a, t, sizeof t); \ + } while (0) + +#define PERM_SMALL_P(a) do { \ + int r; \ + for (r = 0; r < 10; r ++) \ + ROUND_SMALL_P(a, r); \ + } while (0) + +#define PERM_SMALL_Q(a) do { \ + int r; \ + for (r = 0; r < 10; r ++) \ + ROUND_SMALL_Q(a, r); \ + } while (0) + + +#define COMPRESS_SMALL do { \ + sph_u32 g[16], m[16]; \ + size_t u; \ + for (u = 0; u < 16; u ++) { \ + m[u] = dec32e_aligned(buf + (u << 2)); \ + g[u] = m[u] ^ H[u]; \ + } \ + PERM_SMALL_P(g); \ + PERM_SMALL_Q(m); \ + for (u = 0; u < 16; u ++) \ + H[u] ^= g[u] ^ m[u]; \ + } while (0) + +#define FINAL_SMALL do { \ + sph_u32 x[16]; \ + size_t u; \ + memcpy(x, H, sizeof x); \ + PERM_SMALL_P(x); \ + for (u = 0; u < 16; u ++) \ + H[u] ^= x[u]; \ + } while (0) + +#define DECL_STATE_BIG \ + sph_u32 H[32] = {0}; + +#define READ_STATE_BIG(sc) do { \ + memcpy(H, (sc)->state.narrow, sizeof H); \ + } while (0) + +#define WRITE_STATE_BIG(sc) do { \ + memcpy((sc)->state.narrow, H, sizeof H); \ + } while (0) + + +#define RBTT(d0, d1, a, b0, b1, b2, b3, b4, b5, b6, b7) do { \ + sph_u32 fu2 = T0up[B32_2(a[b2])]; \ + sph_u32 fd2 = T0dn[B32_2(a[b2])]; \ + sph_u32 fu3 = T1up[B32_3(a[b3])]; \ + sph_u32 fd3 = T1dn[B32_3(a[b3])]; \ + sph_u32 fu6 = T0up[B32_2(a[b6])]; \ + sph_u32 fd6 = T0dn[B32_2(a[b6])]; \ + sph_u32 fu7 = T1up[B32_3(a[b7])]; \ + sph_u32 fd7 = T1dn[B32_3(a[b7])]; \ + t[d0] = T0up[B32_0(a[b0])] \ + ^ T1up[B32_1(a[b1])] \ + ^ R32u(fu2, fd2) \ + ^ R32u(fu3, fd3) \ + ^ T0dn[B32_0(a[b4])] \ + ^ T1dn[B32_1(a[b5])] \ + ^ R32d(fu6, fd6) \ + ^ R32d(fu7, fd7); \ + t[d1] = T0dn[B32_0(a[b0])] \ + ^ T1dn[B32_1(a[b1])] \ + ^ R32d(fu2, fd2) \ + ^ R32d(fu3, fd3) \ + ^ T0up[B32_0(a[b4])] \ + ^ T1up[B32_1(a[b5])] \ + ^ R32u(fu6, fd6) \ + ^ R32u(fu7, fd7); \ + } while (0) + + +#define ROUND_BIG_P(a, r) do { \ + sph_u32 t[32]; \ + size_t u; \ + a[0x00] ^= PC32up(0x00, r); \ + a[0x01] ^= PC32dn(0x00, r); \ + a[0x02] ^= PC32up(0x10, r); \ + a[0x03] ^= PC32dn(0x10, r); \ + a[0x04] ^= PC32up(0x20, r); \ + a[0x05] ^= PC32dn(0x20, r); \ + a[0x06] ^= PC32up(0x30, r); \ + a[0x07] ^= PC32dn(0x30, r); \ + a[0x08] ^= PC32up(0x40, r); \ + a[0x09] ^= PC32dn(0x40, r); \ + a[0x0A] ^= PC32up(0x50, r); \ + a[0x0B] ^= PC32dn(0x50, r); \ + a[0x0C] ^= PC32up(0x60, r); \ + a[0x0D] ^= PC32dn(0x60, r); \ + a[0x0E] ^= PC32up(0x70, r); \ + a[0x0F] ^= PC32dn(0x70, r); \ + a[0x10] ^= PC32up(0x80, r); \ + a[0x11] ^= PC32dn(0x80, r); \ + a[0x12] ^= PC32up(0x90, r); \ + a[0x13] ^= PC32dn(0x90, r); \ + a[0x14] ^= PC32up(0xA0, r); \ + a[0x15] ^= PC32dn(0xA0, r); \ + a[0x16] ^= PC32up(0xB0, r); \ + a[0x17] ^= PC32dn(0xB0, r); \ + a[0x18] ^= PC32up(0xC0, r); \ + a[0x19] ^= PC32dn(0xC0, r); \ + a[0x1A] ^= PC32up(0xD0, r); \ + a[0x1B] ^= PC32dn(0xD0, r); \ + a[0x1C] ^= PC32up(0xE0, r); \ + a[0x1D] ^= PC32dn(0xE0, r); \ + a[0x1E] ^= PC32up(0xF0, r); \ + a[0x1F] ^= PC32dn(0xF0, r); \ + for (u = 0; u < 32; u += 8) { \ + RBTT(u + 0x00, (u + 0x01) & 0x1F, a, \ + u + 0x00, (u + 0x02) & 0x1F, \ + (u + 0x04) & 0x1F, (u + 0x06) & 0x1F, \ + (u + 0x09) & 0x1F, (u + 0x0B) & 0x1F, \ + (u + 0x0D) & 0x1F, (u + 0x17) & 0x1F); \ + RBTT(u + 0x02, (u + 0x03) & 0x1F, a, \ + u + 0x02, (u + 0x04) & 0x1F, \ + (u + 0x06) & 0x1F, (u + 0x08) & 0x1F, \ + (u + 0x0B) & 0x1F, (u + 0x0D) & 0x1F, \ + (u + 0x0F) & 0x1F, (u + 0x19) & 0x1F); \ + RBTT(u + 0x04, (u + 0x05) & 0x1F, a, \ + u + 0x04, (u + 0x06) & 0x1F, \ + (u + 0x08) & 0x1F, (u + 0x0A) & 0x1F, \ + (u + 0x0D) & 0x1F, (u + 0x0F) & 0x1F, \ + (u + 0x11) & 0x1F, (u + 0x1B) & 0x1F); \ + RBTT(u + 0x06, (u + 0x07) & 0x1F, a, \ + u + 0x06, (u + 0x08) & 0x1F, \ + (u + 0x0A) & 0x1F, (u + 0x0C) & 0x1F, \ + (u + 0x0F) & 0x1F, (u + 0x11) & 0x1F, \ + (u + 0x13) & 0x1F, (u + 0x1D) & 0x1F); \ + } \ + memcpy(a, t, sizeof t); \ + } while (0) + +#define ROUND_BIG_Q(a, r) do { \ + sph_u32 t[32]; \ + size_t u; \ + a[0x00] ^= QC32up(0x00, r); \ + a[0x01] ^= QC32dn(0x00, r); \ + a[0x02] ^= QC32up(0x10, r); \ + a[0x03] ^= QC32dn(0x10, r); \ + a[0x04] ^= QC32up(0x20, r); \ + a[0x05] ^= QC32dn(0x20, r); \ + a[0x06] ^= QC32up(0x30, r); \ + a[0x07] ^= QC32dn(0x30, r); \ + a[0x08] ^= QC32up(0x40, r); \ + a[0x09] ^= QC32dn(0x40, r); \ + a[0x0A] ^= QC32up(0x50, r); \ + a[0x0B] ^= QC32dn(0x50, r); \ + a[0x0C] ^= QC32up(0x60, r); \ + a[0x0D] ^= QC32dn(0x60, r); \ + a[0x0E] ^= QC32up(0x70, r); \ + a[0x0F] ^= QC32dn(0x70, r); \ + a[0x10] ^= QC32up(0x80, r); \ + a[0x11] ^= QC32dn(0x80, r); \ + a[0x12] ^= QC32up(0x90, r); \ + a[0x13] ^= QC32dn(0x90, r); \ + a[0x14] ^= QC32up(0xA0, r); \ + a[0x15] ^= QC32dn(0xA0, r); \ + a[0x16] ^= QC32up(0xB0, r); \ + a[0x17] ^= QC32dn(0xB0, r); \ + a[0x18] ^= QC32up(0xC0, r); \ + a[0x19] ^= QC32dn(0xC0, r); \ + a[0x1A] ^= QC32up(0xD0, r); \ + a[0x1B] ^= QC32dn(0xD0, r); \ + a[0x1C] ^= QC32up(0xE0, r); \ + a[0x1D] ^= QC32dn(0xE0, r); \ + a[0x1E] ^= QC32up(0xF0, r); \ + a[0x1F] ^= QC32dn(0xF0, r); \ + for (u = 0; u < 32; u += 8) { \ + RBTT(u + 0x00, (u + 0x01) & 0x1F, a, \ + (u + 0x02) & 0x1F, (u + 0x06) & 0x1F, \ + (u + 0x0A) & 0x1F, (u + 0x16) & 0x1F, \ + (u + 0x01) & 0x1F, (u + 0x05) & 0x1F, \ + (u + 0x09) & 0x1F, (u + 0x0D) & 0x1F); \ + RBTT(u + 0x02, (u + 0x03) & 0x1F, a, \ + (u + 0x04) & 0x1F, (u + 0x08) & 0x1F, \ + (u + 0x0C) & 0x1F, (u + 0x18) & 0x1F, \ + (u + 0x03) & 0x1F, (u + 0x07) & 0x1F, \ + (u + 0x0B) & 0x1F, (u + 0x0F) & 0x1F); \ + RBTT(u + 0x04, (u + 0x05) & 0x1F, a, \ + (u + 0x06) & 0x1F, (u + 0x0A) & 0x1F, \ + (u + 0x0E) & 0x1F, (u + 0x1A) & 0x1F, \ + (u + 0x05) & 0x1F, (u + 0x09) & 0x1F, \ + (u + 0x0D) & 0x1F, (u + 0x11) & 0x1F); \ + RBTT(u + 0x06, (u + 0x07) & 0x1F, a, \ + (u + 0x08) & 0x1F, (u + 0x0C) & 0x1F, \ + (u + 0x10) & 0x1F, (u + 0x1C) & 0x1F, \ + (u + 0x07) & 0x1F, (u + 0x0B) & 0x1F, \ + (u + 0x0F) & 0x1F, (u + 0x13) & 0x1F); \ + } \ + memcpy(a, t, sizeof t); \ + } while (0) + + +#define PERM_BIG_P(a) do { \ + int r; \ + for (r = 0; r < 14; r ++) \ + ROUND_BIG_P(a, r); \ + } while (0) + +#define PERM_BIG_Q(a) do { \ + int r; \ + for (r = 0; r < 14; r ++) \ + ROUND_BIG_Q(a, r); \ + } while (0) + + +#define COMPRESS_BIG do { \ + sph_u32 g[32], m[32]; \ + size_t uu; \ + for (uu = 0; uu < 32; uu ++) { \ + m[uu] = dec32e_aligned(buf + (uu << 2)); \ + g[uu] = m[uu] ^ H[uu]; \ + } \ + PERM_BIG_P(g); \ + PERM_BIG_Q(m); \ + for (uu = 0; uu < 32; uu ++) \ + H[uu] ^= g[uu] ^ m[uu]; \ + } while (0) + +#define FINAL_BIG do { \ + sph_u32 x[32]; \ + size_t uu; \ + memcpy(x, H, sizeof x); \ + PERM_BIG_P(x); \ + for (uu = 0; uu < 32; uu ++) \ + H[uu] ^= x[uu]; \ + } while (0) + + +static void +groestl_big_init(sph_groestl_big_context *sc, unsigned out_size) +{ + size_t u = 0; + + sc->ptr = 0; + for (u = 0; u < 31; u ++) + sc->state.narrow[u] = 0; + sc->state.narrow[31] = ((sph_u32)(out_size & 0xFF) << 24) + | ((sph_u32)(out_size & 0xFF00) << 8); + sc->count = 0; +} + +static void +groestl_big_core(sph_groestl_big_context *sc, const void *data, size_t len) +{ + if (len == 0) { + return; + } + + unsigned char *buf = NULL; + size_t ptr = 0; + DECL_STATE_BIG + + buf = sc->buf; + ptr = sc->ptr; + if (len < (sizeof sc->buf) - ptr) { + memcpy(buf + ptr, data, len); + ptr += len; + sc->ptr = ptr; + return; + } + + READ_STATE_BIG(sc); + while (len > 0) { + size_t clen = 0; + + clen = (sizeof sc->buf) - ptr; + if (clen > len) + clen = len; + memcpy(buf + ptr, data, clen); + ptr += clen; + data = (const unsigned char *)data + clen; + len -= clen; + if (ptr == sizeof sc->buf) { + COMPRESS_BIG; + sc->count ++; + ptr = 0; + } + } + WRITE_STATE_BIG(sc); + sc->ptr = ptr; +} + +static void +groestl_big_close(sph_groestl_big_context *sc, + unsigned ub, unsigned n, void *dst, size_t out_len) +{ + unsigned char pad[136] = {0}; + size_t ptr = 0, pad_len = 0, u2 = 0; + sph_u64 count = 0; + unsigned z = 0; + DECL_STATE_BIG + + ptr = sc->ptr; + z = 0x80 >> n; + pad[0] = ((ub & -z) | z) & 0xFF; + if (ptr < 120) { + pad_len = 128 - ptr; + count = SPH_T64(sc->count + 1); + } else { + pad_len = 256 - ptr; + count = SPH_T64(sc->count + 2); + } + memzero(pad + 1, pad_len - 9); + sph_enc64be(pad + pad_len - 8, count); + groestl_big_core(sc, pad, pad_len); + READ_STATE_BIG(sc); + FINAL_BIG; + for (u2 = 0; u2 < 16; u2 ++) + enc32e(pad + (u2 << 2), H[u2 + 16]); + memcpy(dst, pad + 64 - out_len, out_len); + groestl_big_init(sc, (unsigned)out_len << 3); +} + +void +groestl512_Init(void *cc) +{ + groestl_big_init((sph_groestl_big_context *)cc, 512); +} + +void +groestl512_Update(void *cc, const void *data, size_t len) +{ + groestl_big_core((sph_groestl_big_context *)cc, data, len); +} + +void +groestl512_Final(void *cc, void *dst) +{ + groestl_big_close((sph_groestl_big_context *)cc, 0, 0, dst, 64); +} + +void +groestl512_DoubleTrunc(void *cc, void *dst) +{ + char buf[64] = {0}; + + groestl512_Final(cc, buf); + groestl512_Update(cc, buf, sizeof(buf)); + groestl512_Final(cc, buf); + memcpy(dst, buf, 32); +} diff --git a/deps/crypto/trezor-crypto/groestl.h b/deps/crypto/trezor-crypto/groestl.h new file mode 100644 index 000000000..7dd89d28a --- /dev/null +++ b/deps/crypto/trezor-crypto/groestl.h @@ -0,0 +1,95 @@ +/* Groestl hash from https://github.com/Groestlcoin/vanitygen + * Trezor adaptation by Yura Pakhuchiy . */ +/** + * Groestl interface. This code implements Groestl with the recommended + * parameters for SHA-3, with outputs of 224, 256, 384 and 512 bits. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @file sph_groestl.h + * @author Thomas Pornin + */ + +#ifndef GROESTL_H__ +#define GROESTL_H__ + +#include + +/** + * This structure is a context for Groestl-384 and Groestl-512 computations: + * it contains the intermediate values and some data from the last + * entered block. Once a Groestl computation has been performed, the + * context can be reused for another computation. + * + * The contents of this structure are private. A running Groestl + * computation can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { + unsigned char buf[128]; /* first field, for alignment */ + size_t ptr; + union { + uint64_t wide[16]; + uint32_t narrow[32]; + } state; + uint64_t count; +} sph_groestl_big_context; + +typedef sph_groestl_big_context GROESTL512_CTX; + +/** + * Initialize a Groestl-512 context. This process performs no memory allocation. + * + * @param cc the Groestl-512 context (pointer to a + * GROESTL512_CTX) + */ +void groestl512_Init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the Groestl-512 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void groestl512_Update(void *cc, const void *data, size_t len); + +/** + * Terminate the current Groestl-512 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (64 bytes). The context is automatically + * reinitialized. + * + * @param cc the Groestl-512 context + * @param dst the destination buffer + */ +void groestl512_Final(void *cc, void *dst); + +/* Calculate double Groestl-512 hash and truncate it to 256-bits. */ +void groestl512_DoubleTrunc(void *cc, void *dst); + +#endif diff --git a/deps/crypto/trezor-crypto/groestl_internal.h b/deps/crypto/trezor-crypto/groestl_internal.h new file mode 100644 index 000000000..3c675d8ea --- /dev/null +++ b/deps/crypto/trezor-crypto/groestl_internal.h @@ -0,0 +1,509 @@ +/* Groestl hash from https://github.com/Groestlcoin/vanitygen + * Trezor adaptation by Yura Pakhuchiy . */ +/** + * Basic type definitions. + * + * This header file defines the generic integer types that will be used + * for the implementation of hash functions; it also contains helper + * functions which encode and decode multi-byte integer values, using + * either little-endian or big-endian conventions. + * + * This file contains a compile-time test on the size of a byte + * (the unsigned char C type). If bytes are not octets, + * i.e. if they do not have a size of exactly 8 bits, then compilation + * is aborted. Architectures where bytes are not octets are relatively + * rare, even in the embedded devices market. We forbid non-octet bytes + * because there is no clear convention on how octet streams are encoded + * on such systems. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @file sph_types.h + * @author Thomas Pornin + */ + +#ifndef GROESTL_INTERNAL_H__ +#define GROESTL_INTERNAL_H__ + +#include + +/* + * All our I/O functions are defined over octet streams. We do not know + * how to handle input data if bytes are not octets. + */ +#if CHAR_BIT != 8 +#error This code requires 8-bit bytes +#endif + +#if defined __STDC__ && __STDC_VERSION__ >= 199901L + +#include + +typedef uint32_t sph_u32; +typedef int32_t sph_s32; +typedef uint64_t sph_u64; +typedef int64_t sph_s64; + +#define SPH_C32(x) ((sph_u32)(x)) +#define SPH_C64(x) ((sph_u64)(x)) + +#else +#error We need at least C99 compiler +#endif + +#define SPH_T32(x) ((x) & SPH_C32(0xFFFFFFFF)) +#define SPH_ROTL32(x, n) SPH_T32(((x) << (n)) | ((x) >> (32 - (n)))) +#define SPH_ROTR32(x, n) SPH_ROTL32(x, (32 - (n))) + +#define SPH_T64(x) ((x) & SPH_C64(0xFFFFFFFFFFFFFFFF)) +#define SPH_ROTL64(x, n) SPH_T64(((x) << (n)) | ((x) >> (64 - (n)))) +#define SPH_ROTR64(x, n) SPH_ROTL64(x, (64 - (n))) + +/* + * 32-bit x86, aka "i386 compatible". + */ +#if defined __i386__ || defined _M_IX86 + +#define SPH_DETECT_LITTLE_ENDIAN 1 +#define SPH_DETECT_BIG_ENDIAN 0 + +/* + * 64-bit x86, hereafter known as "amd64". + */ +#elif defined __x86_64 || defined _M_X64 + +#define SPH_DETECT_LITTLE_ENDIAN 1 +#define SPH_DETECT_BIG_ENDIAN 0 + +/* + * ARM, little-endian. + */ +#elif defined __arm__ && __ARMEL__ + +#define SPH_DETECT_LITTLE_ENDIAN 1 +#define SPH_DETECT_BIG_ENDIAN 0 + +/* + * ARM64, little-endian. + */ +#elif defined __aarch64__ + +#define SPH_DETECT_LITTLE_ENDIAN 1 +#define SPH_DETECT_BIG_ENDIAN 0 + +#endif + + +#if defined SPH_DETECT_LITTLE_ENDIAN && !defined SPH_LITTLE_ENDIAN +#define SPH_LITTLE_ENDIAN SPH_DETECT_LITTLE_ENDIAN +#endif +#if defined SPH_DETECT_BIG_ENDIAN && !defined SPH_BIG_ENDIAN +#define SPH_BIG_ENDIAN SPH_DETECT_BIG_ENDIAN +#endif + +static inline sph_u32 +sph_bswap32(sph_u32 x) +{ + x = SPH_T32((x << 16) | (x >> 16)); + x = ((x & SPH_C32(0xFF00FF00)) >> 8) + | ((x & SPH_C32(0x00FF00FF)) << 8); + return x; +} + +/** + * Byte-swap a 64-bit value. + * + * @param x the input value + * @return the byte-swapped value + */ +static inline sph_u64 +sph_bswap64(sph_u64 x) +{ + x = SPH_T64((x << 32) | (x >> 32)); + x = ((x & SPH_C64(0xFFFF0000FFFF0000)) >> 16) + | ((x & SPH_C64(0x0000FFFF0000FFFF)) << 16); + x = ((x & SPH_C64(0xFF00FF00FF00FF00)) >> 8) + | ((x & SPH_C64(0x00FF00FF00FF00FF)) << 8); + return x; +} + +static inline void +sph_enc16be(void *dst, unsigned val) +{ + ((unsigned char *)dst)[0] = (val >> 8); + ((unsigned char *)dst)[1] = val; +} + +static inline unsigned +sph_dec16be(const void *src) +{ + return ((unsigned)(((const unsigned char *)src)[0]) << 8) + | (unsigned)(((const unsigned char *)src)[1]); +} + +static inline void +sph_enc16le(void *dst, unsigned val) +{ + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = val >> 8; +} + +static inline unsigned +sph_dec16le(const void *src) +{ + return (unsigned)(((const unsigned char *)src)[0]) + | ((unsigned)(((const unsigned char *)src)[1]) << 8); +} + +/** + * Encode a 32-bit value into the provided buffer (big endian convention). + * + * @param dst the destination buffer + * @param val the 32-bit value to encode + */ +static inline void +sph_enc32be(void *dst, sph_u32 val) +{ + ((unsigned char *)dst)[0] = (val >> 24); + ((unsigned char *)dst)[1] = (val >> 16); + ((unsigned char *)dst)[2] = (val >> 8); + ((unsigned char *)dst)[3] = val; +} + +/** + * Encode a 32-bit value into the provided buffer (big endian convention). + * The destination buffer must be properly aligned. + * + * @param dst the destination buffer (32-bit aligned) + * @param val the value to encode + */ +static inline void +sph_enc32be_aligned(void *dst, sph_u32 val) +{ +#if SPH_LITTLE_ENDIAN + *(sph_u32 *)dst = sph_bswap32(val); +#elif SPH_BIG_ENDIAN + *(sph_u32 *)dst = val; +#else + ((unsigned char *)dst)[0] = (val >> 24); + ((unsigned char *)dst)[1] = (val >> 16); + ((unsigned char *)dst)[2] = (val >> 8); + ((unsigned char *)dst)[3] = val; +#endif +} + +/** + * Decode a 32-bit value from the provided buffer (big endian convention). + * + * @param src the source buffer + * @return the decoded value + */ +static inline sph_u32 +sph_dec32be(const void *src) +{ + return ((sph_u32)(((const unsigned char *)src)[0]) << 24) + | ((sph_u32)(((const unsigned char *)src)[1]) << 16) + | ((sph_u32)(((const unsigned char *)src)[2]) << 8) + | (sph_u32)(((const unsigned char *)src)[3]); +} + +/** + * Decode a 32-bit value from the provided buffer (big endian convention). + * The source buffer must be properly aligned. + * + * @param src the source buffer (32-bit aligned) + * @return the decoded value + */ +static inline sph_u32 +sph_dec32be_aligned(const void *src) +{ +#if SPH_LITTLE_ENDIAN + return sph_bswap32(*(const sph_u32 *)src); +#elif SPH_BIG_ENDIAN + return *(const sph_u32 *)src; +#else + return ((sph_u32)(((const unsigned char *)src)[0]) << 24) + | ((sph_u32)(((const unsigned char *)src)[1]) << 16) + | ((sph_u32)(((const unsigned char *)src)[2]) << 8) + | (sph_u32)(((const unsigned char *)src)[3]); +#endif +} + +/** + * Encode a 32-bit value into the provided buffer (little endian convention). + * + * @param dst the destination buffer + * @param val the 32-bit value to encode + */ +static inline void +sph_enc32le(void *dst, sph_u32 val) +{ + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); +} + +/** + * Encode a 32-bit value into the provided buffer (little endian convention). + * The destination buffer must be properly aligned. + * + * @param dst the destination buffer (32-bit aligned) + * @param val the value to encode + */ +static inline void +sph_enc32le_aligned(void *dst, sph_u32 val) +{ +#if SPH_LITTLE_ENDIAN + *(sph_u32 *)dst = val; +#elif SPH_BIG_ENDIAN + *(sph_u32 *)dst = sph_bswap32(val); +#else + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); +#endif +} + +/** + * Decode a 32-bit value from the provided buffer (little endian convention). + * + * @param src the source buffer + * @return the decoded value + */ +static inline sph_u32 +sph_dec32le(const void *src) +{ + return (sph_u32)(((const unsigned char *)src)[0]) + | ((sph_u32)(((const unsigned char *)src)[1]) << 8) + | ((sph_u32)(((const unsigned char *)src)[2]) << 16) + | ((sph_u32)(((const unsigned char *)src)[3]) << 24); +} + +/** + * Decode a 32-bit value from the provided buffer (little endian convention). + * The source buffer must be properly aligned. + * + * @param src the source buffer (32-bit aligned) + * @return the decoded value + */ +static inline sph_u32 +sph_dec32le_aligned(const void *src) +{ +#if SPH_LITTLE_ENDIAN + return *(const sph_u32 *)src; +#elif SPH_BIG_ENDIAN + return sph_bswap32(*(const sph_u32 *)src); +#else + return (sph_u32)(((const unsigned char *)src)[0]) + | ((sph_u32)(((const unsigned char *)src)[1]) << 8) + | ((sph_u32)(((const unsigned char *)src)[2]) << 16) + | ((sph_u32)(((const unsigned char *)src)[3]) << 24); +#endif +} + +/** + * Encode a 64-bit value into the provided buffer (big endian convention). + * + * @param dst the destination buffer + * @param val the 64-bit value to encode + */ +static inline void +sph_enc64be(void *dst, sph_u64 val) +{ + ((unsigned char *)dst)[0] = (val >> 56); + ((unsigned char *)dst)[1] = (val >> 48); + ((unsigned char *)dst)[2] = (val >> 40); + ((unsigned char *)dst)[3] = (val >> 32); + ((unsigned char *)dst)[4] = (val >> 24); + ((unsigned char *)dst)[5] = (val >> 16); + ((unsigned char *)dst)[6] = (val >> 8); + ((unsigned char *)dst)[7] = val; +} + +/** + * Encode a 64-bit value into the provided buffer (big endian convention). + * The destination buffer must be properly aligned. + * + * @param dst the destination buffer (64-bit aligned) + * @param val the value to encode + */ +static inline void +sph_enc64be_aligned(void *dst, sph_u64 val) +{ +#if SPH_LITTLE_ENDIAN + *(sph_u64 *)dst = sph_bswap64(val); +#elif SPH_BIG_ENDIAN + *(sph_u64 *)dst = val; +#else + ((unsigned char *)dst)[0] = (val >> 56); + ((unsigned char *)dst)[1] = (val >> 48); + ((unsigned char *)dst)[2] = (val >> 40); + ((unsigned char *)dst)[3] = (val >> 32); + ((unsigned char *)dst)[4] = (val >> 24); + ((unsigned char *)dst)[5] = (val >> 16); + ((unsigned char *)dst)[6] = (val >> 8); + ((unsigned char *)dst)[7] = val; +#endif +} + +/** + * Decode a 64-bit value from the provided buffer (big endian convention). + * + * @param src the source buffer + * @return the decoded value + */ +static inline sph_u64 +sph_dec64be(const void *src) +{ + return ((sph_u64)(((const unsigned char *)src)[0]) << 56) + | ((sph_u64)(((const unsigned char *)src)[1]) << 48) + | ((sph_u64)(((const unsigned char *)src)[2]) << 40) + | ((sph_u64)(((const unsigned char *)src)[3]) << 32) + | ((sph_u64)(((const unsigned char *)src)[4]) << 24) + | ((sph_u64)(((const unsigned char *)src)[5]) << 16) + | ((sph_u64)(((const unsigned char *)src)[6]) << 8) + | (sph_u64)(((const unsigned char *)src)[7]); +} + +/** + * Decode a 64-bit value from the provided buffer (big endian convention). + * The source buffer must be properly aligned. + * + * @param src the source buffer (64-bit aligned) + * @return the decoded value + */ +static inline sph_u64 +sph_dec64be_aligned(const void *src) +{ +#if SPH_LITTLE_ENDIAN + return sph_bswap64(*(const sph_u64 *)src); +#elif SPH_BIG_ENDIAN + return *(const sph_u64 *)src; +#else + return ((sph_u64)(((const unsigned char *)src)[0]) << 56) + | ((sph_u64)(((const unsigned char *)src)[1]) << 48) + | ((sph_u64)(((const unsigned char *)src)[2]) << 40) + | ((sph_u64)(((const unsigned char *)src)[3]) << 32) + | ((sph_u64)(((const unsigned char *)src)[4]) << 24) + | ((sph_u64)(((const unsigned char *)src)[5]) << 16) + | ((sph_u64)(((const unsigned char *)src)[6]) << 8) + | (sph_u64)(((const unsigned char *)src)[7]); +#endif +} + +/** + * Encode a 64-bit value into the provided buffer (little endian convention). + * + * @param dst the destination buffer + * @param val the 64-bit value to encode + */ +static inline void +sph_enc64le(void *dst, sph_u64 val) +{ + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); + ((unsigned char *)dst)[4] = (val >> 32); + ((unsigned char *)dst)[5] = (val >> 40); + ((unsigned char *)dst)[6] = (val >> 48); + ((unsigned char *)dst)[7] = (val >> 56); +} + +/** + * Encode a 64-bit value into the provided buffer (little endian convention). + * The destination buffer must be properly aligned. + * + * @param dst the destination buffer (64-bit aligned) + * @param val the value to encode + */ +static inline void +sph_enc64le_aligned(void *dst, sph_u64 val) +{ +#if SPH_LITTLE_ENDIAN + *(sph_u64 *)dst = val; +#elif SPH_BIG_ENDIAN + *(sph_u64 *)dst = sph_bswap64(val); +#else + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); + ((unsigned char *)dst)[4] = (val >> 32); + ((unsigned char *)dst)[5] = (val >> 40); + ((unsigned char *)dst)[6] = (val >> 48); + ((unsigned char *)dst)[7] = (val >> 56); +#endif +} + +/** + * Decode a 64-bit value from the provided buffer (little endian convention). + * + * @param src the source buffer + * @return the decoded value + */ +static inline sph_u64 +sph_dec64le(const void *src) +{ + return (sph_u64)(((const unsigned char *)src)[0]) + | ((sph_u64)(((const unsigned char *)src)[1]) << 8) + | ((sph_u64)(((const unsigned char *)src)[2]) << 16) + | ((sph_u64)(((const unsigned char *)src)[3]) << 24) + | ((sph_u64)(((const unsigned char *)src)[4]) << 32) + | ((sph_u64)(((const unsigned char *)src)[5]) << 40) + | ((sph_u64)(((const unsigned char *)src)[6]) << 48) + | ((sph_u64)(((const unsigned char *)src)[7]) << 56); +} + +/** + * Decode a 64-bit value from the provided buffer (little endian convention). + * The source buffer must be properly aligned. + * + * @param src the source buffer (64-bit aligned) + * @return the decoded value + */ +static inline sph_u64 +sph_dec64le_aligned(const void *src) +{ +#if SPH_LITTLE_ENDIAN + return *(const sph_u64 *)src; +#elif SPH_BIG_ENDIAN + return sph_bswap64(*(const sph_u64 *)src); +#else + return (sph_u64)(((const unsigned char *)src)[0]) + | ((sph_u64)(((const unsigned char *)src)[1]) << 8) + | ((sph_u64)(((const unsigned char *)src)[2]) << 16) + | ((sph_u64)(((const unsigned char *)src)[3]) << 24) + | ((sph_u64)(((const unsigned char *)src)[4]) << 32) + | ((sph_u64)(((const unsigned char *)src)[5]) << 40) + | ((sph_u64)(((const unsigned char *)src)[6]) << 48) + | ((sph_u64)(((const unsigned char *)src)[7]) << 56); +#endif +} + +#endif diff --git a/deps/crypto/trezor-crypto/gui/.gitignore b/deps/crypto/trezor-crypto/gui/.gitignore new file mode 100644 index 000000000..b44cbb243 --- /dev/null +++ b/deps/crypto/trezor-crypto/gui/.gitignore @@ -0,0 +1,4 @@ +gui.pro.user +moc_mainwindow.cpp +ui_mainwindow.h +Makefile diff --git a/deps/crypto/trezor-crypto/gui/gui.pro b/deps/crypto/trezor-crypto/gui/gui.pro new file mode 100644 index 000000000..e4623bc4f --- /dev/null +++ b/deps/crypto/trezor-crypto/gui/gui.pro @@ -0,0 +1,34 @@ +QT += core gui +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = gui +TEMPLATE = app + +SOURCES += ../address.c +SOURCES += ../bip32.c +SOURCES += ../bip39.c +SOURCES += ../sha2.c +SOURCES += ../pbkdf2.c +SOURCES += ../hmac.c +SOURCES += ../rand.c +SOURCES += ../bignum.c +SOURCES += ../ecdsa.c +SOURCES += ../rfc6979.c +SOURCES += ../hmac_drbg.c +SOURCES += ../ripemd160.c +SOURCES += ../base58.c +SOURCES += ../secp256k1.c +SOURCES += ../nist256p1.c +SOURCES += ../curves.c +SOURCES += ../ed25519-donna/ed25519.c +SOURCES += mainwindow.cpp +SOURCES += main.cpp + +HEADERS += mainwindow.h +HEADERS += ../bip32.h +HEADERS += ../bip39.h + +FORMS += mainwindow.ui + +INCLUDEPATH += .. +INCLUDEPATH += ../ed25519-donna diff --git a/deps/crypto/trezor-crypto/gui/main.cpp b/deps/crypto/trezor-crypto/gui/main.cpp new file mode 100644 index 000000000..115a22bf7 --- /dev/null +++ b/deps/crypto/trezor-crypto/gui/main.cpp @@ -0,0 +1,10 @@ +#include "mainwindow.h" +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + return a.exec(); +} diff --git a/deps/crypto/trezor-crypto/gui/mainwindow.cpp b/deps/crypto/trezor-crypto/gui/mainwindow.cpp new file mode 100644 index 000000000..1bc7ea5c9 --- /dev/null +++ b/deps/crypto/trezor-crypto/gui/mainwindow.cpp @@ -0,0 +1,78 @@ +#include +#include "mainwindow.h" +#include "ui_mainwindow.h" +extern "C" { +#include "../bip32.h" +#include "../bip39.h" +#include "../ecdsa.h" +#include "../curves.h" +} + +bool root_set = false; +HDNode root; + +MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) +{ + ui->setupUi(this); + for (int i = 0; i < 100; i++) { + ui->listAddress->insertRow(i); + ui->listChange->insertRow(i); + + } +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +// abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about + +void MainWindow::on_buttonLoad_clicked() +{ + if (!mnemonic_check(ui->editMnemonic->text().toLocal8Bit().data())) { + QMessageBox::critical(this, "Error", "Text is not a valid BIP39 mnemonic.", QMessageBox::Ok); + return; + } + uint8_t seed[64]; + mnemonic_to_seed(ui->editMnemonic->text().toLocal8Bit().data(), ui->editPassphrase->text().toLocal8Bit().data(), seed, 0); + hdnode_from_seed(seed, 64, SECP256K1_NAME, &root); + root_set = true; + ui->spinAccount->setValue(1); + on_spinAccount_valueChanged(1); +} + +void MainWindow::on_spinAccount_valueChanged(int arg1) +{ + if (!root_set) return; + // constants for Bitcoin + const uint32_t version_public = 0x0488b21e; + const uint32_t version_private = 0x0488ade4; + const char addr_version = 0x00, wif_version = 0x80; + const size_t buflen = 128; + char buf[buflen + 1]; + HDNode node; + uint32_t fingerprint; + // external chain + for (int chain = 0; chain < 2; chain++) { + QTableWidget *list = chain == 0 ? ui->listAddress : ui->listChange; + node = root; + hdnode_private_ckd(&node, 44 | 0x80000000); + hdnode_private_ckd(&node, 0 | 0x80000000); // bitcoin + hdnode_private_ckd(&node, (arg1 - 1) | 0x80000000); + fingerprint = hdnode_fingerprint(&node); + hdnode_serialize_private(&node, fingerprint, version_private, buf, buflen); QString xprv = QString(buf); ui->lineXprv->setText(xprv); + hdnode_serialize_public(&node, fingerprint, version_public, buf, buflen); QString xpub = QString(buf); ui->lineXpub->setText(xpub); + hdnode_private_ckd(&node, chain); // external / internal + for (int i = 0; i < 100; i++) { + HDNode node2 = node; + hdnode_private_ckd(&node2, i); + hdnode_fill_public_key(&node2); + ecdsa_get_address(node2.public_key, addr_version, buf, buflen); QString address = QString(buf); + ecdsa_get_wif(node2.private_key, wif_version, buf, buflen); QString wif = QString(buf); + list->setItem(i, 0, new QTableWidgetItem(address)); + list->setItem(i, 1, new QTableWidgetItem(wif)); + list->setItem(i, 2, new QTableWidgetItem("0.0")); + } + } +} diff --git a/deps/crypto/trezor-crypto/gui/mainwindow.h b/deps/crypto/trezor-crypto/gui/mainwindow.h new file mode 100644 index 000000000..7275167da --- /dev/null +++ b/deps/crypto/trezor-crypto/gui/mainwindow.h @@ -0,0 +1,27 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + +private slots: + void on_buttonLoad_clicked(); + void on_spinAccount_valueChanged(int arg1); + +private: + Ui::MainWindow *ui; +}; + +#endif // MAINWINDOW_H diff --git a/deps/crypto/trezor-crypto/gui/mainwindow.ui b/deps/crypto/trezor-crypto/gui/mainwindow.ui new file mode 100644 index 000000000..cbc302b3b --- /dev/null +++ b/deps/crypto/trezor-crypto/gui/mainwindow.ui @@ -0,0 +1,161 @@ + + + MainWindow + + + + 0 + 0 + 1000 + 600 + + + + + DejaVu Sans Mono + 8 + + + + Trezor + + + + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + 120 + 16777215 + + + + Load + + + + + + + + address + + + + + private key + + + + + balance + + + + + + + + + address + + + + + private key + + + + + balance + + + + + + + + Mnemonic: + + + + + + + Passphrase: + + + + + + + External Chain: + + + + + + + Internal Chain: + + + + + + + + 130 + 16777215 + + + + Account # + + + 1 + + + 2147483647 + + + + + + + + + + + + + + + editMnemonic + editPassphrase + buttonLoad + spinAccount + listAddress + listChange + + + + diff --git a/deps/crypto/trezor-crypto/hasher.c b/deps/crypto/trezor-crypto/hasher.c new file mode 100644 index 000000000..23a4c82c3 --- /dev/null +++ b/deps/crypto/trezor-crypto/hasher.c @@ -0,0 +1,156 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "hasher.h" +#include "ripemd160.h" + +void hasher_InitParam(Hasher *hasher, HasherType type, const void *param, + uint32_t param_size) { + hasher->type = type; + hasher->param = param; + hasher->param_size = param_size; + + switch (hasher->type) { + case HASHER_SHA2: + case HASHER_SHA2D: + case HASHER_SHA2_RIPEMD: + sha256_Init(&hasher->ctx.sha2); + break; + case HASHER_SHA3: +#if USE_KECCAK + case HASHER_SHA3K: +#endif + sha3_256_Init(&hasher->ctx.sha3); + break; + case HASHER_BLAKE: + case HASHER_BLAKED: + case HASHER_BLAKE_RIPEMD: + blake256_Init(&hasher->ctx.blake); + break; + case HASHER_GROESTLD_TRUNC: + groestl512_Init(&hasher->ctx.groestl); + break; + case HASHER_BLAKE2B: + blake2b_Init(&hasher->ctx.blake2b, 32); + break; + case HASHER_BLAKE2B_PERSONAL: + blake2b_InitPersonal(&hasher->ctx.blake2b, 32, hasher->param, + hasher->param_size); + break; + case HASHER_RIPEMD: + ripemd160_Init(&hasher->ctx.ripemd160); + break; + } +} + +void hasher_Init(Hasher *hasher, HasherType type) { + hasher_InitParam(hasher, type, NULL, 0); +} + +void hasher_Reset(Hasher *hasher) { + hasher_InitParam(hasher, hasher->type, hasher->param, hasher->param_size); +} + +void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length) { + switch (hasher->type) { + case HASHER_SHA2: + case HASHER_SHA2D: + case HASHER_SHA2_RIPEMD: + sha256_Update(&hasher->ctx.sha2, data, length); + break; + case HASHER_SHA3: +#if USE_KECCAK + case HASHER_SHA3K: +#endif + sha3_Update(&hasher->ctx.sha3, data, length); + break; + case HASHER_BLAKE: + case HASHER_BLAKED: + case HASHER_BLAKE_RIPEMD: + blake256_Update(&hasher->ctx.blake, data, length); + break; + case HASHER_GROESTLD_TRUNC: + groestl512_Update(&hasher->ctx.groestl, data, length); + break; + case HASHER_BLAKE2B: + case HASHER_BLAKE2B_PERSONAL: + blake2b_Update(&hasher->ctx.blake2b, data, length); + break; + case HASHER_RIPEMD: + ripemd160_Update(&hasher->ctx.ripemd160, data, length); + break; + } +} + +void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]) { + switch (hasher->type) { + case HASHER_SHA2: + sha256_Final(&hasher->ctx.sha2, hash); + break; + case HASHER_SHA2D: + sha256_Final(&hasher->ctx.sha2, hash); + hasher_Raw(HASHER_SHA2, hash, HASHER_DIGEST_LENGTH, hash); + break; + case HASHER_SHA2_RIPEMD: + sha256_Final(&hasher->ctx.sha2, hash); + ripemd160(hash, HASHER_DIGEST_LENGTH, hash); + break; + case HASHER_SHA3: + sha3_Final(&hasher->ctx.sha3, hash); + break; +#if USE_KECCAK + case HASHER_SHA3K: + keccak_Final(&hasher->ctx.sha3, hash); + break; +#endif + case HASHER_BLAKE: + blake256_Final(&hasher->ctx.blake, hash); + break; + case HASHER_BLAKED: + blake256_Final(&hasher->ctx.blake, hash); + hasher_Raw(HASHER_BLAKE, hash, HASHER_DIGEST_LENGTH, hash); + break; + case HASHER_BLAKE_RIPEMD: + blake256_Final(&hasher->ctx.blake, hash); + ripemd160(hash, HASHER_DIGEST_LENGTH, hash); + break; + case HASHER_GROESTLD_TRUNC: + groestl512_DoubleTrunc(&hasher->ctx.groestl, hash); + break; + case HASHER_BLAKE2B: + case HASHER_BLAKE2B_PERSONAL: + blake2b_Final(&hasher->ctx.blake2b, hash, 32); + break; + case HASHER_RIPEMD: + ripemd160_Final(&hasher->ctx.ripemd160, hash); + break; + } +} + +void hasher_Raw(HasherType type, const uint8_t *data, size_t length, + uint8_t hash[HASHER_DIGEST_LENGTH]) { + Hasher hasher = {0}; + + hasher_Init(&hasher, type); + hasher_Update(&hasher, data, length); + hasher_Final(&hasher, hash); +} diff --git a/deps/crypto/trezor-crypto/hasher.h b/deps/crypto/trezor-crypto/hasher.h new file mode 100644 index 000000000..4dd0f5457 --- /dev/null +++ b/deps/crypto/trezor-crypto/hasher.h @@ -0,0 +1,86 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __HASHER_H__ +#define __HASHER_H__ + +#include +#include + +#include "blake256.h" +#include "blake2b.h" +#include "ripemd160.h" +#include "groestl.h" +#include "sha2.h" +#include "sha3.h" + +#define HASHER_DIGEST_LENGTH 32 + +typedef enum { + HASHER_SHA2, + HASHER_SHA2D, + HASHER_SHA2_RIPEMD, + + HASHER_SHA3, +#if USE_KECCAK + HASHER_SHA3K, +#endif + + HASHER_BLAKE, + HASHER_BLAKED, + HASHER_BLAKE_RIPEMD, + + HASHER_GROESTLD_TRUNC, /* Double Groestl512 hasher truncated to 256 bits */ + + HASHER_BLAKE2B, + HASHER_BLAKE2B_PERSONAL, + + HASHER_RIPEMD, +} HasherType; + +typedef struct { + HasherType type; + + union { + SHA256_CTX sha2; // for HASHER_SHA2{,D} + SHA3_CTX sha3; // for HASHER_SHA3{,K} + BLAKE256_CTX blake; // for HASHER_BLAKE{,D} + GROESTL512_CTX groestl; // for HASHER_GROESTLD_TRUNC + BLAKE2B_CTX blake2b; // for HASHER_BLAKE2B{,_PERSONAL} + RIPEMD160_CTX ripemd160; // for HASHER_RIPEMD + } ctx; + + const void *param; + uint32_t param_size; +} Hasher; + +void hasher_InitParam(Hasher *hasher, HasherType type, const void *param, + uint32_t param_size); +void hasher_Init(Hasher *hasher, HasherType type); +void hasher_Reset(Hasher *hasher); +void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length); +void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]); + +void hasher_Raw(HasherType type, const uint8_t *data, size_t length, + uint8_t hash[HASHER_DIGEST_LENGTH]); + +#endif diff --git a/deps/crypto/trezor-crypto/hmac.c b/deps/crypto/trezor-crypto/hmac.c new file mode 100644 index 000000000..654f2d6e8 --- /dev/null +++ b/deps/crypto/trezor-crypto/hmac.c @@ -0,0 +1,176 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include "hmac.h" +#include "memzero.h" +#include "options.h" + +void hmac_sha256_Init(HMAC_SHA256_CTX *hctx, const uint8_t *key, + const uint32_t keylen) { + static CONFIDENTIAL uint8_t i_key_pad[SHA256_BLOCK_LENGTH]; + memzero(i_key_pad, SHA256_BLOCK_LENGTH); + if (keylen > SHA256_BLOCK_LENGTH) { + sha256_Raw(key, keylen, i_key_pad); + } else { + memcpy(i_key_pad, key, keylen); + } + for (int i = 0; i < SHA256_BLOCK_LENGTH; i++) { + hctx->o_key_pad[i] = i_key_pad[i] ^ 0x5c; + i_key_pad[i] ^= 0x36; + } + sha256_Init(&(hctx->ctx)); + sha256_Update(&(hctx->ctx), i_key_pad, SHA256_BLOCK_LENGTH); + memzero(i_key_pad, sizeof(i_key_pad)); +} + +void hmac_sha256_Update(HMAC_SHA256_CTX *hctx, const uint8_t *msg, + const uint32_t msglen) { + sha256_Update(&(hctx->ctx), msg, msglen); +} + +void hmac_sha256_Final(HMAC_SHA256_CTX *hctx, uint8_t *hmac) { + sha256_Final(&(hctx->ctx), hmac); + sha256_Init(&(hctx->ctx)); + sha256_Update(&(hctx->ctx), hctx->o_key_pad, SHA256_BLOCK_LENGTH); + sha256_Update(&(hctx->ctx), hmac, SHA256_DIGEST_LENGTH); + sha256_Final(&(hctx->ctx), hmac); + memzero(hctx, sizeof(HMAC_SHA256_CTX)); +} + +void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, + const uint32_t msglen, uint8_t *hmac) { + static CONFIDENTIAL HMAC_SHA256_CTX hctx; + hmac_sha256_Init(&hctx, key, keylen); + hmac_sha256_Update(&hctx, msg, msglen); + hmac_sha256_Final(&hctx, hmac); +} + +void hmac_sha256_prepare(const uint8_t *key, const uint32_t keylen, + uint32_t *opad_digest, uint32_t *ipad_digest) { + static CONFIDENTIAL uint32_t key_pad[SHA256_BLOCK_LENGTH / sizeof(uint32_t)]; + + memzero(key_pad, sizeof(key_pad)); + if (keylen > SHA256_BLOCK_LENGTH) { + static CONFIDENTIAL SHA256_CTX context; + sha256_Init(&context); + sha256_Update(&context, key, keylen); + sha256_Final(&context, (uint8_t *)key_pad); + } else { + memcpy(key_pad, key, keylen); + } + + /* compute o_key_pad and its digest */ + for (int i = 0; i < SHA256_BLOCK_LENGTH / (int)sizeof(uint32_t); i++) { + uint32_t data = 0; +#if BYTE_ORDER == LITTLE_ENDIAN + REVERSE32(key_pad[i], data); +#else + data = key_pad[i]; +#endif + key_pad[i] = data ^ 0x5c5c5c5c; + } + sha256_Transform(sha256_initial_hash_value, key_pad, opad_digest); + + /* convert o_key_pad to i_key_pad and compute its digest */ + for (int i = 0; i < SHA256_BLOCK_LENGTH / (int)sizeof(uint32_t); i++) { + key_pad[i] = key_pad[i] ^ 0x5c5c5c5c ^ 0x36363636; + } + sha256_Transform(sha256_initial_hash_value, key_pad, ipad_digest); + memzero(key_pad, sizeof(key_pad)); +} + +void hmac_sha512_Init(HMAC_SHA512_CTX *hctx, const uint8_t *key, + const uint32_t keylen) { + static CONFIDENTIAL uint8_t i_key_pad[SHA512_BLOCK_LENGTH]; + memzero(i_key_pad, SHA512_BLOCK_LENGTH); + if (keylen > SHA512_BLOCK_LENGTH) { + sha512_Raw(key, keylen, i_key_pad); + } else { + memcpy(i_key_pad, key, keylen); + } + for (int i = 0; i < SHA512_BLOCK_LENGTH; i++) { + hctx->o_key_pad[i] = i_key_pad[i] ^ 0x5c; + i_key_pad[i] ^= 0x36; + } + sha512_Init(&(hctx->ctx)); + sha512_Update(&(hctx->ctx), i_key_pad, SHA512_BLOCK_LENGTH); + memzero(i_key_pad, sizeof(i_key_pad)); +} + +void hmac_sha512_Update(HMAC_SHA512_CTX *hctx, const uint8_t *msg, + const uint32_t msglen) { + sha512_Update(&(hctx->ctx), msg, msglen); +} + +void hmac_sha512_Final(HMAC_SHA512_CTX *hctx, uint8_t *hmac) { + sha512_Final(&(hctx->ctx), hmac); + sha512_Init(&(hctx->ctx)); + sha512_Update(&(hctx->ctx), hctx->o_key_pad, SHA512_BLOCK_LENGTH); + sha512_Update(&(hctx->ctx), hmac, SHA512_DIGEST_LENGTH); + sha512_Final(&(hctx->ctx), hmac); + memzero(hctx, sizeof(HMAC_SHA512_CTX)); +} + +void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, + const uint32_t msglen, uint8_t *hmac) { + HMAC_SHA512_CTX hctx = {0}; + hmac_sha512_Init(&hctx, key, keylen); + hmac_sha512_Update(&hctx, msg, msglen); + hmac_sha512_Final(&hctx, hmac); +} + +void hmac_sha512_prepare(const uint8_t *key, const uint32_t keylen, + uint64_t *opad_digest, uint64_t *ipad_digest) { + static CONFIDENTIAL uint64_t key_pad[SHA512_BLOCK_LENGTH / sizeof(uint64_t)]; + + memzero(key_pad, sizeof(key_pad)); + if (keylen > SHA512_BLOCK_LENGTH) { + static CONFIDENTIAL SHA512_CTX context; + sha512_Init(&context); + sha512_Update(&context, key, keylen); + sha512_Final(&context, (uint8_t *)key_pad); + } else { + memcpy(key_pad, key, keylen); + } + + /* compute o_key_pad and its digest */ + for (int i = 0; i < SHA512_BLOCK_LENGTH / (int)sizeof(uint64_t); i++) { + uint64_t data = 0; +#if BYTE_ORDER == LITTLE_ENDIAN + REVERSE64(key_pad[i], data); +#else + data = key_pad[i]; +#endif + key_pad[i] = data ^ 0x5c5c5c5c5c5c5c5c; + } + sha512_Transform(sha512_initial_hash_value, key_pad, opad_digest); + + /* convert o_key_pad to i_key_pad and compute its digest */ + for (int i = 0; i < SHA512_BLOCK_LENGTH / (int)sizeof(uint64_t); i++) { + key_pad[i] = key_pad[i] ^ 0x5c5c5c5c5c5c5c5c ^ 0x3636363636363636; + } + sha512_Transform(sha512_initial_hash_value, key_pad, ipad_digest); + memzero(key_pad, sizeof(key_pad)); +} diff --git a/deps/crypto/trezor-crypto/hmac.h b/deps/crypto/trezor-crypto/hmac.h new file mode 100644 index 000000000..3921a171e --- /dev/null +++ b/deps/crypto/trezor-crypto/hmac.h @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT HMAC_SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __HMAC_H__ +#define __HMAC_H__ + +#include +#include "sha2.h" + +typedef struct _HMAC_SHA256_CTX { + uint8_t o_key_pad[SHA256_BLOCK_LENGTH]; + SHA256_CTX ctx; +} HMAC_SHA256_CTX; + +typedef struct _HMAC_SHA512_CTX { + uint8_t o_key_pad[SHA512_BLOCK_LENGTH]; + SHA512_CTX ctx; +} HMAC_SHA512_CTX; + +void hmac_sha256_Init(HMAC_SHA256_CTX *hctx, const uint8_t *key, + const uint32_t keylen); +void hmac_sha256_Update(HMAC_SHA256_CTX *hctx, const uint8_t *msg, + const uint32_t msglen); +void hmac_sha256_Final(HMAC_SHA256_CTX *hctx, uint8_t *hmac); +void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, + const uint32_t msglen, uint8_t *hmac); +void hmac_sha256_prepare(const uint8_t *key, const uint32_t keylen, + uint32_t *opad_digest, uint32_t *ipad_digest); + +void hmac_sha512_Init(HMAC_SHA512_CTX *hctx, const uint8_t *key, + const uint32_t keylen); +void hmac_sha512_Update(HMAC_SHA512_CTX *hctx, const uint8_t *msg, + const uint32_t msglen); +void hmac_sha512_Final(HMAC_SHA512_CTX *hctx, uint8_t *hmac); +void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, + const uint32_t msglen, uint8_t *hmac); +void hmac_sha512_prepare(const uint8_t *key, const uint32_t keylen, + uint64_t *opad_digest, uint64_t *ipad_digest); + +#endif diff --git a/deps/crypto/trezor-crypto/hmac_drbg.c b/deps/crypto/trezor-crypto/hmac_drbg.c new file mode 100644 index 000000000..1ed1401b8 --- /dev/null +++ b/deps/crypto/trezor-crypto/hmac_drbg.c @@ -0,0 +1,130 @@ +/** + * Copyright (c) 2019 Andrew R. Kozlik + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "hmac_drbg.h" +#include +#include "memzero.h" +#include "sha2.h" + +static void update_k(HMAC_DRBG_CTX *ctx, uint8_t domain, const uint8_t *data1, + size_t len1, const uint8_t *data2, size_t len2) { + // Computes K = HMAC(K, V || domain || data1 || data 2). + + // First hash operation of HMAC. + uint32_t h[SHA256_BLOCK_LENGTH / sizeof(uint32_t)] = {0}; + if (len1 + len2 == 0) { + ctx->v[8] = 0x00800000; + ctx->v[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH + 1) * 8; + sha256_Transform(ctx->idig, ctx->v, h); + ctx->v[8] = 0x80000000; + ctx->v[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8; + } else { + SHA256_CTX sha_ctx = {0}; + memcpy(sha_ctx.state, ctx->idig, SHA256_DIGEST_LENGTH); + for (size_t i = 0; i < SHA256_DIGEST_LENGTH / sizeof(uint32_t); i++) { +#if BYTE_ORDER == LITTLE_ENDIAN + REVERSE32(ctx->v[i], sha_ctx.buffer[i]); +#else + sha_ctx.buffer[i] = ctx->v[i]; +#endif + } + ((uint8_t *)sha_ctx.buffer)[SHA256_DIGEST_LENGTH] = domain; + sha_ctx.bitcount = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH + 1) * 8; + sha256_Update(&sha_ctx, data1, len1); + sha256_Update(&sha_ctx, data2, len2); + sha256_Final(&sha_ctx, (uint8_t *)h); +#if BYTE_ORDER == LITTLE_ENDIAN + for (size_t i = 0; i < SHA256_DIGEST_LENGTH / sizeof(uint32_t); i++) + REVERSE32(h[i], h[i]); +#endif + } + + // Second hash operation of HMAC. + h[8] = 0x80000000; + h[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8; + sha256_Transform(ctx->odig, h, h); + + // Precompute the inner digest and outer digest of K. + h[8] = 0; + h[15] = 0; + for (size_t i = 0; i < SHA256_BLOCK_LENGTH / sizeof(uint32_t); i++) { + h[i] ^= 0x36363636; + } + sha256_Transform(sha256_initial_hash_value, h, ctx->idig); + + for (size_t i = 0; i < SHA256_BLOCK_LENGTH / sizeof(uint32_t); i++) { + h[i] = h[i] ^ 0x36363636 ^ 0x5c5c5c5c; + } + sha256_Transform(sha256_initial_hash_value, h, ctx->odig); + memzero(h, sizeof(h)); +} + +static void update_v(HMAC_DRBG_CTX *ctx) { + sha256_Transform(ctx->idig, ctx->v, ctx->v); + sha256_Transform(ctx->odig, ctx->v, ctx->v); +} + +void hmac_drbg_init(HMAC_DRBG_CTX *ctx, const uint8_t *entropy, + size_t entropy_len, const uint8_t *nonce, + size_t nonce_len) { + uint32_t h[SHA256_BLOCK_LENGTH / sizeof(uint32_t)] = {0}; + + // Precompute the inner digest and outer digest of K = 0x00 ... 0x00. + memset(h, 0x36, sizeof(h)); + sha256_Transform(sha256_initial_hash_value, h, ctx->idig); + memset(h, 0x5c, sizeof(h)); + sha256_Transform(sha256_initial_hash_value, h, ctx->odig); + + // Let V = 0x01 ... 0x01. + memset(ctx->v, 1, SHA256_DIGEST_LENGTH); + for (size_t i = 9; i < 15; i++) ctx->v[i] = 0; + ctx->v[8] = 0x80000000; + ctx->v[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8; + + hmac_drbg_reseed(ctx, entropy, entropy_len, nonce, nonce_len); + + memzero(h, sizeof(h)); +} + +void hmac_drbg_reseed(HMAC_DRBG_CTX *ctx, const uint8_t *entropy, size_t len, + const uint8_t *addin, size_t addin_len) { + update_k(ctx, 0, entropy, len, addin, addin_len); + update_v(ctx); + if (len == 0) return; + update_k(ctx, 1, entropy, len, addin, addin_len); + update_v(ctx); +} + +void hmac_drbg_generate(HMAC_DRBG_CTX *ctx, uint8_t *buf, size_t len) { + size_t i = 0; + while (i < len) { + update_v(ctx); + for (size_t j = 0; j < 8 && i < len; j++) { + uint32_t r = ctx->v[j]; + for (int k = 24; k >= 0 && i < len; k -= 8) { + buf[i++] = (r >> k) & 0xFF; + } + } + } + update_k(ctx, 0, NULL, 0, NULL, 0); + update_v(ctx); +} diff --git a/deps/crypto/trezor-crypto/hmac_drbg.h b/deps/crypto/trezor-crypto/hmac_drbg.h new file mode 100644 index 000000000..6a8f3978c --- /dev/null +++ b/deps/crypto/trezor-crypto/hmac_drbg.h @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2019 Andrew R. Kozlik + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __HMAC_DRBG_H__ +#define __HMAC_DRBG_H__ + +#include "sha2.h" +#include + +// HMAC based Deterministic Random Bit Generator with SHA-256 + +typedef struct _HMAC_DRBG_CTX { + uint32_t odig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; + uint32_t idig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; + uint32_t v[SHA256_BLOCK_LENGTH / sizeof(uint32_t)]; +} HMAC_DRBG_CTX; + +void hmac_drbg_init(HMAC_DRBG_CTX *ctx, const uint8_t *buf, size_t len, + const uint8_t *nonce, size_t nonce_len); +void hmac_drbg_reseed(HMAC_DRBG_CTX *ctx, const uint8_t *buf, size_t len, + const uint8_t *addin, size_t addin_len); +void hmac_drbg_generate(HMAC_DRBG_CTX *ctx, uint8_t *buf, size_t len); + +#endif diff --git a/deps/crypto/trezor-crypto/memzero.c b/deps/crypto/trezor-crypto/memzero.c new file mode 100644 index 000000000..1c5ea77a6 --- /dev/null +++ b/deps/crypto/trezor-crypto/memzero.c @@ -0,0 +1,75 @@ +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ 1 // C11's bounds-checking interface. +#endif +#include + +#ifdef _WIN32 +#include +#endif + +#ifdef __unix__ +#include +#include +#endif + +// C11's bounds-checking interface. +#if defined(__STDC_LIB_EXT1__) +#define HAVE_MEMSET_S 1 +#endif + +// GNU C Library version 2.25 or later. +#if defined(__GLIBC__) && \ + (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25)) +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// Newlib +#if defined(__NEWLIB__) +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// FreeBSD version 11.0 or later. +#if defined(__FreeBSD__) && __FreeBSD_version >= 1100037 +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// OpenBSD version 5.5 or later. +#if defined(__OpenBSD__) && OpenBSD >= 201405 +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// NetBSD version 7.2 or later. +#if defined(__NetBSD__) && __NetBSD_Version__ >= 702000000 +#define HAVE_EXPLICIT_MEMSET 1 +#endif + +// Adapted from +// https://github.com/jedisct1/libsodium/blob/1647f0d53ae0e370378a9195477e3df0a792408f/src/libsodium/sodium/utils.c#L102-L130 + +void memzero(void *const pnt, const size_t len) { +#ifdef _WIN32 + SecureZeroMemory(pnt, len); +#elif defined(HAVE_MEMSET_S) + memset_s(pnt, (rsize_t)len, 0, (rsize_t)len); +#elif defined(HAVE_EXPLICIT_BZERO) + explicit_bzero(pnt, len); +#elif defined(HAVE_EXPLICIT_MEMSET) + explicit_memset(pnt, 0, len); +#else + volatile unsigned char *volatile pnt_ = (volatile unsigned char *volatile)pnt; + size_t i = (size_t)0U; + + while (i < len) { + pnt_[i++] = 0U; + } +#endif + + // explicitly mark the memory as overwritten for the Clang MemorySanitizer + // this is only included at compile time if MemorySanitizer is enabled and + // should not come with any downsides during regular builds +#if defined(__has_feature) +#if __has_feature(memory_sanitizer) + memset(pnt, 0, len); +#endif +#endif +} diff --git a/deps/crypto/trezor-crypto/memzero.h b/deps/crypto/trezor-crypto/memzero.h new file mode 100644 index 000000000..0a959fbc2 --- /dev/null +++ b/deps/crypto/trezor-crypto/memzero.h @@ -0,0 +1,8 @@ +#ifndef __MEMZERO_H__ +#define __MEMZERO_H__ + +#include + +void memzero(void* const pnt, const size_t len); + +#endif diff --git a/deps/crypto/trezor-crypto/monero/base58.c b/deps/crypto/trezor-crypto/monero/base58.c new file mode 100644 index 000000000..6c49d1b24 --- /dev/null +++ b/deps/crypto/trezor-crypto/monero/base58.c @@ -0,0 +1,247 @@ +// Copyright (c) 2014-2018, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#include +#include +#include +#include +#include "base58.h" +#include "int-util.h" +#include "sha2.h" +#include "../base58.h" + +const size_t alphabet_size = 58; // sizeof(b58digits_ordered) - 1; +const size_t encoded_block_sizes[] = {0, 2, 3, 5, 6, 7, 9, 10, 11}; +const size_t full_block_size = sizeof(encoded_block_sizes) / sizeof(encoded_block_sizes[0]) - 1; +const size_t full_encoded_block_size = 11; // encoded_block_sizes[full_block_size]; +const size_t addr_checksum_size = 4; +const int decoded_block_sizes[] = {0, -1, 1, 2, -1, 3, 4, 5, -1, 6, 7, 8}; +#define reverse_alphabet(letter) ((int8_t) b58digits_map[(int)letter]) + + +uint64_t uint_8be_to_64(const uint8_t* data, size_t size) +{ + assert(1 <= size && size <= sizeof(uint64_t)); + + uint64_t res = 0; + switch (9 - size) + { + case 1: res |= *data++; /* FALLTHRU */ + case 2: res <<= 8; res |= *data++; /* FALLTHRU */ + case 3: res <<= 8; res |= *data++; /* FALLTHRU */ + case 4: res <<= 8; res |= *data++; /* FALLTHRU */ + case 5: res <<= 8; res |= *data++; /* FALLTHRU */ + case 6: res <<= 8; res |= *data++; /* FALLTHRU */ + case 7: res <<= 8; res |= *data++; /* FALLTHRU */ + case 8: res <<= 8; res |= *data; break; + default: assert(false); + } + + return res; +} + +void uint_64_to_8be(uint64_t num, size_t size, uint8_t* data) +{ + assert(1 <= size && size <= sizeof(uint64_t)); + + uint64_t num_be = SWAP64(num); + memcpy(data, (uint8_t*)(&num_be) + sizeof(uint64_t) - size, size); +} + +void encode_block(const char* block, size_t size, char* res) +{ + assert(1 <= size && size <= full_block_size); + + uint64_t num = uint_8be_to_64((uint8_t*)(block), size); + int i = ((int)(encoded_block_sizes[size])) - 1; + while (0 <= i) + { + uint64_t remainder = num % alphabet_size; + num /= alphabet_size; + res[i] = b58digits_ordered[remainder]; + --i; + } +} + +bool decode_block(const char* block, size_t size, char* res) +{ + assert(1 <= size && size <= full_encoded_block_size); + + int res_size = decoded_block_sizes[size]; + if (res_size <= 0) + return false; // Invalid block size + + uint64_t res_num = 0; + uint64_t order = 1; + for (size_t i = size - 1; i < size; --i) + { + if (block[i] & 0x80) + return false; // Invalid symbol + int digit = reverse_alphabet(block[i]); + if (digit < 0) + return false; // Invalid symbol + + uint64_t product_hi = 0; + uint64_t tmp = res_num + mul128(order, (uint64_t) digit, &product_hi); + if (tmp < res_num || 0 != product_hi) + return false; // Overflow + + res_num = tmp; + order *= alphabet_size; // Never overflows, 58^10 < 2^64 + } + + if ((size_t)res_size < full_block_size && (UINT64_C(1) << (8 * res_size)) <= res_num) + return false; // Overflow + + uint_64_to_8be(res_num, res_size, (uint8_t*)(res)); + + return true; +} + + +bool xmr_base58_encode(char *b58, size_t *b58sz, const void *data, size_t binsz) +{ + if (binsz==0) + return true; + + const char * data_bin = data; + size_t full_block_count = binsz / full_block_size; + size_t last_block_size = binsz % full_block_size; + size_t res_size = full_block_count * full_encoded_block_size + encoded_block_sizes[last_block_size]; + + if (b58sz){ + if (res_size >= *b58sz){ + return false; + } + *b58sz = res_size; + } + + for (size_t i = 0; i < full_block_count; ++i) + { + encode_block(data_bin + i * full_block_size, full_block_size, b58 + i * full_encoded_block_size); + } + + if (0 < last_block_size) + { + encode_block(data_bin + full_block_count * full_block_size, last_block_size, b58 + full_block_count * full_encoded_block_size); + } + + return true; +} + +bool xmr_base58_decode(const char *b58, size_t b58sz, void *data, size_t *binsz) +{ + if (b58sz == 0) { + *binsz = 0; + return true; + } + + size_t full_block_count = b58sz / full_encoded_block_size; + size_t last_block_size = b58sz % full_encoded_block_size; + int last_block_decoded_size = decoded_block_sizes[last_block_size]; + if (last_block_decoded_size < 0) { + *binsz = 0; + return false; // Invalid enc length + } + + size_t data_size = full_block_count * full_block_size + last_block_decoded_size; + if (*binsz < data_size){ + *binsz = 0; + return false; + } + + char * data_bin = data; + for (size_t i = 0; i < full_block_count; ++i) + { + if (!decode_block(b58 + i * full_encoded_block_size, full_encoded_block_size, data_bin + i * full_block_size)) + return false; + } + + if (0 < last_block_size) + { + if (!decode_block(b58 + full_block_count * full_encoded_block_size, last_block_size, + data_bin + full_block_count * full_block_size)) + return false; + } + + return true; +} + +int xmr_base58_addr_encode_check(uint64_t tag, const uint8_t *data, size_t binsz, char *b58, size_t b58sz) +{ + if (binsz > 128 || tag > 127) { // tag varint + return false; + } + + size_t b58size = b58sz; + uint8_t buf[(binsz + 1) + HASHER_DIGEST_LENGTH]; + memset(buf, 0, sizeof(buf)); + uint8_t *hash = buf + binsz + 1; + buf[0] = (uint8_t) tag; + memcpy(buf + 1, data, binsz); + hasher_Raw(HASHER_SHA3K, buf, binsz + 1, hash); + + bool r = xmr_base58_encode(b58, &b58size, buf, binsz + 1 + addr_checksum_size); + return (int) (!r ? 0 : b58size); +} + +int xmr_base58_addr_decode_check(const char *addr, size_t sz, uint64_t *tag, void *data, size_t datalen) +{ + size_t buflen = 1 + 64 + addr_checksum_size; + uint8_t buf[buflen]; + memset(buf, 0, sizeof(buf)); + uint8_t hash[HASHER_DIGEST_LENGTH] = {0}; + + if (!xmr_base58_decode(addr, sz, buf, &buflen)){ + return 0; + } + + size_t res_size = buflen - addr_checksum_size - 1; + if (datalen < res_size){ + return 0; + } + + if (buflen <= addr_checksum_size+1) { + return 0; + } + + hasher_Raw(HASHER_SHA3K, buf, buflen - addr_checksum_size, hash); + if (memcmp(hash, buf + buflen - addr_checksum_size, addr_checksum_size) != 0){ + return 0; + } + + *tag = buf[0]; + if (*tag > 127){ + return false; // varint + } + + memcpy(data, buf+1, res_size); + return (int) res_size; +} diff --git a/deps/crypto/trezor-crypto/monero/base58.h b/deps/crypto/trezor-crypto/monero/base58.h new file mode 100644 index 000000000..5486d673a --- /dev/null +++ b/deps/crypto/trezor-crypto/monero/base58.h @@ -0,0 +1,43 @@ +// Copyright (c) 2014-2018, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#ifndef __XMR_BASE58_H__ +#define __XMR_BASE58_H__ + +#include +#include "hasher.h" +#include "options.h" + +int xmr_base58_addr_encode_check(uint64_t tag, const uint8_t *data, size_t binsz, char *b58, size_t b58sz); +int xmr_base58_addr_decode_check(const char *addr, size_t sz, uint64_t *tag, void *data, size_t datalen); +bool xmr_base58_encode(char *b58, size_t *b58sz, const void *data, size_t binsz); +bool xmr_base58_decode(const char *b58, size_t b58sz, void *data, size_t *binsz); + +#endif diff --git a/deps/crypto/trezor-crypto/monero/int-util.h b/deps/crypto/trezor-crypto/monero/int-util.h new file mode 100644 index 000000000..9cba47a8b --- /dev/null +++ b/deps/crypto/trezor-crypto/monero/int-util.h @@ -0,0 +1,77 @@ +// Copyright (c) 2014-2018, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#pragma once + +#include +#include + +static inline uint64_t hi_dword(uint64_t val) { + return val >> 32; +} + +static inline uint64_t lo_dword(uint64_t val) { + return val & 0xFFFFFFFF; +} + +static inline uint64_t mul128(uint64_t multiplier, uint64_t multiplicand, uint64_t* product_hi) { + // multiplier = ab = a * 2^32 + b + // multiplicand = cd = c * 2^32 + d + // ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d + uint64_t a = hi_dword(multiplier); + uint64_t b = lo_dword(multiplier); + uint64_t c = hi_dword(multiplicand); + uint64_t d = lo_dword(multiplicand); + + uint64_t ac = a * c; + uint64_t ad = a * d; + uint64_t bc = b * c; + uint64_t bd = b * d; + + uint64_t adbc = ad + bc; + uint64_t adbc_carry = adbc < ad ? 1 : 0; + + // multiplier * multiplicand = product_hi * 2^64 + product_lo + uint64_t product_lo = bd + (adbc << 32); + uint64_t product_lo_carry = product_lo < bd ? 1 : 0; + *product_hi = ac + (adbc >> 32) + (adbc_carry << 32) + product_lo_carry; + assert(ac <= *product_hi); + + return product_lo; +} + +#define SWAP64(x) ((((uint64_t) (x) & 0x00000000000000ff) << 56) | \ + (((uint64_t) (x) & 0x000000000000ff00) << 40) | \ + (((uint64_t) (x) & 0x0000000000ff0000) << 24) | \ + (((uint64_t) (x) & 0x00000000ff000000) << 8) | \ + (((uint64_t) (x) & 0x000000ff00000000) >> 8) | \ + (((uint64_t) (x) & 0x0000ff0000000000) >> 24) | \ + (((uint64_t) (x) & 0x00ff000000000000) >> 40) | \ + (((uint64_t) (x) & 0xff00000000000000) >> 56)) diff --git a/deps/crypto/trezor-crypto/monero/monero.h b/deps/crypto/trezor-crypto/monero/monero.h new file mode 100644 index 000000000..ba436c3a3 --- /dev/null +++ b/deps/crypto/trezor-crypto/monero/monero.h @@ -0,0 +1,21 @@ +// +// Created by Dusan Klinec on 10/05/2018. +// + +#ifndef TREZOR_CRYPTO_MONERO_H +#define TREZOR_CRYPTO_MONERO_H + +#if !USE_MONERO +#error "Compile with -DUSE_MONERO=1" +#endif + +#if !USE_KECCAK +#error "Compile with -DUSE_KECCAK=1" +#endif + +#include "base58.h" +#include "range_proof.h" +#include "serialize.h" +#include "xmr.h" + +#endif // TREZOR_CRYPTO_MONERO_H diff --git a/deps/crypto/trezor-crypto/monero/range_proof.c b/deps/crypto/trezor-crypto/monero/range_proof.c new file mode 100644 index 000000000..e3fd9b6a2 --- /dev/null +++ b/deps/crypto/trezor-crypto/monero/range_proof.c @@ -0,0 +1,115 @@ +// +// Created by Dusan Klinec on 10/05/2018. +// + +#include "range_proof.h" + +static void xmr_hash_ge25519_to_scalar(bignum256modm r, const ge25519 *p) { + unsigned char buff[32] = {0}; + ge25519_pack(buff, p); + xmr_hash_to_scalar(r, buff, sizeof(buff)); +} + +void xmr_gen_range_sig(xmr_range_sig_t *sig, ge25519 *C, bignum256modm mask, + xmr_amount amount, bignum256modm *last_mask) { + bignum256modm ai[64] = {0}; + bignum256modm alpha[64] = {0}; + xmr_gen_range_sig_ex(sig, C, mask, amount, last_mask, ai, alpha); +} + +void xmr_gen_range_sig_ex(xmr_range_sig_t *sig, ge25519 *C, bignum256modm mask, + xmr_amount amount, bignum256modm *last_mask, + bignum256modm ai[64], bignum256modm alpha[64]) { + const unsigned n = XMR_ATOMS; + bignum256modm a = {0}; + bignum256modm si = {0}; + bignum256modm c = {0}; + bignum256modm ee = {0}; + unsigned char buff[32] = {0}; + + Hasher kck = {0}; + xmr_hasher_init(&kck); + + ge25519 C_acc = {0}; + ge25519 C_h = {0}; + ge25519 C_tmp = {0}; + ge25519 L = {0}; + ge25519 Zero = {0}; + + ge25519_set_neutral(&Zero); + ge25519_set_neutral(&C_acc); + ge25519_set_xmr_h(&C_h); + set256_modm(a, 0); + +#define BB(i) ((amount >> (i)) & 1) + + // First pass, generates: ai, alpha, Ci, ee, s1 + for (unsigned ii = 0; ii < n; ++ii) { + xmr_random_scalar(ai[ii]); + if (last_mask != NULL && ii == n - 1) { + sub256_modm(ai[ii], *last_mask, a); + } + + add256_modm(a, a, ai[ii]); // creating the total mask since you have to + // pass this to receiver... + xmr_random_scalar(alpha[ii]); + + ge25519_scalarmult_base_niels(&L, ge25519_niels_base_multiples, alpha[ii]); + ge25519_scalarmult_base_niels(&C_tmp, ge25519_niels_base_multiples, ai[ii]); + + // C_tmp += &Zero if BB(ii) == 0 else &C_h + ge25519_add(&C_tmp, &C_tmp, BB(ii) == 0 ? &Zero : &C_h, 0); + ge25519_add(&C_acc, &C_acc, &C_tmp, 0); + + // Set Ci[ii] to sigs + ge25519_pack(sig->Ci[ii], &C_tmp); + + if (BB(ii) == 0) { + xmr_random_scalar(si); + xmr_hash_ge25519_to_scalar(c, &L); + + ge25519_add(&C_tmp, &C_tmp, &C_h, 1); // Ci[ii] -= c_h + xmr_add_keys2_vartime(&L, si, c, &C_tmp); + + // Set s1[ii] to sigs + contract256_modm(sig->asig.s1[ii], si); + } + + ge25519_pack(buff, &L); + xmr_hasher_update(&kck, buff, sizeof(buff)); + + ge25519_double(&C_h, &C_h); // c_H = crypto.scalarmult(c_H, 2) + } + + // Compute ee + xmr_hasher_final(&kck, buff); + expand256_modm(ee, buff, sizeof(buff)); + + ge25519_set_xmr_h(&C_h); + + // Second pass, s0, s1 + for (unsigned ii = 0; ii < n; ++ii) { + if (BB(ii) == 0) { + mulsub256_modm(si, ai[ii], ee, alpha[ii]); + contract256_modm(sig->asig.s0[ii], si); + + } else { + xmr_random_scalar(si); + contract256_modm(sig->asig.s0[ii], si); + + ge25519_unpack_vartime(&C_tmp, sig->Ci[ii]); + xmr_add_keys2_vartime(&L, si, ee, &C_tmp); + xmr_hash_ge25519_to_scalar(c, &L); + + mulsub256_modm(si, ai[ii], c, alpha[ii]); + contract256_modm(sig->asig.s1[ii], si); + } + + ge25519_double(&C_h, &C_h); // c_H = crypto.scalarmult(c_H, 2) + } + + ge25519_copy(C, &C_acc); + copy256_modm(mask, a); + contract256_modm(sig->asig.ee, ee); +#undef BB +} diff --git a/deps/crypto/trezor-crypto/monero/range_proof.h b/deps/crypto/trezor-crypto/monero/range_proof.h new file mode 100644 index 000000000..f614ab04e --- /dev/null +++ b/deps/crypto/trezor-crypto/monero/range_proof.h @@ -0,0 +1,31 @@ +// +// Created by Dusan Klinec on 10/05/2018. +// + +#ifndef TREZOR_CRYPTO_RANGE_PROOF_H +#define TREZOR_CRYPTO_RANGE_PROOF_H + +#include "xmr.h" +#define XMR_ATOMS 64 + +typedef uint64_t xmr_amount; +typedef xmr_key_t xmr_key64_t[64]; + +typedef struct xmr_boro_sig { + xmr_key64_t s0; + xmr_key64_t s1; + xmr_key_t ee; +} xmr_boro_sig_t; + +typedef struct range_sig { + xmr_boro_sig_t asig; + xmr_key64_t Ci; +} xmr_range_sig_t; + +void xmr_gen_range_sig(xmr_range_sig_t* sig, ge25519* C, bignum256modm mask, + xmr_amount amount, bignum256modm* last_mask); +void xmr_gen_range_sig_ex(xmr_range_sig_t* sig, ge25519* C, bignum256modm mask, + xmr_amount amount, bignum256modm* last_mask, + bignum256modm ai[64], bignum256modm alpha[64]); + +#endif // TREZOR_CRYPTO_RANGE_PROOF_H diff --git a/deps/crypto/trezor-crypto/monero/serialize.c b/deps/crypto/trezor-crypto/monero/serialize.c new file mode 100644 index 000000000..4d4cbd8bb --- /dev/null +++ b/deps/crypto/trezor-crypto/monero/serialize.c @@ -0,0 +1,53 @@ +// +// Created by Dusan Klinec on 02/05/2018. +// + +#include "serialize.h" + +int xmr_size_varint(uint64_t num) { + int ctr = 1; + while (num >= 0x80) { + ++ctr; + num >>= 7; + } + return ctr; +} + +int xmr_write_varint(uint8_t *buff, size_t buff_size, uint64_t num) { + unsigned ctr = 0; + while (num >= 0x80 && ctr < buff_size) { + *buff = (uint8_t)(((num)&0x7f) | 0x80); + ++buff; + ++ctr; + num >>= 7; + } + + /* writes the last one to dest */ + if (ctr < buff_size) { + *buff = (uint8_t)num; + ++ctr; + } + return ctr <= buff_size ? (int)ctr : -1; +} + +int xmr_read_varint(uint8_t *buff, size_t buff_size, uint64_t *val) { + unsigned read = 0; + int finished_ok = 0; + *val = 0; + + for (int shift = 0; read < buff_size; shift += 7, ++read) { + uint8_t byte = buff[read]; + if ((byte == 0 && shift != 0) || (shift >= 63 && byte > 1)) { + return -1; + } + + *val |= (uint64_t)(byte & 0x7f) << shift; + + /* If there is no next */ + if ((byte & 0x80) == 0) { + finished_ok = 1; + break; + } + } + return finished_ok ? (int)read + 1 : -2; +} diff --git a/deps/crypto/trezor-crypto/monero/serialize.h b/deps/crypto/trezor-crypto/monero/serialize.h new file mode 100644 index 000000000..8d3499007 --- /dev/null +++ b/deps/crypto/trezor-crypto/monero/serialize.h @@ -0,0 +1,15 @@ +// +// Created by Dusan Klinec on 02/05/2018. +// + +#ifndef TREZOR_XMR_SERIALIZE_H +#define TREZOR_XMR_SERIALIZE_H + +#include +#include + +int xmr_size_varint(uint64_t num); +int xmr_write_varint(uint8_t *buff, size_t buff_size, uint64_t num); +int xmr_read_varint(uint8_t *buff, size_t buff_size, uint64_t *val); + +#endif // TREZOR_XMR_SERIALIZE_H diff --git a/deps/crypto/trezor-crypto/monero/xmr.c b/deps/crypto/trezor-crypto/monero/xmr.c new file mode 100644 index 000000000..a49e8a2ae --- /dev/null +++ b/deps/crypto/trezor-crypto/monero/xmr.c @@ -0,0 +1,143 @@ +// +// Created by Dusan Klinec on 10/05/2018. +// + +#include "xmr.h" +#include "int-util.h" +#include "rand.h" +#include "serialize.h" + +const ge25519 ALIGN(16) xmr_h = { + {0x1861ec7, 0x1ceac77, 0x2f11626, 0x1f261d3, 0x346107c, 0x06d8c4a, + 0x254201d, 0x1675c09, 0x1301c3f, 0x0211d73}, + {0x326feb4, 0x12e30cc, 0x0cf54b4, 0x1117305, 0x318f5d5, 0x06cf754, + 0x2e578a1, 0x1daf058, 0x34430a1, 0x04410e9}, + {0x0fde4d2, 0x0774049, 0x22ca951, 0x05aec2b, 0x07a36a5, 0x1394f13, + 0x3c5385c, 0x1adb924, 0x2b6c581, 0x0a55fa4}, + {0x24517f7, 0x05ee936, 0x3acf5d9, 0x14b08aa, 0x3363738, 0x1051745, + 0x360601e, 0x0f3f2c9, 0x1ead2cd, 0x1d3e3df}}; + +void ge25519_set_xmr_h(ge25519 *r) { ge25519_copy(r, &xmr_h); } + +void xmr_random_scalar(bignum256modm m) { + unsigned char buff[32] = {0}; + random_buffer(buff, sizeof(buff)); + expand256_modm(m, buff, sizeof(buff)); +} + +void xmr_fast_hash(uint8_t *hash, const void *data, size_t length) { + hasher_Raw(HASHER_SHA3K, data, length, hash); +} + +void xmr_hasher_init(Hasher *hasher) { hasher_Init(hasher, HASHER_SHA3K); } + +void xmr_hasher_update(Hasher *hasher, const void *data, size_t length) { + hasher_Update(hasher, data, length); +} + +void xmr_hasher_final(Hasher *hasher, uint8_t *hash) { + hasher_Final(hasher, hash); +} + +void xmr_hasher_copy(Hasher *dst, const Hasher *src) { + memcpy(dst, src, sizeof(Hasher)); +} + +void xmr_hash_to_scalar(bignum256modm r, const void *data, size_t length) { + uint8_t hash[HASHER_DIGEST_LENGTH] = {0}; + hasher_Raw(HASHER_SHA3K, data, length, hash); + expand256_modm(r, hash, HASHER_DIGEST_LENGTH); +} + +void xmr_hash_to_ec(ge25519 *P, const void *data, size_t length) { + ge25519 point2 = {0}; + uint8_t hash[HASHER_DIGEST_LENGTH] = {0}; + hasher_Raw(HASHER_SHA3K, data, length, hash); + + ge25519_fromfe_frombytes_vartime(&point2, hash); + ge25519_mul8(P, &point2); +} + +void xmr_derivation_to_scalar(bignum256modm s, const ge25519 *p, + uint32_t output_index) { + uint8_t buff[32 + 8] = {0}; + ge25519_pack(buff, p); + int written = xmr_write_varint(buff + 32, 8, output_index); + xmr_hash_to_scalar(s, buff, 32u + written); +} + +void xmr_generate_key_derivation(ge25519 *r, const ge25519 *A, + const bignum256modm b) { + ge25519 bA = {0}; + ge25519_scalarmult(&bA, A, b); + ge25519_mul8(r, &bA); +} + +void xmr_derive_private_key(bignum256modm s, const ge25519 *deriv, uint32_t idx, + const bignum256modm base) { + xmr_derivation_to_scalar(s, deriv, idx); + add256_modm(s, s, base); +} + +void xmr_derive_public_key(ge25519 *r, const ge25519 *deriv, uint32_t idx, + const ge25519 *base) { + bignum256modm s = {0}; + ge25519 p2 = {0}; + + xmr_derivation_to_scalar(s, deriv, idx); + ge25519_scalarmult_base_niels(&p2, ge25519_niels_base_multiples, s); + ge25519_add(r, base, &p2, 0); +} + +void xmr_add_keys2(ge25519 *r, const bignum256modm a, const bignum256modm b, + const ge25519 *B) { + // aG + bB, G is basepoint + ge25519 aG = {0}, bB = {0}; + ge25519_scalarmult_base_niels(&aG, ge25519_niels_base_multiples, a); + ge25519_scalarmult(&bB, B, b); + ge25519_add(r, &aG, &bB, 0); +} + +void xmr_add_keys2_vartime(ge25519 *r, const bignum256modm a, + const bignum256modm b, const ge25519 *B) { + // aG + bB, G is basepoint + ge25519_double_scalarmult_vartime(r, B, b, a); +} + +void xmr_add_keys3(ge25519 *r, const bignum256modm a, const ge25519 *A, + const bignum256modm b, const ge25519 *B) { + // aA + bB + ge25519 aA = {0}, bB = {0}; + ge25519_scalarmult(&aA, A, a); + ge25519_scalarmult(&bB, B, b); + ge25519_add(r, &aA, &bB, 0); +} + +void xmr_add_keys3_vartime(ge25519 *r, const bignum256modm a, const ge25519 *A, + const bignum256modm b, const ge25519 *B) { + // aA + bB + ge25519_double_scalarmult_vartime2(r, A, a, B, b); +} + +void xmr_get_subaddress_secret_key(bignum256modm r, uint32_t major, + uint32_t minor, const bignum256modm m) { + const char prefix[] = "SubAddr"; + unsigned char buff[32] = {0}; + contract256_modm(buff, m); + + char data[sizeof(prefix) + sizeof(buff) + 2 * sizeof(uint32_t)] = {0}; + memcpy(data, prefix, sizeof(prefix)); + memcpy(data + sizeof(prefix), buff, sizeof(buff)); + memcpy(data + sizeof(prefix) + sizeof(buff), &major, sizeof(uint32_t)); + memcpy(data + sizeof(prefix) + sizeof(buff) + sizeof(uint32_t), &minor, + sizeof(uint32_t)); + + xmr_hash_to_scalar(r, data, sizeof(data)); +} + +void xmr_gen_c(ge25519 *r, const bignum256modm a, uint64_t amount) { + // C = aG + bH + bignum256modm b = {0}; + set256_modm(b, amount); + xmr_add_keys2(r, a, b, &xmr_h); +} diff --git a/deps/crypto/trezor-crypto/monero/xmr.h b/deps/crypto/trezor-crypto/monero/xmr.h new file mode 100644 index 000000000..4ef83a06b --- /dev/null +++ b/deps/crypto/trezor-crypto/monero/xmr.h @@ -0,0 +1,76 @@ +// +// Created by Dusan Klinec on 10/05/2018. +// + +#ifndef TREZOR_CRYPTO_XMR_H +#define TREZOR_CRYPTO_XMR_H + +#include "ed25519-donna/ed25519-donna.h" +#include "hasher.h" + +extern const ge25519 ALIGN(16) xmr_h; + +typedef unsigned char xmr_key_t[32]; + +typedef struct xmr_ctkey { + xmr_key_t dest; + xmr_key_t mask; +} xmr_ctkey_t; + +/* sets H point to r */ +void ge25519_set_xmr_h(ge25519 *r); + +/* random scalar value */ +void xmr_random_scalar(bignum256modm m); + +/* cn_fast_hash */ +void xmr_fast_hash(uint8_t *hash, const void *data, size_t length); + +/* incremental hashing wrappers */ +void xmr_hasher_init(Hasher *hasher); +void xmr_hasher_update(Hasher *hasher, const void *data, size_t length); +void xmr_hasher_final(Hasher *hasher, uint8_t *hash); +void xmr_hasher_copy(Hasher *dst, const Hasher *src); + +/* H_s(buffer) */ +void xmr_hash_to_scalar(bignum256modm r, const void *data, size_t length); + +/* H_p(buffer) */ +void xmr_hash_to_ec(ge25519 *P, const void *data, size_t length); + +/* derivation to scalar value */ +void xmr_derivation_to_scalar(bignum256modm s, const ge25519 *p, + uint32_t output_index); + +/* derivation */ +void xmr_generate_key_derivation(ge25519 *r, const ge25519 *A, + const bignum256modm b); + +/* H_s(derivation || varint(output_index)) + base */ +void xmr_derive_private_key(bignum256modm s, const ge25519 *deriv, uint32_t idx, + const bignum256modm base); + +/* H_s(derivation || varint(output_index))G + base */ +void xmr_derive_public_key(ge25519 *r, const ge25519 *deriv, uint32_t idx, + const ge25519 *base); + +/* aG + bB, G is basepoint */ +void xmr_add_keys2(ge25519 *r, const bignum256modm a, const bignum256modm b, + const ge25519 *B); +void xmr_add_keys2_vartime(ge25519 *r, const bignum256modm a, + const bignum256modm b, const ge25519 *B); + +/* aA + bB */ +void xmr_add_keys3(ge25519 *r, const bignum256modm a, const ge25519 *A, + const bignum256modm b, const ge25519 *B); +void xmr_add_keys3_vartime(ge25519 *r, const bignum256modm a, const ge25519 *A, + const bignum256modm b, const ge25519 *B); + +/* subaddress secret */ +void xmr_get_subaddress_secret_key(bignum256modm r, uint32_t major, + uint32_t minor, const bignum256modm m); + +/* Generates Pedersen commitment C = aG + bH */ +void xmr_gen_c(ge25519 *r, const bignum256modm a, uint64_t amount); + +#endif // TREZOR_CRYPTO_XMR_H diff --git a/deps/crypto/trezor-crypto/nano.c b/deps/crypto/trezor-crypto/nano.c new file mode 100644 index 000000000..ad73a20d7 --- /dev/null +++ b/deps/crypto/trezor-crypto/nano.c @@ -0,0 +1,155 @@ +/** + * Copyright (c) 2019 Mart Roosmaa + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#if USE_NANO + +#include + +#include "nano.h" +#include "blake2b.h" +#include "base32.h" + +const char *BASE32_ALPHABET_NANO = "13456789abcdefghijkmnopqrstuwxyz"; + +#define NANO_ADDRESS_BASE_LENGTH 60 +#define NANO_CHECKSUM_LEN 5 + +typedef union { + uint8_t bytes[40]; + struct { + uint8_t padding[3]; + ed25519_public_key public_key; + uint8_t checksum[NANO_CHECKSUM_LEN]; + } data; +} nano_address_raw; + +typedef union { + char chars[65]; + struct { + char padding[4]; // 1111 + char address[NANO_ADDRESS_BASE_LENGTH]; + char terminator; // \0 + } data; +} nano_address_encoded; + +size_t nano_get_address( + const ed25519_public_key public_key, + const char *prefix, + const size_t prefix_len, + char *out, + size_t out_len +) { + if (out_len < prefix_len + NANO_ADDRESS_BASE_LENGTH + 1) { + return 0; + } + + // Construct raw address which is going to be base32 encoded + nano_address_raw raw; + memset(&raw, 0, sizeof(nano_address_raw)); + + uint8_t checksum[NANO_CHECKSUM_LEN]; + blake2b_state hash; + blake2b_Init(&hash, NANO_CHECKSUM_LEN); + blake2b_Update(&hash, public_key, sizeof(ed25519_public_key)); + blake2b_Final(&hash, checksum, NANO_CHECKSUM_LEN); + + for (int i = 0; i < NANO_CHECKSUM_LEN; i++) { + raw.data.checksum[NANO_CHECKSUM_LEN - (i + 1)] = checksum[i]; + } + memcpy(raw.data.public_key, public_key, sizeof(ed25519_public_key)); + + // Encode the address into a buffer and compose the final output + nano_address_encoded encoded; + memset(&encoded, 0, sizeof(nano_address_encoded)); + char *ret = base32_encode( + raw.bytes, sizeof(nano_address_raw), + encoded.chars, sizeof(encoded.chars), + BASE32_ALPHABET_NANO); + if (ret == NULL) { + return 0; + } + + size_t w = 0; + memcpy(&out[w], prefix, prefix_len); + w += prefix_len; + memcpy(&out[w], encoded.data.address, NANO_ADDRESS_BASE_LENGTH); + w += NANO_ADDRESS_BASE_LENGTH; + out[w] = 0; + w += 1; + return w; +} + +bool nano_validate_address( + const char *prefix, + const size_t prefix_len, + const char *address, + const size_t address_len, + ed25519_public_key out_public_key +) { + if (address_len != prefix_len + NANO_ADDRESS_BASE_LENGTH) { + return false; + } + + // Validate that the prefix matches + if (memcmp(address, prefix, prefix_len) != 0) { + return false; + } + + // Try to decode the address + nano_address_encoded encoded; + memcpy(encoded.data.padding, "1111", sizeof(encoded.data.padding)); + memcpy(encoded.data.address, &address[prefix_len], NANO_ADDRESS_BASE_LENGTH); + encoded.data.terminator = '\0'; + + nano_address_raw raw; + memset(&raw, 0, sizeof(nano_address_raw)); + uint8_t *ret = base32_decode( + encoded.chars, strlen(encoded.chars), + raw.bytes, sizeof(nano_address_raw), + BASE32_ALPHABET_NANO + ); + if (ret == NULL) { + return false; + } + + // Validate the checksum + uint8_t checksum[NANO_CHECKSUM_LEN]; + blake2b_state hash; + blake2b_Init(&hash, NANO_CHECKSUM_LEN); + blake2b_Update(&hash, raw.data.public_key, sizeof(ed25519_public_key)); + blake2b_Final(&hash, checksum, NANO_CHECKSUM_LEN); + + for (int i = 0; i < NANO_CHECKSUM_LEN; i++) { + if (raw.data.checksum[NANO_CHECKSUM_LEN - (i + 1)] != checksum[i]) { + return false; + } + } + + // Output the public key if the caller is interested in it + if (out_public_key != NULL) { + memcpy(out_public_key, raw.data.public_key, sizeof(ed25519_public_key)); + } + + return true; +} + +#endif \ No newline at end of file diff --git a/deps/crypto/trezor-crypto/nano.h b/deps/crypto/trezor-crypto/nano.h new file mode 100644 index 000000000..e2c139b72 --- /dev/null +++ b/deps/crypto/trezor-crypto/nano.h @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2019 Mart Roosmaa + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __NANO_H__ +#define __NANO_H__ + +#if USE_NANO + +#include +#include +#include + +#include "ed25519-donna/ed25519.h" + +extern const char *BASE32_ALPHABET_NANO; + +size_t nano_get_address( + const ed25519_public_key public_key, + const char *prefix, + const size_t prefix_len, + char *out, + size_t out_len); + +bool nano_validate_address( + const char *prefix, + const size_t prefix_len, + const char *address, + const size_t address_len, + ed25519_public_key out_public_key); + +#endif + +#endif \ No newline at end of file diff --git a/deps/crypto/trezor-crypto/nem.c b/deps/crypto/trezor-crypto/nem.c new file mode 100644 index 000000000..dd77241ce --- /dev/null +++ b/deps/crypto/trezor-crypto/nem.c @@ -0,0 +1,507 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, E1PRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "nem.h" + +#include + +#include "base32.h" +#include "ed25519-donna/ed25519-keccak.h" +#include "memzero.h" +#include "ripemd160.h" +#include "sha3.h" + +#define CAN_WRITE(NEEDED) ((ctx->offset + (NEEDED)) <= ctx->size) + +#define SERIALIZE_U32(DATA) \ + do { \ + if (!nem_write_u32(ctx, (DATA))) return false; \ + } while (0) +#define SERIALIZE_U64(DATA) \ + do { \ + if (!nem_write_u64(ctx, (DATA))) return false; \ + } while (0) +#define SERIALIZE_TAGGED(DATA, LENGTH) \ + do { \ + if (!nem_write_tagged(ctx, (DATA), (LENGTH))) return false; \ + } while (0) + +const char *nem_network_name(uint8_t network) { + switch (network) { + case NEM_NETWORK_MAINNET: + return "NEM Mainnet"; + case NEM_NETWORK_TESTNET: + return "NEM Testnet"; + case NEM_NETWORK_MIJIN: + return "Mijin"; + default: + return NULL; + } +} + +static inline bool nem_write_checked(nem_transaction_ctx *ctx, + const uint8_t *data, uint32_t length) { + if (!CAN_WRITE(length)) { + return false; + } + + memcpy(&ctx->buffer[ctx->offset], data, length); + ctx->offset += length; + return true; +} + +static inline bool nem_write_u32(nem_transaction_ctx *ctx, uint32_t data) { + if (!CAN_WRITE(4)) { + return false; + } + + ctx->buffer[ctx->offset++] = (data >> 0) & 0xff; + ctx->buffer[ctx->offset++] = (data >> 8) & 0xff; + ctx->buffer[ctx->offset++] = (data >> 16) & 0xff; + ctx->buffer[ctx->offset++] = (data >> 24) & 0xff; + + return true; +} + +static inline bool nem_write_u64(nem_transaction_ctx *ctx, uint64_t data) { + SERIALIZE_U32((data >> 0) & 0xffffffff); + SERIALIZE_U32((data >> 32) & 0xffffffff); + + return true; +} + +static inline bool nem_write_tagged(nem_transaction_ctx *ctx, + const uint8_t *data, uint32_t length) { + SERIALIZE_U32(length); + + return nem_write_checked(ctx, data, length); +} + +static inline bool nem_write_mosaic_str(nem_transaction_ctx *ctx, + const char *name, const char *value) { + uint32_t name_length = strlen(name); + uint32_t value_length = strlen(value); + + SERIALIZE_U32(sizeof(uint32_t) + name_length + sizeof(uint32_t) + + value_length); + SERIALIZE_TAGGED((const uint8_t *)name, name_length); + SERIALIZE_TAGGED((const uint8_t *)value, value_length); + + return true; +} + +static inline bool nem_write_mosaic_bool(nem_transaction_ctx *ctx, + const char *name, bool value) { + return nem_write_mosaic_str(ctx, name, value ? "true" : "false"); +} + +static inline bool nem_write_mosaic_u64(nem_transaction_ctx *ctx, + const char *name, uint64_t value) { + char buffer[21] = {0}; + + if (bn_format_uint64(value, NULL, NULL, 0, 0, false, buffer, + sizeof(buffer)) == 0) { + return false; + } + + return nem_write_mosaic_str(ctx, name, buffer); +} + +void nem_get_address_raw(const ed25519_public_key public_key, uint8_t version, + uint8_t *address) { + uint8_t hash[SHA3_256_DIGEST_LENGTH] = {0}; + + /* 1. Perform 256-bit Sha3 on the public key */ + keccak_256(public_key, sizeof(ed25519_public_key), hash); + + /* 2. Perform 160-bit Ripemd of hash resulting from step 1. */ + ripemd160(hash, SHA3_256_DIGEST_LENGTH, &address[1]); + + /* 3. Prepend version byte to Ripemd hash (either 0x68 or 0x98) */ + address[0] = version; + + /* 4. Perform 256-bit Sha3 on the result, take the first four bytes as a + * checksum */ + keccak_256(address, 1 + RIPEMD160_DIGEST_LENGTH, hash); + + /* 5. Concatenate output of step 3 and the checksum from step 4 */ + memcpy(&address[1 + RIPEMD160_DIGEST_LENGTH], hash, 4); + + memzero(hash, sizeof(hash)); +} + +bool nem_get_address(const ed25519_public_key public_key, uint8_t version, + char *address) { + uint8_t pubkeyhash[NEM_ADDRESS_SIZE_RAW] = {0}; + + nem_get_address_raw(public_key, version, pubkeyhash); + + char *ret = base32_encode(pubkeyhash, sizeof(pubkeyhash), address, + NEM_ADDRESS_SIZE + 1, BASE32_ALPHABET_RFC4648); + + memzero(pubkeyhash, sizeof(pubkeyhash)); + return (ret != NULL); +} + +bool nem_validate_address_raw(const uint8_t *address, uint8_t network) { + if (!nem_network_name(network) || address[0] != network) { + return false; + } + + uint8_t hash[SHA3_256_DIGEST_LENGTH] = {0}; + + keccak_256(address, 1 + RIPEMD160_DIGEST_LENGTH, hash); + bool valid = (memcmp(&address[1 + RIPEMD160_DIGEST_LENGTH], hash, 4) == 0); + + memzero(hash, sizeof(hash)); + return valid; +} + +bool nem_validate_address(const char *address, uint8_t network) { + uint8_t pubkeyhash[NEM_ADDRESS_SIZE_RAW] = {0}; + + if (strlen(address) != NEM_ADDRESS_SIZE) { + return false; + } + + uint8_t *ret = base32_decode(address, NEM_ADDRESS_SIZE, pubkeyhash, + sizeof(pubkeyhash), BASE32_ALPHABET_RFC4648); + bool valid = (ret != NULL) && nem_validate_address_raw(pubkeyhash, network); + + memzero(pubkeyhash, sizeof(pubkeyhash)); + return valid; +} + +void nem_transaction_start(nem_transaction_ctx *ctx, + const ed25519_public_key public_key, uint8_t *buffer, + size_t size) { + memcpy(ctx->public_key, public_key, sizeof(ctx->public_key)); + + ctx->buffer = buffer; + ctx->offset = 0; + ctx->size = size; +} + +size_t nem_transaction_end(nem_transaction_ctx *ctx, + const ed25519_secret_key private_key, + ed25519_signature signature) { + if (private_key != NULL && signature != NULL) { + ed25519_sign_keccak(ctx->buffer, ctx->offset, private_key, signature); + } + + return ctx->offset; +} + +bool nem_transaction_write_common(nem_transaction_ctx *ctx, uint32_t type, + uint32_t version, uint32_t timestamp, + const ed25519_public_key signer, uint64_t fee, + uint32_t deadline) { + SERIALIZE_U32(type); + SERIALIZE_U32(version); + SERIALIZE_U32(timestamp); + SERIALIZE_TAGGED(signer, sizeof(ed25519_public_key)); + SERIALIZE_U64(fee); + SERIALIZE_U32(deadline); + + return true; +} + +bool nem_transaction_create_transfer(nem_transaction_ctx *ctx, uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, uint32_t deadline, + const char *recipient, uint64_t amount, + const uint8_t *payload, uint32_t length, + bool encrypted, uint32_t mosaics) { + if (!signer) { + signer = ctx->public_key; + } + + if (!payload) { + length = 0; + } + + bool ret = + nem_transaction_write_common(ctx, NEM_TRANSACTION_TYPE_TRANSFER, + (uint32_t)network << 24 | (mosaics ? 2 : 1), + timestamp, signer, fee, deadline); + if (!ret) return false; + + SERIALIZE_TAGGED((const uint8_t *)recipient, NEM_ADDRESS_SIZE); + SERIALIZE_U64(amount); + + if (length) { + SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint32_t) + length); + SERIALIZE_U32(encrypted ? 0x02 : 0x01); + SERIALIZE_TAGGED(payload, length); + } else { + SERIALIZE_U32(0); + } + + if (mosaics) { + SERIALIZE_U32(mosaics); + } + + return true; +} + +bool nem_transaction_write_mosaic(nem_transaction_ctx *ctx, + const char *namespace, const char *mosaic, + uint64_t quantity) { + size_t namespace_length = strlen(namespace); + size_t mosaic_length = strlen(mosaic); + size_t identifier_length = + sizeof(uint32_t) + namespace_length + sizeof(uint32_t) + mosaic_length; + + SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint64_t) + identifier_length); + SERIALIZE_U32(identifier_length); + SERIALIZE_TAGGED((const uint8_t *)namespace, namespace_length); + SERIALIZE_TAGGED((const uint8_t *)mosaic, mosaic_length); + SERIALIZE_U64(quantity); + + return true; +} + +bool nem_transaction_create_multisig(nem_transaction_ctx *ctx, uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, uint32_t deadline, + const nem_transaction_ctx *inner) { + if (!signer) { + signer = ctx->public_key; + } + + bool ret = nem_transaction_write_common(ctx, NEM_TRANSACTION_TYPE_MULTISIG, + (uint32_t)network << 24 | 1, + timestamp, signer, fee, deadline); + if (!ret) return false; + + SERIALIZE_TAGGED(inner->buffer, inner->offset); + + return true; +} + +bool nem_transaction_create_multisig_signature( + nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, + const ed25519_public_key signer, uint64_t fee, uint32_t deadline, + const nem_transaction_ctx *inner) { + if (!signer) { + signer = ctx->public_key; + } + + bool ret = nem_transaction_write_common( + ctx, NEM_TRANSACTION_TYPE_MULTISIG_SIGNATURE, (uint32_t)network << 24 | 1, + timestamp, signer, fee, deadline); + if (!ret) return false; + + char address[NEM_ADDRESS_SIZE + 1] = {0}; + nem_get_address(inner->public_key, network, address); + + uint8_t hash[SHA3_256_DIGEST_LENGTH] = {0}; + keccak_256(inner->buffer, inner->offset, hash); + + SERIALIZE_U32(sizeof(uint32_t) + SHA3_256_DIGEST_LENGTH); + SERIALIZE_TAGGED(hash, SHA3_256_DIGEST_LENGTH); + SERIALIZE_TAGGED((const uint8_t *)address, NEM_ADDRESS_SIZE); + + return true; +} + +bool nem_transaction_create_provision_namespace( + nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, + const ed25519_public_key signer, uint64_t fee, uint32_t deadline, + const char *namespace, const char *parent, const char *rental_sink, + uint64_t rental_fee) { + if (!signer) { + signer = ctx->public_key; + } + + bool ret = nem_transaction_write_common( + ctx, NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE, + (uint32_t)network << 24 | 1, timestamp, signer, fee, deadline); + if (!ret) return false; + + if (parent) { + SERIALIZE_TAGGED((const uint8_t *)rental_sink, NEM_ADDRESS_SIZE); + SERIALIZE_U64(rental_fee); + SERIALIZE_TAGGED((const uint8_t *)namespace, strlen(namespace)); + SERIALIZE_TAGGED((const uint8_t *)parent, strlen(parent)); + } else { + SERIALIZE_TAGGED((const uint8_t *)rental_sink, NEM_ADDRESS_SIZE); + SERIALIZE_U64(rental_fee); + SERIALIZE_TAGGED((const uint8_t *)namespace, strlen(namespace)); + SERIALIZE_U32(0xffffffff); + } + + return true; +} + +bool nem_transaction_create_mosaic_creation( + nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, + const ed25519_public_key signer, uint64_t fee, uint32_t deadline, + const char *namespace, const char *mosaic, const char *description, + uint32_t divisibility, uint64_t supply, bool mutable_supply, + bool transferable, uint32_t levy_type, uint64_t levy_fee, + const char *levy_address, const char *levy_namespace, + const char *levy_mosaic, const char *creation_sink, uint64_t creation_fee) { + if (!signer) { + signer = ctx->public_key; + } + + bool ret = nem_transaction_write_common( + ctx, NEM_TRANSACTION_TYPE_MOSAIC_CREATION, (uint32_t)network << 24 | 1, + timestamp, signer, fee, deadline); + if (!ret) return false; + + size_t namespace_length = strlen(namespace); + size_t mosaic_length = strlen(mosaic); + size_t identifier_length = + sizeof(uint32_t) + namespace_length + sizeof(uint32_t) + mosaic_length; + + // This length will be rewritten later on + nem_transaction_ctx state = {0}; + memcpy(&state, ctx, sizeof(state)); + + SERIALIZE_U32(0); + SERIALIZE_TAGGED(signer, sizeof(ed25519_public_key)); + SERIALIZE_U32(identifier_length); + SERIALIZE_TAGGED((const uint8_t *)namespace, namespace_length); + SERIALIZE_TAGGED((const uint8_t *)mosaic, mosaic_length); + SERIALIZE_TAGGED((const uint8_t *)description, strlen(description)); + SERIALIZE_U32(4); // Number of properties + + if (!nem_write_mosaic_u64(ctx, "divisibility", divisibility)) return false; + if (!nem_write_mosaic_u64(ctx, "initialSupply", supply)) return false; + if (!nem_write_mosaic_bool(ctx, "supplyMutable", mutable_supply)) + return false; + if (!nem_write_mosaic_bool(ctx, "transferable", transferable)) return false; + + if (levy_type) { + size_t levy_namespace_length = strlen(levy_namespace); + size_t levy_mosaic_length = strlen(levy_mosaic); + size_t levy_identifier_length = sizeof(uint32_t) + levy_namespace_length + + sizeof(uint32_t) + levy_mosaic_length; + + SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint32_t) + NEM_ADDRESS_SIZE + + sizeof(uint32_t) + levy_identifier_length + sizeof(uint64_t)); + SERIALIZE_U32(levy_type); + SERIALIZE_TAGGED((const uint8_t *)levy_address, NEM_ADDRESS_SIZE); + SERIALIZE_U32(levy_identifier_length); + SERIALIZE_TAGGED((const uint8_t *)levy_namespace, levy_namespace_length); + SERIALIZE_TAGGED((const uint8_t *)levy_mosaic, levy_mosaic_length); + SERIALIZE_U64(levy_fee); + } else { + SERIALIZE_U32(0); + } + + // Rewrite length + nem_write_u32(&state, ctx->offset - state.offset - sizeof(uint32_t)); + + SERIALIZE_TAGGED((const uint8_t *)creation_sink, NEM_ADDRESS_SIZE); + SERIALIZE_U64(creation_fee); + + return true; +} + +bool nem_transaction_create_mosaic_supply_change( + nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, + const ed25519_public_key signer, uint64_t fee, uint32_t deadline, + const char *namespace, const char *mosaic, uint32_t type, uint64_t delta) { + if (!signer) { + signer = ctx->public_key; + } + + bool ret = nem_transaction_write_common( + ctx, NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE, + (uint32_t)network << 24 | 1, timestamp, signer, fee, deadline); + if (!ret) return false; + + size_t namespace_length = strlen(namespace); + size_t mosaic_length = strlen(mosaic); + size_t identifier_length = + sizeof(uint32_t) + namespace_length + sizeof(uint32_t) + mosaic_length; + + SERIALIZE_U32(identifier_length); + SERIALIZE_TAGGED((const uint8_t *)namespace, namespace_length); + SERIALIZE_TAGGED((const uint8_t *)mosaic, mosaic_length); + SERIALIZE_U32(type); + SERIALIZE_U64(delta); + + return true; +} + +bool nem_transaction_create_aggregate_modification( + nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, + const ed25519_public_key signer, uint64_t fee, uint32_t deadline, + uint32_t modifications, bool relative_change) { + if (!signer) { + signer = ctx->public_key; + } + + bool ret = nem_transaction_write_common( + ctx, NEM_TRANSACTION_TYPE_AGGREGATE_MODIFICATION, + (uint32_t)network << 24 | (relative_change ? 2 : 1), timestamp, signer, + fee, deadline); + if (!ret) return false; + + SERIALIZE_U32(modifications); + + return true; +} + +bool nem_transaction_write_cosignatory_modification( + nem_transaction_ctx *ctx, uint32_t type, + const ed25519_public_key cosignatory) { + SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint32_t) + + sizeof(ed25519_public_key)); + SERIALIZE_U32(type); + SERIALIZE_TAGGED(cosignatory, sizeof(ed25519_public_key)); + + return true; +} + +bool nem_transaction_write_minimum_cosignatories(nem_transaction_ctx *ctx, + int32_t relative_change) { + SERIALIZE_U32(sizeof(uint32_t)); + SERIALIZE_U32((uint32_t)relative_change); + + return true; +} + +bool nem_transaction_create_importance_transfer( + nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, + const ed25519_public_key signer, uint64_t fee, uint32_t deadline, + uint32_t mode, const ed25519_public_key remote) { + if (!signer) { + signer = ctx->public_key; + } + + bool ret = nem_transaction_write_common( + ctx, NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER, + (uint32_t)network << 24 | 1, timestamp, signer, fee, deadline); + if (!ret) return false; + + SERIALIZE_U32(mode); + SERIALIZE_TAGGED(remote, sizeof(ed25519_public_key)); + + return true; +} diff --git a/deps/crypto/trezor-crypto/nem.h b/deps/crypto/trezor-crypto/nem.h new file mode 100644 index 000000000..fe68316fb --- /dev/null +++ b/deps/crypto/trezor-crypto/nem.h @@ -0,0 +1,156 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __NEM_H__ +#define __NEM_H__ + +#include +#include +#include + +#include "bip32.h" +#include "ed25519-donna/ed25519.h" + +#define NEM_LEVY_PERCENTILE_DIVISOR 4 +#define NEM_MAX_DIVISIBILITY 6 +#define NEM_MAX_SUPPLY 9000000000 + +#define NEM_NETWORK_MAINNET 0x68 +#define NEM_NETWORK_TESTNET 0x98 +#define NEM_NETWORK_MIJIN 0x60 + +#define NEM_ADDRESS_SIZE 40 +#define NEM_ADDRESS_SIZE_RAW 25 + +#define NEM_TRANSACTION_TYPE_TRANSFER 0x0101 +#define NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER 0x0801 +#define NEM_TRANSACTION_TYPE_AGGREGATE_MODIFICATION 0x1001 +#define NEM_TRANSACTION_TYPE_MULTISIG_SIGNATURE 0x1002 +#define NEM_TRANSACTION_TYPE_MULTISIG 0x1004 +#define NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE 0x2001 +#define NEM_TRANSACTION_TYPE_MOSAIC_CREATION 0x4001 +#define NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE 0x4002 + +#define NEM_SALT_SIZE sizeof(ed25519_public_key) + +#define NEM_ENCRYPTED_SIZE(size) \ + (((size) + AES_BLOCK_SIZE) / AES_BLOCK_SIZE * AES_BLOCK_SIZE) +#define NEM_ENCRYPTED_PAYLOAD_SIZE(size) \ + (AES_BLOCK_SIZE + NEM_SALT_SIZE + NEM_ENCRYPTED_SIZE(size)) + +#define _NEM_PADDING_SIZE(buffer, size) ((buffer)[(size)-1]) +#define NEM_PADDING_SIZE(buffer, size) \ + (_NEM_PADDING_SIZE(buffer, size) > (size) ? (size) \ + : _NEM_PADDING_SIZE(buffer, size)) + +#define NEM_DECRYPTED_SIZE(buffer, size) ((size)-NEM_PADDING_SIZE(buffer, size)) + +typedef struct { + ed25519_public_key public_key; + uint8_t *buffer; + size_t offset; + size_t size; +} nem_transaction_ctx; + +const char *nem_network_name(uint8_t network); + +void nem_get_address_raw(const ed25519_public_key public_key, uint8_t version, + uint8_t *address); +bool nem_get_address(const ed25519_public_key public_key, uint8_t version, + char *address); + +bool nem_validate_address_raw(const uint8_t *address, uint8_t network); +bool nem_validate_address(const char *address, uint8_t network); + +void nem_transaction_start(nem_transaction_ctx *ctx, + const ed25519_public_key public_key, uint8_t *buffer, + size_t size); +size_t nem_transaction_end(nem_transaction_ctx *ctx, + const ed25519_secret_key private_key, + ed25519_signature signature); + +bool nem_transaction_write_common(nem_transaction_ctx *context, uint32_t type, + uint32_t version, uint32_t timestamp, + const ed25519_public_key signer, uint64_t fee, + uint32_t deadline); + +bool nem_transaction_create_transfer(nem_transaction_ctx *context, + uint8_t network, uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, uint32_t deadline, + const char *recipient, uint64_t amount, + const uint8_t *payload, uint32_t length, + bool encrypted, uint32_t mosaics); + +bool nem_transaction_write_mosaic(nem_transaction_ctx *ctx, + const char *namespace, const char *mosaic, + uint64_t quantity); + +bool nem_transaction_create_multisig(nem_transaction_ctx *ctx, uint8_t network, + uint32_t timestamp, + const ed25519_public_key signer, + uint64_t fee, uint32_t deadline, + const nem_transaction_ctx *inner); + +bool nem_transaction_create_multisig_signature( + nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, + const ed25519_public_key signer, uint64_t fee, uint32_t deadline, + const nem_transaction_ctx *inner); + +bool nem_transaction_create_provision_namespace( + nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, + const ed25519_public_key signer, uint64_t fee, uint32_t deadline, + const char *namespace, const char *parent, const char *rental_sink, + uint64_t rental_fee); + +bool nem_transaction_create_mosaic_creation( + nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, + const ed25519_public_key signer, uint64_t fee, uint32_t deadline, + const char *namespace, const char *mosaic, const char *description, + uint32_t divisibility, uint64_t supply, bool mutable_supply, + bool transferable, uint32_t levy_type, uint64_t levy_fee, + const char *levy_address, const char *levy_namespace, + const char *levy_mosaic, const char *creation_sink, uint64_t creation_fee); + +bool nem_transaction_create_mosaic_supply_change( + nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, + const ed25519_public_key signer, uint64_t fee, uint32_t deadline, + const char *namespace, const char *mosaic, uint32_t type, uint64_t delta); + +bool nem_transaction_create_aggregate_modification( + nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, + const ed25519_public_key signer, uint64_t fee, uint32_t deadline, + uint32_t modifications, bool relative_change); + +bool nem_transaction_write_cosignatory_modification( + nem_transaction_ctx *ctx, uint32_t type, + const ed25519_public_key cosignatory); + +bool nem_transaction_write_minimum_cosignatories(nem_transaction_ctx *ctx, + int32_t relative_change); + +bool nem_transaction_create_importance_transfer( + nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, + const ed25519_public_key signer, uint64_t fee, uint32_t deadline, + uint32_t mode, const ed25519_public_key remote); + +#endif diff --git a/deps/crypto/trezor-crypto/nist256p1.c b/deps/crypto/trezor-crypto/nist256p1.c new file mode 100644 index 000000000..1082d334c --- /dev/null +++ b/deps/crypto/trezor-crypto/nist256p1.c @@ -0,0 +1,69 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "nist256p1.h" + +const ecdsa_curve nist256p1 = { + /* .prime */ {/*.val =*/{0x1fffffff, 0x1fffffff, 0x1fffffff, 0x000001ff, + 0x00000000, 0x00000000, 0x00040000, 0x1fe00000, + 0xffffff}}, + + /* G */ + {/*.x =*/{/*.val =*/{0x1898c296, 0x0509ca2e, 0x1acce83d, 0x06fb025b, + 0x040f2770, 0x1372b1d2, 0x091fe2f3, 0x1e5c2588, + 0x6b17d1}}, + /*.y =*/{/*.val =*/{0x17bf51f5, 0x1db20341, 0x0c57b3b2, 0x1c66aed6, + 0x19e162bc, 0x15a53e07, 0x1e6e3b9f, 0x1c5fc34f, + 0x4fe342}}}, + + /* order */ + {/*.val =*/{0x1c632551, 0x1dce5617, 0x05e7a13c, 0x0df55b4e, 0x1ffffbce, + 0x1fffffff, 0x0003ffff, 0x1fe00000, 0xffffff}}, + + /* order_half */ + {/*.val =*/{0x1e3192a8, 0x0ee72b0b, 0x02f3d09e, 0x06faada7, 0x1ffffde7, + 0x1fffffff, 0x0001ffff, 0x1ff00000, 0x7fffff}}, + + /* a */ -3, + + /* b */ + {/*.val =*/{0x07d2604b, 0x1e71e1f1, 0x14ec3d8e, 0x1a0d6198, 0x086bc651, + 0x1eaabb4c, 0x0f9ecfae, 0x1b154752, 0x005ac635}} + +#if USE_PRECOMPUTED_CP + , + /* cp */ + { +#include "nist256p1.table" + } +#endif +}; + +const curve_info nist256p1_info = { + .bip32_name = "Nist256p1 seed", + .params = &nist256p1, + .hasher_base58 = HASHER_SHA2D, + .hasher_sign = HASHER_SHA2D, + .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_script = HASHER_SHA2, +}; diff --git a/deps/crypto/trezor-crypto/nist256p1.h b/deps/crypto/trezor-crypto/nist256p1.h new file mode 100644 index 000000000..02d04025a --- /dev/null +++ b/deps/crypto/trezor-crypto/nist256p1.h @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __NIST256P1_H__ +#define __NIST256P1_H__ + +#include + +#include "bip32.h" +#include "ecdsa.h" + +extern const ecdsa_curve nist256p1; +extern const curve_info nist256p1_info; + +#endif diff --git a/deps/crypto/trezor-crypto/nist256p1.table b/deps/crypto/trezor-crypto/nist256p1.table new file mode 100644 index 000000000..6be01b4d6 --- /dev/null +++ b/deps/crypto/trezor-crypto/nist256p1.table @@ -0,0 +1,1664 @@ + { + /* 1*16^0*G: */ + {{{0x1898c296, 0x0509ca2e, 0x1acce83d, 0x06fb025b, 0x040f2770, 0x1372b1d2, 0x091fe2f3, 0x1e5c2588, 0x6b17d1}}, + {{0x17bf51f5, 0x1db20341, 0x0c57b3b2, 0x1c66aed6, 0x19e162bc, 0x15a53e07, 0x1e6e3b9f, 0x1c5fc34f, 0x4fe342}}}, + /* 3*16^0*G: */ + {{{0x06e7fd6c, 0x1a0b30de, 0x0b6a617e, 0x0d6e43df, 0x1f165e6c, 0x17ca8ea5, 0x091323df, 0x1a34c661, 0x5ecbe4}}, + {{0x027d5032, 0x13cd893d, 0x13ee0f66, 0x15606c70, 0x0a2ecd82, 0x03670d32, 0x1df8dd2c, 0x0189331f, 0x873464}}}, + /* 5*16^0*G: */ + {{{0x03d033ed, 0x0aaa506e, 0x16f94908, 0x1905fa3e, 0x08fdfef8, 0x042b0433, 0x034b5e13, 0x0f4a2a28, 0x51590b}}, + {{0x1da16da4, 0x0e85da27, 0x16022234, 0x025e01a9, 0x079260d0, 0x1f9b5fc5, 0x09f62b86, 0x1512094e, 0xe0c17d}}}, + /* 7*16^0*G: */ + {{{0x1187b2a3, 0x00314381, 0x03fbd6cc, 0x13f17150, 0x1fb607ef, 0x18333e00, 0x0d1896ec, 0x0df417ef, 0x8e533b}}, + {{0x01f400b4, 0x0af0d436, 0x0106c871, 0x0e6c6796, 0x1900053c, 0x0fc1d37a, 0x00d9b41a, 0x17bc0663, 0x73eb1d}}}, + /* 9*16^0*G: */ + {{{0x10949ee0, 0x1cf4525c, 0x1b7e2cf5, 0x15971858, 0x1f8729e0, 0x1c6a8eb8, 0x0dc61e24, 0x16dfdbe1, 0xea68d7}}, + {{0x0dd048fa, 0x02d11252, 0x17a08ffa, 0x029fd549, 0x0a0c84d7, 0x054b2547, 0x139e1c05, 0x192e593f, 0x2a2744}}}, + /* 11*16^0*G: */ + {{{0x14bc21d1, 0x199c8e9b, 0x14122fd0, 0x085da04a, 0x01cda167, 0x1bced861, 0x116418e0, 0x16f10769, 0x3ed113}}, + {{0x082a3740, 0x17c777e7, 0x062276b8, 0x1a09b4bd, 0x0c68a090, 0x01d7d27a, 0x02889321, 0x13599899, 0x909920}}}, + /* 13*16^0*G: */ + {{{0x06072c01, 0x070aecea, 0x1ab562a6, 0x1c5096cb, 0x0e2fc792, 0x0ef96c2f, 0x05698601, 0x0f5c1589, 0x177c83}}, + {{0x0fc7bfd8, 0x021ddf17, 0x1ed37ce7, 0x1c298743, 0x14e7226e, 0x08d6da07, 0x15628902, 0x19a9d7d4, 0x63bb58}}}, + /* 15*16^0*G: */ + {{{0x059b9d5f, 0x1b34631f, 0x0e83bc58, 0x075f25bc, 0x08265ae0, 0x1bc4ccc4, 0x0b9eb7ec, 0x18d2e357, 0xf0454d}}, + {{0x0d034f36, 0x1f2ce6f0, 0x0d7e8fd1, 0x16439ceb, 0x043e62a3, 0x0a728fcb, 0x147d3996, 0x1c6b25c5, 0xb5b93e}}} + }, + { + /* 1*16^1*G: */ + {{{0x01277c6e, 0x0f5a3c3f, 0x1b280e29, 0x10725dfe, 0x0315fcd2, 0x0e314c1b, 0x06162e08, 0x02714d68, 0x76a94d}}, + {{0x0b8c5110, 0x14eeeb92, 0x11e2ea83, 0x1340081f, 0x08720859, 0x10daf08f, 0x1839b2c2, 0x0c2683e4, 0xa985fe}}}, + /* 3*16^1*G: */ + {{{0x1e4536ca, 0x1fdcee34, 0x0806986a, 0x1d252c14, 0x0cda11c2, 0x1a2df038, 0x07b23339, 0x01c924a7, 0x9482fb}}, + {{0x158cc1c8, 0x1d6c31df, 0x01efeec7, 0x1abc52ae, 0x14e63f63, 0x11c653a9, 0x1fe46975, 0x14e8be2a, 0x351d9c}}}, + /* 5*16^1*G: */ + {{{0x15ecff13, 0x0d8ed714, 0x1418cf12, 0x0c9439b7, 0x01eeb637, 0x0d28a984, 0x04656e0d, 0x182f5d26, 0xb2e1b7}}, + {{0x12187d44, 0x1dd24c4d, 0x17a8b9a8, 0x1435302f, 0x158c387d, 0x10d1556b, 0x0f33c8ce, 0x0262747d, 0xe6c044}}}, + /* 7*16^1*G: */ + {{{0x0ef87286, 0x05dd99a7, 0x08c2790e, 0x07d0fbf8, 0x0ee34070, 0x0bbee5e3, 0x0f0b2cd0, 0x05cfe36d, 0xb43346}}, + {{0x041496d9, 0x16023fb4, 0x0b3a92de, 0x1c4100d4, 0x12e6f9dc, 0x073960b4, 0x17f8e0fd, 0x0a4dda56, 0xa0da54}}}, + /* 9*16^1*G: */ + {{{0x19794381, 0x1cc35ad8, 0x0c31d806, 0x02b10ebd, 0x07b19189, 0x1482daab, 0x0933061b, 0x19c9a7b4, 0xa47420}}, + {{0x02769c52, 0x0b671d3f, 0x1dab1e1a, 0x0b811b73, 0x07afff3a, 0x1c9b0ccb, 0x1f839cf7, 0x1bef7c37, 0x2ebbff}}}, + /* 11*16^1*G: */ + {{{0x09a5185a, 0x03a23324, 0x179bcafb, 0x0e15913e, 0x1a3195b8, 0x0a009586, 0x05217fb3, 0x03373a12, 0x5ba7a}}, + {{0x01de3a4e, 0x0a1e4470, 0x016b8005, 0x0c441792, 0x1d48e760, 0x011f1271, 0x025b919e, 0x16bd0583, 0x30e0d2}}}, + /* 13*16^1*G: */ + {{{0x199b85fe, 0x151cc5af, 0x0e977f56, 0x1dfd355c, 0x1e0b79c0, 0x06c8c041, 0x0bf5a5e6, 0x193a1bfc, 0xb29f74}}, + {{0x0da604dc, 0x1d3214bb, 0x1d67a036, 0x1ec7a617, 0x1c6d92de, 0x18974b6b, 0x1e175741, 0x1874d852, 0xa3ce5b}}}, + /* 15*16^1*G: */ + {{{0x07e030ef, 0x1b3a2b74, 0x1543a589, 0x16560af9, 0x02b08576, 0x1f81f924, 0x13d41db2, 0x15517237, 0x99299b}}, + {{0x18d9aa9a, 0x0c735bee, 0x10021113, 0x0258933e, 0x0aa7957c, 0x0080d367, 0x1862fcce, 0x1a6667f1, 0x5cc2e3}}} + }, + { + /* 1*16^2*G: */ + {{{0x12d0441b, 0x0d971af8, 0x1a95930b, 0x1a16e21a, 0x1ed61190, 0x08a94301, 0x19661fff, 0x14760122, 0x34a2d4}}, + {{0x1e93b146, 0x01273c22, 0x1776076d, 0x0ecd73bd, 0x17fc0e7d, 0x1882373b, 0x0f08af29, 0x0d4a743c, 0xbeaaed}}}, + /* 3*16^2*G: */ + {{{0x1da08424, 0x0725719d, 0x1d912a77, 0x1f6f56e9, 0x123ed3ab, 0x02ffd4ae, 0x06a86d63, 0x00f5b86b, 0xa98b0a}}, + {{0x0831800c, 0x10943d07, 0x17d60b4d, 0x17d01741, 0x11320752, 0x0f46470e, 0x0d9b94c6, 0x08e44933, 0x4754c6}}}, + /* 5*16^2*G: */ + {{{0x083c2d6a, 0x096bf2f4, 0x0f4a6ced, 0x1f231b03, 0x0696dd22, 0x15bc642d, 0x0b17486d, 0x013911b5, 0xa034f0}}, + {{0x02c30e72, 0x019b7796, 0x099f9f3d, 0x0c06be2c, 0x0eb06be0, 0x1c2a2e76, 0x107ec336, 0x06d95133, 0xfe1b00}}}, + /* 7*16^2*G: */ + {{{0x08be8c78, 0x0b528ee9, 0x1e4f935c, 0x12d9f056, 0x0e9a14a0, 0x115a04b1, 0x100681db, 0x1fe633a8, 0xb52226}}, + {{0x11686903, 0x019b3e52, 0x0d63fcc8, 0x1eff91cb, 0x0851a819, 0x1b34bf49, 0x1503286c, 0x193ea73e, 0x701ee0}}}, + /* 9*16^2*G: */ + {{{0x0058b5a4, 0x0207f205, 0x0c65e6dc, 0x08c9f0f2, 0x04713de4, 0x07667e66, 0x16cf65a3, 0x0c30d1c0, 0xa3e388}}, + {{0x07113aef, 0x19836c87, 0x1c68a523, 0x1d08b76e, 0x1e68f3ce, 0x1359d74b, 0x04b0e123, 0x110fbe1a, 0xcfd457}}}, + /* 11*16^2*G: */ + {{{0x04a08314, 0x02faf648, 0x11f7fde8, 0x1c6db65b, 0x1197a82f, 0x055cd110, 0x14e4ccf3, 0x094263f4, 0x209954}}, + {{0x07573ccc, 0x1fc64e2f, 0x1f3fa5b9, 0x0dcb4e6d, 0x048dfd40, 0x1472e5c8, 0x0c6243ee, 0x1fa55467, 0xa5cf3d}}}, + /* 13*16^2*G: */ + {{{0x09078c18, 0x017fca57, 0x1b7a4a54, 0x018795dd, 0x1d39b99e, 0x1739556f, 0x11c0c23d, 0x0275981d, 0x751d65}}, + {{0x0ece0d67, 0x0c6b74ae, 0x1816b1e6, 0x12918397, 0x02a4ef00, 0x05d7b515, 0x056214d5, 0x1fb94948, 0xba9c3f}}}, + /* 15*16^2*G: */ + {{{0x1e86d900, 0x167e6ae4, 0x08f6d124, 0x1dc13a2f, 0x03b36405, 0x0184501d, 0x00445ed2, 0x044b88f0, 0x5be0f5}}, + {{0x158a5755, 0x066eb4df, 0x0cd3d6b1, 0x02e4a483, 0x1423df92, 0x11d273da, 0x108b4d1f, 0x1cdbfe58, 0x83d1d9}}} + }, + { + /* 1*16^3*G: */ + {{{0x0245573f, 0x03bf46d5, 0x1f42993c, 0x0cede5e9, 0x16bd2508, 0x04b39736, 0x193665de, 0x1a59e0d3, 0xe716ae}}, + {{0x069218d1, 0x02fe135a, 0x01f26cd4, 0x1a1be5f4, 0x1a851d13, 0x183343dc, 0x0aad644a, 0x1cd29f8e, 0x353663}}}, + /* 3*16^3*G: */ + {{{0x057008ac, 0x1cc3c983, 0x0a7b7edf, 0x1c3d9dc6, 0x1a22d19c, 0x0ac5260e, 0x13a19395, 0x11adea0f, 0xd2bf89}}, + {{0x127beb55, 0x088a9a53, 0x1fc1e620, 0x19c2156b, 0x10c56679, 0x0aed9fd4, 0x1ea8fe06, 0x196b4d6e, 0x69c0b1}}}, + /* 5*16^3*G: */ + {{{0x182f1580, 0x086be54b, 0x080fadff, 0x09bbdc48, 0x064f8b0e, 0x0b9c8f98, 0x19821fe9, 0x09dcb079, 0x4d8830}}, + {{0x1616edd7, 0x007d8b6a, 0x1ac78443, 0x19477ad1, 0x16518aaf, 0x00044c7e, 0x0db3a35a, 0x0e13560c, 0x28a94e}}}, + /* 7*16^3*G: */ + {{{0x00c38e11, 0x1c261ed7, 0x1b89ae97, 0x0c8437d4, 0x1af9e715, 0x1cc90172, 0x1bacc99c, 0x04f91f81, 0x17c727}}, + {{0x0e90decd, 0x0c1b35dd, 0x0336b8f3, 0x07328b4c, 0x1802e7e5, 0x17e67480, 0x0cf10180, 0x1e9fccc9, 0x95c5a4}}}, + /* 9*16^3*G: */ + {{{0x032f36ea, 0x0aafec57, 0x0d5070f6, 0x1e8d4e52, 0x0b8b3cd4, 0x18e7e426, 0x02a2118e, 0x15588e8a, 0x7e03fd}}, + {{0x0a68b8af, 0x16611fe4, 0x140275a2, 0x1d2f3498, 0x0af99419, 0x158b80c2, 0x03699a39, 0x1e240245, 0xdcf6d5}}}, + /* 11*16^3*G: */ + {{{0x1953baa9, 0x01f29536, 0x18637a35, 0x0b5d0c93, 0x0b214261, 0x1d60ee50, 0x1c1d858d, 0x0d096379, 0x8ce6da}}, + {{0x152689e5, 0x073ae147, 0x0a4d075e, 0x0730d76d, 0x1b56807f, 0x1de48030, 0x082f9a6c, 0x171f5262, 0x3d9f4f}}}, + /* 13*16^3*G: */ + {{{0x0f22a96a, 0x15c6c29d, 0x1aae3e52, 0x03753b38, 0x0e2b008b, 0x1aa4badd, 0x15288294, 0x06081b80, 0xb570e7}}, + {{0x085d1b00, 0x199fb30e, 0x15732732, 0x1376f4b0, 0x0cfbda7c, 0x1bb4dae0, 0x1dfc0a30, 0x0c71ee3c, 0xdcd8a2}}}, + /* 15*16^3*G: */ + {{{0x189a7509, 0x12075ca2, 0x1ea01527, 0x0e172c83, 0x1f20de12, 0x0d1f3ae3, 0x10ec1284, 0x04797572, 0x44d943}}, + {{0x00437234, 0x10515cdb, 0x137449b8, 0x07c3fbe2, 0x193586f9, 0x1de693bd, 0x1c280d08, 0x10010803, 0xb2c5b3}}} + }, + { + /* 1*16^4*G: */ + {{{0x0eade3c4, 0x1f4232e3, 0x014a8140, 0x156e9392, 0x186b4714, 0x1219a072, 0x04363971, 0x0de9d23d, 0xa01836}}, + {{0x0b26e8d0, 0x02e21013, 0x1853cdfd, 0x0e509c88, 0x18369d5f, 0x12bc1a4e, 0x0c59f1b3, 0x02e28221, 0xe2bbec}}}, + /* 3*16^4*G: */ + {{{0x19e0af06, 0x10e6f562, 0x1b65635b, 0x07314ac5, 0x1055c92f, 0x1dad36a2, 0x059142f4, 0x001711b1, 0x9cdf1f}}, + {{0x0216ade7, 0x0bd196db, 0x1f2951a3, 0x0a45b832, 0x194b0828, 0x05de6e46, 0x15993656, 0x1fda7e55, 0x916d25}}}, + /* 5*16^4*G: */ + {{{0x1305097e, 0x09b95c9c, 0x0ee94660, 0x0c2e1d08, 0x0448338d, 0x0d9682a0, 0x0fb6adac, 0x1aba34cc, 0x45bfd9}}, + {{0x108ddc04, 0x05d02c74, 0x14b05655, 0x173a677f, 0x0e908683, 0x0182a386, 0x14aeeb62, 0x0250ab5f, 0x9d1dc}}}, + /* 7*16^4*G: */ + {{{0x163bd6df, 0x098f8d05, 0x19abb0f3, 0x184785ba, 0x15e6fd1f, 0x0fce0144, 0x04ed9c7a, 0x02ac8ecd, 0xb599ad}}, + {{0x0efa09ac, 0x150e751c, 0x04d2d163, 0x0189ed22, 0x1c4166a4, 0x1b05c591, 0x0cc918dc, 0x1bd89f56, 0x6979d1}}}, + /* 9*16^4*G: */ + {{{0x07142d62, 0x1c309f99, 0x0ef09b6b, 0x14d46bf0, 0x054c11d9, 0x158913f4, 0x103a4998, 0x1e2ce655, 0xf4dca1}}, + {{0x1a618fc9, 0x04f66603, 0x134f5feb, 0x0f359dfb, 0x1c659bb9, 0x1c0dc8d5, 0x151b527c, 0x1cb69699, 0x551167}}}, + /* 11*16^4*G: */ + {{{0x015fae61, 0x1658ffa3, 0x0e57e087, 0x0b8fb89e, 0x0bb5a7f1, 0x1120738b, 0x0d9b6713, 0x141cdc13, 0xf07278}}, + {{0x096376f9, 0x1e865ba4, 0x0dfaaf3d, 0x0e0e2b70, 0x0f7d42c2, 0x10410c4c, 0x1a97df5e, 0x056294e3, 0x1a681b}}}, + /* 13*16^4*G: */ + {{{0x0466591f, 0x027020a9, 0x11a35a83, 0x0e5d51ff, 0x058ccbe1, 0x15a99dd4, 0x16c3c50e, 0x0af5e141, 0x1fc524}}, + {{0x196f8cdb, 0x077f7ab9, 0x1b1e0891, 0x11958465, 0x14e1629f, 0x1b7f2da1, 0x1047a7b1, 0x070113d7, 0x489c18}}}, + /* 15*16^4*G: */ + {{{0x122a8ebc, 0x12e85c61, 0x1e59c544, 0x039b6e31, 0x056d5a29, 0x05ad9865, 0x17d3f5fc, 0x16634918, 0xfa2501}}, + {{0x0a8a775b, 0x06c93dad, 0x0f20cc60, 0x11c11cd9, 0x1a8cbea5, 0x0f330d37, 0x0588ce14, 0x1629f0b1, 0x71c932}}} + }, + { + /* 1*16^5*G: */ + {{{0x1d96dff1, 0x1bee765b, 0x157f3fa3, 0x08638355, 0x198d530e, 0x105ab866, 0x153ffbda, 0x10a283fc, 0xec738}}, + {{0x1c7b552c, 0x16420d63, 0x1b5e2aa7, 0x04c99d0f, 0x052511d5, 0x0277ac03, 0x1d7646b3, 0x09d0f5d0, 0xd6224f}}}, + /* 3*16^5*G: */ + {{{0x088d58e9, 0x0e192558, 0x18c60e14, 0x14b838c9, 0x0a7b6e94, 0x12353e21, 0x0a1ba64a, 0x1fb8e0c9, 0x96dac3}}, + {{0x0ebebc5e, 0x01a49895, 0x01f9b8e0, 0x17d13729, 0x0c439685, 0x024a49c1, 0x06b615b3, 0x1e75a8d8, 0xcb1faf}}}, + /* 5*16^5*G: */ + {{{0x0db29f92, 0x0a956899, 0x11ecb162, 0x03a4e372, 0x18f811d2, 0x0e1bc575, 0x0c4a8417, 0x079d629e, 0xe297b2}}, + {{0x05e58ddb, 0x0794a645, 0x1b505058, 0x079d770b, 0x19149122, 0x0dd5dc66, 0x02d2d203, 0x041f196e, 0xe13725}}}, + /* 7*16^5*G: */ + {{{0x0ad88c33, 0x0ca1dbdc, 0x1d1af2bf, 0x15c729b2, 0x0da97d91, 0x1e490692, 0x12d9ac1a, 0x071f6572, 0x1cd223}}, + {{0x048fb1b2, 0x14753c21, 0x12879258, 0x1ca262bd, 0x0bc2713f, 0x1205589b, 0x02c25b21, 0x1f071569, 0xfc3acd}}}, + /* 9*16^5*G: */ + {{{0x1b26aa73, 0x09d644e1, 0x18e8383d, 0x0fc23618, 0x11ee0cdf, 0x16986ffd, 0x0eff2c72, 0x15b73d3f, 0xf462d7}}, + {{0x18479e73, 0x02f560bb, 0x140b3289, 0x11c14600, 0x13c7a49e, 0x1d253439, 0x0c50354e, 0x034f068a, 0x406a0d}}}, + /* 11*16^5*G: */ + {{{0x1cd015e3, 0x170f0155, 0x194089cf, 0x01d2b2fc, 0x15168af9, 0x1f59e544, 0x12bdd6f6, 0x04ba7ee1, 0xe0f689}}, + {{0x12157cce, 0x15126a16, 0x0a4daef6, 0x116a723c, 0x0c77c55b, 0x14b6393a, 0x0aa54d89, 0x0621c907, 0x8531e}}}, + /* 13*16^5*G: */ + {{{0x0bb76b12, 0x1362188a, 0x0649da47, 0x1cecee7c, 0x15a00ea8, 0x1598957b, 0x15ff0760, 0x182aa57e, 0x28e4ad}}, + {{0x0c4747bd, 0x1f229d3f, 0x058a3fd5, 0x014c1e2e, 0x0a3f703a, 0x1b2db5cf, 0x06cfd392, 0x09dfb340, 0x14d74c}}}, + /* 15*16^5*G: */ + {{{0x076ff697, 0x1fac00ff, 0x01d918a2, 0x16d10ca4, 0x097c6369, 0x16d5d9d0, 0x017b49c7, 0x04f29750, 0x85a0ba}}, + {{0x12142721, 0x04f6a6d2, 0x02962e4c, 0x12fff4f2, 0x1aa551de, 0x0869ee76, 0x0929551e, 0x0c3d587c, 0xadf32e}}} + }, + { + /* 1*16^6*G: */ + {{{0x0392d805, 0x192e2ee7, 0x1501750d, 0x1500d30e, 0x1449aa87, 0x06d57d51, 0x0f5e9295, 0x19e98d52, 0xf8f5dc}}, + {{0x0cda02fa, 0x1330ca8b, 0x0850ee80, 0x07b4c94a, 0x1327351f, 0x1f19b230, 0x0150e274, 0x19ecdac6, 0xe58176}}}, + /* 3*16^6*G: */ + {{{0x1fa046f7, 0x0ea598b3, 0x01cc2746, 0x021e7204, 0x02d45171, 0x05644a37, 0x0ea53821, 0x0950cb10, 0xe12c8e}}, + {{0x012646ad, 0x1d2ad145, 0x0c464d14, 0x1809c226, 0x126f6dd0, 0x1f6a9c98, 0x0bcd0cec, 0x0c21fb34, 0x7cec04}}}, + /* 5*16^6*G: */ + {{{0x02853c43, 0x0d893f46, 0x08b919ae, 0x0cd8af5c, 0x13236481, 0x1177f1e8, 0x0824f423, 0x0e82f2d2, 0x394bd4}}, + {{0x0064469d, 0x0bc14665, 0x03f3c32c, 0x1ece25b2, 0x00767d52, 0x1fe178eb, 0x1ae481f8, 0x0a42a3b8, 0x2b4d6d}}}, + /* 7*16^6*G: */ + {{{0x1c722e94, 0x016eb9cf, 0x0162587b, 0x102072da, 0x004334ed, 0x132b62ca, 0x0ba51171, 0x1be71bd0, 0xca8538}}, + {{0x1049a527, 0x105316f8, 0x02c9a90e, 0x12a75149, 0x19f12f20, 0x189350fd, 0x170c479c, 0x085d73c0, 0x3b27fc}}}, + /* 9*16^6*G: */ + {{{0x1cad6309, 0x18ba314e, 0x0e7fd221, 0x143f85e4, 0x07b3dd31, 0x1a312653, 0x0dd686ed, 0x0b3e46af, 0x663e1a}}, + {{0x09981f28, 0x19435d1c, 0x1ad4af54, 0x0fa88805, 0x0f918b90, 0x00c1e58e, 0x030f040b, 0x07700cd5, 0x292fb7}}}, + /* 11*16^6*G: */ + {{{0x02c23d03, 0x13ad9229, 0x11ffc924, 0x03609b1f, 0x1eeab3ba, 0x1611b83d, 0x19c25b0d, 0x1ce60c6c, 0xa2d9ef}}, + {{0x1085db74, 0x01726027, 0x0e77d144, 0x134fd2b0, 0x01b92ea0, 0x021b6388, 0x0e3c554c, 0x05199083, 0x1cc852}}}, + /* 13*16^6*G: */ + {{{0x07d4c6d1, 0x1aafcb38, 0x167ffec5, 0x059aa335, 0x135d0f66, 0x085a939f, 0x07bf82e4, 0x05691635, 0x5657e1}}, + {{0x0106bdec, 0x0181f94c, 0x14b05062, 0x1346b428, 0x06a0abff, 0x1c8799d7, 0x07e6b3ec, 0x1e971ba9, 0x72b5be}}}, + /* 15*16^6*G: */ + {{{0x1933564a, 0x032a6eaa, 0x18ebd13e, 0x1169f5db, 0x18d2b7a6, 0x16e333b6, 0x00042193, 0x02ba815c, 0x5b6862}}, + {{0x0204ef63, 0x1af822c4, 0x1e21a7ce, 0x15dc4510, 0x195de392, 0x062a68ce, 0x19154b4c, 0x0d39e744, 0x76b5ea}}} + }, + { + /* 1*16^7*G: */ + {{{0x0f922dbd, 0x025118bb, 0x064863e6, 0x0c622c3f, 0x171b91ca, 0x1556c726, 0x1cc4fe17, 0x17ffa9b5, 0x6d28b6}}, + {{0x00ef3cff, 0x055ff815, 0x1368a651, 0x09d3e170, 0x14a1c4c2, 0x10d30e65, 0x0be903ef, 0x00a283ba, 0xaf39d9}}}, + /* 3*16^7*G: */ + {{{0x1b168b64, 0x0c86ffcc, 0x01b2102d, 0x07a0558b, 0x0467ea15, 0x0482fe0a, 0x0f774f7c, 0x0f4ff7fc, 0x7cd315}}, + {{0x1abbb16b, 0x0b60695a, 0x180b8d61, 0x189b36e5, 0x1fafb13a, 0x073c5e6d, 0x1188815a, 0x0422e525, 0x9ca08d}}}, + /* 5*16^7*G: */ + {{{0x06ef29e8, 0x158e37d0, 0x166bb8ec, 0x18aa9613, 0x1356264d, 0x018ccea2, 0x03115ac9, 0x1b6be5bf, 0xed860b}}, + {{0x19b90f8f, 0x00d0e24d, 0x036a8cd4, 0x061eb85b, 0x17bb1e76, 0x1b59a020, 0x1ff5f1af, 0x086ebab4, 0xb837e7}}}, + /* 7*16^7*G: */ + {{{0x1636e617, 0x0fc8c59f, 0x1c73d667, 0x19a07783, 0x12c9d47d, 0x0e173f13, 0x090dcd78, 0x11fa3a42, 0x6868cc}}, + {{0x1cbb3d27, 0x046ee79f, 0x0e1335c7, 0x1c619148, 0x13f0a60f, 0x081c3c98, 0x079acf16, 0x14b7237f, 0xeed008}}}, + /* 9*16^7*G: */ + {{{0x113e2a34, 0x1ced1530, 0x0e8478b1, 0x1a5ccb9c, 0x1d318291, 0x1a4f8857, 0x1880b172, 0x0c1d591f, 0xec03b3}}, + {{0x184566d6, 0x01121f75, 0x084dade9, 0x102adccb, 0x122728aa, 0x0f108090, 0x010defbf, 0x1f6c140b, 0x86020f}}}, + /* 11*16^7*G: */ + {{{0x087c1b18, 0x1570672e, 0x12646897, 0x1c596a90, 0x056fa101, 0x01ad2c88, 0x04379a8c, 0x1473cf17, 0xa79464}}, + {{0x1b94809a, 0x15ac284b, 0x158a086f, 0x11bd38e2, 0x089f60d9, 0x0bc3cf4d, 0x03309269, 0x1c7ee50b, 0x1361f4}}}, + /* 13*16^7*G: */ + {{{0x1ed10d26, 0x0a714636, 0x19657d96, 0x157df053, 0x10ccc5a9, 0x0fdb4a79, 0x131e43a4, 0x101551f7, 0x544ef2}}, + {{0x16dafcc2, 0x1e127b93, 0x0b01ab8b, 0x1adf2edc, 0x170d3683, 0x0eff46c6, 0x0b3a75ac, 0x13b88b58, 0x95b91c}}}, + /* 15*16^7*G: */ + {{{0x17ad18e6, 0x04a3cfc5, 0x0f2b5789, 0x1a7cf31a, 0x0ff9b57a, 0x1e4235a5, 0x18853794, 0x110be698, 0xe2c26c}}, + {{0x0554cfad, 0x0d7f28d5, 0x0607792b, 0x0a2b94e3, 0x1ba113bc, 0x1337508b, 0x06214738, 0x0509e910, 0xb2121b}}} + }, + { + /* 1*16^8*G: */ + {{{0x185a5943, 0x12d4f110, 0x1977ed8e, 0x12326cb8, 0x071da1ab, 0x15991316, 0x1e248595, 0x0815e455, 0x7fe36b}}, + {{0x099ca101, 0x0868a963, 0x02bc84b5, 0x07ab0cf7, 0x0a6f174b, 0x1a0203ee, 0x18927c27, 0x0b04b6c6, 0xe697d4}}}, + /* 3*16^8*G: */ + {{{0x1f0922a8, 0x153c048e, 0x173e365d, 0x01d3a4a8, 0x18b808e9, 0x072b0117, 0x15ce0249, 0x080b69c5, 0x4b656a}}, + {{0x199a80bb, 0x0d6e562c, 0x0143da53, 0x0773c573, 0x0c4d6d47, 0x06612aec, 0x00e48341, 0x03a25cef, 0xee1ea3}}}, + /* 5*16^8*G: */ + {{{0x09d07e9e, 0x0827c443, 0x09830dad, 0x1cf943ed, 0x18e5ea09, 0x15f07d9e, 0x04f64f6c, 0x0dd7acbc, 0x9d7895}}, + {{0x03d8c8ee, 0x06eb0ad6, 0x0531ecbd, 0x0145b477, 0x010ce746, 0x144e0e99, 0x0335950a, 0x0dde91d5, 0xd5149e}}}, + /* 7*16^8*G: */ + {{{0x1dc4950f, 0x13ba8433, 0x0e5081d9, 0x03655b7a, 0x16316574, 0x1423726d, 0x1ea55c8d, 0x0e5c26a7, 0x4acb12}}, + {{0x03d8b4df, 0x16372223, 0x019ab159, 0x1c85016b, 0x1e29fdf9, 0x0c7b6638, 0x16b633ca, 0x01f6e879, 0x726cd2}}}, + /* 9*16^8*G: */ + {{{0x0d7e8cbd, 0x0063d3df, 0x01f605bd, 0x0cff15e0, 0x1464a2a6, 0x09aa8640, 0x1ed08d11, 0x17e34d62, 0x640c5e}}, + {{0x1ec5a5db, 0x171481e5, 0x1fe6c081, 0x0d3f6319, 0x0ab9eba0, 0x0375b80f, 0x14bcaba7, 0x1fb0539f, 0xd6ae88}}}, + /* 11*16^8*G: */ + {{{0x1e86bddc, 0x18502583, 0x1738f57d, 0x04d72f2e, 0x16b9bf1d, 0x116486ed, 0x0cc91455, 0x16368509, 0x8bba04}}, + {{0x09e349c4, 0x111e2d0f, 0x065b97d4, 0x19fbc9e8, 0x1437ac6a, 0x1c90b34c, 0x1afd966f, 0x18138411, 0xc34099}}}, + /* 13*16^8*G: */ + {{{0x0257f582, 0x0b873c02, 0x10e89634, 0x1213d5bd, 0x05fe41f9, 0x0a1fbe2d, 0x1f88429a, 0x089fd9a6, 0x8b0a57}}, + {{0x17372d4b, 0x00bff6f9, 0x0581d992, 0x168d74f6, 0x17d4656d, 0x0ad09bf1, 0x1ce598a8, 0x09d81ad8, 0x9e57a4}}}, + /* 15*16^8*G: */ + {{{0x185e797e, 0x18a24fcc, 0x0f0c5a0f, 0x1c449e5c, 0x078a6f06, 0x17a49ecb, 0x025c7e15, 0x12f84c8f, 0xa13ff}}, + {{0x139d666f, 0x193d5cfa, 0x0030e4a0, 0x1ede14eb, 0x1dc3ff27, 0x00c747d0, 0x0f5645f6, 0x09644b90, 0xeb1a96}}} + }, + { + /* 1*16^9*G: */ + {{{0x1dde3445, 0x17fa7f0f, 0x0ba9e05e, 0x1753bb45, 0x0519e76b, 0x0ff3ff93, 0x079a14dc, 0x0709ae0c, 0x6965b6}}, + {{0x18855113, 0x0621c4f0, 0x17e6765f, 0x19cc0a34, 0x12dbef47, 0x04b31c39, 0x1444c979, 0x1c738904, 0xd1bcda}}}, + /* 3*16^9*G: */ + {{{0x088acfc5, 0x0f207cb4, 0x1a25e27d, 0x1eb1366c, 0x11a71b1e, 0x1eedea04, 0x1f6809f9, 0x03bbceb8, 0xe1cbc5}}, + {{0x0249a225, 0x1e2ff6ad, 0x0fee948e, 0x065257dd, 0x1e23ce7d, 0x1b27fedc, 0x0bb6cc49, 0x12f9bcfb, 0xec6783}}}, + /* 5*16^9*G: */ + {{{0x0107ccc6, 0x0c7529ff, 0x0f208a1d, 0x112fc2a8, 0x100481d3, 0x0e9422d4, 0x0a85cc7a, 0x0f2e2271, 0x9c3f26}}, + {{0x1dea9152, 0x003ca669, 0x1e6c61a1, 0x11fa9d2b, 0x06eca51a, 0x1afa5f9f, 0x16722f8d, 0x036c96a3, 0xdaee0c}}}, + /* 7*16^9*G: */ + {{{0x15a449e7, 0x0e2f5a1c, 0x0f0af908, 0x054069ca, 0x0922b2fa, 0x160bd8a0, 0x15c9e5be, 0x0aef8d65, 0x5c30d9}}, + {{0x0e2677d0, 0x1875240d, 0x139e439d, 0x1c80a787, 0x192d0b75, 0x12fbcce2, 0x0e48592d, 0x16b611c3, 0x8025e3}}}, + /* 9*16^9*G: */ + {{{0x0b8ceb07, 0x12ac6014, 0x1b89c73e, 0x124a57ff, 0x0d995537, 0x11583f54, 0x1a0abf93, 0x046191d2, 0xaa3bbf}}, + {{0x1fd83984, 0x0d423174, 0x0cfe7ae6, 0x036578f5, 0x162ec3b7, 0x187f2648, 0x09a11372, 0x161383d8, 0xe6320c}}}, + /* 11*16^9*G: */ + {{{0x03bfd1f1, 0x00752aac, 0x1595ccb9, 0x0db86a2b, 0x001943a3, 0x07e4c8a0, 0x0605e798, 0x0a226668, 0xab4a32}}, + {{0x08e1c233, 0x089cb086, 0x07a633c8, 0x1b26484f, 0x1e057a57, 0x1de82097, 0x19a2d3ac, 0x17606d90, 0xea6c64}}}, + /* 13*16^9*G: */ + {{{0x0b1d6d3f, 0x02036bc0, 0x1baee242, 0x0ecd149d, 0x1a8105f3, 0x1fae6c52, 0x15dfdccd, 0x0b3bbdab, 0xdba9b2}}, + {{0x09cd8133, 0x01749414, 0x0af64f31, 0x1b3788a2, 0x1871448b, 0x0ca7a7f5, 0x0ded6b2a, 0x07eaea6b, 0xb3862d}}}, + /* 15*16^9*G: */ + {{{0x11fa2a6a, 0x1cd01c01, 0x0392c959, 0x183ab0b6, 0x1cdfe34f, 0x0ba158d1, 0x1d141eb7, 0x1885d304, 0x1998f4}}, + {{0x06415142, 0x03f6da5e, 0x1c962d58, 0x180470f6, 0x0a1e94c6, 0x1c0045bc, 0x08425c03, 0x0da3215f, 0x2ebb41}}} + }, + { + /* 1*16^10*G: */ + {{{0x0d9aefbd, 0x0c7e5362, 0x0e55dd49, 0x1c8f64e7, 0x043dc1ef, 0x0f86a0de, 0x15d8cb2a, 0x03918cd3, 0xfbc34}}, + {{0x13e71ca0, 0x09db754e, 0x02a7fc7b, 0x160d3c40, 0x1d3d3950, 0x058ea4ab, 0x18ff9005, 0x0c65e6c1, 0xbd8022}}}, + /* 3*16^10*G: */ + {{{0x09434837, 0x1cb6fff7, 0x08306ee1, 0x0628170c, 0x1b06dadb, 0x0e37fda7, 0x0bb6c4d0, 0x1578950f, 0xd76d18}}, + {{0x1b215b4c, 0x1d5027cd, 0x0df33093, 0x08b1ceeb, 0x1933290a, 0x010a7bd5, 0x19137839, 0x1465db2c, 0xf6bc4d}}}, + /* 5*16^10*G: */ + {{{0x1c07f222, 0x1744f90c, 0x183f9f40, 0x0438c758, 0x153d1c5e, 0x0e8d0f8b, 0x1d813d20, 0x0a0c2cff, 0xd5c0c6}}, + {{0x0c6ffd57, 0x177b48f0, 0x004ea1b8, 0x07ea34f1, 0x175b9baf, 0x063bfa4f, 0x02143378, 0x10c102f7, 0x15a30b}}}, + /* 7*16^10*G: */ + {{{0x0e93bfa6, 0x1238b512, 0x084d8a92, 0x1a52b413, 0x09fe0d39, 0x05d335a6, 0x18b39527, 0x09c948de, 0x734c36}}, + {{0x18d10774, 0x037d3ccc, 0x00a5f13f, 0x026c4112, 0x05f48eca, 0x00f1a906, 0x141277a6, 0x007554f3, 0x99515}}}, + /* 9*16^10*G: */ + {{{0x1fa194ae, 0x075a8bfa, 0x0152bb3c, 0x00523b34, 0x0b149064, 0x0ece954f, 0x0a24045d, 0x1b40f6cd, 0x79a3d9}}, + {{0x1fcf634b, 0x1e32f4e4, 0x1e6f1353, 0x084be65e, 0x103d86bd, 0x18dc2c57, 0x06cd2cd9, 0x194e4a96, 0x84e1db}}}, + /* 11*16^10*G: */ + {{{0x01e8b7fe, 0x16483001, 0x016c9a9a, 0x01c5c2ef, 0x098e05dd, 0x06556e7e, 0x160a28f9, 0x0129ab60, 0x3393fd}}, + {{0x023c6821, 0x00a12210, 0x06e52dc3, 0x0d661515, 0x0668d8e5, 0x1576ce2d, 0x1ae0babf, 0x17d90cf7, 0x130437}}}, + /* 13*16^10*G: */ + {{{0x01528cf6, 0x04abceab, 0x141a53a8, 0x004a15ec, 0x10a52e6a, 0x02c3772d, 0x1f85786d, 0x10c268c4, 0xa16b28}}, + {{0x1ce93f3b, 0x05c907cf, 0x132004e0, 0x07f79027, 0x150f4349, 0x16bcec08, 0x166644f3, 0x15d0a6f5, 0xf40598}}}, + /* 15*16^10*G: */ + {{{0x0c8db2e0, 0x0885335c, 0x035cd60d, 0x197b82be, 0x074f6473, 0x04d5d4ad, 0x1d32fdb2, 0x04031c68, 0xd317ce}}, + {{0x074bc9a9, 0x0d9a5159, 0x0e183ce9, 0x04e9a045, 0x19136caa, 0x01f471cb, 0x112e670b, 0x01521270, 0xd61a21}}} + }, + { + /* 1*16^11*G: */ + {{{0x03fe67b2, 0x1718cbd5, 0x0b8cce31, 0x117fce14, 0x123b234a, 0x15cdd4b9, 0x1772f199, 0x086ee790, 0x6608c2}}, + {{0x05b47a28, 0x091ff2e7, 0x1150c206, 0x162b3e81, 0x0e03fc22, 0x1206d3a3, 0x05a211bd, 0x17d8a438, 0xa1a916}}}, + /* 3*16^11*G: */ + {{{0x0bc73e02, 0x1f375569, 0x194c4b04, 0x0cc29dd6, 0x18631849, 0x0c08beab, 0x108c81aa, 0x1c54d8bb, 0xf0956a}}, + {{0x0611219d, 0x0967b4cc, 0x0ba515cb, 0x1a091b77, 0x19356672, 0x02c57941, 0x00f1db88, 0x0c02289c, 0x433fe6}}}, + /* 5*16^11*G: */ + {{{0x1c5fe45c, 0x0f116f28, 0x1f03d65f, 0x05035070, 0x1283488b, 0x124ebe7b, 0x183294bc, 0x1d479454, 0xdb98eb}}, + {{0x1ef45a22, 0x05380e21, 0x12038711, 0x06409f54, 0x12c8ce98, 0x094eec48, 0x168b7854, 0x016eb7b0, 0xe0c0f3}}}, + /* 7*16^11*G: */ + {{{0x02128eac, 0x1acf306f, 0x0bc732eb, 0x0eb1ab99, 0x051690c4, 0x159dbeb5, 0x17d086e9, 0x02c15bb4, 0xa73c0}}, + {{0x04f1180d, 0x02c948eb, 0x1576728e, 0x0eb3e2ee, 0x10a7c793, 0x1b6eca7a, 0x0e329572, 0x0ac089d0, 0x443fda}}}, + /* 9*16^11*G: */ + {{{0x03ccbc30, 0x12d4998b, 0x0d258631, 0x1fcba43a, 0x197249ed, 0x1bb33d04, 0x1c8dc3b4, 0x1868f969, 0x378720}}, + {{0x1315729e, 0x110193f8, 0x0d23e11a, 0x19f2aba2, 0x19b6d16b, 0x05605553, 0x0e324c46, 0x1739ee4a, 0x8f1bdd}}}, + /* 11*16^11*G: */ + {{{0x03bb1b6b, 0x12546f2a, 0x1f0afea9, 0x1fde65e8, 0x1a621575, 0x08c6082a, 0x09867660, 0x03b6f163, 0xfe8fd2}}, + {{0x10eaaf93, 0x1daecdd1, 0x0afe2265, 0x09bb9fe1, 0x113c00f1, 0x074afad6, 0x18dda78a, 0x15d864ad, 0x791e22}}}, + /* 13*16^11*G: */ + {{{0x144b7cea, 0x002acce5, 0x1b3e1f7a, 0x08d28122, 0x1dcca474, 0x00113c59, 0x18bba081, 0x1aaf3f6f, 0x2c331f}}, + {{0x15d1c9c2, 0x1e15a356, 0x0c2501df, 0x04a23fe2, 0x1d650619, 0x19ec61de, 0x19dbf3cf, 0x0399c0c3, 0x20567b}}}, + /* 15*16^11*G: */ + {{{0x0112278c, 0x1c94d9bc, 0x03668563, 0x02c93a15, 0x04b66dd0, 0x1a643fc2, 0x0c828d22, 0x0d88ca34, 0x509bc0}}, + {{0x0e178f66, 0x043ae4c4, 0x0d7e517b, 0x0bfd0dce, 0x164570f6, 0x1a78bdc7, 0x1bb05d83, 0x1856e448, 0xb4b168}}} + }, + { + /* 1*16^12*G: */ + {{{0x17e55104, 0x175d7c00, 0x03a71c70, 0x1506bf77, 0x1561cf73, 0x09e1a6c5, 0x1cdd8f7a, 0x0a44f6f0, 0xd8de76}}, + {{0x052e08cd, 0x10177c07, 0x1036c6ca, 0x0e7f9c32, 0x0f924c2f, 0x114568ee, 0x0b457131, 0x0cb7c27e, 0x2fd294}}}, + /* 3*16^12*G: */ + {{{0x0987bfd3, 0x09ce163f, 0x110a131a, 0x0a8e5fe9, 0x1d19187c, 0x1df57d6e, 0x18cd5477, 0x0df7aa31, 0xe3a578}}, + {{0x0cc23e7d, 0x1698db64, 0x0a38205f, 0x19e5d9b2, 0x0210ca3d, 0x1cffa56c, 0x039a11de, 0x012a6b08, 0xf74bad}}}, + /* 5*16^12*G: */ + {{{0x02d5056e, 0x13ca8e91, 0x11e81f2d, 0x196b4fc4, 0x05e480ed, 0x0ffe74b7, 0x03504549, 0x083d94a4, 0x42a970}}, + {{0x10f7db11, 0x020a6e45, 0x07f47f52, 0x1c907add, 0x03b26b64, 0x16e935ab, 0x1c19bb0d, 0x0cd9e010, 0xf2fc7f}}}, + /* 7*16^12*G: */ + {{{0x13dafd3b, 0x13a2fc8e, 0x12ce55b1, 0x1133e05b, 0x179d66fb, 0x16176b29, 0x1933f88c, 0x036384f2, 0xd6ca7}}, + {{0x1a6fe6e8, 0x156f8a10, 0x021dc6b5, 0x049157dd, 0x1de58a02, 0x0a501383, 0x04f67f92, 0x1671fbc5, 0xa85130}}}, + /* 9*16^12*G: */ + {{{0x11131f8b, 0x15fce3ff, 0x0883537d, 0x08d2c19f, 0x11fb4696, 0x116fce21, 0x0f65f530, 0x0f5b0cb4, 0x5edca}}, + {{0x1a6f779f, 0x167858cd, 0x1a275243, 0x04a00be1, 0x071be335, 0x0b8daf81, 0x1af00727, 0x03c91d10, 0x9e5888}}}, + /* 11*16^12*G: */ + {{{0x0b597e4d, 0x047cfa0f, 0x1f468c67, 0x09e64bce, 0x11c11497, 0x02d19dbb, 0x0290486d, 0x0ac178f4, 0x5a13c0}}, + {{0x041856e0, 0x1bf2434f, 0x04d9992b, 0x1d0f56b2, 0x173ce7bd, 0x0c507916, 0x1ffd47f4, 0x027121f2, 0xc9e73c}}}, + /* 13*16^12*G: */ + {{{0x0260faf0, 0x153c4b0a, 0x1a564d76, 0x17a68b2f, 0x1272ea2b, 0x070d3407, 0x19d50c51, 0x0ac02f6d, 0x96b256}}, + {{0x0366d412, 0x07212907, 0x1f53d6b0, 0x177f30e0, 0x199e1890, 0x072b99df, 0x12b002b6, 0x1400366f, 0xdcf8a6}}}, + /* 15*16^12*G: */ + {{{0x0ad13276, 0x04d0df25, 0x1010f1e9, 0x06a1d5d3, 0x171a3ca6, 0x15959c3b, 0x18909bc4, 0x0218839b, 0xb9719}}, + {{0x0a84dadb, 0x19c79a10, 0x1c3eb8ec, 0x1af25304, 0x0811f593, 0x122d9dfb, 0x1bef538b, 0x0dde00dd, 0xac2848}}} + }, + { + /* 1*16^13*G: */ + {{{0x071e5c83, 0x1535e490, 0x10a82fbb, 0x04fe330a, 0x0e5b18bd, 0x02db952c, 0x1cfc82a1, 0x082a04da, 0x54ccc9}}, + {{0x140916a1, 0x1e8477b8, 0x03b925b3, 0x1c1798bb, 0x0bf22929, 0x038aed69, 0x14c8ea3e, 0x08b68a28, 0x1c433f}}}, + /* 3*16^13*G: */ + {{{0x0f76167c, 0x02f1b115, 0x1d19ce53, 0x1e845988, 0x0d9f22f2, 0x163496e6, 0x1e54e708, 0x1b96e7df, 0x87582e}}, + {{0x0f4d7ff6, 0x037ddb0b, 0x065efa1b, 0x051e0cee, 0x036a8880, 0x0161e1b9, 0x09eff784, 0x06a15ac9, 0x75b94}}}, + /* 5*16^13*G: */ + {{{0x14de6611, 0x1391f743, 0x0087ec11, 0x0cae7297, 0x0f11e33f, 0x1b9b1ab3, 0x1b6c7096, 0x1943e4e6, 0x4a107a}}, + {{0x18a805fe, 0x1ac75f72, 0x084cab00, 0x1aa8f4b8, 0x0052e075, 0x12747b80, 0x1ce4d339, 0x0a200c7d, 0x809b26}}}, + /* 7*16^13*G: */ + {{{0x0dcfecb0, 0x05d27683, 0x0a3611bf, 0x07fa3a61, 0x149f6e98, 0x0706a4df, 0x1f259528, 0x166e555b, 0xfd402e}}, + {{0x0da08de8, 0x02c9f9ef, 0x19979e44, 0x1698497b, 0x1a86b1a4, 0x131c4dd5, 0x088ba698, 0x061bb4c7, 0xd6b340}}}, + /* 9*16^13*G: */ + {{{0x154659ed, 0x1a6eb07a, 0x17659b96, 0x1c7a4432, 0x1d0a07fa, 0x0703ff64, 0x145577ee, 0x08c8c30e, 0x467bb3}}, + {{0x0800cf83, 0x1903e859, 0x004f8026, 0x17821b9a, 0x02cd3701, 0x06ac36dc, 0x03a287cb, 0x1a0b552f, 0xd01eff}}}, + /* 11*16^13*G: */ + {{{0x1c97e515, 0x1324c256, 0x021697fb, 0x09ad8673, 0x0c7e5691, 0x0db1874f, 0x0391b21e, 0x11f19bb8, 0xcf66b9}}, + {{0x006c8a51, 0x0c10a754, 0x0400cea5, 0x00e8b1b3, 0x06a7b33f, 0x1a081a76, 0x04847096, 0x0f72088c, 0xa7071}}}, + /* 13*16^13*G: */ + {{{0x186154e5, 0x1d295080, 0x0be8374e, 0x0054cd35, 0x06770864, 0x04a9d6a4, 0x08d1d472, 0x18c1f7f5, 0x3d9252}}, + {{0x1603a8a2, 0x1fe49fb4, 0x1f75c1dd, 0x03f6faf8, 0x14cf3aea, 0x19a144b5, 0x15ff1124, 0x1b9a5f53, 0x3d0d01}}}, + /* 15*16^13*G: */ + {{{0x0a4a8daa, 0x1db1db15, 0x029728f4, 0x00c01de5, 0x0968ce51, 0x1ada47a5, 0x1a71d83a, 0x164d112e, 0x2bbe38}}, + {{0x1236e49b, 0x1043ba74, 0x1adb9f5f, 0x056749c7, 0x00850990, 0x1f7c8fcb, 0x0dbd78b3, 0x1ec01a76, 0xf85707}}} + }, + { + /* 1*16^14*G: */ + {{{0x02d32936, 0x187dbb89, 0x011fc070, 0x19a05c65, 0x17f38e40, 0x03e8a89e, 0x11f67db3, 0x0b2f0294, 0xc5440c}}, + {{0x07cabfd4, 0x1217d1ba, 0x19079766, 0x0da50c63, 0x0f4acd8a, 0x0f0e91f6, 0x1e9cbb70, 0x174707c3, 0xd27ee9}}}, + /* 3*16^14*G: */ + {{{0x1989a8e1, 0x0c280f63, 0x1b92f75f, 0x1b2de6e9, 0x0fe0a7c1, 0x1023cdce, 0x1e6dd403, 0x188b9bf4, 0x3e4d03}}, + {{0x041c240a, 0x03c89c42, 0x0f59d026, 0x1e31abe7, 0x0a719ffa, 0x0be56be5, 0x11d6ab04, 0x1a102b4c, 0x12f744}}}, + /* 5*16^14*G: */ + {{{0x19bb7902, 0x09cd4686, 0x0df1cfda, 0x04d8e50d, 0x05e9fd8c, 0x124f4a24, 0x00d66a68, 0x09367ac2, 0x1b684}}, + {{0x003ee653, 0x0bfa258f, 0x00d9a0b3, 0x164c08e3, 0x11581fce, 0x0c72e1b6, 0x10f82fc6, 0x143d26f3, 0xe59063}}}, + /* 7*16^14*G: */ + {{{0x0371d9fe, 0x14dab6a6, 0x0675aef0, 0x166ad833, 0x13a4cf04, 0x0ad3e1d5, 0x1288cd65, 0x16359993, 0x952c3c}}, + {{0x0189a13f, 0x1b673692, 0x0231d7b5, 0x08c9e230, 0x0e5d0664, 0x089b7b76, 0x1c1a9f7e, 0x08defac5, 0x59b985}}}, + /* 9*16^14*G: */ + {{{0x0bc2c885, 0x03ffe3b4, 0x19395f21, 0x03dceea4, 0x1cde5155, 0x002285cb, 0x1ab21626, 0x1c2b62cd, 0xdfcb4e}}, + {{0x1345d92e, 0x0ea53218, 0x0afa5d5d, 0x0e7128f7, 0x00f411c7, 0x1e136416, 0x0e854f13, 0x12aaa0c2, 0x536a23}}}, + /* 11*16^14*G: */ + {{{0x1510208e, 0x1c5c295f, 0x15e50e1c, 0x199c5b09, 0x097bbdb8, 0x179d023e, 0x00322a1e, 0x18137cca, 0x157966}}, + {{0x0d207357, 0x10777128, 0x1690f7f5, 0x1f8c8865, 0x0be07008, 0x1bdbddc6, 0x193aaf7f, 0x0b56e244, 0x40446d}}}, + /* 13*16^14*G: */ + {{{0x0b96fe13, 0x04fe65f4, 0x014baa07, 0x0495a769, 0x16e23e49, 0x147fc09f, 0x042b5b86, 0x078963d3, 0xc6b21e}}, + {{0x17bb1417, 0x0035cb57, 0x19b4b5a8, 0x0aa122f3, 0x128a2ff6, 0x1c0f1a75, 0x1523952d, 0x1b186669, 0x335bcd}}}, + /* 15*16^14*G: */ + {{{0x03936565, 0x1b2c0cd6, 0x1fe931f0, 0x0f66db2e, 0x122d997a, 0x054ea9ca, 0x05bc2d2f, 0x188f18e5, 0xa231e4}}, + {{0x15ec5f19, 0x172b5031, 0x1c5509a2, 0x0adc012d, 0x1cf942ba, 0x07634401, 0x1a470365, 0x117d8ff7, 0x80e0c9}}} + }, + { + /* 1*16^15*G: */ + {{{0x1066fd48, 0x1cfa0b95, 0x05c560ef, 0x0e203971, 0x0dca61c3, 0x0dcbd35d, 0x07141b1e, 0x0f4844fe, 0x241c56}}, + {{0x12857b08, 0x1be9633c, 0x08d9815f, 0x10e2715d, 0x003a48ea, 0x00be0219, 0x152e4d8e, 0x127a8605, 0x40a62d}}}, + /* 3*16^15*G: */ + {{{0x0df9591d, 0x10fbedc8, 0x0d320aa1, 0x18758485, 0x07218dce, 0x09e25599, 0x03a72e83, 0x07704d2f, 0xde2fd2}}, + {{0x0457ad84, 0x070cb9e8, 0x100da92d, 0x15143f11, 0x12ebbda9, 0x1bf6425c, 0x0fcc17b2, 0x02676c48, 0x400d71}}}, + /* 5*16^15*G: */ + {{{0x1562282c, 0x15412a57, 0x1ef0ddcb, 0x1e75f271, 0x11340f02, 0x04581270, 0x0f7664e5, 0x16060999, 0x8df889}}, + {{0x01d195cd, 0x12b55ecb, 0x1e6ec55c, 0x1ee0899d, 0x0f35e247, 0x0f318c45, 0x1bb5b1d0, 0x0ce640b9, 0x74525b}}}, + /* 7*16^15*G: */ + {{{0x0dddb2dd, 0x0ea944a8, 0x0b0369be, 0x10c99b98, 0x0f245078, 0x1c0678a9, 0x03e0007e, 0x119b3170, 0xa0fd75}}, + {{0x13ede6b2, 0x1eca7fc3, 0x10269f1f, 0x19d2df12, 0x08f311c8, 0x0fe989d8, 0x0357e1a4, 0x06b8266d, 0x53e5d8}}}, + /* 9*16^15*G: */ + {{{0x0f542e36, 0x0465d502, 0x0d0570b8, 0x05ff5f42, 0x135d84e2, 0x0933ca31, 0x03d9f796, 0x108e5a34, 0x3170c5}}, + {{0x163288b5, 0x1623ad77, 0x066f86f1, 0x1eead2b3, 0x1773d006, 0x0849ff5c, 0x1f88dd45, 0x025f874f, 0xb20836}}}, + /* 11*16^15*G: */ + {{{0x1c7548e9, 0x0cd91d2e, 0x04b5531e, 0x1b500e11, 0x03fe5d8d, 0x00b4a783, 0x180a76d2, 0x152145a7, 0x92fab0}}, + {{0x0917758f, 0x03896682, 0x0b421223, 0x01b8d1de, 0x079ffc8a, 0x18a70613, 0x1af3d0c5, 0x0d019648, 0x55e7b4}}}, + /* 13*16^15*G: */ + {{{0x1498f7f8, 0x06c0285c, 0x104588b8, 0x1ecfa64c, 0x08712c4d, 0x108d8c96, 0x145e742f, 0x17c3006a, 0x91b065}}, + {{0x1f23195b, 0x03a06cf1, 0x0258e78f, 0x18f684af, 0x1e264df2, 0x19a4800b, 0x1883fe7f, 0x0eff6ce2, 0x35b6f}}}, + /* 15*16^15*G: */ + {{{0x0060e322, 0x0ee5f712, 0x113452d4, 0x1b8e6f53, 0x0b9923ec, 0x034ba44d, 0x0cea70e4, 0x09995939, 0x8e4a1f}}, + {{0x104619d7, 0x110c1e6c, 0x13eff813, 0x01531b2a, 0x07bc4fb0, 0x0f692037, 0x1dd4bec1, 0x0bd6651a, 0x4936b7}}} + }, + { + /* 1*16^16*G: */ + {{{0x0e14db63, 0x073ae5a4, 0x1947dfa4, 0x1277555a, 0x025de294, 0x0c971937, 0x0a961249, 0x17850235, 0xfa822}}, + {{0x1f462ee7, 0x008922a2, 0x1fa0bd79, 0x034ca0a1, 0x1188b34b, 0x0a5e59ef, 0x0035bd2b, 0x1d1ebb75, 0xbff44a}}}, + /* 3*16^16*G: */ + {{{0x1db3cdec, 0x096229fb, 0x0a3afd5d, 0x1e742564, 0x04bc8dbe, 0x122f3df5, 0x1d739659, 0x0c9ff225, 0x85b2c0}}, + {{0x0a03f81f, 0x1a684102, 0x133e3823, 0x101669cc, 0x06d00dc9, 0x1d1697e6, 0x14d98f1f, 0x11e73a22, 0xf64b27}}}, + /* 5*16^16*G: */ + {{{0x0607b030, 0x0452d724, 0x01359cca, 0x15fec7cb, 0x0f29c24d, 0x1dd6760b, 0x119de147, 0x0ed88042, 0x110b03}}, + {{0x13617c3a, 0x01d50895, 0x0a61d27d, 0x1c2aadf6, 0x1c70c87b, 0x1c4fc230, 0x19cd31ba, 0x10a631dc, 0x84432b}}}, + /* 7*16^16*G: */ + {{{0x15a76f08, 0x076ec0e3, 0x0efb5395, 0x0be4a717, 0x0aaf8329, 0x1092158e, 0x075c53db, 0x0893ec8e, 0x18784e}}, + {{0x0b824993, 0x19cb02eb, 0x02894c82, 0x1ae94f4c, 0x1e671fc9, 0x147ed638, 0x0b9c5dde, 0x0fe943c3, 0x8d76ed}}}, + /* 9*16^16*G: */ + {{{0x1a6fad81, 0x14719e4f, 0x032c0fb3, 0x06cae918, 0x0037d9c3, 0x16ebb81d, 0x1ae6bbd5, 0x1c0fa0bc, 0x58a2f9}}, + {{0x1b109594, 0x00030af1, 0x0c02e095, 0x1765a65a, 0x1a6bd798, 0x017c38bf, 0x038306da, 0x18b58aac, 0x6ab64}}}, + /* 11*16^16*G: */ + {{{0x1eb52583, 0x191788fc, 0x03304ebe, 0x15339d82, 0x1676fea8, 0x16dd93c7, 0x0e8903b9, 0x1b99cfd7, 0x1ef020}}, + {{0x1a3f17ae, 0x0d93c0cb, 0x04b532d5, 0x0601f2e0, 0x095306ac, 0x1607a5cb, 0x12c025fd, 0x164b4f42, 0x594476}}}, + /* 13*16^16*G: */ + {{{0x10a1958f, 0x0e11f60f, 0x0d5990ed, 0x136a48df, 0x1a32c4f3, 0x0a267d5f, 0x084e5774, 0x0c783ad4, 0x4e4a81}}, + {{0x08636f8a, 0x01d9fa8a, 0x110f59a9, 0x0810bf65, 0x06fa8400, 0x051f714e, 0x03440cfd, 0x0b6f3d19, 0x2574a4}}}, + /* 15*16^16*G: */ + {{{0x04935db5, 0x013ad423, 0x1af6c3ba, 0x0f304c38, 0x0519e281, 0x1f076aca, 0x04138cc9, 0x02d5bac2, 0xf6966a}}, + {{0x1d166838, 0x11a41b60, 0x006fc04e, 0x08a74688, 0x0755e2d7, 0x172b961e, 0x16cb0697, 0x00f52063, 0xba0de3}}} + }, + { + /* 1*16^17*G: */ + {{{0x176a6987, 0x07a0982d, 0x1690ffda, 0x10356887, 0x01b3f2b4, 0x14c46bf7, 0x0551f771, 0x1af53313, 0x54bc18}}, + {{0x1b9aae49, 0x122be682, 0x1cec467f, 0x171da976, 0x1e2fd52e, 0x1c28dd39, 0x0bcdce46, 0x02423cdd, 0x4b2c8c}}}, + /* 3*16^17*G: */ + {{{0x1d1fd820, 0x05fa3faf, 0x1d9d400e, 0x0f0a8c90, 0x1271b788, 0x08113158, 0x14aaa18d, 0x1ed01838, 0xbafbbc}}, + {{0x1bf074f0, 0x176d6a90, 0x07f2b5ba, 0x18694246, 0x1c0fde81, 0x1fad644d, 0x1604b39e, 0x0f93b69b, 0x148799}}}, + /* 5*16^17*G: */ + {{{0x14299b7e, 0x08b84094, 0x01b8343a, 0x0f3e5a13, 0x020ec24e, 0x1dfe3ae1, 0x07f8a8f0, 0x1ee20671, 0x9b1938}}, + {{0x047b84de, 0x0bd942ba, 0x1ae08cb1, 0x1bd0a3f0, 0x03ec90ac, 0x14c70e55, 0x0a0cc503, 0x0dde2e20, 0xfb12aa}}}, + /* 7*16^17*G: */ + {{{0x110cc4c4, 0x0a083a06, 0x094f683f, 0x1a6b4589, 0x01b2cb71, 0x0fee033b, 0x1641f0e0, 0x10b9802e, 0xa67719}}, + {{0x1c976570, 0x1079d91b, 0x1fcc2530, 0x08aee74d, 0x19c3dbc7, 0x0b300f2e, 0x1663ca6f, 0x10beea1b, 0x855061}}}, + /* 9*16^17*G: */ + {{{0x14242a28, 0x0084016a, 0x0f29dc55, 0x1796424a, 0x14eca455, 0x17bc25bb, 0x1f0427a2, 0x0a6d61d5, 0x88b7ed}}, + {{0x194ed8ce, 0x1cb40f63, 0x00f8d1fe, 0x0cd4391f, 0x1bd934e3, 0x1cee9ac3, 0x11791fef, 0x040c48a6, 0x22b053}}}, + /* 11*16^17*G: */ + {{{0x1bc1a94c, 0x0b0a2764, 0x1c76be00, 0x0e3a567c, 0x08757516, 0x1958112f, 0x0f4814b5, 0x002550d6, 0x37114}}, + {{0x0fc2073c, 0x00605b67, 0x110920e3, 0x03186c55, 0x05335c85, 0x10d2a568, 0x0e43be30, 0x07aa3bae, 0x4d1d69}}}, + /* 13*16^17*G: */ + {{{0x077f88ba, 0x1de8f04c, 0x06fb4dbb, 0x100ef3dd, 0x02cc3509, 0x11974275, 0x04f8d2d6, 0x09913085, 0xcc9821}}, + {{0x07885278, 0x123177e4, 0x0d531382, 0x0c1cfdde, 0x163abeff, 0x053233be, 0x1ea44531, 0x1d1ca4b5, 0x4ebb4}}}, + /* 15*16^17*G: */ + {{{0x1d70187c, 0x0b98ca6f, 0x19031fc5, 0x1590c536, 0x15bf8751, 0x12f01487, 0x043e6053, 0x00534854, 0xad3ae}}, + {{0x1fc775a7, 0x0ffe7a59, 0x18a83d9f, 0x09f6102c, 0x1b33dd03, 0x0af82fd5, 0x1b8de171, 0x1a8eb108, 0x2af040}}} + }, + { + /* 1*16^18*G: */ + {{{0x10aae231, 0x0557d68b, 0x1e5adf18, 0x0970a4f3, 0x1756f519, 0x0411c933, 0x0fca17c9, 0x0d32ec3c, 0x1d35c9}}, + {{0x0cd6ac71, 0x033831d6, 0x0699bc56, 0x0b1548e5, 0x1f810edf, 0x055b1175, 0x008c7598, 0x16c5bec1, 0xc7226c}}}, + /* 3*16^18*G: */ + {{{0x0cfa3fac, 0x1069ff0c, 0x0ae064f3, 0x1b0d3f86, 0x1803023a, 0x1da2eb06, 0x0d338b3a, 0x08f4da44, 0xdf3d40}}, + {{0x0fc7d419, 0x03136c9c, 0x020a5d7d, 0x0c79c92d, 0x19dbfafd, 0x10f94e07, 0x036c92a8, 0x0a453fa8, 0x48fa6f}}}, + /* 5*16^18*G: */ + {{{0x1f1322d4, 0x16c92d70, 0x13372eeb, 0x14d28095, 0x1f822cb0, 0x16265188, 0x0513a879, 0x0d563f2c, 0xdbb2af}}, + {{0x0a8c5311, 0x12495a7a, 0x1f8e97ea, 0x1f92f0f6, 0x13f9d9a9, 0x068f6b21, 0x186a86d8, 0x1725e26a, 0xebae75}}}, + /* 7*16^18*G: */ + {{{0x01138f7b, 0x034d19e5, 0x1cba3cbc, 0x03927c5b, 0x15f0bc4c, 0x05133fcd, 0x1f532bea, 0x0b2fe4c3, 0x1dba7b}}, + {{0x039bf268, 0x0416c63d, 0x008cb037, 0x0dcd6f33, 0x007f5813, 0x08035dc0, 0x1f18eb86, 0x07cbbcfd, 0x6aaf7d}}}, + /* 9*16^18*G: */ + {{{0x179a70af, 0x0d43bb80, 0x1937ca23, 0x1a853536, 0x105c6ec9, 0x1416afa9, 0x0674c6ef, 0x0884c4d2, 0x348a2e}}, + {{0x07b66e82, 0x142430a4, 0x184f96b2, 0x0f858b6f, 0x10105b2a, 0x1de70011, 0x1a0231d1, 0x0f3eab47, 0xa1b9fa}}}, + /* 11*16^18*G: */ + {{{0x04d3a201, 0x1a3b6bb6, 0x06e7bbf1, 0x124d49fb, 0x0df5f36e, 0x07dfc98d, 0x1872a1a9, 0x0a333393, 0x3a4ec8}}, + {{0x08635f89, 0x0c2cb7bb, 0x0f3556f7, 0x063cb5ee, 0x14a8b27d, 0x1e08d23b, 0x0b79a780, 0x1f05ec4c, 0xc99a2e}}}, + /* 13*16^18*G: */ + {{{0x1c978567, 0x17d7397e, 0x1707e607, 0x1b4d1081, 0x1f60be15, 0x1aeb17f8, 0x115e13a4, 0x1b10669a, 0xb1ba52}}, + {{0x162dc291, 0x1fd24151, 0x1f35029d, 0x08d96175, 0x1b78fd9a, 0x1e7b89ed, 0x0e9df17d, 0x18f50d28, 0xa46bae}}}, + /* 15*16^18*G: */ + {{{0x12350da1, 0x11477528, 0x1d7c10f4, 0x0298ef82, 0x12c2f194, 0x1bdcb4b0, 0x0bf49c62, 0x07b1de55, 0xae6eb}}, + {{0x10a14bc3, 0x19f04f9b, 0x10f692f1, 0x08d1e1da, 0x189b566d, 0x1a7bfe20, 0x12b8b740, 0x13f6c00d, 0x99cdee}}} + }, + { + /* 1*16^19*G: */ + {{{0x150e4f5f, 0x0b957543, 0x19f83995, 0x0b95354a, 0x0f29acbf, 0x187bd501, 0x0bbce23f, 0x0b30896b, 0x55d9a9}}, + {{0x1ca97db0, 0x02c75bb5, 0x0b46c572, 0x10218c67, 0x0ec524c9, 0x0ba7de64, 0x080dd9b5, 0x1354bb5a, 0x69cb7f}}}, + /* 3*16^19*G: */ + {{{0x1eb142e9, 0x0354c43f, 0x01ff3ef0, 0x0dd60c8c, 0x0d480c17, 0x0341c7d7, 0x1845e536, 0x1d7c8de7, 0x4b0043}}, + {{0x02c68552, 0x0596296b, 0x04962201, 0x06521e74, 0x02d870f2, 0x04231b11, 0x106b6c5e, 0x047461b5, 0x173ccf}}}, + /* 5*16^19*G: */ + {{{0x17f1aa96, 0x16ea5738, 0x1fd9207d, 0x0f4bee69, 0x063c513d, 0x06e5db9a, 0x1f08c9ca, 0x0f3255ad, 0x79ead2}}, + {{0x0b0a3fb7, 0x05d38e72, 0x0ce556a0, 0x09ae2223, 0x16542de8, 0x01c9ab12, 0x0afc69b9, 0x19ff755b, 0xa95de9}}}, + /* 7*16^19*G: */ + {{{0x193a9ae6, 0x002e5397, 0x1dfe2b72, 0x01540b38, 0x1743f8ee, 0x0f1b18d6, 0x073ad49e, 0x0a1e49b4, 0x318e00}}, + {{0x1c447d79, 0x025ab4a6, 0x14ea3b86, 0x06dfb75d, 0x04bd0945, 0x1e528f28, 0x0a67d345, 0x022339d2, 0x2792ee}}}, + /* 9*16^19*G: */ + {{{0x1d30585a, 0x1bca2da6, 0x14052544, 0x1f143546, 0x0a4b495f, 0x197a4860, 0x10eee200, 0x0e3a5e3c, 0x6bbc54}}, + {{0x148b05f3, 0x17cbf779, 0x1e7ab65a, 0x00850205, 0x026be09f, 0x1158af91, 0x07c12a7b, 0x136182a5, 0x467b18}}}, + /* 11*16^19*G: */ + {{{0x00136275, 0x1127c046, 0x01dd4d49, 0x0f8002e7, 0x00d78a64, 0x0d487bbb, 0x144626d4, 0x18c2183f, 0x940148}}, + {{0x1997aa47, 0x0b1d088a, 0x13869097, 0x1675cac0, 0x1d6695d4, 0x06255a82, 0x13ddea89, 0x0be26cf4, 0x6967f9}}}, + /* 13*16^19*G: */ + {{{0x1f0fe850, 0x1d09ee9c, 0x0469ef70, 0x1a4617ca, 0x1f98e864, 0x164946d2, 0x127246d5, 0x124c0736, 0xc41833}}, + {{0x1d38666d, 0x1ac7a235, 0x0682bc04, 0x14fd93c0, 0x1d558065, 0x0aea1357, 0x1debae02, 0x19391a81, 0x3537fe}}}, + /* 15*16^19*G: */ + {{{0x14937fbe, 0x1f2209bb, 0x146e9bb3, 0x009bbbe0, 0x0f546c0b, 0x0000d7cb, 0x15c38305, 0x1ec4f8cf, 0x2baba3}}, + {{0x173a1df4, 0x1c872aba, 0x0b204424, 0x1b896321, 0x0abc9ec2, 0x1866c927, 0x0e235e0e, 0x0cb64411, 0x77e5c7}}} + }, + { + /* 1*16^20*G: */ + {{{0x0351964c, 0x069e96f2, 0x1504b075, 0x12486ede, 0x15c08346, 0x1e50c2ba, 0x11feb96a, 0x0b37c518, 0x6e29f9}}, + {{0x163fd88f, 0x0c4125ea, 0x02fed8c4, 0x0818a4f4, 0x0246def6, 0x163660c2, 0x0bd9414b, 0x13ea01e6, 0x34565d}}}, + /* 3*16^20*G: */ + {{{0x0c0e49cc, 0x1ca8081c, 0x1150034f, 0x065b50b7, 0x140ed412, 0x046f65db, 0x1dbb760a, 0x152f12e1, 0xd691d4}}, + {{0x100f4152, 0x085da60e, 0x1410fcb7, 0x17c3a055, 0x00c52ac5, 0x1edabb1f, 0x0e5fdfee, 0x10e96f1e, 0x7a79e7}}}, + /* 5*16^20*G: */ + {{{0x0b9b930a, 0x0c3b5cf9, 0x0c3d63cf, 0x026a548a, 0x1bc49deb, 0x1befbd3d, 0x1f177b96, 0x08d45c1a, 0x2a5d68}}, + {{0x1b2caeca, 0x17f9a2f9, 0x09c5a161, 0x16e686bc, 0x0ab58ea5, 0x181c81e2, 0x1db79733, 0x012d0ec8, 0xdc3d7c}}}, + /* 7*16^20*G: */ + {{{0x016959ef, 0x13ee5e94, 0x076d66be, 0x13a0ace8, 0x15df8767, 0x18a09713, 0x1498bc10, 0x0d471376, 0x876449}}, + {{0x00cd5010, 0x10188e5f, 0x1e78fc59, 0x0d5a82e5, 0x1961f285, 0x0093cb76, 0x1ff6782d, 0x1ac3a005, 0x599b69}}}, + /* 9*16^20*G: */ + {{{0x1aef0f84, 0x1ca04e71, 0x071d6e58, 0x16a0d50e, 0x1b8cab0b, 0x1fd60bd6, 0x06c4cf78, 0x1790248e, 0x94d393}}, + {{0x178ba7c1, 0x0d730dc9, 0x0b3c4aa1, 0x1e804ca1, 0x19a07dd3, 0x1e1c3591, 0x0fc87872, 0x169d696c, 0x5a826a}}}, + /* 11*16^20*G: */ + {{{0x0ffed1b7, 0x0a2abc27, 0x12a8ed3b, 0x17a24cac, 0x0bd2ee2d, 0x04b8169a, 0x18b745d4, 0x141113c9, 0x4a72b5}}, + {{0x1601dc5f, 0x0f94fec4, 0x1366116d, 0x0c971d8e, 0x0ea9685e, 0x1fe023e4, 0x038b230c, 0x1d4943a4, 0x3531e6}}}, + /* 13*16^20*G: */ + {{{0x10467317, 0x1021f92e, 0x16461a80, 0x03b883b1, 0x07900914, 0x13797d6f, 0x18569e19, 0x1f8b46e3, 0xd7f01c}}, + {{0x0f7d014e, 0x05cabeae, 0x1fef6257, 0x002e86d2, 0x1ef5728a, 0x10a0360a, 0x109bb1cd, 0x1b30ee4d, 0x888dbb}}}, + /* 15*16^20*G: */ + {{{0x1dea02c1, 0x1ebac853, 0x1d021f0e, 0x17736f8e, 0x11206e4f, 0x1fcec8f1, 0x1c6efa02, 0x173eef86, 0x7e50a0}}, + {{0x0d45c201, 0x1e4a36ff, 0x0386ca0c, 0x07269e2b, 0x19517742, 0x178eedc5, 0x0a7185b1, 0x0789c1fc, 0xc3405d}}} + }, + { + /* 1*16^21*G: */ + {{{0x0cb71280, 0x053ea088, 0x1158c44a, 0x0384b350, 0x1458ec14, 0x17783cb7, 0x1b67003c, 0x13d657fd, 0xff046a}}, + {{0x1ec33919, 0x161938fa, 0x0a121e9f, 0x16dcdd7a, 0x0fcc9012, 0x16edeea6, 0x085c2807, 0x159812a7, 0x432f55}}}, + /* 3*16^21*G: */ + {{{0x13ca3ce3, 0x193c1551, 0x1a9df897, 0x1630cb56, 0x0231fef2, 0x1e0fa989, 0x134c6a56, 0x0ba29a7b, 0xf717c4}}, + {{0x10ed88e9, 0x04a666da, 0x05db7c1a, 0x07c57bb8, 0x1ee55af5, 0x0a768556, 0x04b72a6d, 0x0ed1932a, 0x422c40}}}, + /* 5*16^21*G: */ + {{{0x1b28cd88, 0x1b42186a, 0x0a6f66b0, 0x1c12ea05, 0x1b32c738, 0x1ab13fc8, 0x0c830bfa, 0x169e66e1, 0x60e269}}, + {{0x0be2066c, 0x14dd4521, 0x1211ac38, 0x0ac2718d, 0x0df76024, 0x08c44b94, 0x02a58248, 0x0b4caf3e, 0xfe0017}}}, + /* 7*16^21*G: */ + {{{0x061cc594, 0x09d8c994, 0x1414dac5, 0x17ba2e09, 0x06855964, 0x1d02fe5a, 0x05242a96, 0x143cce73, 0x799297}}, + {{0x0f8d309e, 0x14888490, 0x0b1ba427, 0x150d5c17, 0x1e50127d, 0x088c3c4f, 0x06c3841a, 0x119aa479, 0x132ff1}}}, + /* 9*16^21*G: */ + {{{0x172d0aba, 0x04623d12, 0x1f86c5b7, 0x03215b8e, 0x1241dd8d, 0x0775aa80, 0x01c1e7b8, 0x09dfc850, 0x2d9be9}}, + {{0x11fa0876, 0x07b98fd9, 0x0dc439be, 0x038cf311, 0x1d91bbad, 0x1c9a5b0c, 0x0288a57b, 0x16bd3d13, 0xa9708d}}}, + /* 11*16^21*G: */ + {{{0x155e8732, 0x0603da41, 0x1b478c78, 0x0c5dbca0, 0x0c243cfa, 0x03298a49, 0x0859832f, 0x13d91048, 0x212703}}, + {{0x00cacc07, 0x0c91afa3, 0x15ef5a35, 0x07e7e775, 0x10a5cd69, 0x1cedddbf, 0x16a80652, 0x0de475c6, 0x85219c}}}, + /* 13*16^21*G: */ + {{{0x12083347, 0x0489a067, 0x0694c898, 0x15c7ccee, 0x0b42b9e1, 0x07ad5d01, 0x03ae5eb4, 0x09657b1c, 0xfab5b5}}, + {{0x1d38fd2f, 0x0664e6c1, 0x09a6bea7, 0x1c6f4c2d, 0x03eafc05, 0x15791305, 0x0540f21e, 0x02c30da8, 0x5758d1}}}, + /* 15*16^21*G: */ + {{{0x1f572554, 0x1b3930a7, 0x1d36adcf, 0x085c8e31, 0x0a56ff38, 0x0b3b85bf, 0x1f295e42, 0x0ae4f2e3, 0x685d27}}, + {{0x00979e03, 0x18d7b685, 0x1d33292d, 0x15545581, 0x0377cc58, 0x0e4020f0, 0x17f01b8e, 0x18441568, 0xa82f89}}} + }, + { + /* 1*16^22*G: */ + {{{0x05852e50, 0x1e859266, 0x15c33171, 0x18fcc79e, 0x07eff8b2, 0x1511a4f7, 0x016307e6, 0x1bffd576, 0xe486c7}}, + {{0x0ecf107d, 0x15d1e56d, 0x04baf619, 0x08c7ac67, 0x1e05a694, 0x052e4fa8, 0x04ba7ba2, 0x1daac0d4, 0x51fd75}}}, + /* 3*16^22*G: */ + {{{0x1c881907, 0x1355322a, 0x002c76b1, 0x190ce6b6, 0x00415142, 0x02e63357, 0x0df25904, 0x1771c5ff, 0x4acf44}}, + {{0x163cdafc, 0x0935a2b7, 0x1612c94a, 0x0a565ef9, 0x05457993, 0x142d6885, 0x01ecd510, 0x1fc1ffab, 0xad99a8}}}, + /* 5*16^22*G: */ + {{{0x1439383f, 0x15d7034b, 0x0068aaa0, 0x1f4ac56c, 0x14eec34f, 0x11496411, 0x192775ea, 0x10683114, 0x4ddf22}}, + {{0x03d52337, 0x197d40c1, 0x07e09a58, 0x0ba08a26, 0x00c6b3dd, 0x174be9c6, 0x00f5d2ae, 0x0f61b231, 0xe71c62}}}, + /* 7*16^22*G: */ + {{{0x1822b4f4, 0x16e440aa, 0x1977e3c9, 0x0a75f9f0, 0x1f39ba53, 0x14f03cbd, 0x1e784cd3, 0x0f226f30, 0x58b065}}, + {{0x0c60fbca, 0x103d4108, 0x13949659, 0x0940edf8, 0x0836c1ca, 0x12af8131, 0x10dc09f2, 0x14828b45, 0x55a98a}}}, + /* 9*16^22*G: */ + {{{0x14fe39b0, 0x195e8861, 0x0d37b452, 0x02e79ae9, 0x01f358a3, 0x020e119c, 0x14a5d8e9, 0x0b14c966, 0xa345e0}}, + {{0x0baf79dc, 0x184a405d, 0x0da77d4d, 0x18d4eb56, 0x1d949ce8, 0x02ad947c, 0x1c3e47c2, 0x14dab954, 0x7c6dd5}}}, + /* 11*16^22*G: */ + {{{0x126695fb, 0x1df03dcc, 0x0eb7b84f, 0x01773fc8, 0x0ccb6afd, 0x05c3a36b, 0x0b20806b, 0x10603214, 0x3a10bf}}, + {{0x04eb7e47, 0x0ae39595, 0x1514a21d, 0x1fd4d887, 0x065c5f28, 0x1c243445, 0x1c55d880, 0x167d8344, 0xb5d585}}}, + /* 13*16^22*G: */ + {{{0x1d2c8614, 0x00d474b3, 0x16116589, 0x012c14c0, 0x12876a7b, 0x1ad61848, 0x10cf2973, 0x1f592020, 0x12fbdd}}, + {{0x18b0b174, 0x03bde0ea, 0x067d257c, 0x04b04738, 0x0cfb54d4, 0x08a14669, 0x01a0cff6, 0x1a5204f0, 0xa5ff20}}}, + /* 15*16^22*G: */ + {{{0x0d9aeeaf, 0x1fbb2181, 0x16bf2194, 0x00f29940, 0x19a3005d, 0x11d0fd7c, 0x01ddee2b, 0x0b34572f, 0x8bece8}}, + {{0x05f9eb5e, 0x0d06d1e4, 0x02603dd5, 0x04071edf, 0x1c368bb2, 0x0885877f, 0x07f3eee2, 0x1898a0ca, 0x35f933}}} + }, + { + /* 1*16^23*G: */ + {{{0x0b519178, 0x05b5c761, 0x0f47f161, 0x17333148, 0x0ee0ab63, 0x067c5af1, 0x10c33f82, 0x0976bca0, 0xf41d7f}}, + {{0x0a6a3551, 0x1d0b32ee, 0x06787e69, 0x135986d2, 0x02347ab4, 0x16f1fd54, 0x035bc411, 0x17d7b35f, 0xe6a669}}}, + /* 3*16^23*G: */ + {{{0x1e3501d9, 0x138989f0, 0x187f22c6, 0x1059c376, 0x13e611be, 0x0b48eb16, 0x19fccccb, 0x0fdac5a9, 0xd65f82}}, + {{0x0b55759e, 0x1ca23637, 0x1cc2f86a, 0x02755aba, 0x187fc61c, 0x1e528b35, 0x03f94ded, 0x1f9e1352, 0xf24b60}}}, + /* 5*16^23*G: */ + {{{0x0f2ed84e, 0x1b17f120, 0x18ba84b2, 0x129be6bf, 0x0c0ade79, 0x045abc16, 0x10e17b9b, 0x16dbd60b, 0x55a9b5}}, + {{0x146495a3, 0x1cee2a82, 0x08363c15, 0x1f69ae25, 0x1f43ae8f, 0x068c876b, 0x06aca45d, 0x12d593e3, 0xc4f221}}}, + /* 7*16^23*G: */ + {{{0x075495a2, 0x1e967c38, 0x0f002ca6, 0x1c3d6c91, 0x08bc49fd, 0x0b05312a, 0x07687dfb, 0x0db8fb6e, 0x79de57}}, + {{0x0aec6fb8, 0x01646355, 0x04e9d1a0, 0x09ea12c9, 0x079c6831, 0x16d723ee, 0x0809e179, 0x01cd630d, 0x3b2d3d}}}, + /* 9*16^23*G: */ + {{{0x02d1e7bb, 0x17495664, 0x0465933b, 0x07ff206a, 0x1e55524c, 0x19b4acab, 0x12db8992, 0x0642c480, 0x8fe04e}}, + {{0x1a62e84f, 0x13acd686, 0x011aa336, 0x02c8c8de, 0x1b34e5b9, 0x0752bd46, 0x163f975b, 0x0a045ec6, 0x3987db}}}, + /* 11*16^23*G: */ + {{{0x09f7c360, 0x00d25763, 0x00217084, 0x19aaefc9, 0x024e24ef, 0x0531b469, 0x03c542a5, 0x012afdbf, 0x3af499}}, + {{0x087d7a7b, 0x1cee1553, 0x18225734, 0x0a9bac4e, 0x13c33485, 0x03241739, 0x04754c7e, 0x061a763b, 0xd17060}}}, + /* 13*16^23*G: */ + {{{0x170373be, 0x0d291d73, 0x18f4ed4e, 0x1a0c4424, 0x07c4e213, 0x0179ff11, 0x01db0696, 0x0b8c4790, 0x31a7e0}}, + {{0x090950a8, 0x16bc3c87, 0x08950c23, 0x105732a3, 0x1db1e8ce, 0x05571a11, 0x199c086c, 0x1e7f1a3b, 0xc23d2e}}}, + /* 15*16^23*G: */ + {{{0x0b923b45, 0x0130876e, 0x0f892f6d, 0x153f7fe2, 0x18458a33, 0x09a316ec, 0x08fb4554, 0x09026ada, 0x740a66}}, + {{0x11ecaa5f, 0x0609f1c2, 0x121202ea, 0x0f32720f, 0x006cfa89, 0x03c453ab, 0x08fcbd39, 0x1184b9aa, 0x7f6d04}}} + }, + { + /* 1*16^24*G: */ + {{{0x1512218e, 0x025549cb, 0x1280506a, 0x0a4360e9, 0x0e902e9a, 0x059d0c51, 0x1e995e20, 0x0cc254ce, 0x4a5b50}}, + {{0x0c4f3840, 0x1f56d3d2, 0x189b6742, 0x1b62a833, 0x07d40626, 0x027df0b1, 0x07c71098, 0x039d5811, 0xeb1346}}}, + /* 3*16^24*G: */ + {{{0x118473fd, 0x177a0712, 0x05cce454, 0x1204d78d, 0x0a9e3bbb, 0x155ccb94, 0x0e8214a4, 0x06466631, 0x106406}}, + {{0x185cf805, 0x1d30b173, 0x08740e6b, 0x1c321a18, 0x1883ccfb, 0x014f32c2, 0x0b63239e, 0x10477174, 0x9c6832}}}, + /* 5*16^24*G: */ + {{{0x053f30f3, 0x0b3f7643, 0x088e374d, 0x047da5db, 0x03f212b4, 0x0086aa04, 0x1efd7b69, 0x11fe0be4, 0x38c8ad}}, + {{0x0be9217b, 0x03073a4f, 0x1677cde8, 0x07f53052, 0x1641f658, 0x0b2a6ede, 0x045bce42, 0x0f0edb96, 0x83c261}}}, + /* 7*16^24*G: */ + {{{0x16ef1584, 0x01f3488d, 0x04832fd5, 0x1345471f, 0x1184277a, 0x1df1fe9a, 0x0c256163, 0x179d0c17, 0x6fcb8c}}, + {{0x1d3110f2, 0x1e4fbe10, 0x0290c970, 0x05edad25, 0x0459d599, 0x0411d618, 0x15db5530, 0x07b16e43, 0xa8f1a8}}}, + /* 9*16^24*G: */ + {{{0x062255ef, 0x07a89a02, 0x1901e33a, 0x0e3a68ce, 0x1b0ee50d, 0x0e486f22, 0x0af5cd45, 0x1727eedc, 0x7811d0}}, + {{0x1be3252e, 0x0c5f7cd8, 0x150dda29, 0x1da0a275, 0x05132f51, 0x174a00dc, 0x11e95300, 0x06e176b5, 0x99bb76}}}, + /* 11*16^24*G: */ + {{{0x153d2ea7, 0x1f088789, 0x1ea19424, 0x1a104747, 0x16f2a9ee, 0x194eafc0, 0x033831ed, 0x1289516a, 0xc3583d}}, + {{0x0b667bbd, 0x18c1f4f0, 0x17c710ca, 0x124b4ca2, 0x1cccdd6c, 0x113f7c4f, 0x043d6591, 0x1812723d, 0x53967a}}}, + /* 13*16^24*G: */ + {{{0x102e3099, 0x16ef8702, 0x01005963, 0x04274cc5, 0x0d00d53f, 0x180c5dbd, 0x1407ce83, 0x05079bdc, 0xd591cf}}, + {{0x055ac5af, 0x1de13b2a, 0x045bf58c, 0x05dff116, 0x1c5825cf, 0x19869a85, 0x1b913944, 0x19f88f1c, 0x87ebe5}}}, + /* 15*16^24*G: */ + {{{0x12a940a5, 0x1932b231, 0x0539ac4a, 0x06bd6b48, 0x1e8714a4, 0x00f0d27c, 0x17130049, 0x0c25e646, 0xa0aa0d}}, + {{0x0b950422, 0x1fc41534, 0x146fe4e4, 0x1239bb4f, 0x01f3e6c6, 0x067cd00c, 0x10a066cd, 0x174edeec, 0x22340e}}} + }, + { + /* 1*16^25*G: */ + {{{0x008e2df0, 0x1146c1b8, 0x0a397dd9, 0x0764ae86, 0x00f5032c, 0x14efc5df, 0x065404b0, 0x017bc557, 0x2eb391}}, + {{0x1274eaae, 0x08866276, 0x1d97d242, 0x01a241d9, 0x0999f954, 0x1e9a46d2, 0x0ce9df4d, 0x0466e8e9, 0x3f29c0}}}, + /* 3*16^25*G: */ + {{{0x082867f0, 0x1815c25b, 0x06428e6f, 0x084dc436, 0x100f0a21, 0x08b53c04, 0x1388aaaf, 0x111cc98f, 0xf6e9db}}, + {{0x0f1861ea, 0x1ad9d788, 0x1c2d88d1, 0x08374bf2, 0x0d5b1270, 0x1dbb7460, 0x0dd20764, 0x016f5a55, 0x53ca79}}}, + /* 5*16^25*G: */ + {{{0x120d6102, 0x16e821c7, 0x114e5026, 0x1aa6f146, 0x19a5ef06, 0x0adcdb0c, 0x1275e170, 0x070ec1c8, 0xfd1ddb}}, + {{0x0e003b7c, 0x1053248d, 0x144e60f6, 0x1c322422, 0x1b700163, 0x0f8fbc41, 0x0e2bb6a8, 0x0e720a0c, 0xcb54b8}}}, + /* 7*16^25*G: */ + {{{0x02c77cb7, 0x1fb9a0ee, 0x17056dbc, 0x1b281205, 0x0698fef6, 0x139f32f7, 0x00767f92, 0x1844b332, 0x61a273}}, + {{0x1ddb25ed, 0x0a308fc0, 0x0b87dd21, 0x0b5b34e1, 0x10cc9c5c, 0x10cfaf75, 0x0f4fd3a8, 0x0669a75a, 0x5bbacd}}}, + /* 9*16^25*G: */ + {{{0x177d8976, 0x0cc6ab71, 0x03ca4b6e, 0x0e7471c6, 0x104b55e1, 0x164c114e, 0x06d932c0, 0x0cbdeec0, 0xcd2e8e}}, + {{0x0867bc22, 0x0b4b7a0e, 0x10a30144, 0x1dbc1e6a, 0x0ff68f60, 0x074796a3, 0x0c7ff0c7, 0x06c46854, 0xf58ead}}}, + /* 11*16^25*G: */ + {{{0x0c67c998, 0x04d98361, 0x13c6e198, 0x160fd547, 0x04c259a9, 0x0f545218, 0x1bed0089, 0x13870447, 0x9bd61f}}, + {{0x08199514, 0x1a057ce1, 0x1092c630, 0x1b383d20, 0x050fa927, 0x104b4b4a, 0x1d71723c, 0x01322d8d, 0x77b204}}}, + /* 13*16^25*G: */ + {{{0x0aafa568, 0x122f0bdf, 0x07889d9a, 0x1af52ee0, 0x1a016b4c, 0x13d2088b, 0x1dd44ab8, 0x09ef2e0e, 0x7afaeb}}, + {{0x01c1f2df, 0x16a9d17c, 0x14e408cf, 0x1cd28653, 0x1365a972, 0x0a09a820, 0x09f62574, 0x03267f7a, 0xc6efe6}}}, + /* 15*16^25*G: */ + {{{0x0e59ddeb, 0x1f381f28, 0x07a62a2d, 0x1cc5395a, 0x10c3b483, 0x0a60a4b5, 0x0be41876, 0x044fc482, 0xd9a002}}, + {{0x0f0af5a4, 0x19c9ffc0, 0x17c63397, 0x05517956, 0x10581856, 0x07c521b3, 0x08b10f18, 0x1f276f40, 0x975eb2}}} + }, + { + /* 1*16^26*G: */ + {{{0x1ecca7e0, 0x19cd2f51, 0x10cccfb1, 0x05931ece, 0x19428a7d, 0x119a9126, 0x08303fbd, 0x078b8f25, 0x7ef2ee}}, + {{0x152ac094, 0x015916ea, 0x0f4f480c, 0x0428a1bf, 0x009db81b, 0x1fa8eaf3, 0x004693d9, 0x04e61598, 0xafb686}}}, + /* 3*16^26*G: */ + {{{0x033f0ffa, 0x179ac1ed, 0x001e905c, 0x09958c23, 0x1c641cae, 0x12bb64ec, 0x0b35d892, 0x04e2d10f, 0x370457}}, + {{0x00fa35ac, 0x1f69fe33, 0x02fcbf17, 0x147d6f55, 0x1ff4c57b, 0x1a5dc44a, 0x1d3e106e, 0x18c34e3c, 0x5c6408}}}, + /* 5*16^26*G: */ + {{{0x12603513, 0x037cc329, 0x1280254f, 0x0c9b8d02, 0x1b697f6c, 0x15216045, 0x0dc8b47a, 0x1ca8531b, 0xc2a979}}, + {{0x1c3505b9, 0x0baad961, 0x05451265, 0x0ccdbe90, 0x1ce7e8cc, 0x0040c9ad, 0x1721509e, 0x0943cdd6, 0xef9dd7}}}, + /* 7*16^26*G: */ + {{{0x19fdee3e, 0x1237fd8e, 0x0c0b8079, 0x1f2ee2d8, 0x1afb9681, 0x18ae6d8b, 0x07845cae, 0x0d563f8b, 0xc9f418}}, + {{0x0ced22e7, 0x0f33662e, 0x1637d3d4, 0x02a638f6, 0x1214344e, 0x18a15c41, 0x0d0437dc, 0x0fe79674, 0x9420a}}}, + /* 9*16^26*G: */ + {{{0x0814f217, 0x0659f33a, 0x15b3febc, 0x147ef70e, 0x1b6a4a9d, 0x00127c1d, 0x095ac228, 0x0b700900, 0x27dcf5}}, + {{0x0cf2ed4c, 0x064a5ac4, 0x07f0efc5, 0x1d1f5632, 0x02a380a4, 0x1d584a50, 0x17b82f22, 0x09ea91ab, 0xbe18f5}}}, + /* 11*16^26*G: */ + {{{0x1b9e310c, 0x0d1527ea, 0x133f529d, 0x19cb7370, 0x19187313, 0x125619ca, 0x092e7234, 0x00764add, 0x3b8b02}}, + {{0x0d19fc9b, 0x0a0b302d, 0x0cc160e6, 0x1f009705, 0x117a6a8f, 0x171bbe20, 0x056f585d, 0x09d6066c, 0x91117c}}}, + /* 13*16^26*G: */ + {{{0x07615b36, 0x18f0f15d, 0x1cf057e3, 0x1fe3d18f, 0x0c3372a4, 0x12037c8a, 0x00e84170, 0x118b7982, 0xa5e739}}, + {{0x09136d80, 0x0cc171ca, 0x0d84f013, 0x1f8326e1, 0x1f8c547f, 0x06f7950a, 0x1339190e, 0x11b92e9c, 0x1f3ff5}}}, + /* 15*16^26*G: */ + {{{0x0d3e10db, 0x1bd82197, 0x0e1c566e, 0x065c3591, 0x161fa477, 0x021ffa75, 0x0caf7b81, 0x06ab592a, 0xaad218}}, + {{0x0fa05fb3, 0x1a9ad5eb, 0x072e89d8, 0x064ee566, 0x18b4a720, 0x0f147eaf, 0x18ece9f7, 0x1dd75f05, 0x793b1e}}} + }, + { + /* 1*16^27*G: */ + {{{0x0c49e853, 0x180f8487, 0x1d781299, 0x16a6a532, 0x1a77aa9c, 0x12aa75af, 0x0bad5e00, 0x0c842c81, 0xe5141}}, + {{0x16405cb2, 0x1b71e89b, 0x127b8d8c, 0x10728321, 0x1030df56, 0x1a529d48, 0x11a49e3a, 0x1d4cb20a, 0xcf331c}}}, + /* 3*16^27*G: */ + {{{0x1dc6afad, 0x0511f8e0, 0x1e03d1b1, 0x07b2452b, 0x0c6771bd, 0x092fb260, 0x1c977a3b, 0x0cecb959, 0x977ba0}}, + {{0x1d7faa09, 0x0b166e28, 0x16868553, 0x0b42483b, 0x1d9992f7, 0x1d506840, 0x1e8a20cf, 0x0875db71, 0x1bc3bc}}}, + /* 5*16^27*G: */ + {{{0x1d81983b, 0x0fba2ebe, 0x03aade19, 0x041fa05f, 0x1facc102, 0x1b03b8ff, 0x0af930f2, 0x0c254247, 0x3bc328}}, + {{0x11a637b6, 0x0ccf9428, 0x0ee1236f, 0x0910b51f, 0x00a7f433, 0x182e5578, 0x0880942c, 0x0dbda191, 0xa6b582}}}, + /* 7*16^27*G: */ + {{{0x17c8537b, 0x0fbb60ff, 0x07e0185d, 0x19596e88, 0x16c21ca8, 0x17f0e57c, 0x12b146eb, 0x1d1d3d80, 0x67cba4}}, + {{0x185726da, 0x075a82b9, 0x100fdb87, 0x1e087da0, 0x1cc047bd, 0x030f97d8, 0x06128787, 0x1dbd4391, 0x5b65ed}}}, + /* 9*16^27*G: */ + {{{0x0b6a1226, 0x14114672, 0x15194e4d, 0x13d39156, 0x0f3922af, 0x1eb43234, 0x064c681c, 0x14daae93, 0xc5958e}}, + {{0x066961d4, 0x00803446, 0x08422e47, 0x0edb7d74, 0x1bd82968, 0x0cb8cea2, 0x175fb2f8, 0x105ee1ef, 0xa031a8}}}, + /* 11*16^27*G: */ + {{{0x13713a52, 0x06f1fc2d, 0x0f1505f9, 0x0eb718d0, 0x05fa025c, 0x0061e3a5, 0x129f07f3, 0x1f05c84b, 0x83f07b}}, + {{0x1fb0ffb6, 0x088939fc, 0x1ed174a8, 0x0b6ec1c3, 0x1d3cfcab, 0x0a648963, 0x0ee4125e, 0x02144b71, 0xf2ec4f}}}, + /* 13*16^27*G: */ + {{{0x01ba21b0, 0x16cd0489, 0x109954e6, 0x0bb1a401, 0x00076d85, 0x00343757, 0x0b539bda, 0x09f36b48, 0x938dba}}, + {{0x0d5b4325, 0x1a6ccaf2, 0x0ada5f0d, 0x0377dc7e, 0x0b90bcbf, 0x16dee89b, 0x1959ba6a, 0x15135eea, 0x48afc0}}}, + /* 15*16^27*G: */ + {{{0x1f2b24f1, 0x09f24d31, 0x19daf3ed, 0x1d8c9ebf, 0x09779cfa, 0x0d5679da, 0x079cea07, 0x16ed9406, 0x7efa89}}, + {{0x0f8e4b83, 0x12ee2ea5, 0x15291575, 0x15be758a, 0x0ab211db, 0x09117e0b, 0x1bfde33b, 0x1d8c3e95, 0xa99ff3}}} + }, + { + /* 1*16^28*G: */ + {{{0x02f2b734, 0x034cdfcf, 0x007499fc, 0x0776b6aa, 0x0445779c, 0x13c3788b, 0x066818d2, 0x0533dd99, 0x224a02}}, + {{0x11ec7fdf, 0x007ac2a4, 0x11ebf421, 0x0e096ce7, 0x17fff07b, 0x0456c38e, 0x0ad05268, 0x1a536da4, 0xfa41a8}}}, + /* 3*16^28*G: */ + {{{0x1d254033, 0x0f497a3a, 0x091c1eb2, 0x0d050185, 0x0f240783, 0x0fd3445b, 0x1167f36b, 0x1dc2a79d, 0xe63502}}, + {{0x08f05e3f, 0x1455444b, 0x1f3cd81f, 0x02b41897, 0x1ce482c9, 0x14078384, 0x1846b5d3, 0x0f63ec43, 0xa7c583}}}, + /* 5*16^28*G: */ + {{{0x01e08f33, 0x1cb04d7f, 0x060b328a, 0x1ac63b97, 0x000e2b1f, 0x02e299f8, 0x1a1c4aad, 0x184e5d72, 0x5648de}}, + {{0x0269f1c9, 0x1776cd62, 0x045e5449, 0x0577e5c0, 0x1a2693e7, 0x1ae326bb, 0x010fd1e3, 0x0e0e11ee, 0x95fddc}}}, + /* 7*16^28*G: */ + {{{0x1ab98c43, 0x1dc1005f, 0x0fa2a938, 0x14aeeafc, 0x08f03c5b, 0x17c765f6, 0x149a5454, 0x13e6701d, 0x1941c1}}, + {{0x02abe217, 0x1d1086d1, 0x17d58e63, 0x0c5a7b71, 0x18c53d8f, 0x0d95247d, 0x0adb8adb, 0x068b2bb6, 0x8e66b8}}}, + /* 9*16^28*G: */ + {{{0x02d8c2f4, 0x13386882, 0x07006279, 0x064373ef, 0x18a0bd73, 0x1def1b26, 0x0f59fe9c, 0x063a2169, 0xfc5864}}, + {{0x1cfd274a, 0x08c6447f, 0x10ce2d00, 0x05960bd7, 0x1b4ab29e, 0x013cf35e, 0x055928cf, 0x0a59d15b, 0x99fade}}}, + /* 11*16^28*G: */ + {{{0x11ff0f18, 0x1583bf8e, 0x12690b44, 0x0179ce0a, 0x0d6c207e, 0x1d67cd79, 0x077aa6fe, 0x14d6189e, 0xee993b}}, + {{0x050782ad, 0x009c3b65, 0x03cb2c60, 0x0b901bee, 0x1bcfeb43, 0x0eac6742, 0x0cb07db1, 0x1b28af1b, 0xd87fd4}}}, + /* 13*16^28*G: */ + {{{0x0fdde3fc, 0x03d3fbaa, 0x18a33279, 0x11113c0a, 0x131fbe5a, 0x0e20d297, 0x090a3683, 0x0f55d3fc, 0xba4951}}, + {{0x0fcb7d01, 0x1f7e9197, 0x0a4b2aa8, 0x1c3903c6, 0x1359adfd, 0x121bb009, 0x16542d3b, 0x1c39528a, 0xa88fb6}}}, + /* 15*16^28*G: */ + {{{0x1d14da68, 0x0449517b, 0x14805cde, 0x0983f09b, 0x012b54a6, 0x07c139bb, 0x06e9378b, 0x02e8455e, 0xd3398f}}, + {{0x15a90e3d, 0x183b18da, 0x10514e8f, 0x0f4f245a, 0x0b020afc, 0x0968f451, 0x1583adc9, 0x1a9a3fa7, 0xa34ad4}}} + }, + { + /* 1*16^29*G: */ + {{{0x1789b84d, 0x13032d6b, 0x010738ba, 0x1abdc9a2, 0x093fe167, 0x0888dab2, 0x0d3336d7, 0x028ae6e9, 0x4a89a6}}, + {{0x018e3ea8, 0x1cdbebf8, 0x1c46667b, 0x1c500c68, 0x077e6a72, 0x154bcff3, 0x1570230b, 0x10fda901, 0x45b04e}}}, + /* 3*16^29*G: */ + {{{0x02e14c34, 0x13b591ba, 0x0c9d64db, 0x18bd7c0e, 0x177c9834, 0x19873c09, 0x1e4a8aa6, 0x09150e1d, 0xcc9f96}}, + {{0x14be556b, 0x0490abd4, 0x031f8162, 0x122fe305, 0x089db299, 0x1319edf3, 0x05bd0c45, 0x0596bf19, 0x829bff}}}, + /* 5*16^29*G: */ + {{{0x15de4837, 0x1ef3642c, 0x1979d3a1, 0x050d905b, 0x18a758d4, 0x060e856c, 0x106bd3d6, 0x143f55a0, 0x5c618d}}, + {{0x034a7dee, 0x05c2c1db, 0x089e32b0, 0x06cc92c8, 0x19671ecd, 0x071c24fe, 0x067622e0, 0x02f79e74, 0x4c7191}}}, + /* 7*16^29*G: */ + {{{0x16635396, 0x0c49a132, 0x029b0309, 0x15c2b46d, 0x1c11ef2c, 0x116ef338, 0x1a8b9617, 0x0d522b40, 0xab8a88}}, + {{0x1fc92c23, 0x11c7d351, 0x14b5ab5f, 0x0c0b07ef, 0x0d5abb93, 0x1fc1245e, 0x0c6559a3, 0x0f8fb508, 0xe773cf}}}, + /* 9*16^29*G: */ + {{{0x01df49c3, 0x0121f2c4, 0x01a68d6b, 0x11210cda, 0x1604aa9e, 0x125c5b4a, 0x0e337b19, 0x0a284830, 0x62b7c8}}, + {{0x16341c21, 0x1f1b407f, 0x1f2d5426, 0x0a76c270, 0x122db8fb, 0x0b5746a4, 0x0cd56522, 0x042a55c0, 0xa71ed6}}}, + /* 11*16^29*G: */ + {{{0x044f47d0, 0x178a3717, 0x07c00bce, 0x13ebbd29, 0x1c9791b5, 0x0f8434ef, 0x0717e5d4, 0x17f48b91, 0x4897bd}}, + {{0x0e1320bf, 0x0f280d56, 0x1c046560, 0x1b400351, 0x1093f526, 0x1654a0bd, 0x0e30d3a3, 0x01ef5f82, 0xe77dc2}}}, + /* 13*16^29*G: */ + {{{0x11581bd3, 0x10de74db, 0x0641e1b9, 0x14631bec, 0x02f2ecbf, 0x103ded39, 0x15db1147, 0x16aac90c, 0xeb1cfc}}, + {{0x1cd98a09, 0x1e746cc2, 0x0f469916, 0x19e6338b, 0x16e3cb39, 0x002f5f26, 0x14814110, 0x0eae3f29, 0xfd47ce}}}, + /* 15*16^29*G: */ + {{{0x073a3111, 0x00915edb, 0x132063e4, 0x105c82f6, 0x176a018b, 0x05617392, 0x18270355, 0x177c91c3, 0xa1fd8b}}, + {{0x18c704ef, 0x043f3285, 0x15445a6e, 0x18928b7f, 0x116c0c7e, 0x1f03de04, 0x015a6f5d, 0x11469461, 0xad215d}}} + }, + { + /* 1*16^30*G: */ + {{{0x12bd05a0, 0x01c64253, 0x07f2034d, 0x0466fa16, 0x11f90ba8, 0x1ccaf9b6, 0x0173b70b, 0x06c74631, 0xe5e892}}, + {{0x01a69f5d, 0x09b6f15f, 0x14266bb2, 0x0732b739, 0x15c3eca7, 0x1580f3cd, 0x1f484c07, 0x1c9b4370, 0x77439d}}}, + /* 3*16^30*G: */ + {{{0x01467d6b, 0x184a9408, 0x0892d453, 0x1ae252a5, 0x0f1d8357, 0x0308b216, 0x13d74406, 0x1bf286b9, 0x5d2393}}, + {{0x11bc5458, 0x1e339e35, 0x011cea01, 0x0e0f4ea2, 0x0f46d72a, 0x0c2d96ad, 0x1df5eb2f, 0x1e4c7fa1, 0xe66e63}}}, + /* 5*16^30*G: */ + {{{0x1d159f7a, 0x058f49e4, 0x10b9643c, 0x127539e4, 0x1873fecf, 0x1d95e97f, 0x04fceb73, 0x14a75571, 0x453657}}, + {{0x0a02fb78, 0x0e115b84, 0x07769766, 0x0937a9d0, 0x1c7286f9, 0x18489d00, 0x171768bb, 0x1ff10047, 0xbfb5ae}}}, + /* 7*16^30*G: */ + {{{0x146cb42a, 0x0f6f6f9e, 0x08e424cc, 0x0a50a74e, 0x173e7bc0, 0x16f5509e, 0x11193452, 0x1960f609, 0x435b54}}, + {{0x1af72dd0, 0x1f126f6e, 0x0e5269ad, 0x1898f286, 0x0585d5ed, 0x12a660f0, 0x086927d2, 0x063c8e31, 0xd726c0}}}, + /* 9*16^30*G: */ + {{{0x1d2fc263, 0x0beca0d8, 0x19755eea, 0x1f027cb6, 0x1da0e89c, 0x023e2709, 0x15f867ef, 0x033c29db, 0x1805b8}}, + {{0x10870ec7, 0x132385a7, 0x147b2bc9, 0x1835f1ca, 0x131489c8, 0x0d5435e5, 0x05c56163, 0x05012870, 0x101f64}}}, + /* 11*16^30*G: */ + {{{0x0076d1df, 0x1158db86, 0x1fe86ce6, 0x1c410284, 0x15f45f41, 0x1d45153b, 0x053d0185, 0x086cda63, 0xc73aaf}}, + {{0x05ad6605, 0x13cea8b7, 0x024dc834, 0x16af4a3b, 0x0dcfef75, 0x00df1dde, 0x05bbe738, 0x0d3d99f2, 0x9201ec}}}, + /* 13*16^30*G: */ + {{{0x05a745c7, 0x1b41fbcc, 0x1fab01f4, 0x144e7182, 0x152c1bc8, 0x0db57b0e, 0x1b49dc62, 0x11efab86, 0xe3ddee}}, + {{0x178efcc2, 0x1cf84a03, 0x1409ec68, 0x1185e2f7, 0x1d8f47c2, 0x0dc3553d, 0x0e1c6f94, 0x1a723265, 0x487199}}}, + /* 15*16^30*G: */ + {{{0x0d4170b3, 0x06399f42, 0x0e8d61fd, 0x0882adf8, 0x0a1d5401, 0x1508c360, 0x0796bda2, 0x1b8406be, 0x45c78d}}, + {{0x111faa1d, 0x177d1f6a, 0x08331cc5, 0x008cc0c8, 0x13a512cb, 0x14e8a27d, 0x1032c386, 0x08c471ab, 0x11af99}}} + }, + { + /* 1*16^31*G: */ + {{{0x1ab5c2cf, 0x0abccc97, 0x0c213788, 0x05e1843f, 0x090a4531, 0x03a0827d, 0x1d41c79d, 0x0863c443, 0xe4107e}}, + {{0x0b955c2b, 0x014201f9, 0x1ec90434, 0x1125b9fe, 0x02b323c7, 0x03343a0e, 0x1268e523, 0x1cd9ee03, 0x1e5f11}}}, + /* 3*16^31*G: */ + {{{0x09b67b7e, 0x1dadb1e0, 0x070f5216, 0x16f65722, 0x01142766, 0x0b80ef5e, 0x1df6ab3e, 0x0cbdc2f3, 0x85df9a}}, + {{0x030a36e3, 0x059c34f4, 0x0f1ba962, 0x15293a3f, 0x0297386f, 0x1eaf7f87, 0x0c22edad, 0x154735ec, 0xa6b4b7}}}, + /* 5*16^31*G: */ + {{{0x0b3510d3, 0x13e7ef30, 0x0875b904, 0x062cce09, 0x1292885d, 0x10c32e16, 0x1422a362, 0x1fcff3f9, 0x23c493}}, + {{0x1ae89a47, 0x1a317621, 0x0e76f5c4, 0x13c6bc4d, 0x1e6d8f79, 0x0ecf277f, 0x108c309d, 0x153c8682, 0xadf456}}}, + /* 7*16^31*G: */ + {{{0x0b49a71f, 0x06348c04, 0x089f0e6b, 0x0dd6d8c8, 0x035ddac3, 0x09f5d579, 0x03b77966, 0x016629ba, 0x94406d}}, + {{0x10b249a9, 0x18e0ca26, 0x18f3e511, 0x04e4c394, 0x1e897d0e, 0x1e484837, 0x05e73481, 0x0fd0c9be, 0x61aae7}}}, + /* 9*16^31*G: */ + {{{0x00e50c32, 0x0e6f19e3, 0x11a1cff9, 0x0212e5d1, 0x08d3877f, 0x1b6fadf7, 0x1050cdc4, 0x087bd10d, 0x3c2ebf}}, + {{0x0a93c124, 0x117c48be, 0x1a326627, 0x1a118735, 0x028e7be2, 0x1c9e9017, 0x06719496, 0x14d8bd07, 0xa703d9}}}, + /* 11*16^31*G: */ + {{{0x03a2355a, 0x041ecef6, 0x1812641c, 0x0a37e6b8, 0x15f12996, 0x12dc4f62, 0x1ae7ce47, 0x1ae4f281, 0x987536}}, + {{0x1bd05276, 0x063ae260, 0x0eb7337c, 0x1ed8f8d0, 0x17b48b85, 0x18e0a4f2, 0x05c90f82, 0x1ace9e22, 0x12f19a}}}, + /* 13*16^31*G: */ + {{{0x12f3ec22, 0x0782a3e2, 0x0a3e29ac, 0x10db9ee3, 0x0ddddd1f, 0x1c58bf79, 0x11a3c674, 0x08134988, 0xd515ac}}, + {{0x05a2863b, 0x10a31759, 0x06e01bb2, 0x0afbe006, 0x0bd464cd, 0x12420029, 0x0cb87a97, 0x02844893, 0x51c048}}}, + /* 15*16^31*G: */ + {{{0x1971c857, 0x0cd0f4d2, 0x19824fe9, 0x133cdb57, 0x1cf3ddec, 0x1e61c5b0, 0x02eb8914, 0x0930bcb6, 0x70b9d}}, + {{0x0ac8dfc1, 0x1ce5b1ee, 0x15186abf, 0x107b43d8, 0x13cfb33a, 0x0857231b, 0x09421ae0, 0x037fe96c, 0xed8046}}} + }, + { + /* 1*16^32*G: */ + {{{0x1789bd85, 0x1e427e4e, 0x05fab0d5, 0x0bfefb85, 0x0766efc3, 0x17eac463, 0x199fee60, 0x137ddb6b, 0x447d73}}, + {{0x12e25b32, 0x03f19e4b, 0x1eb94003, 0x09372b4f, 0x0aff73d3, 0x0eca9d25, 0x07bb84ba, 0x15706826, 0x2d4825}}}, + /* 3*16^32*G: */ + {{{0x1ea6db68, 0x1f0ccc76, 0x098cb09c, 0x15b0ac10, 0x0f4f6ddf, 0x06fcb2ef, 0x05fd62c5, 0x07c07940, 0xf8b653}}, + {{0x0e760da9, 0x0de92d85, 0x17283b5a, 0x1ae1bb38, 0x03ec66bb, 0x16ed2855, 0x1218bc11, 0x1ebd888a, 0xc30f4e}}}, + /* 5*16^32*G: */ + {{{0x1924e753, 0x16aea75f, 0x1e1c9f19, 0x02e60e59, 0x1fb755f0, 0x18c394f6, 0x11f1523b, 0x1a6ab050, 0xf35289}}, + {{0x0b13a20c, 0x122dae17, 0x0b43c12a, 0x05f8ae52, 0x01bd8c56, 0x0450da87, 0x0fee4f7c, 0x03d8bd82, 0x75c178}}}, + /* 7*16^32*G: */ + {{{0x1018017e, 0x1cae5b39, 0x17c8f5c8, 0x083fffad, 0x14e01af1, 0x0c2fdb39, 0x1c5920d0, 0x0e9b4882, 0xcfd06b}}, + {{0x0e0dff50, 0x0573df26, 0x1de5dde8, 0x0060f0d6, 0x07950003, 0x19cac3ed, 0x044e040e, 0x1536e575, 0xb647b7}}}, + /* 9*16^32*G: */ + {{{0x192db860, 0x0640c82b, 0x06891ec1, 0x11251065, 0x1dbe9810, 0x0b68478a, 0x1344544b, 0x09895abb, 0x755e7}}, + {{0x00d09849, 0x0b3006dd, 0x109dde9f, 0x06e8c99f, 0x15bc2b29, 0x196c11c0, 0x19374926, 0x14ea75b3, 0xfe16af}}}, + /* 11*16^32*G: */ + {{{0x0a26ba6b, 0x0f7b4aaf, 0x1684b0ea, 0x1945492d, 0x0bbdedd2, 0x0606bf58, 0x05a5a284, 0x09986e59, 0x88fba8}}, + {{0x044972f8, 0x020a3c0f, 0x033f73a0, 0x153c51c0, 0x0788d484, 0x0d22da8a, 0x183f499b, 0x0c93a737, 0x512aef}}}, + /* 13*16^32*G: */ + {{{0x14720cab, 0x0e245214, 0x0e6c5f8e, 0x1d4ba82e, 0x06f2c1a1, 0x1b73aaae, 0x0fae3943, 0x197d80ab, 0xe1a0ac}}, + {{0x14b185c9, 0x16a29fab, 0x000953a9, 0x1454e3a1, 0x0bcbf084, 0x1c183bf7, 0x015060db, 0x1f6fd319, 0xe07968}}}, + /* 15*16^32*G: */ + {{{0x0c26c42a, 0x14147eff, 0x0c46ed8a, 0x17f6fc8d, 0x1e6a0249, 0x1ac498f3, 0x11f9436c, 0x10dcd4e7, 0xae93b}}, + {{0x19f808ca, 0x08319a1d, 0x0ab6d924, 0x1473ddeb, 0x00b37278, 0x11f6e0f1, 0x184ea50b, 0x1ba28f0f, 0x7028f6}}} + }, + { + /* 1*16^33*G: */ + {{{0x137de736, 0x15ec5d60, 0x02338907, 0x11aac30d, 0x0c18ea2f, 0x0a15c66f, 0x1cfa24dd, 0x02929399, 0x9022e3}}, + {{0x04c42ecc, 0x077ae042, 0x1a9d95fd, 0x126cd889, 0x0ce087f4, 0x1d822913, 0x0e519b42, 0x09e52094, 0x2fae5e}}}, + /* 3*16^33*G: */ + {{{0x109b01f5, 0x0b8365c6, 0x1cf01464, 0x1e6a3064, 0x1857af73, 0x169f8d7b, 0x0517ec3c, 0x1c60edfd, 0x6e5872}}, + {{0x0bcd5fde, 0x183ac6cd, 0x06a169f0, 0x02f3a9c1, 0x0f0ebc13, 0x0ea579df, 0x05c60330, 0x05d91aee, 0x4213c0}}}, + /* 5*16^33*G: */ + {{{0x0fe45b1f, 0x09cdba3f, 0x185a30ad, 0x02abf65c, 0x1df827bd, 0x0f1a260b, 0x1d412bf4, 0x1634bb47, 0x292220}}, + {{0x134bb026, 0x1f205c5a, 0x17504117, 0x06886099, 0x18d7ff7c, 0x1caffd74, 0x16bb8df1, 0x0a657e2e, 0xe316a0}}}, + /* 7*16^33*G: */ + {{{0x03abd540, 0x14283315, 0x059b790f, 0x0080ca96, 0x13a340e8, 0x07c39084, 0x1c2b0c89, 0x0900f489, 0x3644e1}}, + {{0x155da631, 0x0e37f0e6, 0x1be85378, 0x0ef9db4c, 0x1e293001, 0x02984fd0, 0x05d8470a, 0x0a1b784f, 0xec5a91}}}, + /* 9*16^33*G: */ + {{{0x09142ccb, 0x117e90f4, 0x01fb78c6, 0x0414b58d, 0x1b4824c9, 0x1c7a4c9d, 0x00e3956c, 0x15c2ff9b, 0xedfe7d}}, + {{0x0c593d75, 0x1ca8e98d, 0x14450bae, 0x08856d3a, 0x1beb81da, 0x0e95a7aa, 0x1c858615, 0x0245c1b5, 0xc88692}}}, + /* 11*16^33*G: */ + {{{0x0a41b208, 0x1ed38e32, 0x189c003c, 0x0e8eb9bd, 0x00de8e7f, 0x00135e75, 0x1a5661c5, 0x11680b34, 0x531196}}, + {{0x048e4b69, 0x08f0fcf0, 0x0da1dfda, 0x183b8048, 0x1da113b3, 0x0c0f19d9, 0x05e29b19, 0x0567b845, 0xb78d73}}}, + /* 13*16^33*G: */ + {{{0x095daae7, 0x1e80dae2, 0x1c0cef2c, 0x0dcdd8f8, 0x0e1d5af4, 0x15fb7ab0, 0x1653de88, 0x1e45ff74, 0xf65dd1}}, + {{0x02556738, 0x0a72d4ce, 0x0b366ca3, 0x0c301f3d, 0x04cd0eb0, 0x1f31be7e, 0x1ba0839b, 0x0419c36c, 0x9d71b8}}}, + /* 15*16^33*G: */ + {{{0x1afcf1ee, 0x1f7e0af1, 0x01a6846a, 0x155008e4, 0x007c60af, 0x1a405554, 0x0922d06f, 0x0fdb995c, 0xa6670e}}, + {{0x00c67fc8, 0x1c43855f, 0x0f3ce28d, 0x07312392, 0x1ac131ef, 0x1b97a4ab, 0x0bce8e57, 0x19274a38, 0xa7fd14}}} + }, + { + /* 1*16^34*G: */ + {{{0x04cd3397, 0x008a2e0a, 0x1457ad5d, 0x09820c32, 0x16deddc3, 0x16795a8a, 0x1c8e24e1, 0x00833db4, 0x73baff}}, + {{0x1adcb8e4, 0x0f79509c, 0x0984d250, 0x1df259f0, 0x1825e779, 0x08f460c7, 0x117da803, 0x0c692ef5, 0x1e97de}}}, + /* 3*16^34*G: */ + {{{0x161fb913, 0x1587ca90, 0x14c4a5df, 0x0048c2ad, 0x0d04e3e1, 0x046f225f, 0x0860d10e, 0x01867cc1, 0x45f833}}, + {{0x0c15c3bc, 0x06a40be0, 0x1f0cdcdc, 0x1a10f3ed, 0x07760f06, 0x003b6c5d, 0x01bbe03a, 0x0db7fad2, 0xc212cf}}}, + /* 5*16^34*G: */ + {{{0x0e393654, 0x177cb48f, 0x1b75f1d6, 0x1a97c3e7, 0x15991965, 0x100e45e6, 0x16ad97d6, 0x09359af7, 0x5544dc}}, + {{0x0f53206f, 0x1b085dfc, 0x15639cc8, 0x1dfd2e07, 0x15192241, 0x02dadc49, 0x152b0130, 0x112a10ff, 0xed3e85}}}, + /* 7*16^34*G: */ + {{{0x08a15dfd, 0x1f9acca1, 0x1ea79544, 0x1b75804b, 0x0f695741, 0x176aad71, 0x1dcd2cf4, 0x120c33dc, 0x2757b7}}, + {{0x1042c341, 0x04742067, 0x09c55b7f, 0x112f1479, 0x1500d176, 0x1a909e6a, 0x04b97325, 0x1aaa9856, 0xdf46d2}}}, + /* 9*16^34*G: */ + {{{0x1f840a5b, 0x1f6fa135, 0x0b52613b, 0x195b4ba7, 0x03ccd148, 0x10e6608a, 0x0f236610, 0x0fbca1c5, 0xe87243}}, + {{0x1377e86a, 0x0272c2a8, 0x0e59192e, 0x1468d9f2, 0x08bf5ac3, 0x048fb312, 0x185964ef, 0x11224e52, 0xf984bc}}}, + /* 11*16^34*G: */ + {{{0x136afd6a, 0x0ab54dc5, 0x1e078f52, 0x03f8a142, 0x1334a926, 0x1b6af379, 0x1700e4bb, 0x15749aee, 0xc56cdc}}, + {{0x13f87c26, 0x10435f77, 0x0331c8f9, 0x090764ad, 0x14ef566f, 0x0f58bfac, 0x01c334bb, 0x1c5e70d6, 0xd16056}}}, + /* 13*16^34*G: */ + {{{0x0cfd2cd0, 0x0d6cc069, 0x070304c7, 0x08266883, 0x0abb1239, 0x142c1f24, 0x0a1a73f4, 0x0e71e7fe, 0xd3d6e6}}, + {{0x194ae2dc, 0x02bce3bb, 0x1dbe3c53, 0x1f4ad185, 0x1e59b001, 0x147fb9be, 0x0da14db6, 0x0bf9a2b3, 0xff448f}}}, + /* 15*16^34*G: */ + {{{0x1ab7a64c, 0x0ac442ae, 0x026ade82, 0x011ad474, 0x1d406565, 0x196b911b, 0x101ec0c4, 0x110adc8b, 0x88f977}}, + {{0x1575f103, 0x02f4c708, 0x1b499ce8, 0x06012442, 0x09e5836c, 0x0d792bcb, 0x11d0d14c, 0x1ba8d6ab, 0x4a745c}}} + }, + { + /* 1*16^35*G: */ + {{{0x1fa4e33c, 0x1172fd98, 0x02632cc3, 0x077d8f16, 0x0fb98268, 0x023614bb, 0x16ef25d1, 0x17234984, 0x9cf646}}, + {{0x0e0d4563, 0x0e22f030, 0x10580c86, 0x00b04fd7, 0x01f319e2, 0x0712c5c1, 0x0a247902, 0x09b83ecb, 0x37b062}}}, + /* 3*16^35*G: */ + {{{0x06bf1e67, 0x0c5b0c66, 0x172bd8fa, 0x0cce93fc, 0x04e0f4c5, 0x129c13bb, 0x126675e9, 0x1bc2a36c, 0x83cb43}}, + {{0x099acc97, 0x13f74598, 0x1445a7a8, 0x0884597b, 0x018f8287, 0x00373122, 0x1be3bec6, 0x1449731e, 0xbce28c}}}, + /* 5*16^35*G: */ + {{{0x1c0f057e, 0x1856ba46, 0x154f7608, 0x10c50e03, 0x1022484e, 0x07e0af12, 0x02300cd0, 0x1cac19d6, 0x3ff3b3}}, + {{0x0817965e, 0x0a0fbed5, 0x1c05d88b, 0x0046dd88, 0x07843a01, 0x08b82bc3, 0x1e3dbdff, 0x0de776ca, 0x7f17ad}}}, + /* 7*16^35*G: */ + {{{0x125e69f1, 0x088a5a01, 0x08af2d45, 0x0f51e5a8, 0x0af99636, 0x0ef0b9eb, 0x00ff7686, 0x05bb1ffb, 0x6e9edb}}, + {{0x002b7e9b, 0x1070bf1a, 0x07ca06dc, 0x04e8a8f3, 0x1bff61c7, 0x0b55b2f9, 0x153aacd5, 0x02d9dff2, 0xc08222}}}, + /* 9*16^35*G: */ + {{{0x0288f038, 0x19297b35, 0x17fe082f, 0x0ed129d6, 0x02d32f08, 0x00cef376, 0x112fbeaf, 0x1d009883, 0x5ee280}}, + {{0x16f1ee6e, 0x02d55c35, 0x19b1bd07, 0x0f067531, 0x1eec011d, 0x0c37f664, 0x0e4a1301, 0x1f28cefc, 0xbcd969}}}, + /* 11*16^35*G: */ + {{{0x00c708c8, 0x05f992b6, 0x1c2a1aa8, 0x08609e5e, 0x0288c2c3, 0x1b2ec8ff, 0x15cdb7f8, 0x0dc0b840, 0xe1f016}}, + {{0x1896ed38, 0x18c6b9d9, 0x0d6802b9, 0x0abe45df, 0x13016fb6, 0x1195f451, 0x0d481111, 0x07d22d87, 0xe64765}}}, + /* 13*16^35*G: */ + {{{0x076edefb, 0x10784e52, 0x039f575f, 0x117b0020, 0x1c7badd5, 0x0d5a14bc, 0x1171fc48, 0x10f57ec6, 0x280896}}, + {{0x1d1b0ae0, 0x17a2b914, 0x00e4848b, 0x06360f7c, 0x141c44dd, 0x0cf5ec82, 0x064699f8, 0x1e67a766, 0x5d071c}}}, + /* 15*16^35*G: */ + {{{0x1344897a, 0x096ccde7, 0x1309a774, 0x1da60eb4, 0x1edab7b9, 0x0f429212, 0x132dc161, 0x1bc50320, 0xeb15b0}}, + {{0x05bfe7ee, 0x0cef41e7, 0x1f42e0ab, 0x0d3165f2, 0x12f85814, 0x157c66b9, 0x01c42262, 0x02d384cc, 0x96cdd}}} + }, + { + /* 1*16^36*G: */ + {{{0x123b716d, 0x137d6e02, 0x13869ae0, 0x0712cdee, 0x0df9e0d2, 0x03c9c68c, 0x14d3a297, 0x1c717194, 0xf81f5b}}, + {{0x12632401, 0x120017a8, 0x01e0cc11, 0x0eb0a075, 0x00328660, 0x094e9c07, 0x1b7c755b, 0x065383e0, 0xdc7f49}}}, + /* 3*16^36*G: */ + {{{0x19d19d8a, 0x062b4281, 0x09548561, 0x024f12a3, 0x1490a3b4, 0x161ae0b6, 0x18e16bdb, 0x0a1f6250, 0xa60084}}, + {{0x190d2c4f, 0x0caedd9a, 0x0995cf7f, 0x1c011f4e, 0x1ca84f0f, 0x0a2f3df4, 0x11cb23db, 0x180cf46f, 0x7b4b79}}}, + /* 5*16^36*G: */ + {{{0x096cac9f, 0x14c3d9ca, 0x11379c89, 0x0719d4b8, 0x10e1c59e, 0x04bcc7f5, 0x0d531930, 0x1632cfbe, 0xde5382}}, + {{0x0fa473d3, 0x070417ed, 0x1610455f, 0x07c528e7, 0x19f2bc2e, 0x1804c8e7, 0x06158b0e, 0x0f16d392, 0x9c47b6}}}, + /* 7*16^36*G: */ + {{{0x06807a23, 0x0594b1bc, 0x097fcf9f, 0x0040a2d4, 0x14ec8400, 0x1ccea88c, 0x04214d12, 0x0100fe55, 0xa7227b}}, + {{0x14115894, 0x0238cc1e, 0x0a337247, 0x1f02af6e, 0x075abe7b, 0x023c9050, 0x07a1176a, 0x04ba8ba7, 0xf55075}}}, + /* 9*16^36*G: */ + {{{0x044d14c0, 0x13cbfe10, 0x0a3cd796, 0x1956bf43, 0x01d39005, 0x1f39d1b3, 0x1659196a, 0x11a84688, 0xcd2b2e}}, + {{0x02496315, 0x0b056791, 0x0b33b3a9, 0x16de1973, 0x0f671fdd, 0x0f76ed60, 0x02893541, 0x1bf3610e, 0xf13012}}}, + /* 11*16^36*G: */ + {{{0x199a1566, 0x17a75891, 0x08a3da59, 0x18cab5fe, 0x19dd8f25, 0x1e4dc1ef, 0x1fad33be, 0x0991e1be, 0x11b2e8}}, + {{0x1c56bb73, 0x0d259e02, 0x16025a16, 0x16ab0819, 0x005cc824, 0x0b4c3cba, 0x05d7410b, 0x13b79446, 0x610376}}}, + /* 13*16^36*G: */ + {{{0x1ba6f34a, 0x084f5946, 0x1171be1f, 0x10d41fc4, 0x11485312, 0x1051f7cc, 0x01c1d676, 0x052be574, 0xfb6d19}}, + {{0x0bcf0452, 0x1af9e411, 0x1a16c7e6, 0x19f45b92, 0x191b9ecf, 0x07ea6253, 0x1b7678e2, 0x053af7e8, 0xf29b2d}}}, + /* 15*16^36*G: */ + {{{0x0a435427, 0x06516950, 0x1936d41d, 0x0021304f, 0x06651a69, 0x13b286c8, 0x0f042abd, 0x19820782, 0xff429f}}, + {{0x19853824, 0x12822869, 0x0e8368a3, 0x17dca694, 0x06876205, 0x04e42b0c, 0x16c25350, 0x0cd149d9, 0x2addf9}}} + }, + { + /* 1*16^37*G: */ + {{{0x07354b7a, 0x16ce3f3c, 0x045725e3, 0x1d94ad87, 0x0de1d022, 0x1a31f29e, 0x01208e5f, 0x0e9aefc1, 0x856854}}, + {{0x116e04c6, 0x0aa2015e, 0x15bf6f62, 0x1123b83f, 0x1728706a, 0x089d9537, 0x1edbbaf2, 0x16a17eb0, 0x20b50e}}}, + /* 3*16^37*G: */ + {{{0x1b26165d, 0x1b663fd3, 0x1dc4dfab, 0x07442bec, 0x092dea71, 0x090497e6, 0x199527a7, 0x18ea5647, 0x617344}}, + {{0x06b2a286, 0x04dfee5c, 0x1c5c6931, 0x13582dc6, 0x020b2989, 0x0885e8c1, 0x0d6926df, 0x02f486f0, 0xe99016}}}, + /* 5*16^37*G: */ + {{{0x10442770, 0x10dfbb32, 0x006eb440, 0x11ef4dc2, 0x0fc2e901, 0x00ed4f20, 0x088b6813, 0x1dcabf6d, 0xf8ac03}}, + {{0x1b00c82d, 0x11432788, 0x0107408e, 0x0c057f2a, 0x06d17a97, 0x03a8d9a7, 0x1a3a90db, 0x0cab33a3, 0x5a358e}}}, + /* 7*16^37*G: */ + {{{0x165460de, 0x1f036c37, 0x0fddee3e, 0x07f1a155, 0x08ea60c7, 0x1e5f1866, 0x1719b1b2, 0x16a4b792, 0x8a731f}}, + {{0x1f8dc207, 0x0c2cd0ef, 0x1423b8fa, 0x0cfc78a4, 0x04dc4358, 0x0aa5ffd8, 0x0c663d4a, 0x18bc556c, 0x585855}}}, + /* 9*16^37*G: */ + {{{0x151634a5, 0x0155d6fd, 0x1b549399, 0x1214f06b, 0x1967f3cf, 0x15d0166b, 0x0892fc29, 0x0c26551e, 0xa20b60}}, + {{0x1226afad, 0x1609bcaf, 0x1517b7c9, 0x08eafc79, 0x1315bc67, 0x0ff41b9d, 0x0676b4f5, 0x13ed2fb7, 0x9c43ce}}}, + /* 11*16^37*G: */ + {{{0x13ba54a8, 0x02191225, 0x0eaa5c1c, 0x164c6ac0, 0x1cc0ab58, 0x0761a7e2, 0x1c26450e, 0x127e24ac, 0x16f1f}}, + {{0x064f2889, 0x0be30fd3, 0x08ed39bb, 0x15e4ea8d, 0x0e658d93, 0x188df24e, 0x055dbca6, 0x0822b12a, 0x8bcd3}}}, + /* 13*16^37*G: */ + {{{0x07c16d94, 0x177249e7, 0x0a117f77, 0x103a1540, 0x0c31fe25, 0x1eb3e667, 0x11e23023, 0x0ce17a06, 0xe61586}}, + {{0x114810ab, 0x1a768cd5, 0x0910eefe, 0x0b9a3c8f, 0x0f0ee4e6, 0x15c9fa5b, 0x12fa316c, 0x15d3ce24, 0x65ca03}}}, + /* 15*16^37*G: */ + {{{0x13ce728d, 0x0b6e5332, 0x1c7342f3, 0x1b20fc50, 0x05347f4c, 0x04510b64, 0x08995568, 0x01671aad, 0xdcd37f}}, + {{0x17cacbcb, 0x0be89b4c, 0x076afae3, 0x19a68da5, 0x0d6f3caa, 0x1db159e3, 0x1061cb0d, 0x1aef9b49, 0x6574db}}} + }, + { + /* 1*16^38*G: */ + {{{0x12378c16, 0x0e36e0d8, 0x05588ab7, 0x0c0eaa8c, 0x1597d9e3, 0x1296b5fc, 0x0c46cc67, 0x0b382567, 0x1136b7}}, + {{0x13488127, 0x0facde85, 0x147338de, 0x095451ce, 0x1ecb2961, 0x15e307f4, 0x1f7427c2, 0x19e8a2d1, 0x7dec0f}}}, + /* 3*16^38*G: */ + {{{0x1b299740, 0x18736c13, 0x0f6c4d25, 0x1e8cfae2, 0x0ad48f40, 0x089bc9fd, 0x0cdb312b, 0x16e39ba8, 0x53893e}}, + {{0x1fff7509, 0x0f5378d9, 0x1f7a3354, 0x0265de43, 0x1dc8dd8a, 0x0714753a, 0x0f60e107, 0x0fd290bf, 0x27728a}}}, + /* 5*16^38*G: */ + {{{0x138000fc, 0x059e4ab3, 0x1c0ef04c, 0x1c4ee0f7, 0x0e5604e1, 0x1b5d78fd, 0x089d5f8d, 0x1baea99b, 0xdd64e9}}, + {{0x1df4ac12, 0x1d50e286, 0x07923e2f, 0x0ba04572, 0x079ffbe4, 0x0f1f0ce5, 0x0b25b7e2, 0x1d618526, 0x432193}}}, + /* 7*16^38*G: */ + {{{0x13878c4a, 0x1c10a8b9, 0x1470157b, 0x07a0790a, 0x11b21d88, 0x0e307254, 0x145bcb1a, 0x150fdffa, 0xff9845}}, + {{0x1488df68, 0x1d3423eb, 0x173faf1a, 0x066e8d6c, 0x1e8ddf1f, 0x12476ffa, 0x0a3e3f62, 0x1e949c48, 0x835b9a}}}, + /* 9*16^38*G: */ + {{{0x00f51524, 0x054dc40a, 0x0be1bf23, 0x1d6d42b7, 0x093de5fa, 0x1d184229, 0x0273a1d9, 0x1d17722c, 0x954e13}}, + {{0x05e30a69, 0x0fed9eca, 0x079f2f7a, 0x1d486228, 0x0cbcfa9e, 0x1121a3cf, 0x010764f1, 0x07ff2548, 0xecc836}}}, + /* 11*16^38*G: */ + {{{0x04f77287, 0x1bcc6a9e, 0x0c3678c7, 0x12a786d2, 0x00497412, 0x0862e0ec, 0x0e4f7f35, 0x1edf483f, 0xb2217e}}, + {{0x04e7b5da, 0x1d0253b9, 0x17a4f2e5, 0x13b8e738, 0x0c843d70, 0x1e7c469c, 0x0e8ad77e, 0x1c19cf9e, 0xfb5153}}}, + /* 13*16^38*G: */ + {{{0x05c723e9, 0x17a9cb64, 0x09e05c62, 0x0e775535, 0x15c351f9, 0x175748ae, 0x16b448b1, 0x162f6f37, 0x3c3950}}, + {{0x16834763, 0x11c3bafb, 0x1241ab97, 0x1b596af8, 0x0a8b0b01, 0x1dbf50c3, 0x036ed252, 0x0c441222, 0xb99b73}}}, + /* 15*16^38*G: */ + {{{0x1c18abeb, 0x18beb711, 0x09758a8d, 0x1b9a320e, 0x0a944d59, 0x097c225d, 0x136b477b, 0x0599f2c3, 0x803c7a}}, + {{0x029bfa78, 0x121cdf87, 0x19c8735a, 0x18887854, 0x14409ed7, 0x078b4e25, 0x04a1ac6b, 0x0814f2dd, 0x83fb50}}} + }, + { + /* 1*16^39*G: */ + {{{0x143e832a, 0x03b1778c, 0x01b7dc27, 0x0a15602f, 0x1f18e07e, 0x19d412c4, 0x146a43d5, 0x1174f854, 0xd2bf2}}, + {{0x1b20d37c, 0x0131d78a, 0x15451192, 0x193b72c0, 0x0e7ed27e, 0x10854a5a, 0x02b1c21e, 0x086277a0, 0xcac3f}}}, + /* 3*16^39*G: */ + {{{0x112c9666, 0x0f5625e0, 0x1ff37cd8, 0x118d86cb, 0x1531b1cf, 0x061adbec, 0x00b3f66f, 0x0bd72cff, 0x34e5e8}}, + {{0x192a3666, 0x0d0c29e4, 0x18e949ad, 0x0fdac783, 0x046330f4, 0x12bae65e, 0x0dae0a11, 0x06264434, 0xc0ce68}}}, + /* 5*16^39*G: */ + {{{0x11209502, 0x0b295f1a, 0x16499970, 0x02e4004b, 0x1e154594, 0x09f7848c, 0x018e9b12, 0x198b3e9b, 0x727362}}, + {{0x17042b0d, 0x13be8e9e, 0x09d82ef1, 0x1a6ff376, 0x11d20a18, 0x05c61674, 0x0d627c40, 0x04537575, 0x17b0f4}}}, + /* 7*16^39*G: */ + {{{0x0447f959, 0x0af3c945, 0x1c74da11, 0x0fb57504, 0x1eee9f94, 0x0a625da4, 0x13b25ce8, 0x0c00a94d, 0xa0c3f2}}, + {{0x168b671f, 0x01ce9244, 0x149cb26c, 0x0aa804b1, 0x08208b1b, 0x060865b1, 0x113ce0be, 0x0121c965, 0x508c73}}}, + /* 9*16^39*G: */ + {{{0x1b37e1d3, 0x10fcf812, 0x193788c0, 0x0c37c279, 0x1fd04107, 0x019df20a, 0x09e9032d, 0x063ef2b9, 0x7e81b2}}, + {{0x0155681a, 0x1afe5132, 0x10b8380f, 0x1097e563, 0x07c4e4ec, 0x04b67736, 0x144c497a, 0x0361d37d, 0xf3855a}}}, + /* 11*16^39*G: */ + {{{0x16c051a0, 0x04bb8afa, 0x16cf9b71, 0x1e5248de, 0x12abddcd, 0x0c736d87, 0x1b6128db, 0x038fb004, 0x8035e2}}, + {{0x12d0dd12, 0x00f5d97d, 0x02d88d58, 0x0fb8c613, 0x1d318b3e, 0x1f341bde, 0x0fbcdd76, 0x14896f45, 0xb8810}}}, + /* 13*16^39*G: */ + {{{0x1f12c69e, 0x1006184f, 0x194658f3, 0x0b5deb12, 0x0fcecafe, 0x18008102, 0x14cc1aeb, 0x1bfac314, 0x196908}}, + {{0x1d114831, 0x0998c820, 0x1ee21ae3, 0x05c66e3f, 0x1054eb6b, 0x0ef56e90, 0x18102fb8, 0x0d65f22d, 0x3f65bf}}}, + /* 15*16^39*G: */ + {{{0x0b89c5ed, 0x04c700fe, 0x1e9e31f9, 0x0a619ef2, 0x10f3577b, 0x10e90856, 0x0abd1b9b, 0x1d712c34, 0xdb77fc}}, + {{0x0d25b46e, 0x0ff8e3f7, 0x0266be96, 0x0d8f56d1, 0x1ad411f1, 0x1cdf264c, 0x173bb3cc, 0x070e39dc, 0x7fd1dc}}} + }, + { + /* 1*16^40*G: */ + {{{0x17f82f2a, 0x174e3aef, 0x1f7d0eab, 0x186b0e95, 0x113269e4, 0x16fa1b9b, 0x185fd588, 0x0acdd8e6, 0x8a535f}}, + {{0x023094b7, 0x0fcd0561, 0x031d9a71, 0x0a670c99, 0x092bfcde, 0x140c842d, 0x0f5cdf80, 0x108d1611, 0x455c0}}}, + /* 3*16^40*G: */ + {{{0x0b348fa0, 0x18a790bd, 0x0550777e, 0x1c48b20a, 0x0b4bce0f, 0x1191b612, 0x00b70a88, 0x07bbbd71, 0x86eac9}}, + {{0x0da51cee, 0x171c04aa, 0x13fba293, 0x0db2c6a3, 0x146716c2, 0x17cf46b7, 0x1635690d, 0x0a797789, 0x948f38}}}, + /* 5*16^40*G: */ + {{{0x19222c03, 0x17a0ffe4, 0x197840de, 0x19cefd0f, 0x1f407948, 0x1ebc242c, 0x0ab8fd79, 0x175f3f67, 0x8bf09e}}, + {{0x0a72bb54, 0x0a2fba17, 0x08387528, 0x1d81c3bc, 0x1ba309c9, 0x18edf3f2, 0x09cced22, 0x15fc5c4f, 0x509cba}}}, + /* 7*16^40*G: */ + {{{0x11ae9300, 0x029d160e, 0x1120a02d, 0x188e08eb, 0x1735b5e1, 0x05d6d179, 0x1f18644c, 0x1976fce1, 0xe85e2d}}, + {{0x1546e25e, 0x1506fee8, 0x030c6edc, 0x0fc30bbf, 0x02707deb, 0x1dadc11e, 0x02ff1ee9, 0x14daa39c, 0x451aaf}}}, + /* 9*16^40*G: */ + {{{0x05260cb8, 0x092eaab0, 0x0c854bc9, 0x1e95019d, 0x1dbf6836, 0x13ed0dd3, 0x1e0a8fc0, 0x1e451925, 0x3f5fb0}}, + {{0x1852c964, 0x17da5a20, 0x17b0cc9c, 0x1d0ea3f8, 0x183f2fa3, 0x0f0a9b33, 0x061c38e3, 0x1b5b4933, 0xc55834}}}, + /* 11*16^40*G: */ + {{{0x1a1cd60f, 0x15222216, 0x0c24ba92, 0x0d315398, 0x0002b9f9, 0x083a5a6d, 0x06595ebb, 0x045631b3, 0x336856}}, + {{0x0fd57d67, 0x1fb9bb28, 0x142e2c92, 0x1eb49978, 0x1af175fe, 0x06006f53, 0x1366ea16, 0x13de248f, 0xd42f50}}}, + /* 13*16^40*G: */ + {{{0x17576342, 0x029db75d, 0x06488abc, 0x19110673, 0x179d95b2, 0x1cec4b04, 0x0203df43, 0x0b811e00, 0x4813eb}}, + {{0x17376316, 0x060aaf5c, 0x1aa413d9, 0x1b8cfaa0, 0x1524aca2, 0x0b424719, 0x0903d980, 0x1a846748, 0x043f}}}, + /* 15*16^40*G: */ + {{{0x1f69b2be, 0x1b38b8ef, 0x04447027, 0x03ee9db8, 0x06e56ba4, 0x16ddd71c, 0x05ebc4c8, 0x1f34b5d3, 0x80c3f1}}, + {{0x0102d2f5, 0x0825cbe2, 0x0dea2fe2, 0x16e966b9, 0x15a9bf14, 0x113b2d8e, 0x1a14a603, 0x0814013b, 0xa9321}}} + }, + { + /* 1*16^41*G: */ + {{{0x0476c81d, 0x041bfa7f, 0x194f57a7, 0x06061d33, 0x0a366b7a, 0x06939ed4, 0x08066bdf, 0x1bfb9683, 0xad6090}}, + {{0x0e6705dd, 0x0c55e427, 0x0c1237e0, 0x1fb86c9e, 0x1d8a8393, 0x1ae1662d, 0x047ab335, 0x1ba91e99, 0x77b5d1}}}, + /* 3*16^41*G: */ + {{{0x02725490, 0x11239be7, 0x12d66402, 0x06480c47, 0x1863c4ac, 0x15299d84, 0x05f28ab6, 0x176e35ad, 0xd90b45}}, + {{0x0feb1299, 0x07c27c25, 0x1119b32c, 0x180f7fe7, 0x0cbd80cd, 0x1ab439bc, 0x143c2762, 0x11d83766, 0x332692}}}, + /* 5*16^41*G: */ + {{{0x1e933668, 0x1b59d32b, 0x1aeafc29, 0x05b099f0, 0x106befb0, 0x1c9d7d0f, 0x1f1eb014, 0x02e62427, 0xac2592}}, + {{0x12776fb5, 0x173bfb39, 0x07879e85, 0x0c83138d, 0x0ed7c6f8, 0x009f75ec, 0x02ea143b, 0x070e1b75, 0x6c79a0}}}, + /* 7*16^41*G: */ + {{{0x128de7e3, 0x130be090, 0x1aa65b66, 0x08558757, 0x031bf868, 0x07ded3da, 0x0ea21cc8, 0x095d2f3e, 0x7bc337}}, + {{0x0e6e5e29, 0x1d059975, 0x10333c19, 0x05b67369, 0x1acbd55f, 0x1bd73725, 0x19778031, 0x048c10a9, 0xb431f0}}}, + /* 9*16^41*G: */ + {{{0x035e057d, 0x1659191c, 0x162696d2, 0x1e21b5ed, 0x1119329c, 0x0397e1a0, 0x0ac9a2f2, 0x128a75c0, 0xbf9c14}}, + {{0x0da20fea, 0x1ab25941, 0x1711e6db, 0x173c3038, 0x1a542440, 0x189f82e3, 0x0f83ce14, 0x13e4be47, 0x92acb8}}}, + /* 11*16^41*G: */ + {{{0x021d6584, 0x1566be10, 0x0cf67974, 0x00bac887, 0x1014ef27, 0x1ed1ad6f, 0x1e2a5ba5, 0x0736af09, 0x55bf08}}, + {{0x0ed744ea, 0x0ab27a14, 0x19696a03, 0x1c284055, 0x07dcf089, 0x1fb5d45e, 0x133c9eb2, 0x067c96c3, 0x3d9807}}}, + /* 13*16^41*G: */ + {{{0x01068c5e, 0x0b4efb72, 0x195cf437, 0x0bdcdc97, 0x1d4872a4, 0x10a73c0a, 0x15467cab, 0x02ca66f1, 0xfcf24e}}, + {{0x07c19d75, 0x10fa29f9, 0x052156dd, 0x0ed49650, 0x0e7aee91, 0x0f10dac9, 0x1f8d719d, 0x1ca66dff, 0x186bb0}}}, + /* 15*16^41*G: */ + {{{0x020da860, 0x1becaf83, 0x12744022, 0x08a35490, 0x11f2f843, 0x1b29a1ec, 0x1fb287f6, 0x1a05ea2c, 0x7bc280}}, + {{0x07aac76d, 0x11488208, 0x1058cbaf, 0x03345fb9, 0x0e6e0f2e, 0x15fd382f, 0x07978989, 0x0ef777a6, 0xb33f6d}}} + }, + { + /* 1*16^42*G: */ + {{{0x13c4a205, 0x097961b4, 0x042a1229, 0x15bf13ea, 0x129fcde1, 0x0ab83adc, 0x0f139199, 0x0a2c60b7, 0xb6e06c}}, + {{0x1db36d05, 0x1bfa6c32, 0x0aa7e1d4, 0x13283350, 0x0d73b63f, 0x189373cf, 0x0fd71787, 0x0f843664, 0xbdb427}}}, + /* 3*16^42*G: */ + {{{0x19e27907, 0x17c10fb7, 0x167935a4, 0x15a96711, 0x1bd68771, 0x0eaeb7ef, 0x1139ace5, 0x07f08483, 0xed9e4}}, + {{0x0e78c4fb, 0x09fa7a83, 0x0e86417c, 0x0a39fd71, 0x00e0ce91, 0x07ec7589, 0x0d1fd6f0, 0x095fed64, 0xb5af87}}}, + /* 5*16^42*G: */ + {{{0x15b38f54, 0x1682b929, 0x0bc1f38d, 0x150c1cb9, 0x0e1f92e2, 0x146da47f, 0x1df71549, 0x0200edb1, 0x57a7e4}}, + {{0x045f2809, 0x1d3c0f31, 0x01fae9d7, 0x0edc7352, 0x0dd21dfd, 0x0511de41, 0x14906532, 0x00791d95, 0xfd7f0f}}}, + /* 7*16^42*G: */ + {{{0x07a79593, 0x17f5dfcd, 0x17125e51, 0x14e493a4, 0x05cf3347, 0x0d92c665, 0x16fbd4b6, 0x1c5e7deb, 0x24799a}}, + {{0x10920d55, 0x11c46bae, 0x1ac4e635, 0x086c3f37, 0x1e300999, 0x08d4e9b1, 0x0deccb0f, 0x04c5d90f, 0x9436b5}}}, + /* 9*16^42*G: */ + {{{0x0bf5abdc, 0x010b75a8, 0x02d94198, 0x19a75f7a, 0x15d60456, 0x08e58406, 0x009bb4c4, 0x18d1098e, 0xf15017}}, + {{0x0def85b7, 0x1aef15c5, 0x0e15612d, 0x18ceb84f, 0x1e232cbd, 0x1a0f1fe2, 0x0aa3b360, 0x03858be0, 0xdea7ef}}}, + /* 11*16^42*G: */ + {{{0x1e78e9b1, 0x0f92958f, 0x10507a1a, 0x11cdb89d, 0x0dfcc897, 0x018fba89, 0x1aa9b83e, 0x01f13697, 0xe196e2}}, + {{0x0a77eed7, 0x00bab0fe, 0x1b4d7d11, 0x1a02257d, 0x0ed9a908, 0x045f3b59, 0x1698a990, 0x10bf0350, 0xa5d66d}}}, + /* 13*16^42*G: */ + {{{0x1b1cb64b, 0x17719f2b, 0x02b0f55d, 0x13ca4ac3, 0x1ed14d60, 0x1e6b8a9c, 0x0c0bce5f, 0x1bcd8360, 0x7779f5}}, + {{0x1aba3aab, 0x070c68e5, 0x0aa54cf6, 0x10528479, 0x0e3fae2a, 0x189a53d1, 0x1afab7ea, 0x07e8e987, 0x9a842}}}, + /* 15*16^42*G: */ + {{{0x11d1b492, 0x16c2c3b4, 0x0669bd4f, 0x00c31840, 0x08ce8dfa, 0x16cd5759, 0x0bc4797d, 0x097c8474, 0x8605b9}}, + {{0x18ac6598, 0x18ebbdfb, 0x07a49715, 0x06a4da90, 0x1d1a8ee2, 0x170610a1, 0x1d63cfbd, 0x050fbcea, 0xa8e561}}} + }, + { + /* 1*16^43*G: */ + {{{0x09aa52df, 0x06afa725, 0x0a989fcf, 0x08a56368, 0x1ece618c, 0x00c4ecc8, 0x0fddb6f1, 0x192fec11, 0x45a511}}, + {{0x125ec16c, 0x1a95e890, 0x0a55739e, 0x03364fa4, 0x05ad25a9, 0x19bfe5b1, 0x0db4ff8c, 0x18ee7d53, 0x73be0e}}}, + /* 3*16^43*G: */ + {{{0x0e75bc7f, 0x0b3a9f7d, 0x1dfec7d9, 0x0e2e1b6d, 0x14c7b95c, 0x07890be6, 0x0d0e3bd0, 0x09fce572, 0xb57ac}}, + {{0x0972e9a9, 0x078b96e8, 0x127f1881, 0x12d81c80, 0x094fab1f, 0x1a67d2bf, 0x0ed7ca30, 0x104ef53e, 0xceedbf}}}, + /* 5*16^43*G: */ + {{{0x033125ff, 0x1ba19e7c, 0x16a05084, 0x0aaf60b4, 0x0ae99354, 0x016ce50e, 0x05233d1a, 0x1f6dc97a, 0x1178b3}}, + {{0x18486abd, 0x007cb84e, 0x195346fa, 0x115b9a11, 0x10ed10dc, 0x131bf518, 0x056ce0b7, 0x1d53757b, 0xdfd697}}}, + /* 7*16^43*G: */ + {{{0x1662d955, 0x19b4ae67, 0x033913ce, 0x09ad0b69, 0x15693844, 0x1dbf4693, 0x041fe2a0, 0x104df29d, 0x8ac7a0}}, + {{0x046b3dae, 0x03516df3, 0x1b04e36f, 0x09038b7a, 0x19ad9e3f, 0x1291a65a, 0x0c73275f, 0x1241e664, 0xc80f40}}}, + /* 9*16^43*G: */ + {{{0x088803e5, 0x06c3cd6f, 0x0d1972df, 0x156f9c1a, 0x09e02cc1, 0x1d43802b, 0x08446adf, 0x050b3bbe, 0xc0f48b}}, + {{0x076619ee, 0x14991014, 0x00a3b6e9, 0x1c9c0e17, 0x0d7d3932, 0x12393f30, 0x08da7269, 0x16df1079, 0x3d4326}}}, + /* 11*16^43*G: */ + {{{0x1e1f515c, 0x0b6b384c, 0x194e6bea, 0x09146442, 0x1b8c0e2b, 0x047087fb, 0x19b68067, 0x01e06a2e, 0x2ce870}}, + {{0x052eed6e, 0x08c9b24c, 0x10f54b25, 0x13b9a7c5, 0x15d2ca7a, 0x17a17bf7, 0x129eeb2c, 0x09e76bd8, 0x73879f}}}, + /* 13*16^43*G: */ + {{{0x04dcf274, 0x0d51bbaf, 0x0b3a8911, 0x0400d059, 0x0ca1d807, 0x0dd87ebe, 0x04245178, 0x0c3b96f8, 0xfac442}}, + {{0x112f0472, 0x1b4c3007, 0x11652c58, 0x004f8c4e, 0x097bd732, 0x11eaea77, 0x02a1f31c, 0x18c2acd5, 0x9713fd}}}, + /* 15*16^43*G: */ + {{{0x1dc39d21, 0x1af25b55, 0x06b71a0a, 0x0e7d7a81, 0x12813683, 0x0f21d0cc, 0x18011964, 0x02cb6807, 0xf891e6}}, + {{0x05ca579f, 0x0c8470be, 0x11809535, 0x12fd89ea, 0x1c43b73a, 0x1c54716d, 0x13b462ba, 0x162577bf, 0x129f53}}} + }, + { + /* 1*16^44*G: */ + {{{0x1076f57b, 0x0678d5cc, 0x12b181ca, 0x170dc79d, 0x0a53f030, 0x11a80e79, 0x1e72e49f, 0x0ac91018, 0x20e118}}, + {{0x0da7afe6, 0x0c1df6dd, 0x186dc7a1, 0x01b93681, 0x1e9979fe, 0x01f1fdb6, 0x1bdcc6f7, 0x0a55886f, 0xff67b3}}}, + /* 3*16^44*G: */ + {{{0x0b661da4, 0x04f1d76a, 0x0a129721, 0x14a358c9, 0x01a21940, 0x1fec8183, 0x1b3a3df1, 0x0b770cc0, 0xffca2a}}, + {{0x0f9b8a5a, 0x0c241af5, 0x1a1fdbe2, 0x1f0f5bca, 0x06c8c478, 0x04d0a47a, 0x172294f3, 0x1c656e39, 0xce1cb0}}}, + /* 5*16^44*G: */ + {{{0x1c8cfd22, 0x0560f09c, 0x0daf960f, 0x160ce36c, 0x1354a4e2, 0x1a8a86d6, 0x1aad8d94, 0x1dbff822, 0xff209c}}, + {{0x13bc5535, 0x1c4d8a74, 0x1a12e508, 0x1e972592, 0x1f1c80d4, 0x00e92667, 0x1df881f5, 0x12e8d3a1, 0xad79f3}}}, + /* 7*16^44*G: */ + {{{0x0f4e983e, 0x003f2c2c, 0x05fddf3a, 0x1cdd90e0, 0x14b156d9, 0x0040699d, 0x0ea56181, 0x05a160f3, 0x33d5f0}}, + {{0x11ea37a9, 0x0b86dc3c, 0x18c3255b, 0x035524b2, 0x1a1eb7a7, 0x0b0b2add, 0x1e11cf0f, 0x0eda7388, 0x1eb5a}}}, + /* 9*16^44*G: */ + {{{0x01e52a73, 0x14ad3cfb, 0x01686f2d, 0x0622d92e, 0x15e65d0e, 0x1a6cd6dd, 0x1a42a7a5, 0x07b4c4c2, 0x8f1bd2}}, + {{0x0bea8f2e, 0x1ed0a28f, 0x06142a15, 0x0a05cc96, 0x1eade590, 0x0f2183a1, 0x02e2e1da, 0x0c7275b5, 0x4c7a8f}}}, + /* 11*16^44*G: */ + {{{0x1d2bc078, 0x0217f617, 0x1cfbd696, 0x00ec0a53, 0x080aec4a, 0x0c5bed6c, 0x1fcfb98a, 0x1fdef6c6, 0x963bc9}}, + {{0x1afb8657, 0x0ed918fa, 0x10e8f09f, 0x180851e8, 0x0a4f1c5e, 0x128494c0, 0x188a028f, 0x07f9a3ce, 0x7ed338}}}, + /* 13*16^44*G: */ + {{{0x0fb608ad, 0x038f3b75, 0x03f64e9a, 0x00aca9b1, 0x0bc49748, 0x16ee5be4, 0x011398c6, 0x15b0c3b5, 0x89fe6d}}, + {{0x064d4dad, 0x00a0373c, 0x1c2a1ed8, 0x13aa27c1, 0x1df39aea, 0x1effdb92, 0x03f21ed5, 0x10463e9d, 0x289827}}}, + /* 15*16^44*G: */ + {{{0x19ae4a29, 0x18c4c0d8, 0x08ca82c1, 0x1fb4dd44, 0x06984df2, 0x1d62708b, 0x1d654435, 0x0fe77af2, 0xc34804}}, + {{0x0eb09235, 0x04acd626, 0x126bafcd, 0x05d33e0a, 0x1ae9a842, 0x06e90706, 0x11584f6a, 0x1e40ad43, 0x584781}}} + }, + { + /* 1*16^45*G: */ + {{{0x19273a8f, 0x08a29744, 0x13f552b7, 0x1a8f1cd2, 0x1dac93fd, 0x163fefeb, 0x09ec0c63, 0x1f0e4740, 0x5c9cc4}}, + {{0x1ce80d6e, 0x0ed6534a, 0x06b2ad6b, 0x006ceb42, 0x0af964f0, 0x0c4e9b84, 0x0966a09d, 0x0f43bfda, 0x84efe0}}}, + /* 3*16^45*G: */ + {{{0x0883e382, 0x0464c2a2, 0x154dbce3, 0x009f9dea, 0x07431d06, 0x001ca900, 0x01716f89, 0x12577bfb, 0x5ac8e1}}, + {{0x1dfeaadc, 0x09b9ecde, 0x13674b94, 0x0dd9427a, 0x03976de7, 0x1ff9784b, 0x1200e723, 0x00098f51, 0xfcb7e5}}}, + /* 5*16^45*G: */ + {{{0x0f01a3e8, 0x052183bf, 0x120253af, 0x16ca865c, 0x07362c6e, 0x0ea2706b, 0x0460b545, 0x1316f224, 0x99dc06}}, + {{0x00f61114, 0x14322ff2, 0x1e3ca514, 0x0ce069af, 0x00044b7a, 0x0388b8ec, 0x0af1a5eb, 0x1ba47730, 0x67c69c}}}, + /* 7*16^45*G: */ + {{{0x0cd535ab, 0x01fbd802, 0x1d9370ce, 0x09b107d0, 0x1b9f3772, 0x01abe7e7, 0x18591009, 0x0c31c080, 0xabe2f3}}, + {{0x117b9c1a, 0x0388d9a2, 0x0b237664, 0x1cf43187, 0x1f7957fd, 0x1f959016, 0x0a4f7836, 0x0996eab6, 0x4f02d6}}}, + /* 9*16^45*G: */ + {{{0x0909970c, 0x1a5b359b, 0x19b93836, 0x11b74b33, 0x0099e451, 0x1d8fbbf3, 0x1c84df1b, 0x1af1873c, 0x227cd0}}, + {{0x1f809727, 0x02d25718, 0x0e67b10a, 0x01d87efd, 0x15defa21, 0x043a0e7f, 0x04761f5b, 0x0e390327, 0x2225e7}}}, + /* 11*16^45*G: */ + {{{0x09e65b59, 0x0cd6fe4c, 0x113fddf3, 0x02045efa, 0x1053b7a4, 0x14985466, 0x16da09fb, 0x10415db8, 0x363146}}, + {{0x09b4c2cf, 0x0050b213, 0x116dba72, 0x0792076b, 0x07fc1c14, 0x1c7c9011, 0x0a4a3a09, 0x0c42f12e, 0x1d87db}}}, + /* 13*16^45*G: */ + {{{0x0d4c2506, 0x0bd8ac5e, 0x07a7ebc0, 0x18bb8fe3, 0x11fec5b6, 0x14670c4e, 0x028f9d29, 0x16cd0d63, 0xf65ed6}}, + {{0x1913dfac, 0x0296e129, 0x15950af3, 0x11df8699, 0x0e7bd412, 0x0e17e9bb, 0x0ba14957, 0x0d065175, 0xd6d0bc}}}, + /* 15*16^45*G: */ + {{{0x1b47a80b, 0x0f27cba9, 0x0925d5e0, 0x0f8b4cc8, 0x1dba8ff9, 0x0e13b7d5, 0x0d5ca776, 0x1f423ec2, 0x66a0de}}, + {{0x1f795e8b, 0x1b8cafc7, 0x1bb74803, 0x014850a4, 0x0f474c23, 0x0f92b0d7, 0x09072b63, 0x0dbc6f59, 0x3e24aa}}} + }, + { + /* 1*16^46*G: */ + {{{0x08523eb3, 0x1eecd599, 0x1b1b12b9, 0x1474eaaa, 0x1cde3351, 0x0c22279e, 0x16ad1ab0, 0x1d7f1516, 0xbaffd4}}, + {{0x15acf387, 0x0bc18066, 0x122dbb86, 0x02399f7e, 0x0c09c245, 0x0759bcad, 0x1a0c00ea, 0x18bb792b, 0xfa93d}}}, + /* 3*16^46*G: */ + {{{0x14737641, 0x004cda77, 0x10b84eb4, 0x158182cd, 0x03fb71af, 0x1a891b2b, 0x07b5dde2, 0x04488391, 0x91b445}}, + {{0x0101bbe0, 0x1289594f, 0x01df40fc, 0x0fb8ccdc, 0x1b428c9d, 0x11ad5817, 0x05d8b04c, 0x17a6ffb5, 0x3f4463}}}, + /* 5*16^46*G: */ + {{{0x06dd01df, 0x1515d5c1, 0x03fbee71, 0x1dfeeca7, 0x09165743, 0x1363e434, 0x01ea8dfa, 0x0bbd05b6, 0x296d13}}, + {{0x0a3a0dc8, 0x0a869905, 0x199bd812, 0x15ec31cb, 0x177cadff, 0x094bbb63, 0x1790ae1c, 0x1bb25c28, 0x14054e}}}, + /* 7*16^46*G: */ + {{{0x1650f5dd, 0x13f37836, 0x046cb231, 0x1fc24843, 0x04a9654f, 0x0178f8cf, 0x08c63c4f, 0x1e7226cf, 0x4b0942}}, + {{0x1aeddc6d, 0x1752de63, 0x19ce98b0, 0x18cf05c9, 0x1c25f023, 0x0080ab09, 0x0f038157, 0x14c6cd95, 0x7432aa}}}, + /* 9*16^46*G: */ + {{{0x04e4a96f, 0x11baf478, 0x1956c51e, 0x10c5686a, 0x0e4af188, 0x0dc7e269, 0x046a0cfb, 0x14c5fd98, 0x36377}}, + {{0x11e08cdb, 0x1d7dbf02, 0x0244c9a2, 0x13184286, 0x06263840, 0x062abc2a, 0x1e0e364c, 0x03a6a9fb, 0xa1de19}}}, + /* 11*16^46*G: */ + {{{0x079b5a59, 0x00fe9f0b, 0x1a798a85, 0x03d13d64, 0x03251c62, 0x16ab84ec, 0x058af2ef, 0x1ee61ebc, 0xa1041a}}, + {{0x0c5514a3, 0x0695a011, 0x0b19b676, 0x00d21c3d, 0x02afbfb3, 0x086c39de, 0x0c650899, 0x0d551eb1, 0xad4217}}}, + /* 13*16^46*G: */ + {{{0x0ddd597b, 0x1746d836, 0x015d637a, 0x1262e199, 0x12007d88, 0x0d687cf4, 0x191c0cdc, 0x15a163ca, 0xda2167}}, + {{0x1de7fa04, 0x140b93f1, 0x13e7d189, 0x1c54a428, 0x0ebf6cdd, 0x180753cc, 0x14d87fd9, 0x16c4a8dd, 0xa21992}}}, + /* 15*16^46*G: */ + {{{0x13f7dbb0, 0x09a51115, 0x0fca7026, 0x1c47b84d, 0x0f29df4e, 0x1dc390b2, 0x19e2f218, 0x1846fed8, 0x1c3fdb}}, + {{0x12e16d32, 0x1265ee4b, 0x083e2b75, 0x0c8c7000, 0x118d41f0, 0x129ca525, 0x004fc2ba, 0x0206f253, 0x39260f}}} + }, + { + /* 1*16^47*G: */ + {{{0x1a111101, 0x1a9046c5, 0x16cf17e0, 0x1e1634ed, 0x04c96479, 0x11a692bf, 0x1d9bb48a, 0x0131f9da, 0x6ad2a}}, + {{0x1fb37ef4, 0x0d3dd4ea, 0x03a26bb0, 0x053b056e, 0x162a0de4, 0x000ddcf5, 0x18d56693, 0x038b1f0b, 0x2d5b8b}}}, + /* 3*16^47*G: */ + {{{0x102bef6f, 0x17e1c23b, 0x0c7b90dd, 0x1c9e308a, 0x0d475bba, 0x05eb35ec, 0x15c813de, 0x0aad8779, 0xf1a2ca}}, + {{0x0f6c1ca3, 0x0d968fec, 0x154ad004, 0x08fd503f, 0x00168b0b, 0x0a0bee01, 0x04fb7d15, 0x15e09106, 0xb39b59}}}, + /* 5*16^47*G: */ + {{{0x00455367, 0x030147e5, 0x1584f820, 0x09e59049, 0x11851e6c, 0x00b2c75f, 0x00c3b864, 0x093fc770, 0xe924ad}}, + {{0x08257e92, 0x1e8c67c1, 0x099d4ad7, 0x1463549f, 0x1bb6f52d, 0x029c9eb7, 0x1b55d482, 0x12f34287, 0xfcc97d}}}, + /* 7*16^47*G: */ + {{{0x02f8f1e7, 0x08f849ca, 0x147e78ba, 0x0954ba9b, 0x122f68dd, 0x09a882fd, 0x09be802e, 0x0fb8bee0, 0xf49d9c}}, + {{0x114d9972, 0x1114558c, 0x135ea0e4, 0x0002789c, 0x0f67901b, 0x09d9dcca, 0x12b9ab97, 0x08407c75, 0xf5585d}}}, + /* 9*16^47*G: */ + {{{0x1b219a79, 0x19d4b3bf, 0x0609e9de, 0x19a882fd, 0x189e65c4, 0x01aabaa8, 0x1522c38f, 0x007c8d53, 0x28b04d}}, + {{0x102dbe24, 0x05fbe6c8, 0x0012f97e, 0x0cd99f0c, 0x0206b861, 0x12b90c1f, 0x1c51673f, 0x13cb4299, 0xf658da}}}, + /* 11*16^47*G: */ + {{{0x17774af9, 0x14116ce2, 0x1182b62c, 0x0d74ca22, 0x0efb54c1, 0x01c94435, 0x1a4f5a14, 0x17cf983f, 0x3f4766}}, + {{0x1d4de990, 0x1e6bfb26, 0x0dcc9bfd, 0x1299fbf3, 0x05f511ca, 0x1c483737, 0x12e8eac5, 0x1ad4e663, 0xcc810d}}}, + /* 13*16^47*G: */ + {{{0x08e57705, 0x020cf8f2, 0x1356639e, 0x1d6ff590, 0x1361721c, 0x0d5a0eb7, 0x19e47cab, 0x00581f1d, 0xe3249e}}, + {{0x18caec0c, 0x0a58cf41, 0x1ce10882, 0x128bae2c, 0x06b5a501, 0x1c60f924, 0x141f72dd, 0x10e026d2, 0xa66665}}}, + /* 15*16^47*G: */ + {{{0x125b93ac, 0x1c5e757d, 0x01fe34b1, 0x0404a20b, 0x1b4e917e, 0x13b49efd, 0x1872f7e7, 0x017bf6f2, 0xa68958}}, + {{0x0f589aab, 0x11e8e26b, 0x113f4eba, 0x03f02fb3, 0x19ff2fcf, 0x1780af82, 0x00faa9fc, 0x12969e0f, 0x4657ca}}} + }, + { + /* 1*16^48*G: */ + {{{0x113728be, 0x07907fd9, 0x11ae529b, 0x072b2347, 0x15fc5964, 0x1fc1a218, 0x09d89cdb, 0x0ef4f092, 0xa6d396}}, + {{0x0357f5f4, 0x15d5c19e, 0x010166fc, 0x15241845, 0x1ecdf824, 0x1d5e9693, 0x00599ae2, 0x0e936171, 0x674f84}}}, + /* 3*16^48*G: */ + {{{0x0f15d864, 0x02a5ab4e, 0x13234f30, 0x0dfb8d43, 0x0cf35240, 0x1673df13, 0x0c36bf23, 0x1af8bbdb, 0x7ef66}}, + {{0x140907fe, 0x0312a13b, 0x1392a2d5, 0x0e1c7639, 0x1505e9f4, 0x062910fe, 0x1a941b50, 0x0bb713bc, 0x2db332}}}, + /* 5*16^48*G: */ + {{{0x17c7c05e, 0x14a8a1e0, 0x19505ab1, 0x07972a59, 0x08c0bb28, 0x1397baf9, 0x118053ce, 0x0bf80db8, 0x82df4e}}, + {{0x18fff26b, 0x0b09e816, 0x0b6cc02e, 0x0bb28d08, 0x1cbd1cf1, 0x0b10890b, 0x08289d48, 0x193192c8, 0xe4e188}}}, + /* 7*16^48*G: */ + {{{0x140368b0, 0x0570ea0a, 0x1ba52760, 0x09845f1f, 0x07a62132, 0x0dc69c72, 0x11a9f679, 0x13782561, 0x261efc}}, + {{0x1deb011f, 0x1d692acd, 0x06d74c04, 0x0817c3c7, 0x1ff797e3, 0x02966b27, 0x13a7f722, 0x1b7c70df, 0x8a9d2a}}}, + /* 9*16^48*G: */ + {{{0x15eb8034, 0x0819f4a8, 0x1a3292bc, 0x1666bead, 0x1692df30, 0x1f2cecf3, 0x1e4526a9, 0x1aef4584, 0x6d48df}}, + {{0x1ab0ce30, 0x039843d2, 0x0fa2587a, 0x0421d454, 0x14763080, 0x1cb24f02, 0x04bcf579, 0x08a2cbba, 0x3cb472}}}, + /* 11*16^48*G: */ + {{{0x140535c8, 0x08a1efe2, 0x036c4fad, 0x014ac619, 0x14e6f65f, 0x11fda7e2, 0x048e9244, 0x03cf7731, 0x93a5c0}}, + {{0x1d59b844, 0x04aba041, 0x16fb7ff1, 0x02c40926, 0x1a5c166a, 0x021ac70a, 0x0bd305aa, 0x12093018, 0x2d440e}}}, + /* 13*16^48*G: */ + {{{0x1e2047ba, 0x130d2b34, 0x0c3d94a8, 0x0e0932d7, 0x07031e54, 0x10700beb, 0x0aeecd76, 0x0522c24e, 0x3fb0b9}}, + {{0x1db24158, 0x1ff66a76, 0x1c0274d5, 0x0415cee2, 0x06dc86c4, 0x110e4cb3, 0x1e5329c9, 0x1cd042fb, 0x9d467a}}}, + /* 15*16^48*G: */ + {{{0x02df71c1, 0x05ededd7, 0x0edc8e80, 0x030d7d5f, 0x1e4381c3, 0x1dd4ef19, 0x0f5741d8, 0x073c11d0, 0xdab094}}, + {{0x04c3a1e3, 0x039a4209, 0x0d138eee, 0x0c661949, 0x00b3d6e9, 0x14379069, 0x13bce16b, 0x03ca89c3, 0x763cbc}}} + }, + { + /* 1*16^49*G: */ + {{{0x0514c6fd, 0x177b17fa, 0x0ac04f9b, 0x10769a1b, 0x15936fd6, 0x0dab887f, 0x1380cf53, 0x1001139e, 0xac25da}}, + {{0x05830541, 0x05a9cbb8, 0x0efcde98, 0x1307d048, 0x1338c810, 0x1498950d, 0x11ee20f6, 0x130b9689, 0xebc69d}}}, + /* 3*16^49*G: */ + {{{0x12fd0e3d, 0x0ca0e3f1, 0x09eb5820, 0x03c9b8a8, 0x05547e63, 0x04338f0b, 0x122ed35d, 0x0d893747, 0xeea7e6}}, + {{0x191d5868, 0x0208fb46, 0x0678f304, 0x175b4460, 0x17d985ac, 0x1f93df4d, 0x0984a210, 0x0b73f112, 0x83fed4}}}, + /* 5*16^49*G: */ + {{{0x0ccb63b3, 0x0cf8a793, 0x10239744, 0x1ffcd888, 0x1c67b7dd, 0x0a59aa01, 0x06f6eb46, 0x1a7d27c4, 0x9a3de2}}, + {{0x1df93fcf, 0x0e2994bb, 0x16089800, 0x003b3fde, 0x13c4c49c, 0x139b7740, 0x0b22027c, 0x120c2222, 0x2f809b}}}, + /* 7*16^49*G: */ + {{{0x163f1117, 0x07651a6e, 0x1fdb62f9, 0x12dee174, 0x1adaf348, 0x0698091f, 0x0b6c1440, 0x1e96a772, 0xa7c382}}, + {{0x1934cb9a, 0x091062f0, 0x1129a330, 0x1d6edda7, 0x1cfb5ae4, 0x1bbbb82e, 0x1e201167, 0x022cec37, 0x1b91e5}}}, + /* 9*16^49*G: */ + {{{0x06774a96, 0x05e40e2d, 0x0e38fa14, 0x063fb230, 0x0f497e82, 0x1dfe41d3, 0x084e1c50, 0x1319b0c2, 0x555aa9}}, + {{0x06db0e34, 0x0a04b96c, 0x189be9a7, 0x1aba9791, 0x0bbb89a0, 0x00f389a8, 0x11a66751, 0x0d1a40f7, 0xb05328}}}, + /* 11*16^49*G: */ + {{{0x0f7dac7d, 0x17bf779d, 0x0904848c, 0x0e572422, 0x1c369165, 0x0bc7c6bb, 0x0b5ed633, 0x0b66914f, 0x1a42f}}, + {{0x0195e46e, 0x1c4a518c, 0x13aa5ac9, 0x15e52651, 0x19216172, 0x1caa5c5f, 0x1e04d25f, 0x070aa40e, 0x957a9c}}}, + /* 13*16^49*G: */ + {{{0x002afc36, 0x015d0ea1, 0x0c1c74f8, 0x1bddaa28, 0x1d3a3134, 0x04f78da2, 0x18f4e96c, 0x06fd60b9, 0x4b47f5}}, + {{0x0f8133ff, 0x144fbb53, 0x17ef68d3, 0x1597d364, 0x1f573345, 0x037d0746, 0x1c30b72c, 0x0073390b, 0xf2fc45}}}, + /* 15*16^49*G: */ + {{{0x17d17f68, 0x15f971e3, 0x02eb61aa, 0x0b43bf97, 0x0418f791, 0x0b7a9b57, 0x033b5594, 0x1398a49d, 0x6b3dec}}, + {{0x09232402, 0x1d73d106, 0x1732da33, 0x0552d54d, 0x15d4747f, 0x00da0b66, 0x07bc1426, 0x06ffbdfb, 0xb86539}}} + }, + { + /* 1*16^50*G: */ + {{{0x0fd20bae, 0x0ea71bd1, 0x0d2a0455, 0x06ace5ab, 0x1343a260, 0x1d090bb6, 0x136409ee, 0x1db8779f, 0x285250}}, + {{0x14e0ab97, 0x0ef22ad2, 0x1bfcc8fe, 0x163459e3, 0x0c1716e9, 0x02568823, 0x1aa0fdca, 0x10de95af, 0x7866c0}}}, + /* 3*16^50*G: */ + {{{0x0636a50b, 0x0443b55d, 0x0dd465b3, 0x1dec2d57, 0x0baf65d2, 0x1d097e3c, 0x1d7160db, 0x0ca8bab4, 0xf1e3c5}}, + {{0x0b3128b6, 0x1bbc8a75, 0x0b5e9bb7, 0x1f4aeda4, 0x1f3136b7, 0x1533fb52, 0x139db1cd, 0x0f4dc3df, 0x12b884}}}, + /* 5*16^50*G: */ + {{{0x0e583340, 0x0bf8990a, 0x0d3cec94, 0x1836d6ba, 0x1228cf45, 0x06d5fd4d, 0x129db61f, 0x13903c26, 0x584d72}}, + {{0x14fb24b9, 0x17b72f4b, 0x05301c1c, 0x0ee14cc9, 0x0affa8f1, 0x1e2c9818, 0x02af34c1, 0x148ac1b0, 0x2fdd80}}}, + /* 7*16^50*G: */ + {{{0x0235809b, 0x1641f6f0, 0x1ae05ce4, 0x0e5be16b, 0x03c453c5, 0x0146e11c, 0x1df478b8, 0x001906fb, 0xbaaeae}}, + {{0x0154fd62, 0x0b0ec52e, 0x14b9f973, 0x18788543, 0x1f299835, 0x183de5a4, 0x0e02d288, 0x1067e649, 0x325788}}}, + /* 9*16^50*G: */ + {{{0x0d612268, 0x10021620, 0x17b405bd, 0x1eb3be14, 0x0b8b906c, 0x0f7d21ca, 0x0c69944e, 0x0c6c1842, 0x6c7e4}}, + {{0x060166a0, 0x05a5b009, 0x0b9c262f, 0x1b14b4f0, 0x053ca238, 0x03ae717a, 0x0335d1ff, 0x0bbee5bb, 0xcb6ad5}}}, + /* 11*16^50*G: */ + {{{0x012fbdc8, 0x0a1d1adc, 0x1038a8ef, 0x1c419545, 0x1a36db89, 0x1663db88, 0x10f96f0b, 0x1bd57acc, 0x64131}}, + {{0x09f99380, 0x09ff984d, 0x1ec08297, 0x15c4d163, 0x17598603, 0x006c9a4a, 0x00a3cace, 0x15865ace, 0x882c7f}}}, + /* 13*16^50*G: */ + {{{0x0bac9f32, 0x0f580032, 0x1a26c19d, 0x104398b2, 0x16400443, 0x00b7f0cd, 0x08de2859, 0x15984eb8, 0x366bb7}}, + {{0x1c85d47d, 0x17872e7d, 0x1c09a290, 0x19ca180f, 0x1cfc01fd, 0x01d5c6b0, 0x1c193c1e, 0x0e10f0b5, 0x7d107b}}}, + /* 15*16^50*G: */ + {{{0x06dd27eb, 0x1e5a9294, 0x0ed588c0, 0x18ab86f6, 0x032ecb98, 0x0871cddf, 0x1001ac9f, 0x04af98e7, 0xb767db}}, + {{0x0f65dac4, 0x0a90d23e, 0x1803b505, 0x0e016890, 0x1d85b64b, 0x05c0b5cc, 0x072d73ab, 0x1864c245, 0xdc1308}}} + }, + { + /* 1*16^51*G: */ + {{{0x1e07e4f1, 0x18f9d151, 0x17099f05, 0x0a28fba1, 0x0890e1fc, 0x15e03f7c, 0x19be0637, 0x00c5da06, 0xc472c1}}, + {{0x06b0daa9, 0x18e341ec, 0x0ad76295, 0x076f63c4, 0x067d885f, 0x15ad426b, 0x03a590ca, 0x00328bee, 0x41820e}}}, + /* 3*16^51*G: */ + {{{0x02f8acb1, 0x1b4a9a55, 0x0fc14fd0, 0x1acaa8c2, 0x0c31eb39, 0x1bd25c76, 0x0f5a1786, 0x0732a8bc, 0x86f88f}}, + {{0x05098a19, 0x05821688, 0x05949c45, 0x14c57dd2, 0x1b1214ee, 0x0bc7dac8, 0x035acdf2, 0x0d34d047, 0x2ccfdd}}}, + /* 5*16^51*G: */ + {{{0x1cadab66, 0x041bbdb7, 0x14d580b6, 0x0d46787b, 0x1f9a0e1c, 0x134b306c, 0x19d1f7dd, 0x03f93291, 0xa2a3be}}, + {{0x0c1aeb12, 0x1a509242, 0x002b497b, 0x1bd14a69, 0x15ee1fb2, 0x1f6ba691, 0x199c1941, 0x1cd6a497, 0xa93bd8}}}, + /* 7*16^51*G: */ + {{{0x007c25bf, 0x04e91099, 0x0b6025ee, 0x178eef7c, 0x080be82f, 0x09233be0, 0x16e4d9f8, 0x1daadcf1, 0x354e7c}}, + {{0x1a864211, 0x091d1cca, 0x082a8854, 0x0ead960b, 0x1e5585fd, 0x0c1252e7, 0x01c39baf, 0x1d377328, 0x629d62}}}, + /* 9*16^51*G: */ + {{{0x15e1dad8, 0x13ec1703, 0x112f4b92, 0x014f0b0d, 0x19f498b8, 0x07b90604, 0x016de6d7, 0x155ebbd0, 0xc751c9}}, + {{0x0e4afc8b, 0x09b59b09, 0x02a300b4, 0x112e1474, 0x1a4ffe6f, 0x00feb6e4, 0x178afad3, 0x06ff8f33, 0xcb9864}}}, + /* 11*16^51*G: */ + {{{0x099d9ba2, 0x1890d908, 0x0aa9d5f4, 0x0cafad2f, 0x19ca80cf, 0x09435a87, 0x0085e2ad, 0x08373a3a, 0xaee9cc}}, + {{0x1ed2ad58, 0x06b0241d, 0x05d2439e, 0x1cd1c4d4, 0x0b1f5312, 0x1dfd8063, 0x0dbdefa5, 0x005b6a54, 0xb72cf3}}}, + /* 13*16^51*G: */ + {{{0x094d208d, 0x1ff84124, 0x1ce46918, 0x1b51fe1f, 0x1f0cefb0, 0x1057958f, 0x1b15affd, 0x08d4f225, 0xd0d3f}}, + {{0x1d45d1b1, 0x117a9fbc, 0x0776aff5, 0x0781a34e, 0x09ff0b21, 0x06d32fc8, 0x05a6c11d, 0x1015c3ee, 0xdc371b}}}, + /* 15*16^51*G: */ + {{{0x19cfd890, 0x17411640, 0x01c45171, 0x0d86e6f8, 0x041e1cb3, 0x0c1c3f2a, 0x14d7d1f3, 0x0d68826e, 0x778d14}}, + {{0x16f057f2, 0x0d43fd3e, 0x1482b2b2, 0x148a911d, 0x0cd3796c, 0x18c6cbc3, 0x0bdca949, 0x02676023, 0x3c85ba}}} + }, + { + /* 1*16^52*G: */ + {{{0x039bb85f, 0x10784e1c, 0x14398b0c, 0x03f60d40, 0x13458010, 0x0164cd6a, 0x0cad55d6, 0x11a2ccc8, 0x55d539}}, + {{0x0fed936f, 0x1fb188c2, 0x0cf6787d, 0x1ad4fe30, 0x0a72ad90, 0x154f475d, 0x18b41671, 0x12093ff1, 0x576e22}}}, + /* 3*16^52*G: */ + {{{0x12ea285a, 0x03f15c90, 0x0e443470, 0x0383cdef, 0x0a7a39f0, 0x02c6eee0, 0x022de160, 0x011029f1, 0x1bb464}}, + {{0x107dc702, 0x006453cc, 0x0bea53b7, 0x05469732, 0x0a4fc1e5, 0x0cdc495a, 0x0496903f, 0x17f5f5c2, 0x8a3016}}}, + /* 5*16^52*G: */ + {{{0x1539785a, 0x08094806, 0x0a5fc051, 0x11a0ed70, 0x07a548c8, 0x1f133c31, 0x053b825c, 0x0e1c05f4, 0x4bc4e}}, + {{0x0a62e3bb, 0x1cc823ae, 0x0c9d70d4, 0x002ee4f4, 0x1fb4f877, 0x10e79f9e, 0x130e97d6, 0x04971969, 0x5729f2}}}, + /* 7*16^52*G: */ + {{{0x0114cfb5, 0x096a5d8f, 0x1569a8c4, 0x0c313547, 0x10876d13, 0x1cf0dbef, 0x05cd61dc, 0x1fb83f10, 0xd3e492}}, + {{0x097f7045, 0x075cd52b, 0x1d53bbef, 0x11e0dc8c, 0x1fea39c8, 0x133b5f8a, 0x122c7fb8, 0x014e7f18, 0x3604a7}}}, + /* 9*16^52*G: */ + {{{0x0c55ddff, 0x1133a5dd, 0x152de1c6, 0x1a367ec9, 0x1c1791da, 0x091887e6, 0x094e2939, 0x0ab0c508, 0xbebfc2}}, + {{0x1ea2f303, 0x0a6d8651, 0x02ea9c1b, 0x15045aca, 0x0576c3cc, 0x08e25bbb, 0x133a28e8, 0x0cb812c0, 0x850de2}}}, + /* 11*16^52*G: */ + {{{0x099ead51, 0x0d7a0f26, 0x164893a4, 0x06a87443, 0x184715da, 0x098e8b03, 0x1580beca, 0x1b8e7a41, 0x36e984}}, + {{0x0e0e5e3e, 0x17dcea13, 0x10a02bf1, 0x177d82e0, 0x12b203ba, 0x0fe4d671, 0x017d2fef, 0x08e437e9, 0x143771}}}, + /* 13*16^52*G: */ + {{{0x03093df0, 0x145bbdd9, 0x1d91935e, 0x1c4902ce, 0x193af785, 0x0a3caa6b, 0x12bbcc54, 0x00087ec0, 0x91b675}}, + {{0x12cc9f14, 0x06f461be, 0x12bd9fd7, 0x0d0bf1f3, 0x01c5d933, 0x1d6d4b71, 0x00351df1, 0x03cb0494, 0x7fedb}}}, + /* 15*16^52*G: */ + {{{0x1b7b8dc4, 0x11b3dc37, 0x06ce1228, 0x09260515, 0x02fac5b3, 0x1f0d01b0, 0x00f9f125, 0x18f43891, 0xc5d9c3}}, + {{0x1b2df0ea, 0x0b24bc68, 0x1f524dbb, 0x11ee5fa3, 0x10af3d0d, 0x01c302e2, 0x1e796023, 0x1c4b9fb6, 0x3e59b9}}} + }, + { + /* 1*16^53*G: */ + {{{0x12513926, 0x116de4e1, 0x1b217b31, 0x0d1281df, 0x03383cc2, 0x1d5925fe, 0x1c9a53fa, 0x08c79410, 0x884286}}, + {{0x0fb8a54d, 0x17214155, 0x16f05683, 0x1d6245d7, 0x01207ce0, 0x06d9b2ec, 0x1569a598, 0x1380385b, 0xf77842}}}, + /* 3*16^53*G: */ + {{{0x0520f1f1, 0x095d60cb, 0x1fdf693b, 0x03693cc8, 0x16f4ad7f, 0x1e8b4667, 0x00675697, 0x06deede1, 0x3bad9d}}, + {{0x1698df4d, 0x10cb8392, 0x0d9c961a, 0x1303449d, 0x00e80499, 0x1d3ecef6, 0x1966f367, 0x1c67c49c, 0x49f99d}}}, + /* 5*16^53*G: */ + {{{0x1185ae66, 0x18f22545, 0x09e0f7c2, 0x182db7df, 0x0118ba6e, 0x0fa9e892, 0x11b59e9f, 0x1635b618, 0xa6b3a4}}, + {{0x0bfbf21b, 0x1f5aa9fc, 0x0c92375e, 0x1e14bbeb, 0x1e8d8bcb, 0x148e6cb4, 0x188c4d86, 0x1aec7112, 0xcb6e8}}}, + /* 7*16^53*G: */ + {{{0x0c630e3a, 0x0b426727, 0x1cfc70aa, 0x00c182ff, 0x110c1f61, 0x11d3ec3f, 0x1293889f, 0x0b4d9222, 0x1f848f}}, + {{0x06ca610a, 0x176cffb4, 0x0d65c92b, 0x0724d7fc, 0x1a4264ba, 0x041e8d4e, 0x058e18a7, 0x0599a0df, 0xa02855}}}, + /* 9*16^53*G: */ + {{{0x041bcd10, 0x0ff79e6e, 0x0d138553, 0x12aaec8b, 0x02eb211b, 0x133be365, 0x0d622c68, 0x097d2938, 0xcfd1e5}}, + {{0x0a62e732, 0x000af5cd, 0x154e596b, 0x1322ba10, 0x12fafacd, 0x08dead82, 0x02ee715d, 0x0bec012b, 0xf4e31f}}}, + /* 11*16^53*G: */ + {{{0x028da5fb, 0x1d30ec91, 0x01c39c93, 0x097ebc55, 0x1291b90e, 0x0af1f3b8, 0x19544b1e, 0x01808d93, 0x4b3e73}}, + {{0x1c169e48, 0x1f8531c5, 0x08d1caef, 0x07423938, 0x0b48c65a, 0x1d03dc70, 0x03a7a032, 0x09b446cc, 0x8c4096}}}, + /* 13*16^53*G: */ + {{{0x1f894780, 0x0748d2c4, 0x06bb176e, 0x139946b1, 0x0d8f737e, 0x1c52a5a1, 0x1f9c7552, 0x1bee8871, 0xafe915}}, + {{0x1511d444, 0x1cb4aa9e, 0x102bd14b, 0x1d17ce75, 0x12e36909, 0x01a1199f, 0x1a1aa52d, 0x0811a408, 0x3caec3}}}, + /* 15*16^53*G: */ + {{{0x1182fa6e, 0x0d18fe5e, 0x00722bfd, 0x0c65bad3, 0x1c9e7c0a, 0x11d1b69a, 0x1215619a, 0x05021ff5, 0xc0548}}, + {{0x061cd145, 0x15e7f55b, 0x1db407db, 0x0cc8b096, 0x1602bf5e, 0x05c4a32e, 0x14cf46aa, 0x195a1e3e, 0x2f9cd2}}} + }, + { + /* 1*16^54*G: */ + {{{0x14441fbb, 0x105aead6, 0x1b44578f, 0x150a414b, 0x125559ea, 0x062af6dc, 0x0751fed8, 0x09c43bc4, 0xb4958c}}, + {{0x0add7118, 0x03f1e4fa, 0x118e1053, 0x13ec265a, 0x0b7e12db, 0x00fde1c6, 0x03bf9701, 0x17f32cc8, 0xfcd6e7}}}, + /* 3*16^54*G: */ + {{{0x171f07f1, 0x176b4261, 0x15c31296, 0x19db6e61, 0x0684b878, 0x105b2303, 0x11348cba, 0x0bcf6408, 0xb3a43f}}, + {{0x001dfda5, 0x1e6917a7, 0x12c3b314, 0x10ef419b, 0x15ee7ec7, 0x1139b4cb, 0x1ae1060c, 0x0b6491fa, 0x34c64f}}}, + /* 5*16^54*G: */ + {{{0x0b559d49, 0x1be4bd23, 0x1726d13f, 0x0368d21b, 0x008b148e, 0x17fec260, 0x052b0998, 0x0d348d7c, 0x452e98}}, + {{0x1a0d6ba7, 0x03e30236, 0x07b9095d, 0x050ad876, 0x1ee52598, 0x02bdb3b0, 0x0343d700, 0x11e32bf0, 0x8c5e8a}}}, + /* 7*16^54*G: */ + {{{0x13ce94da, 0x1bd33f5a, 0x00a79814, 0x049e84ad, 0x074ee8bb, 0x106e1d62, 0x0aed4737, 0x1a918dac, 0x19a7f5}}, + {{0x1025e7bb, 0x182238b1, 0x097ac0dc, 0x04a60d5c, 0x0a2e8fb6, 0x08ea2100, 0x170cbda9, 0x14f5260e, 0xa2504b}}}, + /* 9*16^54*G: */ + {{{0x147dc697, 0x0b4b6636, 0x1856e6ee, 0x1c315f6b, 0x06fa417e, 0x18595afe, 0x1370047a, 0x004149e6, 0xbdaf5b}}, + {{0x06a479e2, 0x088e5f3c, 0x0de91dee, 0x045cf10b, 0x1aa08551, 0x1af23dab, 0x0db233d5, 0x0d97bf50, 0x3cec0c}}}, + /* 11*16^54*G: */ + {{{0x0ce05e10, 0x1005c8db, 0x1841880a, 0x1ef93e87, 0x070db8ae, 0x1bff4267, 0x0576ae12, 0x1d2be73a, 0x265dba}}, + {{0x171324f4, 0x1bf80c58, 0x19319fff, 0x07e7267a, 0x15dcb066, 0x0745ab65, 0x1eb7cecf, 0x1a134606, 0x58df63}}}, + /* 13*16^54*G: */ + {{{0x13fe5938, 0x08ade2ad, 0x0db5f37b, 0x10607b6c, 0x068669ec, 0x04ea9d2b, 0x0e5a27dd, 0x07e2fccc, 0xc43e08}}, + {{0x183732f3, 0x13cbab76, 0x1101d1dd, 0x0460e2c4, 0x0402eab6, 0x0181d5e2, 0x1160d424, 0x12473f79, 0x54c602}}}, + /* 15*16^54*G: */ + {{{0x1dd52975, 0x18e387bc, 0x0d106030, 0x1e1fa60d, 0x066ba2bc, 0x086d3bd9, 0x121996b1, 0x0e0147f0, 0x7868f1}}, + {{0x1c626fac, 0x00b76a81, 0x05a4110c, 0x0df3d94d, 0x1276c68f, 0x10e36d88, 0x1b8444fe, 0x19e6242f, 0xe89097}}} + }, + { + /* 1*16^55*G: */ + {{{0x0e12e1df, 0x0127321b, 0x1d87412b, 0x0ffa16fa, 0x0027cd8a, 0x1f89d9a3, 0x0ad904d2, 0x12d11d26, 0xd0e091}}, + {{0x1fd28fbe, 0x132a26dc, 0x11ae37da, 0x19897b30, 0x1f867544, 0x105b48ed, 0x114ad3ad, 0x0b3fcfa2, 0x69c9a}}}, + /* 3*16^55*G: */ + {{{0x084aa098, 0x186c2880, 0x1b8f80ae, 0x02028152, 0x1fa8509c, 0x1ed65fe0, 0x03ace629, 0x0a942661, 0xb517a4}}, + {{0x0540efbf, 0x0025acfa, 0x0911ff58, 0x0916a8d2, 0x06fa3a4d, 0x1f17d879, 0x1e6983a8, 0x0fa183f0, 0xa3d87}}}, + /* 5*16^55*G: */ + {{{0x0744bfa1, 0x0cad6552, 0x04d90f5b, 0x0da4f9c1, 0x1e387cc2, 0x13896c79, 0x1bd9ef08, 0x07096a2c, 0xf8ec14}}, + {{0x12b65f6d, 0x14927319, 0x04001831, 0x06f58b87, 0x00f610a6, 0x07d934eb, 0x0698c8da, 0x164227f7, 0x761134}}}, + /* 7*16^55*G: */ + {{{0x1227a4bb, 0x1161df49, 0x03667cbd, 0x0d63e01f, 0x0f2e64be, 0x075690ea, 0x0b9e539d, 0x0f1b6f7f, 0x320cff}}, + {{0x10f3d2d4, 0x00e64835, 0x18be5c16, 0x0e46e813, 0x16299604, 0x0b512a7f, 0x1a4aadde, 0x1a80e550, 0xaf9fe8}}}, + /* 9*16^55*G: */ + {{{0x1c2ca683, 0x1adad2f2, 0x0569cdce, 0x19e6bc15, 0x1426a206, 0x0ee65aa1, 0x16145fb7, 0x0f8d4f5d, 0xc08de}}, + {{0x1db5f259, 0x12036dab, 0x1a9a31a4, 0x11af6fc1, 0x00e79c3c, 0x14ce6fe7, 0x1866df20, 0x10abd42d, 0xddb76d}}}, + /* 11*16^55*G: */ + {{{0x052ae5cd, 0x033d67c1, 0x1f75e187, 0x0ca5f5e9, 0x0390995b, 0x1bd22672, 0x10f4639b, 0x0d5a188f, 0xd1f8c7}}, + {{0x1e6d2dda, 0x15cbde1f, 0x027d3f1f, 0x15d02ad3, 0x1203239b, 0x0bd80fb0, 0x000ab1e6, 0x18cc241d, 0x74d45d}}}, + /* 13*16^55*G: */ + {{{0x0bdc603f, 0x1c803355, 0x17ff96ad, 0x1acb9acf, 0x020d8c96, 0x1f63133b, 0x03024f8c, 0x0d27e712, 0xa6cb83}}, + {{0x096befcc, 0x16701f06, 0x1985cd72, 0x1d82d498, 0x10b72fb1, 0x0ded2628, 0x0bf23cb6, 0x1c8c3e79, 0xd823c8}}}, + /* 15*16^55*G: */ + {{{0x02c374b0, 0x0f1d3097, 0x1c36d28a, 0x166b316a, 0x04ef0bf5, 0x04b8a921, 0x0c84dafb, 0x123d4d86, 0x8a6c9c}}, + {{0x178c08bd, 0x1fbe7c6d, 0x03d3560e, 0x0a69e868, 0x132a0461, 0x042ee480, 0x1ebde69e, 0x09ecb9bf, 0xe4bc7f}}} + }, + { + /* 1*16^56*G: */ + {{{0x0895df07, 0x1381f887, 0x01daf61a, 0x0be7f403, 0x08ffefd7, 0x03738670, 0x1fbbad6c, 0x0a84f07b, 0x68f6b8}}, + {{0x18712655, 0x063b7c53, 0x042fdfe4, 0x0527a5e6, 0x05028cf5, 0x0226fed2, 0x139bef20, 0x17525c81, 0xcbe1fe}}}, + /* 3*16^56*G: */ + {{{0x1aa89692, 0x00c7d119, 0x1308c239, 0x1611adf2, 0x0a776713, 0x1320920c, 0x1d37a65b, 0x0e302cd1, 0x3bdfca}}, + {{0x1a510308, 0x1ededa18, 0x18bbc4e4, 0x1818c68b, 0x05333c7d, 0x10a8d76d, 0x1ee12509, 0x0d0aca2c, 0xa721f}}}, + /* 5*16^56*G: */ + {{{0x037ea1d7, 0x1cd91a16, 0x06ab9341, 0x126cb1f1, 0x19e4fb23, 0x02a928c6, 0x0158d4ca, 0x12b6ea42, 0xaca8ac}}, + {{0x1ba973a2, 0x0f7d8824, 0x0e4d7a77, 0x1b7fb882, 0x12189e1e, 0x0625c943, 0x108250c1, 0x0cfbaeb9, 0x7f12c5}}}, + /* 7*16^56*G: */ + {{{0x13245b7f, 0x0d93c0e6, 0x165fefd7, 0x1acd2d20, 0x05311a37, 0x10d7cc6c, 0x103881b0, 0x009b6ccf, 0xfa9047}}, + {{0x0ddf6bef, 0x1c19ef8a, 0x13c751fb, 0x1dd9a4c4, 0x1c189cb9, 0x11f6a078, 0x1a90b5be, 0x06ce9506, 0x1a1c8c}}}, + /* 9*16^56*G: */ + {{{0x17f0953a, 0x10fbc7eb, 0x0550e6ad, 0x122907fe, 0x092a8184, 0x1c70e97d, 0x163359ca, 0x15723eaf, 0x1d431a}}, + {{0x1d68f260, 0x1e2cebb4, 0x1c1f9f05, 0x1c535210, 0x1fae0f48, 0x0641e70a, 0x087af14c, 0x1877e322, 0x8d667}}}, + /* 11*16^56*G: */ + {{{0x05227c70, 0x1188b89b, 0x08fa9c16, 0x17d56667, 0x1c60ff32, 0x19ad9718, 0x04df7692, 0x01ab47c2, 0x6deeea}}, + {{0x0369b9b7, 0x0b6d1c08, 0x0420f6eb, 0x15d83cad, 0x0cc84287, 0x05d7f7b5, 0x19000053, 0x01f8e887, 0xcbb93f}}}, + /* 13*16^56*G: */ + {{{0x0421b54d, 0x1afeaf44, 0x159293fe, 0x1657074a, 0x09dca579, 0x0e95d8fd, 0x036352b2, 0x020c6aaf, 0x28135c}}, + {{0x0ee5d868, 0x0e6784dc, 0x18c4362b, 0x09299923, 0x18c15ef0, 0x0eba083f, 0x18541bea, 0x17c70a37, 0x9ed84a}}}, + /* 15*16^56*G: */ + {{{0x08e4ac10, 0x0bf2ac8f, 0x1892a6a4, 0x0d502559, 0x1b568799, 0x062d04ff, 0x1def5b0f, 0x0ec41620, 0x339a05}}, + {{0x0d1312a0, 0x1b6d4322, 0x07319bbd, 0x13cf11e8, 0x1553e503, 0x06fbc567, 0x11fd0e15, 0x17dbad52, 0xca985f}}} + }, + { + /* 1*16^57*G: */ + {{{0x07ea1f34, 0x1a6d58bb, 0x1ce78374, 0x17a6a808, 0x153d6646, 0x0e8bc9d9, 0x0d9b0ed0, 0x1447a8e9, 0x7f9460}}, + {{0x0d9063ec, 0x05f61656, 0x18d3ff16, 0x1f02a249, 0x16661c6f, 0x195fc783, 0x061da7c7, 0x0ef1f60c, 0xd0d516}}}, + /* 3*16^57*G: */ + {{{0x1dfc0a9d, 0x02dba64d, 0x1ddea837, 0x0846b629, 0x0a2a2de4, 0x11b23570, 0x1808a983, 0x1f098653, 0xdb43e7}}, + {{0x1e9ad713, 0x058849d4, 0x14bc153c, 0x1208e6ad, 0x19fa4883, 0x1640a677, 0x1646e295, 0x1457c6d6, 0xb0168d}}}, + /* 5*16^57*G: */ + {{{0x0283808d, 0x05e58bba, 0x190ea24c, 0x1e0f9c6a, 0x078980f8, 0x0f4890fd, 0x06bae145, 0x103dc1a4, 0xe9af30}}, + {{0x19b39d33, 0x13617c71, 0x04db4665, 0x1724a22a, 0x14971976, 0x132a87f7, 0x098216bc, 0x091388e2, 0xa976c8}}}, + /* 7*16^57*G: */ + {{{0x0d8426df, 0x1497a165, 0x1be28289, 0x0272b49c, 0x083590f4, 0x049c1dfc, 0x0601c0eb, 0x0c65900d, 0x6eb733}}, + {{0x000b4267, 0x1fbacf71, 0x1f86e0cf, 0x05d2f907, 0x08e8d925, 0x05967660, 0x0a680c39, 0x1822e60f, 0x96c56e}}}, + /* 9*16^57*G: */ + {{{0x1a16453d, 0x1e8b6be0, 0x040cf6fd, 0x1d0f7cec, 0x0d0e68b7, 0x0dc8fc5a, 0x1d1785d0, 0x0bc0f3ab, 0xd3979d}}, + {{0x07b6d737, 0x1e5dc18b, 0x1a58693c, 0x1becc514, 0x0456917d, 0x092ba9b9, 0x16e69342, 0x06baf335, 0xc55f93}}}, + /* 11*16^57*G: */ + {{{0x0d326504, 0x150ccd2f, 0x0d480b33, 0x15368c4f, 0x0fc12f65, 0x1dc460d7, 0x08d0b0e0, 0x139cb718, 0x54c392}}, + {{0x1ec9e107, 0x1f808fd3, 0x0299c9a2, 0x0a7b3cc1, 0x0ab4447a, 0x1514248a, 0x1b431226, 0x04ac1d42, 0x469630}}}, + /* 13*16^57*G: */ + {{{0x1b5ecce7, 0x0227abb5, 0x03484d4c, 0x102b1618, 0x059c8732, 0x0741e0cb, 0x1b16e13a, 0x1650ccda, 0x3744e9}}, + {{0x0a247721, 0x00990a0b, 0x09be0e48, 0x116be0a5, 0x1ec3c28e, 0x14ab7594, 0x1ea83839, 0x1f1b3208, 0x9546e0}}}, + /* 15*16^57*G: */ + {{{0x05fef996, 0x064946f2, 0x1094d454, 0x0d1ec728, 0x1f2de140, 0x08520f79, 0x154cc933, 0x02fc6cad, 0x11343e}}, + {{0x1792aded, 0x00a8573a, 0x01bc6390, 0x1c9acb41, 0x13765d0c, 0x0fc98313, 0x1bbac137, 0x101bd751, 0x4a9e84}}} + }, + { + /* 1*16^58*G: */ + {{{0x0e6d8483, 0x164da6bc, 0x059fc373, 0x05af508d, 0x0e94582f, 0x1a4f8db7, 0x18f4a563, 0x0c1467aa, 0x9c39cb}}, + {{0x0b2c50fb, 0x0599ab7b, 0x0f90da25, 0x1bca5e7b, 0x16546bba, 0x0b5bde50, 0x14400f46, 0x03dc927c, 0xf097bf}}}, + /* 3*16^58*G: */ + {{{0x07a14dda, 0x0ae18fc2, 0x12d37cfd, 0x1a0852ce, 0x13083606, 0x147b9200, 0x0b5d10dd, 0x19921d5b, 0x18f37a}}, + {{0x05ac8364, 0x117e6e19, 0x014db2f8, 0x11ef8f15, 0x1cd0b77d, 0x1ff6770d, 0x109b5eef, 0x17554125, 0x2f944b}}}, + /* 5*16^58*G: */ + {{{0x0c7d59be, 0x13a74746, 0x024cbed5, 0x1430b11c, 0x0736b98e, 0x1ff723b9, 0x07693b17, 0x118503cf, 0x541335}}, + {{0x04f80590, 0x0bf50fb7, 0x002cd9cb, 0x04b62b92, 0x0515a53e, 0x07e900b2, 0x00939f12, 0x1bd2d396, 0x680fd4}}}, + /* 7*16^58*G: */ + {{{0x076051a8, 0x15c064fc, 0x115fa963, 0x0ee72c74, 0x05280bed, 0x00d1e0dc, 0x13c1773f, 0x04d23632, 0x4e2fd1}}, + {{0x09cc9005, 0x17f63a7f, 0x113f8b9a, 0x11754b25, 0x031bcebb, 0x1ad0a845, 0x0ec8dc6c, 0x1b7ebe9f, 0x122abb}}}, + /* 9*16^58*G: */ + {{{0x16a80e09, 0x13e547d2, 0x097d7f8d, 0x0be1eecc, 0x08fa0a27, 0x1ab409e0, 0x0d648013, 0x1a97dfe3, 0x2de758}}, + {{0x036a1cd3, 0x0b176faa, 0x16b5b267, 0x15b8cd2b, 0x064a07a1, 0x1958132f, 0x199f5f00, 0x062efb1d, 0xdd9acf}}}, + /* 11*16^58*G: */ + {{{0x1a3628ac, 0x1281ad97, 0x16d593b0, 0x177459be, 0x012a4568, 0x10b9e377, 0x095ca316, 0x159b83a9, 0xf597a0}}, + {{0x0cd3550f, 0x1501886b, 0x04841b9f, 0x1d9f23a8, 0x02cc0772, 0x1db944b1, 0x1155eec6, 0x11c6657a, 0xdb916}}}, + /* 13*16^58*G: */ + {{{0x0b75d6c3, 0x06b41ea5, 0x0e8a159e, 0x14a8afaa, 0x040f3c42, 0x038c10df, 0x1ee42284, 0x10dade89, 0xaa222a}}, + {{0x044cb028, 0x1932d273, 0x0a323d84, 0x03f9296b, 0x0df42607, 0x0512d771, 0x19db3912, 0x12600351, 0x563787}}}, + /* 15*16^58*G: */ + {{{0x035790c9, 0x1d42b9c9, 0x1cf140df, 0x03722ee7, 0x15e2e9e0, 0x0321c979, 0x16dd5bc3, 0x0d79b2e2, 0x8568b2}}, + {{0x06b1f5ac, 0x09faa9c1, 0x0151e7f7, 0x0bcbf1f7, 0x03ce8014, 0x0705721b, 0x0ab7a41e, 0x034b09ba, 0xd3f226}}} + }, + { + /* 1*16^59*G: */ + {{{0x1c38d4e4, 0x0ed4be2a, 0x0c5cdd1f, 0x1acbe363, 0x01e25e2f, 0x173a180c, 0x04e25d59, 0x04c22453, 0x3d9285}}, + {{0x00ccf0d3, 0x1d577806, 0x1eaf1fdb, 0x15627032, 0x069eacc0, 0x0b81ae14, 0x0ad4ffc1, 0x14ba8d1d, 0xd32ca0}}}, + /* 3*16^59*G: */ + {{{0x0dd7718a, 0x039192c0, 0x0f9393b4, 0x1036ca33, 0x0dff891c, 0x0cd12f3b, 0x1f0fdf05, 0x06e57205, 0x3b180e}}, + {{0x1afd82db, 0x1331314c, 0x0b45341c, 0x1222ace0, 0x1211e584, 0x1e4e9482, 0x02abea92, 0x02fe6d6b, 0xf2b6b1}}}, + /* 5*16^59*G: */ + {{{0x13d3653d, 0x140d288c, 0x1919f57e, 0x1d8964e9, 0x03eb2134, 0x07a04c54, 0x127d17bd, 0x00723ad3, 0xf352ff}}, + {{0x0a44f28e, 0x0f333c64, 0x1160b41e, 0x132bf2e5, 0x0d5055c1, 0x0b9efed3, 0x1af4082f, 0x0d996d8b, 0x447262}}}, + /* 7*16^59*G: */ + {{{0x0d4478da, 0x130ef8d7, 0x03805535, 0x19ed8448, 0x13ca1f15, 0x02e6dfbc, 0x108c2bed, 0x0e2069b1, 0x670ee4}}, + {{0x14f563f0, 0x147ff27f, 0x1c91dc18, 0x07702c1f, 0x150e81cc, 0x102d89c3, 0x0b289519, 0x084b7404, 0x5ca0c7}}}, + /* 9*16^59*G: */ + {{{0x03dbd581, 0x02714822, 0x15acd6eb, 0x1d671051, 0x06fa93cf, 0x1d185676, 0x0f6fbeef, 0x0a8693b3, 0x96f2e3}}, + {{0x08f59952, 0x0cd27ff7, 0x13d75153, 0x031e3aa0, 0x1baf435a, 0x0c71cb06, 0x1b3d3f97, 0x0110baa4, 0x9fcd8}}}, + /* 11*16^59*G: */ + {{{0x04e9c2fc, 0x159a1925, 0x0f5c1a87, 0x19e19e5f, 0x09a35e72, 0x01058a30, 0x06b20106, 0x0a2fd073, 0xc4946e}}, + {{0x06398ce8, 0x01a3b1bb, 0x1188c48d, 0x17e71da2, 0x18237e48, 0x07b47a3d, 0x0933a668, 0x041630b1, 0x748901}}}, + /* 13*16^59*G: */ + {{{0x04960b03, 0x05c8b9f4, 0x0023a3d7, 0x18756191, 0x14d8fb6a, 0x0462bc04, 0x0f6fe923, 0x09b537c6, 0x1653b6}}, + {{0x10f73c69, 0x00352a75, 0x0d5939fe, 0x11c1c943, 0x1a8948b3, 0x15ec1f4a, 0x15827d2c, 0x102d3cba, 0xa58370}}}, + /* 15*16^59*G: */ + {{{0x1b63640e, 0x0abbf18d, 0x11cb7cb1, 0x176fe521, 0x1cbf4979, 0x13ce5342, 0x14fd4031, 0x1afda5e2, 0x51076d}}, + {{0x02e4476c, 0x1b4b943c, 0x083bc087, 0x1d49d3ce, 0x0fda6c8b, 0x1280b970, 0x1ddabaf9, 0x0945adbb, 0xb39727}}} + }, + { + /* 1*16^60*G: */ + {{{0x044e8de3, 0x0318258d, 0x130781d8, 0x112cd45d, 0x117915c0, 0x1ee7845e, 0x02dce969, 0x16e8d102, 0xf50b99}}, + {{0x1b7f3588, 0x11f9dd36, 0x1c87a152, 0x0be31a42, 0x1cebbe97, 0x0b9d16f6, 0x1c321e26, 0x03cabe31, 0xe2b506}}}, + /* 3*16^60*G: */ + {{{0x02accf8b, 0x0ee35b5c, 0x005be9f7, 0x05332305, 0x1430481d, 0x1871289c, 0x1dc1917c, 0x0c34aa0a, 0x598d7f}}, + {{0x0f6cb808, 0x1c2339e0, 0x0d502e46, 0x11351e6a, 0x1ebcad22, 0x08b15939, 0x182551b1, 0x1ee9f1e4, 0x9f3121}}}, + /* 5*16^60*G: */ + {{{0x04aa7b3e, 0x1d9cd2a3, 0x1b273aa7, 0x09de360a, 0x0581013c, 0x1048aa0e, 0x113593f4, 0x025e93e9, 0x715a20}}, + {{0x1c7d081d, 0x0d19ca25, 0x02d1f436, 0x178b1151, 0x13b62421, 0x1447c548, 0x10287de4, 0x16354c0d, 0x5922b3}}}, + /* 7*16^60*G: */ + {{{0x020db220, 0x0dedb4bb, 0x01eb3934, 0x1996202d, 0x07876c71, 0x0744bfdc, 0x04971027, 0x0bcd5536, 0x49ec8c}}, + {{0x077338c2, 0x0dc56503, 0x0ee733a6, 0x1860e7ca, 0x15429842, 0x061a432f, 0x0a6cf6a7, 0x09fcbd4c, 0x99a97d}}}, + /* 9*16^60*G: */ + {{{0x1e771268, 0x0f5e518a, 0x02995a14, 0x1e294fb2, 0x07b7a2f4, 0x0c8702f0, 0x1120f9bc, 0x01a90a16, 0x1f8fb7}}, + {{0x0909c8dd, 0x17e98086, 0x04aceac6, 0x1a786239, 0x192a14e1, 0x16ba3930, 0x0afc4b0b, 0x1b68c374, 0xf53e7a}}}, + /* 11*16^60*G: */ + {{{0x08d9819e, 0x0f607959, 0x0b6ac695, 0x0cf25ee8, 0x0732cd60, 0x0a15d33c, 0x187f7574, 0x034c92fe, 0xb8d5c7}}, + {{0x09138ac4, 0x03c5f475, 0x15170f37, 0x093e26c3, 0x1dc79e2f, 0x121acdb1, 0x1e08edbb, 0x1e26426f, 0x1cd14e}}}, + /* 13*16^60*G: */ + {{{0x00bca3f3, 0x149edf33, 0x1801241a, 0x0686a28a, 0x0d8c4ecb, 0x15b0e440, 0x18f7758f, 0x158cb755, 0x2265b5}}, + {{0x117409ff, 0x0c14e362, 0x0e4f5689, 0x014c25a4, 0x164983c8, 0x09d1d884, 0x183d868c, 0x17eb959f, 0x97a198}}}, + /* 15*16^60*G: */ + {{{0x05bac36e, 0x19691ffa, 0x1d77340d, 0x11328b32, 0x1abcb599, 0x054fafe4, 0x049487f6, 0x1a206b09, 0xaf381c}}, + {{0x11b119a9, 0x19ec43d5, 0x1352a43f, 0x1705e3de, 0x02648589, 0x1f914a8d, 0x1ef72515, 0x0ff6fbe1, 0x681a08}}} + }, + { + /* 1*16^61*G: */ + {{{0x0037cfb4, 0x10cca02b, 0x136aa167, 0x01e48d87, 0x0b0e0740, 0x1a4406d0, 0x142c35df, 0x1047febd, 0x42531}}, + {{0x18775d23, 0x05b992f6, 0x1b177500, 0x07c9ea69, 0x01faceea, 0x12686433, 0x1df98a32, 0x199f5c01, 0xc90e8b}}}, + /* 3*16^61*G: */ + {{{0x06c34577, 0x027b39aa, 0x094abdde, 0x013d91cd, 0x0e4bde64, 0x11847460, 0x0922c7d7, 0x141c6179, 0x27557a}}, + {{0x0416193c, 0x0ff5cdc0, 0x110e02eb, 0x0594e6e9, 0x134f318a, 0x0bad24fe, 0x0ceddf23, 0x0b08c20b, 0x8399c7}}}, + /* 5*16^61*G: */ + {{{0x0401f4d3, 0x12c7edb5, 0x056cc07b, 0x185ca1d5, 0x1d7decf6, 0x1c1dfab0, 0x0d923941, 0x02fa4b0e, 0x8e6878}}, + {{0x0294d86b, 0x0140f4a2, 0x08644a24, 0x172de25d, 0x13cae900, 0x04d02836, 0x0fe98be0, 0x110dc593, 0x989cab}}}, + /* 7*16^61*G: */ + {{{0x0d2aa8e6, 0x0cb1ef13, 0x1bff8b71, 0x06b3f881, 0x1dbee205, 0x1401e533, 0x13db440d, 0x08c4a7cb, 0x98a417}}, + {{0x006cf75b, 0x0ba05f6b, 0x1fb4865a, 0x042ff556, 0x1cec9e30, 0x017ad17a, 0x0f5ac455, 0x128fc68c, 0x579ac6}}}, + /* 9*16^61*G: */ + {{{0x152c2d31, 0x0516647b, 0x187bb35f, 0x01576118, 0x1a946180, 0x17221f10, 0x03f64885, 0x084460a8, 0xe16854}}, + {{0x04a50fec, 0x05c41b41, 0x0660e507, 0x0c3257f1, 0x1c9343e7, 0x13216815, 0x0850becb, 0x0b9251ce, 0x70085}}}, + /* 11*16^61*G: */ + {{{0x13a7cdad, 0x119dd71b, 0x02f3ebd2, 0x1b07a5ca, 0x151a53ca, 0x117299c4, 0x0fa8728a, 0x09613aa2, 0xbfa631}}, + {{0x095cb953, 0x0fc44981, 0x1011e871, 0x0321f190, 0x0d1a7261, 0x02ddd8f7, 0x11e0a97e, 0x03299005, 0xb452e8}}}, + /* 13*16^61*G: */ + {{{0x0ade0fb7, 0x0de64280, 0x1946363b, 0x1b8e9bd4, 0x18e200c6, 0x0baf36ec, 0x134fb3c2, 0x05a152c3, 0xe68708}}, + {{0x1d4d6ece, 0x0bcf0798, 0x03089664, 0x03d0bdf1, 0x1a72117c, 0x072990e8, 0x1555797c, 0x090d0992, 0x2135a4}}}, + /* 15*16^61*G: */ + {{{0x0e432daf, 0x01e5af86, 0x009eb272, 0x1db41155, 0x14975f3b, 0x146bca83, 0x07a52ff0, 0x1f0c5535, 0x7ab16e}}, + {{0x071bdc48, 0x08bac455, 0x13f6c04c, 0x139c75ce, 0x1a7c5c7e, 0x0c1f146d, 0x02c68d64, 0x0152f865, 0x584e0e}}} + }, + { + /* 1*16^62*G: */ + {{{0x085fbd44, 0x03a3894c, 0x09899eb0, 0x0595473e, 0x1222c89c, 0x18e70b6a, 0x04178151, 0x1b5b356b, 0x9bbf06}}, + {{0x1a1d3e88, 0x1a23efd3, 0x00dbb4a8, 0x097bb82a, 0x147e8c0d, 0x0d798537, 0x028d9d57, 0x1509bc24, 0x1bcc7f}}}, + /* 3*16^62*G: */ + {{{0x14a7b506, 0x1bd73c95, 0x0182f822, 0x0b1775cf, 0x00ee9227, 0x1d9573a8, 0x0f4d0a73, 0x1ecb676b, 0x646ff7}}, + {{0x0b36f946, 0x0bce0929, 0x039a6572, 0x1bf89f81, 0x08fe8492, 0x1198c025, 0x02956987, 0x13a0c943, 0xbc112a}}}, + /* 5*16^62*G: */ + {{{0x0103b553, 0x0a5b8e4e, 0x0e16a005, 0x01d44f06, 0x0507ebe6, 0x0800593f, 0x0e6a7430, 0x0f54c2fa, 0x7cc054}}, + {{0x0d45a526, 0x1cce5d1e, 0x08a2df55, 0x10b41558, 0x094c4001, 0x14659cfe, 0x116af75c, 0x17a46500, 0x7b329e}}}, + /* 7*16^62*G: */ + {{{0x19e717a4, 0x0177a2a0, 0x1c06e06b, 0x1457b559, 0x0e15468d, 0x16a9b6d7, 0x0d38158f, 0x1321783b, 0x946851}}, + {{0x1526dea3, 0x1af87e8d, 0x02b36729, 0x132b21ee, 0x07dc0579, 0x08735933, 0x06a2cee3, 0x0841b8b2, 0xca5c78}}}, + /* 9*16^62*G: */ + {{{0x08362735, 0x1c161b78, 0x0acc9ef7, 0x1166fde2, 0x0d1f5dff, 0x07c75229, 0x03eac496, 0x037cfc1d, 0xe1b98f}}, + {{0x0ecb11b7, 0x0b09c64e, 0x1d0242be, 0x13dc67be, 0x12ba27e1, 0x1a4d41dd, 0x082df816, 0x15b352ed, 0xca83e9}}}, + /* 11*16^62*G: */ + {{{0x19046346, 0x1a05dec1, 0x0510020e, 0x0b1bce60, 0x1962d56a, 0x1035ecb3, 0x1fbdb422, 0x0b91fac0, 0x3536f2}}, + {{0x0c14fea6, 0x0008315e, 0x166cf8a5, 0x187a3d45, 0x1e1c39e6, 0x0b50d294, 0x0279cee8, 0x1c2fbc6a, 0x1e271f}}}, + /* 13*16^62*G: */ + {{{0x0847f6f8, 0x1ffc1f6b, 0x103bd4c3, 0x136a3f7a, 0x18c3c102, 0x08f9a5bf, 0x1379a405, 0x08d7c47a, 0xdf502}}, + {{0x1b1633a6, 0x06654535, 0x17cd126d, 0x1c2ccd13, 0x174ab4c6, 0x1627de10, 0x0728ac8c, 0x0fe53b5e, 0x210704}}}, + /* 15*16^62*G: */ + {{{0x1d4f1b81, 0x02e7576f, 0x1d2ec546, 0x134f4919, 0x09330ad6, 0x11d99b29, 0x0e63da77, 0x1a899ea6, 0xca9dd5}}, + {{0x02b7c8bd, 0x06316572, 0x0b6843e3, 0x12ec17f5, 0x07b3e66c, 0x18fda223, 0x11590091, 0x10ca37c5, 0x6e4b98}}} + }, + { + /* 1*16^63*G: */ + {{{0x044c0448, 0x1569919a, 0x00c678c7, 0x0aed0d82, 0x093e7963, 0x1e659dbc, 0x1e95250f, 0x1ea5287b, 0xb12fad}}, + {{0x1369de57, 0x12baf3b5, 0x1f137ca5, 0x0bce0665, 0x0a6a71d0, 0x07b33bd9, 0x12b3a5be, 0x12b3361e, 0x2e245}}}, + /* 3*16^63*G: */ + {{{0x04e9151f, 0x09b622a3, 0x0361063d, 0x14673390, 0x0fb3e67e, 0x0eed48ec, 0x15a10c95, 0x069e38a0, 0x48388e}}, + {{0x0d7a9434, 0x1f724f6e, 0x17a0c406, 0x028222a7, 0x02bcc99b, 0x19c98aa4, 0x1a79a894, 0x157e9c89, 0xb0ec63}}}, + /* 5*16^63*G: */ + {{{0x0e5b833d, 0x1efda52c, 0x02c90675, 0x1400e794, 0x109c9593, 0x0fc08280, 0x0f697997, 0x08f5c28a, 0xde8e64}}, + {{0x014c5cc7, 0x07e60cd5, 0x0071b27c, 0x1c062652, 0x1e265987, 0x14465eb6, 0x0f638cc8, 0x0782a122, 0x5e146}}}, + /* 7*16^63*G: */ + {{{0x01f7df48, 0x112c9f56, 0x1c4c5ecf, 0x0e8e7d70, 0x0f385b26, 0x0da7272c, 0x1a7a3955, 0x1a149d8f, 0xb18b12}}, + {{0x0846b546, 0x0d9eac87, 0x14795664, 0x07efc907, 0x0c33b3c8, 0x0135e2d6, 0x0d1173b1, 0x04546b3f, 0xff5319}}}, + /* 9*16^63*G: */ + {{{0x19c9fd24, 0x129d6e34, 0x0847837c, 0x1bb1308a, 0x0694402c, 0x05526394, 0x10cf1f07, 0x0e391b92, 0x5f51ad}}, + {{0x0d2ffd3a, 0x01dd7443, 0x092a65a7, 0x03ec488c, 0x04d03872, 0x02fde617, 0x0528334c, 0x023befce, 0x2bbbef}}}, + /* 11*16^63*G: */ + {{{0x17cec42e, 0x1e2031fe, 0x18ef6df8, 0x1b9267dd, 0x0d8556f3, 0x117721a3, 0x1aefe960, 0x1b26e603, 0xfdf340}}, + {{0x0db6908b, 0x07b1a5be, 0x178c320e, 0x1cd57ea1, 0x0d2c4456, 0x0ff39c65, 0x1b875c30, 0x0c72d198, 0xa3e59a}}}, + /* 13*16^63*G: */ + {{{0x01dc4fe8, 0x00c4a2a7, 0x01c9057f, 0x1142752c, 0x1c983f9e, 0x0948bdbe, 0x15e7b191, 0x19173d4b, 0xe3caeb}}, + {{0x1307b403, 0x15b05b90, 0x13e1a845, 0x0006cb42, 0x1f976513, 0x1ae5c580, 0x04a34880, 0x1a4f7e0b, 0x97f093}}}, + /* 15*16^63*G: */ + {{{0x1c119eff, 0x00a6b2e9, 0x07e6e119, 0x005c1815, 0x1a003399, 0x0d2e72c7, 0x16e26bd0, 0x1728550c, 0x3312d}}, + {{0x18b1b950, 0x14ad1d4f, 0x1455617f, 0x18b3b6be, 0x1e86f0ae, 0x1518bc04, 0x137c413b, 0x0c8d66e4, 0x6e3eda}}} + }, diff --git a/deps/crypto/trezor-crypto/options.h b/deps/crypto/trezor-crypto/options.h new file mode 100644 index 000000000..d3a9c2edf --- /dev/null +++ b/deps/crypto/trezor-crypto/options.h @@ -0,0 +1,99 @@ +/** + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __OPTIONS_H__ +#define __OPTIONS_H__ + +// use precomputed Curve Points (some scalar multiples of curve base point G) +#ifndef USE_PRECOMPUTED_CP +#define USE_PRECOMPUTED_CP 1 +#endif + +// use fast inverse method +#ifndef USE_INVERSE_FAST +#define USE_INVERSE_FAST 1 +#endif + +// support for printing bignum256 structures via printf +#ifndef USE_BN_PRINT +#define USE_BN_PRINT 0 +#endif + +// use deterministic signatures +#ifndef USE_RFC6979 +#define USE_RFC6979 1 +#endif + +// implement BIP32 caching +#ifndef USE_BIP32_CACHE +#define USE_BIP32_CACHE 1 +#define BIP32_CACHE_SIZE 10 +#define BIP32_CACHE_MAXDEPTH 8 +#endif + +// support constructing BIP32 nodes from ed25519 and curve25519 curves. +#ifndef USE_BIP32_25519_CURVES +#define USE_BIP32_25519_CURVES 1 +#endif + +// implement BIP39 caching +#ifndef USE_BIP39_CACHE +#define USE_BIP39_CACHE 1 +#define BIP39_CACHE_SIZE 4 +#endif + +// support Ethereum operations +#ifndef USE_ETHEREUM +#define USE_ETHEREUM 0 +#endif + +// support Graphene operations (STEEM, BitShares) +#ifndef USE_GRAPHENE +#define USE_GRAPHENE 0 +#endif + +// support NEM operations +#ifndef USE_NEM +#define USE_NEM 0 +#endif + +// support MONERO operations +#ifndef USE_MONERO +#define USE_MONERO 0 +#endif + +// support CARDANO operations +#ifndef USE_CARDANO +#define USE_CARDANO 0 +#endif + +// support Keccak hashing +#ifndef USE_KECCAK +#define USE_KECCAK 1 +#endif + +// add way how to mark confidential data +#ifndef CONFIDENTIAL +#define CONFIDENTIAL +#endif + +#endif diff --git a/deps/crypto/trezor-crypto/pallas.c b/deps/crypto/trezor-crypto/pallas.c new file mode 100644 index 000000000..9b23f091d --- /dev/null +++ b/deps/crypto/trezor-crypto/pallas.c @@ -0,0 +1,805 @@ +/** + * Copyright (c) 2025 KeepKey + * + * Pallas elliptic curve used by Zcash Orchard protocol. + * Curve equation: y^2 = x^3 + 5 over Fp + * p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001 + * Generator G = (-1 mod p, 2) + * + * IMPORTANT: The trezor-crypto bignum library assumes primes in the range + * [2^256 - 2^224, 2^256]. The Pallas prime (~2^254) falls outside this range, + * so bn_multiply/bn_inverse/bn_fast_mod produce incorrect results. + * This file implements custom field arithmetic using Barrett reduction + * to correctly handle the Pallas prime. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "pallas.h" + +#include + +#include "blake2b.h" +#include "memzero.h" + +/* bn_multiply_long is defined in bignum.c (non-static) */ +extern void bn_multiply_long(const bignum256 *k, const bignum256 *x, + uint32_t res[2 * 9]); + +#define BN_LIMBS 9 +#define BN_BITS_PER_LIMB 29 +#define BN_LIMB_MASK ((1u << BN_BITS_PER_LIMB) - 1) + +/* ==================================================================== + * Constants + * ==================================================================== */ + +const bignum256 pallas_prime = { + /*.val =*/{0x00000001, 0x09698768, 0x133e46e6, 0x0d31f812, 0x00000224, + 0x00000000, 0x00000000, 0x00000000, 0x00400000}}; + +const bignum256 pallas_order = { + /*.val =*/{0x00000001, 0x02375908, 0x052a3763, 0x0d31f813, 0x00000224, + 0x00000000, 0x00000000, 0x00000000, 0x00400000}}; + +const curve_point pallas_G = { + /*.x =*/{/*.val =*/{0x00000000, 0x09698768, 0x133e46e6, 0x0d31f812, + 0x00000224, 0x00000000, 0x00000000, 0x00000000, + 0x00400000}}, + /*.y =*/{/*.val =*/{0x00000002, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000}}}; + +/* + * Barrett reduction constant for the Pallas prime: + * mu_p = floor(2^510 / p) + */ +static const bignum256 mu_p = { + /*.val =*/{0x1ffffffc, 0x1a59e25f, 0x1306e466, 0x0b381fb5, 0x1ffff76e, + 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x00ffffff}}; + +/* + * Barrett reduction constant for the Pallas order: + * mu_q = floor(2^510 / q) + */ +static const bignum256 mu_q = { + /*.val =*/{0x1ffffffc, 0x17229bdf, 0x0b572273, 0x0b381fb3, 0x1ffff76e, + 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x00ffffff}}; + +/* + * Full ecdsa_curve struct (kept for compatibility, but point_multiply + * from ecdsa.c should NOT be used with Pallas - use pallas_scalar_mult_G). + */ +const ecdsa_curve pallas = { + /* prime */ + {/*.val =*/{0x00000001, 0x09698768, 0x133e46e6, 0x0d31f812, 0x00000224, + 0x00000000, 0x00000000, 0x00000000, 0x00400000}}, + /* G */ + {/*.x =*/{/*.val =*/{0x00000000, 0x09698768, 0x133e46e6, 0x0d31f812, + 0x00000224, 0x00000000, 0x00000000, 0x00000000, + 0x00400000}}, + /*.y =*/{/*.val =*/{0x00000002, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000}}}, + /* order */ + {/*.val =*/{0x00000001, 0x02375908, 0x052a3763, 0x0d31f813, 0x00000224, + 0x00000000, 0x00000000, 0x00000000, 0x00400000}}, + /* order_half */ + {/*.val =*/{0x00000000, 0x111bac84, 0x12951bb1, 0x0698fc09, 0x00000112, + 0x00000000, 0x00000000, 0x00000000, 0x00200000}}, + /* a */ 0, + /* b = 5 */ + {/*.val =*/{5}} +#if USE_PRECOMPUTED_CP + , + {{{{0}}}} +#endif +}; + +/* ==================================================================== + * Barrett Reduction for ~254-bit primes + * + * Given an 18-limb product (up to ~510 bits), reduce mod prime. + * Uses Barrett: q_hat = floor(floor(x / 2^254) * mu / 2^256) + * r = x - q_hat * prime + * while r >= prime: r -= prime + * ==================================================================== */ + +/* + * Shift an 18-limb number right by 254 bits. + * 254 = 8*29 + 22, so we skip 8 limbs and shift remaining by 22 bits. + */ +static void shift_right_254(const uint32_t in[18], bignum256 *out) { + for (int i = 0; i < BN_LIMBS; i++) { + uint32_t lo = in[i + 8] >> 22; + uint32_t hi = (i + 9 < 18) ? (in[i + 9] << 7) : 0; + out->val[i] = (lo | hi) & BN_LIMB_MASK; + } +} + +/* + * Shift an 18-limb number right by 256 bits. + * 256 = 8*29 + 24, so we skip 8 limbs and shift remaining by 24 bits. + */ +static void shift_right_256(const uint32_t in[18], bignum256 *out) { + for (int i = 0; i < BN_LIMBS; i++) { + uint32_t lo = in[i + 8] >> 24; + uint32_t hi = (i + 9 < 18) ? (in[i + 9] << 5) : 0; + out->val[i] = (lo | hi) & BN_LIMB_MASK; + } +} + +/* + * Compare two bignum256 values (both must be normalized). + * Returns 1 if a >= b, 0 otherwise. + */ +static int bn_gte(const bignum256 *a, const bignum256 *b) { + for (int i = BN_LIMBS - 1; i >= 0; i--) { + if (a->val[i] > b->val[i]) return 1; + if (a->val[i] < b->val[i]) return 0; + } + return 1; /* equal */ +} + +/* + * Subtract b from a, storing result in res. Assumes a >= b. + * All operands must be normalized. + */ +static void bn_sub(const bignum256 *a, const bignum256 *b, bignum256 *res) { + int32_t borrow = 0; + for (int i = 0; i < BN_LIMBS; i++) { + int32_t diff = (int32_t)a->val[i] - (int32_t)b->val[i] + borrow; + if (diff < 0) { + diff += (1 << BN_BITS_PER_LIMB); + borrow = -1; + } else { + borrow = 0; + } + res->val[i] = (uint32_t)diff; + } +} + +/* + * Barrett reduction: reduce an 18-limb product mod a ~254-bit prime. + * + * prime: the modulus (~254-255 bits) + * mu: precomputed floor(2^510 / prime) (~256 bits) + * res[18]: input product (up to ~510 bits) + * out: output, reduced to [0, prime) + */ +static void pallas_barrett_reduce(const uint32_t res[18], + const bignum256 *prime, + const bignum256 *mu, bignum256 *out) { + /* Step 1: q_hat = floor(floor(x / 2^254) * mu / 2^256) */ + bignum256 x_shifted; + shift_right_254(res, &x_shifted); + bn_normalize(&x_shifted); + + uint32_t qmu[18] = {0}; + bn_multiply_long(&x_shifted, mu, qmu); + + bignum256 q_hat; + shift_right_256(qmu, &q_hat); + bn_normalize(&q_hat); + + /* Step 2: r = x - q_hat * prime (low 9 limbs only) */ + uint32_t qp[18] = {0}; + bn_multiply_long(&q_hat, prime, qp); + + /* Compute r = x - q*p using 9 low limbs. + * The true result fits in ~256 bits (< 3*prime). */ + int64_t borrow = 0; + for (int i = 0; i < BN_LIMBS; i++) { + int64_t diff = (int64_t)res[i] - (int64_t)qp[i] + borrow; + out->val[i] = (uint32_t)(diff & BN_LIMB_MASK); + borrow = diff >> BN_BITS_PER_LIMB; + } + bn_normalize(out); + + /* Step 3: while r >= prime, r -= prime (at most 3 times) */ + for (int i = 0; i < 3; i++) { + if (bn_gte(out, prime)) { + bn_sub(out, prime, out); + } + } +} + +/* ==================================================================== + * Pallas Field Arithmetic + * ==================================================================== */ + +/* + * Field multiplication: x = k * x mod pallas_prime + */ +void pallas_mul_mod_p(bignum256 *x, const bignum256 *k) { + uint32_t res[18] = {0}; + bn_multiply_long(k, x, res); + pallas_barrett_reduce(res, &pallas_prime, &mu_p, x); +} + +/* + * Scalar multiplication: x = k * x mod pallas_order + */ +void pallas_mul_mod_q(bignum256 *x, const bignum256 *k) { + uint32_t res[18] = {0}; + bn_multiply_long(k, x, res); + pallas_barrett_reduce(res, &pallas_order, &mu_q, x); +} + +/* + * Field addition: x = (a + b) mod pallas_prime + */ +void pallas_add_mod_p(const bignum256 *a, const bignum256 *b, + bignum256 *res) { + uint32_t carry = 0; + for (int i = 0; i < BN_LIMBS; i++) { + carry += a->val[i] + b->val[i]; + res->val[i] = carry & BN_LIMB_MASK; + carry >>= BN_BITS_PER_LIMB; + } + bn_normalize(res); + if (bn_gte(res, &pallas_prime)) { + bn_sub(res, &pallas_prime, res); + } +} + +/* + * Field subtraction: res = (a - b) mod pallas_prime + */ +void pallas_sub_mod_p(const bignum256 *a, const bignum256 *b, + bignum256 *res) { + if (bn_gte(a, b)) { + bn_sub(a, b, res); + } else { + /* a < b: res = a + prime - b = prime - (b - a) */ + bignum256 tmp; + bn_sub(b, a, &tmp); + bn_sub(&pallas_prime, &tmp, res); + } +} + +/* + * Field inversion: x = x^(-1) mod pallas_prime + * Uses Fermat's little theorem: x^(-1) = x^(p-2) mod p + */ +void pallas_inv_mod_p(bignum256 *x) { + /* Compute e = p - 2 with proper borrow (since p.val[0] = 1 < 2) */ + bignum256 e; + bn_copy(&pallas_prime, &e); + /* val[0] = 1, so 1 - 2 requires borrow from val[1] */ + e.val[0] = e.val[0] + (1u << BN_BITS_PER_LIMB) - 2; /* 1 + 2^29 - 2 = 0x1FFFFFFF */ + e.val[1] -= 1; /* borrow */ + + /* Square-and-multiply: result = x^e mod p */ + bignum256 result; + bn_one(&result); + + bignum256 base; + bn_copy(x, &base); + + /* Process each bit of e from LSB to MSB */ + for (int bit = 0; bit < 255; bit++) { + int limb_idx = bit / BN_BITS_PER_LIMB; + int bit_idx = bit % BN_BITS_PER_LIMB; + + if ((e.val[limb_idx] >> bit_idx) & 1) { + pallas_mul_mod_p(&result, &base); + } + /* Square the base */ + bignum256 tmp; + bn_copy(&base, &tmp); + pallas_mul_mod_p(&base, &tmp); + } + + bn_copy(&result, x); + memzero(&result, sizeof(result)); + memzero(&base, sizeof(base)); +} + +/* + * Simple modular reduction: x = x mod pallas_prime + * For values already < 2^261 (bignum256 range). + */ +void pallas_mod_p(bignum256 *x) { + bn_normalize(x); + while (bn_gte(x, &pallas_prime)) { + bn_sub(x, &pallas_prime, x); + } +} + +/* + * Simple modular reduction: x = x mod pallas_order + * For values already < 2^261 (bignum256 range). + */ +void pallas_mod_q(bignum256 *x) { + bn_normalize(x); + while (bn_gte(x, &pallas_order)) { + bn_sub(x, &pallas_order, x); + } +} + +/* + * Scalar addition: a = (a + b) mod pallas_order + */ +void pallas_add_mod_q(bignum256 *a, const bignum256 *b) { + uint32_t carry = 0; + for (int i = 0; i < BN_LIMBS; i++) { + carry += a->val[i] + b->val[i]; + a->val[i] = carry & BN_LIMB_MASK; + carry >>= BN_BITS_PER_LIMB; + } + pallas_mod_q(a); +} + +/* + * Modular exponentiation: result = base^exp mod pallas_prime + * Uses square-and-multiply (LSB to MSB). + */ +static void pallas_pow_mod_p(const bignum256 *base, const bignum256 *exp, + bignum256 *result) { + bn_zero(result); + result->val[0] = 1; + + bignum256 b; + bn_copy(base, &b); + + for (int bit = 0; bit < 255; bit++) { + int limb_idx = bit / BN_BITS_PER_LIMB; + int bit_idx = bit % BN_BITS_PER_LIMB; + + if ((exp->val[limb_idx] >> bit_idx) & 1) { + pallas_mul_mod_p(result, &b); + } + bignum256 tmp; + bn_copy(&b, &tmp); + pallas_mul_mod_p(&b, &tmp); + } +} + +/* + * Modular square root: n = sqrt(n) mod pallas_prime + * Uses Tonelli-Shanks algorithm (required because p ≡ 1 mod 4). + * + * For Pallas: p - 1 = Q * 2^32 where Q is odd, S = 32. + * + * Returns 0 on success (n modified to sqrt), -1 if n is not a QR. + */ +int pallas_sqrt_mod_p(bignum256 *n) { + if (bn_is_zero(n)) return 0; + + /* p - 1 */ + bignum256 pm1; + bn_copy(&pallas_prime, &pm1); + pm1.val[0]--; + + /* Compute Q = (p-1) >> 32 (where S = 32, p-1 = Q * 2^S, Q odd) */ + /* 32 = 29 + 3, so shift right by 1 limb then 3 bits */ + bignum256 Q; + int i; + for (i = 0; i < 8; i++) Q.val[i] = pm1.val[i + 1]; + Q.val[8] = 0; + for (i = 0; i < 8; i++) { + Q.val[i] = (Q.val[i] >> 3) | ((Q.val[i + 1] & 0x7) << 26); + } + Q.val[8] >>= 3; + + /* (p-1)/2 for Euler criterion (QNR test) */ + bignum256 half_pm1; + bn_copy(&pm1, &half_pm1); + for (i = 0; i < 8; i++) { + half_pm1.val[i] = (half_pm1.val[i] >> 1) | ((half_pm1.val[i + 1] & 0x1) << 28); + } + half_pm1.val[8] >>= 1; + + /* Find a quadratic non-residue z: z^((p-1)/2) ≡ -1 (mod p) */ + bignum256 z, test; + for (uint32_t zi = 2; zi < 100; zi++) { + bn_zero(&z); + z.val[0] = zi; + pallas_pow_mod_p(&z, &half_pm1, &test); + bn_normalize(&test); + if (bn_is_equal(&test, &pm1)) break; + } + + /* Tonelli-Shanks initialization */ + int M = 32; + bignum256 c; + pallas_pow_mod_p(&z, &Q, &c); /* c = z^Q mod p */ + + bignum256 t; + pallas_pow_mod_p(n, &Q, &t); /* t = n^Q mod p */ + + /* (Q+1)/2 */ + bignum256 Q_half; + bn_copy(&Q, &Q_half); + Q_half.val[0]++; /* Q is odd, so Q+1 is even */ + for (i = 0; i < 8; i++) { + Q_half.val[i] = (Q_half.val[i] >> 1) | ((Q_half.val[i + 1] & 0x1) << 28); + } + Q_half.val[8] >>= 1; + + bignum256 R; + pallas_pow_mod_p(n, &Q_half, &R); /* R = n^((Q+1)/2) mod p */ + + bignum256 one; + bn_zero(&one); + one.val[0] = 1; + + /* Main loop */ + for (;;) { + bn_normalize(&t); + if (bn_is_zero(&t)) { + bn_zero(n); + return 0; + } + if (bn_is_equal(&t, &one)) { + bn_copy(&R, n); + return 0; + } + + /* Find least i (1 ≤ i < M) such that t^(2^i) ≡ 1 (mod p) */ + bignum256 tmp; + bn_copy(&t, &tmp); + int ii; + for (ii = 1; ii < M; ii++) { + bignum256 sq; + bn_copy(&tmp, &sq); + pallas_mul_mod_p(&tmp, &sq); /* tmp = tmp^2 */ + bn_normalize(&tmp); + if (bn_is_equal(&tmp, &one)) break; + } + + if (ii >= M) { + return -1; /* n is not a quadratic residue */ + } + + /* b = c^(2^(M-ii-1)) */ + bignum256 b; + bn_copy(&c, &b); + for (int j = 0; j < M - ii - 1; j++) { + bignum256 sq; + bn_copy(&b, &sq); + pallas_mul_mod_p(&b, &sq); /* b = b^2 */ + } + + /* Update M, c, t, R */ + M = ii; + + /* c = b^2 */ + bn_copy(&b, &c); + { + bignum256 sq; + bn_copy(&c, &sq); + pallas_mul_mod_p(&c, &sq); /* c = c^2 = b^2 */ + } + + /* t = t * c (where c = b^2) */ + pallas_mul_mod_p(&t, &c); /* t = c * t = b^2 * t */ + + /* R = R * b */ + pallas_mul_mod_p(&R, &b); /* R = b * R */ + } +} + +/* ==================================================================== + * Pallas Point Operations (affine coordinates) + * ==================================================================== */ + +static int pallas_point_is_infinity(const curve_point *p) { + return bn_is_zero(&p->x) && bn_is_zero(&p->y); +} + +static void pallas_point_set_infinity(curve_point *p) { + bn_zero(&p->x); + bn_zero(&p->y); +} + +/* + * Point doubling: res = 2*P on Pallas curve (y^2 = x^3 + 5, a=0) + * Formula: lambda = 3*x^2 / (2*y) + * xr = lambda^2 - 2*x + * yr = lambda*(x - xr) - y + */ +static void pallas_point_dbl(const curve_point *p, curve_point *res) { + if (pallas_point_is_infinity(p) || bn_is_zero(&p->y)) { + pallas_point_set_infinity(res); + return; + } + + bignum256 lambda, xr, yr, tmp, tmp2; + + /* lambda = 3*x^2 / (2*y) mod p */ + /* Numerator: 3*x^2 */ + bn_copy(&p->x, &tmp); + pallas_mul_mod_p(&tmp, &p->x); /* tmp = x^2 */ + bn_copy(&tmp, &tmp2); + pallas_add_mod_p(&tmp, &tmp2, &lambda); /* lambda = 2*x^2 */ + pallas_add_mod_p(&lambda, &tmp2, &lambda); /* lambda = 3*x^2 */ + + /* Denominator: 2*y */ + pallas_add_mod_p(&p->y, &p->y, &tmp); /* tmp = 2*y */ + + /* Invert denominator */ + pallas_inv_mod_p(&tmp); /* tmp = 1/(2*y) */ + + /* lambda = 3*x^2 * (1/(2*y)) */ + pallas_mul_mod_p(&lambda, &tmp); + + /* xr = lambda^2 - 2*x */ + bn_copy(&lambda, &xr); + pallas_mul_mod_p(&xr, &lambda); /* xr = lambda^2 */ + pallas_add_mod_p(&p->x, &p->x, &tmp); /* tmp = 2*x */ + pallas_sub_mod_p(&xr, &tmp, &xr); /* xr = lambda^2 - 2*x */ + + /* yr = lambda*(x - xr) - y */ + pallas_sub_mod_p(&p->x, &xr, &yr); /* yr = x - xr */ + pallas_mul_mod_p(&yr, &lambda); /* yr = lambda*(x - xr) */ + pallas_sub_mod_p(&yr, &p->y, &yr); /* yr = lambda*(x-xr) - y */ + + bn_copy(&xr, &res->x); + bn_copy(&yr, &res->y); +} + +/* + * Point addition: res = P + Q on Pallas curve + */ +void pallas_point_add(const curve_point *p, const curve_point *q, + curve_point *res) { + if (pallas_point_is_infinity(p)) { + *res = *q; + return; + } + if (pallas_point_is_infinity(q)) { + *res = *p; + return; + } + + /* Check if P == Q (use doubling) */ + bignum256 px_norm, qx_norm, py_norm, qy_norm; + bn_copy(&p->x, &px_norm); + bn_copy(&q->x, &qx_norm); + bn_copy(&p->y, &py_norm); + bn_copy(&q->y, &qy_norm); + bn_normalize(&px_norm); + bn_normalize(&qx_norm); + bn_normalize(&py_norm); + bn_normalize(&qy_norm); + + int x_equal = 1, y_equal = 1; + for (int i = 0; i < BN_LIMBS; i++) { + if (px_norm.val[i] != qx_norm.val[i]) { x_equal = 0; break; } + } + if (x_equal) { + for (int i = 0; i < BN_LIMBS; i++) { + if (py_norm.val[i] != qy_norm.val[i]) { y_equal = 0; break; } + } + if (y_equal) { + pallas_point_dbl(p, res); + return; + } + /* P.x == Q.x but P.y != Q.y → P + Q = O (point at infinity) */ + pallas_point_set_infinity(res); + return; + } + + bignum256 lambda, xr, yr, tmp; + + /* lambda = (Q.y - P.y) / (Q.x - P.x) mod p */ + pallas_sub_mod_p(&q->y, &p->y, &lambda); /* num = Q.y - P.y */ + pallas_sub_mod_p(&q->x, &p->x, &tmp); /* den = Q.x - P.x */ + pallas_inv_mod_p(&tmp); /* den = 1/(Q.x - P.x) */ + pallas_mul_mod_p(&lambda, &tmp); /* lambda = num/den */ + + /* xr = lambda^2 - P.x - Q.x */ + bn_copy(&lambda, &xr); + pallas_mul_mod_p(&xr, &lambda); /* xr = lambda^2 */ + pallas_sub_mod_p(&xr, &p->x, &xr); /* xr -= P.x */ + pallas_sub_mod_p(&xr, &q->x, &xr); /* xr -= Q.x */ + + /* yr = lambda*(P.x - xr) - P.y */ + pallas_sub_mod_p(&p->x, &xr, &yr); /* yr = P.x - xr */ + pallas_mul_mod_p(&yr, &lambda); /* yr *= lambda */ + pallas_sub_mod_p(&yr, &p->y, &yr); /* yr -= P.y */ + + bn_copy(&xr, &res->x); + bn_copy(&yr, &res->y); +} + +/* ==================================================================== + * Scalar Multiplication (double-and-add, left-to-right) + * ==================================================================== */ + +/* + * Compute res = k * P on Pallas. + * Uses the double-and-add algorithm. + * k must be in [1, order-1]. + */ +static void pallas_scalar_mult_impl(const bignum256 *k, const curve_point *p, + curve_point *res) { + /* Find the highest set bit */ + int highest_bit = -1; + for (int i = BN_LIMBS - 1; i >= 0; i--) { + if (k->val[i] != 0) { + uint32_t v = k->val[i]; + int bit = BN_BITS_PER_LIMB - 1; + while (bit >= 0 && !((v >> bit) & 1)) bit--; + highest_bit = i * BN_BITS_PER_LIMB + bit; + break; + } + } + + if (highest_bit < 0) { + /* k == 0 */ + pallas_point_set_infinity(res); + return; + } + + /* Initialize res = P (for the highest bit) */ + *res = *p; + + /* Process remaining bits from second-highest down to 0 */ + for (int bit = highest_bit - 1; bit >= 0; bit--) { + /* Double */ + curve_point tmp; + pallas_point_dbl(res, &tmp); + *res = tmp; + + /* Add if bit is set */ + int limb_idx = bit / BN_BITS_PER_LIMB; + int bit_idx = bit % BN_BITS_PER_LIMB; + if ((k->val[limb_idx] >> bit_idx) & 1) { + pallas_point_add(res, p, &tmp); + *res = tmp; + } + } +} + +/* ==================================================================== + * Public API + * ==================================================================== */ + +void pallas_scalar_mult_G(const bignum256 *k, curve_point *res) { + if (bn_is_zero(k)) { + pallas_point_set_infinity(res); + return; + } + pallas_scalar_mult_impl(k, &pallas_G, res); +} + +void pallas_point_mult(const bignum256 *k, const curve_point *p, + curve_point *res) { + if (bn_is_zero(k)) { + pallas_point_set_infinity(res); + return; + } + pallas_scalar_mult_impl(k, p, res); +} + +int pallas_point_is_identity(const curve_point *p) { + if (!p) return 1; + return pallas_point_is_infinity(p); +} + +void pallas_point_encode(const curve_point *p, uint8_t out[32]) { + if (!p || !out) return; + + memset(out, 0, 32); + if (pallas_point_is_infinity(p)) return; + + bignum256 x; + bn_copy(&p->x, &x); + bn_write_le(&x, out); + if (bn_is_odd(&p->y)) { + out[31] |= 0x80; + } + memzero(&x, sizeof(x)); +} + +int pallas_expand_message_xmd_blake2b(const uint8_t *msg, size_t msg_len, + const uint8_t *dst, size_t dst_len, + uint8_t *out, size_t out_len) { + enum { + B_IN_BYTES = 64, + R_IN_BYTES = 128, + }; + + if (!out || out_len == 0 || out_len > 0xffff) return -1; + if ((!msg && msg_len != 0) || (!dst && dst_len != 0)) return -1; + if (dst_len > 255) return -1; + + size_t ell = (out_len + B_IN_BYTES - 1) / B_IN_BYTES; + if (ell == 0 || ell > 255) return -1; + + uint8_t dst_prime[256]; + uint8_t z_pad[R_IN_BYTES] = {0}; + uint8_t b0[B_IN_BYTES]; + uint8_t bi[B_IN_BYTES]; + uint8_t tmp[B_IN_BYTES]; + uint8_t len_bytes[2] = {(uint8_t)(out_len >> 8), (uint8_t)out_len}; + uint8_t zero = 0; + uint8_t personal[16] = {0}; + BLAKE2B_CTX ctx; + + if (dst_len != 0) { + memcpy(dst_prime, dst, dst_len); + } + dst_prime[dst_len] = (uint8_t)dst_len; + size_t dst_prime_len = dst_len + 1; + + if (blake2b_InitPersonal(&ctx, B_IN_BYTES, personal, sizeof(personal)) != 0) { + return -1; + } + blake2b_Update(&ctx, z_pad, sizeof(z_pad)); + blake2b_Update(&ctx, msg, msg_len); + blake2b_Update(&ctx, len_bytes, sizeof(len_bytes)); + blake2b_Update(&ctx, &zero, 1); + blake2b_Update(&ctx, dst_prime, dst_prime_len); + if (blake2b_Final(&ctx, b0, sizeof(b0)) != 0) { + memzero(&ctx, sizeof(ctx)); + return -1; + } + + uint8_t ctr = 1; + if (blake2b_InitPersonal(&ctx, B_IN_BYTES, personal, sizeof(personal)) != 0) { + memzero(&ctx, sizeof(ctx)); + return -1; + } + blake2b_Update(&ctx, b0, sizeof(b0)); + blake2b_Update(&ctx, &ctr, 1); + blake2b_Update(&ctx, dst_prime, dst_prime_len); + if (blake2b_Final(&ctx, bi, sizeof(bi)) != 0) { + memzero(&ctx, sizeof(ctx)); + return -1; + } + + size_t take = out_len < B_IN_BYTES ? out_len : B_IN_BYTES; + memcpy(out, bi, take); + size_t produced = take; + + for (size_t i = 2; i <= ell; i++) { + for (size_t j = 0; j < B_IN_BYTES; j++) { + tmp[j] = b0[j] ^ bi[j]; + } + + ctr = (uint8_t)i; + if (blake2b_InitPersonal(&ctx, B_IN_BYTES, personal, sizeof(personal)) != 0) { + memzero(&ctx, sizeof(ctx)); + return -1; + } + blake2b_Update(&ctx, tmp, sizeof(tmp)); + blake2b_Update(&ctx, &ctr, 1); + blake2b_Update(&ctx, dst_prime, dst_prime_len); + if (blake2b_Final(&ctx, bi, sizeof(bi)) != 0) { + memzero(&ctx, sizeof(ctx)); + return -1; + } + + take = out_len - produced; + if (take > B_IN_BYTES) take = B_IN_BYTES; + memcpy(out + produced, bi, take); + produced += take; + } + + memzero(&ctx, sizeof(ctx)); + memzero(dst_prime, sizeof(dst_prime)); + memzero(b0, sizeof(b0)); + memzero(bi, sizeof(bi)); + memzero(tmp, sizeof(tmp)); + return 0; +} diff --git a/deps/crypto/trezor-crypto/pallas.h b/deps/crypto/trezor-crypto/pallas.h new file mode 100644 index 000000000..7fc986e2c --- /dev/null +++ b/deps/crypto/trezor-crypto/pallas.h @@ -0,0 +1,107 @@ +/** + * Copyright (c) 2025 KeepKey + * + * Pallas elliptic curve for Zcash Orchard. + * y^2 = x^3 + 5 over Fp + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __PALLAS_H__ +#define __PALLAS_H__ + +#include +#include + +#include "bignum.h" +#include "ecdsa.h" + +/* + * The ecdsa_curve struct is kept for compatibility but the generic + * point_multiply()/bn_multiply() must NOT be used with Pallas because + * the trezor-crypto bignum library assumes primes in [2^256 - 2^224, 2^256]. + * Use the pallas_* functions below instead. + */ +extern const ecdsa_curve pallas; + +/* Pallas field prime (~254 bits) */ +extern const bignum256 pallas_prime; + +/* Pallas group order (~254 bits) */ +extern const bignum256 pallas_order; + +/* Pallas generator point G = (-1 mod p, 2) */ +extern const curve_point pallas_G; + +/* expand_message_xmd using BLAKE2b-512, per RFC 9380 §5.3.1. */ +int pallas_expand_message_xmd_blake2b(const uint8_t *msg, size_t msg_len, + const uint8_t *dst, size_t dst_len, + uint8_t *out, size_t out_len); + +/* --- Field arithmetic mod p (Barrett reduction) --- */ + +/* x = k * x mod p */ +void pallas_mul_mod_p(bignum256 *x, const bignum256 *k); + +/* x = x mod p (simple reduction for values < 2^261) */ +void pallas_mod_p(bignum256 *x); + +/* x = x^(-1) mod p (Fermat's little theorem) */ +void pallas_inv_mod_p(bignum256 *x); + +/* res = (a + b) mod p */ +void pallas_add_mod_p(const bignum256 *a, const bignum256 *b, bignum256 *res); + +/* res = (a - b) mod p */ +void pallas_sub_mod_p(const bignum256 *a, const bignum256 *b, bignum256 *res); + +/* n = sqrt(n) mod p (Tonelli-Shanks). Returns 0 on success, -1 if no sqrt. */ +int pallas_sqrt_mod_p(bignum256 *n); + +/* --- Scalar arithmetic mod q (Barrett reduction) --- */ + +/* x = k * x mod q */ +void pallas_mul_mod_q(bignum256 *x, const bignum256 *k); + +/* x = x mod q (simple reduction for values < 2^261) */ +void pallas_mod_q(bignum256 *x); + +/* a = (a + b) mod q */ +void pallas_add_mod_q(bignum256 *a, const bignum256 *b); + +/* --- Point operations on Pallas curve --- */ + +/* res = k * G */ +void pallas_scalar_mult_G(const bignum256 *k, curve_point *res); + +/* res = k * P */ +void pallas_point_mult(const bignum256 *k, const curve_point *p, + curve_point *res); + +/* res = P + Q */ +void pallas_point_add(const curve_point *p, const curve_point *q, + curve_point *res); + +/* Returns nonzero if P is the point at infinity in this implementation. */ +int pallas_point_is_identity(const curve_point *p); + +/* Serialize Pallas point as LE x-coordinate with y parity in bit 255. */ +void pallas_point_encode(const curve_point *p, uint8_t out[32]); + +#endif diff --git a/deps/crypto/trezor-crypto/pallas_sinsemilla.c b/deps/crypto/trezor-crypto/pallas_sinsemilla.c new file mode 100644 index 000000000..7120c33bb --- /dev/null +++ b/deps/crypto/trezor-crypto/pallas_sinsemilla.c @@ -0,0 +1,274 @@ +/** + * Copyright (c) 2026 KeepKey + * + * Minimal Sinsemilla short-commit implementation for Orchard IVK derivation. + * + * This intentionally implements only: + * Commit^ivk.Output = SinsemillaShortCommit( + * "z.cash:Orchard-CommitIvk", ak || nk, rivk) + * + * S generators are derived on demand with the upstream + * "z.cash:SinsemillaS" hash-to-curve personalization. This keeps firmware + * ROM usage low by avoiding the 64 KiB precomputed generator table. + */ + +#include "pallas_sinsemilla.h" + +#include +#include + +#include "bignum.h" +#include "memzero.h" +#include "pallas.h" +#include "pallas_swu.h" + +static const uint8_t COMMIT_IVK_Q_X[32] = { + 0xf2, 0x82, 0x0f, 0x79, 0x92, 0x2f, 0xcb, 0x6b, + 0x32, 0xa2, 0x28, 0x51, 0x24, 0xcc, 0x1b, 0x42, + 0xfa, 0x41, 0xa2, 0x5a, 0xb8, 0x81, 0xcc, 0x7d, + 0x11, 0xc8, 0xa9, 0x4a, 0xf1, 0x0c, 0xbc, 0x05, +}; + +static const uint8_t COMMIT_IVK_Q_Y[32] = { + 0xbe, 0xde, 0xad, 0xcf, 0xce, 0xe5, 0x5a, 0xbe, + 0xf1, 0xa5, 0x6d, 0xc9, 0x1d, 0x35, 0xc4, 0x46, + 0x4b, 0x05, 0xde, 0x20, 0x46, 0x07, 0x59, 0xef, + 0xe6, 0xbe, 0x1a, 0xd4, 0xf6, 0x4c, 0x01, 0x1b, +}; + +static const uint8_t COMMIT_IVK_R_X[32] = { + 0x18, 0xa1, 0xf8, 0x5f, 0x6e, 0x48, 0x23, 0x98, + 0xc7, 0xed, 0x1a, 0xd3, 0xe2, 0x7f, 0x95, 0x02, + 0x48, 0x89, 0x80, 0x40, 0x0a, 0x29, 0x34, 0x16, + 0x4e, 0x13, 0x70, 0x50, 0xcd, 0x2c, 0xa2, 0x25, +}; + +static const uint8_t COMMIT_IVK_R_Y[32] = { + 0xa9, 0xdd, 0x7f, 0xe3, 0xb3, 0x93, 0xe7, 0x3f, + 0xc7, 0xa6, 0x58, 0x1b, 0xfb, 0x42, 0x44, 0x6b, + 0x94, 0x57, 0x4b, 0x28, 0xc4, 0x90, 0xc8, 0xc2, + 0xeb, 0xfa, 0xa2, 0x66, 0x99, 0xd2, 0xcf, 0x29, +}; + +static void point_from_xy_le(const uint8_t x[32], const uint8_t y[32], + curve_point *out) { + bn_read_le(x, &out->x); + bn_read_le(y, &out->y); + bn_normalize(&out->x); + bn_normalize(&out->y); +} + +static int read_base_field(const uint8_t in[32], bignum256 *out) { + if (!in || !out) return -1; + bn_read_le(in, out); + bn_normalize(out); + return bn_is_less(out, &pallas_prime) ? 0 : -1; +} + +static int read_scalar_field(const uint8_t in[32], bignum256 *out) { + if (!in || !out) return -1; + bn_read_le(in, out); + bn_normalize(out); + return bn_is_less(out, &pallas_order) ? 0 : -1; +} + +static int points_same_x(const curve_point *a, const curve_point *b) { + bignum256 ax, bx; + bn_copy(&a->x, &ax); + bn_copy(&b->x, &bx); + bn_normalize(&ax); + bn_normalize(&bx); + int same = bn_is_equal(&ax, &bx); + memzero(&ax, sizeof(ax)); + memzero(&bx, sizeof(bx)); + return same; +} + +static int sinsemilla_incomplete_add(const curve_point *a, const curve_point *b, + curve_point *out) { + if (!a || !b || !out) return -1; + if (pallas_point_is_identity(a) || pallas_point_is_identity(b)) return -1; + if (points_same_x(a, b)) return -1; + + pallas_point_add(a, b, out); + return 0; +} + +static int bit_from_msg(const uint8_t *msg, size_t bit) { + return (msg[bit / 8] >> (bit % 8)) & 1; +} + +static uint32_t sinsemilla_word(const uint8_t *msg, size_t msg_bits, + size_t word_idx) { + uint32_t word = 0; + for (size_t i = 0; i < PALLAS_SINSEMILLA_K; i++) { + size_t bit = word_idx * PALLAS_SINSEMILLA_K + i; + if (bit < msg_bits && bit_from_msg(msg, bit)) { + word |= (uint32_t)1 << i; + } + } + return word; +} + +static int sinsemilla_s_generator(uint32_t word, curve_point *out) { + static const char domain[] = "z.cash:SinsemillaS"; + uint8_t word_le[4] = { + (uint8_t)(word & 0xff), + (uint8_t)((word >> 8) & 0xff), + (uint8_t)((word >> 16) & 0xff), + (uint8_t)((word >> 24) & 0xff), + }; + int ret = pallas_hash_to_curve(domain, word_le, sizeof(word_le), out); + memzero(word_le, sizeof(word_le)); + return ret; +} + +static void set_msg_bit(uint8_t *msg, size_t bit) { + msg[bit / 8] |= (uint8_t)(1u << (bit % 8)); +} + +static void pack_commit_ivk_msg(const uint8_t ak[32], const uint8_t nk[32], + uint8_t msg[64]) { + memset(msg, 0, 64); + for (size_t bit = 0; bit < 255; bit++) { + if (bit_from_msg(ak, bit)) { + set_msg_bit(msg, bit); + } + if (bit_from_msg(nk, bit)) { + set_msg_bit(msg, 255 + bit); + } + } +} + +int pallas_sinsemilla_hash_to_point(const curve_point *q, const uint8_t *msg, + size_t msg_bits, curve_point *out) { + if (!q || (!msg && msg_bits != 0) || !out) return -1; + if (msg_bits > PALLAS_SINSEMILLA_MAX_BITS) return -1; + if (pallas_point_is_identity(q)) return -1; + + curve_point acc = *q; + size_t word_count = + (msg_bits + PALLAS_SINSEMILLA_K - 1) / PALLAS_SINSEMILLA_K; + + for (size_t i = 0; i < word_count; i++) { + uint32_t word = sinsemilla_word(msg, msg_bits, i); + curve_point s, old_acc, tmp; + if (sinsemilla_s_generator(word, &s) != 0) { + memzero(&acc, sizeof(acc)); + return -1; + } + old_acc = acc; + + if (sinsemilla_incomplete_add(&old_acc, &s, &tmp) != 0 || + sinsemilla_incomplete_add(&tmp, &old_acc, &acc) != 0) { + memzero(&acc, sizeof(acc)); + memzero(&s, sizeof(s)); + memzero(&old_acc, sizeof(old_acc)); + memzero(&tmp, sizeof(tmp)); + return -1; + } + + memzero(&s, sizeof(s)); + memzero(&old_acc, sizeof(old_acc)); + memzero(&tmp, sizeof(tmp)); + } + + *out = acc; + memzero(&acc, sizeof(acc)); + return 0; +} + +int pallas_sinsemilla_hash(const curve_point *q, const uint8_t *msg, + size_t msg_bits, uint8_t hash_out[32]) { + if (!hash_out) return -1; + + curve_point hash_point; + if (pallas_sinsemilla_hash_to_point(q, msg, msg_bits, &hash_point) != 0) { + return -1; + } + + bignum256 x; + bn_copy(&hash_point.x, &x); + bn_write_le(&x, hash_out); + + memzero(&hash_point, sizeof(hash_point)); + memzero(&x, sizeof(x)); + return 0; +} + +int pallas_sinsemilla_commit(const curve_point *q, const curve_point *r, + const uint8_t *msg, size_t msg_bits, + const uint8_t blind[32], curve_point *out) { + if (!r || !blind || !out) return -1; + if (pallas_point_is_identity(r)) return -1; + + bignum256 blind_scalar; + if (read_scalar_field(blind, &blind_scalar) != 0) { + memzero(&blind_scalar, sizeof(blind_scalar)); + return -1; + } + + curve_point hash_point, blind_point, commit; + if (pallas_sinsemilla_hash_to_point(q, msg, msg_bits, &hash_point) != 0) { + memzero(&blind_scalar, sizeof(blind_scalar)); + return -1; + } + + pallas_point_mult(&blind_scalar, r, &blind_point); + pallas_point_add(&hash_point, &blind_point, &commit); + *out = commit; + + memzero(&blind_scalar, sizeof(blind_scalar)); + memzero(&hash_point, sizeof(hash_point)); + memzero(&blind_point, sizeof(blind_point)); + memzero(&commit, sizeof(commit)); + return 0; +} + +int pallas_sinsemilla_short_commit(const curve_point *q, const curve_point *r, + const uint8_t *msg, size_t msg_bits, + const uint8_t blind[32], + uint8_t out[32]) { + if (!out) return -1; + + curve_point commit; + if (pallas_sinsemilla_commit(q, r, msg, msg_bits, blind, &commit) != 0) { + return -1; + } + + bignum256 x; + bn_copy(&commit.x, &x); + bn_write_le(&x, out); + + memzero(&commit, sizeof(commit)); + memzero(&x, sizeof(x)); + return 0; +} + +int pallas_sinsemilla_commit_ivk(const uint8_t ak[32], const uint8_t nk[32], + const uint8_t rivk[32], + uint8_t ivk_out[32]) { + if (!ak || !nk || !rivk || !ivk_out) return -1; + + bignum256 ak_field, nk_field; + if (read_base_field(ak, &ak_field) != 0 || + read_base_field(nk, &nk_field) != 0) { + memzero(&ak_field, sizeof(ak_field)); + memzero(&nk_field, sizeof(nk_field)); + return -1; + } + + uint8_t msg[64]; + curve_point q, r; + pack_commit_ivk_msg(ak, nk, msg); + point_from_xy_le(COMMIT_IVK_Q_X, COMMIT_IVK_Q_Y, &q); + point_from_xy_le(COMMIT_IVK_R_X, COMMIT_IVK_R_Y, &r); + int ret = pallas_sinsemilla_short_commit(&q, &r, msg, 510, rivk, ivk_out); + + memzero(&ak_field, sizeof(ak_field)); + memzero(&nk_field, sizeof(nk_field)); + memzero(msg, sizeof(msg)); + memzero(&q, sizeof(q)); + memzero(&r, sizeof(r)); + return ret; +} diff --git a/deps/crypto/trezor-crypto/pallas_sinsemilla.h b/deps/crypto/trezor-crypto/pallas_sinsemilla.h new file mode 100644 index 000000000..325f45884 --- /dev/null +++ b/deps/crypto/trezor-crypto/pallas_sinsemilla.h @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2026 KeepKey + * + * Minimal Sinsemilla primitives needed for Zcash Orchard key derivation. + */ + +#ifndef __PALLAS_SINSEMILLA_H__ +#define __PALLAS_SINSEMILLA_H__ + +#include +#include + +#include "ecdsa.h" + +#define PALLAS_SINSEMILLA_K 10 +#define PALLAS_SINSEMILLA_C 253 +#define PALLAS_SINSEMILLA_MAX_BITS \ + (PALLAS_SINSEMILLA_K * PALLAS_SINSEMILLA_C) + +/* + * Compute SinsemillaHashToPoint(Q, msg). + * + * msg is a packed little-endian bit string: bit i is read from + * msg[i / 8] >> (i % 8). msg_bits must be <= PALLAS_SINSEMILLA_MAX_BITS. + */ +int pallas_sinsemilla_hash_to_point(const curve_point *q, const uint8_t *msg, + size_t msg_bits, curve_point *out); + +/* + * Compute SinsemillaHash(Q, msg), returning the little-endian Pallas base-field + * x-coordinate extracted from SinsemillaHashToPoint. + */ +int pallas_sinsemilla_hash(const curve_point *q, const uint8_t *msg, + size_t msg_bits, uint8_t hash_out[32]); + +/* + * Compute SinsemillaCommit(Q, R, msg, r). + * + * blind is a canonical Pallas scalar-field encoding. + */ +int pallas_sinsemilla_commit(const curve_point *q, const curve_point *r, + const uint8_t *msg, size_t msg_bits, + const uint8_t blind[32], curve_point *out); + +/* + * Compute SinsemillaShortCommit(Q, R, msg, r), returning the little-endian + * Pallas base-field x-coordinate extracted from SinsemillaCommit. + */ +int pallas_sinsemilla_short_commit(const curve_point *q, const curve_point *r, + const uint8_t *msg, size_t msg_bits, + const uint8_t blind[32], + uint8_t out[32]); + +/* + * Compute Commit^ivk.Output = SinsemillaShortCommit( + * "z.cash:Orchard-CommitIvk", I2LEBSP_255(ak) || I2LEBSP_255(nk), rivk) + * + * ak and nk are canonical Pallas base-field encodings. rivk is a canonical + * Pallas scalar-field encoding. ivk_out receives the 32-byte LE Pallas + * base-field output; callers must reject zero where required by Orchard IVKs. + */ +int pallas_sinsemilla_commit_ivk(const uint8_t ak[32], const uint8_t nk[32], + const uint8_t rivk[32], + uint8_t ivk_out[32]); + +#endif diff --git a/deps/crypto/trezor-crypto/pallas_sinsemilla_table.inc b/deps/crypto/trezor-crypto/pallas_sinsemilla_table.inc new file mode 100644 index 000000000..a7085bfc9 --- /dev/null +++ b/deps/crypto/trezor-crypto/pallas_sinsemilla_table.inc @@ -0,0 +1,1026 @@ +static const uint8_t SINSEMILLA_S_BYTES[1024][2][32] = { + {{0x5f, 0xea, 0x44, 0x20, 0x91, 0xeb, 0x91, 0x5a, 0xb5, 0x62, 0xde, 0xbe, 0xaf, 0x5b, 0xa0, 0x29, 0x7b, 0xfc, 0x4a, 0x7d, 0xea, 0xd4, 0x31, 0x14, 0x0f, 0x1f, 0x88, 0xe6, 0x8b, 0x21, 0xb5, 0x0d}, {0x83, 0x64, 0x8e, 0xbf, 0x76, 0x4f, 0xc2, 0x17, 0x01, 0xba, 0x65, 0x2e, 0x1c, 0x04, 0x4a, 0x94, 0xd0, 0xd5, 0x93, 0x84, 0x29, 0x66, 0xaf, 0x9c, 0x1c, 0xa0, 0x52, 0xf1, 0xc2, 0x40, 0x0f, 0x2f}}, + {{0x91, 0xaf, 0x08, 0xa1, 0x3e, 0xe3, 0x4a, 0xce, 0x8f, 0x9b, 0x64, 0x24, 0xca, 0x00, 0x77, 0xe6, 0x04, 0x54, 0x17, 0x39, 0xeb, 0x33, 0xfd, 0xc8, 0x18, 0x95, 0xe1, 0xb3, 0xb4, 0x12, 0x11, 0x21}, {0xee, 0xc5, 0x10, 0xf8, 0x93, 0xc2, 0x83, 0x1d, 0xbc, 0x19, 0x0e, 0x67, 0x4a, 0x74, 0x3c, 0xb4, 0xfe, 0x35, 0x5a, 0xcd, 0x79, 0x3e, 0x8a, 0xa3, 0x3b, 0xb0, 0xad, 0x93, 0x39, 0x99, 0xc5, 0x06}}, + {{0x24, 0x6d, 0x8f, 0xa1, 0x75, 0xc4, 0xe0, 0x22, 0xc0, 0x11, 0x54, 0x4b, 0x33, 0xb3, 0x0c, 0xf4, 0x33, 0x9b, 0x5b, 0x35, 0xe2, 0xa4, 0x61, 0x46, 0xa3, 0x25, 0xf9, 0x49, 0xcd, 0x2c, 0xb3, 0x25}, {0x57, 0x97, 0xfd, 0xb8, 0x8d, 0x6b, 0x7d, 0xa6, 0xd2, 0xcc, 0x45, 0xf9, 0xb9, 0xeb, 0xe1, 0x4b, 0x11, 0x47, 0xb4, 0x23, 0xf3, 0xd0, 0x53, 0x7d, 0x2c, 0x69, 0xd0, 0x70, 0xba, 0xf2, 0x0f, 0x14}}, + {{0xbc, 0xda, 0x19, 0x04, 0x0f, 0xef, 0xfa, 0xa5, 0x26, 0x18, 0x8b, 0x93, 0x12, 0xca, 0x39, 0x65, 0x1f, 0x70, 0x2c, 0xd0, 0x5c, 0x46, 0xff, 0x60, 0xc9, 0x32, 0x18, 0xe1, 0x48, 0x5a, 0x21, 0x14}, {0xdc, 0x36, 0xca, 0x25, 0x36, 0x5d, 0x1d, 0x01, 0x56, 0xad, 0xe2, 0x53, 0x4b, 0x3b, 0xb6, 0x97, 0xbd, 0x03, 0x58, 0x0b, 0xb9, 0xa0, 0x11, 0xc7, 0x4d, 0x88, 0xcb, 0xbe, 0x57, 0x69, 0x66, 0x10}}, + {{0x36, 0x09, 0xed, 0x4b, 0xf6, 0xce, 0x48, 0xcd, 0xce, 0x61, 0x38, 0xf7, 0x52, 0x8b, 0x94, 0x0e, 0x9f, 0x05, 0x3f, 0xd2, 0x95, 0xb5, 0xb9, 0x9a, 0x1c, 0x15, 0x63, 0x9e, 0x3b, 0xf9, 0x5c, 0x31}, {0x1a, 0x72, 0x1c, 0xa3, 0x84, 0x76, 0x57, 0xe2, 0x1d, 0xa5, 0x70, 0xc0, 0x86, 0x13, 0xef, 0x81, 0xca, 0x78, 0x43, 0xd0, 0x52, 0x9a, 0xfb, 0x2a, 0x40, 0xad, 0xfb, 0x8d, 0xb3, 0xc0, 0x54, 0x2c}}, + {{0xdf, 0x3f, 0x5a, 0xaa, 0x62, 0x96, 0x62, 0x1e, 0x9b, 0x38, 0x31, 0x9d, 0xdc, 0x57, 0xfb, 0x94, 0xb7, 0x3a, 0x6c, 0xbe, 0x2e, 0x54, 0xc5, 0x63, 0xc5, 0x5e, 0x92, 0x7e, 0xa5, 0x51, 0x74, 0x1d}, {0x4b, 0x45, 0xca, 0xaa, 0xc8, 0x1d, 0x4c, 0x93, 0xdd, 0xc0, 0xef, 0x4e, 0x8c, 0x04, 0x86, 0xc0, 0xbc, 0x6f, 0x4b, 0x16, 0x72, 0x14, 0x9c, 0xc4, 0xc7, 0x7e, 0x47, 0x93, 0x39, 0x51, 0x4b, 0x0a}}, + {{0x8f, 0x11, 0x44, 0xac, 0xbd, 0xce, 0x7c, 0x7e, 0x1c, 0xff, 0x29, 0x84, 0x2f, 0x27, 0x55, 0xe0, 0x24, 0x5f, 0xa7, 0x24, 0xf8, 0xb5, 0x80, 0x3c, 0x68, 0x46, 0xd4, 0x10, 0x74, 0x3c, 0x3d, 0x0d}, {0xcc, 0x55, 0x22, 0xb5, 0x1b, 0xb2, 0xea, 0x79, 0x82, 0x09, 0x4f, 0xde, 0xc0, 0x61, 0x68, 0x12, 0xe9, 0x5a, 0xa5, 0x23, 0x86, 0x31, 0x2e, 0xa0, 0x4f, 0x33, 0x58, 0x97, 0x12, 0xe7, 0x94, 0x2b}}, + {{0x2f, 0x9d, 0x12, 0xd7, 0x3e, 0x38, 0x77, 0x0e, 0x18, 0x9b, 0x0f, 0x4b, 0x71, 0xdf, 0x83, 0x62, 0x2c, 0x06, 0x66, 0xd6, 0x7c, 0x61, 0x64, 0x08, 0x57, 0x0b, 0x91, 0x74, 0xba, 0xfa, 0x7e, 0x19}, {0x27, 0xc1, 0xfd, 0x12, 0xcb, 0xe2, 0xb8, 0x85, 0xcd, 0x45, 0x27, 0xde, 0xb5, 0x75, 0x88, 0x7a, 0x1b, 0xd3, 0x99, 0xed, 0x97, 0x6a, 0xf5, 0x8d, 0xa9, 0x56, 0xe9, 0xd6, 0x47, 0x55, 0xd9, 0x34}}, + {{0x55, 0xb0, 0x24, 0x6b, 0x92, 0xd2, 0x1c, 0xd2, 0x8e, 0x41, 0x46, 0x72, 0x07, 0x7a, 0x16, 0xa4, 0x47, 0x9b, 0x54, 0xef, 0xab, 0x11, 0x29, 0x3e, 0x66, 0xee, 0x1c, 0xb1, 0xe8, 0xd0, 0x5a, 0x30}, {0x38, 0xb9, 0xbf, 0xa5, 0xcf, 0x73, 0x39, 0x9b, 0xd6, 0x80, 0x38, 0xd1, 0xa5, 0x0c, 0xa2, 0x12, 0xa4, 0x34, 0xb7, 0xc3, 0x42, 0x12, 0x07, 0x82, 0xd8, 0xbf, 0xbb, 0x6d, 0x02, 0x91, 0x25, 0x3e}}, + {{0xbe, 0x56, 0x48, 0x6b, 0x62, 0xe3, 0xbc, 0xf6, 0x84, 0x34, 0x66, 0x5b, 0xf1, 0xe6, 0x5e, 0xdf, 0x61, 0x3e, 0x66, 0x47, 0xf1, 0xbd, 0x37, 0xbc, 0x1f, 0x77, 0xcc, 0xae, 0x20, 0xed, 0x80, 0x2a}, {0x53, 0xd7, 0xd9, 0x40, 0xcd, 0x58, 0xaf, 0xae, 0xeb, 0x44, 0xa9, 0x39, 0xa1, 0x81, 0x76, 0x67, 0xae, 0xd1, 0x80, 0xd0, 0x20, 0x42, 0x78, 0xdb, 0x73, 0xc8, 0x89, 0x2f, 0x53, 0x9f, 0xed, 0x3b}}, + {{0x34, 0x3b, 0xe7, 0x69, 0x1c, 0x35, 0x6d, 0xa9, 0x32, 0xb4, 0x74, 0xbb, 0x2c, 0xe6, 0xdf, 0xe5, 0x09, 0x39, 0x63, 0xc5, 0x86, 0xf8, 0x0b, 0x3e, 0x52, 0x0f, 0x6b, 0x51, 0x9d, 0x67, 0x69, 0x11}, {0xee, 0x52, 0x56, 0x3a, 0x48, 0x26, 0x7f, 0x44, 0x12, 0x39, 0xe8, 0xaf, 0xb3, 0x03, 0xd8, 0x77, 0xd3, 0x4f, 0x8f, 0x98, 0x79, 0xa7, 0x1e, 0xbe, 0x5d, 0xf8, 0xef, 0x46, 0xd8, 0x58, 0xdc, 0x24}}, + {{0x30, 0x50, 0x87, 0xbc, 0x2e, 0xc6, 0x1d, 0x85, 0x65, 0x57, 0x3c, 0x70, 0x0c, 0x51, 0x57, 0x19, 0x92, 0xc9, 0xae, 0x3a, 0xe8, 0x8d, 0x39, 0xd4, 0xcb, 0xd1, 0xe0, 0xe0, 0x64, 0x51, 0x64, 0x0a}, {0x6d, 0x93, 0xa6, 0x1a, 0x4c, 0x49, 0x68, 0xd7, 0xa4, 0xc2, 0x48, 0xa5, 0xee, 0xd7, 0x89, 0x0c, 0xb1, 0x76, 0x78, 0x99, 0xb7, 0x87, 0x1f, 0x7e, 0x82, 0xf1, 0x79, 0x38, 0x3d, 0xb6, 0x3f, 0x15}}, + {{0x39, 0x34, 0xa8, 0x42, 0x19, 0x06, 0x65, 0xc5, 0xf2, 0x3d, 0x3a, 0x19, 0x7c, 0xf5, 0x16, 0x77, 0x0a, 0xea, 0x7a, 0x8d, 0xe1, 0xb0, 0x25, 0x13, 0x01, 0x76, 0x8b, 0xa6, 0x53, 0x17, 0xa9, 0x05}, {0x3c, 0xd4, 0xbd, 0x26, 0x16, 0x23, 0x43, 0x24, 0x5f, 0x57, 0xf2, 0xa3, 0x64, 0xe7, 0x9f, 0x95, 0x4e, 0x14, 0x99, 0x97, 0x40, 0x6a, 0x09, 0xd7, 0x08, 0x95, 0x7e, 0x34, 0x30, 0xc6, 0x29, 0x1c}}, + {{0x2a, 0xe7, 0x11, 0x14, 0x46, 0x6f, 0x43, 0xe8, 0x59, 0x2a, 0x49, 0x72, 0x34, 0x40, 0x1a, 0x2c, 0x91, 0xb6, 0x8a, 0x93, 0x8d, 0x0a, 0x47, 0x13, 0x44, 0x35, 0xc9, 0xce, 0xb5, 0x34, 0xe3, 0x25}, {0x3d, 0x4b, 0xad, 0x9c, 0x33, 0xd2, 0xc5, 0xce, 0xab, 0x45, 0xcc, 0xa4, 0x61, 0x07, 0x0d, 0xa4, 0xb2, 0x84, 0x80, 0x2d, 0x50, 0xd2, 0x4c, 0x19, 0x74, 0x24, 0x59, 0x61, 0xdb, 0x64, 0x60, 0x01}}, + {{0xc9, 0x5c, 0x37, 0x25, 0xb5, 0x65, 0xf0, 0xe2, 0xab, 0x25, 0x88, 0x8c, 0x87, 0x59, 0x28, 0x25, 0x66, 0x6a, 0x9d, 0xbc, 0xc1, 0x31, 0x52, 0x92, 0x7e, 0x9c, 0x90, 0xc1, 0xd0, 0x2b, 0x9c, 0x37}, {0x30, 0x94, 0x75, 0x63, 0xa7, 0xef, 0xfb, 0xa0, 0xf0, 0x83, 0x73, 0x7b, 0x41, 0x1e, 0x0e, 0x43, 0x40, 0x6e, 0xf3, 0x66, 0x3a, 0x12, 0xea, 0xdd, 0x1b, 0x9f, 0xd5, 0x99, 0x54, 0xc2, 0xa9, 0x11}}, + {{0xaa, 0xed, 0x2e, 0x86, 0x1e, 0x9e, 0x5a, 0x0b, 0xc6, 0x61, 0xff, 0x61, 0x82, 0x43, 0xa3, 0xc0, 0xa1, 0xf3, 0x01, 0x48, 0xdc, 0xf6, 0x41, 0x4b, 0x82, 0x6f, 0x65, 0xd3, 0xb2, 0xc7, 0x6f, 0x0c}, {0xb5, 0x3b, 0x60, 0x3e, 0xe8, 0x50, 0x0d, 0xf3, 0x5f, 0x8e, 0x54, 0x7d, 0x78, 0xb4, 0x9f, 0x58, 0xeb, 0x0e, 0xea, 0xd1, 0x32, 0xb0, 0xd5, 0x06, 0x8e, 0xfe, 0xdc, 0x96, 0x6d, 0xa7, 0x92, 0x24}}, + {{0xd9, 0xe5, 0x4f, 0x3a, 0x69, 0x4d, 0x19, 0x07, 0x22, 0x70, 0xed, 0x5c, 0xd6, 0xce, 0xf4, 0xc3, 0xb7, 0xe6, 0xee, 0xf9, 0xc3, 0xc5, 0x65, 0x19, 0x04, 0x0e, 0xb5, 0x3b, 0x45, 0x5d, 0x17, 0x0c}, {0x9a, 0x97, 0xa8, 0x02, 0x5c, 0xe6, 0x28, 0x6e, 0xc2, 0x1e, 0x3a, 0x21, 0xb2, 0xbd, 0x55, 0x91, 0x8a, 0xa0, 0x1b, 0xac, 0xd2, 0x5d, 0x92, 0xa5, 0x90, 0x29, 0x01, 0x2d, 0x4f, 0x3d, 0x6e, 0x10}}, + {{0x0a, 0x6d, 0x8f, 0x71, 0x69, 0x57, 0xf5, 0x2a, 0x80, 0x9c, 0x3d, 0xdb, 0x35, 0x01, 0xcc, 0x0a, 0x05, 0x5e, 0x13, 0x93, 0x95, 0x9d, 0xf8, 0x31, 0x55, 0xb1, 0xed, 0x20, 0xe3, 0xea, 0xe5, 0x26}, {0xc9, 0xd1, 0x5f, 0xb9, 0xee, 0xfd, 0x5b, 0xd7, 0x74, 0x53, 0x8c, 0x81, 0x0a, 0xa8, 0x63, 0x1e, 0x40, 0xc0, 0x0b, 0x0f, 0xe6, 0xc3, 0xb1, 0x4b, 0x0c, 0x4b, 0x14, 0xcd, 0x2a, 0x88, 0x05, 0x1d}}, + {{0x94, 0x5b, 0x39, 0x5e, 0xf2, 0x90, 0xc3, 0x7e, 0x49, 0xa5, 0x8f, 0xc6, 0x55, 0x07, 0x30, 0x42, 0x07, 0x04, 0x81, 0xaf, 0x33, 0x97, 0x10, 0x92, 0xd9, 0x00, 0xeb, 0x14, 0xd7, 0x60, 0x0d, 0x31}, {0x0a, 0x65, 0x10, 0x44, 0xcb, 0x43, 0x04, 0xce, 0x43, 0xef, 0x00, 0xf9, 0x53, 0x40, 0xc0, 0xb1, 0xdd, 0x1f, 0x12, 0x93, 0xa3, 0xe7, 0x87, 0x40, 0x5c, 0xec, 0xce, 0xcd, 0x9e, 0x55, 0xe2, 0x3e}}, + {{0x43, 0xeb, 0x09, 0xc7, 0xbb, 0xb2, 0xa0, 0xa2, 0x24, 0x06, 0x18, 0xbf, 0xea, 0x17, 0xde, 0x8a, 0x87, 0x81, 0xac, 0x1e, 0xe5, 0xce, 0x3d, 0xbe, 0x8d, 0xac, 0xec, 0x09, 0x81, 0x04, 0x19, 0x17}, {0x5b, 0xa0, 0x15, 0xcc, 0x3a, 0x97, 0xbc, 0x2a, 0x3a, 0x19, 0x0a, 0x57, 0x0b, 0xdf, 0xa8, 0x50, 0x44, 0x1d, 0x0e, 0x4f, 0x98, 0xe0, 0xf1, 0x87, 0xc5, 0xf8, 0xfe, 0xb9, 0xc5, 0x3a, 0x67, 0x12}}, + {{0x69, 0x33, 0x58, 0x6d, 0xfe, 0xd0, 0x61, 0xb4, 0x87, 0x92, 0x82, 0xc9, 0x0f, 0x11, 0xbc, 0xcc, 0xf0, 0xa5, 0x26, 0x26, 0x47, 0xda, 0x63, 0x02, 0xc6, 0x19, 0x37, 0x9c, 0x22, 0xd2, 0x89, 0x12}, {0x12, 0x62, 0x69, 0xf8, 0x09, 0xd1, 0x84, 0x7f, 0x7e, 0xf3, 0xc9, 0x60, 0x35, 0x84, 0xb6, 0xe7, 0xaa, 0xb9, 0xa3, 0xa8, 0xa3, 0x26, 0xab, 0xc9, 0x44, 0x1e, 0xad, 0xd4, 0xe9, 0xe5, 0xa7, 0x08}}, + {{0xfb, 0xcf, 0xa6, 0x67, 0x0e, 0xd7, 0x57, 0xd6, 0x63, 0xd6, 0xd8, 0xf5, 0x7a, 0x8f, 0xc2, 0x1b, 0xdd, 0xac, 0x2e, 0x5e, 0x97, 0xcb, 0x6c, 0x17, 0x2a, 0x22, 0x1c, 0xa9, 0xf1, 0x48, 0xdc, 0x08}, {0x8c, 0x12, 0xb6, 0x40, 0xeb, 0x0c, 0xaa, 0xc6, 0x17, 0xa2, 0x70, 0xc2, 0xe5, 0x9e, 0xa1, 0x94, 0x3a, 0x08, 0xf4, 0xa1, 0x14, 0xf1, 0x79, 0x9f, 0xd0, 0xb3, 0x55, 0xaa, 0x41, 0x09, 0xf4, 0x21}}, + {{0xc1, 0xc2, 0x13, 0x71, 0x03, 0xe7, 0xc6, 0x84, 0x21, 0xf5, 0x2c, 0x5e, 0x9a, 0x5a, 0x49, 0x95, 0x5e, 0xb8, 0xc8, 0x1b, 0xa2, 0xc0, 0x9d, 0xae, 0x02, 0x2d, 0x7f, 0x25, 0x09, 0x78, 0xde, 0x2b}, {0xf9, 0xd2, 0x4e, 0x31, 0xa6, 0xc0, 0x14, 0xa1, 0x6f, 0x87, 0x7e, 0x3d, 0x08, 0xe6, 0xe7, 0x9b, 0x2a, 0xfd, 0x29, 0xd9, 0x23, 0x68, 0x05, 0xc1, 0xbd, 0x50, 0xe2, 0x83, 0x2a, 0x6d, 0xac, 0x15}}, + {{0x0b, 0x34, 0x21, 0xa4, 0xd5, 0x9f, 0xfe, 0xb0, 0x26, 0xcd, 0x9e, 0x3c, 0x71, 0xf1, 0xe4, 0x48, 0xbc, 0x95, 0x4a, 0x3d, 0x71, 0xac, 0xf4, 0xe4, 0x33, 0xd0, 0xb5, 0x1a, 0x28, 0x61, 0x2b, 0x31}, {0x9c, 0x5d, 0xdb, 0xaf, 0x00, 0xd4, 0x5b, 0x40, 0x90, 0x93, 0x6b, 0xef, 0x90, 0x80, 0xeb, 0xaa, 0xdd, 0x53, 0x3c, 0xe2, 0xb3, 0xc0, 0x69, 0x74, 0x59, 0x45, 0x5d, 0xb0, 0xbf, 0x21, 0x4f, 0x2e}}, + {{0x84, 0x2e, 0x12, 0x76, 0x2b, 0xd8, 0xbf, 0xa0, 0x27, 0x2d, 0x48, 0xb5, 0x0a, 0xca, 0x78, 0x6c, 0x1d, 0xeb, 0xaf, 0x62, 0x53, 0x56, 0xae, 0x75, 0x08, 0xea, 0xd4, 0x8b, 0x7f, 0x3b, 0x9b, 0x08}, {0x79, 0x25, 0x70, 0xc6, 0x34, 0x38, 0xca, 0x7f, 0x58, 0x62, 0x5d, 0x08, 0xd2, 0x31, 0x62, 0xa0, 0x34, 0xeb, 0x82, 0xd7, 0x36, 0x68, 0x2f, 0xb3, 0xc4, 0x10, 0xae, 0x35, 0x31, 0xe8, 0x08, 0x37}}, + {{0xfe, 0xc7, 0x05, 0x6c, 0x14, 0xc0, 0x6d, 0x9f, 0x5f, 0xa6, 0x7c, 0xd6, 0xb5, 0xb3, 0x19, 0x11, 0x54, 0xfe, 0xe6, 0xf7, 0x2e, 0x6d, 0xbf, 0x45, 0x4f, 0x3e, 0xb6, 0x9a, 0xac, 0x08, 0x41, 0x01}, {0x73, 0xd1, 0x14, 0xa5, 0xe7, 0x36, 0xf9, 0x57, 0xf2, 0xa3, 0x3e, 0x28, 0xb8, 0xa9, 0x4e, 0x3d, 0xdf, 0xd8, 0x56, 0xbf, 0xbe, 0x9b, 0x45, 0x0b, 0xce, 0xc3, 0x17, 0x64, 0x83, 0xbe, 0x96, 0x00}}, + {{0x10, 0x1e, 0x0a, 0xa6, 0x6e, 0x7e, 0x84, 0xbf, 0xf7, 0x8a, 0xa1, 0x59, 0xa9, 0x0d, 0x7d, 0x00, 0x6e, 0xf2, 0x5d, 0x80, 0x39, 0x6f, 0x66, 0x9b, 0x98, 0x47, 0x0d, 0xc7, 0xb1, 0xa8, 0xda, 0x2d}, {0x15, 0x32, 0x04, 0x21, 0xa1, 0xe4, 0xfa, 0x8a, 0x5f, 0x43, 0x5c, 0x66, 0x1d, 0x28, 0x45, 0xfc, 0xd6, 0xd0, 0xa4, 0x97, 0x23, 0x5d, 0x42, 0xcf, 0x16, 0xe4, 0x44, 0x35, 0xe4, 0xd5, 0x3b, 0x20}}, + {{0x91, 0xb9, 0x69, 0xc7, 0x42, 0xa3, 0x55, 0x63, 0xa5, 0xfb, 0xa8, 0x7c, 0x61, 0x35, 0x94, 0xaf, 0x7c, 0x86, 0xc6, 0x1b, 0x53, 0x19, 0xc6, 0x9b, 0x84, 0x8c, 0xe9, 0x7c, 0xb2, 0xb4, 0xc6, 0x35}, {0xe2, 0xd0, 0x05, 0xaa, 0xf2, 0x52, 0x8b, 0x35, 0xa7, 0x11, 0x69, 0x10, 0x04, 0xf4, 0x36, 0x1e, 0x5e, 0x92, 0x12, 0xf5, 0x5d, 0x77, 0xb1, 0xdf, 0x60, 0x56, 0x85, 0x28, 0xff, 0x4c, 0x0e, 0x2f}}, + {{0x4f, 0x39, 0x9d, 0x65, 0xaa, 0x45, 0xc6, 0x9b, 0xc2, 0x52, 0xf5, 0xaf, 0xd5, 0xf9, 0xfb, 0x63, 0xdf, 0x0d, 0x7d, 0x15, 0xf9, 0xa1, 0x81, 0x2a, 0xdd, 0x1b, 0x2b, 0x79, 0x6d, 0x8d, 0x40, 0x08}, {0xed, 0x6f, 0x42, 0xa4, 0xe0, 0xc9, 0x14, 0x62, 0xb0, 0x4d, 0xdc, 0xb2, 0xc1, 0x2d, 0x0c, 0x58, 0x91, 0x8b, 0x07, 0x7c, 0xe6, 0x7c, 0x6e, 0xdf, 0x07, 0x58, 0x0a, 0xaa, 0xc7, 0x86, 0x9b, 0x14}}, + {{0x5d, 0xd1, 0x6a, 0x01, 0x20, 0xfb, 0x66, 0x23, 0xa2, 0x92, 0xbe, 0x32, 0x09, 0xa5, 0x11, 0x7e, 0xdb, 0x85, 0x4d, 0xd3, 0x90, 0x3c, 0x46, 0xdf, 0xae, 0xdd, 0xfb, 0x37, 0x24, 0x35, 0x7d, 0x3b}, {0x2c, 0x3b, 0xe7, 0xe2, 0xa2, 0x78, 0x01, 0xd7, 0x17, 0xfd, 0xbb, 0x49, 0x60, 0x7a, 0x76, 0xeb, 0x04, 0x85, 0x18, 0x71, 0x5a, 0x0c, 0x81, 0xa0, 0x8a, 0xac, 0x31, 0x7a, 0x14, 0xda, 0xe1, 0x30}}, + {{0xe2, 0x05, 0xa3, 0x79, 0xc3, 0x1c, 0x6c, 0x99, 0xdf, 0xf9, 0x7f, 0xda, 0xa7, 0x35, 0xd9, 0x61, 0xfe, 0xd1, 0x84, 0x0e, 0x50, 0x3c, 0x7e, 0xe7, 0x09, 0xc0, 0xdf, 0xc1, 0x98, 0x60, 0x9d, 0x11}, {0x89, 0xad, 0xac, 0x0b, 0xf6, 0x68, 0x3c, 0xe8, 0xea, 0x8a, 0x33, 0x7f, 0x6b, 0x5f, 0xe4, 0xe3, 0x11, 0x0a, 0x03, 0x27, 0xb7, 0xed, 0x02, 0xcb, 0xd2, 0x37, 0xa0, 0xc7, 0xd8, 0xfc, 0xfe, 0x0d}}, + {{0x3f, 0x2e, 0xc1, 0xc0, 0xef, 0xe1, 0x49, 0x02, 0x0e, 0x14, 0x1b, 0xfc, 0x50, 0xf7, 0x35, 0xfd, 0xa4, 0x24, 0x0a, 0xee, 0x25, 0xfd, 0xcc, 0x34, 0x36, 0xe9, 0x50, 0x14, 0x37, 0xea, 0x85, 0x2d}, {0xa6, 0xc6, 0x76, 0x70, 0x87, 0x7e, 0x03, 0xea, 0x98, 0x9a, 0x81, 0x71, 0x4a, 0x05, 0x86, 0x1e, 0xdd, 0xff, 0x55, 0xde, 0x67, 0x0a, 0xb2, 0xc8, 0xad, 0x6e, 0x60, 0xc5, 0xdc, 0xf1, 0xa0, 0x2f}}, + {{0x2a, 0x14, 0x69, 0x82, 0x58, 0x40, 0x9d, 0x14, 0x7e, 0x0c, 0xcd, 0x87, 0x99, 0x86, 0x7e, 0xc4, 0x60, 0xc2, 0xe8, 0x4c, 0xe4, 0x84, 0x83, 0x90, 0x51, 0x3d, 0xef, 0x99, 0xec, 0xcc, 0x65, 0x0d}, {0x5c, 0xbb, 0x95, 0x1b, 0xce, 0xbe, 0x9f, 0x3d, 0xce, 0x60, 0x12, 0x5b, 0xea, 0x87, 0x69, 0x73, 0x2c, 0x3c, 0x99, 0xe0, 0x43, 0xcc, 0xc5, 0x69, 0x3d, 0x5e, 0xb2, 0xbc, 0x05, 0x28, 0x96, 0x12}}, + {{0xf6, 0x70, 0x57, 0xf8, 0xac, 0x79, 0x0f, 0xfd, 0xf2, 0x58, 0x87, 0x3b, 0xd0, 0x5a, 0xad, 0x2c, 0x87, 0xf0, 0x3a, 0x95, 0xba, 0x4e, 0x9d, 0xd7, 0x63, 0x03, 0xd8, 0x62, 0x8c, 0x77, 0x74, 0x00}, {0xb2, 0x04, 0xb7, 0x75, 0xbd, 0x43, 0x53, 0x4d, 0x6c, 0xbd, 0x9f, 0x38, 0xdf, 0x64, 0x69, 0xfb, 0x14, 0xc4, 0xf1, 0x36, 0x51, 0x4f, 0x99, 0x09, 0x85, 0x4e, 0xcb, 0xc6, 0xae, 0xf4, 0x76, 0x07}}, + {{0xc4, 0x9d, 0xac, 0x8c, 0x6e, 0xb1, 0x07, 0x22, 0x65, 0x02, 0xc3, 0x92, 0x64, 0x24, 0xcc, 0x6f, 0x45, 0xb8, 0xf4, 0x14, 0x0a, 0xe0, 0x05, 0x1f, 0x72, 0xe8, 0x04, 0xc2, 0xbe, 0xd4, 0xa9, 0x01}, {0xa8, 0x81, 0xfb, 0x24, 0xae, 0x69, 0x83, 0xf7, 0x67, 0x99, 0xae, 0x38, 0xa2, 0xa8, 0x41, 0xf7, 0x0d, 0xb3, 0xae, 0xfa, 0x85, 0x08, 0x08, 0x44, 0xe6, 0x18, 0xb9, 0x49, 0x1f, 0x7f, 0xf7, 0x03}}, + {{0x01, 0xc1, 0x4b, 0xfd, 0x83, 0xe0, 0x73, 0xad, 0x7f, 0x19, 0x3b, 0xca, 0x06, 0xc6, 0x99, 0xb2, 0x06, 0x65, 0xa8, 0x0b, 0x00, 0x00, 0xc8, 0x61, 0x76, 0x4f, 0xb5, 0xc4, 0xf3, 0x35, 0x91, 0x16}, {0x8c, 0xe2, 0x92, 0xeb, 0xce, 0x58, 0x60, 0x87, 0x2d, 0x0e, 0x6c, 0xf8, 0xe0, 0x16, 0xf0, 0x34, 0x50, 0x3f, 0x7b, 0xc4, 0x5e, 0x49, 0xb0, 0x86, 0xff, 0x85, 0xc5, 0xc4, 0x2b, 0xc4, 0xf1, 0x03}}, + {{0x8c, 0x79, 0xab, 0x2c, 0xb7, 0x94, 0x7d, 0x01, 0x23, 0xf5, 0xaa, 0x18, 0x5b, 0xcb, 0x6d, 0x8d, 0x0b, 0xc2, 0x94, 0x89, 0x5d, 0x8b, 0x08, 0x8e, 0x13, 0xfe, 0x35, 0xe6, 0x78, 0xe1, 0xba, 0x19}, {0x19, 0x01, 0x4a, 0x99, 0xb4, 0x84, 0x27, 0xab, 0x33, 0x7e, 0x5c, 0x63, 0x0e, 0xfe, 0xa4, 0x9d, 0xc4, 0xaf, 0xa2, 0xca, 0x12, 0x81, 0x43, 0x11, 0xe7, 0xc4, 0xd9, 0xde, 0x94, 0xda, 0xcf, 0x3a}}, + {{0xbc, 0x55, 0x7a, 0x31, 0x08, 0xcb, 0xce, 0xbb, 0xe6, 0xf0, 0x38, 0x32, 0xcd, 0xdd, 0xaa, 0x36, 0x1e, 0xd6, 0xab, 0xe6, 0xb6, 0x05, 0x00, 0xdf, 0x7c, 0x08, 0x3d, 0x05, 0x4e, 0xc6, 0x27, 0x25}, {0xef, 0x68, 0x3a, 0x03, 0xee, 0x48, 0xe8, 0x6b, 0xe1, 0xce, 0xf4, 0xd4, 0xac, 0xf9, 0xa3, 0x55, 0xbf, 0x28, 0x65, 0xd4, 0xce, 0x57, 0xdd, 0xf6, 0x96, 0xcc, 0x09, 0xb5, 0x7d, 0xea, 0x27, 0x1e}}, + {{0x80, 0x42, 0x16, 0x95, 0xd9, 0x12, 0xbc, 0xe5, 0xf6, 0x5d, 0x25, 0x51, 0xc2, 0x0d, 0x00, 0x2a, 0x82, 0xd8, 0x4c, 0x16, 0x4b, 0x92, 0x36, 0xa9, 0x49, 0xce, 0xa8, 0x32, 0x8a, 0x35, 0xa9, 0x34}, {0xa2, 0xac, 0xcb, 0xdf, 0xe4, 0x77, 0xe8, 0x60, 0x21, 0xa5, 0xf8, 0x25, 0x88, 0x3e, 0xa5, 0x0a, 0x98, 0xf0, 0xdd, 0x83, 0xc5, 0x6c, 0x25, 0xe3, 0xb8, 0xcd, 0xa3, 0x5a, 0x5c, 0xfc, 0xdb, 0x3b}}, + {{0xd8, 0x16, 0x3d, 0xea, 0xea, 0xf7, 0x95, 0x6d, 0x83, 0x53, 0xd6, 0x6b, 0x9a, 0x4e, 0xc0, 0x03, 0x83, 0xb2, 0xfe, 0xc4, 0x17, 0xbb, 0x05, 0xec, 0x07, 0x3b, 0x1f, 0xed, 0xa5, 0x03, 0x9e, 0x28}, {0x86, 0x76, 0xb1, 0xfe, 0x2f, 0xc5, 0x6a, 0x2b, 0x48, 0x89, 0x49, 0x4e, 0x92, 0xda, 0xb7, 0xbc, 0xd3, 0xdb, 0x4d, 0xd0, 0x81, 0xcd, 0x95, 0xa9, 0x4a, 0x22, 0x59, 0x11, 0x57, 0x6c, 0x46, 0x0c}}, + {{0x0c, 0x9f, 0xd2, 0xa4, 0xe7, 0x9b, 0x93, 0x60, 0xa2, 0x0a, 0x99, 0xb7, 0xa2, 0x62, 0x18, 0x15, 0xc2, 0x8c, 0xe7, 0x1c, 0x2c, 0xe6, 0xa3, 0x44, 0xf3, 0xe5, 0x7d, 0x42, 0xea, 0x25, 0x1e, 0x20}, {0x4f, 0x6b, 0xff, 0x27, 0xe9, 0x5e, 0x53, 0x58, 0x26, 0x71, 0x92, 0x95, 0xb3, 0xb5, 0xba, 0xa9, 0x81, 0x56, 0x1e, 0xe6, 0x08, 0x07, 0x60, 0x2c, 0x6d, 0x02, 0xa7, 0x37, 0xf6, 0x68, 0xd4, 0x31}}, + {{0xb3, 0x27, 0xf9, 0x32, 0xda, 0x2b, 0xec, 0x97, 0x87, 0xed, 0x61, 0xc3, 0x38, 0x9f, 0x79, 0x7e, 0x88, 0xfa, 0x01, 0xd6, 0x0b, 0xac, 0x8f, 0x58, 0xfe, 0x27, 0x4d, 0x73, 0x36, 0x77, 0x5f, 0x27}, {0xb9, 0xd9, 0x45, 0xc5, 0x27, 0x8a, 0x26, 0x64, 0xeb, 0x01, 0x23, 0xc4, 0x3d, 0xa2, 0xa0, 0x46, 0x1c, 0xc8, 0xcf, 0xdc, 0x4c, 0xe0, 0x7d, 0xac, 0x99, 0xb4, 0x12, 0x83, 0x78, 0x47, 0x30, 0x30}}, + {{0x28, 0x80, 0x15, 0x32, 0x46, 0xa1, 0x91, 0x94, 0xab, 0xe1, 0x01, 0x64, 0xc2, 0xc9, 0x63, 0xee, 0x7b, 0x84, 0xe6, 0xe3, 0x9c, 0x13, 0x8f, 0xe6, 0x2f, 0x84, 0xca, 0x9a, 0x03, 0xe8, 0xe9, 0x0c}, {0x09, 0x46, 0xc7, 0x25, 0xd1, 0x04, 0x9d, 0xe0, 0xad, 0xf8, 0x5e, 0xc0, 0xd0, 0xbb, 0x70, 0x37, 0x67, 0x95, 0x69, 0xa1, 0x88, 0x8c, 0x8b, 0xdd, 0xe4, 0xa6, 0x27, 0xf1, 0x12, 0x39, 0x99, 0x2d}}, + {{0x08, 0xdd, 0x63, 0x6f, 0x59, 0x54, 0x31, 0xe5, 0xc0, 0x9f, 0xa1, 0x10, 0xfe, 0x13, 0xa0, 0xf7, 0x40, 0xa0, 0x74, 0xac, 0xdc, 0x76, 0xb4, 0xd7, 0x3f, 0x78, 0x3f, 0x2f, 0xbf, 0x75, 0xa0, 0x08}, {0x00, 0xb2, 0xd2, 0x80, 0x09, 0x32, 0x62, 0x19, 0x77, 0x19, 0x7f, 0x5f, 0xb6, 0xe1, 0xa6, 0x3d, 0x35, 0x9c, 0xdb, 0xf2, 0xbf, 0x4d, 0x68, 0x61, 0x04, 0x92, 0x81, 0xb3, 0xf5, 0x4b, 0x21, 0x3c}}, + {{0x9d, 0x8e, 0x05, 0xe3, 0x8d, 0x69, 0xfc, 0x46, 0x53, 0x0e, 0x8b, 0xe5, 0x29, 0x74, 0x82, 0xed, 0xe8, 0x30, 0xd8, 0x65, 0xb5, 0x2a, 0x3b, 0xff, 0x50, 0x1e, 0x25, 0x6f, 0x8e, 0x89, 0xe6, 0x2e}, {0x9e, 0x7f, 0x78, 0xb7, 0x65, 0x16, 0xea, 0x2f, 0x83, 0x90, 0x9e, 0x33, 0x52, 0xeb, 0x4c, 0xa8, 0xf6, 0x9b, 0x06, 0x69, 0x09, 0x28, 0x32, 0xfc, 0xa4, 0x95, 0x44, 0xd2, 0x70, 0x75, 0xa0, 0x22}}, + {{0x50, 0x93, 0x8d, 0x02, 0x30, 0x14, 0x2e, 0x8b, 0xc0, 0x26, 0x86, 0xbf, 0xfb, 0x41, 0xad, 0xa9, 0xa7, 0xb4, 0x63, 0x0a, 0x98, 0x67, 0xff, 0xec, 0xd2, 0xab, 0x84, 0x0d, 0x0b, 0x64, 0xec, 0x38}, {0xc4, 0xdd, 0xd9, 0x9f, 0x9d, 0x24, 0x17, 0xda, 0x13, 0x2c, 0x18, 0xa3, 0x42, 0x5d, 0x62, 0x38, 0x62, 0xa2, 0x77, 0x53, 0x68, 0x4c, 0xb0, 0x74, 0xed, 0x80, 0x50, 0xab, 0xab, 0xc8, 0x61, 0x1e}}, + {{0x8c, 0xdb, 0x92, 0x9d, 0xf4, 0x3b, 0x63, 0x92, 0xc3, 0xfc, 0xd6, 0x12, 0x02, 0x7e, 0x42, 0x5b, 0x68, 0x9c, 0x99, 0x3c, 0x5b, 0x2b, 0x0c, 0xd2, 0x35, 0x36, 0x6d, 0x73, 0xa8, 0x46, 0xa7, 0x34}, {0x20, 0x73, 0xc0, 0x9f, 0xf1, 0x9a, 0x4c, 0x48, 0xc2, 0xdd, 0xb0, 0x4e, 0x04, 0x4c, 0x62, 0x23, 0x73, 0x3b, 0x4d, 0x85, 0x14, 0x35, 0xe8, 0x27, 0x3b, 0xc7, 0xa7, 0x7c, 0xe8, 0x16, 0x64, 0x30}}, + {{0x6b, 0x35, 0x45, 0xcc, 0x0d, 0x11, 0xd4, 0x32, 0xae, 0x07, 0x03, 0xfc, 0x5e, 0x7f, 0xf4, 0x48, 0x83, 0x96, 0xff, 0xf3, 0x2b, 0x0e, 0x53, 0x78, 0x5f, 0x2e, 0x05, 0xda, 0xab, 0x91, 0xd6, 0x36}, {0x2e, 0xff, 0x02, 0x53, 0x77, 0xda, 0xdb, 0xbe, 0x24, 0x70, 0x79, 0xf2, 0x17, 0x59, 0x4c, 0x4a, 0xf5, 0xd7, 0xe3, 0x02, 0x1c, 0x7f, 0x89, 0x0a, 0xe4, 0xa0, 0x4f, 0x61, 0xf3, 0xb0, 0xac, 0x01}}, + {{0xff, 0xd8, 0x46, 0xf0, 0xc0, 0x24, 0xd3, 0x4e, 0xb4, 0x54, 0xbc, 0x41, 0xca, 0x1a, 0x1f, 0xd8, 0x50, 0x58, 0x93, 0x31, 0xfd, 0x70, 0x3d, 0x63, 0x0e, 0xa9, 0x98, 0x93, 0x03, 0xeb, 0x15, 0x2f}, {0xc9, 0x37, 0xf7, 0x5a, 0x99, 0x44, 0xbe, 0xe7, 0xe7, 0x2c, 0x33, 0x03, 0x1b, 0x91, 0x3c, 0x07, 0xda, 0x2d, 0xff, 0xf5, 0xed, 0x25, 0xa6, 0x6e, 0xdf, 0xd3, 0x2d, 0x09, 0xf6, 0x63, 0x90, 0x02}}, + {{0xc1, 0xc6, 0x92, 0x70, 0x0b, 0x26, 0xf2, 0x15, 0x24, 0x24, 0x8b, 0x67, 0xe3, 0x36, 0xfd, 0x00, 0x90, 0x32, 0x3d, 0x40, 0xd5, 0x36, 0x63, 0x14, 0xbe, 0xa6, 0xdd, 0xa8, 0x20, 0xd6, 0xcc, 0x26}, {0xf6, 0x5b, 0x3c, 0xd9, 0xf8, 0x05, 0xd6, 0x24, 0x94, 0x08, 0xca, 0x75, 0x90, 0x14, 0x50, 0xbe, 0x18, 0x11, 0x83, 0x41, 0x43, 0xd5, 0xea, 0x70, 0x14, 0xe5, 0x61, 0xbe, 0x93, 0x42, 0x7e, 0x19}}, + {{0x56, 0x44, 0x73, 0x5c, 0x71, 0x32, 0x50, 0x9b, 0x1f, 0x88, 0x29, 0xb3, 0xcf, 0x79, 0xff, 0x2a, 0x05, 0x23, 0x77, 0x86, 0xf7, 0x27, 0xad, 0x20, 0x54, 0x62, 0x84, 0x00, 0x9c, 0xdf, 0xb2, 0x1f}, {0x8f, 0xd2, 0x3c, 0x63, 0x1c, 0x50, 0x26, 0xd7, 0x7e, 0x1d, 0xc7, 0x87, 0xbd, 0xe9, 0x75, 0xee, 0xdc, 0xa3, 0x7a, 0x3d, 0xd1, 0xff, 0xa0, 0xe5, 0xed, 0x9a, 0xab, 0x8a, 0x18, 0x2a, 0x01, 0x35}}, + {{0x38, 0xa0, 0x25, 0x17, 0xb7, 0x3b, 0xe3, 0xa5, 0xec, 0xca, 0x26, 0xd1, 0xfa, 0x44, 0x6f, 0x1a, 0x11, 0x3c, 0x6b, 0x8b, 0x7b, 0x0c, 0x82, 0xc6, 0x92, 0x4f, 0x4b, 0xf2, 0x87, 0x1a, 0x69, 0x1e}, {0x42, 0xce, 0x8d, 0xcd, 0x4f, 0xcf, 0x4b, 0xef, 0x8a, 0x0c, 0x17, 0x5a, 0xf9, 0x61, 0xd4, 0x9e, 0x33, 0x7b, 0x3e, 0xcc, 0x1a, 0x45, 0x5b, 0x88, 0xb4, 0x95, 0xb0, 0xff, 0xc9, 0x4d, 0xe0, 0x17}}, + {{0x32, 0xe0, 0xf0, 0x1a, 0xde, 0xa4, 0x34, 0xe1, 0x29, 0xaa, 0x65, 0xfd, 0xca, 0xab, 0x55, 0x60, 0xf6, 0x29, 0x63, 0x75, 0x0f, 0xbd, 0x09, 0x81, 0xa6, 0x9b, 0xcd, 0x6f, 0x0c, 0x2e, 0x92, 0x3d}, {0xed, 0x49, 0x01, 0xc9, 0xff, 0xb5, 0x1d, 0xa5, 0xda, 0x44, 0x3a, 0xbe, 0x3c, 0x22, 0x86, 0x88, 0xf1, 0x63, 0xc7, 0x8b, 0x83, 0x0d, 0xf3, 0x9c, 0x9a, 0xd0, 0x76, 0x55, 0x61, 0xdc, 0xd6, 0x23}}, + {{0x0c, 0x99, 0x2a, 0x2b, 0x6e, 0x83, 0xe2, 0x79, 0xb9, 0x7e, 0x4f, 0x43, 0x03, 0x0f, 0x2d, 0x98, 0xab, 0xd5, 0x6c, 0xe7, 0x7f, 0xb4, 0xd2, 0x8b, 0x02, 0x90, 0xce, 0x02, 0xd5, 0xa3, 0x60, 0x15}, {0x38, 0xf5, 0xf6, 0x79, 0x1d, 0x70, 0xca, 0x38, 0xa7, 0x5c, 0x5a, 0x26, 0xa2, 0x15, 0x6a, 0x0e, 0xdb, 0x3c, 0x8a, 0xce, 0xbd, 0xbb, 0x41, 0x69, 0xc2, 0x71, 0x5d, 0x72, 0xbd, 0xbc, 0xed, 0x22}}, + {{0xcc, 0x17, 0x2b, 0x9b, 0xb4, 0x42, 0x62, 0xeb, 0x08, 0xb7, 0xb3, 0xcf, 0xbf, 0xc0, 0x45, 0xdc, 0x3e, 0x3f, 0x1a, 0xfd, 0xab, 0x71, 0xe9, 0x1a, 0xd5, 0xf9, 0x16, 0x61, 0x6a, 0x92, 0x50, 0x38}, {0x3a, 0x1a, 0xd5, 0x99, 0xf9, 0x22, 0x46, 0xdb, 0xf3, 0x1e, 0x98, 0x73, 0x18, 0x26, 0xcd, 0xdd, 0x94, 0x38, 0xd1, 0xb3, 0x08, 0x85, 0xb5, 0x3b, 0x67, 0x6a, 0xee, 0xa7, 0xe8, 0x6e, 0x01, 0x20}}, + {{0x20, 0xa6, 0x4d, 0xba, 0xbf, 0xfd, 0xe7, 0x40, 0xce, 0xf9, 0xe3, 0x22, 0x30, 0xb9, 0x56, 0xf0, 0x25, 0x73, 0x34, 0xe7, 0x49, 0xee, 0xb8, 0x02, 0xe3, 0x8d, 0xbc, 0xe1, 0x61, 0xf5, 0x6f, 0x1d}, {0x9d, 0x36, 0x89, 0x81, 0x7a, 0x02, 0x4e, 0xb8, 0x1d, 0x03, 0x66, 0x07, 0xda, 0x75, 0xf2, 0x22, 0xec, 0xf2, 0x70, 0xc1, 0x87, 0x16, 0xe5, 0x4f, 0xd1, 0x17, 0xe1, 0x39, 0x69, 0xc0, 0x2a, 0x3b}}, + {{0x0c, 0xb2, 0xef, 0x79, 0xeb, 0x1e, 0x07, 0x62, 0x1a, 0x6b, 0x6f, 0x9c, 0x01, 0x01, 0x39, 0x0e, 0x3d, 0x08, 0x63, 0x08, 0xd4, 0xb2, 0x9a, 0xad, 0x0c, 0x43, 0x8e, 0xd9, 0xa6, 0x0d, 0xbb, 0x24}, {0x84, 0x27, 0x28, 0x53, 0x52, 0x75, 0x8e, 0xdc, 0x23, 0x5e, 0x9a, 0x38, 0x6b, 0xd3, 0xf0, 0x97, 0xb4, 0x9b, 0xdf, 0x4d, 0xec, 0x27, 0x59, 0xdf, 0x40, 0x4d, 0x27, 0xf8, 0x78, 0x0b, 0x5f, 0x20}}, + {{0xce, 0x43, 0x0d, 0x68, 0xf6, 0x96, 0xcd, 0x01, 0xef, 0x56, 0x89, 0xb5, 0x81, 0xe9, 0xd1, 0xea, 0xb6, 0x59, 0xd3, 0x61, 0x8f, 0x19, 0x6c, 0x7c, 0xab, 0xca, 0x8e, 0xa2, 0x2c, 0x65, 0x8e, 0x2f}, {0xf0, 0x0f, 0x4a, 0xf3, 0xc8, 0xe5, 0x93, 0xf8, 0x27, 0x0e, 0x20, 0x45, 0x32, 0xcb, 0x0a, 0xc7, 0xc6, 0x6d, 0x29, 0xae, 0xea, 0x36, 0xc6, 0xf8, 0x89, 0x44, 0x67, 0x1d, 0xc1, 0x82, 0x28, 0x23}}, + {{0x7f, 0x2a, 0xbe, 0x68, 0x48, 0x2c, 0x8e, 0xd4, 0x85, 0x37, 0x7c, 0xe9, 0x24, 0x31, 0x76, 0xfd, 0x76, 0x5a, 0x62, 0x28, 0xa0, 0x17, 0x94, 0x24, 0xb6, 0x6b, 0x14, 0x58, 0x39, 0x8e, 0xdb, 0x1a}, {0x71, 0x22, 0xd8, 0x33, 0x33, 0xa9, 0xb2, 0xc5, 0xeb, 0xcc, 0x8d, 0x03, 0x1f, 0x10, 0x34, 0xc2, 0xab, 0xef, 0x60, 0x9f, 0x90, 0xb6, 0xf3, 0x14, 0x71, 0xa7, 0x05, 0xba, 0x97, 0xde, 0xba, 0x27}}, + {{0x41, 0x53, 0x54, 0xa4, 0x14, 0xa8, 0x81, 0x37, 0x87, 0xdb, 0xb0, 0x8d, 0x11, 0x4f, 0x39, 0xa8, 0xe2, 0x04, 0x08, 0x44, 0x40, 0x93, 0x89, 0x5f, 0x18, 0x50, 0x81, 0xa5, 0xf2, 0x7a, 0xc2, 0x32}, {0x21, 0x45, 0xd8, 0x53, 0x0a, 0x47, 0x72, 0x50, 0x19, 0x4d, 0x78, 0xf8, 0x26, 0xf4, 0xca, 0xf3, 0x14, 0xa3, 0x03, 0x0d, 0x07, 0xfc, 0xc7, 0x59, 0x15, 0x2a, 0x2a, 0xd8, 0x81, 0x47, 0xc9, 0x05}}, + {{0x5c, 0x0e, 0x21, 0x70, 0x05, 0x82, 0xd1, 0x80, 0xfd, 0xc3, 0x05, 0xbb, 0x74, 0x9d, 0xc1, 0xc3, 0x32, 0xdc, 0x5d, 0x79, 0x72, 0x09, 0xd7, 0xb4, 0xf2, 0x1f, 0xb0, 0x90, 0x58, 0xd8, 0x03, 0x17}, {0x1c, 0x8f, 0x5b, 0xd9, 0x30, 0xba, 0xa1, 0x48, 0x06, 0x23, 0x1d, 0xcf, 0x72, 0x0c, 0xf0, 0xd8, 0x52, 0x9a, 0x28, 0x31, 0x4c, 0xce, 0xac, 0x13, 0x12, 0xdf, 0x46, 0xf0, 0x4b, 0x5f, 0x18, 0x3e}}, + {{0xce, 0x5a, 0xbe, 0x15, 0xdf, 0x75, 0xe5, 0x6f, 0x25, 0x0b, 0x46, 0x77, 0x80, 0xad, 0x1f, 0x2c, 0x80, 0xe5, 0xff, 0x95, 0x91, 0x8d, 0xb9, 0x1f, 0x74, 0x03, 0xf6, 0x25, 0x6b, 0xf8, 0xd2, 0x25}, {0x4d, 0xa0, 0xaa, 0xad, 0x9b, 0xdd, 0x6d, 0xe5, 0x0c, 0x3d, 0x3d, 0x10, 0x52, 0x54, 0x3a, 0x44, 0x0f, 0xc3, 0x01, 0x2b, 0x54, 0xe3, 0x8f, 0x26, 0xec, 0xb6, 0x36, 0xc0, 0xaf, 0xd0, 0x0a, 0x36}}, + {{0x23, 0xdf, 0x58, 0x73, 0x19, 0x32, 0xbe, 0xd5, 0x4d, 0x9b, 0xc0, 0x65, 0x6c, 0x6c, 0xcd, 0x36, 0x12, 0xf2, 0x3a, 0x7d, 0x9d, 0xca, 0x86, 0x28, 0x3f, 0xf8, 0x7f, 0x2c, 0x00, 0xc1, 0xd0, 0x0a}, {0x30, 0xea, 0x68, 0xc2, 0x80, 0x36, 0x5c, 0x96, 0xbd, 0x7a, 0x8f, 0xc7, 0x88, 0x1c, 0xc2, 0x90, 0x81, 0xb4, 0x2e, 0xd3, 0xfd, 0x7d, 0xbd, 0xad, 0xc8, 0x9c, 0x7e, 0xfe, 0x87, 0x3f, 0x32, 0x3e}}, + {{0xc9, 0x65, 0xbc, 0xbc, 0xf7, 0xc4, 0x27, 0xa9, 0x95, 0xda, 0x6c, 0x35, 0xb4, 0x54, 0x6b, 0xb1, 0x6a, 0x94, 0xa1, 0xc0, 0xce, 0x21, 0x7d, 0x46, 0xf3, 0xfc, 0xa8, 0x8b, 0x7a, 0x7a, 0x94, 0x3a}, {0x2b, 0x80, 0x6b, 0x2e, 0x2f, 0xc8, 0xd5, 0x6a, 0x8c, 0xda, 0xfa, 0x9a, 0x22, 0x5b, 0x34, 0x21, 0xd5, 0xa1, 0x9c, 0xfa, 0xbb, 0x90, 0x8f, 0xfc, 0xfb, 0x1c, 0xf4, 0x3e, 0x23, 0x5d, 0x60, 0x17}}, + {{0xff, 0xb6, 0xf8, 0x84, 0x36, 0x47, 0x5b, 0x74, 0x26, 0xf2, 0x28, 0x7d, 0xe6, 0x72, 0xa7, 0x2f, 0x12, 0x3d, 0x58, 0x0a, 0x1c, 0x28, 0x5c, 0x7f, 0x3a, 0x2e, 0x06, 0x39, 0x74, 0xb9, 0x01, 0x21}, {0x62, 0x3a, 0x4e, 0xcf, 0x09, 0x11, 0x16, 0xe6, 0x42, 0x18, 0x9d, 0x11, 0xad, 0xba, 0x0e, 0x25, 0x49, 0x0f, 0xbc, 0x24, 0x6a, 0x35, 0xd4, 0xfb, 0xe4, 0xfb, 0xa6, 0x7d, 0xa7, 0x86, 0x7f, 0x19}}, + {{0x22, 0xa0, 0xb4, 0x65, 0xf0, 0xcc, 0x78, 0x50, 0xc1, 0xce, 0x0c, 0x76, 0x79, 0xf6, 0xdd, 0xca, 0xf2, 0xa0, 0x50, 0x95, 0x31, 0x19, 0xf9, 0x57, 0x81, 0x4b, 0x2f, 0x20, 0x51, 0x03, 0x99, 0x19}, {0x32, 0x9f, 0x7d, 0xd5, 0x93, 0x10, 0x4c, 0xba, 0x0f, 0xe9, 0x0f, 0x0a, 0x45, 0xf1, 0x0a, 0xa8, 0xf7, 0x6a, 0x13, 0x73, 0x28, 0x43, 0x0a, 0x64, 0x38, 0xc1, 0xeb, 0xd2, 0x5f, 0x46, 0x65, 0x19}}, + {{0xfc, 0x6f, 0x6d, 0xd8, 0xdf, 0x75, 0x75, 0x4d, 0xb5, 0xba, 0x99, 0x14, 0xc0, 0x72, 0x7b, 0x8c, 0xf6, 0x40, 0x86, 0x43, 0xe9, 0x9f, 0x54, 0x83, 0xc7, 0x92, 0x7d, 0x6d, 0x23, 0x17, 0xa5, 0x01}, {0x66, 0x9d, 0x2d, 0x15, 0xdf, 0x9a, 0x0e, 0x85, 0x6e, 0x36, 0xee, 0x43, 0x56, 0xf2, 0x7b, 0xb8, 0x9c, 0xf2, 0x6d, 0x08, 0xaf, 0x1c, 0xdd, 0x39, 0xfa, 0x5c, 0x18, 0x0c, 0xfa, 0xcb, 0x2e, 0x2b}}, + {{0x5e, 0xfb, 0x0c, 0x2c, 0xc3, 0xd2, 0xf4, 0x2f, 0x48, 0x2e, 0x78, 0x1e, 0xfb, 0x20, 0x66, 0x5b, 0x39, 0xa1, 0xa6, 0xa6, 0x8f, 0x04, 0x4e, 0x16, 0x89, 0xd2, 0x17, 0x74, 0x98, 0xde, 0x77, 0x11}, {0xf8, 0x96, 0x63, 0x8b, 0x3c, 0xf6, 0x73, 0x44, 0x68, 0x76, 0x7c, 0xe4, 0x18, 0x70, 0x13, 0x88, 0xd6, 0x58, 0x65, 0x93, 0x8a, 0x65, 0x54, 0x6e, 0x16, 0x4d, 0x24, 0xc1, 0x2e, 0xf3, 0x65, 0x15}}, + {{0xca, 0x54, 0x64, 0xad, 0x46, 0xb0, 0xf8, 0xd3, 0xfb, 0x59, 0x74, 0xf0, 0x28, 0x8e, 0x83, 0x07, 0x35, 0x10, 0x20, 0x39, 0x07, 0x6e, 0x26, 0x2c, 0xb4, 0x58, 0x1e, 0x96, 0x43, 0xae, 0xde, 0x1a}, {0x85, 0x08, 0xcc, 0x97, 0x25, 0x92, 0xac, 0xcb, 0x41, 0xbb, 0xb8, 0xec, 0xf2, 0x41, 0x97, 0x02, 0xfe, 0x0f, 0xa8, 0xbc, 0x81, 0x88, 0xf7, 0x52, 0x97, 0x39, 0xea, 0xd9, 0xd7, 0x3b, 0x26, 0x26}}, + {{0xee, 0x15, 0xba, 0x10, 0x1c, 0xb0, 0x9b, 0x23, 0xd9, 0x21, 0x83, 0xe8, 0x2f, 0x2e, 0xde, 0xe0, 0x58, 0x84, 0xb2, 0x0d, 0x3d, 0xa0, 0x9e, 0x24, 0xea, 0xa8, 0x64, 0xc3, 0x10, 0x10, 0xa1, 0x02}, {0x55, 0xbf, 0xd3, 0x80, 0xbd, 0x66, 0x63, 0xbd, 0xd0, 0x70, 0x85, 0xdf, 0x0e, 0x3e, 0x68, 0xb9, 0x6b, 0xe3, 0xed, 0x04, 0x2f, 0x64, 0x0a, 0xf0, 0x04, 0xa5, 0x0b, 0xb3, 0x22, 0xd6, 0xff, 0x37}}, + {{0xbe, 0x79, 0xf5, 0xd2, 0xa7, 0x07, 0x1a, 0xc3, 0x3b, 0x73, 0x86, 0xdd, 0x16, 0x4a, 0xe0, 0x93, 0x07, 0xac, 0x6f, 0x38, 0xd1, 0x12, 0xc9, 0xbe, 0x39, 0xe7, 0x6c, 0xb7, 0xd9, 0x25, 0x91, 0x19}, {0x31, 0xa7, 0x17, 0x0d, 0x8c, 0x9a, 0x6a, 0x97, 0x56, 0x72, 0x20, 0x44, 0xc4, 0xc9, 0x6f, 0xaf, 0x8d, 0xbf, 0x7e, 0x95, 0xf8, 0x0e, 0x5b, 0x7e, 0x32, 0x95, 0x12, 0x75, 0x1a, 0x40, 0xfe, 0x1a}}, + {{0xfa, 0xb0, 0x13, 0x66, 0x65, 0xfa, 0xe4, 0x3b, 0xe4, 0x94, 0x26, 0x2e, 0x61, 0xbe, 0x1f, 0x3a, 0x57, 0xdd, 0x5e, 0x3b, 0xfc, 0xa6, 0x91, 0x00, 0xd4, 0xea, 0x6b, 0xcf, 0xda, 0x5d, 0xfd, 0x39}, {0x8d, 0x93, 0x2d, 0xa0, 0x10, 0x8e, 0x1e, 0xf6, 0x24, 0x5c, 0xb1, 0xe1, 0xfb, 0x5a, 0x3d, 0x30, 0x15, 0x94, 0xc5, 0xf1, 0x83, 0xc2, 0x3b, 0x4f, 0x68, 0x6d, 0xee, 0x25, 0x6b, 0x63, 0xea, 0x19}}, + {{0x79, 0xc3, 0x08, 0x11, 0xff, 0xd6, 0x71, 0x2f, 0x16, 0x24, 0xf8, 0xc8, 0x9b, 0x64, 0x38, 0x33, 0x00, 0x10, 0x70, 0x09, 0xba, 0x7f, 0xcb, 0x29, 0x1c, 0xc7, 0xbb, 0xde, 0x8d, 0xbe, 0x06, 0x32}, {0xc0, 0x3d, 0xff, 0x97, 0x0c, 0x99, 0x97, 0x47, 0xbc, 0x97, 0x1b, 0xbc, 0x3c, 0x24, 0xf3, 0xb0, 0x59, 0x8a, 0xf3, 0x4c, 0xaf, 0x28, 0x17, 0x80, 0x96, 0x11, 0xdf, 0x53, 0x32, 0xeb, 0x56, 0x3f}}, + {{0x1f, 0x2e, 0x09, 0x6e, 0x74, 0x34, 0x66, 0x5b, 0x82, 0x0a, 0xef, 0xf9, 0xf5, 0x87, 0xe2, 0xc2, 0xca, 0x66, 0x0c, 0x21, 0xdd, 0x95, 0x42, 0x24, 0xae, 0x95, 0x4c, 0xbc, 0x2d, 0xea, 0x88, 0x1d}, {0x56, 0x33, 0x61, 0xf8, 0xb8, 0x8e, 0x9d, 0xe1, 0x71, 0xe9, 0x10, 0x7f, 0xd6, 0x10, 0x53, 0x4b, 0xbf, 0x00, 0x61, 0x28, 0x4e, 0x39, 0xe6, 0x1a, 0xe3, 0x35, 0xa3, 0x3e, 0x8e, 0x98, 0xc9, 0x0b}}, + {{0xde, 0xf2, 0x0e, 0xc2, 0xb7, 0xad, 0xbe, 0xc3, 0x08, 0x97, 0x32, 0x5b, 0x5c, 0xeb, 0xca, 0xe8, 0x1b, 0x63, 0x1d, 0xa9, 0xf5, 0xc8, 0x0b, 0x7c, 0x7f, 0xa8, 0x96, 0xbb, 0x0d, 0x7b, 0x7d, 0x35}, {0x85, 0xed, 0xf6, 0xe6, 0x6d, 0x6f, 0x73, 0xad, 0x09, 0x63, 0x1e, 0x07, 0xea, 0x6f, 0x76, 0xa1, 0x00, 0x44, 0x6e, 0x54, 0x19, 0x11, 0xff, 0x73, 0xb9, 0x6e, 0x32, 0x17, 0xa3, 0xa0, 0xb5, 0x37}}, + {{0x7b, 0x45, 0x81, 0xec, 0xb6, 0xd7, 0xfb, 0x71, 0xf8, 0xe2, 0xbd, 0x8e, 0x0b, 0x88, 0xdb, 0xa3, 0x82, 0x72, 0xf7, 0x77, 0x5e, 0x9d, 0xae, 0x6f, 0xd8, 0xf4, 0xe5, 0xaa, 0xfe, 0x33, 0x22, 0x39}, {0x80, 0x6d, 0x6f, 0x73, 0x8c, 0x93, 0xdb, 0x10, 0x31, 0x97, 0xd1, 0x56, 0x23, 0xe7, 0x3d, 0x34, 0x68, 0xa4, 0x5d, 0x9d, 0x7a, 0xc3, 0xb3, 0x78, 0x2b, 0x0a, 0x60, 0x91, 0x0e, 0x30, 0x17, 0x16}}, + {{0xa3, 0x1a, 0xac, 0x5b, 0x77, 0x88, 0x4a, 0x42, 0xe5, 0xc0, 0x8c, 0x7e, 0xe8, 0x36, 0xc8, 0xa8, 0x64, 0x92, 0xfe, 0x03, 0x74, 0x23, 0x71, 0xc3, 0x0e, 0xa3, 0x66, 0x7a, 0x8a, 0xc9, 0xf1, 0x26}, {0xd9, 0x44, 0xb2, 0x0d, 0x6e, 0xb3, 0xa3, 0x51, 0x35, 0xe0, 0x7d, 0x88, 0x88, 0x1d, 0xea, 0x3e, 0xda, 0xf3, 0x1f, 0xd5, 0x02, 0xa9, 0xcb, 0x25, 0x68, 0x64, 0x48, 0x45, 0x90, 0x0b, 0xe7, 0x36}}, + {{0xc1, 0xd1, 0x61, 0x0b, 0xb5, 0xfd, 0x28, 0x27, 0x21, 0x15, 0xd1, 0x6e, 0x70, 0xa0, 0x71, 0xcb, 0x6f, 0xab, 0x07, 0x1d, 0xbe, 0x29, 0x09, 0x05, 0x4c, 0xc8, 0x7e, 0x2b, 0x62, 0x7b, 0xd2, 0x21}, {0x80, 0xcf, 0xe0, 0x7e, 0xfe, 0x1c, 0x3a, 0xe1, 0x16, 0x64, 0xe1, 0xa8, 0x36, 0x8c, 0x30, 0xae, 0x84, 0x6d, 0xe0, 0x9c, 0x9e, 0xfb, 0x99, 0xed, 0x42, 0x18, 0x03, 0x98, 0xb8, 0xca, 0xa7, 0x34}}, + {{0x8f, 0xc2, 0xeb, 0x3a, 0xef, 0x35, 0xbb, 0xfd, 0x87, 0x0e, 0x44, 0x1e, 0x06, 0x28, 0x4b, 0x83, 0x0d, 0x15, 0x07, 0x66, 0xe3, 0x25, 0x65, 0xbd, 0x87, 0xd9, 0x6a, 0x88, 0x98, 0x3d, 0x3c, 0x18}, {0xa9, 0x5b, 0x3d, 0xbf, 0x6e, 0xe0, 0xb2, 0xef, 0x57, 0xb9, 0x1a, 0x37, 0x83, 0xe7, 0x2e, 0x8d, 0xf8, 0x07, 0xc7, 0xb0, 0xbd, 0x80, 0x32, 0xca, 0xf0, 0x68, 0xf5, 0x08, 0x88, 0x6b, 0xe1, 0x1d}}, + {{0x5b, 0xec, 0x4e, 0x92, 0xc0, 0xbd, 0x6d, 0x78, 0x47, 0x41, 0x9c, 0x18, 0x1c, 0x6c, 0x10, 0xe2, 0xd5, 0x0a, 0x17, 0xbb, 0xab, 0xa8, 0x4b, 0x7a, 0xc8, 0x5e, 0x6a, 0x17, 0xca, 0x5c, 0xd2, 0x27}, {0xe3, 0x38, 0x1a, 0x6a, 0x9c, 0x54, 0xcc, 0xbc, 0xc1, 0xf8, 0xd5, 0xbc, 0x83, 0xd3, 0xe7, 0xff, 0x70, 0xc8, 0x4b, 0xf2, 0x33, 0x06, 0x45, 0x1e, 0xc1, 0x21, 0x95, 0xab, 0x09, 0x07, 0x6e, 0x34}}, + {{0x3e, 0x5a, 0xca, 0x3c, 0x4f, 0xf4, 0x73, 0x5e, 0x35, 0x7e, 0x6c, 0xdd, 0xa3, 0xc7, 0x65, 0xa9, 0xdc, 0x89, 0x49, 0x11, 0xe4, 0xee, 0xc6, 0x3e, 0x07, 0x6b, 0xbe, 0xd4, 0xea, 0xdf, 0x83, 0x10}, {0x9c, 0xcf, 0xdb, 0x9d, 0x25, 0x4b, 0x4d, 0x29, 0xc6, 0x61, 0x45, 0x80, 0x4e, 0x97, 0xce, 0x7a, 0xcd, 0xc0, 0x68, 0x4d, 0x3f, 0x84, 0x7e, 0x50, 0x25, 0xe9, 0xc0, 0xfe, 0x78, 0x8f, 0x2d, 0x0a}}, + {{0x05, 0xb2, 0x6d, 0x2d, 0x8b, 0xc7, 0x5e, 0xf0, 0xc5, 0x3f, 0xa6, 0x8d, 0x3b, 0xd9, 0xed, 0x74, 0xb5, 0xe1, 0x62, 0xc9, 0x3d, 0xee, 0x14, 0x2d, 0xe2, 0x75, 0x06, 0xa2, 0x79, 0xe7, 0x96, 0x3d}, {0xdf, 0x53, 0x42, 0x24, 0xfc, 0x20, 0xb0, 0x74, 0xe5, 0xc1, 0x84, 0x8a, 0x1c, 0x73, 0x67, 0x5e, 0xca, 0x9c, 0x83, 0xee, 0x2f, 0x57, 0xb9, 0x76, 0x3d, 0x79, 0x84, 0xe5, 0xc7, 0x4f, 0xec, 0x20}}, + {{0x6c, 0x9c, 0x2f, 0xbf, 0x50, 0x3a, 0x8d, 0x61, 0xc9, 0x53, 0x9d, 0xd0, 0xad, 0x12, 0x9e, 0x2c, 0x9c, 0xa7, 0x71, 0x99, 0x2a, 0xe1, 0x0e, 0xc4, 0xf2, 0x4a, 0xdb, 0x8c, 0x49, 0x5e, 0x93, 0x21}, {0x71, 0x0d, 0x47, 0x48, 0x71, 0xa4, 0x6d, 0x52, 0xfd, 0x44, 0x06, 0x7e, 0xa6, 0xad, 0xb6, 0x91, 0xb0, 0x8e, 0xf1, 0xf6, 0xc8, 0x0f, 0xd3, 0x0e, 0x03, 0xd5, 0xce, 0xa7, 0xd2, 0xa9, 0x39, 0x33}}, + {{0xd2, 0xc4, 0xe2, 0xeb, 0xa9, 0x6b, 0x83, 0x50, 0x9f, 0xb8, 0x4e, 0xcf, 0x48, 0x6e, 0x97, 0x1a, 0xad, 0x17, 0x6c, 0xd7, 0x36, 0x39, 0x04, 0x87, 0x51, 0x17, 0xb4, 0x94, 0x13, 0x22, 0xaf, 0x29}, {0xc3, 0x50, 0x09, 0x7f, 0x10, 0xcd, 0x44, 0xf6, 0xbc, 0x94, 0xea, 0x01, 0xc3, 0x71, 0x84, 0x88, 0x58, 0x52, 0xe6, 0x3b, 0xcf, 0xb2, 0x37, 0x89, 0xcb, 0x98, 0x02, 0xe2, 0xf5, 0x20, 0x47, 0x26}}, + {{0xdd, 0x6b, 0x5a, 0x4e, 0x72, 0x29, 0xc7, 0x95, 0x0b, 0x75, 0x1e, 0x2f, 0x97, 0xa6, 0x55, 0xcc, 0x75, 0xc3, 0x13, 0xf9, 0xc3, 0x90, 0xb7, 0xb9, 0x6c, 0x12, 0xd6, 0xbc, 0x2a, 0x0c, 0xdf, 0x1d}, {0xc2, 0x68, 0x1f, 0xe5, 0xe7, 0x7f, 0x61, 0xb2, 0xd1, 0x8c, 0xe2, 0x27, 0x00, 0xf7, 0x6a, 0xaf, 0x77, 0x2e, 0x2c, 0x4a, 0xb5, 0x5b, 0xe8, 0x22, 0x31, 0x1c, 0xbe, 0x6a, 0xfe, 0x6c, 0xaf, 0x04}}, + {{0xf3, 0xe2, 0x5f, 0xc0, 0x4e, 0x8c, 0xa6, 0x8e, 0xef, 0x31, 0x7b, 0xba, 0xad, 0xd4, 0x55, 0x01, 0xd9, 0xea, 0x84, 0x1d, 0xdf, 0x74, 0xea, 0xa5, 0x97, 0xe8, 0x38, 0x0a, 0x90, 0x08, 0x23, 0x25}, {0x51, 0x21, 0x63, 0x11, 0x3e, 0x88, 0x4a, 0xa6, 0xff, 0xf8, 0x77, 0x24, 0x43, 0xd7, 0x07, 0xd1, 0xfc, 0x36, 0x58, 0x71, 0xf8, 0x49, 0xaf, 0x0d, 0x35, 0x64, 0x7a, 0x68, 0x63, 0x0b, 0x81, 0x3e}}, + {{0x27, 0x13, 0x83, 0x9d, 0xd3, 0xf1, 0xe8, 0xb8, 0x16, 0xfb, 0x23, 0x2f, 0x9a, 0x12, 0xfd, 0xee, 0x58, 0x4b, 0x7c, 0x41, 0xe9, 0x95, 0xe7, 0x5c, 0x70, 0xa1, 0x75, 0x8c, 0x8c, 0x50, 0x79, 0x35}, {0x71, 0x5e, 0xb2, 0xe4, 0x4c, 0x57, 0xb9, 0xe1, 0x15, 0xb5, 0x7e, 0xe8, 0x4d, 0xb4, 0x7c, 0xa3, 0xb8, 0x8a, 0x55, 0x9d, 0xb9, 0x24, 0x92, 0xf4, 0x23, 0xf6, 0x5b, 0x9e, 0x7f, 0x99, 0xc4, 0x09}}, + {{0x07, 0xf9, 0xee, 0x13, 0x05, 0x39, 0x10, 0x50, 0x99, 0xa8, 0x9a, 0xd3, 0xaa, 0x6a, 0x19, 0x47, 0x02, 0x1a, 0x09, 0xe7, 0x1b, 0x85, 0xde, 0x54, 0x0e, 0xe7, 0x57, 0x49, 0x97, 0xa2, 0x84, 0x27}, {0xab, 0xdf, 0x85, 0x98, 0xef, 0xca, 0xee, 0x24, 0x78, 0xf6, 0x27, 0x5f, 0x09, 0x30, 0x89, 0xd1, 0x1f, 0x09, 0xd9, 0x15, 0xf4, 0x6a, 0xd3, 0x1f, 0x44, 0x8e, 0x37, 0xb4, 0x81, 0xec, 0x4b, 0x08}}, + {{0x13, 0x4f, 0x93, 0xe4, 0xb4, 0x74, 0x9f, 0xb1, 0x3c, 0xe2, 0x84, 0xf0, 0x1b, 0xe8, 0xa0, 0xe3, 0x1b, 0x23, 0xa3, 0xae, 0x1f, 0xef, 0xb2, 0xaf, 0xee, 0x87, 0xc0, 0xac, 0x46, 0xe8, 0x81, 0x02}, {0x2f, 0x54, 0x93, 0x73, 0x0f, 0xd0, 0x75, 0xd9, 0xd0, 0x59, 0x9e, 0xec, 0x1e, 0xf9, 0xae, 0xf8, 0x0c, 0x28, 0xc5, 0xb9, 0x11, 0x8c, 0x85, 0xd2, 0x83, 0xf8, 0xdd, 0x5a, 0x52, 0x5d, 0x00, 0x3b}}, + {{0xec, 0xf3, 0x21, 0xe2, 0xea, 0x98, 0x66, 0x7b, 0x9d, 0xef, 0xe3, 0x81, 0x99, 0x8c, 0x52, 0xaa, 0x22, 0xaf, 0x14, 0xbb, 0x1a, 0x5e, 0x94, 0x85, 0xe0, 0x01, 0x42, 0xd6, 0x76, 0x56, 0x5a, 0x00}, {0x1b, 0x02, 0x31, 0x0a, 0xaa, 0x21, 0x03, 0xf4, 0xce, 0x01, 0xe9, 0x43, 0x72, 0x41, 0x9d, 0x4b, 0xe4, 0x6f, 0xfd, 0xff, 0xa1, 0x30, 0xef, 0xdc, 0x6b, 0x5c, 0xe7, 0x17, 0x90, 0x5d, 0x5c, 0x11}}, + {{0x5f, 0x73, 0xee, 0x29, 0x1a, 0xa3, 0x0b, 0xb5, 0x05, 0x9f, 0xbe, 0x55, 0x44, 0x42, 0x87, 0xe0, 0x41, 0xbb, 0x34, 0x7f, 0x56, 0x53, 0x3d, 0x4b, 0xd5, 0x8f, 0x73, 0xef, 0xa2, 0xdf, 0x92, 0x35}, {0x7f, 0xac, 0xaa, 0x5e, 0xb4, 0xa2, 0xea, 0x5e, 0x51, 0xda, 0xf4, 0x5d, 0x58, 0xa1, 0x64, 0xba, 0x8b, 0xa1, 0xa1, 0xe2, 0x18, 0x1e, 0xf2, 0x64, 0xf4, 0xf4, 0xb3, 0x60, 0x2c, 0x47, 0x44, 0x27}}, + {{0x76, 0xd0, 0x3a, 0x5a, 0x4c, 0x7d, 0xb7, 0x1a, 0xa9, 0x55, 0x8f, 0x13, 0x2e, 0x34, 0xef, 0xec, 0x3b, 0xf9, 0xbd, 0x1c, 0xcf, 0xd4, 0x81, 0xe5, 0x5c, 0x3d, 0x7d, 0x9f, 0x59, 0xf3, 0xa1, 0x0e}, {0x5f, 0xc1, 0xe3, 0x9f, 0xa5, 0xae, 0x25, 0xfc, 0xe0, 0x64, 0x4f, 0xf4, 0x1a, 0xd7, 0xeb, 0xc8, 0xed, 0xa5, 0xb5, 0x38, 0x54, 0x2e, 0x6b, 0xaa, 0x20, 0xfb, 0x7e, 0x1f, 0x50, 0xd9, 0xd7, 0x1c}}, + {{0xf9, 0x7e, 0xf6, 0xd2, 0x75, 0xcc, 0x2c, 0xb9, 0x6c, 0xc7, 0x4b, 0xbb, 0x50, 0x70, 0x8c, 0x7c, 0x05, 0xb7, 0x7c, 0x3e, 0x71, 0xdd, 0x06, 0xae, 0x6f, 0x9a, 0x99, 0x0a, 0x6e, 0xb6, 0xe7, 0x12}, {0x90, 0x1a, 0xde, 0x46, 0x4c, 0x17, 0x73, 0xce, 0x24, 0x36, 0xe6, 0xdc, 0x5c, 0x8c, 0x33, 0xf2, 0xba, 0xca, 0x07, 0x61, 0xf1, 0xd0, 0x11, 0x73, 0xc1, 0x3b, 0x6e, 0x2f, 0xd8, 0x3c, 0xc5, 0x07}}, + {{0x0c, 0x88, 0x63, 0x06, 0xcb, 0x68, 0x9f, 0x67, 0x33, 0xc7, 0xf2, 0xb8, 0xb9, 0x3a, 0xeb, 0x22, 0xd5, 0x7a, 0x17, 0xee, 0xf2, 0xcb, 0x9a, 0x8c, 0x05, 0xc9, 0xb2, 0x96, 0xc2, 0x4c, 0x15, 0x02}, {0x4c, 0xde, 0x53, 0xbb, 0x98, 0x72, 0xf8, 0xf9, 0x90, 0x16, 0xc4, 0x1e, 0x20, 0x8c, 0x36, 0xdf, 0x0e, 0x2e, 0xab, 0xc5, 0x82, 0xd6, 0x64, 0x49, 0x69, 0xcd, 0xb7, 0x1f, 0x23, 0xfd, 0x40, 0x1c}}, + {{0x5d, 0xb7, 0x56, 0x89, 0xfc, 0x8b, 0x19, 0x21, 0x65, 0xb5, 0xa4, 0x35, 0x0b, 0x62, 0x1d, 0x99, 0x6d, 0xd8, 0x4e, 0x81, 0x45, 0xc4, 0xea, 0x71, 0x32, 0x3f, 0x39, 0x47, 0xb6, 0x9d, 0xc7, 0x28}, {0x13, 0xf1, 0x17, 0xae, 0x60, 0x20, 0xce, 0x14, 0x50, 0xfc, 0x46, 0x12, 0xc5, 0xfd, 0x45, 0xbe, 0x73, 0xbe, 0xac, 0x10, 0x19, 0x43, 0x1c, 0x8e, 0x2e, 0x91, 0x83, 0x17, 0xc6, 0x53, 0x12, 0x13}}, + {{0x37, 0xdd, 0x05, 0x10, 0x7e, 0x76, 0x6d, 0x02, 0x8a, 0x42, 0x64, 0x1a, 0xa2, 0x23, 0x59, 0x07, 0x0e, 0x6a, 0x9d, 0xb7, 0x07, 0x45, 0xae, 0xee, 0x6b, 0x25, 0x73, 0x81, 0x0d, 0x76, 0xd5, 0x37}, {0xc0, 0x56, 0x6f, 0x93, 0x9e, 0xd9, 0x14, 0x52, 0x58, 0x2f, 0x31, 0x67, 0x0e, 0xb5, 0xa0, 0x26, 0x38, 0xd2, 0xc1, 0x6e, 0x29, 0x70, 0xfa, 0x3d, 0x90, 0x1a, 0x28, 0x5f, 0xf2, 0x0d, 0x0c, 0x17}}, + {{0x68, 0xbd, 0x4d, 0xba, 0xcb, 0x3b, 0x7a, 0x39, 0xf5, 0x1a, 0xd1, 0x06, 0x16, 0x28, 0x77, 0xf5, 0x6e, 0x1e, 0x0c, 0x22, 0xb5, 0x30, 0x14, 0x08, 0xc9, 0x73, 0xe3, 0x45, 0xc4, 0xca, 0xee, 0x04}, {0xd1, 0x65, 0x4f, 0x1a, 0x9d, 0x61, 0xe6, 0x3d, 0x7a, 0x6b, 0x54, 0xeb, 0x2b, 0xa9, 0x0e, 0x68, 0xbf, 0x51, 0xfc, 0x19, 0xba, 0x31, 0xd4, 0x01, 0x30, 0x07, 0xa7, 0x13, 0xd1, 0x35, 0x0c, 0x07}}, + {{0x0b, 0xc5, 0x4b, 0xe3, 0xda, 0x43, 0x7a, 0x32, 0x17, 0x63, 0xef, 0xf9, 0x0c, 0xb8, 0x27, 0x92, 0xf5, 0x65, 0x7a, 0x72, 0x31, 0xc3, 0x7b, 0x20, 0x87, 0x04, 0x19, 0x95, 0x8e, 0x36, 0x5b, 0x2f}, {0xc1, 0x8b, 0x4b, 0x04, 0xc7, 0xf9, 0xda, 0x59, 0x84, 0x50, 0x78, 0x4c, 0x4a, 0x94, 0xb3, 0x1a, 0x30, 0xa1, 0x9f, 0xed, 0x13, 0x6a, 0x16, 0xb7, 0xb9, 0xe0, 0x00, 0xc3, 0xe0, 0x91, 0x65, 0x21}}, + {{0x5f, 0xb9, 0x1f, 0xf2, 0x88, 0x12, 0xa9, 0x5f, 0x44, 0x47, 0x7b, 0x83, 0xa8, 0x13, 0xd2, 0xbb, 0x8c, 0x5d, 0x38, 0x69, 0x70, 0x32, 0x4a, 0x0a, 0xc1, 0xc9, 0xc5, 0xd5, 0x93, 0xf1, 0xb9, 0x2d}, {0xff, 0x9b, 0x1a, 0x1a, 0x98, 0x98, 0xbd, 0x7b, 0x0e, 0x06, 0x54, 0xef, 0x15, 0x4d, 0xd2, 0x4a, 0x5e, 0x03, 0x5e, 0x91, 0xa3, 0xc7, 0x24, 0x88, 0x16, 0xe3, 0x52, 0x81, 0x3b, 0xa0, 0xea, 0x04}}, + {{0x0c, 0xd0, 0x11, 0xe2, 0x17, 0x51, 0x8e, 0x71, 0x61, 0x2c, 0x06, 0xe8, 0xa7, 0x04, 0x20, 0x68, 0x06, 0x88, 0xee, 0x02, 0x52, 0x12, 0x4d, 0xe1, 0xbe, 0xd8, 0xad, 0x17, 0xce, 0xbb, 0xd6, 0x35}, {0x3e, 0x85, 0x3e, 0x57, 0x95, 0x90, 0x50, 0x6d, 0x54, 0xff, 0x5d, 0xbd, 0x45, 0xbb, 0xe9, 0x9b, 0x0a, 0xe5, 0xb2, 0xc2, 0x15, 0xd6, 0x42, 0xd1, 0x1c, 0x83, 0x49, 0xb0, 0xdc, 0x45, 0x21, 0x0d}}, + {{0xfb, 0x54, 0x77, 0x35, 0xaa, 0x32, 0xe4, 0x8f, 0x8b, 0x89, 0xd3, 0x94, 0x13, 0x85, 0x66, 0x47, 0xc4, 0x75, 0x9d, 0xc8, 0xd0, 0x85, 0x6f, 0x77, 0x34, 0x81, 0xb0, 0x1e, 0x1e, 0x09, 0x44, 0x11}, {0x64, 0x93, 0xb4, 0xdc, 0x36, 0x90, 0x8f, 0x39, 0x3e, 0x1c, 0x46, 0xdd, 0x19, 0x1f, 0xa7, 0xaa, 0x9e, 0x65, 0x5d, 0x7b, 0xf3, 0x0b, 0x24, 0xda, 0x70, 0x38, 0xf2, 0x7b, 0x38, 0x82, 0x09, 0x1c}}, + {{0xfd, 0xd9, 0x5f, 0xe7, 0x93, 0xc9, 0x70, 0x65, 0xf9, 0x37, 0x87, 0xe1, 0xee, 0xd3, 0x95, 0x55, 0x58, 0x4b, 0xc7, 0xce, 0xa7, 0x32, 0x29, 0x06, 0xfa, 0xb4, 0x84, 0xbc, 0x6c, 0x81, 0x02, 0x02}, {0x74, 0xda, 0xb9, 0x5f, 0x9c, 0x9e, 0xf0, 0x1d, 0xee, 0x50, 0xf4, 0x42, 0x71, 0xf2, 0x47, 0xb8, 0xa6, 0xdc, 0x75, 0xda, 0x3b, 0x34, 0x99, 0xf4, 0x26, 0x67, 0x25, 0x74, 0x3b, 0x32, 0x81, 0x17}}, + {{0xd2, 0x51, 0x88, 0x7f, 0x37, 0x0d, 0xff, 0x5a, 0xb3, 0xbf, 0x7d, 0xe8, 0x59, 0x29, 0x53, 0x73, 0x96, 0x1c, 0xb7, 0xfb, 0x6c, 0x47, 0x4c, 0x63, 0x83, 0x76, 0xfd, 0xce, 0x18, 0x88, 0xdf, 0x11}, {0x3d, 0x54, 0x77, 0x45, 0xc4, 0xfa, 0xac, 0x35, 0xfc, 0x61, 0x58, 0x16, 0x44, 0xdb, 0x8f, 0x5c, 0x30, 0xfb, 0x3c, 0xcf, 0x39, 0x0f, 0x19, 0x4b, 0xb8, 0xd6, 0xa3, 0x42, 0x68, 0xc8, 0xdc, 0x27}}, + {{0x34, 0x63, 0xe1, 0xbc, 0xb5, 0x36, 0x6f, 0x70, 0x0d, 0x8f, 0x7e, 0xd6, 0x8e, 0xbc, 0x63, 0xed, 0x8b, 0x14, 0xa1, 0xd9, 0x11, 0x82, 0x89, 0x53, 0x9a, 0x9f, 0x1d, 0xed, 0x66, 0x1a, 0x4e, 0x08}, {0xe5, 0x6e, 0x83, 0x93, 0x24, 0xe9, 0xe0, 0xa9, 0x61, 0x08, 0x95, 0x8f, 0x64, 0xd6, 0xc4, 0x54, 0x06, 0x43, 0x23, 0x8d, 0xff, 0xbe, 0xde, 0xe2, 0x10, 0x2b, 0x48, 0x0b, 0x89, 0x19, 0x38, 0x20}}, + {{0xd7, 0x8a, 0x0c, 0x33, 0x1c, 0xf8, 0xfe, 0x3a, 0x46, 0x7f, 0xb7, 0x3c, 0x8b, 0xb3, 0x31, 0x8f, 0x37, 0xf2, 0xbc, 0xb4, 0xe3, 0xa9, 0xe8, 0x0b, 0x58, 0xae, 0x17, 0x79, 0x9b, 0x72, 0xce, 0x09}, {0xe0, 0x8d, 0x32, 0x47, 0x86, 0xef, 0x99, 0xd1, 0x44, 0x81, 0xf5, 0xa3, 0x44, 0x67, 0x03, 0x7b, 0x94, 0x79, 0x0a, 0x58, 0xef, 0xb8, 0x45, 0xa5, 0xab, 0x07, 0x69, 0x97, 0x11, 0x1c, 0x74, 0x10}}, + {{0xaf, 0xb9, 0xda, 0x86, 0x9a, 0xd6, 0x3d, 0xcc, 0x3e, 0x0b, 0x2b, 0xd5, 0x09, 0x5a, 0xe7, 0xd4, 0x75, 0x7f, 0x10, 0x8b, 0x1d, 0x09, 0xad, 0xe8, 0x1e, 0xf0, 0xd8, 0xf8, 0x2e, 0xcc, 0x43, 0x2b}, {0x63, 0x0f, 0x3d, 0xb0, 0x51, 0x0c, 0x14, 0xbd, 0x5d, 0x28, 0xcf, 0x4b, 0x3c, 0x92, 0x06, 0x10, 0x11, 0x79, 0x0c, 0x12, 0x99, 0x7a, 0x21, 0x72, 0x6f, 0x05, 0x53, 0x8f, 0x79, 0x2b, 0x2f, 0x01}}, + {{0x6c, 0x48, 0x13, 0xa3, 0x9f, 0x94, 0xeb, 0x0b, 0xf8, 0xab, 0x9d, 0x05, 0xd6, 0xe4, 0x5c, 0x0d, 0x16, 0x2b, 0xf5, 0x76, 0x41, 0x4b, 0x91, 0x49, 0x4c, 0xeb, 0xb5, 0x97, 0xc7, 0x5d, 0x14, 0x1a}, {0x02, 0xdc, 0xfb, 0xb5, 0x2b, 0xfb, 0x0a, 0x9b, 0x7e, 0xe6, 0x32, 0x8b, 0x01, 0xd0, 0x2e, 0xb7, 0xa1, 0x40, 0xf6, 0xe7, 0xac, 0xf4, 0xc1, 0x8d, 0xe8, 0x35, 0xc1, 0xe2, 0xe6, 0x99, 0x03, 0x0a}}, + {{0xd6, 0x3b, 0x85, 0x0a, 0xfc, 0x3c, 0xe5, 0x24, 0x8a, 0x53, 0x84, 0x52, 0x40, 0xa4, 0x91, 0xc6, 0x67, 0x3f, 0xca, 0xa2, 0x87, 0x85, 0x5f, 0x28, 0xac, 0xb1, 0x9a, 0x58, 0xba, 0x29, 0x49, 0x00}, {0xb5, 0x11, 0x9e, 0xb5, 0x51, 0x0f, 0xd0, 0x47, 0x18, 0xd0, 0x24, 0x4f, 0xc5, 0xe6, 0x4c, 0x03, 0x77, 0x22, 0x52, 0x93, 0xf5, 0xfd, 0xfa, 0xcd, 0x59, 0xe4, 0x80, 0xcd, 0xa4, 0x01, 0x40, 0x17}}, + {{0xcd, 0x64, 0xe4, 0x88, 0xa6, 0xfb, 0xf2, 0x05, 0x4e, 0xde, 0x93, 0x83, 0x11, 0x4f, 0x07, 0xcc, 0x16, 0xf6, 0x3a, 0x2d, 0xd1, 0x84, 0xd3, 0x8c, 0xdb, 0xc5, 0xbd, 0x65, 0x61, 0xc5, 0x2e, 0x08}, {0x38, 0x14, 0xf6, 0xcd, 0x63, 0xd4, 0xf4, 0x0f, 0x0b, 0x82, 0x97, 0x12, 0x13, 0x85, 0xd4, 0xb9, 0x6f, 0x7b, 0x11, 0x60, 0x49, 0xab, 0x7a, 0x57, 0x49, 0xde, 0x47, 0x6f, 0xa5, 0xca, 0x9f, 0x18}}, + {{0x05, 0x9c, 0x9d, 0x45, 0x34, 0xf2, 0x66, 0x6a, 0xa2, 0x0c, 0x6a, 0x04, 0xe7, 0xb4, 0xb3, 0x52, 0x73, 0x86, 0x0b, 0xac, 0xc7, 0xf5, 0x0c, 0x5f, 0x4d, 0x0f, 0xb7, 0x8a, 0x8b, 0x37, 0x4d, 0x2d}, {0xe3, 0x7d, 0x3b, 0x46, 0xf3, 0xc3, 0xe8, 0x25, 0x0c, 0xdd, 0x23, 0xb3, 0x93, 0x64, 0xb7, 0x1d, 0x7f, 0x7c, 0xf8, 0x69, 0xc7, 0xcb, 0xa6, 0x96, 0xe1, 0x65, 0x7b, 0xd5, 0xe4, 0x09, 0x33, 0x04}}, + {{0xa0, 0xe0, 0x20, 0xc5, 0x04, 0x4d, 0x05, 0xcf, 0xf1, 0x3a, 0xa1, 0x1c, 0xc7, 0xed, 0x40, 0xd5, 0x00, 0x04, 0xdd, 0x77, 0x4b, 0x04, 0x93, 0x49, 0x99, 0xff, 0x7e, 0xb7, 0xcd, 0xa9, 0x0e, 0x1b}, {0x3b, 0xcd, 0x1c, 0x32, 0xa8, 0x0e, 0x28, 0x69, 0x3d, 0xf0, 0xa8, 0xa1, 0x95, 0xb8, 0xab, 0x72, 0x34, 0x77, 0x87, 0x2c, 0x8f, 0x93, 0xd3, 0xf3, 0xcf, 0x6b, 0x73, 0xae, 0x69, 0x17, 0x70, 0x12}}, + {{0x2d, 0xa1, 0x5f, 0xad, 0xf0, 0xa2, 0x52, 0x3e, 0x64, 0xb0, 0xbc, 0x38, 0xa6, 0x5b, 0x18, 0x44, 0x22, 0x66, 0xf1, 0x5b, 0xef, 0xd3, 0x8b, 0xef, 0xbf, 0x28, 0xb2, 0x16, 0xc2, 0x5e, 0xf5, 0x3e}, {0x05, 0x9c, 0xf4, 0xf2, 0x14, 0xcb, 0x2b, 0xb8, 0x58, 0x09, 0x6e, 0x35, 0xe5, 0xae, 0xcb, 0x1e, 0x3a, 0xd8, 0xcd, 0x85, 0x1c, 0x68, 0x50, 0xd8, 0x8a, 0xc1, 0xcd, 0xa3, 0x30, 0x7a, 0x28, 0x13}}, + {{0xd2, 0xe4, 0x5b, 0x67, 0x31, 0x15, 0xc9, 0x76, 0xd5, 0xa3, 0xe7, 0xf5, 0xc0, 0xef, 0xf3, 0xbf, 0x5a, 0x2e, 0x04, 0xc7, 0xeb, 0x1f, 0x16, 0xbf, 0x2d, 0x21, 0x3e, 0x5e, 0x5c, 0xa8, 0x33, 0x00}, {0x07, 0x16, 0x5b, 0x73, 0x5f, 0x29, 0xfe, 0xb3, 0x11, 0x88, 0x85, 0x2f, 0x9f, 0x16, 0x07, 0x4c, 0x4b, 0xe2, 0x14, 0xe3, 0x3d, 0xcd, 0xaf, 0x53, 0xfc, 0x44, 0x46, 0x9d, 0x1a, 0x2f, 0xdd, 0x33}}, + {{0x71, 0x81, 0xe7, 0x97, 0x96, 0x06, 0x41, 0x8e, 0x95, 0xc7, 0xbf, 0x32, 0x08, 0x12, 0xff, 0x26, 0x8a, 0x80, 0x96, 0x11, 0xa4, 0x0a, 0xd7, 0x0b, 0xf5, 0x99, 0xd2, 0x40, 0x44, 0xf3, 0xe0, 0x3a}, {0x9a, 0x66, 0xad, 0x2d, 0x0b, 0xb7, 0x74, 0x24, 0x3f, 0x71, 0x98, 0xe8, 0xa7, 0x66, 0x03, 0x46, 0xba, 0xae, 0xd9, 0x0b, 0x24, 0x5b, 0x69, 0xb3, 0xea, 0xe2, 0x5e, 0x46, 0x6d, 0xbb, 0x74, 0x3c}}, + {{0xea, 0xc2, 0xdd, 0x91, 0xa3, 0x42, 0x89, 0x6e, 0xa9, 0xfb, 0xf3, 0xfc, 0xe1, 0x28, 0x8a, 0xc3, 0x78, 0xf1, 0x79, 0x5a, 0x51, 0x26, 0x31, 0xeb, 0x5b, 0x41, 0x3a, 0x2d, 0x3d, 0x5e, 0x1f, 0x34}, {0xa8, 0x4c, 0x5e, 0x37, 0x64, 0xce, 0x49, 0x74, 0x33, 0x6d, 0xb3, 0x0f, 0x5a, 0x74, 0x02, 0x06, 0x55, 0x90, 0x70, 0xd3, 0x91, 0xf8, 0x58, 0x29, 0x43, 0xe0, 0xc8, 0x2d, 0x12, 0x22, 0xb2, 0x09}}, + {{0x17, 0x1a, 0x86, 0x7f, 0x62, 0xc6, 0xb4, 0x06, 0x30, 0x1a, 0xf7, 0x09, 0x55, 0x8a, 0x92, 0x68, 0x14, 0xc5, 0x6f, 0x21, 0x0c, 0x7e, 0x16, 0x0f, 0x26, 0x5c, 0x2a, 0xd0, 0x95, 0xaf, 0x3a, 0x3d}, {0xc6, 0x9b, 0x31, 0x43, 0xff, 0x9d, 0xdf, 0xf1, 0x55, 0xf7, 0xa6, 0xc9, 0x5b, 0xab, 0x28, 0x37, 0x95, 0x3f, 0xd7, 0x2e, 0x35, 0x02, 0x73, 0x8c, 0xa0, 0x2b, 0x90, 0xc7, 0x0c, 0x6e, 0x65, 0x3f}}, + {{0x0a, 0x3f, 0x62, 0xd0, 0x04, 0x59, 0x45, 0x9f, 0xb6, 0x7b, 0xa6, 0x72, 0x9e, 0x02, 0x23, 0x78, 0xe4, 0x2b, 0x0a, 0x51, 0x2c, 0xf2, 0xfb, 0x99, 0xe7, 0x8a, 0x23, 0x47, 0x2d, 0xdf, 0x85, 0x2e}, {0xe3, 0x66, 0x78, 0xe8, 0x7b, 0x31, 0x7d, 0x32, 0x94, 0x3e, 0xdf, 0x95, 0xef, 0x75, 0x5e, 0xa4, 0x49, 0x0f, 0x02, 0xc4, 0x6d, 0xc7, 0x1a, 0x7b, 0x5e, 0x81, 0x7c, 0xa3, 0xcd, 0xfb, 0x60, 0x3a}}, + {{0xc2, 0xa5, 0xa4, 0xe2, 0x8e, 0xa0, 0xdf, 0x17, 0xc8, 0x3c, 0x39, 0x7f, 0xbf, 0xfd, 0x37, 0x0d, 0xab, 0x3a, 0xa3, 0x69, 0xee, 0x0a, 0x65, 0x5f, 0xef, 0x6f, 0x2f, 0x51, 0x3f, 0xcd, 0xcc, 0x21}, {0xbb, 0x3b, 0x34, 0x19, 0x7b, 0xf4, 0x01, 0x55, 0x03, 0x57, 0x9b, 0x83, 0xda, 0x25, 0x29, 0xc6, 0xdb, 0x98, 0xc7, 0x4a, 0xff, 0x5d, 0x69, 0xe8, 0xb3, 0xb1, 0xe8, 0xe0, 0xc0, 0x31, 0x16, 0x26}}, + {{0xdf, 0x27, 0x00, 0x9e, 0xf9, 0x7a, 0xb8, 0x11, 0xf1, 0xa4, 0xfc, 0xd6, 0x48, 0xbf, 0xd7, 0xaf, 0x33, 0xc2, 0xf4, 0x42, 0xff, 0x1a, 0x40, 0xd5, 0xb2, 0x37, 0x40, 0x8d, 0x45, 0x62, 0x8d, 0x15}, {0x36, 0xeb, 0x43, 0x62, 0x47, 0xfd, 0x6f, 0x8b, 0x2e, 0x19, 0x5d, 0x42, 0xa6, 0x2a, 0x6d, 0x6c, 0x4c, 0x62, 0x60, 0xde, 0x15, 0xaf, 0x48, 0x91, 0xa0, 0x00, 0x86, 0x38, 0x38, 0x99, 0x87, 0x3e}}, + {{0xc2, 0xe7, 0xe1, 0xe4, 0x77, 0x2c, 0x07, 0xfe, 0xde, 0x68, 0x62, 0xe6, 0x8c, 0x3c, 0xd8, 0x93, 0x9b, 0x73, 0xbc, 0x29, 0x02, 0x51, 0x9f, 0x61, 0x59, 0xaf, 0x2b, 0xc0, 0x24, 0x5f, 0x66, 0x3a}, {0x76, 0xa8, 0xc8, 0x58, 0x98, 0xf1, 0x57, 0xc5, 0xf9, 0x1a, 0x81, 0x73, 0x95, 0x98, 0x31, 0x77, 0xe6, 0x93, 0x5d, 0x99, 0x8d, 0x91, 0x7d, 0x6b, 0x36, 0x96, 0x8e, 0xc9, 0x7d, 0x06, 0x7f, 0x30}}, + {{0x75, 0xc6, 0x68, 0x6a, 0x75, 0x54, 0x36, 0xa4, 0x53, 0x35, 0x4f, 0x79, 0x99, 0xf2, 0xf2, 0x88, 0xc7, 0x62, 0xae, 0x74, 0xb8, 0x45, 0x11, 0x7f, 0x81, 0xb4, 0x27, 0x0f, 0x1a, 0xf8, 0xee, 0x0d}, {0x8c, 0xcf, 0x5e, 0x7f, 0xcf, 0x47, 0x3e, 0x99, 0x47, 0x04, 0x5e, 0x1b, 0x2c, 0x5d, 0x10, 0xe8, 0x82, 0xac, 0x1d, 0x1a, 0x23, 0xb9, 0xad, 0xca, 0x30, 0xe2, 0x2b, 0x4b, 0x69, 0x89, 0x7a, 0x14}}, + {{0x84, 0x61, 0x1e, 0xae, 0x66, 0xe3, 0x23, 0x47, 0x9b, 0xea, 0x19, 0xd7, 0x7f, 0x32, 0x04, 0xee, 0x7d, 0xf2, 0x52, 0xe1, 0x73, 0xbe, 0xdb, 0x24, 0x8d, 0x43, 0x71, 0x61, 0x76, 0x99, 0x00, 0x21}, {0x67, 0x12, 0x94, 0x9b, 0x4e, 0x8e, 0xe4, 0xef, 0x84, 0xa0, 0xb0, 0xfa, 0x86, 0x89, 0xb1, 0xac, 0x5e, 0xea, 0x11, 0xae, 0x63, 0x56, 0x10, 0x7b, 0x0c, 0x40, 0x1c, 0x77, 0x1d, 0x22, 0x4f, 0x27}}, + {{0x1e, 0x3d, 0x57, 0x86, 0x90, 0x17, 0xb8, 0x5c, 0xc4, 0xdd, 0xdd, 0x2e, 0xde, 0x63, 0x05, 0xdd, 0xeb, 0xff, 0x88, 0xb3, 0x57, 0xe5, 0xba, 0x78, 0x5d, 0x36, 0xd0, 0x4a, 0xf1, 0xb9, 0x84, 0x1a}, {0x6a, 0x23, 0x66, 0xe9, 0xb8, 0xbf, 0xda, 0xd1, 0xc8, 0x0c, 0xd6, 0xcb, 0x91, 0xfa, 0xd3, 0x57, 0x3a, 0x33, 0x48, 0x02, 0x96, 0x80, 0x92, 0xdc, 0x7f, 0x99, 0x47, 0x52, 0xb4, 0x21, 0x6c, 0x37}}, + {{0xb1, 0xf7, 0x21, 0xdc, 0x7a, 0xc0, 0xf0, 0x13, 0x4b, 0x85, 0xfe, 0x05, 0xe9, 0x69, 0x5c, 0x2a, 0x4f, 0xda, 0x7d, 0x1d, 0x4d, 0xd1, 0x73, 0x05, 0x9d, 0xa4, 0x74, 0xb6, 0xda, 0xe5, 0x3e, 0x19}, {0x90, 0x4b, 0x4a, 0x71, 0xca, 0x74, 0xa1, 0x7f, 0x93, 0xa7, 0xa5, 0x52, 0x2e, 0xaa, 0x21, 0xfe, 0x91, 0xc7, 0x5b, 0x0f, 0x36, 0xb5, 0xdc, 0x69, 0x6c, 0xe2, 0xd7, 0x03, 0x37, 0xb2, 0x16, 0x1b}}, + {{0xe6, 0xb8, 0xd4, 0x27, 0x65, 0x68, 0xf6, 0xea, 0xcf, 0x1f, 0x66, 0x26, 0xb4, 0xaa, 0xa0, 0x1a, 0x73, 0x5e, 0xa0, 0xa2, 0xaf, 0x9b, 0xa7, 0x1a, 0x85, 0x40, 0xc2, 0x8e, 0x2c, 0x72, 0x89, 0x35}, {0x8f, 0xfb, 0x47, 0xd7, 0x91, 0x04, 0x42, 0x41, 0x57, 0xbf, 0x8a, 0x72, 0xf7, 0x63, 0x0b, 0xc2, 0x0b, 0xd2, 0x2a, 0xab, 0x74, 0x19, 0x1d, 0xf6, 0x78, 0xa9, 0xcd, 0x28, 0xb3, 0xa2, 0x16, 0x3a}}, + {{0x11, 0xe0, 0x84, 0xe8, 0xc8, 0x9a, 0x9a, 0x47, 0x26, 0xae, 0x03, 0xcd, 0xb0, 0x93, 0x4e, 0x50, 0x77, 0xe9, 0x19, 0x13, 0x1f, 0x9e, 0x11, 0xc7, 0xe7, 0x15, 0x77, 0xdb, 0xe7, 0x11, 0x93, 0x37}, {0x58, 0xec, 0x78, 0x65, 0x48, 0xef, 0x5b, 0xf0, 0xdd, 0x50, 0xca, 0xde, 0x2f, 0xb5, 0xb9, 0x05, 0xa2, 0x95, 0xf6, 0x9b, 0xfe, 0xc4, 0x92, 0x6c, 0x6d, 0x55, 0xd7, 0x8a, 0xe4, 0x65, 0xe6, 0x2a}}, + {{0x39, 0x50, 0x11, 0x3a, 0x07, 0xf0, 0x18, 0x94, 0x1d, 0xaa, 0x3c, 0x29, 0xe6, 0xf7, 0xba, 0x84, 0xe8, 0xe8, 0x37, 0x6c, 0xb5, 0x7b, 0xe5, 0x4b, 0x9e, 0x2f, 0x9d, 0xba, 0x6c, 0x0c, 0x01, 0x2e}, {0x73, 0x13, 0x3a, 0x79, 0xc5, 0x63, 0x0c, 0xb3, 0x92, 0xa6, 0xda, 0xe4, 0x68, 0xa8, 0xa7, 0xc2, 0xdd, 0xb6, 0x1f, 0xb7, 0x7b, 0xe6, 0x9f, 0x78, 0x2a, 0x8e, 0x26, 0x31, 0x92, 0xc1, 0x12, 0x28}}, + {{0xb6, 0xbc, 0xfb, 0xd6, 0x6d, 0x8b, 0x3e, 0x8a, 0xe2, 0xcb, 0x83, 0x35, 0x86, 0x95, 0xb6, 0xfa, 0xa1, 0xb5, 0xbf, 0xa4, 0x47, 0x3c, 0x2e, 0x3d, 0x9d, 0xe9, 0x51, 0xb3, 0x76, 0x0e, 0x15, 0x17}, {0x57, 0x77, 0xa4, 0x65, 0xfa, 0x22, 0xa8, 0x2e, 0x1c, 0x74, 0x55, 0xc6, 0x4a, 0xe6, 0x2f, 0x1f, 0x70, 0x95, 0xac, 0xf5, 0x5a, 0x20, 0xaa, 0xd1, 0xe9, 0xc8, 0x36, 0x08, 0x88, 0xdd, 0xcf, 0x27}}, + {{0x79, 0x79, 0x2a, 0x82, 0x29, 0x5f, 0x30, 0x7d, 0xe2, 0x96, 0x64, 0xa3, 0xc1, 0x4f, 0x82, 0x80, 0x4d, 0x0f, 0x7a, 0xc7, 0xf4, 0x1c, 0x3d, 0xf7, 0xbe, 0x26, 0x19, 0x6a, 0x3c, 0xbe, 0x9c, 0x1c}, {0x23, 0x18, 0x76, 0x1c, 0x8c, 0xaf, 0x17, 0xaa, 0x26, 0xe9, 0xf6, 0xba, 0x90, 0xa2, 0xd0, 0x09, 0x2b, 0xc2, 0xd6, 0xb5, 0xf8, 0x06, 0x1c, 0xf6, 0xcd, 0xd9, 0x32, 0xfc, 0x6d, 0x1a, 0x2f, 0x17}}, + {{0xb9, 0x2f, 0x20, 0xb5, 0x43, 0x87, 0xd3, 0x5a, 0xd2, 0x40, 0xbe, 0x50, 0x95, 0x26, 0x3a, 0x08, 0xe3, 0xcd, 0x67, 0x3f, 0x03, 0x18, 0x11, 0xb9, 0x10, 0xb8, 0xcf, 0x30, 0x62, 0xf4, 0x46, 0x28}, {0x4c, 0xc5, 0x37, 0xe9, 0xe7, 0xb5, 0x23, 0xe2, 0x21, 0x3f, 0x8b, 0xb0, 0xfd, 0x77, 0xc5, 0xf2, 0xd3, 0xa7, 0x05, 0x75, 0x2b, 0x65, 0xc1, 0xb6, 0x30, 0xe1, 0x60, 0x2e, 0x98, 0xa4, 0x8f, 0x2c}}, + {{0xf3, 0x95, 0x75, 0x41, 0x85, 0xe1, 0xbb, 0x56, 0x02, 0xc2, 0x07, 0x94, 0x53, 0x00, 0xc1, 0xec, 0x2e, 0xfd, 0x30, 0x76, 0x15, 0xc4, 0xa5, 0x90, 0x20, 0xce, 0x10, 0x64, 0xf2, 0x8e, 0x33, 0x1f}, {0xd4, 0xb7, 0x56, 0x1a, 0x59, 0x54, 0x3b, 0x1a, 0x25, 0xbd, 0xc8, 0xcf, 0x2b, 0xc4, 0x11, 0x27, 0x65, 0x19, 0x62, 0xa4, 0xd6, 0x42, 0x13, 0xb3, 0x28, 0xbe, 0x6a, 0x6c, 0x27, 0x57, 0x04, 0x1e}}, + {{0xd6, 0xe9, 0xc2, 0x1f, 0x2d, 0x12, 0xf0, 0x33, 0xf4, 0xb5, 0x0d, 0x6d, 0xe2, 0x07, 0xaf, 0xbb, 0x28, 0x09, 0xf2, 0x90, 0xdb, 0xe1, 0xa4, 0xad, 0x51, 0x9b, 0x1f, 0x7e, 0xd3, 0x78, 0x0d, 0x32}, {0xf9, 0x79, 0x0e, 0xb8, 0x2f, 0xfe, 0x4f, 0x6d, 0x4d, 0x9c, 0x60, 0x01, 0xf5, 0x46, 0x97, 0x16, 0x17, 0xe1, 0x1f, 0x37, 0x69, 0xaa, 0x94, 0x9c, 0x61, 0x76, 0x97, 0x82, 0x7d, 0xa4, 0xff, 0x08}}, + {{0x15, 0x17, 0x55, 0x7d, 0x5f, 0x41, 0xed, 0x0e, 0x7b, 0x45, 0x11, 0xaa, 0x98, 0x3b, 0x20, 0xf4, 0xfb, 0x0a, 0x76, 0x44, 0xd5, 0xf3, 0x53, 0x90, 0xa1, 0x76, 0xa2, 0xde, 0xba, 0x03, 0xc2, 0x02}, {0xaf, 0xa5, 0x42, 0xe8, 0x4a, 0x02, 0xd7, 0x55, 0x2f, 0xcd, 0xeb, 0x9d, 0xba, 0x03, 0x8c, 0xb5, 0xb5, 0x42, 0xaa, 0xce, 0xb6, 0xc8, 0x6b, 0x0c, 0x3e, 0x5c, 0x35, 0x6e, 0xab, 0x7f, 0x4e, 0x3b}}, + {{0xe9, 0xdb, 0x0d, 0x6a, 0xf8, 0x81, 0x9d, 0xea, 0xf1, 0xe6, 0x57, 0x32, 0x09, 0x28, 0x0f, 0xce, 0x04, 0xff, 0x52, 0xfd, 0x64, 0x3b, 0x39, 0x00, 0x24, 0xef, 0x23, 0x8d, 0x21, 0x58, 0x42, 0x29}, {0x5b, 0xdc, 0x17, 0x95, 0x0f, 0x71, 0x7f, 0xbb, 0xca, 0x48, 0xab, 0x43, 0x53, 0x14, 0xdb, 0xb9, 0x51, 0x34, 0xe8, 0x1f, 0xe3, 0x60, 0xcd, 0x94, 0x8b, 0xbe, 0x98, 0xf7, 0xe0, 0x7c, 0xe1, 0x2b}}, + {{0xa2, 0x3a, 0x1f, 0x07, 0x8b, 0xee, 0x71, 0xd9, 0x48, 0x66, 0x21, 0x2f, 0x6f, 0x04, 0x42, 0x65, 0xeb, 0x2f, 0xc5, 0xc4, 0xb4, 0xa0, 0x11, 0x70, 0xcb, 0xc7, 0x5d, 0x30, 0xe4, 0x75, 0x6a, 0x17}, {0x24, 0xae, 0x75, 0xce, 0x0b, 0x68, 0xfe, 0xb8, 0x44, 0x7b, 0xd2, 0xc3, 0xf6, 0xcb, 0x49, 0x85, 0x87, 0xc5, 0x40, 0x6a, 0xa7, 0x92, 0xee, 0xa8, 0x31, 0xf1, 0x3d, 0x01, 0xba, 0xb0, 0xe6, 0x09}}, + {{0x65, 0xda, 0xfd, 0x64, 0x97, 0x9e, 0x0b, 0xb8, 0x2d, 0x8a, 0xc5, 0x0b, 0x11, 0xb4, 0xc0, 0xb0, 0x55, 0x5c, 0xe1, 0xc6, 0xa0, 0xb1, 0x1b, 0xac, 0xe8, 0x70, 0x7a, 0xd3, 0x41, 0x4d, 0xa4, 0x36}, {0x2f, 0xe7, 0xaa, 0x81, 0xb2, 0xef, 0x77, 0x6a, 0xa7, 0xfa, 0x58, 0x9b, 0x86, 0x86, 0x78, 0xc5, 0xdc, 0x68, 0x33, 0x7e, 0xbd, 0x33, 0x74, 0xab, 0x00, 0xa0, 0x54, 0x7f, 0x2e, 0xad, 0x92, 0x17}}, + {{0xa7, 0xa9, 0x95, 0x03, 0xef, 0xf6, 0x92, 0x87, 0x29, 0x72, 0xc2, 0x66, 0x3d, 0x7f, 0x75, 0xd3, 0x10, 0x90, 0xc7, 0xd5, 0x76, 0xe8, 0x49, 0x69, 0xa7, 0x8b, 0x7f, 0x0c, 0x16, 0xf1, 0x6c, 0x17}, {0xbf, 0xc2, 0x8d, 0xa9, 0xf0, 0xd8, 0xf5, 0xf0, 0xe9, 0xd9, 0x6c, 0xac, 0x9e, 0xe0, 0x18, 0x41, 0x57, 0xf6, 0x97, 0x5f, 0xe4, 0x51, 0xd1, 0x4e, 0xe4, 0x54, 0xb8, 0x26, 0x56, 0x37, 0xe7, 0x13}}, + {{0xd0, 0x06, 0xc2, 0xf3, 0x57, 0x32, 0xcd, 0xbc, 0x42, 0xa3, 0x91, 0xf9, 0xae, 0x8e, 0x39, 0x31, 0x6c, 0x5a, 0xa3, 0x2f, 0x14, 0x44, 0x2d, 0x5a, 0x52, 0x31, 0xf6, 0x13, 0xc7, 0xbc, 0xef, 0x3c}, {0xab, 0x00, 0x7e, 0x01, 0x97, 0x3b, 0x06, 0xc8, 0xc3, 0xac, 0xb5, 0x44, 0xd5, 0xfd, 0x20, 0x5e, 0xcd, 0x18, 0x8f, 0xef, 0xf6, 0xc0, 0xce, 0x6c, 0xeb, 0xbf, 0x6a, 0xec, 0x77, 0x4b, 0xee, 0x14}}, + {{0xb3, 0xea, 0xdb, 0x58, 0x38, 0x22, 0x96, 0xc0, 0x29, 0xef, 0x10, 0xdb, 0xb0, 0x61, 0x0e, 0x5c, 0xa4, 0x1d, 0xcb, 0x8a, 0xed, 0xf1, 0x9a, 0x6c, 0x39, 0xd9, 0x25, 0xc4, 0x73, 0xfe, 0x76, 0x3f}, {0x6f, 0x55, 0x80, 0xb2, 0xe8, 0x82, 0xd4, 0xda, 0x4e, 0xc5, 0xdc, 0x7f, 0xde, 0x06, 0xf4, 0xc3, 0xb9, 0x54, 0x36, 0x1d, 0xb8, 0x88, 0xca, 0x37, 0xd3, 0xa4, 0x44, 0x72, 0x76, 0xf7, 0x61, 0x02}}, + {{0xfe, 0x8e, 0x2a, 0xa1, 0x9a, 0xca, 0x1c, 0x7e, 0x9b, 0xec, 0x22, 0xc5, 0xa8, 0x62, 0x8b, 0x94, 0xf8, 0x3d, 0x8c, 0x21, 0x9b, 0x04, 0xbb, 0x9d, 0x78, 0xaf, 0x55, 0xd2, 0x6c, 0x3a, 0xfd, 0x1e}, {0x1f, 0x0a, 0x65, 0x4d, 0x75, 0x0f, 0xb5, 0xa4, 0x13, 0x2c, 0x5e, 0xa7, 0x86, 0x6c, 0xb7, 0x25, 0x53, 0x1d, 0x4d, 0xef, 0x87, 0x68, 0x6c, 0xfd, 0xf0, 0x51, 0xbc, 0x71, 0xd3, 0x0b, 0x59, 0x0a}}, + {{0x50, 0xd6, 0xd0, 0xb8, 0xa8, 0xce, 0xee, 0xdc, 0xd4, 0xf2, 0x29, 0x6a, 0x8d, 0x8b, 0x2d, 0x4f, 0xeb, 0x11, 0xf9, 0xea, 0x8f, 0x52, 0xd0, 0x43, 0x52, 0x2b, 0x6c, 0x54, 0x52, 0x4c, 0x04, 0x24}, {0xf6, 0xd9, 0xf0, 0x1c, 0xcd, 0xfa, 0xc3, 0x96, 0xd8, 0x6a, 0x50, 0x9f, 0x12, 0x67, 0x63, 0xca, 0x5b, 0x9b, 0x5f, 0xfa, 0x05, 0xd0, 0x85, 0x2f, 0x30, 0xc1, 0x96, 0x98, 0x3f, 0x15, 0x9e, 0x06}}, + {{0x57, 0xd9, 0x61, 0x4c, 0x12, 0x82, 0x6e, 0x68, 0x9e, 0x64, 0x86, 0xa4, 0xde, 0x9b, 0xaa, 0xc7, 0x8d, 0x7a, 0xa3, 0xd4, 0xe0, 0x91, 0xc2, 0xd3, 0xf3, 0x28, 0x5f, 0x2c, 0xe3, 0xe2, 0x07, 0x01}, {0x1b, 0x59, 0xd7, 0xc3, 0xdf, 0x45, 0x0b, 0xab, 0x3d, 0xf6, 0x0b, 0x71, 0x4a, 0x85, 0xb5, 0xf7, 0xf3, 0x26, 0x0c, 0x2e, 0xf1, 0xc8, 0x4d, 0x54, 0x85, 0xea, 0xcc, 0x30, 0xa7, 0x95, 0x9b, 0x2d}}, + {{0xf0, 0x56, 0xce, 0x95, 0xc2, 0x33, 0x3d, 0x51, 0x31, 0x70, 0xd7, 0x7f, 0xdd, 0x2f, 0x2b, 0xbd, 0x31, 0xe0, 0xe2, 0x09, 0xfe, 0x47, 0x4f, 0x5d, 0xb4, 0x54, 0x80, 0x7b, 0x42, 0x48, 0x94, 0x2f}, {0x67, 0x74, 0x6a, 0xd3, 0x65, 0xd6, 0x6f, 0xdf, 0x07, 0x6b, 0xea, 0x2f, 0x1f, 0x19, 0xc9, 0x5d, 0x22, 0x64, 0x40, 0x71, 0x63, 0xef, 0xa2, 0xec, 0x2c, 0xf7, 0xda, 0x96, 0xc0, 0x50, 0x71, 0x01}}, + {{0x58, 0x28, 0xce, 0x87, 0x4f, 0x1d, 0x7a, 0x36, 0x19, 0xcd, 0x37, 0x81, 0x07, 0x5c, 0x54, 0x9d, 0xfd, 0x3b, 0x8f, 0x73, 0x72, 0x20, 0x1a, 0xdf, 0xd4, 0x25, 0xf0, 0x52, 0x20, 0x41, 0x4e, 0x11}, {0xea, 0xd5, 0x66, 0xbf, 0xdf, 0x28, 0xfd, 0x18, 0x75, 0x9a, 0x49, 0xf9, 0xf0, 0x77, 0xbd, 0x8b, 0x3b, 0x45, 0xe8, 0xf3, 0x99, 0x4f, 0x62, 0x63, 0x49, 0x84, 0x38, 0x8a, 0xfe, 0xed, 0x80, 0x27}}, + {{0xd4, 0x5a, 0xa9, 0x0e, 0x82, 0x30, 0x02, 0x74, 0xfd, 0x2f, 0x50, 0x35, 0xe5, 0x7b, 0xb2, 0x63, 0xb6, 0x60, 0xe2, 0xfb, 0x3e, 0xcb, 0xdc, 0x91, 0x77, 0x34, 0x32, 0x0f, 0xb1, 0xbf, 0xe2, 0x25}, {0x4f, 0x09, 0xb4, 0x39, 0x71, 0x3a, 0xc0, 0xad, 0xbb, 0xc2, 0xd1, 0xb4, 0x0f, 0xc6, 0xf8, 0xed, 0xcb, 0x9f, 0x02, 0xb7, 0x47, 0x09, 0x11, 0x69, 0x65, 0x80, 0x50, 0xa8, 0xe0, 0x2f, 0xf4, 0x01}}, + {{0xd0, 0xb4, 0x96, 0xe5, 0x62, 0xcd, 0x2d, 0xff, 0xc8, 0x0f, 0xf5, 0x5a, 0xd4, 0x1a, 0xd3, 0xc7, 0xfd, 0x63, 0xa6, 0xb1, 0xfa, 0x73, 0xbf, 0xa0, 0x05, 0xa0, 0x3e, 0x7e, 0x95, 0x46, 0xc5, 0x01}, {0x79, 0x67, 0x8f, 0x93, 0xcf, 0xaa, 0xeb, 0xef, 0x91, 0x72, 0xde, 0x07, 0x6e, 0x3f, 0x86, 0x69, 0x96, 0xe7, 0xe6, 0xad, 0x67, 0x8e, 0x6e, 0xc0, 0xe9, 0x9a, 0x66, 0x79, 0xe7, 0xab, 0x4b, 0x16}}, + {{0xe0, 0x8f, 0x27, 0xb5, 0x51, 0x6e, 0x33, 0x1c, 0x0b, 0x06, 0xb0, 0x88, 0x67, 0x02, 0x0f, 0x83, 0xf4, 0xcd, 0x36, 0x61, 0x8a, 0xfe, 0x89, 0xe5, 0x5b, 0x31, 0x30, 0xec, 0x36, 0xbb, 0xe2, 0x04}, {0xfb, 0x5b, 0x34, 0x93, 0xb5, 0x5c, 0xe6, 0xcd, 0xf4, 0xf5, 0x87, 0x42, 0x83, 0xfb, 0xa1, 0x10, 0xc1, 0x28, 0x19, 0x46, 0x0c, 0xa2, 0xc7, 0x37, 0x62, 0x6b, 0x26, 0x41, 0x85, 0x5a, 0xdc, 0x2a}}, + {{0xba, 0x61, 0xe2, 0x42, 0x35, 0xba, 0x32, 0x39, 0xcd, 0x4d, 0xde, 0x82, 0x9e, 0x39, 0x1e, 0x3a, 0x73, 0x3c, 0xac, 0x03, 0xff, 0x6d, 0x5f, 0x3a, 0xa9, 0x16, 0xd9, 0x53, 0xf4, 0x15, 0xbd, 0x2c}, {0x37, 0x89, 0x8d, 0xa9, 0x5f, 0xa3, 0x25, 0x24, 0x8c, 0x58, 0x9f, 0x5d, 0xd3, 0xa2, 0x66, 0x0a, 0x2b, 0x85, 0x51, 0x39, 0x5a, 0x8c, 0x32, 0xf8, 0x55, 0xdd, 0xa2, 0xb4, 0x66, 0x6f, 0x48, 0x08}}, + {{0x64, 0x95, 0x4d, 0x3a, 0x80, 0x83, 0xc3, 0xa4, 0xf2, 0x54, 0xeb, 0x31, 0x0c, 0xbd, 0x9a, 0x10, 0x11, 0xa2, 0x12, 0xb0, 0xb4, 0x57, 0x3d, 0xa8, 0x85, 0x3f, 0xfd, 0x4c, 0x0c, 0xc8, 0x49, 0x39}, {0x40, 0x9e, 0xf1, 0x1e, 0x0d, 0x3f, 0xcd, 0xfd, 0x81, 0xb4, 0x92, 0x46, 0x77, 0x54, 0xf8, 0x47, 0x07, 0x86, 0x2f, 0x25, 0x1d, 0x0e, 0xfc, 0x60, 0x19, 0xdc, 0xc3, 0x45, 0x08, 0x2a, 0x47, 0x15}}, + {{0xaf, 0x7b, 0xe5, 0x48, 0x6d, 0x59, 0x2e, 0x04, 0x28, 0xf6, 0x15, 0xcb, 0x41, 0x30, 0xd7, 0xd9, 0x16, 0x09, 0x88, 0x4e, 0x78, 0xa3, 0xec, 0x65, 0xda, 0x01, 0xe9, 0x27, 0x0d, 0x7f, 0x9f, 0x05}, {0x43, 0xb4, 0xf8, 0x4c, 0xd4, 0x77, 0x7d, 0xd3, 0xec, 0x76, 0x41, 0x7d, 0xa6, 0x72, 0xa1, 0xbf, 0x4e, 0x7b, 0x24, 0x25, 0x61, 0xb7, 0xc8, 0xd8, 0xf5, 0x24, 0x2d, 0x5c, 0x88, 0x64, 0x9b, 0x07}}, + {{0xbe, 0x6d, 0xb5, 0xa4, 0x03, 0x07, 0x9f, 0xd2, 0xfc, 0x46, 0x6b, 0x95, 0xa8, 0x6a, 0xe2, 0x75, 0x06, 0x28, 0xe2, 0x02, 0xe7, 0x49, 0xa4, 0x84, 0x1c, 0x12, 0xac, 0xce, 0xd6, 0xf1, 0xbb, 0x38}, {0xd1, 0xb6, 0x66, 0x30, 0x73, 0x1a, 0x72, 0xc7, 0x06, 0xec, 0x3b, 0xb5, 0xf3, 0x55, 0x37, 0x17, 0x21, 0x2c, 0x1e, 0x3e, 0x62, 0xbd, 0x2a, 0x3c, 0x16, 0x01, 0x66, 0x63, 0x3b, 0xd4, 0x8d, 0x08}}, + {{0xb6, 0x8b, 0x5a, 0x05, 0x77, 0x6f, 0x16, 0xa1, 0xa4, 0x8d, 0x89, 0x58, 0x8c, 0x2d, 0x85, 0x63, 0x17, 0x77, 0x4b, 0x75, 0xcd, 0xf4, 0xb4, 0x34, 0x5f, 0x51, 0xe7, 0xf3, 0x2d, 0xaa, 0x26, 0x15}, {0xb8, 0xe4, 0x57, 0x26, 0x1a, 0xc5, 0x85, 0x40, 0x45, 0x86, 0x24, 0x46, 0xa4, 0x5e, 0x79, 0x96, 0x98, 0x39, 0xd6, 0xe3, 0xa1, 0x03, 0x04, 0xc8, 0x08, 0x4b, 0x32, 0x21, 0xb0, 0xc2, 0x9c, 0x19}}, + {{0xc2, 0x77, 0x68, 0xd1, 0x5d, 0xdb, 0x2a, 0xa5, 0x2e, 0xaf, 0x52, 0x0b, 0x22, 0xf9, 0x03, 0x6b, 0xbd, 0x22, 0xef, 0xb4, 0xe8, 0x01, 0xc8, 0x7f, 0x1d, 0x2f, 0x81, 0xec, 0xc2, 0x67, 0xe5, 0x12}, {0x0b, 0xc2, 0xe8, 0xa4, 0x14, 0x40, 0x09, 0x03, 0xcc, 0xa8, 0x00, 0xa2, 0xd6, 0x0c, 0xbf, 0xe7, 0xea, 0x94, 0x5b, 0xfb, 0xfe, 0x65, 0x08, 0xc6, 0xac, 0x41, 0x68, 0x3f, 0x45, 0x14, 0x93, 0x09}}, + {{0xd8, 0x75, 0x6f, 0x8b, 0x57, 0xfd, 0xd7, 0xbf, 0x6a, 0x29, 0x3d, 0xd3, 0x6e, 0xf8, 0x7e, 0xf0, 0x12, 0xee, 0x8e, 0xd4, 0x78, 0xc9, 0x54, 0x50, 0x3a, 0xc4, 0x6f, 0x4f, 0xcb, 0x76, 0x3d, 0x0b}, {0xeb, 0x90, 0xed, 0x4e, 0x5a, 0x62, 0xf7, 0xbe, 0xf7, 0x73, 0xfe, 0x22, 0xde, 0xba, 0x8d, 0x1f, 0xfe, 0x1b, 0xe5, 0x3a, 0x94, 0xab, 0x60, 0xc9, 0x3e, 0x97, 0x5c, 0x86, 0xd8, 0xb2, 0x58, 0x08}}, + {{0xdd, 0x04, 0x3a, 0x84, 0x37, 0x3c, 0xe4, 0xe2, 0xc0, 0xe7, 0x66, 0x69, 0x1e, 0x8a, 0xe9, 0x28, 0xa1, 0xf5, 0x29, 0xd6, 0x4f, 0x30, 0xc4, 0x6a, 0xfb, 0x32, 0x0c, 0xec, 0xe1, 0xf1, 0xfc, 0x2d}, {0x6e, 0x7f, 0xd0, 0x99, 0xf8, 0x15, 0x67, 0xbd, 0xff, 0x47, 0xcc, 0x89, 0x99, 0x5a, 0x85, 0xcb, 0xc4, 0x35, 0x72, 0x68, 0x26, 0x24, 0x2d, 0xdd, 0xb8, 0xfc, 0xa3, 0xa3, 0xc6, 0x0e, 0x68, 0x19}}, + {{0x76, 0x10, 0x94, 0x1f, 0x6e, 0xb9, 0xab, 0xa5, 0x68, 0x02, 0x7a, 0xb9, 0x51, 0xb4, 0xb5, 0x51, 0x75, 0xe3, 0xed, 0x58, 0x4f, 0xdc, 0xe0, 0xd7, 0x63, 0x7e, 0x6d, 0xf7, 0xa5, 0x18, 0xee, 0x2b}, {0xb4, 0xd7, 0x1d, 0x44, 0xbe, 0x80, 0x7d, 0xed, 0x3b, 0xcf, 0x19, 0x3c, 0x0a, 0xd3, 0xc2, 0xa4, 0xed, 0x91, 0x1f, 0x2e, 0x9b, 0x73, 0x4f, 0xac, 0x81, 0x3d, 0x89, 0xe3, 0xda, 0x48, 0x62, 0x35}}, + {{0xc0, 0xa1, 0xcb, 0x4d, 0x8c, 0xfc, 0x79, 0x7c, 0xa1, 0xc1, 0x58, 0xb9, 0x35, 0x1c, 0x62, 0x81, 0x4d, 0xf0, 0x65, 0x32, 0x19, 0x6e, 0x41, 0x0a, 0x41, 0x7f, 0xe1, 0x45, 0x48, 0x48, 0x9e, 0x00}, {0xd1, 0xeb, 0x35, 0xab, 0x94, 0x93, 0x2d, 0x71, 0xfb, 0x49, 0xe1, 0xd8, 0x1e, 0xe1, 0x12, 0x63, 0xde, 0x1a, 0xe5, 0x77, 0x33, 0x99, 0xaf, 0x84, 0xc9, 0x1d, 0x36, 0xcd, 0x6c, 0x3c, 0x42, 0x3f}}, + {{0xe1, 0xb1, 0x23, 0x7f, 0x56, 0x6e, 0x71, 0xf3, 0x94, 0x49, 0x0d, 0x6a, 0x4d, 0x3c, 0x8f, 0x53, 0xec, 0x32, 0x89, 0xb0, 0x2a, 0x6e, 0x2a, 0xaf, 0xaf, 0x98, 0xa2, 0x37, 0xc7, 0x49, 0x3e, 0x2f}, {0xcc, 0x18, 0xc3, 0xdc, 0xba, 0xaf, 0xeb, 0xc5, 0x3d, 0xfd, 0x39, 0x63, 0x4c, 0x6b, 0xf2, 0x64, 0xcc, 0xb6, 0x27, 0xfa, 0x54, 0x95, 0xf0, 0x5e, 0x35, 0xe1, 0xe4, 0x51, 0xc1, 0x5e, 0xdd, 0x21}}, + {{0x3c, 0x4b, 0xe5, 0xf9, 0xea, 0xc4, 0x82, 0xc3, 0x43, 0xc1, 0x3e, 0xb1, 0x7a, 0xf2, 0xea, 0x47, 0x0f, 0x40, 0xaf, 0xca, 0x75, 0x37, 0x6c, 0x2a, 0xdf, 0x26, 0xee, 0x65, 0xa6, 0xcb, 0xd1, 0x08}, {0x25, 0xcd, 0x82, 0xf3, 0x0d, 0xf1, 0xf2, 0xfd, 0xf3, 0xd2, 0x45, 0x40, 0x72, 0x4d, 0x2b, 0x81, 0x4b, 0x08, 0x22, 0x64, 0xe2, 0x32, 0xc3, 0xc1, 0xd3, 0x8c, 0x76, 0xf1, 0xa4, 0x9e, 0xa4, 0x26}}, + {{0x53, 0x93, 0xe5, 0x94, 0xea, 0x91, 0x32, 0xe1, 0xe5, 0x82, 0x7b, 0xfc, 0x80, 0x56, 0x69, 0x7d, 0x02, 0xfe, 0xd7, 0xfc, 0x9f, 0xbc, 0xa6, 0xad, 0x35, 0x13, 0x41, 0xac, 0x4f, 0xe9, 0xd4, 0x2a}, {0xef, 0x98, 0x45, 0xd8, 0x57, 0x85, 0x66, 0xf1, 0x6a, 0x5c, 0x3a, 0x9c, 0xdf, 0x78, 0xf8, 0xb6, 0xcf, 0x8c, 0x73, 0x00, 0xb9, 0xe2, 0x93, 0x09, 0x31, 0xae, 0x85, 0x48, 0x67, 0x68, 0xb0, 0x09}}, + {{0x76, 0xa1, 0x51, 0x2c, 0xa7, 0xde, 0x61, 0x41, 0x17, 0x8e, 0xc1, 0x82, 0x28, 0xe2, 0x7b, 0x14, 0xcd, 0x8b, 0xaf, 0xd4, 0x27, 0xb8, 0x7c, 0xf4, 0x33, 0xaa, 0xa9, 0x90, 0xc4, 0x5e, 0xa0, 0x30}, {0x41, 0xa8, 0xa8, 0x3e, 0xdb, 0xf6, 0x09, 0x32, 0x05, 0x69, 0x2d, 0xea, 0xc6, 0x06, 0x9c, 0x1d, 0x8f, 0x62, 0x39, 0xac, 0xc8, 0x34, 0xfe, 0x6a, 0xde, 0xac, 0x2f, 0xac, 0xed, 0x03, 0xf8, 0x35}}, + {{0xed, 0xb5, 0xeb, 0x83, 0xdb, 0xdf, 0x8d, 0xbe, 0xc3, 0x07, 0xab, 0x57, 0x55, 0x8a, 0x5a, 0x18, 0xb0, 0xeb, 0xd5, 0x64, 0xb1, 0x99, 0x9c, 0x10, 0xf7, 0xc4, 0xe7, 0xc0, 0xbe, 0x40, 0x43, 0x02}, {0x39, 0x04, 0x10, 0x6b, 0xb6, 0x37, 0x51, 0x6b, 0xcd, 0x1e, 0x1d, 0x1a, 0xfe, 0x00, 0x2e, 0x6f, 0x97, 0x5f, 0xb4, 0x7a, 0x62, 0xff, 0xaf, 0xe2, 0x68, 0x43, 0xad, 0x0b, 0xbc, 0x3e, 0xd1, 0x31}}, + {{0x5b, 0x80, 0xe0, 0x77, 0xc2, 0x00, 0x2c, 0xe5, 0x3e, 0x61, 0xe4, 0x00, 0xfc, 0x6c, 0x9a, 0x28, 0x43, 0xaf, 0x0e, 0xb8, 0xe6, 0x64, 0x6d, 0xba, 0xe1, 0x10, 0xeb, 0xa2, 0x3a, 0xbb, 0x8d, 0x02}, {0x71, 0xaf, 0xc2, 0xb2, 0x84, 0x5d, 0xe0, 0xb5, 0xb4, 0xd4, 0x2d, 0xed, 0xc8, 0x19, 0xa8, 0x8c, 0x1d, 0x18, 0x4e, 0x89, 0x85, 0x12, 0x23, 0xbf, 0x20, 0x28, 0x42, 0xaf, 0xec, 0x55, 0xdd, 0x13}}, + {{0x78, 0x55, 0x79, 0xf4, 0x64, 0x9e, 0xd5, 0x7c, 0x12, 0x1d, 0xad, 0x4d, 0x01, 0x83, 0xe4, 0xb2, 0x7b, 0x7a, 0xae, 0xf3, 0x33, 0x33, 0xbc, 0x69, 0x73, 0xce, 0x56, 0x8e, 0xe3, 0xbe, 0x8b, 0x1d}, {0x8e, 0x6d, 0xf3, 0x93, 0x32, 0xe0, 0xed, 0x62, 0x90, 0x4d, 0xfd, 0x42, 0x70, 0xb6, 0xff, 0xe0, 0x11, 0x18, 0x9d, 0x3c, 0x7c, 0xb9, 0xe5, 0x28, 0x30, 0xb2, 0xc2, 0x56, 0xd7, 0x4e, 0x6e, 0x1a}}, + {{0x45, 0x86, 0xa1, 0x7c, 0x8e, 0x35, 0x28, 0x08, 0x41, 0xfc, 0x31, 0xc8, 0xd0, 0x04, 0x14, 0x4e, 0xb9, 0x82, 0xed, 0x1d, 0xef, 0x42, 0xd9, 0xa2, 0xc9, 0x41, 0xe6, 0x33, 0x78, 0x99, 0xb8, 0x2f}, {0x51, 0xe3, 0x22, 0x12, 0x3b, 0x88, 0xa1, 0x1f, 0x98, 0x29, 0x5c, 0xa6, 0x72, 0xe6, 0x92, 0x8a, 0xac, 0x66, 0xe3, 0x0c, 0xae, 0x70, 0x95, 0x2c, 0x79, 0x8f, 0x94, 0x2f, 0x30, 0xc4, 0x82, 0x21}}, + {{0x55, 0x44, 0x9c, 0x90, 0x20, 0x14, 0x37, 0x71, 0x95, 0x48, 0xff, 0xe5, 0xfa, 0x72, 0xa8, 0x79, 0x60, 0x2d, 0x9d, 0x25, 0x11, 0x8a, 0xc5, 0x64, 0x0b, 0x9d, 0x40, 0x2c, 0x3f, 0x24, 0x4a, 0x1b}, {0xcf, 0x77, 0x5c, 0x3e, 0x7b, 0x09, 0xb7, 0x24, 0xc1, 0xd3, 0x2c, 0x8a, 0xe4, 0xbb, 0x3c, 0x10, 0xc1, 0x0a, 0x2b, 0xbd, 0x35, 0xff, 0x53, 0xfb, 0xc3, 0x93, 0x2f, 0xda, 0x5c, 0x07, 0x20, 0x35}}, + {{0x2b, 0x19, 0x11, 0x73, 0x1e, 0xd6, 0x0f, 0xf7, 0xbb, 0x66, 0x78, 0x1f, 0x58, 0x66, 0x3f, 0x66, 0xc2, 0x76, 0x99, 0x60, 0xf3, 0xdc, 0x23, 0xb2, 0x66, 0xb1, 0x28, 0xc6, 0xd3, 0xce, 0xc3, 0x22}, {0xea, 0x71, 0x56, 0x46, 0x5b, 0xe1, 0x90, 0xc3, 0x5b, 0xd8, 0xc7, 0x12, 0x74, 0x7a, 0x9c, 0x83, 0xc2, 0xf2, 0x8d, 0x47, 0x65, 0xc1, 0xab, 0x9e, 0x51, 0xb9, 0x9f, 0x27, 0x5e, 0x24, 0x26, 0x04}}, + {{0x6a, 0xa1, 0xac, 0x08, 0x7b, 0x58, 0x2e, 0xf3, 0xd6, 0x18, 0xd1, 0xa0, 0x54, 0x09, 0x0f, 0xef, 0x1b, 0x71, 0x93, 0x0f, 0x0e, 0x0d, 0x3a, 0x66, 0x86, 0x15, 0xc2, 0x09, 0x89, 0xd9, 0xa9, 0x3b}, {0x9b, 0xf3, 0xfa, 0x78, 0x69, 0xfe, 0xb0, 0x67, 0x17, 0x88, 0x17, 0x5d, 0x97, 0x7c, 0x65, 0x43, 0x91, 0xd3, 0x26, 0x9a, 0x54, 0x39, 0x34, 0x36, 0x1d, 0xd6, 0x05, 0x3c, 0xa5, 0x61, 0x12, 0x29}}, + {{0x35, 0x49, 0xd9, 0x16, 0xdc, 0xf8, 0x13, 0xb2, 0xd8, 0xb3, 0x3f, 0x8b, 0xb9, 0x5b, 0x08, 0x6c, 0xcb, 0x61, 0x23, 0xa3, 0x12, 0x77, 0x8e, 0x3c, 0xbf, 0x8d, 0x91, 0x96, 0x28, 0x53, 0x86, 0x11}, {0x61, 0x04, 0x95, 0xc3, 0x6f, 0x6a, 0x0f, 0xdd, 0x9a, 0x8b, 0x0a, 0xf3, 0xec, 0xcd, 0x2e, 0x40, 0x82, 0x9c, 0x3d, 0x4a, 0x42, 0x54, 0xc0, 0x63, 0x34, 0x47, 0x01, 0xe6, 0xb0, 0x87, 0x3b, 0x1e}}, + {{0xaa, 0xf8, 0x25, 0x3f, 0x22, 0xfe, 0xbf, 0xd2, 0x9a, 0x89, 0xe3, 0x88, 0xd2, 0xda, 0x13, 0x3d, 0x96, 0x17, 0x47, 0x10, 0x2b, 0x04, 0x0c, 0xe4, 0xa4, 0xb7, 0xb9, 0xb2, 0x5f, 0x35, 0xef, 0x20}, {0xb7, 0x4e, 0xa4, 0x05, 0x90, 0xfc, 0x84, 0x25, 0x5e, 0x28, 0x60, 0xe8, 0xaa, 0x0f, 0x3d, 0xc7, 0xf6, 0x93, 0xce, 0x9d, 0xb5, 0xe4, 0xa9, 0xa3, 0xfa, 0x73, 0x67, 0x5a, 0x64, 0x47, 0x02, 0x10}}, + {{0x9d, 0xee, 0x5f, 0xf0, 0xef, 0xd4, 0x4d, 0xb4, 0x04, 0xaf, 0xc3, 0x57, 0x5e, 0xe3, 0x11, 0xd3, 0xe0, 0xac, 0x35, 0xdf, 0x48, 0xe7, 0xfa, 0x6a, 0x05, 0xaf, 0x5c, 0xed, 0xbf, 0x47, 0x52, 0x28}, {0x59, 0x59, 0x09, 0x04, 0xc4, 0xbb, 0xe1, 0x67, 0x06, 0xc6, 0xce, 0xf1, 0x3c, 0x02, 0x64, 0x10, 0x2c, 0x8d, 0x55, 0x77, 0x93, 0x7b, 0xea, 0x12, 0xa4, 0x0d, 0xca, 0xa6, 0x5a, 0x9d, 0xe6, 0x14}}, + {{0x58, 0xbf, 0xcc, 0x41, 0xa1, 0x64, 0xad, 0x3d, 0x96, 0x6d, 0xbb, 0xe1, 0x95, 0xcc, 0x45, 0xcd, 0x44, 0x9f, 0x68, 0xc1, 0x71, 0x10, 0x71, 0x4f, 0x2c, 0x60, 0xad, 0x35, 0xce, 0x27, 0x42, 0x0f}, {0x5c, 0xf6, 0x2a, 0xe7, 0x24, 0x05, 0xef, 0x54, 0xbc, 0xdf, 0x2e, 0x43, 0x83, 0x4d, 0xaf, 0x7b, 0x17, 0x99, 0xeb, 0xb7, 0xfb, 0x4b, 0x79, 0x34, 0x5e, 0x3f, 0x75, 0xbc, 0xf2, 0x5f, 0xad, 0x1b}}, + {{0xa0, 0xe4, 0xb4, 0x6e, 0x23, 0x63, 0xdf, 0x17, 0x73, 0xb9, 0x80, 0xc2, 0x58, 0x1e, 0x9a, 0xec, 0x17, 0xe2, 0xab, 0x12, 0xad, 0x46, 0x8d, 0x5a, 0xa4, 0x79, 0x1f, 0x4b, 0xcc, 0x2e, 0x22, 0x02}, {0xc3, 0xcf, 0x7e, 0x62, 0x6b, 0xc2, 0xc6, 0x8d, 0xac, 0xfe, 0x57, 0x8c, 0x92, 0x34, 0xd4, 0xca, 0x1e, 0x76, 0x01, 0xf2, 0x7f, 0xc5, 0x7e, 0x4c, 0x9f, 0xa0, 0xec, 0xeb, 0xc9, 0x19, 0x7a, 0x1a}}, + {{0x8f, 0x3e, 0xf4, 0xde, 0x3a, 0xd3, 0xdd, 0xfb, 0x0a, 0xe3, 0x0f, 0x0b, 0x5d, 0x1c, 0x50, 0xd6, 0x1b, 0xef, 0xc8, 0xc4, 0x34, 0xfd, 0xd5, 0x6f, 0x4e, 0x3a, 0xb3, 0xc8, 0xbe, 0x4f, 0x7e, 0x33}, {0xb1, 0x6f, 0x98, 0x7c, 0x11, 0x53, 0x9a, 0xfe, 0x9c, 0x89, 0x12, 0xd1, 0xee, 0xd9, 0xfe, 0x90, 0x14, 0x88, 0x71, 0xc1, 0xdb, 0x19, 0x35, 0xa9, 0x32, 0xf1, 0x42, 0x2e, 0x59, 0xd8, 0x32, 0x1a}}, + {{0x4c, 0xab, 0x95, 0xd5, 0x0e, 0x57, 0x1f, 0xbd, 0xeb, 0xbc, 0x17, 0xdc, 0x9e, 0x06, 0x11, 0x2e, 0xe8, 0x93, 0xd2, 0x02, 0xf5, 0x4e, 0x63, 0x5c, 0xc5, 0x53, 0x7b, 0x9d, 0x9d, 0x94, 0xe4, 0x3b}, {0xac, 0x0e, 0xc0, 0x6c, 0x6a, 0x45, 0x87, 0xf0, 0xeb, 0xed, 0xb7, 0x73, 0x24, 0x67, 0x8e, 0xb6, 0x99, 0x9a, 0x91, 0x83, 0x52, 0xe5, 0x48, 0x95, 0xd6, 0xb5, 0xae, 0x04, 0x1f, 0x0f, 0x07, 0x01}}, + {{0x17, 0x6e, 0x62, 0x32, 0xea, 0x9a, 0x3a, 0x49, 0x69, 0xe9, 0xb2, 0x74, 0x15, 0x4c, 0x8e, 0x7b, 0x98, 0xca, 0xf2, 0xb5, 0xb6, 0x61, 0x53, 0x80, 0xa3, 0x79, 0x92, 0x17, 0x01, 0xc5, 0xd7, 0x39}, {0xe9, 0xf2, 0xdc, 0x43, 0x19, 0x5c, 0xd3, 0x53, 0x60, 0x32, 0xbf, 0x47, 0x4f, 0x60, 0x13, 0xba, 0x6a, 0x59, 0x46, 0x4d, 0xe7, 0xb8, 0x24, 0x83, 0xeb, 0x45, 0xd8, 0xb7, 0xdb, 0x9b, 0x82, 0x18}}, + {{0xe8, 0xe9, 0x83, 0xf1, 0x51, 0x0a, 0x27, 0x0d, 0x03, 0x8f, 0x66, 0x30, 0xf9, 0xa7, 0x76, 0xd2, 0xe9, 0x88, 0x5d, 0x9e, 0xb5, 0x97, 0x8d, 0xd4, 0xe1, 0x44, 0xa1, 0x45, 0x90, 0xee, 0x8a, 0x0e}, {0x40, 0xbb, 0xa0, 0x3f, 0x9f, 0x4a, 0x18, 0x28, 0x64, 0xaf, 0x50, 0x04, 0xd0, 0xac, 0x0f, 0x71, 0x9f, 0x6e, 0x74, 0x19, 0xdf, 0x4b, 0x0f, 0x90, 0xd4, 0x76, 0x15, 0x21, 0xa3, 0x2d, 0xa4, 0x27}}, + {{0x8d, 0x66, 0xdc, 0x37, 0x40, 0xcf, 0x89, 0xb6, 0x28, 0xc4, 0x2d, 0x14, 0x01, 0x0a, 0x77, 0x93, 0xfd, 0x08, 0x78, 0xc8, 0xc4, 0xea, 0x34, 0x31, 0xed, 0x68, 0x65, 0x80, 0x61, 0x90, 0xfc, 0x3a}, {0xb6, 0x57, 0xad, 0x3f, 0x3d, 0x7d, 0xc7, 0x60, 0xb3, 0x59, 0xaa, 0x34, 0xbc, 0x9e, 0xf4, 0x59, 0x84, 0x73, 0x0a, 0x0c, 0x09, 0xd0, 0x63, 0x9d, 0xce, 0x61, 0x86, 0xbc, 0x58, 0xc3, 0x59, 0x25}}, + {{0xb4, 0x79, 0x5c, 0x14, 0x92, 0x56, 0x09, 0x5c, 0xb4, 0xb0, 0xbd, 0x49, 0x5f, 0xbb, 0x8b, 0xda, 0xd7, 0x9d, 0xbf, 0x9d, 0x94, 0x2c, 0x35, 0x41, 0x78, 0x81, 0x74, 0x9e, 0x79, 0xdc, 0x53, 0x04}, {0x39, 0x95, 0xc7, 0x07, 0x05, 0x9f, 0x01, 0xda, 0x32, 0x6d, 0xef, 0x2a, 0xd5, 0x45, 0x39, 0xe6, 0xe2, 0x39, 0x43, 0x49, 0xc6, 0x4e, 0x19, 0x41, 0x44, 0xfd, 0x81, 0xbe, 0x55, 0xef, 0xa2, 0x2e}}, + {{0x92, 0xf8, 0xbe, 0x04, 0xa9, 0x4f, 0x9f, 0xf4, 0xfb, 0x3f, 0x00, 0x37, 0x8b, 0x97, 0xdc, 0x62, 0xa6, 0x44, 0x63, 0x42, 0x25, 0xe6, 0x02, 0x67, 0xfc, 0x7e, 0x8e, 0xdc, 0x2c, 0xe1, 0x3b, 0x3b}, {0x90, 0x10, 0xe4, 0x93, 0x7f, 0xe6, 0xbd, 0x10, 0x1e, 0x99, 0xb0, 0xec, 0x1e, 0xa1, 0xcc, 0x8c, 0x00, 0xe4, 0x8a, 0xeb, 0xf0, 0x72, 0xdd, 0x50, 0xad, 0x8a, 0x87, 0xa7, 0x56, 0xdb, 0x3c, 0x3f}}, + {{0x30, 0xb4, 0xf4, 0x55, 0xa6, 0x53, 0x0a, 0xff, 0x6b, 0x8e, 0x1c, 0x84, 0xa2, 0x41, 0xbe, 0x0f, 0xda, 0x24, 0x34, 0x55, 0x49, 0x62, 0x4a, 0xe4, 0xf3, 0xe4, 0xd9, 0xcf, 0x83, 0xd1, 0x16, 0x3d}, {0x0d, 0x01, 0x12, 0x4a, 0x47, 0x7a, 0x73, 0xf1, 0x0c, 0x01, 0xe3, 0x5a, 0x20, 0x2a, 0x86, 0x33, 0xb2, 0x6e, 0xc9, 0x7c, 0x8c, 0xac, 0x75, 0x94, 0x7e, 0x78, 0xe3, 0x92, 0xba, 0xed, 0x5e, 0x2d}}, + {{0xc8, 0x8b, 0xb6, 0x3a, 0xcc, 0xbd, 0x32, 0xec, 0xa8, 0x6b, 0x05, 0x82, 0x8d, 0xc6, 0xf1, 0x5e, 0x0a, 0x23, 0x0f, 0x76, 0xb1, 0xc6, 0x79, 0x2a, 0x02, 0xac, 0x42, 0x48, 0x07, 0xc0, 0x69, 0x02}, {0xd7, 0x0d, 0xf7, 0xac, 0x73, 0x6a, 0xa5, 0xde, 0x2c, 0xd3, 0x05, 0xd6, 0xfd, 0x24, 0xae, 0xef, 0x8f, 0x8a, 0x72, 0x5a, 0x79, 0x01, 0x44, 0x76, 0x0d, 0xcf, 0x3b, 0xee, 0x35, 0x59, 0xbf, 0x29}}, + {{0xe0, 0x57, 0x28, 0xd9, 0xa4, 0xfc, 0xec, 0xaf, 0x2a, 0x46, 0x8d, 0x2d, 0x25, 0x4a, 0xef, 0xa2, 0x08, 0x8c, 0x1f, 0x7b, 0xd2, 0x1c, 0x9c, 0x3f, 0x4e, 0xe7, 0x86, 0xae, 0x65, 0xe8, 0x06, 0x3f}, {0xce, 0x5c, 0x2a, 0x54, 0xc6, 0x60, 0xca, 0x2b, 0x45, 0x1f, 0xf9, 0xdd, 0xca, 0xa0, 0x17, 0x20, 0xcf, 0xb9, 0x03, 0xf1, 0x4f, 0x6a, 0xe1, 0x9e, 0x2a, 0xdd, 0x80, 0x45, 0xec, 0x5b, 0x95, 0x37}}, + {{0xc6, 0xed, 0xcf, 0xc1, 0xb4, 0xe4, 0x91, 0x86, 0x13, 0xfd, 0x20, 0x81, 0x8c, 0x46, 0xf6, 0xb4, 0x89, 0xdc, 0x26, 0xb8, 0x17, 0x75, 0xb1, 0x05, 0x0c, 0x71, 0xef, 0x3c, 0x68, 0x35, 0x61, 0x0c}, {0x59, 0x1c, 0xe2, 0x6b, 0x5f, 0x02, 0x19, 0xb1, 0xda, 0x34, 0x1a, 0xcc, 0xd4, 0xc8, 0x0e, 0xe6, 0xff, 0x34, 0x7a, 0xbd, 0xf8, 0xa8, 0xba, 0x61, 0xba, 0xd3, 0x33, 0xa4, 0x98, 0x2a, 0x27, 0x1c}}, + {{0xc4, 0x53, 0x9b, 0x22, 0x6e, 0x8f, 0x75, 0xc7, 0x4f, 0x83, 0xd4, 0x1f, 0xe3, 0x14, 0x87, 0x81, 0xf4, 0xb1, 0x92, 0x52, 0x14, 0x1c, 0x72, 0x9b, 0xa0, 0x69, 0x85, 0xfd, 0x5e, 0x63, 0xd0, 0x2a}, {0x3e, 0xd8, 0x19, 0xa1, 0xe7, 0xb6, 0x9a, 0x35, 0xf0, 0x1e, 0x64, 0x1f, 0x63, 0xfc, 0x8f, 0x59, 0xfd, 0x20, 0x92, 0x77, 0x2b, 0x4b, 0x4e, 0x44, 0x79, 0x92, 0xc9, 0xe7, 0x58, 0x52, 0xdf, 0x03}}, + {{0x2e, 0x5e, 0x30, 0xbe, 0x61, 0x52, 0x34, 0x91, 0x74, 0x28, 0x7a, 0xa3, 0x1d, 0xa1, 0xd4, 0xe6, 0xec, 0xe7, 0x44, 0xb3, 0x1f, 0x28, 0x1c, 0xba, 0xb5, 0x88, 0xda, 0x58, 0xd7, 0xd9, 0x0d, 0x16}, {0x6a, 0x56, 0xfe, 0xbb, 0x8f, 0x8f, 0xde, 0xda, 0x5f, 0xf3, 0x23, 0x54, 0x26, 0x65, 0x00, 0x20, 0xa5, 0x22, 0xa6, 0x71, 0xf2, 0x01, 0x19, 0x0f, 0x20, 0x23, 0xcb, 0xfe, 0x3a, 0x50, 0xa0, 0x32}}, + {{0xba, 0x55, 0x17, 0x12, 0x97, 0x59, 0x83, 0x06, 0x1b, 0x2e, 0x30, 0x87, 0xd0, 0xc9, 0x57, 0x2a, 0x76, 0xd0, 0xdc, 0x3f, 0x7b, 0xc5, 0x07, 0x8f, 0xb5, 0x13, 0x11, 0xec, 0xaf, 0xb2, 0x49, 0x08}, {0x2d, 0x88, 0x27, 0x9c, 0x61, 0x53, 0xd6, 0x13, 0x93, 0x5d, 0x0f, 0xa6, 0x8a, 0x02, 0xd9, 0x84, 0xf2, 0x62, 0xfa, 0x33, 0x7b, 0x43, 0xee, 0xf1, 0x1d, 0x97, 0xdb, 0x3f, 0xe4, 0x0d, 0x6f, 0x0c}}, + {{0x67, 0xef, 0x93, 0x97, 0x04, 0x44, 0x23, 0x6e, 0x41, 0x3c, 0x92, 0x4c, 0xe5, 0x90, 0xd5, 0x7c, 0xfe, 0x45, 0x11, 0x16, 0xd1, 0x0e, 0xdc, 0x27, 0xb1, 0xc9, 0xb4, 0xcf, 0xf4, 0x4e, 0xe0, 0x1c}, {0x67, 0xd3, 0xcf, 0xdd, 0x8f, 0x9f, 0x5b, 0xfd, 0xc2, 0xc9, 0x79, 0x93, 0xbd, 0xc6, 0x5d, 0x6a, 0xb8, 0x63, 0x7b, 0x52, 0xce, 0x9e, 0x97, 0xc2, 0x72, 0x2a, 0x0f, 0x58, 0x3d, 0x87, 0x3d, 0x32}}, + {{0x89, 0x7a, 0x1d, 0xc3, 0xc7, 0x82, 0xf9, 0x44, 0xb5, 0x60, 0x8d, 0x17, 0x59, 0xe8, 0x46, 0x98, 0xac, 0x70, 0xd6, 0x85, 0x97, 0x51, 0x0a, 0xa5, 0xb7, 0x56, 0x38, 0x91, 0x11, 0x87, 0x77, 0x07}, {0x4c, 0x05, 0x40, 0x70, 0x93, 0x50, 0xa1, 0x8f, 0x94, 0xb3, 0xa8, 0x84, 0xe4, 0x8d, 0xaf, 0xe0, 0x1d, 0x26, 0x8f, 0x46, 0x7f, 0xfa, 0xd9, 0x6e, 0x8a, 0x04, 0x70, 0x2f, 0x4c, 0x8f, 0xe0, 0x26}}, + {{0x15, 0x9b, 0x41, 0xbf, 0x6a, 0x36, 0x10, 0x16, 0xcf, 0x49, 0x04, 0xf5, 0xa5, 0x33, 0x95, 0x54, 0x94, 0x74, 0xb9, 0x34, 0x86, 0x74, 0x03, 0xff, 0x23, 0x6a, 0x09, 0xe5, 0x83, 0xde, 0xcd, 0x2c}, {0xb2, 0xd7, 0xfe, 0x1f, 0x25, 0xc7, 0x24, 0x97, 0xa7, 0xbb, 0xb7, 0xb3, 0xd1, 0xa2, 0x4a, 0x01, 0xb9, 0x03, 0xbd, 0x01, 0xab, 0xd6, 0x28, 0xed, 0xfd, 0x37, 0xc8, 0x3c, 0x55, 0x9a, 0xd8, 0x04}}, + {{0x3d, 0xce, 0xcb, 0xa8, 0xc7, 0x2d, 0x53, 0x50, 0x93, 0x6c, 0x79, 0x89, 0x1a, 0x68, 0x32, 0x93, 0x9f, 0x95, 0xaa, 0xe7, 0x55, 0xf3, 0x1c, 0x1b, 0x8b, 0xec, 0x97, 0x98, 0x61, 0xc4, 0x04, 0x0b}, {0x03, 0x60, 0xc2, 0xea, 0x15, 0x98, 0xc0, 0x91, 0x05, 0x8f, 0x52, 0x8b, 0x5a, 0xc9, 0x44, 0xdf, 0xc5, 0x96, 0xa2, 0x32, 0xb9, 0x53, 0x9d, 0xfb, 0x81, 0x94, 0x4d, 0x51, 0xc0, 0xa7, 0xf7, 0x05}}, + {{0xaa, 0xc3, 0x6a, 0xf3, 0xbd, 0x2e, 0xe8, 0xe9, 0xc6, 0x84, 0xe3, 0xdd, 0xba, 0x3a, 0x3c, 0xd6, 0xd2, 0x57, 0xd5, 0xbb, 0x94, 0x47, 0x65, 0xa0, 0xb4, 0x6b, 0xeb, 0xb8, 0xe3, 0x74, 0xf1, 0x2a}, {0x1c, 0xbc, 0x1c, 0xb6, 0x28, 0xec, 0xb7, 0xc1, 0xa5, 0xad, 0x44, 0x3b, 0xd9, 0x1f, 0xdf, 0xa6, 0xe1, 0x40, 0xb7, 0x54, 0xbd, 0x1f, 0xb4, 0x41, 0xae, 0xd6, 0x00, 0x62, 0xb5, 0xb7, 0xb6, 0x07}}, + {{0x25, 0x7c, 0x0c, 0xc6, 0xb1, 0x14, 0x09, 0xf8, 0xbb, 0x0b, 0xd2, 0xd9, 0x7a, 0x9d, 0x6e, 0xc9, 0x90, 0x60, 0x5a, 0x06, 0xb6, 0x14, 0xf1, 0x9b, 0x1c, 0x63, 0x99, 0x39, 0x75, 0xc0, 0xf3, 0x07}, {0x71, 0xfe, 0xfb, 0x41, 0x70, 0xa9, 0x84, 0x6d, 0xed, 0x6a, 0x32, 0x48, 0xcc, 0xf8, 0x67, 0x73, 0x0d, 0x98, 0x98, 0xb9, 0x9a, 0xb0, 0xa4, 0x9f, 0x9b, 0x9d, 0x81, 0x40, 0xf4, 0x51, 0xb5, 0x10}}, + {{0xeb, 0x06, 0x88, 0x84, 0x1f, 0x21, 0xb2, 0x13, 0x3f, 0xa9, 0xbd, 0x68, 0xe5, 0xa8, 0x61, 0x87, 0xdb, 0xbe, 0xc7, 0xb2, 0xb0, 0x18, 0x79, 0xfe, 0xe6, 0x66, 0xfa, 0xe7, 0x28, 0x94, 0xb8, 0x0e}, {0x0f, 0x02, 0xdd, 0x74, 0xd1, 0x5c, 0xae, 0xa4, 0xd5, 0xeb, 0xbc, 0xd7, 0x83, 0x74, 0x36, 0x0a, 0x9f, 0xb4, 0x89, 0xa5, 0x79, 0xe4, 0xee, 0x02, 0x02, 0x3d, 0x03, 0xf7, 0x3f, 0x44, 0x1f, 0x38}}, + {{0x6c, 0xab, 0xea, 0x65, 0x99, 0x72, 0xe9, 0xbf, 0x3e, 0x22, 0x96, 0xd1, 0x43, 0xc6, 0xd7, 0x91, 0xe2, 0x0e, 0xba, 0x2f, 0xe0, 0x1e, 0xc4, 0xc1, 0x11, 0x92, 0xd5, 0xee, 0x82, 0xa5, 0x91, 0x03}, {0x0a, 0x87, 0xbe, 0x5f, 0x50, 0xac, 0xf5, 0xf6, 0xb7, 0x10, 0xa9, 0xa3, 0x4f, 0xce, 0x32, 0x45, 0xfc, 0xed, 0x6f, 0x07, 0xdc, 0x95, 0x04, 0x2e, 0x8e, 0xc7, 0x70, 0xb0, 0x99, 0x68, 0x66, 0x25}}, + {{0x99, 0x46, 0x3a, 0xf7, 0xf8, 0x31, 0xd3, 0x59, 0x84, 0xec, 0x3e, 0x6b, 0x33, 0xa1, 0x9e, 0xb8, 0xda, 0x95, 0x8f, 0xe6, 0x92, 0x85, 0xbb, 0x67, 0xfc, 0xfa, 0xed, 0x03, 0x6e, 0x43, 0x17, 0x09}, {0x7e, 0x6f, 0x68, 0x77, 0x3f, 0xc1, 0x28, 0x27, 0xeb, 0xf8, 0x2a, 0xf4, 0xe8, 0xd6, 0x15, 0x26, 0x26, 0x57, 0xfb, 0x1f, 0x77, 0xdf, 0xc5, 0x5c, 0x97, 0xb4, 0x2d, 0x91, 0x9f, 0xeb, 0xa0, 0x00}}, + {{0xde, 0x61, 0xc1, 0x5f, 0xf7, 0x12, 0xa5, 0x45, 0x54, 0x55, 0x96, 0x3c, 0x44, 0xe3, 0xc6, 0x0f, 0xd0, 0xeb, 0x55, 0x21, 0xc5, 0x37, 0xea, 0x4f, 0x91, 0xe8, 0x9f, 0x59, 0xac, 0xcf, 0xc2, 0x07}, {0xbb, 0x02, 0x0c, 0x3c, 0x5d, 0x93, 0x2a, 0xd3, 0x9c, 0x5e, 0x2b, 0x43, 0x68, 0x1e, 0x63, 0x62, 0x93, 0xb3, 0x3d, 0x1f, 0xd2, 0xbe, 0x2c, 0x07, 0x16, 0x4b, 0xdc, 0x83, 0x49, 0xe7, 0xed, 0x28}}, + {{0xee, 0xba, 0xa8, 0x8d, 0x39, 0x48, 0xde, 0x06, 0xe0, 0xf4, 0x93, 0x02, 0xa7, 0x20, 0xcc, 0x68, 0x54, 0x76, 0x77, 0x24, 0xe2, 0xa9, 0x3f, 0xde, 0xb5, 0xbe, 0x6a, 0x17, 0x54, 0xfa, 0xd6, 0x3f}, {0x99, 0x97, 0xa7, 0xe5, 0x9f, 0xf5, 0x53, 0x53, 0x6d, 0xd4, 0x3b, 0xf8, 0x05, 0x1d, 0x82, 0x17, 0xc3, 0x5f, 0x5e, 0xa0, 0x8d, 0x07, 0x6d, 0x42, 0xe7, 0xd6, 0x43, 0x74, 0x06, 0xe8, 0x8e, 0x27}}, + {{0x63, 0x3f, 0x29, 0x83, 0xcb, 0x01, 0x62, 0xc0, 0xa8, 0x5c, 0xc3, 0xe6, 0x03, 0xbb, 0x12, 0x26, 0xb2, 0xb2, 0x5f, 0x48, 0xc9, 0xe8, 0xf4, 0x6c, 0x9e, 0xd8, 0x70, 0x35, 0x99, 0x2e, 0xf7, 0x1d}, {0xa7, 0x70, 0x6d, 0x1b, 0xc2, 0xd3, 0xa4, 0x78, 0x69, 0x2f, 0xc1, 0xb0, 0x2f, 0xc8, 0xd8, 0x14, 0xe3, 0x4a, 0x88, 0x49, 0xaa, 0x2d, 0x78, 0xf6, 0x4f, 0xfd, 0x12, 0xdf, 0xf4, 0xee, 0xd2, 0x35}}, + {{0xed, 0x19, 0xb0, 0x23, 0xcc, 0xfd, 0xae, 0xb4, 0x99, 0x99, 0x89, 0xc1, 0xb7, 0xa1, 0x89, 0xac, 0x2d, 0x0a, 0x7a, 0x4f, 0x65, 0x81, 0x5b, 0x3c, 0x3f, 0x1d, 0x65, 0x17, 0x69, 0x7d, 0xb3, 0x0a}, {0x10, 0x7b, 0x3d, 0xd0, 0x49, 0xf5, 0x30, 0xa1, 0xc7, 0xb8, 0x76, 0xaf, 0xa5, 0xfb, 0x3e, 0xfe, 0x68, 0x4d, 0x15, 0xd5, 0x92, 0xb2, 0x9c, 0x47, 0x37, 0x57, 0xd1, 0x7c, 0x27, 0xb1, 0xed, 0x08}}, + {{0x66, 0x9e, 0xd1, 0x4a, 0x81, 0x35, 0x50, 0x72, 0xc1, 0x09, 0xa2, 0x94, 0x01, 0x6a, 0xad, 0x9f, 0x13, 0x1a, 0x38, 0x01, 0x3f, 0x3f, 0x98, 0xea, 0x5b, 0x88, 0x1f, 0x78, 0x7c, 0xe9, 0xb3, 0x17}, {0xdf, 0xb6, 0x5d, 0x52, 0xed, 0x12, 0x1a, 0x87, 0xd7, 0xa3, 0x09, 0x59, 0xb0, 0x9d, 0xc2, 0xad, 0xce, 0xda, 0xcc, 0x70, 0x73, 0xdf, 0x07, 0x98, 0x04, 0x18, 0xe8, 0x16, 0xe8, 0xcb, 0xcc, 0x31}}, + {{0x1a, 0x30, 0x16, 0x85, 0xa3, 0xc7, 0xb6, 0x42, 0xec, 0x3f, 0xaa, 0x58, 0x4d, 0x54, 0x85, 0x64, 0x01, 0x2a, 0x25, 0x0c, 0xa4, 0x5c, 0x05, 0xe1, 0x85, 0x68, 0xe8, 0xad, 0xc5, 0xac, 0xed, 0x3c}, {0x0c, 0xc2, 0x63, 0xe5, 0xcc, 0xed, 0xe5, 0x4d, 0xea, 0x36, 0x36, 0x6a, 0xb7, 0x53, 0x79, 0x08, 0xa3, 0xa3, 0xca, 0xe6, 0x9c, 0xcf, 0xda, 0x1e, 0xb1, 0xb3, 0x98, 0x41, 0x15, 0xb4, 0x82, 0x3f}}, + {{0x58, 0x76, 0xf5, 0x15, 0x03, 0x61, 0x81, 0x27, 0x82, 0xa5, 0x1d, 0xa5, 0x79, 0xb7, 0xc0, 0xfc, 0xd7, 0xe1, 0xf2, 0x92, 0xf3, 0xbf, 0xdf, 0x99, 0x01, 0xae, 0x4d, 0xa8, 0x1e, 0x2f, 0x09, 0x1e}, {0x80, 0x20, 0xa2, 0x8e, 0xc5, 0x2b, 0x6f, 0x1e, 0x75, 0x5f, 0x99, 0x03, 0x5d, 0xb1, 0xd9, 0x8e, 0xaf, 0x20, 0x0e, 0x91, 0xa9, 0xeb, 0x7a, 0x72, 0xb1, 0xcb, 0x5a, 0x92, 0x55, 0xdc, 0xc6, 0x38}}, + {{0x47, 0x27, 0x22, 0xdb, 0x05, 0xbc, 0xfc, 0x91, 0x2c, 0x0c, 0x6b, 0x33, 0xc1, 0x36, 0xbc, 0x25, 0x63, 0x52, 0xfe, 0xdc, 0x49, 0xc9, 0xf4, 0x4d, 0x5a, 0xbe, 0x90, 0xec, 0x5b, 0x78, 0xec, 0x2e}, {0x65, 0x5b, 0xb1, 0xc1, 0x93, 0xfc, 0x7e, 0x4d, 0x6b, 0x98, 0xdc, 0x0f, 0xcc, 0xfa, 0xef, 0x2d, 0x4d, 0xa7, 0xa3, 0xca, 0xef, 0x98, 0x50, 0x12, 0xc1, 0x41, 0x83, 0x59, 0xfe, 0x77, 0x24, 0x06}}, + {{0xea, 0xe3, 0xd5, 0x55, 0x66, 0x7e, 0x3d, 0xb6, 0x87, 0xcc, 0x65, 0x61, 0xcb, 0xb4, 0x16, 0xfb, 0x90, 0x16, 0xe2, 0x6a, 0x4d, 0x6c, 0xd2, 0x36, 0x9d, 0x44, 0xf8, 0x81, 0x6c, 0xc7, 0x6a, 0x16}, {0x2b, 0x5c, 0x88, 0x93, 0x68, 0x39, 0xe2, 0x82, 0x30, 0x6a, 0xdf, 0x85, 0x98, 0x9d, 0x87, 0x1b, 0x04, 0xce, 0xad, 0x69, 0x6d, 0x15, 0x07, 0x54, 0xfa, 0xfa, 0xcc, 0xe5, 0x2d, 0xbd, 0x06, 0x09}}, + {{0x23, 0x78, 0x96, 0x97, 0x41, 0xcc, 0x7c, 0x73, 0x97, 0xec, 0x6f, 0x1f, 0xe0, 0x28, 0x07, 0x10, 0x24, 0x2d, 0x9e, 0xba, 0xd3, 0x08, 0x9b, 0xfc, 0x65, 0xc9, 0x40, 0x29, 0xe5, 0xaa, 0xf5, 0x06}, {0xbe, 0x43, 0x85, 0x28, 0xcd, 0x62, 0xf1, 0x28, 0x65, 0x38, 0xad, 0xfc, 0x0d, 0x68, 0x9e, 0x3f, 0xce, 0x13, 0xb3, 0x76, 0x21, 0x03, 0x61, 0x86, 0x2f, 0x37, 0xb9, 0xab, 0xcd, 0xd4, 0xbd, 0x14}}, + {{0xdf, 0x4e, 0x4e, 0xe7, 0xd7, 0xb3, 0x25, 0x6c, 0x39, 0x04, 0xad, 0x2e, 0x65, 0xae, 0xfb, 0x67, 0x51, 0x8a, 0x0b, 0xbf, 0x37, 0x08, 0x82, 0xc1, 0x84, 0x7d, 0xf3, 0x4d, 0x19, 0xce, 0xc9, 0x3b}, {0xb8, 0x40, 0xde, 0x98, 0x74, 0x2e, 0x05, 0x6a, 0xc7, 0x7f, 0x6d, 0x4c, 0x73, 0xa0, 0x78, 0xca, 0x62, 0xec, 0x69, 0x74, 0x26, 0xa1, 0x0a, 0x5a, 0xed, 0xc7, 0x0f, 0x85, 0x1c, 0x85, 0x17, 0x2f}}, + {{0x0d, 0xfc, 0x91, 0xfd, 0x3a, 0xc0, 0x17, 0x33, 0x3c, 0xa9, 0xa8, 0xfe, 0xcf, 0x9e, 0x0d, 0x38, 0x6e, 0xb8, 0x9f, 0x3a, 0xbc, 0xe1, 0xcd, 0x7e, 0xe3, 0xaf, 0xa4, 0x98, 0x7b, 0x3f, 0x70, 0x17}, {0xc7, 0xf2, 0xa0, 0xc9, 0x20, 0x50, 0x4b, 0xc5, 0x8c, 0xc9, 0xef, 0xad, 0xc3, 0x05, 0x6b, 0xc6, 0x10, 0x7d, 0x47, 0x8e, 0xae, 0xa7, 0x8d, 0xf3, 0xf5, 0xef, 0x1b, 0x9c, 0x9a, 0x0c, 0x84, 0x37}}, + {{0x1e, 0x82, 0x39, 0xa7, 0xfe, 0x7e, 0x93, 0x50, 0x6e, 0x10, 0xa1, 0xfa, 0xa2, 0x6c, 0xf8, 0x7f, 0xf1, 0x2c, 0x9d, 0x7e, 0x4b, 0x97, 0x2a, 0x25, 0x10, 0xb0, 0x2b, 0xd6, 0x9c, 0xd1, 0x69, 0x1b}, {0x4e, 0x84, 0xa2, 0x12, 0x7f, 0x5a, 0x6f, 0xc1, 0x14, 0x57, 0xad, 0x8e, 0xbb, 0xd0, 0x53, 0xae, 0x67, 0x4f, 0x66, 0x66, 0xf5, 0x0a, 0xc7, 0xa3, 0x76, 0x12, 0x51, 0x93, 0x8a, 0xb9, 0xcb, 0x3e}}, + {{0xe9, 0xf0, 0x48, 0xe8, 0x53, 0x48, 0xc5, 0xbd, 0x85, 0x24, 0x77, 0x1e, 0xbe, 0x67, 0x28, 0x1b, 0x94, 0x9e, 0xca, 0xda, 0x54, 0x15, 0xf5, 0xe0, 0x70, 0xb6, 0xc4, 0x89, 0x13, 0xda, 0x86, 0x11}, {0x00, 0x2b, 0x76, 0xc7, 0x05, 0x3d, 0x51, 0x16, 0x2b, 0x87, 0x5f, 0xb9, 0xa4, 0xe3, 0xb2, 0x20, 0x32, 0x13, 0xfc, 0x15, 0x39, 0xeb, 0x7c, 0xbf, 0x6a, 0x49, 0x90, 0xac, 0xcc, 0x5a, 0x23, 0x04}}, + {{0x9f, 0x25, 0x56, 0xd8, 0x5d, 0x7e, 0xb0, 0x01, 0xc1, 0xb0, 0x55, 0xa1, 0x8f, 0x20, 0x43, 0x7f, 0x73, 0x8b, 0x93, 0x21, 0x15, 0xe8, 0x28, 0x89, 0xac, 0x7e, 0x38, 0xa5, 0x14, 0x97, 0x8d, 0x17}, {0xbb, 0x46, 0x20, 0x4c, 0x8a, 0x65, 0xb4, 0xfc, 0x7f, 0xc7, 0x35, 0xa2, 0x82, 0xe4, 0xc7, 0x6b, 0xff, 0x88, 0xb7, 0x3f, 0xb0, 0xf7, 0xe8, 0x44, 0x42, 0x37, 0x04, 0x6e, 0x72, 0x77, 0xe7, 0x3c}}, + {{0xda, 0x91, 0x3e, 0xd4, 0xa0, 0xea, 0xee, 0x55, 0x27, 0x5f, 0xca, 0x78, 0x24, 0x60, 0x0e, 0xc9, 0x51, 0xe0, 0xb6, 0xcb, 0x40, 0xec, 0x2a, 0x6c, 0x7c, 0xbe, 0x48, 0x4a, 0x5c, 0x36, 0xff, 0x0b}, {0xc9, 0x8d, 0xea, 0xd8, 0x04, 0xef, 0x5a, 0x14, 0x4d, 0x41, 0xc8, 0xe5, 0x48, 0x9b, 0x56, 0x2d, 0x73, 0xfe, 0x8f, 0x06, 0x3a, 0x94, 0x1c, 0x78, 0x7b, 0xb9, 0x7a, 0x96, 0x38, 0x9f, 0x61, 0x33}}, + {{0xd4, 0x2b, 0x96, 0x79, 0xa5, 0x71, 0xbe, 0xac, 0x2b, 0xe7, 0xb9, 0x9c, 0x6b, 0x76, 0x08, 0x3a, 0x65, 0xb0, 0x3d, 0x53, 0x2c, 0xd8, 0x88, 0x15, 0xe6, 0xc3, 0x67, 0x77, 0xd1, 0xc1, 0xd6, 0x30}, {0x17, 0x6e, 0xe4, 0xef, 0xac, 0x0d, 0x52, 0x5d, 0x3f, 0x7d, 0xab, 0x6e, 0x1f, 0x65, 0x7a, 0xd8, 0xdb, 0xb6, 0x4e, 0x32, 0x1f, 0x59, 0x75, 0x6a, 0xe4, 0xd8, 0x74, 0x77, 0x98, 0x9a, 0x5d, 0x1a}}, + {{0x6b, 0xff, 0x01, 0xae, 0xe9, 0x72, 0x25, 0x02, 0x2b, 0x21, 0x36, 0xef, 0xd2, 0x1a, 0x5a, 0xce, 0xad, 0xb3, 0x3d, 0xda, 0x42, 0x0f, 0xc1, 0x14, 0x0e, 0x0f, 0xa9, 0x16, 0x5e, 0x62, 0x67, 0x22}, {0xec, 0x71, 0xd6, 0xd6, 0xd3, 0x5d, 0xf4, 0x7b, 0xac, 0xcc, 0x98, 0x11, 0x02, 0x0a, 0xbb, 0x01, 0xfa, 0x48, 0xfa, 0x24, 0xca, 0x34, 0xd0, 0x15, 0xe2, 0xc0, 0x76, 0xdd, 0x5b, 0x8c, 0xa8, 0x19}}, + {{0x2d, 0x1e, 0xfa, 0x34, 0xc1, 0x7c, 0xd9, 0xfd, 0x34, 0x81, 0xcf, 0x9c, 0x75, 0xb7, 0x14, 0x37, 0x77, 0x6b, 0x82, 0xd9, 0xe3, 0x7a, 0x6b, 0xb7, 0xa2, 0x91, 0xbd, 0xe1, 0x31, 0xf6, 0xcb, 0x1e}, {0xde, 0x4e, 0xd1, 0xea, 0xce, 0x00, 0x11, 0xb6, 0x3c, 0x63, 0xf7, 0x9b, 0x5c, 0xdc, 0x64, 0x9f, 0xe6, 0xc2, 0x6e, 0xf0, 0x26, 0x4d, 0x5e, 0x31, 0x26, 0x6f, 0x88, 0x50, 0x5a, 0x53, 0x4a, 0x02}}, + {{0x41, 0x23, 0xb6, 0x74, 0x1e, 0x4f, 0x75, 0x9c, 0xa1, 0x2c, 0xa3, 0xcf, 0xf2, 0xdb, 0x29, 0xc2, 0x78, 0x96, 0xb9, 0xe1, 0x06, 0xa0, 0x12, 0x80, 0x05, 0x22, 0x8e, 0x9f, 0xf4, 0x7d, 0x9a, 0x28}, {0x4c, 0x85, 0xcc, 0x14, 0xb7, 0x86, 0x92, 0xa2, 0x39, 0xb2, 0xb8, 0xba, 0x80, 0x5a, 0xc0, 0x63, 0xdf, 0x16, 0x93, 0x33, 0x5b, 0xa9, 0xbc, 0x77, 0x06, 0x6e, 0xc4, 0x67, 0xe8, 0x78, 0xa1, 0x0a}}, + {{0xfc, 0xb0, 0xeb, 0xab, 0x05, 0xe3, 0x83, 0x69, 0x24, 0xc6, 0xe4, 0xcd, 0x11, 0x86, 0x47, 0x40, 0xed, 0xb7, 0x7f, 0x55, 0xfe, 0xdb, 0xee, 0xcd, 0xd1, 0x18, 0x02, 0x8e, 0x14, 0x1c, 0xe8, 0x04}, {0x29, 0x06, 0xa8, 0x21, 0x33, 0x8d, 0x56, 0xe5, 0x53, 0xae, 0xbb, 0xf2, 0xe9, 0x66, 0xf8, 0x97, 0xbb, 0x2b, 0x02, 0x50, 0x4e, 0xb6, 0xa5, 0xce, 0x1a, 0xf5, 0xea, 0xac, 0xe0, 0x52, 0x34, 0x1a}}, + {{0x52, 0x2c, 0xc7, 0x8c, 0x17, 0xd7, 0x05, 0x34, 0x1b, 0x1e, 0x9a, 0x39, 0x04, 0xa5, 0xa7, 0x28, 0x44, 0xc8, 0xe9, 0xf7, 0x39, 0xe2, 0x70, 0xf1, 0x88, 0xdc, 0x69, 0xbb, 0x95, 0x63, 0xd3, 0x1c}, {0x2d, 0x8e, 0xe6, 0x04, 0x51, 0x0b, 0x5b, 0x67, 0x63, 0x21, 0xed, 0x1d, 0xcc, 0x6e, 0x7f, 0x18, 0x79, 0x70, 0xe3, 0x85, 0x1e, 0x42, 0x53, 0x1a, 0x51, 0x77, 0x2b, 0x75, 0xc7, 0xe3, 0x8a, 0x15}}, + {{0xd7, 0xcf, 0xa9, 0x12, 0x3e, 0x88, 0x00, 0x55, 0x53, 0x47, 0xbd, 0x12, 0x02, 0x04, 0xd8, 0x9c, 0xd5, 0xda, 0x2b, 0xf6, 0x54, 0x89, 0x75, 0x1f, 0xd0, 0xd2, 0xfe, 0xc2, 0x9c, 0xfa, 0xbb, 0x0b}, {0x8d, 0xa2, 0x24, 0x48, 0x09, 0xd9, 0xe6, 0x19, 0x51, 0x3e, 0x83, 0x98, 0xc0, 0xc4, 0xd6, 0x8c, 0x59, 0x6f, 0xcc, 0xbe, 0x4f, 0x19, 0x46, 0xb6, 0xe5, 0x13, 0x34, 0xd7, 0xec, 0xe2, 0x20, 0x34}}, + {{0x9e, 0xf6, 0x10, 0x16, 0xe3, 0xe5, 0xa9, 0x80, 0x20, 0x8e, 0x56, 0x10, 0x92, 0x4a, 0x9c, 0xdd, 0x56, 0x43, 0x5c, 0xc8, 0xb6, 0xae, 0x6c, 0xf8, 0x0d, 0x70, 0x4b, 0x5e, 0xcc, 0xdf, 0xad, 0x31}, {0x04, 0xdf, 0xe1, 0x79, 0x14, 0xd9, 0xab, 0xe9, 0xdc, 0x74, 0xf6, 0x36, 0xf3, 0x23, 0xf0, 0xb7, 0xb6, 0x8b, 0x13, 0x7f, 0x71, 0x33, 0xd2, 0xa9, 0x6f, 0x97, 0x34, 0xcb, 0x17, 0x26, 0x15, 0x1f}}, + {{0x78, 0x50, 0x22, 0xfb, 0xa3, 0x00, 0x0d, 0x96, 0x5f, 0x3f, 0x61, 0x0e, 0x56, 0x71, 0x88, 0x99, 0xeb, 0xa3, 0xa6, 0xcc, 0x97, 0xaf, 0xba, 0xb2, 0xfd, 0xb5, 0x04, 0xc7, 0xe7, 0x19, 0x7f, 0x2e}, {0x09, 0xb2, 0xd9, 0x0d, 0x9f, 0x46, 0xbb, 0x57, 0x26, 0xbd, 0x4a, 0xc8, 0x86, 0x81, 0x40, 0x9c, 0x60, 0x97, 0x45, 0x24, 0xb7, 0x30, 0x13, 0x54, 0x50, 0xb8, 0x4f, 0xee, 0x77, 0x37, 0xa7, 0x3e}}, + {{0x53, 0x00, 0x88, 0xbe, 0x2d, 0x5e, 0x41, 0x62, 0x7a, 0x5f, 0x95, 0x05, 0x5b, 0x81, 0x5d, 0xe6, 0x74, 0x54, 0xe0, 0x43, 0xed, 0xe7, 0x5b, 0x6b, 0xff, 0x20, 0x3d, 0x01, 0x3c, 0xef, 0xf9, 0x29}, {0x1a, 0x71, 0xf0, 0xcf, 0x74, 0xe0, 0x5c, 0x64, 0xdc, 0x30, 0xe6, 0x0a, 0x5e, 0x6e, 0x08, 0x9b, 0xdf, 0x68, 0xf2, 0x7f, 0xe6, 0x5e, 0x65, 0x17, 0xa9, 0x62, 0xea, 0xe6, 0x0f, 0x19, 0x30, 0x28}}, + {{0x81, 0x42, 0x61, 0x9c, 0x8b, 0x56, 0xa6, 0xf9, 0xce, 0xd5, 0x46, 0xd5, 0x7b, 0xf3, 0xf3, 0x4b, 0x14, 0x7b, 0x74, 0x34, 0x10, 0x77, 0xfc, 0x47, 0xef, 0xf9, 0x6a, 0xf7, 0xa4, 0x2a, 0x46, 0x3a}, {0x79, 0x4c, 0xef, 0xae, 0xd7, 0x19, 0x0d, 0x48, 0x1d, 0x93, 0xfb, 0xae, 0x75, 0xe1, 0x60, 0xab, 0xb4, 0xa5, 0x1f, 0xc7, 0xd0, 0x85, 0x55, 0x4d, 0x35, 0x95, 0xd5, 0x97, 0x62, 0x8e, 0x96, 0x0a}}, + {{0xf9, 0x9d, 0xac, 0x24, 0x3f, 0x90, 0x36, 0xe4, 0xa6, 0x17, 0xa8, 0x1d, 0xf0, 0xdd, 0x00, 0x93, 0x2a, 0x93, 0xbc, 0xb4, 0x39, 0x68, 0x3e, 0x12, 0x7f, 0xd7, 0xfd, 0x35, 0x88, 0x84, 0x18, 0x27}, {0xbc, 0x46, 0x09, 0x9b, 0xbd, 0x7a, 0xe4, 0x52, 0xa5, 0xe4, 0xeb, 0x0f, 0xce, 0x3e, 0x85, 0xc0, 0x5d, 0x99, 0x7e, 0x34, 0xc8, 0x35, 0xf8, 0xf3, 0x24, 0xa2, 0xc0, 0x2c, 0x13, 0xe9, 0xde, 0x19}}, + {{0x58, 0xa7, 0xe6, 0xb4, 0xa9, 0x83, 0x53, 0xa4, 0x47, 0xe4, 0xc1, 0x23, 0xb5, 0x00, 0x15, 0x90, 0x36, 0x57, 0x26, 0x86, 0xc8, 0xc0, 0x5e, 0xe8, 0x5a, 0xf8, 0xc8, 0x40, 0xe6, 0xa8, 0x61, 0x14}, {0xc8, 0xb2, 0x72, 0xfd, 0xea, 0x08, 0x1d, 0x50, 0x03, 0xf4, 0x6d, 0x4f, 0x79, 0xec, 0x63, 0xeb, 0x19, 0x0d, 0x53, 0x1c, 0x50, 0xf2, 0xe3, 0xf1, 0xd8, 0x19, 0x3d, 0x69, 0x59, 0xd7, 0x2e, 0x06}}, + {{0x75, 0xfc, 0x49, 0xb2, 0x8d, 0xa3, 0xc4, 0xa2, 0x90, 0x85, 0xc7, 0x77, 0x21, 0x07, 0xe4, 0x8a, 0xa5, 0x9e, 0x5b, 0x8d, 0x04, 0x4b, 0xdc, 0x03, 0x7d, 0x31, 0x03, 0xe8, 0x38, 0x0d, 0x89, 0x0d}, {0xa7, 0xad, 0x58, 0x93, 0x60, 0xee, 0x10, 0x3e, 0x0e, 0xd7, 0x62, 0x08, 0xeb, 0x48, 0x09, 0x35, 0x1c, 0x8c, 0x5a, 0x18, 0xdf, 0x80, 0xaa, 0x75, 0x77, 0xa8, 0x27, 0xd0, 0x80, 0xc3, 0xe7, 0x37}}, + {{0xcf, 0x06, 0x9a, 0xf0, 0x65, 0xa5, 0xfd, 0xaa, 0xeb, 0x00, 0x68, 0xb6, 0xc0, 0xf0, 0xe9, 0x91, 0xeb, 0x5d, 0x9a, 0x9a, 0x61, 0x4a, 0x89, 0xba, 0xa5, 0x67, 0x2a, 0xa7, 0x2f, 0x6c, 0xab, 0x35}, {0x6f, 0xa2, 0xc1, 0xbb, 0x30, 0x58, 0x34, 0xdd, 0x47, 0x97, 0xc3, 0x6f, 0x0c, 0x14, 0xd2, 0xc3, 0x2c, 0xf6, 0xa3, 0xa4, 0xaa, 0x4a, 0x80, 0x65, 0x5f, 0x9e, 0x04, 0x1b, 0x2b, 0xda, 0x8a, 0x2c}}, + {{0x0f, 0x63, 0xad, 0x98, 0x6a, 0x24, 0x1e, 0x64, 0x2c, 0x2e, 0xb3, 0x19, 0xde, 0x91, 0xab, 0x72, 0x61, 0xb6, 0x69, 0x21, 0x4b, 0x77, 0x92, 0x5c, 0xcd, 0x61, 0xce, 0x70, 0x43, 0xc5, 0x1a, 0x1e}, {0x48, 0x84, 0x5b, 0x28, 0xf5, 0x3f, 0xb2, 0x9c, 0x27, 0x67, 0x31, 0xf3, 0x2b, 0xa4, 0xb4, 0x9b, 0x20, 0x47, 0x6e, 0xc8, 0x13, 0xa5, 0xdd, 0x62, 0x85, 0xae, 0xd0, 0x4f, 0xf0, 0xa0, 0x38, 0x21}}, + {{0xc0, 0xc2, 0xc8, 0x31, 0x30, 0x8a, 0xff, 0x05, 0xaf, 0x13, 0x7d, 0xb3, 0x8a, 0x4e, 0x0c, 0x32, 0x62, 0x0a, 0xe0, 0x7d, 0x92, 0x61, 0xe1, 0x5f, 0x01, 0xdf, 0x99, 0xc8, 0xec, 0x6e, 0x39, 0x32}, {0x0b, 0xdb, 0x4c, 0x25, 0xa7, 0x5a, 0x6a, 0xf8, 0x01, 0x40, 0x50, 0x7c, 0x43, 0x63, 0xf8, 0xff, 0x34, 0x28, 0xc4, 0x13, 0x31, 0xce, 0x7e, 0x90, 0x04, 0x4f, 0xf6, 0xfe, 0x20, 0x91, 0x83, 0x00}}, + {{0x05, 0x71, 0x0b, 0xe8, 0x15, 0x56, 0xa3, 0x0d, 0x68, 0xea, 0xf5, 0x83, 0xc7, 0x35, 0x0d, 0xcd, 0x84, 0xc7, 0x14, 0xfd, 0x17, 0x8f, 0x56, 0x19, 0x80, 0x5b, 0x21, 0x8e, 0x9d, 0x16, 0x44, 0x38}, {0x51, 0xed, 0x9b, 0x1c, 0xf4, 0x6f, 0xcc, 0x1f, 0x6b, 0xec, 0xd7, 0x5d, 0x81, 0x94, 0xe5, 0x34, 0x5d, 0x7c, 0xad, 0x7c, 0x16, 0xd3, 0xa0, 0x0b, 0x8e, 0x63, 0x8a, 0x39, 0x3c, 0xc8, 0xc0, 0x3e}}, + {{0x23, 0x9e, 0xa8, 0xca, 0x2a, 0xdd, 0xe3, 0x30, 0xaa, 0x34, 0x21, 0xa9, 0xc7, 0x24, 0x56, 0xca, 0x0a, 0x0c, 0x62, 0xbe, 0x5d, 0x4c, 0x9a, 0x56, 0xe1, 0x07, 0x64, 0xf0, 0x35, 0xf4, 0xb5, 0x0b}, {0x3b, 0xf5, 0x22, 0x5e, 0x97, 0xe1, 0xe8, 0xdf, 0xfb, 0xb1, 0x37, 0x71, 0xc5, 0xbe, 0xfa, 0x8d, 0x1a, 0xae, 0x85, 0xb6, 0x98, 0x9f, 0xe1, 0x01, 0xc1, 0xc2, 0x28, 0x05, 0x90, 0x14, 0xc1, 0x28}}, + {{0xf8, 0xe4, 0xd8, 0x0a, 0xce, 0xf7, 0xcc, 0x3d, 0x3b, 0x76, 0x9e, 0x19, 0x2e, 0x31, 0x8e, 0x58, 0x8d, 0x55, 0x25, 0x03, 0x2f, 0xa5, 0x6a, 0x8c, 0xf3, 0xf4, 0x72, 0xc6, 0x69, 0xba, 0xc4, 0x29}, {0xd7, 0x52, 0x71, 0x71, 0x18, 0xf2, 0xec, 0x19, 0x4e, 0xba, 0x38, 0xfa, 0x55, 0x7a, 0xee, 0x06, 0x95, 0xfd, 0x3c, 0x6c, 0xf2, 0xa4, 0xf0, 0xd8, 0x0c, 0x7f, 0xbb, 0x4d, 0xaf, 0x61, 0xf7, 0x3e}}, + {{0x75, 0x5f, 0xbb, 0x04, 0xad, 0xba, 0x0f, 0x1f, 0xf0, 0xe2, 0xf4, 0x56, 0xb6, 0x02, 0xef, 0x4a, 0xa4, 0x8e, 0xa0, 0xb8, 0xff, 0x9b, 0x89, 0x4c, 0x8d, 0x70, 0xc7, 0xa1, 0x2c, 0x7e, 0x4e, 0x3f}, {0xbf, 0x9b, 0x9c, 0x1c, 0x10, 0x7a, 0xf6, 0x02, 0xd6, 0x8a, 0xa2, 0x8b, 0xdb, 0x0c, 0xf3, 0x05, 0xe2, 0xa8, 0x60, 0x15, 0x9a, 0xc4, 0x3a, 0xc1, 0x18, 0x59, 0x35, 0x94, 0xdb, 0xbe, 0x34, 0x15}}, + {{0x23, 0xbe, 0x10, 0xb8, 0xff, 0x6d, 0x87, 0xfa, 0x41, 0x20, 0x75, 0xe0, 0xe1, 0x0c, 0xc7, 0x72, 0xef, 0x3c, 0x1f, 0x51, 0x38, 0xbf, 0xc8, 0x07, 0x5b, 0xe2, 0x1b, 0xed, 0x3e, 0x5f, 0x6c, 0x1a}, {0xb0, 0x65, 0xfa, 0x85, 0xae, 0xc0, 0xdd, 0x51, 0x47, 0x3f, 0xc3, 0x4c, 0xca, 0x4d, 0x5b, 0x83, 0x07, 0x68, 0x1a, 0x22, 0xbd, 0x02, 0xd6, 0x1b, 0x9f, 0xae, 0x90, 0x8a, 0x1a, 0x3d, 0xc2, 0x32}}, + {{0x0d, 0x96, 0x14, 0xa1, 0x2c, 0x53, 0xed, 0x0e, 0x0d, 0x03, 0x45, 0x97, 0x07, 0x2d, 0x83, 0x69, 0x92, 0x87, 0x97, 0xc5, 0x0e, 0x8c, 0xb8, 0x0c, 0xbc, 0x8f, 0xbd, 0xba, 0xf3, 0x46, 0xd4, 0x3e}, {0xbb, 0x6e, 0xe7, 0x7c, 0x62, 0x95, 0xa7, 0x2f, 0x0b, 0x5e, 0x86, 0x7c, 0x19, 0x50, 0x21, 0x7e, 0x09, 0x26, 0x16, 0x0b, 0x86, 0x69, 0x0e, 0x6d, 0xbd, 0x9d, 0xd2, 0x03, 0x03, 0xa8, 0xed, 0x17}}, + {{0x6e, 0x4f, 0x75, 0x28, 0x7f, 0xf0, 0xdd, 0x5a, 0x69, 0x6e, 0x38, 0xce, 0x19, 0x10, 0xd2, 0xde, 0x46, 0x45, 0x46, 0xd1, 0x0e, 0x5d, 0x11, 0xba, 0x7b, 0xd5, 0xf7, 0x6b, 0xf5, 0xad, 0xb8, 0x1c}, {0x9f, 0x5c, 0x67, 0x30, 0xe7, 0x43, 0xb3, 0x74, 0x0c, 0x25, 0x38, 0xc0, 0x6c, 0x1a, 0xbe, 0xaa, 0x68, 0xeb, 0x5c, 0x7c, 0x02, 0x58, 0xf9, 0x8e, 0xf3, 0xcb, 0x34, 0xb6, 0x08, 0x23, 0xf7, 0x26}}, + {{0xa3, 0x09, 0x2a, 0x2e, 0xd0, 0x9c, 0x97, 0xe6, 0xb6, 0x08, 0x41, 0xb1, 0xb4, 0x1a, 0xb4, 0xbf, 0x61, 0x57, 0xb0, 0x2c, 0x81, 0xdd, 0x0d, 0x29, 0x82, 0xe5, 0x10, 0x8d, 0x2d, 0x64, 0x6c, 0x2a}, {0xa4, 0x84, 0x3e, 0xe1, 0x2a, 0x8a, 0x36, 0x85, 0xd2, 0x86, 0x9e, 0x49, 0xb2, 0x6c, 0xce, 0x9e, 0x11, 0x68, 0x4e, 0x1f, 0x04, 0x03, 0xd1, 0xa6, 0x0b, 0xc0, 0x4f, 0x29, 0x86, 0x35, 0x49, 0x17}}, + {{0xec, 0xc9, 0x88, 0xb2, 0x33, 0xf9, 0x00, 0xd0, 0x6c, 0xf8, 0xfc, 0xb1, 0x27, 0xfa, 0x08, 0x00, 0xf6, 0x0a, 0xde, 0x5e, 0x36, 0xdc, 0xb8, 0x77, 0x26, 0x3f, 0xeb, 0x59, 0x2d, 0xea, 0x9d, 0x28}, {0xfc, 0x4d, 0x6e, 0x2b, 0xad, 0x9a, 0xe9, 0x6e, 0x8d, 0x5c, 0xb5, 0x63, 0xfb, 0xf9, 0x57, 0xa3, 0x10, 0xd7, 0xa8, 0x98, 0xc4, 0x03, 0x9d, 0xb9, 0x19, 0x4f, 0xc3, 0x9d, 0x80, 0xb9, 0xfd, 0x2c}}, + {{0xdf, 0x5c, 0xbd, 0xfa, 0x4b, 0xf2, 0x3f, 0x4a, 0xe8, 0x20, 0x33, 0x36, 0xb3, 0x5b, 0x15, 0x74, 0xb6, 0xa3, 0xa6, 0x99, 0xd9, 0xad, 0x05, 0xf6, 0x58, 0x3f, 0xa5, 0x3d, 0xf1, 0x39, 0x65, 0x03}, {0x08, 0xc4, 0x59, 0x04, 0x10, 0xe9, 0xa5, 0x4a, 0x99, 0x30, 0xfc, 0xdb, 0xe4, 0xd4, 0xdf, 0xe4, 0xae, 0x8b, 0xe1, 0x47, 0x1e, 0x6d, 0xe4, 0xec, 0x52, 0x0f, 0xaf, 0x3a, 0xf8, 0xfb, 0x71, 0x25}}, + {{0xf0, 0x56, 0xa6, 0x6f, 0x5a, 0x75, 0x8b, 0xc0, 0xa6, 0x19, 0x58, 0x35, 0xd2, 0xcb, 0x17, 0xac, 0x9f, 0xd5, 0xde, 0x76, 0xa9, 0x63, 0x1d, 0x0e, 0x71, 0xcd, 0x8f, 0x06, 0xcc, 0xba, 0x0d, 0x0f}, {0x36, 0xc2, 0x66, 0xd3, 0x17, 0x88, 0xb6, 0x9a, 0xd7, 0x5f, 0x88, 0x3f, 0x76, 0x42, 0xda, 0x7a, 0xec, 0x44, 0xe3, 0x9f, 0x4f, 0xde, 0x3d, 0x08, 0x09, 0x4d, 0xf7, 0xca, 0x93, 0xe1, 0xde, 0x33}}, + {{0x6e, 0xb4, 0x87, 0x28, 0xfd, 0x8b, 0x95, 0x35, 0x28, 0x4e, 0xbe, 0xf1, 0x01, 0x91, 0x38, 0x5f, 0xd5, 0x08, 0xed, 0x99, 0xba, 0xac, 0xd1, 0xf9, 0x3e, 0x37, 0x73, 0xfa, 0x66, 0xa6, 0xae, 0x34}, {0xc2, 0x6c, 0x69, 0xb2, 0x6d, 0x38, 0x50, 0x85, 0xc0, 0x9e, 0x04, 0x85, 0x6f, 0xf2, 0xe0, 0xac, 0x54, 0x54, 0x3d, 0x9d, 0x6d, 0xd4, 0x1e, 0x8e, 0xee, 0xae, 0x44, 0x5b, 0xd8, 0x82, 0x78, 0x09}}, + {{0x60, 0xa7, 0x35, 0x54, 0xa0, 0x19, 0x37, 0x13, 0xd0, 0xfa, 0xce, 0x0f, 0xb7, 0x3a, 0x59, 0xeb, 0x3a, 0x85, 0x0d, 0xbf, 0xa8, 0x89, 0x6b, 0x06, 0x6e, 0x01, 0xf7, 0x1b, 0x20, 0xdf, 0x05, 0x1a}, {0xc6, 0x6a, 0x88, 0x7e, 0x8a, 0x56, 0xf0, 0x69, 0x0d, 0x88, 0xb8, 0xcc, 0x1a, 0xfb, 0xd1, 0x90, 0xf4, 0x03, 0x87, 0x0f, 0x9b, 0xcb, 0xf3, 0x81, 0xcf, 0x6e, 0x36, 0xa9, 0x89, 0x03, 0xe5, 0x28}}, + {{0x15, 0xd7, 0xdd, 0x64, 0x29, 0x3f, 0xbb, 0x50, 0x06, 0x77, 0x3f, 0xdc, 0xa6, 0xf9, 0xaa, 0xd5, 0x3d, 0x3c, 0x9c, 0xc4, 0x33, 0x14, 0x6d, 0x6e, 0x40, 0x44, 0x06, 0xb0, 0x90, 0x0e, 0x87, 0x1a}, {0x67, 0x2a, 0xfe, 0x9f, 0x0d, 0x8f, 0x4a, 0x8f, 0xb2, 0xe8, 0x3d, 0x8b, 0x37, 0xff, 0xf7, 0x3d, 0x4a, 0x22, 0xe5, 0xb2, 0x50, 0xac, 0x00, 0xe2, 0xd6, 0x19, 0x5f, 0x62, 0x75, 0xbe, 0xa8, 0x2e}}, + {{0xa6, 0x84, 0xdf, 0x79, 0xae, 0xf3, 0x52, 0x93, 0xd2, 0x7c, 0x1e, 0xb9, 0x6a, 0xc7, 0x21, 0xd8, 0x9b, 0x36, 0xe5, 0xaf, 0x7d, 0x8b, 0x16, 0x15, 0x01, 0x28, 0x5f, 0xed, 0xb3, 0xd1, 0xb2, 0x39}, {0xed, 0xcd, 0xc0, 0x4a, 0xd3, 0xc8, 0xc1, 0xe3, 0xb2, 0x12, 0xb8, 0x7f, 0xbb, 0x48, 0x67, 0x24, 0xca, 0xe9, 0x23, 0x9a, 0xf6, 0x46, 0x8d, 0xf1, 0x73, 0x57, 0xbd, 0x3c, 0xbf, 0x73, 0xb1, 0x12}}, + {{0x4d, 0xc7, 0x6a, 0x47, 0x07, 0xcb, 0x92, 0x0d, 0xa2, 0x9e, 0xe5, 0x91, 0x2a, 0xb8, 0x79, 0x91, 0xe0, 0xf5, 0x92, 0xd6, 0xb3, 0x3a, 0xfc, 0xd5, 0x50, 0x3a, 0xc3, 0x00, 0xd0, 0xef, 0xee, 0x3d}, {0xcd, 0x43, 0x32, 0xfa, 0x44, 0x70, 0x37, 0xce, 0x83, 0xa1, 0x75, 0xa9, 0xca, 0x04, 0xea, 0x23, 0x71, 0xb8, 0x62, 0xec, 0x2e, 0xb0, 0xa3, 0x3a, 0xf0, 0x8e, 0x58, 0xc5, 0x11, 0x21, 0xa9, 0x04}}, + {{0x5f, 0x66, 0xa5, 0x7d, 0x02, 0xa1, 0x97, 0xdc, 0x18, 0x58, 0xfd, 0xce, 0x5d, 0x5b, 0xbb, 0xa1, 0x71, 0x35, 0xcd, 0x62, 0x76, 0x1a, 0x4e, 0x7b, 0x70, 0x2d, 0x76, 0x52, 0x9b, 0xd9, 0xa3, 0x3a}, {0x59, 0x77, 0xc3, 0xfe, 0x36, 0x79, 0xbd, 0x94, 0x3c, 0x5a, 0x2e, 0x23, 0x55, 0x4b, 0x16, 0x72, 0x71, 0xb2, 0xbd, 0x52, 0xa2, 0xe2, 0x6b, 0x75, 0x3b, 0x6f, 0x56, 0xd6, 0x74, 0xbb, 0xf2, 0x33}}, + {{0xb9, 0xd9, 0xdc, 0xd6, 0x56, 0x72, 0xfd, 0xc8, 0x5e, 0x7f, 0x65, 0x7f, 0xd8, 0xc9, 0x03, 0xca, 0xdb, 0x46, 0xf6, 0x2b, 0xfa, 0x43, 0x39, 0xfd, 0x91, 0xa5, 0x99, 0x63, 0x4f, 0x59, 0xc1, 0x22}, {0x6c, 0x06, 0xbe, 0x58, 0x89, 0x1b, 0xd3, 0xa3, 0x51, 0xd7, 0x71, 0x43, 0x4c, 0xdf, 0x76, 0x37, 0x87, 0x7a, 0x00, 0x00, 0xcd, 0x1d, 0x4f, 0x6b, 0x19, 0xe2, 0x33, 0xa4, 0xe9, 0x83, 0x6d, 0x3a}}, + {{0xa1, 0x8c, 0x9d, 0x74, 0xca, 0x92, 0xac, 0x2b, 0xc1, 0x64, 0x83, 0xd9, 0x6a, 0xb7, 0xff, 0xcd, 0x66, 0xe2, 0x4b, 0x07, 0x43, 0x9e, 0x71, 0x4a, 0x31, 0x3d, 0xf1, 0x4a, 0x9f, 0x19, 0x1d, 0x21}, {0x72, 0x3f, 0x8a, 0x7d, 0x75, 0xf3, 0x5c, 0x61, 0xcf, 0xe0, 0x25, 0x2b, 0x4e, 0x0a, 0x71, 0xe2, 0x0f, 0x18, 0xe1, 0xa9, 0xf8, 0x62, 0x7e, 0xe0, 0x63, 0x46, 0x8f, 0xd2, 0x69, 0x51, 0x68, 0x36}}, + {{0x11, 0x72, 0x25, 0xa0, 0x2b, 0xb9, 0x26, 0x50, 0x8b, 0x55, 0x03, 0x2a, 0x9a, 0xbe, 0x61, 0x0f, 0xce, 0x57, 0x58, 0xc5, 0xce, 0x4f, 0xb5, 0x6e, 0xd7, 0x6b, 0x0e, 0x38, 0xa0, 0x20, 0x93, 0x31}, {0xa8, 0xf6, 0x4a, 0x55, 0x43, 0x1d, 0xe5, 0x6f, 0x72, 0xf9, 0xc9, 0xb9, 0xc0, 0x48, 0xf0, 0x6f, 0x77, 0x04, 0xa3, 0x07, 0xca, 0x7b, 0xf3, 0xb6, 0xa1, 0x6e, 0x97, 0xf3, 0x0c, 0x08, 0xb4, 0x01}}, + {{0x83, 0xbf, 0xc5, 0x21, 0xb2, 0x14, 0x85, 0x0c, 0xe3, 0xf1, 0x86, 0xf7, 0xf8, 0xf7, 0x65, 0x6a, 0x46, 0xf0, 0x5b, 0x86, 0x2c, 0x3a, 0x45, 0x3c, 0x07, 0xe7, 0xc1, 0xfb, 0x3f, 0x8c, 0xe2, 0x18}, {0xbd, 0x60, 0xe0, 0x19, 0x90, 0x7e, 0x11, 0xb3, 0x79, 0xf2, 0xd5, 0x85, 0x29, 0xb0, 0x2c, 0x68, 0x80, 0x3c, 0xf3, 0xac, 0x39, 0x18, 0x07, 0x2d, 0x2a, 0x25, 0xe4, 0x09, 0x5a, 0xbe, 0xfb, 0x24}}, + {{0xdd, 0x13, 0x30, 0xfd, 0x49, 0x13, 0x38, 0x3f, 0xc4, 0xac, 0xf9, 0x64, 0x2c, 0x3f, 0xa3, 0x50, 0x52, 0x48, 0xae, 0xea, 0x9a, 0xc2, 0xfc, 0xbd, 0x1f, 0x4d, 0x7e, 0x73, 0xf1, 0xe7, 0xcd, 0x08}, {0xf9, 0xcf, 0x2e, 0x0d, 0xf1, 0x95, 0xeb, 0xc9, 0xb8, 0x7c, 0xfa, 0xe8, 0x1e, 0x09, 0x16, 0x2e, 0xdf, 0x87, 0xb1, 0xb2, 0x45, 0xd5, 0x38, 0x23, 0xa5, 0x39, 0x4a, 0x93, 0xcd, 0x01, 0x9c, 0x2f}}, + {{0x32, 0xdd, 0x98, 0xfa, 0x86, 0x24, 0x4f, 0x2f, 0x02, 0xab, 0x29, 0x94, 0xb9, 0x50, 0xb3, 0x5a, 0x09, 0xfb, 0xf9, 0x67, 0x08, 0x5b, 0x00, 0x4d, 0x4c, 0xfb, 0x44, 0x62, 0x28, 0x1b, 0x79, 0x37}, {0xed, 0x19, 0x70, 0xad, 0x41, 0x1b, 0x7a, 0xf3, 0xf3, 0xef, 0x04, 0x04, 0x91, 0x62, 0x58, 0x3d, 0x31, 0x71, 0x0b, 0x69, 0x64, 0x9d, 0x10, 0x37, 0x01, 0x0a, 0x8a, 0x64, 0x2b, 0xfe, 0x3d, 0x32}}, + {{0xac, 0x90, 0x4c, 0x42, 0x63, 0x1b, 0x99, 0x2c, 0xb1, 0x19, 0x01, 0x92, 0x48, 0xe1, 0xe0, 0xcd, 0xdd, 0x23, 0x4e, 0xa9, 0xcd, 0xcd, 0x0a, 0x6b, 0x5b, 0xa2, 0x67, 0x54, 0x85, 0xec, 0x83, 0x0a}, {0xf5, 0x5f, 0x29, 0xe0, 0x56, 0xb4, 0xae, 0xe2, 0x9e, 0x0f, 0xd4, 0x95, 0x7e, 0x15, 0xf2, 0xbb, 0x23, 0x21, 0x86, 0x52, 0x85, 0x83, 0xf3, 0xfc, 0x60, 0x18, 0x21, 0x63, 0xb8, 0xc6, 0xd4, 0x09}}, + {{0x6a, 0xdd, 0x8a, 0xb6, 0x9b, 0x26, 0x98, 0x5a, 0x2a, 0xb2, 0x39, 0x46, 0x41, 0xb9, 0xfe, 0x1e, 0x2b, 0x62, 0xae, 0x46, 0x04, 0x1c, 0x71, 0x35, 0x04, 0xc4, 0xe2, 0x61, 0x4e, 0x0c, 0x24, 0x07}, {0x79, 0xbf, 0xe0, 0xb9, 0xc5, 0x32, 0xf2, 0x4e, 0x79, 0x46, 0xb9, 0x82, 0x6d, 0x2c, 0x49, 0x28, 0xce, 0x5a, 0x95, 0xd5, 0x62, 0xc1, 0xc9, 0x6d, 0x4b, 0x7e, 0x46, 0xcb, 0xc9, 0x46, 0xa1, 0x23}}, + {{0x44, 0x57, 0x88, 0x16, 0x67, 0xe4, 0xa6, 0x0e, 0x51, 0x0f, 0x06, 0x3c, 0xa9, 0xc7, 0x3a, 0xd7, 0xf0, 0x0f, 0x11, 0x09, 0xef, 0x3e, 0x46, 0x1b, 0xb0, 0x15, 0x2b, 0x8b, 0x1b, 0x1a, 0xf5, 0x25}, {0xf0, 0xcf, 0x47, 0xd8, 0xd7, 0x24, 0x94, 0x0e, 0x22, 0x4d, 0xd3, 0xc8, 0x26, 0x1c, 0xca, 0x9e, 0x8a, 0x35, 0x71, 0xa0, 0xf4, 0x44, 0x7c, 0x3e, 0xcc, 0x2a, 0x85, 0x9e, 0x55, 0x3e, 0xe0, 0x02}}, + {{0x8c, 0x54, 0x72, 0x4f, 0x63, 0xe9, 0xf6, 0xfa, 0x18, 0x30, 0xcb, 0x06, 0x78, 0x66, 0xba, 0x75, 0xd0, 0x1e, 0xa6, 0xf6, 0xc1, 0x4d, 0x5c, 0xdd, 0x11, 0x7d, 0x9c, 0x96, 0x4a, 0xaa, 0x8a, 0x35}, {0xf7, 0x26, 0x41, 0x0b, 0x8c, 0xb8, 0x92, 0x71, 0x72, 0xd6, 0x73, 0x51, 0xaa, 0x5f, 0xbf, 0xdc, 0x6b, 0x38, 0xc5, 0xd7, 0x7b, 0x3f, 0x44, 0x28, 0x82, 0x88, 0x54, 0x0d, 0x2d, 0x62, 0x26, 0x03}}, + {{0x8d, 0xf0, 0x49, 0x16, 0x20, 0x86, 0x1d, 0xf3, 0xdb, 0x1c, 0x2e, 0xc6, 0xc9, 0x50, 0xc2, 0x1f, 0x8b, 0x30, 0x2a, 0xc1, 0x7f, 0x7d, 0xa2, 0x3f, 0xd6, 0x40, 0x2b, 0x3f, 0x98, 0x76, 0x7a, 0x08}, {0x1f, 0xcf, 0x1a, 0xf1, 0xf8, 0x55, 0xfe, 0x1d, 0xef, 0x34, 0x95, 0x99, 0xfd, 0xc9, 0x33, 0xee, 0x18, 0x23, 0xaa, 0x68, 0x6a, 0x77, 0x06, 0xc3, 0xac, 0x64, 0xf0, 0x37, 0xfb, 0x5a, 0xc3, 0x2a}}, + {{0x97, 0x34, 0xe3, 0xe5, 0xe8, 0xcf, 0xde, 0x3a, 0xed, 0xcb, 0x4a, 0x37, 0x0f, 0x93, 0x41, 0x6c, 0xd8, 0x8a, 0xa8, 0xc7, 0x64, 0xf8, 0xb0, 0x12, 0x58, 0x25, 0xf4, 0x97, 0xb0, 0xdf, 0x0f, 0x37}, {0x99, 0xcf, 0xb5, 0x1a, 0xe4, 0xb1, 0x20, 0x72, 0x3c, 0x62, 0x9c, 0x77, 0xde, 0x92, 0x32, 0x16, 0xe7, 0x86, 0x4a, 0x4b, 0x22, 0x00, 0x34, 0xb0, 0x5b, 0x92, 0xf2, 0x6e, 0xa2, 0xaf, 0x9b, 0x30}}, + {{0x27, 0x51, 0xc0, 0xf9, 0x12, 0x50, 0x06, 0x34, 0x75, 0x4b, 0x00, 0x99, 0x19, 0xf4, 0x28, 0xc8, 0xf3, 0xe3, 0x80, 0xf4, 0x1d, 0xa1, 0xd7, 0xf6, 0x07, 0xf2, 0x42, 0xfc, 0x46, 0x2d, 0x33, 0x2d}, {0xe3, 0x6e, 0x68, 0x9e, 0x50, 0x62, 0x46, 0x2e, 0x25, 0x5e, 0x9e, 0xdf, 0x7c, 0xde, 0xfd, 0xab, 0xd5, 0x75, 0x02, 0x4b, 0x95, 0x0e, 0x57, 0xfd, 0x13, 0x9a, 0xea, 0x28, 0x02, 0xef, 0x77, 0x24}}, + {{0xbe, 0x58, 0xca, 0x76, 0x2f, 0xe2, 0x3e, 0xbc, 0x0b, 0xc5, 0x9b, 0xd5, 0xd8, 0x77, 0xa8, 0x3e, 0x46, 0xd7, 0x8b, 0x77, 0x65, 0x9b, 0x8b, 0xa8, 0x63, 0x15, 0x82, 0xa6, 0x81, 0x76, 0xc6, 0x3a}, {0x0c, 0xa6, 0xa2, 0x75, 0xa1, 0x26, 0x2d, 0x01, 0x0e, 0x52, 0x9e, 0x5b, 0x75, 0x16, 0x93, 0xd2, 0x04, 0x08, 0x0a, 0xf9, 0xb2, 0x81, 0xb3, 0x7b, 0x89, 0x7a, 0xde, 0x70, 0x0d, 0xbb, 0xa1, 0x33}}, + {{0x90, 0xee, 0x44, 0x84, 0xca, 0xc9, 0xca, 0xb0, 0x61, 0x1d, 0x27, 0xff, 0xad, 0x19, 0x8e, 0x96, 0x6b, 0xf6, 0x5a, 0x83, 0x09, 0x3e, 0x26, 0x3f, 0x64, 0x0c, 0x1c, 0xda, 0xf7, 0x71, 0xbd, 0x05}, {0x82, 0x25, 0x85, 0x6f, 0xce, 0xde, 0xe9, 0x61, 0xf5, 0xc9, 0xf5, 0x5d, 0xee, 0x17, 0xd1, 0xe5, 0x47, 0x81, 0x5d, 0xbc, 0x5f, 0x5b, 0xd6, 0xa3, 0x4e, 0x75, 0x3c, 0x1b, 0x9c, 0x82, 0x58, 0x3b}}, + {{0x80, 0xef, 0x9c, 0xb5, 0x16, 0x91, 0xe8, 0x39, 0x99, 0x9a, 0x8d, 0x86, 0x15, 0x3f, 0xee, 0xe8, 0x44, 0x84, 0xd5, 0xa5, 0xdd, 0x6a, 0x32, 0x4b, 0x66, 0x9f, 0xf7, 0x9f, 0x02, 0x94, 0xfe, 0x14}, {0xcb, 0xb5, 0x12, 0x00, 0x20, 0x40, 0x66, 0x8f, 0x13, 0xfa, 0x37, 0x15, 0x79, 0xc9, 0xcc, 0x6f, 0x82, 0x82, 0x6a, 0x38, 0xcc, 0x3e, 0x9e, 0xd1, 0xdd, 0x74, 0x5c, 0x6d, 0x85, 0xc7, 0x2c, 0x16}}, + {{0xaf, 0x88, 0xfe, 0x07, 0x8e, 0x2e, 0xc0, 0xdc, 0x34, 0xf8, 0xae, 0xff, 0x17, 0x2a, 0x3b, 0xbd, 0xd5, 0x78, 0x0b, 0x64, 0x98, 0x32, 0x6f, 0x0c, 0x56, 0xcf, 0x10, 0xe0, 0x83, 0xa6, 0xa4, 0x34}, {0x33, 0xea, 0x73, 0x72, 0xee, 0xab, 0xf3, 0x63, 0xa5, 0x92, 0x0b, 0x04, 0x2e, 0x70, 0x37, 0x05, 0xc9, 0x3b, 0xd6, 0x8d, 0xc3, 0x6e, 0x7d, 0x54, 0x45, 0x15, 0x8a, 0x75, 0x12, 0x5b, 0x64, 0x00}}, + {{0x75, 0x51, 0x0f, 0xb3, 0x91, 0x7e, 0x8e, 0xee, 0x4f, 0x2a, 0xb1, 0x98, 0x8b, 0x32, 0x18, 0x91, 0xf5, 0x2e, 0x19, 0xce, 0x43, 0x7d, 0x6b, 0x0c, 0xc2, 0x77, 0x07, 0xf7, 0x45, 0x65, 0x83, 0x26}, {0x29, 0xf8, 0xd5, 0x8f, 0x0b, 0x78, 0x98, 0xd7, 0xa4, 0xeb, 0x78, 0x02, 0x5e, 0xa0, 0x68, 0xc4, 0xc1, 0x7a, 0x64, 0x00, 0x3c, 0xf1, 0xfa, 0xb7, 0x76, 0xd1, 0xa4, 0x3b, 0xee, 0x6a, 0x2a, 0x32}}, + {{0xdd, 0x13, 0x89, 0x61, 0xd6, 0x4d, 0x3b, 0x1e, 0x94, 0x8f, 0x95, 0xda, 0xdd, 0xf2, 0x8b, 0x24, 0x26, 0x18, 0xe1, 0x97, 0x26, 0x48, 0x16, 0x82, 0xec, 0xdc, 0xe7, 0xa5, 0x98, 0x93, 0xac, 0x21}, {0xf4, 0x3f, 0x4c, 0x5b, 0x75, 0x8d, 0x2d, 0x77, 0xe3, 0xbc, 0xdf, 0xff, 0xf9, 0xd0, 0x77, 0x76, 0x1f, 0x40, 0x8e, 0xa2, 0x08, 0xb8, 0xa3, 0x10, 0x6e, 0xc8, 0x49, 0xb3, 0x46, 0x5b, 0x6e, 0x3f}}, + {{0x7c, 0x36, 0xbe, 0xf1, 0x87, 0xd8, 0x85, 0x55, 0x59, 0xb6, 0x3a, 0xa5, 0x5a, 0xcc, 0x07, 0xaf, 0x46, 0x17, 0xa8, 0x35, 0xe1, 0x92, 0x3e, 0x92, 0x83, 0xf1, 0x4d, 0xf2, 0x8c, 0x26, 0xf2, 0x3b}, {0x4d, 0xa7, 0x78, 0x5e, 0x73, 0x04, 0xe6, 0x6f, 0x47, 0x84, 0x46, 0xb7, 0x91, 0x90, 0xa1, 0x39, 0xeb, 0xcb, 0xed, 0xb7, 0x5e, 0xc4, 0x94, 0xa5, 0xc3, 0xec, 0xca, 0x4c, 0xda, 0x13, 0xc9, 0x0b}}, + {{0x03, 0x49, 0x37, 0xc5, 0x2c, 0x2c, 0xd4, 0x1d, 0x61, 0xae, 0x39, 0xd4, 0xe7, 0x7d, 0xcd, 0xa6, 0x07, 0x4b, 0x7a, 0x3b, 0x7f, 0x89, 0xdb, 0x15, 0xd7, 0x3d, 0x51, 0xce, 0xf8, 0x81, 0x5c, 0x38}, {0xc9, 0x8d, 0x9e, 0x19, 0x1c, 0x0b, 0xd8, 0x0e, 0xed, 0x39, 0x1d, 0x5b, 0x22, 0x67, 0xe2, 0x79, 0x2f, 0x07, 0x0b, 0x6c, 0x41, 0x79, 0x04, 0x8b, 0x34, 0xd9, 0x25, 0x53, 0x37, 0xa6, 0x07, 0x15}}, + {{0x35, 0x46, 0xad, 0x84, 0xeb, 0x86, 0x31, 0xaf, 0x36, 0x03, 0xd3, 0xcc, 0x31, 0x63, 0x79, 0xa7, 0x1f, 0x67, 0x7c, 0xc6, 0xe2, 0x6c, 0x28, 0xf1, 0x0a, 0x7c, 0xb2, 0x5c, 0x69, 0xb4, 0xc1, 0x00}, {0xda, 0xa3, 0xae, 0x1c, 0x0e, 0xbe, 0x4f, 0x7c, 0x18, 0xbe, 0x48, 0x02, 0xad, 0x1b, 0x7b, 0xc1, 0x61, 0x6c, 0x0f, 0xc5, 0x03, 0xf9, 0xdd, 0xbd, 0xe7, 0x03, 0xa9, 0xea, 0x5e, 0x84, 0x3f, 0x2f}}, + {{0x7f, 0x14, 0x4b, 0x26, 0x10, 0x66, 0x38, 0x73, 0x05, 0x70, 0x18, 0xe0, 0xe6, 0xea, 0x8a, 0xe7, 0xfc, 0xb8, 0x92, 0x6e, 0x4d, 0x4f, 0x9e, 0x90, 0x28, 0x3f, 0xb4, 0x98, 0xc4, 0x33, 0xec, 0x20}, {0xea, 0x3e, 0x07, 0x55, 0xa1, 0xea, 0xa8, 0x29, 0x0f, 0x1b, 0x31, 0x2a, 0x7c, 0x22, 0x9d, 0x72, 0x1b, 0x65, 0xee, 0x6d, 0x99, 0x9c, 0x54, 0xb1, 0xf5, 0x17, 0x24, 0x8a, 0xc3, 0x2a, 0x60, 0x30}}, + {{0xe7, 0xd1, 0x38, 0xfc, 0x32, 0x0f, 0xa1, 0x3f, 0x12, 0x2e, 0x0c, 0xd0, 0x6c, 0x71, 0x30, 0x11, 0x07, 0xcf, 0x9c, 0xbb, 0xee, 0xe7, 0x7b, 0x8b, 0xc8, 0xb4, 0x25, 0x7c, 0x4e, 0x0d, 0xdc, 0x03}, {0x4e, 0x49, 0xf0, 0x1c, 0x2f, 0x2d, 0x37, 0xcc, 0xcb, 0xa7, 0x3f, 0x69, 0x71, 0x19, 0x81, 0xf2, 0x89, 0xd7, 0x12, 0x01, 0x23, 0x57, 0xc8, 0x71, 0x5a, 0xd3, 0x68, 0xde, 0x62, 0x40, 0x3a, 0x0b}}, + {{0xf5, 0x3c, 0xe6, 0x8f, 0x5d, 0x96, 0x57, 0x2e, 0x2f, 0xb4, 0xcf, 0x96, 0x75, 0x03, 0x7d, 0x1e, 0x21, 0xf2, 0x71, 0xe0, 0xfa, 0xac, 0xeb, 0xe4, 0x6b, 0xb9, 0xa9, 0x25, 0xaa, 0x30, 0xc8, 0x18}, {0xa5, 0xdb, 0x45, 0xb1, 0x55, 0xc9, 0x35, 0x1e, 0x55, 0x8c, 0x66, 0x4c, 0x39, 0xa2, 0xbf, 0x38, 0xe5, 0x44, 0xe1, 0x0a, 0xc0, 0xb6, 0x79, 0x2b, 0x18, 0xde, 0x1a, 0x2a, 0xf2, 0x70, 0x06, 0x33}}, + {{0x2c, 0x52, 0x89, 0x80, 0x7d, 0xc1, 0x37, 0x03, 0x93, 0x1e, 0x09, 0xe5, 0xf9, 0xb7, 0xf3, 0x8c, 0x82, 0x28, 0xf9, 0x5b, 0x95, 0x00, 0xc2, 0x30, 0x8f, 0x30, 0x74, 0x34, 0x94, 0x6e, 0x03, 0x18}, {0xbb, 0xf3, 0xab, 0x14, 0x60, 0xe9, 0xac, 0x83, 0x48, 0xa2, 0x58, 0x67, 0x89, 0x4c, 0xe9, 0x39, 0x78, 0x22, 0xbb, 0xba, 0xaf, 0x4e, 0x82, 0x3b, 0xbe, 0xab, 0x0e, 0x77, 0x8a, 0xdc, 0xfc, 0x05}}, + {{0xec, 0x11, 0xdc, 0xa6, 0x9f, 0xaf, 0x15, 0x4d, 0x56, 0xb7, 0x83, 0xfa, 0xf7, 0xb4, 0x88, 0x96, 0x12, 0x2c, 0x56, 0xc5, 0x92, 0x95, 0x00, 0xa9, 0xa9, 0x76, 0x3e, 0xc2, 0xb2, 0xf9, 0x31, 0x31}, {0xd1, 0x17, 0x8d, 0x41, 0x0b, 0xbc, 0x77, 0x63, 0x5e, 0x20, 0xa8, 0xa1, 0x2f, 0xc6, 0xc7, 0xbd, 0xe1, 0x27, 0x75, 0xdc, 0x8c, 0xe5, 0x08, 0xb8, 0xa0, 0x0a, 0xea, 0x42, 0x6a, 0x9a, 0xe3, 0x3c}}, + {{0xe0, 0xaa, 0x95, 0x1b, 0x61, 0x36, 0x9c, 0x91, 0x29, 0x1f, 0x70, 0x85, 0xf5, 0xad, 0xc0, 0x21, 0x95, 0x7e, 0x43, 0x0a, 0x24, 0xa8, 0xd8, 0x15, 0x50, 0xe2, 0x5b, 0x97, 0x7f, 0x0e, 0x87, 0x24}, {0x8f, 0x4f, 0x25, 0xd3, 0x42, 0xf9, 0x8a, 0x2b, 0x03, 0x28, 0x0e, 0x9d, 0x93, 0xf2, 0xbf, 0xb8, 0x11, 0x36, 0xe5, 0xfd, 0x01, 0x14, 0x36, 0x2b, 0xe0, 0x6f, 0x25, 0x1e, 0x3d, 0x97, 0x5f, 0x09}}, + {{0xf7, 0xaf, 0xd7, 0xaf, 0x69, 0xca, 0xb5, 0x25, 0x5f, 0x96, 0x67, 0xb6, 0x1b, 0x76, 0x31, 0x57, 0xf6, 0xd5, 0x78, 0xe0, 0x00, 0x80, 0xdb, 0xf0, 0x6c, 0x48, 0x6f, 0x9a, 0x51, 0xd6, 0x5f, 0x10}, {0x25, 0x3a, 0xdf, 0x4e, 0x18, 0x7c, 0xed, 0xf6, 0xc1, 0x26, 0x4c, 0xb5, 0xfc, 0xd2, 0x16, 0xf7, 0x0a, 0xc7, 0xf8, 0xde, 0x72, 0x30, 0x03, 0x83, 0xa8, 0xd8, 0xf9, 0xc6, 0xcc, 0x43, 0x72, 0x3c}}, + {{0x13, 0x29, 0xaf, 0xa1, 0x40, 0xf5, 0x9a, 0xd2, 0x9a, 0xf0, 0x00, 0xed, 0x75, 0x17, 0xf8, 0x86, 0xb6, 0xfc, 0x96, 0x79, 0x8d, 0x72, 0x78, 0xc9, 0xcf, 0x2b, 0x52, 0x5c, 0xcf, 0xc4, 0xaa, 0x15}, {0xa2, 0x65, 0xf6, 0x5b, 0x65, 0x8b, 0xad, 0xcc, 0x0a, 0x8a, 0x3d, 0xfe, 0x29, 0x44, 0x7e, 0x19, 0xef, 0xf7, 0xc8, 0xcb, 0x82, 0x5a, 0x26, 0xbc, 0x7a, 0xcc, 0x33, 0x0c, 0xe9, 0x7b, 0x63, 0x09}}, + {{0x63, 0xf1, 0xa5, 0x9c, 0xce, 0x37, 0xdc, 0x75, 0x67, 0x0d, 0x01, 0xf8, 0x1c, 0x4f, 0xe4, 0x3c, 0x70, 0xae, 0x04, 0xd3, 0x6f, 0x91, 0x33, 0x19, 0xd0, 0x3e, 0xa7, 0x3d, 0x82, 0x28, 0xc9, 0x09}, {0x29, 0x8d, 0x35, 0xeb, 0x5b, 0x78, 0x1a, 0x14, 0x36, 0xca, 0xb8, 0x6b, 0x21, 0x75, 0xa1, 0x10, 0x26, 0x82, 0x64, 0x99, 0x7e, 0xd7, 0x51, 0xcd, 0x6c, 0xb5, 0x38, 0x25, 0xb1, 0x15, 0x96, 0x1d}}, + {{0xd3, 0x54, 0x57, 0x6f, 0xbd, 0xc1, 0x71, 0x7c, 0x6c, 0xb1, 0xdf, 0x95, 0x3d, 0x53, 0xa0, 0xc9, 0xc6, 0x86, 0xeb, 0x48, 0x60, 0x11, 0x45, 0xc9, 0x2e, 0x0d, 0x44, 0x8c, 0xf3, 0xf8, 0xa8, 0x05}, {0x60, 0xf4, 0x88, 0xcf, 0x95, 0x59, 0xd8, 0x11, 0x42, 0x3f, 0xbb, 0xf7, 0x8a, 0x7f, 0xeb, 0x44, 0x5b, 0xea, 0xee, 0x79, 0x43, 0xbb, 0x8c, 0xbe, 0x86, 0x2f, 0x50, 0xed, 0x8f, 0xb9, 0xdc, 0x02}}, + {{0x15, 0xa9, 0x5d, 0x4d, 0xbe, 0xae, 0xa2, 0x4a, 0xec, 0x62, 0x33, 0xb9, 0xb2, 0x6c, 0x25, 0x34, 0x07, 0x66, 0x44, 0x6a, 0x1e, 0xad, 0x29, 0xd2, 0xf8, 0xcb, 0x5f, 0xe6, 0xb2, 0xe2, 0xfd, 0x35}, {0xc0, 0x7c, 0x0a, 0xe1, 0xcc, 0xe5, 0x36, 0x9a, 0x9e, 0x8e, 0x42, 0x64, 0xbf, 0xad, 0x41, 0x7d, 0xc3, 0xdd, 0x7d, 0xe7, 0xb0, 0xaa, 0x4a, 0xc6, 0x86, 0xb0, 0x17, 0xdd, 0x44, 0xce, 0xb6, 0x28}}, + {{0x09, 0xde, 0x57, 0xc7, 0x3e, 0xf0, 0x29, 0x17, 0xd6, 0xdd, 0xae, 0x3c, 0x98, 0xd5, 0x14, 0x87, 0xbe, 0x5c, 0xf8, 0x76, 0x1b, 0x98, 0xbc, 0x46, 0xb6, 0x34, 0xd4, 0x98, 0x5d, 0x7a, 0x7c, 0x1b}, {0xfc, 0xfa, 0x97, 0x0f, 0x81, 0x88, 0x61, 0xfb, 0x00, 0x7d, 0x44, 0x47, 0x53, 0x12, 0x9e, 0x76, 0x66, 0xac, 0x37, 0x6b, 0xe5, 0x94, 0x66, 0xe1, 0xd6, 0x40, 0xa4, 0xaa, 0x2c, 0x59, 0x0d, 0x0e}}, + {{0x74, 0x4e, 0x9a, 0x7b, 0x1c, 0x69, 0x77, 0xb4, 0x8a, 0x99, 0x73, 0xb2, 0xa0, 0xea, 0x61, 0x1c, 0x38, 0x87, 0x69, 0xa8, 0x04, 0x2b, 0x95, 0x92, 0xcb, 0x31, 0x4d, 0xf9, 0xc7, 0xd1, 0xae, 0x18}, {0xa0, 0x3a, 0xa0, 0x91, 0x02, 0xa1, 0xb4, 0x63, 0xe8, 0xe2, 0x00, 0xcd, 0x59, 0x6a, 0x56, 0x84, 0xea, 0x99, 0xfb, 0xf4, 0x76, 0x8f, 0xac, 0xd9, 0x6c, 0x00, 0x19, 0x1f, 0x3c, 0xc3, 0x9a, 0x24}}, + {{0x29, 0xc1, 0xd9, 0x9d, 0xc5, 0xc5, 0x11, 0xa6, 0x9a, 0x3b, 0x0c, 0x46, 0x1e, 0x43, 0x49, 0xb4, 0x07, 0x64, 0xac, 0x50, 0xde, 0x28, 0xca, 0x8a, 0x47, 0xef, 0xa7, 0xa7, 0xa6, 0xf2, 0xe1, 0x2b}, {0x52, 0x1f, 0xca, 0x87, 0xc9, 0x46, 0x4c, 0xa1, 0x62, 0x93, 0xf9, 0xa4, 0xbb, 0xf4, 0xfd, 0x40, 0x47, 0x5d, 0xf0, 0xff, 0xe2, 0x8c, 0xf2, 0x99, 0x23, 0x62, 0xfd, 0x20, 0x72, 0xe6, 0x39, 0x23}}, + {{0xdf, 0x19, 0x53, 0xd5, 0xee, 0x39, 0x7e, 0xb0, 0x9e, 0x7b, 0x63, 0xcd, 0xb6, 0xa2, 0x2e, 0x2e, 0x85, 0x4d, 0x76, 0x58, 0x5c, 0x1c, 0x30, 0xb2, 0x11, 0x6e, 0x3f, 0x85, 0x76, 0x88, 0x01, 0x31}, {0x40, 0xf7, 0x88, 0xfd, 0xbb, 0x01, 0x1c, 0x6d, 0xf9, 0xf0, 0x0e, 0x81, 0x78, 0xec, 0x45, 0xac, 0x53, 0x7c, 0xd9, 0x5e, 0xe7, 0x89, 0x78, 0x91, 0x64, 0xa8, 0xfb, 0x12, 0x72, 0xe7, 0x02, 0x2e}}, + {{0xd8, 0xfb, 0x04, 0xa9, 0x95, 0xce, 0x2b, 0x48, 0x4e, 0xdf, 0xd4, 0xd9, 0xef, 0x45, 0x9f, 0x09, 0xa5, 0x32, 0x6c, 0x03, 0x56, 0x16, 0x70, 0x6e, 0xdf, 0x12, 0xd5, 0x47, 0xd7, 0xcf, 0x38, 0x0a}, {0x79, 0x48, 0x76, 0xac, 0x01, 0x11, 0x0e, 0x57, 0x1a, 0xe4, 0x5e, 0x20, 0x14, 0xff, 0xd6, 0x99, 0x7d, 0xca, 0x64, 0x83, 0xe1, 0x4c, 0xcb, 0xc0, 0xab, 0x88, 0x27, 0x21, 0x0f, 0x3a, 0x21, 0x3f}}, + {{0x89, 0x31, 0x8e, 0x99, 0x05, 0xd7, 0x91, 0xd4, 0x2a, 0x14, 0x3c, 0x66, 0xdc, 0xba, 0xbe, 0x7b, 0xbf, 0x18, 0xcb, 0x63, 0x90, 0x98, 0x71, 0x1d, 0x7b, 0xe5, 0xcc, 0x2b, 0xc5, 0xa1, 0xf8, 0x24}, {0x52, 0x6f, 0x46, 0xb9, 0xab, 0x3f, 0x52, 0x10, 0x17, 0x76, 0x1b, 0x6b, 0x50, 0x61, 0x21, 0x46, 0xbb, 0x15, 0x66, 0x5f, 0x33, 0xb1, 0x2b, 0xe2, 0xe3, 0xd4, 0x4c, 0xc3, 0x2e, 0xbe, 0xf7, 0x00}}, + {{0xa9, 0x11, 0x18, 0x19, 0xc0, 0xba, 0x7c, 0x9b, 0xcd, 0x13, 0x27, 0xbf, 0x33, 0x1c, 0x4a, 0xe1, 0x71, 0x07, 0xd5, 0x4e, 0x6f, 0x67, 0x34, 0x9c, 0xdf, 0xcb, 0xc7, 0xe4, 0xf9, 0xb8, 0xc3, 0x3b}, {0xbe, 0x2b, 0x19, 0x3a, 0xa5, 0xe7, 0xc3, 0xc0, 0x5b, 0x60, 0xa8, 0xd8, 0xc0, 0xbe, 0x97, 0x96, 0xb0, 0x48, 0x8d, 0xd0, 0x8b, 0xdc, 0x32, 0xf8, 0x47, 0xdb, 0x36, 0x7a, 0x64, 0x7d, 0xd3, 0x0a}}, + {{0xa0, 0x77, 0x69, 0xd5, 0xca, 0xdc, 0x49, 0x1a, 0x61, 0xe4, 0x48, 0x2b, 0x40, 0x74, 0x69, 0x27, 0x4a, 0x42, 0xc1, 0xf6, 0xb2, 0xb7, 0x35, 0x76, 0x9f, 0xb8, 0x89, 0xa2, 0xf4, 0x10, 0xe6, 0x2b}, {0x04, 0xfc, 0xf3, 0x3e, 0x67, 0xc1, 0x61, 0x3e, 0xed, 0xf0, 0x47, 0xce, 0x8b, 0x26, 0x4f, 0x70, 0x36, 0xd8, 0xde, 0xd2, 0x5f, 0x3f, 0x45, 0x14, 0xd8, 0x1d, 0xcd, 0x4e, 0x34, 0xd8, 0xc9, 0x2c}}, + {{0x43, 0xe2, 0x43, 0x7c, 0xa7, 0xa2, 0xbe, 0x11, 0x6a, 0x1e, 0x49, 0xbb, 0x58, 0x1a, 0xcc, 0xae, 0x3e, 0x4f, 0x4b, 0x84, 0x6c, 0x3b, 0x18, 0xad, 0x01, 0x8c, 0x78, 0x1e, 0xa8, 0x29, 0xf2, 0x3a}, {0xdd, 0x46, 0x57, 0x38, 0x11, 0x88, 0xc9, 0xe5, 0x5b, 0x06, 0x4b, 0x3f, 0xa6, 0x37, 0xa2, 0x18, 0x6e, 0x50, 0x4f, 0x8a, 0xa3, 0x77, 0xeb, 0x95, 0x9f, 0x9e, 0x81, 0xbb, 0xb4, 0xe7, 0x19, 0x0f}}, + {{0xc9, 0xcc, 0x0d, 0x12, 0x95, 0x86, 0x89, 0x42, 0x0d, 0x50, 0x8f, 0xb2, 0xb5, 0x76, 0x47, 0x7c, 0x43, 0x0e, 0x57, 0x62, 0xf6, 0xa0, 0x87, 0x73, 0x6f, 0x72, 0x03, 0x04, 0x75, 0x1a, 0x0a, 0x3e}, {0xd0, 0xe2, 0xa5, 0xf5, 0x7f, 0x61, 0xb8, 0xa4, 0x8f, 0xbe, 0xc0, 0x8d, 0x17, 0x75, 0x01, 0xbf, 0xce, 0xaa, 0x63, 0x57, 0x0f, 0x8a, 0x12, 0x3e, 0xf2, 0xc5, 0x1b, 0x1b, 0xb6, 0x05, 0x19, 0x10}}, + {{0xb0, 0x69, 0x7a, 0xc3, 0x36, 0x63, 0x1c, 0x6a, 0x38, 0xc9, 0x9c, 0x4c, 0xf5, 0xb8, 0x01, 0xab, 0xf1, 0x0f, 0x58, 0x88, 0xc2, 0x77, 0x70, 0x4b, 0x13, 0x93, 0x57, 0x26, 0x62, 0x94, 0x9d, 0x21}, {0xb4, 0xb8, 0x1d, 0x48, 0x54, 0xec, 0xca, 0xf0, 0x19, 0xf8, 0xed, 0x8c, 0x6e, 0x70, 0xaa, 0x9c, 0x27, 0xd9, 0x2d, 0x34, 0xf8, 0x4c, 0x2e, 0x89, 0x19, 0x95, 0xa8, 0xc2, 0x80, 0x19, 0x1c, 0x24}}, + {{0xc3, 0x4c, 0x36, 0xeb, 0x3e, 0x58, 0x57, 0x22, 0x88, 0x50, 0x28, 0xd5, 0x7e, 0x3e, 0x29, 0x27, 0xcd, 0x6f, 0xf9, 0x60, 0x57, 0x14, 0xca, 0x7e, 0xb6, 0x9b, 0x40, 0xd5, 0xfd, 0x41, 0x6d, 0x36}, {0xf9, 0x19, 0x82, 0x1e, 0x59, 0x29, 0xfe, 0x8b, 0x16, 0xe2, 0xec, 0xef, 0x22, 0x17, 0xcf, 0xbb, 0xfe, 0xa5, 0xee, 0x03, 0x43, 0xfd, 0x60, 0x95, 0xa8, 0xfa, 0x6f, 0x05, 0xf4, 0xcc, 0xa2, 0x01}}, + {{0x4c, 0xa9, 0x18, 0x52, 0x0b, 0xad, 0xb5, 0xf4, 0x54, 0x93, 0x6d, 0xdd, 0x90, 0x90, 0x24, 0x3a, 0x7c, 0xc5, 0x87, 0xde, 0x69, 0x0f, 0xdc, 0x98, 0x3e, 0x40, 0xf1, 0x5f, 0x7c, 0x35, 0xda, 0x3d}, {0x3a, 0xb1, 0x5d, 0xc8, 0x9b, 0x45, 0x19, 0x51, 0x40, 0x7f, 0xb0, 0x90, 0x0c, 0x72, 0xfc, 0x2b, 0x81, 0xd5, 0x8b, 0xf8, 0x1d, 0x0f, 0x37, 0x85, 0x98, 0xa2, 0x0e, 0xc0, 0x6e, 0x22, 0xdb, 0x37}}, + {{0xd2, 0x77, 0xa1, 0x39, 0xa9, 0x23, 0xb3, 0x63, 0xcc, 0x01, 0x3d, 0x71, 0x48, 0x97, 0x2f, 0xe6, 0xbf, 0x59, 0xa1, 0xa0, 0x50, 0x90, 0x08, 0x25, 0x1d, 0x85, 0xb8, 0xe9, 0x78, 0x7c, 0x7c, 0x3d}, {0xce, 0x6f, 0xb2, 0xb4, 0xcb, 0x54, 0x84, 0x39, 0xb9, 0xd4, 0x1f, 0xb1, 0xb1, 0xf1, 0x6e, 0xc0, 0x97, 0xa2, 0xd7, 0xe7, 0x1c, 0x78, 0x56, 0x44, 0x53, 0xf4, 0xb8, 0xf1, 0x94, 0x81, 0xcd, 0x04}}, + {{0xf4, 0x7a, 0x17, 0xb6, 0xcb, 0x83, 0x48, 0x18, 0xd5, 0xc3, 0xfe, 0xa4, 0x6c, 0x54, 0x57, 0x2d, 0x0a, 0xdc, 0x32, 0x92, 0xa8, 0xe3, 0x4d, 0x98, 0x76, 0xf5, 0x13, 0xb3, 0x7a, 0x7d, 0xe5, 0x0f}, {0xb7, 0x2d, 0x0e, 0x70, 0xb1, 0x4a, 0x5f, 0x67, 0x27, 0x71, 0x0d, 0x3a, 0xdd, 0x6b, 0x44, 0xb0, 0x80, 0x80, 0x74, 0xc1, 0xa3, 0xc6, 0x66, 0x8d, 0xfb, 0x92, 0x52, 0x05, 0x89, 0xae, 0x9e, 0x33}}, + {{0xce, 0xb6, 0x97, 0x54, 0xe7, 0x46, 0xc6, 0x28, 0x01, 0xd1, 0x08, 0x09, 0x3a, 0x75, 0xfa, 0xa3, 0xdc, 0x2a, 0x5d, 0x06, 0xf5, 0xd0, 0x09, 0x1f, 0x73, 0x15, 0x6e, 0x21, 0xdd, 0xd1, 0x8a, 0x17}, {0x57, 0x1e, 0x41, 0xb0, 0x06, 0xa3, 0x0e, 0x03, 0xa9, 0xbd, 0x28, 0xdf, 0xec, 0x03, 0x2a, 0x76, 0x1c, 0xb5, 0xc9, 0xec, 0x5a, 0xf3, 0xc1, 0xa2, 0x31, 0xe1, 0x3f, 0x80, 0x14, 0x71, 0x7f, 0x03}}, + {{0x66, 0x83, 0x53, 0x94, 0xbb, 0xb5, 0xea, 0x59, 0x24, 0x30, 0xf0, 0xc2, 0xf8, 0x07, 0xd1, 0x5f, 0xf2, 0x85, 0xa0, 0x77, 0x0a, 0x9e, 0x1f, 0x49, 0x46, 0x33, 0xd6, 0x5a, 0xba, 0x5b, 0x48, 0x19}, {0x40, 0xf7, 0xf6, 0x5f, 0x70, 0x85, 0x7d, 0xe0, 0xfb, 0xeb, 0x8f, 0xf7, 0x4b, 0x9f, 0xeb, 0xa7, 0xe2, 0x87, 0x74, 0xba, 0xd5, 0xd8, 0xc7, 0x4e, 0x48, 0xa4, 0xd3, 0x1a, 0x0c, 0xbf, 0x2f, 0x15}}, + {{0x04, 0xe3, 0x8a, 0xb8, 0xb7, 0xa4, 0x51, 0x89, 0xe5, 0x2d, 0xd6, 0x63, 0x94, 0xf4, 0xba, 0xfb, 0x04, 0xb6, 0xfb, 0x46, 0xcf, 0xf4, 0xdc, 0x52, 0x53, 0x82, 0xa2, 0xf0, 0xaf, 0x61, 0x67, 0x38}, {0x55, 0xf2, 0x3d, 0x0c, 0x33, 0xa3, 0x9e, 0xa7, 0xfa, 0x7b, 0xf3, 0xef, 0x06, 0x18, 0xc0, 0x98, 0xd6, 0xbc, 0xb8, 0x36, 0x7b, 0x7c, 0x04, 0xce, 0xea, 0xed, 0x63, 0xc3, 0xf4, 0xa7, 0x8b, 0x3c}}, + {{0xef, 0x0a, 0xab, 0x71, 0x61, 0xf6, 0x3d, 0xaf, 0xb0, 0xcc, 0xb7, 0xfe, 0x27, 0xdf, 0x2a, 0xf4, 0x4e, 0x71, 0xe0, 0x95, 0x6a, 0x09, 0x52, 0xf6, 0x00, 0xdc, 0x9f, 0xbb, 0x2e, 0x2f, 0xd2, 0x12}, {0x1a, 0x7e, 0x5c, 0x74, 0x3b, 0xe1, 0xd3, 0x2b, 0x31, 0x47, 0x3b, 0x1c, 0xed, 0x8b, 0xd5, 0x30, 0x6c, 0x0e, 0x6d, 0x15, 0x60, 0xde, 0xe9, 0x4f, 0xe1, 0xa5, 0x6c, 0x04, 0xca, 0x82, 0x75, 0x1e}}, + {{0x4e, 0xbe, 0x30, 0x2d, 0x3a, 0x3b, 0x26, 0x4b, 0x4e, 0x9c, 0x9e, 0xef, 0xb5, 0xe1, 0x03, 0xa3, 0x4d, 0xd3, 0x78, 0x1f, 0xc7, 0xd3, 0x0c, 0x1a, 0x09, 0x1a, 0x93, 0x2b, 0xe2, 0xcb, 0xc6, 0x0b}, {0xe6, 0x78, 0x50, 0xc9, 0x0a, 0x54, 0xf8, 0x5e, 0x85, 0x5e, 0x65, 0x85, 0x0b, 0xb7, 0x90, 0x5d, 0x78, 0x4c, 0xe6, 0x36, 0x17, 0xc7, 0x53, 0xed, 0x66, 0x91, 0x79, 0x30, 0x8a, 0x46, 0x86, 0x16}}, + {{0x48, 0x9e, 0x31, 0xb7, 0x14, 0xdd, 0x0d, 0x0d, 0xdc, 0x3f, 0x91, 0x53, 0x82, 0xbc, 0x2e, 0x71, 0xba, 0x08, 0x1e, 0xb5, 0xa4, 0xdd, 0xcf, 0x5f, 0x78, 0xfe, 0x44, 0x2d, 0xeb, 0x06, 0x3d, 0x2f}, {0x2d, 0xf3, 0xb3, 0xa0, 0x34, 0x86, 0x69, 0xa5, 0x50, 0x95, 0x30, 0x0d, 0xd0, 0xe6, 0xa6, 0xc8, 0x58, 0x9f, 0x20, 0x96, 0x74, 0x82, 0xe7, 0x89, 0x05, 0x64, 0x90, 0x5b, 0x04, 0xf1, 0xb3, 0x05}}, + {{0xf1, 0x5e, 0x3f, 0xc9, 0xab, 0x9f, 0x56, 0x65, 0xf0, 0x3f, 0xb0, 0xe5, 0x45, 0xfb, 0x77, 0x8c, 0x5d, 0x0d, 0x61, 0xa6, 0x04, 0x44, 0x62, 0x14, 0xa9, 0x8c, 0x12, 0x8c, 0x82, 0xfd, 0x31, 0x14}, {0x2a, 0x53, 0x81, 0x7a, 0xe0, 0xff, 0xf4, 0xe0, 0x73, 0xe5, 0x45, 0x76, 0x69, 0xe0, 0x54, 0x62, 0x2a, 0x82, 0xfd, 0x19, 0x4b, 0xfa, 0x42, 0x36, 0x52, 0xbb, 0x91, 0x03, 0x35, 0xd1, 0x85, 0x24}}, + {{0x25, 0x49, 0x66, 0xb2, 0x06, 0xe3, 0x68, 0x57, 0x52, 0xf6, 0x29, 0xe7, 0xa1, 0xfd, 0xef, 0xd2, 0xc0, 0xa9, 0x9c, 0x31, 0x7c, 0xd4, 0xc6, 0x21, 0xee, 0xb3, 0x4d, 0xe5, 0x36, 0x0c, 0x01, 0x24}, {0x80, 0x0b, 0x1b, 0xeb, 0xfc, 0x90, 0x51, 0x49, 0xf2, 0x91, 0x04, 0xee, 0x15, 0xc3, 0xc2, 0xf0, 0xd6, 0xb3, 0x07, 0x13, 0x08, 0x9d, 0xbc, 0x61, 0x64, 0xa2, 0x07, 0x36, 0x3e, 0xb7, 0x4a, 0x02}}, + {{0x3f, 0xef, 0xf4, 0x54, 0x7e, 0x38, 0x7f, 0x10, 0x6b, 0xf5, 0x43, 0x0a, 0xda, 0x32, 0x0a, 0x29, 0x09, 0x09, 0x83, 0x4e, 0x56, 0x86, 0x9f, 0x8b, 0x03, 0x62, 0xae, 0xb6, 0x45, 0x0f, 0x7f, 0x27}, {0x0e, 0x4c, 0xcc, 0xf5, 0x65, 0x28, 0x6b, 0x54, 0x10, 0x00, 0xbf, 0x07, 0xd6, 0x55, 0x70, 0x82, 0x71, 0x03, 0x61, 0xfe, 0xbd, 0x68, 0x7e, 0x3f, 0x35, 0x72, 0x4d, 0x0f, 0x45, 0xeb, 0x87, 0x16}}, + {{0x48, 0x26, 0x6d, 0x31, 0xac, 0x4e, 0xa6, 0x78, 0xaa, 0x50, 0x7f, 0xa6, 0x21, 0x25, 0x3e, 0x75, 0xfd, 0x46, 0x1f, 0xf1, 0xa5, 0x79, 0x78, 0x6e, 0xb7, 0x6e, 0xda, 0xb1, 0xff, 0x18, 0xd9, 0x05}, {0xe9, 0x3a, 0xc9, 0x9b, 0x63, 0x58, 0xb9, 0xba, 0x55, 0x57, 0xcf, 0x04, 0x46, 0x3f, 0x7b, 0xc3, 0xdf, 0xd2, 0x29, 0x9f, 0x79, 0xae, 0xe4, 0x7d, 0xa3, 0x00, 0x0c, 0x06, 0xa6, 0xe1, 0x7b, 0x04}}, + {{0xb6, 0x7c, 0xdf, 0x61, 0xc2, 0x71, 0xc8, 0x49, 0x1a, 0x0b, 0xea, 0xe9, 0x6c, 0xca, 0x80, 0x53, 0x0e, 0xfe, 0xb8, 0x41, 0x03, 0x44, 0x5a, 0xd0, 0x1c, 0x3d, 0x5f, 0x03, 0x8c, 0xd1, 0x0c, 0x08}, {0x4a, 0x24, 0x94, 0xa8, 0xb3, 0xe1, 0x74, 0x52, 0xb2, 0x7f, 0x1e, 0xa2, 0xaf, 0x74, 0xdc, 0xde, 0xb4, 0x54, 0xee, 0x99, 0x0d, 0x5f, 0xb1, 0xef, 0xf6, 0xdb, 0xb6, 0x4e, 0x62, 0x32, 0x4c, 0x16}}, + {{0x77, 0x68, 0x88, 0xd5, 0x53, 0xab, 0x0a, 0x72, 0xae, 0xdf, 0x71, 0x16, 0xf8, 0x5c, 0xaa, 0xce, 0xe7, 0x52, 0x05, 0x54, 0x16, 0x9e, 0x4b, 0x6d, 0xbe, 0x06, 0x3f, 0x23, 0xfa, 0x47, 0x6c, 0x1c}, {0x3f, 0xaa, 0xa4, 0xf4, 0x0a, 0x3c, 0xf5, 0x61, 0x9a, 0x38, 0xf0, 0xb4, 0x34, 0x23, 0x58, 0x52, 0xfe, 0xf8, 0xaa, 0x50, 0x30, 0xdb, 0xa1, 0xc8, 0x5c, 0x47, 0x6c, 0xc4, 0x34, 0xdb, 0xdc, 0x26}}, + {{0x89, 0x3e, 0x40, 0x38, 0x70, 0x29, 0x08, 0x32, 0xe3, 0x4f, 0xf1, 0x19, 0x3b, 0x59, 0xa1, 0x90, 0xe4, 0x1b, 0xd7, 0xe6, 0x71, 0xee, 0xf3, 0x09, 0x5e, 0x53, 0x4a, 0x13, 0x25, 0x8f, 0x1f, 0x0e}, {0x12, 0x76, 0xac, 0xb1, 0xf9, 0xb8, 0x19, 0xd5, 0x46, 0x58, 0x74, 0x90, 0x0e, 0x85, 0xf7, 0x91, 0x28, 0x2b, 0xcf, 0x08, 0x11, 0x36, 0x46, 0x88, 0x4c, 0x0d, 0xe0, 0x73, 0x2b, 0xa6, 0xea, 0x13}}, + {{0x6f, 0xc6, 0x5a, 0x44, 0x53, 0xa3, 0x39, 0x4f, 0xb7, 0x84, 0xba, 0xe1, 0x67, 0xa7, 0x9d, 0xb5, 0xa8, 0xaf, 0x54, 0x09, 0x04, 0x9c, 0x17, 0x37, 0xd8, 0xb6, 0x6a, 0xd6, 0x36, 0xf2, 0xcf, 0x2f}, {0x7b, 0x59, 0x6a, 0x0d, 0x95, 0xf2, 0x1a, 0x68, 0x0a, 0x72, 0x25, 0x60, 0xae, 0x9c, 0x42, 0x56, 0x4d, 0x57, 0x5c, 0x76, 0x8d, 0x99, 0x44, 0x8a, 0xd2, 0x6e, 0x17, 0x10, 0x7e, 0xe6, 0xee, 0x12}}, + {{0xee, 0xbf, 0x04, 0xaf, 0xf1, 0x66, 0x10, 0xa3, 0x90, 0x65, 0x79, 0xfb, 0x36, 0xea, 0x37, 0x25, 0xb9, 0x75, 0xe1, 0x64, 0xf6, 0x25, 0xa7, 0xb3, 0x5e, 0xd0, 0x35, 0x9e, 0x7e, 0x93, 0x88, 0x07}, {0xa2, 0xa0, 0x9f, 0x8f, 0x7e, 0xdf, 0x4e, 0xb5, 0x21, 0xa9, 0x73, 0x9b, 0x00, 0x20, 0x62, 0xe3, 0xfb, 0xae, 0x4f, 0xcd, 0x46, 0x8c, 0xdb, 0xf8, 0xda, 0xde, 0x90, 0xb5, 0xee, 0x43, 0x19, 0x25}}, + {{0xcb, 0x77, 0x18, 0xde, 0x82, 0x2b, 0x8e, 0xa8, 0x59, 0xd0, 0x6c, 0xe4, 0xd7, 0xf5, 0x94, 0x8b, 0xda, 0x1f, 0x54, 0x32, 0x81, 0x03, 0xa7, 0x87, 0x91, 0x2e, 0xf3, 0xf5, 0x8f, 0x72, 0xb7, 0x22}, {0x97, 0xf9, 0x50, 0xfa, 0x69, 0x78, 0x3d, 0x67, 0xa3, 0x51, 0xd2, 0xf4, 0x99, 0x24, 0x19, 0x97, 0xd3, 0xb1, 0xc7, 0xcf, 0xa8, 0x1d, 0x21, 0x1c, 0x37, 0x99, 0xac, 0x77, 0x60, 0x9b, 0xcb, 0x2b}}, + {{0xb6, 0xae, 0x91, 0x0e, 0x35, 0x8e, 0x85, 0xa6, 0xe8, 0xda, 0x3e, 0x42, 0x16, 0x6a, 0xa5, 0x97, 0x54, 0x0e, 0xa0, 0x28, 0xa2, 0x8d, 0xd3, 0xf9, 0x3a, 0x57, 0xaa, 0x12, 0xfb, 0x88, 0x9b, 0x1e}, {0x22, 0xc3, 0x0c, 0x2d, 0xb7, 0x63, 0xe1, 0x9b, 0xed, 0x8c, 0x70, 0x39, 0xd4, 0x4c, 0x50, 0x66, 0x37, 0xab, 0x3e, 0xc4, 0xca, 0xff, 0xb1, 0xd3, 0xfe, 0x60, 0x97, 0x9f, 0x8a, 0xb2, 0x46, 0x11}}, + {{0x34, 0x89, 0xb1, 0xa8, 0x9e, 0xd2, 0xda, 0xda, 0x9b, 0x53, 0x06, 0x36, 0x0f, 0x94, 0x50, 0x12, 0x76, 0x88, 0xf1, 0x6c, 0x39, 0xb1, 0x2b, 0xde, 0x65, 0x63, 0x28, 0x9f, 0x63, 0xcf, 0xe8, 0x11}, {0xa6, 0x5a, 0x02, 0x21, 0x8c, 0x5f, 0x15, 0x50, 0xfb, 0x1d, 0x67, 0x45, 0x88, 0xd8, 0xa1, 0xa1, 0xb2, 0x0f, 0x36, 0xd2, 0x35, 0x08, 0x27, 0x49, 0x7b, 0xb8, 0x96, 0xb9, 0x82, 0x55, 0x53, 0x27}}, + {{0x8f, 0xca, 0xb4, 0xe0, 0x92, 0xe4, 0xc5, 0x8c, 0x48, 0x3c, 0xc6, 0xb0, 0xf7, 0x29, 0x8f, 0xb2, 0x1e, 0x77, 0xa2, 0x32, 0x10, 0xef, 0x38, 0x7e, 0xad, 0x32, 0x37, 0xe6, 0x43, 0xc5, 0x13, 0x33}, {0x0c, 0x73, 0x2c, 0xeb, 0x57, 0x4d, 0x69, 0x76, 0x08, 0xfe, 0xf7, 0xb3, 0xc0, 0x9e, 0x74, 0x05, 0xa4, 0xf1, 0x49, 0xe4, 0x53, 0x24, 0xa7, 0x20, 0x12, 0x80, 0x60, 0x4f, 0x56, 0xc6, 0x70, 0x20}}, + {{0x4c, 0x00, 0x6a, 0x23, 0x43, 0x1a, 0xc2, 0x7e, 0xdb, 0x56, 0x13, 0x5d, 0x43, 0x0e, 0x75, 0xa0, 0x7d, 0x76, 0xd9, 0xa0, 0xde, 0x38, 0xfe, 0xf3, 0x10, 0x01, 0x62, 0xb5, 0x93, 0xf0, 0x37, 0x03}, {0x24, 0x5d, 0x06, 0x74, 0x84, 0x71, 0xce, 0x62, 0xaf, 0x55, 0xd5, 0x81, 0xa5, 0xc9, 0xbb, 0x6b, 0xea, 0xbe, 0x18, 0x60, 0xe6, 0x4e, 0x2d, 0xfa, 0xa0, 0xdc, 0xe7, 0xe7, 0x54, 0xc6, 0x0b, 0x28}}, + {{0xfb, 0x44, 0xc2, 0xb0, 0x3d, 0x91, 0xe1, 0xb0, 0x38, 0x59, 0x8e, 0x21, 0xc4, 0xd9, 0xa4, 0xaa, 0xc6, 0x28, 0xd6, 0x5f, 0x6b, 0x9b, 0x46, 0x35, 0x22, 0xb2, 0xd3, 0x43, 0x07, 0x91, 0x95, 0x23}, {0x9e, 0xe9, 0x4c, 0x4b, 0x9b, 0x12, 0xaa, 0x5c, 0xec, 0x85, 0x13, 0x53, 0xaa, 0xec, 0x45, 0xef, 0x2b, 0xfb, 0xc2, 0xc8, 0xcc, 0xa2, 0x0f, 0x9c, 0x0a, 0xb8, 0x18, 0xf5, 0x31, 0x81, 0x9c, 0x18}}, + {{0xdd, 0xa4, 0x13, 0xb0, 0x6c, 0x42, 0x2c, 0x03, 0xa0, 0xd9, 0x17, 0x33, 0x5a, 0x5e, 0x1b, 0xe1, 0x80, 0x3b, 0x0d, 0x83, 0xfd, 0xb9, 0x92, 0x14, 0xd4, 0x55, 0x5c, 0xcf, 0x94, 0x9d, 0xf1, 0x05}, {0x03, 0xd0, 0x3d, 0x67, 0x04, 0x47, 0x4c, 0x2c, 0x07, 0x8d, 0xd8, 0x97, 0xaf, 0x29, 0x8e, 0xc4, 0xdf, 0x53, 0xd8, 0x91, 0x3d, 0xdd, 0x27, 0xd1, 0x05, 0x64, 0xd8, 0xf2, 0x52, 0xc0, 0x94, 0x0d}}, + {{0x09, 0x36, 0xb9, 0xd4, 0xc9, 0x7b, 0x81, 0x02, 0x92, 0xa5, 0xd4, 0x2d, 0x0d, 0x6a, 0x46, 0xfd, 0x94, 0xc4, 0x3c, 0x05, 0xad, 0xd5, 0xbf, 0xd7, 0xf6, 0x06, 0x06, 0xc9, 0x6d, 0x09, 0x23, 0x3e}, {0xbb, 0xd0, 0x48, 0xcf, 0xad, 0xa2, 0x1b, 0xca, 0xbd, 0x5e, 0x12, 0xe6, 0x9e, 0x2a, 0x88, 0x48, 0xaa, 0xfa, 0xcd, 0x33, 0x00, 0xf3, 0x57, 0xa8, 0x77, 0x9f, 0x10, 0x29, 0xb5, 0xd8, 0x0d, 0x0c}}, + {{0x1b, 0x57, 0x16, 0xcd, 0x76, 0x2c, 0xaa, 0x63, 0xee, 0x9e, 0x5d, 0xf3, 0xee, 0x27, 0x08, 0x67, 0x28, 0x8f, 0x30, 0xed, 0x0c, 0x37, 0x32, 0xf7, 0x28, 0xb2, 0x45, 0x9c, 0x0f, 0x69, 0xe7, 0x2c}, {0x00, 0x22, 0xda, 0xd2, 0xe5, 0x8f, 0x08, 0xcf, 0x4a, 0x5a, 0x79, 0x3b, 0xa5, 0x35, 0x75, 0x6b, 0x58, 0x3d, 0xeb, 0x35, 0xc6, 0x78, 0xdd, 0x6c, 0xd4, 0xbe, 0x94, 0xe7, 0x57, 0xda, 0x8b, 0x08}}, + {{0xfa, 0x04, 0x82, 0x35, 0xf2, 0x90, 0x92, 0x4f, 0x0f, 0x6e, 0x7a, 0xce, 0xd5, 0x9b, 0x25, 0xbc, 0x6a, 0x59, 0x99, 0xfd, 0xba, 0x7d, 0x44, 0xe9, 0x27, 0xa6, 0xea, 0xbb, 0x69, 0xa3, 0x51, 0x21}, {0xd1, 0x83, 0x99, 0x4d, 0x08, 0x3f, 0x1e, 0xc1, 0x9b, 0x61, 0x7b, 0x3a, 0x0e, 0x88, 0x2d, 0x3a, 0xfc, 0x11, 0xf2, 0x75, 0x46, 0xdf, 0xce, 0xa9, 0xa8, 0x79, 0x41, 0x8a, 0x40, 0xe1, 0x3b, 0x15}}, + {{0x15, 0x4e, 0xaa, 0x32, 0x0b, 0xed, 0xb4, 0x16, 0x3e, 0x16, 0x03, 0xe0, 0x26, 0x98, 0x02, 0x5d, 0xc2, 0xfe, 0xf9, 0x12, 0xa0, 0x90, 0x74, 0xa6, 0xde, 0xe0, 0xd4, 0x13, 0xf3, 0x0d, 0xb1, 0x13}, {0xc9, 0x6f, 0xbf, 0x0d, 0x14, 0x58, 0xc3, 0xfa, 0xd8, 0x64, 0xdd, 0xf3, 0xe3, 0xdb, 0x97, 0x8d, 0x8e, 0x19, 0x73, 0xb9, 0xc5, 0x80, 0x04, 0xf6, 0xfe, 0x30, 0xc7, 0xc4, 0xa1, 0x6b, 0x44, 0x0e}}, + {{0xfc, 0xb3, 0x67, 0xd6, 0xce, 0x02, 0xe5, 0x53, 0x31, 0xb6, 0x35, 0x2d, 0x92, 0xf2, 0x6f, 0xbd, 0x89, 0xb2, 0x78, 0x0c, 0x81, 0x76, 0x1e, 0x51, 0xa6, 0xc3, 0xeb, 0xf2, 0x68, 0xb9, 0xd9, 0x35}, {0x8d, 0x3f, 0x59, 0x17, 0xa7, 0xf3, 0x3b, 0x4b, 0xbf, 0x7e, 0x76, 0x99, 0x38, 0x76, 0x20, 0x48, 0x60, 0x4f, 0x4e, 0x96, 0x03, 0x67, 0x49, 0x15, 0xf0, 0x33, 0xf0, 0x43, 0xa1, 0x81, 0x3d, 0x15}}, + {{0x01, 0xff, 0xe5, 0x3d, 0xfc, 0x52, 0xba, 0x31, 0xe2, 0xec, 0xd1, 0xb9, 0x41, 0x2b, 0x6a, 0x37, 0xa0, 0x2d, 0xe8, 0xdc, 0x31, 0x83, 0xfc, 0x62, 0x80, 0xa7, 0xac, 0xf6, 0x44, 0x57, 0x8f, 0x11}, {0xa0, 0xf7, 0xa7, 0x1e, 0x68, 0xdf, 0xe6, 0xb1, 0x95, 0xf4, 0xeb, 0x1d, 0x63, 0xd3, 0xad, 0x40, 0x8b, 0xcb, 0x5f, 0x08, 0xbb, 0xda, 0xbc, 0x41, 0x47, 0x22, 0xc1, 0x42, 0x20, 0xf0, 0x4f, 0x36}}, + {{0x0e, 0xd0, 0x9e, 0x0c, 0x38, 0x16, 0xb4, 0x36, 0xdb, 0xd1, 0xa4, 0x10, 0xdc, 0xbf, 0xe0, 0x51, 0xab, 0xae, 0xb5, 0x4a, 0x35, 0x58, 0x3c, 0x91, 0x89, 0x13, 0x29, 0x6a, 0x64, 0x7d, 0xab, 0x0f}, {0xab, 0x99, 0x38, 0xc4, 0xa5, 0x18, 0x21, 0x33, 0xa2, 0xff, 0x9a, 0xec, 0x69, 0xef, 0x16, 0xaf, 0x00, 0xd1, 0x0b, 0xaf, 0xaa, 0x59, 0xb2, 0xc1, 0x47, 0x73, 0x7c, 0xef, 0x07, 0x66, 0x75, 0x05}}, + {{0x34, 0x98, 0xa1, 0xfa, 0x18, 0x08, 0xe0, 0x74, 0xfd, 0x60, 0xed, 0x6b, 0x7c, 0x2b, 0x98, 0xfb, 0x74, 0x46, 0xbd, 0x2e, 0x5a, 0x23, 0xe3, 0xdd, 0xb6, 0xf4, 0xa3, 0xfd, 0x74, 0x52, 0x5a, 0x21}, {0xce, 0xcd, 0x4d, 0xc5, 0x83, 0x97, 0x6c, 0x10, 0x54, 0x54, 0x71, 0x1a, 0x46, 0x72, 0x28, 0xe1, 0xc3, 0x1d, 0x3a, 0xc9, 0x85, 0x6b, 0xf3, 0xd4, 0x70, 0x4b, 0xf9, 0xd9, 0xc5, 0x92, 0x6e, 0x0c}}, + {{0x15, 0x46, 0xc0, 0xc0, 0x26, 0xd7, 0x65, 0x1b, 0xda, 0x7e, 0x7b, 0x19, 0x63, 0xe8, 0x8b, 0xbf, 0xd1, 0xbf, 0x52, 0x24, 0xb1, 0xe0, 0xd7, 0xaa, 0x89, 0x9c, 0xd8, 0xa5, 0x5c, 0x41, 0x11, 0x35}, {0x63, 0x6f, 0x96, 0x49, 0x78, 0x0a, 0x33, 0xd8, 0xd4, 0xf6, 0x6b, 0x4b, 0x47, 0x64, 0xe1, 0x30, 0x7c, 0x10, 0x59, 0x13, 0x50, 0x7c, 0xff, 0xca, 0x61, 0x5c, 0xf1, 0x91, 0x5e, 0xff, 0x52, 0x09}}, + {{0x74, 0xe9, 0x4a, 0xa3, 0xde, 0x79, 0x03, 0x0d, 0x1a, 0xd7, 0x73, 0x86, 0x1f, 0x56, 0x94, 0xcc, 0xbf, 0xfd, 0x1b, 0xd1, 0xe3, 0xc0, 0x1a, 0x13, 0xd8, 0x41, 0xc7, 0x6a, 0x19, 0xc0, 0xf8, 0x25}, {0x4e, 0x30, 0x4d, 0x89, 0x04, 0x34, 0x4d, 0xc1, 0xe9, 0x16, 0xb3, 0x6a, 0xa9, 0x69, 0x83, 0x16, 0xa8, 0xed, 0x9c, 0xcd, 0x70, 0xbc, 0x35, 0x37, 0xa5, 0x48, 0x23, 0xf5, 0x3a, 0x44, 0xb4, 0x37}}, + {{0x68, 0x75, 0x2e, 0x19, 0x6e, 0x1c, 0x56, 0x99, 0xa8, 0x44, 0x9a, 0xd7, 0x87, 0xbe, 0xe7, 0x65, 0xa5, 0xcf, 0xf7, 0x88, 0x69, 0x13, 0x77, 0xc4, 0x1f, 0xf9, 0x6a, 0x1f, 0xd1, 0xd2, 0x08, 0x2e}, {0xeb, 0xaf, 0x4d, 0xcf, 0x78, 0x68, 0x16, 0x8a, 0x6c, 0xde, 0x05, 0xe7, 0xd6, 0x04, 0xb3, 0xab, 0xa7, 0x15, 0xdc, 0x89, 0x14, 0xc8, 0x59, 0x08, 0x6f, 0xb4, 0x79, 0xa0, 0x75, 0x07, 0x4d, 0x27}}, + {{0x13, 0xeb, 0xa8, 0x4f, 0xa8, 0x11, 0x3d, 0xdb, 0xaf, 0xd6, 0xd3, 0x9a, 0xa8, 0x7e, 0x3a, 0xea, 0xae, 0x4c, 0xf1, 0x3a, 0x35, 0xaf, 0x81, 0x99, 0xd9, 0xdf, 0xe8, 0x7a, 0x1e, 0xc0, 0x38, 0x2b}, {0x77, 0x80, 0x06, 0x3c, 0xc0, 0xde, 0x0d, 0x83, 0x38, 0xeb, 0xe2, 0x51, 0x90, 0xfa, 0x2d, 0x42, 0xbc, 0x76, 0x0c, 0xd1, 0x0d, 0x0d, 0xf7, 0xb8, 0xac, 0x88, 0x51, 0x0e, 0x67, 0x5d, 0x9f, 0x05}}, + {{0x0e, 0xe1, 0xbd, 0xe2, 0xf8, 0x97, 0x10, 0xd9, 0xa0, 0x53, 0x28, 0x8f, 0x52, 0x4c, 0x49, 0x2f, 0x3b, 0x92, 0xab, 0xb3, 0x81, 0xd4, 0xce, 0x18, 0x82, 0x84, 0x18, 0xa7, 0xdb, 0xe3, 0xd9, 0x25}, {0x86, 0x09, 0x95, 0xba, 0x05, 0x80, 0xa7, 0xd5, 0x56, 0x25, 0x6d, 0xd7, 0x67, 0x23, 0xff, 0xca, 0x94, 0x10, 0xf5, 0xd2, 0x15, 0x0e, 0x49, 0xfd, 0x01, 0xc1, 0x2e, 0x73, 0xa9, 0x51, 0xec, 0x04}}, + {{0x37, 0xc2, 0x08, 0x2d, 0x55, 0xb0, 0x75, 0x9f, 0x1f, 0x55, 0x4b, 0xb9, 0xf6, 0x40, 0x7b, 0x8f, 0xd4, 0x02, 0x12, 0x65, 0x65, 0x1d, 0x0a, 0xff, 0x0e, 0x2a, 0xad, 0x44, 0x07, 0x35, 0x59, 0x32}, {0xfc, 0x87, 0x35, 0x56, 0x7b, 0x00, 0xb0, 0xc3, 0x8b, 0x00, 0x56, 0x15, 0x4c, 0x66, 0xfe, 0x67, 0x4b, 0xa1, 0x90, 0x7c, 0x4e, 0xd1, 0x33, 0x39, 0xf5, 0x9e, 0xf5, 0x37, 0x66, 0xb0, 0xdc, 0x08}}, + {{0x1e, 0x6f, 0xf4, 0xd7, 0x91, 0x56, 0xd6, 0x66, 0x7a, 0xed, 0x39, 0xa0, 0xe4, 0x25, 0x74, 0x57, 0x8b, 0x09, 0xdd, 0xc7, 0xf5, 0xc3, 0x27, 0xfe, 0x31, 0xa2, 0xf1, 0x22, 0x7a, 0xb7, 0xaf, 0x1d}, {0x9b, 0xac, 0x9d, 0x9f, 0x10, 0xe6, 0xbf, 0xa3, 0x5c, 0x86, 0x14, 0x53, 0xf2, 0xe6, 0x38, 0xa5, 0x35, 0x61, 0xf2, 0x13, 0x19, 0x56, 0x8c, 0xd4, 0x67, 0x55, 0xc3, 0xeb, 0xbd, 0x66, 0x7d, 0x26}}, + {{0x9a, 0xfd, 0x5a, 0x00, 0xb7, 0x55, 0xc0, 0x22, 0xc1, 0xdf, 0x4d, 0x54, 0xb4, 0x5f, 0xe9, 0xfb, 0xcc, 0xc6, 0xd1, 0x43, 0x41, 0x26, 0xd5, 0x48, 0x08, 0x3c, 0x7a, 0xea, 0x2a, 0xa7, 0xc3, 0x37}, {0xa4, 0xd2, 0x2f, 0xeb, 0xd5, 0xaf, 0xe1, 0x77, 0x9c, 0x52, 0x8c, 0x24, 0xbf, 0x76, 0xcf, 0xbf, 0x4a, 0xa4, 0xfa, 0x9f, 0xaa, 0x07, 0x89, 0x85, 0x11, 0x98, 0x3d, 0xa2, 0xad, 0xb3, 0x8a, 0x28}}, + {{0x83, 0xa2, 0x9a, 0xb0, 0x2e, 0x2f, 0x7f, 0x84, 0x88, 0xa0, 0xec, 0x5f, 0xee, 0xcb, 0x74, 0x28, 0x72, 0x86, 0xf2, 0x9a, 0x8d, 0xfc, 0xd9, 0x34, 0x35, 0xff, 0x79, 0xd5, 0x4f, 0x11, 0x01, 0x3e}, {0x0b, 0xc6, 0x54, 0x22, 0x37, 0xd2, 0x04, 0x55, 0x27, 0xb7, 0xa7, 0x6b, 0xcd, 0x14, 0x8f, 0x8f, 0x07, 0xd5, 0x80, 0x11, 0x3f, 0x9f, 0x39, 0x75, 0x4b, 0xc2, 0x20, 0x83, 0x97, 0x56, 0x77, 0x19}}, + {{0x54, 0x37, 0xef, 0xa4, 0x7d, 0x67, 0xd8, 0x21, 0xcc, 0x71, 0xfe, 0xc4, 0xca, 0x79, 0x0f, 0x97, 0xf0, 0xa2, 0xe7, 0x93, 0x38, 0x56, 0x02, 0x92, 0x72, 0x81, 0x7d, 0x59, 0x65, 0x31, 0x6c, 0x27}, {0xee, 0x4f, 0xa1, 0xa9, 0xd9, 0x83, 0xdb, 0xcd, 0x2c, 0xce, 0xdf, 0x95, 0x1e, 0x2b, 0xfa, 0x05, 0x84, 0x7c, 0xb6, 0xe1, 0xef, 0x11, 0x8c, 0xd5, 0xe1, 0xfd, 0xe0, 0x23, 0xc6, 0xcb, 0xc7, 0x01}}, + {{0xf8, 0x9b, 0x41, 0xbe, 0xb7, 0x11, 0xc4, 0x5d, 0x9e, 0x50, 0xfd, 0x71, 0xde, 0x61, 0x02, 0x61, 0xc1, 0x15, 0x6f, 0x4b, 0xe5, 0x5f, 0xdf, 0x93, 0x8c, 0xfc, 0x55, 0xef, 0x2a, 0xa6, 0x17, 0x2b}, {0x43, 0xfe, 0x28, 0x54, 0xe7, 0x27, 0xe9, 0x13, 0x48, 0xd9, 0x58, 0x53, 0x3a, 0x6e, 0x07, 0x3d, 0x94, 0x73, 0xa0, 0x07, 0x85, 0x90, 0x1d, 0x32, 0xf9, 0xf5, 0x85, 0x3f, 0xbc, 0x17, 0x48, 0x26}}, + {{0x4a, 0x54, 0xc9, 0xc5, 0x8c, 0x66, 0x55, 0xda, 0xe9, 0x4a, 0xf1, 0x06, 0xc2, 0x42, 0xd5, 0x7d, 0x22, 0xee, 0x1c, 0x3d, 0xeb, 0xaf, 0x8a, 0xb8, 0xdc, 0xd6, 0xa6, 0x42, 0xc2, 0x25, 0x12, 0x1a}, {0xe7, 0xf4, 0x61, 0x70, 0xd6, 0x02, 0xd8, 0xd8, 0xe2, 0xe0, 0x3e, 0xed, 0xe6, 0xe3, 0x21, 0x1a, 0x6b, 0x85, 0xe5, 0x89, 0x38, 0x92, 0xe5, 0xcb, 0x89, 0xbd, 0x17, 0x2e, 0xab, 0x44, 0x90, 0x03}}, + {{0x0b, 0x29, 0xb7, 0xe3, 0xdf, 0x41, 0xe8, 0x3a, 0x70, 0x61, 0x80, 0xfd, 0xde, 0xec, 0x3f, 0xf1, 0x97, 0x3f, 0xe5, 0x4c, 0x4e, 0xa2, 0x39, 0xac, 0x22, 0xe1, 0xd5, 0xb2, 0xc5, 0x75, 0xce, 0x26}, {0x5d, 0x11, 0x79, 0xdc, 0x56, 0xf0, 0x73, 0xe4, 0xae, 0x0d, 0x62, 0xad, 0xa5, 0x15, 0xe3, 0x76, 0x21, 0x97, 0x3c, 0x48, 0x1e, 0x6c, 0x13, 0xa3, 0x26, 0xd9, 0xd5, 0x86, 0xea, 0x83, 0x6d, 0x3e}}, + {{0xf1, 0x16, 0x83, 0xd9, 0x1a, 0x74, 0x2f, 0xae, 0xbd, 0x44, 0x9d, 0xcf, 0x58, 0x58, 0x2d, 0x38, 0xbe, 0x0f, 0x2d, 0xf7, 0xab, 0x98, 0x4e, 0x38, 0x04, 0x38, 0x6d, 0x40, 0x4b, 0xd3, 0xf3, 0x30}, {0x63, 0x80, 0x47, 0x22, 0x62, 0x53, 0x45, 0xc2, 0x4b, 0xbb, 0xb4, 0x60, 0x08, 0x26, 0x17, 0x3e, 0xd6, 0x27, 0x00, 0xc5, 0xfc, 0xda, 0x6d, 0xb8, 0x18, 0x2c, 0x29, 0x5f, 0x41, 0x48, 0xe8, 0x2f}}, + {{0xfa, 0x80, 0x3c, 0x3c, 0x28, 0x11, 0x6a, 0x7b, 0xb4, 0xf3, 0xf3, 0xdf, 0xc2, 0xb9, 0xa2, 0x9c, 0x80, 0x37, 0xd1, 0x7e, 0x61, 0xf2, 0x0f, 0x34, 0xec, 0x2b, 0x7d, 0xec, 0xac, 0xe5, 0x0c, 0x3e}, {0x89, 0xfb, 0x37, 0x3d, 0x2b, 0x2e, 0x41, 0xd7, 0xd8, 0xfe, 0xb1, 0xc8, 0x6a, 0x86, 0x47, 0x62, 0x0c, 0x59, 0x05, 0x28, 0x39, 0x02, 0x6b, 0x6f, 0xf4, 0xf3, 0x68, 0x92, 0x2c, 0x38, 0xed, 0x0c}}, + {{0xab, 0xe3, 0xe9, 0x62, 0xec, 0xdc, 0x17, 0xf5, 0x35, 0x67, 0x0c, 0x1b, 0xeb, 0x7e, 0x0f, 0xef, 0xcf, 0x37, 0xf9, 0x70, 0x7c, 0xf2, 0x97, 0x8b, 0xfc, 0xee, 0x3c, 0xf8, 0x37, 0x7d, 0x8f, 0x3b}, {0xe0, 0xca, 0x26, 0x71, 0xe6, 0xa8, 0x9c, 0xc8, 0x08, 0xe2, 0x05, 0x79, 0xf9, 0x8a, 0x34, 0xbb, 0xf5, 0x6f, 0xe2, 0x15, 0x6d, 0xe5, 0x4a, 0x45, 0xf4, 0xbd, 0x82, 0x2c, 0x1f, 0x8d, 0x45, 0x1e}}, + {{0x90, 0x5b, 0xaa, 0xac, 0x55, 0xd2, 0x21, 0x8f, 0xfb, 0xe7, 0x40, 0x08, 0xa0, 0xe5, 0x29, 0xe7, 0x5d, 0xeb, 0x63, 0x0b, 0x75, 0x9b, 0xc6, 0x56, 0xf7, 0x82, 0xc3, 0x4c, 0xb9, 0xc9, 0xaa, 0x1e}, {0xf4, 0xad, 0xf0, 0xd4, 0x67, 0xd4, 0x70, 0xa3, 0xe2, 0x0b, 0x7c, 0x19, 0xcf, 0xc5, 0xc1, 0x5e, 0x42, 0x6d, 0x3f, 0xf0, 0xf4, 0x51, 0xcf, 0xc1, 0xff, 0x27, 0xdc, 0x4e, 0x44, 0x04, 0xfb, 0x09}}, + {{0xfe, 0x31, 0x5c, 0x20, 0x2f, 0x0d, 0x2c, 0xb1, 0x91, 0x15, 0xfb, 0x6b, 0x1c, 0xf7, 0xa6, 0xee, 0xb2, 0x03, 0x50, 0xf7, 0x9c, 0x0a, 0xaf, 0x67, 0xe7, 0x47, 0x37, 0x1d, 0x66, 0xbc, 0x98, 0x03}, {0x86, 0xe8, 0x1c, 0xa7, 0x9b, 0xc5, 0xcb, 0xcf, 0xe3, 0xf8, 0xed, 0xab, 0xea, 0xdc, 0xc5, 0x13, 0x7f, 0x13, 0x37, 0xe3, 0x2b, 0xf9, 0xcc, 0x94, 0x0e, 0x26, 0x99, 0x71, 0xf8, 0x13, 0x84, 0x06}}, + {{0x2b, 0x98, 0x8d, 0x30, 0xf7, 0x26, 0x2d, 0xf8, 0x37, 0xd7, 0x64, 0x51, 0x95, 0xf7, 0x63, 0xa4, 0x93, 0x27, 0x01, 0x2a, 0xdb, 0x0c, 0x3b, 0x94, 0xd2, 0x77, 0x77, 0xd9, 0xc7, 0x43, 0xdc, 0x36}, {0xd4, 0x9c, 0x00, 0xc9, 0x9c, 0x72, 0xd0, 0x28, 0x38, 0x64, 0xb7, 0x83, 0x1e, 0x75, 0xce, 0x95, 0x2f, 0xd8, 0xe4, 0x1e, 0x0c, 0x8d, 0x75, 0x7f, 0xb2, 0x23, 0x03, 0x87, 0x5c, 0x97, 0x84, 0x04}}, + {{0x03, 0xbc, 0x95, 0xc2, 0x07, 0x64, 0x3b, 0x57, 0x76, 0xb2, 0x53, 0x36, 0x62, 0x43, 0x81, 0x3d, 0x99, 0x62, 0x19, 0x16, 0x38, 0x55, 0x5a, 0x71, 0xdd, 0x13, 0x24, 0x29, 0x4c, 0x54, 0x2d, 0x1a}, {0xb9, 0xeb, 0x2a, 0xa8, 0x37, 0x0d, 0xeb, 0x35, 0x2b, 0xff, 0x68, 0x76, 0x74, 0xbf, 0x3b, 0xc4, 0x6f, 0xe3, 0xbe, 0xca, 0x7f, 0xe2, 0x86, 0xb0, 0x68, 0xe8, 0x5e, 0x0d, 0x8b, 0x49, 0xa3, 0x2a}}, + {{0x45, 0x4e, 0x2e, 0x36, 0xad, 0xbf, 0xc2, 0xbd, 0x90, 0x92, 0x9d, 0xa9, 0xc4, 0x1d, 0xa5, 0xe6, 0x5d, 0x7d, 0xf6, 0x60, 0xf1, 0x06, 0x7b, 0x7a, 0xd8, 0xd9, 0xa7, 0x65, 0x77, 0x88, 0xcd, 0x19}, {0x6f, 0x93, 0xff, 0x64, 0x05, 0x63, 0x51, 0x8d, 0xef, 0x97, 0x13, 0x50, 0x4d, 0xc6, 0xdb, 0xfa, 0xbc, 0xe5, 0xe4, 0x10, 0x0f, 0x7c, 0x9f, 0xc6, 0x9d, 0x98, 0xb6, 0xd1, 0xea, 0xdb, 0x2a, 0x2d}}, + {{0x63, 0x72, 0x55, 0xcd, 0xb1, 0xb4, 0x3a, 0x58, 0x56, 0x8c, 0x2f, 0x31, 0x10, 0xf8, 0xe4, 0xaa, 0x4d, 0xdf, 0xd9, 0x07, 0x1d, 0x2a, 0x23, 0x2f, 0x3a, 0x77, 0xc6, 0xc4, 0xa3, 0xb5, 0xba, 0x2f}, {0xf2, 0xbe, 0x5d, 0xd3, 0x12, 0x44, 0xe5, 0x73, 0xa8, 0xe5, 0xec, 0x67, 0xa1, 0x87, 0xce, 0x3e, 0x81, 0x67, 0xe9, 0x59, 0x3f, 0xf6, 0x23, 0x92, 0x5d, 0x05, 0x98, 0xf5, 0x10, 0xe0, 0xe5, 0x0e}}, + {{0xa4, 0x45, 0xf2, 0xd0, 0xcf, 0x6d, 0x69, 0x29, 0xa0, 0x66, 0xc3, 0x73, 0xbf, 0xfc, 0x77, 0x82, 0xcf, 0x74, 0x99, 0x1f, 0x74, 0xc2, 0x41, 0x68, 0x9b, 0x28, 0xe6, 0x18, 0x4c, 0x2e, 0x09, 0x37}, {0x82, 0xf2, 0x37, 0x2d, 0x53, 0x2b, 0x8f, 0x83, 0x16, 0x60, 0xb0, 0xc4, 0x60, 0x5e, 0xdd, 0x81, 0x5d, 0x4e, 0x11, 0x45, 0x34, 0xb0, 0x7c, 0xfc, 0x1f, 0x34, 0xa9, 0x4d, 0x63, 0x9c, 0xff, 0x32}}, + {{0x6d, 0x5d, 0x44, 0x00, 0x31, 0xae, 0xf0, 0x9f, 0x4e, 0xf6, 0x8c, 0x96, 0x2c, 0xe2, 0xd8, 0x7c, 0x2d, 0xbc, 0x3f, 0xfd, 0x99, 0x70, 0xc7, 0x6e, 0x7a, 0x75, 0xce, 0x4a, 0x09, 0xd4, 0xed, 0x03}, {0xab, 0xda, 0x7d, 0xaa, 0xf4, 0xd0, 0x49, 0xb9, 0x51, 0xce, 0x21, 0xe4, 0xa6, 0x75, 0x79, 0x95, 0x9a, 0x19, 0xd4, 0x68, 0xc9, 0xf7, 0x87, 0xe3, 0x8c, 0x37, 0xc2, 0xac, 0xd8, 0x83, 0x76, 0x10}}, + {{0x92, 0xf9, 0x02, 0x0d, 0x16, 0xca, 0x36, 0x7c, 0x1b, 0xcf, 0x2a, 0xbd, 0x44, 0x77, 0xc4, 0xb3, 0x7d, 0x23, 0x8e, 0x2a, 0x7a, 0x87, 0xfa, 0xd4, 0x9a, 0x81, 0xc5, 0xf7, 0xda, 0xa3, 0x94, 0x13}, {0x5a, 0x45, 0x63, 0x1b, 0x52, 0x5e, 0x13, 0xb6, 0x5a, 0xe1, 0x38, 0xac, 0xa0, 0x1f, 0xf9, 0x4b, 0xb6, 0x55, 0xe8, 0x1b, 0x64, 0x9f, 0xd9, 0x81, 0x21, 0x14, 0x5d, 0xd7, 0x8b, 0x1b, 0x24, 0x22}}, + {{0x1b, 0xfe, 0x89, 0xb9, 0x69, 0x5f, 0xb4, 0xce, 0x45, 0x8d, 0x97, 0xc7, 0xed, 0x93, 0xe7, 0xb7, 0x39, 0x0c, 0x03, 0x41, 0x63, 0x5a, 0x07, 0x3b, 0xe6, 0xd2, 0x00, 0x6c, 0x8f, 0xb6, 0x76, 0x2d}, {0x3e, 0x0c, 0x1f, 0xce, 0x11, 0x1f, 0xc8, 0x3a, 0x0c, 0x05, 0xb5, 0x2a, 0x29, 0xaf, 0x65, 0x50, 0xf1, 0x43, 0xba, 0xa9, 0x5a, 0x30, 0xc1, 0x8a, 0x67, 0x30, 0xd9, 0xe7, 0xba, 0x81, 0x97, 0x16}}, + {{0x8f, 0xa4, 0x35, 0xd8, 0x89, 0xf0, 0xfe, 0x20, 0x64, 0x2a, 0x07, 0xd6, 0x66, 0x77, 0x23, 0xcb, 0x7c, 0x3b, 0x7c, 0xdd, 0x57, 0x0b, 0xef, 0x18, 0xa0, 0xa4, 0x57, 0x8f, 0x57, 0x5f, 0x3d, 0x1a}, {0x89, 0xc9, 0x32, 0x3e, 0x97, 0x25, 0x74, 0x25, 0xee, 0x9a, 0xb5, 0x38, 0x1a, 0xcb, 0x95, 0xde, 0x08, 0xae, 0x8e, 0x32, 0x5a, 0xc4, 0x69, 0x5e, 0x17, 0x90, 0x45, 0x51, 0x70, 0x38, 0xfa, 0x12}}, + {{0xf3, 0x00, 0x15, 0xb1, 0x1d, 0xb7, 0xcc, 0x54, 0x07, 0x4e, 0x55, 0xc9, 0x08, 0x7b, 0xe2, 0xea, 0x5d, 0x81, 0x33, 0x6e, 0x91, 0xa0, 0xac, 0xd7, 0x53, 0xa8, 0xdd, 0x11, 0x73, 0xe2, 0x24, 0x09}, {0x2a, 0x94, 0xe9, 0xcc, 0x3c, 0xf9, 0x61, 0x6d, 0x33, 0xe8, 0x83, 0x7e, 0xd1, 0x5d, 0x9e, 0x2d, 0x50, 0xf7, 0x67, 0x6d, 0xea, 0x7a, 0x10, 0x84, 0xa5, 0xa1, 0x7c, 0x75, 0x62, 0x6e, 0xbe, 0x3c}}, + {{0x76, 0x73, 0x97, 0xb7, 0xd0, 0x11, 0x96, 0x74, 0x34, 0xec, 0xcd, 0x4c, 0x46, 0x16, 0xee, 0x91, 0x1a, 0x12, 0x2a, 0xa8, 0x11, 0xee, 0x1a, 0xa7, 0x95, 0xde, 0x85, 0xd1, 0xbf, 0x4b, 0x9f, 0x0b}, {0x6d, 0xa2, 0x7e, 0xea, 0xcc, 0x72, 0x57, 0xd1, 0x27, 0x6d, 0x08, 0x87, 0xdb, 0x58, 0x71, 0xd1, 0x4d, 0x2b, 0xea, 0x1e, 0xae, 0x1f, 0x93, 0x60, 0x99, 0xdd, 0x28, 0xb8, 0x13, 0x46, 0xdc, 0x34}}, + {{0x6f, 0xf9, 0xe5, 0x1e, 0xd8, 0x03, 0xbd, 0x1f, 0x7a, 0x07, 0x91, 0xb6, 0x82, 0x97, 0x1c, 0x37, 0xe5, 0x5c, 0xbf, 0x19, 0xa7, 0xf5, 0x2d, 0xf5, 0x53, 0x9d, 0x1d, 0x45, 0xb2, 0xca, 0xd6, 0x02}, {0xc3, 0xf9, 0x90, 0x5e, 0x71, 0x53, 0xb8, 0x19, 0x2b, 0xe0, 0xb7, 0x62, 0x9e, 0x10, 0x1e, 0x6e, 0x35, 0x5b, 0x4a, 0x1d, 0x2c, 0xb7, 0x02, 0x43, 0xf8, 0x46, 0x21, 0xe2, 0x6d, 0xbe, 0xb0, 0x10}}, + {{0x22, 0x73, 0xaa, 0x81, 0xc7, 0x34, 0xcf, 0x24, 0xe3, 0x5e, 0xc4, 0xb1, 0x2e, 0xbd, 0x47, 0x32, 0x39, 0xea, 0x13, 0x04, 0x78, 0x43, 0xae, 0xf9, 0xa6, 0x78, 0x65, 0x78, 0xb8, 0xdc, 0x16, 0x0d}, {0xc8, 0xb1, 0xa7, 0x3b, 0x02, 0xe5, 0x41, 0x9d, 0x81, 0x1a, 0x66, 0xfc, 0x86, 0x2c, 0x5e, 0xfe, 0xc3, 0x0f, 0x7e, 0x42, 0xd6, 0xc0, 0x29, 0xe7, 0xcb, 0x05, 0x71, 0x49, 0xca, 0x05, 0xf3, 0x05}}, + {{0x9d, 0x7b, 0x2f, 0x25, 0x68, 0xa8, 0xfa, 0x1a, 0x2c, 0xb4, 0xe9, 0x52, 0x7b, 0x61, 0x19, 0x9e, 0x83, 0xf1, 0xe3, 0xe9, 0x9d, 0x44, 0xf4, 0xd5, 0xe8, 0x20, 0xce, 0x63, 0x11, 0x0e, 0x2a, 0x32}, {0x73, 0xbf, 0x51, 0x63, 0x0a, 0xcb, 0x91, 0xb3, 0xcd, 0x6a, 0x5a, 0x4f, 0x7b, 0x1f, 0x0b, 0x61, 0x26, 0xaa, 0x20, 0xcd, 0x31, 0x9f, 0x76, 0x3a, 0x67, 0xbf, 0x1b, 0x56, 0xa2, 0x28, 0xe3, 0x3c}}, + {{0xb2, 0x3f, 0x40, 0xfd, 0x39, 0x9e, 0xc7, 0x30, 0x04, 0xf5, 0x6f, 0x91, 0x56, 0x12, 0x82, 0x1d, 0x6b, 0x2b, 0xd6, 0x65, 0xde, 0xef, 0x73, 0xfe, 0xe2, 0x4d, 0xa3, 0xc6, 0x42, 0x47, 0x94, 0x29}, {0x17, 0x4d, 0xa5, 0xb2, 0x41, 0x99, 0x6e, 0xaa, 0xca, 0xd4, 0x34, 0x1b, 0x96, 0x44, 0xe2, 0x50, 0x45, 0xcb, 0x99, 0xa1, 0xc4, 0x42, 0x06, 0x6b, 0x0c, 0xa0, 0xfd, 0xee, 0x9d, 0x60, 0xf3, 0x01}}, + {{0x9e, 0x4a, 0x77, 0xe0, 0xa5, 0x06, 0xab, 0x4b, 0x99, 0x53, 0xbd, 0x52, 0x42, 0x3b, 0x30, 0xa3, 0x20, 0x95, 0x29, 0xe7, 0x7b, 0x1f, 0xb4, 0x4b, 0xb4, 0xfa, 0xeb, 0xd0, 0xef, 0xed, 0x21, 0x3e}, {0xe5, 0x99, 0x64, 0xcb, 0x5f, 0x14, 0x4c, 0x46, 0x10, 0x48, 0xca, 0x1a, 0xb7, 0x61, 0x35, 0xdf, 0x35, 0x56, 0x56, 0x37, 0xfc, 0x58, 0xbc, 0x04, 0x50, 0x57, 0xbf, 0x6b, 0x9a, 0x27, 0x58, 0x1c}}, + {{0x44, 0xca, 0xc0, 0x9d, 0xfe, 0xf0, 0xf4, 0x99, 0x02, 0x17, 0x42, 0xb0, 0x82, 0xd6, 0xfb, 0x02, 0x90, 0xd8, 0x68, 0x29, 0x31, 0xf1, 0xfe, 0x2e, 0x10, 0x44, 0xb1, 0x6d, 0x2e, 0x22, 0xe2, 0x15}, {0x67, 0x06, 0x9a, 0xc9, 0xe2, 0x83, 0xa0, 0x67, 0xfb, 0x87, 0xd2, 0x6b, 0x4a, 0xd1, 0xab, 0x23, 0xb0, 0xfd, 0x5d, 0x2a, 0x1e, 0xeb, 0xdd, 0xab, 0x7e, 0x66, 0x90, 0xbe, 0x0a, 0x96, 0x60, 0x0b}}, + {{0xaf, 0x4f, 0x5a, 0xba, 0x4e, 0x68, 0x40, 0xc7, 0x6c, 0xc3, 0x7c, 0x13, 0x95, 0xce, 0x22, 0x4c, 0x1a, 0x2b, 0x5a, 0xc4, 0x2b, 0xa4, 0x1a, 0x28, 0x59, 0x9a, 0xe0, 0x97, 0x6b, 0x14, 0x6b, 0x37}, {0x89, 0xe2, 0x2a, 0x98, 0xb0, 0xbd, 0xef, 0xc4, 0xfc, 0x83, 0x4c, 0x56, 0xb6, 0xa7, 0x54, 0xf5, 0xdf, 0xf8, 0x31, 0xbe, 0x0f, 0xd2, 0x67, 0x8a, 0xf6, 0x6d, 0x78, 0x41, 0x03, 0x9f, 0x37, 0x2c}}, + {{0x4f, 0x8e, 0x1f, 0x4b, 0xa8, 0x2f, 0xb6, 0x2a, 0xd4, 0xd7, 0xe0, 0x51, 0x52, 0x76, 0x04, 0x56, 0x9b, 0x0b, 0x61, 0x62, 0xb4, 0x2e, 0x1d, 0x86, 0x50, 0x6e, 0x0e, 0x45, 0xbd, 0xe0, 0xc4, 0x31}, {0x1e, 0xbe, 0x2a, 0xf7, 0x9e, 0x3e, 0xd3, 0xd8, 0xef, 0x6c, 0x4a, 0x7f, 0x7b, 0xee, 0x03, 0xb8, 0xa6, 0x4d, 0x39, 0x0c, 0x38, 0xb4, 0x3c, 0x9a, 0xf0, 0xb5, 0xb3, 0x13, 0x27, 0x8e, 0x28, 0x12}}, + {{0x3e, 0x0f, 0xea, 0x1f, 0x9e, 0x11, 0x8c, 0x1d, 0x53, 0xa7, 0xc0, 0xaf, 0x23, 0x84, 0x48, 0xcf, 0xf4, 0x1a, 0x1d, 0x42, 0x85, 0xdc, 0x6e, 0x0b, 0x8e, 0x5d, 0x1f, 0xff, 0xdd, 0xf1, 0x1f, 0x26}, {0xaa, 0x6c, 0x9e, 0xd1, 0x50, 0x57, 0x99, 0x01, 0xd4, 0x8e, 0x49, 0xb7, 0xdf, 0x82, 0x1d, 0xad, 0xb7, 0x31, 0x91, 0xb6, 0x09, 0xd7, 0x7b, 0x24, 0x80, 0xf7, 0xa5, 0x15, 0x79, 0xb8, 0x39, 0x25}}, + {{0x9a, 0x93, 0xe8, 0xf8, 0x80, 0xfb, 0x89, 0x75, 0xcd, 0xbc, 0x5a, 0xd4, 0x10, 0x08, 0xbd, 0x9e, 0x44, 0x9b, 0xcc, 0x0c, 0xca, 0x79, 0xba, 0xfd, 0x80, 0xc9, 0x5d, 0x8f, 0xea, 0x1a, 0xa0, 0x1a}, {0x0b, 0xe3, 0x83, 0x6b, 0x27, 0xfa, 0x55, 0xa5, 0x1b, 0x8a, 0xa4, 0x8c, 0xd3, 0x1d, 0x8f, 0x57, 0x0d, 0x37, 0x6b, 0xf8, 0x02, 0xd1, 0xf7, 0x1d, 0x91, 0x53, 0x33, 0x4e, 0x63, 0x46, 0x4a, 0x39}}, + {{0x05, 0x60, 0xa0, 0xb2, 0xb4, 0xff, 0xa6, 0x20, 0xe2, 0xc4, 0x24, 0xfb, 0x71, 0x8f, 0xeb, 0x92, 0xf8, 0x84, 0xf7, 0x96, 0x67, 0x09, 0x8d, 0xaa, 0x0d, 0x33, 0x0e, 0x8d, 0x07, 0x16, 0xe3, 0x16}, {0x70, 0x50, 0x32, 0xd4, 0x60, 0x1a, 0x44, 0xdd, 0x5b, 0x7b, 0x21, 0x1b, 0x1a, 0x77, 0x11, 0x4b, 0x48, 0x2f, 0xda, 0x26, 0x4e, 0x50, 0x9b, 0xcd, 0x7e, 0x47, 0x72, 0x2a, 0xe3, 0xeb, 0x0a, 0x30}}, + {{0x8c, 0x50, 0xd4, 0xd1, 0x87, 0x4c, 0x4f, 0x74, 0x73, 0xa5, 0x48, 0xd9, 0x58, 0x60, 0xec, 0xb3, 0xea, 0x9f, 0xb9, 0x43, 0x79, 0xb4, 0xcc, 0xc4, 0xf2, 0x3f, 0xeb, 0x7c, 0x8f, 0x92, 0x2e, 0x29}, {0xad, 0x27, 0xd0, 0x03, 0x76, 0x44, 0xce, 0x87, 0x20, 0x0b, 0x88, 0xe6, 0xca, 0x90, 0xb9, 0x9b, 0x5a, 0x74, 0x65, 0xe4, 0xda, 0x41, 0x2d, 0xc9, 0x9c, 0x27, 0x29, 0x2d, 0xf5, 0x81, 0x23, 0x02}}, + {{0xe3, 0x1d, 0xd6, 0x30, 0x07, 0x38, 0x62, 0x07, 0x05, 0xcc, 0x71, 0x37, 0xf3, 0xe3, 0xdd, 0x1e, 0xb3, 0x4a, 0xb6, 0xc2, 0x1c, 0x05, 0x7f, 0x1b, 0x93, 0x0e, 0x0a, 0x8a, 0x02, 0xef, 0x53, 0x04}, {0x3f, 0xb8, 0x06, 0x51, 0x8c, 0x20, 0xf4, 0x4a, 0xb2, 0xe9, 0x11, 0x19, 0xb8, 0x0b, 0x2f, 0xa1, 0x84, 0x62, 0xca, 0x13, 0xe3, 0x55, 0x23, 0x8d, 0x2d, 0xe4, 0xdd, 0x77, 0x26, 0xc6, 0x9a, 0x19}}, + {{0xcb, 0x31, 0xa5, 0x65, 0x8b, 0x07, 0xd5, 0xa5, 0xad, 0xde, 0xa8, 0x40, 0x96, 0xd3, 0xd4, 0xd6, 0x4a, 0x19, 0x84, 0x2e, 0xa3, 0x10, 0x95, 0x73, 0xda, 0xb2, 0x24, 0x2d, 0x7f, 0x7e, 0x46, 0x07}, {0xe5, 0x65, 0x51, 0x18, 0x5d, 0xd5, 0xca, 0x2a, 0xad, 0xc7, 0xc9, 0x77, 0x6a, 0x14, 0xb2, 0x0f, 0x3d, 0x79, 0x25, 0x5a, 0xc7, 0xf9, 0x21, 0x4a, 0x9a, 0x66, 0x5c, 0x7e, 0x53, 0xb6, 0x1f, 0x05}}, + {{0xfc, 0xe3, 0x39, 0x27, 0x3e, 0x2c, 0x77, 0x5c, 0xfd, 0x20, 0xdc, 0xc5, 0x27, 0x51, 0xf3, 0xfe, 0x04, 0xb0, 0xf0, 0x43, 0x2b, 0x09, 0xd1, 0x93, 0x81, 0x2e, 0x30, 0x3a, 0xb4, 0x1a, 0x10, 0x36}, {0x61, 0x29, 0x27, 0x69, 0x8a, 0x2c, 0x06, 0xa2, 0x3c, 0x55, 0xfe, 0x33, 0xda, 0x1e, 0xae, 0x95, 0x9f, 0x1d, 0xc3, 0x13, 0xd6, 0x8e, 0x55, 0x0c, 0x18, 0xf5, 0xb1, 0x0b, 0xad, 0xb3, 0x79, 0x26}}, + {{0x87, 0x65, 0x56, 0x93, 0x2d, 0x4a, 0x99, 0x4c, 0x60, 0x2d, 0xd1, 0x95, 0x82, 0x0d, 0xeb, 0xde, 0xc4, 0x8d, 0xec, 0x45, 0x93, 0x25, 0xc2, 0xe1, 0xeb, 0x88, 0x72, 0x37, 0xf2, 0xd2, 0x35, 0x2a}, {0x4d, 0xee, 0x9d, 0xaf, 0x3f, 0x20, 0x98, 0xdd, 0xb8, 0x19, 0x21, 0xc5, 0x8c, 0x2c, 0x66, 0x5c, 0x4e, 0x51, 0x80, 0x84, 0xcb, 0xcd, 0x3e, 0xa6, 0xaa, 0x1b, 0x2a, 0x33, 0xd5, 0xf4, 0xda, 0x18}}, + {{0xc3, 0x70, 0xfa, 0xcc, 0xad, 0xd0, 0x4c, 0xd8, 0xa0, 0x09, 0x31, 0xcc, 0x09, 0xd2, 0x7c, 0x00, 0x0f, 0xfa, 0x25, 0x32, 0x5e, 0x58, 0xed, 0x78, 0xa0, 0xbe, 0x8a, 0x42, 0x43, 0xaa, 0x9e, 0x03}, {0x5c, 0xc6, 0x61, 0xaa, 0xf9, 0x04, 0xf7, 0xb8, 0xd1, 0x1f, 0x81, 0xd7, 0xee, 0x1e, 0x02, 0xb5, 0xb6, 0xc3, 0x41, 0x06, 0xe1, 0xd1, 0x3a, 0x5e, 0xc8, 0x09, 0xfb, 0x97, 0x99, 0x2d, 0x6d, 0x28}}, + {{0x73, 0x9c, 0x43, 0xf5, 0xb3, 0x78, 0x16, 0x2f, 0x1b, 0x11, 0x0a, 0xd3, 0xdd, 0x1c, 0x1b, 0x9f, 0x4d, 0x83, 0x32, 0x9b, 0x9f, 0x47, 0x01, 0x16, 0x1b, 0x72, 0x20, 0x94, 0xb6, 0xc1, 0xc1, 0x17}, {0x1a, 0x20, 0xc2, 0x90, 0x72, 0x0b, 0x68, 0x5b, 0x23, 0xbc, 0x1a, 0xb0, 0x4d, 0xcb, 0xf9, 0xf9, 0x04, 0xe5, 0x6a, 0xf2, 0xd4, 0x6b, 0x4e, 0x1d, 0x2f, 0x82, 0x88, 0x59, 0x69, 0xe0, 0x9d, 0x38}}, + {{0x86, 0xbd, 0x6c, 0xa2, 0x46, 0xa5, 0xcc, 0xb1, 0x30, 0x75, 0x48, 0x8d, 0xf0, 0x36, 0x81, 0xd5, 0x07, 0x2f, 0xc4, 0x93, 0x61, 0x5c, 0x22, 0xc0, 0xd4, 0x6b, 0xdc, 0x1c, 0xd2, 0x59, 0x00, 0x39}, {0xd4, 0x22, 0x8e, 0x31, 0xde, 0x72, 0x0c, 0x6b, 0xb6, 0xb6, 0x2f, 0x54, 0x3a, 0x9e, 0x5b, 0xc2, 0x40, 0x74, 0x9f, 0xda, 0xe6, 0x06, 0xa8, 0xa7, 0x4d, 0x8d, 0x26, 0x43, 0xce, 0x71, 0x2a, 0x3c}}, + {{0x22, 0xf1, 0x89, 0x04, 0xa2, 0x11, 0xe1, 0x50, 0xcb, 0x8e, 0x5f, 0xfd, 0xda, 0x1a, 0xdb, 0x07, 0xb9, 0x02, 0x90, 0x1f, 0xee, 0x51, 0xa6, 0xf6, 0xca, 0x57, 0xca, 0x41, 0x85, 0x8f, 0xdc, 0x25}, {0xdc, 0xee, 0xed, 0xc4, 0xe0, 0xe6, 0x41, 0x82, 0x92, 0x53, 0xa0, 0x57, 0x05, 0x5a, 0xdb, 0xe1, 0xa3, 0x32, 0xe5, 0x6e, 0xa1, 0xd4, 0x07, 0x4b, 0x32, 0xf4, 0xed, 0x70, 0x97, 0x0c, 0x1a, 0x1d}}, + {{0xf4, 0x71, 0x86, 0x00, 0xf6, 0x68, 0x6b, 0xb2, 0x07, 0x43, 0x9e, 0x0b, 0x0b, 0xa0, 0xdb, 0x75, 0x1f, 0x71, 0x2f, 0xc8, 0xb7, 0x65, 0xa7, 0xd9, 0x53, 0xe8, 0xcb, 0x27, 0xc0, 0xf4, 0x65, 0x27}, {0x5b, 0xb6, 0x7a, 0xe9, 0x24, 0xd0, 0xa7, 0xb2, 0x6d, 0x2a, 0x27, 0x77, 0x26, 0xee, 0xf5, 0x1d, 0x3d, 0x27, 0x89, 0xc7, 0x51, 0x45, 0x0e, 0x6c, 0x9d, 0x63, 0x75, 0x28, 0x99, 0x7d, 0xa1, 0x27}}, + {{0x8d, 0xd6, 0x60, 0x42, 0xfe, 0xfc, 0x10, 0xdb, 0x63, 0x26, 0xbe, 0xa7, 0x95, 0x7c, 0x54, 0x71, 0xa3, 0xa1, 0xce, 0xd0, 0x6a, 0x28, 0x58, 0x12, 0xea, 0x47, 0xe9, 0x88, 0xac, 0x52, 0xdf, 0x27}, {0xb7, 0x0f, 0xc3, 0x00, 0x53, 0x5b, 0x4e, 0x3d, 0x32, 0x6e, 0x88, 0x36, 0xe4, 0xbe, 0xf6, 0x93, 0x5d, 0x55, 0xd9, 0xbd, 0x1c, 0xcf, 0xe4, 0xbc, 0xe2, 0x10, 0x55, 0xc3, 0xcf, 0x32, 0x46, 0x20}}, + {{0xa6, 0xc2, 0xec, 0xd7, 0xf8, 0x28, 0x7c, 0x8b, 0x17, 0x2a, 0xd2, 0x04, 0xb7, 0xba, 0x84, 0x34, 0xcd, 0xbf, 0xd8, 0xe6, 0x38, 0x55, 0xeb, 0x68, 0x2f, 0xfd, 0x09, 0x05, 0x25, 0x8d, 0x08, 0x04}, {0x08, 0xb9, 0x2e, 0x75, 0x8e, 0x01, 0xf8, 0x57, 0xe9, 0xb3, 0x60, 0x33, 0xe2, 0x94, 0x09, 0xc7, 0x64, 0x13, 0x9a, 0x96, 0xc5, 0xe0, 0xb5, 0x31, 0x51, 0x1c, 0x4c, 0xb6, 0x9c, 0x3b, 0x1d, 0x24}}, + {{0x37, 0x8b, 0x32, 0x63, 0x07, 0xa9, 0x0f, 0x07, 0x4e, 0x45, 0xd1, 0xf7, 0xc9, 0x7f, 0xb7, 0x80, 0x9f, 0x9b, 0x1c, 0xb0, 0x95, 0xba, 0x51, 0xa8, 0x3c, 0xdf, 0x20, 0x72, 0x54, 0x17, 0x4f, 0x10}, {0xfb, 0x19, 0xe7, 0x05, 0x53, 0x7e, 0xc8, 0x7d, 0x87, 0x8b, 0xd5, 0xfb, 0xd5, 0xf6, 0x8f, 0x33, 0x5f, 0x32, 0xf7, 0x14, 0x20, 0xe7, 0xc5, 0xf8, 0x88, 0xfe, 0x51, 0x0c, 0xfc, 0xfe, 0x09, 0x03}}, + {{0x80, 0x15, 0xf8, 0x9c, 0x47, 0x81, 0x3e, 0xb3, 0xd8, 0x39, 0x1a, 0x43, 0x78, 0xf7, 0x43, 0x3d, 0xd1, 0x16, 0xaf, 0xf8, 0x67, 0x25, 0x34, 0xca, 0xdb, 0x0c, 0x4b, 0x21, 0x0a, 0x43, 0x13, 0x31}, {0x99, 0x43, 0x4f, 0x0b, 0x73, 0x59, 0xc9, 0x13, 0xb0, 0xa2, 0x5c, 0xc6, 0x6e, 0x1a, 0x34, 0xe5, 0xd3, 0xe4, 0x14, 0x33, 0x23, 0xa6, 0x52, 0xcb, 0x21, 0xda, 0xfc, 0xf9, 0x52, 0xc5, 0xed, 0x2c}}, + {{0xa7, 0x2c, 0x0b, 0xbc, 0x21, 0xd3, 0xf2, 0xe2, 0x5b, 0x41, 0xf2, 0xb9, 0x8b, 0x6d, 0x52, 0xb2, 0x01, 0x10, 0xfe, 0x52, 0x8f, 0x2a, 0x60, 0xbf, 0xbc, 0x8e, 0xeb, 0x95, 0x89, 0xf2, 0x68, 0x3d}, {0xae, 0xe0, 0x60, 0xf2, 0x8c, 0x98, 0xbc, 0x15, 0xb4, 0x73, 0x15, 0xa7, 0x53, 0x72, 0xfe, 0xd3, 0xb9, 0x55, 0x30, 0x5a, 0x86, 0xa0, 0x6e, 0x5d, 0xfe, 0x40, 0x67, 0xec, 0xfd, 0x9a, 0xef, 0x08}}, + {{0x14, 0xc5, 0xbe, 0x91, 0xc3, 0xd6, 0xa6, 0x4f, 0xb8, 0xec, 0x64, 0xb8, 0x29, 0x32, 0xa8, 0xb5, 0x67, 0x21, 0x98, 0x41, 0x27, 0x3f, 0x59, 0x35, 0xe4, 0x91, 0xb4, 0x64, 0xd3, 0xab, 0x02, 0x14}, {0xbf, 0x9c, 0x82, 0x5f, 0xb5, 0x91, 0x4f, 0xad, 0xc1, 0x46, 0x17, 0xbd, 0xce, 0x24, 0x78, 0x60, 0xaf, 0x5c, 0x35, 0xad, 0xad, 0x5a, 0x41, 0x89, 0x02, 0xaa, 0x31, 0x8e, 0xb1, 0x54, 0x1d, 0x1e}}, + {{0xf0, 0x92, 0x17, 0xff, 0xe3, 0xff, 0x68, 0xf2, 0xb7, 0x7a, 0x24, 0xc1, 0x6d, 0x82, 0x0d, 0xd3, 0x6a, 0x54, 0x51, 0x04, 0xa8, 0xde, 0x35, 0xd8, 0x28, 0x67, 0x1b, 0x5b, 0x7f, 0x78, 0xf3, 0x07}, {0x48, 0x5b, 0xda, 0x22, 0x30, 0x7c, 0xbe, 0x06, 0xce, 0xee, 0x7e, 0xe5, 0xaf, 0xb0, 0x19, 0x61, 0xed, 0xeb, 0xd0, 0x3b, 0x93, 0xef, 0xb2, 0xff, 0xcb, 0x2f, 0x1b, 0xdb, 0x2c, 0xf7, 0x69, 0x01}}, + {{0x8d, 0x88, 0x4b, 0x29, 0x34, 0x28, 0x56, 0xe4, 0x84, 0x56, 0xf2, 0x64, 0x3b, 0x51, 0xfd, 0xbc, 0x23, 0xd4, 0xab, 0xc4, 0xfb, 0xb8, 0x8e, 0xf0, 0x9f, 0xb4, 0x6b, 0xc8, 0xe3, 0x00, 0xb6, 0x0f}, {0xde, 0xf8, 0x3f, 0x3b, 0x0e, 0xfc, 0xbc, 0xe7, 0x1e, 0xd7, 0xae, 0xf9, 0xea, 0x5e, 0xa6, 0xbe, 0x58, 0x1b, 0x8a, 0xcd, 0x85, 0xec, 0xdf, 0x70, 0xa6, 0xd8, 0x6c, 0x89, 0x67, 0x53, 0xf6, 0x19}}, + {{0x33, 0x1b, 0x22, 0x3c, 0xcf, 0xbf, 0xfa, 0x34, 0x7b, 0x09, 0xc6, 0xd5, 0x3c, 0x88, 0x4b, 0x04, 0x7c, 0x0c, 0xcc, 0x00, 0x5a, 0x71, 0xb0, 0xbf, 0xf5, 0xc9, 0x44, 0x20, 0xd0, 0x54, 0x79, 0x06}, {0x07, 0x8d, 0xdf, 0x61, 0xda, 0x1b, 0x19, 0xd9, 0x75, 0x44, 0x85, 0xa6, 0x46, 0xa4, 0x2a, 0x6d, 0x13, 0xdb, 0x8a, 0xa5, 0xbb, 0xbf, 0xbc, 0x92, 0x39, 0x4f, 0x1c, 0xba, 0xfb, 0xec, 0x5a, 0x06}}, + {{0x57, 0xbd, 0x88, 0x7c, 0x48, 0xeb, 0xc3, 0x86, 0x8e, 0xf8, 0xd2, 0x11, 0xd0, 0xd4, 0x8b, 0xdb, 0xcf, 0x4d, 0xe4, 0xa7, 0xea, 0x69, 0xd8, 0xfa, 0x28, 0x6e, 0x9c, 0x6e, 0xed, 0x30, 0x22, 0x30}, {0xf6, 0x91, 0xa2, 0xbb, 0xa5, 0xed, 0xbe, 0x0f, 0x9a, 0x35, 0x91, 0xab, 0x64, 0x6a, 0xea, 0x92, 0x73, 0x83, 0x8b, 0x4b, 0x70, 0x72, 0x65, 0x2e, 0xf4, 0x02, 0x84, 0xe5, 0x73, 0x76, 0xfd, 0x30}}, + {{0x3a, 0xbf, 0x55, 0xa9, 0xab, 0x2e, 0x84, 0xea, 0xb9, 0x19, 0x1d, 0x65, 0xa2, 0x8c, 0x0d, 0xa2, 0x7a, 0xfb, 0xeb, 0x8c, 0x50, 0x31, 0x2e, 0xab, 0x53, 0xe8, 0x73, 0x83, 0x91, 0xf4, 0xca, 0x3a}, {0x97, 0xca, 0xec, 0x92, 0xf6, 0xa4, 0xca, 0x44, 0xd3, 0xd3, 0xac, 0x22, 0x9a, 0x4b, 0x2e, 0x2b, 0xaa, 0xe6, 0x7b, 0xff, 0x9e, 0x27, 0x30, 0xbc, 0x15, 0x17, 0x5b, 0x84, 0x71, 0x6c, 0x91, 0x3b}}, + {{0x47, 0xd0, 0xd1, 0x21, 0x3b, 0xb0, 0x02, 0x12, 0xbe, 0xb5, 0x54, 0xaa, 0x52, 0x57, 0xae, 0x03, 0x3c, 0x2a, 0xaf, 0x2e, 0x08, 0x41, 0x25, 0xc9, 0x7a, 0x0b, 0x29, 0x5d, 0x1c, 0xe5, 0xad, 0x13}, {0x4c, 0x97, 0x36, 0x5c, 0xdc, 0x8c, 0x41, 0x80, 0x9f, 0xc2, 0x81, 0x1a, 0x73, 0x04, 0x04, 0xd6, 0x6d, 0x1b, 0x89, 0x93, 0x06, 0xba, 0xa2, 0x23, 0xa1, 0x36, 0x16, 0x4b, 0xdc, 0x9a, 0x6f, 0x26}}, + {{0x02, 0x0c, 0xca, 0x40, 0x5e, 0xaa, 0xfd, 0x9a, 0x51, 0x8a, 0x14, 0xa4, 0x4d, 0x98, 0x58, 0xa3, 0x78, 0x0f, 0x42, 0x99, 0x7c, 0xcc, 0xd4, 0xac, 0x8b, 0x31, 0x2c, 0x23, 0x85, 0xc1, 0x87, 0x21}, {0x80, 0x45, 0x9f, 0x49, 0x5d, 0x3d, 0x81, 0x8a, 0x26, 0xd8, 0xa2, 0xdf, 0x3e, 0x11, 0x13, 0xa5, 0x66, 0xf4, 0x2d, 0xf2, 0xf7, 0xfe, 0x8d, 0xeb, 0xd0, 0x99, 0x59, 0x43, 0x3b, 0xfd, 0x31, 0x20}}, + {{0x9a, 0x30, 0x18, 0x33, 0x61, 0x65, 0x8e, 0x03, 0x18, 0x16, 0x67, 0x68, 0x98, 0xcc, 0xbc, 0xfb, 0xed, 0x87, 0x90, 0x0b, 0x5f, 0xf4, 0x78, 0xc0, 0xbb, 0xbd, 0x9c, 0x84, 0xef, 0xe8, 0xf2, 0x30}, {0x91, 0xda, 0xef, 0x49, 0x01, 0x5a, 0x6b, 0xa3, 0x74, 0x93, 0x20, 0x1b, 0x96, 0xde, 0x95, 0x7a, 0xb8, 0x5a, 0x3b, 0x0f, 0xaa, 0x06, 0xca, 0xec, 0x15, 0xde, 0xcb, 0x64, 0xb8, 0x63, 0xdd, 0x31}}, + {{0xb3, 0x93, 0x8e, 0xf9, 0x97, 0xb2, 0x96, 0x47, 0x1e, 0x02, 0xd9, 0x1e, 0x41, 0xb3, 0x93, 0xf4, 0x22, 0xc9, 0x11, 0x5a, 0xf0, 0x49, 0x59, 0x19, 0x86, 0x87, 0xc5, 0x4c, 0x32, 0xa0, 0xc5, 0x35}, {0x04, 0x18, 0x63, 0x26, 0xa7, 0xce, 0x71, 0xfe, 0xed, 0x07, 0xbb, 0xe5, 0x5d, 0x54, 0x35, 0x3b, 0xe0, 0x9b, 0x08, 0x64, 0x02, 0x8c, 0x0c, 0x1e, 0x7e, 0x82, 0x9e, 0x13, 0x27, 0x4b, 0xb2, 0x24}}, + {{0x1b, 0x70, 0x18, 0x48, 0x1e, 0x52, 0x3d, 0xf3, 0xeb, 0x12, 0xb1, 0x4f, 0x9b, 0x6b, 0xd0, 0x0e, 0x38, 0x57, 0x68, 0xd5, 0xb1, 0xf6, 0x8d, 0xd3, 0x2d, 0x1f, 0x64, 0xe3, 0xa3, 0x54, 0x83, 0x2f}, {0x9c, 0x48, 0x5d, 0x8e, 0x8b, 0xb5, 0x57, 0x2f, 0xc5, 0x61, 0xc3, 0x4d, 0x17, 0xab, 0xb1, 0x88, 0x91, 0xa0, 0x07, 0x17, 0x60, 0x61, 0xfe, 0xff, 0x26, 0x40, 0xd9, 0x3f, 0xd9, 0x75, 0x97, 0x07}}, + {{0xe0, 0x34, 0x06, 0x9f, 0x08, 0x4b, 0x09, 0x7d, 0xf3, 0xb4, 0x97, 0x20, 0x73, 0x42, 0x60, 0x32, 0xe3, 0x4a, 0x05, 0x8f, 0x56, 0x5d, 0x95, 0x2d, 0x37, 0xa8, 0xb0, 0xa0, 0xe1, 0x83, 0x94, 0x20}, {0x65, 0x21, 0x8b, 0xc6, 0x32, 0xcb, 0x32, 0x74, 0x3f, 0x2d, 0xb0, 0x7f, 0x65, 0x21, 0xd9, 0x7b, 0x8a, 0xed, 0x43, 0x61, 0x9e, 0xcd, 0x8e, 0x0f, 0x49, 0xec, 0x4a, 0xb9, 0xa9, 0x5f, 0x80, 0x1e}}, + {{0x04, 0xca, 0x44, 0x83, 0x6c, 0x89, 0x13, 0x51, 0x62, 0xb0, 0xdc, 0x14, 0x40, 0x81, 0xf8, 0x3e, 0x36, 0x86, 0xe3, 0x64, 0x2a, 0x40, 0x12, 0x44, 0xab, 0x3a, 0xdf, 0x7f, 0xca, 0xc0, 0xa2, 0x2c}, {0x4e, 0x33, 0x39, 0xdd, 0xb6, 0x11, 0xd4, 0xae, 0xf5, 0x59, 0x88, 0x3c, 0xe8, 0x64, 0xbf, 0xac, 0x0f, 0x8b, 0xf1, 0xbb, 0x0f, 0x90, 0x8a, 0xc6, 0x1c, 0xad, 0xb7, 0x59, 0x97, 0xa1, 0xc2, 0x35}}, + {{0xfa, 0x62, 0xd8, 0x68, 0xaf, 0x18, 0x3e, 0x3d, 0x13, 0x6b, 0x05, 0x7f, 0x49, 0x06, 0xd5, 0xe3, 0xd3, 0x7f, 0x7b, 0xbe, 0xad, 0xfa, 0x45, 0x4e, 0x57, 0xe9, 0xcd, 0x20, 0x3e, 0xda, 0x59, 0x18}, {0x49, 0xe7, 0x6a, 0xf3, 0x90, 0xa0, 0x5d, 0x64, 0xf1, 0x2a, 0x46, 0xa0, 0xb2, 0xb3, 0x1d, 0xd4, 0x58, 0x3c, 0x97, 0x65, 0x5e, 0x2c, 0x6d, 0xa9, 0xd0, 0xe0, 0x51, 0x8f, 0x18, 0x14, 0x1e, 0x14}}, + {{0xf0, 0xfe, 0x67, 0x7a, 0xbe, 0x00, 0xbb, 0xda, 0xda, 0xed, 0xd7, 0x6a, 0x1c, 0xcf, 0x7b, 0x5c, 0xa1, 0x55, 0x6c, 0x31, 0x56, 0xf4, 0x6c, 0x93, 0x06, 0x7f, 0x67, 0xe1, 0xba, 0x6b, 0x3a, 0x0d}, {0xa3, 0xba, 0x60, 0x00, 0x75, 0x80, 0x9b, 0xd3, 0xaf, 0x61, 0x51, 0x30, 0xfa, 0x40, 0xe3, 0xe8, 0x2d, 0x65, 0x85, 0x05, 0x4b, 0xc4, 0x5d, 0x19, 0xd1, 0x07, 0xa9, 0x0b, 0x6b, 0x79, 0xd3, 0x00}}, + {{0x81, 0x1d, 0x33, 0xc0, 0x5e, 0xb9, 0x72, 0x0f, 0xf0, 0x3a, 0x36, 0x8e, 0xb4, 0x70, 0x09, 0xc5, 0xc4, 0xfc, 0x16, 0xa7, 0x23, 0x30, 0x67, 0x8d, 0x14, 0x68, 0x24, 0xfb, 0x5d, 0x48, 0x2d, 0x01}, {0xde, 0x17, 0x24, 0x26, 0xb8, 0x6b, 0x91, 0xed, 0xd3, 0x49, 0x70, 0x01, 0x8d, 0x02, 0x6d, 0x42, 0x8c, 0x0d, 0xe3, 0xb9, 0x50, 0x15, 0x8f, 0x39, 0xee, 0xfd, 0xb5, 0xac, 0x46, 0xc2, 0x18, 0x09}}, + {{0x44, 0x40, 0x25, 0x07, 0xc9, 0xb9, 0x93, 0x12, 0xdc, 0xac, 0x2f, 0x1a, 0xdf, 0x0c, 0x88, 0x40, 0xbe, 0x03, 0x05, 0xf4, 0x80, 0xcd, 0xe3, 0x4d, 0x1d, 0x5c, 0x21, 0xe0, 0x8c, 0xdc, 0xc9, 0x21}, {0xbb, 0xa3, 0xd9, 0x23, 0xe0, 0x32, 0x0b, 0x2a, 0x5d, 0xa8, 0x4d, 0x2c, 0x00, 0x33, 0xfd, 0x8d, 0x2c, 0x03, 0xdc, 0xea, 0x54, 0xfa, 0xfa, 0x90, 0x94, 0xbb, 0x76, 0xd9, 0xb4, 0xe6, 0x22, 0x2b}}, + {{0xf5, 0x6d, 0x43, 0x36, 0x22, 0xfb, 0x67, 0x7f, 0xf4, 0xbf, 0x05, 0x69, 0x40, 0xa9, 0xb7, 0x8c, 0x0a, 0xf2, 0x1f, 0x48, 0xc6, 0x85, 0x00, 0x07, 0x58, 0x61, 0xb8, 0xc4, 0xf1, 0x6b, 0x67, 0x2c}, {0x9e, 0x1a, 0x9c, 0x4a, 0x00, 0x8c, 0xf1, 0x7c, 0x6c, 0xb0, 0x5f, 0xa1, 0x8f, 0xe6, 0x31, 0xf9, 0x87, 0x95, 0x7e, 0x67, 0x21, 0x00, 0x5a, 0x4b, 0x60, 0x6c, 0x5e, 0xa3, 0x4a, 0xf6, 0xb0, 0x2f}}, + {{0x5f, 0x59, 0x70, 0x02, 0x35, 0x11, 0x0c, 0x98, 0x60, 0x8a, 0x80, 0x54, 0xc2, 0xa0, 0x07, 0xda, 0x81, 0x88, 0x15, 0xdd, 0xe1, 0x67, 0xaa, 0xb0, 0xfb, 0xc6, 0xfc, 0x9f, 0x46, 0xe4, 0x75, 0x20}, {0x32, 0x19, 0x0a, 0xaa, 0xf6, 0xd6, 0xd0, 0x44, 0x1b, 0xe0, 0x04, 0xf3, 0xb6, 0x52, 0x2b, 0x86, 0x5e, 0x13, 0x17, 0xb5, 0x48, 0x6e, 0x0d, 0x69, 0x3f, 0xe3, 0x92, 0x63, 0x2c, 0x93, 0xe5, 0x22}}, + {{0x46, 0xfa, 0x5e, 0xd5, 0x4d, 0xd2, 0x61, 0xf2, 0x1d, 0x2d, 0xce, 0x2e, 0xe1, 0x8c, 0xa2, 0xe3, 0x3c, 0x1a, 0xe4, 0x5d, 0x0f, 0xed, 0xc3, 0xb6, 0xa0, 0xcf, 0x87, 0x1a, 0x91, 0xda, 0xb0, 0x1c}, {0x42, 0x1f, 0x36, 0x53, 0x55, 0x56, 0x42, 0x54, 0xf5, 0x38, 0x48, 0xa0, 0x45, 0xc2, 0x9b, 0x08, 0x9e, 0x5a, 0x41, 0x79, 0x66, 0x4e, 0xcc, 0x8d, 0x1b, 0x66, 0xd7, 0x1d, 0xfb, 0x80, 0xc6, 0x34}}, + {{0x18, 0x5b, 0x6e, 0xd5, 0x72, 0x90, 0x65, 0x2d, 0xf3, 0xdb, 0xbd, 0x22, 0xb4, 0x24, 0x87, 0x79, 0x23, 0x6f, 0x78, 0x17, 0xd1, 0x5b, 0x46, 0xa3, 0x85, 0xe3, 0x13, 0x4b, 0x0e, 0x40, 0x61, 0x39}, {0x3c, 0x5d, 0xd2, 0xae, 0x92, 0x62, 0x5e, 0xfd, 0x3f, 0x78, 0xcb, 0xb3, 0xbc, 0x16, 0x75, 0x48, 0x56, 0x58, 0x3c, 0x29, 0x18, 0xfe, 0x9f, 0x8e, 0xcf, 0xd0, 0xc3, 0x99, 0xa9, 0xcd, 0x7e, 0x25}}, + {{0x12, 0x0f, 0x56, 0xaa, 0x7e, 0xe4, 0x13, 0x83, 0xce, 0xc1, 0xd0, 0x19, 0xce, 0xd1, 0x88, 0xa2, 0xce, 0xd9, 0xb5, 0x24, 0xc8, 0x47, 0xe7, 0x0d, 0xb8, 0xf9, 0x50, 0x60, 0xf6, 0x17, 0xf9, 0x1e}, {0x12, 0xd5, 0xe3, 0xaa, 0x17, 0xc4, 0xb3, 0x51, 0x20, 0xb5, 0xf9, 0x3e, 0xcb, 0x26, 0x8c, 0x30, 0x24, 0xc1, 0x10, 0x05, 0xe2, 0xfe, 0x24, 0x9e, 0xfa, 0x09, 0x45, 0x4a, 0x20, 0x59, 0xc4, 0x10}}, + {{0x0b, 0x1d, 0xb1, 0x26, 0xf6, 0x70, 0x54, 0x53, 0xb4, 0x51, 0xf8, 0xc3, 0x98, 0x2b, 0x6e, 0x36, 0x5e, 0x70, 0x19, 0xb0, 0xef, 0x1a, 0x2a, 0xc0, 0x29, 0x3a, 0xc4, 0xde, 0x78, 0xf8, 0xf2, 0x0e}, {0xfb, 0xd6, 0xf8, 0xc8, 0xfd, 0xea, 0xe1, 0xbb, 0xc1, 0x0f, 0x62, 0xc0, 0x4a, 0x35, 0x82, 0xba, 0x7c, 0x91, 0x9b, 0xd3, 0x9a, 0x28, 0x84, 0x49, 0x14, 0x1e, 0xd5, 0xbb, 0x6e, 0x04, 0xb0, 0x32}}, + {{0x73, 0xcf, 0x16, 0x32, 0x09, 0xe7, 0xaf, 0xe5, 0x80, 0xe5, 0x92, 0x25, 0x62, 0xea, 0x7c, 0xce, 0x3d, 0x46, 0x7b, 0x9d, 0x3d, 0xbe, 0x3b, 0x07, 0xd7, 0xb9, 0xc1, 0xe9, 0x6f, 0x97, 0x05, 0x02}, {0xdc, 0x16, 0xab, 0xb9, 0x46, 0x29, 0xef, 0x1e, 0xc4, 0xa5, 0xab, 0x5c, 0x0e, 0xea, 0x13, 0x55, 0x25, 0x14, 0xf9, 0x88, 0x8f, 0xf3, 0x74, 0x01, 0xe9, 0x4d, 0x48, 0x65, 0xc6, 0xf6, 0xb7, 0x16}}, + {{0x85, 0x5c, 0x62, 0x77, 0x9c, 0x2e, 0xcb, 0x07, 0xec, 0x1a, 0x51, 0x73, 0x24, 0xd3, 0xf6, 0x33, 0xae, 0xe7, 0xf1, 0xf1, 0x0e, 0xac, 0xf0, 0xf7, 0xef, 0x90, 0x97, 0x4e, 0x94, 0xc5, 0x3f, 0x3e}, {0xad, 0x23, 0x8c, 0xe2, 0xff, 0x21, 0x86, 0xf2, 0xe6, 0xfa, 0xb5, 0x2e, 0xd2, 0x45, 0xe4, 0x44, 0xf0, 0x57, 0xdf, 0x5b, 0xad, 0x91, 0xc6, 0xdd, 0xa9, 0xdc, 0x5d, 0x39, 0x6f, 0x15, 0xbf, 0x36}}, + {{0x9a, 0x7d, 0x26, 0x44, 0x65, 0xa1, 0x24, 0xd5, 0xab, 0xae, 0xb2, 0x84, 0x96, 0x2e, 0x66, 0x1f, 0xef, 0x47, 0xb1, 0x13, 0x45, 0x68, 0x89, 0x2c, 0xf1, 0x54, 0xd0, 0x31, 0xde, 0xc6, 0xc9, 0x38}, {0x1d, 0xe2, 0x68, 0x5a, 0x2b, 0x03, 0xac, 0x05, 0xab, 0x20, 0x6c, 0x60, 0xc0, 0xdd, 0xbb, 0x13, 0x3a, 0x8b, 0x7c, 0x22, 0xda, 0x8a, 0x26, 0x30, 0x46, 0xff, 0x71, 0x7b, 0xbe, 0x3f, 0x5b, 0x2d}}, + {{0x2b, 0xc9, 0x2e, 0x84, 0xe3, 0x85, 0xb6, 0x11, 0x8b, 0x49, 0x24, 0xa6, 0xdb, 0xf4, 0x44, 0x99, 0x97, 0x6a, 0x40, 0xb0, 0x41, 0xd6, 0xc0, 0x9f, 0x7f, 0x37, 0x4c, 0x12, 0x51, 0x4f, 0x47, 0x16}, {0xae, 0x2d, 0x34, 0xaf, 0xf3, 0x60, 0x68, 0x11, 0xc5, 0xfc, 0xc3, 0xf3, 0x48, 0xc2, 0x05, 0x78, 0x8a, 0x09, 0xd3, 0xd1, 0x52, 0xd1, 0x13, 0x48, 0xf9, 0xe5, 0x3b, 0x82, 0xdf, 0xc6, 0x8f, 0x20}}, + {{0x3e, 0xbe, 0x5e, 0x83, 0x99, 0x7a, 0x69, 0xc1, 0xca, 0x1a, 0x99, 0x31, 0xbb, 0xb7, 0xf1, 0x5e, 0x37, 0xc9, 0xb8, 0xfa, 0x3b, 0xd9, 0x3b, 0x42, 0xdd, 0x0b, 0x18, 0x04, 0xa3, 0x35, 0x67, 0x29}, {0xda, 0xd1, 0xa2, 0x07, 0x09, 0xc0, 0xb7, 0xbd, 0xa1, 0xe0, 0x43, 0xb5, 0x5b, 0x8c, 0x8c, 0x36, 0x8e, 0x74, 0x8c, 0x86, 0x20, 0x95, 0x13, 0xc2, 0x7c, 0xfe, 0xc2, 0x46, 0x1f, 0x17, 0x8a, 0x0f}}, + {{0xc1, 0xe0, 0xc0, 0xaa, 0x16, 0xfb, 0xdb, 0x6a, 0x5c, 0xf2, 0x29, 0xa3, 0x7f, 0x9f, 0x70, 0xe6, 0xa1, 0xad, 0xcd, 0x36, 0x50, 0x33, 0x45, 0x03, 0xb7, 0xef, 0x5d, 0x1a, 0x0e, 0x22, 0x7c, 0x06}, {0xca, 0x52, 0xd4, 0x1f, 0x08, 0x7a, 0xfb, 0xef, 0x41, 0xfa, 0x95, 0x39, 0x9e, 0x53, 0xc5, 0x91, 0xc2, 0x2b, 0x09, 0xb2, 0x70, 0xe2, 0x9f, 0x94, 0xf5, 0x63, 0x6c, 0x95, 0x80, 0xeb, 0x94, 0x0c}}, + {{0xe9, 0x3c, 0xb9, 0xc4, 0x8f, 0xf0, 0xce, 0x76, 0x9b, 0xd1, 0x89, 0xd8, 0xbb, 0x00, 0x65, 0xcd, 0xba, 0xc0, 0x14, 0xe5, 0x91, 0xbc, 0x76, 0xcb, 0x35, 0xcc, 0x7f, 0xf1, 0xed, 0xb3, 0x76, 0x26}, {0xb1, 0x3b, 0x0d, 0x44, 0xfc, 0x7c, 0xee, 0xa6, 0x68, 0xb5, 0x9f, 0x55, 0x37, 0xfa, 0xf0, 0xf9, 0xfd, 0xe0, 0x7b, 0x98, 0x22, 0x99, 0x75, 0x5c, 0xcc, 0x1e, 0xb9, 0x9f, 0x25, 0x9b, 0xba, 0x18}}, + {{0xe5, 0xf1, 0xaa, 0xb7, 0x70, 0x90, 0xaa, 0x88, 0x67, 0xbb, 0x33, 0x2b, 0x4a, 0x12, 0x19, 0xed, 0x13, 0xf8, 0xd2, 0xc5, 0x69, 0xe5, 0x6e, 0xe5, 0x45, 0x65, 0x9c, 0x68, 0x48, 0x3d, 0x6d, 0x3c}, {0x37, 0x27, 0x92, 0x6d, 0x98, 0x3c, 0xd3, 0x2d, 0xc5, 0xd3, 0x68, 0xcc, 0xc9, 0x67, 0x38, 0x4a, 0x89, 0x84, 0x50, 0x23, 0x4b, 0x10, 0xd8, 0x0d, 0x55, 0xd5, 0x29, 0x51, 0x03, 0xa7, 0x20, 0x12}}, + {{0xf6, 0xe3, 0x9e, 0xc2, 0xdc, 0xb7, 0x4f, 0xf3, 0xb4, 0xd6, 0x7f, 0x78, 0x9f, 0x41, 0xff, 0x68, 0x24, 0xfd, 0x50, 0xb6, 0x44, 0x60, 0x13, 0xe1, 0xbb, 0x06, 0x0a, 0x3f, 0x4e, 0xbb, 0x07, 0x0f}, {0x68, 0x48, 0xd6, 0x30, 0x9b, 0x3c, 0x2f, 0xaf, 0x41, 0x8d, 0xbc, 0xee, 0xbd, 0xd0, 0x76, 0xb8, 0x1d, 0x97, 0x31, 0xa5, 0xea, 0xcf, 0xe1, 0xd5, 0xb0, 0xe7, 0x45, 0x95, 0x3f, 0x73, 0x9f, 0x04}}, + {{0x34, 0x26, 0xba, 0x1d, 0xca, 0xf7, 0x30, 0x07, 0x5d, 0xa9, 0x49, 0xac, 0x6c, 0xc8, 0x9c, 0x22, 0xff, 0x5b, 0xf0, 0x67, 0x87, 0x54, 0x9f, 0x29, 0x65, 0x72, 0xc9, 0xbb, 0x6f, 0x6c, 0xf0, 0x1f}, {0x9e, 0xfb, 0x43, 0xc3, 0xb3, 0x85, 0xd4, 0x42, 0xed, 0x32, 0xf4, 0xd7, 0x09, 0xb5, 0xa0, 0xa6, 0x41, 0xc3, 0x54, 0x3e, 0x25, 0x75, 0x60, 0xea, 0x1e, 0x26, 0x9b, 0x8e, 0x3d, 0x14, 0x00, 0x2c}}, + {{0x47, 0xf2, 0xfc, 0x2e, 0xae, 0x58, 0xda, 0x8f, 0x0e, 0xe1, 0xf7, 0x54, 0x22, 0x00, 0x35, 0xee, 0x54, 0x68, 0xd8, 0xa1, 0x67, 0xf0, 0x6e, 0x73, 0xdb, 0x7b, 0x81, 0xf3, 0xf6, 0x73, 0x1b, 0x17}, {0x65, 0x11, 0x78, 0x28, 0x82, 0xb4, 0x4f, 0xc3, 0x8f, 0xfc, 0x61, 0xa1, 0xaf, 0x16, 0xa5, 0xf1, 0x21, 0xf7, 0x9f, 0x6d, 0xbd, 0x8c, 0xc7, 0x98, 0xc1, 0x11, 0x9f, 0xb9, 0xd3, 0x7d, 0x38, 0x3b}}, + {{0xc2, 0x01, 0x5b, 0xff, 0xdc, 0x8d, 0x2c, 0xf5, 0x28, 0xca, 0x93, 0xbd, 0xdf, 0x70, 0x3d, 0x52, 0x74, 0x37, 0xc1, 0xc4, 0xa5, 0xd3, 0x29, 0x9c, 0xc3, 0x73, 0xde, 0x38, 0xcb, 0xfe, 0xcd, 0x31}, {0xb8, 0x9c, 0xb1, 0x26, 0x28, 0x3f, 0x8c, 0xc6, 0x60, 0xfe, 0x10, 0x06, 0x93, 0x75, 0x8b, 0xfa, 0x84, 0x99, 0x51, 0x2f, 0x95, 0xd4, 0xf2, 0xde, 0x85, 0xb1, 0xad, 0xdd, 0xb6, 0x6c, 0x21, 0x22}}, + {{0x4e, 0xd2, 0xc0, 0xf3, 0xdf, 0x8e, 0xed, 0x6b, 0xd4, 0xa0, 0xba, 0xcd, 0xb9, 0x37, 0xef, 0x99, 0xdb, 0x54, 0xfd, 0x65, 0x49, 0x74, 0x57, 0xaf, 0x44, 0xca, 0x19, 0x24, 0x4e, 0xec, 0x04, 0x27}, {0xc2, 0xb1, 0x7e, 0xb6, 0xd0, 0x2b, 0xdf, 0x8c, 0x6b, 0xe8, 0x26, 0xb4, 0x3d, 0xa3, 0xf8, 0x58, 0x7f, 0x96, 0x66, 0xfe, 0x62, 0xaf, 0x3b, 0x65, 0x08, 0x47, 0xce, 0x4d, 0x58, 0x7f, 0x26, 0x23}}, + {{0x34, 0x22, 0xb7, 0xad, 0x84, 0xf2, 0x12, 0x63, 0x96, 0xab, 0x1c, 0xfa, 0xa2, 0x0a, 0x4f, 0x77, 0x95, 0x56, 0x7c, 0x13, 0xe7, 0x4c, 0x2f, 0x7b, 0xd2, 0xe0, 0xda, 0x83, 0x03, 0xb2, 0x64, 0x08}, {0x6c, 0xb7, 0xfe, 0x53, 0xd1, 0x3e, 0x1d, 0x73, 0x3e, 0x4c, 0xc9, 0xd5, 0xbc, 0x32, 0xf0, 0xca, 0xc6, 0xaa, 0xb2, 0x83, 0x28, 0x0b, 0xb6, 0xc4, 0xb5, 0xc0, 0xcf, 0xb9, 0x3c, 0xd6, 0x25, 0x21}}, + {{0x59, 0x97, 0xd9, 0xa1, 0x17, 0x3f, 0xe9, 0x53, 0x20, 0xa0, 0x1b, 0xe0, 0x3e, 0xc7, 0xbd, 0x5b, 0x75, 0x2f, 0xd3, 0xf9, 0xa6, 0xbb, 0xf7, 0xac, 0x75, 0x6a, 0x35, 0x16, 0xc8, 0xc1, 0x52, 0x19}, {0xe0, 0xd4, 0xf3, 0x1a, 0xb6, 0xf0, 0xec, 0x66, 0x90, 0x1a, 0x6e, 0xed, 0x24, 0x09, 0x1c, 0x57, 0xc0, 0x14, 0xc0, 0x1f, 0xde, 0xb5, 0x05, 0x77, 0x80, 0xea, 0x73, 0xf6, 0x22, 0x5a, 0xd7, 0x1f}}, + {{0xd6, 0xaa, 0x91, 0x8c, 0x40, 0xea, 0xe1, 0x51, 0xa3, 0x5d, 0xd7, 0x6d, 0x4a, 0xdc, 0xb3, 0x9d, 0x96, 0x9a, 0x1f, 0xe8, 0x06, 0x5a, 0x5d, 0x56, 0x90, 0x53, 0x99, 0xed, 0x0f, 0xfb, 0x2a, 0x0b}, {0xa3, 0xea, 0xeb, 0x24, 0xf7, 0xe6, 0x85, 0xcb, 0xdc, 0xb9, 0x27, 0x95, 0xb8, 0x3d, 0xe7, 0x0a, 0x68, 0x7a, 0x1c, 0x95, 0xe1, 0x28, 0xe3, 0xcb, 0x71, 0x15, 0x9e, 0x23, 0x1a, 0xae, 0x2f, 0x2e}}, + {{0xd5, 0x89, 0xc1, 0x64, 0xa2, 0xea, 0x58, 0xf9, 0xf7, 0x4f, 0x1c, 0x12, 0xd1, 0xb7, 0x66, 0xfd, 0x1b, 0x54, 0x6d, 0xe9, 0x0c, 0x6c, 0xb3, 0x34, 0x25, 0x00, 0x3b, 0x6c, 0x09, 0x86, 0x73, 0x0e}, {0xec, 0xb8, 0x3b, 0x7f, 0xde, 0x19, 0xbd, 0x2c, 0x7f, 0x17, 0xc9, 0x0d, 0x74, 0x98, 0x9d, 0x04, 0x50, 0x6c, 0x8b, 0xdc, 0x94, 0xe4, 0x76, 0xdc, 0x1a, 0xab, 0x68, 0xa9, 0x6c, 0xea, 0x16, 0x3c}}, + {{0xf3, 0xda, 0xb7, 0x89, 0xcc, 0xad, 0x5a, 0x91, 0x85, 0x97, 0x1f, 0x0e, 0x1c, 0xff, 0x09, 0x29, 0xf2, 0x7e, 0x9a, 0x01, 0x28, 0xa1, 0xbd, 0xd5, 0x51, 0x8d, 0xea, 0x9e, 0x8f, 0xfb, 0x37, 0x3d}, {0x38, 0xf1, 0x80, 0xa0, 0x28, 0xe3, 0xbe, 0x09, 0x20, 0x21, 0xfe, 0x07, 0x90, 0x58, 0x73, 0xe6, 0x10, 0x91, 0x7c, 0x5d, 0xe1, 0x15, 0x13, 0x21, 0x77, 0x54, 0xfd, 0xee, 0xf4, 0x69, 0x0f, 0x19}}, + {{0x9b, 0x45, 0x14, 0xc8, 0x28, 0xd0, 0x87, 0x98, 0x7d, 0x9a, 0x77, 0xc9, 0x14, 0x97, 0xfe, 0x0b, 0x37, 0x2c, 0x70, 0xa0, 0x23, 0xa1, 0xbc, 0x09, 0xef, 0x33, 0xf9, 0x55, 0x3f, 0xd6, 0xb5, 0x2a}, {0xaa, 0xcb, 0x9a, 0x66, 0x75, 0x31, 0x04, 0x77, 0xaf, 0xaa, 0x9c, 0x27, 0x56, 0x32, 0xd9, 0xd2, 0x03, 0x0d, 0x2e, 0x99, 0x14, 0xf4, 0x3b, 0x16, 0x8a, 0x37, 0x23, 0x07, 0x25, 0xad, 0xd3, 0x2d}}, + {{0xe1, 0x1e, 0x62, 0x2c, 0x4d, 0xaf, 0x70, 0xaa, 0x6a, 0xe1, 0x4f, 0xa4, 0xf9, 0x76, 0xbf, 0x82, 0xf4, 0x1b, 0xe9, 0x28, 0xb3, 0xdf, 0x23, 0xd8, 0xce, 0x50, 0xef, 0x8f, 0xa7, 0x86, 0x2e, 0x0e}, {0x90, 0x9e, 0xe6, 0x95, 0xdd, 0x97, 0xdf, 0x96, 0xd6, 0xbc, 0x59, 0xe9, 0x75, 0x7d, 0x40, 0xa3, 0x55, 0x92, 0x9f, 0xd8, 0xc5, 0x08, 0x06, 0x88, 0x33, 0x2b, 0xc1, 0x6d, 0xe1, 0xb3, 0xe3, 0x2d}}, + {{0xcb, 0xb2, 0xec, 0x58, 0x34, 0x29, 0x96, 0x0c, 0x0e, 0x56, 0x1e, 0x7d, 0x4d, 0x86, 0x7d, 0x0d, 0x55, 0xc5, 0xdd, 0x3c, 0xa6, 0xd3, 0x28, 0xec, 0x1a, 0x74, 0x63, 0x02, 0x00, 0xeb, 0xe0, 0x0d}, {0x0e, 0x6f, 0x7b, 0x93, 0x7d, 0x20, 0xc8, 0x1c, 0xc6, 0xc8, 0x7e, 0xdc, 0xee, 0xe7, 0x97, 0x97, 0x7a, 0xe7, 0x41, 0xe4, 0x8a, 0x08, 0x86, 0x22, 0xa4, 0xc5, 0x4f, 0xc5, 0x11, 0x48, 0x2f, 0x24}}, + {{0x91, 0x30, 0x21, 0xb4, 0xb8, 0x08, 0xe6, 0x02, 0xfb, 0x83, 0xaf, 0x26, 0x2c, 0xd8, 0xf9, 0x04, 0x25, 0x25, 0x2f, 0xba, 0x44, 0xe5, 0x9c, 0x4d, 0x3b, 0xa5, 0x51, 0x48, 0x48, 0xe2, 0x8e, 0x3f}, {0xb4, 0x2a, 0x3d, 0xf9, 0x3c, 0x0a, 0xac, 0x9d, 0x67, 0xed, 0x1b, 0xf3, 0x69, 0x55, 0xd7, 0x7e, 0x31, 0x87, 0xe7, 0x14, 0x3f, 0xb7, 0x30, 0xb5, 0xd8, 0xb1, 0xef, 0xc7, 0x58, 0x68, 0x0a, 0x32}}, + {{0xef, 0x5b, 0x8c, 0xc1, 0x73, 0x9c, 0xc7, 0xf1, 0x33, 0xaf, 0x5d, 0xbe, 0x27, 0xfb, 0xdc, 0xb4, 0xb8, 0x9a, 0x13, 0xa4, 0x37, 0x34, 0xfb, 0x00, 0x58, 0x46, 0xb8, 0xfe, 0x26, 0x69, 0xa9, 0x27}, {0x01, 0x59, 0x05, 0xa8, 0x04, 0x95, 0x4f, 0xf9, 0x86, 0xc1, 0x8c, 0x5f, 0xb5, 0x70, 0x16, 0xd8, 0x4c, 0xd4, 0xca, 0x3f, 0xc9, 0x41, 0x0a, 0xd8, 0xf9, 0xfa, 0x96, 0x69, 0xfa, 0x6d, 0xfb, 0x35}}, + {{0x08, 0xdd, 0xfd, 0x8a, 0xc8, 0x1c, 0xd4, 0xba, 0x27, 0xeb, 0x81, 0x31, 0xa3, 0xbd, 0xd2, 0x49, 0x87, 0xf2, 0x64, 0xe7, 0x2e, 0xa4, 0xd9, 0x6b, 0xd3, 0x3d, 0xd6, 0xaa, 0xbc, 0x7f, 0xf9, 0x1b}, {0x79, 0x34, 0x3f, 0xb9, 0xb6, 0x14, 0x70, 0x9e, 0x8e, 0x0a, 0xd9, 0x85, 0xcc, 0x3a, 0xcd, 0x2e, 0xbf, 0x73, 0x7e, 0x38, 0x24, 0xda, 0xdc, 0x9a, 0xa1, 0xe6, 0x13, 0xee, 0x8e, 0x20, 0x46, 0x1e}}, + {{0xe7, 0x12, 0xe2, 0x32, 0x37, 0x4b, 0xfc, 0xbe, 0xc7, 0x82, 0x43, 0x19, 0x4e, 0x0a, 0x94, 0x79, 0xcb, 0x76, 0x54, 0xba, 0x41, 0x21, 0xb5, 0x31, 0x7e, 0x09, 0xc6, 0x11, 0xd9, 0xb8, 0xd7, 0x0d}, {0xf7, 0x24, 0xa6, 0x45, 0xbe, 0x37, 0x8f, 0x87, 0x0e, 0x29, 0x8d, 0xb5, 0x10, 0xf7, 0x03, 0x9e, 0xf8, 0x08, 0xca, 0x79, 0xc0, 0xae, 0xeb, 0x9d, 0xbd, 0xb8, 0x00, 0x15, 0xac, 0x3e, 0xc9, 0x00}}, + {{0xfb, 0x42, 0x09, 0x03, 0x89, 0xeb, 0x08, 0xd8, 0x91, 0xe6, 0x1f, 0x81, 0xe4, 0x47, 0xff, 0xbc, 0x56, 0x91, 0x22, 0x74, 0xb6, 0xd2, 0xa7, 0x48, 0xbf, 0xfd, 0x0e, 0xe0, 0x52, 0xa7, 0x8e, 0x22}, {0xca, 0xd4, 0x4c, 0xc2, 0x0a, 0xca, 0x99, 0xf1, 0x21, 0x86, 0x52, 0x07, 0xa7, 0x07, 0x0f, 0x6b, 0x36, 0xdb, 0x2d, 0x03, 0x36, 0x65, 0x45, 0x8d, 0x78, 0x33, 0xb1, 0x40, 0x48, 0x3b, 0x88, 0x02}}, + {{0x1b, 0x5b, 0x9e, 0x9f, 0xb4, 0x43, 0x93, 0xe6, 0xc7, 0x13, 0xfd, 0x32, 0x6a, 0xce, 0xd5, 0x89, 0x97, 0x9a, 0xa1, 0x5a, 0x5c, 0x6f, 0xd7, 0x9e, 0xd1, 0xbb, 0xe1, 0x00, 0xc9, 0x33, 0xc4, 0x2e}, {0xe1, 0xab, 0x3e, 0x40, 0x86, 0xed, 0xc3, 0xea, 0x4e, 0x8a, 0xb8, 0xdf, 0x5e, 0x9a, 0xfe, 0xf6, 0x20, 0xdb, 0xb0, 0x97, 0x51, 0x63, 0x6a, 0x8f, 0xa2, 0xcf, 0x11, 0x05, 0x3d, 0x04, 0x2c, 0x1e}}, + {{0xd4, 0x94, 0xa3, 0xba, 0x15, 0xf2, 0xb7, 0x9a, 0x6f, 0xa2, 0x8f, 0xe3, 0x16, 0x3e, 0x8f, 0x1d, 0x56, 0x74, 0x38, 0x77, 0x19, 0xfc, 0x59, 0x41, 0xdb, 0x25, 0xc0, 0xf3, 0xa1, 0x08, 0xab, 0x00}, {0xaa, 0x84, 0x53, 0x22, 0x47, 0x42, 0x27, 0x71, 0x8b, 0xa6, 0x1e, 0xfc, 0x39, 0xd2, 0x16, 0xbb, 0x70, 0x35, 0xe4, 0x0b, 0xc2, 0xb7, 0x3b, 0x0e, 0x8e, 0x9c, 0x76, 0x3b, 0xd7, 0xd9, 0x0e, 0x10}}, + {{0xff, 0x24, 0xe9, 0x48, 0xc9, 0xae, 0xc3, 0x42, 0x14, 0xf4, 0x4b, 0xca, 0x8f, 0x1a, 0x63, 0x9b, 0x16, 0xa4, 0x0e, 0x06, 0xfe, 0xf7, 0xf2, 0x9e, 0xd1, 0x81, 0x95, 0xf0, 0x9f, 0x8d, 0xb4, 0x25}, {0x6e, 0x76, 0xa0, 0x35, 0x3a, 0x2d, 0xe4, 0x8a, 0xd6, 0x72, 0xcd, 0xe9, 0xd8, 0xf6, 0x4d, 0x10, 0x63, 0x29, 0x23, 0x04, 0xb2, 0x5c, 0xdf, 0x71, 0x36, 0x62, 0x54, 0x78, 0xd7, 0x58, 0x99, 0x08}}, + {{0xbf, 0x67, 0x5b, 0xa6, 0xad, 0x0b, 0xdc, 0xa5, 0x57, 0xb0, 0x44, 0x22, 0xa2, 0xe8, 0x9f, 0xf2, 0x90, 0xb1, 0xb8, 0x8d, 0xee, 0x3e, 0x11, 0x55, 0x85, 0xd4, 0x7b, 0x2f, 0x19, 0xc1, 0x10, 0x12}, {0x23, 0xdf, 0xe9, 0x60, 0xe5, 0xe8, 0x62, 0x4b, 0xdb, 0x5e, 0x69, 0x22, 0xa0, 0x32, 0x25, 0xe6, 0xe4, 0xf9, 0xa2, 0xbf, 0x17, 0xa3, 0xfe, 0x4a, 0x88, 0x4b, 0x26, 0x1d, 0xf6, 0x67, 0x34, 0x01}}, + {{0x9d, 0x20, 0x78, 0x9f, 0x8c, 0x3c, 0xd5, 0xd1, 0xd1, 0xf6, 0xc7, 0x9d, 0x54, 0x2e, 0x13, 0x97, 0x8f, 0xce, 0xe2, 0x19, 0xb6, 0xfe, 0x99, 0x99, 0x83, 0xad, 0xb2, 0x45, 0xc1, 0x19, 0x27, 0x18}, {0xca, 0xeb, 0x1b, 0x0d, 0xe8, 0x07, 0x40, 0x64, 0xaa, 0xc8, 0xc2, 0x21, 0x5a, 0xb4, 0x9a, 0xb5, 0xe9, 0xbd, 0x1b, 0x13, 0x6a, 0x16, 0xcd, 0x37, 0xae, 0x11, 0x39, 0x05, 0xf1, 0x79, 0x88, 0x3e}}, + {{0xd1, 0xaf, 0xb3, 0x80, 0xa7, 0x47, 0x28, 0x21, 0x7b, 0x14, 0x9d, 0x72, 0xa3, 0x98, 0x2d, 0xd6, 0x55, 0xe4, 0x80, 0x77, 0x5b, 0xcd, 0x76, 0xac, 0x57, 0x79, 0x93, 0x64, 0x55, 0xd8, 0x71, 0x13}, {0x61, 0xd8, 0x21, 0x78, 0xac, 0x35, 0xc5, 0x03, 0xff, 0x21, 0xd3, 0xd4, 0xb8, 0x7f, 0x97, 0x18, 0x4c, 0xd9, 0xd2, 0x09, 0x9d, 0x5e, 0xec, 0x57, 0x3d, 0xc3, 0x25, 0x3d, 0x96, 0x88, 0x33, 0x29}}, + {{0x33, 0xb7, 0x5b, 0x4f, 0x09, 0x90, 0x64, 0x4c, 0x3d, 0x12, 0x38, 0xb6, 0x9e, 0x14, 0x25, 0x2f, 0x56, 0xfe, 0x07, 0x3c, 0xe6, 0xd5, 0x3b, 0x58, 0xfc, 0xd8, 0x9a, 0xcf, 0xbe, 0xe3, 0xd0, 0x38}, {0x57, 0xf3, 0x82, 0x02, 0x10, 0x76, 0x82, 0x94, 0x74, 0xd4, 0x55, 0xfd, 0x5d, 0x4a, 0x35, 0x90, 0x61, 0x34, 0xd7, 0x46, 0x5f, 0x06, 0x90, 0xdf, 0x62, 0x11, 0xf7, 0xa7, 0xe9, 0xe8, 0xe2, 0x1e}}, + {{0xf6, 0xf9, 0x25, 0x83, 0xda, 0x20, 0xcf, 0xc2, 0x6c, 0xe0, 0xb5, 0x3a, 0x2b, 0x32, 0x58, 0x41, 0xaf, 0xde, 0x5f, 0xe7, 0x70, 0x03, 0xea, 0x55, 0x45, 0xb3, 0x07, 0x23, 0x55, 0x51, 0x91, 0x04}, {0x56, 0x11, 0xd2, 0x58, 0xc7, 0xb7, 0x6c, 0x3a, 0xd4, 0xc8, 0x0a, 0x42, 0xa9, 0xac, 0xe5, 0x3e, 0x2b, 0x04, 0xb0, 0x93, 0xfc, 0x78, 0x4e, 0x82, 0x67, 0xd6, 0x79, 0x86, 0x5f, 0xec, 0x00, 0x23}}, + {{0x86, 0x12, 0x4a, 0xcd, 0xe7, 0x4d, 0x34, 0x45, 0x95, 0xbd, 0x45, 0xd5, 0xbe, 0x9f, 0x00, 0x70, 0x4d, 0xfe, 0x9c, 0x32, 0xdc, 0x45, 0xf3, 0x56, 0x70, 0x86, 0x22, 0x4c, 0x10, 0x0f, 0x11, 0x1b}, {0x13, 0x0b, 0x03, 0x4d, 0xee, 0x67, 0x7e, 0x58, 0xfd, 0xe3, 0xa1, 0xcf, 0xe0, 0x4e, 0xd6, 0x26, 0x66, 0x31, 0x5b, 0xe4, 0xbc, 0x3d, 0xa4, 0x31, 0x87, 0x7d, 0x99, 0xcf, 0x74, 0x1a, 0x4c, 0x38}}, + {{0xde, 0x5b, 0xaf, 0x03, 0x15, 0xb8, 0x39, 0xa7, 0x51, 0x37, 0x16, 0x59, 0xc3, 0x4f, 0x73, 0xfe, 0x68, 0x0f, 0x71, 0xa5, 0xab, 0xe2, 0xae, 0x87, 0x69, 0x60, 0xdb, 0xfb, 0x09, 0x7f, 0x80, 0x28}, {0xfe, 0x91, 0xc3, 0x08, 0x52, 0xef, 0x9a, 0x95, 0x5c, 0xc3, 0x96, 0xb2, 0x94, 0x48, 0x83, 0x92, 0x73, 0x5f, 0xf0, 0x99, 0x7f, 0xc4, 0x5c, 0x4a, 0xf2, 0xe5, 0x50, 0x95, 0xd4, 0x23, 0xa5, 0x04}}, + {{0xf0, 0xa2, 0x73, 0x84, 0x55, 0xa1, 0xaa, 0xbb, 0x97, 0x70, 0x4a, 0x59, 0xdd, 0x48, 0x8d, 0x84, 0xc1, 0xdd, 0xee, 0xfa, 0x5c, 0xec, 0xdc, 0xe3, 0x2e, 0xd9, 0xc4, 0xd7, 0x5a, 0x2c, 0x8c, 0x3a}, {0xe1, 0x2b, 0xfe, 0xd4, 0x50, 0x77, 0xbc, 0x3b, 0xff, 0xba, 0x3b, 0xe5, 0x48, 0x0c, 0xba, 0x70, 0x04, 0x68, 0x0d, 0xc1, 0x83, 0x56, 0x04, 0xa8, 0xfe, 0x0d, 0x7f, 0xc6, 0x31, 0x66, 0x94, 0x10}}, + {{0xd7, 0xcc, 0x77, 0x36, 0xc5, 0x21, 0x02, 0x36, 0xb3, 0x11, 0x9e, 0x60, 0xd9, 0x46, 0xe8, 0x9d, 0x1e, 0xe5, 0xc5, 0x0f, 0x59, 0x0f, 0x00, 0xc6, 0xf3, 0x83, 0x2a, 0xba, 0x18, 0x6f, 0xe5, 0x12}, {0xfd, 0x7c, 0x6e, 0x63, 0x33, 0xc9, 0x72, 0xb4, 0x2b, 0x25, 0xf1, 0xb1, 0x5e, 0x50, 0x7b, 0x74, 0x69, 0x9e, 0xbe, 0x0f, 0x8b, 0x8b, 0x4f, 0x94, 0xcd, 0x1f, 0x35, 0xcc, 0xb2, 0x05, 0x1b, 0x08}}, + {{0xcc, 0x02, 0xe6, 0xa2, 0x36, 0x27, 0x9f, 0xf6, 0x1f, 0x62, 0xc4, 0xd5, 0xb7, 0x25, 0xb6, 0x40, 0x80, 0xbc, 0xc9, 0x4b, 0xa7, 0xe2, 0xba, 0x09, 0xb4, 0xa1, 0x98, 0x32, 0x42, 0x39, 0xb0, 0x19}, {0xdd, 0x6d, 0xdd, 0x92, 0x06, 0x9c, 0x25, 0xab, 0x77, 0x26, 0x5a, 0x71, 0x85, 0x0e, 0x30, 0x89, 0x91, 0x7b, 0x96, 0x6d, 0x35, 0x4d, 0x18, 0x15, 0x77, 0xf7, 0x25, 0xc0, 0x7e, 0x01, 0xfc, 0x1a}}, + {{0xc4, 0x47, 0xd1, 0xc9, 0x1d, 0xa1, 0x9c, 0xbd, 0x65, 0xf6, 0xea, 0x74, 0xe7, 0x70, 0x29, 0xa7, 0x9b, 0x8d, 0x50, 0xe3, 0x51, 0x7f, 0xb2, 0x4a, 0xf1, 0x65, 0xe2, 0x52, 0x5f, 0x85, 0x80, 0x1b}, {0x31, 0x4c, 0xbe, 0x25, 0xf3, 0x3e, 0xcd, 0x47, 0x9b, 0xad, 0x2a, 0xf5, 0x95, 0x38, 0xc1, 0xe4, 0x27, 0x7f, 0x99, 0x93, 0xa3, 0x9d, 0x33, 0x35, 0x6f, 0xcf, 0x5a, 0xf4, 0x28, 0x7e, 0x88, 0x23}}, + {{0xe2, 0x11, 0xa6, 0xe1, 0x44, 0xf0, 0x63, 0x08, 0xf8, 0x78, 0x7a, 0x8e, 0x75, 0x55, 0xe4, 0x79, 0xd6, 0x30, 0x54, 0x0f, 0x15, 0x9c, 0xfc, 0xc8, 0x4d, 0x27, 0xde, 0x84, 0x36, 0x8e, 0x7a, 0x3a}, {0x4d, 0x3a, 0xb3, 0xba, 0xb5, 0x2f, 0xa3, 0x03, 0x67, 0x78, 0x64, 0x5c, 0xa6, 0x34, 0xd2, 0x0b, 0xc1, 0xd7, 0x13, 0xd0, 0xad, 0x19, 0x2b, 0x97, 0x60, 0xf2, 0x2e, 0xe2, 0x94, 0x2c, 0x12, 0x16}}, + {{0xfb, 0xf8, 0x53, 0xc5, 0x4d, 0x18, 0x78, 0xdf, 0x14, 0x28, 0x55, 0x37, 0x38, 0xea, 0xe8, 0x95, 0x38, 0xdb, 0x39, 0x6d, 0x2f, 0x09, 0x03, 0x16, 0x9f, 0xbb, 0x01, 0xc9, 0xea, 0xe6, 0x69, 0x27}, {0x45, 0x2d, 0xb6, 0x22, 0xd2, 0x1a, 0xae, 0x6a, 0xa9, 0x1e, 0x0d, 0x98, 0x4f, 0x70, 0x41, 0x83, 0xa6, 0x23, 0x60, 0xda, 0x03, 0xb5, 0x17, 0x73, 0xe6, 0x92, 0x7c, 0xa7, 0xaa, 0x5b, 0xb1, 0x16}}, + {{0xe5, 0x93, 0xf3, 0xd3, 0x4f, 0x69, 0xad, 0x35, 0x5d, 0x63, 0xc1, 0xec, 0xab, 0x6b, 0x77, 0xb9, 0x7f, 0x84, 0x0f, 0xa8, 0x52, 0x25, 0x3e, 0x67, 0x2d, 0x6c, 0xfd, 0x6f, 0x2e, 0x56, 0x2a, 0x28}, {0x33, 0x76, 0x9b, 0xaf, 0x0f, 0x30, 0x61, 0xcd, 0x7a, 0x76, 0xb9, 0x6f, 0xdd, 0x7b, 0x78, 0x5f, 0x2e, 0xa8, 0xcb, 0xa3, 0x0b, 0x3e, 0xe6, 0xf8, 0x26, 0x58, 0xf6, 0x70, 0x6c, 0x8b, 0x29, 0x3c}}, + {{0xf0, 0x85, 0x33, 0x40, 0x0b, 0x92, 0x78, 0xf9, 0xed, 0xf4, 0xe7, 0x87, 0xed, 0xdf, 0x41, 0x47, 0x40, 0xb0, 0x97, 0xa0, 0x50, 0x9a, 0xf7, 0x9a, 0x55, 0x3d, 0x7f, 0x7a, 0x01, 0x04, 0xf2, 0x09}, {0xde, 0xcf, 0x1d, 0x1e, 0xc7, 0xa7, 0x4c, 0x48, 0xc1, 0xcb, 0xa5, 0xc8, 0x17, 0xfe, 0x5e, 0x43, 0x57, 0x50, 0x04, 0x71, 0xaa, 0x12, 0x81, 0xe9, 0x26, 0x80, 0xc5, 0xb8, 0x05, 0x99, 0x2c, 0x1d}}, + {{0x87, 0xe6, 0xa4, 0xe2, 0xc1, 0xdd, 0x4e, 0x8a, 0x8f, 0x85, 0x8e, 0x01, 0xe2, 0x5c, 0xff, 0x5b, 0x6a, 0xe5, 0xa1, 0x83, 0x2f, 0x66, 0xe5, 0xc6, 0xba, 0x2d, 0x9b, 0x67, 0x0d, 0x00, 0xa2, 0x02}, {0xa0, 0xb2, 0x76, 0x7c, 0xea, 0xf6, 0x6a, 0x2f, 0x56, 0x40, 0x69, 0x9b, 0xfa, 0x4b, 0xc7, 0xb8, 0x14, 0x1e, 0x6d, 0x49, 0xad, 0x16, 0x79, 0xfb, 0xe2, 0x04, 0x4d, 0xf1, 0x05, 0xca, 0xf4, 0x1d}}, + {{0x5c, 0xea, 0x36, 0xe3, 0xef, 0xf6, 0x88, 0x60, 0xc8, 0x54, 0xb5, 0x3a, 0x0a, 0x11, 0x97, 0x74, 0x70, 0x1b, 0xab, 0x90, 0x7e, 0x8a, 0x4a, 0xbb, 0x07, 0xe3, 0x44, 0xa6, 0xa8, 0x05, 0xca, 0x16}, {0xcf, 0x03, 0xe0, 0xee, 0xf6, 0x4b, 0x6b, 0xbc, 0x4c, 0x31, 0x17, 0x5d, 0x39, 0xc2, 0x97, 0x94, 0xeb, 0x57, 0xdf, 0x96, 0x4e, 0x8c, 0x28, 0xa5, 0x2f, 0xc3, 0xb2, 0x70, 0xd2, 0x2c, 0xec, 0x05}}, + {{0x44, 0x68, 0x51, 0x2d, 0xba, 0x5a, 0x4b, 0x1d, 0xf0, 0xcf, 0xac, 0x14, 0x63, 0xe7, 0xbb, 0x0e, 0x47, 0x59, 0x50, 0x19, 0xc3, 0x52, 0xe2, 0xca, 0xec, 0x58, 0x6b, 0x98, 0x69, 0x77, 0x6f, 0x10}, {0x91, 0x26, 0x53, 0xbd, 0x24, 0xde, 0x32, 0xec, 0xaa, 0xb8, 0xba, 0x9f, 0x79, 0xb1, 0x82, 0xaf, 0x51, 0x4d, 0xf3, 0x33, 0x2d, 0x59, 0xf7, 0xad, 0xdb, 0x22, 0x80, 0x53, 0x82, 0xab, 0xd7, 0x1d}}, + {{0xf9, 0x94, 0x6c, 0x35, 0xcc, 0x5d, 0x01, 0x77, 0xab, 0x73, 0x9f, 0xf8, 0x5f, 0x8f, 0x5b, 0xe7, 0x37, 0x47, 0xe2, 0x81, 0x89, 0x7c, 0x4a, 0x93, 0xe3, 0x9e, 0x04, 0xe7, 0x05, 0xea, 0x52, 0x09}, {0xf7, 0x75, 0x50, 0x9d, 0x2d, 0xc9, 0xdb, 0x7b, 0xd4, 0x9e, 0x28, 0x5f, 0xf0, 0x21, 0x85, 0x99, 0xb2, 0x6f, 0x28, 0x7a, 0xfe, 0x4f, 0x0d, 0x92, 0x92, 0x32, 0x69, 0x4b, 0xf6, 0xed, 0xb4, 0x19}}, + {{0xac, 0xb3, 0xf9, 0x18, 0xb7, 0x48, 0x93, 0x2d, 0x72, 0xcb, 0xe9, 0x07, 0xd8, 0xc3, 0xe6, 0x1e, 0x59, 0x0b, 0x7b, 0xbd, 0xe3, 0x47, 0xf7, 0x27, 0xaf, 0x39, 0x0f, 0x0e, 0x4e, 0x26, 0x44, 0x33}, {0x85, 0x7f, 0x27, 0x9f, 0xe5, 0x14, 0x92, 0x53, 0x84, 0xfa, 0xc7, 0x75, 0x5c, 0xf1, 0xb5, 0xba, 0x8a, 0xa8, 0xcb, 0x1b, 0x01, 0xa5, 0x92, 0x5e, 0xef, 0xeb, 0x98, 0x6e, 0xc4, 0x7b, 0xbe, 0x39}}, + {{0x36, 0x7d, 0x98, 0x57, 0xb8, 0x5c, 0xfc, 0xef, 0x06, 0x1c, 0x8a, 0xe0, 0x83, 0xe3, 0x31, 0x42, 0xe5, 0x5f, 0xb4, 0x99, 0xe7, 0xc3, 0xf4, 0x83, 0x24, 0xb3, 0x8d, 0x62, 0xd9, 0x4a, 0xc4, 0x1b}, {0xbc, 0x83, 0x60, 0x1a, 0xed, 0x73, 0x51, 0xb0, 0x0f, 0x55, 0x7c, 0x37, 0x9d, 0xb4, 0x3f, 0x5d, 0x56, 0xc9, 0x34, 0xc6, 0x7e, 0x1f, 0xc4, 0x9e, 0x52, 0xe3, 0x49, 0x79, 0xbd, 0xa4, 0xa2, 0x2e}}, + {{0xc5, 0x15, 0xab, 0x18, 0x6d, 0xb8, 0x11, 0xce, 0xbd, 0xeb, 0xcf, 0xe7, 0xbb, 0x58, 0xfd, 0xfd, 0x41, 0xa7, 0xde, 0x1a, 0x65, 0x16, 0x1a, 0x01, 0xbe, 0xdc, 0xfc, 0x03, 0x83, 0x76, 0x67, 0x18}, {0xa6, 0x63, 0x36, 0x74, 0xb3, 0xa7, 0x65, 0x8c, 0xca, 0xbc, 0xb4, 0x82, 0x2c, 0xf6, 0x95, 0x08, 0x42, 0xbf, 0xe5, 0x19, 0x48, 0x26, 0x7f, 0x69, 0x55, 0xc1, 0x3a, 0x69, 0x89, 0x8a, 0x9e, 0x1c}}, + {{0x62, 0xd9, 0x83, 0xb5, 0xc1, 0x50, 0xf1, 0x20, 0xa4, 0x33, 0xf3, 0x6b, 0xdd, 0x4f, 0x7c, 0x5b, 0x95, 0x06, 0x56, 0x6b, 0x14, 0xf2, 0x16, 0x66, 0xd7, 0xf9, 0x39, 0xae, 0x2a, 0x15, 0x09, 0x3c}, {0x76, 0x5f, 0xe4, 0x11, 0x5c, 0xd1, 0x4c, 0x8d, 0x95, 0x7a, 0x65, 0xa3, 0xa2, 0xfb, 0xe6, 0x3e, 0x68, 0xae, 0x90, 0x29, 0x4d, 0x94, 0xdf, 0x57, 0xfd, 0xfc, 0x7f, 0xdd, 0x06, 0x96, 0x40, 0x3e}}, + {{0x7f, 0x20, 0x4e, 0xc6, 0xaa, 0xcb, 0x1d, 0x0f, 0xaf, 0x74, 0xe8, 0x04, 0x96, 0x00, 0xce, 0x24, 0x2b, 0x3b, 0x16, 0x4f, 0x41, 0xa3, 0x06, 0x82, 0x83, 0x53, 0x60, 0x95, 0xa5, 0xff, 0x41, 0x18}, {0xb7, 0xdf, 0x2d, 0x17, 0x84, 0x4a, 0x45, 0x74, 0x87, 0x8c, 0x74, 0xe9, 0x3d, 0x66, 0x61, 0x4e, 0x10, 0xae, 0x52, 0x76, 0x6f, 0xc4, 0xac, 0x49, 0x40, 0x3d, 0xa0, 0x2d, 0x31, 0xeb, 0xf9, 0x35}}, + {{0xd2, 0x7c, 0x21, 0xe6, 0x29, 0xcf, 0xb2, 0x71, 0x72, 0xc7, 0xdc, 0x0c, 0xe4, 0x6d, 0xfb, 0x85, 0x7a, 0x87, 0x46, 0x0a, 0x60, 0x2d, 0xb0, 0xfc, 0x34, 0x62, 0x83, 0x25, 0xa8, 0xcb, 0xcd, 0x0d}, {0x7b, 0x32, 0x11, 0xd6, 0x58, 0xe0, 0xe7, 0xa5, 0xdd, 0x02, 0x46, 0xd4, 0xdc, 0xda, 0x29, 0x1f, 0xe5, 0x60, 0xaa, 0x22, 0x16, 0x06, 0xd2, 0x50, 0x28, 0x5d, 0x11, 0x69, 0xd7, 0x4a, 0xc1, 0x1b}}, + {{0x9f, 0x41, 0x3b, 0xab, 0xd4, 0x98, 0xad, 0x76, 0xff, 0x97, 0x25, 0x6e, 0x50, 0x8c, 0xad, 0xff, 0xbd, 0x1e, 0xea, 0x43, 0xb6, 0xbb, 0x06, 0x3a, 0xf7, 0xc5, 0xfb, 0x6f, 0xf3, 0xb0, 0xa3, 0x3d}, {0x6d, 0x29, 0xf0, 0x6b, 0x0e, 0xed, 0x47, 0xf7, 0xb0, 0x93, 0x58, 0xd3, 0x63, 0x98, 0xb5, 0x08, 0x4e, 0x06, 0x7f, 0xa7, 0x01, 0xa3, 0xc9, 0xfe, 0x86, 0x03, 0xdc, 0xd7, 0x9e, 0xb5, 0xe9, 0x18}}, + {{0x4f, 0x68, 0xa0, 0x65, 0x9b, 0x7b, 0x65, 0x19, 0x69, 0x1b, 0xc4, 0x19, 0x2d, 0x8c, 0x38, 0x21, 0xfa, 0x87, 0x83, 0xd7, 0x0b, 0x21, 0x4f, 0xae, 0x1b, 0xaa, 0xf9, 0x17, 0x56, 0xf1, 0x4a, 0x2e}, {0xac, 0x23, 0xbb, 0x7d, 0x88, 0xda, 0x5a, 0x7e, 0xa5, 0xce, 0x1a, 0xaa, 0xda, 0x81, 0x6a, 0x07, 0xc7, 0x12, 0x29, 0x46, 0x4a, 0x2c, 0xf5, 0x46, 0x00, 0xcd, 0x9a, 0xa7, 0x47, 0x3c, 0x7c, 0x37}}, + {{0x60, 0x89, 0x5a, 0x77, 0x4f, 0x9b, 0xe6, 0xd9, 0x53, 0x22, 0x8c, 0x3a, 0x6d, 0x68, 0xf8, 0x3c, 0x50, 0xf6, 0xdd, 0x38, 0xe7, 0x16, 0x7c, 0x00, 0xfb, 0xaf, 0xa9, 0xd1, 0x7f, 0xd8, 0x5c, 0x27}, {0xdc, 0x39, 0xbe, 0x83, 0xe8, 0xfa, 0xac, 0x2e, 0x92, 0x97, 0x5e, 0x54, 0x90, 0xcb, 0x47, 0xa1, 0x56, 0x21, 0xa5, 0x0c, 0x0b, 0x66, 0x94, 0xb8, 0x1f, 0x2a, 0xe6, 0x54, 0xd5, 0x7b, 0x2c, 0x10}}, + {{0x43, 0xd7, 0x8a, 0x81, 0x25, 0x52, 0x50, 0x3d, 0x51, 0x44, 0x96, 0x22, 0xda, 0xa4, 0x10, 0x76, 0x38, 0xe1, 0xcd, 0x15, 0xa3, 0xdb, 0xc1, 0x4a, 0x68, 0x8b, 0xb4, 0x93, 0xea, 0xe9, 0x63, 0x2a}, {0xae, 0xa0, 0x7c, 0x98, 0x8a, 0x7b, 0x2f, 0x60, 0xa2, 0x9c, 0x2b, 0xd1, 0xff, 0xd9, 0x6d, 0xf2, 0x74, 0x51, 0xde, 0x6c, 0x96, 0x36, 0x34, 0x74, 0xf6, 0x98, 0x8d, 0x59, 0x01, 0x2b, 0x77, 0x1d}}, + {{0x2d, 0xf1, 0x03, 0x25, 0xfa, 0x79, 0xe6, 0x9e, 0xa7, 0xc1, 0x7c, 0xab, 0xa8, 0x67, 0xa0, 0xe3, 0x0d, 0x5d, 0x00, 0xa9, 0xd6, 0xcf, 0x04, 0x4a, 0x0e, 0x35, 0xce, 0x03, 0x1f, 0xe7, 0xb6, 0x20}, {0xc0, 0xe9, 0xd9, 0x01, 0x2e, 0x35, 0x99, 0xff, 0x8a, 0x91, 0x8b, 0xf3, 0x28, 0xeb, 0xff, 0x1c, 0x4b, 0x6a, 0x2f, 0x6b, 0x1d, 0x21, 0x5a, 0x3f, 0x78, 0x3f, 0x33, 0xb9, 0xc5, 0x1a, 0xfc, 0x35}}, + {{0x3b, 0xc1, 0x2e, 0x0d, 0x30, 0xac, 0x29, 0xfd, 0x9d, 0x26, 0x90, 0xa0, 0x28, 0x88, 0x86, 0x6d, 0x3f, 0x6e, 0x1d, 0xdf, 0xe3, 0xb4, 0x7b, 0x61, 0x22, 0x3d, 0x99, 0x20, 0xbd, 0x44, 0x62, 0x10}, {0x53, 0xb0, 0x83, 0x7d, 0x07, 0x62, 0x4b, 0xba, 0xb4, 0xa5, 0x54, 0x05, 0xb3, 0x22, 0x2b, 0x75, 0xc4, 0x12, 0xa0, 0xf3, 0x20, 0x83, 0x99, 0x93, 0xf3, 0x53, 0xa7, 0xf9, 0x95, 0x12, 0x32, 0x3e}}, + {{0xf6, 0x2d, 0xda, 0x67, 0x13, 0x2a, 0xb0, 0x21, 0xe5, 0x71, 0xbb, 0x2a, 0x36, 0xf5, 0x5e, 0xd9, 0x8d, 0xbb, 0x9a, 0x81, 0x97, 0xcf, 0x66, 0xc4, 0x8d, 0xd1, 0xef, 0xa9, 0xf5, 0xd2, 0xc1, 0x0a}, {0x3d, 0x05, 0x6f, 0xe5, 0xda, 0x72, 0x2c, 0x65, 0xf8, 0x25, 0x09, 0xdd, 0x3c, 0xdf, 0x16, 0x3e, 0x8e, 0xae, 0xae, 0xf0, 0x64, 0xdc, 0x86, 0x44, 0x28, 0x3d, 0xcc, 0xaf, 0xd6, 0xd1, 0x83, 0x10}}, + {{0x22, 0xcb, 0x04, 0x15, 0x3f, 0x90, 0x6d, 0xd6, 0xa2, 0xf1, 0xfd, 0x24, 0x95, 0x1d, 0x74, 0x7d, 0x1d, 0x70, 0x05, 0x5b, 0x42, 0x11, 0x20, 0x04, 0xf9, 0x28, 0xa6, 0xa4, 0xdb, 0xa1, 0x81, 0x25}, {0xe8, 0x04, 0x35, 0x94, 0x61, 0x31, 0xf5, 0x31, 0xee, 0x27, 0x23, 0xe9, 0x6a, 0x08, 0xb5, 0x56, 0x0b, 0xd4, 0x53, 0xf4, 0xa6, 0xdb, 0x70, 0x04, 0xc3, 0x8b, 0x46, 0x6a, 0xbb, 0x3c, 0xb7, 0x37}}, + {{0x5a, 0x09, 0x62, 0x2a, 0xe6, 0xfa, 0x64, 0x5a, 0xe1, 0x09, 0xcc, 0xa3, 0x9a, 0xb9, 0x5d, 0x1a, 0xcf, 0xd4, 0xf1, 0xb4, 0x4d, 0xbf, 0x87, 0x5c, 0x25, 0xce, 0xc7, 0x5a, 0x45, 0xe1, 0x54, 0x35}, {0x3c, 0x65, 0x59, 0xb2, 0xaa, 0x29, 0xfb, 0x62, 0x99, 0xbf, 0x69, 0xf6, 0x28, 0xe0, 0x79, 0x10, 0xd3, 0x56, 0x6a, 0xb6, 0xa2, 0xe1, 0xb5, 0xc7, 0x3d, 0x66, 0x79, 0x06, 0x27, 0x6c, 0xa9, 0x1d}}, + {{0x95, 0xc5, 0xe4, 0x05, 0x97, 0x75, 0x8a, 0xa3, 0x04, 0x91, 0x79, 0x36, 0xbf, 0x16, 0xb5, 0x93, 0xa9, 0xec, 0xb7, 0x06, 0x7c, 0x61, 0xf3, 0xdc, 0x0a, 0xd9, 0x46, 0x62, 0x49, 0x96, 0x04, 0x1c}, {0x10, 0xb0, 0x98, 0x20, 0xde, 0x62, 0x9b, 0xcb, 0x5b, 0x3c, 0xc4, 0xe6, 0xdc, 0xbd, 0x11, 0x0b, 0xb5, 0xa4, 0x71, 0x21, 0x19, 0x96, 0x06, 0x0e, 0x63, 0xb5, 0x5e, 0x54, 0xbd, 0xf9, 0xa0, 0x0c}}, + {{0x8c, 0xd6, 0xe1, 0x5c, 0xbb, 0xcc, 0xcc, 0xab, 0x82, 0xa2, 0x0d, 0xe5, 0x47, 0xaf, 0x7c, 0x6f, 0x6f, 0x80, 0xaa, 0xab, 0x5e, 0x13, 0x6a, 0xf3, 0xe8, 0xaa, 0x95, 0x10, 0xde, 0xba, 0x6e, 0x0c}, {0xe2, 0xb3, 0xe6, 0x69, 0x9e, 0xcc, 0x9c, 0x75, 0xbf, 0x63, 0xa2, 0x05, 0xdf, 0x54, 0xdd, 0xf9, 0x6b, 0x94, 0x47, 0xcf, 0x3c, 0xd7, 0xda, 0x89, 0x52, 0xbc, 0x83, 0x2b, 0xaf, 0xd8, 0x12, 0x03}}, + {{0x84, 0x40, 0x09, 0x32, 0x19, 0xf4, 0x63, 0x3d, 0xbd, 0xd3, 0x0d, 0xa1, 0x39, 0x09, 0x2e, 0xa8, 0x24, 0xca, 0x16, 0xe0, 0x48, 0x2d, 0xa4, 0x09, 0xd6, 0xa5, 0xfb, 0x48, 0x60, 0x25, 0xd5, 0x22}, {0x8e, 0xf0, 0x85, 0xe3, 0x7b, 0x91, 0x5f, 0x20, 0xc5, 0x96, 0x82, 0x15, 0xea, 0x59, 0xba, 0xe8, 0xf4, 0x61, 0x02, 0x12, 0x05, 0x5f, 0xdb, 0x07, 0x81, 0x2d, 0x0d, 0xcf, 0x10, 0xfe, 0x27, 0x1b}}, + {{0xbc, 0xcd, 0xc0, 0xc4, 0x26, 0x20, 0xc5, 0xc3, 0xf1, 0xc4, 0x04, 0x98, 0x75, 0xa0, 0xc9, 0xe5, 0x01, 0x6d, 0x9b, 0x89, 0x4f, 0xa3, 0x3d, 0x33, 0xf1, 0x9f, 0xee, 0x69, 0x6f, 0x9b, 0x93, 0x08}, {0x29, 0x6a, 0x0b, 0xa6, 0x90, 0x5c, 0x38, 0x57, 0xe3, 0x9e, 0x89, 0x98, 0xf0, 0x0a, 0xfe, 0xcb, 0xc2, 0x94, 0x05, 0xed, 0x49, 0x4f, 0x6c, 0xe5, 0xd0, 0xfe, 0xe4, 0xa7, 0xdf, 0x87, 0x8c, 0x1a}}, + {{0x52, 0x70, 0x4a, 0x52, 0x17, 0x86, 0xcc, 0x9b, 0x39, 0x80, 0x3b, 0xa5, 0x3e, 0xbc, 0xd1, 0x9e, 0xae, 0xb3, 0xc1, 0x98, 0x28, 0x0a, 0x3b, 0xe8, 0x5f, 0x00, 0x78, 0xf3, 0x79, 0xb8, 0x56, 0x21}, {0x03, 0x0c, 0x4c, 0x1a, 0xd6, 0x4f, 0x45, 0xe4, 0x37, 0xd1, 0x45, 0x9e, 0xee, 0x77, 0x2d, 0xfd, 0x2e, 0x46, 0xca, 0xbe, 0xd1, 0xd7, 0x4c, 0x36, 0x24, 0x02, 0x06, 0x6d, 0xa0, 0x61, 0x54, 0x04}}, + {{0xdf, 0xc8, 0x42, 0x77, 0x0b, 0xe4, 0xdc, 0xa6, 0xbb, 0x4c, 0x5e, 0x2f, 0x9f, 0xfb, 0xf6, 0x77, 0xf6, 0x01, 0xa1, 0xc8, 0xf2, 0xa6, 0x71, 0x89, 0x7e, 0x55, 0x8d, 0xe6, 0x1d, 0x89, 0xf6, 0x06}, {0x60, 0x93, 0x2c, 0xf3, 0x32, 0xeb, 0x36, 0xe1, 0xe3, 0x94, 0x83, 0x15, 0x7a, 0x80, 0xcc, 0x43, 0x85, 0x0e, 0x3f, 0xbd, 0xd8, 0x68, 0x83, 0xb8, 0x9b, 0xd9, 0xff, 0xa3, 0x43, 0xf7, 0xc7, 0x39}}, + {{0x88, 0xa1, 0xc5, 0xde, 0x24, 0x80, 0x92, 0x4d, 0x3e, 0x35, 0x86, 0xd3, 0x2b, 0xa9, 0xfc, 0xc6, 0x66, 0x76, 0x1b, 0xf5, 0x5d, 0xc8, 0x12, 0x58, 0x75, 0xad, 0x85, 0xb9, 0xae, 0x96, 0x22, 0x36}, {0x5b, 0xcc, 0xbc, 0x0e, 0x47, 0x43, 0x74, 0xaf, 0x4e, 0xe0, 0x4f, 0xbd, 0x03, 0xdf, 0x64, 0x86, 0xe1, 0xa6, 0xed, 0x90, 0xe1, 0xdf, 0x7c, 0xbb, 0x6d, 0x8d, 0xc1, 0x6a, 0xf0, 0x49, 0xb7, 0x04}}, + {{0x64, 0x5d, 0xe6, 0x61, 0x3a, 0x7e, 0xcb, 0x47, 0x8b, 0x16, 0x1d, 0x61, 0x4b, 0x8f, 0x68, 0x26, 0x0a, 0x27, 0x81, 0xf0, 0xc6, 0xb1, 0x1e, 0x85, 0xd3, 0xc4, 0xd9, 0x07, 0x77, 0x65, 0xcd, 0x0b}, {0x59, 0x6e, 0x64, 0x01, 0x1d, 0x9c, 0xa7, 0xb8, 0x14, 0x8d, 0xbe, 0x3c, 0x81, 0x0a, 0xa0, 0xac, 0x61, 0x22, 0xd4, 0xa4, 0x22, 0xd6, 0xe3, 0x9b, 0xaf, 0x0a, 0x21, 0xff, 0xec, 0x44, 0x8f, 0x22}}, + {{0xd8, 0x77, 0xfc, 0x32, 0xeb, 0x32, 0xe8, 0x01, 0x1d, 0x6d, 0x1e, 0xcf, 0x9f, 0xd4, 0x7b, 0xa3, 0x02, 0x69, 0x3a, 0x00, 0x26, 0x76, 0xde, 0x4a, 0x5b, 0x28, 0x73, 0x68, 0xba, 0x18, 0x10, 0x28}, {0xf7, 0xe0, 0x6a, 0x3f, 0x8c, 0xbd, 0x22, 0x3b, 0xf9, 0x9d, 0x9e, 0xcc, 0xe9, 0xd4, 0x7a, 0x64, 0x1a, 0x86, 0xe2, 0xe5, 0x4e, 0x26, 0x9f, 0x59, 0x1b, 0xe1, 0x11, 0xc7, 0xbb, 0x4d, 0xc7, 0x1b}}, + {{0x15, 0x0e, 0xb8, 0xf1, 0x2c, 0x50, 0x31, 0xea, 0x28, 0xb4, 0x48, 0xcd, 0x60, 0x51, 0x3d, 0xc3, 0xec, 0xad, 0x17, 0xde, 0x10, 0xc9, 0x23, 0xcc, 0x47, 0x9c, 0xa5, 0x1a, 0xce, 0xf9, 0xde, 0x07}, {0x32, 0x59, 0x64, 0xb4, 0xba, 0xee, 0xae, 0xa4, 0x65, 0x4d, 0x87, 0x10, 0x50, 0x14, 0x23, 0xb1, 0xd6, 0xfb, 0xb3, 0xe2, 0x73, 0x28, 0x4f, 0xd7, 0x2f, 0x46, 0xe4, 0x56, 0xe5, 0x28, 0xf7, 0x37}}, + {{0xb4, 0xc5, 0x4b, 0xbb, 0x95, 0x9f, 0x30, 0x7e, 0x80, 0xc5, 0x61, 0x72, 0x7d, 0xf4, 0x62, 0x60, 0x90, 0x85, 0x15, 0x6d, 0x2a, 0x4f, 0x3d, 0x8e, 0x98, 0xa3, 0x38, 0x16, 0x94, 0xe2, 0xd5, 0x01}, {0x52, 0x62, 0x76, 0x51, 0xe0, 0x25, 0x94, 0x2d, 0x2b, 0x2f, 0x6d, 0x6d, 0x26, 0x3a, 0x1f, 0x66, 0xdd, 0xb8, 0xf4, 0x2f, 0x37, 0x60, 0x26, 0xe2, 0xa5, 0xe4, 0x8e, 0x77, 0xc3, 0x12, 0x17, 0x12}}, + {{0x7c, 0x6f, 0xce, 0x77, 0x3e, 0xbc, 0x89, 0x80, 0xc0, 0x7f, 0x0f, 0xd8, 0xeb, 0x22, 0xb2, 0xa6, 0x50, 0x82, 0x3e, 0x94, 0x90, 0xb7, 0xb8, 0xe9, 0xb1, 0x15, 0xb4, 0x66, 0x60, 0x06, 0x95, 0x10}, {0x6c, 0x21, 0x30, 0xaa, 0x23, 0x58, 0xaf, 0xec, 0x67, 0xc8, 0x8c, 0xae, 0x76, 0x71, 0xd3, 0x1b, 0x92, 0x4c, 0x00, 0x3a, 0x17, 0x5d, 0x46, 0x66, 0xa2, 0x5f, 0xac, 0xbb, 0xda, 0xb8, 0x08, 0x17}}, + {{0x06, 0x04, 0xd5, 0x1e, 0xf4, 0xb3, 0x5a, 0x0f, 0x93, 0x81, 0x8e, 0x6b, 0x24, 0xb8, 0xd6, 0x3e, 0xef, 0x72, 0x66, 0xc1, 0xa7, 0x17, 0xc8, 0xef, 0xed, 0x6f, 0xe0, 0x55, 0x5c, 0xe6, 0xd9, 0x03}, {0xd9, 0xef, 0x15, 0x3a, 0x0a, 0x0a, 0x66, 0xd2, 0x3a, 0x60, 0x38, 0x02, 0x60, 0x31, 0x58, 0x31, 0x07, 0x04, 0x04, 0xef, 0x6e, 0x57, 0x8a, 0xd0, 0xad, 0x02, 0x86, 0x33, 0x79, 0xfc, 0xb5, 0x12}}, + {{0x61, 0xb2, 0x1a, 0x86, 0x38, 0x50, 0xb4, 0xaf, 0xef, 0xdd, 0xa2, 0x0e, 0x12, 0x25, 0x36, 0x33, 0xf0, 0xc3, 0xe9, 0xbd, 0x8a, 0x1e, 0xd2, 0xd0, 0x67, 0x66, 0x44, 0x0f, 0x07, 0x56, 0x42, 0x31}, {0x26, 0x95, 0xcd, 0xb0, 0xf6, 0x2b, 0x7d, 0xd4, 0x97, 0x59, 0xea, 0x03, 0x62, 0x51, 0xb6, 0xdf, 0x86, 0x3d, 0xf1, 0xd9, 0x3a, 0xe9, 0xc8, 0x6b, 0xfe, 0xa3, 0x9f, 0x87, 0x1e, 0x7b, 0xe3, 0x36}}, + {{0xf8, 0x63, 0x71, 0x38, 0x25, 0xb7, 0x41, 0x96, 0x89, 0xfb, 0x7d, 0x97, 0x13, 0xe2, 0x14, 0x2f, 0x01, 0x24, 0x8e, 0x81, 0x0f, 0x0f, 0x2e, 0x87, 0x55, 0x52, 0x01, 0x94, 0x42, 0x47, 0x05, 0x27}, {0x3e, 0xbf, 0x77, 0xe2, 0xe9, 0x98, 0x14, 0xe9, 0xe8, 0x0d, 0xcc, 0x46, 0x36, 0x13, 0x1c, 0xbc, 0xc2, 0x24, 0xbb, 0x9d, 0x5f, 0x26, 0x0d, 0x81, 0x17, 0xd4, 0x22, 0x0c, 0xa7, 0x4f, 0x3c, 0x07}}, + {{0xdb, 0xcb, 0x57, 0x4f, 0x76, 0x84, 0xe0, 0x72, 0x74, 0xec, 0x5a, 0xed, 0xbe, 0x43, 0xde, 0xaa, 0xa8, 0xef, 0xaa, 0x38, 0xe7, 0x19, 0x7a, 0x6b, 0x38, 0x9c, 0x03, 0xb2, 0xe4, 0x03, 0xe1, 0x3f}, {0xfc, 0x5f, 0x47, 0x90, 0x09, 0xa4, 0xb0, 0xf7, 0x7f, 0xd4, 0x6c, 0x59, 0x45, 0x8b, 0x27, 0xf2, 0x20, 0x9b, 0x61, 0x00, 0x33, 0x3c, 0x89, 0x8e, 0x44, 0xb3, 0x51, 0x99, 0x12, 0x0a, 0x9a, 0x1e}}, + {{0xf7, 0xde, 0xf4, 0x25, 0x1d, 0x1d, 0x3e, 0x27, 0xb1, 0xbe, 0x71, 0x31, 0x5a, 0x84, 0x03, 0x20, 0xd4, 0xf2, 0x29, 0x5f, 0x65, 0x81, 0x17, 0x6d, 0xc0, 0x29, 0x5b, 0x5d, 0x7f, 0x5e, 0x70, 0x08}, {0xff, 0x7c, 0x5d, 0xfa, 0x29, 0x58, 0x93, 0x55, 0x7e, 0x5d, 0x89, 0xf7, 0xcd, 0x41, 0x2a, 0xf3, 0x3d, 0xe7, 0xa2, 0xd1, 0x43, 0xea, 0xf2, 0x1b, 0x54, 0xd6, 0x53, 0x04, 0x08, 0xbf, 0x0f, 0x02}}, + {{0x13, 0x9a, 0xb8, 0x2d, 0xc7, 0x99, 0xcc, 0xc7, 0x7f, 0x45, 0x3e, 0x1a, 0x72, 0xf8, 0x69, 0xe8, 0x27, 0x5e, 0xe9, 0xf9, 0x75, 0x9b, 0xd5, 0xf8, 0x21, 0x72, 0xec, 0xb0, 0xb9, 0xdf, 0x3c, 0x2a}, {0xae, 0x43, 0xb3, 0xc8, 0x87, 0x9b, 0x92, 0xda, 0xf0, 0x23, 0xca, 0x1a, 0xe3, 0x22, 0x3c, 0xb3, 0x9b, 0x02, 0xd5, 0x43, 0x20, 0xc0, 0xf6, 0x7e, 0x16, 0x60, 0x1b, 0xfb, 0xe5, 0x75, 0x16, 0x0f}}, + {{0xf5, 0xa8, 0x1e, 0x58, 0x9c, 0xc4, 0xa7, 0xda, 0xa4, 0x68, 0xf6, 0x0b, 0xdf, 0x60, 0x24, 0x5e, 0x46, 0x61, 0xaf, 0x9c, 0x29, 0xec, 0xe2, 0x04, 0x89, 0x62, 0xb6, 0xc6, 0xee, 0xe7, 0x38, 0x24}, {0xe3, 0x5c, 0x90, 0x09, 0x50, 0xc5, 0x4c, 0xd9, 0xbb, 0xac, 0x98, 0x7c, 0xc9, 0x39, 0x49, 0x91, 0x4f, 0x00, 0x9d, 0xe6, 0xd5, 0xa0, 0xd6, 0x90, 0x5e, 0x00, 0x0a, 0x43, 0x99, 0x97, 0x30, 0x0e}}, + {{0x37, 0xba, 0x3d, 0xdf, 0x71, 0xba, 0xd2, 0x16, 0xf3, 0x46, 0x72, 0x90, 0x39, 0x3a, 0x87, 0xf9, 0x78, 0x89, 0x2c, 0x2e, 0xc7, 0x0f, 0x09, 0x73, 0xd8, 0xdb, 0x93, 0x76, 0x9f, 0xca, 0x6a, 0x3e}, {0x42, 0x82, 0x2f, 0xe1, 0x67, 0xc6, 0xbb, 0x14, 0x8e, 0xce, 0xc7, 0x64, 0xdf, 0xda, 0xab, 0xb8, 0x2a, 0xea, 0xb2, 0x7b, 0xc1, 0x5b, 0x94, 0x1a, 0xec, 0x3a, 0x71, 0xaf, 0xf6, 0xbb, 0x2d, 0x01}}, + {{0xac, 0x36, 0xd7, 0xc9, 0xda, 0x00, 0x0d, 0x24, 0x54, 0x60, 0xd5, 0x1e, 0x24, 0x54, 0x01, 0x5e, 0xfb, 0x9c, 0x42, 0x3e, 0x76, 0x8e, 0x7b, 0xb7, 0xef, 0xba, 0xcd, 0x38, 0xec, 0x95, 0x43, 0x14}, {0xf8, 0xf4, 0xef, 0x18, 0x3f, 0x46, 0xd5, 0xa1, 0x12, 0xe9, 0xec, 0x6e, 0x2b, 0x6a, 0x13, 0xac, 0xb6, 0xab, 0x5b, 0x65, 0x1a, 0x2f, 0x5b, 0x17, 0x12, 0xdc, 0x62, 0x88, 0x77, 0xe5, 0xf8, 0x11}}, + {{0x26, 0x9f, 0x8e, 0x1b, 0xa5, 0x91, 0x7d, 0x91, 0xf9, 0x2e, 0xdb, 0xe2, 0xb3, 0xd4, 0xa7, 0x96, 0xa5, 0x80, 0xec, 0xeb, 0x93, 0x28, 0x67, 0x64, 0xad, 0xa7, 0xdd, 0x6a, 0x2c, 0xc7, 0x15, 0x04}, {0x9d, 0xb6, 0x1c, 0x54, 0xe5, 0x78, 0xfe, 0x31, 0x07, 0xa9, 0x64, 0xa1, 0x2e, 0xa4, 0xd0, 0x6f, 0x9d, 0xa9, 0xe7, 0x59, 0x38, 0xfe, 0x9b, 0x77, 0x53, 0xcc, 0xea, 0xf9, 0x13, 0xf3, 0x02, 0x15}}, + {{0x2c, 0x96, 0x09, 0xf5, 0xd0, 0x68, 0x99, 0x62, 0xe8, 0xa1, 0xb9, 0xa5, 0x6c, 0x54, 0xd8, 0x0f, 0x4d, 0x86, 0xee, 0x88, 0x37, 0x71, 0x71, 0x4f, 0xff, 0x98, 0x78, 0xbb, 0xd7, 0x39, 0xbe, 0x21}, {0xfa, 0xb4, 0xa1, 0x56, 0x7c, 0x59, 0x30, 0x2e, 0xe1, 0x07, 0x81, 0x83, 0x53, 0xad, 0x02, 0x1a, 0x33, 0x6d, 0xfd, 0x1c, 0x9e, 0x2a, 0x02, 0x4d, 0xc1, 0xb4, 0xaa, 0x51, 0x7d, 0xe3, 0x3c, 0x1f}}, + {{0x9b, 0xad, 0x87, 0x97, 0x7a, 0x27, 0xe8, 0xd2, 0xf3, 0xde, 0x81, 0x3d, 0x87, 0xef, 0xb8, 0x06, 0x94, 0x92, 0xdc, 0x0c, 0x58, 0xa0, 0x3f, 0xcb, 0xd5, 0xda, 0x10, 0xb6, 0x66, 0xb8, 0x0e, 0x3e}, {0xe1, 0xfc, 0x0b, 0x29, 0x8d, 0x98, 0x6f, 0x41, 0xfc, 0xa7, 0xea, 0x9e, 0x46, 0x9c, 0x9d, 0xe9, 0x1a, 0xf3, 0x8c, 0x96, 0x7c, 0xd3, 0x26, 0xe8, 0x3e, 0xbc, 0x96, 0x29, 0x65, 0x50, 0x3a, 0x30}}, + {{0x96, 0x65, 0xf9, 0xb7, 0x3d, 0xc4, 0x0d, 0x97, 0x7a, 0xb3, 0xbe, 0x7b, 0x04, 0xa0, 0xbe, 0x8b, 0x20, 0xff, 0x86, 0x4f, 0x7c, 0xc0, 0xbf, 0xff, 0x7b, 0x81, 0x5b, 0x2a, 0x70, 0xe8, 0xb0, 0x2e}, {0x15, 0xcf, 0x3a, 0xc7, 0x92, 0xdf, 0xec, 0xcd, 0x4b, 0x1a, 0xc1, 0x4b, 0xf4, 0xb8, 0x49, 0xa3, 0x86, 0x04, 0x35, 0x1a, 0x82, 0x5c, 0xa2, 0x4c, 0x4e, 0xce, 0x63, 0x8f, 0xee, 0xa8, 0x35, 0x0c}}, + {{0x9d, 0x90, 0xc5, 0x82, 0xff, 0xfe, 0x30, 0x33, 0x65, 0x8f, 0x76, 0x15, 0xf5, 0xcc, 0x37, 0xa0, 0x7e, 0xab, 0x65, 0xd1, 0xbf, 0xe5, 0xb4, 0x04, 0x1f, 0x70, 0x98, 0x2e, 0x0d, 0xd3, 0x8f, 0x3d}, {0x16, 0x69, 0x3f, 0x61, 0x4c, 0x35, 0xcf, 0x76, 0xe4, 0xb8, 0x68, 0xef, 0xfc, 0x8c, 0xac, 0xb3, 0x48, 0x33, 0x6d, 0xfb, 0xec, 0x23, 0x1e, 0x12, 0x7e, 0x00, 0x65, 0x69, 0x76, 0x46, 0x9c, 0x04}}, + {{0x16, 0xad, 0x8a, 0x20, 0xf8, 0x5a, 0x8b, 0xd2, 0xc1, 0x9e, 0x22, 0x25, 0x01, 0x0c, 0xcc, 0x85, 0x44, 0xb7, 0xba, 0xfc, 0xb7, 0x00, 0x10, 0x00, 0xda, 0x50, 0x59, 0xe1, 0xb5, 0x3c, 0x16, 0x2f}, {0x0c, 0x8f, 0x4c, 0x85, 0xa6, 0xa5, 0x04, 0x82, 0xf3, 0x1b, 0x9c, 0x9f, 0xed, 0x50, 0xc2, 0xae, 0xba, 0xcf, 0xa8, 0x4c, 0x3b, 0x97, 0x78, 0xa6, 0xf6, 0xad, 0x62, 0x10, 0xc2, 0x78, 0x60, 0x20}}, + {{0xe7, 0xba, 0x44, 0xae, 0xa2, 0xbf, 0x72, 0xb5, 0xd9, 0x65, 0x58, 0xed, 0xe5, 0x7b, 0x39, 0x47, 0x9d, 0xcd, 0xd5, 0xd7, 0x60, 0x26, 0xd8, 0x12, 0xf4, 0x11, 0xfb, 0xd0, 0xb0, 0x91, 0x02, 0x38}, {0xed, 0x00, 0x4f, 0xe3, 0x04, 0xf0, 0x9e, 0xda, 0x9e, 0x71, 0x45, 0xf1, 0xc5, 0xc9, 0xc7, 0xd1, 0x77, 0x9c, 0x32, 0xe0, 0x71, 0xb0, 0x07, 0x5d, 0x6c, 0xcc, 0xca, 0x5a, 0xf3, 0x1b, 0x1f, 0x11}}, + {{0x4b, 0xf7, 0xec, 0xdb, 0xe9, 0xfe, 0x4e, 0x9d, 0x40, 0x1c, 0xd1, 0x6e, 0x98, 0x6b, 0xb6, 0x54, 0x77, 0x92, 0x2a, 0x1f, 0x67, 0xe9, 0x9d, 0xc6, 0x19, 0x6f, 0x01, 0x09, 0xc2, 0xf7, 0x1e, 0x38}, {0x70, 0x48, 0x3d, 0x4c, 0x91, 0x62, 0xcd, 0x78, 0xc9, 0xa7, 0x66, 0x43, 0x3f, 0xb0, 0x9d, 0x96, 0xca, 0x8c, 0x98, 0xad, 0xfc, 0xed, 0x3f, 0xc6, 0x39, 0xed, 0x6c, 0x19, 0xf1, 0xc3, 0x71, 0x08}}, + {{0xe4, 0x88, 0x25, 0xcd, 0xe0, 0x5a, 0x95, 0xbf, 0xc6, 0x85, 0xc1, 0x5b, 0x45, 0xbe, 0x5d, 0x1a, 0x70, 0x1b, 0xe7, 0x93, 0x1f, 0xfb, 0x0f, 0x80, 0xb8, 0x93, 0xa4, 0x1f, 0x52, 0x68, 0x99, 0x04}, {0x7f, 0x44, 0xa4, 0x46, 0x2b, 0xa0, 0x88, 0x08, 0x28, 0x8c, 0xb9, 0x9c, 0x8f, 0x42, 0x4f, 0xbf, 0xe2, 0x9d, 0xff, 0x14, 0x03, 0x07, 0x37, 0x81, 0x10, 0xb4, 0x10, 0x43, 0x76, 0x90, 0x87, 0x13}}, + {{0xdf, 0x07, 0x6b, 0x0f, 0xc0, 0xb4, 0x2e, 0xd1, 0xf4, 0x39, 0x77, 0xf3, 0xb7, 0x9c, 0x67, 0x48, 0x00, 0x44, 0x7d, 0xb1, 0x85, 0x9c, 0x8d, 0xd2, 0x49, 0xe3, 0x75, 0xa8, 0xe1, 0x47, 0xd9, 0x0b}, {0xba, 0xe1, 0x6c, 0xe5, 0x27, 0x8d, 0x62, 0xda, 0xd8, 0x9f, 0xb8, 0x96, 0xd5, 0xf8, 0xb9, 0x3f, 0x37, 0x62, 0x58, 0xf6, 0x29, 0xb9, 0xe3, 0x5d, 0xb6, 0x2e, 0x38, 0x26, 0xa4, 0x62, 0x35, 0x15}}, + {{0x5c, 0xaf, 0xe6, 0xbd, 0x03, 0x3b, 0xaf, 0x36, 0xc6, 0x0d, 0xf6, 0xd7, 0x15, 0x33, 0xa4, 0x4f, 0x97, 0x91, 0x91, 0xa4, 0x20, 0xa0, 0x67, 0x70, 0xee, 0xdd, 0x06, 0xb3, 0xf1, 0x47, 0x32, 0x1c}, {0x96, 0xf6, 0x0f, 0x65, 0x5a, 0xbb, 0x52, 0xc6, 0xe1, 0x64, 0xfe, 0xd2, 0x0c, 0x89, 0x3e, 0xf5, 0x51, 0xac, 0x0e, 0x67, 0x20, 0xc1, 0xbd, 0x9d, 0x8a, 0xb0, 0x23, 0x44, 0xe0, 0xcc, 0x86, 0x07}}, + {{0xe2, 0xab, 0x02, 0x5c, 0x04, 0x5a, 0x52, 0x9b, 0x10, 0xfc, 0x69, 0x3c, 0xcd, 0x03, 0x88, 0xab, 0x22, 0xf8, 0x67, 0x49, 0xe7, 0x04, 0x5c, 0x4f, 0x73, 0xc9, 0x24, 0x8d, 0x8b, 0xba, 0x7c, 0x3d}, {0xa7, 0x8c, 0x0e, 0xc2, 0xa9, 0x6d, 0x6f, 0xc3, 0x4d, 0x05, 0xc7, 0x18, 0xd3, 0x0c, 0xb8, 0x3a, 0xd8, 0x88, 0xfb, 0xf1, 0x8b, 0xc4, 0x00, 0xea, 0xd5, 0x75, 0xe9, 0x78, 0x4f, 0xcd, 0x85, 0x2a}}, + {{0xa2, 0x11, 0xb6, 0xd4, 0x5e, 0xf9, 0x5b, 0xac, 0x43, 0x2c, 0xc7, 0x80, 0x81, 0x4d, 0x6d, 0x13, 0x4e, 0x8d, 0x8c, 0xd2, 0x88, 0xdf, 0xb6, 0x1f, 0x11, 0x60, 0xd5, 0x17, 0x1b, 0xfe, 0x6a, 0x24}, {0x72, 0x49, 0x56, 0x47, 0x33, 0x7b, 0x68, 0x36, 0x64, 0xbc, 0x0d, 0x36, 0x2d, 0xdd, 0x67, 0x14, 0x58, 0x62, 0xa9, 0x93, 0x5f, 0xdf, 0x0c, 0x41, 0xa0, 0xe8, 0xc6, 0x24, 0x68, 0x8b, 0x88, 0x35}}, + {{0x92, 0xd4, 0x62, 0x4a, 0x72, 0x2a, 0xc2, 0x5d, 0x8c, 0x8d, 0x50, 0xa7, 0x2b, 0x9b, 0x60, 0x26, 0x71, 0x84, 0x53, 0x1b, 0xe6, 0x5a, 0x59, 0x50, 0xff, 0xcd, 0x65, 0x97, 0xb1, 0x34, 0x6a, 0x26}, {0xcb, 0xa2, 0x58, 0xd3, 0xdb, 0x5b, 0xbe, 0x7f, 0x6a, 0xa7, 0xa8, 0x1c, 0xfd, 0xf7, 0xa4, 0x40, 0x4a, 0x00, 0x0e, 0xa5, 0x73, 0x32, 0x1d, 0x49, 0xad, 0x62, 0x4f, 0xdc, 0x4a, 0x0e, 0x68, 0x35}}, + {{0x4e, 0xfd, 0x77, 0xf9, 0x0c, 0x99, 0xdb, 0xbf, 0x9e, 0xcc, 0x6d, 0xca, 0x9d, 0x36, 0x37, 0x64, 0xee, 0x51, 0x50, 0xb5, 0x48, 0xd0, 0xb5, 0xc7, 0x45, 0x46, 0xd5, 0x71, 0xec, 0x73, 0x0b, 0x25}, {0x81, 0xb3, 0x12, 0x44, 0x6b, 0xe4, 0xae, 0x41, 0xfb, 0x61, 0xdc, 0x6d, 0x00, 0xe5, 0x9e, 0x9e, 0x94, 0xcf, 0xce, 0xbb, 0xf5, 0x6d, 0x2f, 0xec, 0x3d, 0x60, 0x16, 0x0b, 0x15, 0xe2, 0x93, 0x17}}, + {{0x47, 0x62, 0x0c, 0x77, 0x79, 0x6d, 0x88, 0x6f, 0x82, 0xe1, 0xa1, 0x0f, 0x74, 0x03, 0x00, 0x15, 0x82, 0x2f, 0x69, 0x17, 0xb2, 0x03, 0x76, 0xf3, 0xec, 0xb7, 0xf5, 0x0a, 0x68, 0x73, 0x1f, 0x3d}, {0x9e, 0x72, 0xf9, 0xe4, 0x5a, 0xa7, 0xb6, 0x81, 0x17, 0xae, 0x1f, 0x34, 0xaa, 0xae, 0x35, 0xe7, 0x0a, 0xbb, 0xaa, 0xe1, 0xc5, 0xb7, 0xff, 0x4e, 0x4a, 0xc3, 0x5d, 0x4c, 0xd4, 0xc1, 0x23, 0x02}}, + {{0x32, 0x75, 0x45, 0x79, 0x4d, 0xf1, 0x9d, 0x41, 0x12, 0xc5, 0x02, 0x4e, 0x3f, 0x28, 0x80, 0xd7, 0x36, 0xc5, 0x6c, 0x75, 0xa1, 0x47, 0xfc, 0xf0, 0x82, 0xed, 0x6b, 0xa0, 0x02, 0x07, 0xe3, 0x1c}, {0x60, 0x68, 0x79, 0x14, 0x53, 0x97, 0x20, 0xaa, 0xa0, 0x53, 0x50, 0xd9, 0x71, 0x96, 0x7b, 0xb7, 0xba, 0x84, 0xdd, 0x09, 0x3e, 0xe6, 0x4e, 0x80, 0x06, 0xa8, 0xdd, 0x96, 0x1b, 0x71, 0xe1, 0x09}}, + {{0x19, 0xc0, 0x89, 0xa5, 0x34, 0xba, 0x7f, 0x60, 0x98, 0x59, 0x82, 0x5d, 0xb6, 0xba, 0xbd, 0x79, 0x38, 0xd9, 0xbb, 0x7f, 0xbd, 0xa4, 0xca, 0xca, 0x4d, 0xe5, 0xf8, 0x2c, 0x85, 0xca, 0x94, 0x36}, {0x54, 0x7e, 0xb3, 0x3f, 0xc0, 0x28, 0x55, 0xf5, 0xe4, 0x66, 0xbb, 0x11, 0x81, 0xb7, 0x49, 0x4a, 0x5b, 0x51, 0xc5, 0x59, 0xe7, 0x77, 0xe4, 0x94, 0x48, 0xfe, 0x09, 0x0b, 0xf2, 0xa0, 0x9b, 0x36}}, + {{0x61, 0xe7, 0x41, 0x3c, 0x43, 0x48, 0x03, 0xa9, 0xae, 0xb2, 0xda, 0x07, 0x0e, 0x6c, 0x4f, 0x33, 0xe1, 0xe8, 0x75, 0x07, 0xb1, 0x35, 0x76, 0xfa, 0x21, 0x19, 0x1d, 0x90, 0xd1, 0x43, 0xdd, 0x1f}, {0xa3, 0xe1, 0xf5, 0x11, 0x7e, 0xaf, 0x42, 0xb0, 0xda, 0x0a, 0x84, 0x05, 0x43, 0xc3, 0xdc, 0x72, 0x4a, 0x7a, 0xa0, 0x40, 0xf3, 0x22, 0x1f, 0xec, 0xa7, 0xaf, 0x46, 0x0c, 0x14, 0xcd, 0x4d, 0x3d}}, + {{0x63, 0xb8, 0x5a, 0xad, 0xa1, 0x53, 0x16, 0x65, 0x99, 0x72, 0x3a, 0x3f, 0xa4, 0xc5, 0x09, 0x31, 0xd9, 0x8c, 0x51, 0xac, 0xfe, 0x89, 0x26, 0x4a, 0x25, 0x4b, 0x6f, 0x30, 0xe5, 0x28, 0xcb, 0x32}, {0x32, 0x07, 0x70, 0x77, 0xf1, 0x41, 0x22, 0xce, 0x1a, 0xf8, 0x77, 0x14, 0xbf, 0x68, 0xc2, 0xe9, 0x7c, 0xf5, 0xd9, 0xbe, 0xf5, 0xc5, 0x43, 0xb6, 0xaf, 0x3e, 0xed, 0x8f, 0x0c, 0x8e, 0xb3, 0x1a}}, + {{0x29, 0xc9, 0x5b, 0xcf, 0x7d, 0xf4, 0x37, 0xad, 0x20, 0xb6, 0xa6, 0x3c, 0xcb, 0x68, 0xc4, 0xfe, 0x5d, 0x62, 0xcd, 0xe2, 0x60, 0x52, 0x8c, 0x38, 0x61, 0xb4, 0x47, 0xbf, 0x94, 0x20, 0x14, 0x3e}, {0xd6, 0xdb, 0xc4, 0xb9, 0xcc, 0x3b, 0x91, 0xe1, 0xfe, 0x94, 0xd3, 0xcb, 0x8e, 0x01, 0x6b, 0xf5, 0x48, 0xd1, 0xd8, 0xb2, 0x8b, 0xd8, 0x84, 0x7a, 0x1a, 0x57, 0xd1, 0x31, 0x8b, 0xd0, 0x95, 0x10}}, + {{0xa4, 0x18, 0x3b, 0xa4, 0x73, 0xda, 0x24, 0x4c, 0x1c, 0x4f, 0x6d, 0x88, 0x49, 0xad, 0x2f, 0x19, 0x9e, 0xfd, 0xb0, 0x29, 0x00, 0x22, 0xca, 0xb9, 0x61, 0x3f, 0x0e, 0x91, 0x8e, 0xcd, 0xc3, 0x23}, {0x5b, 0x99, 0x53, 0x0c, 0x2c, 0x7b, 0x6a, 0x44, 0xc6, 0xd6, 0x46, 0xf7, 0x82, 0x9e, 0x40, 0xf6, 0x46, 0xf0, 0x60, 0xd6, 0xa5, 0xf1, 0x9a, 0xd4, 0xda, 0xa7, 0xf7, 0xc8, 0x88, 0x66, 0x9f, 0x28}}, + {{0xea, 0x19, 0x69, 0xf4, 0x89, 0x2f, 0x22, 0x93, 0xaf, 0x41, 0x2f, 0xd5, 0x6d, 0xce, 0xca, 0x23, 0xec, 0xb7, 0xb5, 0xa0, 0x36, 0x00, 0x9f, 0x7b, 0xf8, 0x1b, 0xf7, 0x3a, 0xcc, 0x0e, 0xa9, 0x36}, {0x6e, 0xe9, 0xed, 0x2f, 0x5a, 0x4d, 0x78, 0xac, 0xa1, 0x48, 0xcc, 0xe5, 0xc2, 0x0e, 0xc7, 0x83, 0x88, 0x65, 0xbe, 0xda, 0xcd, 0x7a, 0x3c, 0x62, 0xc2, 0x55, 0x9f, 0x68, 0x3c, 0x4d, 0x2e, 0x26}}, + {{0x0e, 0x13, 0xdd, 0xd3, 0x3e, 0xb0, 0x8b, 0xc4, 0xc0, 0xc4, 0xe8, 0xe3, 0x8d, 0x66, 0xda, 0xc8, 0x78, 0x4d, 0x0e, 0x62, 0xfb, 0x8d, 0x96, 0x84, 0x07, 0x3a, 0x14, 0xef, 0x83, 0x8b, 0xd2, 0x21}, {0x2b, 0x51, 0x9f, 0x7c, 0xba, 0x41, 0x07, 0xa6, 0x8f, 0x04, 0x3f, 0xb2, 0x59, 0x6b, 0xaf, 0xe9, 0x6b, 0xdd, 0x97, 0x9a, 0xe3, 0xff, 0x9b, 0xb4, 0x7c, 0xe6, 0xb5, 0xea, 0x7a, 0xef, 0x3c, 0x07}}, + {{0x02, 0x5c, 0xef, 0x02, 0xbd, 0x2e, 0x8c, 0xbb, 0xe7, 0xd5, 0xa3, 0xa8, 0x6b, 0xfb, 0x3e, 0x9f, 0xfd, 0x7a, 0x24, 0x82, 0xd6, 0xaf, 0x5e, 0xdd, 0x49, 0x1d, 0xc2, 0x34, 0x96, 0x06, 0x4d, 0x0a}, {0x17, 0x21, 0x45, 0x74, 0x93, 0x26, 0x8b, 0xde, 0x75, 0x91, 0xc8, 0x9a, 0x13, 0x3e, 0x27, 0x88, 0x22, 0xce, 0xfa, 0x60, 0x11, 0x3f, 0x4d, 0xaf, 0xb0, 0xf5, 0x0c, 0x42, 0xde, 0xf7, 0x2e, 0x37}}, + {{0x4f, 0xad, 0x94, 0xe6, 0x71, 0x31, 0x7a, 0x00, 0x83, 0x64, 0x99, 0xb4, 0x43, 0x7d, 0x63, 0x0b, 0x1e, 0xe3, 0xd9, 0x71, 0xa4, 0xd9, 0x41, 0x3f, 0xe2, 0x5f, 0x67, 0xf7, 0x59, 0x41, 0x04, 0x23}, {0xc3, 0x22, 0xf0, 0x98, 0xd9, 0xd9, 0x89, 0xc6, 0xea, 0xf3, 0xef, 0x96, 0xa4, 0x04, 0x43, 0x38, 0x98, 0x96, 0x86, 0xa7, 0xfb, 0x07, 0xf7, 0xcd, 0x75, 0x10, 0xf3, 0x52, 0x52, 0xaa, 0xff, 0x00}}, + {{0x0c, 0xae, 0xbd, 0x3b, 0x50, 0x59, 0xed, 0xc7, 0xcf, 0xa8, 0x63, 0xf3, 0x4e, 0x0a, 0x71, 0x07, 0x22, 0x22, 0x24, 0x25, 0x1d, 0xa4, 0x54, 0xb8, 0xd1, 0xf7, 0x71, 0x8c, 0x98, 0xd9, 0x1c, 0x36}, {0x5e, 0xe8, 0x1d, 0xe3, 0xa8, 0xf5, 0xc3, 0xd1, 0xf5, 0x72, 0xed, 0xa2, 0xe1, 0x1f, 0xf9, 0x61, 0x6b, 0x7a, 0x42, 0xb4, 0x47, 0x30, 0x2a, 0xd0, 0x61, 0x7f, 0x0a, 0x14, 0xc8, 0x2a, 0xa9, 0x28}}, + {{0xef, 0x09, 0xdb, 0x68, 0xf5, 0x8f, 0x9b, 0xe6, 0x1d, 0x1b, 0xb6, 0x45, 0x84, 0xa8, 0x55, 0xa9, 0x37, 0x0a, 0xc0, 0x0b, 0xf8, 0x0f, 0x81, 0x01, 0x34, 0xb6, 0xa1, 0x2d, 0x87, 0x74, 0x77, 0x3f}, {0x9e, 0x11, 0x58, 0x5f, 0x97, 0x61, 0xfc, 0xba, 0x02, 0x4a, 0xcf, 0x94, 0x17, 0x68, 0xc8, 0x8e, 0x6b, 0x58, 0x61, 0xef, 0xf7, 0xb4, 0x9d, 0xf7, 0x32, 0xb3, 0xe9, 0xde, 0xff, 0x0e, 0xcb, 0x1e}}, + {{0x02, 0x6b, 0x9a, 0x5d, 0x51, 0x1b, 0x7c, 0x2e, 0x63, 0x5b, 0x41, 0xbc, 0xd9, 0x5e, 0xb8, 0x6d, 0xe1, 0x31, 0x78, 0xf2, 0x61, 0xc7, 0x61, 0x9e, 0xc5, 0x68, 0xe7, 0x1d, 0x07, 0x7f, 0x63, 0x1d}, {0xfc, 0xe8, 0x8a, 0xa8, 0x3b, 0x01, 0x95, 0xb6, 0xf5, 0x9b, 0x52, 0x56, 0x1a, 0x86, 0x87, 0x60, 0xd0, 0xc3, 0x9e, 0x44, 0xe2, 0x54, 0xe4, 0x37, 0xb1, 0xa6, 0x89, 0xa8, 0x34, 0xac, 0xf1, 0x32}}, + {{0x9d, 0x8f, 0xc8, 0x95, 0x79, 0xe9, 0xc6, 0x45, 0x11, 0x35, 0x4f, 0x36, 0xbd, 0x13, 0x77, 0x91, 0xec, 0x4c, 0x37, 0xf7, 0x8a, 0xd4, 0xb5, 0x18, 0xf3, 0x21, 0xbc, 0x82, 0xaa, 0x50, 0xcb, 0x1a}, {0x7c, 0x13, 0x73, 0x0e, 0x1e, 0xac, 0xb5, 0xa0, 0xdd, 0x33, 0x2a, 0x7c, 0x69, 0x3b, 0xcc, 0xe9, 0xb9, 0x46, 0x7f, 0x83, 0xd6, 0xfb, 0x43, 0x38, 0x22, 0xf0, 0xbd, 0xda, 0x07, 0xc3, 0xf2, 0x3a}}, + {{0xaf, 0x80, 0x85, 0xb1, 0x7d, 0x51, 0x20, 0xf3, 0xfa, 0xae, 0xb8, 0xda, 0x5d, 0x76, 0xe4, 0x4e, 0xec, 0x34, 0x2c, 0xcb, 0xc8, 0x9e, 0x87, 0x6b, 0xa7, 0x9a, 0x2c, 0xd0, 0x61, 0x0e, 0x04, 0x18}, {0xd5, 0x44, 0x66, 0xca, 0x31, 0x9a, 0x99, 0x77, 0x37, 0x8c, 0x52, 0xdf, 0xbb, 0x40, 0x57, 0x5c, 0xc2, 0x5c, 0x73, 0x99, 0x5b, 0xfa, 0x6f, 0x3c, 0xb2, 0x02, 0xe3, 0x2d, 0xcb, 0x7f, 0x42, 0x2d}}, + {{0x14, 0xd3, 0x8b, 0x24, 0x4e, 0x1f, 0x02, 0xb7, 0x6f, 0xfc, 0x77, 0x1e, 0x7d, 0xd4, 0xa6, 0x45, 0xb3, 0xc0, 0x47, 0x94, 0x7e, 0x17, 0xde, 0x71, 0x95, 0x82, 0x81, 0xfc, 0x8e, 0x6f, 0x36, 0x2c}, {0xbe, 0x59, 0xf7, 0x3e, 0x1c, 0x64, 0x17, 0xd4, 0xea, 0x27, 0x6d, 0x37, 0x93, 0xa4, 0xf0, 0x46, 0x94, 0x3e, 0x98, 0xa3, 0xf3, 0x89, 0x58, 0xcc, 0x0c, 0x6a, 0x24, 0x95, 0x04, 0x82, 0xca, 0x24}}, + {{0x2d, 0x02, 0xf9, 0xfd, 0xa1, 0x08, 0x41, 0x4d, 0x2a, 0xab, 0x38, 0xff, 0xf6, 0xc1, 0x5b, 0x44, 0xcd, 0x67, 0xc5, 0x08, 0x8f, 0x46, 0x34, 0x2c, 0xfb, 0xf2, 0x05, 0xb0, 0x4e, 0x22, 0xc9, 0x27}, {0x58, 0x58, 0xd8, 0x3a, 0x86, 0xe3, 0x7f, 0xb6, 0xe0, 0x0a, 0x70, 0x32, 0xc1, 0x89, 0xe7, 0x35, 0xc2, 0x72, 0x9c, 0xbe, 0x8e, 0xea, 0x43, 0xaf, 0x42, 0x01, 0x93, 0xa5, 0x7b, 0xb9, 0xff, 0x35}}, + {{0xea, 0xad, 0x3e, 0xfa, 0x77, 0x9c, 0x9c, 0x67, 0xdd, 0xe9, 0x59, 0xc1, 0x7e, 0x61, 0x0c, 0x05, 0x53, 0x5d, 0x9e, 0x27, 0x0b, 0xad, 0xd0, 0xe4, 0xd0, 0xd2, 0xca, 0xac, 0xa7, 0x85, 0x13, 0x1c}, {0x9e, 0xf9, 0xd8, 0x76, 0x8c, 0x75, 0x05, 0xa6, 0x09, 0xc1, 0x3e, 0x23, 0xb6, 0x09, 0x5c, 0x24, 0x4f, 0xc9, 0xde, 0xfa, 0x3f, 0x12, 0x51, 0x99, 0x9e, 0xdb, 0x1a, 0xe1, 0x32, 0xcb, 0x06, 0x0e}}, + {{0xa1, 0xe3, 0xfa, 0x97, 0x46, 0xc6, 0xa6, 0xdd, 0xbc, 0xd2, 0xb9, 0x51, 0x80, 0x3e, 0xf4, 0x57, 0x5d, 0x45, 0xfa, 0x2b, 0x26, 0x16, 0xac, 0x05, 0xea, 0xb4, 0x6d, 0xc4, 0x14, 0xb2, 0xe6, 0x27}, {0xe4, 0xca, 0x65, 0x72, 0x24, 0x39, 0xdf, 0xe0, 0x5b, 0x7a, 0xd4, 0xc3, 0xb2, 0x1e, 0xc0, 0x09, 0x3c, 0xdc, 0x18, 0xa7, 0xdd, 0xd6, 0x07, 0x4b, 0x80, 0xd6, 0xa4, 0x16, 0xb1, 0xe6, 0x6e, 0x04}}, + {{0xfb, 0x93, 0x84, 0x0d, 0x4a, 0x88, 0x27, 0x88, 0x25, 0x2a, 0xe5, 0x17, 0xbe, 0xd4, 0x41, 0xb6, 0xe5, 0xf1, 0x13, 0xca, 0x5e, 0xd6, 0xbb, 0xd1, 0xb7, 0xf9, 0xbd, 0x9d, 0x75, 0x83, 0xe6, 0x14}, {0xd6, 0x09, 0x3e, 0x04, 0xf2, 0x27, 0xbc, 0xc5, 0xbc, 0x18, 0x0d, 0x74, 0xd8, 0x1b, 0x83, 0x43, 0x6c, 0x64, 0x51, 0xdb, 0x51, 0xb9, 0x28, 0x4d, 0x06, 0x41, 0x35, 0xae, 0x5c, 0x92, 0xf2, 0x2f}}, + {{0x65, 0xc0, 0x09, 0xa8, 0xea, 0xb8, 0xab, 0xd2, 0xf7, 0x42, 0x58, 0xd5, 0x4f, 0x4c, 0x26, 0xa5, 0x6a, 0x68, 0xed, 0x52, 0x33, 0x68, 0xbd, 0x36, 0x8e, 0x02, 0xd9, 0xa2, 0x20, 0xa1, 0x03, 0x3e}, {0xff, 0xbc, 0x64, 0x2b, 0xa2, 0x15, 0xcd, 0xad, 0x4e, 0x1d, 0x41, 0xfa, 0xcf, 0xfb, 0x41, 0x8b, 0x18, 0x17, 0xc4, 0xaa, 0x29, 0xe7, 0x75, 0x62, 0xca, 0x76, 0x28, 0xa5, 0xdd, 0xd1, 0xf4, 0x05}}, + {{0x92, 0x42, 0x18, 0xdb, 0xdf, 0x45, 0x9f, 0x25, 0xa2, 0x88, 0x27, 0xbd, 0x21, 0x9f, 0xa3, 0x85, 0x69, 0xa4, 0x2b, 0x9d, 0x50, 0xd0, 0x41, 0x77, 0xaf, 0x7c, 0xd3, 0xfa, 0x8a, 0xe4, 0x28, 0x36}, {0xd4, 0xed, 0xc2, 0x52, 0x09, 0xa5, 0x8c, 0xf3, 0x4f, 0x96, 0x5d, 0xfa, 0xce, 0x3d, 0xc8, 0xdb, 0x0d, 0xdc, 0x4a, 0x70, 0x58, 0x13, 0xe5, 0x67, 0x2a, 0xb7, 0x72, 0x77, 0x7f, 0x03, 0xd7, 0x2d}}, + {{0x57, 0x3d, 0xbb, 0x92, 0xbd, 0x38, 0x93, 0xde, 0x41, 0x94, 0x60, 0xc8, 0x38, 0x72, 0x4b, 0x94, 0x55, 0x42, 0xeb, 0x6c, 0xc0, 0x5b, 0x3d, 0xe0, 0x43, 0xbe, 0x03, 0x16, 0xf6, 0x0b, 0x89, 0x28}, {0xc4, 0x91, 0x5b, 0xff, 0xbe, 0xdf, 0x8d, 0x59, 0xd8, 0x66, 0x40, 0xb0, 0x24, 0x7d, 0x17, 0x90, 0x92, 0x95, 0x62, 0xca, 0xaa, 0x24, 0xfe, 0x29, 0x5d, 0xee, 0x0f, 0xd0, 0x6d, 0xb5, 0x1b, 0x0e}}, + {{0xc3, 0xa2, 0x31, 0xcd, 0xd9, 0xb1, 0xf2, 0x80, 0x2b, 0xe8, 0x64, 0x53, 0x34, 0x81, 0xca, 0xfe, 0x26, 0x78, 0x86, 0x47, 0x05, 0x84, 0x7e, 0x66, 0x04, 0x24, 0xcc, 0xdf, 0xa5, 0x2a, 0x6a, 0x19}, {0x22, 0x7b, 0xcb, 0x50, 0x4e, 0xea, 0xf2, 0x44, 0x87, 0x25, 0x2b, 0x84, 0xa9, 0xac, 0x03, 0xa2, 0x7d, 0x48, 0x3f, 0xe0, 0x5e, 0x52, 0x3f, 0x9c, 0xc8, 0x36, 0x24, 0xd6, 0xc6, 0x0f, 0xbb, 0x1d}}, + {{0xa7, 0x2e, 0x26, 0x17, 0x1d, 0xf8, 0xf8, 0xd9, 0xbc, 0x8b, 0xba, 0x3e, 0x8d, 0x21, 0xc2, 0x48, 0xeb, 0xab, 0x2a, 0x90, 0xc9, 0xac, 0x31, 0x6a, 0x82, 0x93, 0xc6, 0xc6, 0x57, 0xbe, 0x86, 0x10}, {0xb0, 0x3f, 0x38, 0x44, 0xee, 0xc4, 0x21, 0x9b, 0x13, 0x71, 0xc6, 0xd2, 0x7c, 0x18, 0xbb, 0xff, 0xf9, 0x9d, 0x9c, 0x0d, 0xa0, 0x86, 0xdf, 0xbb, 0x39, 0xef, 0x15, 0x69, 0xbd, 0x0d, 0x00, 0x19}}, + {{0x83, 0xf0, 0x50, 0x71, 0xa1, 0xe6, 0x7e, 0xb8, 0x4c, 0xbb, 0xca, 0xc7, 0x2a, 0x17, 0xd3, 0x1d, 0xa7, 0x2a, 0x53, 0x75, 0x85, 0x60, 0x0d, 0x45, 0xa9, 0xbe, 0xea, 0xa4, 0xf5, 0x4a, 0x87, 0x0e}, {0xf0, 0xbd, 0x39, 0x6a, 0x05, 0x30, 0xd9, 0x27, 0x75, 0x24, 0xac, 0xfa, 0x8f, 0xea, 0xfc, 0xaf, 0xd1, 0x26, 0x1e, 0xac, 0x2b, 0xf9, 0xce, 0x27, 0x55, 0xe8, 0xf2, 0x93, 0xf2, 0xec, 0xce, 0x1d}}, + {{0xa6, 0xb6, 0x7c, 0xf6, 0x24, 0xf1, 0x32, 0xec, 0xc7, 0x6f, 0x04, 0xbb, 0xa9, 0xc0, 0x6f, 0xe7, 0x4b, 0x9d, 0x69, 0xa8, 0xb9, 0x2f, 0xc9, 0x08, 0x19, 0x1f, 0x13, 0x36, 0xca, 0xf0, 0xa4, 0x0a}, {0x8c, 0x29, 0xf9, 0xf5, 0x3a, 0x38, 0x7a, 0xc7, 0x6a, 0x7a, 0x61, 0x8f, 0x57, 0x0c, 0x2a, 0x6c, 0x23, 0x57, 0x69, 0x87, 0xf4, 0x83, 0xfb, 0xa8, 0x74, 0x7d, 0xb1, 0x2f, 0x38, 0x93, 0xac, 0x0d}}, + {{0xaf, 0xf7, 0xd7, 0x9b, 0x26, 0xed, 0xae, 0xa4, 0x65, 0x81, 0x79, 0xbe, 0x90, 0x55, 0x45, 0xcf, 0x02, 0xba, 0x07, 0xca, 0xc2, 0xa5, 0x66, 0xbb, 0x3b, 0x2f, 0xe0, 0x33, 0xfb, 0x97, 0x71, 0x2f}, {0xff, 0x55, 0xdc, 0x26, 0x79, 0xfa, 0xf5, 0xc6, 0x75, 0xb8, 0x2c, 0x79, 0x00, 0x1d, 0xd7, 0xb1, 0x81, 0xfc, 0x4b, 0xb3, 0x82, 0x1b, 0x00, 0x43, 0xff, 0x35, 0x9d, 0x24, 0xf9, 0x89, 0x85, 0x25}}, + {{0x26, 0xc3, 0xea, 0x84, 0x54, 0x69, 0x86, 0xca, 0x8f, 0x52, 0x05, 0x76, 0x54, 0xb4, 0xd8, 0x64, 0x14, 0x69, 0xc8, 0xf1, 0x98, 0x13, 0xa1, 0x47, 0x96, 0x8b, 0x94, 0x66, 0x33, 0xf3, 0x26, 0x06}, {0x1a, 0xac, 0xdf, 0x8c, 0x95, 0xc6, 0x9a, 0xcb, 0x56, 0x5a, 0x8c, 0xf2, 0x5d, 0x39, 0xa2, 0x51, 0x62, 0x87, 0x43, 0x01, 0x7a, 0x99, 0x82, 0x29, 0xea, 0xcd, 0x87, 0xe5, 0x34, 0x36, 0xa0, 0x20}}, + {{0x87, 0xaf, 0x6a, 0xad, 0x15, 0x38, 0x22, 0x4a, 0x14, 0xf1, 0x51, 0xfe, 0x39, 0xc2, 0x3d, 0xb2, 0xf9, 0x71, 0x76, 0x1d, 0xbc, 0x6f, 0x44, 0xe7, 0x41, 0x62, 0x77, 0xf2, 0xc4, 0xb3, 0x8f, 0x00}, {0xe1, 0x2b, 0xcf, 0x38, 0xbc, 0xff, 0x35, 0xef, 0x2a, 0x15, 0x4b, 0x6e, 0x67, 0x10, 0x06, 0x64, 0xca, 0x55, 0x43, 0xf7, 0x65, 0x1b, 0x39, 0xcd, 0xc4, 0x2d, 0xaa, 0x8f, 0x54, 0xac, 0xa9, 0x33}}, + {{0x1a, 0xac, 0xb7, 0x16, 0x60, 0x61, 0x3e, 0xb4, 0xbe, 0xdb, 0xdd, 0x33, 0xfa, 0x45, 0x17, 0x2d, 0x96, 0xb9, 0x8c, 0x15, 0xdc, 0xc7, 0xf2, 0xfc, 0xda, 0x41, 0xf5, 0x22, 0xb4, 0xd6, 0x2d, 0x22}, {0x71, 0x19, 0x9a, 0x6b, 0xb6, 0x8e, 0x5f, 0xd1, 0x8c, 0xde, 0x76, 0x8b, 0x37, 0xb4, 0x5e, 0x73, 0x2f, 0xcb, 0x1c, 0xe2, 0x09, 0xfd, 0x9e, 0x7a, 0xe3, 0x47, 0xd0, 0x36, 0x91, 0x68, 0x05, 0x26}}, + {{0x27, 0x0c, 0x7d, 0xb2, 0x0e, 0x67, 0x28, 0xa7, 0xf4, 0x09, 0x6e, 0xd8, 0x9b, 0x85, 0xfa, 0x0f, 0x3e, 0x1d, 0xca, 0x5b, 0xdd, 0x1d, 0x12, 0xfc, 0x15, 0x39, 0x70, 0x92, 0xac, 0xf5, 0xd5, 0x3e}, {0xb5, 0x9e, 0xb0, 0xf3, 0x9c, 0xad, 0x66, 0x2d, 0x3f, 0x49, 0x75, 0x39, 0x1b, 0x4a, 0x76, 0x0f, 0xe4, 0x80, 0x6c, 0xde, 0x39, 0x7d, 0x1c, 0x31, 0x61, 0x21, 0x8e, 0x53, 0x10, 0xa9, 0xc5, 0x10}}, + {{0x9e, 0x44, 0xfe, 0x08, 0x55, 0x2e, 0xef, 0xd8, 0xdc, 0x21, 0x38, 0x9b, 0xb4, 0xf0, 0x95, 0x97, 0x92, 0xff, 0x56, 0x19, 0x59, 0x33, 0x6d, 0x43, 0x2f, 0x56, 0x67, 0xff, 0xa1, 0xc2, 0xf0, 0x2e}, {0x2c, 0x25, 0x96, 0x23, 0xc0, 0x5a, 0x61, 0xea, 0xec, 0xf4, 0x8f, 0x24, 0x72, 0xe5, 0xc3, 0xd3, 0xf8, 0x15, 0xef, 0x35, 0x93, 0x51, 0x91, 0x08, 0x53, 0xd0, 0x09, 0xc5, 0xdf, 0x7d, 0x0b, 0x0e}}, + {{0xd1, 0x3a, 0x9b, 0x52, 0x75, 0x74, 0x5f, 0x59, 0x1a, 0xef, 0x14, 0xe1, 0xa2, 0x93, 0x02, 0xc2, 0xf2, 0x03, 0x87, 0x4b, 0x31, 0x79, 0x18, 0xa3, 0x31, 0x81, 0xdf, 0x56, 0xfe, 0xde, 0xb5, 0x25}, {0x9a, 0xc8, 0x75, 0xce, 0x3d, 0x68, 0x07, 0x32, 0x3e, 0x6a, 0x66, 0xee, 0xcc, 0x95, 0xa3, 0x0a, 0x63, 0x3a, 0x70, 0xdb, 0x4b, 0x0d, 0x75, 0x1d, 0xf2, 0x50, 0x5d, 0x6d, 0x14, 0x8c, 0xa8, 0x21}}, + {{0xd0, 0x54, 0x44, 0xfe, 0x57, 0xa1, 0xa0, 0xf1, 0x48, 0x8e, 0xa1, 0xb9, 0x83, 0xea, 0x8f, 0xe5, 0x75, 0xbd, 0x21, 0xb3, 0xbe, 0x1e, 0x5f, 0xe7, 0x99, 0xeb, 0x3d, 0x26, 0xe1, 0xcd, 0xf0, 0x2f}, {0x8b, 0xd5, 0x71, 0x38, 0xcb, 0x13, 0xad, 0x78, 0x15, 0x4a, 0xdf, 0xde, 0x0a, 0xf9, 0x0b, 0xd7, 0x55, 0x18, 0x86, 0x4a, 0x9b, 0x46, 0x59, 0xce, 0xb3, 0xf8, 0xb0, 0xd8, 0xf2, 0xb9, 0xd0, 0x07}}, + {{0x60, 0x81, 0x94, 0x3d, 0xc8, 0x5f, 0x86, 0x11, 0xac, 0xf8, 0x9d, 0x7d, 0xf6, 0xcd, 0x33, 0xef, 0x16, 0x08, 0x87, 0x1b, 0x1f, 0xc8, 0xfe, 0x77, 0x08, 0xf2, 0xbc, 0x81, 0x8e, 0x5c, 0xe4, 0x33}, {0x39, 0x80, 0x8f, 0x5f, 0x7d, 0xf5, 0x9c, 0xa7, 0x8d, 0x1e, 0x2f, 0x18, 0xab, 0xdb, 0xbd, 0x46, 0x1b, 0x2d, 0xe6, 0xc3, 0x62, 0x1e, 0x1e, 0x12, 0x6b, 0x12, 0x08, 0x7a, 0x26, 0x86, 0xab, 0x2a}}, + {{0x26, 0x4e, 0x57, 0x92, 0x4e, 0x5f, 0x09, 0x73, 0xab, 0xd0, 0xc6, 0x65, 0xc5, 0x92, 0x0a, 0x80, 0x3e, 0xdf, 0x33, 0x8c, 0x96, 0x73, 0x9b, 0x95, 0x6e, 0x66, 0x9a, 0xdb, 0xbc, 0x0a, 0x12, 0x17}, {0xa4, 0xdd, 0xbf, 0xdc, 0x71, 0xdb, 0xce, 0xa4, 0x25, 0x71, 0x45, 0xcc, 0x12, 0xbb, 0xa9, 0x23, 0x12, 0x50, 0x44, 0x50, 0x98, 0x65, 0x84, 0x49, 0x1a, 0x15, 0x2d, 0x45, 0x23, 0xa8, 0xb9, 0x15}}, + {{0xb3, 0x37, 0xf8, 0xd4, 0xc9, 0x58, 0x81, 0x18, 0xbf, 0xd4, 0xea, 0x12, 0x3a, 0xf5, 0xe1, 0x35, 0x72, 0x96, 0x05, 0x71, 0x80, 0x10, 0xb0, 0x43, 0xf4, 0xaf, 0xae, 0xf6, 0x18, 0xbb, 0xa1, 0x12}, {0xff, 0xae, 0x05, 0x64, 0x8c, 0x3a, 0xc9, 0xd0, 0x68, 0xb8, 0xed, 0x21, 0x4b, 0xdb, 0x79, 0x7c, 0x0d, 0x58, 0x85, 0x32, 0x4d, 0xab, 0x64, 0xfe, 0xd6, 0x4a, 0x96, 0x4e, 0x9b, 0x6e, 0xf2, 0x21}}, + {{0xbe, 0x93, 0xbc, 0xd8, 0x27, 0x74, 0xad, 0x5e, 0x10, 0xdc, 0x40, 0xa2, 0x9b, 0xdf, 0x74, 0x10, 0x75, 0xe4, 0x83, 0xb8, 0x58, 0xf4, 0x02, 0x5e, 0xba, 0x48, 0x71, 0x1a, 0x88, 0x94, 0x58, 0x16}, {0x93, 0xe4, 0xb6, 0x30, 0xa3, 0xd6, 0x20, 0xcf, 0xca, 0xb5, 0x2a, 0x3e, 0x5b, 0xfc, 0x50, 0xc0, 0x4d, 0x4b, 0x1c, 0x52, 0x64, 0xca, 0xd1, 0xca, 0xa9, 0x4d, 0xa9, 0x4f, 0xeb, 0x99, 0x9b, 0x2d}}, + {{0xc0, 0x1f, 0xab, 0x20, 0x52, 0x9e, 0x05, 0xbf, 0x3a, 0x0e, 0x1e, 0x8a, 0x2b, 0x61, 0x7d, 0x8a, 0x8c, 0xb3, 0xcd, 0xf4, 0x44, 0x42, 0xde, 0xea, 0xf2, 0x54, 0x24, 0x81, 0x8e, 0x7f, 0x31, 0x33}, {0x5e, 0x4c, 0x93, 0x05, 0x91, 0x9b, 0x88, 0xc8, 0xf6, 0x97, 0x7c, 0x0a, 0x0e, 0xc7, 0x69, 0xe5, 0xf4, 0x48, 0x91, 0xf8, 0xc8, 0xb9, 0xd5, 0x44, 0x2f, 0xc7, 0xf5, 0x68, 0x5b, 0x5a, 0x12, 0x23}}, + {{0x28, 0x14, 0xa6, 0xf2, 0x9b, 0xbf, 0xe4, 0x94, 0x10, 0xf3, 0x89, 0xdf, 0x68, 0x57, 0x90, 0xa5, 0x48, 0xbf, 0xd7, 0xe6, 0xc4, 0xea, 0x26, 0x5f, 0xef, 0x42, 0x31, 0x3a, 0x61, 0x84, 0x77, 0x17}, {0x44, 0xe9, 0xa9, 0x01, 0x3d, 0xa9, 0xc5, 0xd4, 0xb4, 0x1a, 0x82, 0xf3, 0xb3, 0x0b, 0xf3, 0x00, 0x5c, 0x11, 0x01, 0x90, 0x5e, 0xb0, 0x30, 0x3e, 0x01, 0xd5, 0x62, 0x0d, 0x7d, 0x86, 0xaa, 0x13}}, + {{0x84, 0x68, 0xd5, 0x83, 0xe6, 0x6e, 0x77, 0x0d, 0xad, 0x7f, 0xb0, 0x0c, 0x33, 0x31, 0x90, 0xc6, 0xac, 0xb6, 0x3c, 0xd8, 0x71, 0xfa, 0xf9, 0x03, 0x4e, 0x2e, 0xf2, 0x69, 0x3f, 0x2c, 0x5b, 0x38}, {0x9c, 0x47, 0x26, 0xf9, 0x77, 0xda, 0x2a, 0xe5, 0xd5, 0xf7, 0xf9, 0xa3, 0xdd, 0x18, 0x32, 0x40, 0x63, 0x3b, 0xe0, 0x0f, 0x67, 0xca, 0x8a, 0x69, 0x73, 0x0d, 0xa9, 0x45, 0x6f, 0xe4, 0xe6, 0x1b}}, + {{0xf3, 0x23, 0x4c, 0xb3, 0x88, 0x24, 0x4f, 0xb5, 0x6c, 0x55, 0xf3, 0xdc, 0x0f, 0x4d, 0xf7, 0x20, 0x83, 0x51, 0xca, 0x87, 0x6b, 0xc4, 0x29, 0xb6, 0x7d, 0x4d, 0xe5, 0x97, 0x07, 0x1b, 0x05, 0x3e}, {0xa9, 0xc4, 0xf4, 0xa7, 0x6b, 0xdf, 0x45, 0x28, 0x12, 0x32, 0xc5, 0xef, 0xb3, 0x7b, 0xd8, 0x01, 0xeb, 0x68, 0xc3, 0xf0, 0x6f, 0x84, 0x38, 0x74, 0x3e, 0x78, 0x68, 0x95, 0xcd, 0x4c, 0x4c, 0x05}}, + {{0x1e, 0x60, 0xf2, 0xed, 0x41, 0x2b, 0x03, 0x0e, 0xab, 0xa1, 0x56, 0x26, 0x80, 0x63, 0x56, 0xca, 0xba, 0x4a, 0x36, 0x5b, 0xf4, 0x73, 0xc1, 0xa9, 0xc7, 0x98, 0xfe, 0x76, 0xa4, 0xf6, 0x0b, 0x37}, {0xc8, 0x23, 0x73, 0x70, 0xc8, 0xb9, 0x3a, 0xe8, 0x63, 0xe4, 0x2c, 0x92, 0xfc, 0x12, 0xcb, 0x68, 0x1d, 0xcd, 0xe2, 0xaa, 0xa7, 0xcb, 0x58, 0x1d, 0xac, 0x85, 0x73, 0xd7, 0xbe, 0xdc, 0x41, 0x16}}, + {{0xb1, 0x8c, 0x86, 0x07, 0xb2, 0x50, 0xd9, 0x33, 0x81, 0x18, 0xb0, 0x79, 0x24, 0x4d, 0x46, 0x55, 0xcf, 0xe7, 0xb3, 0x70, 0x63, 0xae, 0xf8, 0xce, 0x9f, 0xdf, 0x54, 0x56, 0x6f, 0x0d, 0xdd, 0x1e}, {0x7d, 0x6d, 0xf8, 0x3b, 0xd2, 0x5f, 0x19, 0xca, 0x87, 0x0c, 0x1d, 0x48, 0x8b, 0x77, 0x88, 0xd8, 0x04, 0xa0, 0x9c, 0x9a, 0xb6, 0x4c, 0x18, 0x77, 0x85, 0x17, 0x39, 0xc5, 0x22, 0x84, 0xcd, 0x18}}, + {{0xa9, 0x38, 0x40, 0x3c, 0x1d, 0x06, 0xd0, 0xd3, 0x7d, 0x33, 0x3a, 0xb3, 0x6f, 0xba, 0xd2, 0x35, 0x8c, 0x8c, 0x48, 0xa0, 0xd0, 0xcc, 0x5a, 0x2b, 0xc8, 0x55, 0xf0, 0x70, 0xf9, 0x51, 0x77, 0x31}, {0x44, 0xcf, 0xdc, 0xe5, 0x46, 0x2d, 0xa0, 0x7d, 0x87, 0xac, 0xfd, 0x00, 0x04, 0x72, 0x48, 0x19, 0xed, 0x09, 0x52, 0x79, 0x05, 0x2f, 0x5d, 0xd3, 0xae, 0x40, 0xd4, 0x8f, 0xe4, 0x66, 0x7b, 0x06}}, + {{0x19, 0x62, 0x3b, 0xc5, 0xc1, 0xf5, 0x67, 0xbe, 0x41, 0x51, 0xdc, 0x49, 0xeb, 0xd3, 0x4d, 0x0c, 0x72, 0xdc, 0x3d, 0xc8, 0x06, 0x6e, 0x85, 0x19, 0x9d, 0xf3, 0x60, 0x6c, 0x34, 0x4e, 0x80, 0x05}, {0xca, 0x2e, 0x4e, 0xe8, 0xf8, 0xb5, 0x70, 0xd9, 0x0a, 0x0b, 0xaa, 0x6f, 0xe7, 0xba, 0xee, 0x8d, 0xdd, 0xcf, 0x75, 0x4c, 0x0d, 0x46, 0x36, 0xce, 0xff, 0xc2, 0xb6, 0x4e, 0xa8, 0x30, 0x0b, 0x0c}}, + {{0x37, 0xf3, 0xda, 0x85, 0xb4, 0xb3, 0x11, 0xd2, 0x9b, 0x8b, 0x76, 0xd1, 0xc9, 0xc1, 0xaf, 0x7c, 0x91, 0x66, 0xa0, 0x6a, 0x08, 0x6d, 0x29, 0x4f, 0x50, 0xe4, 0x6e, 0x39, 0x56, 0x17, 0x69, 0x14}, {0x18, 0x93, 0xb7, 0x6c, 0xbe, 0x5e, 0x8c, 0x90, 0x93, 0x19, 0x7a, 0x8a, 0x3c, 0x12, 0x5e, 0x48, 0x4d, 0x54, 0x30, 0xdc, 0x97, 0x82, 0x9c, 0xba, 0x9f, 0x57, 0xad, 0x67, 0xc8, 0xb3, 0x1b, 0x0b}}, + {{0x38, 0x8e, 0x89, 0x9c, 0x6a, 0x12, 0xbb, 0xfd, 0x6a, 0xe1, 0xc7, 0x24, 0xe3, 0xb9, 0xb0, 0xee, 0x76, 0x39, 0xbd, 0xa4, 0x9b, 0x64, 0x63, 0x2a, 0x67, 0x2e, 0xcf, 0x38, 0xe3, 0x8a, 0xbe, 0x2c}, {0x10, 0xdf, 0x87, 0x42, 0x97, 0xe2, 0xc8, 0x02, 0x36, 0x5e, 0xcb, 0xff, 0x3a, 0x30, 0x4b, 0xfd, 0x80, 0x26, 0xc2, 0x99, 0x64, 0x5d, 0x24, 0xfe, 0x42, 0x09, 0x6a, 0xac, 0x03, 0xf0, 0xd4, 0x2a}}, + {{0x2e, 0x47, 0xf2, 0x5c, 0xe4, 0x45, 0x66, 0x63, 0xf3, 0x06, 0x70, 0x8c, 0x20, 0xfa, 0x1b, 0x58, 0xb6, 0x53, 0x8c, 0xa6, 0x2f, 0xfc, 0x42, 0x7f, 0x85, 0x3e, 0x96, 0xa5, 0x59, 0x5c, 0x5f, 0x3e}, {0x98, 0x74, 0x95, 0x17, 0xd7, 0x7c, 0xae, 0x3f, 0xcd, 0x17, 0x0f, 0x33, 0x0d, 0xf7, 0x97, 0x18, 0x24, 0x96, 0xbe, 0x93, 0xa8, 0xc4, 0xbc, 0x08, 0x96, 0x11, 0x0a, 0x88, 0x70, 0x5a, 0xb6, 0x16}}, + {{0x00, 0x64, 0xfa, 0x6c, 0x4e, 0xa3, 0xb8, 0xec, 0x69, 0xb0, 0x37, 0x17, 0x8d, 0xa6, 0x2b, 0x87, 0xd6, 0x00, 0x30, 0x4d, 0x56, 0x8b, 0x2b, 0x69, 0xf7, 0x28, 0xbd, 0xc2, 0x32, 0x6b, 0xc8, 0x1a}, {0xb6, 0xec, 0xb8, 0x4a, 0xd7, 0x73, 0x15, 0xcd, 0x59, 0x89, 0x6f, 0xd0, 0x56, 0xd4, 0xd8, 0x10, 0xa6, 0xa6, 0xb8, 0x40, 0xdb, 0x94, 0xd7, 0xc4, 0xe8, 0x01, 0x22, 0xf6, 0x05, 0x14, 0xc4, 0x0f}}, + {{0x29, 0xcc, 0x86, 0xfb, 0x21, 0x4e, 0x3c, 0xb1, 0x41, 0xa8, 0x0b, 0x22, 0x56, 0x22, 0xd4, 0x6d, 0xf6, 0x44, 0x09, 0x91, 0x57, 0xd3, 0x5d, 0x48, 0x36, 0x62, 0x5c, 0xe8, 0xf3, 0x37, 0xe6, 0x13}, {0x20, 0x25, 0x95, 0xd1, 0xd6, 0xd2, 0x3e, 0x39, 0xd9, 0x41, 0x4d, 0x7d, 0xe0, 0x20, 0x14, 0x87, 0xa0, 0xd5, 0x4d, 0x1b, 0xc9, 0xe4, 0x97, 0x4f, 0x99, 0x79, 0x56, 0x93, 0x26, 0x6e, 0xe1, 0x0e}}, + {{0xc4, 0x78, 0x7f, 0xb6, 0x18, 0xe8, 0xf0, 0x18, 0xd7, 0x52, 0xfe, 0x5c, 0x76, 0x82, 0x8e, 0xc7, 0x49, 0x52, 0x72, 0x33, 0x8e, 0x10, 0x29, 0x10, 0xbb, 0x15, 0x32, 0x3e, 0x9f, 0x77, 0xe7, 0x1c}, {0xef, 0x7d, 0xf4, 0x69, 0x79, 0x2c, 0x3c, 0x0a, 0x77, 0xb2, 0x0a, 0xc1, 0xd3, 0x5b, 0x4a, 0x92, 0xde, 0x00, 0xda, 0x3f, 0x02, 0x51, 0x84, 0xa6, 0x1e, 0x35, 0x86, 0x8b, 0x7f, 0xc6, 0x48, 0x28}}, + {{0x19, 0x0a, 0xf4, 0x6e, 0x70, 0x00, 0x5a, 0x78, 0x0c, 0x45, 0x79, 0x1e, 0x6d, 0xe1, 0x9e, 0xfc, 0x31, 0xee, 0x13, 0x8f, 0x13, 0xbe, 0xb0, 0x21, 0x15, 0xe5, 0x30, 0xeb, 0x79, 0x6e, 0x5a, 0x20}, {0x92, 0xff, 0xcd, 0x54, 0x36, 0x7b, 0x9b, 0x10, 0x64, 0xd6, 0x44, 0xbb, 0x76, 0xfd, 0x19, 0xe2, 0xd4, 0xcf, 0xc6, 0xa4, 0xf5, 0x47, 0xdc, 0x26, 0x73, 0x8e, 0x38, 0x96, 0x22, 0x00, 0x96, 0x13}}, + {{0x0a, 0x7e, 0xdb, 0xde, 0xe3, 0xee, 0x4f, 0x28, 0x34, 0x86, 0x74, 0xab, 0xd6, 0xd6, 0xa3, 0xeb, 0xb3, 0x88, 0x87, 0x73, 0x3e, 0x13, 0x6d, 0x20, 0xd2, 0x67, 0x19, 0x08, 0x44, 0x94, 0xe2, 0x06}, {0x26, 0xfa, 0x5d, 0xdd, 0x45, 0x77, 0xf2, 0x32, 0x7e, 0x6c, 0x1d, 0x43, 0x69, 0xff, 0xb9, 0x61, 0xdd, 0xec, 0x68, 0xd8, 0x81, 0xc3, 0x5e, 0x7b, 0x8e, 0x99, 0x1f, 0x1b, 0x42, 0xb4, 0x6d, 0x39}}, + {{0x5a, 0x43, 0xb3, 0x09, 0x25, 0x29, 0x9f, 0xf0, 0x89, 0x62, 0x0e, 0x70, 0x72, 0x7f, 0xd8, 0x5d, 0xe7, 0xe4, 0x27, 0x30, 0x6b, 0x03, 0x8f, 0x42, 0xc2, 0xc4, 0x2a, 0x85, 0xab, 0x38, 0xa1, 0x3b}, {0xc9, 0x63, 0xa6, 0xe3, 0xf7, 0x6e, 0xeb, 0x31, 0xef, 0x5e, 0x2a, 0x22, 0x19, 0xa5, 0xfb, 0x66, 0x2d, 0x5f, 0xa5, 0xd9, 0x85, 0xea, 0x56, 0xf0, 0x7b, 0xaf, 0xc7, 0x42, 0x6e, 0x1a, 0x9d, 0x0f}}, + {{0x4d, 0x5c, 0x7d, 0x5a, 0x0f, 0xb6, 0xd8, 0x2e, 0xd4, 0x0b, 0x2b, 0xbb, 0x81, 0xec, 0x41, 0x3c, 0x57, 0xcc, 0xd3, 0xcf, 0xc1, 0x51, 0x62, 0x51, 0x7a, 0x25, 0x92, 0x84, 0x47, 0xf8, 0x28, 0x16}, {0xd2, 0x3a, 0x49, 0xdf, 0xa0, 0xde, 0x28, 0x10, 0x5d, 0x1f, 0xba, 0x54, 0xe0, 0x8e, 0x64, 0x9f, 0x71, 0x50, 0x4b, 0x33, 0xa6, 0x00, 0xc3, 0xa5, 0xcb, 0x8d, 0x9d, 0x4c, 0x47, 0xd6, 0xec, 0x22}}, + {{0xc9, 0xb4, 0x18, 0xa6, 0x4f, 0x88, 0x78, 0xba, 0xde, 0xb8, 0x1c, 0xef, 0xbd, 0xcf, 0x90, 0x24, 0xcf, 0xa7, 0xb8, 0x49, 0x55, 0x45, 0x62, 0x62, 0x2e, 0x82, 0xd8, 0x52, 0x00, 0x6c, 0xde, 0x22}, {0x3b, 0xf1, 0xb4, 0x4e, 0xb6, 0xd8, 0x74, 0xb5, 0x91, 0x74, 0xfd, 0xc6, 0xa8, 0x7d, 0xe5, 0x3a, 0xeb, 0xd2, 0x6a, 0xc5, 0x9a, 0x84, 0x51, 0xd9, 0x67, 0xbb, 0xf5, 0x8a, 0x43, 0x27, 0x95, 0x3d}}, + {{0x02, 0xe5, 0xae, 0xa9, 0xc9, 0x21, 0x3b, 0x42, 0x2a, 0x37, 0x59, 0xa1, 0x4f, 0x58, 0x60, 0xb5, 0xf3, 0x27, 0x54, 0xe1, 0x52, 0xa6, 0xe3, 0xbd, 0x48, 0x66, 0x6a, 0x10, 0xee, 0x25, 0xe9, 0x13}, {0xd4, 0x3c, 0x51, 0xf0, 0xc5, 0x83, 0xc0, 0x21, 0x0f, 0x67, 0xfb, 0xbb, 0x06, 0x9c, 0xa4, 0x1a, 0xc4, 0xde, 0x35, 0xa9, 0x20, 0x26, 0x3e, 0x00, 0x00, 0xd3, 0xfc, 0xfe, 0x9b, 0x2c, 0xd0, 0x06}}, + {{0x9d, 0xdf, 0x68, 0x39, 0x9a, 0x34, 0xac, 0x1b, 0xf4, 0x8c, 0x94, 0xdd, 0x88, 0x95, 0x7a, 0x4f, 0xda, 0x41, 0x5b, 0x42, 0xb9, 0xb2, 0x25, 0x9c, 0x22, 0x04, 0x06, 0x67, 0x80, 0xc3, 0xbc, 0x34}, {0x6a, 0xab, 0x7d, 0x76, 0x08, 0xe5, 0x43, 0x2e, 0x22, 0xd5, 0xde, 0x30, 0x57, 0x13, 0x2e, 0x8f, 0x7b, 0xb9, 0x9c, 0x7b, 0x5e, 0x42, 0x5d, 0x1e, 0xd1, 0xa1, 0x4c, 0x3a, 0x68, 0xc0, 0x61, 0x3b}}, + {{0xb3, 0x33, 0x8d, 0xdc, 0x15, 0x15, 0x22, 0x2f, 0x44, 0x57, 0xcf, 0xf4, 0xd2, 0x45, 0x44, 0x87, 0x4b, 0x70, 0x24, 0x7a, 0x9c, 0x9e, 0x39, 0xd4, 0x6d, 0xcb, 0xaa, 0xb7, 0xcd, 0xd0, 0x48, 0x0a}, {0xf8, 0xb4, 0xed, 0x76, 0x94, 0xa9, 0x65, 0x32, 0xfb, 0x34, 0xdb, 0x83, 0x4c, 0x4f, 0x35, 0xad, 0x6b, 0xf5, 0x83, 0x01, 0x9a, 0x97, 0x76, 0x8c, 0x4b, 0xf3, 0x3c, 0x38, 0x4a, 0x3c, 0xc0, 0x24}}, + {{0x36, 0x8f, 0xde, 0x6b, 0xde, 0x48, 0x64, 0x02, 0xcc, 0x94, 0x5b, 0x06, 0x8c, 0xc9, 0xdf, 0x47, 0xd4, 0x65, 0x7b, 0x8f, 0x86, 0x00, 0xae, 0x1b, 0x27, 0xfc, 0xfa, 0x49, 0xe4, 0xed, 0x25, 0x37}, {0xad, 0xab, 0xa0, 0xc2, 0x74, 0x2c, 0x84, 0x07, 0x5c, 0xc6, 0xfa, 0xa1, 0x31, 0x69, 0xb0, 0x98, 0x49, 0xd6, 0xa0, 0xc5, 0xf5, 0xf3, 0xa2, 0xa0, 0xaa, 0xf6, 0x7a, 0xf0, 0xb4, 0x0a, 0xe4, 0x34}}, + {{0x2d, 0x80, 0x5a, 0x98, 0xa5, 0x82, 0x4a, 0xc0, 0xe3, 0xf8, 0xf2, 0x0f, 0xc2, 0x11, 0xdc, 0xf0, 0x5b, 0xab, 0x43, 0xc3, 0x42, 0x88, 0x9c, 0xf9, 0x1e, 0xbc, 0x43, 0x49, 0x60, 0xd5, 0xfe, 0x1e}, {0x87, 0x7c, 0xb1, 0x72, 0xaf, 0x38, 0x73, 0x2b, 0x8a, 0x45, 0x1f, 0x13, 0x90, 0x3e, 0x76, 0x7a, 0x7e, 0x79, 0xe7, 0xed, 0x8c, 0x1a, 0x58, 0xf5, 0x48, 0x52, 0xe5, 0x54, 0x7f, 0x88, 0x60, 0x21}}, + {{0x19, 0x82, 0x78, 0xbd, 0x29, 0x79, 0x06, 0xa8, 0xa6, 0x4b, 0x68, 0x08, 0xc2, 0xb7, 0x02, 0x45, 0x62, 0x86, 0xfa, 0x12, 0x13, 0xa7, 0x24, 0x18, 0xc0, 0x82, 0x9c, 0xec, 0x68, 0xeb, 0x5f, 0x1d}, {0x7e, 0x19, 0xff, 0xa0, 0xd8, 0x6f, 0x0c, 0xb5, 0xef, 0x17, 0x98, 0x1a, 0xc8, 0x67, 0xcb, 0x1e, 0xad, 0xe9, 0xe2, 0xc3, 0x8e, 0x66, 0x02, 0x38, 0xc5, 0xbd, 0xea, 0xb8, 0xe8, 0xbf, 0x1f, 0x17}}, + {{0x20, 0x0b, 0xa3, 0x1a, 0xcb, 0x32, 0x04, 0x38, 0xf5, 0xdb, 0x8a, 0x12, 0x76, 0x9e, 0x06, 0x72, 0x3e, 0x41, 0xf9, 0x13, 0x81, 0x62, 0x30, 0xfe, 0x3d, 0xa2, 0xc0, 0xa3, 0xf6, 0xfa, 0x95, 0x3d}, {0x0c, 0x5f, 0x70, 0x7b, 0x6d, 0x68, 0x91, 0x5c, 0x9a, 0xf7, 0x76, 0xab, 0xab, 0x25, 0x32, 0xa4, 0x10, 0x0e, 0x52, 0xb0, 0xe8, 0xba, 0x34, 0x15, 0x2d, 0x8a, 0x93, 0x7d, 0xf7, 0x24, 0x51, 0x13}}, + {{0x9a, 0xa4, 0x33, 0x07, 0x3e, 0xd4, 0xa5, 0xd8, 0x5b, 0x68, 0xf8, 0x4d, 0x6c, 0x16, 0xfc, 0x59, 0x80, 0xd5, 0x1e, 0x48, 0x0b, 0x73, 0x2c, 0x6b, 0x39, 0x87, 0xa5, 0xb3, 0xc9, 0xb4, 0x74, 0x0b}, {0x68, 0xe9, 0x4b, 0x03, 0x4c, 0xaf, 0xc3, 0xf7, 0x42, 0xb7, 0x46, 0xda, 0xd1, 0x4d, 0x0b, 0x28, 0xf1, 0x2b, 0xa5, 0x92, 0x43, 0x63, 0x7c, 0x81, 0x21, 0xfd, 0xa4, 0x0f, 0x19, 0x72, 0xc6, 0x20}}, + {{0xa9, 0xce, 0x8c, 0xcc, 0x85, 0x5d, 0x9a, 0x9b, 0xe0, 0x69, 0x5f, 0x63, 0x6c, 0xdb, 0x3a, 0x8a, 0x84, 0x11, 0x60, 0x15, 0x8c, 0xbb, 0xe9, 0xd9, 0xee, 0xb5, 0x2a, 0x29, 0x60, 0x42, 0xcc, 0x1d}, {0x66, 0x69, 0x6d, 0xf6, 0x46, 0xc6, 0x91, 0x12, 0xdc, 0xfa, 0xaf, 0x6b, 0x60, 0xd8, 0xb2, 0xd0, 0x8e, 0x39, 0xf2, 0x21, 0xf8, 0x42, 0xe4, 0x5f, 0x0c, 0x62, 0xeb, 0x35, 0x42, 0xd0, 0x97, 0x1b}}, + {{0xcb, 0xb0, 0x21, 0x86, 0xed, 0x47, 0x11, 0x91, 0xd4, 0x13, 0x75, 0x90, 0xc5, 0xa0, 0xd9, 0x15, 0x14, 0x57, 0xb5, 0xf6, 0x41, 0x82, 0xb6, 0x55, 0xa8, 0x18, 0xba, 0xbd, 0xcd, 0x21, 0x8f, 0x38}, {0xe9, 0x0b, 0xdd, 0x57, 0xed, 0xb6, 0xf4, 0xd7, 0x8f, 0x71, 0x2f, 0xc7, 0xa1, 0xdc, 0x59, 0xc6, 0x30, 0xc2, 0x80, 0x04, 0x01, 0xb0, 0x3b, 0x67, 0x1d, 0x2b, 0x14, 0xb0, 0x34, 0x37, 0x9f, 0x08}}, + {{0xd3, 0x64, 0xf0, 0x66, 0x11, 0xe2, 0xef, 0x3f, 0x74, 0xfe, 0x23, 0x2b, 0x92, 0xa6, 0x1e, 0xab, 0xd3, 0xed, 0x13, 0x5b, 0xb8, 0x16, 0xcc, 0xab, 0x02, 0x97, 0xfd, 0x5b, 0x92, 0x58, 0x1e, 0x2f}, {0x0c, 0x6e, 0x6b, 0xcd, 0xf5, 0x5f, 0x11, 0xe1, 0xd3, 0xc9, 0x62, 0x6a, 0x60, 0x60, 0x8e, 0x3b, 0x2a, 0x96, 0x29, 0x23, 0x0a, 0x2c, 0x71, 0x2a, 0xb5, 0xa3, 0xc2, 0xe5, 0x1d, 0x1f, 0x8a, 0x39}}, + {{0x27, 0x55, 0x6c, 0x51, 0xaf, 0x5f, 0xf7, 0xb1, 0x74, 0x5d, 0x54, 0xa9, 0x11, 0xe4, 0x34, 0x18, 0xe5, 0x48, 0x92, 0x51, 0x22, 0x8f, 0x3d, 0x5a, 0xe4, 0xe2, 0xe5, 0x99, 0x3b, 0x5c, 0x9b, 0x0c}, {0x78, 0x91, 0x4c, 0xcd, 0x97, 0x1b, 0x19, 0xc5, 0x37, 0x9f, 0x1d, 0xec, 0xfd, 0x2c, 0x1f, 0x3d, 0x12, 0x9b, 0x74, 0xa6, 0xb5, 0x1a, 0xea, 0x77, 0x19, 0x92, 0x50, 0x1a, 0x37, 0x75, 0x54, 0x1c}}, + {{0xa3, 0xec, 0xf0, 0xbd, 0x7c, 0xbb, 0x48, 0xeb, 0xf9, 0x23, 0x8a, 0x3f, 0x8f, 0xaf, 0x18, 0x38, 0xc2, 0x52, 0x51, 0x82, 0xc6, 0x2b, 0x25, 0x12, 0x6b, 0x75, 0x91, 0x6b, 0x1c, 0x23, 0xf2, 0x20}, {0xdf, 0x64, 0xbc, 0x41, 0x70, 0xb7, 0x6c, 0xe5, 0xeb, 0x88, 0x7c, 0xec, 0xfb, 0x3e, 0x07, 0x65, 0xa3, 0xe9, 0xe3, 0xe0, 0x10, 0xfc, 0xb8, 0x4d, 0x7a, 0xe3, 0xd0, 0x7e, 0x8d, 0xaa, 0xf5, 0x25}}, + {{0x92, 0x15, 0xb5, 0xc5, 0x74, 0x11, 0x9d, 0x98, 0x3d, 0x4f, 0x18, 0xd3, 0x23, 0xde, 0x22, 0xbc, 0x16, 0x92, 0x0c, 0xc3, 0xe1, 0xe3, 0x74, 0x0d, 0x0e, 0xef, 0x74, 0x99, 0xe6, 0x46, 0x9f, 0x3c}, {0x8f, 0xa6, 0x4e, 0x27, 0x9f, 0xbc, 0x71, 0xca, 0xb0, 0x77, 0x87, 0xb7, 0xd4, 0xf4, 0x0a, 0xda, 0x52, 0x54, 0x25, 0x54, 0x7f, 0x19, 0x11, 0xe0, 0xce, 0x07, 0xad, 0x5f, 0x24, 0x1f, 0xbc, 0x02}}, + {{0x17, 0xb0, 0x81, 0xa0, 0x06, 0xe1, 0x6e, 0xf6, 0x66, 0xed, 0x1a, 0x14, 0xb9, 0x9f, 0xa0, 0xbd, 0x8f, 0x21, 0xb2, 0xa5, 0xd3, 0x85, 0x9b, 0x8d, 0x05, 0x52, 0xa0, 0x9a, 0xdf, 0x44, 0x68, 0x33}, {0x3e, 0x28, 0x50, 0x7a, 0xc2, 0x9e, 0xcb, 0x21, 0x5e, 0x35, 0x98, 0x8a, 0x8d, 0xeb, 0x26, 0x65, 0xd2, 0x5b, 0x5b, 0x5a, 0x51, 0x66, 0x25, 0x46, 0xaa, 0x31, 0xbb, 0xea, 0xa2, 0xcf, 0xcc, 0x0d}}, + {{0x78, 0x10, 0xd5, 0xd5, 0xdc, 0xeb, 0x01, 0xdf, 0xa9, 0x40, 0x97, 0x45, 0xfe, 0x4f, 0xe7, 0xdc, 0x6f, 0x92, 0xd4, 0x88, 0x21, 0xc7, 0x30, 0xec, 0xd2, 0x0b, 0xd0, 0x66, 0xba, 0xe3, 0xf4, 0x25}, {0x48, 0xbd, 0x5d, 0x30, 0x28, 0xcf, 0xa4, 0x1a, 0xce, 0x2f, 0xc5, 0x29, 0x41, 0xed, 0xac, 0xf1, 0x23, 0x20, 0x9d, 0x41, 0x99, 0xae, 0x79, 0x6a, 0xa2, 0xdd, 0xa7, 0xab, 0xc2, 0xcc, 0x7a, 0x28}}, + {{0x01, 0x37, 0xe4, 0x61, 0xb1, 0x67, 0xc9, 0xf6, 0x4a, 0x31, 0x75, 0xcf, 0x71, 0x41, 0x59, 0xba, 0x26, 0xd3, 0x45, 0x98, 0x0c, 0xfd, 0x66, 0x23, 0x43, 0x10, 0x55, 0x2e, 0xef, 0x75, 0xea, 0x07}, {0xb3, 0x02, 0x50, 0x1d, 0x63, 0xb3, 0x6a, 0x5f, 0x86, 0x18, 0xf7, 0x8d, 0xd3, 0xf1, 0xa7, 0x42, 0xb1, 0x41, 0x44, 0xe2, 0xda, 0x5f, 0x75, 0xb1, 0x84, 0xe8, 0xe9, 0x47, 0x81, 0xb8, 0xd8, 0x06}}, + {{0x97, 0xf7, 0x69, 0x24, 0xe1, 0x0e, 0x60, 0x77, 0x00, 0x21, 0xcf, 0x63, 0x11, 0x94, 0x28, 0x9d, 0xac, 0xd7, 0x38, 0x1e, 0xbc, 0xd9, 0xf5, 0x94, 0xd8, 0xf1, 0x48, 0x23, 0xed, 0xa8, 0x9d, 0x0d}, {0x81, 0x43, 0xf9, 0x7e, 0x45, 0x10, 0xcb, 0x9d, 0x0d, 0x25, 0xde, 0x41, 0x8e, 0x88, 0x6f, 0xf2, 0xff, 0x98, 0xbe, 0xa5, 0x9e, 0x56, 0xb4, 0x4d, 0xb6, 0xb1, 0x83, 0xe7, 0xfe, 0x26, 0x6e, 0x2c}}, + {{0x7e, 0xe7, 0x68, 0x8b, 0x17, 0x21, 0x52, 0x82, 0xdb, 0x0e, 0xaf, 0xda, 0x04, 0x4c, 0xb6, 0x62, 0x21, 0x9b, 0xce, 0xc5, 0x6a, 0xef, 0xfc, 0x56, 0x0f, 0xb2, 0xa9, 0x26, 0x83, 0x21, 0x60, 0x00}, {0xbe, 0x57, 0x58, 0xc7, 0x56, 0xf7, 0x81, 0x93, 0xd0, 0xaa, 0xb2, 0xe9, 0x22, 0x87, 0x64, 0x2c, 0x9f, 0x89, 0xb7, 0x22, 0x97, 0xfa, 0x1d, 0xd2, 0x97, 0x3b, 0xd1, 0x36, 0xab, 0x34, 0xb3, 0x37}}, + {{0x7e, 0x25, 0xac, 0xc9, 0xa7, 0xd2, 0xca, 0x1d, 0x1e, 0x56, 0xde, 0xdf, 0x41, 0xbd, 0x81, 0xf4, 0xa1, 0x9b, 0x4f, 0xe1, 0x59, 0x5d, 0xb9, 0x7f, 0xf1, 0x5f, 0x75, 0x3a, 0xae, 0xe5, 0x4f, 0x16}, {0xb9, 0x04, 0xed, 0x04, 0x80, 0x23, 0x5d, 0xd8, 0xbe, 0x67, 0x0b, 0x24, 0xca, 0xf4, 0xa2, 0xf0, 0xc0, 0xe8, 0x37, 0xb1, 0x39, 0x65, 0x8d, 0x32, 0x38, 0x29, 0x72, 0x3c, 0xd2, 0x7a, 0x91, 0x1f}}, + {{0xc8, 0xdd, 0x1d, 0x51, 0x69, 0x1f, 0x1a, 0x7c, 0xbb, 0xc6, 0x93, 0x8a, 0xd0, 0x22, 0xef, 0xaf, 0x86, 0x8e, 0xfb, 0x5d, 0x6e, 0xde, 0x7d, 0x6b, 0xdf, 0x1f, 0x1b, 0x9b, 0xfb, 0x14, 0x18, 0x04}, {0x19, 0xee, 0xde, 0x5a, 0x8d, 0x8d, 0x32, 0xc2, 0x8c, 0x32, 0xaa, 0x1f, 0x3e, 0x23, 0xcd, 0xfc, 0x5d, 0x08, 0xd2, 0xbf, 0x62, 0xeb, 0x4a, 0xb7, 0x74, 0xb6, 0xda, 0xe2, 0x7a, 0x49, 0x9b, 0x34}}, + {{0x40, 0x8c, 0x05, 0xde, 0x2e, 0x49, 0x76, 0xee, 0xfd, 0x0d, 0x21, 0x63, 0xa9, 0xce, 0x67, 0x96, 0x78, 0x4d, 0xaf, 0xbb, 0xe7, 0xdf, 0xfb, 0x9f, 0xfb, 0xed, 0xf2, 0xbb, 0x47, 0x7f, 0x4a, 0x02}, {0xa6, 0xb6, 0xc0, 0x54, 0x53, 0x94, 0x98, 0x27, 0x06, 0x93, 0x7c, 0xe9, 0xf1, 0x04, 0x58, 0x02, 0xf8, 0x31, 0x0f, 0xf7, 0x5b, 0x74, 0x89, 0xa5, 0xd5, 0x1b, 0xa0, 0xd2, 0x3e, 0x75, 0x80, 0x29}}, + {{0x1f, 0xcf, 0x8d, 0xfb, 0xea, 0x79, 0x17, 0xc2, 0x99, 0x1a, 0xe8, 0x74, 0x68, 0x3d, 0xd4, 0xc7, 0x25, 0x02, 0xa7, 0x3d, 0x7a, 0xe8, 0x4e, 0xdf, 0xec, 0x66, 0xc0, 0x7e, 0x64, 0x66, 0x74, 0x26}, {0xff, 0x71, 0x66, 0x3e, 0x8d, 0x43, 0x08, 0x9a, 0x33, 0xe0, 0xf0, 0x7e, 0xfd, 0xf5, 0x97, 0x25, 0x6b, 0x33, 0xe4, 0x16, 0xb3, 0xd2, 0x90, 0x34, 0xd0, 0x50, 0xe5, 0x2c, 0xb8, 0x68, 0xf1, 0x0a}}, + {{0xb9, 0xd7, 0x81, 0xad, 0xce, 0x3a, 0xe7, 0x9e, 0x87, 0x22, 0x20, 0xc4, 0x51, 0x4d, 0x7d, 0x7f, 0xd5, 0x21, 0x2c, 0xf7, 0xda, 0x8c, 0xa4, 0x7e, 0x62, 0x92, 0x05, 0x7c, 0x89, 0xab, 0xa5, 0x3b}, {0x62, 0x1f, 0xaf, 0xe7, 0xf6, 0x2d, 0xa7, 0x65, 0x01, 0x6e, 0x87, 0xed, 0x79, 0x70, 0x18, 0x50, 0x33, 0xf5, 0xf8, 0xb2, 0xac, 0x7b, 0x49, 0xdd, 0x48, 0x83, 0xca, 0x10, 0xe1, 0xb1, 0x05, 0x23}}, + {{0x66, 0x08, 0x81, 0x6f, 0x6e, 0x85, 0xb8, 0x7b, 0x2c, 0x34, 0x58, 0x35, 0xa6, 0x87, 0x10, 0x29, 0xee, 0x2a, 0xec, 0xa5, 0xa1, 0xf6, 0x97, 0x01, 0x36, 0xa9, 0x82, 0xbe, 0x84, 0x0e, 0x3f, 0x2e}, {0x6e, 0xd2, 0xfe, 0xde, 0x23, 0x4f, 0xd2, 0x24, 0x1f, 0x53, 0x23, 0xe1, 0xcb, 0xfd, 0xa3, 0xa6, 0x7a, 0x9b, 0x59, 0x90, 0x4f, 0x54, 0x54, 0xf5, 0x88, 0xd7, 0x05, 0x2c, 0x74, 0x2c, 0x2b, 0x1b}}, + {{0xb7, 0x61, 0x5f, 0xe7, 0xc5, 0x8c, 0xaa, 0x77, 0x5d, 0x22, 0x7a, 0x2c, 0x2c, 0xd2, 0xb0, 0x7a, 0x33, 0x62, 0x04, 0xd9, 0xae, 0x0b, 0x1a, 0x26, 0x96, 0xfe, 0xe6, 0xdf, 0x27, 0x54, 0xca, 0x23}, {0xf1, 0xf4, 0xe5, 0x8b, 0x26, 0xf1, 0x65, 0x39, 0x68, 0x44, 0xe0, 0x19, 0x5d, 0xf0, 0xbc, 0xfb, 0x90, 0xda, 0xa3, 0xdd, 0x1a, 0x7a, 0x20, 0xcf, 0x9f, 0xae, 0x58, 0xe7, 0xb3, 0x38, 0xc1, 0x2d}}, + {{0x97, 0x3a, 0xf1, 0x51, 0xbb, 0xd4, 0xcd, 0xe4, 0x66, 0xf1, 0x47, 0xd9, 0x07, 0xb3, 0xe0, 0x0a, 0xdd, 0x61, 0x54, 0x95, 0x80, 0x0d, 0xc1, 0x95, 0x6b, 0xa2, 0x8c, 0xf5, 0xcd, 0x0d, 0x63, 0x26}, {0xfb, 0xe7, 0x25, 0x7f, 0xce, 0x76, 0x69, 0xec, 0xb9, 0xb2, 0x3e, 0x60, 0x67, 0xef, 0xf1, 0x21, 0xef, 0xd7, 0xdc, 0x65, 0xae, 0x45, 0x38, 0xb5, 0xf0, 0xd4, 0x75, 0x34, 0xd2, 0xe5, 0x6b, 0x00}}, + {{0xb5, 0x37, 0x4d, 0xc7, 0xf5, 0xda, 0x37, 0xd9, 0xd4, 0x78, 0xb0, 0xd7, 0x60, 0xad, 0x6f, 0x7b, 0x8e, 0x2e, 0x19, 0xcc, 0xf9, 0x48, 0xa2, 0xea, 0xf3, 0x61, 0x9c, 0x3f, 0x49, 0x98, 0xff, 0x1b}, {0xb8, 0x79, 0x93, 0x69, 0x71, 0xde, 0xb4, 0x1e, 0x28, 0xc6, 0xb0, 0x84, 0xa7, 0xad, 0x31, 0x16, 0xcc, 0x74, 0xfa, 0x06, 0x00, 0x52, 0xaf, 0x00, 0x83, 0x2a, 0xc5, 0x9a, 0x48, 0x0f, 0x97, 0x14}}, + {{0x6c, 0xc3, 0x7b, 0xb0, 0xa2, 0x8c, 0x5d, 0x58, 0x53, 0x31, 0xfb, 0xb3, 0x5b, 0x12, 0x0e, 0x6a, 0xe5, 0x48, 0x1c, 0xa3, 0xd8, 0x99, 0x56, 0x16, 0xcd, 0x2e, 0x3d, 0x2d, 0x43, 0x28, 0x90, 0x0c}, {0x53, 0x05, 0x9f, 0x0a, 0xaa, 0xc3, 0xb6, 0x37, 0x06, 0x09, 0x31, 0x3b, 0x83, 0x7c, 0x5f, 0xe7, 0xf0, 0x80, 0xdd, 0xfe, 0x59, 0x13, 0x28, 0x0b, 0xe7, 0x2a, 0xe4, 0x78, 0x1d, 0xf2, 0xea, 0x2a}}, + {{0xbb, 0xab, 0x98, 0xf0, 0x92, 0xb4, 0x05, 0xf9, 0xb9, 0xfb, 0x3d, 0x15, 0xad, 0x32, 0xe7, 0x91, 0x6e, 0x95, 0x6f, 0xc2, 0x3d, 0x9b, 0xb7, 0x23, 0x02, 0x08, 0xde, 0xb4, 0x99, 0x69, 0xa8, 0x30}, {0x80, 0xce, 0x1a, 0xef, 0x4a, 0x1e, 0x98, 0xab, 0xf7, 0x76, 0x7f, 0xcc, 0xb7, 0x1a, 0x6a, 0x3e, 0xbd, 0x24, 0xa9, 0xb0, 0x90, 0xac, 0xfc, 0xfc, 0xf0, 0xd9, 0x64, 0xb3, 0x1a, 0x7b, 0x0c, 0x29}}, + {{0x10, 0x23, 0x95, 0x14, 0x03, 0x59, 0xd2, 0x89, 0x02, 0x9b, 0xfe, 0xe3, 0x93, 0x47, 0xf6, 0xb8, 0xed, 0xdd, 0x48, 0x10, 0x4c, 0x31, 0x98, 0x12, 0x47, 0x5f, 0x87, 0x3f, 0xef, 0x6a, 0xf6, 0x35}, {0x00, 0x9a, 0x0b, 0x4e, 0xec, 0xc9, 0x09, 0x7f, 0xe8, 0xc5, 0x63, 0x8b, 0xa8, 0x58, 0xe5, 0x02, 0x4d, 0xd2, 0x34, 0xeb, 0xab, 0xa2, 0xf2, 0xdf, 0xa5, 0x3e, 0xa5, 0x61, 0xc6, 0x04, 0x2a, 0x18}}, + {{0xc0, 0xc3, 0x8d, 0x5a, 0x48, 0x9a, 0x49, 0x77, 0xa8, 0x54, 0x0b, 0xd6, 0xb7, 0x8b, 0x01, 0x73, 0xd3, 0xf4, 0x34, 0xe1, 0xec, 0x5a, 0x74, 0xbd, 0x25, 0x9f, 0x96, 0x98, 0x40, 0x43, 0xe6, 0x0c}, {0xc9, 0x5a, 0xe8, 0xa5, 0x4a, 0xa9, 0x14, 0xb2, 0xbf, 0x71, 0x5b, 0x2c, 0xdb, 0x00, 0x7b, 0x3a, 0xa7, 0x3e, 0x95, 0x4a, 0xe9, 0x97, 0x1f, 0x1f, 0xc3, 0xbd, 0xf2, 0x90, 0x13, 0x1f, 0xdc, 0x0f}}, + {{0x49, 0x92, 0x34, 0x36, 0x12, 0x37, 0x7b, 0xfd, 0x01, 0xe9, 0x3e, 0xa2, 0xf6, 0x31, 0x9c, 0xb2, 0xb0, 0x19, 0x6a, 0xab, 0xb7, 0x09, 0x8c, 0x42, 0xc3, 0x7f, 0x4a, 0x7f, 0xac, 0x6e, 0xdb, 0x3e}, {0xfe, 0x39, 0xd0, 0x33, 0x62, 0x5f, 0xae, 0x41, 0xae, 0x3f, 0x83, 0x6a, 0xad, 0x2f, 0x1b, 0x35, 0xd6, 0xab, 0x3c, 0xdc, 0x87, 0xde, 0x27, 0xb0, 0xe6, 0xfb, 0xf4, 0x8f, 0x89, 0x6b, 0x3c, 0x1c}}, + {{0x79, 0x73, 0xd7, 0x36, 0xb4, 0xea, 0x79, 0x85, 0x4f, 0x6a, 0xad, 0xa7, 0x0e, 0xf6, 0x76, 0x69, 0xe0, 0x82, 0x7f, 0xbd, 0x86, 0x04, 0x44, 0x4d, 0x33, 0x6b, 0x69, 0xd1, 0x7b, 0x08, 0xdf, 0x33}, {0xb1, 0xe1, 0x04, 0x77, 0x3e, 0x25, 0xae, 0xd8, 0x72, 0xcb, 0xa9, 0x5c, 0x98, 0x3c, 0x80, 0x6c, 0x2a, 0xe7, 0x73, 0x71, 0x94, 0x0a, 0x76, 0x4f, 0x3e, 0xb5, 0x76, 0xa5, 0x2a, 0x3c, 0x49, 0x17}}, + {{0xa8, 0xd2, 0xe5, 0xbe, 0xe3, 0x9c, 0x8d, 0x0d, 0xc7, 0x7e, 0x16, 0x14, 0x32, 0x1e, 0x11, 0x3b, 0x29, 0x24, 0xbc, 0xf7, 0x44, 0x56, 0x6a, 0x86, 0x69, 0x6b, 0x70, 0xd6, 0x5c, 0xe6, 0x53, 0x2f}, {0xb9, 0x54, 0x27, 0x53, 0x8d, 0xa9, 0xbc, 0xc9, 0x52, 0xac, 0x60, 0x33, 0x22, 0x0a, 0x20, 0x1c, 0x67, 0x5f, 0x49, 0x32, 0x1f, 0x44, 0xd1, 0x8f, 0x4c, 0xa0, 0x7a, 0x7b, 0xa6, 0xe7, 0x91, 0x08}}, + {{0x5e, 0xe6, 0x36, 0x33, 0xc2, 0xb0, 0xac, 0x33, 0x80, 0xb2, 0x5f, 0x36, 0xb7, 0xf7, 0xbd, 0xe9, 0x9c, 0x35, 0x24, 0xb1, 0x1c, 0x30, 0xdb, 0x3f, 0xfc, 0x0b, 0xfb, 0x48, 0xa4, 0xf8, 0x5c, 0x22}, {0xf5, 0x37, 0x01, 0x7c, 0x5c, 0x52, 0xd0, 0x7b, 0xac, 0x3c, 0xf5, 0x5e, 0x9e, 0x2e, 0xcc, 0x25, 0x65, 0x58, 0xf6, 0x33, 0xe7, 0x86, 0xbf, 0x0a, 0xfd, 0x34, 0xd5, 0x9b, 0x37, 0xf8, 0xec, 0x25}}, + {{0x39, 0x0d, 0x3a, 0x43, 0xdf, 0x74, 0x59, 0x19, 0xc1, 0x45, 0x66, 0xfe, 0x55, 0xd5, 0x2a, 0xf9, 0xa3, 0x05, 0x67, 0x6b, 0x69, 0xfe, 0x22, 0xde, 0x7f, 0xcf, 0x89, 0x52, 0xcd, 0x33, 0xc6, 0x30}, {0xb9, 0xcd, 0x5b, 0x21, 0xae, 0x06, 0xe2, 0x2d, 0x6f, 0xf0, 0x1c, 0x5d, 0x3a, 0x73, 0xba, 0x1d, 0xb6, 0x07, 0x29, 0x7c, 0x62, 0x05, 0x95, 0x77, 0x5f, 0x29, 0xf8, 0x58, 0x43, 0xa4, 0x05, 0x2e}}, + {{0xe2, 0x27, 0x9e, 0x0e, 0x5a, 0x3e, 0x8d, 0x8c, 0xd5, 0x9a, 0x83, 0x33, 0x34, 0xac, 0xa7, 0x33, 0xf2, 0x27, 0xca, 0x67, 0x88, 0xef, 0x3a, 0x81, 0xea, 0x93, 0x57, 0xaa, 0xc5, 0x82, 0x51, 0x03}, {0x75, 0x9e, 0x19, 0x05, 0x28, 0xd3, 0x7a, 0xe3, 0x8f, 0x4d, 0x25, 0x72, 0xb8, 0xec, 0x92, 0x94, 0x4f, 0x3b, 0xd9, 0x32, 0x58, 0x0d, 0x40, 0xe4, 0x04, 0x0e, 0xde, 0x31, 0x34, 0xf6, 0xd7, 0x23}}, + {{0xc7, 0xd2, 0x7c, 0x8b, 0x4d, 0xfc, 0x93, 0xed, 0x39, 0x10, 0x13, 0x28, 0x2a, 0xe8, 0xf9, 0x2f, 0x82, 0x74, 0xdd, 0x8e, 0x2f, 0x40, 0x41, 0x9b, 0x26, 0x55, 0x7c, 0xe8, 0x8a, 0x40, 0xe8, 0x2d}, {0x5b, 0x6f, 0x78, 0x90, 0xee, 0x7a, 0x82, 0x84, 0x6f, 0x8a, 0xa9, 0x7a, 0xcc, 0x1a, 0xa5, 0xfc, 0x41, 0x76, 0xb1, 0x1f, 0xd8, 0xc0, 0x26, 0x3b, 0x4f, 0xce, 0x30, 0x34, 0xa5, 0xcf, 0x97, 0x1e}}, + {{0x4b, 0x2e, 0x30, 0xdd, 0x6f, 0x3f, 0xd8, 0x28, 0x62, 0xb1, 0x48, 0xdf, 0x16, 0x16, 0x33, 0x8b, 0xc6, 0xd5, 0xbe, 0xab, 0x0b, 0x7f, 0x66, 0xeb, 0x2d, 0x99, 0x00, 0x2f, 0x7d, 0x9f, 0xb4, 0x1b}, {0x8f, 0x5b, 0x75, 0x59, 0x85, 0x25, 0x1b, 0x8f, 0xa4, 0x49, 0x44, 0xac, 0x45, 0x56, 0x2a, 0x99, 0x8e, 0x87, 0x8a, 0x37, 0x78, 0xa7, 0xf8, 0xc7, 0x14, 0x2f, 0x9a, 0xaa, 0x95, 0xd4, 0x88, 0x23}}, + {{0x5c, 0xe1, 0xa6, 0xcc, 0x2b, 0x83, 0xee, 0xb3, 0xb0, 0xf5, 0x9c, 0xd0, 0x76, 0x09, 0x2e, 0x30, 0x90, 0x05, 0xca, 0x07, 0x11, 0xc9, 0x73, 0x3b, 0xe5, 0x20, 0x2a, 0xe3, 0x9d, 0x72, 0x33, 0x10}, {0x97, 0xfb, 0xab, 0x62, 0xc9, 0x03, 0x4d, 0x82, 0x48, 0xda, 0xa4, 0xfc, 0xc3, 0x05, 0x76, 0x33, 0x7b, 0xeb, 0xb1, 0xc1, 0x92, 0x5b, 0x38, 0xd9, 0x53, 0x03, 0xd7, 0x9d, 0x3b, 0xd5, 0xe9, 0x04}}, + {{0x89, 0x1b, 0xfe, 0x2b, 0xea, 0xce, 0x31, 0x2a, 0xb2, 0xfa, 0xed, 0x3e, 0x64, 0x78, 0x9c, 0x45, 0xf7, 0x21, 0x08, 0x9a, 0xda, 0xeb, 0x15, 0x80, 0x38, 0x8f, 0x2e, 0xed, 0x48, 0x5d, 0x76, 0x31}, {0x67, 0xa5, 0x00, 0x22, 0x2e, 0xe1, 0xd2, 0xbb, 0x61, 0x31, 0xc9, 0x60, 0x8e, 0x8b, 0x7e, 0xee, 0x7f, 0xa1, 0x1e, 0xb5, 0xa8, 0x13, 0x50, 0x44, 0x0f, 0x60, 0x3f, 0x41, 0x3d, 0xea, 0xb3, 0x3f}}, + {{0x99, 0x54, 0xaf, 0x65, 0xbb, 0xe1, 0x92, 0x57, 0xdb, 0x90, 0xd1, 0xd9, 0xce, 0xec, 0x8e, 0xf3, 0xed, 0xa1, 0xf9, 0xae, 0x7f, 0x77, 0x2e, 0x78, 0xf4, 0x89, 0x7e, 0xd4, 0xf6, 0x1a, 0x75, 0x32}, {0xac, 0x9f, 0x9c, 0xd7, 0x57, 0x86, 0x58, 0x05, 0xaa, 0x3f, 0x97, 0xc7, 0x59, 0xfa, 0xfc, 0x4c, 0x25, 0xe0, 0x3a, 0x3e, 0x9c, 0x52, 0xec, 0x46, 0x90, 0xb5, 0xfe, 0x1c, 0xc7, 0x9f, 0x88, 0x2e}}, + {{0xcf, 0x98, 0xdf, 0x27, 0x89, 0x5a, 0x36, 0x4f, 0xd4, 0x90, 0xdf, 0xe1, 0x2a, 0xad, 0x4d, 0xdc, 0xa6, 0xa3, 0x34, 0xf5, 0xc9, 0xf8, 0xc7, 0xe8, 0xb1, 0x88, 0x6f, 0x54, 0x72, 0xdb, 0x53, 0x1f}, {0x8e, 0x45, 0xf3, 0x64, 0x10, 0xf7, 0x21, 0xc5, 0x44, 0xca, 0xeb, 0xb4, 0x13, 0xb8, 0xf4, 0x55, 0xf7, 0xc1, 0xc2, 0x69, 0xa1, 0xfc, 0xbe, 0x1f, 0x08, 0xdb, 0x69, 0x05, 0xd0, 0x72, 0x70, 0x32}}, + {{0x0a, 0xc3, 0x34, 0x45, 0x5e, 0xbf, 0x1c, 0xe5, 0x9b, 0xac, 0x82, 0x5b, 0xfe, 0x38, 0x11, 0x9f, 0x40, 0x67, 0xc9, 0x64, 0x8e, 0x61, 0xe5, 0x31, 0x1f, 0xae, 0x65, 0x80, 0x08, 0xa0, 0x26, 0x16}, {0x2b, 0x3b, 0x62, 0x03, 0xca, 0x35, 0x4f, 0x4e, 0x66, 0xca, 0x43, 0x4b, 0xc7, 0x4e, 0x9e, 0x58, 0x79, 0x17, 0x39, 0x97, 0x52, 0xa8, 0xfc, 0xad, 0xfc, 0xb4, 0x7f, 0x30, 0xc2, 0xc8, 0xc9, 0x3e}}, + {{0xc5, 0xfc, 0x26, 0x2b, 0x72, 0x17, 0x58, 0xe5, 0x6b, 0xbc, 0xd7, 0x57, 0xc7, 0x78, 0xd2, 0x8c, 0x13, 0x8c, 0x83, 0x56, 0xd7, 0x0e, 0x6f, 0x21, 0xef, 0x67, 0xa1, 0x0c, 0x14, 0xb2, 0xad, 0x2b}, {0x74, 0x5d, 0xe4, 0xbd, 0xac, 0x54, 0x8e, 0x7b, 0x2b, 0xef, 0x85, 0xf0, 0x08, 0xee, 0x2b, 0xf1, 0xba, 0x7c, 0xb3, 0x9b, 0x38, 0xcb, 0xbe, 0x59, 0x05, 0x32, 0x89, 0xd2, 0x3a, 0xe5, 0xc2, 0x10}}, + {{0x2b, 0x92, 0xcc, 0xa2, 0x73, 0x60, 0xbf, 0x05, 0xf5, 0xa6, 0x61, 0xc1, 0xb1, 0xa1, 0x40, 0xaa, 0xbe, 0xf2, 0xb3, 0xd7, 0x99, 0xa1, 0xaa, 0xe7, 0x76, 0x53, 0x5b, 0xff, 0x5a, 0x89, 0xc8, 0x2e}, {0x34, 0xad, 0x37, 0x5c, 0x6f, 0x2a, 0xa9, 0x21, 0x54, 0xd3, 0x30, 0x4c, 0x7e, 0x8f, 0xd0, 0x9e, 0xf0, 0xdd, 0xd0, 0x73, 0x6b, 0xae, 0x92, 0x0c, 0x24, 0x85, 0xd8, 0xf6, 0xc9, 0xe3, 0xaf, 0x02}}, + {{0x5f, 0x44, 0xf7, 0x2e, 0x63, 0x1c, 0x64, 0xa3, 0xe9, 0x06, 0x17, 0xab, 0x41, 0x44, 0x01, 0x16, 0x5c, 0x6d, 0x68, 0xd2, 0xdd, 0xe5, 0x0c, 0x5e, 0xb2, 0x49, 0x5a, 0x58, 0x56, 0xbd, 0x62, 0x29}, {0x90, 0xc4, 0x08, 0x69, 0x12, 0x39, 0x33, 0x8f, 0xc6, 0xf2, 0xfb, 0xf6, 0xa1, 0x01, 0x37, 0xb3, 0x7e, 0x58, 0xa1, 0xd5, 0x95, 0xed, 0x5d, 0x5b, 0xfa, 0xdc, 0x0b, 0x9d, 0xc9, 0x30, 0x5a, 0x17}}, + {{0xec, 0x84, 0x89, 0xaa, 0x5c, 0x0b, 0x82, 0xf9, 0x00, 0x00, 0xf7, 0x04, 0x8a, 0x6f, 0xd5, 0x8c, 0x68, 0xc6, 0xe6, 0x42, 0x43, 0x1e, 0xbf, 0x45, 0x83, 0x0c, 0xc8, 0xcf, 0xf2, 0x5e, 0x33, 0x2b}, {0x4c, 0xeb, 0x73, 0xa9, 0x9a, 0x8c, 0x8e, 0xd2, 0xb8, 0x5e, 0x65, 0xc5, 0x3c, 0x63, 0x8d, 0xfc, 0x60, 0x24, 0xf8, 0xb1, 0x8f, 0x80, 0xf8, 0x49, 0x6c, 0xe5, 0x32, 0xc7, 0x92, 0x24, 0xdf, 0x26}}, + {{0xdf, 0x15, 0x10, 0xed, 0x4a, 0xe1, 0x02, 0xcc, 0x32, 0x1b, 0x48, 0x61, 0xda, 0xe6, 0xb2, 0x7a, 0x1f, 0x7c, 0x59, 0x79, 0xf5, 0xcc, 0xb8, 0xf1, 0xd4, 0x87, 0xa5, 0xd2, 0x76, 0x1c, 0x39, 0x1f}, {0x78, 0xc0, 0x00, 0xc9, 0x3c, 0x8e, 0x61, 0x61, 0x06, 0xca, 0xb8, 0x5d, 0xda, 0xd2, 0x51, 0x80, 0x59, 0x7e, 0x81, 0x4a, 0xa6, 0xbb, 0x0c, 0xf0, 0xa4, 0x28, 0x61, 0x99, 0x79, 0xf2, 0x12, 0x02}}, + {{0x2d, 0x35, 0xd1, 0x1e, 0xa4, 0xbe, 0x12, 0xba, 0x06, 0x4e, 0x74, 0x30, 0x38, 0x12, 0x2a, 0xc7, 0x1e, 0x52, 0xce, 0x7b, 0x80, 0x46, 0x4b, 0x77, 0x44, 0x19, 0x83, 0x44, 0x07, 0xf3, 0x55, 0x1b}, {0x56, 0xf7, 0x99, 0x71, 0xb5, 0x05, 0x39, 0x43, 0xcd, 0x18, 0x74, 0x83, 0xd2, 0xa2, 0x18, 0x50, 0x3f, 0xe3, 0x2c, 0x48, 0x35, 0x37, 0x69, 0xc3, 0x22, 0xed, 0x35, 0xe9, 0xc4, 0x33, 0xd1, 0x06}}, + {{0x6b, 0x9a, 0xf8, 0x42, 0x55, 0xe0, 0xd2, 0x17, 0x11, 0x99, 0x4a, 0x83, 0x2c, 0x57, 0xc4, 0x63, 0xb9, 0x06, 0xe9, 0x30, 0x7d, 0x19, 0x98, 0x7c, 0x73, 0xa7, 0x1c, 0x7b, 0x9c, 0x0e, 0xb8, 0x1b}, {0xdd, 0x82, 0xdd, 0xf5, 0x77, 0x56, 0x7f, 0x75, 0x2b, 0x18, 0xbb, 0x57, 0x92, 0x53, 0x30, 0x60, 0xf2, 0x46, 0x3b, 0x49, 0x11, 0xe7, 0xe8, 0x22, 0x39, 0x63, 0x07, 0x11, 0x6c, 0x9d, 0x62, 0x24}}, + {{0xfa, 0x67, 0x48, 0x0d, 0x07, 0x00, 0x27, 0xc2, 0x4c, 0x16, 0x5a, 0x8e, 0xed, 0xa6, 0x14, 0x5a, 0xdc, 0xa4, 0xfa, 0xe4, 0x9b, 0x97, 0x1b, 0xf3, 0xe1, 0x2f, 0x8a, 0xae, 0x32, 0x9c, 0x60, 0x22}, {0x7a, 0x6c, 0xba, 0x36, 0x59, 0xcd, 0xbe, 0xcb, 0xe0, 0x39, 0xb9, 0xdd, 0x86, 0x77, 0x8f, 0x76, 0x23, 0xe1, 0x06, 0xe2, 0x03, 0x86, 0xe0, 0x8e, 0x52, 0x98, 0xad, 0x19, 0x3e, 0xbb, 0xf1, 0x14}}, + {{0x8a, 0x1f, 0x5e, 0x86, 0xfe, 0xd0, 0xcc, 0x36, 0x83, 0x01, 0x9b, 0x2f, 0xf1, 0x6d, 0x2a, 0xd1, 0x58, 0x37, 0x75, 0x80, 0x86, 0x79, 0xc1, 0x8f, 0xa6, 0x5f, 0xb2, 0xfe, 0x92, 0xa7, 0x0a, 0x23}, {0xe0, 0xba, 0xc0, 0x0c, 0xcd, 0xa5, 0x89, 0x24, 0x76, 0x46, 0x4f, 0x92, 0xd3, 0xc5, 0x0d, 0x6f, 0x71, 0x9b, 0x34, 0x97, 0x02, 0x65, 0x2a, 0xea, 0xed, 0x40, 0xcd, 0x6b, 0xb5, 0x75, 0x96, 0x25}}, + {{0xb0, 0x6c, 0xce, 0x14, 0xf6, 0xad, 0x11, 0xc1, 0x92, 0x00, 0xb9, 0xba, 0x21, 0x0e, 0xba, 0x4a, 0xd0, 0xea, 0x39, 0x1d, 0xdc, 0xd9, 0xe9, 0x99, 0x84, 0xea, 0x15, 0x92, 0xc6, 0x4e, 0x84, 0x1d}, {0x28, 0x3a, 0xd6, 0x34, 0xce, 0x32, 0x5f, 0x66, 0xda, 0x51, 0xf3, 0xb4, 0xaf, 0x7f, 0x6d, 0x16, 0x37, 0x08, 0x3a, 0x4a, 0xc9, 0x1d, 0xf2, 0x71, 0x07, 0x7a, 0x02, 0xd8, 0x75, 0xdd, 0xbd, 0x1c}}, + {{0x44, 0x34, 0x07, 0xb4, 0x4f, 0x0c, 0x16, 0xbb, 0xf7, 0xa4, 0x00, 0xac, 0x61, 0x3c, 0x4f, 0x4f, 0x8b, 0x98, 0x2b, 0x01, 0x1a, 0x27, 0x3a, 0x3c, 0x10, 0xae, 0xd3, 0x2b, 0x60, 0x41, 0x4d, 0x1b}, {0x5b, 0xb2, 0xf7, 0x22, 0x12, 0x91, 0xf2, 0x61, 0x64, 0x23, 0xdf, 0xd3, 0xe7, 0xee, 0xe6, 0xd2, 0x96, 0x9b, 0xef, 0xa1, 0xe6, 0x24, 0x6e, 0x15, 0x19, 0x94, 0x98, 0x2b, 0xf6, 0xb4, 0xc4, 0x2c}}, + {{0x52, 0x50, 0x99, 0xcf, 0x9e, 0x37, 0xad, 0x90, 0x0f, 0xf1, 0x2e, 0x45, 0x06, 0x5b, 0xd3, 0xfd, 0x47, 0x58, 0xd6, 0xcc, 0xe1, 0x9f, 0x31, 0x32, 0x7d, 0x15, 0x9b, 0x6f, 0x5c, 0x0e, 0xd6, 0x37}, {0x11, 0x36, 0x11, 0x8a, 0x6d, 0x4b, 0x5e, 0xef, 0x8f, 0xe6, 0x19, 0x97, 0xed, 0x8a, 0xf2, 0xff, 0x86, 0x4b, 0xc5, 0x2b, 0x04, 0xf7, 0x22, 0x00, 0x0f, 0x15, 0xa0, 0x87, 0x39, 0x17, 0xd1, 0x24}}, + {{0x29, 0xdf, 0x76, 0x5b, 0x04, 0xa0, 0xb6, 0x67, 0xc5, 0x72, 0xd1, 0x5d, 0x58, 0x77, 0x80, 0xd7, 0x47, 0x61, 0x47, 0x1b, 0xda, 0xba, 0x94, 0xfd, 0x75, 0x79, 0xb1, 0x3b, 0x12, 0xef, 0x5a, 0x05}, {0x59, 0x00, 0xfd, 0xb6, 0x14, 0x79, 0x0d, 0xc4, 0xcf, 0xc0, 0x21, 0x96, 0xe5, 0x03, 0x4b, 0xcd, 0xb4, 0x5c, 0x1b, 0xaa, 0x59, 0x39, 0x04, 0x58, 0x5c, 0x9f, 0x3c, 0x33, 0x93, 0x7d, 0x9e, 0x39}}, + {{0xf3, 0xa8, 0xf3, 0x6f, 0xb6, 0x36, 0x87, 0xe9, 0x29, 0x1c, 0xd0, 0xe2, 0x7c, 0x6b, 0x33, 0xb6, 0x94, 0x85, 0x71, 0xe8, 0x38, 0xe1, 0xb5, 0x72, 0x94, 0x2d, 0x59, 0xf7, 0xf0, 0x1a, 0xe3, 0x39}, {0x91, 0x69, 0xe9, 0xa9, 0xd2, 0xaa, 0x84, 0x25, 0xf8, 0x00, 0xa0, 0x57, 0xb6, 0xc9, 0x67, 0x4d, 0x6b, 0xf6, 0x5d, 0x24, 0x39, 0x7c, 0xef, 0x1f, 0xce, 0x13, 0x0e, 0xb6, 0xf5, 0x61, 0xa5, 0x39}}, + {{0x7d, 0x2e, 0x9d, 0x67, 0xb3, 0x2b, 0xa8, 0x12, 0x6e, 0x26, 0x92, 0xcf, 0x9d, 0x94, 0x23, 0x79, 0x46, 0xa7, 0xda, 0x8e, 0xd1, 0xe0, 0x97, 0xb9, 0x9d, 0x91, 0x7a, 0x93, 0xbf, 0xd4, 0x22, 0x27}, {0x91, 0x73, 0x79, 0x5c, 0xfd, 0x3a, 0xc8, 0xdc, 0xac, 0x98, 0x33, 0xa7, 0x3d, 0x83, 0xa7, 0x25, 0x8b, 0x3f, 0x0f, 0xc0, 0x3f, 0x90, 0x2e, 0xd8, 0x1a, 0xb4, 0x3f, 0x26, 0xe6, 0x7a, 0xb2, 0x20}}, + {{0xab, 0xaa, 0xec, 0x52, 0x2a, 0xec, 0x97, 0xef, 0x32, 0x05, 0x4c, 0xb8, 0x73, 0x0e, 0x56, 0x64, 0xbc, 0x9d, 0x64, 0x21, 0x1e, 0x0f, 0x2e, 0xf4, 0x9b, 0x42, 0x3b, 0x3e, 0x9b, 0x76, 0x2d, 0x36}, {0xc7, 0x07, 0x29, 0x82, 0xd4, 0x45, 0x49, 0xa8, 0x24, 0xeb, 0xfd, 0x9d, 0x9a, 0x31, 0x19, 0x83, 0x47, 0x9d, 0x2f, 0x83, 0xbd, 0x33, 0x53, 0x1b, 0xeb, 0x14, 0x0e, 0x44, 0x05, 0x46, 0x8d, 0x1a}}, + {{0x84, 0xc4, 0x0e, 0x52, 0x55, 0xf0, 0xfe, 0x2c, 0x89, 0x85, 0x10, 0x5e, 0xd9, 0x1a, 0x9b, 0xd3, 0x08, 0x4b, 0x02, 0x81, 0xa7, 0x3b, 0xaf, 0x1a, 0x09, 0x60, 0xfe, 0x22, 0x28, 0xc6, 0xc3, 0x39}, {0xac, 0x67, 0x32, 0x22, 0x4e, 0x89, 0xf8, 0x45, 0x79, 0xd8, 0xf2, 0x94, 0xd4, 0x0e, 0x96, 0x42, 0x28, 0xa6, 0x2e, 0x0a, 0x75, 0x59, 0xc3, 0x91, 0xd8, 0xb9, 0xa2, 0x2e, 0x58, 0x3f, 0x55, 0x00}}, + {{0x4c, 0xa2, 0x8d, 0x73, 0xf4, 0x97, 0xd7, 0x9d, 0x58, 0x31, 0x90, 0x33, 0xca, 0x7d, 0x59, 0x27, 0x88, 0x39, 0xe1, 0x55, 0x2d, 0xcf, 0x69, 0x25, 0xc7, 0xec, 0x5a, 0x85, 0x03, 0x44, 0x35, 0x3a}, {0x58, 0x8d, 0x21, 0x24, 0xdf, 0x53, 0xd4, 0x8c, 0xba, 0x7b, 0xdf, 0x39, 0x6a, 0x60, 0xb8, 0x3e, 0x04, 0x2c, 0x6d, 0x01, 0xcd, 0xb3, 0xb6, 0xe1, 0x59, 0x28, 0x2f, 0x12, 0x01, 0x1e, 0xc0, 0x2a}}, + {{0xef, 0xbb, 0x74, 0xee, 0xc3, 0xbe, 0xee, 0x05, 0x20, 0x76, 0x61, 0xd2, 0xb6, 0xbe, 0x35, 0x92, 0xfd, 0x92, 0x4f, 0xc3, 0x9b, 0xe8, 0x1b, 0xbe, 0x8b, 0xb8, 0x2c, 0x75, 0x1c, 0xf0, 0x52, 0x3e}, {0x53, 0xaf, 0x8a, 0xcd, 0xca, 0x51, 0xa9, 0xf3, 0x43, 0xc3, 0x7e, 0x09, 0xe4, 0x97, 0x4a, 0xc7, 0x22, 0x9a, 0xfc, 0xbf, 0x05, 0x9e, 0x2e, 0x09, 0x39, 0xba, 0xe3, 0x11, 0xc8, 0x5f, 0x5a, 0x3d}}, + {{0x58, 0x3a, 0x38, 0xd5, 0x2c, 0x3d, 0xe5, 0x0c, 0x2f, 0xe7, 0xa3, 0x6c, 0x32, 0xeb, 0xf1, 0x3e, 0x9b, 0xfc, 0x98, 0x76, 0x88, 0x76, 0x78, 0x3c, 0xc6, 0xc6, 0xd2, 0x49, 0xd7, 0xca, 0x74, 0x3e}, {0xd5, 0x13, 0x97, 0x0c, 0xed, 0xfa, 0x1c, 0x1f, 0x78, 0x18, 0x3b, 0xd4, 0xd9, 0xcd, 0x44, 0x3c, 0xbe, 0x8d, 0xa6, 0x45, 0xe2, 0x49, 0x9e, 0xa9, 0x90, 0x2e, 0x57, 0x67, 0xac, 0x8b, 0x13, 0x3d}}, + {{0x2f, 0xc7, 0x6e, 0xd7, 0x35, 0xda, 0xf7, 0x83, 0xe5, 0x06, 0x9e, 0x35, 0xe6, 0x36, 0x1b, 0x5d, 0x07, 0x15, 0x08, 0x0e, 0x98, 0xa1, 0x67, 0x44, 0x58, 0xfc, 0xcf, 0x12, 0xd4, 0xe9, 0x16, 0x34}, {0x65, 0x77, 0xd4, 0x8e, 0x07, 0x09, 0x30, 0x27, 0x90, 0x7d, 0x2b, 0x91, 0xb4, 0x0a, 0x22, 0xb0, 0xc9, 0xe9, 0x19, 0x63, 0x2b, 0xbc, 0x16, 0xb4, 0x2c, 0x34, 0x9a, 0xa1, 0xcc, 0xd4, 0xfa, 0x10}}, + {{0x4f, 0x88, 0x21, 0x91, 0x94, 0x27, 0xce, 0xa6, 0x44, 0x8e, 0xe8, 0x02, 0x8f, 0xa1, 0xa8, 0x92, 0xe9, 0x43, 0x95, 0x39, 0xd1, 0x04, 0xdf, 0xca, 0x76, 0x17, 0x7e, 0xa2, 0x7c, 0x98, 0xf2, 0x35}, {0x63, 0xf8, 0xd8, 0xe5, 0xa3, 0x1e, 0x73, 0x4f, 0x28, 0x80, 0xcb, 0xda, 0xc9, 0xb1, 0xfa, 0xbe, 0xd4, 0x02, 0x4e, 0xab, 0xef, 0xd4, 0xbd, 0x91, 0xec, 0x47, 0xb8, 0x6c, 0x5e, 0x3c, 0xea, 0x39}}, + {{0x26, 0xa5, 0x40, 0x90, 0x38, 0xd6, 0x0e, 0xba, 0x2f, 0xce, 0x46, 0x10, 0x2d, 0x6a, 0xe3, 0xad, 0xda, 0xbf, 0x63, 0x7d, 0x1f, 0x03, 0xc4, 0x07, 0x4b, 0x6d, 0xf1, 0xef, 0xe5, 0x7f, 0x05, 0x37}, {0x4f, 0x7d, 0x0f, 0x23, 0x9a, 0xda, 0x3d, 0xcb, 0x2c, 0xe2, 0xc4, 0xac, 0xc7, 0xfa, 0xc2, 0x3e, 0xca, 0x52, 0x22, 0x60, 0xc8, 0x83, 0xbc, 0x09, 0x50, 0x18, 0x90, 0x7b, 0x69, 0xc1, 0xd7, 0x01}}, + {{0x8b, 0xaa, 0x62, 0x70, 0x75, 0x22, 0x16, 0x03, 0x68, 0xeb, 0x01, 0xc3, 0x78, 0xbf, 0xe7, 0x06, 0xfe, 0xe8, 0x8d, 0x51, 0x8c, 0xea, 0x45, 0x5a, 0x16, 0x5a, 0xd8, 0xfd, 0x76, 0xf1, 0x8b, 0x1a}, {0xa9, 0x3d, 0x61, 0x62, 0x97, 0xed, 0xe4, 0x1d, 0x8e, 0xc5, 0xa5, 0x75, 0x5b, 0x26, 0x2d, 0x7c, 0x3c, 0x49, 0xa6, 0x13, 0xe1, 0x84, 0xcf, 0xde, 0xd9, 0x1a, 0x18, 0xfc, 0xac, 0xc9, 0x53, 0x18}}, + {{0x7a, 0x85, 0x5c, 0xda, 0x90, 0xf6, 0xf8, 0x18, 0x66, 0x4c, 0x7a, 0xf4, 0x54, 0x5e, 0xaf, 0x8b, 0x87, 0xe4, 0x56, 0x90, 0xdb, 0x5a, 0x96, 0xc5, 0x23, 0x47, 0x0b, 0xc5, 0x4f, 0x5e, 0x41, 0x0b}, {0x33, 0x52, 0xc1, 0xd1, 0x8b, 0x8e, 0x58, 0xf7, 0x4e, 0xa0, 0x1e, 0x7b, 0x2d, 0x51, 0xb8, 0x3b, 0xda, 0x73, 0xda, 0xb3, 0x10, 0x0e, 0x82, 0x37, 0xaf, 0xe0, 0x5a, 0x01, 0x26, 0x10, 0x2a, 0x2c}}, + {{0xfa, 0x38, 0x40, 0xab, 0xa2, 0x0d, 0x91, 0xc4, 0xb0, 0x4b, 0x17, 0x21, 0xf6, 0x0b, 0x19, 0x89, 0x31, 0x1c, 0x70, 0xfe, 0x46, 0x33, 0xb6, 0x11, 0x50, 0x93, 0x3f, 0x58, 0x81, 0xfd, 0xe3, 0x01}, {0x1e, 0x60, 0xc1, 0x98, 0xc0, 0x17, 0x61, 0xdc, 0x1e, 0xf8, 0x5e, 0xe4, 0x7b, 0xa2, 0xb5, 0x1a, 0x12, 0x16, 0x7e, 0xf3, 0x16, 0x3f, 0xa2, 0x52, 0xcf, 0xe6, 0xe2, 0x97, 0x80, 0x7f, 0x0a, 0x0b}}, + {{0xa4, 0xe7, 0x8a, 0xe7, 0x2f, 0x06, 0x0b, 0x52, 0x5e, 0xe1, 0xc5, 0x15, 0xc9, 0x2a, 0xfd, 0x3c, 0x42, 0xd5, 0xc1, 0x41, 0x82, 0x0d, 0x6f, 0x6f, 0x32, 0x9f, 0x13, 0x60, 0xb4, 0xbb, 0x45, 0x3d}, {0x79, 0x38, 0x7a, 0xc9, 0x97, 0x5c, 0xac, 0xb1, 0x21, 0x53, 0xab, 0x56, 0xf2, 0xc0, 0x0c, 0xef, 0xc6, 0x60, 0x84, 0xe1, 0x6f, 0x37, 0x2a, 0x62, 0xb5, 0x32, 0x4c, 0x37, 0xfd, 0x7e, 0x29, 0x05}}, + {{0x0a, 0xc6, 0x5f, 0x4c, 0x73, 0x49, 0x26, 0xc2, 0xe6, 0x50, 0x5a, 0xb1, 0x28, 0x2f, 0x93, 0xda, 0xd4, 0xce, 0x75, 0x9c, 0x13, 0xe4, 0xe7, 0xcc, 0x0c, 0xca, 0xf3, 0x84, 0xdf, 0x7e, 0x0a, 0x2a}, {0xc6, 0xe9, 0x51, 0xcf, 0x4d, 0xae, 0xe9, 0x97, 0x62, 0xeb, 0xf8, 0x34, 0x76, 0x6a, 0x63, 0x77, 0xd7, 0x84, 0xd6, 0x15, 0x1f, 0x73, 0xdb, 0xc1, 0x80, 0x22, 0x11, 0x28, 0xa0, 0x45, 0xae, 0x28}}, + {{0x06, 0xf9, 0x6f, 0x52, 0x04, 0x79, 0xe1, 0x48, 0x5d, 0xd2, 0x18, 0x31, 0xaf, 0x96, 0xfd, 0xd5, 0x85, 0x3e, 0x5a, 0x29, 0x79, 0x13, 0xf2, 0x16, 0x65, 0xf0, 0x09, 0x12, 0x82, 0x66, 0x6e, 0x05}, {0x53, 0x48, 0xf0, 0x18, 0x0c, 0x3b, 0x09, 0x4d, 0xed, 0x36, 0x57, 0xc7, 0xcf, 0xae, 0x8c, 0xf2, 0x9b, 0xa6, 0x6f, 0x96, 0xba, 0x3c, 0x24, 0x01, 0x95, 0xe1, 0xf4, 0xa8, 0xd1, 0x69, 0xf0, 0x2b}}, + {{0x18, 0x8c, 0x7a, 0x3f, 0xa3, 0x2c, 0xab, 0xa2, 0xee, 0x3f, 0x2c, 0x29, 0x9e, 0x9a, 0xbf, 0x5f, 0x6f, 0xbf, 0xd4, 0x62, 0x9b, 0xfb, 0xd2, 0x42, 0xa8, 0xb2, 0x19, 0x50, 0xc4, 0x87, 0x13, 0x15}, {0x92, 0x8f, 0x9d, 0x70, 0x99, 0x0a, 0xde, 0x45, 0x51, 0x2d, 0x8c, 0xf1, 0x2b, 0xc6, 0x3b, 0x01, 0xb5, 0xa5, 0x51, 0xe4, 0x77, 0xe4, 0x17, 0xdc, 0xfa, 0xcc, 0x48, 0x27, 0xb3, 0xe9, 0x9b, 0x18}}, + {{0x97, 0x36, 0x38, 0xc3, 0xc0, 0x10, 0xd2, 0xb1, 0x1e, 0x9f, 0x98, 0x0a, 0xf0, 0x1f, 0xe9, 0xdd, 0x0b, 0xae, 0xc4, 0xfa, 0x11, 0x55, 0xb1, 0x57, 0x3a, 0xfb, 0xa9, 0xed, 0x09, 0x55, 0x15, 0x34}, {0xa0, 0xf2, 0x04, 0x4d, 0xe4, 0xa0, 0x36, 0x03, 0x68, 0x11, 0x1d, 0xf5, 0x30, 0x80, 0x38, 0x0c, 0xb6, 0x52, 0x9b, 0x35, 0x18, 0x02, 0x88, 0xdb, 0x04, 0x19, 0x29, 0x37, 0x54, 0x79, 0x69, 0x16}}, + {{0x46, 0xd6, 0x15, 0x2e, 0x39, 0x4d, 0x54, 0xf7, 0xfe, 0xbf, 0x5c, 0xe7, 0xb5, 0x85, 0x2c, 0x04, 0x1e, 0x37, 0xa3, 0xc3, 0xe1, 0xc7, 0x8b, 0xe3, 0xfd, 0x3f, 0x55, 0x39, 0x54, 0x49, 0x78, 0x1f}, {0x55, 0xfe, 0x95, 0xce, 0xef, 0x03, 0xb0, 0xb3, 0x21, 0xa2, 0x43, 0x3e, 0x20, 0xf0, 0x47, 0x34, 0xa7, 0xa4, 0x01, 0xf1, 0x00, 0x5b, 0xec, 0xd3, 0xbb, 0xe9, 0xca, 0xfd, 0x55, 0xfb, 0xaf, 0x1d}}, + {{0x71, 0x57, 0x43, 0x3b, 0xe4, 0xb2, 0x22, 0xd0, 0xa9, 0x5f, 0xae, 0x0d, 0x73, 0x80, 0x98, 0x1f, 0x79, 0x22, 0x9d, 0xee, 0xae, 0x1d, 0x9c, 0xa1, 0xe2, 0xfb, 0x8a, 0x1f, 0xf1, 0x10, 0x7c, 0x2d}, {0x51, 0x9e, 0xc6, 0xe5, 0xc4, 0x4d, 0x3e, 0xe5, 0xc3, 0xbf, 0x3c, 0xe7, 0x7b, 0x1c, 0xf4, 0x2a, 0x18, 0x70, 0x8b, 0x6a, 0x36, 0x11, 0xe0, 0xf0, 0xbf, 0xfc, 0x77, 0x8c, 0xc8, 0x44, 0x77, 0x0b}}, + {{0xb9, 0xbc, 0x40, 0x3b, 0x62, 0xbe, 0xd7, 0x9e, 0x96, 0xeb, 0xdf, 0x58, 0x60, 0xf6, 0x31, 0x3e, 0x0d, 0x43, 0x31, 0x63, 0xc1, 0x90, 0x58, 0x01, 0xa9, 0x64, 0x86, 0xf1, 0xae, 0x7e, 0xad, 0x21}, {0x0b, 0xf6, 0x57, 0xde, 0xd6, 0x85, 0x97, 0x49, 0x61, 0x28, 0x6b, 0xc4, 0x1d, 0x9c, 0x83, 0x3a, 0x9a, 0xdf, 0xcd, 0xe1, 0x0e, 0xad, 0xa4, 0xae, 0xb2, 0x53, 0x0b, 0x1d, 0x0e, 0x29, 0x72, 0x24}}, + {{0xcf, 0xd3, 0xb0, 0x1e, 0x84, 0x32, 0x3e, 0xa7, 0x57, 0xcd, 0xcb, 0x16, 0xb8, 0xc1, 0xd2, 0x5d, 0xb6, 0x66, 0xc2, 0xa9, 0x59, 0x78, 0x16, 0xac, 0xdc, 0x5f, 0x2f, 0xee, 0x80, 0x2f, 0xd0, 0x39}, {0xe5, 0x08, 0xf4, 0x81, 0x23, 0xb5, 0x3d, 0xf3, 0xce, 0x94, 0xb6, 0xdd, 0x64, 0xd4, 0x67, 0xa2, 0x7a, 0x3f, 0xaf, 0x83, 0x54, 0x2c, 0x0d, 0xde, 0xfc, 0x8a, 0xb0, 0x4e, 0xd7, 0xd9, 0x05, 0x31}}, + {{0x1c, 0x74, 0x51, 0xae, 0xf2, 0xd3, 0x06, 0x0f, 0x80, 0x5a, 0xb9, 0xa4, 0x5c, 0x9d, 0x47, 0xb7, 0xb0, 0x89, 0x15, 0x47, 0xab, 0x36, 0x39, 0x78, 0xce, 0xab, 0x73, 0xcf, 0xf7, 0x7c, 0xe1, 0x17}, {0xa6, 0x0c, 0x39, 0x7e, 0xf0, 0x32, 0x8e, 0x22, 0xa8, 0x16, 0x4d, 0x74, 0xe7, 0x35, 0xfe, 0x92, 0xa7, 0xdf, 0xd9, 0xa1, 0x1c, 0x5e, 0x5f, 0x23, 0x26, 0x67, 0xd6, 0x3b, 0x5b, 0x4c, 0xdb, 0x2a}}, + {{0x41, 0x38, 0x66, 0x32, 0x66, 0x60, 0x19, 0x58, 0x04, 0x9f, 0x28, 0x6b, 0x1e, 0xb9, 0xda, 0x24, 0x05, 0x41, 0xa4, 0x63, 0x49, 0xcf, 0x9a, 0xb7, 0x03, 0x77, 0xb6, 0x0c, 0xc6, 0xe5, 0xda, 0x21}, {0x6e, 0x57, 0x06, 0x64, 0x7e, 0x48, 0x23, 0xa2, 0xb2, 0x7e, 0x67, 0x74, 0x9e, 0x9d, 0xb6, 0x86, 0xe2, 0x6a, 0x8b, 0x04, 0x1d, 0x53, 0x2e, 0x7e, 0x67, 0x05, 0xb9, 0x46, 0x64, 0xbb, 0x96, 0x17}}, + {{0xdc, 0x04, 0x1d, 0x56, 0x45, 0xeb, 0x90, 0x6b, 0x9a, 0xae, 0x1c, 0x13, 0x60, 0x94, 0x43, 0xe7, 0x74, 0x32, 0xb1, 0xd3, 0x72, 0x4e, 0x35, 0x27, 0xf2, 0xdb, 0xe6, 0x1c, 0x96, 0x89, 0x1b, 0x18}, {0xcb, 0xeb, 0x7d, 0x6e, 0x74, 0xa5, 0x93, 0x43, 0x21, 0x73, 0x4b, 0x37, 0xb0, 0x57, 0xb9, 0x17, 0xff, 0xf4, 0xeb, 0x0a, 0x99, 0x14, 0x8f, 0xf4, 0x59, 0xad, 0xd8, 0x80, 0xcc, 0xa0, 0xf0, 0x2a}}, + {{0xa9, 0xc5, 0x81, 0x9a, 0x9c, 0xd2, 0x86, 0x8a, 0x97, 0x1f, 0x1a, 0x41, 0x2f, 0x6d, 0x93, 0x23, 0x25, 0x95, 0xfa, 0x40, 0x2a, 0x24, 0xf6, 0x50, 0x4b, 0x0a, 0x15, 0xc3, 0xf1, 0xfa, 0xb0, 0x05}, {0x95, 0x1c, 0x83, 0xab, 0x93, 0x9a, 0x0c, 0xc7, 0xb1, 0xef, 0xea, 0xce, 0xe9, 0x9a, 0xd2, 0x6e, 0x03, 0xcf, 0xe1, 0x22, 0xb2, 0x68, 0xfe, 0xc7, 0xb4, 0x44, 0x18, 0x19, 0xd0, 0xcf, 0x1d, 0x38}}, + {{0xd9, 0xb7, 0xbe, 0x5d, 0x27, 0x31, 0x5a, 0x7d, 0xb6, 0xda, 0xce, 0x25, 0xe5, 0x3d, 0xe0, 0x79, 0xb4, 0xea, 0xdc, 0x9f, 0xdc, 0x02, 0x5a, 0x93, 0x48, 0x44, 0x11, 0x78, 0x19, 0x47, 0x4d, 0x2b}, {0xb2, 0x1e, 0xfe, 0xe2, 0xdf, 0x78, 0x73, 0x76, 0x18, 0x5f, 0xaa, 0xc9, 0x01, 0x93, 0x91, 0xbe, 0x8e, 0xa2, 0x96, 0x47, 0xc0, 0x48, 0xee, 0x60, 0x93, 0x46, 0x7f, 0x7b, 0x8c, 0x3e, 0x24, 0x2f}}, + {{0x02, 0x63, 0x6a, 0x3b, 0xec, 0xfc, 0xac, 0x58, 0xb4, 0xff, 0x49, 0x8a, 0xb2, 0xce, 0x8c, 0x77, 0x04, 0x8a, 0x71, 0x27, 0x5d, 0xf5, 0x28, 0x8c, 0xb3, 0x7d, 0x24, 0x6f, 0x86, 0xcb, 0x4e, 0x3c}, {0x86, 0xfc, 0x3f, 0x7b, 0xdf, 0xd4, 0xbe, 0x7f, 0xed, 0xf2, 0x70, 0xd4, 0xc9, 0x6c, 0x40, 0x85, 0x20, 0x02, 0x0e, 0x83, 0x3d, 0x5e, 0xef, 0x0b, 0x8e, 0xd7, 0x7a, 0x45, 0x74, 0xc8, 0x60, 0x2c}}, + {{0x76, 0x56, 0x18, 0xf9, 0xb7, 0xb9, 0xb1, 0x2f, 0x85, 0xe3, 0x79, 0xf9, 0x85, 0x09, 0x9c, 0x3b, 0x3f, 0xdf, 0x9e, 0xb1, 0x99, 0xe2, 0x64, 0x3c, 0x1a, 0xe2, 0xc2, 0xf4, 0xc7, 0x03, 0xc6, 0x38}, {0xf9, 0x34, 0xc3, 0x3b, 0x4b, 0x4e, 0x28, 0xb3, 0x21, 0x9b, 0xa6, 0x9c, 0x9d, 0x4a, 0x14, 0x1a, 0xb6, 0xb9, 0x92, 0x49, 0x79, 0xc2, 0x0c, 0x8d, 0x85, 0x10, 0x7c, 0xd5, 0xca, 0x19, 0xe6, 0x0c}}, + {{0x7a, 0x61, 0x95, 0xa6, 0xa8, 0xd1, 0x55, 0x95, 0x5e, 0x4c, 0x64, 0x80, 0xfe, 0x43, 0x38, 0x9f, 0xe7, 0xc2, 0x85, 0x8d, 0xcb, 0x35, 0x95, 0xa4, 0x6f, 0x97, 0x7c, 0xeb, 0x13, 0x21, 0x01, 0x2d}, {0xb5, 0x50, 0x91, 0x64, 0xbd, 0x72, 0xb7, 0xb4, 0xd5, 0x1f, 0xeb, 0xbd, 0x2f, 0xd9, 0xdd, 0x45, 0x41, 0x1b, 0xd8, 0x41, 0x43, 0x64, 0xaa, 0xed, 0x92, 0x02, 0xe0, 0x12, 0xc6, 0xc1, 0x66, 0x29}}, + {{0x23, 0x9f, 0xd5, 0xff, 0xb2, 0x00, 0x95, 0x60, 0x48, 0xde, 0x58, 0xb2, 0xef, 0x61, 0xc2, 0xc0, 0xac, 0x00, 0xc2, 0x51, 0x7b, 0xb9, 0xcd, 0xcb, 0xa6, 0x70, 0x4a, 0x5b, 0x3a, 0x2f, 0xef, 0x0b}, {0x26, 0xc2, 0x73, 0xdf, 0xcf, 0xff, 0xf9, 0x69, 0xdf, 0x5d, 0x51, 0x5b, 0x1d, 0xf5, 0x86, 0x3c, 0x20, 0xe0, 0x5e, 0xef, 0x6c, 0x40, 0x26, 0x08, 0xc9, 0xe8, 0x5f, 0x22, 0xfe, 0x31, 0xf0, 0x05}}, + {{0x6c, 0x73, 0x19, 0x09, 0x2e, 0xd5, 0x4d, 0x31, 0xff, 0x39, 0xe9, 0x55, 0xea, 0xb5, 0x54, 0xf5, 0x27, 0x9f, 0x7f, 0xd0, 0xd8, 0xa5, 0x75, 0x77, 0xd4, 0xaf, 0xbe, 0x57, 0xfb, 0x43, 0xb9, 0x18}, {0xe7, 0x63, 0x45, 0x87, 0x74, 0x13, 0x63, 0xf5, 0xd2, 0x8c, 0x2e, 0x62, 0xd6, 0xa9, 0x1c, 0xbd, 0x4e, 0xcc, 0x1b, 0x61, 0x06, 0x60, 0x60, 0xd0, 0xa0, 0x02, 0xf6, 0x38, 0x5e, 0x02, 0x0d, 0x36}}, + {{0xb9, 0xd3, 0x2d, 0x4e, 0x74, 0x2e, 0x9e, 0x39, 0xba, 0x0c, 0x83, 0x8b, 0xf8, 0x74, 0xe3, 0x43, 0xe0, 0xf4, 0xcd, 0x48, 0xc4, 0xa1, 0x89, 0x42, 0x16, 0x97, 0x94, 0xb5, 0x15, 0xf3, 0x6d, 0x19}, {0xeb, 0x4d, 0x3f, 0x67, 0xd6, 0x6c, 0x88, 0xc2, 0xd3, 0x4e, 0x9f, 0xb8, 0x28, 0x27, 0xf2, 0x21, 0xfe, 0x48, 0xa9, 0xd9, 0x66, 0x6d, 0x39, 0x34, 0x75, 0xbb, 0xfe, 0x40, 0xb4, 0x5f, 0x89, 0x10}}, + {{0x4a, 0xdd, 0x82, 0xfc, 0x51, 0xa3, 0x16, 0x43, 0x50, 0xed, 0xfc, 0x4c, 0x50, 0x79, 0x59, 0xc9, 0x5e, 0xd1, 0xcf, 0x84, 0x3a, 0x94, 0x73, 0x72, 0xc1, 0x6a, 0xb9, 0xc1, 0x6c, 0xaa, 0xaa, 0x15}, {0x6d, 0x79, 0x2b, 0x51, 0x76, 0xd6, 0x99, 0x1b, 0xbb, 0xdb, 0xa5, 0xcb, 0xf1, 0xdf, 0x39, 0xce, 0x44, 0x6d, 0x62, 0x14, 0xa7, 0x4f, 0x1d, 0x42, 0x69, 0x5b, 0xaf, 0xdf, 0x2a, 0x9d, 0xad, 0x34}}, + {{0xef, 0x6e, 0x4a, 0x10, 0xd1, 0xa6, 0xad, 0x49, 0xcf, 0xb7, 0xb5, 0xcf, 0x4f, 0x02, 0x8b, 0xcf, 0x91, 0xcc, 0x3b, 0x3a, 0x9d, 0xcc, 0x0c, 0x84, 0xfc, 0xdd, 0xe1, 0x64, 0x44, 0x57, 0xb9, 0x29}, {0x80, 0xc2, 0x8c, 0x70, 0x6a, 0x71, 0x87, 0x0b, 0x35, 0x44, 0x21, 0x6f, 0x0f, 0x80, 0x3d, 0xf9, 0xff, 0x83, 0x6a, 0x2d, 0x67, 0x3c, 0x51, 0x1d, 0xbc, 0xf3, 0xbd, 0xc1, 0x91, 0xd4, 0xe6, 0x0a}}, + {{0x72, 0xc1, 0xfc, 0xf1, 0xb0, 0x41, 0x5e, 0x47, 0xb0, 0x0b, 0xc4, 0x69, 0x08, 0x14, 0xb7, 0x09, 0x14, 0x0c, 0x58, 0x6b, 0xaa, 0x2e, 0xed, 0xc7, 0xae, 0x7e, 0x56, 0x45, 0xce, 0xdd, 0x5a, 0x1d}, {0xa9, 0x19, 0x0a, 0xed, 0x89, 0xa9, 0x05, 0xb8, 0x6a, 0xce, 0x48, 0x4a, 0x92, 0xa0, 0xf0, 0x18, 0xba, 0x48, 0x67, 0x66, 0x90, 0xc3, 0x7c, 0x37, 0x84, 0x87, 0x9b, 0x5e, 0xec, 0x7b, 0x01, 0x01}}, + {{0xd1, 0x4f, 0x4a, 0xdf, 0x9d, 0x86, 0x24, 0xc4, 0x77, 0x8e, 0x06, 0x15, 0xc6, 0xe9, 0x89, 0xcb, 0x1e, 0xad, 0x64, 0x0d, 0x9d, 0x5f, 0x73, 0x65, 0xa8, 0xd2, 0xef, 0xf3, 0x10, 0x19, 0x16, 0x1a}, {0xb9, 0xe2, 0x96, 0x2e, 0x44, 0xec, 0x2a, 0x1c, 0xd1, 0x3c, 0x93, 0xe7, 0xbb, 0x6c, 0xe2, 0xe5, 0x33, 0x0b, 0xcf, 0xaf, 0xa5, 0xf5, 0x52, 0x41, 0xc2, 0xaf, 0xd7, 0x2c, 0xf6, 0x33, 0xbd, 0x18}}, + {{0xa3, 0x62, 0x12, 0x0f, 0xd4, 0x2e, 0xef, 0x6c, 0xb6, 0x13, 0x08, 0x9a, 0x6a, 0xbe, 0x9f, 0x62, 0x9a, 0x5e, 0x70, 0xfd, 0x7a, 0xe9, 0x88, 0xe1, 0xdd, 0xbb, 0x5e, 0x08, 0xae, 0xab, 0x81, 0x1c}, {0xcc, 0x14, 0x3d, 0xd8, 0x2d, 0xe3, 0x64, 0x6b, 0x72, 0x8e, 0xd3, 0xb7, 0x12, 0xe8, 0x1c, 0x05, 0x5d, 0x95, 0xab, 0x9d, 0xff, 0xe5, 0x9c, 0x7c, 0x3a, 0x55, 0xd5, 0x7e, 0xb2, 0xdc, 0x11, 0x2c}}, + {{0x5c, 0x7c, 0x43, 0x65, 0x53, 0x10, 0x86, 0xa4, 0xb5, 0x99, 0x49, 0x59, 0x28, 0x35, 0xef, 0xba, 0x56, 0x78, 0xd5, 0x8b, 0x21, 0x2d, 0xbc, 0x6e, 0xd8, 0x20, 0x8d, 0x8f, 0xa8, 0xf3, 0x94, 0x11}, {0x44, 0x0b, 0xc6, 0x02, 0xcf, 0x16, 0x83, 0xc5, 0x2c, 0x4f, 0x95, 0x66, 0x73, 0xdb, 0xe8, 0xba, 0x74, 0xff, 0xc8, 0x4b, 0x4b, 0xfe, 0x21, 0x13, 0xc9, 0x66, 0xdb, 0x5c, 0x5d, 0xec, 0x90, 0x1f}}, + {{0x1b, 0x06, 0x0b, 0x50, 0xbc, 0x8b, 0x78, 0x3e, 0xb4, 0xd1, 0x40, 0x7d, 0xd5, 0x04, 0x9f, 0xa3, 0x2e, 0x32, 0x95, 0xe6, 0x0a, 0xff, 0x75, 0x10, 0x6f, 0xd7, 0xeb, 0x17, 0xf2, 0xf7, 0xe8, 0x29}, {0xc9, 0x1f, 0x13, 0x6b, 0x79, 0x0b, 0x38, 0xbf, 0x97, 0x45, 0x3b, 0xf5, 0x0d, 0xa7, 0x64, 0x64, 0x44, 0x46, 0x97, 0xdd, 0xe6, 0x66, 0x26, 0x70, 0x50, 0xe6, 0x89, 0x96, 0xd1, 0xb0, 0xfe, 0x12}}, + {{0x71, 0x49, 0x5d, 0x4e, 0x00, 0x2e, 0x13, 0xfd, 0x72, 0x60, 0xea, 0xb5, 0xd2, 0x01, 0x05, 0xc5, 0xd7, 0x9e, 0x65, 0x2e, 0x52, 0xb9, 0x02, 0x92, 0x11, 0x7b, 0x43, 0x10, 0xaa, 0x84, 0xb2, 0x3a}, {0xe1, 0xf5, 0xf7, 0x70, 0x20, 0x8d, 0xe0, 0x4d, 0x08, 0xc5, 0x48, 0x56, 0x7d, 0xb4, 0x0f, 0x55, 0x33, 0x9c, 0x73, 0x60, 0x30, 0x5a, 0x4a, 0xf7, 0xec, 0x48, 0xdb, 0x59, 0x8c, 0xc9, 0x52, 0x3b}}, + {{0x66, 0xf2, 0x9d, 0x4d, 0xc3, 0x72, 0x65, 0xb5, 0x25, 0xe6, 0x6e, 0x2f, 0x31, 0x8d, 0xcb, 0xd4, 0x01, 0xa5, 0x0a, 0x6f, 0x93, 0x21, 0x7e, 0xcd, 0xb7, 0xbc, 0xb9, 0xe1, 0xb5, 0xb0, 0x73, 0x31}, {0x2b, 0x38, 0x36, 0xd9, 0x67, 0x03, 0xb7, 0x7b, 0xa0, 0x9f, 0x24, 0x1a, 0xe0, 0x03, 0xd5, 0x90, 0x5a, 0x29, 0xeb, 0x21, 0xeb, 0xfc, 0x1a, 0x1d, 0xde, 0xf2, 0xb7, 0x0a, 0x86, 0x55, 0x42, 0x2a}}, + {{0x8a, 0x42, 0xda, 0xc9, 0x65, 0xff, 0x5b, 0xea, 0x54, 0x53, 0xdb, 0xea, 0x20, 0xa5, 0xcb, 0xa4, 0xdb, 0x7b, 0x03, 0x0b, 0x43, 0x50, 0x0d, 0xd8, 0x71, 0xd4, 0xbf, 0x17, 0x3e, 0x49, 0xf5, 0x30}, {0xa5, 0xdb, 0x99, 0xdd, 0x7f, 0x0e, 0x52, 0xa7, 0x25, 0x2a, 0xa3, 0xd9, 0xd0, 0x6e, 0x12, 0x5d, 0x66, 0x9c, 0x3e, 0x52, 0xc5, 0x77, 0x35, 0xf8, 0x2a, 0xd4, 0x12, 0x5f, 0x36, 0x0d, 0x96, 0x30}}, + {{0xa6, 0x6a, 0x44, 0xac, 0x13, 0x5d, 0x98, 0x66, 0x12, 0x6e, 0x77, 0x96, 0x26, 0x2f, 0x73, 0xb7, 0xb1, 0x50, 0x01, 0x85, 0x40, 0xb6, 0xb7, 0x1f, 0x29, 0xa8, 0xac, 0xe3, 0x5c, 0x04, 0x5c, 0x33}, {0x01, 0xae, 0xdf, 0xbd, 0xf8, 0xb8, 0x34, 0x11, 0x4d, 0x9e, 0x0b, 0x11, 0x22, 0x96, 0x14, 0xfc, 0x5a, 0x49, 0xd2, 0xfe, 0xfe, 0x9d, 0x2a, 0x29, 0x8c, 0x9f, 0xd6, 0x78, 0x74, 0x47, 0x23, 0x2d}}, + {{0xb9, 0xe7, 0xe0, 0xbf, 0x84, 0xa3, 0x97, 0xe6, 0x61, 0x8f, 0xec, 0x7e, 0x48, 0xe5, 0x00, 0x96, 0x80, 0x40, 0x0d, 0xd0, 0x11, 0xd9, 0xf6, 0x5c, 0x3d, 0x9c, 0xb4, 0x7f, 0xef, 0x9f, 0x72, 0x2f}, {0xea, 0xcc, 0xb3, 0x0e, 0xcd, 0x44, 0x27, 0x6f, 0xee, 0x75, 0x0f, 0x85, 0x82, 0xf5, 0xa3, 0x20, 0x26, 0xf6, 0xa9, 0x44, 0x13, 0xde, 0x5d, 0x0a, 0x99, 0x11, 0xba, 0x5a, 0x74, 0x72, 0xce, 0x35}}, + {{0x66, 0xa4, 0xad, 0x21, 0x33, 0xe7, 0x45, 0x77, 0xc1, 0xea, 0x4e, 0x9e, 0xaf, 0xb0, 0x96, 0x7e, 0x08, 0x41, 0xfe, 0xd2, 0xd2, 0x89, 0x76, 0x90, 0x59, 0xde, 0x9a, 0x27, 0xec, 0x74, 0xd7, 0x0a}, {0x45, 0xf9, 0x30, 0xfa, 0xd2, 0x26, 0x87, 0xeb, 0x8e, 0x75, 0x2a, 0x95, 0x36, 0xfb, 0x9f, 0xf5, 0x5b, 0xf1, 0x7b, 0x27, 0x97, 0xd3, 0x6c, 0xf4, 0x1e, 0x4e, 0x88, 0xa7, 0x00, 0xe6, 0x42, 0x0e}}, + {{0x39, 0x7d, 0x54, 0x1a, 0xe8, 0xc6, 0xd7, 0x42, 0x62, 0xbd, 0xa8, 0x50, 0x5f, 0x69, 0x71, 0xb1, 0xba, 0x16, 0x39, 0x57, 0x93, 0x5f, 0x87, 0xfe, 0x47, 0xf1, 0x1a, 0x9e, 0xa1, 0x81, 0x7b, 0x2b}, {0xf0, 0x7c, 0x58, 0xeb, 0xbc, 0xf6, 0x79, 0x54, 0xab, 0x06, 0x9e, 0xf3, 0x7c, 0x82, 0xa1, 0x55, 0xae, 0xaa, 0xe9, 0xd3, 0xc4, 0x0f, 0x9c, 0x2a, 0x82, 0xe6, 0x19, 0x9c, 0x67, 0xb5, 0x34, 0x19}}, + {{0xfb, 0x21, 0x8f, 0x01, 0x78, 0xeb, 0x8f, 0xe1, 0x07, 0x00, 0xa5, 0x0f, 0x75, 0x40, 0xa5, 0xcf, 0x8b, 0x5e, 0x0f, 0x9d, 0xd5, 0xf7, 0xe3, 0x05, 0x54, 0x37, 0x1a, 0xfe, 0xc1, 0x4c, 0xc9, 0x2c}, {0x1c, 0xae, 0x4c, 0x8b, 0x24, 0xf3, 0xd2, 0xc2, 0xdd, 0xde, 0xa9, 0xc5, 0x45, 0x77, 0x7f, 0x44, 0x68, 0x9c, 0xf6, 0x32, 0xcb, 0x26, 0x21, 0x3c, 0x5b, 0x5d, 0xa5, 0xfb, 0xf6, 0xcf, 0xd2, 0x08}}, + {{0x12, 0xc2, 0x4c, 0x44, 0x90, 0x53, 0xd8, 0xb5, 0x10, 0x3c, 0xf6, 0xbe, 0x9d, 0xcf, 0x8f, 0xe0, 0xe3, 0x80, 0x3c, 0xfb, 0x6a, 0x86, 0xcc, 0xe6, 0xa4, 0x0f, 0x2f, 0xd0, 0xe7, 0xff, 0x73, 0x19}, {0x80, 0xe3, 0x39, 0xb6, 0x74, 0x19, 0x3d, 0x43, 0xb2, 0x3b, 0x9c, 0xd7, 0xf5, 0xa8, 0xe3, 0x10, 0x97, 0xf5, 0x98, 0xc7, 0x33, 0x76, 0x8b, 0xc4, 0x34, 0xe4, 0x43, 0xaf, 0x88, 0x6a, 0x49, 0x2b}}, + {{0x0a, 0x9b, 0x46, 0x46, 0x9e, 0x5a, 0xe3, 0x6b, 0x30, 0xf6, 0x07, 0xd1, 0x57, 0xd6, 0xfe, 0x21, 0x62, 0x8d, 0x7b, 0xab, 0xbd, 0x0a, 0xd3, 0x99, 0x2f, 0xe3, 0x0e, 0x4a, 0x66, 0x18, 0x09, 0x35}, {0x23, 0x87, 0x38, 0x2b, 0x7b, 0xba, 0x54, 0x04, 0xd3, 0xad, 0x35, 0x05, 0x44, 0xfd, 0x4c, 0x99, 0x82, 0x10, 0x94, 0xa6, 0xd5, 0xe7, 0x3e, 0x5c, 0xe2, 0x57, 0xbb, 0x16, 0x1f, 0x3a, 0x6b, 0x3e}}, + {{0x3d, 0x27, 0xf9, 0xf4, 0x7a, 0xe8, 0xb6, 0xff, 0xf0, 0xd1, 0x4f, 0x84, 0x90, 0x92, 0xb4, 0xa3, 0xa2, 0x03, 0x41, 0xac, 0x77, 0x91, 0xd9, 0xd9, 0xe0, 0x5d, 0xad, 0x98, 0xf8, 0xf2, 0xa6, 0x1b}, {0xd2, 0x20, 0x0a, 0x0e, 0xd0, 0xf2, 0x99, 0x21, 0x48, 0x7f, 0x69, 0x1c, 0x92, 0x5d, 0xbf, 0x47, 0x95, 0x4e, 0x42, 0xb3, 0x9d, 0x40, 0x0d, 0xb5, 0xa4, 0x8f, 0x69, 0xb9, 0x05, 0x68, 0xc8, 0x0f}}, + {{0xf4, 0x16, 0xd6, 0x26, 0xe6, 0x72, 0xee, 0x36, 0xd1, 0xe5, 0x2e, 0x8f, 0x1e, 0x13, 0x5c, 0xa8, 0x77, 0xbc, 0xfe, 0xd5, 0xb6, 0x49, 0x4d, 0x54, 0xfd, 0x23, 0xdf, 0x10, 0x79, 0x2d, 0x00, 0x09}, {0x0b, 0x92, 0xa7, 0x47, 0x41, 0xc6, 0x8f, 0x76, 0xf3, 0x7e, 0x91, 0x37, 0x26, 0x4d, 0xed, 0xaf, 0x3c, 0xa8, 0x72, 0xb9, 0x62, 0xbc, 0xef, 0x25, 0x55, 0xe6, 0xfe, 0xa0, 0x46, 0xb6, 0x20, 0x0a}}, + {{0x2c, 0x6a, 0x03, 0x67, 0xde, 0x09, 0x3e, 0xb8, 0x6f, 0x8a, 0x1c, 0x9a, 0x86, 0x2d, 0xe4, 0xc6, 0x57, 0x37, 0x40, 0xa1, 0x28, 0x99, 0xcf, 0x26, 0x2b, 0xd6, 0x61, 0xbb, 0xa4, 0x20, 0xa1, 0x2e}, {0xfd, 0xea, 0x21, 0xb1, 0x56, 0x52, 0xaa, 0xc7, 0x45, 0xfb, 0xa1, 0x91, 0x99, 0xd8, 0xa9, 0x37, 0xbd, 0x4b, 0x34, 0x51, 0xa8, 0x29, 0x6b, 0x0c, 0x19, 0xfb, 0x24, 0xf2, 0x6a, 0xcc, 0x47, 0x00}}, + {{0x2f, 0x8c, 0x69, 0x94, 0x82, 0x5b, 0x0e, 0x9c, 0x14, 0xeb, 0xf7, 0x57, 0x8d, 0xab, 0x6a, 0x24, 0x5c, 0x01, 0x8b, 0xd2, 0xf8, 0x27, 0xcc, 0x6a, 0xbb, 0xb6, 0x2e, 0x2e, 0xc2, 0xc3, 0xbc, 0x14}, {0x84, 0xac, 0x03, 0x98, 0x65, 0x9f, 0xfd, 0xbc, 0xa8, 0xf1, 0x1a, 0x7b, 0x67, 0x8c, 0x65, 0x90, 0x34, 0x9d, 0xca, 0xfb, 0xd7, 0x13, 0x9e, 0x77, 0xf5, 0x1d, 0x4e, 0x32, 0xbd, 0xf9, 0xde, 0x0c}}, + {{0xf1, 0x61, 0x90, 0xb4, 0xdd, 0x5d, 0xb5, 0x2f, 0x60, 0xff, 0x8c, 0xf4, 0xf6, 0xc4, 0x8d, 0xe1, 0x22, 0x8e, 0x95, 0x1f, 0x49, 0x17, 0x9e, 0x20, 0xc6, 0x11, 0xd8, 0xe0, 0x74, 0xe4, 0x51, 0x06}, {0xbb, 0xcb, 0x3c, 0xec, 0xc2, 0x45, 0xb6, 0xad, 0x10, 0x02, 0xd3, 0xb2, 0xc6, 0xea, 0xa0, 0x35, 0x94, 0xa1, 0x43, 0x3d, 0xad, 0x2e, 0xd9, 0x4a, 0xb6, 0x85, 0x18, 0xbc, 0x7a, 0x0f, 0x39, 0x2e}}, + {{0x86, 0x87, 0x99, 0x4a, 0xf8, 0xec, 0xca, 0x23, 0x18, 0x33, 0xd6, 0x2b, 0x27, 0xdb, 0xda, 0x48, 0x99, 0x77, 0xd3, 0xb2, 0xf9, 0x40, 0x89, 0x9d, 0x87, 0x89, 0xa5, 0x05, 0xd6, 0x61, 0xfa, 0x17}, {0xaf, 0x8d, 0x26, 0x1d, 0xe1, 0x47, 0x8f, 0xc8, 0xbc, 0x62, 0xff, 0x55, 0x12, 0xa0, 0x0d, 0xfb, 0xca, 0x2c, 0x83, 0xdf, 0x88, 0xcf, 0x10, 0xac, 0x29, 0xab, 0xeb, 0x19, 0x77, 0x0c, 0xf1, 0x32}}, + {{0x31, 0x9b, 0x27, 0xc3, 0x2f, 0x10, 0x95, 0x31, 0x78, 0xd8, 0xa5, 0x89, 0xc5, 0xb6, 0xfe, 0xac, 0x23, 0xa4, 0xe8, 0xd8, 0xb2, 0x2a, 0x67, 0x93, 0x07, 0xba, 0x69, 0x66, 0xc6, 0x50, 0xac, 0x14}, {0x0e, 0xe7, 0x3a, 0x09, 0x70, 0xfc, 0x54, 0x84, 0x16, 0x97, 0xea, 0x71, 0x18, 0xe2, 0xcf, 0x83, 0x97, 0x88, 0x60, 0x25, 0x3a, 0x51, 0x87, 0x8f, 0xfd, 0x82, 0xf3, 0x65, 0x5c, 0x84, 0x42, 0x30}}, + {{0x48, 0xb9, 0x62, 0xcf, 0xe1, 0x44, 0xbd, 0xe3, 0xf9, 0xf8, 0x97, 0xf0, 0x96, 0x83, 0xa4, 0xac, 0x59, 0xdd, 0x33, 0xe5, 0xf2, 0x28, 0xe7, 0xaa, 0x0e, 0x79, 0x92, 0xd2, 0x02, 0x00, 0x5a, 0x20}, {0x58, 0xda, 0x40, 0x63, 0x3a, 0x57, 0x47, 0x37, 0x4c, 0xc3, 0x66, 0xe6, 0x08, 0xbe, 0x62, 0xc4, 0xd1, 0x0d, 0xef, 0x22, 0xbd, 0xa9, 0x2b, 0x93, 0xc2, 0x55, 0x23, 0x75, 0xd9, 0x7d, 0x05, 0x3c}}, + {{0xe9, 0xc7, 0x01, 0x3b, 0xf6, 0x7a, 0xbc, 0x21, 0x77, 0xdc, 0xba, 0xb6, 0x2a, 0x73, 0x52, 0x62, 0xaf, 0x3e, 0xda, 0xa6, 0xd2, 0x7a, 0x36, 0x89, 0x8c, 0x64, 0xb2, 0xa8, 0x5a, 0x22, 0x23, 0x34}, {0xbd, 0xcd, 0x7e, 0xd3, 0xb4, 0x96, 0x9f, 0xbf, 0x1e, 0xc2, 0xb5, 0xa6, 0x31, 0x57, 0x88, 0x97, 0x3f, 0xd0, 0xbd, 0x53, 0xb0, 0xde, 0x53, 0x8e, 0x57, 0x9d, 0x41, 0x8e, 0x59, 0xf6, 0x67, 0x02}}, + {{0x32, 0x4e, 0xd8, 0x99, 0x25, 0xc5, 0xce, 0x16, 0x1a, 0x79, 0x6b, 0xf7, 0xcf, 0x87, 0xe9, 0x0b, 0xcb, 0x90, 0xed, 0x3d, 0x24, 0xf7, 0xe9, 0x64, 0x5b, 0x0a, 0xfd, 0xf7, 0x45, 0x7c, 0x4b, 0x3f}, {0x9b, 0x6f, 0x5e, 0x0a, 0x2d, 0xf5, 0x4d, 0x50, 0x5e, 0xc2, 0x71, 0xc4, 0x14, 0x7f, 0xfd, 0x0f, 0x35, 0x32, 0xe4, 0xf4, 0xa6, 0xf6, 0xf5, 0x05, 0x2f, 0x8e, 0x9b, 0x1b, 0xf6, 0x4d, 0xed, 0x03}}, + {{0x76, 0xb0, 0xbc, 0xd9, 0xcd, 0x7e, 0x55, 0x4d, 0xe4, 0x78, 0x07, 0xd2, 0x9b, 0x52, 0x08, 0x54, 0xd5, 0x9b, 0xef, 0x83, 0x33, 0xce, 0xde, 0x58, 0xce, 0xf1, 0xc4, 0x80, 0x7f, 0x3b, 0xe2, 0x08}, {0xe7, 0x5f, 0x3f, 0x1d, 0x0a, 0x55, 0x39, 0x24, 0xde, 0xe7, 0x29, 0xc2, 0xba, 0x49, 0x35, 0x6f, 0x4c, 0xc3, 0x58, 0x54, 0x63, 0x81, 0xf1, 0x4f, 0x2d, 0x5b, 0x6c, 0xf8, 0x33, 0x10, 0xb0, 0x18}}, + {{0xb6, 0xac, 0x90, 0x14, 0x1f, 0x98, 0x32, 0x79, 0x87, 0xba, 0xf1, 0x69, 0xc6, 0xd1, 0x32, 0xae, 0x2f, 0xad, 0xde, 0x98, 0x38, 0x3e, 0x7d, 0x48, 0xbb, 0xe4, 0xb9, 0x1c, 0x96, 0x9d, 0x60, 0x33}, {0xd9, 0x42, 0xe0, 0x9d, 0x07, 0xc1, 0xf5, 0x2d, 0x8e, 0x33, 0x95, 0x4f, 0xd8, 0xe2, 0x5e, 0x3a, 0x71, 0x60, 0x5d, 0x8e, 0x54, 0x1e, 0x61, 0x0f, 0x6a, 0x4f, 0x86, 0xb6, 0x99, 0xf5, 0x4a, 0x31}}, + {{0x9c, 0x4c, 0x34, 0xfb, 0xda, 0x74, 0xec, 0x12, 0xb0, 0xb2, 0x8c, 0x39, 0x94, 0xc3, 0xe7, 0x86, 0xb3, 0x55, 0x41, 0x0f, 0x55, 0x5e, 0x50, 0xb3, 0x04, 0x96, 0x0f, 0xd1, 0x74, 0xc2, 0x82, 0x38}, {0xc8, 0x3c, 0x40, 0xa7, 0x16, 0x54, 0x75, 0x04, 0x17, 0x84, 0xbe, 0x18, 0x57, 0x5c, 0xc7, 0x7b, 0xbb, 0xf0, 0xef, 0x5d, 0x87, 0xcf, 0x25, 0x72, 0xb5, 0x8a, 0xb7, 0xe4, 0xaf, 0xa5, 0x4b, 0x35}}, + {{0x6b, 0xcf, 0x60, 0xae, 0x66, 0x8c, 0x28, 0xb9, 0x33, 0x61, 0x67, 0x83, 0xed, 0x3b, 0x01, 0x8a, 0xaf, 0x61, 0x69, 0xa2, 0xe7, 0xd4, 0xd3, 0xf9, 0x0f, 0x8a, 0x17, 0xb7, 0x3d, 0xbf, 0x90, 0x15}, {0x3b, 0xb6, 0x9d, 0xe0, 0xe5, 0x6d, 0x88, 0x29, 0x31, 0x59, 0x3f, 0x59, 0xe1, 0x8d, 0xee, 0xff, 0xb0, 0x4a, 0x4a, 0x78, 0x9c, 0xc9, 0x10, 0x6c, 0x8f, 0xc1, 0x4e, 0x7a, 0x40, 0x0c, 0xb8, 0x08}}, + {{0x64, 0x6a, 0x84, 0x76, 0x82, 0x5d, 0xef, 0x07, 0xe4, 0x83, 0x16, 0x33, 0x42, 0x75, 0x66, 0xf2, 0xa8, 0x98, 0xe0, 0xb6, 0xb2, 0xe5, 0xe8, 0x63, 0x15, 0x39, 0x16, 0xa1, 0xde, 0x36, 0x5d, 0x11}, {0x17, 0xb8, 0x81, 0x69, 0xd4, 0xcc, 0xcb, 0xf5, 0xc1, 0xac, 0x3a, 0x5a, 0x08, 0x6e, 0x9c, 0x73, 0x1b, 0x4a, 0xc8, 0x0d, 0xdc, 0xa2, 0xc3, 0x43, 0x8c, 0x72, 0xc9, 0xbe, 0x0b, 0x05, 0x61, 0x30}}, + {{0x97, 0x98, 0xc4, 0x84, 0xba, 0x97, 0x84, 0xa7, 0x7b, 0x47, 0x11, 0x6f, 0x54, 0x4a, 0xdf, 0x0b, 0xc4, 0x4f, 0xb4, 0x61, 0xc7, 0x5b, 0xd4, 0x78, 0x27, 0xbd, 0xe4, 0x01, 0x5a, 0x26, 0x9c, 0x00}, {0x2f, 0x44, 0x24, 0x31, 0xe2, 0x88, 0xd6, 0x83, 0x28, 0x72, 0x37, 0x73, 0x10, 0x41, 0xf5, 0xda, 0x6c, 0xa9, 0x5f, 0xa3, 0x4e, 0xe7, 0x76, 0x04, 0xce, 0xa6, 0xc5, 0x31, 0x0c, 0xb1, 0xbc, 0x1c}}, + {{0x41, 0xc9, 0x25, 0x74, 0xef, 0x09, 0x5f, 0x81, 0x6e, 0xb1, 0x1f, 0xaf, 0x91, 0x5b, 0xea, 0xdd, 0x5b, 0x4d, 0x4c, 0x6e, 0xc0, 0x8e, 0xc4, 0x44, 0x7a, 0x34, 0xdd, 0x09, 0x44, 0x69, 0xb2, 0x3e}, {0xe1, 0x36, 0x7d, 0x08, 0x3b, 0x85, 0x75, 0x50, 0xd2, 0x8c, 0xb9, 0x4f, 0xed, 0x4c, 0x37, 0xa6, 0x4d, 0x76, 0x56, 0xfa, 0x71, 0x04, 0x41, 0x8f, 0x31, 0x54, 0x0a, 0xe5, 0x49, 0x29, 0x49, 0x2a}}, + {{0xb1, 0xc7, 0xca, 0x80, 0xc5, 0x94, 0x44, 0x2a, 0x20, 0x4c, 0x0c, 0xbe, 0x62, 0xbc, 0x80, 0x5c, 0x9d, 0xa2, 0xee, 0x76, 0xa6, 0xc8, 0x9b, 0x3e, 0x52, 0x02, 0x73, 0x53, 0x89, 0xf4, 0xe9, 0x31}, {0x5f, 0x79, 0x44, 0x2d, 0xcc, 0x99, 0xc5, 0x0c, 0x69, 0xd7, 0xbb, 0x6d, 0x7a, 0x2d, 0x34, 0x5f, 0x70, 0x3b, 0xb1, 0x5b, 0xac, 0x83, 0x03, 0x1e, 0x90, 0x53, 0xcc, 0xee, 0xfa, 0xb8, 0x76, 0x35}}, + {{0x24, 0x9a, 0x2c, 0xf1, 0x02, 0x88, 0x73, 0x0d, 0x47, 0xfc, 0x88, 0x7a, 0x1a, 0xd3, 0x4b, 0x57, 0x92, 0x35, 0x93, 0x5d, 0x6a, 0x3f, 0x84, 0xfc, 0x27, 0x9c, 0xbe, 0xf8, 0xfb, 0xf0, 0x86, 0x13}, {0x44, 0xf0, 0x6c, 0x29, 0x0a, 0x54, 0x23, 0x5a, 0x98, 0x7a, 0x08, 0x15, 0xf4, 0x3a, 0x92, 0x61, 0x10, 0x28, 0xcc, 0x15, 0xcf, 0xb4, 0x95, 0x59, 0x36, 0xf0, 0xa0, 0x50, 0x76, 0x32, 0x06, 0x17}}, + {{0x0b, 0xa9, 0xde, 0x85, 0x55, 0xf1, 0x53, 0x26, 0x2f, 0x48, 0xa1, 0x8a, 0xd0, 0x94, 0x3d, 0xd6, 0x55, 0xd1, 0x27, 0x80, 0x15, 0x47, 0x82, 0x6a, 0x4c, 0xda, 0xb8, 0x50, 0xc5, 0x02, 0xf5, 0x1d}, {0x37, 0xeb, 0x62, 0xda, 0xbe, 0xbe, 0x94, 0x1c, 0x67, 0x12, 0xb8, 0x04, 0xbc, 0x52, 0x7d, 0x0d, 0xe4, 0x04, 0x00, 0xeb, 0x33, 0xbe, 0x2f, 0x8c, 0x2f, 0x61, 0x35, 0xea, 0x84, 0x0a, 0x40, 0x04}}, + {{0x36, 0x45, 0x59, 0x56, 0x52, 0x8f, 0x1b, 0x5c, 0x5f, 0x82, 0x97, 0x23, 0x4d, 0x4d, 0x79, 0x9b, 0x1c, 0xba, 0x7d, 0x0f, 0xdf, 0xa8, 0xde, 0xbb, 0x64, 0x55, 0x2a, 0x08, 0xf0, 0xb2, 0x29, 0x3d}, {0x81, 0xc3, 0xe8, 0xa8, 0xbe, 0xe0, 0x7a, 0x99, 0x27, 0x7e, 0x46, 0x39, 0x89, 0x2e, 0xfb, 0xd8, 0x9c, 0x74, 0xae, 0x32, 0x6b, 0x4e, 0xe9, 0x23, 0xf1, 0x6e, 0xd3, 0x96, 0xa7, 0xd4, 0xbe, 0x37}}, + {{0x15, 0xaf, 0xa0, 0x49, 0x72, 0xfd, 0x55, 0x2b, 0x19, 0x22, 0xbf, 0x00, 0x86, 0xef, 0xb6, 0x84, 0xe1, 0x25, 0x88, 0x41, 0xda, 0x27, 0x42, 0xa7, 0x87, 0x4b, 0x48, 0xd3, 0x50, 0xdd, 0xe3, 0x2d}, {0xaf, 0x19, 0x87, 0x01, 0x35, 0x99, 0x51, 0x7c, 0x80, 0x33, 0xad, 0xf5, 0x42, 0xc3, 0x2b, 0xe1, 0xdb, 0x6f, 0xb6, 0xd6, 0x97, 0x39, 0x71, 0x47, 0xbd, 0x88, 0x80, 0xf0, 0x1a, 0xcf, 0x81, 0x27}}, + {{0x28, 0x62, 0x2e, 0xe4, 0x67, 0x85, 0xb5, 0xd6, 0x84, 0x16, 0xab, 0xca, 0xee, 0xc9, 0x55, 0xba, 0xa9, 0xbf, 0xe2, 0xc0, 0x3e, 0xb0, 0x98, 0xb0, 0x72, 0xab, 0x6c, 0x2d, 0xf6, 0x92, 0x58, 0x16}, {0x0a, 0x75, 0x04, 0x70, 0xc2, 0xf3, 0xce, 0x7c, 0xbd, 0x0f, 0xaf, 0x87, 0xec, 0xb8, 0x64, 0x67, 0xda, 0x10, 0x8f, 0xb8, 0x23, 0x3e, 0x4a, 0x95, 0xb4, 0x6e, 0x75, 0xed, 0x55, 0x7c, 0x6b, 0x01}}, + {{0x81, 0x6a, 0x41, 0xf4, 0x92, 0x37, 0x72, 0x15, 0x4f, 0x56, 0x87, 0x4d, 0x29, 0xd3, 0x95, 0xf9, 0xe8, 0x2e, 0x5c, 0xcc, 0x0e, 0x1f, 0xd2, 0xb0, 0xba, 0x22, 0xbd, 0xd4, 0x0b, 0xc3, 0xd0, 0x27}, {0x73, 0x04, 0x47, 0xab, 0xc7, 0xfd, 0x2c, 0xdb, 0xb9, 0x03, 0x56, 0x22, 0x3d, 0xd1, 0xf3, 0x6c, 0xca, 0x23, 0x53, 0xb0, 0x49, 0x3b, 0x32, 0x20, 0x92, 0x2a, 0x24, 0x3a, 0xf6, 0x12, 0x74, 0x38}}, + {{0x3c, 0xb8, 0x44, 0xd0, 0x38, 0x0c, 0x6a, 0x99, 0xa5, 0xcd, 0x92, 0x5b, 0x18, 0x06, 0x09, 0xde, 0x55, 0xa2, 0x00, 0xd5, 0x67, 0x0a, 0x43, 0x46, 0x7e, 0xac, 0x77, 0xeb, 0x85, 0x96, 0xf5, 0x27}, {0xdf, 0x5e, 0xd1, 0xdf, 0x6e, 0x23, 0x9a, 0x05, 0x63, 0x1f, 0xe6, 0xea, 0x5f, 0x31, 0x61, 0xe5, 0x3a, 0xb3, 0xa4, 0x85, 0x94, 0xa5, 0x05, 0xbb, 0xd8, 0x1e, 0xac, 0x14, 0xba, 0xdd, 0x85, 0x32}}, + {{0xc3, 0x9d, 0xeb, 0x0c, 0xd0, 0xc0, 0x49, 0xe5, 0x39, 0xaa, 0x21, 0xb4, 0xf6, 0x7c, 0x73, 0xd2, 0x2b, 0x3a, 0x8f, 0x5a, 0xa0, 0x32, 0xd6, 0x97, 0x6c, 0xa3, 0x0c, 0x8e, 0x47, 0x5f, 0x24, 0x3c}, {0x8b, 0x7d, 0x4a, 0xaa, 0x37, 0x8a, 0x0b, 0xf2, 0xda, 0x23, 0x20, 0x56, 0x0c, 0xe0, 0x89, 0x81, 0x47, 0x81, 0x27, 0x2f, 0x54, 0xd1, 0xff, 0x5a, 0x15, 0x1c, 0x90, 0x16, 0x9b, 0xd6, 0xa2, 0x03}}, + {{0xb8, 0x63, 0x43, 0x2a, 0x71, 0xec, 0xb8, 0x1d, 0x60, 0xc0, 0x26, 0x68, 0x49, 0x3a, 0x20, 0x89, 0xdd, 0x0a, 0x30, 0xda, 0xe8, 0x38, 0x52, 0xab, 0x83, 0xfd, 0xf9, 0x05, 0x64, 0xc0, 0xba, 0x1f}, {0x48, 0xc7, 0x3e, 0xfd, 0x6a, 0x28, 0xca, 0x35, 0x3a, 0x2a, 0xd4, 0xdb, 0x71, 0xe2, 0x74, 0x4d, 0x4b, 0x30, 0x10, 0xe3, 0xff, 0x48, 0xf7, 0x1a, 0x9c, 0x70, 0xbe, 0x6b, 0x64, 0x48, 0xe5, 0x38}}, + {{0xa5, 0x46, 0x17, 0xc4, 0x80, 0x64, 0x3f, 0x9c, 0x10, 0xec, 0x55, 0x96, 0xcb, 0x11, 0x55, 0x74, 0xba, 0xc3, 0xdf, 0x92, 0x95, 0xd9, 0x30, 0x0b, 0x95, 0x56, 0x2d, 0xaa, 0x08, 0xd2, 0xb5, 0x04}, {0x0b, 0x2f, 0x80, 0xdb, 0x8a, 0x14, 0xfa, 0xe3, 0x7b, 0xf2, 0x21, 0xcc, 0xdb, 0xde, 0x2a, 0x69, 0x61, 0x01, 0x5e, 0x81, 0x53, 0x32, 0xbd, 0xe5, 0xb3, 0xd7, 0xb7, 0x74, 0x6a, 0x83, 0xae, 0x06}}, + {{0x33, 0x82, 0x3a, 0x63, 0xe7, 0x7f, 0xa6, 0x23, 0xac, 0x4f, 0x71, 0x7e, 0xca, 0x4e, 0x9a, 0xfb, 0xcd, 0x24, 0xbd, 0xa5, 0x5f, 0xef, 0x0d, 0x95, 0x6c, 0xe3, 0xdd, 0x68, 0x53, 0x48, 0x7a, 0x18}, {0x54, 0x3e, 0x66, 0x96, 0x76, 0x63, 0xd9, 0x4a, 0xab, 0x7e, 0x44, 0x47, 0x72, 0x60, 0x5b, 0x93, 0x17, 0xba, 0xf4, 0x0c, 0x01, 0xef, 0xd0, 0x40, 0x4e, 0xef, 0x7b, 0xe0, 0x8f, 0x8f, 0xd6, 0x2b}}, + {{0x18, 0x8c, 0x7b, 0x14, 0xa7, 0x82, 0x69, 0xe2, 0x5d, 0xbe, 0xb9, 0xb9, 0xc4, 0xe6, 0x7b, 0x60, 0xef, 0xe0, 0xdb, 0xb3, 0x7b, 0x30, 0x2d, 0xe3, 0xb0, 0xc8, 0xd3, 0x80, 0x0b, 0x01, 0x76, 0x3a}, {0x92, 0x84, 0x74, 0xa6, 0x6c, 0x14, 0xa9, 0x06, 0x1b, 0x73, 0xaa, 0x49, 0x6b, 0x2d, 0x4b, 0xce, 0xbb, 0x95, 0x5a, 0x4a, 0x3d, 0x87, 0x5b, 0x79, 0x46, 0x7a, 0x76, 0x98, 0x8d, 0x77, 0xe5, 0x19}}, + {{0xca, 0xfd, 0x69, 0x83, 0x28, 0xe5, 0xc9, 0x02, 0xec, 0x62, 0x46, 0xd9, 0xed, 0x8e, 0x6f, 0x54, 0x88, 0xa0, 0xbd, 0x12, 0x26, 0x8b, 0xc4, 0xa4, 0x53, 0x2c, 0x49, 0xcb, 0xbc, 0xab, 0x51, 0x35}, {0xf7, 0xb4, 0xa1, 0x29, 0x04, 0xb7, 0xbe, 0xdf, 0x61, 0x19, 0xa9, 0x0c, 0x50, 0x73, 0x43, 0x69, 0x05, 0x57, 0xd1, 0x2d, 0x5d, 0xbc, 0xf2, 0x4c, 0x76, 0x04, 0x4d, 0x49, 0x7f, 0x16, 0x41, 0x23}}, + {{0x6f, 0x35, 0xab, 0x8b, 0xd5, 0x67, 0xc8, 0xae, 0x66, 0x26, 0x97, 0xe7, 0x89, 0x34, 0x07, 0x5a, 0x87, 0x58, 0x88, 0x85, 0x0b, 0xe0, 0x93, 0xe5, 0xcc, 0x1b, 0xd8, 0x8b, 0xb7, 0x8e, 0x98, 0x32}, {0xbe, 0xbd, 0x27, 0xd1, 0x3b, 0x44, 0x3c, 0xca, 0x2f, 0x23, 0xf9, 0xcb, 0x87, 0xdb, 0xf6, 0x53, 0x8d, 0x40, 0x75, 0x13, 0x81, 0x3c, 0x5e, 0x92, 0x11, 0x9c, 0x48, 0xda, 0xbb, 0xd3, 0x2f, 0x36}}, + {{0xac, 0xe3, 0x4c, 0x79, 0xd0, 0x85, 0x10, 0x60, 0x0a, 0xff, 0x2e, 0x42, 0x69, 0x79, 0x2b, 0x16, 0x4d, 0x32, 0x18, 0x97, 0x4b, 0x7c, 0x12, 0xfa, 0xb0, 0x6e, 0x18, 0xac, 0xba, 0x74, 0xeb, 0x05}, {0xd4, 0xdb, 0xad, 0x37, 0x76, 0x61, 0x9c, 0xfa, 0x49, 0xc9, 0x26, 0x96, 0x5f, 0x98, 0x7b, 0xd7, 0x7a, 0x4e, 0xa6, 0x34, 0xb7, 0xde, 0xe4, 0x53, 0xcf, 0x93, 0xbb, 0x91, 0x31, 0x27, 0x33, 0x11}}, + {{0x34, 0x16, 0xb4, 0x08, 0x17, 0xfb, 0xc9, 0x96, 0x92, 0xcb, 0x24, 0x2d, 0x5e, 0xbc, 0xa6, 0xa9, 0x70, 0x38, 0x16, 0xfd, 0x2b, 0xa2, 0x4c, 0x83, 0x99, 0xfc, 0x41, 0x11, 0x12, 0xae, 0x56, 0x3e}, {0x93, 0x9f, 0x3f, 0x16, 0xbc, 0x4d, 0xbb, 0x50, 0x93, 0x3b, 0x60, 0xff, 0x15, 0x6f, 0x25, 0x1e, 0x6b, 0x8a, 0x6c, 0xb6, 0x6f, 0xaa, 0x61, 0x3e, 0xc0, 0xe3, 0xb8, 0x06, 0x21, 0xda, 0xe2, 0x00}}, + {{0x13, 0xb5, 0xb6, 0x23, 0x79, 0x8b, 0xdd, 0x42, 0x9d, 0x77, 0x9a, 0xb5, 0x04, 0xbf, 0x85, 0xea, 0xdd, 0x72, 0x1a, 0xa0, 0x50, 0xfa, 0xa9, 0xb0, 0xf4, 0x1f, 0x74, 0x41, 0x38, 0x0b, 0xa0, 0x08}, {0x9b, 0xff, 0x1e, 0x3f, 0x14, 0xe0, 0xcb, 0x64, 0xb9, 0x15, 0xe7, 0x67, 0xf2, 0x12, 0x45, 0xa1, 0x11, 0x36, 0x1b, 0x8d, 0xcc, 0x3a, 0xfc, 0xd5, 0x6b, 0xee, 0x6d, 0x7f, 0x1f, 0xcf, 0x17, 0x27}}, + {{0x3d, 0xc3, 0xdb, 0x0c, 0x5e, 0x92, 0xe3, 0x11, 0x78, 0x47, 0xc3, 0x51, 0x34, 0xd4, 0x8e, 0xbc, 0x31, 0x9b, 0x43, 0x97, 0x3c, 0x85, 0x04, 0x73, 0x1d, 0x62, 0x6c, 0x95, 0xd3, 0x7a, 0xda, 0x1a}, {0x7b, 0x91, 0x72, 0x7f, 0x05, 0xed, 0x0f, 0x55, 0x78, 0x60, 0xcd, 0x73, 0x15, 0xcf, 0x45, 0x23, 0x21, 0xf9, 0x99, 0x84, 0xde, 0xbe, 0x0f, 0xc0, 0x65, 0x33, 0x2e, 0xeb, 0xfc, 0x21, 0x35, 0x39}}, + {{0x35, 0xf2, 0xa3, 0x16, 0x3c, 0xcc, 0xdc, 0x0a, 0x03, 0xac, 0x85, 0x8d, 0xb3, 0xdc, 0x76, 0x26, 0x54, 0x3f, 0x32, 0x32, 0x06, 0xfa, 0xc2, 0xb7, 0x6c, 0x26, 0x68, 0x81, 0x4e, 0xc0, 0x00, 0x1b}, {0x81, 0x63, 0xb2, 0xc6, 0x75, 0xf9, 0xb8, 0x22, 0x89, 0x65, 0x7f, 0x87, 0x21, 0xf5, 0xa0, 0x64, 0xb2, 0xb2, 0x46, 0x62, 0x34, 0x39, 0xe4, 0x0d, 0x68, 0xc9, 0x67, 0xc8, 0x63, 0x0d, 0xab, 0x10}}, + {{0x10, 0xcb, 0x4e, 0x05, 0x9f, 0x4d, 0xff, 0x72, 0x53, 0x3c, 0x71, 0x10, 0xc5, 0xc6, 0xcc, 0x28, 0xcf, 0x7b, 0x40, 0x36, 0xa1, 0x3c, 0x44, 0x41, 0xe3, 0xdc, 0x48, 0x82, 0x54, 0x8a, 0xa1, 0x3c}, {0xa9, 0x23, 0xf6, 0xc4, 0x07, 0x86, 0xb5, 0x74, 0xe8, 0xb4, 0x24, 0x40, 0xce, 0x86, 0xcf, 0x52, 0xb8, 0x9e, 0xa9, 0x8f, 0xde, 0x22, 0x1f, 0x0c, 0x12, 0x28, 0x17, 0x28, 0x7c, 0x9d, 0xd1, 0x06}}, + {{0x1a, 0xb4, 0x25, 0x1a, 0xcb, 0x9e, 0x29, 0x34, 0x53, 0x4f, 0x0f, 0x43, 0xcd, 0xe2, 0x20, 0x4c, 0x85, 0x63, 0xfa, 0x5d, 0xe7, 0x8d, 0xac, 0xd3, 0xaa, 0x49, 0x0d, 0x29, 0x9f, 0x54, 0x5d, 0x31}, {0xda, 0x01, 0x91, 0x73, 0x7a, 0x7a, 0x0a, 0x95, 0xc5, 0x15, 0x59, 0x2b, 0x17, 0x44, 0x6e, 0xd0, 0x5b, 0x8a, 0x2c, 0xc3, 0x6b, 0xd5, 0x72, 0x88, 0x4c, 0x64, 0xf9, 0x64, 0x5d, 0xa4, 0x28, 0x1f}}, + {{0x5a, 0xdd, 0x9c, 0x3f, 0x2b, 0xb8, 0x62, 0xec, 0x0f, 0x26, 0x89, 0xba, 0xe0, 0x68, 0xe4, 0x53, 0x63, 0x8a, 0x44, 0x66, 0x40, 0xb8, 0x71, 0xbf, 0xca, 0xa6, 0x0e, 0x30, 0x78, 0x25, 0x7d, 0x1a}, {0x43, 0x34, 0x52, 0x79, 0xe1, 0xea, 0xd2, 0xdf, 0x43, 0x3e, 0x58, 0x90, 0x4b, 0x28, 0x53, 0xe7, 0xec, 0xb2, 0x3e, 0xe0, 0x70, 0xe3, 0x50, 0x38, 0xca, 0x41, 0xb5, 0x10, 0x42, 0x1e, 0xf2, 0x24}}, + {{0x6b, 0x05, 0x39, 0xd7, 0xf3, 0x69, 0x60, 0x39, 0x9b, 0xa9, 0x0a, 0x24, 0x7d, 0x25, 0x84, 0x2f, 0x47, 0x3e, 0x2e, 0x1d, 0x3e, 0x6a, 0xbc, 0xcb, 0x88, 0x6c, 0xf5, 0x60, 0xfd, 0x11, 0xf2, 0x32}, {0xd6, 0x01, 0xe7, 0xf3, 0x0a, 0xdc, 0x93, 0x89, 0xfb, 0x1f, 0x5f, 0x3d, 0x08, 0x7f, 0x49, 0x3c, 0x80, 0x40, 0x2e, 0x76, 0xc3, 0x98, 0x69, 0x7c, 0x62, 0x49, 0xd8, 0x47, 0x09, 0xcd, 0xff, 0x25}}, + {{0x05, 0x05, 0x5e, 0xa0, 0x7a, 0xdf, 0xeb, 0x00, 0x9a, 0x76, 0x8d, 0x8a, 0xfe, 0x73, 0xd7, 0x32, 0x5d, 0xc7, 0x94, 0xba, 0xe0, 0x4a, 0xd7, 0xa0, 0xb8, 0x6a, 0x19, 0xbf, 0x28, 0x68, 0x8f, 0x02}, {0x3f, 0xcb, 0xa1, 0xdb, 0x61, 0x07, 0x40, 0x12, 0x21, 0xc1, 0xee, 0x5a, 0x09, 0x7e, 0x39, 0xf4, 0x85, 0xc0, 0xaf, 0xcd, 0xbe, 0x26, 0x39, 0x9a, 0x55, 0xd9, 0x22, 0x22, 0x6d, 0x6e, 0xd1, 0x11}}, + {{0xfe, 0x50, 0x5e, 0xa4, 0xc8, 0xea, 0x43, 0xeb, 0xca, 0xe4, 0xb9, 0x9f, 0x55, 0x31, 0xe1, 0x76, 0x78, 0x0d, 0x1b, 0x3f, 0x04, 0x71, 0x66, 0x8f, 0xa5, 0x3b, 0x26, 0x62, 0xa3, 0x64, 0xc9, 0x0d}, {0xea, 0xd9, 0xf7, 0x98, 0x80, 0xa2, 0x43, 0x24, 0x2d, 0x18, 0xfc, 0x13, 0x11, 0x9d, 0x73, 0x78, 0x7e, 0x27, 0xdf, 0x30, 0x84, 0x6c, 0x2c, 0xd6, 0xad, 0x77, 0xf0, 0x29, 0xf2, 0x79, 0x81, 0x39}}, + {{0xa6, 0x41, 0x8b, 0xe1, 0xe1, 0x83, 0x3b, 0x3f, 0x0e, 0x1f, 0x99, 0xd4, 0xd0, 0xb7, 0x79, 0xe8, 0xa4, 0xa3, 0x57, 0xdc, 0x91, 0x52, 0x14, 0x3a, 0x8d, 0x42, 0x1b, 0xa5, 0xa3, 0x64, 0x06, 0x11}, {0x7e, 0xfc, 0x93, 0xd7, 0x5d, 0x83, 0xcb, 0x9a, 0xac, 0x69, 0x1d, 0x7b, 0xbc, 0xbb, 0x5e, 0x69, 0xeb, 0x77, 0x41, 0x24, 0xef, 0xbf, 0x8d, 0x41, 0x31, 0xc6, 0x61, 0x88, 0x59, 0x0d, 0x03, 0x0e}}, + {{0x17, 0x4a, 0x79, 0x3d, 0xbb, 0x1b, 0x6c, 0x67, 0x24, 0x18, 0x0b, 0xa3, 0xb1, 0x40, 0xf7, 0x86, 0xcd, 0xd6, 0x6e, 0x2c, 0x38, 0x81, 0x14, 0x04, 0x88, 0xb8, 0xa9, 0xac, 0x7a, 0x26, 0x60, 0x24}, {0xa3, 0x91, 0xde, 0xc2, 0xe4, 0x28, 0x8e, 0x4b, 0xe7, 0x72, 0x90, 0xbb, 0xe6, 0x23, 0xb9, 0x0e, 0x4b, 0xd6, 0x18, 0x95, 0xa1, 0xc9, 0xa5, 0x84, 0x63, 0xf5, 0xfe, 0xc7, 0x4f, 0x85, 0x28, 0x20}}, + {{0xdc, 0x5e, 0xb3, 0xb4, 0x1b, 0x0b, 0x55, 0xec, 0xf1, 0x44, 0xa0, 0xa2, 0x13, 0xe7, 0xd6, 0x9b, 0x9b, 0x84, 0x15, 0xe2, 0x2f, 0xd5, 0xb7, 0x1b, 0x89, 0xe5, 0xa8, 0x60, 0x5a, 0x4a, 0x3b, 0x2a}, {0x7b, 0x90, 0xf9, 0x47, 0x09, 0x82, 0xdb, 0x37, 0x37, 0xec, 0xd0, 0xfe, 0x5f, 0xa9, 0x06, 0x96, 0x91, 0x2a, 0xdb, 0x06, 0x91, 0xf4, 0xa5, 0xa4, 0x7b, 0x96, 0x44, 0x8a, 0x45, 0x8e, 0xc3, 0x2d}}, + {{0x6c, 0xeb, 0xf9, 0xd9, 0x99, 0x34, 0x40, 0xac, 0x88, 0x2e, 0xa1, 0xf3, 0xc4, 0xa7, 0x6d, 0x02, 0x6b, 0xa6, 0x67, 0x18, 0xff, 0x04, 0xfa, 0x7d, 0xa9, 0x13, 0x24, 0xe4, 0x29, 0x4e, 0x80, 0x09}, {0x5f, 0x05, 0x0a, 0x3a, 0x8c, 0x21, 0xb5, 0x51, 0xbb, 0x34, 0x61, 0x74, 0xfd, 0xc1, 0xdc, 0x5d, 0x00, 0xc4, 0x53, 0xcf, 0xf0, 0xcd, 0x96, 0x36, 0x20, 0x0c, 0x8f, 0x79, 0x64, 0x13, 0x94, 0x35}}, + {{0x42, 0x32, 0xcb, 0x25, 0xfc, 0x7c, 0xa7, 0xe6, 0x88, 0x29, 0x37, 0x88, 0xf5, 0xd7, 0x31, 0x2c, 0x85, 0xac, 0x07, 0xa4, 0x94, 0x90, 0x2e, 0x56, 0x80, 0xe1, 0x22, 0x26, 0xfb, 0xef, 0xb1, 0x3a}, {0x57, 0x65, 0x7c, 0x59, 0xcf, 0xbd, 0x24, 0xb4, 0x19, 0x22, 0x67, 0xba, 0xf9, 0x48, 0xa3, 0xed, 0xcd, 0xd3, 0xf2, 0x63, 0x7b, 0xe3, 0x1a, 0x8c, 0x9a, 0x09, 0x2f, 0x5a, 0x5a, 0xed, 0xf7, 0x26}}, + {{0x12, 0x72, 0xed, 0xdd, 0x3e, 0x86, 0x97, 0xd2, 0xbc, 0xbe, 0x36, 0x3e, 0x7e, 0x2b, 0x1b, 0xf9, 0xb9, 0x08, 0xbf, 0x04, 0x46, 0xd4, 0xff, 0xae, 0x4e, 0xc7, 0x7c, 0xab, 0xdd, 0x95, 0x67, 0x24}, {0x04, 0xf7, 0x75, 0xe9, 0xde, 0x53, 0x13, 0xc7, 0x08, 0x04, 0x4d, 0x64, 0x3d, 0x04, 0x76, 0xb2, 0xad, 0xde, 0x75, 0x30, 0xed, 0x7f, 0x78, 0x58, 0x7a, 0xae, 0x9b, 0x20, 0x39, 0xe9, 0x71, 0x27}}, + {{0xf9, 0x99, 0x3d, 0x37, 0xd7, 0x9a, 0xdd, 0x06, 0x6a, 0xfa, 0x08, 0xb6, 0x54, 0x60, 0x73, 0x8a, 0xb5, 0x33, 0x93, 0x22, 0xd3, 0x7e, 0x11, 0x34, 0xde, 0x02, 0x21, 0x20, 0x8a, 0x7d, 0x33, 0x2e}, {0x33, 0xd6, 0x3b, 0xa7, 0xd0, 0x16, 0xee, 0xc3, 0x88, 0xb2, 0x65, 0x2b, 0xe9, 0x08, 0x5f, 0xd2, 0xb9, 0x28, 0x1a, 0x30, 0xce, 0x08, 0x6a, 0xc2, 0xbe, 0x39, 0x6f, 0x14, 0x8f, 0x35, 0x35, 0x39}}, + {{0x5b, 0xce, 0xef, 0xf6, 0x0c, 0xb5, 0x5b, 0x3f, 0x5d, 0x4c, 0x67, 0x5f, 0xe4, 0x32, 0x6d, 0xb7, 0x4b, 0xbb, 0xd7, 0x2b, 0xf1, 0x7f, 0xa1, 0xca, 0xb2, 0x06, 0x4d, 0xb9, 0xfd, 0xce, 0x8d, 0x1b}, {0x78, 0x20, 0x83, 0x2c, 0x14, 0xb0, 0x69, 0xa4, 0x8f, 0x47, 0x58, 0x2a, 0x69, 0xae, 0x17, 0x4d, 0x6b, 0x38, 0x47, 0x69, 0xee, 0xc0, 0x08, 0xcc, 0x51, 0x48, 0x2d, 0x31, 0xa3, 0x6b, 0x28, 0x14}}, + {{0x37, 0x03, 0x1a, 0xa4, 0xe9, 0xb3, 0x3d, 0x2f, 0x6d, 0xa2, 0x67, 0x3f, 0x23, 0x7f, 0xa4, 0x03, 0x5b, 0x35, 0xc3, 0xbf, 0xcf, 0xfe, 0xc2, 0x28, 0x81, 0xf4, 0x2e, 0xbd, 0x0a, 0x96, 0xbc, 0x2b}, {0x86, 0x21, 0x21, 0xb1, 0x52, 0x09, 0x11, 0xc3, 0x53, 0xfc, 0xd5, 0x48, 0x01, 0x52, 0x87, 0x2e, 0x2c, 0xda, 0x6a, 0xa9, 0xf6, 0x9f, 0x5c, 0x87, 0xe5, 0xa5, 0x15, 0xd4, 0x35, 0x49, 0x23, 0x02}}, + {{0xfe, 0x56, 0xe2, 0x22, 0x15, 0x84, 0xf0, 0x36, 0x26, 0xf1, 0xb1, 0x1c, 0x96, 0x4c, 0x55, 0x6d, 0xd6, 0x0f, 0xeb, 0xdc, 0xc5, 0xe6, 0xbe, 0xef, 0x0c, 0x18, 0x7a, 0xd9, 0xec, 0xb1, 0xe2, 0x3d}, {0x66, 0x9b, 0xe6, 0xaa, 0x95, 0xab, 0x04, 0x53, 0x93, 0x79, 0x80, 0x0c, 0x93, 0x38, 0xed, 0x60, 0x3e, 0x4a, 0xf5, 0x6f, 0x8d, 0x3e, 0xb4, 0xd9, 0x90, 0x30, 0xba, 0x16, 0x36, 0x8e, 0xfc, 0x18}}, + {{0xf0, 0x69, 0xfe, 0x4d, 0x85, 0xd8, 0x22, 0x08, 0x38, 0xdc, 0xf1, 0xcc, 0x45, 0x1f, 0x5e, 0x50, 0x84, 0x8b, 0xec, 0x7e, 0x0a, 0x64, 0x8a, 0x62, 0x01, 0x9c, 0xc8, 0x14, 0xd3, 0x23, 0x27, 0x01}, {0x36, 0x77, 0xd4, 0xd5, 0xcb, 0xf3, 0x4e, 0x7e, 0xac, 0x5b, 0xe5, 0xd6, 0xbd, 0x2f, 0x0b, 0x85, 0x02, 0x96, 0xf3, 0x18, 0xc2, 0x3b, 0x2f, 0x6c, 0x1f, 0xf1, 0xdc, 0x28, 0x70, 0x13, 0x35, 0x25}}, + {{0xfe, 0xa6, 0xd2, 0x3a, 0xeb, 0x90, 0x34, 0xa1, 0x0a, 0x31, 0x4d, 0x08, 0x63, 0x11, 0x67, 0x0b, 0x13, 0x16, 0xca, 0x08, 0xcb, 0x15, 0xdf, 0x86, 0x67, 0x61, 0x1c, 0x8d, 0x67, 0x09, 0x86, 0x21}, {0x43, 0x90, 0x3d, 0x61, 0x4b, 0x95, 0xde, 0x58, 0xde, 0x5c, 0x4a, 0x9d, 0x72, 0xa0, 0xdf, 0x4c, 0x09, 0x75, 0x00, 0xb9, 0x58, 0xf0, 0xa4, 0xd2, 0xfb, 0x94, 0x5e, 0xe8, 0x63, 0x6d, 0x60, 0x26}}, + {{0x59, 0x30, 0x2e, 0x51, 0x83, 0xc3, 0xee, 0x1b, 0x31, 0xb5, 0x35, 0xaf, 0xef, 0x6d, 0xe4, 0x75, 0x69, 0x74, 0xfa, 0x89, 0x6c, 0x86, 0xcb, 0x25, 0x35, 0xc6, 0x9c, 0x70, 0xc8, 0xa9, 0x00, 0x23}, {0x3a, 0xdd, 0xb6, 0xd8, 0x0a, 0xba, 0xfe, 0x30, 0x7b, 0xa1, 0x6c, 0x3c, 0x9a, 0x28, 0x7b, 0xfe, 0x95, 0x05, 0x92, 0x4f, 0x3f, 0x76, 0x6a, 0x7a, 0x1c, 0xf8, 0x7d, 0x78, 0xfe, 0xe3, 0x69, 0x06}}, + {{0x5a, 0xfb, 0xc1, 0x2b, 0x7e, 0xaf, 0x17, 0x23, 0x7a, 0xc5, 0x76, 0x0f, 0x3c, 0xa8, 0xa0, 0x4f, 0xf4, 0x2a, 0x18, 0xe9, 0x50, 0x18, 0x4d, 0xad, 0x24, 0xa7, 0x09, 0x99, 0x4e, 0x29, 0x95, 0x30}, {0xee, 0x15, 0x22, 0xc0, 0x2b, 0x71, 0x4c, 0xb0, 0x5d, 0x37, 0x88, 0xc5, 0x20, 0x0f, 0x18, 0xf1, 0x93, 0xbf, 0x7d, 0x9f, 0xd2, 0xde, 0xbd, 0xaa, 0x04, 0xdc, 0xf6, 0x7f, 0x0e, 0xa1, 0x0b, 0x17}}, + {{0x5d, 0x16, 0x11, 0x64, 0x37, 0xca, 0x14, 0x46, 0xea, 0xd2, 0xf2, 0x1c, 0xff, 0x19, 0x5e, 0xfe, 0x9b, 0xf2, 0xb7, 0x75, 0x2b, 0x70, 0x57, 0xfd, 0x1a, 0x32, 0xb5, 0x4e, 0x96, 0x3d, 0x1b, 0x2d}, {0xd7, 0x94, 0x52, 0x8c, 0xb1, 0x6f, 0xb0, 0x03, 0xaf, 0x83, 0x58, 0xa6, 0xa7, 0xd2, 0x82, 0xd2, 0x4e, 0x25, 0xef, 0xb3, 0xbc, 0xb5, 0x6d, 0x13, 0xeb, 0x9a, 0xfe, 0x61, 0xf8, 0x5e, 0x8c, 0x2e}}, + {{0x0f, 0xfe, 0xd7, 0x18, 0xaa, 0xd5, 0xcc, 0x79, 0xc5, 0x9f, 0x84, 0x7f, 0x2a, 0xe4, 0xfb, 0x21, 0x1c, 0xf9, 0xa4, 0x52, 0x6b, 0xf3, 0x28, 0x6a, 0x69, 0x04, 0xda, 0x2d, 0x72, 0xe6, 0x1d, 0x01}, {0x9c, 0xdc, 0x53, 0x2c, 0x30, 0x97, 0x07, 0x4f, 0x85, 0xcf, 0x2b, 0xb0, 0x09, 0xa7, 0x9d, 0x6c, 0x53, 0x37, 0x08, 0x27, 0xa1, 0xcd, 0xf0, 0x6b, 0x60, 0xeb, 0x96, 0x45, 0xfa, 0xa1, 0xad, 0x02}}, + {{0xb7, 0x11, 0x5e, 0xd4, 0x26, 0xd9, 0xf1, 0x74, 0xa2, 0x87, 0x37, 0x0e, 0x4b, 0x97, 0x48, 0x1c, 0x08, 0xee, 0x60, 0x25, 0xb1, 0x54, 0x4f, 0x57, 0x8b, 0xfa, 0x9b, 0xff, 0xcd, 0xa6, 0x17, 0x1a}, {0xdd, 0x6f, 0xc2, 0x18, 0x0a, 0x43, 0xbd, 0x65, 0xb4, 0x44, 0xff, 0x5f, 0x26, 0xf2, 0xa7, 0x06, 0xa6, 0xd4, 0x0e, 0x32, 0x17, 0x27, 0x0f, 0x60, 0x6b, 0xa0, 0x95, 0xac, 0x95, 0x4e, 0x3b, 0x0c}}, + {{0x69, 0x26, 0xe6, 0x26, 0xc6, 0xaf, 0x8b, 0xb1, 0x0b, 0x29, 0x7d, 0x40, 0xc8, 0x90, 0xde, 0x34, 0x0e, 0x68, 0x58, 0xfe, 0x71, 0x80, 0xc9, 0x47, 0x16, 0x4b, 0x20, 0xc9, 0xe0, 0x01, 0x74, 0x12}, {0x45, 0xfc, 0x92, 0x2f, 0xa5, 0xe7, 0x2d, 0x33, 0x9d, 0x1a, 0x6b, 0x68, 0xc6, 0xcd, 0x17, 0xc9, 0x68, 0x8b, 0xe0, 0x72, 0xfe, 0x76, 0x6c, 0xb8, 0x0f, 0xb7, 0x5a, 0x54, 0xca, 0x39, 0x4f, 0x0b}}, + {{0x4a, 0xcc, 0xb9, 0xbc, 0x70, 0x36, 0x17, 0xc4, 0x92, 0x21, 0x64, 0x0b, 0xb8, 0xf1, 0x5c, 0xbd, 0xfb, 0xc2, 0x09, 0x8e, 0x02, 0x6a, 0x97, 0x18, 0x32, 0x87, 0xa4, 0x79, 0x1a, 0x65, 0x7e, 0x18}, {0xaf, 0xc1, 0x94, 0x52, 0x7d, 0x5d, 0x69, 0xae, 0x54, 0xbf, 0x13, 0xe8, 0x4c, 0x65, 0x34, 0x19, 0xdd, 0xc2, 0x3d, 0x29, 0x6f, 0xb2, 0x2c, 0x64, 0x63, 0xda, 0x7b, 0x51, 0x31, 0xe0, 0x2c, 0x09}}, + {{0x79, 0xbc, 0xc9, 0xec, 0x07, 0x8a, 0x62, 0x76, 0xb3, 0x5b, 0xa6, 0xaa, 0x86, 0x1f, 0xb2, 0x8c, 0x26, 0xd2, 0x56, 0x8a, 0x23, 0xcf, 0x09, 0xbb, 0x1a, 0x35, 0xa6, 0x19, 0x7b, 0x5d, 0x1a, 0x1c}, {0xaf, 0x71, 0x5c, 0xfe, 0x31, 0x87, 0x9f, 0xfe, 0xcf, 0xc6, 0x60, 0x76, 0x82, 0x80, 0x8d, 0xdd, 0xf6, 0xb4, 0x7d, 0x60, 0x46, 0xbb, 0xfb, 0xa2, 0xf4, 0x02, 0xfa, 0x29, 0xc4, 0xde, 0x6c, 0x06}}, + {{0xb9, 0xfa, 0xcd, 0x4d, 0x99, 0x38, 0xba, 0xfe, 0xe9, 0xb2, 0xa8, 0x53, 0xe0, 0xbe, 0x85, 0x01, 0x6c, 0xda, 0x19, 0x67, 0xe3, 0x4a, 0x18, 0x2d, 0x8c, 0x4e, 0xfc, 0x97, 0x43, 0xde, 0xde, 0x38}, {0x96, 0x5a, 0x49, 0x97, 0x56, 0x1a, 0x8c, 0xaf, 0xf8, 0x3f, 0x61, 0x56, 0xef, 0x43, 0xaf, 0x1e, 0xed, 0xfc, 0xc4, 0x44, 0xce, 0x2c, 0x65, 0xfe, 0xf4, 0xf2, 0x91, 0x2d, 0x9b, 0xf6, 0xca, 0x24}}, + {{0x8a, 0x88, 0xe8, 0x3f, 0x15, 0x23, 0x0e, 0x05, 0xda, 0xea, 0xfb, 0xd7, 0x94, 0x75, 0xd6, 0x5c, 0x9e, 0x16, 0xfa, 0x5f, 0xac, 0x89, 0x90, 0x58, 0x77, 0x0a, 0x79, 0x02, 0x4e, 0xdb, 0x7a, 0x2c}, {0x0b, 0x31, 0x89, 0x48, 0x4c, 0x6f, 0xe5, 0xac, 0x97, 0x2d, 0xa8, 0x49, 0xe6, 0xa3, 0xcb, 0x36, 0xef, 0x02, 0x72, 0x4d, 0x71, 0x5f, 0x3f, 0x0a, 0xd8, 0xb3, 0x66, 0xec, 0xc6, 0x12, 0xe9, 0x34}}, + {{0x38, 0x44, 0x3c, 0x93, 0xa6, 0x8c, 0x2d, 0x8d, 0x61, 0x3f, 0xf3, 0x54, 0x09, 0xb6, 0xf0, 0xd7, 0x4c, 0xf9, 0xed, 0x13, 0xcc, 0xe7, 0x3b, 0xe9, 0x86, 0xaf, 0x55, 0x6b, 0x4c, 0xbe, 0x4a, 0x11}, {0xb7, 0x22, 0x10, 0x70, 0xf1, 0x62, 0x37, 0x18, 0x98, 0xa6, 0xa2, 0xd2, 0x3d, 0x6b, 0x11, 0x48, 0x8e, 0x18, 0xf3, 0xa3, 0x7f, 0x85, 0x41, 0xea, 0x43, 0x77, 0xba, 0x65, 0x38, 0x18, 0xb5, 0x1f}}, + {{0x78, 0xf5, 0xa3, 0xd8, 0x60, 0x8c, 0x82, 0xa0, 0x8f, 0x6c, 0x3f, 0x65, 0x4f, 0x68, 0x25, 0x0a, 0x26, 0x77, 0x66, 0xdc, 0xc4, 0x9d, 0x4d, 0x2b, 0x1d, 0x65, 0x81, 0xd6, 0x48, 0x20, 0xc8, 0x36}, {0x9c, 0xc2, 0x0a, 0x23, 0x96, 0x91, 0x6c, 0xe2, 0x1b, 0x07, 0x18, 0xbc, 0x78, 0x03, 0xfb, 0x08, 0x27, 0xa7, 0x78, 0xc5, 0x44, 0x8f, 0xa0, 0x75, 0x10, 0x9c, 0xdc, 0x24, 0x96, 0x71, 0xee, 0x15}}, + {{0x18, 0xcc, 0xf3, 0xd7, 0xbf, 0x76, 0xaa, 0xfe, 0xa5, 0xe9, 0x2b, 0xff, 0xbe, 0xd0, 0x70, 0x7d, 0x99, 0xe8, 0x9f, 0x81, 0xe3, 0xad, 0xb7, 0xbf, 0xa2, 0x89, 0x01, 0x82, 0x7f, 0x59, 0x80, 0x0a}, {0xcb, 0xab, 0x73, 0x5e, 0xf8, 0x7c, 0x0c, 0x7c, 0xee, 0x04, 0x06, 0xc1, 0x40, 0x39, 0xb0, 0xef, 0x43, 0xef, 0x14, 0x3d, 0x88, 0xc5, 0xe4, 0x85, 0xb7, 0x97, 0x0a, 0x9d, 0xb2, 0xfb, 0xfe, 0x27}}, + {{0xbe, 0xbd, 0x4f, 0x68, 0x88, 0xa8, 0xc6, 0x47, 0x79, 0x52, 0x19, 0x0e, 0x44, 0x21, 0x27, 0x54, 0xea, 0xac, 0x9c, 0x84, 0x23, 0x79, 0xb3, 0xf6, 0xf1, 0x34, 0x33, 0x33, 0x73, 0x41, 0xf3, 0x34}, {0xd4, 0xda, 0xaa, 0xd2, 0x69, 0x18, 0x04, 0x0a, 0x6f, 0xb6, 0xa6, 0xf7, 0x4d, 0x9c, 0xa7, 0x34, 0x3a, 0x6d, 0x1b, 0x12, 0xe9, 0xe1, 0x7b, 0x7b, 0xbc, 0x09, 0xbb, 0xb1, 0x52, 0x7f, 0x21, 0x24}}, + {{0xc0, 0x40, 0xdc, 0x3d, 0xe7, 0xfd, 0x01, 0xfe, 0xde, 0x27, 0xe0, 0x9d, 0xdf, 0x87, 0x31, 0x67, 0xf9, 0x84, 0x24, 0x21, 0xc8, 0x0d, 0x50, 0x21, 0xd1, 0x05, 0xbf, 0x4f, 0xfe, 0x90, 0x64, 0x17}, {0x60, 0x27, 0xde, 0x83, 0xcc, 0xff, 0x96, 0x3e, 0x91, 0x11, 0x69, 0x6e, 0xcc, 0x6c, 0xd3, 0xff, 0xf7, 0x1a, 0xa6, 0x54, 0x5b, 0x95, 0xce, 0xe3, 0x86, 0x18, 0xa0, 0xc2, 0xc1, 0x70, 0x1d, 0x09}}, + {{0x75, 0x60, 0x3e, 0xd1, 0x18, 0x1b, 0x0c, 0xdf, 0x8c, 0xa2, 0x7c, 0x6d, 0xcd, 0xd9, 0x60, 0x36, 0x70, 0x5a, 0x85, 0x5e, 0x2a, 0x74, 0xdb, 0xc8, 0x18, 0xb7, 0xde, 0xfc, 0xdf, 0x63, 0x56, 0x08}, {0xa9, 0x4b, 0xcb, 0xbf, 0x44, 0x3b, 0xc6, 0xdf, 0xa3, 0xe5, 0xda, 0xc6, 0x7a, 0x07, 0xab, 0xe1, 0x6f, 0x10, 0x0a, 0x1d, 0xf8, 0x31, 0x4a, 0x2b, 0x1a, 0xba, 0x41, 0x3c, 0x38, 0x9d, 0xe9, 0x26}}, + {{0xb6, 0x8e, 0xc8, 0x22, 0x19, 0xb7, 0x5b, 0xa5, 0xfd, 0x01, 0x76, 0xf7, 0xd9, 0x93, 0xa9, 0x2b, 0x55, 0xb9, 0x90, 0x45, 0xc3, 0x38, 0x9d, 0xef, 0x85, 0x88, 0xb2, 0x8a, 0xd8, 0x90, 0x3c, 0x39}, {0x18, 0xdc, 0x98, 0x86, 0x6c, 0x9c, 0x67, 0x23, 0x77, 0xed, 0x04, 0xe2, 0x89, 0x1a, 0x75, 0xc3, 0xc5, 0x42, 0xc0, 0x2c, 0x0a, 0xf6, 0xcc, 0xa2, 0xc9, 0xef, 0xf5, 0x31, 0x64, 0x7e, 0x1a, 0x3b}}, + {{0x28, 0x12, 0xd8, 0x93, 0x03, 0x20, 0xaa, 0x01, 0x6a, 0x42, 0x65, 0x61, 0xb4, 0xde, 0x65, 0xd5, 0x19, 0xa2, 0xc3, 0x23, 0xb2, 0xc8, 0x59, 0x13, 0xea, 0xfb, 0x6d, 0x65, 0x3b, 0x22, 0x41, 0x17}, {0x17, 0x66, 0xd2, 0x99, 0x8d, 0xaa, 0xa2, 0x68, 0x5c, 0xe0, 0x95, 0x8e, 0xe3, 0xd5, 0x48, 0x32, 0x5c, 0xa9, 0x53, 0x36, 0x64, 0xe2, 0x47, 0x43, 0x40, 0x2a, 0x9e, 0x00, 0x30, 0xab, 0x6a, 0x3b}}, + {{0xb7, 0xd7, 0x0b, 0xb8, 0xf5, 0xca, 0x01, 0xc4, 0xe4, 0x8d, 0xbc, 0xbb, 0x2f, 0x06, 0x75, 0xd4, 0x4e, 0xd4, 0xa9, 0x55, 0x22, 0xa3, 0x88, 0xf8, 0x4d, 0x46, 0x21, 0x3b, 0xfb, 0x8b, 0x01, 0x1a}, {0x86, 0x43, 0xd2, 0x1c, 0x4e, 0x72, 0x8f, 0x5d, 0xd4, 0xef, 0x40, 0x86, 0x5f, 0x53, 0xa3, 0x78, 0xa1, 0x53, 0x05, 0x49, 0x0a, 0x29, 0xce, 0x47, 0x4c, 0x4a, 0x73, 0x3b, 0xea, 0x7a, 0x91, 0x2a}}, + {{0x09, 0x6e, 0xf2, 0x99, 0xdd, 0x89, 0x4e, 0x03, 0xa9, 0x62, 0xda, 0xe4, 0x00, 0xbd, 0xb5, 0x45, 0x1e, 0x27, 0x88, 0xba, 0xff, 0xdb, 0xf3, 0xeb, 0x0f, 0xaf, 0x98, 0xea, 0x9c, 0x2b, 0xc8, 0x02}, {0x4f, 0xbd, 0x68, 0x65, 0xde, 0xa2, 0xca, 0x3a, 0x43, 0x66, 0xed, 0x3a, 0xfc, 0xcf, 0x44, 0x55, 0x1d, 0x13, 0x59, 0x26, 0x05, 0xd1, 0xf8, 0x52, 0x34, 0xa5, 0x48, 0xf2, 0x44, 0x47, 0x1f, 0x01}}, + {{0x8e, 0xa6, 0x83, 0x51, 0x54, 0x9c, 0x04, 0xe5, 0xfd, 0xdd, 0x04, 0xfd, 0xd0, 0x76, 0xd8, 0xb2, 0x06, 0xfa, 0x17, 0x44, 0xda, 0x0c, 0x66, 0xe2, 0xad, 0x66, 0x2f, 0x29, 0xd1, 0xf5, 0xc0, 0x2b}, {0x04, 0x4d, 0xe4, 0xc7, 0xc1, 0x34, 0xfa, 0x98, 0x54, 0x6a, 0x2c, 0xc9, 0x5a, 0xdf, 0xf0, 0x86, 0x86, 0x6a, 0xc6, 0xe1, 0xbc, 0x25, 0x8a, 0x45, 0x21, 0x74, 0x5f, 0x9a, 0xb7, 0xdd, 0xc6, 0x36}}, + {{0xf5, 0x5d, 0xf9, 0xea, 0xce, 0xb8, 0x9b, 0x30, 0x01, 0xea, 0xba, 0xa4, 0x0f, 0x4b, 0x49, 0x01, 0x72, 0xd1, 0xe6, 0xcc, 0x65, 0x46, 0x24, 0xa1, 0xcd, 0xe4, 0x59, 0x85, 0xee, 0xac, 0x12, 0x34}, {0x9c, 0x03, 0x21, 0x99, 0x37, 0x80, 0x0c, 0xa0, 0x29, 0xf9, 0x26, 0x26, 0xf0, 0x3f, 0xec, 0x26, 0x15, 0x61, 0xc7, 0x1e, 0x84, 0x51, 0x42, 0x7f, 0x3f, 0xde, 0x11, 0x51, 0xa9, 0x4d, 0x32, 0x0d}}, + {{0x48, 0xc3, 0x26, 0x84, 0x14, 0x49, 0x23, 0x06, 0xae, 0xc2, 0xfb, 0x75, 0x8a, 0x75, 0x3b, 0x92, 0x18, 0x3a, 0x1c, 0x8a, 0x9a, 0x47, 0x63, 0x85, 0x26, 0x90, 0x30, 0x6b, 0x89, 0xf1, 0x22, 0x02}, {0x66, 0x9f, 0x58, 0x3a, 0x7a, 0xb8, 0x83, 0x63, 0x04, 0x08, 0x4c, 0xc0, 0xdb, 0x22, 0x68, 0x5d, 0x26, 0x5e, 0xc8, 0xb8, 0x0d, 0x30, 0xd5, 0x3c, 0x81, 0x7f, 0xa9, 0xf5, 0xaf, 0x87, 0xd6, 0x1e}}, + {{0x5a, 0xe0, 0xf4, 0x23, 0xd9, 0xa9, 0x76, 0x49, 0x37, 0x50, 0xf3, 0x80, 0x56, 0xd3, 0xa9, 0x89, 0x79, 0xa6, 0xff, 0x20, 0x0b, 0xd8, 0xce, 0xfc, 0x2e, 0x8c, 0x72, 0xe5, 0x6a, 0xc9, 0xaa, 0x2e}, {0x94, 0xa8, 0xb1, 0x35, 0xc8, 0x9e, 0x26, 0xe3, 0x84, 0xf5, 0xd5, 0x38, 0x5d, 0x6c, 0x34, 0xe3, 0x68, 0x15, 0xb6, 0x9e, 0x5b, 0x99, 0xd6, 0x58, 0xab, 0x2c, 0x1e, 0x18, 0x37, 0x13, 0x13, 0x3b}}, + {{0x5e, 0x22, 0xab, 0x8f, 0x8c, 0x3c, 0x26, 0xd6, 0xd6, 0x0c, 0x49, 0xc2, 0x8a, 0xaf, 0x11, 0x61, 0xd6, 0x86, 0x7c, 0x14, 0x29, 0x6c, 0xef, 0xf2, 0xad, 0xc0, 0x62, 0x39, 0x89, 0x4f, 0xf5, 0x27}, {0x86, 0x59, 0x5c, 0x18, 0x35, 0x3c, 0x42, 0xa8, 0xa3, 0xbf, 0x9c, 0x77, 0x50, 0xf8, 0xae, 0x70, 0x6e, 0xb7, 0xc8, 0x1f, 0x88, 0xf4, 0x28, 0xf6, 0xfa, 0x9d, 0x41, 0xfe, 0x92, 0xf2, 0x9c, 0x0a}}, + {{0x3f, 0xf5, 0x1c, 0x3a, 0xe1, 0x08, 0x7c, 0x53, 0x61, 0xfc, 0x2b, 0x7b, 0x65, 0x42, 0xdf, 0x78, 0xc6, 0x35, 0xc6, 0xea, 0x8a, 0xa5, 0x00, 0x25, 0x23, 0xf1, 0x99, 0xbc, 0xc2, 0xc9, 0xcf, 0x0f}, {0x4a, 0x1b, 0xbe, 0x8f, 0x47, 0x0e, 0x47, 0x31, 0xb9, 0xe3, 0x85, 0xb4, 0x18, 0xe3, 0x1e, 0x99, 0x0e, 0xbb, 0x42, 0x30, 0xdd, 0x47, 0x3d, 0x63, 0x27, 0xa5, 0xb0, 0x99, 0x03, 0x81, 0x60, 0x33}}, + {{0x72, 0x69, 0x89, 0xf9, 0x17, 0x1d, 0xa2, 0xd7, 0x2b, 0xaa, 0xd7, 0x30, 0x6b, 0x6e, 0x8b, 0x5e, 0x05, 0xa3, 0x97, 0xee, 0xae, 0x73, 0x54, 0x84, 0xe5, 0x18, 0xc1, 0x7c, 0x56, 0x21, 0x16, 0x31}, {0x81, 0xdf, 0x1e, 0xb1, 0x9f, 0x5d, 0xcf, 0xfc, 0x00, 0xb2, 0x3e, 0xc0, 0x58, 0x77, 0x12, 0x2e, 0x21, 0x19, 0xaa, 0xee, 0xb9, 0x7d, 0x04, 0x5f, 0x24, 0xf5, 0xb3, 0x77, 0x45, 0xfc, 0x86, 0x3a}}, + {{0x93, 0x84, 0x48, 0xc1, 0xc8, 0x1c, 0x93, 0x9e, 0x92, 0xe3, 0x69, 0x25, 0x13, 0xcf, 0x0f, 0x90, 0x22, 0xd0, 0xb5, 0x48, 0xe9, 0x58, 0x5e, 0x76, 0xc0, 0x64, 0x69, 0xef, 0x2e, 0xc3, 0xde, 0x2e}, {0xd4, 0xeb, 0xeb, 0xbf, 0xac, 0xeb, 0x95, 0x56, 0xff, 0x21, 0x64, 0xfd, 0xa8, 0x74, 0xcc, 0x98, 0x38, 0x32, 0x31, 0x19, 0xcb, 0x5e, 0xd8, 0x27, 0x3c, 0xda, 0x23, 0x54, 0xb5, 0x65, 0x53, 0x10}}, + {{0xed, 0xd3, 0x70, 0x2d, 0x18, 0x98, 0x22, 0xf2, 0xeb, 0xfb, 0x8b, 0xb9, 0xdb, 0x0d, 0x8e, 0xdf, 0x0b, 0x55, 0xef, 0x57, 0xc2, 0xa0, 0xec, 0x44, 0x3a, 0xa0, 0x99, 0x4f, 0x8e, 0x83, 0xe2, 0x12}, {0x71, 0xd9, 0x8e, 0x8d, 0x7c, 0xb0, 0x55, 0x66, 0x35, 0xc6, 0x99, 0xf7, 0xe8, 0xb9, 0x54, 0x9d, 0xe0, 0x0a, 0xb0, 0x31, 0xab, 0xf7, 0xac, 0xd3, 0xb4, 0xce, 0x9d, 0x04, 0x34, 0xb0, 0xb7, 0x3d}}, + {{0x30, 0xf7, 0xc6, 0xc8, 0x3a, 0x76, 0xba, 0x10, 0x7a, 0xc6, 0x50, 0x91, 0xb4, 0x86, 0x79, 0xae, 0x74, 0xa9, 0x11, 0xe4, 0xf2, 0x80, 0xed, 0x82, 0x89, 0x65, 0x2c, 0x0b, 0xd6, 0x22, 0xe0, 0x04}, {0xe4, 0xc3, 0xad, 0xe8, 0xa2, 0x79, 0x8c, 0x08, 0x4f, 0xd6, 0xe1, 0x60, 0xb2, 0xbf, 0xb1, 0xa2, 0xa8, 0x03, 0xf5, 0x50, 0xdf, 0xea, 0x53, 0x21, 0x06, 0xc1, 0x45, 0x1f, 0x95, 0xd7, 0x71, 0x04}}, + {{0x2a, 0x1d, 0x0a, 0x54, 0x34, 0x68, 0xaf, 0xa0, 0x7d, 0x33, 0x09, 0xa6, 0x0b, 0x53, 0x22, 0xbc, 0x06, 0x12, 0x92, 0xff, 0x01, 0x74, 0x7e, 0xb2, 0x48, 0x7a, 0xce, 0x5f, 0x47, 0x0b, 0x66, 0x0f}, {0x91, 0x1e, 0x34, 0x5d, 0xe4, 0x0c, 0x2d, 0x0d, 0xe5, 0x73, 0x48, 0x62, 0x9b, 0xed, 0xd6, 0x5e, 0xa8, 0x04, 0x6f, 0x85, 0x88, 0xb3, 0x0d, 0xdb, 0xad, 0xec, 0x4d, 0x6b, 0xe5, 0x13, 0x09, 0x39}}, + {{0x85, 0x8d, 0x32, 0x34, 0xf4, 0xeb, 0x1f, 0x93, 0x8f, 0x77, 0xf3, 0x13, 0xb4, 0xdf, 0xac, 0xb4, 0x46, 0x47, 0x5a, 0x06, 0xf0, 0x10, 0x98, 0x21, 0xac, 0x28, 0xee, 0xd0, 0xe6, 0x25, 0x4b, 0x27}, {0x1e, 0x0d, 0xf8, 0x2a, 0xcf, 0x5d, 0xff, 0x85, 0xaa, 0x6a, 0xd5, 0x73, 0x75, 0xda, 0xcf, 0x4f, 0x17, 0xde, 0x55, 0xf6, 0xd6, 0x10, 0xbf, 0xfe, 0xaa, 0x3d, 0xfb, 0xe2, 0x1e, 0xed, 0xc4, 0x0f}}, + {{0x47, 0xfb, 0x07, 0x08, 0x2b, 0x68, 0x88, 0x2c, 0x33, 0x98, 0x2a, 0x76, 0x61, 0xe2, 0x72, 0xe5, 0xd6, 0xe2, 0x97, 0xdd, 0xb7, 0x94, 0xa5, 0x92, 0xf1, 0x92, 0x67, 0xae, 0x08, 0x0f, 0x0c, 0x29}, {0xf2, 0xe2, 0xbd, 0x9f, 0x2a, 0xa2, 0x3e, 0x9f, 0x9d, 0x3f, 0x48, 0xb5, 0x1a, 0xc1, 0x28, 0x78, 0x49, 0xfc, 0x71, 0x60, 0x4d, 0xbe, 0x9f, 0x88, 0xff, 0x31, 0x34, 0xa4, 0x2a, 0x23, 0x27, 0x21}}, + {{0xd2, 0x7f, 0x2f, 0xcd, 0x6a, 0x27, 0x50, 0xdf, 0x09, 0x4c, 0x32, 0x05, 0x8a, 0x30, 0x21, 0x62, 0xe4, 0x99, 0xb6, 0x3f, 0x54, 0x3f, 0x28, 0x1c, 0x03, 0xd9, 0x3a, 0x09, 0x94, 0xbf, 0x91, 0x26}, {0x33, 0x97, 0x8c, 0xff, 0xff, 0x82, 0xf0, 0x6a, 0xc0, 0xd8, 0x6e, 0xe3, 0xf0, 0xfa, 0xf9, 0x5f, 0x0f, 0x60, 0x88, 0x17, 0x4a, 0xf4, 0x94, 0xce, 0x9b, 0xc4, 0x35, 0x1c, 0x5d, 0xd6, 0x18, 0x13}}, + {{0x1c, 0xbb, 0x89, 0xbe, 0x9a, 0x55, 0x63, 0x91, 0xa7, 0x01, 0x49, 0x77, 0xcf, 0xbf, 0x51, 0x52, 0x1e, 0xcf, 0x93, 0x81, 0xe2, 0x6d, 0xfb, 0x3e, 0x49, 0x69, 0x5b, 0xfe, 0xc3, 0x18, 0x42, 0x19}, {0xe0, 0xed, 0x3b, 0xcc, 0xc0, 0xf4, 0x74, 0x71, 0x87, 0x46, 0x7f, 0x88, 0xc2, 0xe3, 0x5b, 0x73, 0x20, 0x05, 0x97, 0x56, 0xf4, 0x3d, 0xab, 0x93, 0x51, 0x86, 0x12, 0xf6, 0x03, 0xd8, 0x9d, 0x0d}}, + {{0xa4, 0xec, 0xc3, 0x1f, 0x33, 0xe0, 0x74, 0x7f, 0x56, 0xc8, 0x07, 0x5f, 0x48, 0x78, 0x5f, 0xd5, 0x79, 0xfd, 0x34, 0x4f, 0x42, 0x55, 0x3f, 0x4a, 0xfc, 0x64, 0xbb, 0xe6, 0x64, 0x77, 0x48, 0x0a}, {0xa9, 0x53, 0x7c, 0xb0, 0x1b, 0xae, 0x46, 0x77, 0x82, 0xf1, 0x4e, 0xb5, 0xa8, 0x26, 0xd8, 0x0c, 0xf5, 0x2e, 0xa7, 0xc7, 0x90, 0xd5, 0xd2, 0x64, 0x2f, 0xa7, 0x19, 0xdb, 0x7c, 0x9a, 0xe7, 0x34}}, + {{0xfe, 0xc6, 0x74, 0x99, 0x2c, 0x82, 0xe7, 0x9e, 0x62, 0xdf, 0xf8, 0xec, 0xe6, 0x96, 0x79, 0x6d, 0xf0, 0x4a, 0xdf, 0xf5, 0x2e, 0x2b, 0x63, 0x32, 0xe5, 0x30, 0x81, 0xb4, 0x27, 0xbe, 0xf9, 0x10}, {0x3a, 0x62, 0xb2, 0x8a, 0x17, 0x0f, 0x72, 0x12, 0x48, 0x08, 0x25, 0x6f, 0x3b, 0xea, 0x50, 0xa0, 0xd4, 0xe6, 0x47, 0x99, 0x95, 0x84, 0xf1, 0x01, 0x08, 0xb5, 0x42, 0xe8, 0x31, 0xd5, 0x25, 0x3e}}, + {{0xcb, 0x38, 0xf2, 0x8f, 0xac, 0x5d, 0x20, 0x1c, 0xd7, 0x0c, 0x46, 0x73, 0x71, 0x7a, 0x0e, 0x4c, 0xe7, 0x19, 0x49, 0x4c, 0xa1, 0xb1, 0xb8, 0x5c, 0x1c, 0xa3, 0x6c, 0x7f, 0x43, 0xcc, 0x17, 0x10}, {0xab, 0xcf, 0xd7, 0xb0, 0x29, 0x93, 0xa7, 0xc7, 0xef, 0x57, 0x2e, 0xb2, 0x4e, 0x05, 0x10, 0xf9, 0x9a, 0xe3, 0xf3, 0x3e, 0xe2, 0x9b, 0x7e, 0xa2, 0x1c, 0x47, 0xa3, 0xde, 0xd3, 0x8f, 0x1a, 0x22}}, + {{0x1d, 0x51, 0x56, 0xc1, 0xaa, 0xc8, 0xa5, 0x8d, 0x19, 0x95, 0xad, 0x01, 0x50, 0x29, 0xf5, 0x3d, 0xd2, 0x95, 0xfe, 0xfe, 0xc1, 0x3c, 0x4e, 0x65, 0x94, 0xc5, 0xf3, 0xf7, 0xe8, 0x50, 0x26, 0x18}, {0xcc, 0x27, 0xe2, 0x4f, 0x90, 0x57, 0x14, 0x6a, 0xde, 0x90, 0x7f, 0x38, 0x0a, 0x60, 0xdc, 0xdb, 0xbd, 0xd3, 0x06, 0x89, 0x36, 0xa7, 0x7f, 0xb4, 0x8b, 0x5c, 0x53, 0x28, 0xf4, 0x7a, 0x19, 0x29}}, + {{0x5b, 0xa1, 0x92, 0xc2, 0x90, 0x47, 0x60, 0x0e, 0xc0, 0x70, 0x02, 0xb5, 0x3d, 0xbf, 0x8d, 0x56, 0xde, 0xd7, 0x45, 0xbb, 0x35, 0xc9, 0xae, 0x54, 0x8a, 0xe5, 0x62, 0x3c, 0xd9, 0x56, 0xeb, 0x30}, {0xf4, 0x14, 0xd7, 0xce, 0x00, 0x2e, 0x0f, 0x94, 0xbb, 0xc6, 0xd8, 0x5d, 0x90, 0x1a, 0xd0, 0xf3, 0x8f, 0xec, 0x9c, 0x36, 0xb3, 0x66, 0x88, 0x21, 0x22, 0xf0, 0x9e, 0x92, 0x60, 0x3c, 0xad, 0x16}}, + {{0x1f, 0xc4, 0x46, 0x64, 0xc3, 0xe5, 0x17, 0x0c, 0x01, 0x31, 0x59, 0x64, 0xb7, 0xae, 0x36, 0xbc, 0xbb, 0x1c, 0x9f, 0xf8, 0x2b, 0x22, 0xb3, 0xe6, 0xa6, 0x65, 0x94, 0x26, 0xf7, 0x07, 0x55, 0x0a}, {0x7c, 0xc0, 0xb0, 0x13, 0x02, 0x92, 0x8e, 0x5d, 0x25, 0xef, 0x53, 0x66, 0x80, 0x20, 0x75, 0x0c, 0x48, 0xec, 0x71, 0x9e, 0x9c, 0xc9, 0x8a, 0x0a, 0x7a, 0x9c, 0x48, 0x12, 0xfc, 0x69, 0xea, 0x0c}}, + {{0xe4, 0xbf, 0x67, 0x2e, 0x25, 0xaa, 0xf7, 0x6b, 0xb2, 0xef, 0x64, 0x32, 0x62, 0xdd, 0x38, 0xf6, 0xeb, 0x95, 0xb8, 0x7a, 0xdd, 0xd3, 0xd9, 0xc5, 0x0f, 0x40, 0xea, 0xd5, 0x41, 0x6f, 0xcc, 0x19}, {0x24, 0xa4, 0x3d, 0xc9, 0xac, 0x31, 0xf9, 0xb5, 0x0b, 0xab, 0x68, 0xf0, 0xe6, 0x28, 0x69, 0x06, 0x63, 0x85, 0x16, 0x25, 0xf0, 0xd1, 0x97, 0xaa, 0x7e, 0x02, 0x1a, 0xf4, 0x45, 0x2e, 0xc9, 0x12}}, + {{0x8c, 0x2d, 0x6f, 0x54, 0xf6, 0x03, 0xcd, 0xb5, 0xcc, 0xd8, 0xb4, 0x5f, 0x8d, 0xed, 0x8b, 0x00, 0x34, 0x5e, 0x82, 0xde, 0x13, 0x86, 0xcb, 0xfb, 0x27, 0xbf, 0xa1, 0x27, 0x74, 0x95, 0x1d, 0x32}, {0x7e, 0xf6, 0x5a, 0x5d, 0x71, 0xef, 0x6e, 0xf4, 0x69, 0xa9, 0xdf, 0xd7, 0xa5, 0x6a, 0x18, 0x07, 0x54, 0x65, 0x0a, 0x72, 0x43, 0x65, 0xd8, 0xcd, 0x49, 0x81, 0x21, 0x2d, 0x38, 0x07, 0x09, 0x01}}, + {{0xf2, 0x6a, 0x1d, 0x2f, 0x14, 0xd0, 0x0a, 0x3b, 0x14, 0xfc, 0x34, 0xd2, 0xda, 0x56, 0xd7, 0x99, 0xfb, 0x5d, 0x4c, 0x45, 0xc4, 0xb1, 0xa8, 0x45, 0x29, 0xf6, 0x27, 0xad, 0x77, 0x4f, 0xe7, 0x1e}, {0x0f, 0x5a, 0x92, 0xdf, 0x64, 0x12, 0x8f, 0xf3, 0xd7, 0x18, 0xac, 0x05, 0xc9, 0x81, 0x8a, 0x19, 0x42, 0xed, 0xf4, 0x24, 0xaf, 0x1c, 0x50, 0xcc, 0x40, 0x38, 0xd1, 0xd4, 0x1d, 0x53, 0x9e, 0x39}}, + {{0xbf, 0x6b, 0xc8, 0xb8, 0x9a, 0xb3, 0x29, 0xb5, 0x8e, 0x67, 0x2d, 0xe0, 0xda, 0xeb, 0x8f, 0x7d, 0x02, 0x83, 0x8e, 0xca, 0x95, 0xd7, 0xae, 0x7f, 0x2c, 0xac, 0x02, 0xe0, 0x41, 0xa4, 0xed, 0x31}, {0xbb, 0x6c, 0x55, 0x68, 0xf8, 0x1e, 0x9d, 0x61, 0xd6, 0xab, 0x81, 0xa3, 0xed, 0x2f, 0x8c, 0xd8, 0xd0, 0xdd, 0x1f, 0x1e, 0xa1, 0x42, 0x45, 0x68, 0x93, 0x22, 0x9c, 0xa3, 0xca, 0x38, 0x71, 0x07}}, + {{0x63, 0x9c, 0xbe, 0xf2, 0x0a, 0x04, 0x3c, 0x8e, 0xe2, 0xe1, 0xb0, 0x41, 0xc4, 0xac, 0xfc, 0x0c, 0x3f, 0x36, 0x06, 0x1f, 0x75, 0x28, 0x52, 0xf7, 0xcc, 0xe3, 0x81, 0x2b, 0xbd, 0x71, 0x32, 0x00}, {0x80, 0x61, 0xdc, 0x26, 0xdb, 0xae, 0xad, 0xc3, 0x86, 0x79, 0x77, 0x2e, 0x13, 0x7b, 0xd6, 0x2a, 0x54, 0xde, 0x7b, 0x02, 0x63, 0xe0, 0xc6, 0x2d, 0xa4, 0x04, 0x28, 0x6e, 0xe5, 0xda, 0xf4, 0x0a}}, + {{0x2e, 0xdc, 0xd0, 0x94, 0xc9, 0x53, 0x75, 0x50, 0xa7, 0x26, 0x9a, 0x64, 0x12, 0x40, 0x0f, 0x94, 0xdb, 0x7b, 0x07, 0xcb, 0x3d, 0x6f, 0x62, 0x91, 0x97, 0x8e, 0x99, 0xba, 0x61, 0x90, 0x6c, 0x3c}, {0x45, 0x3f, 0x32, 0x07, 0x4b, 0xff, 0x78, 0x21, 0x48, 0x37, 0xa7, 0xb4, 0x17, 0x6c, 0xbd, 0xc7, 0x3f, 0x1f, 0x36, 0xd3, 0xaf, 0x30, 0x7e, 0x56, 0xd2, 0x92, 0x98, 0xdc, 0x2e, 0x0d, 0xe0, 0x0f}}, + {{0x8b, 0x83, 0x71, 0xfc, 0xf9, 0x5e, 0x3e, 0x92, 0x2f, 0xa7, 0x40, 0xd2, 0x35, 0x03, 0x0f, 0x7d, 0x3e, 0xbb, 0xc7, 0x1b, 0x95, 0x48, 0x95, 0x19, 0x41, 0x77, 0x38, 0x8b, 0xc3, 0x30, 0xab, 0x21}, {0xb2, 0x2c, 0x1c, 0x4d, 0xb8, 0x52, 0xa5, 0x28, 0xf9, 0xc6, 0x7d, 0xdb, 0x6b, 0xb6, 0x79, 0x78, 0xc3, 0xc3, 0x07, 0xb2, 0xa2, 0xe4, 0xcb, 0x66, 0xc2, 0x1f, 0x7e, 0xce, 0x4e, 0x32, 0x5e, 0x1c}}, + {{0xe3, 0x5d, 0x6e, 0x7a, 0x37, 0x8b, 0xea, 0x0b, 0x88, 0xc8, 0x8f, 0x7b, 0xbe, 0xfc, 0xad, 0xe8, 0x44, 0x15, 0x54, 0xeb, 0xff, 0x7d, 0x43, 0x64, 0x08, 0xd7, 0x98, 0xe0, 0x01, 0x71, 0xe3, 0x17}, {0x49, 0x75, 0x18, 0xea, 0xee, 0x16, 0x3c, 0x5e, 0xdc, 0x4f, 0xda, 0x5d, 0x7b, 0xd0, 0xbc, 0xce, 0x17, 0x13, 0x65, 0xc3, 0x61, 0xd0, 0xef, 0xca, 0x79, 0xf5, 0xb0, 0xc8, 0xac, 0xaf, 0xba, 0x08}}, + {{0x60, 0xc3, 0xdc, 0xdf, 0xd3, 0x64, 0x45, 0x0c, 0x43, 0xb7, 0x7a, 0x62, 0xdb, 0xd6, 0x34, 0x3c, 0x7d, 0xe5, 0xce, 0xae, 0xef, 0x66, 0xd6, 0x19, 0xb8, 0x7c, 0xb6, 0xd1, 0x7c, 0x13, 0x2c, 0x20}, {0xbc, 0x1a, 0x32, 0xc4, 0x7f, 0xc6, 0xee, 0x0d, 0x83, 0x87, 0x4a, 0xbc, 0x68, 0x45, 0xcb, 0xc5, 0x0c, 0x55, 0xca, 0xec, 0x51, 0x14, 0xb1, 0x86, 0x77, 0x2e, 0x20, 0x48, 0xf7, 0x09, 0xf0, 0x0f}}, + {{0x8b, 0x3c, 0x05, 0xa9, 0xe2, 0xeb, 0x99, 0xf2, 0x9d, 0xa2, 0xdf, 0x89, 0x01, 0x13, 0x4d, 0x42, 0x4b, 0x4a, 0x0d, 0x49, 0x64, 0xf3, 0x28, 0xea, 0x81, 0xd8, 0x7f, 0x33, 0xa0, 0xa2, 0x08, 0x25}, {0x33, 0xbc, 0xa9, 0x16, 0x8b, 0xbf, 0x5c, 0xd2, 0xf0, 0xd5, 0x72, 0xa9, 0xed, 0xc1, 0xa1, 0x11, 0x4e, 0x31, 0x7d, 0x9d, 0xda, 0x8a, 0xef, 0x9c, 0xd3, 0x2e, 0xd1, 0xba, 0xdf, 0xb4, 0xa8, 0x00}}, + {{0x73, 0x19, 0x9d, 0x9a, 0xeb, 0x9b, 0xbe, 0x23, 0x1a, 0x89, 0xbe, 0xd6, 0x9c, 0xa7, 0xcb, 0x08, 0x76, 0xca, 0x9e, 0x0d, 0x74, 0x6d, 0x6b, 0xfe, 0x72, 0xc7, 0xad, 0x7c, 0x3d, 0x8a, 0xf9, 0x1c}, {0x67, 0x13, 0xa6, 0x8c, 0xa9, 0x48, 0xb5, 0x37, 0xe9, 0xf7, 0xb5, 0xa9, 0x6a, 0x85, 0x17, 0x77, 0x38, 0xe3, 0x85, 0xa6, 0x77, 0xed, 0xc3, 0xbb, 0x4f, 0x82, 0x7a, 0xa6, 0xad, 0x1c, 0x21, 0x37}}, + {{0xb6, 0x90, 0x63, 0x51, 0xff, 0x2e, 0x8f, 0xec, 0xaa, 0xb6, 0x35, 0x70, 0xeb, 0x81, 0x2b, 0x50, 0x3e, 0x4d, 0xfa, 0x5d, 0xf9, 0x0d, 0xf2, 0xc6, 0x49, 0x59, 0x97, 0xc1, 0x2b, 0x84, 0x19, 0x0a}, {0x0d, 0x61, 0xbe, 0x8f, 0x17, 0xa3, 0x0b, 0x76, 0x05, 0xb3, 0xbd, 0x6a, 0x62, 0xd5, 0x70, 0x03, 0x4c, 0x2d, 0x18, 0x6e, 0xbf, 0xae, 0x05, 0xb0, 0x27, 0x64, 0x56, 0xeb, 0xda, 0x19, 0xfb, 0x0b}}, + {{0x50, 0x07, 0xfc, 0x60, 0x79, 0x5c, 0x7e, 0x57, 0x27, 0x73, 0x0d, 0xca, 0xac, 0x42, 0x55, 0xef, 0xb2, 0x85, 0x1b, 0xce, 0x26, 0xe1, 0x01, 0x1f, 0x3e, 0xa8, 0xf1, 0x4f, 0xd0, 0x42, 0x4a, 0x2a}, {0xb6, 0x15, 0xda, 0x05, 0x4d, 0x59, 0xfb, 0x89, 0x67, 0x6e, 0x92, 0xc2, 0xa7, 0xa8, 0x9f, 0x40, 0xbc, 0xd7, 0xd8, 0xaa, 0x98, 0x18, 0x1d, 0xf5, 0xa1, 0xcc, 0x1d, 0xd5, 0x49, 0x29, 0xa2, 0x11}}, + {{0xfd, 0xdd, 0x54, 0x6c, 0x54, 0xce, 0x3a, 0xa1, 0x24, 0xc6, 0x6b, 0x3b, 0xd0, 0x05, 0x2f, 0x4f, 0xd6, 0xbe, 0x1b, 0x6f, 0x2b, 0x34, 0xd8, 0x24, 0xb0, 0x49, 0x58, 0x30, 0xfd, 0xdc, 0xf6, 0x10}, {0x8b, 0x2c, 0x1e, 0xb1, 0x6c, 0x77, 0xe4, 0x45, 0xb1, 0x9f, 0x31, 0x73, 0x40, 0x78, 0xdd, 0x21, 0x91, 0xf3, 0x94, 0x2c, 0x29, 0x9a, 0x3d, 0x9b, 0x49, 0x09, 0xeb, 0x6b, 0xc1, 0x66, 0x76, 0x24}}, + {{0xd1, 0x97, 0x86, 0x0f, 0x5b, 0xa7, 0x42, 0x69, 0xb9, 0xff, 0xde, 0x73, 0x55, 0x35, 0x65, 0x1e, 0x4f, 0x17, 0xcc, 0x14, 0x77, 0x52, 0xa7, 0xca, 0x3f, 0x9e, 0xd8, 0xfd, 0x52, 0x3c, 0xd5, 0x0b}, {0x56, 0x2a, 0x79, 0x07, 0xab, 0x85, 0xbd, 0xef, 0x09, 0xb6, 0xe0, 0x5b, 0xd3, 0x6d, 0xee, 0x94, 0xad, 0x80, 0x60, 0x4c, 0xf4, 0xeb, 0xe2, 0xe2, 0x64, 0xf5, 0xa4, 0x6d, 0xb5, 0xf6, 0xe7, 0x37}}, + {{0x2c, 0xa8, 0xf0, 0xda, 0x8c, 0x93, 0x85, 0xa7, 0x1a, 0xe0, 0x0f, 0x6b, 0x2c, 0x05, 0xf1, 0x0f, 0x06, 0xd5, 0x45, 0x96, 0x92, 0x48, 0xa3, 0xa3, 0x0c, 0xee, 0xe4, 0x25, 0x9f, 0x4d, 0xfc, 0x35}, {0xd0, 0xee, 0xd5, 0x35, 0x87, 0x13, 0xd8, 0x1b, 0x10, 0x22, 0x02, 0x44, 0x2b, 0x6e, 0x31, 0x20, 0xc8, 0x18, 0x82, 0x33, 0xe5, 0x87, 0xe4, 0x1d, 0x86, 0xac, 0xb7, 0x7b, 0xef, 0x15, 0x39, 0x26}}, + {{0x25, 0xaf, 0x68, 0x9d, 0x94, 0x53, 0x70, 0x72, 0x12, 0x85, 0x55, 0xbc, 0x68, 0x3a, 0xec, 0x31, 0x45, 0x47, 0x90, 0x41, 0xb9, 0xb2, 0x24, 0x62, 0x92, 0x7f, 0xa0, 0xbf, 0xfb, 0xd2, 0xae, 0x2b}, {0xe7, 0x17, 0x9d, 0xc3, 0x6e, 0xad, 0x85, 0x15, 0xe0, 0x30, 0x09, 0x79, 0x31, 0x5d, 0xf4, 0xb3, 0xab, 0x27, 0xce, 0x6d, 0x93, 0xcf, 0xf2, 0x10, 0x5b, 0x5a, 0xcc, 0xa3, 0xdc, 0x25, 0xc7, 0x3a}}, + {{0xd3, 0xe6, 0x5e, 0x79, 0xfd, 0x99, 0xd5, 0x16, 0x8d, 0x26, 0x5a, 0x53, 0x0c, 0x7e, 0x32, 0xa8, 0xa0, 0xc9, 0xd0, 0xa2, 0xf1, 0x59, 0xf3, 0x66, 0x13, 0xef, 0x55, 0xc7, 0xcf, 0xb8, 0x43, 0x0b}, {0x4f, 0x73, 0x93, 0x99, 0x8c, 0xbb, 0x1e, 0x77, 0x78, 0x89, 0x0e, 0x7f, 0xfa, 0x9e, 0x2b, 0xe2, 0xf5, 0x95, 0xaa, 0xa0, 0x6e, 0x28, 0x47, 0xf8, 0x65, 0x4e, 0xcb, 0xf0, 0xdc, 0x00, 0xab, 0x3c}}, + {{0xd6, 0x5e, 0x81, 0x93, 0x99, 0x5b, 0x0e, 0x94, 0x72, 0x84, 0xc9, 0x4a, 0x32, 0xf9, 0x58, 0xe4, 0x96, 0x6b, 0xc6, 0xa4, 0xb2, 0xa9, 0x77, 0x72, 0xff, 0x6a, 0x71, 0x35, 0xbb, 0x1d, 0x9b, 0x2a}, {0xfa, 0x74, 0x5f, 0x7c, 0x61, 0x85, 0x1e, 0x1d, 0xec, 0xbd, 0x5e, 0x2d, 0x57, 0xd9, 0xe0, 0x04, 0xdd, 0x36, 0x0e, 0x73, 0x0f, 0x9f, 0x7f, 0x69, 0xae, 0x29, 0x6b, 0x7d, 0x63, 0x68, 0x96, 0x31}}, + {{0xba, 0xce, 0x5d, 0xbe, 0x6a, 0x66, 0xec, 0xf4, 0x70, 0x36, 0x20, 0x62, 0x54, 0x75, 0x55, 0x4e, 0x56, 0xcb, 0x37, 0xa2, 0xb4, 0x90, 0xc0, 0xc2, 0x33, 0xe4, 0x7a, 0xd9, 0x8d, 0x22, 0xae, 0x32}, {0x98, 0xa9, 0x6e, 0xe7, 0xb3, 0x69, 0x96, 0xad, 0x7c, 0x7b, 0x57, 0xed, 0x9f, 0x87, 0xe7, 0x91, 0xd7, 0x94, 0x6c, 0x9e, 0x83, 0x9d, 0x41, 0x1e, 0x00, 0x08, 0xe3, 0xa0, 0xba, 0x94, 0x8d, 0x04}}, + {{0x19, 0x76, 0x6a, 0x57, 0x9f, 0x7b, 0x90, 0x6c, 0x20, 0x91, 0x1c, 0x1d, 0x9f, 0x59, 0xb1, 0x7b, 0x0c, 0xe9, 0x29, 0xd4, 0x4d, 0xe8, 0x2f, 0x3b, 0xe9, 0x5a, 0xcc, 0x8a, 0xea, 0xfb, 0xd9, 0x33}, {0xec, 0x17, 0xca, 0x44, 0x50, 0xec, 0x9a, 0x54, 0xd2, 0x2c, 0xae, 0xdb, 0xee, 0x16, 0x5d, 0x64, 0xef, 0xfe, 0x8b, 0x9c, 0x27, 0x6a, 0xb1, 0x0a, 0xf2, 0x08, 0xec, 0x6f, 0xb9, 0x42, 0xe8, 0x3c}}, + {{0x29, 0xbc, 0x9c, 0xb4, 0xea, 0xab, 0xfe, 0x66, 0xd0, 0x1a, 0x80, 0x4f, 0xfd, 0x43, 0x1b, 0x83, 0x77, 0x9f, 0x5b, 0xa9, 0x1f, 0xb8, 0x63, 0x89, 0xda, 0xc8, 0xa9, 0x33, 0x9f, 0x5b, 0xff, 0x3f}, {0xf6, 0xc0, 0xce, 0x3e, 0xb3, 0xfd, 0x46, 0xb8, 0xc1, 0x2d, 0x86, 0x2d, 0xde, 0xee, 0x8f, 0x02, 0x53, 0x84, 0x83, 0xd7, 0xa0, 0xb8, 0xfe, 0xb6, 0x84, 0xf1, 0x47, 0xea, 0x3e, 0xfb, 0xbf, 0x1e}}, + {{0x02, 0xd1, 0x7e, 0x18, 0xa6, 0x28, 0xd3, 0xdb, 0x08, 0xc4, 0xb1, 0xfa, 0xe1, 0xba, 0x92, 0x4d, 0x5c, 0x3f, 0xc4, 0x4d, 0xa9, 0x8c, 0x36, 0x50, 0x5e, 0x7f, 0x35, 0x91, 0x90, 0x65, 0xe9, 0x03}, {0xbe, 0x3c, 0x64, 0x51, 0x25, 0x10, 0x29, 0x69, 0x53, 0x9b, 0x56, 0xbc, 0xf3, 0x9b, 0x88, 0xa4, 0x13, 0xf4, 0xcd, 0x2c, 0xe6, 0xbf, 0x20, 0xf0, 0x46, 0x87, 0xa2, 0x0a, 0x40, 0x5e, 0x28, 0x01}}, + {{0xb6, 0x12, 0xa2, 0xb4, 0xaf, 0x35, 0x24, 0x8a, 0x84, 0x93, 0xfa, 0x3f, 0x88, 0x15, 0x32, 0x51, 0x02, 0xb3, 0x41, 0xc7, 0x35, 0xb5, 0x59, 0xba, 0x14, 0x50, 0x46, 0xc5, 0xe6, 0x79, 0x4f, 0x02}, {0xbd, 0xb6, 0x7d, 0x74, 0x44, 0x07, 0x8d, 0x70, 0xb8, 0x4a, 0x56, 0x99, 0x9c, 0x0f, 0xa0, 0x4b, 0x85, 0x0d, 0x2b, 0x80, 0x26, 0x86, 0xa1, 0xa6, 0x5f, 0x9f, 0xbe, 0x83, 0xb3, 0x93, 0x80, 0x11}}, + {{0x41, 0x33, 0x86, 0xac, 0x80, 0xe8, 0x81, 0x4e, 0x52, 0xd0, 0x5c, 0xee, 0xa5, 0xdd, 0x99, 0xb1, 0xbf, 0x40, 0x9e, 0x2b, 0xdb, 0x9e, 0xfb, 0x4b, 0x71, 0x4e, 0x82, 0xbc, 0xf9, 0xcc, 0xf3, 0x31}, {0x9a, 0xa3, 0x4c, 0x41, 0x27, 0xac, 0x7e, 0xc7, 0x63, 0x80, 0x2d, 0x3e, 0x0b, 0x9a, 0xe7, 0x75, 0x83, 0x73, 0x2c, 0x39, 0x29, 0x16, 0x22, 0x06, 0x9a, 0x54, 0xdb, 0x01, 0xa6, 0xf9, 0x3f, 0x00}}, + {{0x77, 0x99, 0x19, 0x89, 0x6e, 0xfe, 0xa3, 0x19, 0xdc, 0x1f, 0x2a, 0x3a, 0xab, 0xdc, 0xae, 0xca, 0x5d, 0xb0, 0x71, 0xb8, 0xfb, 0x6f, 0x08, 0x5d, 0x0b, 0x54, 0xa2, 0x10, 0xda, 0xd4, 0x09, 0x10}, {0xd2, 0xd8, 0x6e, 0xe5, 0x0b, 0xb6, 0x52, 0x3e, 0x02, 0x55, 0x20, 0x52, 0xc0, 0x62, 0xd1, 0xa1, 0xe2, 0x40, 0xff, 0x9e, 0x5f, 0x4b, 0x1e, 0xdf, 0x5e, 0x7d, 0x75, 0xa4, 0x83, 0x04, 0x83, 0x39}}, + {{0x28, 0xfc, 0x3e, 0xfd, 0x9e, 0x97, 0x0e, 0x8a, 0x68, 0x89, 0xe0, 0x94, 0x2d, 0x28, 0x49, 0x49, 0xeb, 0x6b, 0x13, 0x9c, 0x4b, 0x9f, 0xb2, 0xf2, 0x78, 0xca, 0x11, 0xf7, 0xf3, 0x7b, 0xff, 0x10}, {0x2b, 0x9a, 0x6f, 0xfe, 0x39, 0xa7, 0xac, 0xf3, 0xe1, 0x89, 0x09, 0x3b, 0xdd, 0x32, 0xa4, 0x24, 0x58, 0x88, 0x9c, 0xe6, 0xec, 0x37, 0x22, 0x2f, 0x9f, 0x01, 0x48, 0x64, 0xa5, 0x82, 0x7e, 0x2d}}, + {{0x7c, 0x2f, 0xb2, 0xb2, 0xb4, 0x25, 0xd9, 0x0d, 0x23, 0x36, 0xb3, 0xa5, 0x2a, 0xb2, 0x56, 0x5f, 0x4c, 0xa8, 0x91, 0xf2, 0xe0, 0x9f, 0xd5, 0x57, 0x14, 0xbe, 0xf1, 0x30, 0x2b, 0x97, 0x09, 0x0d}, {0xb4, 0xd6, 0xf8, 0x52, 0xc2, 0xd4, 0x74, 0x33, 0x3b, 0xd0, 0xd1, 0xbd, 0xb4, 0x3c, 0x76, 0xc0, 0x62, 0xc7, 0x9b, 0xfa, 0xd7, 0xca, 0x75, 0x00, 0x5f, 0x3b, 0x25, 0x5a, 0x43, 0xc5, 0x31, 0x32}}, + {{0xc6, 0x5e, 0x1b, 0x36, 0x5d, 0x39, 0x7e, 0xd2, 0x57, 0xaa, 0xa3, 0x5f, 0x0b, 0xb4, 0x65, 0xbf, 0x47, 0xd0, 0x4c, 0x73, 0x7a, 0xd4, 0xbe, 0x6e, 0x0b, 0x52, 0x59, 0x99, 0xcb, 0x49, 0x72, 0x1c}, {0x38, 0xef, 0x1f, 0x92, 0xe5, 0xb8, 0xa7, 0xda, 0x3f, 0xee, 0x05, 0xad, 0x6d, 0x2a, 0xef, 0x96, 0xa4, 0x18, 0x0b, 0xfc, 0xe2, 0x76, 0xf1, 0xc6, 0x4d, 0x8a, 0x75, 0x70, 0x81, 0x67, 0x9f, 0x38}}, + {{0xe7, 0xee, 0x3e, 0x9e, 0xe7, 0xca, 0x19, 0xb7, 0xa0, 0x15, 0xb1, 0x1d, 0x78, 0x05, 0x95, 0x71, 0x1a, 0x10, 0xd4, 0x89, 0x1d, 0xdf, 0xf3, 0x4b, 0xfe, 0xb2, 0x88, 0x06, 0x8a, 0x02, 0x80, 0x11}, {0xfa, 0x84, 0x81, 0xc1, 0x5b, 0x6a, 0xd4, 0xea, 0x59, 0xd2, 0xd1, 0x9e, 0xf1, 0x4e, 0x2e, 0x75, 0x0f, 0x6e, 0x42, 0x44, 0x4e, 0x46, 0x87, 0x69, 0x51, 0x9e, 0x2d, 0x84, 0x02, 0x4f, 0x76, 0x0e}}, + {{0xfb, 0x7a, 0xe3, 0xe0, 0x1b, 0x56, 0xc8, 0x4f, 0x43, 0x81, 0xaf, 0xb7, 0xcd, 0x7e, 0x22, 0x4e, 0x60, 0x44, 0x30, 0x3d, 0xcc, 0xad, 0xe5, 0x18, 0x8a, 0x5b, 0x90, 0x5c, 0x61, 0x1e, 0x1d, 0x1c}, {0x02, 0x32, 0x1a, 0xfa, 0xc9, 0x9f, 0x4b, 0xe8, 0x9f, 0x97, 0xa5, 0xde, 0x73, 0x8a, 0xd2, 0x64, 0xe3, 0xac, 0xc4, 0x52, 0x78, 0x2a, 0xb7, 0xa1, 0x88, 0xe0, 0x90, 0x90, 0x2e, 0x46, 0x76, 0x31}}, + {{0x6e, 0x40, 0x7d, 0x42, 0xc4, 0x58, 0x3d, 0x07, 0x73, 0xb9, 0xa4, 0x9d, 0x4c, 0xa6, 0xae, 0xea, 0xfd, 0x98, 0x9c, 0xce, 0x6a, 0x60, 0x2b, 0xdb, 0xf0, 0xcf, 0x06, 0x06, 0x61, 0xab, 0x0d, 0x32}, {0x38, 0xb7, 0x67, 0xe5, 0x17, 0x60, 0xf5, 0xf6, 0xcf, 0x6d, 0x0d, 0xc8, 0xa4, 0x2f, 0x8b, 0xad, 0xc6, 0xee, 0xc5, 0xac, 0x87, 0x67, 0x76, 0xef, 0xfd, 0x8c, 0xc2, 0x0c, 0x02, 0xaf, 0x46, 0x20}}, + {{0xe2, 0x93, 0x45, 0xea, 0x8c, 0xbe, 0xe0, 0xdf, 0x57, 0xa7, 0x01, 0x2c, 0xe6, 0x71, 0x25, 0xbf, 0xe4, 0xcd, 0x1f, 0x72, 0x2a, 0xbd, 0x46, 0x56, 0x5a, 0xdf, 0x5e, 0x0c, 0x65, 0x84, 0x56, 0x2e}, {0xe0, 0x3d, 0x23, 0xe7, 0x9b, 0x11, 0x67, 0xc3, 0xe2, 0xd7, 0x19, 0x83, 0xd3, 0x64, 0x59, 0xa8, 0xb3, 0x44, 0x72, 0x77, 0x06, 0x41, 0x56, 0xbf, 0xe3, 0x3f, 0x1c, 0xf9, 0xa3, 0xa0, 0xa7, 0x05}}, + {{0xcf, 0xb1, 0xbd, 0x7e, 0xb9, 0x1f, 0x57, 0xa1, 0xfb, 0x4a, 0x84, 0x94, 0xd4, 0x58, 0x70, 0xad, 0xda, 0x34, 0xf9, 0xfd, 0x3e, 0x38, 0xff, 0x22, 0x55, 0xa5, 0x8d, 0x62, 0x36, 0xf5, 0xa8, 0x03}, {0xdf, 0x83, 0x35, 0x8b, 0x60, 0xb5, 0xa6, 0x89, 0xbe, 0x3a, 0xb6, 0x4b, 0x5b, 0x76, 0xd8, 0x93, 0xce, 0x39, 0x5e, 0xc7, 0x89, 0xc2, 0x07, 0x66, 0x93, 0x3c, 0x13, 0xd6, 0xc7, 0x7a, 0x46, 0x08}}, + {{0x6d, 0x59, 0xf7, 0xc0, 0xa5, 0x0a, 0xbb, 0x09, 0x09, 0x3f, 0x31, 0x0a, 0x5e, 0x9d, 0xb7, 0xc0, 0x2d, 0xdf, 0xc8, 0x63, 0x48, 0xae, 0xc7, 0x25, 0xf5, 0xc4, 0xc8, 0x57, 0x78, 0x71, 0x0f, 0x34}, {0x5c, 0x17, 0xbd, 0xe9, 0x99, 0x09, 0xd6, 0x58, 0xcc, 0x3d, 0x36, 0x69, 0xe3, 0x51, 0x3c, 0x41, 0x5f, 0xcc, 0xbd, 0xa5, 0xfb, 0x08, 0xbf, 0x44, 0x33, 0x72, 0x10, 0x42, 0xab, 0x43, 0xd9, 0x09}}, + {{0xa3, 0x69, 0x0b, 0x19, 0xb2, 0xe2, 0x60, 0x76, 0xba, 0x5a, 0x68, 0x12, 0xbd, 0xe6, 0x75, 0xa6, 0xa3, 0x61, 0x5f, 0x34, 0x4c, 0x46, 0xc3, 0x70, 0x5c, 0x83, 0x3a, 0x20, 0x69, 0xa2, 0x06, 0x0c}, {0xb8, 0x4a, 0x7f, 0x2f, 0xb8, 0x81, 0xa9, 0x5e, 0x95, 0x6b, 0x02, 0x5e, 0x6c, 0x89, 0x0c, 0x27, 0x54, 0x79, 0x16, 0x11, 0xeb, 0x6b, 0x0a, 0x41, 0x3f, 0x41, 0xf9, 0x51, 0x5d, 0xf4, 0xcc, 0x25}}, + {{0x8f, 0xc2, 0x6a, 0x1a, 0x9a, 0x8e, 0xb6, 0x83, 0x2b, 0x8c, 0x5e, 0xe8, 0x79, 0x90, 0x2f, 0x25, 0x23, 0x7d, 0x27, 0x3f, 0x34, 0xa3, 0xd5, 0x3d, 0x86, 0xd3, 0xfe, 0xbd, 0x77, 0x66, 0x00, 0x1f}, {0x39, 0x4b, 0x1e, 0xa0, 0x7c, 0x59, 0xc2, 0x21, 0xa8, 0x3a, 0xb6, 0xca, 0x79, 0xb2, 0x95, 0x11, 0x1c, 0x37, 0xd5, 0x89, 0x5d, 0xc4, 0x47, 0x59, 0x9a, 0xf6, 0xf2, 0x76, 0x05, 0xbc, 0xfd, 0x0b}}, + {{0xae, 0xae, 0xd6, 0xf6, 0xa5, 0xcc, 0xaa, 0x56, 0x5d, 0x17, 0x56, 0x5b, 0xed, 0xb6, 0xde, 0x00, 0x48, 0xac, 0xe3, 0xf6, 0x20, 0x09, 0x9e, 0xe9, 0x68, 0x70, 0x50, 0xfa, 0xf9, 0x6d, 0x70, 0x19}, {0xfb, 0x93, 0xd8, 0xdc, 0x52, 0x01, 0xd1, 0x68, 0x47, 0x7f, 0xb3, 0xe5, 0x1d, 0xc8, 0xce, 0x05, 0x14, 0x9c, 0x1f, 0x2c, 0x62, 0xe0, 0x83, 0x7f, 0x35, 0x7b, 0x05, 0xed, 0x5d, 0x80, 0xcb, 0x31}}, + {{0x01, 0x3c, 0xf5, 0x84, 0x33, 0x89, 0x40, 0xf7, 0x91, 0x3a, 0x70, 0x4b, 0xad, 0x85, 0x5d, 0xa6, 0xb4, 0x9e, 0x16, 0x9c, 0x51, 0xf1, 0x88, 0xe9, 0x37, 0x45, 0x50, 0x9c, 0x68, 0x63, 0xb7, 0x39}, {0x3c, 0x9d, 0x89, 0x8f, 0x81, 0x28, 0xcc, 0x8f, 0xed, 0xb7, 0x4e, 0x34, 0x67, 0x76, 0x09, 0x9a, 0xac, 0xb9, 0x99, 0x10, 0x9a, 0xff, 0x7a, 0xc7, 0x40, 0x9a, 0x3f, 0xe5, 0x28, 0xf2, 0x20, 0x3c}}, + {{0x2f, 0x51, 0x99, 0x04, 0xb6, 0x02, 0x5f, 0x3e, 0x3e, 0x7e, 0xfc, 0xb5, 0xd0, 0x35, 0xaa, 0xc6, 0x77, 0x90, 0x3b, 0x99, 0x54, 0x15, 0x0d, 0x31, 0x98, 0xe5, 0xa7, 0x97, 0x1c, 0xaf, 0x2e, 0x3b}, {0xbf, 0x42, 0x4c, 0x9b, 0x64, 0xcb, 0xeb, 0xc7, 0x19, 0xce, 0xf2, 0x10, 0x91, 0x2b, 0xf3, 0x2b, 0x8e, 0xa2, 0x84, 0x68, 0x68, 0xb8, 0xeb, 0xd0, 0x68, 0xe9, 0xa4, 0x95, 0xd6, 0x43, 0x5e, 0x02}}, + {{0xa3, 0x77, 0xe9, 0x05, 0xed, 0x3a, 0x21, 0xe5, 0x89, 0x60, 0x6e, 0x36, 0xc6, 0x23, 0x91, 0xfe, 0xc7, 0x55, 0xbd, 0x4b, 0xbf, 0xb1, 0x9d, 0xff, 0x87, 0x43, 0xeb, 0x7f, 0x09, 0xf8, 0x06, 0x28}, {0xa3, 0x3f, 0xfc, 0xd0, 0xd7, 0xf9, 0xcd, 0xf2, 0xb7, 0x6a, 0xe8, 0xe9, 0x9b, 0xe7, 0x7e, 0x27, 0x4e, 0x9c, 0x38, 0x82, 0xf8, 0x96, 0xc9, 0x37, 0x31, 0x62, 0xad, 0xfa, 0xcf, 0x9e, 0xd0, 0x37}}, + {{0x65, 0xa1, 0x3a, 0x3d, 0x2d, 0xb1, 0x97, 0x6d, 0x43, 0x07, 0xdb, 0x97, 0x33, 0xbd, 0xa0, 0x3c, 0x4c, 0x2a, 0xec, 0x27, 0xf5, 0xcd, 0xeb, 0xc6, 0xe2, 0xc8, 0x7b, 0x58, 0x72, 0x77, 0x7f, 0x37}, {0x65, 0x2e, 0xfd, 0x3f, 0x30, 0xf9, 0x63, 0x25, 0x21, 0x9b, 0x1a, 0xef, 0x2c, 0x47, 0xe7, 0x54, 0x52, 0x49, 0xba, 0xa4, 0x09, 0xb2, 0xf1, 0xfd, 0x30, 0x76, 0xad, 0x09, 0x94, 0xbf, 0x5e, 0x28}}, + {{0xbb, 0x0a, 0x4f, 0xf8, 0x13, 0x9e, 0x0d, 0x30, 0xd6, 0xc8, 0x8d, 0x9c, 0x40, 0x77, 0x6d, 0xd1, 0x05, 0x97, 0xc4, 0x02, 0xdb, 0x6e, 0xb4, 0x88, 0x6d, 0xd3, 0xda, 0xba, 0xfb, 0xe9, 0xc4, 0x05}, {0x02, 0x76, 0xad, 0xbe, 0xe8, 0x5c, 0x51, 0xf1, 0xae, 0x02, 0x22, 0x9b, 0x28, 0xbb, 0x28, 0x39, 0xd9, 0x38, 0xb5, 0x58, 0x76, 0x80, 0xdd, 0x11, 0x74, 0x79, 0x87, 0x2c, 0x47, 0x8f, 0xef, 0x0b}}, + {{0x23, 0x4b, 0xdb, 0xac, 0x76, 0x50, 0x82, 0x91, 0x01, 0x5e, 0x52, 0x2b, 0xb6, 0xaa, 0x1d, 0x5e, 0xab, 0x7e, 0x00, 0xcf, 0x94, 0xf6, 0x48, 0xd3, 0x56, 0xb0, 0x27, 0x25, 0xbf, 0x10, 0xcc, 0x0f}, {0x51, 0xcb, 0x58, 0x92, 0xc9, 0xac, 0xf6, 0x80, 0x46, 0x70, 0x48, 0x1e, 0x31, 0x6f, 0x5d, 0xc1, 0x8a, 0x07, 0xab, 0x8b, 0x8e, 0xb4, 0x42, 0x30, 0x1b, 0x5d, 0xab, 0x48, 0xcf, 0x7f, 0xf4, 0x3c}}, + {{0xfd, 0x58, 0xce, 0x49, 0x12, 0x9e, 0x13, 0x6c, 0xe8, 0xd9, 0xc7, 0x23, 0xf9, 0x81, 0xb0, 0x04, 0x43, 0x0d, 0xe5, 0x88, 0x39, 0x92, 0x7a, 0x8f, 0xbe, 0xa3, 0x25, 0xb3, 0x8d, 0x3b, 0xca, 0x1f}, {0xe1, 0xef, 0xc7, 0x5b, 0x92, 0xf2, 0x2f, 0x69, 0x95, 0xd8, 0x02, 0xb1, 0x8d, 0x35, 0x5d, 0x37, 0x7e, 0xee, 0x12, 0x21, 0x46, 0xf1, 0x77, 0x73, 0xcf, 0xac, 0xd3, 0x74, 0x2a, 0xca, 0xb9, 0x22}}, + {{0x94, 0x77, 0x91, 0x94, 0x58, 0xd3, 0x8d, 0xda, 0x4b, 0x05, 0x77, 0x89, 0x6d, 0xe0, 0x67, 0xe0, 0x99, 0x3e, 0x35, 0xe8, 0xcf, 0x65, 0xe7, 0x68, 0xc6, 0x05, 0x60, 0x7c, 0x76, 0xae, 0x7b, 0x2c}, {0x4f, 0xe3, 0x5e, 0x4e, 0x06, 0x5d, 0x71, 0xbf, 0xeb, 0xab, 0x46, 0x87, 0xe1, 0xa7, 0x99, 0x9c, 0xc4, 0xcc, 0x16, 0x5e, 0xeb, 0xe9, 0x15, 0x76, 0xfa, 0xf7, 0xab, 0x73, 0xb7, 0x84, 0x8e, 0x32}}, + {{0xee, 0xb8, 0xa3, 0x7f, 0xce, 0xfc, 0x57, 0xfe, 0x7a, 0x68, 0xc2, 0xf7, 0x8c, 0x44, 0xc2, 0xc9, 0xd4, 0xc2, 0xd3, 0xef, 0x38, 0xbe, 0xd2, 0x6f, 0xa2, 0x3c, 0x64, 0xad, 0x02, 0x65, 0x88, 0x02}, {0x5c, 0x4d, 0x3f, 0xb0, 0x41, 0x98, 0xc1, 0x4b, 0x01, 0x74, 0xb0, 0xdc, 0x82, 0xea, 0x0b, 0x46, 0xb4, 0x84, 0x57, 0x6c, 0x5e, 0x4a, 0xb2, 0x95, 0x92, 0x9c, 0xa6, 0x7d, 0xee, 0xf8, 0xfb, 0x2b}}, + {{0x2c, 0x23, 0x15, 0xc4, 0x30, 0xac, 0x9f, 0xd3, 0x8d, 0x41, 0xac, 0x3b, 0x9e, 0xa7, 0xdd, 0x76, 0xbd, 0xa8, 0x03, 0xcc, 0x61, 0x50, 0x6a, 0x14, 0xc8, 0x45, 0xb0, 0x23, 0x1b, 0xe6, 0xd1, 0x33}, {0x67, 0x61, 0xc1, 0xa0, 0x38, 0x1d, 0x86, 0x0a, 0x76, 0xfd, 0x25, 0x36, 0x50, 0xd7, 0x03, 0x34, 0x11, 0x51, 0xfc, 0x4d, 0xd8, 0x43, 0x14, 0x5c, 0xb8, 0x34, 0xca, 0x43, 0x6d, 0x16, 0xc4, 0x11}}, + {{0x32, 0xdc, 0xf3, 0x73, 0x01, 0x49, 0xd0, 0x59, 0x64, 0x39, 0xc4, 0xfe, 0x5b, 0x8d, 0x05, 0xba, 0x5a, 0xb9, 0x39, 0x66, 0x16, 0xdd, 0x34, 0xe9, 0xe0, 0xcd, 0x03, 0xbb, 0xea, 0xc6, 0xbb, 0x2b}, {0x07, 0x3d, 0x23, 0x45, 0x18, 0xcf, 0x85, 0xee, 0xf3, 0x3c, 0xa9, 0xe0, 0xb6, 0x4c, 0x68, 0xee, 0xd0, 0x21, 0xee, 0x79, 0xba, 0x3b, 0x6b, 0x25, 0xb9, 0x7b, 0x7f, 0x0f, 0xec, 0x24, 0x22, 0x19}}, + {{0xae, 0xe7, 0x70, 0x26, 0x24, 0x42, 0x0d, 0x5e, 0x12, 0x7a, 0xa1, 0x14, 0x15, 0x3e, 0x25, 0x16, 0xee, 0xfe, 0x06, 0x5d, 0x27, 0x77, 0x19, 0xdc, 0xdd, 0x75, 0x05, 0x3e, 0xc3, 0xe2, 0x45, 0x19}, {0x34, 0x76, 0x99, 0x72, 0x0f, 0x15, 0x3a, 0xd1, 0x78, 0xd8, 0xb3, 0xae, 0xc0, 0x5f, 0x54, 0xfb, 0xb9, 0xfa, 0x5b, 0x4f, 0x6d, 0x97, 0xf3, 0x30, 0xc2, 0x57, 0x4e, 0x96, 0xd6, 0x8d, 0xe2, 0x39}}, + {{0x31, 0x13, 0xef, 0x1d, 0xe3, 0x94, 0x38, 0x63, 0xf0, 0x17, 0x72, 0x91, 0xd2, 0xdc, 0x8a, 0x17, 0x83, 0x38, 0xe1, 0x6b, 0x78, 0x38, 0x1d, 0x66, 0xe2, 0x2c, 0xc8, 0x6f, 0x10, 0xa7, 0x08, 0x34}, {0x3f, 0xed, 0x1b, 0xc7, 0x44, 0x2e, 0x2c, 0x34, 0xd6, 0x70, 0xee, 0x09, 0xe1, 0x42, 0xde, 0x96, 0x0f, 0x82, 0x66, 0xdd, 0x91, 0x68, 0x89, 0x85, 0xcf, 0x7b, 0x70, 0x5d, 0x93, 0x87, 0x41, 0x07}}, + {{0x1d, 0x89, 0xdc, 0xf2, 0x08, 0x7e, 0x0b, 0xc1, 0x1e, 0xd0, 0xe6, 0xd9, 0x3c, 0x91, 0x68, 0x5d, 0x03, 0x39, 0x0b, 0x09, 0x4c, 0x23, 0x5d, 0xdd, 0x4d, 0xb3, 0x16, 0xa2, 0x8d, 0x5b, 0xf0, 0x15}, {0x57, 0xf2, 0x7a, 0xcf, 0xa0, 0xfa, 0x62, 0x79, 0x7d, 0xa4, 0x52, 0x12, 0x1c, 0x18, 0xb0, 0xae, 0xa5, 0xe2, 0xca, 0xf1, 0x4b, 0x6f, 0x61, 0x12, 0x22, 0x91, 0xbd, 0x1f, 0x04, 0xda, 0x22, 0x23}}, + {{0x54, 0xb5, 0x10, 0x49, 0xd7, 0xd4, 0x1f, 0x6a, 0xfb, 0x2d, 0x4e, 0xa3, 0x07, 0x11, 0x8f, 0xe3, 0xa4, 0x3e, 0x6b, 0x80, 0xcb, 0xf5, 0xc6, 0x68, 0xda, 0x07, 0x56, 0x8c, 0x11, 0x47, 0x4a, 0x2b}, {0x26, 0x10, 0xaa, 0x01, 0xcb, 0xe3, 0x83, 0xc7, 0x99, 0x51, 0x8f, 0x28, 0x54, 0x26, 0x61, 0x5c, 0xfd, 0x1a, 0x7a, 0x4c, 0xa7, 0x5a, 0x08, 0x63, 0x2c, 0xc6, 0x93, 0x60, 0x2c, 0xc5, 0xe0, 0x2b}}, + {{0x3a, 0x67, 0x84, 0xb9, 0x7f, 0x88, 0xd8, 0xcf, 0x7a, 0x84, 0x2d, 0x57, 0xf5, 0x4a, 0x45, 0x7d, 0xfa, 0xca, 0x57, 0xe4, 0x6b, 0x5e, 0xcc, 0xb8, 0x31, 0x6b, 0x14, 0x15, 0x4a, 0x5b, 0xf0, 0x05}, {0xdf, 0xb9, 0x66, 0x33, 0x07, 0xb1, 0x83, 0x9b, 0x83, 0xad, 0x08, 0x62, 0x6e, 0x4e, 0x64, 0x7e, 0xbe, 0xec, 0x7f, 0x4f, 0x6b, 0xff, 0xf1, 0xe7, 0xa1, 0x5a, 0x07, 0xe2, 0x07, 0x47, 0x5c, 0x31}}, + {{0x60, 0x9b, 0xf4, 0x75, 0x39, 0xa4, 0x7f, 0x93, 0x00, 0x87, 0xe5, 0x40, 0x08, 0xb8, 0x2b, 0x30, 0x68, 0x26, 0x5d, 0x3f, 0x91, 0xc1, 0x39, 0xb1, 0x55, 0x8e, 0x38, 0x3f, 0x47, 0xf7, 0xd0, 0x37}, {0xaf, 0x51, 0xbb, 0xe1, 0x85, 0xde, 0xc8, 0x85, 0xfe, 0xa3, 0x54, 0x67, 0xa6, 0x5c, 0x8e, 0x24, 0x73, 0xc8, 0xf9, 0xd4, 0x4a, 0x2e, 0xd6, 0xfc, 0xc7, 0xd5, 0xa7, 0x6b, 0x68, 0x03, 0xff, 0x33}}, + {{0x43, 0x04, 0xfb, 0xd5, 0xbc, 0xad, 0x5b, 0x5e, 0x13, 0x66, 0x35, 0x95, 0x8d, 0xd6, 0xc4, 0x78, 0xf9, 0xce, 0x25, 0xe8, 0x1d, 0xf9, 0x3a, 0xfc, 0x1c, 0x4f, 0x2d, 0xe1, 0x87, 0xce, 0xa7, 0x0d}, {0x77, 0xd3, 0x74, 0x60, 0x88, 0x5e, 0xf0, 0x7e, 0x9c, 0x60, 0xb5, 0x52, 0x08, 0xaf, 0x7f, 0x4a, 0x86, 0x89, 0x81, 0x2f, 0xa2, 0x33, 0x09, 0x0b, 0x90, 0x86, 0x55, 0xde, 0xc5, 0xbb, 0x6f, 0x0d}}, + {{0x32, 0xe1, 0xec, 0xb5, 0xbf, 0x03, 0x91, 0xaa, 0x14, 0x9c, 0x6c, 0x12, 0xeb, 0xaa, 0x04, 0x11, 0x08, 0x66, 0x6f, 0x57, 0xc6, 0x39, 0xd5, 0x03, 0x23, 0xe3, 0xb4, 0xc5, 0xd2, 0xa2, 0x97, 0x22}, {0xbe, 0xe7, 0x9c, 0x21, 0x48, 0xc8, 0xd6, 0x60, 0xb0, 0x63, 0xcd, 0x00, 0xe1, 0x10, 0x5a, 0xb0, 0x88, 0x4b, 0x3f, 0x7b, 0x17, 0xea, 0x9b, 0x42, 0xba, 0xe7, 0x23, 0xf3, 0x16, 0xc9, 0x1d, 0x0c}}, + {{0xf4, 0x8b, 0xb0, 0x41, 0x55, 0xaf, 0x91, 0x7e, 0xb1, 0xd6, 0x5f, 0xce, 0xf3, 0x87, 0xb7, 0x7e, 0x56, 0x2b, 0xf1, 0x45, 0x88, 0xa3, 0x6d, 0x71, 0x4d, 0x6f, 0x64, 0xac, 0x98, 0x6e, 0x63, 0x0b}, {0xdb, 0x13, 0x3e, 0xa4, 0xd1, 0x12, 0xb7, 0x4a, 0xbf, 0x27, 0x4b, 0xe2, 0xeb, 0x52, 0x0a, 0xe6, 0x09, 0x7f, 0x55, 0x2b, 0xa5, 0xfb, 0x6c, 0x05, 0x36, 0xf2, 0xcd, 0x32, 0xf4, 0x62, 0xac, 0x1f}}, + {{0x31, 0xe6, 0xbd, 0xeb, 0xb7, 0x15, 0xfa, 0x2d, 0xaf, 0x63, 0xc0, 0xa9, 0x4d, 0xf9, 0x20, 0xb3, 0x37, 0x6a, 0xe8, 0x50, 0x1c, 0x60, 0x77, 0x1b, 0x76, 0x38, 0x0a, 0xd0, 0xf5, 0x2f, 0x4c, 0x3d}, {0xbc, 0x26, 0xde, 0x43, 0x17, 0x34, 0x2a, 0x27, 0x71, 0x3c, 0x92, 0x49, 0x59, 0x4b, 0xa5, 0xae, 0x83, 0xb1, 0x35, 0xc5, 0x07, 0xe8, 0x4d, 0x0c, 0xa7, 0x71, 0xc7, 0xae, 0x06, 0xc8, 0x65, 0x27}}, + {{0x3a, 0xe1, 0x63, 0x7b, 0x25, 0x8f, 0xec, 0x55, 0xe8, 0x9e, 0xec, 0x66, 0xd5, 0x34, 0xfc, 0xd5, 0x78, 0x82, 0xd0, 0x91, 0x20, 0xe3, 0xc2, 0x56, 0x23, 0xdc, 0x3d, 0x0e, 0x85, 0x21, 0x91, 0x16}, {0x8d, 0x63, 0xe5, 0xbe, 0x83, 0x49, 0x48, 0xa1, 0x71, 0x8b, 0x92, 0xc4, 0x1b, 0xeb, 0x79, 0x8a, 0x4b, 0x98, 0x29, 0xd0, 0xfc, 0xd4, 0xdf, 0xd6, 0xe9, 0x9a, 0x2f, 0x16, 0x98, 0x36, 0xbd, 0x2c}}, + {{0x20, 0x73, 0xc4, 0xe3, 0xbc, 0x05, 0x1b, 0x7a, 0x09, 0x84, 0x7e, 0x29, 0x39, 0x60, 0xa7, 0x32, 0x97, 0xa9, 0x80, 0x53, 0xe5, 0x44, 0x2f, 0x73, 0x4e, 0xa4, 0x70, 0xe8, 0x4a, 0xa3, 0x2a, 0x20}, {0xe7, 0x74, 0x31, 0x4f, 0x6e, 0x6f, 0x68, 0x48, 0xe3, 0xa1, 0x12, 0xae, 0x5c, 0x57, 0xff, 0x36, 0xa7, 0x50, 0x1b, 0x58, 0x2d, 0xf4, 0x9a, 0xe0, 0x25, 0xf8, 0x1c, 0x0a, 0x37, 0x49, 0x14, 0x21}}, + {{0x02, 0x11, 0x83, 0xb1, 0x77, 0x2a, 0x42, 0xdb, 0xb1, 0x98, 0x49, 0x10, 0x1d, 0xc2, 0xf8, 0x7b, 0xf9, 0x75, 0xd6, 0x9a, 0x9c, 0xb7, 0x43, 0xce, 0x21, 0x89, 0x18, 0xa7, 0xc6, 0x78, 0x9d, 0x34}, {0x0f, 0x08, 0x9f, 0x69, 0x0f, 0xba, 0x70, 0x30, 0x8a, 0xc1, 0xb8, 0x36, 0xe0, 0xf6, 0x34, 0xd1, 0x3f, 0xaa, 0xd2, 0x2c, 0xa7, 0xd0, 0x34, 0xda, 0x20, 0xb0, 0xc3, 0x37, 0x3e, 0x7a, 0x45, 0x29}}, + {{0x4e, 0x77, 0x1b, 0xd2, 0x66, 0x66, 0xa1, 0x6f, 0x7c, 0x76, 0x6f, 0x0e, 0xb1, 0xc4, 0x1f, 0xb9, 0x0b, 0xdf, 0x6c, 0x41, 0x01, 0x84, 0xaf, 0x12, 0xa0, 0xd1, 0xc1, 0x4c, 0xa3, 0x43, 0x0f, 0x22}, {0x92, 0xf8, 0x6e, 0xb2, 0x0c, 0x06, 0x2b, 0xab, 0xe2, 0x10, 0x38, 0xa5, 0xb1, 0x8a, 0x80, 0xe5, 0x0c, 0x57, 0x13, 0x33, 0x72, 0xe4, 0x6f, 0xf3, 0xb1, 0x59, 0x34, 0x39, 0x73, 0x3b, 0xf1, 0x36}}, + {{0x88, 0xb4, 0x7d, 0x94, 0xb2, 0xeb, 0x49, 0x4e, 0x53, 0xc2, 0x7d, 0xd9, 0xd3, 0x04, 0x2c, 0x24, 0x17, 0xb0, 0xfd, 0xd7, 0xd8, 0xd8, 0x41, 0x9f, 0xe0, 0x81, 0xff, 0xad, 0xdc, 0x52, 0x3c, 0x01}, {0xd9, 0xeb, 0xca, 0x54, 0xca, 0x7a, 0x29, 0x0a, 0x09, 0x9e, 0x34, 0xe4, 0xde, 0xab, 0xb0, 0x63, 0x0b, 0xf2, 0x49, 0xc7, 0x8c, 0x94, 0xd0, 0x51, 0xf4, 0xb0, 0x55, 0x9a, 0xb0, 0x8d, 0x9a, 0x06}}, + {{0x32, 0x80, 0xf7, 0x71, 0x8a, 0xb2, 0x6f, 0x40, 0x29, 0x49, 0xfe, 0x82, 0x29, 0xb4, 0x9e, 0x96, 0x95, 0x20, 0xc8, 0x53, 0xa1, 0x24, 0xaf, 0xb1, 0xa7, 0x23, 0x65, 0xa1, 0x55, 0x32, 0x2a, 0x05}, {0xd2, 0xdc, 0xc3, 0x5a, 0xb9, 0x82, 0xf1, 0x98, 0xa8, 0xf3, 0x43, 0xbf, 0x0c, 0xed, 0x88, 0xb0, 0x22, 0xdb, 0x59, 0xc0, 0x2d, 0xfe, 0x50, 0xf9, 0x39, 0xd5, 0x6f, 0xcd, 0xda, 0x06, 0x40, 0x14}}, + {{0x1e, 0x3f, 0x9d, 0xac, 0xdf, 0xfe, 0x59, 0xda, 0xb1, 0x29, 0x98, 0x3e, 0x4a, 0xcb, 0x6a, 0x22, 0xdc, 0x88, 0x04, 0xa5, 0x88, 0x33, 0x73, 0x3a, 0x57, 0xa4, 0x3b, 0x13, 0x0a, 0xf7, 0x91, 0x38}, {0x1f, 0xd7, 0xf2, 0x4b, 0xd8, 0x6e, 0xc4, 0x25, 0x37, 0xe7, 0x00, 0x1b, 0xe2, 0x2f, 0xf1, 0xbf, 0x87, 0x87, 0x3f, 0x1e, 0x77, 0x63, 0xdc, 0xae, 0xac, 0xd5, 0xef, 0xc7, 0x7c, 0xb2, 0xd1, 0x0e}}, + {{0x81, 0xcc, 0xd3, 0x40, 0x6d, 0x51, 0xd0, 0xc0, 0xc9, 0x43, 0x77, 0x16, 0x16, 0x08, 0x49, 0xa6, 0xd5, 0xc1, 0x43, 0x42, 0xc4, 0xf4, 0x42, 0xca, 0x5e, 0x8b, 0x3d, 0xb2, 0x5b, 0x8f, 0xb3, 0x23}, {0x23, 0xfa, 0xc3, 0xdc, 0x2c, 0xa3, 0x2a, 0xed, 0xc3, 0x02, 0xf1, 0xfe, 0x63, 0x34, 0xda, 0x8c, 0x3c, 0xce, 0x33, 0xe4, 0x06, 0xf0, 0x5a, 0x6b, 0xb2, 0x56, 0x84, 0x7f, 0x05, 0xdf, 0x25, 0x12}}, + {{0x4c, 0xe0, 0xa0, 0x56, 0x73, 0x0d, 0x91, 0x82, 0xf0, 0x66, 0x8f, 0xc3, 0xac, 0x73, 0xb6, 0x64, 0x32, 0x09, 0x03, 0x9d, 0x57, 0xf6, 0x23, 0xdd, 0xcd, 0x73, 0x28, 0x03, 0x8d, 0xcf, 0x91, 0x2e}, {0xb3, 0xd6, 0xc0, 0x64, 0x50, 0x85, 0x94, 0x6c, 0xb0, 0xbe, 0x0a, 0x5e, 0xd2, 0x80, 0x29, 0x7a, 0x56, 0x16, 0xb8, 0x26, 0xfb, 0xe0, 0x51, 0xb6, 0x32, 0x15, 0x40, 0x96, 0x40, 0x84, 0x5a, 0x3b}}, + {{0xfb, 0xbb, 0x71, 0x95, 0x27, 0x86, 0xdb, 0xba, 0x35, 0x88, 0x5e, 0xa7, 0x09, 0x48, 0x4b, 0x12, 0x17, 0x1c, 0x61, 0x47, 0xa7, 0x00, 0xe7, 0xc9, 0xcd, 0x5b, 0x07, 0xf2, 0x57, 0xb0, 0x20, 0x09}, {0x69, 0x6e, 0x57, 0x7f, 0xd2, 0x28, 0xf4, 0xed, 0x38, 0xb4, 0xe9, 0x29, 0x61, 0xb8, 0xdb, 0x81, 0x93, 0xec, 0x15, 0x1e, 0xd3, 0xee, 0x8e, 0xfa, 0xed, 0x0b, 0x4e, 0x89, 0xbe, 0x9f, 0x26, 0x11}}, + {{0x1f, 0x7f, 0x44, 0x7c, 0x1d, 0xfe, 0xf4, 0xb1, 0xfc, 0x51, 0x58, 0x97, 0x9d, 0x25, 0xc4, 0x83, 0x1b, 0x60, 0x1e, 0xbf, 0xb5, 0x2c, 0x7c, 0x11, 0xdd, 0x00, 0x54, 0xd9, 0x09, 0x4c, 0xd9, 0x22}, {0x24, 0x49, 0xd2, 0xb5, 0x9f, 0x7d, 0x83, 0xd6, 0x19, 0x06, 0x04, 0xf5, 0x36, 0x26, 0x3b, 0x31, 0xd6, 0x48, 0xe0, 0x08, 0x49, 0xfc, 0x63, 0x2b, 0x9c, 0xac, 0x53, 0x05, 0xd2, 0xde, 0x44, 0x11}}, + {{0x94, 0x53, 0x42, 0xa2, 0x08, 0xb4, 0x7c, 0x38, 0xd9, 0x53, 0x4c, 0xb2, 0x9b, 0x36, 0x79, 0xd0, 0xc3, 0xd4, 0xe9, 0xd9, 0x08, 0xd0, 0x15, 0x8f, 0x9d, 0xf4, 0xc6, 0xe2, 0xbf, 0xc6, 0x50, 0x31}, {0x9d, 0x72, 0xf7, 0xc1, 0x8f, 0x72, 0x04, 0x04, 0x8c, 0xfc, 0x54, 0x24, 0xbd, 0xa4, 0x67, 0x78, 0xe2, 0x12, 0x8a, 0x3e, 0x2d, 0x53, 0xce, 0x41, 0x5f, 0xf3, 0x8e, 0x46, 0xa9, 0x02, 0xa3, 0x1b}}, + {{0xc5, 0x4e, 0xb3, 0xc9, 0xbf, 0x09, 0xb3, 0x3d, 0xcc, 0x8b, 0xca, 0x20, 0x96, 0x0f, 0x33, 0x50, 0xe0, 0x2b, 0xaa, 0x76, 0x58, 0xc0, 0xba, 0xa8, 0xeb, 0x7a, 0x53, 0x52, 0x6c, 0xb1, 0x48, 0x14}, {0x6f, 0x2a, 0xd8, 0x00, 0x90, 0xae, 0x39, 0xc1, 0xb5, 0x47, 0x43, 0xe2, 0xa0, 0x76, 0x82, 0xe8, 0x5b, 0xaf, 0x82, 0x1e, 0x6e, 0x9c, 0xdd, 0x3d, 0xb8, 0x70, 0x20, 0xc0, 0x12, 0x29, 0xf6, 0x36}}, + {{0x8f, 0xfd, 0x61, 0xd8, 0x05, 0x2b, 0x02, 0x14, 0xe6, 0xa9, 0xb6, 0x50, 0xf5, 0x89, 0xd7, 0x41, 0x32, 0x23, 0xc8, 0x6f, 0x5d, 0x6c, 0xd2, 0x87, 0x2e, 0x56, 0xb6, 0x95, 0xe2, 0x35, 0xf8, 0x02}, {0xd8, 0x4a, 0xf7, 0x52, 0x06, 0x3c, 0xb9, 0xbe, 0x9d, 0xcd, 0xe4, 0x05, 0xc1, 0x72, 0x19, 0xe6, 0xdd, 0x75, 0x8f, 0x67, 0x7f, 0x8d, 0x4a, 0x88, 0x6f, 0x88, 0xc8, 0x1c, 0x06, 0x60, 0x74, 0x28}}, + {{0xf2, 0x58, 0xb9, 0xc3, 0xca, 0x75, 0xf1, 0x69, 0x98, 0x39, 0xb5, 0xab, 0xef, 0xf1, 0x47, 0x67, 0x4c, 0xf4, 0x49, 0x09, 0x53, 0x4c, 0xec, 0x46, 0x0e, 0x1e, 0xe1, 0x46, 0xf2, 0xe7, 0xba, 0x07}, {0x41, 0xdc, 0x19, 0x0c, 0x5b, 0xd2, 0x21, 0x10, 0xf4, 0x28, 0x97, 0x94, 0xbd, 0x36, 0x7a, 0xea, 0xa7, 0xc8, 0xea, 0x2c, 0xcd, 0xe7, 0x59, 0xa8, 0x90, 0x39, 0x25, 0xf8, 0x8c, 0x9a, 0xfc, 0x0e}}, + {{0x7b, 0xa7, 0xa5, 0x0d, 0xb9, 0x1f, 0xea, 0x5d, 0xc6, 0xbc, 0x4a, 0x13, 0xb8, 0x3b, 0xe1, 0xc0, 0xd4, 0xb2, 0xea, 0xc9, 0x5c, 0xd3, 0x38, 0x99, 0x1f, 0xcd, 0x6b, 0xa1, 0x12, 0x55, 0x83, 0x22}, {0x7e, 0xad, 0x0f, 0x1b, 0xf3, 0xea, 0xe9, 0x9b, 0xf9, 0x71, 0xa1, 0x0c, 0x52, 0x2b, 0x91, 0x34, 0x7e, 0xac, 0xb9, 0x31, 0x00, 0x8f, 0x21, 0x07, 0x2f, 0x69, 0xc4, 0x90, 0xe8, 0xf8, 0x74, 0x0e}}, + {{0xb9, 0x5f, 0xac, 0x26, 0xe4, 0x0c, 0x4a, 0x6b, 0x7e, 0x70, 0x71, 0xe1, 0x31, 0x23, 0xcf, 0x13, 0xa1, 0x6e, 0xcd, 0x4f, 0x2e, 0x19, 0x39, 0x85, 0xab, 0x01, 0x03, 0x6e, 0x53, 0xaa, 0x8c, 0x12}, {0xba, 0xfc, 0xa7, 0x43, 0xb3, 0x8c, 0x6b, 0x6e, 0x3d, 0x32, 0x72, 0x64, 0x3a, 0x35, 0xb2, 0xb4, 0xa2, 0x61, 0xfd, 0xa8, 0x71, 0x08, 0x67, 0x48, 0x4d, 0x1c, 0xca, 0xbd, 0xf8, 0xbc, 0xc8, 0x11}}, + {{0x93, 0x76, 0x0c, 0x6f, 0x6f, 0xbb, 0x8f, 0x8f, 0xda, 0x9e, 0x6f, 0x9f, 0x9f, 0x2c, 0xcd, 0xa8, 0xfa, 0xda, 0xab, 0x01, 0x1d, 0x1e, 0xf7, 0xf8, 0xdc, 0xa1, 0x12, 0x05, 0xe0, 0x41, 0x1a, 0x30}, {0x8f, 0x86, 0x80, 0x9d, 0x7b, 0x6c, 0x70, 0xcb, 0xf4, 0x64, 0x03, 0x5c, 0x79, 0xd2, 0xa6, 0xf2, 0x43, 0x73, 0x6b, 0xec, 0x48, 0xe1, 0x2a, 0xbf, 0xb8, 0x59, 0xc4, 0x74, 0x4b, 0x3b, 0x3f, 0x30}}, + {{0x3b, 0x8e, 0x07, 0xe0, 0xc8, 0xa5, 0x67, 0x4c, 0xcb, 0x6b, 0x59, 0xf2, 0x87, 0xf4, 0x11, 0x5a, 0xaa, 0xb8, 0x98, 0xe4, 0xc8, 0x26, 0xd4, 0x52, 0xd6, 0xe1, 0x46, 0x45, 0xee, 0x81, 0xf9, 0x1b}, {0xce, 0x0a, 0xc4, 0xf3, 0xda, 0x9e, 0x5b, 0xb2, 0x8e, 0xa6, 0xf9, 0x5f, 0xe5, 0x57, 0xd8, 0x4c, 0xaa, 0xe5, 0x0b, 0xa5, 0x95, 0x42, 0x57, 0x4c, 0x72, 0xef, 0x13, 0x9f, 0xd8, 0xbc, 0x57, 0x14}}, + {{0x23, 0x50, 0xf9, 0x9a, 0x96, 0x81, 0x49, 0x6e, 0x4d, 0xfd, 0x85, 0xda, 0x41, 0xad, 0xf4, 0xa9, 0x79, 0xda, 0xdb, 0xfc, 0xf0, 0xd9, 0x43, 0xf6, 0x75, 0x62, 0xd6, 0x2d, 0xdf, 0x61, 0x77, 0x10}, {0x6e, 0xc7, 0xaf, 0xb1, 0x06, 0xbd, 0x32, 0xfa, 0x0e, 0xcb, 0xa2, 0x1d, 0xa4, 0x2f, 0x1c, 0xe6, 0xed, 0xe9, 0x3c, 0x04, 0x9c, 0x28, 0x70, 0x4c, 0x91, 0xd3, 0xfb, 0xdd, 0x5d, 0xdd, 0x56, 0x20}}, + {{0xf4, 0x8a, 0xeb, 0xa5, 0x11, 0xb3, 0xf7, 0xe6, 0x3d, 0xc1, 0x28, 0x4f, 0xa1, 0xde, 0xcb, 0xbb, 0xc0, 0x48, 0x6b, 0xc0, 0x2a, 0xfc, 0x2a, 0x83, 0xd1, 0x39, 0x23, 0x9a, 0x84, 0xc4, 0x84, 0x18}, {0x7e, 0x14, 0x05, 0xcf, 0x27, 0xea, 0x85, 0xae, 0x70, 0x87, 0xd7, 0x5a, 0x54, 0xd6, 0x61, 0xa6, 0x02, 0x1e, 0xcd, 0x23, 0xbd, 0xb5, 0xff, 0x8c, 0xb0, 0x87, 0x59, 0x3d, 0x7a, 0xa1, 0x4a, 0x0c}}, + {{0xd6, 0xc6, 0xd2, 0x20, 0x71, 0x2b, 0x03, 0x09, 0xc6, 0xcc, 0x6d, 0xd0, 0x5d, 0x35, 0x1f, 0x63, 0x96, 0x6b, 0x4a, 0xef, 0x8c, 0xc7, 0x7c, 0xf8, 0x9d, 0x9f, 0x6f, 0xdc, 0xd1, 0xd7, 0xf8, 0x3e}, {0xd2, 0xc9, 0xdd, 0x48, 0x49, 0xad, 0xce, 0x43, 0xfc, 0x9f, 0xca, 0x7c, 0x07, 0x74, 0xc3, 0x2d, 0x8d, 0x3e, 0xdb, 0x67, 0xbd, 0xdd, 0x61, 0xac, 0xdc, 0xde, 0x3f, 0xd0, 0xb8, 0xf7, 0x97, 0x02}}, + {{0x0d, 0xa0, 0xba, 0xaf, 0xb5, 0x0e, 0x1c, 0x36, 0x25, 0x82, 0xc8, 0x48, 0x9c, 0x78, 0x51, 0x80, 0x22, 0x2d, 0x49, 0x26, 0x16, 0x16, 0x87, 0x98, 0xa2, 0x18, 0x1f, 0x50, 0x90, 0x66, 0x51, 0x3d}, {0x26, 0xd1, 0x3d, 0x84, 0xfb, 0x1b, 0x63, 0x3a, 0x22, 0x05, 0xeb, 0xc4, 0xd0, 0x64, 0x8c, 0x4a, 0xf3, 0x76, 0x15, 0x30, 0x2e, 0x95, 0x24, 0x91, 0xc8, 0x10, 0xaf, 0x79, 0x83, 0x25, 0x00, 0x1a}}, + {{0x43, 0x6e, 0xee, 0x1e, 0x60, 0xd0, 0xb3, 0xd1, 0x7c, 0x3d, 0xcb, 0xaf, 0x77, 0xf7, 0xc5, 0xc4, 0x41, 0x4f, 0xee, 0xcd, 0x65, 0xcf, 0x90, 0x58, 0x69, 0x08, 0xa7, 0x6c, 0xcd, 0x6d, 0xac, 0x3b}, {0xc6, 0x0f, 0x7d, 0x9c, 0xc5, 0x20, 0xf9, 0xdd, 0x3d, 0x2d, 0xfe, 0x6a, 0x0c, 0x3a, 0x86, 0x05, 0x16, 0xf4, 0x17, 0x93, 0x76, 0xe2, 0xd2, 0x14, 0x97, 0xb0, 0xc7, 0xda, 0xba, 0x6e, 0x0a, 0x1b}}, + {{0x39, 0xaa, 0xaa, 0x46, 0xb6, 0x4a, 0x96, 0x13, 0x1b, 0xf3, 0x54, 0xae, 0x7a, 0x08, 0xab, 0x63, 0x20, 0x53, 0x03, 0xb9, 0x8d, 0x90, 0x98, 0x6d, 0xe0, 0x9e, 0xd6, 0x6e, 0x93, 0xa5, 0xd0, 0x38}, {0x2a, 0x57, 0xe3, 0xae, 0x45, 0xdf, 0xad, 0x63, 0xfe, 0x96, 0xa8, 0x3a, 0x42, 0x22, 0x8b, 0xce, 0x07, 0x5d, 0x24, 0xc7, 0x61, 0x42, 0xc1, 0xdd, 0xa2, 0x1b, 0xf9, 0xd4, 0xd4, 0x1c, 0x35, 0x35}}, + {{0xdd, 0xe9, 0x44, 0xa7, 0x6f, 0xa0, 0xca, 0xb5, 0x57, 0xd4, 0x70, 0x56, 0x58, 0x7f, 0xe3, 0x38, 0xbb, 0x0b, 0x6f, 0x54, 0x67, 0xa4, 0xdf, 0xb4, 0x94, 0xc3, 0xe9, 0x87, 0x21, 0x18, 0xc3, 0x01}, {0x6f, 0xa4, 0x86, 0x1c, 0xf3, 0x1d, 0x5c, 0x73, 0x84, 0x87, 0x30, 0x95, 0xe7, 0x47, 0x5a, 0xc3, 0x15, 0xd7, 0xad, 0x17, 0x84, 0xcd, 0x2d, 0x0b, 0xaa, 0x2b, 0x3a, 0xb6, 0xe8, 0xdf, 0x6c, 0x10}}, + {{0xbb, 0x0a, 0x07, 0x0c, 0x6d, 0x02, 0x6e, 0x1a, 0xb2, 0x32, 0xb5, 0x15, 0x62, 0xb5, 0xa9, 0xac, 0x0a, 0xf3, 0x5c, 0x36, 0x95, 0x5c, 0x1e, 0xd4, 0xdc, 0x36, 0xc0, 0x8d, 0x02, 0xca, 0x8d, 0x28}, {0xed, 0x98, 0x23, 0x85, 0xed, 0x4d, 0x2c, 0x66, 0x3d, 0x42, 0x12, 0x1d, 0x0a, 0xbe, 0xd7, 0xb2, 0x5c, 0x81, 0x20, 0xde, 0xb5, 0xe3, 0xc6, 0x3e, 0x8f, 0xaf, 0x24, 0xd0, 0x61, 0xf4, 0x1f, 0x29}}, + {{0xec, 0x27, 0x6c, 0xd1, 0x66, 0xfa, 0x9f, 0xb0, 0x2a, 0xd7, 0x93, 0x85, 0xb0, 0x22, 0xda, 0xa1, 0x20, 0xeb, 0x54, 0xdc, 0x40, 0x92, 0x32, 0xe6, 0x8d, 0x67, 0x44, 0xe0, 0x54, 0x79, 0x76, 0x1a}, {0x27, 0x04, 0xa5, 0x85, 0x09, 0xcd, 0xfa, 0xe6, 0xb2, 0xf7, 0xdd, 0xed, 0x98, 0x85, 0x48, 0xd3, 0xc4, 0xbc, 0xc8, 0x08, 0x6f, 0x30, 0xa2, 0xd7, 0x59, 0xe4, 0x16, 0x03, 0xd5, 0xfc, 0xf0, 0x14}}, + {{0x4e, 0x6f, 0x64, 0x5b, 0xf3, 0xc8, 0x32, 0x8f, 0xef, 0x4d, 0xeb, 0x88, 0xfc, 0x08, 0xaa, 0x21, 0x34, 0x9a, 0x58, 0xde, 0x7f, 0x59, 0x01, 0x28, 0x66, 0x04, 0xd6, 0x2a, 0x17, 0xa4, 0x30, 0x3a}, {0xee, 0x19, 0x11, 0xe0, 0x40, 0x95, 0x06, 0x7d, 0x56, 0x73, 0x1b, 0x73, 0x7c, 0x55, 0x67, 0xc9, 0x1d, 0x2f, 0xa4, 0x83, 0x02, 0x4c, 0x5a, 0xda, 0xe0, 0xc1, 0x72, 0xc9, 0xfb, 0x57, 0x3a, 0x3d}}, + {{0x53, 0x2a, 0xe0, 0xc3, 0xcc, 0xf6, 0xc1, 0xd3, 0x68, 0x12, 0xc7, 0x7e, 0xdc, 0x5f, 0x47, 0x05, 0x9d, 0x5b, 0x9f, 0xf1, 0x37, 0x96, 0x00, 0xf0, 0x81, 0xbd, 0x48, 0xca, 0xfd, 0xde, 0xff, 0x30}, {0x9a, 0xc2, 0x15, 0x82, 0x09, 0x94, 0xae, 0x91, 0xf6, 0x03, 0xeb, 0x20, 0xd0, 0x5e, 0x32, 0x61, 0xdc, 0x18, 0xbe, 0x04, 0x95, 0xc7, 0x02, 0x79, 0xe2, 0xff, 0x6b, 0xcb, 0x09, 0x0d, 0xd2, 0x2f}}, + {{0xdc, 0x73, 0x42, 0xd5, 0x0b, 0xa6, 0x31, 0x1a, 0x50, 0xb1, 0xb6, 0x04, 0xc7, 0x1c, 0x7f, 0xdb, 0x13, 0xd0, 0x21, 0x01, 0x54, 0xc0, 0x61, 0x18, 0xa3, 0xa5, 0x53, 0x91, 0x73, 0xc1, 0x6c, 0x20}, {0xd5, 0xfb, 0x75, 0x57, 0x82, 0xcb, 0xe9, 0xe0, 0xdf, 0xf7, 0x24, 0x75, 0xcc, 0x49, 0x76, 0x43, 0x15, 0xcd, 0x34, 0x21, 0x0e, 0x08, 0xd2, 0x7b, 0x71, 0x7e, 0xda, 0xe2, 0x88, 0xde, 0xf0, 0x31}}, + {{0xa5, 0xd7, 0x0b, 0x78, 0x73, 0x81, 0x72, 0xfc, 0x5b, 0x06, 0xbf, 0xbc, 0x64, 0xd6, 0xef, 0x7a, 0x55, 0xe3, 0x2c, 0x0b, 0xb7, 0xa3, 0x0b, 0xb0, 0xdb, 0xf5, 0xc9, 0x28, 0xa7, 0x84, 0x99, 0x36}, {0x17, 0x42, 0x9f, 0x83, 0x05, 0x10, 0x09, 0xce, 0xa3, 0x58, 0x7c, 0xfe, 0xc5, 0xdc, 0x95, 0x32, 0x0a, 0xb6, 0xa0, 0xbd, 0x09, 0x06, 0xa3, 0x5a, 0xf2, 0xb0, 0xbb, 0xcd, 0x89, 0xcf, 0x41, 0x02}}, + {{0xb1, 0x29, 0xba, 0x9e, 0x31, 0x19, 0x00, 0x1b, 0xa3, 0x8d, 0xf9, 0x26, 0x55, 0x7d, 0x16, 0x72, 0x4f, 0x75, 0x99, 0xa7, 0x05, 0xf7, 0xcf, 0xe7, 0x2b, 0xdc, 0xf8, 0x70, 0x50, 0xfd, 0x90, 0x29}, {0x99, 0x3e, 0xc6, 0x49, 0xc4, 0xc7, 0xed, 0x1e, 0x44, 0x55, 0x85, 0xef, 0x38, 0x26, 0xf4, 0xbb, 0x2e, 0xa4, 0xf0, 0x23, 0x96, 0xcb, 0x55, 0xf7, 0x97, 0x1d, 0xe3, 0x5f, 0xe0, 0xb0, 0xee, 0x01}}, + {{0xa3, 0x54, 0xb1, 0x40, 0x9e, 0x1f, 0x7e, 0xe3, 0x6d, 0x02, 0x13, 0xcc, 0xf0, 0x23, 0x2d, 0x65, 0xe8, 0x7e, 0x49, 0x1d, 0x90, 0x41, 0x86, 0x8e, 0xb9, 0xb3, 0x25, 0x07, 0x66, 0x9f, 0x64, 0x06}, {0xf4, 0x56, 0xc0, 0x83, 0xbc, 0xdc, 0x7e, 0xf1, 0x3f, 0x38, 0xc1, 0x3d, 0xc3, 0xce, 0x63, 0xbb, 0x36, 0xa5, 0x4f, 0x89, 0x21, 0x61, 0x3f, 0x8e, 0x7c, 0xb0, 0x60, 0x1c, 0x8a, 0x2d, 0x11, 0x3c}}, + {{0x12, 0xfe, 0xbb, 0x56, 0x79, 0x7d, 0x3e, 0x1a, 0xbe, 0x37, 0x1d, 0x4c, 0x39, 0xca, 0xa9, 0xa7, 0x2e, 0xa8, 0xc4, 0xc9, 0xaf, 0x4a, 0x40, 0x97, 0x8a, 0x37, 0x7c, 0x3d, 0xa0, 0x35, 0xaa, 0x38}, {0x5d, 0xbb, 0xe0, 0x8d, 0x5e, 0x7d, 0x31, 0xb6, 0xd0, 0x69, 0xbc, 0xad, 0x17, 0x99, 0x67, 0xdc, 0x66, 0x85, 0xf3, 0xc7, 0xfe, 0x71, 0xb9, 0x68, 0x95, 0x7a, 0x70, 0x99, 0x89, 0xcd, 0x89, 0x19}}, + {{0xbb, 0x96, 0x92, 0xba, 0x13, 0x50, 0x20, 0xb2, 0x76, 0xa7, 0xfa, 0x36, 0x75, 0xda, 0x58, 0x20, 0x88, 0xc0, 0x4a, 0xf8, 0xe3, 0x5b, 0x36, 0x04, 0x32, 0xa0, 0x0f, 0x3b, 0x2f, 0x7a, 0xf4, 0x1a}, {0x8f, 0xd5, 0x43, 0x3d, 0x96, 0x47, 0xbf, 0x2a, 0xf1, 0xf0, 0x3d, 0x40, 0x75, 0x0d, 0x35, 0xb2, 0x5a, 0x3e, 0xfe, 0x77, 0x06, 0xf7, 0x21, 0xa0, 0x90, 0x7b, 0x07, 0x4c, 0xad, 0xcd, 0x2f, 0x32}}, + {{0xd4, 0xd5, 0xe5, 0xcb, 0x6c, 0xae, 0xa9, 0x06, 0xf6, 0xe6, 0xa5, 0x03, 0xd7, 0x45, 0x6b, 0xaa, 0x32, 0x09, 0xbe, 0xbe, 0x8b, 0xa7, 0x14, 0x46, 0x21, 0xec, 0x90, 0x2c, 0xd2, 0x6b, 0xcc, 0x18}, {0xb8, 0xa0, 0xd8, 0xfe, 0x8d, 0x71, 0x7c, 0x96, 0x47, 0x42, 0xb3, 0x31, 0x7f, 0xbc, 0xa7, 0x95, 0x2c, 0xda, 0xe0, 0x19, 0xaf, 0x1f, 0x19, 0x5a, 0x8f, 0x48, 0x38, 0x13, 0x41, 0xc8, 0x5b, 0x11}}, + {{0x85, 0xa4, 0x5e, 0x91, 0x19, 0xca, 0x51, 0x1d, 0xaf, 0xb7, 0x1d, 0x25, 0xf8, 0x77, 0x43, 0x0b, 0x48, 0x5a, 0xea, 0xe0, 0x37, 0xfb, 0x25, 0x08, 0xbf, 0x9c, 0x8c, 0x3b, 0x2e, 0x07, 0x48, 0x15}, {0x29, 0x4b, 0x54, 0xab, 0xb8, 0x6b, 0xeb, 0x48, 0x3a, 0xea, 0x75, 0xec, 0x9c, 0xf2, 0x66, 0xae, 0x9c, 0xb4, 0x7a, 0x16, 0xa2, 0x4b, 0x95, 0x31, 0x7b, 0x5f, 0x93, 0xdb, 0xaa, 0xaa, 0x57, 0x3d}}, + {{0x97, 0x43, 0x14, 0xd4, 0x90, 0x33, 0x46, 0x0c, 0xf6, 0x80, 0xf0, 0x4b, 0xdc, 0x52, 0x83, 0xb6, 0x45, 0x0e, 0x37, 0x07, 0x61, 0x58, 0xa1, 0xa6, 0x41, 0xd3, 0xbc, 0xff, 0xaa, 0x81, 0x00, 0x24}, {0x03, 0xa8, 0xb3, 0x46, 0xca, 0xdf, 0xef, 0xbb, 0x77, 0x68, 0x04, 0x0c, 0x85, 0x0e, 0xdd, 0xc3, 0x64, 0xec, 0xeb, 0x2f, 0xe2, 0xe8, 0xe3, 0x71, 0xfc, 0x39, 0xa5, 0xb5, 0xf7, 0xea, 0xa9, 0x08}}, + {{0xb4, 0x93, 0x1b, 0xb3, 0xb1, 0xc2, 0x06, 0x5e, 0x75, 0xdc, 0x20, 0x43, 0x7c, 0xa3, 0x13, 0xc3, 0x7b, 0x6f, 0x12, 0x26, 0x95, 0xa2, 0xfc, 0x7e, 0x41, 0x17, 0xbf, 0x40, 0x3d, 0xf8, 0xff, 0x0a}, {0x4b, 0x1d, 0xc8, 0xfd, 0x4c, 0x8f, 0xcb, 0xc7, 0x57, 0x84, 0x0c, 0xf4, 0x94, 0xfd, 0x50, 0x5a, 0x2b, 0xf1, 0x74, 0x1e, 0x91, 0x47, 0xd6, 0x71, 0x70, 0x7c, 0x80, 0xee, 0x61, 0x66, 0x41, 0x15}}, + {{0x61, 0x5d, 0xe9, 0x89, 0xf2, 0xc3, 0x02, 0x28, 0x84, 0xea, 0x07, 0x6c, 0xfb, 0x77, 0x3c, 0xf3, 0x3a, 0x14, 0xf4, 0x0d, 0x0f, 0x32, 0xc9, 0xbb, 0x80, 0x4f, 0xc0, 0x9c, 0xdf, 0xa3, 0x6c, 0x35}, {0xaa, 0x1d, 0xd8, 0x9f, 0x2b, 0xfa, 0x45, 0x4f, 0x6e, 0x61, 0x99, 0x71, 0x59, 0x5e, 0x47, 0x7f, 0xb5, 0xdf, 0x4e, 0xce, 0x29, 0xdf, 0x3b, 0x7d, 0x87, 0x1f, 0x27, 0xf9, 0x6b, 0x8d, 0xae, 0x1d}}, + {{0x2f, 0x19, 0x94, 0x7e, 0xde, 0x87, 0x3f, 0x47, 0xb0, 0x44, 0x11, 0x12, 0x88, 0x9d, 0x93, 0xd3, 0xea, 0xc5, 0x10, 0x10, 0x98, 0xe7, 0x3b, 0x96, 0x2e, 0xde, 0x23, 0xdf, 0x97, 0x35, 0xef, 0x17}, {0x76, 0xdb, 0xe3, 0x55, 0xac, 0x8d, 0x95, 0x1e, 0x9c, 0xed, 0x2e, 0xd8, 0x81, 0xc6, 0xd2, 0x12, 0xcf, 0xe0, 0x5e, 0x1d, 0x84, 0x16, 0xd5, 0xd3, 0x47, 0x34, 0xea, 0x9c, 0xdd, 0x26, 0xc9, 0x0a}}, + {{0x08, 0x8b, 0x05, 0x15, 0xc4, 0x89, 0x58, 0x68, 0xaf, 0x97, 0x13, 0xdb, 0xe4, 0xb0, 0xb7, 0x6d, 0x77, 0xa7, 0x5c, 0xf6, 0x48, 0x15, 0x80, 0x5b, 0x4b, 0x08, 0x5e, 0x14, 0x44, 0xe8, 0xc7, 0x0b}, {0x8a, 0x20, 0x79, 0x3f, 0x8c, 0x4d, 0x38, 0xe5, 0x54, 0x33, 0xfd, 0x29, 0xe1, 0x22, 0x1f, 0x15, 0xdb, 0x21, 0xac, 0x27, 0x5c, 0xa9, 0x90, 0x7a, 0x55, 0xa6, 0x02, 0x22, 0x45, 0xe4, 0xed, 0x19}}, + {{0x89, 0x37, 0x32, 0xee, 0xfc, 0x57, 0xd8, 0xde, 0x33, 0x6f, 0x1d, 0x30, 0x0f, 0xaa, 0xfe, 0x0b, 0x6d, 0xbf, 0x9b, 0x5d, 0xd3, 0x96, 0x9c, 0xf3, 0x6f, 0x97, 0xbf, 0xfa, 0x09, 0x83, 0x9d, 0x2a}, {0x61, 0x31, 0xee, 0x53, 0x45, 0x0f, 0x8c, 0x52, 0x93, 0xaa, 0x93, 0xef, 0xcc, 0xd2, 0xca, 0x6d, 0x6c, 0x99, 0xc9, 0x2e, 0x8a, 0xf0, 0x04, 0xe7, 0x3f, 0x2d, 0x0d, 0xcc, 0xda, 0x16, 0xfd, 0x1b}}, + {{0x40, 0x36, 0x0c, 0xe4, 0x71, 0x84, 0x8b, 0x18, 0xd0, 0x76, 0x97, 0x06, 0x59, 0x86, 0x01, 0xa2, 0x71, 0x05, 0x9d, 0x20, 0xe0, 0x57, 0x8d, 0xd0, 0xae, 0x64, 0x54, 0xe1, 0xbb, 0x63, 0x90, 0x1a}, {0x96, 0xc0, 0x97, 0xe5, 0x49, 0x90, 0x8d, 0x56, 0xc5, 0x87, 0xaa, 0x87, 0xd0, 0x78, 0x50, 0xdd, 0xf2, 0x5e, 0x87, 0x71, 0xd9, 0x73, 0x15, 0x3c, 0xf4, 0x23, 0x9e, 0xea, 0x1e, 0x69, 0x8e, 0x38}}, + {{0x60, 0x15, 0x70, 0x93, 0xc1, 0x3f, 0xab, 0x40, 0xf5, 0x40, 0xc8, 0x2e, 0x90, 0xa2, 0xce, 0x29, 0x7b, 0xf9, 0xf7, 0xa9, 0x95, 0x0b, 0x5d, 0xd7, 0x13, 0xc6, 0xd8, 0xab, 0x79, 0x79, 0xf0, 0x0a}, {0xed, 0x9c, 0x53, 0x05, 0xd2, 0xca, 0x15, 0x5c, 0x1b, 0x09, 0x6b, 0x03, 0x43, 0x09, 0x02, 0xc6, 0x5e, 0x7f, 0x91, 0xe5, 0xce, 0x78, 0x2c, 0x4c, 0xf9, 0x4b, 0xa3, 0xf5, 0xff, 0xac, 0x59, 0x19}}, + {{0xb8, 0x0f, 0xc0, 0x7c, 0x6d, 0x87, 0x8d, 0xfa, 0xa1, 0x19, 0x6d, 0x78, 0x97, 0x4a, 0x9c, 0x5a, 0xe9, 0xae, 0x9b, 0x3b, 0x15, 0x81, 0xbe, 0x12, 0x3f, 0xd4, 0x94, 0x85, 0x78, 0x29, 0x0f, 0x1a}, {0xf7, 0x8d, 0xe8, 0xd4, 0xbc, 0x14, 0x97, 0xed, 0xa3, 0x9e, 0xd8, 0x0d, 0xd3, 0xc0, 0x34, 0xe7, 0xf5, 0xe1, 0x6d, 0xc8, 0x59, 0x22, 0x5d, 0xec, 0xaf, 0x8f, 0x88, 0x57, 0xf3, 0x03, 0x22, 0x13}}, + {{0x93, 0x8f, 0x84, 0x04, 0x69, 0x3b, 0xb5, 0x93, 0x22, 0xcf, 0x8c, 0xdf, 0x0d, 0x8c, 0x39, 0x13, 0x42, 0x4f, 0x66, 0xa5, 0x2e, 0x11, 0x6d, 0xf4, 0x40, 0x86, 0xd6, 0xf2, 0xf5, 0xe2, 0x41, 0x00}, {0x60, 0x77, 0x10, 0xbc, 0x79, 0x0c, 0x05, 0xb6, 0xac, 0xad, 0x49, 0x4b, 0xea, 0x15, 0x50, 0xee, 0x68, 0x22, 0xf4, 0x22, 0x82, 0x21, 0xe3, 0x65, 0xad, 0xc0, 0xa9, 0x41, 0x94, 0x69, 0xcc, 0x31}}, + {{0xab, 0x81, 0x62, 0xeb, 0x7c, 0xab, 0xae, 0x94, 0xab, 0x56, 0xf1, 0xd8, 0x94, 0xca, 0x28, 0x52, 0x4e, 0x88, 0xb9, 0x16, 0x93, 0xaf, 0x5a, 0x47, 0x6d, 0xb1, 0x3e, 0x6c, 0x4a, 0x0f, 0x86, 0x19}, {0x40, 0x6d, 0x8c, 0xed, 0x8f, 0xe9, 0xdc, 0xeb, 0x7f, 0x30, 0x4e, 0x45, 0x97, 0x82, 0x40, 0x05, 0x03, 0x67, 0x4a, 0x3f, 0x25, 0x32, 0x24, 0xd0, 0xe3, 0x5b, 0x7d, 0xf5, 0xe4, 0xa0, 0xf1, 0x1a}}, + {{0x34, 0xe6, 0x5b, 0xb8, 0x2e, 0xa9, 0x36, 0xfa, 0x50, 0x88, 0xb7, 0xea, 0x3d, 0xed, 0x4a, 0xb4, 0x4b, 0xc1, 0x70, 0x67, 0xd6, 0x58, 0x32, 0xbe, 0x4f, 0x63, 0x6d, 0x81, 0x41, 0x51, 0xff, 0x35}, {0x2c, 0xbd, 0xaa, 0xce, 0x1b, 0x0c, 0x0c, 0x50, 0x2e, 0xef, 0x8a, 0xf6, 0x9b, 0x66, 0xd6, 0xf0, 0x72, 0x9c, 0x39, 0x94, 0x04, 0xf9, 0x8d, 0xbd, 0xd3, 0x69, 0xad, 0x35, 0x2c, 0xef, 0xb1, 0x2d}}, + {{0x0c, 0xc1, 0xff, 0x58, 0x5d, 0x8b, 0xb4, 0xc0, 0xd2, 0x8c, 0x8e, 0xa2, 0xbe, 0x70, 0xca, 0xe5, 0xbd, 0xfb, 0xab, 0x87, 0xaf, 0x95, 0x39, 0xf4, 0x77, 0xd3, 0x83, 0xd5, 0xf6, 0x82, 0x30, 0x07}, {0x13, 0x0d, 0x05, 0xd5, 0xa0, 0x30, 0x62, 0x10, 0x50, 0xc3, 0x4b, 0xf3, 0x80, 0x3c, 0x6a, 0x4b, 0x19, 0xa3, 0x96, 0x30, 0x27, 0x83, 0xfe, 0xc6, 0xf0, 0x89, 0xc2, 0x0c, 0x7f, 0x63, 0x30, 0x22}}, + {{0x09, 0xb0, 0x8b, 0xc1, 0x91, 0x91, 0xe8, 0x25, 0xad, 0x8a, 0xa1, 0xb2, 0xc5, 0x29, 0xf9, 0x82, 0x06, 0x97, 0x2a, 0x6a, 0x20, 0x15, 0x85, 0x3f, 0x7c, 0x73, 0xd7, 0x1e, 0x61, 0x42, 0xfe, 0x25}, {0xf6, 0x02, 0x3e, 0xd6, 0x52, 0xc5, 0x37, 0x83, 0xb4, 0x5f, 0x10, 0x0b, 0xa9, 0x77, 0xcc, 0x73, 0x8c, 0x7a, 0xad, 0x3b, 0x61, 0xe5, 0xdb, 0x94, 0x40, 0xc4, 0x9f, 0xa3, 0xb7, 0x36, 0xe7, 0x26}}, + {{0x43, 0x87, 0xc0, 0xb1, 0x50, 0xb6, 0x46, 0x09, 0x65, 0x8c, 0xb8, 0x11, 0x20, 0xc0, 0xb9, 0x9d, 0x13, 0xff, 0xf8, 0xcb, 0xca, 0x4d, 0x3c, 0xfa, 0xbc, 0x24, 0x13, 0xeb, 0x44, 0xc8, 0xe5, 0x06}, {0xa1, 0x70, 0xa3, 0xa8, 0xf9, 0x57, 0x8f, 0x3c, 0xaf, 0x1b, 0xfc, 0xe0, 0x38, 0x8b, 0xc5, 0x37, 0x3b, 0x81, 0xc8, 0xaf, 0x15, 0x35, 0x33, 0x6b, 0x3a, 0x57, 0x9f, 0x79, 0xf2, 0xf5, 0x82, 0x1a}}, + {{0x9b, 0x27, 0x0a, 0x42, 0x63, 0x5e, 0xa1, 0xbe, 0x1d, 0x35, 0x12, 0x89, 0x2b, 0x28, 0x07, 0x8e, 0x7d, 0xfd, 0x6a, 0xd8, 0x99, 0xf7, 0x8f, 0x40, 0xe4, 0x22, 0x6e, 0xce, 0x8e, 0x7b, 0x8f, 0x07}, {0xdf, 0xec, 0xf1, 0xce, 0x99, 0xd9, 0xbc, 0x88, 0xec, 0x0b, 0xe7, 0xd4, 0x44, 0x9c, 0x3d, 0x33, 0x8e, 0xb1, 0x1a, 0x69, 0xbd, 0xfe, 0x35, 0x80, 0x48, 0x11, 0xa5, 0x70, 0x98, 0xa0, 0x07, 0x14}}, + {{0x5f, 0xaa, 0x84, 0x25, 0xde, 0x97, 0x4c, 0x45, 0x99, 0xa8, 0x27, 0x7a, 0x06, 0x94, 0xc7, 0xee, 0x02, 0x47, 0xd3, 0x80, 0x27, 0xd4, 0x55, 0x09, 0xff, 0xd6, 0x43, 0xc1, 0x59, 0x97, 0x35, 0x1d}, {0x5c, 0x60, 0xf6, 0x15, 0x30, 0xaf, 0x16, 0xa8, 0x43, 0xa9, 0x9b, 0x68, 0xd6, 0x71, 0x10, 0x07, 0xe1, 0xa8, 0x3c, 0xc7, 0x8a, 0x14, 0x02, 0xdb, 0x77, 0xa7, 0x65, 0xb7, 0xec, 0x3d, 0xdd, 0x05}}, + {{0x2f, 0xfb, 0x6a, 0xd7, 0xeb, 0x38, 0x80, 0xdb, 0x5d, 0x32, 0x88, 0x1c, 0x9f, 0x0a, 0xc9, 0x0d, 0xf5, 0x6c, 0x22, 0x16, 0x1e, 0xc8, 0x8c, 0xcf, 0x72, 0xa1, 0x71, 0xa7, 0x7b, 0x7c, 0x99, 0x2a}, {0x2f, 0xe2, 0x55, 0x21, 0xbd, 0xd9, 0xc2, 0xe8, 0xa9, 0xe9, 0x8f, 0xbd, 0xa0, 0x25, 0x70, 0x8a, 0x41, 0xe8, 0x28, 0x1d, 0x92, 0xc1, 0xe9, 0x5b, 0x3b, 0x9c, 0x8a, 0x5c, 0x63, 0x87, 0xea, 0x12}}, + {{0x3c, 0x93, 0xb8, 0x84, 0x98, 0x22, 0x5c, 0x4e, 0x4c, 0x99, 0xa8, 0xb2, 0xa0, 0x86, 0x77, 0x46, 0x30, 0x5b, 0x23, 0xc3, 0x0b, 0x90, 0x25, 0x13, 0x18, 0xcc, 0xae, 0xa4, 0x23, 0x46, 0x1e, 0x2a}, {0x9b, 0xd4, 0x4b, 0x6e, 0x2b, 0x51, 0x6c, 0x56, 0x5d, 0x0b, 0x2f, 0x1e, 0x1c, 0x0f, 0x4e, 0xa7, 0x1d, 0x6e, 0x83, 0x55, 0x3c, 0x55, 0x43, 0xcb, 0x46, 0xa3, 0x30, 0x69, 0x75, 0xa1, 0xa4, 0x13}}, + {{0x10, 0x22, 0x21, 0x89, 0xf0, 0x48, 0x3c, 0x50, 0xd0, 0x86, 0x5d, 0x78, 0x32, 0x72, 0x91, 0xed, 0xfa, 0x35, 0xfd, 0xb9, 0x95, 0xad, 0xc2, 0xc0, 0xf6, 0x17, 0x38, 0x1e, 0x6a, 0xca, 0x03, 0x0b}, {0xb6, 0xbe, 0x3b, 0xf4, 0x2e, 0x4c, 0x85, 0x4c, 0x12, 0xc7, 0x97, 0x07, 0xe3, 0x8f, 0x25, 0x33, 0x7f, 0xd1, 0xd7, 0x71, 0xb2, 0x65, 0x2b, 0x7b, 0xd7, 0xfe, 0xcb, 0x59, 0xd2, 0x45, 0x08, 0x26}}, + {{0x42, 0x16, 0xca, 0x16, 0x65, 0x96, 0x43, 0x51, 0x4d, 0xad, 0x4f, 0x09, 0xc5, 0x77, 0xa0, 0xfa, 0xeb, 0x14, 0x7d, 0xaa, 0x69, 0xd8, 0xc1, 0xcb, 0x25, 0x10, 0xc2, 0x34, 0x0a, 0x0f, 0xf2, 0x2c}, {0xc6, 0xcd, 0x21, 0x99, 0xa9, 0xee, 0x36, 0xad, 0x41, 0x0a, 0x7f, 0x29, 0x0d, 0x37, 0x1d, 0x2e, 0x41, 0x93, 0x15, 0x09, 0x6f, 0x08, 0x57, 0xc9, 0xaf, 0x1d, 0x1e, 0xe2, 0x10, 0xcf, 0xcc, 0x22}}, + {{0x4c, 0xad, 0x14, 0xc3, 0x14, 0xe6, 0x44, 0xfb, 0x7d, 0x61, 0xd8, 0xdf, 0x0b, 0xdb, 0x24, 0x8b, 0x26, 0x9e, 0x6a, 0x3f, 0x6f, 0x19, 0x7d, 0xd1, 0x64, 0x77, 0xdf, 0x32, 0xd6, 0xff, 0xc8, 0x27}, {0xdc, 0x42, 0x0c, 0x39, 0xb4, 0x43, 0xca, 0xa5, 0x8b, 0x56, 0x1b, 0x6a, 0x1f, 0x79, 0xa2, 0xd7, 0x51, 0xb2, 0x63, 0x9c, 0x22, 0x1f, 0xa7, 0x98, 0x9d, 0x77, 0xa9, 0xe7, 0x03, 0x0d, 0xa3, 0x31}}, + {{0x0d, 0x55, 0x22, 0x87, 0xe9, 0x4c, 0xb4, 0xf4, 0xc8, 0x0a, 0x39, 0x01, 0x22, 0x8b, 0x93, 0xdd, 0xaa, 0xee, 0x27, 0x52, 0x23, 0xf4, 0x86, 0xfe, 0xcb, 0xad, 0xb7, 0xad, 0xfe, 0x8d, 0xd2, 0x31}, {0xdc, 0x7b, 0xbc, 0x74, 0x33, 0x7f, 0xdb, 0x5a, 0x30, 0x86, 0xb8, 0x2b, 0xb1, 0xd1, 0x0f, 0xc1, 0x1c, 0xf4, 0x5b, 0x93, 0xe5, 0x7c, 0x28, 0xae, 0x9f, 0xa3, 0x54, 0x80, 0x73, 0x97, 0x20, 0x2a}}, + {{0x6b, 0x14, 0x67, 0x3d, 0x3e, 0x41, 0xe7, 0x3b, 0xbd, 0x75, 0x17, 0x2e, 0xa9, 0xcd, 0x57, 0xad, 0xe9, 0xae, 0x71, 0xe3, 0xc4, 0xf9, 0x5f, 0x2c, 0x49, 0x4e, 0x33, 0x2f, 0x0e, 0x7a, 0x81, 0x1b}, {0x37, 0x27, 0x6d, 0xcd, 0xfb, 0x8d, 0x5d, 0xa1, 0xcb, 0x8f, 0x43, 0x5f, 0x19, 0xce, 0x49, 0x2a, 0xd1, 0xcf, 0x1a, 0x1b, 0x52, 0x1b, 0x38, 0x4d, 0x3c, 0xa2, 0x28, 0x58, 0x94, 0xce, 0x93, 0x0e}}, + {{0xa2, 0xce, 0x76, 0xd4, 0x5d, 0xce, 0x51, 0x1f, 0xd4, 0x73, 0x84, 0x21, 0xcf, 0x92, 0x2f, 0xdd, 0x6b, 0x0b, 0x66, 0xc7, 0x31, 0x92, 0x6a, 0x66, 0xfb, 0xb3, 0x56, 0x97, 0xae, 0xa9, 0x1a, 0x2b}, {0xa3, 0xcc, 0x15, 0x8c, 0xce, 0x9c, 0xa9, 0x46, 0xaa, 0xd9, 0x60, 0xc4, 0xce, 0xbb, 0x85, 0xbf, 0x21, 0x10, 0xa4, 0x4a, 0xb8, 0xa7, 0x8a, 0x4e, 0x4c, 0xe5, 0x2a, 0x6a, 0x1a, 0xa8, 0x80, 0x17}}, + {{0x8a, 0xc0, 0x68, 0x95, 0x50, 0x6b, 0x7a, 0xe1, 0x82, 0xfd, 0x4e, 0x9e, 0x60, 0xae, 0x9f, 0x25, 0xdc, 0x4b, 0xc4, 0x3e, 0x28, 0xd1, 0x7f, 0xaf, 0xad, 0x91, 0xa6, 0x74, 0xd3, 0xde, 0x09, 0x1c}, {0xd5, 0xa4, 0x51, 0x35, 0xa3, 0xb9, 0xdf, 0x70, 0x82, 0xc5, 0x87, 0x11, 0xcc, 0xee, 0x2e, 0xfe, 0x56, 0x14, 0x21, 0xdb, 0x26, 0xf4, 0x86, 0x85, 0xca, 0x0f, 0x50, 0x93, 0xa8, 0x2b, 0xa6, 0x26}}, + {{0x58, 0x66, 0x24, 0x56, 0x23, 0xcd, 0xc3, 0x5e, 0x7f, 0xb0, 0xfe, 0x14, 0x6b, 0x69, 0xab, 0x0b, 0x25, 0x1b, 0x80, 0x5b, 0x72, 0x9a, 0x0e, 0xf7, 0x80, 0xcd, 0xc6, 0xa1, 0x7b, 0x98, 0xff, 0x22}, {0x41, 0xee, 0x7c, 0x8b, 0xb5, 0x0f, 0x08, 0x78, 0x9b, 0x92, 0x56, 0xb9, 0x3d, 0xd8, 0x4d, 0xce, 0xc4, 0xdd, 0x4d, 0xa7, 0xce, 0x39, 0xc8, 0xea, 0x6d, 0xa8, 0x06, 0x2b, 0xea, 0x33, 0x17, 0x23}}, + {{0x1f, 0xfe, 0x5d, 0x68, 0x46, 0x67, 0xc8, 0xae, 0x68, 0x51, 0x1e, 0xb7, 0x0a, 0x0c, 0x18, 0xc2, 0xfa, 0x70, 0x70, 0x1a, 0x76, 0x69, 0x76, 0x8d, 0xdb, 0x9c, 0xfc, 0x7b, 0xa2, 0xc8, 0x08, 0x00}, {0x77, 0xca, 0x71, 0x98, 0x36, 0x3a, 0x4f, 0xaa, 0x6f, 0x69, 0xad, 0xc1, 0xa1, 0x0e, 0x4c, 0x7b, 0x80, 0xf9, 0xb0, 0xfa, 0x10, 0x52, 0xd8, 0x4e, 0xdb, 0x1b, 0x9c, 0xb4, 0x12, 0xbd, 0x6c, 0x3e}}, + {{0xc8, 0x7b, 0xe1, 0x47, 0xea, 0x0c, 0x6a, 0x8f, 0x26, 0xaf, 0x91, 0x07, 0xeb, 0x1f, 0x64, 0x28, 0x89, 0x2b, 0x2a, 0xc7, 0x79, 0xc1, 0xa3, 0x60, 0xf3, 0xcb, 0xe0, 0x7c, 0x30, 0x44, 0xee, 0x10}, {0x63, 0xa4, 0xc0, 0xf4, 0x97, 0xdb, 0xaa, 0x66, 0x6d, 0x57, 0xd5, 0x78, 0xdb, 0xd7, 0x02, 0xe3, 0x2f, 0x1e, 0xcb, 0x87, 0x94, 0x91, 0x2d, 0x48, 0x81, 0x18, 0xad, 0x36, 0x4a, 0x4a, 0x9a, 0x0e}}, + {{0x70, 0x64, 0x98, 0xf8, 0x29, 0x5c, 0x34, 0x4c, 0x80, 0x60, 0xf7, 0xe1, 0xe0, 0x47, 0xf4, 0xdf, 0x70, 0x19, 0x2c, 0x06, 0xba, 0xc0, 0xdb, 0xf9, 0x77, 0xe2, 0x7c, 0xac, 0x93, 0x61, 0xcd, 0x06}, {0x97, 0x35, 0x7d, 0x34, 0x61, 0xa7, 0x04, 0x61, 0x04, 0xe1, 0xa1, 0x48, 0xa1, 0xfa, 0x80, 0x82, 0x47, 0x37, 0x37, 0x2f, 0x0a, 0x5d, 0x11, 0xa0, 0x3b, 0xb7, 0x9e, 0x82, 0xb8, 0x50, 0x73, 0x0c}}, + {{0xf0, 0x03, 0x18, 0x1d, 0xa0, 0x41, 0x98, 0x7a, 0x30, 0xd0, 0x9d, 0xea, 0x39, 0xa6, 0xcd, 0x9d, 0x14, 0xd4, 0xfc, 0xf2, 0x1f, 0x8c, 0x1c, 0xd9, 0x7f, 0x4d, 0xfc, 0x75, 0x59, 0x7e, 0xb1, 0x22}, {0x21, 0xdd, 0x74, 0x54, 0x61, 0xf4, 0xea, 0xca, 0x0e, 0x15, 0x35, 0x4e, 0xe9, 0x49, 0x3b, 0x97, 0x49, 0xbc, 0xcb, 0x03, 0xe4, 0x3e, 0x20, 0x1a, 0x2c, 0x2c, 0x3d, 0x94, 0xe4, 0x40, 0x12, 0x20}}, + {{0x51, 0x53, 0x56, 0x14, 0xd9, 0x33, 0xf1, 0x75, 0x54, 0x28, 0x87, 0x00, 0x4f, 0x21, 0x96, 0x18, 0x9d, 0xea, 0xfe, 0x26, 0xe7, 0x7c, 0xd4, 0x0c, 0x6e, 0x28, 0x05, 0x70, 0xf8, 0x26, 0x63, 0x26}, {0x5f, 0xf3, 0x71, 0x42, 0x26, 0x38, 0x37, 0x17, 0x1f, 0x7c, 0x0a, 0x6e, 0x40, 0xf9, 0xd8, 0xc7, 0x5c, 0x9d, 0x7f, 0x76, 0x83, 0xd2, 0x24, 0x59, 0x7d, 0x57, 0x27, 0x31, 0x0e, 0x0f, 0xb5, 0x0e}}, + {{0x4c, 0xc1, 0x39, 0xbd, 0x5e, 0x0f, 0xe2, 0x68, 0xcb, 0x77, 0x9f, 0xa9, 0x56, 0x69, 0x7b, 0x47, 0xce, 0x99, 0x70, 0xa1, 0x85, 0x98, 0x3a, 0x31, 0x73, 0xdf, 0xa2, 0x04, 0x1d, 0x5d, 0x86, 0x1a}, {0xbb, 0x65, 0x52, 0xc1, 0xc4, 0x0f, 0x23, 0x06, 0x76, 0xe3, 0x81, 0x27, 0xd4, 0x72, 0xdd, 0x52, 0x35, 0x66, 0x4e, 0x86, 0xf5, 0x49, 0x18, 0xa4, 0x0d, 0x27, 0x03, 0xeb, 0x9d, 0xc2, 0xfa, 0x10}}, + {{0x15, 0xfb, 0x64, 0x4a, 0x95, 0x38, 0x7d, 0xa5, 0xe2, 0xca, 0x21, 0x74, 0x4e, 0xc6, 0x09, 0xca, 0x7f, 0xfe, 0x60, 0xec, 0x2b, 0x5c, 0x17, 0xf0, 0x7e, 0xac, 0x5a, 0xb0, 0xa1, 0x07, 0x95, 0x01}, {0xac, 0x77, 0xab, 0x63, 0x27, 0xdd, 0x75, 0x60, 0x07, 0x8a, 0xb7, 0x7b, 0x90, 0x60, 0xa0, 0x1a, 0x5f, 0x63, 0x68, 0x8c, 0xdb, 0xbd, 0x6a, 0xef, 0x82, 0xf8, 0x7a, 0x1b, 0xe0, 0xb5, 0x09, 0x1b}}, + {{0xc3, 0x37, 0xe0, 0x1a, 0xec, 0x72, 0x49, 0x78, 0xbd, 0xd8, 0x26, 0x47, 0xbe, 0x69, 0x42, 0x5a, 0xc7, 0x6d, 0x65, 0xe1, 0xa2, 0x19, 0xa7, 0x56, 0x83, 0xd3, 0xda, 0x50, 0x78, 0x9c, 0x18, 0x14}, {0x95, 0xeb, 0x53, 0xca, 0x2b, 0xcd, 0x5b, 0x81, 0xf6, 0xdb, 0x51, 0x77, 0xb4, 0x78, 0x6c, 0x55, 0xc1, 0x08, 0x20, 0x1a, 0x13, 0xfd, 0x53, 0xf0, 0xd2, 0x68, 0xab, 0xfe, 0x8c, 0xc7, 0x81, 0x28}}, + {{0x9e, 0x7a, 0xe0, 0x4a, 0x13, 0x19, 0x06, 0xf3, 0x10, 0x4a, 0x6b, 0xbd, 0x26, 0x6f, 0x06, 0xd3, 0xfc, 0x51, 0x9a, 0xc2, 0xea, 0xd8, 0x30, 0xd2, 0xf0, 0xc0, 0xea, 0xd1, 0xf8, 0xd0, 0x6c, 0x0e}, {0xb8, 0x9b, 0xec, 0xac, 0xbe, 0x27, 0xa4, 0x9f, 0x7f, 0x69, 0xaa, 0x80, 0x50, 0xc2, 0x2b, 0x2a, 0x95, 0xbd, 0x4d, 0xdb, 0x2f, 0x9c, 0xf7, 0xdb, 0xf5, 0x43, 0x22, 0x86, 0x6a, 0xbb, 0x28, 0x00}}, + {{0x99, 0x18, 0x96, 0xcc, 0x49, 0x84, 0x13, 0xf0, 0x6a, 0x87, 0xbf, 0x9e, 0x9d, 0xac, 0x9d, 0x37, 0x3d, 0xe9, 0xcd, 0x31, 0xd0, 0x99, 0x7f, 0xeb, 0xfd, 0x08, 0xbe, 0x19, 0x85, 0x5b, 0x0b, 0x13}, {0xeb, 0xba, 0x2c, 0x42, 0x43, 0x7e, 0xed, 0xa4, 0xf1, 0x99, 0xd0, 0xcf, 0x65, 0xa5, 0xbd, 0x15, 0x08, 0x82, 0x12, 0xef, 0xae, 0x3f, 0xe7, 0x75, 0xbc, 0x1f, 0xf1, 0x3c, 0x27, 0xb0, 0x96, 0x11}}, + {{0xe5, 0xba, 0x30, 0x55, 0x9e, 0xf9, 0x11, 0xc3, 0xc0, 0x67, 0x98, 0x2f, 0x91, 0x21, 0x96, 0x5e, 0x1f, 0x79, 0x32, 0x08, 0x79, 0x61, 0xc4, 0x0e, 0xbc, 0xca, 0x1f, 0x79, 0x62, 0x8c, 0xb8, 0x3a}, {0xf3, 0x46, 0xa3, 0xd1, 0xb2, 0xdb, 0x0c, 0xe3, 0x73, 0xd5, 0x57, 0x21, 0x1b, 0x88, 0x0d, 0x30, 0x32, 0xb0, 0x62, 0xaf, 0x2b, 0x29, 0x62, 0xe3, 0xa1, 0xa3, 0xf4, 0x26, 0xea, 0x23, 0xc4, 0x02}}, + {{0x15, 0x5b, 0x4a, 0xf1, 0x82, 0xfb, 0x44, 0x72, 0xa0, 0xc5, 0x80, 0xc8, 0xf8, 0xdb, 0x16, 0x17, 0x30, 0xd1, 0x04, 0xfa, 0x0d, 0xbb, 0x4b, 0x13, 0x1f, 0x97, 0x16, 0xac, 0x43, 0x09, 0x80, 0x2c}, {0x31, 0x5c, 0x9a, 0x08, 0xca, 0xd2, 0x8a, 0x97, 0x49, 0x3f, 0x63, 0x01, 0xbd, 0x1b, 0xe6, 0xe1, 0xd0, 0xcb, 0x42, 0xb6, 0xf3, 0xaa, 0x30, 0x33, 0x2c, 0x3d, 0x6b, 0xba, 0xd2, 0xc6, 0xa1, 0x09}}, + {{0xbe, 0xd5, 0x33, 0xbc, 0xf3, 0x4f, 0xa5, 0x28, 0x5c, 0x39, 0x48, 0xcf, 0x2e, 0xb1, 0xf6, 0x3b, 0x43, 0x90, 0x7c, 0x55, 0x1b, 0xc7, 0x2d, 0x22, 0x5b, 0xa8, 0x74, 0x1f, 0x65, 0x8b, 0x40, 0x24}, {0xc0, 0x52, 0xaf, 0x04, 0x95, 0x08, 0x66, 0x90, 0xd1, 0x15, 0xc0, 0x66, 0xf7, 0xe8, 0xe4, 0x35, 0x84, 0x24, 0x9f, 0x65, 0x29, 0x92, 0x86, 0xa3, 0xc7, 0x6b, 0xdf, 0x11, 0x98, 0x31, 0x7d, 0x20}}, + {{0x54, 0xc0, 0x7c, 0xd9, 0x2b, 0x72, 0xd9, 0x15, 0xf9, 0x45, 0x39, 0x62, 0x40, 0x04, 0xa4, 0xc0, 0x9c, 0x98, 0xfd, 0x73, 0xe5, 0x37, 0x6b, 0xb4, 0x66, 0x91, 0x3a, 0xac, 0xe7, 0x6c, 0x58, 0x2b}, {0xef, 0xdb, 0x31, 0x3f, 0x9d, 0x2d, 0xd6, 0xb9, 0xa5, 0xa7, 0xe6, 0xb7, 0x16, 0xcd, 0x75, 0x72, 0x4d, 0x7a, 0xd5, 0x6d, 0x44, 0xc0, 0x85, 0x8d, 0x05, 0x05, 0x53, 0xda, 0xfc, 0xa9, 0x86, 0x0d}}, + {{0x27, 0xe7, 0x16, 0x20, 0xbc, 0xc1, 0xc3, 0x6c, 0x4b, 0x16, 0x0a, 0x18, 0xd8, 0x0d, 0x7b, 0x61, 0x1e, 0x97, 0x61, 0x9f, 0xde, 0x39, 0xd6, 0x4f, 0xf0, 0x27, 0xba, 0x19, 0xd8, 0x6f, 0x4a, 0x3d}, {0xd4, 0x8b, 0x57, 0xaa, 0x0e, 0xe8, 0x13, 0x34, 0x9f, 0x76, 0xbb, 0x63, 0x5e, 0x48, 0x16, 0x7b, 0xa2, 0x4a, 0x4c, 0x8c, 0x21, 0x59, 0xbb, 0x62, 0x6f, 0x58, 0xaf, 0xf8, 0x57, 0x98, 0x98, 0x10}}, + {{0x3d, 0xe5, 0x3a, 0x2e, 0xd2, 0xb7, 0x33, 0x4d, 0xa1, 0x5a, 0x24, 0xb7, 0x7e, 0xaf, 0x88, 0xe8, 0x96, 0xb8, 0x76, 0x0b, 0xf3, 0xf0, 0xe6, 0x78, 0x61, 0x8e, 0x50, 0xf8, 0xca, 0xf0, 0xf9, 0x15}, {0x6a, 0xcb, 0x33, 0xe2, 0x0d, 0x4f, 0xce, 0xbe, 0x89, 0x9b, 0xc3, 0xd0, 0xdf, 0xa9, 0x3f, 0xeb, 0xc6, 0xca, 0xcb, 0x43, 0x58, 0xff, 0x51, 0xb3, 0x30, 0x3f, 0x20, 0xe9, 0x1b, 0xa6, 0x2a, 0x37}}, + {{0x26, 0xf2, 0xd5, 0xa5, 0x0c, 0x4a, 0xf7, 0x74, 0xb6, 0x7c, 0x03, 0xe7, 0x52, 0xb8, 0x51, 0x37, 0x91, 0x18, 0x9a, 0x75, 0xfa, 0xc8, 0xd1, 0x9a, 0x42, 0x84, 0x34, 0x24, 0xb7, 0xb6, 0xfd, 0x10}, {0x75, 0xe4, 0x16, 0x67, 0x2c, 0xaa, 0xd7, 0xfc, 0x92, 0xc3, 0xde, 0xce, 0x46, 0x22, 0x9c, 0x4f, 0xe3, 0x97, 0xb9, 0x01, 0x36, 0xa4, 0xaa, 0x06, 0x10, 0xc0, 0x7e, 0xd5, 0x4b, 0x80, 0x26, 0x0a}}, + {{0x36, 0x48, 0x64, 0xf1, 0x81, 0xf7, 0x9f, 0x53, 0xc6, 0xa0, 0x99, 0x3d, 0x87, 0xdc, 0xdc, 0xd1, 0x89, 0x0b, 0xf1, 0x8e, 0x96, 0x73, 0xe4, 0x2d, 0x4c, 0x33, 0xba, 0x82, 0xa9, 0x67, 0xf1, 0x0f}, {0x47, 0x8e, 0x88, 0x51, 0x91, 0xab, 0x0d, 0xb5, 0xcb, 0x88, 0xdf, 0x97, 0xfa, 0x55, 0xe0, 0xc1, 0x5d, 0x75, 0xdd, 0xe0, 0xa1, 0xe3, 0x47, 0x35, 0x0a, 0xed, 0xfb, 0x9a, 0x5e, 0x73, 0x28, 0x2d}}, + {{0x96, 0xd6, 0x89, 0xc0, 0x09, 0x8a, 0x78, 0xa2, 0x1e, 0x71, 0x00, 0x06, 0xd9, 0xcb, 0x29, 0xf5, 0x3e, 0x52, 0xf8, 0x1e, 0x7a, 0xbb, 0x66, 0xcb, 0xac, 0x2b, 0xeb, 0x34, 0xaa, 0x17, 0xb9, 0x29}, {0x96, 0xbf, 0xa4, 0x85, 0x39, 0xa6, 0x7f, 0xed, 0x64, 0x86, 0xa4, 0xce, 0xa4, 0xb5, 0x46, 0xbc, 0xde, 0x3f, 0x52, 0x16, 0x91, 0x86, 0x0b, 0x2c, 0x17, 0x74, 0xdc, 0x7d, 0xc2, 0x43, 0x30, 0x3d}}, + {{0xfc, 0xc6, 0x45, 0x65, 0x12, 0xe7, 0x6e, 0x3c, 0xb5, 0x72, 0x64, 0x9a, 0xa3, 0x60, 0x1e, 0x36, 0x72, 0x37, 0x5a, 0x6f, 0xc5, 0x2b, 0xfa, 0xa4, 0x4a, 0x84, 0x5d, 0xab, 0x68, 0x09, 0x6b, 0x20}, {0x08, 0xad, 0x43, 0xba, 0x87, 0x6e, 0xc3, 0x7c, 0xdc, 0xb1, 0xa6, 0xec, 0xeb, 0x23, 0x15, 0xf9, 0x5a, 0x94, 0x1f, 0x38, 0xda, 0xd1, 0xa9, 0x2f, 0x43, 0xaa, 0x6c, 0x8a, 0xc6, 0x57, 0xff, 0x25}}, + {{0xe0, 0x2b, 0xc2, 0xc1, 0xa3, 0x42, 0x26, 0x77, 0xae, 0xda, 0xb7, 0x7a, 0x08, 0x84, 0x61, 0x50, 0xe4, 0xc3, 0xe3, 0x89, 0x82, 0xd9, 0xee, 0x67, 0x79, 0x73, 0xe1, 0x12, 0x32, 0x78, 0x40, 0x1c}, {0x01, 0xce, 0xb9, 0xfc, 0xcb, 0xbe, 0x43, 0xaa, 0x52, 0x4a, 0xb9, 0xea, 0xfd, 0x4a, 0x38, 0xe5, 0xff, 0x33, 0x24, 0x8d, 0x32, 0x4b, 0x9c, 0x3e, 0xa2, 0x24, 0xe5, 0xa2, 0xff, 0x5a, 0x57, 0x00}}, + {{0x4f, 0x85, 0xe1, 0x54, 0x17, 0xce, 0x0e, 0xea, 0xc4, 0x86, 0xc0, 0x9f, 0x94, 0x60, 0x59, 0x44, 0x66, 0xe7, 0x3d, 0xc2, 0x59, 0x67, 0x5e, 0x83, 0x4d, 0x48, 0xec, 0xee, 0x41, 0xab, 0xe3, 0x0b}, {0xe1, 0x6b, 0x01, 0x62, 0x09, 0xa6, 0xf9, 0x48, 0x49, 0xd5, 0xb7, 0xef, 0x63, 0x38, 0x09, 0x19, 0xce, 0x39, 0xcf, 0xac, 0xf2, 0x8f, 0x59, 0x2b, 0xe9, 0xb1, 0xa1, 0xe5, 0x7e, 0x84, 0x9d, 0x38}}, + {{0x37, 0x65, 0x6b, 0x69, 0x37, 0xc0, 0x6a, 0x93, 0xa8, 0x28, 0x13, 0xa3, 0xb4, 0xe5, 0x60, 0x35, 0x90, 0x28, 0xcb, 0xcf, 0xa4, 0xfe, 0x47, 0x1f, 0x28, 0x3c, 0x57, 0x49, 0x4d, 0xbc, 0x6b, 0x0c}, {0x46, 0x87, 0xa6, 0xfb, 0x2f, 0x7e, 0xc6, 0x2a, 0x38, 0xe5, 0xb1, 0x95, 0xee, 0xd8, 0xe1, 0x80, 0x19, 0xa3, 0x93, 0x47, 0xf0, 0x37, 0xf9, 0x0f, 0x18, 0x27, 0x71, 0xa6, 0x8b, 0xa3, 0x94, 0x10}}, + {{0xe3, 0xfa, 0xb8, 0xb2, 0x2c, 0xdf, 0xc7, 0x8e, 0x89, 0xef, 0x2c, 0x65, 0xe1, 0xcb, 0x40, 0xeb, 0x85, 0x18, 0xdf, 0xaa, 0x53, 0xa3, 0x2d, 0xa0, 0x85, 0xe4, 0xcb, 0x84, 0x5e, 0x88, 0x64, 0x2c}, {0x77, 0xe2, 0x26, 0xd9, 0xa7, 0x06, 0xf9, 0xcc, 0x3e, 0x5c, 0xf5, 0x57, 0x08, 0x8f, 0x7e, 0x5d, 0xf2, 0xd5, 0x72, 0x17, 0x47, 0x1b, 0x71, 0xdf, 0x33, 0xb3, 0x85, 0xf1, 0x0c, 0x26, 0xa8, 0x0c}}, + {{0x07, 0x23, 0x99, 0xd9, 0x1d, 0x50, 0xba, 0xef, 0xda, 0x86, 0x0a, 0xbc, 0xbf, 0xe2, 0xce, 0xcb, 0x58, 0x0e, 0xca, 0x8c, 0x66, 0xc3, 0xa9, 0x7b, 0x28, 0xfc, 0x33, 0x67, 0xda, 0x7b, 0xe0, 0x10}, {0xc3, 0xeb, 0x7d, 0xdf, 0x6f, 0xe6, 0x72, 0x0a, 0xb9, 0x75, 0xa2, 0x2a, 0xd6, 0x67, 0x6a, 0xf1, 0x6f, 0x2a, 0x84, 0xaa, 0x00, 0x5e, 0xd2, 0x03, 0x70, 0xce, 0xdb, 0xdf, 0xbc, 0x55, 0xc7, 0x26}}, + {{0xff, 0x2d, 0xef, 0x9a, 0x64, 0x76, 0x53, 0x18, 0x17, 0x97, 0xa4, 0x10, 0x4f, 0x4c, 0x94, 0x7f, 0x99, 0xac, 0xf5, 0xb9, 0xff, 0x80, 0x35, 0xe2, 0x52, 0x4a, 0x7f, 0x5f, 0xb6, 0x7f, 0x38, 0x1d}, {0x9e, 0xc1, 0x1f, 0xb4, 0x06, 0x69, 0x9f, 0xb5, 0x6b, 0xd2, 0x4b, 0xba, 0x26, 0xf2, 0xe3, 0x6a, 0x0c, 0xcb, 0xe3, 0xd3, 0xca, 0x2a, 0x71, 0x51, 0x25, 0x0e, 0x50, 0x92, 0xab, 0xb3, 0x19, 0x30}}, + {{0xec, 0x97, 0x13, 0x8d, 0x8c, 0xdb, 0x05, 0x74, 0xb2, 0xb4, 0xb8, 0x44, 0x63, 0x5c, 0x1f, 0x3a, 0xcb, 0xea, 0x99, 0xdf, 0x5b, 0x17, 0x16, 0x3b, 0x66, 0x49, 0x61, 0x5a, 0x36, 0x39, 0x5c, 0x0e}, {0xee, 0x26, 0x3b, 0x2a, 0x4f, 0x82, 0x2a, 0x3c, 0xc9, 0x4d, 0x77, 0x2e, 0x14, 0xc8, 0xb5, 0x0c, 0xf6, 0x90, 0x5f, 0xe4, 0xf6, 0x7d, 0x48, 0xe6, 0x79, 0xe4, 0x0a, 0xe2, 0xc5, 0x71, 0x37, 0x3a}}, + {{0xa9, 0x08, 0x29, 0x96, 0xa8, 0x40, 0x51, 0x0f, 0xc5, 0xc6, 0x37, 0x46, 0x99, 0xd0, 0x28, 0xab, 0x7d, 0x59, 0xbb, 0xdf, 0x2d, 0x0c, 0x40, 0x8d, 0x23, 0x98, 0xf2, 0xb4, 0x63, 0xfe, 0x9a, 0x35}, {0xcc, 0x75, 0x42, 0xdb, 0x14, 0xf0, 0xc4, 0x1f, 0x3c, 0x50, 0x04, 0x54, 0xd6, 0x5f, 0x6d, 0x13, 0x3a, 0x52, 0x86, 0xce, 0x43, 0x9c, 0x44, 0x08, 0x8f, 0x09, 0x4e, 0x03, 0x6e, 0x00, 0x77, 0x06}}, + {{0x93, 0x0a, 0xfc, 0xec, 0xb7, 0x4b, 0xb5, 0x7c, 0xaf, 0xa1, 0xba, 0x53, 0x54, 0x3b, 0xfc, 0x64, 0xd5, 0x86, 0x6a, 0x2e, 0x19, 0xe6, 0x53, 0xc4, 0x17, 0x99, 0x98, 0xac, 0x5c, 0x03, 0x38, 0x28}, {0x40, 0x86, 0xf8, 0xdf, 0x39, 0x58, 0x6e, 0x0f, 0xdf, 0x73, 0xbc, 0x7e, 0x82, 0x41, 0x90, 0x12, 0x8a, 0x7e, 0x1f, 0x4a, 0x6f, 0x3b, 0x35, 0x47, 0x4c, 0x7f, 0x93, 0xca, 0xad, 0xa1, 0xaa, 0x31}}, + {{0x4d, 0x53, 0x2b, 0x6d, 0xc3, 0x37, 0x43, 0x9f, 0xc3, 0x0b, 0xe7, 0xed, 0x39, 0xbb, 0xc4, 0x3b, 0x55, 0x8a, 0x4b, 0x10, 0xae, 0x79, 0x38, 0x2f, 0xc8, 0x4f, 0x7a, 0xd9, 0x71, 0xc1, 0xb0, 0x13}, {0x21, 0x54, 0x0c, 0x37, 0xfa, 0xd1, 0x46, 0x0d, 0x53, 0xb7, 0xbe, 0x65, 0x28, 0x7f, 0x97, 0x83, 0xd8, 0xdf, 0x9e, 0xe4, 0x7d, 0x7e, 0xf4, 0x63, 0x9f, 0xa1, 0xf3, 0x17, 0xbf, 0x46, 0x8c, 0x11}}, + {{0xbf, 0x48, 0x69, 0x89, 0xce, 0xa0, 0xeb, 0xb4, 0xf3, 0x0c, 0x6d, 0x65, 0xd9, 0x98, 0x2a, 0xad, 0x8a, 0x66, 0x5c, 0x4d, 0x1d, 0x74, 0x51, 0xc6, 0x6f, 0x4d, 0x42, 0xe9, 0x84, 0xbf, 0x9e, 0x03}, {0xa2, 0x81, 0x6c, 0x47, 0x78, 0xc8, 0x95, 0xe0, 0x0e, 0x68, 0x9d, 0x67, 0x68, 0xbc, 0xc7, 0xed, 0xf1, 0x2a, 0xed, 0x4e, 0x2b, 0x85, 0x63, 0xf7, 0x1b, 0x6e, 0x8e, 0xe9, 0xb1, 0x98, 0xe9, 0x15}}, + {{0x21, 0x8d, 0x28, 0x2b, 0x18, 0x9a, 0x66, 0x85, 0x13, 0xda, 0x1f, 0x0a, 0x7f, 0x35, 0x44, 0x93, 0xed, 0xb8, 0x79, 0xa1, 0x44, 0xd7, 0x72, 0x37, 0x5a, 0xb5, 0xc0, 0x4e, 0x34, 0x85, 0x03, 0x1b}, {0x21, 0x04, 0xb6, 0x39, 0xac, 0x8d, 0x61, 0x46, 0xb6, 0x01, 0x3c, 0xb1, 0x88, 0x5d, 0xf5, 0x4e, 0x34, 0x97, 0xc6, 0x50, 0x47, 0x7c, 0x15, 0x53, 0x95, 0x03, 0x74, 0x21, 0x07, 0x6e, 0x3a, 0x2a}}, + {{0x91, 0x3b, 0x99, 0x43, 0x75, 0xb7, 0x17, 0x1e, 0x3d, 0x6f, 0x03, 0xc4, 0xac, 0xec, 0x37, 0x28, 0xb4, 0x8f, 0x4d, 0x66, 0x0a, 0x0a, 0xb4, 0x56, 0x54, 0xd5, 0xe4, 0xe7, 0x71, 0x0f, 0x04, 0x2f}, {0x69, 0xc2, 0x8f, 0xb9, 0xde, 0x51, 0xf0, 0xcb, 0x96, 0x94, 0x88, 0x75, 0x04, 0xa7, 0x6a, 0x5c, 0xfe, 0xbc, 0x9f, 0x29, 0xf8, 0xc5, 0xfa, 0x42, 0x5b, 0x64, 0x49, 0x78, 0xcd, 0xec, 0x47, 0x12}}, + {{0x40, 0x71, 0x5f, 0x4d, 0xad, 0x3a, 0x3e, 0x16, 0xa5, 0x67, 0x10, 0x74, 0x58, 0x81, 0x92, 0xb6, 0xa2, 0x8b, 0x9f, 0x50, 0x68, 0x68, 0xb5, 0x26, 0xff, 0xa4, 0x3f, 0x6a, 0x3d, 0x5c, 0xb1, 0x05}, {0xc7, 0x1d, 0xd0, 0xa8, 0xa8, 0x64, 0xab, 0x7c, 0x07, 0x36, 0x68, 0x2d, 0x69, 0xf2, 0x3b, 0x5b, 0x34, 0x39, 0x87, 0x67, 0x48, 0x84, 0x15, 0x2a, 0xa1, 0x39, 0x04, 0x1c, 0x62, 0x0f, 0x9a, 0x25}}, + {{0xf5, 0x6d, 0xfb, 0xbd, 0xcf, 0xea, 0xda, 0x5b, 0x3d, 0xa4, 0xb9, 0x32, 0xd7, 0x56, 0x6e, 0xff, 0xc9, 0xaf, 0xf9, 0xef, 0x7b, 0x5d, 0x57, 0x45, 0x60, 0xbb, 0x70, 0xb3, 0x25, 0x3e, 0x5f, 0x11}, {0xaa, 0x8d, 0xc8, 0xda, 0xbd, 0xdf, 0x75, 0xfa, 0xb3, 0xfd, 0x39, 0x6e, 0xf7, 0x93, 0x30, 0x2f, 0xff, 0x95, 0xc5, 0x7d, 0x27, 0xe2, 0xc1, 0xc8, 0x9d, 0x67, 0x8c, 0x14, 0xc5, 0x7e, 0xa1, 0x3e}}, + {{0xd1, 0x6a, 0x93, 0x99, 0x8c, 0x5f, 0x47, 0x24, 0xc0, 0x87, 0x78, 0x1f, 0x62, 0x63, 0xee, 0x51, 0x28, 0xf6, 0x29, 0xab, 0xd0, 0xd1, 0x5e, 0x47, 0xb7, 0xa0, 0x30, 0x24, 0xaa, 0xff, 0x03, 0x03}, {0x9d, 0x18, 0xa5, 0xd5, 0x52, 0xa9, 0xd2, 0x1d, 0x71, 0x42, 0x41, 0x50, 0xbf, 0xa0, 0xcc, 0x22, 0x27, 0xc6, 0x2c, 0x62, 0x58, 0x34, 0xb2, 0x49, 0x89, 0x7f, 0xf8, 0x40, 0x36, 0xc2, 0x30, 0x01}}, + {{0x28, 0x1c, 0xd7, 0xca, 0x5a, 0x9c, 0xf1, 0xaa, 0x58, 0x78, 0x7a, 0x8b, 0x18, 0x29, 0xb1, 0x8b, 0x6a, 0xd6, 0xdc, 0x92, 0x2d, 0xce, 0xe7, 0x23, 0x23, 0x2f, 0x3a, 0x8e, 0x51, 0x37, 0x42, 0x19}, {0xd9, 0xd4, 0x3e, 0x4b, 0x66, 0xeb, 0x2c, 0xa3, 0x73, 0x67, 0xb0, 0xf2, 0x3e, 0x68, 0x2b, 0xeb, 0x07, 0x3a, 0x6e, 0x39, 0x19, 0x55, 0xf3, 0xa6, 0x4c, 0xc3, 0x1e, 0xb6, 0x4d, 0xb9, 0x2b, 0x1d}}, + {{0xd9, 0x0e, 0x0b, 0xed, 0x83, 0xde, 0x21, 0x4d, 0x3b, 0x5e, 0xf2, 0xa5, 0xab, 0xda, 0xdf, 0xbd, 0xd5, 0x59, 0x5e, 0x49, 0x86, 0xa4, 0xbc, 0x0b, 0xad, 0xe3, 0xa6, 0x9d, 0x68, 0x47, 0x85, 0x16}, {0x25, 0x6e, 0x59, 0xe0, 0xfb, 0x6a, 0x04, 0x87, 0x88, 0x59, 0x4a, 0x6f, 0x21, 0xef, 0x4f, 0xbf, 0x97, 0x70, 0x21, 0x5d, 0xd0, 0xe9, 0x6a, 0x33, 0xe5, 0x02, 0x8e, 0x75, 0xb0, 0x13, 0x21, 0x0a}}, + {{0xc2, 0x4e, 0xf6, 0x90, 0x19, 0x4f, 0x2a, 0x1b, 0x69, 0x05, 0x02, 0x5d, 0x9f, 0x84, 0xab, 0x56, 0xed, 0xa9, 0xbf, 0xf7, 0xaa, 0x07, 0x14, 0x28, 0x41, 0x8b, 0x06, 0x21, 0x1a, 0xc9, 0x01, 0x06}, {0x3d, 0xbc, 0x8e, 0x80, 0xdd, 0xa0, 0x15, 0xcb, 0x56, 0xd5, 0x64, 0xc0, 0x85, 0xf3, 0xde, 0x07, 0xd8, 0x64, 0x93, 0x1e, 0x28, 0x5a, 0x6e, 0x2d, 0x54, 0xa1, 0x9e, 0xcb, 0x0a, 0xdc, 0x39, 0x10}}, + {{0x82, 0xec, 0x8f, 0x2f, 0x05, 0xe9, 0x0a, 0xed, 0xb2, 0x54, 0x30, 0xe5, 0x2c, 0xbd, 0x13, 0xc1, 0x9b, 0x77, 0x03, 0xf3, 0xfc, 0xa4, 0x7a, 0x0c, 0x08, 0xa7, 0x8c, 0xcd, 0x29, 0x28, 0x74, 0x08}, {0xf0, 0xc3, 0x99, 0x78, 0x87, 0x2f, 0x82, 0x68, 0xb3, 0x67, 0x9e, 0x5b, 0xab, 0xa6, 0x96, 0x18, 0x30, 0x63, 0x6c, 0x35, 0x99, 0x52, 0x49, 0xcd, 0x13, 0xb6, 0xdc, 0x3a, 0x29, 0xee, 0xa6, 0x28}}, + {{0xb1, 0x5c, 0x83, 0x35, 0x5b, 0x4d, 0x5e, 0x4b, 0xe4, 0x48, 0xa9, 0xaa, 0x85, 0x2a, 0x02, 0x7c, 0x20, 0xd3, 0x4b, 0x8d, 0x9b, 0x4a, 0x1f, 0x8e, 0xc6, 0x3f, 0xa9, 0xa7, 0xdb, 0x94, 0x17, 0x3a}, {0xd3, 0x59, 0xfe, 0xe0, 0xe9, 0x72, 0x55, 0xdd, 0xcb, 0x5a, 0x4a, 0x52, 0xc9, 0xd3, 0x10, 0x7b, 0x7c, 0x64, 0x63, 0x7b, 0x82, 0x2d, 0xfd, 0xfd, 0xac, 0x01, 0xe5, 0xef, 0xb5, 0x11, 0x9a, 0x0f}}, + {{0xda, 0xdf, 0x8a, 0xf8, 0x66, 0xdb, 0x46, 0x8a, 0x61, 0x91, 0x14, 0xd9, 0x30, 0xf1, 0x1a, 0x23, 0x4d, 0x04, 0x37, 0xa0, 0xb8, 0xb0, 0xfc, 0x9a, 0x76, 0x06, 0xd6, 0x43, 0x78, 0xba, 0x80, 0x2f}, {0xac, 0xf9, 0xb0, 0xb3, 0x86, 0x44, 0x8b, 0x7b, 0x2a, 0x23, 0xff, 0x03, 0x52, 0x01, 0xb8, 0xe9, 0x27, 0x2e, 0x6b, 0xbf, 0x3f, 0xb6, 0x52, 0x31, 0xcd, 0x25, 0x9a, 0x3b, 0xdd, 0x0a, 0x41, 0x2c}}, + {{0xe5, 0x95, 0x76, 0xbe, 0xf0, 0xdb, 0x6c, 0x34, 0x6a, 0xd7, 0x16, 0xed, 0x6a, 0xf6, 0xe3, 0x67, 0xa3, 0x60, 0x63, 0x87, 0xa2, 0xf1, 0x61, 0x04, 0xd5, 0xa1, 0x91, 0x9f, 0xce, 0x29, 0x18, 0x0a}, {0x92, 0x83, 0xc8, 0x6f, 0x2b, 0x9a, 0x7b, 0xf1, 0x52, 0xfd, 0x5d, 0xbc, 0xa2, 0xa7, 0x4e, 0x2c, 0xac, 0xa2, 0x65, 0x53, 0x2f, 0x09, 0x12, 0xf5, 0x96, 0x56, 0xce, 0xef, 0x6d, 0x2e, 0x5f, 0x2c}}, + {{0xd0, 0x9b, 0x0d, 0x46, 0xf8, 0xe1, 0xc1, 0xa5, 0x42, 0x22, 0xb6, 0xfb, 0xe1, 0xce, 0x39, 0xb1, 0x38, 0x25, 0x85, 0x27, 0xa0, 0x14, 0xe6, 0xf5, 0x91, 0xdf, 0x71, 0x09, 0x23, 0xce, 0x3b, 0x13}, {0x52, 0xda, 0xf7, 0x00, 0x97, 0xcd, 0x9c, 0x18, 0xce, 0x65, 0x47, 0xcb, 0xf0, 0x79, 0xbf, 0x0e, 0x11, 0x1d, 0x7d, 0x1e, 0xef, 0x44, 0x9c, 0x74, 0x04, 0xc2, 0xe7, 0xbb, 0x99, 0xad, 0x2f, 0x31}}, + {{0xe2, 0x6b, 0x7a, 0x91, 0xbc, 0x8b, 0x52, 0xe7, 0x52, 0xcf, 0x04, 0x25, 0x1e, 0xab, 0xc2, 0x0b, 0x31, 0x40, 0xca, 0x09, 0x26, 0x17, 0x48, 0x3a, 0x9a, 0x52, 0x7c, 0x0a, 0xe1, 0x37, 0xe5, 0x2c}, {0x79, 0x2d, 0xc4, 0xf4, 0xef, 0x9a, 0xf7, 0x64, 0x64, 0xed, 0x92, 0x85, 0x65, 0xdb, 0xd8, 0x9f, 0xaf, 0x9f, 0x86, 0x88, 0xda, 0x04, 0x42, 0xf8, 0x0c, 0x86, 0x1b, 0x3a, 0x5c, 0x98, 0x7a, 0x37}}, + {{0xfa, 0x05, 0xd2, 0x25, 0xc6, 0xbf, 0x3e, 0x5d, 0x3f, 0xff, 0xe6, 0x20, 0xb3, 0xda, 0xfa, 0x10, 0xca, 0x30, 0x9a, 0xe2, 0x63, 0xf6, 0x84, 0x17, 0x73, 0x96, 0xc5, 0x3a, 0xbb, 0x96, 0x69, 0x2a}, {0x88, 0x04, 0xd6, 0xe6, 0xc2, 0xa9, 0xb6, 0x3f, 0xbf, 0x79, 0x01, 0xa4, 0x21, 0x92, 0xb5, 0x90, 0xcb, 0xfa, 0x28, 0x75, 0x4b, 0xa9, 0x88, 0xdc, 0x89, 0x9a, 0xbd, 0x7f, 0xd6, 0xee, 0x29, 0x2c}}, + {{0x4c, 0xaf, 0xa6, 0x74, 0x82, 0x2c, 0xa6, 0xfe, 0xfe, 0x73, 0x8c, 0x22, 0xcf, 0x7b, 0x8c, 0x38, 0xd7, 0xdd, 0x55, 0xe9, 0x19, 0xea, 0xc7, 0xc0, 0xca, 0xc1, 0x2b, 0x7b, 0x02, 0x46, 0x46, 0x1e}, {0x01, 0x3c, 0x9c, 0xe3, 0xe1, 0xe0, 0x09, 0xca, 0xfc, 0xaf, 0x7e, 0x47, 0xec, 0x20, 0x1a, 0x70, 0x67, 0x43, 0xe9, 0x79, 0x8e, 0xdb, 0xa5, 0x0f, 0xd1, 0x04, 0x3a, 0xe7, 0x48, 0x3c, 0xfc, 0x3c}}, + {{0x79, 0x41, 0x33, 0xeb, 0xf5, 0xcc, 0x4c, 0xd8, 0xc7, 0xf8, 0xde, 0x15, 0x98, 0x18, 0x23, 0xce, 0x1f, 0x8e, 0xb5, 0x7d, 0xea, 0x8d, 0x6c, 0xe7, 0x8a, 0x9d, 0xb4, 0xf6, 0x9f, 0x47, 0xca, 0x3a}, {0x60, 0x7a, 0x23, 0xf1, 0x6d, 0x24, 0xf1, 0x17, 0xa6, 0x2f, 0x2f, 0x8d, 0x8f, 0x9d, 0x17, 0x2e, 0x4f, 0xf6, 0x3e, 0x42, 0x13, 0xe6, 0xd0, 0x32, 0xae, 0xc1, 0x6e, 0x8b, 0x3d, 0x29, 0x7c, 0x06}}, + {{0x19, 0x8a, 0xa7, 0x17, 0x0a, 0x0c, 0xcd, 0x8e, 0x88, 0xb1, 0x60, 0x7f, 0xa6, 0x7b, 0x36, 0x71, 0x3a, 0xd6, 0xaa, 0xd1, 0x2c, 0xbf, 0x5a, 0xff, 0xb5, 0xed, 0x5e, 0xd1, 0x9b, 0x09, 0x56, 0x36}, {0xbc, 0x9e, 0xe2, 0xd1, 0x63, 0x10, 0xdf, 0xc0, 0xb5, 0x5a, 0xf3, 0x3d, 0xeb, 0x45, 0xec, 0x9a, 0xa1, 0xcb, 0x86, 0x7b, 0x49, 0x3f, 0x71, 0x6e, 0xca, 0x59, 0x23, 0xb5, 0x1d, 0x9f, 0x44, 0x2e}}, + {{0x69, 0x0e, 0xba, 0xaf, 0x0e, 0x44, 0x6e, 0xa5, 0x1a, 0xbe, 0x3e, 0x43, 0xc0, 0x4a, 0xfb, 0x10, 0x6d, 0xee, 0x71, 0x8d, 0x2c, 0x39, 0x5f, 0xd9, 0xdb, 0x75, 0xf4, 0x8a, 0x9e, 0x08, 0xef, 0x34}, {0x29, 0xee, 0xaf, 0x4f, 0x68, 0x89, 0xde, 0x9c, 0x93, 0x46, 0x45, 0x46, 0x2b, 0x7c, 0x90, 0xd3, 0xef, 0x6d, 0xb2, 0x9e, 0x45, 0xc0, 0x58, 0xf8, 0x9e, 0x19, 0x96, 0xfc, 0x36, 0x61, 0x59, 0x2a}}, + {{0x4b, 0x09, 0xa0, 0x68, 0xb8, 0x83, 0x41, 0xd3, 0x4f, 0xb2, 0x24, 0x12, 0x30, 0x63, 0xc5, 0x46, 0x4b, 0x39, 0x0b, 0xdc, 0x11, 0xac, 0x9f, 0x93, 0x85, 0xed, 0x5f, 0xb4, 0xdc, 0x5d, 0x98, 0x11}, {0xac, 0xbd, 0x23, 0x8c, 0x52, 0x52, 0x03, 0x45, 0xa8, 0x31, 0x79, 0x04, 0x78, 0xe2, 0x8c, 0x81, 0x68, 0x0a, 0xbe, 0x33, 0xaf, 0x05, 0x8b, 0x4d, 0x47, 0x29, 0xfe, 0x01, 0x40, 0xb2, 0x54, 0x28}}, + {{0x57, 0x27, 0xba, 0x9d, 0x3b, 0x92, 0xea, 0x21, 0xa4, 0xba, 0x67, 0x72, 0xee, 0x32, 0x2d, 0x10, 0x6d, 0xd9, 0x5b, 0xff, 0x17, 0x8d, 0x7e, 0xe0, 0x44, 0xcb, 0x3b, 0x59, 0x92, 0xfe, 0x39, 0x05}, {0xda, 0x2c, 0x98, 0xa7, 0x8c, 0xe7, 0xa6, 0x89, 0x45, 0xfc, 0xc1, 0xc6, 0xae, 0x98, 0x6a, 0x77, 0xc5, 0x20, 0xfb, 0x5e, 0x4e, 0xcc, 0xc1, 0xa4, 0x2c, 0xfe, 0x53, 0x89, 0x00, 0x1e, 0x15, 0x2f}}, + {{0x97, 0x1d, 0xb9, 0x83, 0x41, 0x50, 0x23, 0x10, 0x60, 0xca, 0x77, 0x88, 0x2a, 0xbc, 0xfe, 0x81, 0x4c, 0xbb, 0x3f, 0xfe, 0x49, 0x5c, 0x24, 0x19, 0xf3, 0x74, 0xf3, 0xe3, 0x3f, 0xa1, 0x38, 0x0d}, {0xde, 0x45, 0xa1, 0x44, 0x31, 0x17, 0x43, 0xd6, 0x87, 0x5f, 0x57, 0x73, 0x8b, 0xd7, 0x95, 0xcd, 0xe3, 0x09, 0x29, 0xd3, 0x3f, 0x6c, 0xd2, 0x6e, 0x2a, 0x34, 0x5f, 0xe8, 0x80, 0x83, 0x60, 0x09}}, + {{0x5e, 0xc0, 0x2f, 0xbe, 0xdb, 0x8c, 0x91, 0x42, 0x95, 0xd4, 0x66, 0xb1, 0x57, 0x4a, 0xcf, 0x9a, 0xab, 0x49, 0x5e, 0xf4, 0x23, 0xc9, 0x99, 0xca, 0xe9, 0xa1, 0xb7, 0x04, 0xab, 0x33, 0xa1, 0x3f}, {0xa0, 0x4d, 0x4d, 0x52, 0x82, 0xa9, 0x31, 0xd7, 0x72, 0x11, 0x21, 0x03, 0x8d, 0x87, 0xec, 0x55, 0xcd, 0x92, 0x24, 0xe3, 0xed, 0xea, 0xd5, 0x48, 0x98, 0x71, 0x67, 0xd1, 0x57, 0xb9, 0xff, 0x0c}}, + {{0xc2, 0xa4, 0x29, 0xc4, 0x8a, 0xad, 0x28, 0xf5, 0x7e, 0x92, 0xcb, 0x8b, 0xcd, 0x85, 0x9b, 0xd9, 0x1d, 0xf1, 0xcd, 0x3e, 0x3f, 0x6c, 0x3a, 0x85, 0xb0, 0xec, 0x91, 0x0d, 0xe9, 0xd9, 0xb4, 0x3f}, {0x70, 0xa7, 0x88, 0x70, 0xbd, 0x5c, 0x37, 0x91, 0x5d, 0xfc, 0x63, 0x40, 0xbd, 0x46, 0x73, 0xbc, 0x1c, 0xa3, 0x34, 0x19, 0xa0, 0xb5, 0xee, 0x52, 0x34, 0x13, 0xc1, 0x0d, 0x9b, 0x38, 0x97, 0x35}}, + {{0x02, 0x38, 0xa3, 0xc6, 0xbd, 0xe2, 0x04, 0xdb, 0x78, 0x09, 0xbe, 0xce, 0xc3, 0x61, 0x96, 0x48, 0x97, 0xf5, 0x9e, 0xa4, 0xcc, 0x61, 0xf9, 0x21, 0x42, 0x22, 0x94, 0xb3, 0xb7, 0xc0, 0xc8, 0x0f}, {0xd6, 0xbe, 0x8a, 0x94, 0x56, 0x9b, 0x85, 0x8f, 0x47, 0x23, 0x7c, 0xbb, 0xa1, 0x52, 0xb1, 0x72, 0xd3, 0x88, 0xb4, 0x34, 0xd5, 0x82, 0xda, 0xfc, 0xf7, 0xdc, 0xbf, 0xc1, 0x0b, 0x04, 0x4d, 0x3e}}, + {{0x4c, 0xfb, 0xf8, 0xf5, 0xd9, 0xd7, 0xa9, 0x24, 0x64, 0x65, 0x7a, 0xda, 0x2f, 0xe9, 0x4b, 0xa8, 0xf6, 0x9f, 0xac, 0x1b, 0xc0, 0xa2, 0x10, 0x7c, 0xf9, 0x9e, 0x70, 0x2e, 0xbb, 0xec, 0x3d, 0x34}, {0x54, 0xe6, 0xfd, 0xd7, 0x2e, 0x64, 0x38, 0xf5, 0x4b, 0x58, 0x2e, 0x43, 0xa6, 0xfa, 0x30, 0x6d, 0xcc, 0x2b, 0x56, 0x28, 0xad, 0x02, 0xf2, 0x18, 0x1d, 0xd2, 0x52, 0x23, 0x66, 0x71, 0x0c, 0x1a}}, + {{0x6a, 0x3f, 0xd3, 0x14, 0x11, 0x90, 0xe8, 0x08, 0xa2, 0x28, 0x8c, 0xf4, 0xea, 0x62, 0x82, 0x0d, 0x46, 0x65, 0x50, 0x27, 0x7b, 0x08, 0xfe, 0x89, 0xe6, 0xe8, 0xaa, 0xef, 0x7a, 0x2f, 0x95, 0x08}, {0xad, 0x84, 0x55, 0x95, 0x0f, 0x28, 0x63, 0xca, 0x22, 0xd5, 0xa5, 0xe8, 0x03, 0xa1, 0xbe, 0xc7, 0x91, 0xe4, 0x41, 0x54, 0x13, 0xd9, 0x95, 0xb7, 0x32, 0xa0, 0xab, 0x62, 0xad, 0x13, 0xa2, 0x3a}}, + {{0xa1, 0xaf, 0x6d, 0xa4, 0xe2, 0xe3, 0x4d, 0x15, 0x41, 0x96, 0x7c, 0xaf, 0x7e, 0xcb, 0x1b, 0xef, 0xb7, 0x48, 0x9c, 0x0b, 0x3f, 0x1e, 0xcc, 0xc4, 0x2e, 0x2a, 0x99, 0x1a, 0xa3, 0x14, 0x7b, 0x22}, {0x61, 0x4a, 0xfb, 0x71, 0x90, 0xe2, 0xe2, 0xe7, 0x73, 0x3b, 0x2c, 0x9e, 0xfe, 0xa7, 0xf4, 0x28, 0x6a, 0xc8, 0x25, 0x19, 0x36, 0x80, 0xc8, 0x2f, 0x6a, 0xf9, 0x92, 0x3d, 0x3d, 0x37, 0xde, 0x2c}}, + {{0xc8, 0xf4, 0xd6, 0xa7, 0x42, 0x18, 0x19, 0x6c, 0x70, 0x3d, 0x39, 0x30, 0x99, 0xba, 0x1d, 0xa3, 0x76, 0x70, 0x06, 0x3e, 0x26, 0x6c, 0x14, 0x35, 0x6b, 0x48, 0x46, 0x46, 0x47, 0x9a, 0x03, 0x38}, {0xc5, 0x96, 0x82, 0x59, 0x49, 0xd2, 0xaf, 0x27, 0x52, 0xd2, 0xb2, 0xf5, 0xaa, 0xb6, 0xf6, 0xfc, 0xec, 0xdf, 0x95, 0x74, 0x1e, 0xb9, 0x22, 0x5c, 0x07, 0x65, 0xa4, 0xdf, 0x70, 0x9b, 0x57, 0x2d}}, + {{0xdf, 0x64, 0x76, 0x43, 0x11, 0xb1, 0xaf, 0x50, 0x25, 0x53, 0x6f, 0xfe, 0xf4, 0x72, 0x85, 0x1a, 0x0e, 0x63, 0xcf, 0xea, 0x8b, 0xbf, 0x88, 0x13, 0x13, 0x76, 0x09, 0xe1, 0x99, 0x37, 0x6b, 0x38}, {0x2a, 0xe1, 0x43, 0x91, 0x5b, 0x2f, 0x70, 0x1d, 0x8d, 0x42, 0xf3, 0xc5, 0x7e, 0xaf, 0xc6, 0xaa, 0xf2, 0x52, 0x1f, 0x55, 0x11, 0x6b, 0xdc, 0x17, 0x93, 0xe7, 0x35, 0xe8, 0xb0, 0x38, 0x7c, 0x0f}}, + {{0x46, 0x3e, 0xd4, 0x9b, 0x75, 0xbd, 0xe1, 0xc6, 0xaf, 0x0b, 0xe1, 0x41, 0x52, 0xcc, 0xa0, 0xb4, 0xab, 0xf6, 0x6e, 0xc4, 0x75, 0xed, 0x77, 0x9b, 0x03, 0xff, 0x48, 0x52, 0x29, 0xf9, 0x02, 0x0c}, {0x25, 0x68, 0x56, 0x09, 0x24, 0x50, 0x45, 0xc4, 0x18, 0x79, 0xe1, 0xb2, 0x5c, 0xb6, 0x96, 0x09, 0xa6, 0x49, 0xb1, 0x1e, 0x0f, 0x9f, 0x22, 0xec, 0x87, 0x58, 0x62, 0x44, 0x28, 0x88, 0x64, 0x0c}}, + {{0x18, 0xba, 0x97, 0x27, 0xbd, 0x8b, 0x12, 0xc4, 0x08, 0x5b, 0xd3, 0x69, 0x04, 0x1f, 0x47, 0xbd, 0x64, 0x23, 0x6c, 0x84, 0xe6, 0x0a, 0x1a, 0x02, 0x79, 0x63, 0xea, 0xf4, 0x1e, 0x3b, 0x0d, 0x1e}, {0x78, 0x9f, 0xab, 0x1c, 0xb2, 0x8e, 0xbd, 0xd0, 0xe3, 0x74, 0x72, 0xfe, 0x11, 0xe6, 0xfb, 0x1b, 0xde, 0xd7, 0xe3, 0x10, 0x15, 0x88, 0x44, 0xf8, 0x96, 0x93, 0xac, 0xa5, 0xbb, 0x00, 0x0b, 0x15}}, + {{0xde, 0xc0, 0x69, 0x91, 0x2b, 0x2b, 0x2e, 0x75, 0x56, 0x16, 0x2b, 0x5a, 0xeb, 0x7f, 0xe4, 0xf2, 0x12, 0x79, 0x4b, 0x31, 0x31, 0x78, 0xf7, 0x61, 0x6c, 0x14, 0x30, 0x15, 0xbf, 0x36, 0xd5, 0x29}, {0x72, 0x0c, 0xff, 0x9a, 0x54, 0xbb, 0x90, 0xc8, 0x2a, 0xb4, 0xdb, 0x76, 0xe0, 0xa4, 0x7d, 0x19, 0x06, 0x52, 0x21, 0x38, 0x42, 0x01, 0x6f, 0x74, 0x1e, 0x95, 0x5a, 0x4c, 0x7e, 0xc5, 0x12, 0x25}}, + {{0x6c, 0x68, 0xaa, 0xc1, 0x45, 0x6a, 0xe6, 0xe7, 0x67, 0x12, 0x46, 0xbd, 0x74, 0xb4, 0x98, 0x8c, 0xdf, 0x4c, 0xc1, 0x4c, 0x14, 0xd4, 0xe1, 0x8a, 0x67, 0x8c, 0x5c, 0x94, 0xfa, 0x33, 0x9f, 0x1b}, {0x21, 0x6b, 0x6d, 0xad, 0x95, 0x74, 0x02, 0x98, 0x1b, 0x1b, 0xcc, 0xce, 0x29, 0xed, 0xc8, 0xcc, 0x44, 0x70, 0x30, 0x69, 0x51, 0x0f, 0xc8, 0x74, 0x38, 0x22, 0x06, 0x3b, 0xec, 0xd2, 0x4b, 0x33}}, + {{0x42, 0x45, 0x8a, 0xe4, 0x4a, 0xe3, 0xe3, 0xe2, 0x3a, 0x23, 0x72, 0xee, 0x9d, 0x9d, 0xa7, 0x77, 0x99, 0x3f, 0x97, 0x5d, 0xcd, 0x2f, 0x90, 0x92, 0x6b, 0xd8, 0x7b, 0x53, 0x80, 0xdf, 0x28, 0x0e}, {0x9a, 0x5b, 0x98, 0xa1, 0xb7, 0xf5, 0x57, 0xb2, 0x19, 0x8f, 0xc2, 0xcb, 0x70, 0x7e, 0xdd, 0xad, 0x77, 0xbb, 0xd3, 0x11, 0xdf, 0x17, 0x5b, 0xc3, 0x4c, 0x98, 0x5b, 0xe8, 0x76, 0x8a, 0xf4, 0x28}}, + {{0x83, 0x7f, 0xa5, 0x7a, 0xb9, 0x64, 0xd2, 0xc1, 0xba, 0xd3, 0x31, 0x10, 0x7d, 0x69, 0xa7, 0xc8, 0xba, 0xc1, 0xc1, 0xd6, 0xc8, 0x33, 0x54, 0x1e, 0x95, 0x7a, 0x85, 0x7c, 0x62, 0x43, 0x28, 0x1a}, {0x3b, 0x80, 0x38, 0xf6, 0x05, 0x70, 0x00, 0x5c, 0x36, 0x34, 0xd1, 0x33, 0x10, 0x68, 0x3c, 0x15, 0xcf, 0xc4, 0xec, 0x65, 0xfa, 0x84, 0xca, 0x39, 0xa1, 0x2d, 0xe3, 0xeb, 0x69, 0x73, 0xa5, 0x36}}, + {{0xd1, 0x88, 0xd6, 0x1e, 0xb7, 0xfa, 0x3b, 0xcb, 0x70, 0x44, 0xda, 0xc3, 0xb1, 0x75, 0x9d, 0x95, 0x2b, 0x3d, 0x2e, 0x21, 0x88, 0xcf, 0x6b, 0xff, 0x99, 0x6b, 0x0b, 0x99, 0xe5, 0x0e, 0xb4, 0x1a}, {0x43, 0x8e, 0xe5, 0xd6, 0x71, 0xcc, 0xfc, 0x18, 0x21, 0x0d, 0x00, 0x1c, 0xcf, 0xe1, 0xfa, 0x52, 0x25, 0xa2, 0xa4, 0x42, 0xc1, 0x97, 0x55, 0xfe, 0xba, 0x13, 0xa3, 0x72, 0xab, 0x53, 0x8a, 0x0a}}, + {{0x4b, 0x8e, 0x16, 0x54, 0x37, 0x3a, 0xce, 0xf4, 0x4a, 0x43, 0x52, 0xec, 0x6a, 0x54, 0xc7, 0x61, 0xe8, 0x57, 0x93, 0x68, 0x66, 0xac, 0x70, 0x7d, 0xc8, 0xef, 0x7d, 0x9a, 0x75, 0x44, 0x12, 0x1c}, {0x5a, 0xdb, 0x6e, 0xa9, 0xb6, 0x2c, 0x5f, 0x3b, 0x4f, 0x5d, 0x59, 0x23, 0x86, 0xe8, 0x71, 0xef, 0xe0, 0xc9, 0xfd, 0x5a, 0x36, 0x74, 0xa2, 0xe5, 0xfe, 0x3e, 0x74, 0x27, 0x1f, 0xf9, 0x0a, 0x11}}, + {{0x95, 0xde, 0x77, 0xe6, 0x2a, 0xe2, 0x95, 0x68, 0xc3, 0x3d, 0x7b, 0x93, 0x3d, 0x9b, 0xbb, 0x9f, 0x66, 0xbd, 0xd5, 0xd4, 0xd9, 0xf4, 0xc1, 0x0b, 0x8a, 0xe7, 0xec, 0x1f, 0x7f, 0xb6, 0xf2, 0x27}, {0xc4, 0xef, 0xbc, 0x50, 0x11, 0x94, 0x34, 0x72, 0x62, 0x03, 0xf5, 0xa8, 0x53, 0x57, 0x8e, 0xac, 0x6c, 0x46, 0x28, 0xe4, 0x41, 0x8c, 0xe3, 0xf7, 0x13, 0xcf, 0x4d, 0x5d, 0x5b, 0x64, 0x5e, 0x31}}, + {{0x93, 0x69, 0x08, 0xe8, 0x94, 0xbb, 0x94, 0x54, 0xe8, 0xef, 0x21, 0xc4, 0x5b, 0x79, 0x9a, 0x90, 0x33, 0xf4, 0x45, 0x6b, 0x01, 0xcb, 0x8b, 0x03, 0xdd, 0xd6, 0xb6, 0xcb, 0x36, 0x46, 0xc4, 0x2f}, {0x87, 0xbb, 0xbd, 0x0c, 0xe0, 0x6f, 0x7f, 0xa3, 0x06, 0x05, 0x08, 0xbe, 0x06, 0xcb, 0xae, 0x0a, 0x6f, 0xf3, 0x4d, 0xe8, 0x2f, 0xa1, 0x80, 0xdd, 0x50, 0xe2, 0xf9, 0x7a, 0xe0, 0x84, 0xc8, 0x1d}}, + {{0x0b, 0x0e, 0x6d, 0xa5, 0x05, 0x1d, 0xa4, 0xda, 0x3c, 0x44, 0xeb, 0x13, 0x75, 0x5c, 0xed, 0x6f, 0x50, 0xcd, 0xb1, 0x65, 0x4c, 0x0e, 0x8b, 0x7a, 0xef, 0xb0, 0x8b, 0xed, 0x8e, 0x7c, 0x4f, 0x21}, {0x16, 0xea, 0x81, 0x18, 0xd5, 0xd9, 0x49, 0xfe, 0x37, 0x13, 0x34, 0xed, 0x64, 0xdd, 0x53, 0x23, 0xd9, 0x26, 0xf1, 0xd9, 0x8e, 0x0c, 0xb2, 0x56, 0xe8, 0x0d, 0x2b, 0x4c, 0xb4, 0x92, 0x22, 0x2c}}, + {{0xbb, 0x04, 0x7c, 0x9b, 0x4e, 0x96, 0x4d, 0xa7, 0xec, 0x2d, 0xc0, 0x4e, 0x5b, 0xbb, 0x5c, 0x33, 0x9f, 0x32, 0x94, 0x69, 0xec, 0x7b, 0x84, 0x8a, 0xd4, 0xc5, 0xe7, 0x0d, 0x22, 0x1c, 0xa7, 0x1a}, {0x93, 0xf5, 0xf9, 0xd6, 0xa6, 0x82, 0xb8, 0xc3, 0xe6, 0x8a, 0x9f, 0x25, 0x1b, 0x9e, 0xa7, 0x9b, 0x26, 0xcc, 0x79, 0xbd, 0x63, 0xb7, 0xb6, 0x8a, 0x40, 0xb7, 0xfa, 0x34, 0xaf, 0x61, 0x83, 0x21}}, + {{0x61, 0x36, 0xd5, 0x5b, 0x79, 0x5e, 0xb6, 0x97, 0x38, 0x8b, 0xdc, 0xf4, 0x4b, 0xb2, 0x0b, 0x56, 0xda, 0x12, 0x55, 0xc0, 0xc1, 0xdc, 0xce, 0x16, 0x5b, 0x10, 0xf2, 0xb4, 0xae, 0x6c, 0x71, 0x15}, {0x25, 0x7f, 0x91, 0xab, 0xa4, 0xb4, 0x1a, 0x3f, 0xc7, 0x2e, 0x48, 0x4e, 0x6e, 0xf1, 0x97, 0x45, 0x4b, 0x54, 0x78, 0x9f, 0xe2, 0xb3, 0xc4, 0x43, 0x59, 0x1c, 0xbf, 0x26, 0xc2, 0xee, 0xbf, 0x0a}}, + {{0xd7, 0x91, 0xb6, 0x41, 0x39, 0xa7, 0xeb, 0x9b, 0xa3, 0xeb, 0x08, 0x9d, 0x9b, 0xe4, 0x15, 0xcf, 0x6e, 0xbb, 0x9b, 0x4f, 0x65, 0x24, 0x43, 0xd4, 0xf6, 0xb4, 0x75, 0x59, 0x0c, 0xf1, 0x42, 0x25}, {0x1c, 0x22, 0xc7, 0xf3, 0xa6, 0xc2, 0x0d, 0x41, 0x1d, 0x82, 0x38, 0xf1, 0x82, 0xef, 0x64, 0x9e, 0x50, 0xcb, 0x2a, 0xdf, 0xe2, 0x68, 0x07, 0x36, 0x46, 0xa9, 0xa1, 0xa2, 0x0c, 0x28, 0xf0, 0x2a}}, + {{0xcc, 0x32, 0x25, 0x25, 0xa4, 0x4d, 0xaa, 0x40, 0x18, 0x69, 0x50, 0x68, 0xf5, 0x25, 0x47, 0xa0, 0x4a, 0xe1, 0xfc, 0xfe, 0x44, 0x86, 0x96, 0xd0, 0x85, 0xa1, 0xa9, 0x96, 0x22, 0xae, 0x91, 0x05}, {0x23, 0xc2, 0xe9, 0x2d, 0x56, 0xea, 0x9d, 0xc5, 0xf1, 0x94, 0x62, 0x8a, 0x85, 0x1b, 0x48, 0x15, 0xa2, 0x25, 0xb6, 0xc1, 0x8d, 0xa0, 0xac, 0x0a, 0xa1, 0xdd, 0xce, 0x21, 0x9a, 0xcf, 0x05, 0x0f}}, + {{0xcc, 0x72, 0x76, 0x50, 0xd1, 0xb7, 0x4b, 0xd1, 0xd5, 0x3a, 0xce, 0x52, 0x6f, 0x7f, 0x30, 0x63, 0x72, 0x30, 0x24, 0xad, 0x25, 0x1e, 0xe5, 0x7c, 0xa0, 0x6e, 0x7c, 0xdd, 0xac, 0x2b, 0xdc, 0x07}, {0xae, 0xff, 0x40, 0x7c, 0xd5, 0xc3, 0x36, 0x58, 0x09, 0xae, 0xb7, 0x44, 0x9e, 0x81, 0xf5, 0x46, 0x85, 0x97, 0x9c, 0xe0, 0x55, 0xfb, 0x96, 0xb7, 0xd1, 0x5d, 0xd5, 0x55, 0x7b, 0x73, 0x95, 0x2d}}, + {{0xaf, 0x82, 0x15, 0x01, 0xbf, 0xa9, 0xdd, 0x86, 0x44, 0x6b, 0x90, 0x36, 0x1e, 0xe4, 0xd9, 0x40, 0xa2, 0xbf, 0x83, 0x89, 0xaa, 0x20, 0x87, 0x57, 0xfb, 0x8a, 0xf1, 0x18, 0x06, 0x17, 0x1a, 0x2f}, {0xc6, 0xa8, 0xe4, 0x75, 0x09, 0x93, 0xf8, 0x09, 0x79, 0x9f, 0x1c, 0xbe, 0x7d, 0x96, 0x85, 0xef, 0xd4, 0xbc, 0xb7, 0x32, 0xba, 0x18, 0x38, 0x4a, 0xb7, 0x5c, 0xb5, 0x63, 0x95, 0x12, 0x8f, 0x0a}}, + {{0x38, 0x2a, 0x4e, 0xa8, 0x0f, 0x85, 0xe5, 0x64, 0x92, 0x28, 0xcb, 0xa1, 0xd2, 0xf9, 0xa1, 0x67, 0xdc, 0x1a, 0x3d, 0x6a, 0xa9, 0xe8, 0xb6, 0x34, 0xc0, 0xa0, 0xd6, 0x86, 0xe3, 0x30, 0x6f, 0x2e}, {0x6a, 0xff, 0x65, 0x8e, 0x17, 0x3f, 0xd1, 0xb9, 0x48, 0x78, 0x5a, 0xe2, 0x20, 0x0b, 0xfb, 0x4f, 0xd3, 0xe2, 0x68, 0xe6, 0xd2, 0xdc, 0x2f, 0x6c, 0x9c, 0x23, 0xfa, 0xa6, 0x54, 0x9c, 0x93, 0x1e}}, + {{0xf6, 0xe7, 0xce, 0x79, 0x67, 0x84, 0x16, 0x33, 0x60, 0xc3, 0x60, 0x55, 0x7b, 0xd0, 0x6e, 0xfb, 0x57, 0x63, 0xff, 0x55, 0x59, 0x2f, 0x8f, 0x4a, 0x8d, 0x6d, 0x75, 0x93, 0xfc, 0x77, 0xfb, 0x28}, {0x12, 0x56, 0xcf, 0xb2, 0x78, 0x1b, 0xe2, 0xe3, 0x88, 0x76, 0x22, 0xcb, 0xe2, 0x70, 0xd4, 0xc8, 0x4b, 0xf2, 0xd4, 0xe1, 0x6e, 0x0c, 0x1b, 0x73, 0xc2, 0x55, 0x19, 0x46, 0xff, 0x02, 0xcd, 0x30}}, + {{0x26, 0x91, 0xea, 0xe5, 0x02, 0x4a, 0x9c, 0x8e, 0xdd, 0x96, 0x5e, 0x4e, 0x8e, 0xf1, 0xb9, 0x6f, 0x31, 0x11, 0x49, 0x68, 0x74, 0x32, 0x4c, 0x49, 0x12, 0x09, 0xaa, 0x35, 0x24, 0xfe, 0xb5, 0x18}, {0x75, 0x8d, 0xfc, 0x8d, 0x92, 0x0a, 0x56, 0x49, 0x7e, 0x26, 0x11, 0x3b, 0x69, 0x7b, 0x48, 0xc9, 0x9f, 0x78, 0x42, 0x1b, 0x1d, 0xda, 0x5e, 0x31, 0x9a, 0xbf, 0x73, 0x9f, 0x03, 0x35, 0xd4, 0x35}}, + {{0x62, 0x2f, 0x96, 0x9f, 0x21, 0x68, 0x10, 0x00, 0xe7, 0xe2, 0x30, 0x6b, 0x4d, 0x2d, 0x31, 0x39, 0xc6, 0xc2, 0x36, 0xad, 0x9a, 0xb2, 0xbe, 0x94, 0xd2, 0x73, 0x07, 0xc0, 0x28, 0x53, 0xf4, 0x36}, {0xb5, 0xd8, 0x5d, 0x1e, 0x41, 0x0b, 0xf3, 0xe4, 0xd8, 0xcb, 0x23, 0x48, 0x6f, 0x1f, 0xe5, 0x65, 0x99, 0xf2, 0xb6, 0xd0, 0xd3, 0x3f, 0x7f, 0xf4, 0xbe, 0x56, 0x51, 0xe9, 0xf8, 0x8f, 0x27, 0x14}}, + {{0x15, 0x20, 0x1e, 0xd9, 0xad, 0xd0, 0x4f, 0xe1, 0xab, 0xfd, 0xa9, 0x60, 0xd9, 0xcc, 0xbc, 0xa2, 0x72, 0xb5, 0x1c, 0xf7, 0xb5, 0xaa, 0x5f, 0x71, 0x8c, 0x8c, 0x3f, 0xe2, 0x3b, 0xed, 0x60, 0x19}, {0xb0, 0x75, 0xd9, 0x32, 0x92, 0xe7, 0x4d, 0x6d, 0x90, 0x44, 0x9c, 0xf7, 0x6f, 0xd8, 0xe0, 0xa0, 0xd9, 0x08, 0x3c, 0x5f, 0x8e, 0xec, 0x7e, 0x94, 0xb6, 0xee, 0x76, 0xf1, 0xd0, 0xf9, 0x2a, 0x16}}, + {{0x4f, 0x4e, 0x4f, 0x64, 0x89, 0x2a, 0xbe, 0x77, 0xf8, 0x19, 0x79, 0xf9, 0x2f, 0xfd, 0xc2, 0xda, 0x6e, 0x33, 0xa4, 0x0a, 0x5e, 0x41, 0x2d, 0x48, 0xea, 0xdd, 0x5d, 0xc2, 0x67, 0x8f, 0xb4, 0x12}, {0xc2, 0xfd, 0x95, 0x54, 0x56, 0xb3, 0x47, 0x14, 0xbd, 0xa6, 0x46, 0x20, 0x2d, 0x15, 0x86, 0xfa, 0x30, 0x34, 0xb6, 0x96, 0xee, 0x3c, 0x48, 0x0e, 0x6b, 0x35, 0x04, 0x9f, 0x69, 0xf9, 0x0a, 0x31}}, + {{0xb2, 0x90, 0x49, 0x4b, 0x8f, 0x56, 0xd9, 0x49, 0xed, 0x0e, 0x43, 0x6c, 0xe9, 0x52, 0x1d, 0xff, 0xbc, 0x7f, 0xb6, 0x0a, 0x7e, 0xc6, 0xab, 0x9d, 0xd0, 0x6b, 0xfc, 0xda, 0xf0, 0xac, 0xb8, 0x15}, {0xe1, 0xeb, 0xaf, 0xc8, 0xbc, 0x2a, 0xdb, 0x04, 0xde, 0xae, 0xed, 0xb8, 0x02, 0x43, 0x8a, 0x85, 0x1a, 0x37, 0x83, 0x96, 0xdf, 0xf9, 0x7e, 0x85, 0xa9, 0x56, 0xbc, 0xc5, 0x92, 0x67, 0xd5, 0x0e}}, + {{0xb8, 0x29, 0xbe, 0x97, 0xbb, 0xc4, 0xc8, 0x8f, 0x88, 0x93, 0xfd, 0xc6, 0x3a, 0xec, 0x3f, 0x72, 0x00, 0x38, 0xce, 0x14, 0x44, 0x5b, 0x18, 0xcc, 0x8c, 0xaf, 0x7c, 0xed, 0xa9, 0x31, 0x03, 0x19}, {0x68, 0x17, 0x0c, 0x82, 0xb0, 0x8e, 0x48, 0x6e, 0x49, 0xca, 0xf1, 0x98, 0x2c, 0x5d, 0xcb, 0x7f, 0x25, 0x41, 0x8e, 0x23, 0x66, 0x89, 0xc6, 0x32, 0xcc, 0xea, 0x65, 0xb1, 0x5e, 0xd0, 0xca, 0x06}}, + {{0x38, 0x4c, 0x42, 0x99, 0xc0, 0x73, 0xd6, 0x05, 0x6c, 0xd3, 0xd8, 0x65, 0x44, 0xe9, 0x1c, 0x9b, 0x99, 0x0b, 0x65, 0xf3, 0xf4, 0xc0, 0x92, 0x41, 0x71, 0xb8, 0x4d, 0x08, 0x85, 0xb3, 0x83, 0x33}, {0xdc, 0x42, 0xb4, 0xab, 0x62, 0xb1, 0xa3, 0x41, 0xed, 0x46, 0x83, 0x25, 0xb0, 0x86, 0x7f, 0x01, 0xb5, 0xa2, 0xed, 0xe3, 0x83, 0x97, 0x8e, 0x45, 0x81, 0x6b, 0xd3, 0x29, 0xcb, 0xe1, 0x3e, 0x08}}, + {{0x7d, 0x76, 0x77, 0x79, 0x43, 0x95, 0x76, 0xe4, 0x5f, 0x17, 0x6c, 0xf6, 0x2a, 0x7b, 0x9c, 0xed, 0x5e, 0xcd, 0x41, 0x57, 0x88, 0xa5, 0x33, 0xb8, 0x2c, 0xd7, 0x58, 0xcd, 0xfb, 0xb7, 0x3d, 0x36}, {0xe3, 0x02, 0xf8, 0xd9, 0xcb, 0x93, 0x13, 0xf3, 0x8b, 0x07, 0x43, 0x2b, 0x6c, 0x36, 0xeb, 0xe6, 0x4e, 0x59, 0x12, 0x32, 0xdc, 0xb4, 0xa3, 0xbc, 0x34, 0x1b, 0x11, 0xdf, 0x78, 0x19, 0xb1, 0x08}}, + {{0x6c, 0x00, 0x6f, 0x9e, 0x05, 0xa7, 0xce, 0x77, 0xab, 0x66, 0x08, 0xdc, 0x7d, 0xdb, 0x5b, 0xa3, 0xea, 0x97, 0xf1, 0x56, 0x2e, 0xf9, 0x5a, 0x71, 0x6e, 0xd8, 0xc4, 0x05, 0x45, 0x93, 0x64, 0x36}, {0xfc, 0xcf, 0x1d, 0xa1, 0x68, 0xe4, 0x53, 0x9c, 0x2c, 0x60, 0xdd, 0x68, 0x67, 0x0f, 0x3e, 0x1c, 0x77, 0x45, 0x5c, 0xd6, 0xb8, 0x77, 0xa5, 0x1b, 0xe6, 0x9a, 0xf6, 0x67, 0xb8, 0x09, 0x42, 0x1d}}, + {{0x80, 0x58, 0x0f, 0xa1, 0x80, 0x53, 0x0a, 0x26, 0xe5, 0x04, 0x5a, 0xb6, 0xcc, 0xb8, 0x1b, 0x7a, 0x08, 0x23, 0x8b, 0xd2, 0xff, 0xf9, 0xa8, 0x27, 0xc3, 0xf3, 0xbe, 0xac, 0x37, 0xfb, 0x32, 0x3a}, {0x54, 0x99, 0x74, 0xa3, 0x46, 0x9b, 0x4a, 0x91, 0x35, 0x81, 0x61, 0x0c, 0xfc, 0xb9, 0xd9, 0xfe, 0x1e, 0xf2, 0x72, 0xa1, 0xc9, 0x3e, 0x45, 0xfe, 0x0f, 0xec, 0x78, 0x57, 0xfd, 0x90, 0x9f, 0x1c}}, + {{0x08, 0x31, 0x09, 0xc2, 0x61, 0xa4, 0x10, 0x99, 0x04, 0x90, 0x9e, 0xb3, 0x23, 0xd0, 0x2e, 0x2c, 0x3b, 0x91, 0x7f, 0xa2, 0x33, 0x9b, 0x03, 0x2c, 0xec, 0x4d, 0x77, 0x95, 0x54, 0x69, 0x0e, 0x0a}, {0xd8, 0x90, 0x49, 0x45, 0x3d, 0xb7, 0xb9, 0xe6, 0xed, 0x1e, 0x52, 0x23, 0x67, 0xdd, 0xba, 0x47, 0x00, 0xcc, 0xa5, 0x81, 0x46, 0xe0, 0xbe, 0x40, 0x2d, 0x93, 0xff, 0x1e, 0x1f, 0xea, 0xb5, 0x36}}, + {{0xa3, 0xf7, 0x61, 0x46, 0x98, 0x03, 0xe0, 0xd2, 0xe1, 0x51, 0xe6, 0x09, 0x7c, 0xc1, 0x79, 0xca, 0x38, 0xa5, 0x0b, 0x41, 0xd3, 0x47, 0x36, 0x78, 0x5d, 0x9a, 0xcb, 0x8a, 0xa4, 0x55, 0x7c, 0x21}, {0x63, 0xe2, 0xfd, 0x04, 0x6c, 0x0b, 0xd2, 0x1b, 0x59, 0xa3, 0x6d, 0xdc, 0x94, 0xb6, 0xc7, 0x02, 0x1c, 0x9a, 0x1b, 0x8a, 0xfc, 0x9c, 0x71, 0x3a, 0xbe, 0x9b, 0x48, 0x5b, 0x23, 0x53, 0xff, 0x3f}}, + {{0xd2, 0x16, 0xfc, 0x66, 0xf6, 0xd2, 0x5b, 0xe2, 0xc2, 0x75, 0x9c, 0xdb, 0xa1, 0xb1, 0x99, 0xf9, 0x2d, 0x16, 0x4f, 0x79, 0xcf, 0xf6, 0xf6, 0xd0, 0x98, 0x5f, 0x52, 0x53, 0xde, 0x32, 0x66, 0x33}, {0x98, 0xe0, 0x30, 0x92, 0x79, 0x3a, 0x68, 0x1c, 0xed, 0x04, 0x2c, 0xa7, 0x25, 0x7b, 0x7c, 0x80, 0x62, 0xe7, 0x08, 0x0c, 0x05, 0x0c, 0x4e, 0x53, 0xb0, 0xba, 0xb2, 0x88, 0x1f, 0x1d, 0xc6, 0x2b}}, + {{0x06, 0x38, 0x11, 0x6d, 0x02, 0xad, 0xe1, 0x6e, 0xf8, 0xc2, 0x69, 0x0c, 0x86, 0xcf, 0x02, 0xc4, 0x48, 0x79, 0xd4, 0x7a, 0x98, 0x0a, 0x43, 0x1b, 0x73, 0x40, 0xe7, 0x04, 0xb0, 0xca, 0x23, 0x31}, {0x93, 0x11, 0x74, 0xaf, 0x1e, 0xc0, 0xac, 0x28, 0xb5, 0xb2, 0x65, 0x3e, 0x06, 0x2c, 0x35, 0x3d, 0xab, 0x52, 0x2a, 0x3d, 0x88, 0x81, 0xa6, 0x5d, 0x7a, 0x51, 0x69, 0x55, 0xb3, 0x4a, 0xf2, 0x38}}, + {{0x80, 0x9a, 0x02, 0x27, 0x1c, 0x34, 0xaf, 0x6b, 0xc1, 0x22, 0x26, 0x23, 0x3d, 0xcf, 0xd7, 0x31, 0xa3, 0x7d, 0x6f, 0x45, 0x61, 0xe3, 0x6b, 0xb5, 0x94, 0x04, 0x47, 0x5b, 0xc2, 0x07, 0xd9, 0x22}, {0xe1, 0xb2, 0x21, 0x93, 0xea, 0x08, 0x10, 0x81, 0xc1, 0x0e, 0x04, 0x8b, 0x9c, 0xc1, 0x15, 0x9e, 0x1a, 0x0f, 0xfd, 0xa4, 0x0c, 0x86, 0xb4, 0xc7, 0x92, 0xce, 0xf2, 0x9f, 0x5c, 0x5b, 0xb3, 0x3f}}, + {{0x5d, 0x21, 0xc3, 0x57, 0xe9, 0xcb, 0xb4, 0x3e, 0x18, 0x20, 0x5a, 0xaa, 0x30, 0x1c, 0xbb, 0xe3, 0x6a, 0xce, 0xdf, 0x04, 0x64, 0xf3, 0x29, 0x68, 0x02, 0x35, 0x77, 0x5e, 0xb8, 0x9b, 0x4c, 0x1e}, {0x92, 0xb6, 0x5a, 0xc3, 0x06, 0x54, 0x27, 0xf9, 0xeb, 0xd2, 0xf8, 0x43, 0xcf, 0xca, 0xb3, 0xed, 0x8d, 0xfa, 0x2f, 0xe8, 0x41, 0x6f, 0x04, 0x5b, 0x2e, 0x77, 0xe1, 0x1b, 0x90, 0xb4, 0xc2, 0x16}}, + {{0x25, 0xb3, 0xf3, 0x0d, 0xb0, 0x5b, 0xf2, 0x91, 0x0e, 0x31, 0x14, 0xbf, 0x2e, 0x04, 0xa2, 0x9f, 0x05, 0x5a, 0xb1, 0x8b, 0x06, 0x8c, 0x0d, 0x44, 0xb6, 0x51, 0x17, 0x11, 0x5a, 0xe0, 0x0a, 0x00}, {0xfc, 0x96, 0xdc, 0xe8, 0x52, 0xf2, 0xa9, 0x71, 0xfc, 0x47, 0x48, 0xa9, 0x94, 0x0e, 0xe9, 0x93, 0x22, 0x65, 0xe4, 0x82, 0x6d, 0x75, 0xbd, 0x35, 0xad, 0x90, 0x22, 0x09, 0x2d, 0x18, 0xd4, 0x0d}}, + {{0x5a, 0x39, 0x2e, 0x15, 0x8a, 0x89, 0x7d, 0xac, 0xda, 0x33, 0xb3, 0x1a, 0x51, 0x88, 0x3e, 0x89, 0x12, 0x18, 0x1e, 0x79, 0xb1, 0x82, 0x69, 0xf0, 0x02, 0xd0, 0x65, 0xcf, 0xc4, 0xf3, 0xb6, 0x1f}, {0x38, 0xbc, 0xa2, 0xbc, 0x04, 0xe1, 0xc5, 0x65, 0x62, 0xa2, 0x3f, 0x11, 0x3c, 0x88, 0x1b, 0xcd, 0x5e, 0xd4, 0xae, 0x58, 0x49, 0xaf, 0xbc, 0x96, 0x72, 0xa3, 0xb9, 0x6e, 0xd2, 0xe7, 0x4c, 0x3c}}, + {{0xea, 0x02, 0x90, 0xed, 0x0f, 0xb4, 0x7f, 0x86, 0x76, 0xa7, 0xba, 0x7c, 0x1b, 0x04, 0xa5, 0x40, 0x98, 0xac, 0xc4, 0xc7, 0xa4, 0x37, 0x06, 0xc2, 0xbe, 0x8f, 0x46, 0x0e, 0xa2, 0x9d, 0x70, 0x25}, {0x53, 0xfd, 0xc0, 0x4e, 0x9f, 0x68, 0x1a, 0x65, 0x98, 0xe0, 0xea, 0x41, 0x08, 0x30, 0x1e, 0x4a, 0xd2, 0x49, 0x83, 0xca, 0x05, 0xec, 0x4d, 0x9e, 0x95, 0x07, 0xc6, 0x57, 0x31, 0xed, 0xcb, 0x2f}}, + {{0xd1, 0x6f, 0x17, 0xe8, 0x60, 0x1c, 0xb5, 0xa5, 0x0f, 0x75, 0xb9, 0xbf, 0xe3, 0x21, 0x8f, 0x2e, 0x41, 0xa9, 0x74, 0x8b, 0x3c, 0xe5, 0x5c, 0xf4, 0x99, 0x7b, 0x4a, 0xe0, 0x36, 0x1a, 0xfd, 0x04}, {0xf9, 0xd4, 0x5a, 0x9b, 0xc9, 0x72, 0xa7, 0x5c, 0xee, 0xca, 0x93, 0x83, 0x3d, 0xaa, 0x3c, 0xea, 0xa6, 0x0b, 0x18, 0x28, 0x20, 0xad, 0x08, 0x35, 0x0f, 0x07, 0x2c, 0xc5, 0x69, 0xcd, 0x7d, 0x1b}}, + {{0x0e, 0xd2, 0xf1, 0xb3, 0x26, 0x4e, 0x76, 0xf0, 0xc8, 0xe9, 0x25, 0x86, 0x2e, 0x14, 0xc7, 0x18, 0xe2, 0xdc, 0xde, 0x7d, 0x4f, 0x7d, 0xf7, 0x51, 0x22, 0x3f, 0x2b, 0x23, 0x50, 0xbf, 0x73, 0x23}, {0x60, 0xc6, 0x8c, 0x32, 0x3d, 0xd6, 0xb8, 0x47, 0x5d, 0xae, 0x05, 0x0e, 0xc4, 0xf5, 0xfe, 0xda, 0x89, 0x12, 0xc9, 0x47, 0x65, 0xa9, 0xb5, 0x98, 0x6c, 0x0a, 0x05, 0x09, 0x91, 0x04, 0xad, 0x01}}, + {{0xdf, 0x94, 0x7f, 0x94, 0x89, 0xa1, 0x44, 0x11, 0xba, 0x22, 0x10, 0xcd, 0x16, 0xdf, 0x28, 0xe4, 0xa8, 0xc4, 0x76, 0x34, 0xea, 0xd9, 0x65, 0x75, 0xdc, 0xc3, 0x65, 0x12, 0xe3, 0xa6, 0x70, 0x20}, {0x46, 0xe1, 0xc9, 0xde, 0x7d, 0x7f, 0xdf, 0x91, 0xe7, 0xdb, 0x9e, 0x34, 0x1c, 0x87, 0x35, 0x91, 0x0a, 0xbb, 0xe8, 0xd0, 0xb4, 0xdc, 0xdb, 0x7e, 0x15, 0x8d, 0x75, 0x05, 0x09, 0xc9, 0x90, 0x0c}}, + {{0xa6, 0x1e, 0x1f, 0xb3, 0x18, 0x9d, 0x7e, 0x49, 0xe3, 0xb0, 0xec, 0x1b, 0x39, 0x5e, 0x7a, 0x08, 0x64, 0x8c, 0x44, 0x6a, 0x9c, 0x4d, 0xde, 0xe8, 0xb8, 0x22, 0x85, 0xdf, 0xad, 0x4a, 0x1d, 0x14}, {0x64, 0x3c, 0xae, 0xb7, 0x77, 0x62, 0x15, 0xff, 0x3c, 0xa7, 0x5b, 0x0f, 0x96, 0xb0, 0x55, 0x34, 0x61, 0xe8, 0xf9, 0x04, 0xe3, 0xcf, 0x51, 0x20, 0xd7, 0xd6, 0xe2, 0x52, 0x8b, 0x6f, 0xf8, 0x19}}, + {{0xa4, 0x46, 0x0c, 0xee, 0xac, 0x3c, 0xb2, 0x9e, 0xd6, 0x7c, 0xa7, 0xcb, 0x93, 0xc2, 0x1a, 0xe6, 0xaf, 0x30, 0x07, 0x9c, 0x71, 0x65, 0x0e, 0xc5, 0x26, 0xd9, 0xc9, 0x0d, 0x4f, 0x2c, 0x25, 0x22}, {0x35, 0x43, 0x20, 0x2d, 0x10, 0x8f, 0xee, 0x99, 0xd3, 0x02, 0xf6, 0x3b, 0x54, 0xc1, 0xd9, 0x09, 0x19, 0xc5, 0x64, 0x9e, 0xd0, 0xe3, 0xd7, 0x61, 0xf3, 0xb8, 0x27, 0xc2, 0xbc, 0xb8, 0x3f, 0x1b}}, + {{0x3f, 0xcb, 0x65, 0xdf, 0xea, 0xa4, 0x9e, 0x6b, 0x27, 0xeb, 0x17, 0x67, 0x22, 0xf8, 0xfe, 0xc1, 0x2c, 0x4f, 0xf3, 0xa0, 0x2e, 0xb8, 0x69, 0xfb, 0x4c, 0x6c, 0x2c, 0x92, 0xaf, 0xf3, 0x94, 0x25}, {0xae, 0xa9, 0x21, 0x6a, 0xb7, 0xa2, 0x31, 0xc4, 0xaa, 0x4c, 0x49, 0xa7, 0x4e, 0xfa, 0x4f, 0xba, 0xf9, 0xc4, 0x36, 0xab, 0x08, 0xe3, 0x4d, 0x35, 0x1b, 0x71, 0x78, 0x5d, 0xc7, 0x96, 0x4b, 0x24}}, + {{0x92, 0x51, 0x42, 0x65, 0xc3, 0xed, 0x68, 0x47, 0xfe, 0xfe, 0x47, 0xa3, 0x8a, 0x8e, 0x35, 0x66, 0xce, 0x73, 0xb9, 0xe5, 0xd5, 0xdf, 0xf4, 0xb5, 0x54, 0xf4, 0xbf, 0x25, 0xc5, 0x51, 0x59, 0x1a}, {0x8a, 0xfd, 0xf5, 0x8d, 0x9a, 0x04, 0x01, 0x7e, 0xdd, 0x19, 0xd2, 0x41, 0x90, 0x28, 0x01, 0x6b, 0x12, 0xe0, 0x00, 0xe5, 0x89, 0x3e, 0x44, 0x38, 0x77, 0x6d, 0xf5, 0x4a, 0x34, 0xf2, 0xe0, 0x2b}}, + {{0x3a, 0x21, 0x60, 0x18, 0xfc, 0x74, 0x1e, 0xae, 0x2c, 0xf2, 0x86, 0x28, 0x3a, 0x3c, 0xe4, 0x3f, 0xe1, 0xc1, 0xbe, 0xed, 0x1e, 0x9b, 0xfa, 0xde, 0xaf, 0x5f, 0x9f, 0x4e, 0xb6, 0x5a, 0xbc, 0x31}, {0x13, 0x85, 0x2a, 0x57, 0x96, 0xb1, 0x19, 0xbd, 0xc9, 0xf2, 0x26, 0xf4, 0x9b, 0xe0, 0x72, 0x42, 0xf7, 0xdd, 0x11, 0xae, 0x75, 0xf8, 0x25, 0x99, 0x63, 0x0d, 0xfb, 0x53, 0x9e, 0x5b, 0xb9, 0x1f}}, + {{0x26, 0x73, 0xe8, 0x08, 0x63, 0xa7, 0x36, 0xb2, 0xa3, 0xdc, 0xe8, 0x45, 0x2e, 0xb0, 0x74, 0x89, 0xd8, 0x10, 0x33, 0xff, 0x04, 0xb9, 0x75, 0x05, 0xca, 0xef, 0x04, 0x4f, 0x41, 0xed, 0x47, 0x03}, {0xd8, 0x0a, 0xb5, 0x32, 0x89, 0xfd, 0xeb, 0x18, 0x5d, 0x51, 0xd0, 0x4e, 0x74, 0x55, 0xa2, 0x82, 0x2a, 0x15, 0x77, 0x03, 0xbf, 0xd6, 0x35, 0xb1, 0x80, 0x98, 0x9a, 0xbc, 0xdb, 0xa1, 0x19, 0x34}}, + {{0x00, 0xe4, 0x42, 0x8c, 0x14, 0x07, 0x84, 0x8c, 0x67, 0x83, 0x99, 0x61, 0x72, 0xbd, 0x8a, 0xee, 0xd9, 0x4c, 0x51, 0x5c, 0xe9, 0xc3, 0x4e, 0xfe, 0x07, 0xcf, 0xc8, 0x0b, 0x9a, 0x7f, 0x7d, 0x2b}, {0xd4, 0xdf, 0x68, 0x30, 0x61, 0x7f, 0x8f, 0xe5, 0xd4, 0x7d, 0x92, 0x71, 0x82, 0xd4, 0xc9, 0x31, 0x74, 0xfe, 0x5e, 0xdb, 0x90, 0x1e, 0x9f, 0xa0, 0x46, 0xb5, 0x54, 0x7e, 0x57, 0xf9, 0x12, 0x2e}}, + {{0xc1, 0x14, 0x56, 0xeb, 0xf3, 0xc1, 0x25, 0x3d, 0xdc, 0x5a, 0x91, 0xdb, 0xf0, 0x2f, 0xb0, 0x78, 0xbb, 0x1a, 0x45, 0x47, 0x5a, 0x59, 0xe4, 0x52, 0x62, 0x26, 0x28, 0x5d, 0x2b, 0x81, 0xc0, 0x20}, {0x74, 0x97, 0xff, 0xa3, 0x32, 0xe0, 0x66, 0xc1, 0xc1, 0x5c, 0x7f, 0x88, 0x3f, 0x61, 0x21, 0xbf, 0xb3, 0xac, 0x5a, 0xe4, 0xcc, 0x23, 0x66, 0x66, 0x15, 0x54, 0xae, 0x47, 0x0a, 0x67, 0x8a, 0x1f}}, + {{0xb3, 0x1b, 0x94, 0xb2, 0x98, 0xea, 0x32, 0x0e, 0x4b, 0x17, 0xd0, 0xd5, 0xf6, 0xf5, 0x40, 0x00, 0xa4, 0x65, 0x71, 0x32, 0xe7, 0x87, 0x7c, 0x13, 0x0a, 0xda, 0x9b, 0xf9, 0x65, 0x8c, 0x14, 0x06}, {0xdc, 0x7e, 0x4d, 0xf4, 0x06, 0x5e, 0x48, 0x63, 0xab, 0x07, 0x80, 0xb1, 0xa4, 0x37, 0x2b, 0x3b, 0x6d, 0x3b, 0x23, 0x40, 0x2e, 0x30, 0x96, 0xfe, 0xd1, 0x80, 0xca, 0xef, 0xda, 0x9d, 0x86, 0x0c}}, + {{0xf1, 0x1c, 0xd4, 0x17, 0x3e, 0x30, 0xe3, 0x74, 0xc1, 0xd1, 0x45, 0x89, 0x56, 0x50, 0xb5, 0xb9, 0xee, 0xc8, 0xb0, 0xba, 0xd6, 0xf3, 0xca, 0xf5, 0x16, 0x18, 0xdc, 0xdc, 0xce, 0xc0, 0xaa, 0x20}, {0x76, 0xa8, 0x0c, 0xf8, 0x4b, 0x2a, 0x5b, 0x46, 0x07, 0x49, 0x30, 0xeb, 0xed, 0xde, 0x65, 0x7f, 0xe2, 0x77, 0x38, 0x9f, 0x80, 0xc8, 0x39, 0xcf, 0x3b, 0x74, 0xe5, 0x71, 0x46, 0xa3, 0x86, 0x02}}, + {{0x4b, 0xb0, 0x7f, 0x12, 0x68, 0xa1, 0x50, 0xfb, 0x03, 0xdf, 0xf5, 0x04, 0xe3, 0x01, 0xf8, 0x40, 0xeb, 0x50, 0x59, 0xc9, 0x34, 0xc0, 0xe1, 0xb4, 0x07, 0x5d, 0xf7, 0xca, 0x17, 0x93, 0x26, 0x11}, {0xad, 0x93, 0xbe, 0x71, 0xbd, 0x97, 0xc5, 0x42, 0x4b, 0x2e, 0x7d, 0xf8, 0x27, 0x1b, 0x20, 0xe2, 0x34, 0x69, 0x1c, 0xa8, 0xf5, 0xa2, 0xf2, 0x11, 0xdf, 0xad, 0x5b, 0x1d, 0x53, 0x0d, 0xa7, 0x25}}, + {{0xa4, 0x3f, 0x8d, 0x1d, 0x12, 0xb6, 0xc3, 0x86, 0x5f, 0xf1, 0xa4, 0x0c, 0x83, 0xc7, 0x14, 0x49, 0xec, 0xa7, 0x86, 0xf9, 0xe6, 0x4f, 0xea, 0x04, 0x0c, 0x7b, 0x50, 0x4a, 0x68, 0xf4, 0x26, 0x20}, {0xeb, 0x66, 0x74, 0x79, 0xf3, 0x50, 0x5e, 0x43, 0x33, 0x00, 0x0e, 0xb7, 0xb6, 0x73, 0x5c, 0x8b, 0xbf, 0x18, 0x4a, 0x14, 0xb6, 0x4a, 0xd9, 0x7e, 0x75, 0xd7, 0xa9, 0xff, 0xf0, 0x91, 0x10, 0x2b}}, + {{0xa5, 0x85, 0xf2, 0x15, 0xd6, 0xa5, 0x35, 0x73, 0x53, 0x46, 0x9a, 0x37, 0x55, 0xce, 0xe3, 0x65, 0xf0, 0x2a, 0x76, 0xcc, 0x4a, 0xed, 0x9c, 0xc5, 0x76, 0x7f, 0x46, 0x60, 0x2c, 0x7a, 0x29, 0x04}, {0x57, 0x62, 0x86, 0x02, 0x3f, 0xec, 0xf3, 0x38, 0xc0, 0xa5, 0x9e, 0xa4, 0x10, 0xf0, 0x13, 0x1e, 0xec, 0x2e, 0xca, 0x06, 0xbb, 0xe8, 0xf1, 0xda, 0x2d, 0x92, 0x5a, 0x9b, 0xdb, 0x3d, 0x9d, 0x32}}, + {{0x88, 0x1b, 0x3b, 0x11, 0xf0, 0xe7, 0x0a, 0x40, 0xd9, 0x0e, 0x9f, 0x72, 0x5a, 0xdd, 0x05, 0x65, 0xc8, 0xb4, 0x61, 0x82, 0xa6, 0x81, 0x6d, 0xf4, 0x20, 0x38, 0x87, 0xe8, 0x90, 0x84, 0x50, 0x24}, {0x21, 0x86, 0xea, 0x7f, 0x5b, 0x1e, 0xb8, 0x35, 0x86, 0x6a, 0x06, 0x5e, 0xbd, 0x93, 0xb1, 0x9a, 0xc3, 0x8f, 0x66, 0xd2, 0xf1, 0x12, 0x92, 0x86, 0x1e, 0x0d, 0x54, 0x2b, 0x70, 0xd0, 0xea, 0x15}}, + {{0xda, 0x66, 0x2e, 0xf4, 0x6a, 0x8b, 0x8c, 0x95, 0xf5, 0xd6, 0x14, 0x1c, 0x1f, 0x95, 0xcd, 0xdf, 0x0a, 0xf3, 0x54, 0x6f, 0xdc, 0x07, 0xbc, 0xb5, 0xda, 0x56, 0x16, 0x70, 0x49, 0xd6, 0x82, 0x1d}, {0xf9, 0x01, 0x6e, 0xa3, 0xe3, 0xa7, 0xbe, 0x05, 0xbe, 0x47, 0x18, 0x46, 0x6c, 0xd9, 0xab, 0x77, 0xf3, 0x5f, 0x67, 0x97, 0xd3, 0x16, 0xb5, 0xa7, 0xbe, 0xe4, 0x3c, 0xcc, 0x76, 0x5e, 0x85, 0x17}}, + {{0x5a, 0x5f, 0xfb, 0xb4, 0x0a, 0x31, 0x0a, 0xfd, 0x6f, 0xbb, 0x18, 0x46, 0xc2, 0xe1, 0x5f, 0xd0, 0x84, 0xe3, 0x3d, 0x01, 0x67, 0xe0, 0x41, 0x57, 0xf1, 0x4b, 0x9c, 0x87, 0xd6, 0x0e, 0x73, 0x23}, {0x16, 0x5d, 0x4c, 0xb9, 0xbc, 0xf7, 0x9f, 0x7e, 0x96, 0xfd, 0x76, 0x9f, 0xb3, 0x56, 0x5e, 0xd7, 0x0f, 0xea, 0x6d, 0x25, 0xb1, 0x35, 0x62, 0x55, 0x6d, 0x05, 0x08, 0x4f, 0xbe, 0x11, 0xcd, 0x3e}}, + {{0xa6, 0x8c, 0xb7, 0xd2, 0x38, 0x44, 0x04, 0x3d, 0xb0, 0xdc, 0xf3, 0x51, 0x14, 0xdb, 0x79, 0xa6, 0x15, 0xbb, 0xb2, 0xa2, 0x6c, 0x16, 0x2b, 0x92, 0x8a, 0x77, 0x3d, 0x6e, 0x35, 0x38, 0x07, 0x11}, {0xe2, 0xb7, 0x3e, 0xd6, 0x5d, 0xa4, 0xce, 0x95, 0x26, 0xd5, 0x26, 0xe6, 0x17, 0xc6, 0xf0, 0x2a, 0x5d, 0xd9, 0x31, 0x91, 0x37, 0x35, 0x55, 0x9d, 0x77, 0x3a, 0x99, 0x6b, 0x1a, 0x16, 0x84, 0x0d}}, + {{0x91, 0x51, 0x61, 0xf1, 0xc2, 0x74, 0xf8, 0x4d, 0xf4, 0x1f, 0x43, 0x08, 0x9a, 0x0d, 0x97, 0xd2, 0x89, 0xf8, 0x5d, 0x52, 0x9b, 0x4b, 0xc1, 0x66, 0x9a, 0xed, 0x22, 0x8a, 0x77, 0x8a, 0x83, 0x3b}, {0xae, 0xca, 0xcb, 0x06, 0x21, 0x96, 0x86, 0x67, 0x2b, 0xf6, 0x3f, 0x43, 0x98, 0x0b, 0xf2, 0x83, 0x0e, 0x97, 0x11, 0x4d, 0xa9, 0xc2, 0x05, 0xff, 0x4c, 0x89, 0x6c, 0x59, 0x0c, 0x3f, 0xdb, 0x32}}, + {{0xb4, 0x95, 0xb7, 0xc5, 0x17, 0x6b, 0xd2, 0x18, 0x6b, 0x3d, 0xdf, 0x31, 0x4c, 0x01, 0x97, 0x50, 0x47, 0x6f, 0xa3, 0xa9, 0xb7, 0x54, 0xbc, 0xc1, 0xa4, 0x2c, 0x52, 0x42, 0x49, 0x01, 0x3f, 0x00}, {0x5d, 0x2b, 0x71, 0x68, 0x73, 0x17, 0x04, 0xe7, 0xd0, 0x6e, 0x25, 0x14, 0x17, 0x3a, 0x2a, 0x01, 0xba, 0x4d, 0xc8, 0xda, 0xe1, 0x6a, 0x0f, 0x75, 0xec, 0xdc, 0xa9, 0x0d, 0xac, 0xe6, 0xfa, 0x39}}, + {{0x17, 0x30, 0x96, 0xc1, 0x4f, 0xfc, 0x22, 0x00, 0xf2, 0xa6, 0x5a, 0xb7, 0x91, 0xa8, 0x6d, 0x6e, 0x41, 0x84, 0xc7, 0xd9, 0x60, 0xaa, 0x65, 0x8e, 0xa8, 0x9f, 0x1a, 0x18, 0x81, 0xf1, 0xf0, 0x2f}, {0xf3, 0x74, 0xa0, 0xea, 0x6a, 0x64, 0xea, 0x08, 0x00, 0xbe, 0xbb, 0x01, 0xca, 0x09, 0x93, 0xe8, 0x64, 0x24, 0xf7, 0x55, 0x36, 0xc9, 0x21, 0x00, 0x4f, 0xaf, 0x8c, 0xb3, 0xdc, 0x5f, 0x6f, 0x2e}}, + {{0x01, 0xc5, 0x84, 0x57, 0xd6, 0x57, 0xbf, 0x99, 0x2c, 0xb5, 0x8e, 0x7c, 0x72, 0xbd, 0x17, 0x70, 0x5d, 0x8f, 0x32, 0x2d, 0x1c, 0xd3, 0x19, 0xe9, 0xb7, 0x2f, 0xf5, 0xaa, 0xaf, 0x43, 0xcd, 0x0b}, {0xa8, 0xe2, 0xd4, 0xc3, 0xa3, 0x5b, 0xd0, 0x60, 0xd2, 0x02, 0x52, 0xdf, 0xf0, 0x39, 0xa1, 0x03, 0x81, 0x94, 0xe1, 0x21, 0x6e, 0x8a, 0xc8, 0xe5, 0xa5, 0x9b, 0x52, 0x1d, 0xa4, 0xd0, 0x4a, 0x38}}, + {{0xfb, 0xc3, 0x3b, 0x69, 0x53, 0x11, 0x1f, 0xac, 0x64, 0x08, 0xf8, 0x26, 0x54, 0x3d, 0xcb, 0x95, 0xa7, 0x17, 0xc2, 0x91, 0x1f, 0x53, 0xc9, 0xac, 0xd6, 0xba, 0x62, 0x2b, 0xab, 0x65, 0xa0, 0x37}, {0x98, 0xcc, 0x28, 0xd7, 0x33, 0x28, 0x56, 0x25, 0x86, 0x7a, 0xdc, 0x6b, 0xe3, 0x5f, 0x7a, 0x15, 0x96, 0x6e, 0x03, 0x17, 0xbe, 0xfa, 0xa9, 0x45, 0xfb, 0x6e, 0x84, 0x3e, 0x9a, 0x2e, 0xa6, 0x15}}, + {{0x7e, 0x7d, 0xb5, 0x60, 0x66, 0x09, 0xeb, 0x84, 0xb6, 0x69, 0x9f, 0x68, 0x83, 0xc1, 0xb3, 0xbc, 0x8d, 0x7a, 0xa2, 0x1a, 0x0c, 0x6b, 0x79, 0xc1, 0xe3, 0x73, 0x77, 0x6b, 0xb0, 0x12, 0x47, 0x1f}, {0x66, 0x6f, 0xc4, 0xf3, 0x0a, 0xa1, 0x00, 0x2e, 0x1e, 0xe3, 0x58, 0x49, 0xa4, 0xd9, 0xd2, 0xd4, 0x6a, 0x6e, 0x8c, 0x9f, 0xf9, 0xc9, 0xe5, 0xaa, 0xaa, 0xc3, 0x4a, 0x6c, 0x9c, 0x5c, 0xfb, 0x0f}}, + {{0x32, 0x60, 0xaa, 0xe6, 0x7c, 0x42, 0xdf, 0xeb, 0x3a, 0xcc, 0x8f, 0x88, 0xb0, 0xd8, 0x84, 0x22, 0x8d, 0xfe, 0xf2, 0x83, 0x66, 0x81, 0x9c, 0x3f, 0xb0, 0xd2, 0x62, 0x18, 0xd2, 0xc3, 0xe0, 0x3b}, {0x82, 0x03, 0x25, 0x78, 0xe3, 0x4f, 0x68, 0xd0, 0x8f, 0x53, 0x3b, 0x56, 0xcf, 0x85, 0xa3, 0x29, 0x61, 0x91, 0xb0, 0x07, 0xc9, 0x2a, 0x01, 0xb4, 0x16, 0x06, 0x26, 0x5f, 0xbe, 0xfa, 0xe4, 0x3f}}, + {{0x9a, 0xc2, 0x4d, 0x8d, 0xa7, 0x86, 0xc2, 0x0b, 0x72, 0x7c, 0xcb, 0x57, 0xc0, 0xba, 0x08, 0xa8, 0xcd, 0xd6, 0xad, 0xe7, 0x13, 0xe2, 0x71, 0x1e, 0x11, 0x0b, 0x96, 0x95, 0x7c, 0x98, 0x6b, 0x3d}, {0x5a, 0x47, 0x1d, 0x7e, 0xd3, 0xcd, 0xac, 0xe4, 0x7c, 0xe9, 0x9a, 0x8e, 0xb2, 0xaf, 0xb1, 0xe6, 0x1b, 0x77, 0x38, 0xdc, 0x42, 0x79, 0x3c, 0xb4, 0x1d, 0x58, 0x76, 0x5b, 0x2c, 0x62, 0x9f, 0x0a}}, + {{0x0d, 0xd2, 0x15, 0xd3, 0x37, 0x1c, 0x6d, 0x34, 0x32, 0x22, 0x59, 0x97, 0xb6, 0x33, 0x90, 0x2f, 0x03, 0xfd, 0x46, 0xc4, 0x95, 0x99, 0xfa, 0x19, 0x42, 0xfc, 0x67, 0xb3, 0xfa, 0xa5, 0x97, 0x0e}, {0x80, 0x3a, 0x47, 0x7b, 0x58, 0x78, 0xf9, 0xa4, 0xcc, 0x9b, 0x48, 0x58, 0xcf, 0x72, 0x3a, 0x5c, 0x99, 0xa2, 0x21, 0x24, 0xe4, 0x72, 0x2b, 0x81, 0xf7, 0xbe, 0x6d, 0x41, 0xab, 0x99, 0x11, 0x2b}}, + {{0x48, 0x4e, 0x3a, 0xb7, 0xb3, 0xf1, 0x07, 0x5e, 0x83, 0x6b, 0x8f, 0x6f, 0x5f, 0x92, 0xb0, 0x19, 0xb2, 0x9c, 0x9a, 0x7f, 0xcc, 0xc5, 0x98, 0xcf, 0x17, 0x16, 0x39, 0x9b, 0x41, 0x0d, 0x1a, 0x0f}, {0xec, 0xfd, 0x90, 0xf0, 0x3e, 0xc8, 0x2f, 0x63, 0x60, 0xd6, 0x8e, 0xa1, 0x5b, 0x0e, 0x3c, 0x2f, 0xbf, 0xca, 0xe7, 0x46, 0x80, 0xd8, 0x90, 0xce, 0x59, 0xea, 0x2e, 0xa4, 0x0b, 0xfd, 0xad, 0x0c}}, + {{0x23, 0x50, 0xab, 0x76, 0x74, 0xcf, 0x8c, 0x23, 0x35, 0x00, 0x1b, 0xfb, 0x8a, 0x88, 0x4a, 0x07, 0xee, 0xec, 0xeb, 0xef, 0xe8, 0x56, 0x63, 0x37, 0x54, 0xdb, 0x51, 0x44, 0x97, 0x1e, 0x3e, 0x20}, {0xb7, 0xd1, 0x57, 0xd8, 0xcc, 0xa8, 0x5f, 0x20, 0x84, 0x72, 0x4f, 0x27, 0x9b, 0x37, 0x71, 0xa2, 0xfc, 0xd8, 0x2f, 0x53, 0x66, 0x8f, 0x47, 0x3d, 0x71, 0xe7, 0xb9, 0x56, 0xbe, 0x88, 0x66, 0x13}}, + {{0x6f, 0x74, 0x1c, 0xbb, 0x3d, 0xb5, 0x08, 0x2b, 0xf9, 0x59, 0x0e, 0x13, 0x32, 0x63, 0xd6, 0xde, 0xb3, 0x11, 0x0f, 0x89, 0x70, 0x7d, 0x3e, 0xec, 0x71, 0xa5, 0x57, 0x05, 0x94, 0x83, 0x0b, 0x07}, {0xbc, 0xfe, 0x6c, 0x00, 0x85, 0x2c, 0x20, 0x93, 0x4d, 0x5b, 0xc6, 0x3f, 0x93, 0x36, 0x9f, 0x67, 0xe1, 0x06, 0x2a, 0x0d, 0x30, 0xf0, 0x12, 0xea, 0x2c, 0x79, 0x2f, 0x80, 0x23, 0x47, 0x11, 0x2e}}, + {{0x47, 0xe2, 0x67, 0x2e, 0x5c, 0xe8, 0x6f, 0x35, 0x6d, 0x5f, 0x00, 0xa3, 0x5e, 0x77, 0x0d, 0x1d, 0x6c, 0xc1, 0xd0, 0xbb, 0xc6, 0x64, 0xf8, 0x80, 0xf0, 0xe9, 0x4e, 0x11, 0xa0, 0xed, 0x7a, 0x31}, {0x55, 0x04, 0xfc, 0x4b, 0x89, 0x45, 0xa6, 0xcd, 0x1f, 0x3c, 0x88, 0xac, 0x76, 0x3a, 0xfc, 0xf9, 0xec, 0x28, 0x8d, 0x79, 0x08, 0xa2, 0xf6, 0x61, 0x49, 0x9b, 0xc2, 0xa8, 0xe9, 0x1b, 0x02, 0x2c}}, + {{0x89, 0xbe, 0xc5, 0xf5, 0x37, 0xa1, 0x7a, 0x71, 0x5b, 0x98, 0x02, 0x31, 0x59, 0x53, 0x28, 0x90, 0x50, 0x07, 0x5a, 0x2c, 0x33, 0x0b, 0xfc, 0x4f, 0x53, 0x3a, 0x84, 0xed, 0x9c, 0x2c, 0x94, 0x24}, {0xa7, 0x4f, 0xae, 0x0c, 0x8d, 0x19, 0xdb, 0xfb, 0x29, 0xae, 0x9f, 0x33, 0x66, 0xd6, 0x1e, 0x30, 0xc1, 0x54, 0x1f, 0x35, 0x1b, 0x27, 0xdb, 0xe8, 0xda, 0x48, 0x0c, 0xe4, 0x1d, 0xb8, 0xc6, 0x1e}}, + {{0xe3, 0x61, 0x49, 0x71, 0xb9, 0xff, 0xad, 0x1f, 0xeb, 0x6f, 0xe4, 0x04, 0x27, 0x39, 0x76, 0xa1, 0x8d, 0x03, 0x91, 0x20, 0xf8, 0x89, 0x5d, 0x33, 0x4a, 0x03, 0x8a, 0xb6, 0xa5, 0x0d, 0x56, 0x05}, {0x29, 0x31, 0xef, 0x15, 0x61, 0xa0, 0xbc, 0x7c, 0x8d, 0x00, 0x9c, 0xdb, 0x8d, 0xe0, 0x19, 0x8e, 0xfb, 0x36, 0xa1, 0xb7, 0xb6, 0xab, 0x45, 0xa7, 0x45, 0x55, 0xde, 0x6b, 0x07, 0xb7, 0xcc, 0x2c}}, + {{0x40, 0x1b, 0x88, 0x6f, 0x9c, 0xc5, 0xba, 0x66, 0x6c, 0xf9, 0xc5, 0x51, 0x86, 0x1f, 0x9b, 0xae, 0xe1, 0x52, 0xdc, 0x9b, 0x00, 0x7e, 0x8e, 0x68, 0x33, 0xd7, 0x2e, 0x84, 0x0e, 0x38, 0xe4, 0x27}, {0xdb, 0x78, 0x8d, 0x61, 0xf3, 0x47, 0xe8, 0x1b, 0x7f, 0xf5, 0x8b, 0x6c, 0x3d, 0xc6, 0xf1, 0xcb, 0xdc, 0x91, 0x9f, 0xa3, 0x48, 0x3b, 0xcb, 0x62, 0x52, 0x85, 0x84, 0x0b, 0x2b, 0x7d, 0xed, 0x0c}}, + {{0xae, 0x9d, 0xb1, 0xd3, 0x47, 0xed, 0xc3, 0x2b, 0x80, 0x68, 0xdf, 0x2b, 0x5c, 0x23, 0x29, 0x79, 0xae, 0xde, 0x23, 0x4d, 0x66, 0x71, 0xc8, 0x4e, 0x47, 0x96, 0x92, 0xd7, 0x29, 0xbf, 0x6a, 0x02}, {0x96, 0x6b, 0x62, 0x52, 0x4b, 0x20, 0x51, 0x89, 0xd2, 0xfa, 0x72, 0xc6, 0xc7, 0x29, 0xba, 0x15, 0x4c, 0x13, 0x80, 0xa4, 0xa7, 0x9b, 0x49, 0x0d, 0xce, 0x65, 0x54, 0x4d, 0xb1, 0xdf, 0x7c, 0x39}}, +}; diff --git a/deps/crypto/trezor-crypto/pallas_swu.c b/deps/crypto/trezor-crypto/pallas_swu.c new file mode 100644 index 000000000..7a4fa43d7 --- /dev/null +++ b/deps/crypto/trezor-crypto/pallas_swu.c @@ -0,0 +1,712 @@ +/** + * Copyright (c) 2026 KeepKey + * + * Pallas simplified SWU, iso-Pallas isogeny, and hash-to-curve primitives. + * + * This follows pasta_curves 0.5.1: + * hash_to_field("pallas", domain, msg) + * map_to_curve_simple_swu:: + * iso_map:: + */ + +#include "pallas_swu.h" + +#include + +#include "memzero.h" +#include "pallas.h" + +typedef pallas_jacobian_point iso_point; + +static const uint8_t TWO_256_MOD_P[32] = { + 0xfd, 0xff, 0xff, 0xff, 0x38, 0x6d, 0x78, 0x34, + 0xad, 0x14, 0x19, 0xe4, 0x0b, 0x35, 0x2c, 0x99, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, +}; + +static const uint64_t ISO_A_RAW[4] = { + UINT64_C(0x92bb4b0b657a014b), + UINT64_C(0xb74134581a27a59f), + UINT64_C(0x49be2d7258370742), + UINT64_C(0x18354a2eb0ea8c9c), +}; + +static const uint64_t ISO_B_RAW[4] = { + UINT64_C(1265), + UINT64_C(0), + UINT64_C(0), + UINT64_C(0), +}; + +static const uint64_t PALLAS_Z_RAW[4] = { + UINT64_C(0x992d30ecfffffff4), + UINT64_C(0x224698fc094cf91b), + UINT64_C(0x0000000000000000), + UINT64_C(0x4000000000000000), +}; + +static const uint64_t PALLAS_THETA_RAW[4] = { + UINT64_C(0xca330bcc09ac318e), + UINT64_C(0x51f64fc4dc888857), + UINT64_C(0x4647aef782d5cdc8), + UINT64_C(0x0f7bdb65814179b4), +}; + +static const uint64_t PALLAS_ROOT_OF_UNITY_RAW[4] = { + UINT64_C(0xbdad6fabd87ea32f), + UINT64_C(0xea322bf2b7bb7584), + UINT64_C(0x362120830561f81a), + UINT64_C(0x2bce74deac30ebda), +}; + +static const uint64_t ISOGENY_RAW[13][4] = { + {UINT64_C(0x775f6034aaaaaaab), UINT64_C(0x4081775473d8375b), + UINT64_C(0xe38e38e38e38e38e), UINT64_C(0x0e38e38e38e38e38)}, + {UINT64_C(0x08cf863b02814fb76), UINT64_C(0x0f93b82ee4b99495), + UINT64_C(0x267c7ffa51cf412a), UINT64_C(0x3509afd51872d88e)}, + {UINT64_C(0x0eb64faef37ea4f7), UINT64_C(0x380af066cfeb6d69), + UINT64_C(0x98c7d7ac3d98fd13), UINT64_C(0x17329b9ec5253753)}, + {UINT64_C(0xeebec06955555580), UINT64_C(0x8102eea8e7b06eb6), + UINT64_C(0xc71c71c71c71c71c), UINT64_C(0x1c71c71c71c71c71)}, + {UINT64_C(0xc47f2ab668bcd71f), UINT64_C(0x9c434ac1c96b6980), + UINT64_C(0x5a607fcce0494a79), UINT64_C(0x1d572e7ddc099cff)}, + {UINT64_C(0x2aa3af1eae5b6604), UINT64_C(0xb4abf9fb9a1fc81c), + UINT64_C(0x1d13bf2a7f22b105), UINT64_C(0x325669becaecd5d1)}, + {UINT64_C(0x5ad985b5e38e38e4), UINT64_C(0x7642b01ad461bad2), + UINT64_C(0x4bda12f684bda12f), UINT64_C(0x1a12f684bda12f68)}, + {UINT64_C(0xc67c31d8140a7dbb), UINT64_C(0x07c9dc17725cca4a), + UINT64_C(0x133e3ffd28e7a095), UINT64_C(0x1a84d7ea8c396c47)}, + {UINT64_C(0x02e2be87d225b234), UINT64_C(0x1765e924f7459378), + UINT64_C(0x303216cce1db9ff1), UINT64_C(0x3fb98ff0d2ddcadd)}, + {UINT64_C(0x93e53ab371c71c4f), UINT64_C(0x0ac03e8e134eb3e4), + UINT64_C(0x7b425ed097b425ed), UINT64_C(0x025ed097b425ed09)}, + {UINT64_C(0x5a28279b1d1b42ae), UINT64_C(0x5941a3a4a97aa1b3), + UINT64_C(0x0790bfb3506defb6), UINT64_C(0x0c02c5bcca0e6b7f)}, + {UINT64_C(0x4d90ab820b12320a), UINT64_C(0xd976bbfabbc5661d), + UINT64_C(0x573b3d7f7d681310), UINT64_C(0x17033d3c60c68173)}, + {UINT64_C(0x992d30ecfffffde5), UINT64_C(0x224698fc094cf91b), + UINT64_C(0x0000000000000000), UINT64_C(0x4000000000000000)}, +}; + +static void fp_from_raw_u64(const uint64_t raw[4], bignum256 *out) { + uint8_t le[32]; + for (int i = 0; i < 4; i++) { + uint64_t v = raw[i]; + for (int j = 0; j < 8; j++) { + le[i * 8 + j] = (uint8_t)(v & 0xff); + v >>= 8; + } + } + bn_read_le(le, out); + pallas_mod_p(out); + memzero(le, sizeof(le)); +} + +static void fp_from_u32(uint32_t v, bignum256 *out) { + bn_zero(out); + out->val[0] = v; + pallas_mod_p(out); +} + +static void fp_one(bignum256 *out) { fp_from_u32(1, out); } + +static int fp_is_zero(const bignum256 *a) { return bn_is_zero(a); } + +static int fp_is_equal(const bignum256 *a, const bignum256 *b) { + bignum256 aa, bb; + bn_copy(a, &aa); + bn_copy(b, &bb); + bn_normalize(&aa); + bn_normalize(&bb); + return bn_is_equal(&aa, &bb); +} + +static void fp_add(const bignum256 *a, const bignum256 *b, bignum256 *out) { + pallas_add_mod_p(a, b, out); +} + +static void fp_sub(const bignum256 *a, const bignum256 *b, bignum256 *out) { + pallas_sub_mod_p(a, b, out); +} + +static void fp_neg(const bignum256 *a, bignum256 *out) { + if (bn_is_zero(a)) { + bn_zero(out); + } else { + pallas_sub_mod_p(&pallas_prime, a, out); + } +} + +static void fp_mul(const bignum256 *a, const bignum256 *b, bignum256 *out) { + bignum256 aa, bb; + bn_copy(a, &aa); + bn_copy(b, &bb); + pallas_mul_mod_p(&aa, &bb); + bn_copy(&aa, out); + memzero(&aa, sizeof(aa)); + memzero(&bb, sizeof(bb)); +} + +static void fp_square(const bignum256 *a, bignum256 *out) { + fp_mul(a, a, out); +} + +static void fp_double(const bignum256 *a, bignum256 *out) { + fp_add(a, a, out); +} + +static void fp_inv0(const bignum256 *a, bignum256 *out) { + if (bn_is_zero(a)) { + bn_zero(out); + } else { + bn_copy(a, out); + pallas_inv_mod_p(out); + } +} + +static int fp_sqrt_ratio(const bignum256 *num, const bignum256 *div, + bignum256 *out) { + bignum256 inv_div, a, candidate; + + if (bn_is_zero(div)) { + bn_zero(out); + return bn_is_zero(num); + } + + fp_inv0(div, &inv_div); + fp_mul(num, &inv_div, &a); + + bn_copy(&a, &candidate); + if (pallas_sqrt_mod_p(&candidate) == 0) { + bn_copy(&candidate, out); + memzero(&inv_div, sizeof(inv_div)); + memzero(&a, sizeof(a)); + memzero(&candidate, sizeof(candidate)); + return 1; + } + + bignum256 root_of_unity; + fp_from_raw_u64(PALLAS_ROOT_OF_UNITY_RAW, &root_of_unity); + fp_mul(&a, &root_of_unity, &candidate); + if (pallas_sqrt_mod_p(&candidate) == 0) { + bn_copy(&candidate, out); + } else { + bn_zero(out); + } + + memzero(&inv_div, sizeof(inv_div)); + memzero(&a, sizeof(a)); + memzero(&candidate, sizeof(candidate)); + memzero(&root_of_unity, sizeof(root_of_unity)); + return 0; +} + +static void fp_from_uniform64(const uint8_t in[64], bignum256 *out) { + bignum256 lo, hi, two_256, tmp; + + bn_read_le(in, &lo); + pallas_mod_p(&lo); + + bn_read_le(in + 32, &hi); + pallas_mod_p(&hi); + + bn_read_le(TWO_256_MOD_P, &two_256); + + bn_copy(&hi, &tmp); + pallas_mul_mod_p(&tmp, &two_256); + pallas_add_mod_p(&tmp, &lo, out); + + memzero(&lo, sizeof(lo)); + memzero(&hi, sizeof(hi)); + memzero(&two_256, sizeof(two_256)); + memzero(&tmp, sizeof(tmp)); +} + +static int iso_is_identity(const iso_point *p) { + return !p || bn_is_zero(&p->z); +} + +static void iso_set_identity(iso_point *p) { + bn_zero(&p->x); + bn_zero(&p->y); + bn_zero(&p->z); +} + +static int iso_is_on_curve(const iso_point *p) { + if (iso_is_identity(p)) return 1; + + bignum256 a, b, y2, x2, x3, z2, z4, z6, axz4, bz6, rhs, tmp; + fp_from_raw_u64(ISO_A_RAW, &a); + fp_from_raw_u64(ISO_B_RAW, &b); + + fp_square(&p->y, &y2); + fp_square(&p->x, &x2); + fp_mul(&x2, &p->x, &x3); + fp_square(&p->z, &z2); + fp_square(&z2, &z4); + fp_mul(&z4, &z2, &z6); + fp_mul(&a, &p->x, &axz4); + fp_mul(&axz4, &z4, &axz4); + fp_mul(&b, &z6, &bz6); + fp_add(&x3, &axz4, &tmp); + fp_add(&tmp, &bz6, &rhs); + + int ok = fp_is_equal(&y2, &rhs); + memzero(&a, sizeof(a)); + memzero(&b, sizeof(b)); + memzero(&y2, sizeof(y2)); + memzero(&x2, sizeof(x2)); + memzero(&x3, sizeof(x3)); + memzero(&z2, sizeof(z2)); + memzero(&z4, sizeof(z4)); + memzero(&z6, sizeof(z6)); + memzero(&axz4, sizeof(axz4)); + memzero(&bz6, sizeof(bz6)); + memzero(&rhs, sizeof(rhs)); + memzero(&tmp, sizeof(tmp)); + return ok; +} + +static void iso_double(const iso_point *p, iso_point *out) { + if (iso_is_identity(p)) { + iso_set_identity(out); + return; + } + + bignum256 curve_a; + fp_from_raw_u64(ISO_A_RAW, &curve_a); + + bignum256 xx, yy, yyyy, zz, s, m, x3, y3, z3, tmp1, tmp2; + fp_square(&p->x, &xx); + fp_square(&p->y, &yy); + fp_square(&yy, &yyyy); + fp_square(&p->z, &zz); + + fp_add(&p->x, &yy, &tmp1); + fp_square(&tmp1, &tmp1); + fp_sub(&tmp1, &xx, &tmp1); + fp_sub(&tmp1, &yyyy, &tmp1); + fp_double(&tmp1, &s); + + fp_double(&xx, &tmp1); + fp_add(&tmp1, &xx, &m); + fp_square(&zz, &tmp1); + fp_mul(&curve_a, &tmp1, &tmp1); + fp_add(&m, &tmp1, &m); + + fp_square(&m, &x3); + fp_double(&s, &tmp1); + fp_sub(&x3, &tmp1, &x3); + + fp_sub(&s, &x3, &tmp1); + fp_mul(&m, &tmp1, &y3); + fp_double(&yyyy, &tmp2); + fp_double(&tmp2, &tmp2); + fp_double(&tmp2, &tmp2); + fp_sub(&y3, &tmp2, &y3); + + fp_add(&p->y, &p->z, &z3); + fp_square(&z3, &z3); + fp_sub(&z3, &yy, &z3); + fp_sub(&z3, &zz, &z3); + + bn_copy(&x3, &out->x); + bn_copy(&y3, &out->y); + bn_copy(&z3, &out->z); + + memzero(&curve_a, sizeof(curve_a)); + memzero(&xx, sizeof(xx)); + memzero(&yy, sizeof(yy)); + memzero(&yyyy, sizeof(yyyy)); + memzero(&zz, sizeof(zz)); + memzero(&s, sizeof(s)); + memzero(&m, sizeof(m)); + memzero(&x3, sizeof(x3)); + memzero(&y3, sizeof(y3)); + memzero(&z3, sizeof(z3)); + memzero(&tmp1, sizeof(tmp1)); + memzero(&tmp2, sizeof(tmp2)); +} + +static void iso_add(const iso_point *p, const iso_point *q, iso_point *out) { + if (iso_is_identity(p)) { + *out = *q; + return; + } + if (iso_is_identity(q)) { + *out = *p; + return; + } + + bignum256 z1z1, z2z2, u1, u2, s1, s2, h, i, j, r, v; + bignum256 x3, y3, z3; + + fp_square(&p->z, &z1z1); + fp_square(&q->z, &z2z2); + fp_mul(&p->x, &z2z2, &u1); + fp_mul(&q->x, &z1z1, &u2); + fp_mul(&p->y, &z2z2, &s1); + fp_mul(&s1, &q->z, &s1); + fp_mul(&q->y, &z1z1, &s2); + fp_mul(&s2, &p->z, &s2); + + if (fp_is_equal(&u1, &u2)) { + if (fp_is_equal(&s1, &s2)) { + iso_double(p, out); + } else { + iso_set_identity(out); + } + return; + } + + fp_sub(&u2, &u1, &h); + fp_double(&h, &i); + fp_square(&i, &i); + fp_mul(&h, &i, &j); + fp_sub(&s2, &s1, &r); + fp_double(&r, &r); + fp_mul(&u1, &i, &v); + + fp_square(&r, &x3); + fp_sub(&x3, &j, &x3); + fp_sub(&x3, &v, &x3); + fp_sub(&x3, &v, &x3); + + fp_mul(&s1, &j, &s1); + fp_double(&s1, &s1); + fp_sub(&v, &x3, &y3); + fp_mul(&r, &y3, &y3); + fp_sub(&y3, &s1, &y3); + + fp_add(&p->z, &q->z, &z3); + fp_square(&z3, &z3); + fp_sub(&z3, &z1z1, &z3); + fp_sub(&z3, &z2z2, &z3); + fp_mul(&z3, &h, &z3); + + bn_copy(&x3, &out->x); + bn_copy(&y3, &out->y); + bn_copy(&z3, &out->z); + + memzero(&z1z1, sizeof(z1z1)); + memzero(&z2z2, sizeof(z2z2)); + memzero(&u1, sizeof(u1)); + memzero(&u2, sizeof(u2)); + memzero(&s1, sizeof(s1)); + memzero(&s2, sizeof(s2)); + memzero(&h, sizeof(h)); + memzero(&i, sizeof(i)); + memzero(&j, sizeof(j)); + memzero(&r, sizeof(r)); + memzero(&v, sizeof(v)); + memzero(&x3, sizeof(x3)); + memzero(&y3, sizeof(y3)); + memzero(&z3, sizeof(z3)); +} + +int pallas_map_to_curve_simple_swu(const uint8_t u_le[32], + pallas_jacobian_point *out) { + if (!u_le || !out) return -1; + + bignum256 u, a, b, z, theta, one; + bignum256 u2, z_u2, ta, num_x1, div, num2_x1, div2, div3; + bignum256 num_gx1, num_x2, y1, y2, num_x, y, tmp1, tmp2; + + bn_read_le(u_le, &u); + pallas_mod_p(&u); + fp_from_raw_u64(ISO_A_RAW, &a); + fp_from_raw_u64(ISO_B_RAW, &b); + fp_from_raw_u64(PALLAS_Z_RAW, &z); + fp_from_raw_u64(PALLAS_THETA_RAW, &theta); + fp_one(&one); + + fp_square(&u, &u2); + fp_mul(&z, &u2, &z_u2); + fp_square(&z_u2, &ta); + fp_add(&ta, &z_u2, &ta); + + fp_add(&ta, &one, &tmp1); + fp_mul(&b, &tmp1, &num_x1); + + if (fp_is_zero(&ta)) { + bn_copy(&z, &tmp1); + } else { + fp_neg(&ta, &tmp1); + } + fp_mul(&a, &tmp1, &div); + + fp_square(&num_x1, &num2_x1); + fp_square(&div, &div2); + fp_mul(&div2, &div, &div3); + fp_mul(&a, &div2, &tmp1); + fp_add(&num2_x1, &tmp1, &tmp1); + fp_mul(&tmp1, &num_x1, &tmp1); + fp_mul(&b, &div3, &tmp2); + fp_add(&tmp1, &tmp2, &num_gx1); + + fp_mul(&z_u2, &num_x1, &num_x2); + + int gx1_square = fp_sqrt_ratio(&num_gx1, &div3, &y1); + + fp_mul(&theta, &z_u2, &y2); + fp_mul(&y2, &u, &y2); + fp_mul(&y2, &y1, &y2); + + if (gx1_square) { + bn_copy(&num_x1, &num_x); + bn_copy(&y1, &y); + } else { + bn_copy(&num_x2, &num_x); + bn_copy(&y2, &y); + } + + if (bn_is_odd(&u) != bn_is_odd(&y)) { + fp_neg(&y, &y); + } + + fp_mul(&num_x, &div, &out->x); + fp_mul(&y, &div3, &out->y); + bn_copy(&div, &out->z); + + int ok = iso_is_on_curve(out); + + memzero(&u, sizeof(u)); + memzero(&a, sizeof(a)); + memzero(&b, sizeof(b)); + memzero(&z, sizeof(z)); + memzero(&theta, sizeof(theta)); + memzero(&one, sizeof(one)); + memzero(&u2, sizeof(u2)); + memzero(&z_u2, sizeof(z_u2)); + memzero(&ta, sizeof(ta)); + memzero(&num_x1, sizeof(num_x1)); + memzero(&div, sizeof(div)); + memzero(&num2_x1, sizeof(num2_x1)); + memzero(&div2, sizeof(div2)); + memzero(&div3, sizeof(div3)); + memzero(&num_gx1, sizeof(num_gx1)); + memzero(&num_x2, sizeof(num_x2)); + memzero(&y1, sizeof(y1)); + memzero(&y2, sizeof(y2)); + memzero(&num_x, sizeof(num_x)); + memzero(&y, sizeof(y)); + memzero(&tmp1, sizeof(tmp1)); + memzero(&tmp2, sizeof(tmp2)); + + return ok ? 0 : -1; +} + +static void pallas_projective_to_affine(const bignum256 *x, const bignum256 *y, + const bignum256 *z, curve_point *out) { + if (bn_is_zero(z)) { + bn_zero(&out->x); + bn_zero(&out->y); + return; + } + + bignum256 z_inv, z_inv2, z_inv3; + bn_copy(z, &z_inv); + pallas_inv_mod_p(&z_inv); + fp_square(&z_inv, &z_inv2); + fp_mul(&z_inv2, &z_inv, &z_inv3); + fp_mul(x, &z_inv2, &out->x); + fp_mul(y, &z_inv3, &out->y); + + memzero(&z_inv, sizeof(z_inv)); + memzero(&z_inv2, sizeof(z_inv2)); + memzero(&z_inv3, sizeof(z_inv3)); +} + +static int pallas_point_on_curve(const curve_point *p) { + if (pallas_point_is_identity(p)) return 1; + + bignum256 y2, x2, x3, five, rhs; + fp_square(&p->y, &y2); + fp_square(&p->x, &x2); + fp_mul(&x2, &p->x, &x3); + fp_from_u32(5, &five); + fp_add(&x3, &five, &rhs); + int ok = fp_is_equal(&y2, &rhs); + memzero(&y2, sizeof(y2)); + memzero(&x2, sizeof(x2)); + memzero(&x3, sizeof(x3)); + memzero(&five, sizeof(five)); + memzero(&rhs, sizeof(rhs)); + return ok; +} + +int pallas_iso_map_to_pallas(const pallas_jacobian_point *iso, + curve_point *out) { + if (!iso || !out) return -1; + if (iso_is_identity(iso)) { + bn_zero(&out->x); + bn_zero(&out->y); + return 0; + } + + bignum256 c[13]; + for (int i = 0; i < 13; i++) { + fp_from_raw_u64(ISOGENY_RAW[i], &c[i]); + } + + bignum256 z2, z3, z4, z6, num_x, div_x, num_y, div_y; + bignum256 zo, xo, yo, tmp1, tmp2, tmp3; + + fp_square(&iso->z, &z2); + fp_mul(&z2, &iso->z, &z3); + fp_square(&z2, &z4); + fp_square(&z3, &z6); + + fp_mul(&c[0], &iso->x, &tmp1); + fp_mul(&c[1], &z2, &tmp2); + fp_add(&tmp1, &tmp2, &tmp1); + fp_mul(&tmp1, &iso->x, &tmp1); + fp_mul(&c[2], &z4, &tmp2); + fp_add(&tmp1, &tmp2, &tmp1); + fp_mul(&tmp1, &iso->x, &tmp1); + fp_mul(&c[3], &z6, &tmp2); + fp_add(&tmp1, &tmp2, &num_x); + + fp_mul(&z2, &iso->x, &tmp1); + fp_mul(&c[4], &z4, &tmp2); + fp_add(&tmp1, &tmp2, &tmp1); + fp_mul(&tmp1, &iso->x, &tmp1); + fp_mul(&c[5], &z6, &tmp2); + fp_add(&tmp1, &tmp2, &div_x); + + fp_mul(&c[6], &iso->x, &tmp1); + fp_mul(&c[7], &z2, &tmp2); + fp_add(&tmp1, &tmp2, &tmp1); + fp_mul(&tmp1, &iso->x, &tmp1); + fp_mul(&c[8], &z4, &tmp2); + fp_add(&tmp1, &tmp2, &tmp1); + fp_mul(&tmp1, &iso->x, &tmp1); + fp_mul(&c[9], &z6, &tmp2); + fp_add(&tmp1, &tmp2, &tmp1); + fp_mul(&tmp1, &iso->y, &num_y); + + fp_mul(&c[10], &z2, &tmp1); + fp_add(&iso->x, &tmp1, &tmp1); + fp_mul(&tmp1, &iso->x, &tmp1); + fp_mul(&c[11], &z4, &tmp2); + fp_add(&tmp1, &tmp2, &tmp1); + fp_mul(&tmp1, &iso->x, &tmp1); + fp_mul(&c[12], &z6, &tmp2); + fp_add(&tmp1, &tmp2, &tmp1); + fp_mul(&tmp1, &z3, &div_y); + + fp_mul(&div_x, &div_y, &zo); + fp_mul(&num_x, &div_y, &xo); + fp_mul(&xo, &zo, &xo); + fp_mul(&num_y, &div_x, &yo); + fp_square(&zo, &tmp3); + fp_mul(&yo, &tmp3, &yo); + + pallas_projective_to_affine(&xo, &yo, &zo, out); + int ok = pallas_point_on_curve(out); + + for (int i = 0; i < 13; i++) { + memzero(&c[i], sizeof(c[i])); + } + memzero(&z2, sizeof(z2)); + memzero(&z3, sizeof(z3)); + memzero(&z4, sizeof(z4)); + memzero(&z6, sizeof(z6)); + memzero(&num_x, sizeof(num_x)); + memzero(&div_x, sizeof(div_x)); + memzero(&num_y, sizeof(num_y)); + memzero(&div_y, sizeof(div_y)); + memzero(&zo, sizeof(zo)); + memzero(&xo, sizeof(xo)); + memzero(&yo, sizeof(yo)); + memzero(&tmp1, sizeof(tmp1)); + memzero(&tmp2, sizeof(tmp2)); + memzero(&tmp3, sizeof(tmp3)); + + return ok ? 0 : -1; +} + +static int hash_to_field(const char *domain_prefix, const uint8_t *msg, + size_t msg_len, bignum256 out[2]) { + static const char curve_id[] = "pallas"; + static const char suffix[] = "_XMD:BLAKE2b_SSWU_RO_"; + + if (!domain_prefix || (!msg && msg_len != 0) || !out) return -1; + + size_t domain_len = strlen(domain_prefix); + size_t curve_len = sizeof(curve_id) - 1; + size_t suffix_len = sizeof(suffix) - 1; + size_t dst_len = domain_len + 1 + curve_len + suffix_len; + if (domain_len >= 256 || dst_len >= 256) return -1; + + uint8_t dst[255]; + uint8_t uniform[128]; + uint8_t le[64]; + + memcpy(dst, domain_prefix, domain_len); + dst[domain_len] = '-'; + memcpy(dst + domain_len + 1, curve_id, curve_len); + memcpy(dst + domain_len + 1 + curve_len, suffix, suffix_len); + + if (pallas_expand_message_xmd_blake2b(msg, msg_len, dst, dst_len, uniform, + sizeof(uniform)) != 0) { + memzero(dst, sizeof(dst)); + return -1; + } + + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 64; j++) { + le[j] = uniform[i * 64 + (63 - j)]; + } + fp_from_uniform64(le, &out[i]); + } + + memzero(dst, sizeof(dst)); + memzero(uniform, sizeof(uniform)); + memzero(le, sizeof(le)); + return 0; +} + +int pallas_hash_to_curve(const char *domain_prefix, const uint8_t *msg, + size_t msg_len, curve_point *out) { + if (!domain_prefix || (!msg && msg_len != 0) || !out) return -1; + + bignum256 u[2]; + iso_point q0, q1, r; + uint8_t u_le[32]; + + if (hash_to_field(domain_prefix, msg, msg_len, u) != 0) { + return -1; + } + + bn_write_le(&u[0], u_le); + if (pallas_map_to_curve_simple_swu(u_le, &q0) != 0) { + memzero(u, sizeof(u)); + memzero(u_le, sizeof(u_le)); + return -1; + } + + bn_write_le(&u[1], u_le); + if (pallas_map_to_curve_simple_swu(u_le, &q1) != 0) { + memzero(u, sizeof(u)); + memzero(u_le, sizeof(u_le)); + memzero(&q0, sizeof(q0)); + return -1; + } + + iso_add(&q0, &q1, &r); + int ret = pallas_iso_map_to_pallas(&r, out); + + memzero(u, sizeof(u)); + memzero(u_le, sizeof(u_le)); + memzero(&q0, sizeof(q0)); + memzero(&q1, sizeof(q1)); + memzero(&r, sizeof(r)); + return ret; +} + +int pallas_group_hash(const char *domain_prefix, const uint8_t *msg, + size_t msg_len, curve_point *out) { + return pallas_hash_to_curve(domain_prefix, msg, msg_len, out); +} diff --git a/deps/crypto/trezor-crypto/pallas_swu.h b/deps/crypto/trezor-crypto/pallas_swu.h new file mode 100644 index 000000000..eff414ee2 --- /dev/null +++ b/deps/crypto/trezor-crypto/pallas_swu.h @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2026 KeepKey + * + * Pallas hash-to-curve primitives for Zcash Orchard. + */ + +#ifndef __PALLAS_SWU_H__ +#define __PALLAS_SWU_H__ + +#include +#include + +#include "bignum.h" +#include "ecdsa.h" + +typedef struct { + bignum256 x; + bignum256 y; + bignum256 z; +} pallas_jacobian_point; + +/* + * Map a Pallas base-field element to the iso-Pallas curve using the + * simplified SWU map used by pasta_curves. + */ +int pallas_map_to_curve_simple_swu(const uint8_t u_le[32], + pallas_jacobian_point *out); + +/* Apply the degree-3 isogeny from iso-Pallas to Pallas. */ +int pallas_iso_map_to_pallas(const pallas_jacobian_point *iso, + curve_point *out); + +/* Hash to Pallas using domain_prefix as in pasta_curves::Point::hash_to_curve. */ +int pallas_hash_to_curve(const char *domain_prefix, const uint8_t *msg, + size_t msg_len, curve_point *out); + +/* Alias for protocol GroupHash^Pallas call sites. */ +int pallas_group_hash(const char *domain_prefix, const uint8_t *msg, + size_t msg_len, curve_point *out); + +#endif diff --git a/deps/crypto/trezor-crypto/pbkdf2.c b/deps/crypto/trezor-crypto/pbkdf2.c new file mode 100644 index 000000000..d9e142297 --- /dev/null +++ b/deps/crypto/trezor-crypto/pbkdf2.c @@ -0,0 +1,179 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "pbkdf2.h" +#include +#include "hmac.h" +#include "memzero.h" +#include "sha2.h" + +void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass, + int passlen, const uint8_t *salt, int saltlen, + uint32_t blocknr) { + SHA256_CTX ctx = {0}; +#if BYTE_ORDER == LITTLE_ENDIAN + REVERSE32(blocknr, blocknr); +#endif + + hmac_sha256_prepare(pass, passlen, pctx->odig, pctx->idig); + memzero(pctx->g, sizeof(pctx->g)); + pctx->g[8] = 0x80000000; + pctx->g[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8; + + memcpy(ctx.state, pctx->idig, sizeof(pctx->idig)); + ctx.bitcount = SHA256_BLOCK_LENGTH * 8; + sha256_Update(&ctx, salt, saltlen); + sha256_Update(&ctx, (uint8_t *)&blocknr, sizeof(blocknr)); + sha256_Final(&ctx, (uint8_t *)pctx->g); +#if BYTE_ORDER == LITTLE_ENDIAN + for (uint32_t k = 0; k < SHA256_DIGEST_LENGTH / sizeof(uint32_t); k++) { + REVERSE32(pctx->g[k], pctx->g[k]); + } +#endif + sha256_Transform(pctx->odig, pctx->g, pctx->g); + memcpy(pctx->f, pctx->g, SHA256_DIGEST_LENGTH); + pctx->first = 1; +} + +void pbkdf2_hmac_sha256_Update(PBKDF2_HMAC_SHA256_CTX *pctx, + uint32_t iterations) { + for (uint32_t i = pctx->first; i < iterations; i++) { + sha256_Transform(pctx->idig, pctx->g, pctx->g); + sha256_Transform(pctx->odig, pctx->g, pctx->g); + for (uint32_t j = 0; j < SHA256_DIGEST_LENGTH / sizeof(uint32_t); j++) { + pctx->f[j] ^= pctx->g[j]; + } + } + pctx->first = 0; +} + +void pbkdf2_hmac_sha256_Final(PBKDF2_HMAC_SHA256_CTX *pctx, uint8_t *key) { +#if BYTE_ORDER == LITTLE_ENDIAN + for (uint32_t k = 0; k < SHA256_DIGEST_LENGTH / sizeof(uint32_t); k++) { + REVERSE32(pctx->f[k], pctx->f[k]); + } +#endif + memcpy(key, pctx->f, SHA256_DIGEST_LENGTH); + memzero(pctx, sizeof(PBKDF2_HMAC_SHA256_CTX)); +} + +void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, const uint8_t *salt, + int saltlen, uint32_t iterations, uint8_t *key, + int keylen) { + uint32_t last_block_size = keylen % SHA256_DIGEST_LENGTH; + uint32_t blocks_count = keylen / SHA256_DIGEST_LENGTH; + if (last_block_size) { + blocks_count++; + } else { + last_block_size = SHA256_DIGEST_LENGTH; + } + for (uint32_t blocknr = 1; blocknr <= blocks_count; blocknr++) { + PBKDF2_HMAC_SHA256_CTX pctx = {0}; + pbkdf2_hmac_sha256_Init(&pctx, pass, passlen, salt, saltlen, blocknr); + pbkdf2_hmac_sha256_Update(&pctx, iterations); + uint8_t digest[SHA256_DIGEST_LENGTH] = {0}; + pbkdf2_hmac_sha256_Final(&pctx, digest); + uint32_t key_offset = (blocknr - 1) * SHA256_DIGEST_LENGTH; + if (blocknr < blocks_count) { + memcpy(key + key_offset, digest, SHA256_DIGEST_LENGTH); + } else { + memcpy(key + key_offset, digest, last_block_size); + } + } +} + +void pbkdf2_hmac_sha512_Init(PBKDF2_HMAC_SHA512_CTX *pctx, const uint8_t *pass, + int passlen, const uint8_t *salt, int saltlen, + uint32_t blocknr) { + SHA512_CTX ctx = {0}; +#if BYTE_ORDER == LITTLE_ENDIAN + REVERSE32(blocknr, blocknr); +#endif + + hmac_sha512_prepare(pass, passlen, pctx->odig, pctx->idig); + memzero(pctx->g, sizeof(pctx->g)); + pctx->g[8] = 0x8000000000000000; + pctx->g[15] = (SHA512_BLOCK_LENGTH + SHA512_DIGEST_LENGTH) * 8; + + memcpy(ctx.state, pctx->idig, sizeof(pctx->idig)); + ctx.bitcount[0] = SHA512_BLOCK_LENGTH * 8; + ctx.bitcount[1] = 0; + sha512_Update(&ctx, salt, saltlen); + sha512_Update(&ctx, (uint8_t *)&blocknr, sizeof(blocknr)); + sha512_Final(&ctx, (uint8_t *)pctx->g); +#if BYTE_ORDER == LITTLE_ENDIAN + for (uint32_t k = 0; k < SHA512_DIGEST_LENGTH / sizeof(uint64_t); k++) { + REVERSE64(pctx->g[k], pctx->g[k]); + } +#endif + sha512_Transform(pctx->odig, pctx->g, pctx->g); + memcpy(pctx->f, pctx->g, SHA512_DIGEST_LENGTH); + pctx->first = 1; +} + +void pbkdf2_hmac_sha512_Update(PBKDF2_HMAC_SHA512_CTX *pctx, + uint32_t iterations) { + for (uint32_t i = pctx->first; i < iterations; i++) { + sha512_Transform(pctx->idig, pctx->g, pctx->g); + sha512_Transform(pctx->odig, pctx->g, pctx->g); + for (uint32_t j = 0; j < SHA512_DIGEST_LENGTH / sizeof(uint64_t); j++) { + pctx->f[j] ^= pctx->g[j]; + } + } + pctx->first = 0; +} + +void pbkdf2_hmac_sha512_Final(PBKDF2_HMAC_SHA512_CTX *pctx, uint8_t *key) { +#if BYTE_ORDER == LITTLE_ENDIAN + for (uint32_t k = 0; k < SHA512_DIGEST_LENGTH / sizeof(uint64_t); k++) { + REVERSE64(pctx->f[k], pctx->f[k]); + } +#endif + memcpy(key, pctx->f, SHA512_DIGEST_LENGTH); + memzero(pctx, sizeof(PBKDF2_HMAC_SHA512_CTX)); +} + +void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, const uint8_t *salt, + int saltlen, uint32_t iterations, uint8_t *key, + int keylen) { + uint32_t last_block_size = keylen % SHA512_DIGEST_LENGTH; + uint32_t blocks_count = keylen / SHA512_DIGEST_LENGTH; + if (last_block_size) { + blocks_count++; + } else { + last_block_size = SHA512_DIGEST_LENGTH; + } + for (uint32_t blocknr = 1; blocknr <= blocks_count; blocknr++) { + PBKDF2_HMAC_SHA512_CTX pctx = {0}; + pbkdf2_hmac_sha512_Init(&pctx, pass, passlen, salt, saltlen, blocknr); + pbkdf2_hmac_sha512_Update(&pctx, iterations); + uint8_t digest[SHA512_DIGEST_LENGTH] = {0}; + pbkdf2_hmac_sha512_Final(&pctx, digest); + uint32_t key_offset = (blocknr - 1) * SHA512_DIGEST_LENGTH; + if (blocknr < blocks_count) { + memcpy(key + key_offset, digest, SHA512_DIGEST_LENGTH); + } else { + memcpy(key + key_offset, digest, last_block_size); + } + } +} diff --git a/deps/crypto/trezor-crypto/pbkdf2.h b/deps/crypto/trezor-crypto/pbkdf2.h new file mode 100644 index 000000000..c2e3f04a6 --- /dev/null +++ b/deps/crypto/trezor-crypto/pbkdf2.h @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __PBKDF2_H__ +#define __PBKDF2_H__ + +#include +#include "sha2.h" + +typedef struct _PBKDF2_HMAC_SHA256_CTX { + uint32_t odig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; + uint32_t idig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; + uint32_t f[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; + uint32_t g[SHA256_BLOCK_LENGTH / sizeof(uint32_t)]; + char first; +} PBKDF2_HMAC_SHA256_CTX; + +typedef struct _PBKDF2_HMAC_SHA512_CTX { + uint64_t odig[SHA512_DIGEST_LENGTH / sizeof(uint64_t)]; + uint64_t idig[SHA512_DIGEST_LENGTH / sizeof(uint64_t)]; + uint64_t f[SHA512_DIGEST_LENGTH / sizeof(uint64_t)]; + uint64_t g[SHA512_BLOCK_LENGTH / sizeof(uint64_t)]; + char first; +} PBKDF2_HMAC_SHA512_CTX; + +void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass, + int passlen, const uint8_t *salt, int saltlen, + uint32_t blocknr); +void pbkdf2_hmac_sha256_Update(PBKDF2_HMAC_SHA256_CTX *pctx, + uint32_t iterations); +void pbkdf2_hmac_sha256_Final(PBKDF2_HMAC_SHA256_CTX *pctx, uint8_t *key); +void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, const uint8_t *salt, + int saltlen, uint32_t iterations, uint8_t *key, + int keylen); + +void pbkdf2_hmac_sha512_Init(PBKDF2_HMAC_SHA512_CTX *pctx, const uint8_t *pass, + int passlen, const uint8_t *salt, int saltlen, + uint32_t blocknr); +void pbkdf2_hmac_sha512_Update(PBKDF2_HMAC_SHA512_CTX *pctx, + uint32_t iterations); +void pbkdf2_hmac_sha512_Final(PBKDF2_HMAC_SHA512_CTX *pctx, uint8_t *key); +void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, const uint8_t *salt, + int saltlen, uint32_t iterations, uint8_t *key, + int keylen); + +#endif diff --git a/deps/crypto/trezor-crypto/rand.c b/deps/crypto/trezor-crypto/rand.c new file mode 100644 index 000000000..ea95d143b --- /dev/null +++ b/deps/crypto/trezor-crypto/rand.c @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "rand.h" + +#ifndef RAND_PLATFORM_INDEPENDENT + +#pragma message( \ + "NOT SUITABLE FOR PRODUCTION USE! Replace random32() function with your own secure code.") + +// The following code is not supposed to be used in a production environment. +// It's included only to make the library testable. +// The message above tries to prevent any accidental use outside of the test +// environment. +// +// You are supposed to replace the random8() and random32() function with your +// own secure code. There is also a possibility to replace the random_buffer() +// function as it is defined as a weak symbol. + +static uint32_t seed = 0; + +void random_reseed(const uint32_t value) { seed = value; } + +uint32_t random32(void) { + // Linear congruential generator from Numerical Recipes + // https://en.wikipedia.org/wiki/Linear_congruential_generator + seed = 1664525 * seed + 1013904223; + return seed; +} + +#endif /* RAND_PLATFORM_INDEPENDENT */ + +// +// The following code is platform independent +// + +void __attribute__((weak)) random_buffer(uint8_t *buf, size_t len) { + uint32_t r = 0; + for (size_t i = 0; i < len; i++) { + if (i % 4 == 0) { + r = random32(); + } + buf[i] = (r >> ((i % 4) * 8)) & 0xFF; + } +} + +uint32_t random_uniform(uint32_t n) { + uint32_t x = 0, max = 0xFFFFFFFF - (0xFFFFFFFF % n); + while ((x = random32()) >= max) + ; + return x / (max / n); +} + +void random_permute(char *str, size_t len) { + for (int i = len - 1; i >= 1; i--) { + int j = random_uniform(i + 1); + char t = str[j]; + str[j] = str[i]; + str[i] = t; + } +} diff --git a/deps/crypto/trezor-crypto/rand.h b/deps/crypto/trezor-crypto/rand.h new file mode 100644 index 000000000..49d9cfaf2 --- /dev/null +++ b/deps/crypto/trezor-crypto/rand.h @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __RAND_H__ +#define __RAND_H__ + +#include +#include + +void random_reseed(const uint32_t value); +uint32_t random32(void); +void random_buffer(uint8_t *buf, size_t len); + +uint32_t random_uniform(uint32_t n); +void random_permute(char *buf, size_t len); + +#endif diff --git a/deps/crypto/trezor-crypto/rc4.c b/deps/crypto/trezor-crypto/rc4.c new file mode 100644 index 000000000..fea73cab1 --- /dev/null +++ b/deps/crypto/trezor-crypto/rc4.c @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, E1PRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "rc4.h" + +static inline void rc4_swap(RC4_CTX *ctx, uint8_t i, uint8_t j) { + uint8_t temp = ctx->S[i]; + ctx->S[i] = ctx->S[j]; + ctx->S[j] = temp; +} + +void rc4_init(RC4_CTX *ctx, const uint8_t *key, size_t length) { + ctx->i = 0; + ctx->j = 0; + + for (size_t i = 0; i < 256; i++) { + ctx->S[i] = i; + } + + uint8_t j = 0; + for (size_t i = 0; i < 256; i++) { + j += ctx->S[i] + key[i % length]; + rc4_swap(ctx, i, j); + } +} + +void rc4_encrypt(RC4_CTX *ctx, uint8_t *buffer, size_t length) { + for (size_t idx = 0; idx < length; idx++) { + ctx->i++; + ctx->j += ctx->S[ctx->i]; + + rc4_swap(ctx, ctx->i, ctx->j); + + uint8_t K = ctx->S[(ctx->S[ctx->i] + ctx->S[ctx->j]) % 256]; + buffer[idx] ^= K; + } +} diff --git a/deps/crypto/trezor-crypto/rc4.h b/deps/crypto/trezor-crypto/rc4.h new file mode 100644 index 000000000..8ba8a9b25 --- /dev/null +++ b/deps/crypto/trezor-crypto/rc4.h @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __RC4_H__ +#define __RC4_H__ + +#include +#include + +typedef struct { + uint8_t S[256]; + uint8_t i, j; +} RC4_CTX; + +void rc4_init(RC4_CTX *ctx, const uint8_t *key, size_t length); +void rc4_encrypt(RC4_CTX *ctx, uint8_t *buffer, size_t length); + +#endif diff --git a/deps/crypto/trezor-crypto/redpallas.c b/deps/crypto/trezor-crypto/redpallas.c new file mode 100644 index 000000000..6694c6f14 --- /dev/null +++ b/deps/crypto/trezor-crypto/redpallas.c @@ -0,0 +1,357 @@ +/** + * Copyright (c) 2025 KeepKey + * + * RedPallas (re-randomized Schnorr) signature scheme for Zcash Orchard. + * + * IMPORTANT: All modular arithmetic uses pallas_mul_mod_p/q etc. from pallas.c. + * The generic bn_multiply/bn_mod/bn_sqrt from bignum.c MUST NOT be used + * because they assume primes in [2^256 - 2^224, 2^256], while the Pallas + * prime is only ~2^254. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "redpallas.h" + +#include + +#include "bignum.h" +#include "blake2b.h" +#include "ecdsa.h" +#include "memzero.h" +#include "pallas.h" +#include "rand.h" + +/* + * Zcash Orchard SpendAuth basepoint. + * + * This is NOT the standard Pallas generator G = (-1 mod p, 2). + * It is the hash-derived basepoint: GroupHash^P("z.cash:Orchard", "G") + * as specified in ZIP-224 / the reddsa crate. + * + * Serialized as compressed Pallas point (LE x-coordinate, sign bit in MSB). + * Source: reddsa-0.5.1 ORCHARD_SPENDAUTHSIG_BASEPOINT_BYTES constant. + */ +static const uint8_t pallas_spendauth_G_bytes[32] = { + 0x63, 0xc9, 0x75, 0xb8, 0x84, 0x72, 0x1a, 0x8d, + 0x0c, 0xa1, 0x70, 0x7b, 0xe3, 0x0c, 0x7f, 0x0c, + 0x5f, 0x44, 0x5f, 0x3e, 0x7c, 0x18, 0x8d, 0x3b, + 0x06, 0xd6, 0xf1, 0x28, 0xb3, 0x23, 0x55, 0xb7, +}; + +/* Cached SpendAuth basepoint (lazy-initialized from compressed bytes) */ +static curve_point spendauth_G_cache; +static int spendauth_G_initialized = 0; + +/* + * Pallas point serialization (Pasta encoding): + * 32 bytes, little-endian x-coordinate, with the sign of y encoded + * in the most significant bit of the last byte. + * + * sign(y) = y is odd (bit 0 of y) + */ + +static void pallas_point_serialize(const curve_point *p, uint8_t out[32]) { + bignum256 x_copy; + bn_copy(&p->x, &x_copy); + bn_write_le(&x_copy, out); + if (bn_is_odd(&p->y)) { + out[31] |= 0x80; + } +} + +static int pallas_point_deserialize(const uint8_t in[32], curve_point *p) { + uint8_t buf[32]; + memcpy(buf, in, 32); + /* Extract sign bit */ + int y_odd = (buf[31] >> 7) & 1; + buf[31] &= 0x7f; + + /* Read x-coordinate (little-endian) */ + bn_read_le(buf, &p->x); + + /* Check x < prime */ + if (!bn_is_less(&p->x, &pallas_prime)) { + return -1; + } + + /* Compute y^2 = x^3 + 5 mod p using custom Pallas arithmetic */ + bignum256 y2; + bn_copy(&p->x, &y2); + pallas_mul_mod_p(&y2, &p->x); /* y2 = x^2 */ + pallas_mul_mod_p(&y2, &p->x); /* y2 = x^3 */ + bignum256 b; + bn_zero(&b); + b.val[0] = 5; + pallas_add_mod_p(&y2, &b, &y2); /* y2 = x^3 + 5 mod p */ + + /* Compute y = sqrt(y2) mod p using Tonelli-Shanks */ + bn_copy(&y2, &p->y); + if (pallas_sqrt_mod_p(&p->y) != 0) { + return -1; /* Not a valid point (y2 is not a QR) */ + } + + /* Verify sqrt is correct: check y^2 == y2 */ + bignum256 check; + bn_copy(&p->y, &check); + pallas_mul_mod_p(&check, &p->y); /* check = y^2 */ + + /* Normalize both for comparison */ + bn_normalize(&check); + bn_normalize(&y2); + if (!bn_is_equal(&check, &y2)) { + return -1; /* Not a valid point */ + } + + /* Fix sign of y */ + if (bn_is_odd(&p->y) != y_odd) { + /* y = p - y */ + pallas_sub_mod_p(&pallas_prime, &p->y, &p->y); + } + + return 0; +} + +/* + * Scalar multiplication by the SpendAuth basepoint. + * Uses lazy initialization: decompresses the basepoint once, then caches it. + * + * res = k * G_spendauth + */ +static void pallas_scalar_mult_spendauth(const bignum256 *k, curve_point *res) { + if (!spendauth_G_initialized) { + pallas_point_deserialize(pallas_spendauth_G_bytes, &spendauth_G_cache); + spendauth_G_initialized = 1; + } + if (bn_is_zero(k)) { + bn_zero(&res->x); + bn_zero(&res->y); + return; + } + pallas_point_mult(k, &spendauth_G_cache, res); +} + +/* + * Public API: Scalar multiplication by SpendAuth basepoint. + * For use by FVK export (ak = [ask]*G_spendauth). + */ +void redpallas_scalar_mult_spendauth_G(const bignum256 *k, curve_point *res) { + pallas_scalar_mult_spendauth(k, res); +} + +/* + * Constant: 2^256 mod q (Pallas scalar field order). + * + * q = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001 + * 2^256 mod q = 2^254 - 3*(q - 2^254) + * = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF992C350BE34205675B2B3E9CFFFFFFFD + * + * Stored as 32 bytes little-endian. + * Source: pasta_curves Montgomery radix R for the Pallas scalar field (Fq). + * Verified: R + 3*q == 2^256. + */ +static const uint8_t two_256_mod_q[32] = { + 0xfd, 0xff, 0xff, 0xff, 0x9c, 0x3e, 0x2b, 0x5b, + 0x67, 0x05, 0x42, 0xe3, 0x0b, 0x35, 0x2c, 0x99, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, +}; + +/* + * Wide reduction: reduce a 512-bit LE value mod Pallas scalar order q. + * + * Matches the orchard crate's pallas::Scalar::from_uniform_bytes(): + * result = (lo + hi * 2^256) mod q + * + * where lo = input[0..31] and hi = input[32..63], both little-endian. + * + * This MUST be used instead of simple truncation (taking low 256 bits) + * because the orchard crate verifies against from_uniform_bytes — the + * values differ whenever hi != 0, which is ~100% of the time. + */ +static void pallas_from_uniform_bytes(const uint8_t input[64], bignum256 *out) { + bignum256 lo, hi, t256; + + bn_read_le(input, &lo); + pallas_mod_q(&lo); + + bn_read_le(input + 32, &hi); + pallas_mod_q(&hi); + + bn_read_le(two_256_mod_q, &t256); + + /* out = hi * (2^256 mod q) mod q */ + bn_copy(&hi, out); + pallas_mul_mod_q(out, &t256); + + /* out = out + lo mod q */ + pallas_add_mod_q(out, &lo); + + memzero(&lo, sizeof(lo)); + memzero(&hi, sizeof(hi)); +} + +/* + * RedPallas challenge hash: + * H = BLAKE2b-512("Zcash_RedPallasH", R_bytes || rk_bytes || sighash) + * Reduced to a scalar mod order using wide reduction (from_uniform_bytes). + */ +static void redpallas_hash_challenge(const uint8_t R_bytes[32], + const uint8_t rk_bytes[32], + const uint8_t sighash[32], + bignum256 *c) { + uint8_t hash_out[64]; + BLAKE2B_CTX ctx; + + blake2b_InitPersonal(&ctx, 64, "Zcash_RedPallasH", 16); + blake2b_Update(&ctx, R_bytes, 32); + blake2b_Update(&ctx, rk_bytes, 32); + blake2b_Update(&ctx, sighash, 32); + blake2b_Final(&ctx, hash_out, 64); + + /* Wide reduction matching orchard crate's from_uniform_bytes */ + pallas_from_uniform_bytes(hash_out, c); + + memzero(hash_out, sizeof(hash_out)); +} + +int redpallas_sign_digest(const uint8_t *ask, const uint8_t *alpha, + const uint8_t *sighash, uint8_t *sig_out) { + bignum256 ask_scalar, alpha_scalar, rsk, r, c, s; + curve_point R_point, rk_point; + uint8_t R_bytes[32], rk_bytes[32]; + + /* Read scalars (little-endian, as used by Zcash) */ + bn_read_le(ask, &ask_scalar); + bn_read_le(alpha, &alpha_scalar); + + /* rsk = (ask + alpha) mod order */ + bn_copy(&ask_scalar, &rsk); + pallas_add_mod_q(&rsk, &alpha_scalar); + + /* rk = [rsk]G_spendauth - randomized verification key */ + pallas_scalar_mult_spendauth(&rsk, &rk_point); + pallas_point_serialize(&rk_point, rk_bytes); + + /* Generate random nonce r */ + uint8_t rbuf[32]; + random_buffer(rbuf, 32); + bn_read_le(rbuf, &r); + pallas_mod_q(&r); + + /* Ensure r is not zero */ + if (bn_is_zero(&r)) { + r.val[0] = 1; + } + + /* R = [r]G_spendauth - nonce commitment */ + pallas_scalar_mult_spendauth(&r, &R_point); + pallas_point_serialize(&R_point, R_bytes); + + /* c = H("Zcash_RedPallasH", R || rk || sighash) mod order */ + redpallas_hash_challenge(R_bytes, rk_bytes, sighash, &c); + + /* S = r + c * rsk (mod order) */ + pallas_mul_mod_q(&c, &rsk); /* c = c * rsk mod order */ + bn_copy(&r, &s); + pallas_add_mod_q(&s, &c); /* s = r + c*rsk mod order */ + + /* Output: R (32 bytes LE) || S (32 bytes LE) */ + memcpy(sig_out, R_bytes, 32); + bn_write_le(&s, sig_out + 32); + + /* Clean up sensitive data */ + memzero(&ask_scalar, sizeof(ask_scalar)); + memzero(&alpha_scalar, sizeof(alpha_scalar)); + memzero(&rsk, sizeof(rsk)); + memzero(&r, sizeof(r)); + memzero(&s, sizeof(s)); + memzero(rbuf, sizeof(rbuf)); + + return 0; +} + +int redpallas_verify_digest(const uint8_t *rk, const uint8_t *sighash, + const uint8_t *sig) { + bignum256 c, s; + curve_point R_point, rk_point, lhs, rhs, cR; + + /* Deserialize R from signature */ + if (pallas_point_deserialize(sig, &R_point) != 0) { + return -1; + } + + /* Read S from signature */ + bn_read_le(sig + 32, &s); + if (!bn_is_less(&s, &pallas_order)) { + return -2; + } + + /* Deserialize rk */ + if (pallas_point_deserialize(rk, &rk_point) != 0) { + return -3; + } + + /* Recompute challenge: c = H("Zcash_RedPallasH", R || rk || sighash) */ + uint8_t R_bytes[32]; + pallas_point_serialize(&R_point, R_bytes); + redpallas_hash_challenge(R_bytes, rk, sighash, &c); + + /* Verify: [S]G_spendauth == R + [c]rk */ + /* LHS: [S]G_spendauth */ + pallas_scalar_mult_spendauth(&s, &lhs); + + /* RHS: [c]rk + R */ + pallas_point_mult(&c, &rk_point, &cR); + pallas_point_add(&cR, &R_point, &rhs); + + /* Compare (both should be normalized from our custom operations) */ + bn_normalize(&lhs.x); + bn_normalize(&lhs.y); + bn_normalize(&rhs.x); + bn_normalize(&rhs.y); + if (!bn_is_equal(&lhs.x, &rhs.x) || !bn_is_equal(&lhs.y, &rhs.y)) { + return -4; + } + + return 0; +} + +int redpallas_derive_rk(const uint8_t *ask, const uint8_t *alpha, + uint8_t *rk_out) { + bignum256 ask_scalar, alpha_scalar, rsk; + curve_point rk_point; + + bn_read_le(ask, &ask_scalar); + bn_read_le(alpha, &alpha_scalar); + + /* rsk = (ask + alpha) mod order */ + bn_copy(&ask_scalar, &rsk); + pallas_add_mod_q(&rsk, &alpha_scalar); + + /* rk = [rsk]G_spendauth */ + pallas_scalar_mult_spendauth(&rsk, &rk_point); + pallas_point_serialize(&rk_point, rk_out); + + memzero(&ask_scalar, sizeof(ask_scalar)); + memzero(&alpha_scalar, sizeof(alpha_scalar)); + memzero(&rsk, sizeof(rsk)); + + return 0; +} diff --git a/deps/crypto/trezor-crypto/redpallas.h b/deps/crypto/trezor-crypto/redpallas.h new file mode 100644 index 000000000..a16e7a3eb --- /dev/null +++ b/deps/crypto/trezor-crypto/redpallas.h @@ -0,0 +1,85 @@ +/** + * Copyright (c) 2025 KeepKey + * + * RedPallas (re-randomized Schnorr) signature scheme for Zcash Orchard. + * Used for spend authorization signatures in the Orchard shielded protocol. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __REDPALLAS_H__ +#define __REDPALLAS_H__ + +#include +#include "bignum.h" +#include "ecdsa.h" + +/** + * RedPallas spend authorization signature. + * + * Computes a re-randomized Schnorr signature over the Pallas curve: + * rsk = ask + alpha (mod order) -- randomized signing key + * rk = [rsk]G -- randomized verification key + * r = random_scalar() -- nonce + * R = [r]G -- nonce commitment + * c = H("Zcash_RedPallasH", R || rk || sighash) -- challenge (mod order) + * S = r + c * rsk (mod order) -- response + * sig = R || S (64 bytes) + * + * @param ask 32-byte spend authorizing key (little-endian scalar) + * @param alpha 32-byte randomizer from PCZT (little-endian scalar) + * @param sighash 32-byte transaction sighash (ZIP 244) + * @param sig_out 64-byte output: R (32 bytes) || S (32 bytes), little-endian + * @return 0 on success, non-zero on error + */ +int redpallas_sign_digest(const uint8_t *ask, const uint8_t *alpha, + const uint8_t *sighash, uint8_t *sig_out); + +/** + * Verify a RedPallas signature. + * + * @param rk 32-byte randomized verification key (compressed point, LE) + * @param sighash 32-byte transaction sighash + * @param sig 64-byte signature: R (32 bytes) || S (32 bytes) + * @return 0 if signature is valid, non-zero otherwise + */ +int redpallas_verify_digest(const uint8_t *rk, const uint8_t *sighash, + const uint8_t *sig); + +/** + * Derive randomized verification key: rk = [(ask + alpha) mod order] * G + * + * @param ask 32-byte spend authorizing key (little-endian) + * @param alpha 32-byte randomizer (little-endian) + * @param rk_out 32-byte output: compressed point (little-endian x-coordinate) + * @return 0 on success + */ +int redpallas_derive_rk(const uint8_t *ask, const uint8_t *alpha, + uint8_t *rk_out); + +/** + * Scalar multiplication by the Orchard SpendAuth basepoint. + * Computes res = k * G_spendauth where G_spendauth = GroupHash^P("z.cash:Orchard", "G"). + * + * @param k Scalar to multiply (bignum256) + * @param res Output point + */ +void redpallas_scalar_mult_spendauth_G(const bignum256 *k, curve_point *res); + +#endif diff --git a/deps/crypto/trezor-crypto/rfc6979.c b/deps/crypto/trezor-crypto/rfc6979.c new file mode 100644 index 000000000..96f4dfcbf --- /dev/null +++ b/deps/crypto/trezor-crypto/rfc6979.c @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * Copyright (c) 2015 Jochen Hoenicke + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#include + +#include "hmac_drbg.h" +#include "memzero.h" +#include "rfc6979.h" + +void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, + const ecdsa_curve *curve, rfc6979_state *state) { + if (curve) { + bignum256 hash_bn = {0}; + bn_read_be(hash, &hash_bn); + + // Make sure hash is partly reduced modulo order + assert(bn_bitcount(&curve->order) >= 256); + bn_mod(&hash_bn, &curve->order); + + uint8_t hash_reduced[32] = {0}; + bn_write_be(&hash_bn, hash_reduced); + memzero(&hash_bn, sizeof(hash_bn)); + hmac_drbg_init(state, priv_key, 32, hash_reduced, 32); + memzero(hash_reduced, sizeof(hash_reduced)); + } else { + hmac_drbg_init(state, priv_key, 32, hash, 32); + } +} + +// generate next number from deterministic random number generator +void generate_rfc6979(uint8_t rnd[32], rfc6979_state *state) { + hmac_drbg_generate(state, rnd, 32); +} + +// generate K in a deterministic way, according to RFC6979 +// http://tools.ietf.org/html/rfc6979 +void generate_k_rfc6979(bignum256 *k, rfc6979_state *state) { + uint8_t buf[32] = {0}; + generate_rfc6979(buf, state); + bn_read_be(buf, k); + memzero(buf, sizeof(buf)); +} diff --git a/deps/crypto/trezor-crypto/rfc6979.h b/deps/crypto/trezor-crypto/rfc6979.h new file mode 100644 index 000000000..e4cb9ff04 --- /dev/null +++ b/deps/crypto/trezor-crypto/rfc6979.h @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * Copyright (c) 2015-2017 Jochen Hoenicke + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __RFC6979_H__ +#define __RFC6979_H__ + +#include +#include "bignum.h" +#include "ecdsa.h" +#include "hmac_drbg.h" + +// rfc6979 pseudo random number generator state +typedef HMAC_DRBG_CTX rfc6979_state; + +void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, + const ecdsa_curve *curve, rfc6979_state *rng); +void generate_rfc6979(uint8_t rnd[32], rfc6979_state *rng); +void generate_k_rfc6979(bignum256 *k, rfc6979_state *rng); + +#endif diff --git a/deps/crypto/trezor-crypto/ripemd160.c b/deps/crypto/trezor-crypto/ripemd160.c new file mode 100644 index 000000000..5aef8b8d3 --- /dev/null +++ b/deps/crypto/trezor-crypto/ripemd160.c @@ -0,0 +1,343 @@ +/* + * RIPE MD-160 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * The RIPEMD-160 algorithm was designed by RIPE in 1996 + * http://homes.esat.kuleuven.be/~bosselae/ripemd160.html + * http://ehash.iaik.tugraz.at/wiki/RIPEMD-160 + */ + +#include + +#include "ripemd160.h" +#include "memzero.h" + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_UINT32_LE +#define GET_UINT32_LE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] ) \ + | ( (uint32_t) (b)[(i) + 1] << 8 ) \ + | ( (uint32_t) (b)[(i) + 2] << 16 ) \ + | ( (uint32_t) (b)[(i) + 3] << 24 ); \ +} +#endif + +#ifndef PUT_UINT32_LE +#define PUT_UINT32_LE(n,b,i) \ +{ \ + (b)[(i) ] = (uint8_t) ( ( (n) ) & 0xFF ); \ + (b)[(i) + 1] = (uint8_t) ( ( (n) >> 8 ) & 0xFF ); \ + (b)[(i) + 2] = (uint8_t) ( ( (n) >> 16 ) & 0xFF ); \ + (b)[(i) + 3] = (uint8_t) ( ( (n) >> 24 ) & 0xFF ); \ +} +#endif + +/* + * RIPEMD-160 context setup + */ +void ripemd160_Init(RIPEMD160_CTX *ctx) +{ + memzero(ctx, sizeof(RIPEMD160_CTX)); + ctx->total[0] = 0; + ctx->total[1] = 0; + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; +} + +#if !defined(MBEDTLS_RIPEMD160_PROCESS_ALT) +/* + * Process one block + */ +void ripemd160_process( RIPEMD160_CTX *ctx, const uint8_t data[RIPEMD160_BLOCK_LENGTH] ) +{ + uint32_t A = 0, B = 0, C = 0, D = 0, E = 0, Ap = 0, Bp = 0, Cp = 0, Dp = 0, Ep = 0, X[16] = {0}; + + GET_UINT32_LE( X[ 0], data, 0 ); + GET_UINT32_LE( X[ 1], data, 4 ); + GET_UINT32_LE( X[ 2], data, 8 ); + GET_UINT32_LE( X[ 3], data, 12 ); + GET_UINT32_LE( X[ 4], data, 16 ); + GET_UINT32_LE( X[ 5], data, 20 ); + GET_UINT32_LE( X[ 6], data, 24 ); + GET_UINT32_LE( X[ 7], data, 28 ); + GET_UINT32_LE( X[ 8], data, 32 ); + GET_UINT32_LE( X[ 9], data, 36 ); + GET_UINT32_LE( X[10], data, 40 ); + GET_UINT32_LE( X[11], data, 44 ); + GET_UINT32_LE( X[12], data, 48 ); + GET_UINT32_LE( X[13], data, 52 ); + GET_UINT32_LE( X[14], data, 56 ); + GET_UINT32_LE( X[15], data, 60 ); + + A = Ap = ctx->state[0]; + B = Bp = ctx->state[1]; + C = Cp = ctx->state[2]; + D = Dp = ctx->state[3]; + E = Ep = ctx->state[4]; + +#define F1( x, y, z ) ( x ^ y ^ z ) +#define F2( x, y, z ) ( ( x & y ) | ( ~x & z ) ) +#define F3( x, y, z ) ( ( x | ~y ) ^ z ) +#define F4( x, y, z ) ( ( x & z ) | ( y & ~z ) ) +#define F5( x, y, z ) ( x ^ ( y | ~z ) ) + +#define S( x, n ) ( ( x << n ) | ( x >> (32 - n) ) ) + +#define P( a, b, c, d, e, r, s, f, k ) \ + a += f( b, c, d ) + X[r] + k; \ + a = S( a, s ) + e; \ + c = S( c, 10 ); + +#define P2( a, b, c, d, e, r, s, rp, sp ) \ + P( a, b, c, d, e, r, s, F, K ); \ + P( a ## p, b ## p, c ## p, d ## p, e ## p, rp, sp, Fp, Kp ); + +#define F F1 +#define K 0x00000000 +#define Fp F5 +#define Kp 0x50A28BE6 + P2( A, B, C, D, E, 0, 11, 5, 8 ); + P2( E, A, B, C, D, 1, 14, 14, 9 ); + P2( D, E, A, B, C, 2, 15, 7, 9 ); + P2( C, D, E, A, B, 3, 12, 0, 11 ); + P2( B, C, D, E, A, 4, 5, 9, 13 ); + P2( A, B, C, D, E, 5, 8, 2, 15 ); + P2( E, A, B, C, D, 6, 7, 11, 15 ); + P2( D, E, A, B, C, 7, 9, 4, 5 ); + P2( C, D, E, A, B, 8, 11, 13, 7 ); + P2( B, C, D, E, A, 9, 13, 6, 7 ); + P2( A, B, C, D, E, 10, 14, 15, 8 ); + P2( E, A, B, C, D, 11, 15, 8, 11 ); + P2( D, E, A, B, C, 12, 6, 1, 14 ); + P2( C, D, E, A, B, 13, 7, 10, 14 ); + P2( B, C, D, E, A, 14, 9, 3, 12 ); + P2( A, B, C, D, E, 15, 8, 12, 6 ); +#undef F +#undef K +#undef Fp +#undef Kp + +#define F F2 +#define K 0x5A827999 +#define Fp F4 +#define Kp 0x5C4DD124 + P2( E, A, B, C, D, 7, 7, 6, 9 ); + P2( D, E, A, B, C, 4, 6, 11, 13 ); + P2( C, D, E, A, B, 13, 8, 3, 15 ); + P2( B, C, D, E, A, 1, 13, 7, 7 ); + P2( A, B, C, D, E, 10, 11, 0, 12 ); + P2( E, A, B, C, D, 6, 9, 13, 8 ); + P2( D, E, A, B, C, 15, 7, 5, 9 ); + P2( C, D, E, A, B, 3, 15, 10, 11 ); + P2( B, C, D, E, A, 12, 7, 14, 7 ); + P2( A, B, C, D, E, 0, 12, 15, 7 ); + P2( E, A, B, C, D, 9, 15, 8, 12 ); + P2( D, E, A, B, C, 5, 9, 12, 7 ); + P2( C, D, E, A, B, 2, 11, 4, 6 ); + P2( B, C, D, E, A, 14, 7, 9, 15 ); + P2( A, B, C, D, E, 11, 13, 1, 13 ); + P2( E, A, B, C, D, 8, 12, 2, 11 ); +#undef F +#undef K +#undef Fp +#undef Kp + +#define F F3 +#define K 0x6ED9EBA1 +#define Fp F3 +#define Kp 0x6D703EF3 + P2( D, E, A, B, C, 3, 11, 15, 9 ); + P2( C, D, E, A, B, 10, 13, 5, 7 ); + P2( B, C, D, E, A, 14, 6, 1, 15 ); + P2( A, B, C, D, E, 4, 7, 3, 11 ); + P2( E, A, B, C, D, 9, 14, 7, 8 ); + P2( D, E, A, B, C, 15, 9, 14, 6 ); + P2( C, D, E, A, B, 8, 13, 6, 6 ); + P2( B, C, D, E, A, 1, 15, 9, 14 ); + P2( A, B, C, D, E, 2, 14, 11, 12 ); + P2( E, A, B, C, D, 7, 8, 8, 13 ); + P2( D, E, A, B, C, 0, 13, 12, 5 ); + P2( C, D, E, A, B, 6, 6, 2, 14 ); + P2( B, C, D, E, A, 13, 5, 10, 13 ); + P2( A, B, C, D, E, 11, 12, 0, 13 ); + P2( E, A, B, C, D, 5, 7, 4, 7 ); + P2( D, E, A, B, C, 12, 5, 13, 5 ); +#undef F +#undef K +#undef Fp +#undef Kp + +#define F F4 +#define K 0x8F1BBCDC +#define Fp F2 +#define Kp 0x7A6D76E9 + P2( C, D, E, A, B, 1, 11, 8, 15 ); + P2( B, C, D, E, A, 9, 12, 6, 5 ); + P2( A, B, C, D, E, 11, 14, 4, 8 ); + P2( E, A, B, C, D, 10, 15, 1, 11 ); + P2( D, E, A, B, C, 0, 14, 3, 14 ); + P2( C, D, E, A, B, 8, 15, 11, 14 ); + P2( B, C, D, E, A, 12, 9, 15, 6 ); + P2( A, B, C, D, E, 4, 8, 0, 14 ); + P2( E, A, B, C, D, 13, 9, 5, 6 ); + P2( D, E, A, B, C, 3, 14, 12, 9 ); + P2( C, D, E, A, B, 7, 5, 2, 12 ); + P2( B, C, D, E, A, 15, 6, 13, 9 ); + P2( A, B, C, D, E, 14, 8, 9, 12 ); + P2( E, A, B, C, D, 5, 6, 7, 5 ); + P2( D, E, A, B, C, 6, 5, 10, 15 ); + P2( C, D, E, A, B, 2, 12, 14, 8 ); +#undef F +#undef K +#undef Fp +#undef Kp + +#define F F5 +#define K 0xA953FD4E +#define Fp F1 +#define Kp 0x00000000 + P2( B, C, D, E, A, 4, 9, 12, 8 ); + P2( A, B, C, D, E, 0, 15, 15, 5 ); + P2( E, A, B, C, D, 5, 5, 10, 12 ); + P2( D, E, A, B, C, 9, 11, 4, 9 ); + P2( C, D, E, A, B, 7, 6, 1, 12 ); + P2( B, C, D, E, A, 12, 8, 5, 5 ); + P2( A, B, C, D, E, 2, 13, 8, 14 ); + P2( E, A, B, C, D, 10, 12, 7, 6 ); + P2( D, E, A, B, C, 14, 5, 6, 8 ); + P2( C, D, E, A, B, 1, 12, 2, 13 ); + P2( B, C, D, E, A, 3, 13, 13, 6 ); + P2( A, B, C, D, E, 8, 14, 14, 5 ); + P2( E, A, B, C, D, 11, 11, 0, 15 ); + P2( D, E, A, B, C, 6, 8, 3, 13 ); + P2( C, D, E, A, B, 15, 5, 9, 11 ); + P2( B, C, D, E, A, 13, 6, 11, 11 ); +#undef F +#undef K +#undef Fp +#undef Kp + + C = ctx->state[1] + C + Dp; + ctx->state[1] = ctx->state[2] + D + Ep; + ctx->state[2] = ctx->state[3] + E + Ap; + ctx->state[3] = ctx->state[4] + A + Bp; + ctx->state[4] = ctx->state[0] + B + Cp; + ctx->state[0] = C; +} +#endif /* !MBEDTLS_RIPEMD160_PROCESS_ALT */ + +/* + * RIPEMD-160 process buffer + */ +void ripemd160_Update( RIPEMD160_CTX *ctx, const uint8_t *input, uint32_t ilen ) +{ + uint32_t fill = 0; + uint32_t left = 0; + + if( ilen == 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = RIPEMD160_BLOCK_LENGTH - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + ripemd160_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= RIPEMD160_BLOCK_LENGTH ) + { + ripemd160_process( ctx, input ); + input += RIPEMD160_BLOCK_LENGTH; + ilen -= RIPEMD160_BLOCK_LENGTH; + } + + if( ilen > 0 ) + { + memcpy( (void *) (ctx->buffer + left), input, ilen ); + } +} + +static const uint8_t ripemd160_padding[RIPEMD160_BLOCK_LENGTH] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * RIPEMD-160 final digest + */ +void ripemd160_Final( RIPEMD160_CTX *ctx, uint8_t output[RIPEMD160_DIGEST_LENGTH] ) +{ + uint32_t last = 0; uint32_t padn = 0; + uint32_t high = 0; uint32_t low = 0; + uint8_t msglen[8] = {0}; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_LE( low, msglen, 0 ); + PUT_UINT32_LE( high, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + ripemd160_Update( ctx, ripemd160_padding, padn ); + ripemd160_Update( ctx, msglen, 8 ); + + PUT_UINT32_LE( ctx->state[0], output, 0 ); + PUT_UINT32_LE( ctx->state[1], output, 4 ); + PUT_UINT32_LE( ctx->state[2], output, 8 ); + PUT_UINT32_LE( ctx->state[3], output, 12 ); + PUT_UINT32_LE( ctx->state[4], output, 16 ); + + memzero(ctx, sizeof(RIPEMD160_CTX)); +} + +/* + * output = RIPEMD-160( input buffer ) + */ +void ripemd160(const uint8_t *msg, uint32_t msg_len, uint8_t hash[RIPEMD160_DIGEST_LENGTH]) +{ + RIPEMD160_CTX ctx = {0}; + ripemd160_Init( &ctx ); + ripemd160_Update( &ctx, msg, msg_len ); + ripemd160_Final( &ctx, hash ); +} diff --git a/deps/crypto/trezor-crypto/ripemd160.h b/deps/crypto/trezor-crypto/ripemd160.h new file mode 100644 index 000000000..8256b08a1 --- /dev/null +++ b/deps/crypto/trezor-crypto/ripemd160.h @@ -0,0 +1,22 @@ +#ifndef __RIPEMD160_H__ +#define __RIPEMD160_H__ + +#include + +#define RIPEMD160_BLOCK_LENGTH 64 +#define RIPEMD160_DIGEST_LENGTH 20 + +typedef struct _RIPEMD160_CTX { + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[5]; /*!< intermediate digest state */ + uint8_t buffer[RIPEMD160_BLOCK_LENGTH]; /*!< data block being processed */ +} RIPEMD160_CTX; + +void ripemd160_Init(RIPEMD160_CTX *ctx); +void ripemd160_Update(RIPEMD160_CTX *ctx, const uint8_t *input, uint32_t ilen); +void ripemd160_Final(RIPEMD160_CTX *ctx, + uint8_t output[RIPEMD160_DIGEST_LENGTH]); +void ripemd160(const uint8_t *msg, uint32_t msg_len, + uint8_t hash[RIPEMD160_DIGEST_LENGTH]); + +#endif diff --git a/deps/crypto/trezor-crypto/schnorr.c b/deps/crypto/trezor-crypto/schnorr.c new file mode 100644 index 000000000..ac704fba7 --- /dev/null +++ b/deps/crypto/trezor-crypto/schnorr.c @@ -0,0 +1,215 @@ +/** + * Copyright (c) 2021 The Bitcoin ABC developers + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "schnorr.h" +#include "hmac_drbg.h" +#include "memzero.h" +#include "rfc6979.h" + +#include +#include +#include + +static int jacobi(const bignum256 *_n, const bignum256 *_k) { + assert(!bn_is_zero(_k) && bn_is_odd(_k)); + + bignum256 n_copy = {0}; + bignum256 *n = &n_copy; + bn_copy(_n, n); + + bignum256 k_copy = {0}; + bignum256 *k = &k_copy; + bn_copy(_k, k); + + int t = 0; + while (!bn_is_zero(n)) { + while (bn_is_even(n)) { + // jacobi(2 * n, k) = jacobi(n, k) if k = 1 (mod 8) or k = 7 (mod 8) + // jacobi(2 * n, k) = -jacobi(n, k) if k = 3 (mod 8) or k = 5 (mod 8) + uint32_t r = k->val[0] & 0x07; + t ^= (r == 3 || r == 5); + bn_rshift(n); + } + + if (bn_is_less(n, k)) { + // jacobi(n, k) = jacobi(k, n) if k = n = 1 (mod 4) + // jacobi(n, k) = -jacobi(k, n) if k = n = 3 (mod 4) + t ^= ((n->val[0] & k->val[0] & 3) == 3); + bignum256 *temp = n; + n = k; + k = temp; + } + + // jacobi(n, k) = jacobi(n - k, k) + bn_subtract(n, k, n); + } + + int k_is_one = bn_is_one(k); + + // Cleanup + memzero(&n_copy, sizeof(n_copy)); + memzero(&k_copy, sizeof(k_copy)); + + // Map t: [0] => 1, [1] => -1 + t = -2 * t + 1; + + return k_is_one * t; +} + +static int is_non_quad_residue(const bignum256 *n, const bignum256 *prime) { + return jacobi(n, prime) == -1; +} + +static int generate_k_schnorr(const ecdsa_curve *curve, const uint8_t *priv_key, + const uint8_t *hash, bignum256 *k) { + rfc6979_state rng = {0}; + uint8_t hmac_data[SHA256_DIGEST_LENGTH + 16] = {0}; + + /* + * Init the HMAC with additional data specific to Schnorr. This prevents from + * leaking the private key in the case the same message is signed with both + * Schnorr and ECDSA. + */ + memcpy(hmac_data, hash, SHA256_DIGEST_LENGTH); + memcpy(hmac_data + SHA256_DIGEST_LENGTH, "Schnorr+SHA256 ", 16); + hmac_drbg_init(&rng, priv_key, 32, hmac_data, SHA256_DIGEST_LENGTH + 16); + + for (int i = 0; i < 10000; i++) { + generate_k_rfc6979(k, &rng); + // If k is too big or too small, we don't like it + if (bn_is_zero(k) || !bn_is_less(k, &curve->order)) { + continue; + } + + memzero(&rng, sizeof(rng)); + return 0; + } + + memzero(&rng, sizeof(rng)); + return 1; +} + +// e = H(Rx, pub_key, msg_hash) +static void calc_e(const ecdsa_curve *curve, const bignum256 *Rx, + const uint8_t pub_key[33], const uint8_t *msg_hash, + bignum256 *e) { + uint8_t Rxbuf[32] = {0}; + SHA256_CTX ctx = {0}; + uint8_t digest[SHA256_DIGEST_LENGTH] = {0}; + + bn_write_be(Rx, Rxbuf); + + sha256_Init(&ctx); + sha256_Update(&ctx, Rxbuf, sizeof(Rxbuf)); + sha256_Update(&ctx, pub_key, 33); + sha256_Update(&ctx, msg_hash, SHA256_DIGEST_LENGTH); + sha256_Final(&ctx, digest); + + bn_read_be(digest, e); + bn_fast_mod(e, &curve->order); + bn_mod(e, &curve->order); +} + +int schnorr_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, + const uint8_t *digest, uint8_t *sign) { + uint8_t pub_key[33] = {0}; + curve_point R = {0}; + bignum256 e = {0}, s = {0}, k = {0}; + + if (ecdsa_get_public_key33(curve, priv_key, pub_key) != 0) { + return 1; + } + + // Compute k + if (generate_k_schnorr(curve, priv_key, digest, &k) != 0) { + memzero(&k, sizeof(k)); + return 1; + } + + // Compute R = k * G + scalar_multiply(curve, &k, &R); + + // If R.y is not a quadratic residue, negate the nonce + bn_cnegate(is_non_quad_residue(&R.y, &curve->prime), &k, &curve->order); + + bn_write_be(&R.x, sign); + + // Compute e = H(Rx, pub_key, msg_hash) + calc_e(curve, &R.x, pub_key, digest, &e); + + // Compute s = k + e * priv_key + bn_read_be(priv_key, &s); + bn_multiply(&e, &s, &curve->order); + bn_addmod(&s, &k, &curve->order); + memzero(&k, sizeof(k)); + bn_mod(&s, &curve->order); + bn_write_be(&s, sign + 32); + + return 0; +} + +int schnorr_verify_digest(const ecdsa_curve *curve, const uint8_t *pub_key, + const uint8_t *digest, const uint8_t *sign) { + curve_point P = {0}, sG = {0}, R = {0}; + bignum256 r = {0}, s = {0}, e = {0}; + + bn_read_be(sign, &r); + bn_read_be(sign + 32, &s); + + // Signature is invalid if s >= n or r >= p. + if (!bn_is_less(&r, &curve->prime) || !bn_is_less(&s, &curve->order)) { + return 1; + } + + if (!ecdsa_read_pubkey(curve, pub_key, &P)) { + return 2; + } + + // Compute e + calc_e(curve, &r, pub_key, digest, &e); + + if (bn_is_zero(&e)) { + return 3; + } + + // Compute R = sG - eP + bn_subtract(&curve->order, &e, &e); + scalar_multiply(curve, &s, &sG); + point_multiply(curve, &e, &P, &R); + point_add(curve, &sG, &R); + + if (point_is_infinity(&R)) { + return 4; + } + + // Check r == Rx + if (!bn_is_equal(&r, &R.x)) { + return 5; + } + + // Check Ry is a quadratic residue + if (is_non_quad_residue(&R.y, &curve->prime)) { + return 6; + } + + return 0; +} diff --git a/deps/crypto/trezor-crypto/schnorr.h b/deps/crypto/trezor-crypto/schnorr.h new file mode 100644 index 000000000..781452bab --- /dev/null +++ b/deps/crypto/trezor-crypto/schnorr.h @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2021 The Bitcoin ABC developers + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __SCHNORR_H__ +#define __SCHNORR_H__ + +#include "ecdsa.h" + +/* A Schnorr signature is always 64 bytes */ +#define SCHNORR_SIG_LENGTH 64 + +// sign/verify returns 0 if operation succeeded +int schnorr_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, + const uint8_t *digest, uint8_t *result); +int schnorr_verify_digest(const ecdsa_curve *curve, const uint8_t *pub_key, + const uint8_t *msg_hash, const uint8_t *sign); +#endif diff --git a/deps/crypto/trezor-crypto/script.c b/deps/crypto/trezor-crypto/script.c new file mode 100644 index 000000000..cbc71b219 --- /dev/null +++ b/deps/crypto/trezor-crypto/script.c @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2016 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "script.h" +#include +#include "base58.h" + +int script_output_to_address(const uint8_t *script, int scriptlen, char *addr, + int addrsize) { + uint8_t raw[35] = {0}; + + // P2PKH + if (scriptlen == 25 && script[0] == 0x76 && script[1] == 0xA9 && + script[2] == 0x14 && script[23] == 0x88 && script[24] == 0xAC) { + raw[0] = 0x00; + memcpy(raw + 1, script + 3, 20); + return base58_encode_check(raw, 1 + 20, HASHER_SHA2D, addr, addrsize); + } + + // P2SH + if (scriptlen == 23 && script[0] == 0xA9 && script[1] == 0x14 && + script[22] == 0x87) { + raw[0] = 0x05; + memcpy(raw + 1, script + 2, 20); + return base58_encode_check(raw, 1 + 20, HASHER_SHA2D, addr, addrsize); + } + + // P2WPKH + if (scriptlen == 22 && script[0] == 0x00 && script[1] == 0x14) { + raw[0] = 0x06; + raw[1] = 0x00; + raw[2] = 0x00; + memcpy(raw + 3, script + 2, 20); + return base58_encode_check(raw, 3 + 20, HASHER_SHA2D, addr, addrsize); + } + + // P2WSH + if (scriptlen == 34 && script[0] == 0x00 && script[1] == 0x20) { + raw[0] = 0x0A; + raw[1] = 0x00; + raw[2] = 0x00; + memcpy(raw + 3, script + 2, 32); + return base58_encode_check(raw, 3 + 32, HASHER_SHA2D, addr, addrsize); + } + + return 0; +} diff --git a/deps/crypto/trezor-crypto/script.h b/deps/crypto/trezor-crypto/script.h new file mode 100644 index 000000000..c9cc003b8 --- /dev/null +++ b/deps/crypto/trezor-crypto/script.h @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2016 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __SCRIPT_H__ +#define __SCRIPT_H__ + +#include + +int script_output_to_address(const uint8_t *script, int scriptlen, char *addr, + int addrsize); + +#endif diff --git a/deps/crypto/trezor-crypto/secp256k1.c b/deps/crypto/trezor-crypto/secp256k1.c new file mode 100644 index 000000000..34ccaaacb --- /dev/null +++ b/deps/crypto/trezor-crypto/secp256k1.c @@ -0,0 +1,94 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "secp256k1.h" + +const ecdsa_curve secp256k1 = { + /* .prime */ {/*.val =*/{0x1ffffc2f, 0x1ffffff7, 0x1fffffff, 0x1fffffff, + 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, + 0xffffff}}, + + /* G */ + {/*.x =*/{/*.val =*/{0x16f81798, 0x0f940ad8, 0x138a3656, 0x17f9b65b, + 0x10b07029, 0x114ae743, 0x0eb15681, 0x0fdf3b97, + 0x79be66}}, + /*.y =*/{/*.val =*/{0x1b10d4b8, 0x023e847f, 0x01550667, 0x0f68914d, + 0x108a8fd1, 0x1dfe0708, 0x11957693, 0x0ee4d478, + 0x483ada}}}, + + /* order */ + {/*.val =*/{0x10364141, 0x1e92f466, 0x12280eef, 0x1db9cd5e, 0x1fffebaa, + 0x1fffffff, 0x1fffffff, 0x1fffffff, 0xffffff}}, + + /* order_half */ + {/*.val =*/{0x081b20a0, 0x1f497a33, 0x09140777, 0x0edce6af, 0x1ffff5d5, + 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x7fffff}}, + + /* a */ 0, + + /* b */ {/*.val =*/{7}} + +#if USE_PRECOMPUTED_CP + , + /* cp */ + { +#include "secp256k1.table" + } +#endif +}; + +const curve_info secp256k1_info = { + .bip32_name = "Bitcoin seed", + .params = &secp256k1, + .hasher_base58 = HASHER_SHA2D, + .hasher_sign = HASHER_SHA2D, + .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_script = HASHER_SHA2, +}; + +const curve_info secp256k1_decred_info = { + .bip32_name = "Bitcoin seed", + .params = &secp256k1, + .hasher_base58 = HASHER_BLAKED, + .hasher_sign = HASHER_BLAKE, + .hasher_pubkey = HASHER_BLAKE_RIPEMD, + .hasher_script = HASHER_BLAKE, +}; + +const curve_info secp256k1_groestl_info = { + .bip32_name = "Bitcoin seed", + .params = &secp256k1, + .hasher_base58 = HASHER_GROESTLD_TRUNC, + .hasher_sign = HASHER_SHA2, + .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_script = HASHER_SHA2, +}; + +const curve_info secp256k1_smart_info = { + .bip32_name = "Bitcoin seed", + .params = &secp256k1, + .hasher_base58 = HASHER_SHA3K, + .hasher_sign = HASHER_SHA2, + .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_script = HASHER_SHA2, +}; diff --git a/deps/crypto/trezor-crypto/secp256k1.h b/deps/crypto/trezor-crypto/secp256k1.h new file mode 100644 index 000000000..3b45e48fe --- /dev/null +++ b/deps/crypto/trezor-crypto/secp256k1.h @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __SECP256K1_H__ +#define __SECP256K1_H__ + +#include + +#include "bip32.h" +#include "ecdsa.h" + +extern const ecdsa_curve secp256k1; +extern const curve_info secp256k1_info; +extern const curve_info secp256k1_decred_info; +extern const curve_info secp256k1_groestl_info; +extern const curve_info secp256k1_smart_info; + +#endif diff --git a/deps/crypto/trezor-crypto/secp256k1.table b/deps/crypto/trezor-crypto/secp256k1.table new file mode 100644 index 000000000..0fa87a8b1 --- /dev/null +++ b/deps/crypto/trezor-crypto/secp256k1.table @@ -0,0 +1,1664 @@ + { + /* 1*16^0*G: */ + {{{0x16f81798, 0x0f940ad8, 0x138a3656, 0x17f9b65b, 0x10b07029, 0x114ae743, 0x0eb15681, 0x0fdf3b97, 0x79be66}}, + {{0x1b10d4b8, 0x023e847f, 0x01550667, 0x0f68914d, 0x108a8fd1, 0x1dfe0708, 0x11957693, 0x0ee4d478, 0x483ada}}}, + /* 3*16^0*G: */ + {{{0x1ce036f9, 0x100f889d, 0x1be66c21, 0x03908b06, 0x15229b53, 0x07c2fc4e, 0x0c4124d1, 0x00324b18, 0xf9308a}}, + {{0x04b8e672, 0x05cfebac, 0x1088c6db, 0x01533269, 0x1f356650, 0x1bf3151b, 0x00503f8c, 0x01ec65bd, 0x388f7b}}}, + /* 5*16^0*G: */ + {{{0x1240efe4, 0x1d46ab4d, 0x1866adf2, 0x17097bb8, 0x05128e88, 0x1392852e, 0x024d56d2, 0x09a340e4, 0x2f8bde}}, + {{0x06ac62d6, 0x0543e9d5, 0x035a1037, 0x104e3756, 0x1c426f78, 0x14eed364, 0x0f5b536e, 0x04c6dcbc, 0xd8ac22}}}, + /* 7*16^0*G: */ + {{{0x0ac4f9bc, 0x095eef6e, 0x0c38e73a, 0x0336fc06, 0x07a0e3d4, 0x19b2f975, 0x13aa8e63, 0x0c8dcbb6, 0x5cbdf0}}, + {{0x087264da, 0x08413140, 0x1f79ed69, 0x07a17027, 0x054dba81, 0x06b6c30d, 0x05828c5e, 0x081744ab, 0x6aebca}}}, + /* 9*16^0*G: */ + {{{0x1c27ccbe, 0x1af8886f, 0x15f9c530, 0x0f2d2e98, 0x19abde09, 0x0bc54faa, 0x194c26b4, 0x1c5e18fe, 0xacd484}}, + {{0x064f9c37, 0x0e613156, 0x17e383c1, 0x1111486e, 0x161e9add, 0x04b8bb1d, 0x07f590e0, 0x043614fb, 0xcc3389}}}, + /* 11*16^0*G: */ + {{{0x1da008cb, 0x1f60bc4a, 0x105e246e, 0x133017cb, 0x05aac564, 0x1235b863, 0x04797bd0, 0x1f0b1528, 0x774ae7}}, + {{0x0953c61b, 0x00eba64e, 0x1e75aa0c, 0x1b63c5bf, 0x1b365372, 0x0eab6bdb, 0x1864090f, 0x065d6d6b, 0xd984a0}}}, + /* 13*16^0*G: */ + {{{0x19405aa8, 0x176efc78, 0x03963377, 0x0bf78cc2, 0x08651b07, 0x0902e1ba, 0x022f1f47, 0x185b2ea5, 0xf28773}}, + {{0x1b03ed81, 0x0dae5a96, 0x07ea47ca, 0x140db4a4, 0x1af473a1, 0x0975b2e6, 0x0a25d608, 0x05d1b101, 0xab090}}}, + /* 15*16^0*G: */ + {{{0x027e080e, 0x056de7c7, 0x017de791, 0x0b28de79, 0x1f41131e, 0x0d7184af, 0x0a596919, 0x09efa87d, 0xd7924d}}, + {{0x16a26b58, 0x0826e4ff, 0x05b4e971, 0x015e57b1, 0x06defea4, 0x17611466, 0x0a9a0e10, 0x0e550d8e, 0x581e28}}} + }, + { + /* 1*16^1*G: */ + {{{0x0a6dec0a, 0x027744f1, 0x1e96ba71, 0x0626d370, 0x03e97b2a, 0x155e10e1, 0x1b14c046, 0x1276b3d3, 0xe60fce}}, + {{0x09616821, 0x0f996673, 0x148fc2f8, 0x0d123c89, 0x13710129, 0x0f9a7abc, 0x164a76e6, 0x0e733cb2, 0xf7e350}}}, + /* 3*16^1*G: */ + {{{0x1118e5c3, 0x1ec38550, 0x0afaf066, 0x0f364e8a, 0x05b4bfc5, 0x12b77a73, 0x01f6d105, 0x0bb2c8a6, 0x6eca33}}, + {{0x05a08668, 0x0c517bc0, 0x1e3b0d12, 0x12d47477, 0x075a03a4, 0x0bc83a5c, 0x1c4164bd, 0x16af4f40, 0xd50123}}}, + /* 5*16^1*G: */ + {{{0x0f87f62e, 0x16698f0a, 0x1c5849c3, 0x0dcc70c6, 0x059f010e, 0x1a2769a3, 0x03b035f1, 0x17de37f2, 0xe9623b}}, + {{0x044ee737, 0x1809f57d, 0x1a211394, 0x008793ba, 0x0a929fe6, 0x0a9d476d, 0x07a783fa, 0x07697853, 0x38a974}}}, + /* 7*16^1*G: */ + {{{0x0a8d733c, 0x18556fc1, 0x1f2a3e7a, 0x04e97ec5, 0x0d682ffc, 0x11b79040, 0x16e82212, 0x0e7ca2c3, 0xbc82dd}}, + {{0x147797f0, 0x13c30827, 0x0e25cc07, 0x074175ce, 0x102dfae9, 0x1a5fb8cf, 0x12b152a6, 0x07408963, 0xe5f28c}}}, + /* 9*16^1*G: */ + {{{0x1fbc7671, 0x1f7f118a, 0x01638cb5, 0x1e3790a5, 0x0f490743, 0x08e70bcc, 0x0847480a, 0x0918ecae, 0x8e3d12}}, + {{0x18717dec, 0x178ee320, 0x0f85129f, 0x0a57554c, 0x1e90eb93, 0x0070c9c9, 0x0e07d912, 0x1c21d9f9, 0x99a48}}}, + /* 11*16^1*G: */ + {{{0x1eb31db2, 0x1943a195, 0x1d41a83c, 0x15d04f11, 0x0a2b68fc, 0x0c9f6844, 0x126225a8, 0x15444694, 0x78a891}}, + {{0x19fa4343, 0x034eb11d, 0x002e0b4c, 0x0f379bb0, 0x02df6543, 0x192a9398, 0x172ff3d7, 0x0b7d6a06, 0x6912a3}}}, + /* 13*16^1*G: */ + {{{0x0db0e595, 0x09a47bbc, 0x0820aed9, 0x0c7973f7, 0x076eba71, 0x1bb2c0b0, 0x0c5f5f38, 0x030abb63, 0x7d8678}}, + {{0x1c733de8, 0x0ca8f1d5, 0x09754ca6, 0x0f089c1c, 0x18838293, 0x1715f6a7, 0x01dcb958, 0x1bfd90df, 0xe2b99a}}}, + /* 15*16^1*G: */ + {{{0x16060dfc, 0x047f7c28, 0x179a8a80, 0x08bf0840, 0x0b086765, 0x05cee20d, 0x0b212125, 0x01e00b05, 0xddc531}}, + {{0x07820ca8, 0x1afc55b7, 0x1411cc3e, 0x175f8d57, 0x10e9041d, 0x15b6e647, 0x1a480646, 0x075e41b2, 0xba0d2f}}} + }, + { + /* 1*16^2*G: */ + {{{0x15f51508, 0x123711fe, 0x0b072841, 0x073957ab, 0x1e238d8c, 0x171f0b96, 0x0767a8a9, 0x064258c1, 0x828226}}, + {{0x16e26caf, 0x18db757f, 0x1ec5efb4, 0x0c27585e, 0x00ace62d, 0x0b74185b, 0x1f917a09, 0x0130aafb, 0x11f8a8}}}, + /* 3*16^2*G: */ + {{{0x057e8dfa, 0x07e065cf, 0x11f8613f, 0x01232347, 0x18ca0098, 0x187c5654, 0x11303668, 0x05fe0f33, 0x8262cf}}, + {{0x1bac376a, 0x0e7fc6c7, 0x05311e0d, 0x0dda6656, 0x14f3457b, 0x111762d9, 0x19399bfb, 0x1c412213, 0x83fd95}}}, + /* 5*16^2*G: */ + {{{0x026bdb6f, 0x02972458, 0x1cd2e524, 0x0837a8f6, 0x19c877ca, 0x02d92674, 0x17545a04, 0x1163b41b, 0x19825c}}, + {{0x049cfc9b, 0x0efb8426, 0x1db4e9ad, 0x13dd9919, 0x19f6cebe, 0x10e64a7a, 0x1e3cc809, 0x01e1a990, 0x629431}}}, + /* 7*16^2*G: */ + {{{0x1d82824c, 0x07684a91, 0x054d3994, 0x0b1c68bc, 0x0999edfa, 0x1ab76361, 0x04510f17, 0x0d822c03, 0x6f12d8}}, + {{0x06eb34d0, 0x0bce1a40, 0x152f16e1, 0x19248210, 0x03769391, 0x0a79feb1, 0x1e821d66, 0x1e895677, 0x5c4ff7}}}, + /* 9*16^2*G: */ + {{{0x1b453629, 0x1b6ee016, 0x167980c1, 0x1fb9b81e, 0x0bef645c, 0x138b511d, 0x09745098, 0x0df34155, 0x203a8c}}, + {{0x1ff89f84, 0x0b8e3c29, 0x0a17b516, 0x1bd64b8a, 0x10612686, 0x1b68afa0, 0x06e4db31, 0x0a7bcbbb, 0x3b0f0b}}}, + /* 11*16^2*G: */ + {{{0x046c7ecb, 0x018986ef, 0x0ed33a5e, 0x15da7fcb, 0x0e1ec9d3, 0x1b99a433, 0x0607207b, 0x1d67a068, 0x6e2aca}}, + {{0x0ebc8720, 0x024900f7, 0x19d44b21, 0x0e0d7236, 0x1643afac, 0x026d787d, 0x18527603, 0x0cf2fdfd, 0x9e61a4}}}, + /* 13*16^2*G: */ + {{{0x10a4147e, 0x1b80c79f, 0x1d7c807a, 0x0fbb17ee, 0x10a58274, 0x18bf4524, 0x15aebd85, 0x125d3d22, 0xd5a704}}, + {{0x13fb65ff, 0x1259e5c1, 0x19fd5fe3, 0x09b308f2, 0x00532f4c, 0x04c83b2f, 0x071bf124, 0x1ebb7571, 0x9db526}}}, + /* 15*16^2*G: */ + {{{0x18edcec6, 0x16eda35e, 0x18d3d153, 0x0c3985a6, 0x0dac6a10, 0x17e31816, 0x0ea0148f, 0x13557c31, 0x38c511}}, + {{0x1933db08, 0x0b705fd8, 0x154c2991, 0x02d90456, 0x1282f28a, 0x196d13af, 0x0ca99a32, 0x0450bb2e, 0xe649dd}}} + }, + { + /* 1*16^3*G: */ + {{{0x11e5b739, 0x1fe72daa, 0x0888bb5c, 0x127067fa, 0x0846de0b, 0x0e63637e, 0x1969cbe6, 0x13ee5170, 0x175e15}}, + {{0x09fed695, 0x17d37ff7, 0x090d171b, 0x0b2ab5ba, 0x11f5eacb, 0x0bd28ffb, 0x07ae93be, 0x01b3c78f, 0xd3506e}}}, + /* 3*16^3*G: */ + {{{0x05041216, 0x0dbfc78e, 0x0ae0da99, 0x066bed08, 0x1ed523f7, 0x0cf7ee17, 0x13d04a2d, 0x0f643ef5, 0xda7531}}, + {{0x0e708572, 0x176994c3, 0x1eb3b6b6, 0x1580f5ce, 0x17fc6e9a, 0x110d9a16, 0x17c37c67, 0x08d7ee5a, 0x73f8a0}}}, + /* 5*16^3*G: */ + {{{0x0465a930, 0x00a1f38f, 0x04d4bf6c, 0x0fe382d6, 0x0eb1e258, 0x02c62541, 0x075c15cf, 0x1691d2e9, 0x1c71c5}}, + {{0x034638b5, 0x0c39fb66, 0x05d351c7, 0x08bc7f6e, 0x1b68c793, 0x18f94125, 0x08309c4f, 0x069d1ebf, 0x4a91c3}}}, + /* 7*16^3*G: */ + {{{0x1adb6ee7, 0x18c6d72d, 0x11281df8, 0x01ba864e, 0x14c9c785, 0x01bd484d, 0x159a4dba, 0x1f83e634, 0xd84e4a}}, + {{0x142ebed2, 0x16aab736, 0x08f99260, 0x11592e95, 0x1de4dfdd, 0x06ac7ab2, 0x07384a8e, 0x134f8f6f, 0xe52580}}}, + /* 9*16^3*G: */ + {{{0x049e6d10, 0x0a74f67d, 0x0b26748e, 0x15bfe75d, 0x16ed3f60, 0x15c942ff, 0x053506c8, 0x097bccd0, 0xf3d444}}, + {{0x1347da3f, 0x101c6602, 0x075b18c2, 0x15b4a19d, 0x04b5bfc1, 0x0ad60cc5, 0x18f52eae, 0x1bf4de02, 0xa4324}}}, + /* 11*16^3*G: */ + {{{0x09d33a07, 0x0659a037, 0x0e6f2ad2, 0x05dc1154, 0x1f4044e7, 0x0a9066de, 0x1627e421, 0x0593b383, 0xae3065}}, + {{0x00a0b2a6, 0x0438607b, 0x15fa571d, 0x186febbf, 0x0d5cf1c9, 0x13e99edc, 0x195fbf33, 0x1871ac7f, 0x6cb9d9}}}, + /* 13*16^3*G: */ + {{{0x0c28caca, 0x0cb2a5c8, 0x00a0769d, 0x138f7799, 0x08c9a186, 0x1f3ac19c, 0x07205785, 0x054b7abc, 0xd8dc1b}}, + {{0x03b3ec7a, 0x0db3b751, 0x004a3db3, 0x02ba59d9, 0x07d947d3, 0x06d21012, 0x1f5631b6, 0x1b24f9d8, 0x8cec0a}}}, + /* 15*16^3*G: */ + {{{0x1bc4416f, 0x090fdb31, 0x02c100a2, 0x1dfa47e6, 0x0f31da7a, 0x12d46819, 0x1b335650, 0x1258bf09, 0x2749e2}}, + {{0x1c6bbd8e, 0x14c5ef17, 0x1a58415f, 0x1d3f6cbd, 0x0db3ef59, 0x0a4c87e5, 0x0f1100f6, 0x09c6ece5, 0x50cc2d}}} + }, + { + /* 1*16^4*G: */ + {{{0x03ff4640, 0x135d6c7c, 0x154bff94, 0x0838fcaa, 0x02ee0534, 0x1602db13, 0x1272673a, 0x1a88f601, 0x363d90}}, + {{0x1bee9de9, 0x1001e3f9, 0x0667b2d8, 0x13512010, 0x1363145b, 0x0229cbf9, 0x088654ed, 0x15bf8e64, 0x4e273}}}, + /* 3*16^4*G: */ + {{{0x16e55dc8, 0x1c4890b7, 0x12810e52, 0x12b56dd5, 0x094426ff, 0x12206028, 0x1ecaea12, 0x08f218bf, 0x443140}}, + {{0x1be323b3, 0x0eca2576, 0x0a8b940c, 0x14536f3d, 0x0fed7a66, 0x01bfab21, 0x1be3fa66, 0x085cca6c, 0x96b0c1}}}, + /* 5*16^4*G: */ + {{{0x101b23a8, 0x1f4a42eb, 0x01fb82b7, 0x16fa8e15, 0x1089dab7, 0x01eadc90, 0x01f04989, 0x11b0cd95, 0x9e22fe}}, + {{0x0884edae, 0x1d209e28, 0x14473b3d, 0x0f9293f6, 0x01533c0f, 0x1f8104ce, 0x14405dfc, 0x1d394245, 0xfd2ff0}}}, + /* 7*16^4*G: */ + {{{0x071a70e4, 0x0ba045f8, 0x173d1d77, 0x1dca3ebe, 0x1306dcd5, 0x14f32382, 0x0a34bb75, 0x1aa079c5, 0x508df6}}, + {{0x09950984, 0x1972dfb9, 0x02ab7fb7, 0x006451dd, 0x049c54ec, 0x0255399f, 0x10b5ddcc, 0x13726778, 0x154c43}}}, + /* 9*16^4*G: */ + {{{0x0e1abe11, 0x157ed3b6, 0x12c883db, 0x124384b3, 0x125b2dab, 0x1ac0c980, 0x1d8cce37, 0x108aa212, 0xe3dbff}}, + {{0x1fa8de63, 0x1a4d6aa4, 0x1ad71052, 0x12fb2078, 0x08ef3d3c, 0x1d3aedc5, 0x108590e3, 0x01334682, 0x6f2f9}}}, + /* 11*16^4*G: */ + {{{0x03593449, 0x078d91b0, 0x0a91bff7, 0x16f825c8, 0x1014af61, 0x0e09d03e, 0x10361e36, 0x0c98fbd2, 0x19ace0}}, + {{0x0df83631, 0x120a5c9d, 0x0101a28e, 0x02173e81, 0x02c46ac7, 0x0b9ceca0, 0x0cceffaf, 0x006a4d14, 0xe37992}}}, + /* 13*16^4*G: */ + {{{0x0cba6b63, 0x11f4c496, 0x02ceed7b, 0x1fcce9fa, 0x08e310a0, 0x19914754, 0x16a84230, 0x1d841f0f, 0xd8740c}}, + {{0x0934c5f3, 0x1751b603, 0x005a52af, 0x009eb987, 0x0c37d401, 0x1774c81d, 0x0afcde29, 0x0678d726, 0x6472c1}}}, + /* 15*16^4*G: */ + {{{0x1b3ec038, 0x0ca7f960, 0x031ac9d8, 0x1aa2d5cc, 0x10a50d9f, 0x1f3b1794, 0x020d9220, 0x07236a0c, 0x58ac33}}, + {{0x10246279, 0x17551f88, 0x13eef285, 0x12087816, 0x1fe97021, 0x0924f4c8, 0x0b65e1de, 0x00daab92, 0x9163d7}}} + }, + { + /* 1*16^5*G: */ + {{{0x1ffdf80c, 0x0fbcd2ae, 0x16f346da, 0x094f0342, 0x1638843e, 0x025adba2, 0x0afa3189, 0x02cbbe78, 0x8b4b5f}}, + {{0x1fd4fd36, 0x1f7f8632, 0x18bb95ac, 0x066ca8c2, 0x0da04f9e, 0x0bc09d58, 0x02d2cfef, 0x0ded1a61, 0x4aad0a}}}, + /* 3*16^5*G: */ + {{{0x155812dd, 0x05152c17, 0x0b4c38a8, 0x08ce46aa, 0x0f78e3d4, 0x1f6b602c, 0x14bc2daa, 0x0f525fe6, 0x7029bd}}, + {{0x1a2d2927, 0x10e63358, 0x0cb1cf1c, 0x15d08487, 0x083ac47d, 0x0a257183, 0x0f49f759, 0x1b5fbd16, 0xb0eefa}}}, + /* 5*16^5*G: */ + {{{0x1d486ed1, 0x0e72b41d, 0x1596da92, 0x0b7d7492, 0x17560574, 0x0084ec67, 0x12640275, 0x195d5ccb, 0x9ccfed}}, + {{0x15e95d8d, 0x1b6acf6b, 0x164aa893, 0x02ceb2d2, 0x13411242, 0x12409005, 0x0b3ed848, 0x0e27ad46, 0x7c2f4d}}}, + /* 7*16^5*G: */ + {{{0x1bd0eaca, 0x10358d3a, 0x0b52ade8, 0x0e8aed74, 0x0df19d0c, 0x1ef19e52, 0x050cd6a3, 0x10ec6828, 0xcd9a4b}}, + {{0x0bff4acc, 0x137d7dad, 0x1bd8d3db, 0x0f671dda, 0x0a08b012, 0x0457499f, 0x08fa0552, 0x0f343d1e, 0xf04558}}}, + /* 9*16^5*G: */ + {{{0x07bc57c6, 0x104a9d1e, 0x0c9db2fc, 0x07af447d, 0x03094490, 0x169749eb, 0x0faa213c, 0x05f11db3, 0xad0988}}, + {{0x0e4a0ab8, 0x1196076d, 0x0438b4f2, 0x023a6e6b, 0x0be5f7b3, 0x036394ed, 0x14ae8a06, 0x11885f74, 0x7243c0}}}, + /* 11*16^5*G: */ + {{{0x0ba56302, 0x14186395, 0x03c618ba, 0x0d526f5e, 0x0d2e0f50, 0x116954fd, 0x107c7ab6, 0x015d6794, 0xd9d129}}, + {{0x08291c29, 0x156ed7d4, 0x09d3caba, 0x135d9b3f, 0x186e4173, 0x0ae33931, 0x1bb40a5c, 0x027d85a7, 0x7eb531}}}, + /* 13*16^5*G: */ + {{{0x14d1243a, 0x1669b827, 0x15297f6e, 0x024c047e, 0x1558402b, 0x10d6031f, 0x13be4734, 0x1bca73ad, 0xbc5079}}, + {{0x055db68a, 0x0e4a8b44, 0x1d1c5a7d, 0x1dc9eb63, 0x1c8d75f7, 0x195ca6ff, 0x12ee3bb1, 0x07674e0b, 0x65062a}}}, + /* 15*16^5*G: */ + {{{0x174a3f9f, 0x06922735, 0x02605a42, 0x0f4ccbb8, 0x0625ac28, 0x15573ed9, 0x1fa244f7, 0x0fca0bf8, 0x4d31a7}}, + {{0x101e0ba7, 0x1e581209, 0x18029d53, 0x0df6a36d, 0x02753cbf, 0x079c63c0, 0x1d6c1ac6, 0x192c130a, 0x22241e}}} + }, + { + /* 1*16^6*G: */ + {{{0x1232fcda, 0x1b08ac92, 0x1039def2, 0x01b7ff4d, 0x148c7b70, 0x18e005ea, 0x05b5afdd, 0x14dcbb73, 0x723cba}}, + {{0x1eb39f5f, 0x0ee034ec, 0x1e525200, 0x0140ca6e, 0x04d6e266, 0x09ba4441, 0x1262a484, 0x16ab2b98, 0x96e867}}}, + /* 3*16^6*G: */ + {{{0x00633cb1, 0x0b3f04f4, 0x140844c9, 0x144496d3, 0x01fcb575, 0x1399090c, 0x0b500318, 0x1e62f559, 0x6dde9c}}, + {{0x07ce6b34, 0x1eea4d53, 0x0167bcd5, 0x04ffb59f, 0x066a880b, 0x17c350dd, 0x10757267, 0x1cf4e0fc, 0x9188fb}}}, + /* 5*16^6*G: */ + {{{0x0933f3c5, 0x0cd28c69, 0x1c494890, 0x141ee22b, 0x1b850085, 0x1dbfc723, 0x17a04f12, 0x059ab6b9, 0x486fa7}}, + {{0x0afb0f53, 0x16a538d6, 0x03c8ede6, 0x136f079e, 0x0f19f62d, 0x045d7664, 0x150f9231, 0x033ead7b, 0x62e123}}}, + /* 7*16^6*G: */ + {{{0x1e99f728, 0x1eaca112, 0x1c48813a, 0x06ebf7cd, 0x05303677, 0x1f93dbb5, 0x1d3ed993, 0x0e951295, 0x247969}}, + {{0x0baaebff, 0x1d0028b7, 0x1d68b60d, 0x17e7812a, 0x1664a5ad, 0x143f3ec6, 0x0007b14b, 0x088d11e6, 0xe3d78d}}}, + /* 9*16^6*G: */ + {{{0x0fb0079a, 0x0f0636a1, 0x04981272, 0x1f3dee47, 0x18324916, 0x0cf73b59, 0x1fc18c69, 0x1b547aab, 0x2f39cb}}, + {{0x0c5690ba, 0x1114b981, 0x0a808c3f, 0x167f7910, 0x1a58b9bf, 0x1b6813c6, 0x060d36a4, 0x1bc270c7, 0xabeadb}}}, + /* 11*16^6*G: */ + {{{0x04f7ab73, 0x09980597, 0x1110e9de, 0x07a9d53a, 0x0aed262e, 0x0f43629a, 0x06e95a8e, 0x0d864fac, 0xe5a31d}}, + {{0x10561f42, 0x089d1fe3, 0x032e884e, 0x18889350, 0x0ce5dbf8, 0x054bbd27, 0x15e83046, 0x07b1a3d3, 0x37788c}}}, + /* 13*16^6*G: */ + {{{0x014dcd86, 0x07c94d1e, 0x0fdc6d62, 0x0ba8412d, 0x1dcf11fc, 0x0ecc1028, 0x111f7d43, 0x0941a2a6, 0xcc389d}}, + {{0x08f0a873, 0x075b6ece, 0x1f9e1d1a, 0x0afc31fc, 0x110ca05c, 0x05eddf54, 0x0fb66d5a, 0x1acc1ed7, 0x93ae4f}}}, + /* 15*16^6*G: */ + {{{0x18819311, 0x07ce375b, 0x01dc51c9, 0x1c3dc421, 0x1ed1f0b3, 0x10bf067a, 0x0408dd42, 0x1913ae3d, 0x7f9291}}, + {{0x0c2eb125, 0x14fcdabd, 0x01a85d2a, 0x15548139, 0x015b6120, 0x0f462292, 0x1bc3d743, 0x020c7d87, 0x9da00d}}} + }, + { + /* 1*16^7*G: */ + {{{0x0e7dd7fa, 0x1299f650, 0x0a4660e6, 0x0f2c246f, 0x0d3b5094, 0x17640961, 0x1e62e97f, 0x1a9277d7, 0xeebfa4}}, + {{0x01de8999, 0x0fea7ed7, 0x047dc4b7, 0x099b874e, 0x0089d9ae, 0x1f6d78bc, 0x03c9a7b9, 0x1472e1de, 0x5d9a8c}}}, + /* 3*16^7*G: */ + {{{0x1b7ceceb, 0x1fb3c7fd, 0x05febc3c, 0x0b3f2711, 0x0681473a, 0x1c0937b7, 0x1140dbfe, 0x04084eda, 0x437a86}}, + {{0x16c181e1, 0x1b1de61a, 0x03e5e09c, 0x041f9fb9, 0x097ff872, 0x1f5b4ce9, 0x0cbda6e3, 0x1427dd58, 0xb916b}}}, + /* 5*16^7*G: */ + {{{0x097f96f2, 0x0c6b94f0, 0x121cd735, 0x046a53a5, 0x0c273358, 0x1f1dcd1e, 0x06f20f2d, 0x027c5491, 0xa9ef9f}}, + {{0x16c04be4, 0x01eaad82, 0x06d1c0b0, 0x1f135eb5, 0x1613db74, 0x170b075d, 0x15f3655b, 0x1cb28ab3, 0xe814cc}}}, + /* 7*16^7*G: */ + {{{0x150cf77e, 0x0055ad09, 0x0a2ac36f, 0x17eae8a9, 0x0064207d, 0x13eb4fd5, 0x16f954e0, 0x083dc3a6, 0x66d805}}, + {{0x00eaa3a6, 0x12fcbd7d, 0x0c6ddb4a, 0x0968756f, 0x013f6944, 0x0a1029ab, 0x0d0b0fc7, 0x1ce65fff, 0x51cfdf}}}, + /* 9*16^7*G: */ + {{{0x07213a5a, 0x1aa43144, 0x17e98ae4, 0x064094f0, 0x0c3c80b7, 0x0450e326, 0x1e8afcd4, 0x1c26ca07, 0x62ac05}}, + {{0x146a9e45, 0x08690e07, 0x1e653bf0, 0x12120302, 0x12579e55, 0x13cf03d4, 0x1b934e57, 0x1e741a34, 0x236fbd}}}, + /* 11*16^7*G: */ + {{{0x07bad12b, 0x187ea4c3, 0x1d9b87b0, 0x0bd401d5, 0x12db385d, 0x09d7ae37, 0x1d6d6fd8, 0x092e4891, 0xca13c4}}, + {{0x1723b0f2, 0x0b4cfa34, 0x095d59a2, 0x0156e223, 0x1a3d6637, 0x1d327556, 0x1f22b057, 0x106c3850, 0x83aa09}}}, + /* 13*16^7*G: */ + {{{0x1c80414e, 0x0d772fca, 0x19b3dff7, 0x1f150c5a, 0x09e4914e, 0x0e27a230, 0x0ba16b04, 0x0034e0a5, 0x1cecb1}}, + {{0x12169a3b, 0x0574a496, 0x1c8c7437, 0x0aafca88, 0x1ad16907, 0x11941af6, 0x13ed396a, 0x0cd2c12f, 0xf34360}}}, + /* 15*16^7*G: */ + {{{0x0ed810a9, 0x07ade462, 0x1c005571, 0x113a7e78, 0x123924f8, 0x0d7af8ef, 0x1e732543, 0x0ea09af1, 0x2a6990}}, + {{0x1a9b4728, 0x1c359c47, 0x105171f3, 0x1a8fd2fd, 0x104fc667, 0x0c34aa7d, 0x1f6b0fb1, 0x136d87bf, 0x54f903}}} + }, + { + /* 1*16^8*G: */ + {{{0x19a48db0, 0x1ebc1ad9, 0x0f00effb, 0x042b4536, 0x1de459f1, 0x08504dbd, 0x059c9e47, 0x1b4d2dce, 0x100f44}}, + {{0x0bc65a09, 0x1deae6b1, 0x14656b03, 0x1e9431fe, 0x10666b7f, 0x19980604, 0x0ddcbb23, 0x06325401, 0xcdd9e1}}}, + /* 3*16^8*G: */ + {{{0x15bc15b4, 0x05cd09a4, 0x168bb9a7, 0x0a051c8c, 0x1ca8d927, 0x0774e76b, 0x1727b616, 0x05ca3dd5, 0x10e90e}}, + {{0x18aa258d, 0x075f304a, 0x0edaa20d, 0x0b12c605, 0x11f754ca, 0x14630b56, 0x0109355e, 0x00701abc, 0xc68a37}}}, + /* 5*16^8*G: */ + {{{0x1fe75269, 0x0e9fe181, 0x0f4cc60b, 0x0f47980a, 0x17dcda37, 0x1c85b8a5, 0x18e115d6, 0x085b4a82, 0xf7422f}}, + {{0x17e49bd5, 0x04c07438, 0x08e63806, 0x07446fe9, 0x035977fb, 0x13ee5cfb, 0x04ff4633, 0x03466261, 0x406c2f}}}, + /* 7*16^8*G: */ + {{{0x15a7175f, 0x09db34b7, 0x073d0a99, 0x11cee3a6, 0x1debbedb, 0x0d2ac16a, 0x13fdca1e, 0x0082fa87, 0x2d8cad}}, + {{0x1b9d592a, 0x19bddc8d, 0x0d797833, 0x08d7fb39, 0x09d377a8, 0x197d3096, 0x0529eec8, 0x10663195, 0xc73f3b}}}, + /* 9*16^8*G: */ + {{{0x14b51045, 0x1a64de1c, 0x07096cf8, 0x0d912de6, 0x0cf73bbc, 0x1ea758f4, 0x1a962b9c, 0x03b7314d, 0x1ecbfd}}, + {{0x02c70026, 0x1d338808, 0x0d908b54, 0x000c8d68, 0x09b38b19, 0x05d8c24d, 0x0e9911f4, 0x06117338, 0x1cf6e2}}}, + /* 11*16^8*G: */ + {{{0x09358533, 0x1d66bb37, 0x1ed2e77d, 0x1267f3a9, 0x12a8c10a, 0x0ad148e9, 0x14a20fa5, 0x18bfcaee, 0x9a0894}}, + {{0x0360ba08, 0x19f0e2ee, 0x00376b7e, 0x0dcb7b77, 0x1c32165a, 0x1eafcaa7, 0x1f0c7e45, 0x18840371, 0xa79883}}}, + /* 13*16^8*G: */ + {{{0x198ef7f6, 0x0a202eb0, 0x01e3e7da, 0x07e7eef4, 0x0aea6592, 0x042939dc, 0x0b8d6f67, 0x093b69fa, 0x664dd8}}, + {{0x1d1eac94, 0x1a4b7f9a, 0x039bb3b9, 0x1a756637, 0x058cffc3, 0x0672ee82, 0x04ca8512, 0x02e2fe4f, 0xad5120}}}, + /* 15*16^8*G: */ + {{{0x03c934b3, 0x060535be, 0x02b8b138, 0x03eb00b6, 0x1a7022b3, 0x0cb34c08, 0x018e08c7, 0x126efa17, 0x82113a}}, + {{0x042c6a0f, 0x1f2f3156, 0x111a00dd, 0x1ef84d34, 0x0c628aa1, 0x16795ad0, 0x19982119, 0x1b5935c6, 0x8da1b8}}} + }, + { + /* 1*16^9*G: */ + {{{0x0534fd2d, 0x04566f37, 0x1cece14b, 0x1f1a88c9, 0x0c017a77, 0x113d2502, 0x146c7724, 0x1c4c58fd, 0xe1031b}}, + {{0x1456a00d, 0x0278c794, 0x073b5e69, 0x05ba833c, 0x1535af29, 0x120bb2cb, 0x0179aeda, 0x12512808, 0x9d7061}}}, + /* 3*16^9*G: */ + {{{0x0f028d83, 0x1cb11d77, 0x1d0e5855, 0x0b24db74, 0x069db619, 0x1f2d0aef, 0x17b1a96a, 0x189c78f0, 0xa7ebf7}}, + {{0x19d0bed1, 0x1201c95c, 0x014e4665, 0x07124e96, 0x0804b47a, 0x039bb822, 0x0b573f67, 0x05f7fc6c, 0x620515}}}, + /* 5*16^9*G: */ + {{{0x07dd5cfa, 0x17072011, 0x02752d6e, 0x138a26fe, 0x146336a8, 0x1529a131, 0x1d307371, 0x11b96049, 0x5b5ca0}}, + {{0x1e48e98c, 0x132537cc, 0x0c9a74f9, 0x00cf995e, 0x09094bfd, 0x18675443, 0x0097a647, 0x1ee1542b, 0x3eccb6}}}, + /* 7*16^9*G: */ + {{{0x03531f82, 0x1ca94719, 0x030b27ca, 0x0264d762, 0x02c29ff5, 0x1f3a44e1, 0x0ed733bc, 0x15982229, 0x46f26}}, + {{0x0bceda07, 0x082fe458, 0x0d571fe9, 0x0b28b9b5, 0x12579d02, 0x185617e1, 0x0bab388d, 0x062c6b70, 0x6b804b}}}, + /* 9*16^9*G: */ + {{{0x10432711, 0x058aa1b8, 0x045ae418, 0x08165fbb, 0x1645acf1, 0x1787844c, 0x1ed4d7e5, 0x1b263c1d, 0xc11926}}, + {{0x0fe2610c, 0x04930f17, 0x1cd01579, 0x17245941, 0x0c6cf83a, 0x05f8c366, 0x1a246125, 0x198fa4b6, 0x8be1f8}}}, + /* 11*16^9*G: */ + {{{0x01257963, 0x0bcc3a7d, 0x12aa1870, 0x031aa586, 0x179c45b0, 0x1aa5a9c4, 0x1cb9b36e, 0x1d3d6d11, 0x690846}}, + {{0x066f9835, 0x12bb2cca, 0x124ac94e, 0x18795043, 0x1bb7f6cb, 0x18127c97, 0x0f16d005, 0x196fe7fd, 0xe2485f}}}, + /* 13*16^9*G: */ + {{{0x1ee23ace, 0x0889ca5e, 0x1374bf4b, 0x10f8cb6a, 0x12915dec, 0x0a96fa51, 0x02eaee9d, 0x1f719244, 0xfb3df7}}, + {{0x1722e8de, 0x04ef7a64, 0x149fd7b8, 0x04e285fd, 0x0b58a9e7, 0x08aa06dd, 0x11594a89, 0x178238e7, 0x510e29}}}, + /* 15*16^9*G: */ + {{{0x10272351, 0x103e7f7a, 0x07fc4261, 0x06967bf3, 0x1cd41707, 0x11f59d58, 0x062cfae2, 0x1849eb8a, 0x6dd85e}}, + {{0x1fc7664b, 0x183fd15b, 0x18205f26, 0x18dfef87, 0x041b7877, 0x03fcd7ae, 0x09f82750, 0x1e8243e8, 0x16ea67}}} + }, + { + /* 1*16^10*G: */ + {{{0x1094696d, 0x0af3446c, 0x075abd4b, 0x1164cd48, 0x1d7ec5cf, 0x01cf8a1d, 0x0d4c2b0a, 0x15c8daab, 0xfeea6c}}, + {{0x18090088, 0x0aaef5f8, 0x10510b4c, 0x1912af98, 0x0cd5c981, 0x07095f9f, 0x06eac1b9, 0x0d92fb9c, 0xe57c6b}}}, + /* 3*16^10*G: */ + {{{0x08dfd587, 0x1c9b0dda, 0x0c099581, 0x09747193, 0x1a12d5ec, 0x1d55167a, 0x022cd219, 0x03759e8a, 0x5084b4}}, + {{0x11470e89, 0x13cf4bfc, 0x047d581b, 0x0deac0d1, 0x127475db, 0x13642a94, 0x14c5866a, 0x0343b301, 0x34a963}}}, + /* 5*16^10*G: */ + {{{0x1ab34cc6, 0x0411930b, 0x1cc284b4, 0x1852ecf9, 0x17128c80, 0x1f8fe8c6, 0x17a94fec, 0x07c0c85a, 0x4f14c0}}, + {{0x187e681f, 0x0f61297c, 0x00774089, 0x1c799d1d, 0x02540b9d, 0x1387a1d3, 0x0253194e, 0x1519549d, 0x7b53d0}}}, + /* 7*16^10*G: */ + {{{0x1241d90d, 0x013b8808, 0x09113e0d, 0x19e283b6, 0x1d363e81, 0x1b04af6e, 0x1b475050, 0x0fc938f3, 0xa74db8}}, + {{0x1f7adad4, 0x1928c5c1, 0x0828c4fc, 0x1ca12689, 0x171c8a9e, 0x08452c40, 0x1bcc9ff7, 0x19b5e47d, 0xf78691}}}, + /* 9*16^10*G: */ + {{{0x11c1ae1f, 0x0f665111, 0x13502ca9, 0x1cb18d15, 0x15658456, 0x06a275d1, 0x0b3e6b37, 0x0ae89754, 0x6901fa}}, + {{0x122838b0, 0x1c19832e, 0x11dea4c3, 0x1e774bcb, 0x0900dd79, 0x09c0614e, 0x0849186d, 0x11044e78, 0x35de5c}}}, + /* 11*16^10*G: */ + {{{0x127a4bdb, 0x1818840d, 0x12532b12, 0x14da086a, 0x1a35d046, 0x1b21f8dd, 0x049e8912, 0x05a3a870, 0x8d3cd8}}, + {{0x069a8a2c, 0x1e9a63e7, 0x02b4a5b0, 0x0700fa6e, 0x0236ed4e, 0x1fce803b, 0x07d1c33e, 0x0c301dc8, 0x9bd425}}}, + /* 13*16^10*G: */ + {{{0x14ec1d2d, 0x00669e35, 0x1f63d151, 0x133eb8dc, 0x1691fd90, 0x0b394b3d, 0x1ce6bfa7, 0x0c7ac0c8, 0xeaf983}}, + {{0x0c838452, 0x07f3ab02, 0x1a12d4ff, 0x0a5aa8af, 0x199aaa9f, 0x14507358, 0x1489dd48, 0x074ffcf1, 0xe51818}}}, + /* 15*16^10*G: */ + {{{0x045ae767, 0x059adfb8, 0x025dc72f, 0x0753973d, 0x0e5d8c27, 0x07029603, 0x18d19bd0, 0x02c75db6, 0xfb95bd}}, + {{0x1bbf0e11, 0x029f5057, 0x167c4d06, 0x0de8e314, 0x0275bb81, 0x06ce9b41, 0x16f14801, 0x1b02351b, 0x664c14}}} + }, + { + /* 1*16^11*G: */ + {{{0x01ec6cb1, 0x1fd4bc5e, 0x0160f78c, 0x1acafb01, 0x1ca3cfee, 0x1f25f37f, 0x1372cd9e, 0x03b22093, 0xda67a9}}, + {{0x1a68be1d, 0x14f54713, 0x1dd0285f, 0x0f5b8a11, 0x180e5dec, 0x11fbf64b, 0x0af107d1, 0x06a902c8, 0x9bacaa}}}, + /* 3*16^11*G: */ + {{{0x15bc8a44, 0x17ee8328, 0x18546867, 0x0202ef97, 0x05fc7684, 0x12d25d2d, 0x168f4e15, 0x0b079f9d, 0x4d0180}}, + {{0x1adbc09e, 0x18fca648, 0x00b68d8b, 0x08408d0b, 0x03813969, 0x1d4003eb, 0x174d9fa6, 0x1831969e, 0x3a33c6}}}, + /* 5*16^11*G: */ + {{{0x05daeb00, 0x00d5a943, 0x1917ddaf, 0x07d6499c, 0x0e9d1592, 0x1b5139db, 0x055c20b2, 0x00fbeb9f, 0x2f6615}}, + {{0x033992c0, 0x113b3c4c, 0x174c2304, 0x1bdc4e32, 0x0add06ec, 0x09bd4100, 0x0cfdbbe5, 0x026dea56, 0xfd5c12}}}, + /* 7*16^11*G: */ + {{{0x116aa6d9, 0x01548504, 0x1c0b73c6, 0x05916c8e, 0x15a38366, 0x0ba6d0c1, 0x1f48953c, 0x0fa0bfc8, 0xf59411}}, + {{0x1f2e50cf, 0x1e834b75, 0x1ad6e1b1, 0x04ef107c, 0x0bceb7a9, 0x0ded584a, 0x0c4b3d97, 0x14add2e3, 0xcaa761}}}, + /* 9*16^11*G: */ + {{{0x1ac6f4c0, 0x15701cab, 0x12f71332, 0x1d1bd198, 0x0711dda4, 0x01c5f34b, 0x137b1387, 0x0fe3e9b3, 0xf2d4d}}, + {{0x12339b58, 0x1f3ddd6b, 0x090995b9, 0x14214f20, 0x1e71e8f6, 0x13fef9c0, 0x19345fec, 0x10afd27b, 0x3ec89f}}}, + /* 11*16^11*G: */ + {{{0x1f428cb2, 0x02a829fe, 0x088ad576, 0x1045facd, 0x0d0f1233, 0x10c0acac, 0x0ef47ade, 0x185c5429, 0x1d5dce}}, + {{0x095b189b, 0x12f68804, 0x18112947, 0x1d225f0e, 0x10b88bd3, 0x03c12437, 0x0314341e, 0x10762859, 0x6e5c40}}}, + /* 13*16^11*G: */ + {{{0x08381273, 0x1875447d, 0x04f6b97e, 0x06ed2c0d, 0x126ced84, 0x14d96620, 0x1d0e7f7a, 0x1fa6012c, 0x89d9a2}}, + {{0x1309773d, 0x01f59f76, 0x049cc928, 0x03ad015a, 0x162f58f6, 0x17903b67, 0x1d40ddea, 0x168a3acd, 0xdfca25}}}, + /* 15*16^11*G: */ + {{{0x15c71d91, 0x06195965, 0x0253f487, 0x08bc5c55, 0x0fece239, 0x0e0988ad, 0x0b8714a8, 0x10f074a1, 0x83191b}}, + {{0x02148a61, 0x05cf6047, 0x01117b9c, 0x023ea2ea, 0x0ae8a17a, 0x0f09e8be, 0x0dc2781b, 0x02ae7003, 0xe0ac7f}}} + }, + { + /* 1*16^12*G: */ + {{{0x1a37b7c0, 0x1aa2e660, 0x0441a7d5, 0x11a1ef76, 0x02151ec0, 0x0049af79, 0x13769b80, 0x15416669, 0x53904f}}, + {{0x022771c8, 0x0e584b58, 0x110d1a67, 0x133303c2, 0x13c1c139, 0x16656106, 0x01b62327, 0x1a179002, 0x5bc087}}}, + /* 3*16^12*G: */ + {{{0x08a2050e, 0x0d6217f2, 0x17e299dc, 0x1deaaec2, 0x19b89742, 0x14e63723, 0x0c625add, 0x1fa4978e, 0x673724}}, + {{0x061d3d70, 0x0864d248, 0x0d2730ae, 0x1759fa86, 0x06b6dbe6, 0x01604d44, 0x088080d2, 0x0af12d49, 0xe4cf82}}}, + /* 5*16^12*G: */ + {{{0x02de63bf, 0x1fb7241c, 0x098719b2, 0x15ea650e, 0x166a8e03, 0x05318fb0, 0x10c27966, 0x148e5be9, 0x4366ef}}, + {{0x017924cd, 0x16352047, 0x0a9b5ac0, 0x1618a4b5, 0x068eaf33, 0x09bf0981, 0x1f38bb89, 0x0137dc5a, 0x2e7dd9}}}, + /* 7*16^12*G: */ + {{{0x06f96190, 0x08293ff8, 0x125497bc, 0x005bd20f, 0x0a75fd1f, 0x0ab4b33d, 0x0c7e5ef9, 0x0c4f3235, 0x7bd753}}, + {{0x0bda00f6, 0x1e8b9025, 0x03a9a568, 0x1f98b83c, 0x027d6ce0, 0x123a4a1c, 0x0c2757b5, 0x167b774c, 0x8336f2}}}, + /* 9*16^12*G: */ + {{{0x16ad41ed, 0x1d8a98aa, 0x1c0d490c, 0x11586be9, 0x0dc92030, 0x00cf448c, 0x1706be8d, 0x0f7bb55a, 0x4f7e92}}, + {{0x1e642d57, 0x1a1abc33, 0x0bddd6f7, 0x0628e29d, 0x0f6a62e7, 0x006fa9d4, 0x0c4154a6, 0x0a2ad511, 0xdfe774}}}, + /* 11*16^12*G: */ + {{{0x07748690, 0x1d302893, 0x18c2c073, 0x0f209bb0, 0x13d007d5, 0x0958f6e9, 0x133252d1, 0x10cfa523, 0x2355cb}}, + {{0x0c89582b, 0x1e23a98a, 0x0724e451, 0x10d0b19a, 0x07c58582, 0x02f60ad5, 0x07e3d56e, 0x114b4e3c, 0x21c2f1}}}, + /* 13*16^12*G: */ + {{{0x0ade7f16, 0x0d7510b0, 0x0f80a31b, 0x1975d279, 0x15d24ae9, 0x0955b613, 0x15b004d6, 0x0b7367b4, 0xb6682}}, + {{0x08c56217, 0x0a221342, 0x19f34af6, 0x08781be7, 0x1a97fb72, 0x1b5d45ab, 0x0cffbce9, 0x17031c13, 0xa1fba0}}}, + /* 15*16^12*G: */ + {{{0x19060d5b, 0x08358114, 0x0e8e9f0a, 0x0c276238, 0x151cb904, 0x0d97ecfc, 0x08b2d842, 0x079e17a0, 0xf60204}}, + {{0x1af88f13, 0x17b7a858, 0x17468fdd, 0x14ada56f, 0x17bea37a, 0x07b25627, 0x1c66206a, 0x00d83e19, 0xf036b7}}} + }, + { + /* 1*16^13*G: */ + {{{0x1ad86047, 0x1fcacfa1, 0x06e2f2bb, 0x0a740875, 0x0906779b, 0x053bb265, 0x0e9dc673, 0x017a6b30, 0x8e7bcd}}, + {{0x0460372a, 0x108023f4, 0x1f5a2cfa, 0x111c5c8f, 0x1514579e, 0x08210654, 0x12ce500c, 0x016547b4, 0x10b777}}}, + /* 3*16^13*G: */ + {{{0x041ead4b, 0x1f443cd0, 0x06c0f07f, 0x0bdbf6d2, 0x076be3a7, 0x19a77d7f, 0x0dfb1c51, 0x019191e6, 0xbfc90c}}, + {{0x06fedaed, 0x02963784, 0x182b8f9d, 0x0d1dfe65, 0x02d36fb4, 0x18c6ea82, 0x1b4936e9, 0x163c139b, 0x7a9481}}}, + /* 5*16^13*G: */ + {{{0x15bb3b3e, 0x173de83b, 0x07dcf2c9, 0x0a6c2fdf, 0x13f5b507, 0x0c9f4616, 0x0a937296, 0x0397c7f5, 0x732df1}}, + {{0x17366693, 0x02bbf0f6, 0x11610db3, 0x1b5adac9, 0x13916e69, 0x12ac2012, 0x05df2df8, 0x07dbd1f3, 0x7f4190}}}, + /* 7*16^13*G: */ + {{{0x088dc3b9, 0x0fad9e0c, 0x1dd32671, 0x0cd249d2, 0x1ef6019a, 0x0420664b, 0x1ed0a36a, 0x172c0728, 0x4ce094}}, + {{0x05c0de52, 0x00a7bdb7, 0x1a81940b, 0x00b64193, 0x0aca2162, 0x06c0653b, 0x0cfb55ed, 0x1757e353, 0x5390f}}}, + /* 9*16^13*G: */ + {{{0x0aaafe5a, 0x01baf058, 0x026bb753, 0x08e1674a, 0x03fd0e25, 0x1354ad81, 0x1f7a5b62, 0x16edf8cc, 0x9a968e}}, + {{0x0ed975c0, 0x135fea12, 0x19c33033, 0x0b1014cb, 0x01d0ee7b, 0x13681ec3, 0x08a553f1, 0x00f4da77, 0xabf6fb}}}, + /* 11*16^13*G: */ + {{{0x134c6397, 0x1a8e5fcf, 0x1d33424d, 0x1a7b6a00, 0x0b22107d, 0x17c0129b, 0x06553c2b, 0x1da02e2c, 0xd3c6fb}}, + {{0x08cb3f9c, 0x0fe4682b, 0x1783802c, 0x18ee1120, 0x0b6468a0, 0x1ca6c975, 0x0bc65160, 0x18abcbc5, 0x4a0dd2}}}, + /* 13*16^13*G: */ + {{{0x0ac3137e, 0x0dc12c98, 0x0bd91186, 0x04b6c54b, 0x13953fe9, 0x0353b555, 0x0ee380bc, 0x13025248, 0x4cbde3}}, + {{0x0ec02fe6, 0x00478ae7, 0x03ab5830, 0x074f5cb1, 0x0c370d19, 0x1509a5ca, 0x05654024, 0x0c11e26c, 0x6ce554}}}, + /* 15*16^13*G: */ + {{{0x00fbf84b, 0x1d118367, 0x0fc2e291, 0x091f9778, 0x0cebb03c, 0x0e39860a, 0x091ee2f6, 0x0790562c, 0x4b9d33}}, + {{0x036c3c48, 0x1cf725a5, 0x1d6d7988, 0x0daa87c5, 0x1b7eb676, 0x1ecc133c, 0x054954c4, 0x1f7c4998, 0xfd7fc7}}} + }, + { + /* 1*16^14*G: */ + {{{0x19c43862, 0x1420f0ac, 0x05f99a42, 0x0fe9e307, 0x01bde71a, 0x00c344dc, 0x1c879b42, 0x069839bf, 0x385eed}}, + {{0x142e5453, 0x022c7f2a, 0x01b72330, 0x009dd841, 0x1f4576b3, 0x0f0cf4f5, 0x0fd59c07, 0x187d1d44, 0x283beb}}}, + /* 3*16^14*G: */ + {{{0x16e2d9b3, 0x05e98355, 0x0e358d45, 0x17250636, 0x1845641d, 0x15309ce7, 0x179d784b, 0x1e72f8e0, 0x19a314}}, + {{0x0baaaf33, 0x0a97712e, 0x012f95b5, 0x043a3a48, 0x128b3a50, 0x12fc43fa, 0x03748d25, 0x1ebb58e5, 0x6cacd8}}}, + /* 5*16^14*G: */ + {{{0x12f00480, 0x0c2c3f58, 0x00373b9f, 0x0b100942, 0x07219203, 0x0c31b27b, 0x0a8d5772, 0x0972b51b, 0x5840ed}}, + {{0x1e22cf9e, 0x0c96af15, 0x0b8e1c85, 0x0a44a8a5, 0x1d8daba7, 0x06f550ae, 0x05041e5a, 0x0d64417e, 0x670cda}}}, + /* 7*16^14*G: */ + {{{0x03f54c42, 0x0426f741, 0x068f7239, 0x1834784d, 0x0532545d, 0x060fa767, 0x03ec7716, 0x14a68d23, 0x9f5701}}, + {{0x0feb6a21, 0x1070e249, 0x067949e1, 0x1cf09564, 0x1bfdd89e, 0x0db5ab94, 0x195efee5, 0x171003b3, 0xce7b8f}}}, + /* 9*16^14*G: */ + {{{0x1522461a, 0x14a09994, 0x11c60c9f, 0x06144cb7, 0x0f9a0bcb, 0x0380833f, 0x13f006ee, 0x0d246b51, 0x27f611}}, + {{0x07301a2d, 0x152657ce, 0x018e511a, 0x103641b5, 0x08ee8e49, 0x02b093a1, 0x0b4ba923, 0x1532014d, 0xe512f1}}}, + /* 11*16^14*G: */ + {{{0x114f36b9, 0x07164d96, 0x0e7ce433, 0x119576c7, 0x0a981259, 0x197a1afa, 0x0504986f, 0x10ad9ddf, 0x640779}}, + {{0x04b4b50a, 0x0a58f74f, 0x073baca2, 0x1410e093, 0x07b6c8cd, 0x0bafec2d, 0x1bebbe43, 0x11e89cad, 0xda6192}}}, + /* 13*16^14*G: */ + {{{0x14d6b76f, 0x17b1efcc, 0x120576f3, 0x0b53f769, 0x1feae7fe, 0x1845e04e, 0x1a7d14bd, 0x1c6390ac, 0xa23750}}, + {{0x0dcca8da, 0x0ec96664, 0x0e123450, 0x00f823fb, 0x11113e77, 0x1d1f26a0, 0x19b6b0cb, 0x0294dcfb, 0xf7339b}}}, + /* 15*16^14*G: */ + {{{0x1ceee475, 0x1774e327, 0x1b5e0ac4, 0x15905081, 0x0ff41ab6, 0x0010f9e5, 0x1e357b4f, 0x00f47e46, 0xbbf1ac}}, + {{0x07fe5067, 0x03115004, 0x02d075a1, 0x173b1287, 0x15fe324e, 0x1e641b58, 0x03984220, 0x1bdd5a8c, 0xb4bfb8}}} + }, + { + /* 1*16^15*G: */ + {{{0x03fac3a7, 0x10376c36, 0x11fef271, 0x1bf094b2, 0x1fa180fd, 0x19d2209e, 0x06458df1, 0x17007d9e, 0x6f9d9}}, + {{0x1a842160, 0x03448301, 0x0a0400b6, 0x09ba5eb8, 0x1c4d47ea, 0x11518722, 0x06e9a6e3, 0x11cc060b, 0x7c80c6}}}, + /* 3*16^15*G: */ + {{{0x121ce204, 0x076baf46, 0x19d8f549, 0x0e4b1c84, 0x0f72fb2a, 0x06c2ce53, 0x193ee0dd, 0x1a2c5678, 0x43ca41}}, + {{0x134a8f6b, 0x09282274, 0x09291a39, 0x0d8f667d, 0x1a31f9ab, 0x07c90c6d, 0x0fe87194, 0x105c6e04, 0xdcea5a}}}, + /* 5*16^15*G: */ + {{{0x0be6efda, 0x07e74967, 0x1ca01659, 0x1a9fe7f0, 0x0506d922, 0x1b91bc2d, 0x0fd6d99b, 0x1de45125, 0x9c3e06}}, + {{0x07aefc7d, 0x18a07995, 0x0dbf7df7, 0x1790d0f6, 0x06fd5d43, 0x196a2671, 0x08f62bc2, 0x1cbcec52, 0xa7b709}}}, + /* 7*16^15*G: */ + {{{0x06c88be2, 0x0893d5ae, 0x1bb9789e, 0x18f041a0, 0x0775bea2, 0x13acec18, 0x1c0ceedc, 0x14627c41, 0x5d6f8a}}, + {{0x0d7ad75d, 0x0972a9f8, 0x0fe4b0a2, 0x16df1d4d, 0x0bc20eda, 0x1799d584, 0x13a31c6a, 0x11b1aada, 0xadc4b1}}}, + /* 9*16^15*G: */ + {{{0x12d1b844, 0x1449a8dc, 0x1cf9213c, 0x18070582, 0x08bc5c69, 0x0ae1e09c, 0x157f21ac, 0x186094c1, 0xf57d35}}, + {{0x01266837, 0x125d5deb, 0x04571a91, 0x0d2e4061, 0x0634c700, 0x09fad4f2, 0x1365e413, 0x13d531de, 0x707f3d}}}, + /* 11*16^15*G: */ + {{{0x1cc7cb09, 0x1a6803f9, 0x146d0d48, 0x0fd6d143, 0x071463bc, 0x10ff71ec, 0x1297d65b, 0x0f474cb2, 0x13e760}}, + {{0x08079160, 0x1f3ad450, 0x0d5d9046, 0x15c576cd, 0x0299d65e, 0x1eec2d9a, 0x02c78c97, 0x11bd1f77, 0x284dc8}}}, + /* 13*16^15*G: */ + {{{0x18cdee05, 0x03067092, 0x0bb0ee40, 0x0c3f642e, 0x0901da87, 0x12858d83, 0x0b989000, 0x044ad030, 0x29bea3}}, + {{0x062651c8, 0x12501acd, 0x11a638e7, 0x18636d91, 0x05ec7f9f, 0x0d9fdc38, 0x083aa402, 0x144d21d3, 0x7c40d9}}}, + /* 15*16^15*G: */ + {{{0x12f18ada, 0x0db63ab0, 0x16f6f304, 0x017b2777, 0x14a59d46, 0x17d7f99e, 0x039f670d, 0x0da47051, 0xf52178}}, + {{0x03953516, 0x0eb457e9, 0x16fc2607, 0x1de946d8, 0x1d1d6aa5, 0x10815e68, 0x0d5fb309, 0x17ec071b, 0xe0686f}}} + }, + { + /* 1*16^16*G: */ + {{{0x02d0e6bd, 0x1dbf073a, 0x03d794c4, 0x09a2c7b6, 0x16ecbf77, 0x0a3e0826, 0x18960a88, 0x00248789, 0x3322d4}}, + {{0x0c28b2a0, 0x079d174b, 0x01cebd89, 0x0bec7d45, 0x0f9b7280, 0x0cde26ed, 0x1bd6fec0, 0x12fd2cc9, 0x56e707}}}, + /* 3*16^16*G: */ + {{{0x059ab499, 0x1ece9f90, 0x1cf0cc2a, 0x065338dc, 0x101bc0b1, 0x0b59e33f, 0x16e97486, 0x1e602b80, 0x78baaf}}, + {{0x1ee097fd, 0x00e918c7, 0x0494665a, 0x065ddd1a, 0x0082e916, 0x027076c1, 0x02bebf2a, 0x1b7b60d8, 0xad4bdc}}}, + /* 5*16^16*G: */ + {{{0x1d06ace6, 0x049f0b67, 0x0e883291, 0x01366df0, 0x1ab1a237, 0x024c2494, 0x0f53082e, 0x0234295c, 0x6f70f2}}, + {{0x1602d5de, 0x045f69a5, 0x16b17b81, 0x052acd7c, 0x19f50753, 0x0c79a3dc, 0x0dcdbe57, 0x0612804f, 0x791e8a}}}, + /* 7*16^16*G: */ + {{{0x00ee1b40, 0x04771f73, 0x1a5891f7, 0x1a90b6e3, 0x1ccd48ce, 0x04f8c881, 0x1057e025, 0x1653ad54, 0xe1599d}}, + {{0x178f93a6, 0x0eb132f6, 0x0ca66778, 0x0c74e978, 0x1c7cfa63, 0x04a55517, 0x1283bebe, 0x0465503a, 0x793362}}}, + /* 9*16^16*G: */ + {{{0x09c00c3e, 0x00efd142, 0x048238be, 0x1d1e0792, 0x11859f00, 0x11699ea2, 0x05590d95, 0x12e0880d, 0xbb0b04}}, + {{0x11955a35, 0x0cd4c168, 0x1772429e, 0x0e089d20, 0x1b052fe6, 0x17d0bd58, 0x1d8d9574, 0x0b0a75f3, 0x4067e4}}}, + /* 11*16^16*G: */ + {{{0x05dd32e6, 0x073adce0, 0x0f97b9f8, 0x076aa36a, 0x05fbfc66, 0x0edf03ad, 0x027a6d92, 0x0aa832af, 0xdc5a41}}, + {{0x154a99b9, 0x073edbd3, 0x1926f3e0, 0x05dd20ed, 0x159442ff, 0x12f100df, 0x1e9db73a, 0x14c7f3ec, 0x4af3a8}}}, + /* 13*16^16*G: */ + {{{0x0544e7cb, 0x16a2dd62, 0x0a580d67, 0x0c844b6a, 0x14e99a10, 0x0a52b880, 0x0e76f8cd, 0x0e0730e7, 0x156e19}}, + {{0x0d250a37, 0x0a9c9605, 0x0d0e735b, 0x0dab1abd, 0x14be8949, 0x0b9531c1, 0x01f6a4e5, 0x13f1e632, 0x6bc08d}}}, + /* 15*16^16*G: */ + {{{0x059853ca, 0x1fde14e6, 0x066fd536, 0x12c4d73e, 0x1161348e, 0x1b511473, 0x0e09af29, 0x19d96d08, 0x4269bc}}, + {{0x15b8d367, 0x14ac77a9, 0x196a28f6, 0x12814bf3, 0x1a409fd3, 0x0654e218, 0x1adc8f21, 0x03505802, 0xed2b1c}}} + }, + { + /* 1*16^17*G: */ + {{{0x0134ab83, 0x10eba694, 0x190ce5dc, 0x167f35ee, 0x05868741, 0x1b86c4b3, 0x1f68af45, 0x0fa5bc16, 0x85672c}}, + {{0x190313a6, 0x07184a7b, 0x0a63d132, 0x1e2ff98a, 0x0c2e5e77, 0x024dfd31, 0x0bad8dd0, 0x136b6876, 0x7c481b}}}, + /* 3*16^17*G: */ + {{{0x03ba9000, 0x0f8391d4, 0x097a2dbf, 0x0e5f38d0, 0x0143dc48, 0x1b03ac20, 0x0305a121, 0x1f3ffe3b, 0xac3874}}, + {{0x0f10cf0a, 0x0d1e3ecb, 0x19ba7e93, 0x1c6a1afe, 0x17f93085, 0x0ef44a08, 0x01a6e18b, 0x04611438, 0xaa65e9}}}, + /* 5*16^17*G: */ + {{{0x0d06dbd4, 0x13037b37, 0x08834206, 0x1c7f0af1, 0x1e729ec0, 0x003af4d1, 0x004e6b45, 0x1cf54d0e, 0x570d5c}}, + {{0x1d1ed495, 0x132df675, 0x1182fb56, 0x0746db8c, 0x01bbbb68, 0x173388e8, 0x0bd816d9, 0x092841c0, 0xa6ae53}}}, + /* 7*16^17*G: */ + {{{0x092d230e, 0x1a60fc90, 0x04ce4a10, 0x1c6541a5, 0x06ef5dae, 0x114f701b, 0x0edbe1f0, 0x0e0504d1, 0x75b5f8}}, + {{0x151570b8, 0x1be5efde, 0x047e3ec0, 0x0f49600a, 0x1fa8e026, 0x03a2aa6e, 0x148d8f5e, 0x043c74f0, 0x527cce}}}, + /* 9*16^17*G: */ + {{{0x034fcc0e, 0x1db5fb56, 0x18e21311, 0x1e214857, 0x059c8927, 0x1c0713e9, 0x1b0ac296, 0x1f5c3dbb, 0x44fc8e}}, + {{0x119c420a, 0x07f818f3, 0x14122767, 0x1d294979, 0x1d3d7720, 0x13f3c419, 0x0d9f9249, 0x12975362, 0xd2c7de}}}, + /* 11*16^17*G: */ + {{{0x0bb69991, 0x0d240fe4, 0x0c1c5d75, 0x167f4586, 0x0f535fff, 0x0b310701, 0x0f1a19a8, 0x08f759cf, 0xdea2ba}}, + {{0x116fe2df, 0x033a154f, 0x07b66f1c, 0x1b9b66c4, 0x1b9e7229, 0x1ff6427b, 0x0392b172, 0x1adb2185, 0xae28bf}}}, + /* 13*16^17*G: */ + {{{0x114fc9cc, 0x01206812, 0x09185963, 0x00157853, 0x0a83626d, 0x07b6625c, 0x035bbf07, 0x1314dc2d, 0x3968fc}}, + {{0x1fad37dd, 0x0c9ca44a, 0x023ccd00, 0x08caedff, 0x132c91a1, 0x0c168d56, 0x04a048de, 0x1a1b696b, 0x789cbb}}}, + /* 15*16^17*G: */ + {{{0x0e0c85f1, 0x17610c8d, 0x0e8e8942, 0x0a5ca6c0, 0x145d5a6a, 0x0ef84abc, 0x08a49ac9, 0x00d31c0d, 0x689691}}, + {{0x0dc1de21, 0x03a41199, 0x1540e48b, 0x01833b41, 0x1d72d1f4, 0x02e0ec22, 0x1e495bcc, 0x16967192, 0xaefd3f}}} + }, + { + /* 1*16^18*G: */ + {{{0x00c82a0a, 0x1ecacd7b, 0x19a20cbf, 0x044d8c1e, 0x013b10f9, 0x04f8c8ca, 0x0291ac1b, 0x10136331, 0x948bf}}, + {{0x18c8e589, 0x065bfc46, 0x1f34afb5, 0x1bfe1192, 0x1418c6d4, 0x1a62e8e1, 0x191b71ad, 0x10adb96c, 0x53a562}}}, + /* 3*16^18*G: */ + {{{0x18c8ac7f, 0x1417f2fd, 0x18aa949c, 0x0485dccb, 0x0f849641, 0x1cb6902b, 0x0ef2d70c, 0x1f7c7045, 0x9945b2}}, + {{0x09aea3b0, 0x16ca1d0b, 0x16b37ea5, 0x1ef447dd, 0x0eff5282, 0x1a27fd94, 0x00b581f6, 0x104961e5, 0x3eefed}}}, + /* 5*16^18*G: */ + {{{0x169e353a, 0x08ebcf1c, 0x0ef87dbb, 0x008810a5, 0x1d5fe10a, 0x01113883, 0x03988d7e, 0x0d640b0e, 0x2a314c}}, + {{0x05746067, 0x12c9370f, 0x09962ff0, 0x14a955b6, 0x01ba0138, 0x1f23b5d5, 0x1eb06918, 0x017e6b44, 0x15a4ac}}}, + /* 7*16^18*G: */ + {{{0x09b84966, 0x0f17a4f7, 0x1fcffe62, 0x1e820dba, 0x16c911b4, 0x17d79d35, 0x10b5262d, 0x0016e07f, 0x5959a5}}, + {{0x07473a6a, 0x0533190c, 0x1f890990, 0x01b98119, 0x02a70910, 0x094106e4, 0x025fe50c, 0x0e83eb95, 0x370e6}}}, + /* 9*16^18*G: */ + {{{0x0bc6b173, 0x1864dc91, 0x1b4fface, 0x10c478fd, 0x15f9d7dd, 0x0623182d, 0x1fa38458, 0x0726e445, 0x9eeb31}}, + {{0x1723a71d, 0x09cb106c, 0x19c312e5, 0x0e357da1, 0x01ae30ea, 0x15fedddd, 0x163654aa, 0x1c0221da, 0xe121f1}}}, + /* 11*16^18*G: */ + {{{0x1ec805f3, 0x1b9221fb, 0x16656455, 0x081eea13, 0x097887de, 0x191c4037, 0x03d45bae, 0x1c98fee3, 0x39cc4f}}, + {{0x1a3c48d3, 0x0c8d0609, 0x1244b934, 0x12ae6e7f, 0x0de7dbbb, 0x1349e7a1, 0x03cc5479, 0x058b48df, 0xecb147}}}, + /* 13*16^18*G: */ + {{{0x0e22580e, 0x1eb17dae, 0x15be21e4, 0x06512da5, 0x1d4d2c71, 0x1fef326d, 0x11a5a24b, 0x0e8cdd9b, 0xf94c80}}, + {{0x1127db82, 0x0f291fb3, 0x0dc753a0, 0x0fd88a64, 0x081f6988, 0x1ffb55ad, 0x096a4652, 0x1b8cf0a4, 0x5e9c7f}}}, + /* 15*16^18*G: */ + {{{0x10c4f21f, 0x1f205d68, 0x00f69e9a, 0x0952b29a, 0x199d2502, 0x10346d8c, 0x058bf300, 0x0d8d5aba, 0x8cccb8}}, + {{0x129dfea0, 0x1f893753, 0x192f8a3d, 0x05b95904, 0x158a54b9, 0x17aa4e43, 0x110da66f, 0x0b0c4ea3, 0x57f896}}} + }, + { + /* 1*16^19*G: */ + {{{0x138fd8e8, 0x0766c0cf, 0x1a5d4ab3, 0x01c89bf8, 0x073a8f1b, 0x1e707814, 0x070d3c19, 0x0fe8c300, 0x6260ce}}, + {{0x12b4ae17, 0x0d4274ad, 0x14706630, 0x05244700, 0x01ef7ecd, 0x0824bbb5, 0x15c69fc2, 0x056df4b6, 0xbc2da8}}}, + /* 3*16^19*G: */ + {{{0x01136602, 0x185d232a, 0x078e96ee, 0x08de901b, 0x13b3d38c, 0x049bf919, 0x1f0cf416, 0x0500905b, 0x87d127}}, + {{0x18af6aac, 0x1b41e20e, 0x14efdf13, 0x1108e8df, 0x1745387a, 0x13b67fb3, 0x0f7a49a8, 0x10e14b40, 0x71ce24}}}, + /* 5*16^19*G: */ + {{{0x08c5a916, 0x1902eb9a, 0x15843c96, 0x18881aa6, 0x14aa13f5, 0x0631ed5a, 0x05d1ac2b, 0x07fc4c3d, 0xfd5d7d}}, + {{0x1adb8bda, 0x0a59bd83, 0x13dbeaac, 0x0e70297b, 0x1b52fe5d, 0x1e533ce3, 0x0c1f4ad0, 0x1a1dd6ab, 0xdd83e}}}, + /* 7*16^19*G: */ + {{{0x15f7529c, 0x0ecc84b1, 0x0f547751, 0x0cb7316b, 0x04381387, 0x09e1969a, 0x1848ae91, 0x02130384, 0xde0dd4}}, + {{0x04cd88fe, 0x1e106017, 0x06ddd018, 0x12498d11, 0x03570178, 0x04c116bd, 0x117e6c84, 0x13a21442, 0xd70a6e}}}, + /* 9*16^19*G: */ + {{{0x18f76d11, 0x0417a469, 0x014555cf, 0x02001f7f, 0x092a2151, 0x1f7e1ce1, 0x1139a716, 0x115b499e, 0xb26c20}}, + {{0x03b7356b, 0x00e0058f, 0x009892f7, 0x0060cb3b, 0x16433050, 0x143ec866, 0x0cf3c313, 0x1041293a, 0x1f1cf8}}}, + /* 11*16^19*G: */ + {{{0x069e22db, 0x0a71d833, 0x07224cfe, 0x127feb3f, 0x0294eac9, 0x1e9480c6, 0x148e9f8e, 0x171f8ffe, 0xfceb14}}, + {{0x1c2260a1, 0x1ab96d92, 0x13af932f, 0x0a1cf274, 0x10924ad5, 0x12d3a92f, 0x0347f362, 0x07481ad7, 0x64aa6b}}}, + /* 13*16^19*G: */ + {{{0x038a2755, 0x18420bcd, 0x1271541b, 0x0434e2ca, 0x07faa537, 0x1abba5a8, 0x12b15705, 0x0c4799ab, 0x4e909a}}, + {{0x03cca3de, 0x1bd24fb1, 0x0a60032b, 0x1aa729a4, 0x159dbb6c, 0x036ea83a, 0x16bb3bc9, 0x10f199c6, 0xae56da}}}, + /* 15*16^19*G: */ + {{{0x183ba64d, 0x012c4acc, 0x116568ea, 0x0c1eef11, 0x040e2bde, 0x10a2f5c7, 0x100efec2, 0x0b845c09, 0xc36745}}, + {{0x0a2181fd, 0x0a6647cb, 0x1de3c518, 0x04d55942, 0x164c7426, 0x0737426c, 0x00cc2038, 0x1a0d396c, 0x3a520a}}} + }, + { + /* 1*16^20*G: */ + {{{0x0037fa2d, 0x0a9e6469, 0x0ff710ca, 0x1d91eaeb, 0x14103043, 0x0420a5df, 0x0350f60d, 0x1c15f83b, 0xe5037d}}, + {{0x1d755bda, 0x072ee420, 0x1207c438, 0x1eb607d8, 0x10bddbd5, 0x0684fdcc, 0x0ed7e7e6, 0x0975529a, 0x457153}}}, + /* 3*16^20*G: */ + {{{0x177e7775, 0x04545370, 0x1b657d8e, 0x02ab2711, 0x091aeb5e, 0x01dd67a9, 0x0f3b9615, 0x075ff2c6, 0x9d896a}}, + {{0x1a056691, 0x1e7b69d5, 0x06494efb, 0x139afdc5, 0x0927de89, 0x1276b928, 0x1c2e53a5, 0x1c87e937, 0xdd91a9}}}, + /* 5*16^20*G: */ + {{{0x1c2a3293, 0x1ef026f1, 0x00d1db17, 0x1170ddd2, 0x0f4cd568, 0x052b9941, 0x1e4b43ac, 0x1dce22c6, 0x8327b8}}, + {{0x0e0df9bd, 0x1e42a70c, 0x0c9a905a, 0x1fb569dc, 0x1708496a, 0x1f53313c, 0x063862ec, 0x04cddc15, 0x4997e}}}, + /* 7*16^20*G: */ + {{{0x0562c042, 0x010d9362, 0x037ec689, 0x1a464697, 0x08ed6092, 0x130ec7cd, 0x05a25f59, 0x15454db6, 0x5ae42a}}, + {{0x0f79269c, 0x082e66fc, 0x1f3636fe, 0x01b72a20, 0x09d4a94e, 0x0eee301c, 0x147aad70, 0x0f80bfe0, 0x99d93a}}}, + /* 9*16^20*G: */ + {{{0x1e85af61, 0x1a440942, 0x12b9d9ac, 0x1dae45ba, 0x01b0f4e8, 0x1b47fb61, 0x03ad66ba, 0x1c84d439, 0x92c23a}}, + {{0x036a2b09, 0x1391b34e, 0x0a1bfb53, 0x075b056c, 0x0d5792d2, 0x0beae39c, 0x0ed027c8, 0x11e02aa3, 0x414cf8}}}, + /* 11*16^20*G: */ + {{{0x07b5eba8, 0x11578d96, 0x063a8db3, 0x17db8ff2, 0x0df422da, 0x1a0bb57c, 0x1c422343, 0x118ed5fb, 0xfee560}}, + {{0x0d0b9b5c, 0x1a8ae9b4, 0x04151e4f, 0x01fe857f, 0x1c14ee38, 0x017cc943, 0x02bec450, 0x12269fcb, 0x380759}}}, + /* 13*16^20*G: */ + {{{0x1c63caf4, 0x0f1dd259, 0x1d4f54a0, 0x1fe75651, 0x06afca28, 0x09da6315, 0x1f988284, 0x1d725ccc, 0x42e544}}, + {{0x169c29c8, 0x03d7604c, 0x1bf17c46, 0x0a1cf6d7, 0x15e7873a, 0x11060ba0, 0x19c7dc7c, 0x1c1f2398, 0x9ff854}}}, + /* 15*16^20*G: */ + {{{0x1e0f09a1, 0x0515ecc2, 0x100ca0e0, 0x0213e372, 0x00efef0a, 0x17695238, 0x138e0e65, 0x16ccaa65, 0x7aed83}}, + {{0x05857d73, 0x02ec66f4, 0x0fd29501, 0x165e601e, 0x12d8ed88, 0x1e855881, 0x1df1f76b, 0x0bf3463d, 0xf5b854}}} + }, + { + /* 1*16^21*G: */ + {{{0x04fce725, 0x0c335057, 0x09b16dc9, 0x11b7a38d, 0x171b4e7e, 0x082f478b, 0x1eb7d7aa, 0x161e9440, 0xe06372}}, + {{0x0eee31dd, 0x1381a7ca, 0x04121c2c, 0x1094ef0e, 0x0488cd74, 0x1dd956ad, 0x13f84a89, 0x0e979c31, 0x7a9089}}}, + /* 3*16^21*G: */ + {{{0x1a328d6a, 0x1d540c46, 0x0b7062f6, 0x1aee752b, 0x08fa7b24, 0x04c8c2d8, 0x18028d1a, 0x0b74c469, 0xc663c0}}, + {{0x1ec9b8c0, 0x1d85db55, 0x0afe7308, 0x0aa3d4a2, 0x11317dd8, 0x1ee793ab, 0x10e34e6b, 0x11abee43, 0x3331e9}}}, + /* 5*16^21*G: */ + {{{0x1996de2f, 0x048e4241, 0x0c94452f, 0x1dbe5dc1, 0x1e4e977c, 0x186f7507, 0x091673ac, 0x105bf70d, 0xd3fc26}}, + {{0x14526f8c, 0x0249120e, 0x1eafc5a3, 0x136931be, 0x181da4e5, 0x03aa6a7b, 0x0863da2d, 0x13348be1, 0xc4f0df}}}, + /* 7*16^21*G: */ + {{{0x03e697ea, 0x03624688, 0x17e0fa17, 0x0cf1f730, 0x1abd19ce, 0x0ff64d1f, 0x008df728, 0x087fd658, 0xc17a4b}}, + {{0x1edc6c87, 0x171dc3ee, 0x07c0aac3, 0x03436aff, 0x01fae96e, 0x1c7b8cb0, 0x05532b85, 0x05aab56b, 0x39355c}}}, + /* 9*16^21*G: */ + {{{0x1163da1b, 0x16961811, 0x04e8c460, 0x1dbdcc1f, 0x11fde9a0, 0x1a4ebfe0, 0x02d1a324, 0x0f944cf2, 0x8f618b}}, + {{0x03bdd76e, 0x1f989088, 0x126db9f1, 0x018cd464, 0x05a42645, 0x0d3a6bd6, 0x0dbad7ef, 0x04be117d, 0x78233f}}}, + /* 11*16^21*G: */ + {{{0x0ec8ae90, 0x142c87f0, 0x0ef177bb, 0x04d725d1, 0x1f1b8cfb, 0x0dc6d641, 0x19bae1b5, 0x1e2b6f43, 0x9798c0}}, + {{0x052844d3, 0x14d61757, 0x0c62389e, 0x092cb7a0, 0x073bee2e, 0x04a4a7ce, 0x1b4f74bb, 0x154eb485, 0xba40e2}}}, + /* 13*16^21*G: */ + {{{0x11d66b7f, 0x0d0cbc78, 0x01f72041, 0x0d24a0a3, 0x084757aa, 0x0dc85c49, 0x159d1f3c, 0x1c7f6b45, 0xfdfa6e}}, + {{0x18e5178b, 0x1547c033, 0x15e37a76, 0x0df3ba27, 0x018c4d84, 0x00e4d1ed, 0x036e4f03, 0x03c44933, 0x4d9cf3}}}, + /* 15*16^21*G: */ + {{{0x1265bcf0, 0x003abc24, 0x071f4c2e, 0x1c56f082, 0x1220e69c, 0x14d230e7, 0x190eb77a, 0x071bc453, 0xfd58ce}}, + {{0x0b996292, 0x19f3d4e7, 0x1c73477c, 0x0c37fc51, 0x1e4fb872, 0x155cd242, 0x056f54e0, 0x1ca6ec64, 0xffe0a5}}} + }, + { + /* 1*16^22*G: */ + {{{0x10559754, 0x056b4846, 0x08fd6150, 0x0217bbc5, 0x0e02204b, 0x1dfcee06, 0x114d6342, 0x0e2b9aba, 0x213c7a}}, + {{0x14b458f2, 0x1f9613a9, 0x1a9fbb77, 0x10a1ebe6, 0x1a190bb4, 0x1683122d, 0x0941c04e, 0x016b5c8c, 0x4b6dad}}}, + /* 3*16^22*G: */ + {{{0x1e05dccc, 0x196c008c, 0x066a4f94, 0x1f47da98, 0x1d172ae3, 0x104b5ca9, 0x00c2551b, 0x1c2ea7b4, 0xb8cef6}}, + {{0x0c6d5750, 0x00a5067e, 0x1ada04cc, 0x0aff86d4, 0x0bd99df7, 0x053a7269, 0x0efda935, 0x0c14d993, 0x302b8a}}}, + /* 5*16^22*G: */ + {{{0x173bb31a, 0x0deff709, 0x16e5ed21, 0x1ef6d6bf, 0x15f49701, 0x05ef175d, 0x0e1780a8, 0x1cef368e, 0x3fb33}}, + {{0x1d215c9e, 0x1a65f34b, 0x1d903538, 0x14f8ed88, 0x1572bc65, 0x0b0d55dd, 0x18a07830, 0x0a4a91df, 0xf36ad9}}}, + /* 7*16^22*G: */ + {{{0x1d9a4ab4, 0x0da8af5e, 0x16edf029, 0x186d830a, 0x17a36717, 0x17bda687, 0x184587c5, 0x1a213d87, 0x4b177c}}, + {{0x035ab6f7, 0x156eff23, 0x1d07d562, 0x0fc4abe2, 0x06b486e3, 0x1b3949b1, 0x0997f6a3, 0x1d34bc5f, 0x3ec966}}}, + /* 9*16^22*G: */ + {{{0x101c23a4, 0x1a37d94d, 0x09273d5b, 0x1482b08f, 0x1cd75c22, 0x1c14dcdc, 0x081b0a80, 0x0a40d44f, 0x5e8703}}, + {{0x10d986f9, 0x10bccb58, 0x1333f684, 0x0e3b0e94, 0x06e2da21, 0x0ae8d716, 0x08879c5d, 0x09df7392, 0x5b9664}}}, + /* 11*16^22*G: */ + {{{0x007b0c66, 0x19f9ae90, 0x1b21bec7, 0x0ffdc8ca, 0x0eb7434a, 0x1227b056, 0x002911c8, 0x003261ad, 0xe545c3}}, + {{0x11f2d470, 0x03fabe93, 0x1688e776, 0x0b051c36, 0x1bcbf97e, 0x17ed1cac, 0x1579f971, 0x01d18c52, 0xe06a34}}}, + /* 13*16^22*G: */ + {{{0x03648bba, 0x12c0c85c, 0x10f1d112, 0x01e160d3, 0x1b39882a, 0x17112f80, 0x160284cf, 0x02af4a9e, 0xb2a442}}, + {{0x00fb6452, 0x037d5a50, 0x0705eec9, 0x10aa2a39, 0x17e31c0d, 0x1e4bc7de, 0x19867a7e, 0x1856d26c, 0xfe4f5f}}}, + /* 15*16^22*G: */ + {{{0x0bab27d0, 0x1b6e9177, 0x11440ff3, 0x1683f458, 0x17007f70, 0x180c8c6c, 0x01946ea5, 0x01e7a8a7, 0x1b908e}}, + {{0x00d3d110, 0x0f433af2, 0x1f946d5c, 0x179526b0, 0x04b9ab5b, 0x1e48c0be, 0x0d79bcd5, 0x0bdd88cd, 0x9b6d62}}} + }, + { + /* 1*16^23*G: */ + {{{0x08fbd53c, 0x0661d1d8, 0x118b377c, 0x0718e15b, 0x19a87e28, 0x09a952a0, 0x0d3a36ee, 0x054f5e96, 0x4e7c27}}, + {{0x17dcaae6, 0x059ca0c0, 0x1df74cf8, 0x172c297f, 0x1681b530, 0x084fb6f7, 0x0c6385bf, 0x0ecd93a1, 0x17749c}}}, + /* 3*16^23*G: */ + {{{0x0521b3ff, 0x114c2327, 0x0a9d433b, 0x180e2fd3, 0x024a5233, 0x0695f4d7, 0x1571d791, 0x06021928, 0x2484e}}, + {{0x0269da7e, 0x00d725c8, 0x0eb22ef3, 0x000dbd24, 0x10eebad7, 0x159e1596, 0x0c341fb0, 0x1415447c, 0x9619d0}}}, + /* 5*16^23*G: */ + {{{0x004ba7b9, 0x0b5bcfd4, 0x1d05d47e, 0x0d48e060, 0x0954e20d, 0x1b86b396, 0x195fbde6, 0x04d9f6d9, 0x16c1c5}}, + {{0x1c5bd741, 0x1adf1d28, 0x126a7311, 0x0ab8037b, 0x094deec7, 0x13a2ce45, 0x10e41898, 0x0f868062, 0xdb157f}}}, + /* 7*16^23*G: */ + {{{0x036683fa, 0x01b243d5, 0x1b02097a, 0x0436a701, 0x07b66958, 0x0e73ba29, 0x06be1ea2, 0x1aea7f26, 0x3973c}}, + {{0x1f4a577f, 0x1afd95bb, 0x1a6077b7, 0x1109c31f, 0x1a26cd77, 0x095b195a, 0x0e8d90f8, 0x05986194, 0x38cf5a}}}, + /* 9*16^23*G: */ + {{{0x00bf6f06, 0x0059ccce, 0x010ed5c6, 0x1826644a, 0x05765713, 0x027a5810, 0x054470b0, 0x174e5d9e, 0xba6a9b}}, + {{0x181db551, 0x195f7b83, 0x1a5eabf8, 0x1a29ef58, 0x0bd8e9e5, 0x05f972ac, 0x06c0c808, 0x07166942, 0x13771e}}}, + /* 11*16^23*G: */ + {{{0x11231a43, 0x08f7cf83, 0x0b50ee7f, 0x0a29accb, 0x0442f44d, 0x0ca8326f, 0x174b62bb, 0x1984f989, 0x35c5bc}}, + {{0x1620c8f6, 0x0db97228, 0x0f3c2b9f, 0x0f49980c, 0x0589d4cf, 0x0c105b7d, 0x1b39cd39, 0x0e4772e8, 0xe3675}}}, + /* 13*16^23*G: */ + {{{0x1dd40609, 0x1a05e2b7, 0x00735daf, 0x0321301b, 0x0356ac74, 0x1897e2c4, 0x1af2848b, 0x048b8ab0, 0xfd479c}}, + {{0x0a64ca53, 0x0f1789b3, 0x07291ce7, 0x075dae4c, 0x041fd911, 0x0bd21e4c, 0x1fbfcb2b, 0x16a4d295, 0x3069cf}}}, + /* 15*16^23*G: */ + {{{0x0b799a7f, 0x0db817a9, 0x0e3a1093, 0x116d9aa7, 0x07d544f1, 0x075cd796, 0x0192f7b6, 0x0547599b, 0x6c4000}}, + {{0x13c81e32, 0x1ae64166, 0x0120fda2, 0x157a9904, 0x1dcbdc07, 0x01b5070e, 0x16f9a42e, 0x02a616c6, 0x95c2dc}}} + }, + { + /* 1*16^24*G: */ + {{{0x00fb27b6, 0x1213f142, 0x10c15d8c, 0x1c7b657c, 0x06aa5c76, 0x1c56b0b4, 0x0c6c43c8, 0x07b7cef1, 0xfea74e}}, + {{0x123cb96f, 0x00e9edbf, 0x0fdedddc, 0x16b2d72e, 0x0af93126, 0x1a6f665b, 0x0ca5f3d9, 0x1b736162, 0x6e0568}}}, + /* 3*16^24*G: */ + {{{0x1e889756, 0x0ec0d74d, 0x0012ec97, 0x16c932f6, 0x099f3f27, 0x0cbd938c, 0x1aa089b3, 0x1866423f, 0x762e8b}}, + {{0x1ca6b774, 0x0f12cf03, 0x013e9789, 0x05b66291, 0x0e347197, 0x0278a4c1, 0x05f0f1f3, 0x04c15e7d, 0xc02894}}}, + /* 5*16^24*G: */ + {{{0x0975d2ea, 0x17baf4b8, 0x053a3a89, 0x0559f420, 0x0f4a91e5, 0x1edd9184, 0x14d23866, 0x08fbec12, 0xdf077d}}, + {{0x11936f95, 0x11e16cf1, 0x0f749dea, 0x1d8b709f, 0x0527c8a1, 0x012e4c51, 0x1d109321, 0x11001def, 0xf8617a}}}, + /* 7*16^24*G: */ + {{{0x1c4c92d7, 0x1c248fdd, 0x10e46d16, 0x169addca, 0x1142935d, 0x0f5419a5, 0x080cb85f, 0x0eb17a7b, 0x9f3e7d}}, + {{0x114906dd, 0x05ddfe7d, 0x0538461b, 0x144607ad, 0x11502452, 0x1590e5d5, 0x19ad6218, 0x03d4efa8, 0xecd284}}}, + /* 9*16^24*G: */ + {{{0x12a8c483, 0x1706b995, 0x0102b0d6, 0x1619118a, 0x15281174, 0x01e9177c, 0x1e7b70e3, 0x0baf6b99, 0xa0cc79}}, + {{0x12cc6ba9, 0x04b3a2ac, 0x1a4d8154, 0x091e37be, 0x1df786b3, 0x07e4b918, 0x1cfb88dd, 0x045f1670, 0xabc301}}}, + /* 11*16^24*G: */ + {{{0x05dd3aee, 0x1878db5e, 0x05b4bc85, 0x0a75151f, 0x176ca131, 0x154d6354, 0x1f338388, 0x14a2aa78, 0x6d1c50}}, + {{0x1df597f7, 0x171aa727, 0x1b54eb7f, 0x1c621551, 0x1d474851, 0x19001143, 0x1f725dc9, 0x11c0d57b, 0xafff14}}}, + /* 13*16^24*G: */ + {{{0x04a6d0bb, 0x1c654dbf, 0x086bf719, 0x1a6245eb, 0x0418f659, 0x136c5453, 0x07cfcc46, 0x0c3172ff, 0x5e5f1d}}, + {{0x1033eaf9, 0x141c23c8, 0x1bd94e85, 0x0abe5ca0, 0x121da725, 0x15e68273, 0x1bdcd63d, 0x0560d4fc, 0xd7b150}}}, + /* 15*16^24*G: */ + {{{0x0f005e3f, 0x0d4daf22, 0x10e6f4b7, 0x0d1c637d, 0x1a1495af, 0x05cd6700, 0x09ffff4f, 0x0d6782c8, 0xf8138a}}, + {{0x0f357eb7, 0x16bf0101, 0x12f884d0, 0x18837aaa, 0x1cb51f4e, 0x0af2bd52, 0x0f67e740, 0x077df69d, 0xca758f}}} + }, + { + /* 1*16^25*G: */ + {{{0x17bdde39, 0x16015220, 0x1810ca54, 0x09c2f36e, 0x168d3154, 0x0b86accc, 0x1c384289, 0x027ecef9, 0x76e641}}, + {{0x1901ac01, 0x058ba968, 0x1b480cad, 0x1467a56a, 0x1f0d35e2, 0x136b8340, 0x173d5dc1, 0x11bdc9d2, 0xc90ddf}}}, + /* 3*16^25*G: */ + {{{0x0078ee8d, 0x182848e6, 0x1a46510b, 0x1e419ca0, 0x14ff64eb, 0x1931d54d, 0x06f897fd, 0x15b0b3b5, 0xd08e57}}, + {{0x0da63e86, 0x0cbfa6e1, 0x08bb677a, 0x1def9f28, 0x06df4123, 0x19773abf, 0x035cb585, 0x13095691, 0x852e97}}}, + /* 5*16^25*G: */ + {{{0x029129ec, 0x0c8a3382, 0x12095205, 0x1c759e3c, 0x11d080ca, 0x1f407669, 0x149d7d62, 0x10bc9a89, 0x7da6c0}}, + {{0x0cd9ff0e, 0x1a857715, 0x12961aba, 0x11810ca9, 0x027bf044, 0x0103a48b, 0x015d4474, 0x0d773e83, 0xf49814}}}, + /* 7*16^25*G: */ + {{{0x11654f22, 0x1c1ea4aa, 0x06abba53, 0x0fe72846, 0x1d94fb2f, 0x0800df34, 0x19b886fa, 0x19feb837, 0x90d090}}, + {{0x001a43e1, 0x1aef02bb, 0x08fe1d03, 0x0c6aca7b, 0x170336dd, 0x010f035f, 0x186a54fc, 0x03a5759e, 0xcd569a}}}, + /* 9*16^25*G: */ + {{{0x076b19fa, 0x1b77b28e, 0x020675c6, 0x0dc0da0d, 0x1292ed9d, 0x16188410, 0x07b31cc8, 0x0b0f9e3a, 0xda4798}}, + {{0x126f5af7, 0x15137759, 0x14ff081a, 0x17a27d2a, 0x0569ea67, 0x1483bf0b, 0x1c0745cd, 0x0f137995, 0xebb1d7}}}, + /* 11*16^25*G: */ + {{{0x19135dbd, 0x0c97db2d, 0x1618c7b3, 0x010f5e73, 0x1897cf0c, 0x157ac174, 0x19ab605e, 0x00951bbd, 0xe3e475}}, + {{0x0748045d, 0x083579f2, 0x12576a5a, 0x0405febd, 0x03ffea5a, 0x040ca95c, 0x1b102e63, 0x1f013978, 0x930a5b}}}, + /* 13*16^25*G: */ + {{{0x0dee455f, 0x1f85cf2e, 0x13901d72, 0x0fffcdd1, 0x1db4aff6, 0x099c7c05, 0x06c291d1, 0x0dfd0e15, 0x7e8c65}}, + {{0x171b9cba, 0x19ef4cc0, 0x1d1989c5, 0x05a2ce8d, 0x1a53b4aa, 0x1b07a401, 0x103ca8fd, 0x0659460e, 0xbdddc6}}}, + /* 15*16^25*G: */ + {{{0x0698b59e, 0x1bcb5cdb, 0x0d11e90d, 0x06b24b12, 0x1c7260a3, 0x01ad59f1, 0x1ac56fac, 0x1f12352b, 0x3df841}}, + {{0x0b92baf5, 0x07c733cb, 0x12527e2f, 0x190cf642, 0x0f3867bf, 0x1d74788e, 0x0307680a, 0x1bf31612, 0xb38fe6}}} + }, + { + /* 1*16^26*G: */ + {{{0x0bcbb891, 0x158a8121, 0x09b2fb8e, 0x198c87be, 0x18f9a8f7, 0x0dd53a1f, 0x0f87a0a0, 0x0d607655, 0xc738c5}}, + {{0x099a84c3, 0x1f39aecb, 0x0033fa45, 0x029ddef1, 0x1bbbb823, 0x0797565f, 0x094dfdc6, 0x0f12a35a, 0x893fb5}}}, + /* 3*16^26*G: */ + {{{0x0761d58d, 0x05d5799c, 0x15838bcd, 0x1937c811, 0x0df7aca4, 0x0051ab90, 0x05184289, 0x04f047ec, 0xb8c461}}, + {{0x1d1051a4, 0x1c7505d4, 0x041f16d8, 0x0a08f0bc, 0x1c5053f7, 0x0c7b4bf9, 0x0df45291, 0x0d8a2e1c, 0x8f9ed9}}}, + /* 5*16^26*G: */ + {{{0x050b0040, 0x0d859820, 0x04d2b70b, 0x08fb73e0, 0x03671f3f, 0x04c9ff4d, 0x07de8d43, 0x13ee204e, 0x8d56e}}, + {{0x1b3fd0a1, 0x0c7133d2, 0x05e0afad, 0x0f88e41c, 0x1b285f6d, 0x0a8546bc, 0x0a887ff4, 0x15d7a153, 0xa12185}}}, + /* 7*16^26*G: */ + {{{0x13573b7f, 0x0b2b1ef8, 0x02d89c3d, 0x1438bda6, 0x05a37889, 0x07cbbdf3, 0x198d0788, 0x065a85f9, 0xdc13f2}}, + {{0x0c1f2ba6, 0x15669142, 0x1012c710, 0x0aa8e02e, 0x10a76704, 0x086d4254, 0x1030f1d0, 0x100853c6, 0xc909ba}}}, + /* 9*16^26*G: */ + {{{0x07ae9ceb, 0x017ac85c, 0x1bcb452c, 0x1843d4e1, 0x119a8226, 0x0ab2ed90, 0x1c1cebc6, 0x1cc03bef, 0x25c02d}}, + {{0x0bc6e275, 0x1848689a, 0x1961c991, 0x0c83be14, 0x111d537c, 0x0706e7d6, 0x00f03221, 0x1a590247, 0x8a9fea}}}, + /* 11*16^26*G: */ + {{{0x0c5a3c34, 0x1c04c7b7, 0x16527f87, 0x1d058052, 0x03e58aec, 0x0fa653d7, 0x1273a2ae, 0x03659f1c, 0xfedd9d}}, + {{0x013d7714, 0x15aa5fa7, 0x0fe0a5d8, 0x1d6a8d33, 0x14b00ada, 0x02989647, 0x0382c2fa, 0x18630a77, 0xa52e24}}}, + /* 13*16^26*G: */ + {{{0x0ab6a396, 0x1a72a68d, 0x04d81da6, 0x04372342, 0x088b3730, 0x16bfaf42, 0x1230b7b8, 0x10d78dd4, 0x3e0e32}}, + {{0x1980e27e, 0x1598f246, 0x11a3da8b, 0x002083e6, 0x13fc66ab, 0x1f0ef5a2, 0x1e593cc7, 0x0e5f4766, 0xca4481}}}, + /* 15*16^26*G: */ + {{{0x141023ec, 0x179ac311, 0x1b3d5c2a, 0x0bb1eedf, 0x0b9af564, 0x101004c1, 0x14a1260b, 0x06101865, 0x344ab9}}, + {{0x1e1eeb87, 0x07c4c148, 0x0e6575c1, 0x1d2ed5f8, 0x14c5ffc4, 0x1968f528, 0x18a9cfe3, 0x00856488, 0x6e1c2b}}} + }, + { + /* 1*16^27*G: */ + {{{0x08f6c14b, 0x1974fb2c, 0x0494050d, 0x0e5cbe75, 0x12877d1d, 0x03b1be4b, 0x0e078993, 0x0ca916cb, 0xd89562}}, + {{0x1d7d991f, 0x09b1f6ba, 0x0c19f85e, 0x051ac657, 0x140eb034, 0x03040c61, 0x1ab9ca3b, 0x071e578f, 0xfebfaa}}}, + /* 3*16^27*G: */ + {{{0x0127b756, 0x05d43ffb, 0x0825c120, 0x0517c957, 0x0b416034, 0x116d2830, 0x0499cb4d, 0x05ee2dbe, 0x6d8c78}}, + {{0x1f172571, 0x0a8fba55, 0x1f373299, 0x154db45a, 0x14daf4e3, 0x14169b69, 0x04445166, 0x0112dfb7, 0x99aedf}}}, + /* 5*16^27*G: */ + {{{0x158cf17a, 0x0f70d39b, 0x0208d493, 0x10bb974b, 0x097f8f1f, 0x0d778da0, 0x0b2a3416, 0x1bb2b7ef, 0xebcabe}}, + {{0x1caa0ccd, 0x0366e2fa, 0x0b3a5711, 0x15a425a1, 0x12e6b10f, 0x050db3e1, 0x072c0b00, 0x01f1e457, 0x47d3ce}}}, + /* 7*16^27*G: */ + {{{0x0c855c5b, 0x077728ad, 0x1f22beef, 0x0ac43402, 0x1fc28118, 0x0d1b4f0b, 0x189114cc, 0x05c97a99, 0xe8df4d}}, + {{0x0e465650, 0x0eaf3961, 0x07935f56, 0x076abe3c, 0x132c5966, 0x0da7acf7, 0x0c991113, 0x0e188ff3, 0x6c57fd}}}, + /* 9*16^27*G: */ + {{{0x12e7e454, 0x047aded2, 0x03985434, 0x05dfde1e, 0x01662fe3, 0x03011d4c, 0x00ca4492, 0x1ae31d95, 0x4068d3}}, + {{0x18ef191e, 0x1cd66f2e, 0x10dccc9d, 0x1a43da27, 0x138d1988, 0x0a2cbece, 0x1eaae7b0, 0x16e4a948, 0x8cd853}}}, + /* 11*16^27*G: */ + {{{0x06c5d939, 0x02bd6fc2, 0x0a4cf782, 0x0b450ef7, 0x0027ea47, 0x19973065, 0x1782d56f, 0x19b63b04, 0x12550e}}, + {{0x19e757c9, 0x153a7e2a, 0x16350c64, 0x16e83fd9, 0x04a72838, 0x121e0bb9, 0x1e9d5123, 0x069f0e5a, 0x7b8f83}}}, + /* 13*16^27*G: */ + {{{0x16c8a56f, 0x06855632, 0x1cdd084e, 0x1278a869, 0x0d08f850, 0x1bda9d7d, 0x17531a6e, 0x035876b0, 0x944d67}}, + {{0x1a7be289, 0x0fa6e32e, 0x01945fae, 0x0982e9ba, 0x0c61967d, 0x1c9b099d, 0x1ffd3050, 0x12ef6a03, 0xa71065}}}, + /* 15*16^27*G: */ + {{{0x0e08f15a, 0x175c50c5, 0x04a402eb, 0x13cadb90, 0x1c305fd6, 0x01b2ad69, 0x0833f9ac, 0x1239a133, 0x86a54e}}, + {{0x01388308, 0x09268f3e, 0x0d49534d, 0x053a24b6, 0x16867771, 0x146836ba, 0x1180e9ca, 0x0906f4f0, 0xcfee61}}} + }, + { + /* 1*16^28*G: */ + {{{0x0f676e03, 0x08a852b2, 0x1a13b752, 0x1f8e6d27, 0x08761cef, 0x1219ab8f, 0x1463ac3d, 0x006552ae, 0xb8da94}}, + {{0x0efdf6e7, 0x0447273a, 0x1fced445, 0x18b09b2b, 0x008b092c, 0x0e64bb14, 0x07935f26, 0x148900b4, 0x2804df}}}, + /* 3*16^28*G: */ + {{{0x06e1346b, 0x10cc24ee, 0x16bc717a, 0x1cf62070, 0x152c05ab, 0x1b0f8a68, 0x042f9531, 0x1fe1305a, 0x69068}}, + {{0x17226c13, 0x1dac52a6, 0x11809b9e, 0x0d127329, 0x0442aa4f, 0x0d95e843, 0x189b6a17, 0x1c1217fb, 0xb863e3}}}, + /* 5*16^28*G: */ + {{{0x1ca1f6a1, 0x07348fe6, 0x033fc68c, 0x197a2869, 0x06ce1068, 0x0e2e58f4, 0x1d854a1b, 0x127964b2, 0x898c34}}, + {{0x164f647c, 0x056e1078, 0x0af5e729, 0x0f9f2f3e, 0x06e93b2a, 0x0a122956, 0x15527611, 0x10d56ad4, 0x75f759}}}, + /* 7*16^28*G: */ + {{{0x1d1e3998, 0x134f01e1, 0x0810ca2a, 0x0d91722f, 0x0274e5e5, 0x0ceb8115, 0x0fc0694a, 0x1fda5231, 0xb213e2}}, + {{0x125fb81e, 0x0165ee31, 0x17b45d7b, 0x082cb7d7, 0x03bc3d53, 0x0f5fc1d2, 0x104b0f58, 0x1841e5a7, 0x229f8e}}}, + /* 9*16^28*G: */ + {{{0x025be234, 0x05f0ff65, 0x17cd41c0, 0x07c7ce1b, 0x06e060e8, 0x05d348b0, 0x04f97474, 0x1b02d8ff, 0x4b3b3a}}, + {{0x120e8362, 0x11dbf01c, 0x0846e101, 0x0ffb259e, 0x0c04c41e, 0x14b6fec6, 0x1271e1d7, 0x0770bb57, 0x5eec02}}}, + /* 11*16^28*G: */ + {{{0x0289f55e, 0x0b31a53f, 0x11d9c1ee, 0x0d61e1c5, 0x165be297, 0x08d813c4, 0x1e580809, 0x16dbb609, 0x9f7b88}}, + {{0x1e1e4bde, 0x1e69db2f, 0x0428ac6c, 0x0a6dc1d6, 0x1c71fc0e, 0x035a14c7, 0x03def8c5, 0x1098e082, 0x32f9f7}}}, + /* 13*16^28*G: */ + {{{0x1dfe1d2b, 0x12a4e460, 0x1a1e3945, 0x07ea13ca, 0x173a4c49, 0x056fe9fd, 0x038f9db3, 0x1d396e89, 0xd58a43}}, + {{0x0cd50922, 0x0793cadc, 0x0f5befff, 0x137442b9, 0x0276b54d, 0x14899414, 0x0f3c429c, 0x0d740b10, 0xfc1786}}}, + /* 15*16^28*G: */ + {{{0x049c795e, 0x120a8df1, 0x13a01784, 0x080d5533, 0x1ea4eed4, 0x0b4e1e13, 0x0c4335b6, 0x072e2230, 0x21d271}}, + {{0x19208ece, 0x0009761c, 0x17edd86c, 0x03289495, 0x1b4c3d67, 0x0dc2a915, 0x13a85dcd, 0x16960eb5, 0x94c5f9}}} + }, + { + /* 1*16^29*G: */ + {{{0x03c0df5d, 0x0d08bbc7, 0x15a9e4bc, 0x13dff6a2, 0x17fab201, 0x0d5ca3ae, 0x0ce9f62b, 0x028883f6, 0xe80fea}}, + {{0x0ac9ec78, 0x05a148db, 0x0c8baa7f, 0x0abd015e, 0x094472d1, 0x1b4651e5, 0x01dc7a25, 0x0fec71c0, 0xeed1de}}}, + /* 3*16^29*G: */ + {{{0x17592d55, 0x001acf66, 0x18d4064b, 0x0b728e81, 0x0e3b106d, 0x17b4b19e, 0x149822bf, 0x1b789420, 0x5d2ec6}}, + {{0x0f5183a7, 0x1372e875, 0x04545d09, 0x14f79b5a, 0x0d6950e2, 0x087d1346, 0x17ad63dc, 0x1f138dc8, 0xa92cd}}}, + /* 5*16^29*G: */ + {{{0x1e8f9f5c, 0x08fa5a4f, 0x02029466, 0x03e3c2b3, 0x1404d736, 0x171a10af, 0x1d0bf8b2, 0x1876237e, 0xac371d}}, + {{0x125a503c, 0x1d41ff99, 0x1d478745, 0x0a68b1dc, 0x0e735229, 0x00f3992a, 0x11dffc84, 0x1830e134, 0xc51616}}}, + /* 7*16^29*G: */ + {{{0x19e33446, 0x050e46a8, 0x0bce177d, 0x127788a5, 0x0a17a408, 0x005e8111, 0x10324d23, 0x07429e30, 0x894200}}, + {{0x06387689, 0x069c5007, 0x19d3e610, 0x1aee6cf3, 0x1e4e06bf, 0x16b6877e, 0x1de9362c, 0x12b2b4a0, 0xa9fd03}}}, + /* 9*16^29*G: */ + {{{0x1913cb26, 0x0b9464ad, 0x0ef5b40f, 0x16833802, 0x05c9899e, 0x1227faa8, 0x0aa28b36, 0x0d661468, 0x277026}}, + {{0x1348a7a2, 0x1f38b99f, 0x0056faef, 0x01923799, 0x0b324e94, 0x092683f9, 0x0c69554b, 0x0bcf361b, 0xf649bc}}}, + /* 11*16^29*G: */ + {{{0x195e8247, 0x0555010a, 0x01b346bc, 0x1fb88aad, 0x0ba9097b, 0x13700e7c, 0x1485e397, 0x1a70797d, 0x75e4d0}}, + {{0x19982d22, 0x111fecea, 0x06b624f2, 0x156b6dd5, 0x126d47dd, 0x0b8763db, 0x0641d07e, 0x142ea821, 0x1fce42}}}, + /* 13*16^29*G: */ + {{{0x06333323, 0x03cfa26d, 0x1d2afd1d, 0x177838d1, 0x0da849cb, 0x06b02cc2, 0x0fc0fc08, 0x07066c37, 0x3ed1b6}}, + {{0x15d61ba3, 0x189fe245, 0x1e3dca52, 0x0e514216, 0x1929ea9b, 0x04c4b447, 0x1b9d765f, 0x14916b69, 0xd84f2d}}}, + /* 15*16^29*G: */ + {{{0x133980bf, 0x1282bea5, 0x17402ebc, 0x06e05ca1, 0x0dd4368a, 0x1ebb91a4, 0x0606e11b, 0x1e0d4eb0, 0x70fdd2}}, + {{0x00b75785, 0x17754675, 0x15d29584, 0x006b070b, 0x0596b0a1, 0x008688f7, 0x1a5a55e9, 0x181a1ab0, 0x5edfca}}} + }, + { + /* 1*16^30*G: */ + {{{0x04e16070, 0x0e03dde6, 0x1f5a4577, 0x0304063d, 0x07543f2a, 0x04728eab, 0x010c4ee9, 0x0f7bf9ae, 0xa30169}}, + {{0x1e177ea1, 0x0068d020, 0x084684c3, 0x0bb7ef81, 0x00f9b173, 0x04fd12ea, 0x13d42060, 0x039f6cfc, 0x7370f9}}}, + /* 3*16^30*G: */ + {{{0x138011fc, 0x18093800, 0x1ca15899, 0x12d4cf5a, 0x00a4d835, 0x09984110, 0x0c4455ac, 0x146102bd, 0x6e8313}}, + {{0x1f15ab7d, 0x165b4fd1, 0x1147e69a, 0x1f22b5d3, 0x0c30426a, 0x16d900ed, 0x08130684, 0x117b849e, 0xc14781}}}, + /* 5*16^30*G: */ + {{{0x100e6ba7, 0x1d3a4dc6, 0x045bdfd4, 0x0dd8b689, 0x1e1b43d3, 0x101c526c, 0x147caf47, 0x0132f090, 0xf952a9}}, + {{0x0175e4c1, 0x0dd77728, 0x18a8ae63, 0x0e2cf698, 0x1a0f6555, 0x1b51713f, 0x1afe184d, 0x0b611579, 0xd8a93a}}}, + /* 7*16^30*G: */ + {{{0x03aa0e93, 0x08032d14, 0x1ec7d89a, 0x1c72875d, 0x0893a8f2, 0x18d0cecf, 0x1b9d4100, 0x0bc63a7f, 0x94016d}}, + {{0x07addac2, 0x07769344, 0x15ec1e8e, 0x086e7754, 0x06fd7f48, 0x0e9aa777, 0x165900d5, 0x1dcb88a9, 0x675032}}}, + /* 9*16^30*G: */ + {{{0x0266b17b, 0x07a43170, 0x18aeccac, 0x0ad14404, 0x109c2023, 0x1c42354f, 0x0a246ee5, 0x0e9ab3f6, 0xef22d1}}, + {{0x19dac83e, 0x1537021b, 0x10d06dcc, 0x0e4edee3, 0x0a1073ee, 0x0661d71a, 0x11d5a3e7, 0x192f5649, 0xbc5784}}}, + /* 11*16^30*G: */ + {{{0x12d382a0, 0x18980ad4, 0x1b366b88, 0x1b9779c5, 0x1f927f28, 0x063c0596, 0x04b4e72b, 0x19c99d71, 0xb5f7ef}}, + {{0x05b4b532, 0x117855dd, 0x0b3e316e, 0x1612da53, 0x1ddd371f, 0x0be37065, 0x08d4f025, 0x0b6a387e, 0x684354}}}, + /* 13*16^30*G: */ + {{{0x012cffa5, 0x13492322, 0x0331711f, 0x1a8410cd, 0x0624389e, 0x0a6c7dea, 0x01d9021d, 0x1a565ce2, 0x1cddc3}}, + {{0x1521954e, 0x0f36c4e6, 0x0dad4a2b, 0x193084d6, 0x0b08ac41, 0x0935fca1, 0x0298ff6c, 0x01965e3f, 0x1e476a}}}, + /* 15*16^30*G: */ + {{{0x14a9f22f, 0x1aff21c9, 0x1ea38ab4, 0x10338a42, 0x035b0cc0, 0x05c5ca44, 0x04e7c87e, 0x0b3e4b9d, 0x2accb3}}, + {{0x175c4927, 0x1baee59d, 0x0e9542de, 0x17af7d8b, 0x0edf1154, 0x1d1bf6f8, 0x0b946484, 0x1d2b115a, 0xd518a4}}} + }, + { + /* 1*16^31*G: */ + {{{0x1fb04ed4, 0x1bd631f1, 0x0c1fffea, 0x18661622, 0x18de208c, 0x0e828933, 0x04d918fe, 0x16713ad7, 0x90ad85}}, + {{0x0b6ef150, 0x08ea6a46, 0x00a25366, 0x1df57c2b, 0x022b839a, 0x05eca139, 0x0986bff7, 0x06c41470, 0xe507a}}}, + /* 3*16^31*G: */ + {{{0x10b7b678, 0x13aed99d, 0x1d8e0598, 0x18862379, 0x16c76f13, 0x15e52135, 0x0c6e8661, 0x0e669c84, 0x186e49}}, + {{0x18d91fc1, 0x1d03b797, 0x054d7729, 0x0ee44a89, 0x1e67e110, 0x0412e05b, 0x1612a9ff, 0x1c9300f7, 0xc0d460}}}, + /* 5*16^31*G: */ + {{{0x13421fb8, 0x18372e5d, 0x16957433, 0x12e3e5de, 0x12412984, 0x159a61db, 0x1d8b9f81, 0x1069edb7, 0x61c8d}}, + {{0x0e3ccd80, 0x0af7b342, 0x1bf374a6, 0x0e269674, 0x1eb5c806, 0x092c8702, 0x12deea4e, 0x1b320076, 0x6dfc6a}}}, + /* 7*16^31*G: */ + {{{0x0f6b35a4, 0x0925f0c5, 0x09fed21c, 0x1e6f4d56, 0x068ad889, 0x1920399d, 0x144edcd8, 0x074411dc, 0xf6a6b6}}, + {{0x01f422a6, 0x175b7f64, 0x1b8618b2, 0x0aeadceb, 0x0186f19d, 0x1b827ab0, 0x0e2c72b4, 0x150005a2, 0x3df7c8}}}, + /* 9*16^31*G: */ + {{{0x06954c11, 0x0b411f45, 0x1834062e, 0x1148782a, 0x178ff7fa, 0x0d878a83, 0x0dd88834, 0x051850d8, 0x87a2fc}}, + {{0x072a8b45, 0x0b719971, 0x1e0492dd, 0x11267e54, 0x07532cc4, 0x0a46d069, 0x13be5ec6, 0x1168b55d, 0x33ad51}}}, + /* 11*16^31*G: */ + {{{0x02706ab6, 0x123a3957, 0x194f036b, 0x16683ba5, 0x04cfe3c0, 0x177e5e1c, 0x069a1155, 0x008dcf10, 0xe1472e}}, + {{0x1d58de05, 0x174350b4, 0x0f349d4d, 0x113aaa8a, 0x021f8aa5, 0x08cbc643, 0x1f1a0fda, 0x1548f8b1, 0x82cd92}}}, + /* 13*16^31*G: */ + {{{0x07a84fb6, 0x1fd72a10, 0x0854087a, 0x06d0ea1f, 0x0b9ebc42, 0x06b00f24, 0x1bd77a2d, 0x19009f15, 0x1caf92}}, + {{0x07149109, 0x158c0c81, 0x0b399d85, 0x1982d2d4, 0x01622ec1, 0x127c7f88, 0x14e92069, 0x0b592edc, 0xbc24b8}}}, + /* 15*16^31*G: */ + {{{0x0a955911, 0x1b467f0a, 0x17b54b6d, 0x1c2d44c1, 0x18397107, 0x17f4d9eb, 0x14349627, 0x0d35e12c, 0x705bfd}}, + {{0x1fd200e4, 0x1dbe349f, 0x10b9cb62, 0x1e76a454, 0x051fa297, 0x1ec0faa0, 0x06429f98, 0x02616e7f, 0xe14aa4}}} + }, + { + /* 1*16^32*G: */ + {{{0x1ec4c0da, 0x1bda2264, 0x0fa8cd46, 0x18acf0e4, 0x1162ee88, 0x00d6cc0f, 0x1cce48e7, 0x1a5ec76b, 0x8f68b9}}, + {{0x101fff82, 0x11e5fbca, 0x1442ff7c, 0x1459fd2a, 0x0215dbbe, 0x08615b5f, 0x061b7876, 0x05b740c7, 0x662a9f}}}, + /* 3*16^32*G: */ + {{{0x123809fa, 0x0715c76e, 0x16552f86, 0x08b966a3, 0x11f08fd8, 0x19b1f922, 0x1c8a2ea4, 0x17c5ca13, 0x38381d}}, + {{0x131fed52, 0x0b83a8c1, 0x163c936f, 0x03f99665, 0x0b1cc368, 0x02d2a907, 0x1f72c250, 0x0141f722, 0xe4a32d}}}, + /* 5*16^32*G: */ + {{{0x17c2a310, 0x15213244, 0x04898c0f, 0x0d5d4a80, 0x099a1f18, 0x0dc15523, 0x0b9bda48, 0x049c86e5, 0x492627}}, + {{0x1e27ded0, 0x020db40a, 0x17fe3383, 0x0c6c254e, 0x0303b6d1, 0x1d2b4b8a, 0x0fe568b3, 0x0e7794f5, 0x1337e7}}}, + /* 7*16^32*G: */ + {{{0x0ebd2d31, 0x1c2583ce, 0x01b6e344, 0x1834adfe, 0x1e2f84dc, 0x09d9f23b, 0x12435789, 0x11834481, 0xe30656}}, + {{0x12546e44, 0x095a041c, 0x0dce099a, 0x1900857c, 0x10db6ffb, 0x15883fbe, 0x0982223c, 0x1c6f1268, 0xeac6f}}}, + /* 9*16^32*G: */ + {{{0x163136b0, 0x09861cf1, 0x0d077671, 0x17f1b355, 0x1d63374e, 0x073b11fd, 0x1bf09c6c, 0x01c48519, 0x3b9e10}}, + {{0x0cdbbc8a, 0x09f60b7b, 0x14c7e065, 0x1c514675, 0x15b26a2a, 0x19f5c7a3, 0x0dc77c54, 0x02a5a2d7, 0xfafb98}}}, + /* 11*16^32*G: */ + {{{0x0f485d3f, 0x10478239, 0x01efbba5, 0x140ed102, 0x0def717c, 0x05407aef, 0x06a4addb, 0x092e2559, 0xbb0aad}}, + {{0x1ca2f975, 0x1c9c9281, 0x19c2fff9, 0x14b5f462, 0x1da34895, 0x100fb94b, 0x11e63b34, 0x0a78b06a, 0xea699c}}}, + /* 13*16^32*G: */ + {{{0x16718dc9, 0x177699d1, 0x0448f792, 0x0b169b60, 0x00113e1e, 0x158cbd7f, 0x130353a3, 0x191c9ddf, 0x79090a}}, + {{0x1cfae7c5, 0x11991588, 0x0a4022e5, 0x0d5f6e17, 0x0aa56dd3, 0x0b65e6cd, 0x0e3c4f60, 0x0572320b, 0xeaab72}}}, + /* 15*16^32*G: */ + {{{0x1f60c7d1, 0x134b4a63, 0x1dd6b4a8, 0x0e3bcf9a, 0x1ba668dd, 0x0dde72a4, 0x0d54700f, 0x15bd3f2f, 0xe77c81}}, + {{0x02d72449, 0x162c0f94, 0x0a61b4d3, 0x08e1ee38, 0x01543631, 0x1d991f54, 0x0c8717f0, 0x0f1ddf02, 0x3acf14}}} + }, + { + /* 1*16^33*G: */ + {{{0x13231e11, 0x1437ea82, 0x1a078f99, 0x11d0ca06, 0x036091f4, 0x0ffc8cc6, 0x17597fe6, 0x002ed5f0, 0xe4f3fb}}, + {{0x0feb73bc, 0x1161c2bb, 0x14747260, 0x0fce9d92, 0x0b7286cc, 0x13687501, 0x1c705986, 0x075a1de9, 0x1e6363}}}, + /* 3*16^33*G: */ + {{{0x0bf05bd6, 0x1ccf8273, 0x0aa65194, 0x0adc0642, 0x10deca2f, 0x1a8ff5a3, 0x1fa420cb, 0x0837dc89, 0x900c32}}, + {{0x100d358b, 0x129569df, 0x13bec577, 0x10a6b078, 0x12439d69, 0x19022b85, 0x03d7e571, 0x1d1d163e, 0x6c31f9}}}, + /* 5*16^33*G: */ + {{{0x1f105c50, 0x13e14664, 0x04e1495e, 0x01bddef6, 0x033cd82e, 0x061a01e1, 0x02ab58a3, 0x0c5560b2, 0x5a8d03}}, + {{0x18a4cde9, 0x04d900c1, 0x1404f0d7, 0x0bed14cd, 0x1ff74a60, 0x15b920a1, 0x14da4da9, 0x16227a9c, 0xc059ea}}}, + /* 7*16^33*G: */ + {{{0x12d64feb, 0x03f0c5cd, 0x048a4b19, 0x05f14b25, 0x1a4e8377, 0x1d2bbb65, 0x182923bc, 0x0062465e, 0xd93f4d}}, + {{0x14698359, 0x187deac9, 0x124368de, 0x008617dd, 0x08c4d93e, 0x188e2a6e, 0x1cce88dc, 0x0ba8b964, 0x792555}}}, + /* 9*16^33*G: */ + {{{0x039fbc84, 0x1110266a, 0x15e8059c, 0x00c522c0, 0x0c65b7e7, 0x115e3315, 0x01106c53, 0x18dc6de5, 0x2f0769}}, + {{0x1c201bec, 0x1dc816f0, 0x137575cf, 0x0f36d498, 0x02149cca, 0x1803cc87, 0x1777e977, 0x0e49ae77, 0xb434f3}}}, + /* 11*16^33*G: */ + {{{0x06a758ea, 0x09bf5664, 0x1fc67135, 0x11063124, 0x16e39911, 0x04ad0aa0, 0x0c26561a, 0x100ab3c0, 0xfe7e67}}, + {{0x1b7ab649, 0x07916cae, 0x0c483479, 0x002e0e88, 0x1251f3b8, 0x070b4c24, 0x12e62302, 0x0cf4503b, 0x38aa69}}}, + /* 13*16^33*G: */ + {{{0x0cfffefa, 0x138ab134, 0x1946beb7, 0x10089ee0, 0x1af85101, 0x17c8a861, 0x049f5b7d, 0x194ea706, 0x91baf5}}, + {{0x1f7f6faf, 0x1e9b79a6, 0x1f4c0f71, 0x1de621cd, 0x13d92f4b, 0x14f893ee, 0x13af9765, 0x023268f7, 0x4e5cf}}}, + /* 15*16^33*G: */ + {{{0x0d33c546, 0x1e048bf4, 0x17b6bccb, 0x0ebf6650, 0x1ddd7825, 0x09b9f07a, 0x029f2cb1, 0x043967ef, 0x445841}}, + {{0x000b4fd4, 0x05368c38, 0x0b29cd98, 0x1e1479f6, 0x0da20852, 0x0f571c8d, 0x14e9dc89, 0x0efe7f0e, 0x308d93}}} + }, + { + /* 1*16^34*G: */ + {{{0x00eae29e, 0x17db7571, 0x138741c5, 0x069e5e1a, 0x04266c70, 0x0a9bd22d, 0x0cc7ae58, 0x13631d7e, 0x8c00fa}}, + {{0x0702414b, 0x1e952633, 0x18db1539, 0x15b5f503, 0x0c974c2f, 0x1a1d1b9b, 0x0686a770, 0x0cffd4a4, 0xefa472}}}, + /* 3*16^34*G: */ + {{{0x0bfd913d, 0x1fcab01f, 0x15327ab0, 0x0d01cddc, 0x08d2050a, 0x1d042615, 0x17e1d341, 0x14fd20fb, 0x36362a}}, + {{0x052e243d, 0x027cd756, 0x0cbeabf1, 0x017621ad, 0x02a82d83, 0x1221b86d, 0x1f54d058, 0x0ced9715, 0x48f278}}}, + /* 5*16^34*G: */ + {{{0x0d132896, 0x055d5fcd, 0x0f1b259f, 0x03c7756f, 0x1200dfcb, 0x16cb16ec, 0x180bca56, 0x0dbe6543, 0x448797}}, + {{0x0f685248, 0x0600d895, 0x1daa9e92, 0x081ab4c4, 0x01a3306b, 0x1483ba2b, 0x1f87bf26, 0x0c1a22b5, 0x27bd58}}}, + /* 7*16^34*G: */ + {{{0x1fa2670c, 0x040ab7b5, 0x189cf9b8, 0x01f05740, 0x10324740, 0x0e55419a, 0x0de22daa, 0x18517970, 0x4a4d3a}}, + {{0x16c1764d, 0x045cffee, 0x0a6fbb60, 0x00b2997e, 0x02b9d493, 0x188eef78, 0x093c5f9d, 0x0380308b, 0x70abb9}}}, + /* 9*16^34*G: */ + {{{0x0cb24aa7, 0x0cb57f12, 0x0d1714c3, 0x02118c72, 0x0fe18903, 0x17ec4ffc, 0x000b0eb9, 0x03215d23, 0x5f7b2d}}, + {{0x0a693d7d, 0x0bc03a1a, 0x1207431b, 0x1bd6e127, 0x07c47ce8, 0x1c051e73, 0x0accc28f, 0x00189fbe, 0x77036}}}, + /* 11*16^34*G: */ + {{{0x0f7fb8bd, 0x0c8de2f9, 0x19024290, 0x08c942bf, 0x086d87bc, 0x12736ca4, 0x0340abb0, 0x0a2673b2, 0x513974}}, + {{0x03908c0f, 0x04a5616c, 0x1e6356a0, 0x1865a7c7, 0x15c47faf, 0x1f7ed740, 0x0fcd2e23, 0x07c8ec87, 0xfcd714}}}, + /* 13*16^34*G: */ + {{{0x0e36ca73, 0x15ba48af, 0x0efcfb78, 0x10c9a6d7, 0x14887eac, 0x08895f80, 0x1ee2a90a, 0x1ac57f7b, 0xcf8316}}, + {{0x0ec25534, 0x1a490ca1, 0x035c43d6, 0x0c2b31b1, 0x0ca681c9, 0x0284486e, 0x15cf8e11, 0x11bd6bb3, 0x9feb5}}}, + /* 15*16^34*G: */ + {{{0x1752f97d, 0x0449beb5, 0x0d1d984f, 0x1df78ebe, 0x1a6165a2, 0x09433467, 0x127794e7, 0x13498976, 0x8610de}}, + {{0x1f1b1af2, 0x02bee6a0, 0x1550f820, 0x169b3ea8, 0x1f99e57a, 0x0ccd9299, 0x0ef24df3, 0x14056c61, 0xd31997}}} + }, + { + /* 1*16^35*G: */ + {{{0x00cb3e41, 0x0bfeefe3, 0x02e4b026, 0x1a109e61, 0x18ed3143, 0x076054f4, 0x0a7cf843, 0x1cd3ba90, 0xe7a26c}}, + {{0x0f2cfd51, 0x1454a10e, 0x03a0f883, 0x0d658084, 0x1bb18d0a, 0x00350d57, 0x012d1c6c, 0x0601f4f3, 0x2a758e}}}, + /* 3*16^35*G: */ + {{{0x1aee42db, 0x07cfe95f, 0x0c1c529c, 0x1778b68e, 0x0bfc1d9b, 0x176dc8f6, 0x0543f1ed, 0x1cfb36b2, 0xcc3427}}, + {{0x15d87bdb, 0x1114e008, 0x1c908b71, 0x0b975b1c, 0x1520010e, 0x1fe9fd90, 0x1a862178, 0x0834a438, 0xea2498}}}, + /* 5*16^35*G: */ + {{{0x1ed4a086, 0x1a1b3633, 0x071043bf, 0x0eb82b1d, 0x15cf4b1d, 0x02c2fde5, 0x1177b20f, 0x1759b308, 0x948f05}}, + {{0x1e2bca4b, 0x150c007c, 0x0fe8b468, 0x06514e38, 0x139411c2, 0x08533008, 0x08ce0bd1, 0x13ff6b45, 0x864ca8}}}, + /* 7*16^35*G: */ + {{{0x17542c21, 0x065f5365, 0x09930570, 0x13e9a51d, 0x16d43ae1, 0x1e22a28e, 0x0b24195b, 0x0c525233, 0x258419}}, + {{0x072bfabf, 0x1f5f18cb, 0x10ab5ece, 0x07430dc9, 0x113d5f3e, 0x0d52663a, 0x11200797, 0x03e39b64, 0xfcb35b}}}, + /* 9*16^35*G: */ + {{{0x0c1ecbf8, 0x1e230fa0, 0x1bb5f290, 0x13e1bd35, 0x0421f648, 0x1aa660f4, 0x14948aa5, 0x18826e78, 0x7e12cd}}, + {{0x10bed615, 0x0a2dc66d, 0x18767d67, 0x13ec3b1f, 0x11259c96, 0x0a6d5f26, 0x00dc50fe, 0x111111b9, 0x71284f}}}, + /* 11*16^35*G: */ + {{{0x14557d86, 0x1f3328e0, 0x199ffd05, 0x1dd88f1c, 0x1a6cf1cf, 0x08e53d02, 0x0a99dcae, 0x1fe546e8, 0x4b8ec2}}, + {{0x15167eb9, 0x0ecd8c8d, 0x10fda4af, 0x0be5de1f, 0x1ac5f28d, 0x0396f293, 0x1eac5290, 0x1fe0982a, 0xfde6c3}}}, + /* 13*16^35*G: */ + {{{0x0780763c, 0x15c169da, 0x195a4754, 0x14dabd24, 0x0c07e5f8, 0x1b6e34bd, 0x09094c90, 0x00e672c7, 0xfcd5c1}}, + {{0x18e851cb, 0x0a73a101, 0x1918e92d, 0x13645ce2, 0x0e38cb11, 0x06d9afb9, 0x1118edc8, 0x1c5caa45, 0x18ddab}}}, + /* 15*16^35*G: */ + {{{0x1d8ef686, 0x071df182, 0x09cb99af, 0x1c91e804, 0x06e53f68, 0x12ed7c13, 0x0f9488e2, 0x1dcb0879, 0x900f2c}}, + {{0x0121a8cf, 0x19d24b3f, 0x0455b541, 0x19bfe879, 0x1d110596, 0x0a8d89a4, 0x096b5871, 0x0abd8c08, 0x732ac1}}} + }, + { + /* 1*16^36*G: */ + {{{0x1e6b80ef, 0x0794f59e, 0x1e5093cf, 0x17972cfa, 0x0bdc571c, 0x006111de, 0x1b2348d5, 0x01dc6cc5, 0xb6459e}}, + {{0x1a71ba45, 0x185f85b0, 0x18d6cbfc, 0x075cda91, 0x01db3c4b, 0x0f8b72b3, 0x01b7876b, 0x0da0de7c, 0x67c87}}}, + /* 3*16^36*G: */ + {{{0x119888e9, 0x1ce793c9, 0x1122a2d0, 0x0574d7e4, 0x081673d1, 0x069814b3, 0x1b8b7798, 0x0ee75874, 0x1f90ea}}, + {{0x0f113b79, 0x17efe4bf, 0x0548b995, 0x0ea3fdcb, 0x196a8213, 0x09e938f5, 0x043a5605, 0x0f82bb54, 0x89be36}}}, + /* 5*16^36*G: */ + {{{0x1562222c, 0x02f7db79, 0x19bcb182, 0x0688f323, 0x152bade0, 0x15d699a5, 0x02b5b9c0, 0x09bdbffc, 0x13a4e5}}, + {{0x08200145, 0x058b3465, 0x12413023, 0x138aef5b, 0x09a52d4f, 0x017c0eb0, 0x004ecb2b, 0x09cb02dd, 0xc9d67d}}}, + /* 7*16^36*G: */ + {{{0x143b46bb, 0x1bf26e07, 0x12494950, 0x1a74c7f5, 0x15dbd12e, 0x1e02ec22, 0x0b747501, 0x17e46795, 0x61991e}}, + {{0x0c20a848, 0x047ac80e, 0x0bb363bd, 0x10e5394a, 0x1adf11ca, 0x1c38b37d, 0x124a54bc, 0x011e7fbc, 0x1c5e3}}}, + /* 9*16^36*G: */ + {{{0x121add3b, 0x12df1eee, 0x1c9f63df, 0x15289e8a, 0x026118b9, 0x0e6d868b, 0x0e1d240e, 0x1496f0fa, 0xea27ae}}, + {{0x168ce7dd, 0x1af148ed, 0x1386f9c6, 0x0425ad1c, 0x02f6278b, 0x0759192e, 0x1f795c8f, 0x1cdc8542, 0xc70ff1}}}, + /* 11*16^36*G: */ + {{{0x011ff757, 0x1457c5db, 0x13089b9b, 0x19d2e838, 0x0b6da9b4, 0x087c5b71, 0x1552ea40, 0x06ad6fff, 0x594651}}, + {{0x094d031a, 0x05337654, 0x0fff8eca, 0x1778f6ff, 0x006f9961, 0x1c680ae2, 0x1d401080, 0x019cbbe4, 0x361136}}}, + /* 13*16^36*G: */ + {{{0x036160b5, 0x1b12c51b, 0x19faf019, 0x0a7e48e1, 0x11ec0ccc, 0x17bcb804, 0x0a43a10e, 0x0722bee6, 0x16b26e}}, + {{0x18a1dc0e, 0x0312fdfa, 0x0e8fbe05, 0x0c7558e1, 0x054d4e13, 0x01a9231b, 0x1e2ed8d9, 0x0b4c605d, 0x60f56}}}, + /* 15*16^36*G: */ + {{{0x17b32db8, 0x0b269449, 0x11de47ce, 0x1dae93ec, 0x0ea85c91, 0x0a1e4216, 0x1e4c6fa8, 0x12b88ab3, 0x24b52}}, + {{0x0a64f760, 0x0a2a7d55, 0x16e06a56, 0x16d02240, 0x05be862a, 0x1410e62f, 0x0271edb8, 0x11eb7fe6, 0x609fef}}} + }, + { + /* 1*16^37*G: */ + {{{0x096943e8, 0x16d07ada, 0x1cf16977, 0x1e3f8cfc, 0x106231d6, 0x1a5508c7, 0x0101e4c8, 0x19050177, 0xd68a80}}, + {{0x0b133120, 0x0a642133, 0x114a568a, 0x1cf71ef0, 0x0e28b5b0, 0x0fc8bbd8, 0x1b40312c, 0x1ffe96b0, 0xdb8ba9}}}, + /* 3*16^37*G: */ + {{{0x0ca1c4f9, 0x0da1550c, 0x0df8a08d, 0x1dfc6995, 0x116f44f4, 0x1c1ed30f, 0x0a313102, 0x11e457ae, 0x7815f7}}, + {{0x1778bc15, 0x158f51b5, 0x1df47866, 0x085bcc2a, 0x0c35d5cb, 0x1e798a2c, 0x1da9f764, 0x1d19a735, 0xc1c601}}}, + /* 5*16^37*G: */ + {{{0x0e8c8530, 0x09370e1f, 0x03d3639b, 0x1bed03df, 0x06c6d512, 0x1e3200b5, 0x005db8dd, 0x19b41d88, 0xc39273}}, + {{0x198446c7, 0x0018787b, 0x1bb5c571, 0x1bf97b45, 0x1199850e, 0x09ca20e1, 0x123a7407, 0x084ae867, 0x8c41be}}}, + /* 7*16^37*G: */ + {{{0x037a26c1, 0x0f9205d9, 0x16fda94c, 0x18dcb181, 0x03b25166, 0x1218e0e8, 0x06c09d48, 0x08feb082, 0xda3174}}, + {{0x0cf74d6f, 0x08c1b767, 0x0a05497d, 0x106d8baf, 0x1d8b7d36, 0x00b3e12c, 0x11a748e1, 0x170febb1, 0x753b97}}}, + /* 9*16^37*G: */ + {{{0x1739dc49, 0x15b14549, 0x1d5580f4, 0x0725b4cd, 0x1231a239, 0x162845ff, 0x19b04192, 0x196055e1, 0x6a4be6}}, + {{0x12edd5cf, 0x13515cef, 0x1292934f, 0x1c569962, 0x08058ab7, 0x1371b07d, 0x1d65f705, 0x15455120, 0xf15d8f}}}, + /* 11*16^37*G: */ + {{{0x06987fac, 0x05f45062, 0x0a1bd9e6, 0x121f0c81, 0x18a3c8bc, 0x01301f64, 0x1c4d13a6, 0x13e275cf, 0x1f7c6}}, + {{0x19174c68, 0x1c8f39c0, 0x1daf098f, 0x1ebbc433, 0x0b6f9cb7, 0x01b7194d, 0x08b796c4, 0x07e6dfb4, 0x9d4ecc}}}, + /* 13*16^37*G: */ + {{{0x16daba4d, 0x099d0deb, 0x0c658987, 0x0bf61c40, 0x02bcb9c6, 0x1176ec7d, 0x0e072dc1, 0x002ec3fa, 0x557e94}}, + {{0x17a52316, 0x09ba50dd, 0x10d64294, 0x1371ebf4, 0x0bc86c5e, 0x0e7d0ae6, 0x1f811b4d, 0x074c03f4, 0x7a7e8f}}}, + /* 15*16^37*G: */ + {{{0x09f5341a, 0x1c7a97f9, 0x058dae00, 0x0f4658cd, 0x101419cc, 0x0a0753d8, 0x16a4eca7, 0x10433310, 0x3adada}}, + {{0x0586c6cc, 0x08ac049b, 0x17a3ef2d, 0x0da5cb68, 0x11017e9d, 0x1adf9b55, 0x1a7d54b8, 0x04513326, 0xbfea1e}}} + }, + { + /* 1*16^38*G: */ + {{{0x028d3d5d, 0x04acc07e, 0x11273a90, 0x055d72e6, 0x030b0961, 0x0138483d, 0x01094b70, 0x0fbecb90, 0x324aed}}, + {{0x16ab7c84, 0x1391257c, 0x0cca10e5, 0x027618fc, 0x01f4f192, 0x0061ad76, 0x1cbfc4c3, 0x0aee96c3, 0x648a36}}}, + /* 3*16^38*G: */ + {{{0x0fd53ed3, 0x0e48bac1, 0x095b33bd, 0x1ee9f73b, 0x17c49163, 0x105c98ef, 0x0ab56e3d, 0x1ab32cee, 0x20840b}}, + {{0x1a7a7132, 0x18a1ff28, 0x19c22661, 0x0f88e729, 0x0fac2548, 0x0a3b535d, 0x090d21ef, 0x12f9d830, 0xf29934}}}, + /* 5*16^38*G: */ + {{{0x08a35b35, 0x1e965dac, 0x028487b6, 0x0bb114b8, 0x0ebfd1ab, 0x0814f2c4, 0x06eef44f, 0x1ec1d667, 0xe6b6bf}}, + {{0x1c1007bd, 0x0b949edc, 0x1a6671f1, 0x16d93a77, 0x161ddfe3, 0x01f1c1ac, 0x0bcc99bd, 0x17a6601a, 0x1a5ff2}}}, + /* 7*16^38*G: */ + {{{0x00360dd3, 0x0a77c696, 0x14388243, 0x11506db0, 0x0e3bb47a, 0x1c043706, 0x06ca22c2, 0x0e8b7c93, 0xe05317}}, + {{0x1c24f87b, 0x15766c89, 0x040f70ac, 0x130fbd30, 0x0a01461b, 0x0ac15adb, 0x1ce73602, 0x0e34bb25, 0xdc1c3b}}}, + /* 9*16^38*G: */ + {{{0x1098dfea, 0x00a33316, 0x099e1e5f, 0x1967925d, 0x05e57fad, 0x12e9541d, 0x11678063, 0x074ef10d, 0xa8153b}}, + {{0x0e6d892f, 0x124d4efb, 0x16bd0562, 0x0bc1ee85, 0x13e03b1b, 0x0dce2bc2, 0x03f14f63, 0x0c8c3a0c, 0x2a4739}}}, + /* 11*16^38*G: */ + {{{0x0bcecfa5, 0x13f3bd24, 0x05aec082, 0x1ac5b436, 0x0da3b2a0, 0x14ae31c7, 0x176b7ad1, 0x1661fd95, 0x4f05c3}}, + {{0x15d37b53, 0x16681254, 0x06d2334b, 0x1dc863e0, 0x134b9447, 0x191b0aca, 0x09beb758, 0x1d4c07a8, 0x53a499}}}, + /* 13*16^38*G: */ + {{{0x084b96aa, 0x10f3b2c8, 0x0aaf3391, 0x130c6aa4, 0x1980ed02, 0x02f0d51d, 0x046f8990, 0x1733ecf5, 0xd9309a}}, + {{0x02b28a86, 0x136279be, 0x13fa5e3c, 0x0d93f75f, 0x0cb5fd3b, 0x0783313a, 0x155f5f84, 0x055369d8, 0x6ef99b}}}, + /* 15*16^38*G: */ + {{{0x1f8fcf0e, 0x1bdc682c, 0x1129beb3, 0x16dffbcf, 0x03411d65, 0x1a236f55, 0x14d6ea70, 0x14270ac5, 0x7d587c}}, + {{0x18bc9459, 0x00e0d04e, 0x08de0294, 0x072015a6, 0x16ad0c46, 0x0005b67e, 0x11849c8d, 0x00710609, 0xa7295c}}} + }, + { + /* 1*16^39*G: */ + {{{0x1d054c96, 0x145e9b9f, 0x1472a223, 0x08287751, 0x0e5dceec, 0x0fedf2ff, 0x187db547, 0x092339bc, 0x4df9c1}}, + {{0x0ad10d5d, 0x175d6036, 0x02124064, 0x0a0d9b85, 0x185d4b5d, 0x1a611d0e, 0x1ca01425, 0x0a2125b0, 0x35ec}}}, + /* 3*16^39*G: */ + {{{0x1def001d, 0x07912ed2, 0x06e89fbd, 0x1377ad31, 0x1b64b21f, 0x1e8e04f1, 0x12bc8382, 0x05b64fc5, 0xa549a3}}, + {{0x10624783, 0x0aed8d3f, 0x125c16b7, 0x083c54c5, 0x19456eb1, 0x01876c52, 0x1b2f7d33, 0x0f20db2c, 0x799b7a}}}, + /* 5*16^39*G: */ + {{{0x052ed4cb, 0x0d778f2e, 0x027b1681, 0x09bdf678, 0x12e6ec95, 0x05ecc1a9, 0x13448fc2, 0x061b40fd, 0x7e798f}}, + {{0x14bb9462, 0x0b8b303c, 0x07cde849, 0x06ae37ff, 0x0f057b17, 0x0aa4ef79, 0x120c106a, 0x189449b5, 0xd23dcc}}}, + /* 7*16^39*G: */ + {{{0x13630834, 0x0f9d07de, 0x16b019ff, 0x07e250c7, 0x08108846, 0x0f4b5d46, 0x1e0eb56e, 0x00062a28, 0x224fa2}}, + {{0x047a2272, 0x09e239be, 0x0943dd73, 0x05249d81, 0x109f53d6, 0x187d1c8e, 0x0970f12d, 0x065767db, 0xbbe54e}}}, + /* 9*16^39*G: */ + {{{0x183c19d7, 0x13b24e8a, 0x0b3d5eed, 0x16bc8b58, 0x08ef2bbb, 0x12e67211, 0x07904a68, 0x198c0147, 0xc2d4a0}}, + {{0x0507928d, 0x17945c16, 0x0d1725dc, 0x0095062e, 0x1260d268, 0x1dafbfa0, 0x0a535060, 0x1f38100c, 0x65ada0}}}, + /* 11*16^39*G: */ + {{{0x1c940c9a, 0x064056a5, 0x1d08cc21, 0x1e79c275, 0x1dc2113c, 0x02f13a26, 0x0c643956, 0x0fd860be, 0x2ec22a}}, + {{0x051e7a4d, 0x08ca7ecc, 0x08d6f6b3, 0x00a307b3, 0x07feb124, 0x127a814e, 0x05a130b8, 0x0d1bc66f, 0x8b1da4}}}, + /* 13*16^39*G: */ + {{{0x1d683eeb, 0x138772fe, 0x034c4cea, 0x0dd67141, 0x0b8f33e3, 0x1b292842, 0x13b2ac6b, 0x0e71f351, 0xafc669}}, + {{0x10cd4509, 0x0f14e559, 0x1b77f724, 0x1756aa4b, 0x19c16570, 0x0e3fe511, 0x1d4af0d6, 0x12edba44, 0x2c21}}}, + /* 15*16^39*G: */ + {{{0x176f4293, 0x1100fc3d, 0x0f144e7a, 0x12f16aca, 0x1282e10e, 0x04679b85, 0x0c24486f, 0x0b53e686, 0xd2557b}}, + {{0x1282740a, 0x0d8c3d12, 0x101697c7, 0x16d071bc, 0x0d21fe34, 0x178375a5, 0x1fc049a0, 0x086abc84, 0xa787b3}}} + }, + { + /* 1*16^40*G: */ + {{{0x0c1f98cd, 0x1fe4ce45, 0x1fc0c232, 0x09120a9a, 0x06021523, 0x054e0e63, 0x01c3ebb6, 0x150948e9, 0x9c3919}}, + {{0x14fc599d, 0x13f2f01e, 0x193239af, 0x064deed8, 0x0e641905, 0x0225f930, 0x155d613c, 0x01e949bb, 0xddb84f}}}, + /* 3*16^40*G: */ + {{{0x0fb64db3, 0x1dcc6a9c, 0x1754e105, 0x1bc99473, 0x1b8d6a7e, 0x1c1fdf29, 0x12dd02ee, 0x124537b9, 0xc11423}}, + {{0x1c0259be, 0x118674ff, 0x1159f478, 0x0b01209a, 0x18bd1a87, 0x06f27f4b, 0x1f0a973b, 0x1b8b690d, 0x1237f6}}}, + /* 5*16^40*G: */ + {{{0x03081e46, 0x16f6c1a0, 0x11567a87, 0x044318aa, 0x034713a5, 0x0e160c93, 0x089020b6, 0x1f0634ee, 0x6c5b4b}}, + {{0x0bfbcd70, 0x08fce5c0, 0x108a98bb, 0x019f04d5, 0x1e47841d, 0x1c31e715, 0x10bec8d1, 0x0e2924da, 0xcb0513}}}, + /* 7*16^40*G: */ + {{{0x064dcd4b, 0x0572d762, 0x04704937, 0x018fab32, 0x10a450c3, 0x0332e558, 0x1792d59c, 0x0acce195, 0xe1e9a8}}, + {{0x1b041f2c, 0x085b12f5, 0x085aca4b, 0x09a33559, 0x177927f4, 0x01accd92, 0x14c6deb1, 0x12a88ab8, 0x562b0a}}}, + /* 9*16^40*G: */ + {{{0x0badd73c, 0x02c3b7f1, 0x0992df40, 0x139bb205, 0x014208fd, 0x1a72176e, 0x0265de29, 0x0af5a236, 0x51b21a}}, + {{0x0b36d8d1, 0x1bea570f, 0x11cd2e9b, 0x00261e51, 0x01cfa6c2, 0x03f80e96, 0x0f975528, 0x020003fa, 0x7930}}}, + /* 11*16^40*G: */ + {{{0x1b09f34b, 0x0bae85b9, 0x1319b39b, 0x10e7cc11, 0x19d61e58, 0x114b79f9, 0x1e6186ad, 0x14c76396, 0x9701f3}}, + {{0x00df5793, 0x06e42866, 0x1731e52b, 0x097872ff, 0x08337710, 0x18da98ab, 0x1b4575c0, 0x177195e1, 0x3dd44b}}}, + /* 13*16^40*G: */ + {{{0x1f1e2f46, 0x0e73111d, 0x09de0c05, 0x01ee3d0e, 0x03c57527, 0x0970206b, 0x1b311156, 0x03a593cc, 0xa036b4}}, + {{0x1effb349, 0x198f134a, 0x1c2c7d3d, 0x01c5059f, 0x0b08d068, 0x1b5523cf, 0x0cf5f7c7, 0x14007d2d, 0xc3bf91}}}, + /* 15*16^40*G: */ + {{{0x0c4cea08, 0x06c5c81c, 0x03a8876f, 0x16b1741c, 0x04652654, 0x108a9a00, 0x1141bd29, 0x1b7549d1, 0x6a85fa}}, + {{0x1862f4f3, 0x0cef672c, 0x15c86da8, 0x0e349687, 0x06230b42, 0x19e0a47f, 0x16754c64, 0x00975c8c, 0xb646}}} + }, + { + /* 1*16^41*G: */ + {{{0x00a959e5, 0x1109c109, 0x04753316, 0x02927517, 0x006bb91e, 0x0f940ec7, 0x1f7e3781, 0x0163ba25, 0x605717}}, + {{0x0385a2a8, 0x04cdf499, 0x1893197a, 0x02a5787d, 0x1f262465, 0x116d7b8e, 0x001eb766, 0x164d4d49, 0x9a1af0}}}, + /* 3*16^41*G: */ + {{{0x171c032b, 0x0a6d0b14, 0x0bf72603, 0x16cd142f, 0x166c5ff6, 0x0dafefe3, 0x0980f744, 0x1f9adc00, 0x71eba8}}, + {{0x1668359f, 0x1d5ad470, 0x12d1d579, 0x0635a2ee, 0x0bb7f719, 0x028b7aa6, 0x0e77bd98, 0x0c496c3a, 0xd2ff12}}}, + /* 5*16^41*G: */ + {{{0x0a03a61c, 0x03723a29, 0x01c15d34, 0x10d1e8d2, 0x09dd0507, 0x1a215d55, 0x148cb285, 0x00b66493, 0x855ec3}}, + {{0x065dfc07, 0x0fe37556, 0x1f912597, 0x05ee9d42, 0x0fb4ed33, 0x05ffcda1, 0x105fd50f, 0x05d8be03, 0xdd85d}}}, + /* 7*16^41*G: */ + {{{0x1f32d706, 0x00605240, 0x1a819e2c, 0x119948e8, 0x1bfa2061, 0x094d184a, 0x0fc7c543, 0x0d57567f, 0x3ce448}}, + {{0x1c7fd9e4, 0x05b9b1bf, 0x187a27d0, 0x02ac879a, 0x14906edd, 0x08235884, 0x014a23bf, 0x11b55c6f, 0xe77540}}}, + /* 9*16^41*G: */ + {{{0x191cd3fb, 0x0da065db, 0x0a6f9a1b, 0x1467fb2e, 0x044eb4a2, 0x0190c7c4, 0x1febc0b8, 0x0287e9c6, 0x11ccc5}}, + {{0x15160d86, 0x09b8b5d2, 0x174d1caa, 0x163dfa59, 0x0c239fa0, 0x112249c6, 0x077ad4a3, 0x05520562, 0x4aa56b}}}, + /* 11*16^41*G: */ + {{{0x018f7552, 0x03dc88cb, 0x0153eb0e, 0x02271730, 0x182ddbd4, 0x1bba7c11, 0x11bd0ee5, 0x02fca293, 0x250bb}}, + {{0x1510b14d, 0x18424b11, 0x0f5bc78f, 0x00de7866, 0x1d817da0, 0x1efbaff4, 0x0208d0b5, 0x1f9377d0, 0x731930}}}, + /* 13*16^41*G: */ + {{{0x1f725d12, 0x0e89f49c, 0x0d7d1d41, 0x0c8577b9, 0x02fbfd94, 0x1ce70501, 0x1f4ead28, 0x111668cf, 0x1a749c}}, + {{0x03ac56e4, 0x09b28a69, 0x0436a9c0, 0x0410d313, 0x13d8f607, 0x1f3ae157, 0x18b3d162, 0x12ae7d81, 0x7e91d1}}}, + /* 15*16^41*G: */ + {{{0x09fae458, 0x10824729, 0x1bb25ff5, 0x14b884ec, 0x17b328b0, 0x0ab52efd, 0x06304274, 0x0b7c1f04, 0xc75068}}, + {{0x1757b598, 0x00b420ca, 0x165468ac, 0x1b94a066, 0x0c7b40a5, 0x1a0a6339, 0x1817ed4b, 0x1f19f243, 0xead795}}} + }, + { + /* 1*16^42*G: */ + {{{0x0cb94266, 0x0d34b9f7, 0x1537c4ac, 0x1de1f74f, 0x1a31880c, 0x1cd228c6, 0x10450850, 0x11c47410, 0xa576df}}, + {{0x01b28ec8, 0x145f08d7, 0x05367cfb, 0x1c214fea, 0x0d82c432, 0x0bd7f2c6, 0x02cb24ae, 0x041cecc8, 0x40a6bf}}}, + /* 3*16^42*G: */ + {{{0x0d9ed6c1, 0x14575ac6, 0x1564f5ad, 0x1ce8b787, 0x0dd0ec24, 0x00c3b82f, 0x14fa02ff, 0x0db96e9e, 0x32833}}, + {{0x18fafeee, 0x16375f37, 0x12d252b7, 0x17e9be4b, 0x17c8c265, 0x0ca1d106, 0x1ca311b5, 0x07025fb3, 0x71a898}}}, + /* 5*16^42*G: */ + {{{0x1235983a, 0x0cd4d469, 0x0ef3aca4, 0x14206e02, 0x01531e38, 0x0936b87f, 0x1153718e, 0x15d17223, 0xce4f4e}}, + {{0x0d3cdecf, 0x07eb58c8, 0x0fdd02bb, 0x18ca451d, 0x07543526, 0x10124f38, 0x0eecfab7, 0x0e78721f, 0xf3c9f9}}}, + /* 7*16^42*G: */ + {{{0x15b0e6c9, 0x16d55b32, 0x1b932269, 0x1ff39ef0, 0x0bcbddb5, 0x07d9b6fc, 0x0889e38a, 0x14a9730c, 0x4dbebf}}, + {{0x1eb2cc25, 0x0a53c2aa, 0x1413beba, 0x06236578, 0x029f3589, 0x11373711, 0x0bb7d169, 0x16079227, 0x10fee7}}}, + /* 9*16^42*G: */ + {{{0x05857295, 0x0700d08d, 0x10cfc059, 0x11c8fe06, 0x0a12069c, 0x08c7e50e, 0x10862cb8, 0x017fde8b, 0xa42a24}}, + {{0x0a7eb9c1, 0x159bbff6, 0x1464e555, 0x038459a2, 0x1a4c427a, 0x1915926e, 0x15159e9a, 0x1e4c200b, 0x3aa0b3}}}, + /* 11*16^42*G: */ + {{{0x0fcdc098, 0x1107faab, 0x191a00c8, 0x15c01ed5, 0x099c1550, 0x0fc36062, 0x0899e9fc, 0x05f2df64, 0x34e12b}}, + {{0x0a7474e2, 0x0658d6f3, 0x0620fd99, 0x1ea261e3, 0x172db04d, 0x05e420bc, 0x0c8b65d3, 0x1bbaf6ba, 0xa64ac2}}}, + /* 13*16^42*G: */ + {{{0x0f173b92, 0x06b75af4, 0x07edd847, 0x1ce5e82d, 0x165683b7, 0x0d10c7a6, 0x07ca6f8c, 0x081b3772, 0x10f4d2}}, + {{0x033146c2, 0x0810036b, 0x01ab6df2, 0x16ed3a29, 0x108ba90b, 0x12d2d19c, 0x0eb4846c, 0x12a122ea, 0x850e2d}}}, + /* 15*16^42*G: */ + {{{0x08d84958, 0x137e8ecd, 0x0b3172bb, 0x03bd62d9, 0x0cc866a1, 0x0dcbb6a0, 0x1f9d27c6, 0x016d36ce, 0xe846e8}}, + {{0x1882cf9f, 0x062323db, 0x18306990, 0x03466ce3, 0x0b76fad5, 0x0c8823cc, 0x1895076f, 0x1f91298f, 0xa29cb8}}} + }, + { + /* 1*16^43*G: */ + {{{0x1e58ad71, 0x1bb1c44d, 0x068e8823, 0x01a3eb9f, 0x08c38bb3, 0x1f4b14ef, 0x0f8c2817, 0x11851bd8, 0x7778a7}}, + {{0x1d9f43ac, 0x1a89fe0f, 0x092b158e, 0x070823fe, 0x1580087b, 0x0709797f, 0x08bfdc26, 0x1356b4b6, 0x34626d}}}, + /* 3*16^43*G: */ + {{{0x1319c869, 0x1be37571, 0x07ac9c0b, 0x13f2baec, 0x0acdc18a, 0x1c8117e6, 0x1f234060, 0x0bb302e7, 0x301804}}, + {{0x12b856f0, 0x0063b64e, 0x0f669eff, 0x15099494, 0x02e3bca2, 0x121906b1, 0x1edbe198, 0x0f04a076, 0xac5fc5}}}, + /* 5*16^43*G: */ + {{{0x05ed29b5, 0x0334c37d, 0x0ab746d3, 0x0616c0e2, 0x1c885f58, 0x13edcd31, 0x1bcd0ead, 0x16c3dcaf, 0x322881}}, + {{0x1cd15ad2, 0x1a789373, 0x1b9d813b, 0x075d5729, 0x131e1ca8, 0x18cefa0a, 0x113ac442, 0x1082f406, 0x167702}}}, + /* 7*16^43*G: */ + {{{0x06c96100, 0x1fd4203c, 0x1a72398e, 0x0602354d, 0x1dbcca16, 0x0ecd96f9, 0x0e7fed0f, 0x07581f63, 0x3f3847}}, + {{0x12624707, 0x0f1560df, 0x1d7c6f3c, 0x0e38f816, 0x19ce5665, 0x02231783, 0x0e5494d3, 0x0abeba80, 0x70c69c}}}, + /* 9*16^43*G: */ + {{{0x1d22d2ac, 0x1a637637, 0x12ab3808, 0x1bfc24db, 0x1df2f10d, 0x00704bc2, 0x1db72d0f, 0x18bfa4f4, 0x288113}}, + {{0x0f42a268, 0x00f5aafc, 0x12323f42, 0x07a8942a, 0x16137ddc, 0x1b93064b, 0x1723c81d, 0x002b1f78, 0xa1a7eb}}}, + /* 11*16^43*G: */ + {{{0x045f8ea8, 0x05d406e9, 0x134a4035, 0x0491c72c, 0x19fe5d17, 0x06caeb88, 0x08a954fd, 0x001908c7, 0xf963a2}}, + {{0x19bc99eb, 0x1e2afd82, 0x02d82092, 0x11e46b3b, 0x027208bb, 0x11180ffa, 0x0f028edc, 0x04d18ff0, 0x9c8594}}}, + /* 13*16^43*G: */ + {{{0x0606a315, 0x10d44189, 0x1a58eb67, 0x04c0e5e4, 0x0097e407, 0x05952c87, 0x069fe636, 0x099fee1b, 0xa5d922}}, + {{0x1e3b68d1, 0x1ab099ac, 0x0469f274, 0x1a1a68fa, 0x00de9ed4, 0x0355ebcc, 0x096cd0cc, 0x0007641b, 0x87328b}}}, + /* 15*16^43*G: */ + {{{0x06231493, 0x06dbdaa0, 0x131351a7, 0x02350619, 0x1e6a4964, 0x120e8072, 0x0d813ad3, 0x05c36e78, 0xf1fe98}}, + {{0x158848c1, 0x0b54cd33, 0x17fc3406, 0x07f668dc, 0x199d3f17, 0x1e102fbe, 0x177085b4, 0x1d5db349, 0x2e2019}}} + }, + { + /* 1*16^44*G: */ + {{{0x06d903ac, 0x04f6d4e0, 0x0b5f972c, 0x12c4e9cb, 0x0fd2ed5f, 0x0fe9873d, 0x01118dca, 0x0bdcc6f5, 0x92895}}, + {{0x1bcd091f, 0x08c0749a, 0x0a360ff1, 0x1a4ddf51, 0x095eeac3, 0x0509849d, 0x0aa09ede, 0x0007a7e8, 0xc25621}}}, + /* 3*16^44*G: */ + {{{0x1874b839, 0x088943ab, 0x0f4ad060, 0x022b672a, 0x0b6aebe4, 0x186fd918, 0x16a014f7, 0x03f81c3c, 0x3e03b8}}, + {{0x1c0594ba, 0x060e72b3, 0x0ad6e368, 0x0b8be1fb, 0x18f667de, 0x1303ab8c, 0x1d0b113d, 0x0c7bfe0f, 0xd13ae1}}}, + /* 5*16^44*G: */ + {{{0x0357a513, 0x11fbc734, 0x0cc08fce, 0x037a268b, 0x122c5f15, 0x1141d514, 0x04b358be, 0x16f45e89, 0xe662c0}}, + {{0x0017d07e, 0x095100e5, 0x14e36246, 0x06b9ac4a, 0x1a419d80, 0x11045090, 0x148c176b, 0x079cc248, 0xab0b19}}}, + /* 7*16^44*G: */ + {{{0x1f37d242, 0x0cafbf7e, 0x07052c12, 0x1fd94c0f, 0x1587dc29, 0x1163e5f1, 0x1b2e10e1, 0x1639299e, 0x40bf80}}, + {{0x06405088, 0x08ec13cd, 0x0f4d560f, 0x043d7485, 0x0fe12743, 0x1f4d8d93, 0x0bc13d4f, 0x06bb0ad5, 0xb579dd}}}, + /* 9*16^44*G: */ + {{{0x195a3558, 0x17959b22, 0x0d29fcae, 0x0e3f0bc4, 0x159f6ac0, 0x0bc09c6d, 0x09c201be, 0x12ec03b9, 0x3d14fe}}, + {{0x0443df4c, 0x156d9d63, 0x1075c9f1, 0x0145c28f, 0x16e1482e, 0x1498edfa, 0x07be3ca6, 0x1add08d0, 0x16c6bd}}}, + /* 11*16^44*G: */ + {{{0x02b1fc24, 0x0f4fad6c, 0x0fdd5c3b, 0x11b038fc, 0x04865252, 0x16269649, 0x14947306, 0x081d05cc, 0xdd6fa5}}, + {{0x0e9b74ca, 0x1218e230, 0x1cc88c12, 0x01bcd7da, 0x17e77ec1, 0x18f5f8b2, 0x01bf8d9b, 0x0fd63a63, 0x67e62b}}}, + /* 13*16^44*G: */ + {{{0x1dd08e02, 0x0f548ac9, 0x0b7c0a20, 0x0a8f6ffb, 0x11e80108, 0x0a4cd51e, 0x15e03e1a, 0x1505bcab, 0x13fa2d}}, + {{0x1cb03410, 0x12aa0ee1, 0x090ae5f6, 0x095f7633, 0x032c7e64, 0x0b1035da, 0x09c8c4cd, 0x1608aabb, 0x136338}}}, + /* 15*16^44*G: */ + {{{0x144ee41a, 0x0119d5cc, 0x1f5a69ab, 0x16adba76, 0x08282879, 0x085b3963, 0x0910fdf0, 0x0a3a78e1, 0xd06c48}}, + {{0x0b295e6f, 0x18fc274c, 0x18bb894b, 0x170868c2, 0x030919b7, 0x166a7a7b, 0x02b6eec2, 0x0980b09a, 0x5815fd}}} + }, + { + /* 1*16^45*G: */ + {{{0x03d82751, 0x1d573a8b, 0x0b4d5149, 0x0b69520f, 0x1b285564, 0x1279d071, 0x0424e641, 0x1e7d8db6, 0x85d0fe}}, + {{0x0eb1f962, 0x1611bd12, 0x1dccc560, 0x0ea3d2d0, 0x0f5663e8, 0x04b72c16, 0x102f8a75, 0x10827471, 0x1f0364}}}, + /* 3*16^45*G: */ + {{{0x0cde4cf3, 0x0caa830f, 0x02819aae, 0x01ca6a8f, 0x19ae7934, 0x169368ae, 0x0b0ef9f0, 0x09582284, 0x384dab}}, + {{0x052d0566, 0x1e3cb591, 0x146e9ced, 0x0614672e, 0x0c6f01f4, 0x16b6d15a, 0x090efed3, 0x179a3739, 0xd6e3c5}}}, + /* 5*16^45*G: */ + {{{0x1e5238c2, 0x0579f490, 0x03b2e2e6, 0x0abeb870, 0x0ed48403, 0x1085a741, 0x16a906c5, 0x01d6fa82, 0x14f0ec}}, + {{0x12f07922, 0x14351a3c, 0x0124e75b, 0x1801b006, 0x0747fd25, 0x039f1c21, 0x1602487f, 0x07ba906b, 0xab12d5}}}, + /* 7*16^45*G: */ + {{{0x1543e94d, 0x1b1a977e, 0x1e638623, 0x06054ead, 0x00ddadd1, 0x1a33c52d, 0x01fb1070, 0x176f0585, 0xeb42f3}}, + {{0x05924d89, 0x02acef22, 0x035b5090, 0x108d1bcc, 0x1fb774cd, 0x0eab97e6, 0x04b72683, 0x00e9e4bb, 0x234a6d}}}, + /* 9*16^45*G: */ + {{{0x1e19aaed, 0x19272dab, 0x199cc9c0, 0x1759bd18, 0x0a920459, 0x0017b703, 0x0366a7bb, 0x194a2d04, 0x1cf138}}, + {{0x092f400e, 0x09b752eb, 0x11dffef0, 0x1ddf1fdf, 0x1de17479, 0x195335b6, 0x0e197d0d, 0x1e62e38c, 0xd6ffda}}}, + /* 11*16^45*G: */ + {{{0x16a8aa39, 0x1b6074fd, 0x1e3eb157, 0x0cc6f694, 0x190d937a, 0x104b424c, 0x104b21d6, 0x17cbe81a, 0xb58686}}, + {{0x0b493c1f, 0x1e3c9ae9, 0x16cd1ee3, 0x1b5f31cd, 0x0a91dabb, 0x1c6a2a60, 0x10b05251, 0x086498f1, 0x5632d5}}}, + /* 13*16^45*G: */ + {{{0x103b4cc5, 0x148f5f1d, 0x071df0bb, 0x106374b4, 0x1a802572, 0x1e27f3f9, 0x10ad9ed6, 0x160d7179, 0x5fc19d}}, + {{0x05b57c28, 0x1d9cfdc3, 0x021fb128, 0x0dea0798, 0x05ef4927, 0x09c7cd1d, 0x1f19bb88, 0x181d9318, 0xec8e84}}}, + /* 15*16^45*G: */ + {{{0x0cb38cb5, 0x1a5c2bea, 0x0e22522e, 0x16ffbe9a, 0x0ea1be10, 0x05207e9f, 0x0a277aea, 0x01a85dbc, 0xb88fb7}}, + {{0x1965f3d7, 0x1dfd3ab2, 0x0be31c65, 0x1e7c244f, 0x1a8e24d4, 0x1dcca59a, 0x0a0180d2, 0x15a8dd46, 0xd6c736}}} + }, + { + /* 1*16^46*G: */ + {{{0x0526087e, 0x1aa02412, 0x16880c23, 0x16db1105, 0x0b85dfdf, 0x1b020bcc, 0x1a5f0726, 0x19d2fdd9, 0xff2b0d}}, + {{0x10c29907, 0x04a8f00f, 0x038b3acb, 0x0fdadf72, 0x07936c7b, 0x026e2a68, 0x08622bd3, 0x1fdea497, 0x493d13}}}, + /* 3*16^46*G: */ + {{{0x19d681f9, 0x0c82a7f3, 0x03fae7f1, 0x1c1ddf59, 0x094b066c, 0x1f92f016, 0x0c2222df, 0x1e4eebe4, 0xc745fd}}, + {{0x1bbb1247, 0x018b9a1b, 0x1f5171d8, 0x17a66b8c, 0x018678cd, 0x1ca63874, 0x179e29c4, 0x1e5ed73c, 0x590222}}}, + /* 5*16^46*G: */ + {{{0x15cd0ea3, 0x10267769, 0x12b12057, 0x08f1d041, 0x0e7f2b34, 0x0f2f5b39, 0x142c9e96, 0x1e752ea0, 0xabb279}}, + {{0x1c307bce, 0x1849899b, 0x00bced91, 0x0ed20b3c, 0x18ed47c9, 0x1f060183, 0x1c367ed2, 0x0777e2f2, 0x5dee10}}}, + /* 7*16^46*G: */ + {{{0x1bc9ee3e, 0x017179f8, 0x19ce0b17, 0x1f4352c7, 0x1ed11ea9, 0x1553a133, 0x00a09feb, 0x016b3f8d, 0x3f8115}}, + {{0x199aae06, 0x0756d862, 0x16a0580f, 0x0765b9f9, 0x15662762, 0x1f59e23c, 0x00b519c6, 0x0d1fb7f5, 0x19c88a}}}, + /* 9*16^46*G: */ + {{{0x18e4a007, 0x0b8df7d7, 0x0ecd62d8, 0x19dd9e11, 0x0c7ec15e, 0x1d19d52b, 0x179a5652, 0x05ba0105, 0x5cf813}}, + {{0x1068b883, 0x131f8484, 0x071ffa33, 0x08df2d8f, 0x03df6c89, 0x00ac4246, 0x0837d2b5, 0x0b81ac3f, 0xb45aee}}}, + /* 11*16^46*G: */ + {{{0x06c2d4a7, 0x0ab7f3d9, 0x13ffec42, 0x06df2677, 0x04ed21bc, 0x19cb9e20, 0x125194f8, 0x09a1a974, 0xb6d5fe}}, + {{0x1ae86371, 0x0c6e73f1, 0x178f3204, 0x16fc9cde, 0x1fd8e745, 0x1c904eff, 0x1b0537f3, 0x1427577a, 0x47f373}}}, + /* 13*16^46*G: */ + {{{0x1c66dd33, 0x0499b117, 0x171db714, 0x1f791fe3, 0x1b022ea8, 0x0d8a8014, 0x021c1aec, 0x180cd9eb, 0x61c8bb}}, + {{0x16f10bfa, 0x1ddd4f9d, 0x00832328, 0x020dd585, 0x1d3fb6a5, 0x0cca5cc2, 0x1c0d119a, 0x0473ca9e, 0x93599e}}}, + /* 15*16^46*G: */ + {{{0x1d6b2ff8, 0x002dbe66, 0x01b23ea6, 0x066d82e5, 0x1bdf1876, 0x1a9b9f61, 0x01461f27, 0x14ae84cf, 0x94e32b}}, + {{0x0ce1af3e, 0x0ea42aa9, 0x1aff84eb, 0x15e084a4, 0x19e8cb33, 0x12443316, 0x13864bc7, 0x11687b40, 0xd1b44}}} + }, + { + /* 1*16^47*G: */ + {{{0x1856e241, 0x0072f167, 0x15b74a1e, 0x03dc2919, 0x1212b57f, 0x1973180d, 0x03aa7b4a, 0x1c963d10, 0x827fbb}}, + {{0x0ec293ec, 0x102db45d, 0x040c59b5, 0x0f4c630d, 0x112687ff, 0x19633e8e, 0x0c2dc6fb, 0x12478e4f, 0xc60f9c}}}, + /* 3*16^47*G: */ + {{{0x1bb80fa7, 0x1a242e59, 0x0104e218, 0x0fb4d76e, 0x0819f3aa, 0x1035e990, 0x0bef0346, 0x03ec6118, 0x857e3}}, + {{0x09366b2d, 0x0cc108f8, 0x15c05aaf, 0x1c6e0879, 0x17147172, 0x064e8ee5, 0x1c824b5f, 0x08475c02, 0xf64393}}}, + /* 5*16^47*G: */ + {{{0x09c70e63, 0x0e8161d0, 0x14f525bd, 0x1716f1ce, 0x0672e9cb, 0x032abb25, 0x0010d517, 0x1d4ad7ac, 0x28aacc}}, + {{0x1057da4e, 0x0f81c417, 0x13687a2e, 0x18b39c88, 0x0ebb7f5f, 0x0b33e3b4, 0x18559ea2, 0x05df0341, 0x2b6932}}}, + /* 7*16^47*G: */ + {{{0x13e674b5, 0x00ee297b, 0x0182ab18, 0x11ed39ce, 0x18a4f92d, 0x1964de75, 0x19851776, 0x04b40ab4, 0xa2f3b6}}, + {{0x0e937941, 0x049c6470, 0x0cfe94ec, 0x05f462f8, 0x07c4b922, 0x05487995, 0x02ba0011, 0x0b2c298d, 0x620ea1}}}, + /* 9*16^47*G: */ + {{{0x191eb056, 0x1b00b18e, 0x13f4e1b1, 0x05dfb71d, 0x115f5a00, 0x1ae351fa, 0x048c7662, 0x193d55cb, 0x3c4f83}}, + {{0x005cecab, 0x012c49ed, 0x13dae1dd, 0x056a8903, 0x07880198, 0x12b9e1d9, 0x0da8ceb5, 0x00ea2951, 0x944790}}}, + /* 11*16^47*G: */ + {{{0x1d86dfa9, 0x0830fedd, 0x0e64e9c6, 0x11694813, 0x03baadc3, 0x0f01f408, 0x1f538a70, 0x0511532c, 0xaff8e1}}, + {{0x01d12681, 0x1881e1b6, 0x067e71c1, 0x02db5288, 0x153f4f91, 0x15d50fe7, 0x10ff4f4f, 0x166426ef, 0x8d8b4b}}}, + /* 13*16^47*G: */ + {{{0x189ba9c1, 0x07939b5c, 0x074ce38a, 0x1ef94b41, 0x0e579e40, 0x01315767, 0x02cfa116, 0x08a51b80, 0xd3fb78}}, + {{0x0b51b267, 0x10dc46ff, 0x046b7801, 0x19dbab80, 0x10fe6341, 0x102bac5b, 0x139f29f2, 0x069df4d6, 0xf894d4}}}, + /* 15*16^47*G: */ + {{{0x0f2bb909, 0x0d4b60e8, 0x16636667, 0x0204f8a6, 0x07d7f639, 0x14c41c8c, 0x0a23fd1c, 0x01c15935, 0x4ec930}}, + {{0x04cf4071, 0x0451c1fd, 0x0b0e09ee, 0x1c2d041b, 0x049bad52, 0x0e228c26, 0x13717203, 0x00d7c360, 0x782ba1}}} + }, + { + /* 1*16^48*G: */ + {{{0x0120e2b3, 0x19dac7d1, 0x11fe6a9f, 0x11fb9cfe, 0x0e5217a5, 0x0571a673, 0x16eb9ef9, 0x1e43ea37, 0xeaa649}}, + {{0x1a5ad93d, 0x03d2982d, 0x0fdf9675, 0x0d72cbe2, 0x1aa5a01a, 0x007c4c3c, 0x00eb1a6a, 0x1dab7776, 0xbe3279}}}, + /* 3*16^48*G: */ + {{{0x1f2e070d, 0x0c1fe9d1, 0x0a9aa63d, 0x156e398a, 0x047e229a, 0x18e1dc28, 0x0affd21c, 0x1d2085e9, 0x4b72a5}}, + {{0x096dd780, 0x025d4177, 0x05230f79, 0x08cbbba5, 0x13c10b0b, 0x1dd9b687, 0x073d809d, 0x09c3ad5c, 0x599e1d}}}, + /* 5*16^48*G: */ + {{{0x0a02591c, 0x0e73fec2, 0x1449687a, 0x0a932cb0, 0x1fd613ef, 0x1fdf5af0, 0x038a169a, 0x1f8ca739, 0xa9fc93}}, + {{0x09bec2dc, 0x0856ef7b, 0x13dc94de, 0x111882bf, 0x165e5ca8, 0x00bd0d48, 0x1c5cfa13, 0x073b8a70, 0x9c2ce7}}}, + /* 7*16^48*G: */ + {{{0x0d968b59, 0x08037071, 0x12ef0b84, 0x05175c27, 0x1027709a, 0x1d60904d, 0x1c29a9f5, 0x0f834df3, 0xc94001}}, + {{0x0de572fb, 0x17ebb204, 0x0432723f, 0x08596c87, 0x1742ce28, 0x10dfd2da, 0x18804ee2, 0x0a019370, 0x39d922}}}, + /* 9*16^48*G: */ + {{{0x126b3332, 0x143999ab, 0x1b9779a8, 0x0711a0e7, 0x1f8e0310, 0x09d2fb85, 0x0093b19e, 0x13afdda0, 0x1f84bb}}, + {{0x14e8d52e, 0x0a214518, 0x1b70e895, 0x199c5a86, 0x1edf0c2b, 0x013fbadc, 0x1b30951f, 0x00e57953, 0xee726d}}}, + /* 11*16^48*G: */ + {{{0x0defa98e, 0x06d52a56, 0x0b09e657, 0x1088d023, 0x1e9c7724, 0x0abd9cc8, 0x1341b2a0, 0x112128bf, 0xf13e0}}, + {{0x1e286767, 0x0453bb4d, 0x13ab3370, 0x1ce0bc2d, 0x162db287, 0x1c5853d9, 0x1140d78f, 0x1e2ec9cf, 0xadd521}}}, + /* 13*16^48*G: */ + {{{0x09f59b6b, 0x0f0e01df, 0x02238be9, 0x0718c783, 0x026d3e9b, 0x050e96ac, 0x11f6cdca, 0x14aa3bbd, 0xdde191}}, + {{0x06cb1410, 0x156cb149, 0x0553fb3d, 0x0e7177ce, 0x0e14e8b5, 0x0beb0e29, 0x172f829d, 0x0f00504e, 0x5b2bfb}}}, + /* 15*16^48*G: */ + {{{0x09c6b699, 0x1462afee, 0x191a1c6d, 0x1eae6ad7, 0x01682a86, 0x0bdfcbda, 0x1de9685b, 0x05ddb06d, 0x5fab01}}, + {{0x01c6c3aa, 0x0b990a96, 0x020d466c, 0x1622ffd5, 0x02f7b90a, 0x1a08986b, 0x0513a7ae, 0x0e14787a, 0x2d9bfa}}} + }, + { + /* 1*16^49*G: */ + {{{0x1a34d24f, 0x111b196e, 0x084dd007, 0x0db1e193, 0x02ee541b, 0x0fb6f67a, 0x1a764e47, 0x0878b9e2, 0xe4a42d}}, + {{0x1eba9414, 0x13fb898e, 0x16393c4e, 0x0dddbf51, 0x0d34ce88, 0x0ce67dc5, 0x1cd49bf2, 0x1ce2da38, 0x4d9f92}}}, + /* 3*16^49*G: */ + {{{0x1bea0c68, 0x04208579, 0x1ece4ad7, 0x060246ce, 0x16faf094, 0x1e47469c, 0x0e892526, 0x069c2ad4, 0x3e4196}}, + {{0x1a45edb6, 0x05db7fb8, 0x0f3686af, 0x02328c60, 0x093062fa, 0x05ff1b83, 0x07dfcdcf, 0x13b24964, 0x123c5}}}, + /* 5*16^49*G: */ + {{{0x139824d7, 0x1bae91e4, 0x072625eb, 0x0f6c986a, 0x10b576eb, 0x11f317bf, 0x1423bb52, 0x1ea8abae, 0x8d9438}}, + {{0x1366489f, 0x10027a44, 0x1ac18f62, 0x13c57064, 0x0ef6f8fb, 0x05e98d5b, 0x10a8b298, 0x0e69fdcd, 0x3261e0}}}, + /* 7*16^49*G: */ + {{{0x18d713de, 0x124038d4, 0x0a398823, 0x0185f6e8, 0x14543936, 0x089517f2, 0x1108352a, 0x18ab1dca, 0xb72524}}, + {{0x1b8350e9, 0x17ff292c, 0x1297f2dd, 0x05a4dfc8, 0x09415048, 0x08c174eb, 0x1914410b, 0x13514507, 0x4c51b3}}}, + /* 9*16^49*G: */ + {{{0x1e3b2cb4, 0x0636149f, 0x1c84100b, 0x13e6b7e6, 0x1149e304, 0x1b71c090, 0x09466b71, 0x0b442da2, 0x3de45f}}, + {{0x107eb02f, 0x10f19d61, 0x01c1133d, 0x1c51ccb5, 0x09106823, 0x055254be, 0x17714382, 0x13080bd5, 0xba2a85}}}, + /* 11*16^49*G: */ + {{{0x0ce4e5bf, 0x11a3b37b, 0x04016c5c, 0x0f950d41, 0x106ae9b6, 0x1e71ba44, 0x1a1f078f, 0x18d12b37, 0x8511f1}}, + {{0x01789c08, 0x1e494a26, 0x14d9498b, 0x10f11378, 0x000232da, 0x0fbf6355, 0x121d3077, 0x19f2379a, 0xecdff5}}}, + /* 13*16^49*G: */ + {{{0x1d3258ab, 0x0dab3451, 0x0f05370c, 0x04850315, 0x0ab5957d, 0x0e39770a, 0x0088b3e8, 0x05d039ec, 0x8c5a05}}, + {{0x022d0f8f, 0x0bf04298, 0x16512b79, 0x15d1f381, 0x008c246d, 0x0063c826, 0x16841e6a, 0x09768877, 0x6811db}}}, + /* 15*16^49*G: */ + {{{0x1f91bcee, 0x0c615055, 0x03036105, 0x1e3b1e3c, 0x1f137f5c, 0x1e762ab5, 0x1582f718, 0x02dbd7a6, 0xcef7f8}}, + {{0x01966b33, 0x1da6d4fc, 0x1cbdab1a, 0x1c960542, 0x1245fa63, 0x199ce00e, 0x1c04918e, 0x106c6e90, 0x67e74c}}} + }, + { + /* 1*16^50*G: */ + {{{0x0300bf19, 0x18b9dcea, 0x03fa9251, 0x0a6aed51, 0x12b6b92b, 0x07d6d59a, 0x17655058, 0x1de6c197, 0x1ec80f}}, + {{0x0107cefd, 0x18e6e0e6, 0x05681ed9, 0x0dcefec5, 0x1bf5e014, 0x04ac53d5, 0x1034bce9, 0x06ead6a6, 0xaeefe9}}}, + /* 3*16^50*G: */ + {{{0x12fea1f9, 0x18be5de2, 0x0114ae52, 0x1e16a118, 0x06531c4f, 0x0ed5b388, 0x0ba0ef3f, 0x014aba3e, 0xa6dc88}}, + {{0x1bc345e9, 0x18e0a723, 0x1a3df98e, 0x1713b6fc, 0x0bc50057, 0x01d08b56, 0x1f0c0e1a, 0x0a8fb86c, 0x7ef1a8}}}, + /* 5*16^50*G: */ + {{{0x06d6c9b3, 0x06a061f8, 0x01958df2, 0x1899d0e9, 0x081ba8c6, 0x114e3c52, 0x1664af70, 0x07fd4848, 0xfe6ba9}}, + {{0x0948bdfb, 0x0163c47d, 0x10ba6c03, 0x01e37e0b, 0x13b56d98, 0x00d9a2a0, 0x01cadaed, 0x1ae80a73, 0x7ee918}}}, + /* 7*16^50*G: */ + {{{0x0cf95151, 0x11788398, 0x0b12d910, 0x0900dc88, 0x0ded1b96, 0x04616e04, 0x02fec083, 0x1e28df93, 0x15d5e2}}, + {{0x0ff8ecf2, 0x01503e61, 0x16303e52, 0x009f72fb, 0x023f9bb2, 0x1084bc48, 0x13b1fe43, 0x06322bfa, 0xa5b72e}}}, + /* 9*16^50*G: */ + {{{0x096a5658, 0x0bc085c9, 0x1bd9590f, 0x0964a483, 0x029be381, 0x100493d7, 0x11eb631f, 0x0e4ad108, 0x84c0e8}}, + {{0x181b80d1, 0x0cb394de, 0x13c7f48b, 0x0c35303e, 0x1725ed3a, 0x118c8329, 0x0b12821f, 0x10182c04, 0x265983}}}, + /* 11*16^50*G: */ + {{{0x14dc6a0f, 0x1addae44, 0x1f855d4d, 0x06832285, 0x077c2744, 0x1273d160, 0x0c755949, 0x18e3526e, 0xfed6b1}}, + {{0x176fc7e0, 0x05c6b96c, 0x0ff10273, 0x09ab2614, 0x1ae23137, 0x0c0d7269, 0x1c2a11e4, 0x1cd61fff, 0x8de2ab}}}, + /* 13*16^50*G: */ + {{{0x18e29355, 0x19c42f88, 0x1c8361b6, 0x191d2672, 0x1b9d82f1, 0x1c302011, 0x0f1c3f3b, 0x1b325a79, 0x2a6a4d}}, + {{0x15cc2872, 0x029f007d, 0x1131db00, 0x00b474c9, 0x0f90dfe9, 0x0e40f134, 0x1831d83f, 0x174f894f, 0x8677df}}}, + /* 15*16^50*G: */ + {{{0x0148dabf, 0x1cfd447f, 0x075e3ac7, 0x1ba57269, 0x0e735c1a, 0x07611afd, 0x151b65d9, 0x004d924e, 0xe42d93}}, + {{0x011e1361, 0x1b963ab4, 0x19dfae75, 0x04eae033, 0x18530327, 0x0675fef9, 0x12c362ce, 0x058dc5b0, 0x641386}}} + }, + { + /* 1*16^51*G: */ + {{{0x166642be, 0x0edac941, 0x162ea227, 0x0920e2fa, 0x1fa8bce3, 0x057a3406, 0x10be46c0, 0x11808ce1, 0x146a77}}, + {{0x1d83efd0, 0x0594ba41, 0x1f97b474, 0x152e3a5e, 0x0b2870aa, 0x0c13fcea, 0x0a2b759a, 0x1d866a80, 0xb318e0}}}, + /* 3*16^51*G: */ + {{{0x07315443, 0x0c9c39c1, 0x1a19ca67, 0x1377aa95, 0x142a13d7, 0x04cc1050, 0x0d7fd0b2, 0x0080cc12, 0xfc696c}}, + {{0x17d28960, 0x0486b05a, 0x06f46c5d, 0x1fe90c21, 0x077b5487, 0x10e6eb4b, 0x024aefc3, 0x1d7f076b, 0xe0ce27}}}, + /* 5*16^51*G: */ + {{{0x16fdb4eb, 0x0dd97ae0, 0x0b9a9e74, 0x07baf38c, 0x0b0928fa, 0x151ab15f, 0x0ab46b95, 0x043fe9fe, 0x974af2}}, + {{0x09f6f484, 0x004e1efd, 0x1ff08d21, 0x18ae5477, 0x090ed111, 0x121e8160, 0x0f299347, 0x0faa6a00, 0x555238}}}, + /* 7*16^51*G: */ + {{{0x1d5aeee3, 0x1c8256da, 0x163204dc, 0x109786cc, 0x070c5e82, 0x0d9d3349, 0x062c2448, 0x13693bc7, 0x5baab5}}, + {{0x10f69717, 0x1694d7db, 0x14c7bb60, 0x1bb93b57, 0x1daf7215, 0x004330ff, 0x1a15b968, 0x0c2f81ef, 0x8a577f}}}, + /* 9*16^51*G: */ + {{{0x15726890, 0x08d8f227, 0x00df4561, 0x004bfd59, 0x10a0ee59, 0x17e75fc8, 0x10f4040c, 0x14fd6938, 0xfb685f}}, + {{0x1835783a, 0x0375479d, 0x039e6c98, 0x0d9625d2, 0x0ba094fa, 0x10b6cc32, 0x18ba1a72, 0x045931cb, 0xd750df}}}, + /* 11*16^51*G: */ + {{{0x08bca48a, 0x0325f89d, 0x0f7d8bd5, 0x09abe9d0, 0x1f71d78b, 0x1dc8e143, 0x05682ac9, 0x1ecb3c53, 0x5de58f}}, + {{0x12fd41cd, 0x03ca7406, 0x03e2aa56, 0x0b7b389c, 0x13c843fe, 0x111e1296, 0x0d54c269, 0x07b006b3, 0x685a3b}}}, + /* 13*16^51*G: */ + {{{0x05ef63b6, 0x0f1c1a27, 0x06c60baf, 0x09a02ce6, 0x1c1c85ab, 0x1fed1da7, 0x02febc6d, 0x19bd5ac3, 0x6f1825}}, + {{0x05c655f3, 0x1642367a, 0x1fe51504, 0x12b4c804, 0x134553c8, 0x1026bc19, 0x046e63d0, 0x0fbab232, 0xff097e}}}, + /* 15*16^51*G: */ + {{{0x14a63f3b, 0x1a823f6f, 0x1e3e5c9e, 0x00760332, 0x0c765832, 0x08afaf3b, 0x0ddad61c, 0x12beec54, 0xc5ecb8}}, + {{0x05005024, 0x09f9ba34, 0x0c2fb96d, 0x16cbdcbc, 0x033ec8be, 0x002c7fc9, 0x07cdd3a9, 0x03032f10, 0x222525}}} + }, + { + /* 1*16^52*G: */ + {{{0x1180eef9, 0x0bb543c9, 0x0a2e5ddb, 0x00244134, 0x07b128d0, 0x075d8d50, 0x17c1f8eb, 0x1ec3a45c, 0xfa50c0}}, + {{0x1f4f2811, 0x066c6be9, 0x1e884ece, 0x1065274a, 0x1a68a5e6, 0x09439140, 0x0ea6dcb3, 0x124472fd, 0x6b84c6}}}, + /* 3*16^52*G: */ + {{{0x11da5e12, 0x0f70719c, 0x12b2ca5c, 0x0c14802b, 0x0a2b6a9c, 0x14fc9d0e, 0x0c6f368c, 0x07886f3c, 0xf7502e}}, + {{0x0385f4eb, 0x125ce2f4, 0x0973af1e, 0x0da65dee, 0x072047b8, 0x04a2e1eb, 0x0bf5665c, 0x1dbacf9f, 0x3c57f5}}}, + /* 5*16^52*G: */ + {{{0x10b7d105, 0x03a49988, 0x195f27c8, 0x14b89729, 0x055b3f4c, 0x1b31271a, 0x018a8e93, 0x1f3075cb, 0x12fe78}}, + {{0x1f794a60, 0x0c5637dc, 0x1ba42e11, 0x19c4cbad, 0x1cb771de, 0x0d50ccd3, 0x13dde1ad, 0x14671ad7, 0x2062f1}}}, + /* 7*16^52*G: */ + {{{0x1e0c5d05, 0x110ec19c, 0x15cb6bfd, 0x1cd8a154, 0x04b1a480, 0x1d881404, 0x1cf56312, 0x0268fbe8, 0x76aac3}}, + {{0x11ece63e, 0x0b30cdba, 0x179bb8d5, 0x044b9e02, 0x0625f4b1, 0x19641901, 0x03beafbc, 0x1de1ab8e, 0xef5576}}}, + /* 9*16^52*G: */ + {{{0x1c53c086, 0x1137a42f, 0x0686bb27, 0x0ab86939, 0x08104c6b, 0x0618a2f4, 0x13321f98, 0x0b77cb8b, 0xa663fe}}, + {{0x05016201, 0x14e28195, 0x0653f039, 0x1d994ae7, 0x03dc3991, 0x081644c1, 0x1efd746c, 0x0fed6423, 0xb54199}}}, + /* 11*16^52*G: */ + {{{0x0b758574, 0x16c00f6a, 0x13e71ba6, 0x04cd1286, 0x0bdf3d83, 0x10813d71, 0x16096df2, 0x0f4040d9, 0xde9552}}, + {{0x1b67232a, 0x1bef8fe7, 0x168b7ad2, 0x0d420a2a, 0x09ed7bae, 0x0e423f8b, 0x05393887, 0x0ad5927a, 0x4cd3e0}}}, + /* 13*16^52*G: */ + {{{0x1d85474f, 0x1bcdc55f, 0x18d19a35, 0x18945712, 0x05aea894, 0x065f223c, 0x0b76ffb7, 0x1c0cda65, 0x8da6bc}}, + {{0x1d7b4ef7, 0x1efce3e9, 0x16f75e97, 0x198b260b, 0x1fff10b1, 0x0fae838e, 0x13fe13f7, 0x0d5e63da, 0x13fc6c}}}, + /* 15*16^52*G: */ + {{{0x1dd042ea, 0x1aea12b3, 0x03abf41a, 0x144d4c8b, 0x093beebf, 0x1324f19e, 0x08e6c6f5, 0x18f9f677, 0x7329ac}}, + {{0x0f5c94a1, 0x0d467f61, 0x1ead3c2b, 0x112ee63b, 0x168ee184, 0x073ca7d5, 0x1c5224a1, 0x06a836ed, 0x927249}}} + }, + { + /* 1*16^53*G: */ + {{{0x1f067ec2, 0x129e995a, 0x0ee94883, 0x11156bab, 0x0e8421a2, 0x1fb5bec4, 0x0846c696, 0x1a194e43, 0xda1d61}}, + {{0x1ad836f1, 0x0afdd078, 0x1e6d2299, 0x0e7133a4, 0x11e2966a, 0x1b30b0e4, 0x01b1e701, 0x0b4f9326, 0x8157f5}}}, + /* 3*16^53*G: */ + {{{0x1a95a8db, 0x0ec3b997, 0x074dbd85, 0x1d81888f, 0x11723b83, 0x13234c8d, 0x141067a5, 0x148c607b, 0xe3e90d}}, + {{0x1b0d1cf9, 0x00b67bf8, 0x06134f44, 0x03df2f99, 0x0e76afbb, 0x15486381, 0x1e2ec03e, 0x1800ad82, 0xfbe53b}}}, + /* 5*16^53*G: */ + {{{0x112ee214, 0x1d57eb20, 0x04c55005, 0x149d2f2b, 0x0c01c782, 0x086feae0, 0x1dd6a2d9, 0x18e65c7a, 0x9f4ffe}}, + {{0x1085f37a, 0x17a21112, 0x12200a0f, 0x136d2617, 0x1c69d971, 0x13417eba, 0x1cb983a5, 0x1c2631c5, 0x639ce2}}}, + /* 7*16^53*G: */ + {{{0x1f61a0a5, 0x05b40a28, 0x10538fbe, 0x04a7c367, 0x00b2c4b1, 0x10520fa2, 0x0b06c5c6, 0x05a82269, 0x431f62}}, + {{0x18cef899, 0x15bdbff3, 0x1595dc91, 0x1554086a, 0x1aa7241b, 0x1328cb91, 0x0e3db5b7, 0x0ffcf548, 0xa29832}}}, + /* 9*16^53*G: */ + {{{0x07748503, 0x16133eab, 0x04ca39f2, 0x1c1c8ee6, 0x012ac0e6, 0x1779cfc5, 0x1ee1b2d8, 0x1bbd9cf1, 0x993dba}}, + {{0x1eb0cee2, 0x1d39b09b, 0x02b6a926, 0x10f7ed37, 0x1f51a17f, 0x1c23c3d0, 0x1bade17d, 0x1dd0ad3d, 0xa521a9}}}, + /* 11*16^53*G: */ + {{{0x06d23d80, 0x0f5113ad, 0x11d351e3, 0x17a23e4c, 0x162c0e10, 0x018e5c84, 0x1a968ce5, 0x1740d5ab, 0x75f17a}}, + {{0x080dd57e, 0x03542d81, 0x13a96426, 0x1ff7db76, 0x16292372, 0x1e85f8cd, 0x0a031ff1, 0x1fc2ac73, 0xa07a62}}}, + /* 13*16^53*G: */ + {{{0x01ad3413, 0x115cdb6b, 0x09f5a12b, 0x13800806, 0x07b7a8db, 0x0fa42e5c, 0x12829ba5, 0x0bc23b3e, 0x667855}}, + {{0x1ebca672, 0x12408103, 0x17199804, 0x1c5a2a75, 0x1df9ea6c, 0x136c93e5, 0x191a4949, 0x07bc4f1e, 0x510dda}}}, + /* 15*16^53*G: */ + {{{0x06cc8563, 0x00057ad8, 0x18407aab, 0x09beb7ff, 0x03688922, 0x015ec0cb, 0x1d22b6b2, 0x06c59b4e, 0xebdc4a}}, + {{0x0394ccfa, 0x0d8bde75, 0x0813e492, 0x080f2492, 0x14f07bec, 0x11af366e, 0x0d7e6c7b, 0x089d0ada, 0x659a31}}} + }, + { + /* 1*16^54*G: */ + {{{0x0d064e13, 0x139d8308, 0x1bc7818a, 0x023bc088, 0x14166153, 0x1fcc747e, 0x1a41c857, 0x1fe192e0, 0xa8e282}}, + {{0x11f4cc0c, 0x17be3988, 0x175af5b3, 0x0f347ca1, 0x115888b6, 0x1f9e2d92, 0x1026afed, 0x0b71b703, 0x7f9735}}}, + /* 3*16^54*G: */ + {{{0x1a3979b5, 0x150ccd85, 0x1fa0a788, 0x111f1bcc, 0x00e50ba2, 0x1f858f72, 0x098c9fcd, 0x18b9b5bc, 0xae2207}}, + {{0x0450fa6f, 0x079e6b34, 0x153e225a, 0x10f6fa6f, 0x17060fca, 0x092291d6, 0x1dc6b532, 0x0a2180f3, 0xea91fe}}}, + /* 5*16^54*G: */ + {{{0x0efca824, 0x0080c880, 0x08593eb9, 0x1c189fd4, 0x05461e0b, 0x0a08032c, 0x139673b1, 0x0195ae55, 0xcb8ded}}, + {{0x0f227361, 0x0a05e82c, 0x04c5d0bc, 0x1a3fbf8f, 0x0cbc496a, 0x16243d16, 0x03216cc5, 0x11ee81b1, 0x33a500}}}, + /* 7*16^54*G: */ + {{{0x1bcbd327, 0x008da6d1, 0x192abba5, 0x1c10a443, 0x16ed6b04, 0x04806bf3, 0x0d9c23a5, 0x05315e30, 0xb0c53b}}, + {{0x0d7be436, 0x10b5e251, 0x18da83c5, 0x144418e8, 0x0b2afd82, 0x15300db3, 0x1a858e3d, 0x0803f7af, 0xee2a97}}}, + /* 9*16^54*G: */ + {{{0x17b836a1, 0x1377db1c, 0x19e7bdf7, 0x0c80bfee, 0x1f526c80, 0x0317673b, 0x04835362, 0x07e653b7, 0x6f6ba7}}, + {{0x06832b84, 0x0def97d8, 0x187fe4d3, 0x1218a511, 0x0e9c0d89, 0x1c5202df, 0x0638f6c2, 0x02ffebf8, 0xdc778a}}}, + /* 11*16^54*G: */ + {{{0x1eb39ede, 0x1771a104, 0x0184b50a, 0x110065ae, 0x04360310, 0x1a33f081, 0x0bd2ef3f, 0x0fb8e845, 0x7d471a}}, + {{0x0bf6607e, 0x04de6ca5, 0x08aa3f43, 0x0b9efa38, 0x086fa779, 0x1118f7fe, 0x15941ee0, 0x033e74d0, 0x4a7b}}}, + /* 13*16^54*G: */ + {{{0x165eb1c1, 0x0b6a4f12, 0x0b9716a9, 0x1aeacf9b, 0x0f0967fc, 0x1e618cc1, 0x1eb1c1c3, 0x0c7f36e7, 0xf00251}}, + {{0x0dde2ae0, 0x0d3eb823, 0x1344795f, 0x0dfeb9ad, 0x0afed857, 0x1a52ed13, 0x037d319a, 0x1d1107a4, 0x54ea9}}}, + /* 15*16^54*G: */ + {{{0x1ac32c64, 0x079a849e, 0x0b92fe13, 0x0dfc07d9, 0x1715e0e3, 0x074a87a3, 0x0ea83dc1, 0x00003da4, 0xac1214}}, + {{0x1eb1a867, 0x00956dd6, 0x14fc2262, 0x14ba74b4, 0x099a3ed5, 0x1b4ab982, 0x0ebc61c2, 0x19758671, 0xce8ebc}}} + }, + { + /* 1*16^55*G: */ + {{{0x0319497c, 0x179c16f4, 0x09423008, 0x1363f4a2, 0x1cab15d5, 0x12b73489, 0x161cb4e7, 0x17393450, 0x174a53}}, + {{0x079afa73, 0x1ed09d60, 0x0e6150e0, 0x16743b19, 0x1f9e6646, 0x0aaf9623, 0x10595ed0, 0x06f57f93, 0xccc9dc}}}, + /* 3*16^55*G: */ + {{{0x154b8367, 0x0a4039eb, 0x1541affa, 0x0b6efacf, 0x16a5db77, 0x12ea2c21, 0x09b9032a, 0x095c88ca, 0x5e5a09}}, + {{0x11ce85ca, 0x0994d4ec, 0x197fe911, 0x1553de7b, 0x04b7a796, 0x00f8ab95, 0x18170b24, 0x19348f2b, 0xae8af8}}}, + /* 5*16^55*G: */ + {{{0x17b10d9d, 0x0cc2bc9c, 0x07e3f2bc, 0x0a5e313a, 0x0b82de6a, 0x05c19886, 0x1a1677b3, 0x15b72e05, 0xd4e0}}, + {{0x1140dced, 0x01080243, 0x18b648fa, 0x113192f1, 0x087f70b5, 0x1c232191, 0x10251f4b, 0x130306ec, 0x87b801}}}, + /* 7*16^55*G: */ + {{{0x1c9caee8, 0x0408d304, 0x089c2ec8, 0x1c408b63, 0x0a667632, 0x10cd7762, 0x1303dbde, 0x026d1dee, 0x36652}}, + {{0x1772b711, 0x14f6351d, 0x056e9fc2, 0x17531265, 0x0944501c, 0x1e340dd3, 0x1b666527, 0x0565527b, 0x1f18c3}}}, + /* 9*16^55*G: */ + {{{0x1446c85c, 0x1ffcba8c, 0x007018d4, 0x0fbc11cc, 0x0c6eade3, 0x1b6229fb, 0x1c7ea819, 0x00adfb71, 0xe5891}}, + {{0x0148972e, 0x1b63bf39, 0x1376b757, 0x00469d01, 0x01898f49, 0x00c5d7a4, 0x0f683b1d, 0x0be23f4f, 0xe39a48}}}, + /* 11*16^55*G: */ + {{{0x022e1259, 0x18c56f9e, 0x004d8abf, 0x0e73480d, 0x17771931, 0x1afd5003, 0x18fcadb3, 0x0da4de28, 0xa74012}}, + {{0x134a5f43, 0x1bb8b921, 0x075b6b57, 0x0cbcea76, 0x07ee5178, 0x18ba533e, 0x07fc6c17, 0x175e329e, 0x5a9ff}}}, + /* 13*16^55*G: */ + {{{0x0b08f1fe, 0x0450bd1e, 0x0821eff6, 0x1cfdce17, 0x0d177d7c, 0x02bb2ec1, 0x13929950, 0x042db28e, 0x87e4b8}}, + {{0x0ed5e2ec, 0x0fba564d, 0x1e1b675d, 0x1e47b7ac, 0x0c2cc6e2, 0x1fc7517c, 0x033b35f5, 0x180ecc69, 0xf74e3a}}}, + /* 15*16^55*G: */ + {{{0x01c4d15c, 0x14380735, 0x1039d2e6, 0x1d4f7e0f, 0x14a44105, 0x11606092, 0x0696a4b0, 0x08c7fd4f, 0x35ea1b}}, + {{0x1f3fe1ea, 0x049cdd7b, 0x194257b7, 0x06754060, 0x13b185d6, 0x1d2feba6, 0x0b35e223, 0x0ca373da, 0xad2191}}} + }, + { + /* 1*16^56*G: */ + {{{0x1475b7ba, 0x027eff84, 0x0462cf62, 0x13ce61c9, 0x18cdbe03, 0x0bf6fa80, 0x0170f4f9, 0x1303286f, 0x959396}}, + {{0x1524f2fd, 0x0dc55fc3, 0x1c24e17a, 0x0a7ec990, 0x0d6849c6, 0x1c3525ce, 0x07762e80, 0x05111866, 0x2e7e55}}}, + /* 3*16^56*G: */ + {{{0x0fd69985, 0x04e2eec8, 0x17dcaba8, 0x013996db, 0x0cf149f3, 0x1486fde6, 0x1df9e23d, 0x0eb9d6e5, 0xae976}}, + {{0x1409a003, 0x0e475a08, 0x1b86bfe2, 0x133a82f5, 0x054c5d0b, 0x0ff7028d, 0x1453a6e3, 0x0e7edc91, 0x912199}}}, + /* 5*16^56*G: */ + {{{0x19262b90, 0x0e0c9efe, 0x0f30a6a7, 0x078983fc, 0x05d1fb72, 0x0f8bbc01, 0x04bb26d9, 0x054b582c, 0x2b1586}}, + {{0x083d7557, 0x08ccb732, 0x05226926, 0x0692e1f3, 0x149066f5, 0x06a96d43, 0x0fea9e8c, 0x07b54146, 0x2eb005}}}, + /* 7*16^56*G: */ + {{{0x08e7be40, 0x1fcb8a65, 0x0103b964, 0x05912922, 0x0769af2d, 0x0e0b0b72, 0x199dfba5, 0x1da352dd, 0x6af9ea}}, + {{0x0e387e1c, 0x120b7013, 0x1d655a7e, 0x07eccd41, 0x1dc8145e, 0x152141a3, 0x19259c27, 0x022d200c, 0xb3812a}}}, + /* 9*16^56*G: */ + {{{0x1482801e, 0x135b7d07, 0x0f505574, 0x129f178b, 0x0d6f9407, 0x15a1265c, 0x113bacea, 0x1dc08882, 0x596668}}, + {{0x04870c37, 0x03b8a478, 0x14d4d6b5, 0x0d8396c7, 0x1304e8db, 0x1cb043b8, 0x1d7c7b23, 0x150b775d, 0x949aa0}}}, + /* 11*16^56*G: */ + {{{0x032c19fd, 0x064d973e, 0x000a30f9, 0x1571d20b, 0x10b5b4ac, 0x068bd5ab, 0x01d8bf7d, 0x11036a0a, 0xbe84d1}}, + {{0x12f1281f, 0x1b4a529b, 0x14370dd9, 0x0b4feabc, 0x03994795, 0x12fa4184, 0x02513479, 0x19665b8a, 0xeff960}}}, + /* 13*16^56*G: */ + {{{0x16c69482, 0x08dbafea, 0x0be859ef, 0x156a8026, 0x0bc88cbe, 0x193a6579, 0x1b9507d5, 0x062981af, 0x9867a0}}, + {{0x0f792cd7, 0x178308a3, 0x158a2a45, 0x048b9ea2, 0x099639e6, 0x16aad8dd, 0x0d3e71e4, 0x0b476210, 0xd02e61}}}, + /* 15*16^56*G: */ + {{{0x1d557aa1, 0x0511cec8, 0x007f0a5e, 0x1b25fd9a, 0x1d6abdf1, 0x1975004c, 0x0569649f, 0x08a81b10, 0xa866f2}}, + {{0x01430634, 0x0c0ddda6, 0x184692de, 0x16d38cf8, 0x0e13961e, 0x0c7d2ed8, 0x0d135e4f, 0x1ed50045, 0xb58739}}} + }, + { + /* 1*16^57*G: */ + {{{0x1d82b151, 0x1a89a064, 0x07ee8b6e, 0x01487aac, 0x09a8fcca, 0x108a9d88, 0x195b5916, 0x0a15c803, 0xd2a63a}}, + {{0x1cf89405, 0x00a10ba6, 0x013294b5, 0x1eea15e9, 0x08220a70, 0x172c594a, 0x12dd596b, 0x1f6c887f, 0xe82d86}}}, + /* 3*16^57*G: */ + {{{0x0e4b3ba0, 0x02cfb1af, 0x02fc7c5e, 0x157debe3, 0x1245f5c2, 0x0b8798df, 0x0dcefbf8, 0x00a443ff, 0x410811}}, + {{0x17525595, 0x034b0ee0, 0x08191552, 0x0c930acb, 0x18498133, 0x12d70eb5, 0x19a3cb29, 0x0d2edfea, 0xdc37f3}}}, + /* 5*16^57*G: */ + {{{0x13d98ded, 0x114e4dc4, 0x02808611, 0x1e450677, 0x1d65edbd, 0x114c8298, 0x0323233c, 0x02142d98, 0x63a2a2}}, + {{0x00d1cfc2, 0x0c8cbea7, 0x11e1ce94, 0x17ed4013, 0x194461fa, 0x01992a76, 0x1dbf4194, 0x1c5cffd8, 0x882b42}}}, + /* 7*16^57*G: */ + {{{0x18045445, 0x1430d285, 0x07a35fba, 0x1ee6e320, 0x1bef080f, 0x17172eab, 0x1f28f7c4, 0x0ba893ac, 0xc1581}}, + {{0x0054a206, 0x0a7c3eaa, 0x1633a8c8, 0x00a9c86c, 0x1cd28ba3, 0x1e1db331, 0x045742a4, 0x01475d28, 0x2f30d6}}}, + /* 9*16^57*G: */ + {{{0x03857faf, 0x14891ce6, 0x05865c07, 0x1f95bc3d, 0x0ef7f882, 0x1d47a414, 0x0a70355e, 0x0d7135d1, 0xc757eb}}, + {{0x00584ca4, 0x0eced865, 0x06253040, 0x1a621a20, 0x0c61b627, 0x14f9045f, 0x1cd895cd, 0x19f9a47f, 0xf03a59}}}, + /* 11*16^57*G: */ + {{{0x1459225d, 0x1268c27a, 0x02163443, 0x15eefc5b, 0x002a244f, 0x0a04c8ce, 0x0343e057, 0x15d5b5f4, 0xfa8063}}, + {{0x1ece1507, 0x115bf1db, 0x01f1670e, 0x16d86da0, 0x0425c0a2, 0x11104126, 0x01a45837, 0x120af818, 0xba71f}}}, + /* 13*16^57*G: */ + {{{0x16f0d044, 0x13cff4a0, 0x079869e5, 0x153fa921, 0x0e0a5aab, 0x14e7c317, 0x1ea278bd, 0x18b3a04a, 0x658ca3}}, + {{0x17cb872d, 0x0e8f9977, 0x0633a26b, 0x02cec788, 0x1d37655a, 0x0eb1389d, 0x15183c59, 0x06ef5d44, 0xae5cc1}}}, + /* 15*16^57*G: */ + {{{0x1696756d, 0x1ad64ab9, 0x158505ea, 0x15e2c0ac, 0x1305c676, 0x0cc1ae9f, 0x0aeb3930, 0x0955f23e, 0x31c94b}}, + {{0x1e08ae78, 0x1e22f46e, 0x0b441c2a, 0x1dbf95cd, 0x0160683a, 0x05acd57a, 0x0ea6fd2e, 0x096aadd0, 0xf80f88}}} + }, + { + /* 1*16^58*G: */ + {{{0x1617e073, 0x01b7cda2, 0x0e4c5ecd, 0x197b7a70, 0x1dc866ba, 0x1c4b6be7, 0x1ae243b9, 0x0466a8e3, 0x64587e}}, + {{0x1faf6589, 0x014cf2f4, 0x0ebaacd6, 0x12147226, 0x099a185b, 0x0eb223e1, 0x0b8aba5b, 0x1ab7ed20, 0xd99fcd}}}, + /* 3*16^58*G: */ + {{{0x0e103dd6, 0x0fb8a390, 0x0012166b, 0x0c0980f8, 0x0a17ac34, 0x09e7e2c9, 0x0fe0da88, 0x1aab4840, 0xbc477b}}, + {{0x16f7c343, 0x1c8416c6, 0x0ed12b18, 0x126ae58c, 0x0a6395d2, 0x02a9636f, 0x1549b2eb, 0x0485351b, 0xe31e1e}}}, + /* 5*16^58*G: */ + {{{0x144eab31, 0x086e1d86, 0x198d241f, 0x0b5e2809, 0x1f8e80ac, 0x1a11933d, 0x00e00c0e, 0x1fcb4d77, 0x589db4}}, + {{0x11361f6a, 0x00d75f3a, 0x123e36e5, 0x021caa42, 0x190f31f6, 0x0310125e, 0x0a93d81c, 0x0b821154, 0x625544}}}, + /* 7*16^58*G: */ + {{{0x1a0c2c41, 0x1fcb0b94, 0x00cdb19e, 0x063838ac, 0x0db7c428, 0x0c3056b7, 0x1e8baa28, 0x06fa2dc5, 0x1339b3}}, + {{0x09f1bc2b, 0x02f82a5d, 0x1a48e906, 0x044ff0fb, 0x1a3406b1, 0x1207e889, 0x196e9e8c, 0x0c6c58f5, 0x9f9b29}}}, + /* 9*16^58*G: */ + {{{0x18fc47af, 0x18258fc2, 0x10337b0d, 0x1bfd9065, 0x1b568a8d, 0x194da800, 0x1c5f3140, 0x14226c79, 0x7ff3bb}}, + {{0x19ba43a7, 0x1c30b267, 0x02eb0a5f, 0x0a7635a3, 0x1446b17a, 0x048dba39, 0x18a682f2, 0x15d00314, 0x1f6ba7}}}, + /* 11*16^58*G: */ + {{{0x15213775, 0x0c26b004, 0x150aa640, 0x08527647, 0x07f6100b, 0x149caff6, 0x02ed8507, 0x08c79d6c, 0x8ec670}}, + {{0x1841ffff, 0x100879f3, 0x13d47a43, 0x15314179, 0x1ee0e71d, 0x01a0ae76, 0x0f8c1b99, 0x0df41b4b, 0x8f58a6}}}, + /* 13*16^58*G: */ + {{{0x1452abbb, 0x059ffc69, 0x0e570b8f, 0x154e5fc5, 0x1d495ae6, 0x161ff6ca, 0x06ee276e, 0x16883ce0, 0x83de61}}, + {{0x054eb66e, 0x1028bb58, 0x1390a462, 0x18be6d77, 0x01563d79, 0x1b57c627, 0x027e9afe, 0x0694698c, 0x32f0e3}}}, + /* 15*16^58*G: */ + {{{0x159276f1, 0x0b446137, 0x085ec57a, 0x1c4b6525, 0x0d86833a, 0x1ae007be, 0x076c6a2e, 0x1131ea18, 0x3d7663}}, + {{0x059cbcb3, 0x0f2532dc, 0x0c65e180, 0x03304033, 0x0333ef32, 0x171a6d6c, 0x176d825d, 0x0e6f430f, 0xd37669}}} + }, + { + /* 1*16^59*G: */ + {{{0x1d45e458, 0x0c6b6436, 0x1439ff4d, 0x154d9d44, 0x1de042f0, 0x0369f2a4, 0x0216ce95, 0x1c1c9c9b, 0x8481bd}}, + {{0x1779057e, 0x0b258dac, 0x098b955b, 0x14f38856, 0x0b2ca900, 0x0df9ce76, 0x13761289, 0x11974a80, 0x38ee7b}}}, + /* 3*16^59*G: */ + {{{0x152da17d, 0x10507d20, 0x14191ac5, 0x1827b611, 0x00bc811d, 0x13582ff0, 0x117c2253, 0x03c1ea31, 0x3beaed}}, + {{0x0cc768d2, 0x13824c2f, 0x1fb105b3, 0x1bcef71b, 0x0e1b554c, 0x145f5f40, 0x0b37fbd2, 0x1eab5fef, 0xc3b0d7}}}, + /* 5*16^59*G: */ + {{{0x1a4edcc5, 0x1a7d0bed, 0x00c46dc8, 0x1c644284, 0x15997e74, 0x0fe01c93, 0x15861d4b, 0x14197b93, 0x6e73db}}, + {{0x159da0e4, 0x198fbe6e, 0x019e40de, 0x14efb4e0, 0x08693278, 0x0a844441, 0x1122fa91, 0x1f893dd9, 0xee0ac1}}}, + /* 7*16^59*G: */ + {{{0x0a80b979, 0x04e26212, 0x06aecc50, 0x01ebf465, 0x1c310049, 0x0cbf5523, 0x1649d89f, 0x1126fcb6, 0x7706dd}}, + {{0x0126cfde, 0x067a4082, 0x1fbf8c85, 0x141469fa, 0x09c7117f, 0x0ebcc8f5, 0x1c51dde3, 0x104fab76, 0x8a02a9}}}, + /* 9*16^59*G: */ + {{{0x126fe285, 0x06dce25b, 0x0fbc49f7, 0x17585282, 0x1e06aa45, 0x1e3d20fc, 0x03e034bc, 0x18b25378, 0x16d422}}, + {{0x0155b441, 0x1f07ff36, 0x0d93508c, 0x1e18226e, 0x131b1e93, 0x1f34d31a, 0x1906a2ad, 0x1f4a3c44, 0xdf888}}}, + /* 11*16^59*G: */ + {{{0x1acfa513, 0x11885e55, 0x1838ebab, 0x080f3f34, 0x16a9c4e2, 0x1a23a87a, 0x158ea968, 0x08fdd8ed, 0x1fcc0e}}, + {{0x107afc9c, 0x083add20, 0x060e461d, 0x1bdba2c9, 0x1f9b44be, 0x1c3aa19c, 0x11e2d238, 0x14083c6a, 0x165dc1}}}, + /* 13*16^59*G: */ + {{{0x1edc69b2, 0x0d1383e7, 0x1addc5c8, 0x14c11364, 0x0a386a50, 0x01821ae5, 0x0285cc19, 0x0e75ad97, 0xc12b90}}, + {{0x00dd41dd, 0x19574d81, 0x09eca800, 0x1c3b7c7a, 0x14976b8e, 0x16e44fc4, 0x17c765dc, 0x07fca699, 0x3173c4}}}, + /* 15*16^59*G: */ + {{{0x1961fe4d, 0x1b7ac2ef, 0x041c65ea, 0x0910df16, 0x0a73e8a1, 0x14989896, 0x0a3e8fcf, 0x10bb864f, 0xd059bf}}, + {{0x0ae823c2, 0x0c9ad833, 0x16ad932e, 0x111743e9, 0x155b4fd3, 0x1b2ee424, 0x0978ff81, 0x0c18116a, 0x45107a}}} + }, + { + /* 1*16^60*G: */ + {{{0x0caf666b, 0x06b181fb, 0x0c738c2f, 0x19fda789, 0x1f4637ff, 0x0bcd740b, 0x0aa98ada, 0x0af4f020, 0x13464a}}, + {{0x1f6ecc27, 0x1a4ad483, 0x0250b84f, 0x0601503a, 0x0b0ca48f, 0x019a29e6, 0x1603bdf9, 0x12008c28, 0x69be15}}}, + /* 3*16^60*G: */ + {{{0x0eca5f51, 0x10b5904c, 0x1f26bafc, 0x142e3729, 0x1b5cfdde, 0x0b595f82, 0x1a58b1bb, 0x029bb3dc, 0xdde9d5}}, + {{0x10c638f7, 0x16b4d39e, 0x0255c7e6, 0x1dd7d1bd, 0x18f0950f, 0x19a5853f, 0x04476247, 0x02679c50, 0xb84e69}}}, + /* 5*16^60*G: */ + {{{0x199c88e4, 0x1c83582c, 0x0b51bb0b, 0x1aa27c41, 0x04b179ae, 0x00375890, 0x0dcdba7d, 0x02046d32, 0xfd1a62}}, + {{0x195bc8df, 0x0e4648b2, 0x13003ca6, 0x16e3a92b, 0x17782dc6, 0x0034aa4b, 0x082fec4f, 0x0a973918, 0x1ac97b}}}, + /* 7*16^60*G: */ + {{{0x1f8018ce, 0x0a8adada, 0x024b5a2f, 0x1b4ae71b, 0x06dc7cf2, 0x1e727964, 0x1ae7c4ff, 0x063b1852, 0x4ee485}}, + {{0x1e48381f, 0x01ad30d8, 0x1a01804f, 0x0e92e369, 0x1c5e6710, 0x02046863, 0x02d7f1ed, 0x1a90217f, 0xb68f9e}}}, + /* 9*16^60*G: */ + {{{0x11473678, 0x1429748f, 0x10e4bdc0, 0x00af2a12, 0x0c070cba, 0x18a62adc, 0x036ffd78, 0x13869880, 0xfd76cc}}, + {{0x0d144f4f, 0x10b27754, 0x007210df, 0x051ddc28, 0x12cd6606, 0x10539e81, 0x0f6b83fb, 0x086f0e28, 0xf20465}}}, + /* 11*16^60*G: */ + {{{0x0d7a2193, 0x1805b8a4, 0x05d51bb7, 0x123c89e3, 0x0ea212c6, 0x07413a5a, 0x1008679b, 0x14662476, 0x85a2ab}}, + {{0x10cdcf3a, 0x18641ea5, 0x0ec4909f, 0x0db5bf38, 0x0029fe1c, 0x104168e6, 0x145b60b1, 0x0afd6560, 0x9c1298}}}, + /* 13*16^60*G: */ + {{{0x177568b0, 0x0d8182d9, 0x180ec14d, 0x1d1ba033, 0x1650f35a, 0x16b62bc1, 0x19d1102d, 0x1f8e79ff, 0xd25ddb}}, + {{0x1f39929c, 0x0509c936, 0x0f0fc018, 0x04e7103c, 0x1d92b832, 0x17ba66f3, 0x024e2fab, 0x0eb27f09, 0x7a3aff}}}, + /* 15*16^60*G: */ + {{{0x071d7c13, 0x0ff288c5, 0x03fe8e15, 0x156beff4, 0x0c805641, 0x1f4d4bd5, 0x09c957c1, 0x06287d29, 0x458135}}, + {{0x1aff63cf, 0x11c5e2a9, 0x0f65ae65, 0x000caa85, 0x169c9702, 0x0878bbee, 0x0b62d5fd, 0x1d8292f3, 0x9f5858}}} + }, + { + /* 1*16^61*G: */ + {{{0x0d83f366, 0x16d1d069, 0x1ca16232, 0x1399dbc5, 0x1c97a0cd, 0x0185e60e, 0x18ba6bbd, 0x1eb6e27f, 0xbc4a9d}}, + {{0x181f33c1, 0x1ac6b332, 0x151ec5b5, 0x1153f7f4, 0x198caa6e, 0x1bd6fa5b, 0x1018e0e4, 0x194dcf0b, 0xd3a81}}}, + /* 3*16^61*G: */ + {{{0x1712be3c, 0x03517197, 0x051a99ac, 0x0be31db4, 0x01534729, 0x12edd580, 0x0de34f1c, 0x13b26636, 0x39d734}}, + {{0x1c6ff65c, 0x0180cfa0, 0x09059133, 0x1def4bd9, 0x012e8ef5, 0x1aaa6334, 0x0fdfec49, 0x09eadde7, 0x8f929b}}}, + /* 5*16^61*G: */ + {{{0x1f77f22b, 0x15727de6, 0x1e0b80d6, 0x12e47329, 0x1af26c69, 0x06b614ca, 0x17427947, 0x02fefb83, 0xf0cba6}}, + {{0x1909a03c, 0x1e47163a, 0x08255987, 0x0318fd21, 0x0d04004f, 0x1361b28b, 0x1e627bcc, 0x08627f3b, 0x1a25ab}}}, + /* 7*16^61*G: */ + {{{0x06509c12, 0x0566e6a6, 0x147d1d96, 0x17fc46b7, 0x068ed8d6, 0x18746c39, 0x134c8745, 0x173b642a, 0x381d7a}}, + {{0x0eb46102, 0x03215471, 0x19babdd5, 0x1050b0d9, 0x181e7205, 0x122b9d32, 0x16a7ad74, 0x0b6ffb47, 0xa47aab}}}, + /* 9*16^61*G: */ + {{{0x184fe955, 0x0d9da6b1, 0x18ef3923, 0x12ad4b40, 0x08a53f69, 0x1b9f34a6, 0x1f991e4e, 0x0a8cf570, 0xa703f0}}, + {{0x161344bd, 0x135977de, 0x05c9dfe8, 0x1c2c538b, 0x1199b539, 0x1c96b58c, 0x1eb703a9, 0x06b45608, 0xd500f9}}}, + /* 11*16^61*G: */ + {{{0x06eace58, 0x04cb2b60, 0x1cc8474d, 0x1c8ac745, 0x1a03f1b7, 0x1686b829, 0x035d1b1a, 0x18b55aaa, 0x73c6b3}}, + {{0x0af8654e, 0x0b8548b9, 0x0e34a45c, 0x150f1b77, 0x191c6aa6, 0x04c89b36, 0x1dd06ea4, 0x148e6749, 0x3a2fb4}}}, + /* 13*16^61*G: */ + {{{0x00181d5e, 0x059c45f8, 0x16abc815, 0x03675372, 0x0ddb8de7, 0x069d0e07, 0x1ff68740, 0x1cea0da8, 0xc627f3}}, + {{0x169f886d, 0x13c80531, 0x12f8b0e4, 0x0d600a93, 0x1f7d68ef, 0x0b009c50, 0x098ecb5a, 0x1ae3c885, 0xd78f9d}}}, + /* 15*16^61*G: */ + {{{0x17828b16, 0x07146cfd, 0x09211fcd, 0x0f2b1e51, 0x0de53a04, 0x1a053783, 0x08cfe897, 0x17c1dbfa, 0xbb88fa}}, + {{0x0aea5df7, 0x08a39d10, 0x087a5a71, 0x1502e9c7, 0x19163ec4, 0x02cb008a, 0x0374d177, 0x16609ebd, 0xb73676}}} + }, + { + /* 1*16^62*G: */ + {{{0x05324caa, 0x0a55987f, 0x051ca8e5, 0x16cbc615, 0x0a32e694, 0x063a4a29, 0x0f0348f6, 0x0f7f0531, 0x8c28a9}}, + {{0x0bef9482, 0x138ee39e, 0x072e5167, 0x0f09e08a, 0x0c0eb7ae, 0x16f98fbe, 0x064cde3f, 0x0c74660a, 0x40a304}}}, + /* 3*16^62*G: */ + {{{0x0754dd40, 0x11f438aa, 0x0d19b3e1, 0x044c63f8, 0x0f6e9a24, 0x020fe6b9, 0x1f3d16d2, 0x0e06581b, 0x972924}}, + {{0x0aa36143, 0x025a4979, 0x0b2bd24e, 0x15d0a4ab, 0x0df3690d, 0x03aee5ea, 0x08773457, 0x0884cbfd, 0x91d1a2}}}, + /* 5*16^62*G: */ + {{{0x0c2ca7ff, 0x016c175c, 0x17c0868f, 0x06c8bb2b, 0x127af180, 0x08d6ad17, 0x05b8141e, 0x12eb014f, 0x89637f}}, + {{0x10493e68, 0x16a0af0b, 0x10baadef, 0x178d471c, 0x17489f87, 0x0e78aa1a, 0x109355ee, 0x04919110, 0x2d1fe1}}}, + /* 7*16^62*G: */ + {{{0x0ca8dd7f, 0x0c36b1d0, 0x084e0698, 0x0e5006ad, 0x157421bc, 0x0ed01ea9, 0x1824bf72, 0x1ce37c4b, 0x308138}}, + {{0x0a92c7f2, 0x00af923c, 0x12b64579, 0x0cac8c86, 0x08e18c81, 0x1622e8a0, 0x124978e7, 0x1a51051f, 0x28d1e2}}}, + /* 9*16^62*G: */ + {{{0x066a3fb1, 0x06e62b44, 0x04b881b0, 0x00125033, 0x0862f6ec, 0x1a8642db, 0x0d974795, 0x1d054dbd, 0x575fc4}}, + {{0x102655ad, 0x0dc74854, 0x08ebcbc2, 0x076ae78d, 0x087daed3, 0x0de14bc7, 0x128b59c7, 0x120854df, 0x6f6edb}}}, + /* 11*16^62*G: */ + {{{0x190117df, 0x0db54523, 0x08040a48, 0x0a77779c, 0x02a8fda2, 0x137c0f75, 0x0de889fc, 0x06d6c9d5, 0xa5ec90}}, + {{0x186462fe, 0x0094099f, 0x0528d8f6, 0x08c3e0ac, 0x1a0f71c8, 0x1cc1d68f, 0x01003165, 0x0c4bd828, 0xb79dc6}}}, + /* 13*16^62*G: */ + {{{0x172ad712, 0x187cbae0, 0x0411ca42, 0x131961bc, 0x149b95a3, 0x1cbb0a31, 0x0c252779, 0x1d226621, 0xa153df}}, + {{0x0d48fdd2, 0x052fb29c, 0x1c2cca72, 0x0a7e50b5, 0x1b89abd0, 0x0c6af8f8, 0x0cbf120c, 0x0827f60b, 0xfd94d8}}}, + /* 15*16^62*G: */ + {{{0x11cf5b3a, 0x1861b808, 0x0d69e040, 0x0675077b, 0x1c824c44, 0x1a684476, 0x18564d70, 0x18d5ef28, 0x9a541a}}, + {{0x16a44ae4, 0x1faabaf9, 0x07a94b58, 0x11fdc4a4, 0x1475f554, 0x0d79b447, 0x0adf2bf8, 0x1839620d, 0xb66148}}} + }, + { + /* 1*16^63*G: */ + {{{0x1faccae0, 0x0625d088, 0x12eccdd2, 0x166a18b4, 0x11fd23c8, 0x0a672783, 0x1ea30776, 0x0cc272a4, 0x8ea96}}, + {{0x0e62b945, 0x0d79a518, 0x1c3e3a55, 0x0f077d39, 0x1c5d735b, 0x1e067dca, 0x1e0b8939, 0x17791dc4, 0x620efa}}}, + /* 3*16^63*G: */ + {{{0x06a06f5e, 0x0d205acb, 0x0820dc08, 0x0324a2dd, 0x1b716a34, 0x06a10931, 0x14eb0dec, 0x1f7d4284, 0x383b24}}, + {{0x13c6e772, 0x04fa3c36, 0x030ac102, 0x0d5ce977, 0x05a19e8f, 0x0b36aa75, 0x0881133d, 0x0d589db7, 0x54cf70}}}, + /* 5*16^63*G: */ + {{{0x0638a136, 0x1cbae0ea, 0x00e06571, 0x1a39c66d, 0x1790c2b0, 0x0ce35b06, 0x15b5e279, 0x1a07c05d, 0xe68432}}, + {{0x0c6c2584, 0x17e8c084, 0x0d5ccdaa, 0x13c7d7b6, 0x1e6472e0, 0x13981d00, 0x0998934a, 0x02731c6b, 0xca5be4}}}, + /* 7*16^63*G: */ + {{{0x16e8c10c, 0x0743e220, 0x06f5a01f, 0x0530be72, 0x06e7fb47, 0x1ef67398, 0x10a83bbe, 0x0b3c5fcb, 0x395dd5}}, + {{0x05fe638e, 0x01eb6c98, 0x19a48b2f, 0x013809b8, 0x04e274c9, 0x1f43d7fd, 0x0b174104, 0x1a968b25, 0xfd62dc}}}, + /* 9*16^63*G: */ + {{{0x0d6c14ef, 0x0b326d90, 0x1e4f23d4, 0x11f8ea0d, 0x06480085, 0x16adf771, 0x172e7dbb, 0x1b86aa4b, 0x7a514a}}, + {{0x0b3fbd13, 0x169f0c38, 0x09b893de, 0x1d5dee55, 0x15c3729b, 0x185ca647, 0x1363a25f, 0x1fda2a5c, 0x56edd1}}}, + /* 11*16^63*G: */ + {{{0x0f6d65eb, 0x14a31e82, 0x10085492, 0x1220eea8, 0x08f235a9, 0x179dfa48, 0x04363aa3, 0x0b0864bb, 0x1ee1fd}}, + {{0x1d22941c, 0x101b5c92, 0x0d60ac47, 0x05e9d30c, 0x0fcfaca3, 0x1cfe27a1, 0x1cf073ea, 0x1237bad8, 0xbb6928}}}, + /* 13*16^63*G: */ + {{{0x0e36cb44, 0x18ca8778, 0x12880647, 0x1d16d91b, 0x1357d617, 0x07e86c41, 0x0aa2f016, 0x069a71f5, 0x155156}}, + {{0x1f495a68, 0x14d7a328, 0x0830794c, 0x06e2ebe0, 0x1205da8c, 0x11f85a31, 0x08578dc3, 0x18eaaaea, 0xab4fff}}}, + /* 15*16^63*G: */ + {{{0x1427bacc, 0x0fca3083, 0x0b58b854, 0x0662c9ba, 0x1c4aa9e7, 0x07584ac6, 0x0804d8d6, 0x0c88d7ea, 0x3bc6bc}}, + {{0x0ad6fda6, 0x0619feaf, 0x02fad1c5, 0x16eb4a45, 0x0c02bd71, 0x1771136b, 0x0c1736d8, 0x180e2ed8, 0x8e305c}}} + }, diff --git a/deps/crypto/trezor-crypto/segwit_addr.c b/deps/crypto/trezor-crypto/segwit_addr.c new file mode 100644 index 000000000..446c0d6e6 --- /dev/null +++ b/deps/crypto/trezor-crypto/segwit_addr.c @@ -0,0 +1,209 @@ +/* Copyright (c) 2017, 2021 Pieter Wuille + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include + +#include "segwit_addr.h" + +static uint32_t bech32_polymod_step(uint32_t pre) { + uint8_t b = pre >> 25; + return ((pre & 0x1FFFFFF) << 5) ^ + (-((b >> 0) & 1) & 0x3b6a57b2UL) ^ + (-((b >> 1) & 1) & 0x26508e6dUL) ^ + (-((b >> 2) & 1) & 0x1ea119faUL) ^ + (-((b >> 3) & 1) & 0x3d4233ddUL) ^ + (-((b >> 4) & 1) & 0x2a1462b3UL); +} + +static uint32_t bech32_final_constant(bech32_encoding enc) { + if (enc == BECH32_ENCODING_BECH32) return 1; + if (enc == BECH32_ENCODING_BECH32M) return 0x2bc830a3; + return 0; +} + +static const char* charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; + +static const int8_t charset_rev[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1, + -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, + 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1, + -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, + 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1 +}; + +int bech32_encode(char *output, const char *hrp, const uint8_t *data, size_t data_len, bech32_encoding enc) { + uint32_t chk = 1; + size_t i = 0; + while (hrp[i] != 0) { + int ch = hrp[i]; + if (ch < 33 || ch > 126) { + return 0; + } + + if (ch >= 'A' && ch <= 'Z') return 0; + chk = bech32_polymod_step(chk) ^ (ch >> 5); + ++i; + } + if (i + 7 + data_len > 90) return 0; + chk = bech32_polymod_step(chk); + while (*hrp != 0) { + chk = bech32_polymod_step(chk) ^ (*hrp & 0x1f); + *(output++) = *(hrp++); + } + *(output++) = '1'; + for (i = 0; i < data_len; ++i) { + if (*data >> 5) return 0; + chk = bech32_polymod_step(chk) ^ (*data); + *(output++) = charset[*(data++)]; + } + for (i = 0; i < 6; ++i) { + chk = bech32_polymod_step(chk); + } + chk ^= bech32_final_constant(enc); + for (i = 0; i < 6; ++i) { + *(output++) = charset[(chk >> ((5 - i) * 5)) & 0x1f]; + } + *output = 0; + return 1; +} + +bech32_encoding bech32_decode(char* hrp, uint8_t *data, size_t *data_len, const char *input) { + uint32_t chk = 1; + size_t i = 0; + size_t input_len = strlen(input); + size_t hrp_len = 0; + int have_lower = 0, have_upper = 0; + if (input_len < 8) { + return BECH32_ENCODING_NONE; + } + *data_len = 0; + while (*data_len < input_len && input[(input_len - 1) - *data_len] != '1') { + ++(*data_len); + } + hrp_len = input_len - (1 + *data_len); + if (1 + *data_len >= input_len || *data_len < 6 || hrp_len > BECH32_MAX_HRP_LEN) { + return BECH32_ENCODING_NONE; + } + *(data_len) -= 6; + for (i = 0; i < hrp_len; ++i) { + int ch = input[i]; + if (ch < 33 || ch > 126) { + return BECH32_ENCODING_NONE; + } + if (ch >= 'a' && ch <= 'z') { + have_lower = 1; + } else if (ch >= 'A' && ch <= 'Z') { + have_upper = 1; + ch = (ch - 'A') + 'a'; + } + hrp[i] = ch; + chk = bech32_polymod_step(chk) ^ (ch >> 5); + } + hrp[i] = 0; + chk = bech32_polymod_step(chk); + for (i = 0; i < hrp_len; ++i) { + chk = bech32_polymod_step(chk) ^ (input[i] & 0x1f); + } + ++i; + while (i < input_len) { + int v = (input[i] & 0x80) ? -1 : charset_rev[(int)input[i]]; + if (input[i] >= 'a' && input[i] <= 'z') have_lower = 1; + if (input[i] >= 'A' && input[i] <= 'Z') have_upper = 1; + if (v == -1) { + return BECH32_ENCODING_NONE; + } + chk = bech32_polymod_step(chk) ^ v; + if (i + 6 < input_len) { + data[i - (1 + hrp_len)] = v; + } + ++i; + } + if (have_lower && have_upper) { + return BECH32_ENCODING_NONE; + } + if (chk == bech32_final_constant(BECH32_ENCODING_BECH32)) { + return BECH32_ENCODING_BECH32; + } else if (chk == bech32_final_constant(BECH32_ENCODING_BECH32M)) { + return BECH32_ENCODING_BECH32M; + } else { + return BECH32_ENCODING_NONE; + } +} + +static int convert_bits(uint8_t* out, size_t* outlen, int outbits, const uint8_t* in, size_t inlen, int inbits, int pad) { + uint32_t val = 0; + int bits = 0; + uint32_t maxv = (((uint32_t)1) << outbits) - 1; + while (inlen--) { + val = (val << inbits) | *(in++); + bits += inbits; + while (bits >= outbits) { + bits -= outbits; + out[(*outlen)++] = (val >> bits) & maxv; + } + } + if (pad) { + if (bits) { + out[(*outlen)++] = (val << (outbits - bits)) & maxv; + } + } else if (((val << (outbits - bits)) & maxv) || bits >= inbits) { + return 0; + } + return 1; +} + +int segwit_addr_encode(char *output, const char *hrp, int witver, const uint8_t *witprog, size_t witprog_len) { + uint8_t data[65] = {0}; + size_t datalen = 0; + bech32_encoding enc = BECH32_ENCODING_BECH32; + if (witver > 16) return 0; + if (witver == 0 && witprog_len != 20 && witprog_len != 32) return 0; + if (witprog_len < 2 || witprog_len > 40) return 0; + if (witver > 0) enc = BECH32_ENCODING_BECH32M; + data[0] = witver; + convert_bits(data + 1, &datalen, 5, witprog, witprog_len, 8, 1); + ++datalen; + return bech32_encode(output, hrp, data, datalen, enc); +} + +int segwit_addr_decode(int* witver, uint8_t* witdata, size_t* witdata_len, const char* hrp, const char* addr) { + uint8_t data[84] = {0}; + char hrp_actual[84] = {0}; + size_t data_len = 0; + if (strlen(addr) > 90) return 0; + bech32_encoding enc = bech32_decode(hrp_actual, data, &data_len, addr); + if (enc == BECH32_ENCODING_NONE) return 0; + if (data_len == 0 || data_len > 65) return 0; + if (strncmp(hrp, hrp_actual, 84) != 0) return 0; + if (data[0] > 16) return 0; + if (data[0] == 0 && enc != BECH32_ENCODING_BECH32) return 0; + if (data[0] > 0 && enc != BECH32_ENCODING_BECH32M) return 0; + *witdata_len = 0; + if (!convert_bits(witdata, witdata_len, 8, data + 1, data_len - 1, 5, 0)) return 0; + if (*witdata_len < 2 || *witdata_len > 40) return 0; + if (data[0] == 0 && *witdata_len != 20 && *witdata_len != 32) return 0; + *witver = data[0]; + return 1; +} diff --git a/deps/crypto/trezor-crypto/segwit_addr.h b/deps/crypto/trezor-crypto/segwit_addr.h new file mode 100644 index 000000000..844874ccf --- /dev/null +++ b/deps/crypto/trezor-crypto/segwit_addr.h @@ -0,0 +1,116 @@ +/* Copyright (c) 2017, 2021 Pieter Wuille + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef _SEGWIT_ADDR_H_ +#define _SEGWIT_ADDR_H_ 1 + +#include + +// The maximum length of the Bech32 human-readable part according to BIP-173. +#define BECH32_MAX_HRP_LEN 83 + + +/** Encode a SegWit address + * + * Out: output: Pointer to a buffer of size 73 + strlen(hrp) that will be + * updated to contain the null-terminated address. + * In: hrp: Pointer to the null-terminated human readable part to use + * (chain/network specific). + * ver: Version of the witness program (between 0 and 16 inclusive). + * prog: Data bytes for the witness program (between 2 and 40 bytes). + * prog_len: Number of data bytes in prog. + * Returns 1 if successful. + */ +int segwit_addr_encode( + char *output, + const char *hrp, + int ver, + const uint8_t *prog, + size_t prog_len +); + +/** Decode a SegWit address + * + * Out: ver: Pointer to an int that will be updated to contain the witness + * program version (between 0 and 16 inclusive). + * prog: Pointer to a buffer of size 40 that will be updated to + * contain the witness program bytes. + * prog_len: Pointer to a size_t that will be updated to contain the length + * of bytes in prog. + * hrp: Pointer to the null-terminated human readable part that is + * expected (chain/network specific). + * addr: Pointer to the null-terminated address. + * Returns 1 if successful. + */ +int segwit_addr_decode( + int* ver, + uint8_t* prog, + size_t* prog_len, + const char* hrp, + const char* addr +); + +/** Supported encodings. */ +typedef enum { + BECH32_ENCODING_NONE, + BECH32_ENCODING_BECH32, + BECH32_ENCODING_BECH32M +} bech32_encoding; + +/** Encode a Bech32 or Bech32m string + * + * Out: output: Pointer to a buffer of size strlen(hrp) + data_len + 8 that + * will be updated to contain the null-terminated Bech32 string. + * In: hrp : Pointer to the null-terminated human readable part. + * data : Pointer to an array of 5-bit values. + * data_len: Length of the data array. + * enc: Which encoding to use (BECH32_ENCODING_BECH32{,M}). + * Returns 1 if successful. + */ +int bech32_encode( + char *output, + const char *hrp, + const uint8_t *data, + size_t data_len, + bech32_encoding enc +); + +/** Decode a Bech32 or Bech32m string + * + * Out: hrp: Pointer to a buffer of size BECH32_MAX_HRP_LEN + 1. Will be + * updated to contain the null-terminated human readable part. + * data: Pointer to a buffer of size strlen(input) - 8 that will + * hold the encoded 5-bit data values. + * data_len: Pointer to a size_t that will be updated to be the number + * of entries in data. + * In: input: Pointer to a null-terminated Bech32 string. + * Returns BECH32_ENCODING_BECH32{,M} to indicate decoding was successful + * with the specified encoding standard. BECH32_ENCODING_NONE is returned if + * decoding failed. + */ +bech32_encoding bech32_decode( + char *hrp, + uint8_t *data, + size_t *data_len, + const char *input +); + +#endif diff --git a/deps/crypto/trezor-crypto/setup.py b/deps/crypto/trezor-crypto/setup.py new file mode 100755 index 000000000..aee3dd4a9 --- /dev/null +++ b/deps/crypto/trezor-crypto/setup.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python +from distutils.core import setup +from distutils.extension import Extension + +from Cython.Build import cythonize +from Cython.Distutils import build_ext + +srcs = [ + "nist256p1", + "base58", + "bignum", + "bip32", + "ecdsa", + "curve25519", + "hmac", + "rand", + "ripemd160", + "secp256k1", + "sha2", +] + +extensions = [ + Extension( + "TrezorCrypto", + sources=["TrezorCrypto.pyx", "c.pxd"] + [x + ".c" for x in srcs], + extra_compile_args=[], + ) +] + +setup( + name="TrezorCrypto", + version="0.0.0", + description="Cython wrapper around trezor-crypto library", + author="Pavol Rusnak", + author_email="stick@satoshilabs.com", + url="https://github.com/trezor/trezor-crypto", + cmdclass={"build_ext": build_ext}, + ext_modules=cythonize(extensions), +) diff --git a/deps/crypto/trezor-crypto/sha2.c b/deps/crypto/trezor-crypto/sha2.c new file mode 100644 index 000000000..5aa0ea38c --- /dev/null +++ b/deps/crypto/trezor-crypto/sha2.c @@ -0,0 +1,1283 @@ +/** + * Copyright (c) 2000-2001 Aaron D. Gifford + * Copyright (c) 2013-2014 Pavol Rusnak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include "sha2.h" +#include "memzero.h" + +/* + * ASSERT NOTE: + * Some sanity checking code is included using assert(). On my FreeBSD + * system, this additional code can be removed by compiling with NDEBUG + * defined. Check your own systems manpage on assert() to see how to + * compile WITHOUT the sanity checking code on your system. + * + * UNROLLED TRANSFORM LOOP NOTE: + * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform + * loop version for the hash transform rounds (defined using macros + * later in this file). Either define on the command line, for example: + * + * cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c + * + * or define below: + * + * #define SHA2_UNROLL_TRANSFORM + * + */ + + +/*** SHA-256/384/512 Machine Architecture Definitions *****************/ +/* + * BYTE_ORDER NOTE: + * + * Please make sure that your system defines BYTE_ORDER. If your + * architecture is little-endian, make sure it also defines + * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are + * equivilent. + * + * If your system does not define the above, then you can do so by + * hand like this: + * + * #define LITTLE_ENDIAN 1234 + * #define BIG_ENDIAN 4321 + * + * And for little-endian machines, add: + * + * #define BYTE_ORDER LITTLE_ENDIAN + * + * Or for big-endian machines: + * + * #define BYTE_ORDER BIG_ENDIAN + * + * The FreeBSD machine this was written on defines BYTE_ORDER + * appropriately by including (which in turn includes + * where the appropriate definitions are actually + * made). + */ + +#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN) +#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN +#endif + +typedef uint8_t sha2_byte; /* Exactly 1 byte */ +typedef uint32_t sha2_word32; /* Exactly 4 bytes */ +typedef uint64_t sha2_word64; /* Exactly 8 bytes */ + +/*** SHA-256/384/512 Various Length Definitions ***********************/ +/* NOTE: Most of these are in sha2.h */ +#define SHA1_SHORT_BLOCK_LENGTH (SHA1_BLOCK_LENGTH - 8) +#define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8) +#define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16) + +/* + * Macro for incrementally adding the unsigned 64-bit integer n to the + * unsigned 128-bit integer (represented using a two-element array of + * 64-bit words): + */ +#define ADDINC128(w,n) { \ + (w)[0] += (sha2_word64)(n); \ + if ((w)[0] < (n)) { \ + (w)[1]++; \ + } \ +} + +#define MEMCPY_BCOPY(d,s,l) memcpy((d), (s), (l)) + +/*** THE SIX LOGICAL FUNCTIONS ****************************************/ +/* + * Bit shifting and rotation (used by the six SHA-XYZ logical functions: + * + * NOTE: In the original SHA-256/384/512 document, the shift-right + * function was named R and the rotate-right function was called S. + * (See: http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf on the + * web.) + * + * The newer NIST FIPS 180-2 document uses a much clearer naming + * scheme, SHR for shift-right, ROTR for rotate-right, and ROTL for + * rotate-left. (See: + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf + * on the web.) + * + * WARNING: These macros must be used cautiously, since they reference + * supplied parameters sometimes more than once, and thus could have + * unexpected side-effects if used without taking this into account. + */ + +/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */ +#define SHR(b,x) ((x) >> (b)) +/* 32-bit Rotate-right (used in SHA-256): */ +#define ROTR32(b,x) (((x) >> (b)) | ((x) << (32 - (b)))) +/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */ +#define ROTR64(b,x) (((x) >> (b)) | ((x) << (64 - (b)))) +/* 32-bit Rotate-left (used in SHA-1): */ +#define ROTL32(b,x) (((x) << (b)) | ((x) >> (32 - (b)))) + +/* Two of six logical functions used in SHA-1, SHA-256, SHA-384, and SHA-512: */ +#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) +#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + +/* Function used in SHA-1: */ +#define Parity(x,y,z) ((x) ^ (y) ^ (z)) + +/* Four of six logical functions used in SHA-256: */ +#define Sigma0_256(x) (ROTR32(2, (x)) ^ ROTR32(13, (x)) ^ ROTR32(22, (x))) +#define Sigma1_256(x) (ROTR32(6, (x)) ^ ROTR32(11, (x)) ^ ROTR32(25, (x))) +#define sigma0_256(x) (ROTR32(7, (x)) ^ ROTR32(18, (x)) ^ SHR(3 , (x))) +#define sigma1_256(x) (ROTR32(17, (x)) ^ ROTR32(19, (x)) ^ SHR(10, (x))) + +/* Four of six logical functions used in SHA-384 and SHA-512: */ +#define Sigma0_512(x) (ROTR64(28, (x)) ^ ROTR64(34, (x)) ^ ROTR64(39, (x))) +#define Sigma1_512(x) (ROTR64(14, (x)) ^ ROTR64(18, (x)) ^ ROTR64(41, (x))) +#define sigma0_512(x) (ROTR64( 1, (x)) ^ ROTR64( 8, (x)) ^ SHR( 7, (x))) +#define sigma1_512(x) (ROTR64(19, (x)) ^ ROTR64(61, (x)) ^ SHR( 6, (x))) + +/*** INTERNAL FUNCTION PROTOTYPES *************************************/ +/* NOTE: These should not be accessed directly from outside this + * library -- they are intended for private internal visibility/use + * only. + */ +static void sha512_Last(SHA512_CTX*); + + +/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ + +/* Hash constant words K for SHA-1: */ +#define K1_0_TO_19 0x5a827999UL +#define K1_20_TO_39 0x6ed9eba1UL +#define K1_40_TO_59 0x8f1bbcdcUL +#define K1_60_TO_79 0xca62c1d6UL + +/* Initial hash value H for SHA-1: */ +const sha2_word32 sha1_initial_hash_value[SHA1_DIGEST_LENGTH / sizeof(sha2_word32)] = { + 0x67452301UL, + 0xefcdab89UL, + 0x98badcfeUL, + 0x10325476UL, + 0xc3d2e1f0UL +}; + +/* Hash constant words K for SHA-256: */ +static const sha2_word32 K256[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, + 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, + 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, + 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, + 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, + 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, + 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, + 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, + 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, + 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, + 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL +}; + +/* Initial hash value H for SHA-256: */ +const sha2_word32 sha256_initial_hash_value[8] = { + 0x6a09e667UL, + 0xbb67ae85UL, + 0x3c6ef372UL, + 0xa54ff53aUL, + 0x510e527fUL, + 0x9b05688cUL, + 0x1f83d9abUL, + 0x5be0cd19UL +}; + +/* Hash constant words K for SHA-384 and SHA-512: */ +static const sha2_word64 K512[80] = { + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, + 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, + 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, + 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, + 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, + 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, + 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, + 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, + 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, + 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, + 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, + 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, + 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, + 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, + 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, + 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, + 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, + 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, + 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, + 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, + 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, + 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, + 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, + 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, + 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, + 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, + 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, + 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, + 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, + 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, + 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, + 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, + 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL +}; + +/* Initial hash value H for SHA-512 */ +const sha2_word64 sha512_initial_hash_value[8] = { + 0x6a09e667f3bcc908ULL, + 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, + 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, + 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, + 0x5be0cd19137e2179ULL +}; + +/* + * Constant used by SHA256/384/512_End() functions for converting the + * digest to a readable hexadecimal character string: + */ +static const char *sha2_hex_digits = "0123456789abcdef"; + + +/*** SHA-1: ***********************************************************/ +void sha1_Init(SHA1_CTX* context) { + MEMCPY_BCOPY(context->state, sha1_initial_hash_value, SHA1_DIGEST_LENGTH); + memzero(context->buffer, SHA1_BLOCK_LENGTH); + context->bitcount = 0; +} + +#ifdef SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-1 round macros: */ + +#define ROUND1_0_TO_15(a,b,c,d,e) \ + (e) = ROTL32(5, (a)) + Ch((b), (c), (d)) + (e) + \ + K1_0_TO_19 + ( W1[j] = *data++ ); \ + (b) = ROTL32(30, (b)); \ + j++; + +#define ROUND1_16_TO_19(a,b,c,d,e) \ + T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; \ + (e) = ROTL32(5, a) + Ch(b,c,d) + e + K1_0_TO_19 + ( W1[j&0x0f] = ROTL32(1, T1) ); \ + (b) = ROTL32(30, b); \ + j++; + +#define ROUND1_20_TO_39(a,b,c,d,e) \ + T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; \ + (e) = ROTL32(5, a) + Parity(b,c,d) + e + K1_20_TO_39 + ( W1[j&0x0f] = ROTL32(1, T1) ); \ + (b) = ROTL32(30, b); \ + j++; + +#define ROUND1_40_TO_59(a,b,c,d,e) \ + T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; \ + (e) = ROTL32(5, a) + Maj(b,c,d) + e + K1_40_TO_59 + ( W1[j&0x0f] = ROTL32(1, T1) ); \ + (b) = ROTL32(30, b); \ + j++; + +#define ROUND1_60_TO_79(a,b,c,d,e) \ + T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; \ + (e) = ROTL32(5, a) + Parity(b,c,d) + e + K1_60_TO_79 + ( W1[j&0x0f] = ROTL32(1, T1) ); \ + (b) = ROTL32(30, b); \ + j++; + +void sha1_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2_word32* state_out) { + sha2_word32 a = 0, b = 0, c = 0, d = 0, e = 0; + sha2_word32 T1 = 0; + sha2_word32 W1[16] = {0}; + int j = 0; + + /* Initialize registers with the prev. intermediate value */ + a = state_in[0]; + b = state_in[1]; + c = state_in[2]; + d = state_in[3]; + e = state_in[4]; + + j = 0; + + /* Rounds 0 to 15 unrolled: */ + ROUND1_0_TO_15(a,b,c,d,e); + ROUND1_0_TO_15(e,a,b,c,d); + ROUND1_0_TO_15(d,e,a,b,c); + ROUND1_0_TO_15(c,d,e,a,b); + ROUND1_0_TO_15(b,c,d,e,a); + ROUND1_0_TO_15(a,b,c,d,e); + ROUND1_0_TO_15(e,a,b,c,d); + ROUND1_0_TO_15(d,e,a,b,c); + ROUND1_0_TO_15(c,d,e,a,b); + ROUND1_0_TO_15(b,c,d,e,a); + ROUND1_0_TO_15(a,b,c,d,e); + ROUND1_0_TO_15(e,a,b,c,d); + ROUND1_0_TO_15(d,e,a,b,c); + ROUND1_0_TO_15(c,d,e,a,b); + ROUND1_0_TO_15(b,c,d,e,a); + ROUND1_0_TO_15(a,b,c,d,e); + + /* Rounds 16 to 19 unrolled: */ + ROUND1_16_TO_19(e,a,b,c,d); + ROUND1_16_TO_19(d,e,a,b,c); + ROUND1_16_TO_19(c,d,e,a,b); + ROUND1_16_TO_19(b,c,d,e,a); + + /* Rounds 20 to 39 unrolled: */ + ROUND1_20_TO_39(a,b,c,d,e); + ROUND1_20_TO_39(e,a,b,c,d); + ROUND1_20_TO_39(d,e,a,b,c); + ROUND1_20_TO_39(c,d,e,a,b); + ROUND1_20_TO_39(b,c,d,e,a); + ROUND1_20_TO_39(a,b,c,d,e); + ROUND1_20_TO_39(e,a,b,c,d); + ROUND1_20_TO_39(d,e,a,b,c); + ROUND1_20_TO_39(c,d,e,a,b); + ROUND1_20_TO_39(b,c,d,e,a); + ROUND1_20_TO_39(a,b,c,d,e); + ROUND1_20_TO_39(e,a,b,c,d); + ROUND1_20_TO_39(d,e,a,b,c); + ROUND1_20_TO_39(c,d,e,a,b); + ROUND1_20_TO_39(b,c,d,e,a); + ROUND1_20_TO_39(a,b,c,d,e); + ROUND1_20_TO_39(e,a,b,c,d); + ROUND1_20_TO_39(d,e,a,b,c); + ROUND1_20_TO_39(c,d,e,a,b); + ROUND1_20_TO_39(b,c,d,e,a); + + /* Rounds 40 to 59 unrolled: */ + ROUND1_40_TO_59(a,b,c,d,e); + ROUND1_40_TO_59(e,a,b,c,d); + ROUND1_40_TO_59(d,e,a,b,c); + ROUND1_40_TO_59(c,d,e,a,b); + ROUND1_40_TO_59(b,c,d,e,a); + ROUND1_40_TO_59(a,b,c,d,e); + ROUND1_40_TO_59(e,a,b,c,d); + ROUND1_40_TO_59(d,e,a,b,c); + ROUND1_40_TO_59(c,d,e,a,b); + ROUND1_40_TO_59(b,c,d,e,a); + ROUND1_40_TO_59(a,b,c,d,e); + ROUND1_40_TO_59(e,a,b,c,d); + ROUND1_40_TO_59(d,e,a,b,c); + ROUND1_40_TO_59(c,d,e,a,b); + ROUND1_40_TO_59(b,c,d,e,a); + ROUND1_40_TO_59(a,b,c,d,e); + ROUND1_40_TO_59(e,a,b,c,d); + ROUND1_40_TO_59(d,e,a,b,c); + ROUND1_40_TO_59(c,d,e,a,b); + ROUND1_40_TO_59(b,c,d,e,a); + + /* Rounds 60 to 79 unrolled: */ + ROUND1_60_TO_79(a,b,c,d,e); + ROUND1_60_TO_79(e,a,b,c,d); + ROUND1_60_TO_79(d,e,a,b,c); + ROUND1_60_TO_79(c,d,e,a,b); + ROUND1_60_TO_79(b,c,d,e,a); + ROUND1_60_TO_79(a,b,c,d,e); + ROUND1_60_TO_79(e,a,b,c,d); + ROUND1_60_TO_79(d,e,a,b,c); + ROUND1_60_TO_79(c,d,e,a,b); + ROUND1_60_TO_79(b,c,d,e,a); + ROUND1_60_TO_79(a,b,c,d,e); + ROUND1_60_TO_79(e,a,b,c,d); + ROUND1_60_TO_79(d,e,a,b,c); + ROUND1_60_TO_79(c,d,e,a,b); + ROUND1_60_TO_79(b,c,d,e,a); + ROUND1_60_TO_79(a,b,c,d,e); + ROUND1_60_TO_79(e,a,b,c,d); + ROUND1_60_TO_79(d,e,a,b,c); + ROUND1_60_TO_79(c,d,e,a,b); + ROUND1_60_TO_79(b,c,d,e,a); + + /* Compute the current intermediate hash value */ + state_out[0] = state_in[0] + a; + state_out[1] = state_in[1] + b; + state_out[2] = state_in[2] + c; + state_out[3] = state_in[3] + d; + state_out[4] = state_in[4] + e; + + /* Clean up */ + a = b = c = d = e = T1 = 0; +} + +#else /* SHA2_UNROLL_TRANSFORM */ + +void sha1_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2_word32* state_out) { + sha2_word32 a = 0, b = 0, c = 0, d = 0, e = 0; + sha2_word32 T1 = 0; + sha2_word32 W1[16] = {0}; + int j = 0; + + /* Initialize registers with the prev. intermediate value */ + a = state_in[0]; + b = state_in[1]; + c = state_in[2]; + d = state_in[3]; + e = state_in[4]; + j = 0; + do { + T1 = ROTL32(5, a) + Ch(b, c, d) + e + K1_0_TO_19 + (W1[j] = *data++); + e = d; + d = c; + c = ROTL32(30, b); + b = a; + a = T1; + j++; + } while (j < 16); + + do { + T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; + T1 = ROTL32(5, a) + Ch(b,c,d) + e + K1_0_TO_19 + (W1[j&0x0f] = ROTL32(1, T1)); + e = d; + d = c; + c = ROTL32(30, b); + b = a; + a = T1; + j++; + } while (j < 20); + + do { + T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; + T1 = ROTL32(5, a) + Parity(b,c,d) + e + K1_20_TO_39 + (W1[j&0x0f] = ROTL32(1, T1)); + e = d; + d = c; + c = ROTL32(30, b); + b = a; + a = T1; + j++; + } while (j < 40); + + do { + T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; + T1 = ROTL32(5, a) + Maj(b,c,d) + e + K1_40_TO_59 + (W1[j&0x0f] = ROTL32(1, T1)); + e = d; + d = c; + c = ROTL32(30, b); + b = a; + a = T1; + j++; + } while (j < 60); + + do { + T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; + T1 = ROTL32(5, a) + Parity(b,c,d) + e + K1_60_TO_79 + (W1[j&0x0f] = ROTL32(1, T1)); + e = d; + d = c; + c = ROTL32(30, b); + b = a; + a = T1; + j++; + } while (j < 80); + + + /* Compute the current intermediate hash value */ + state_out[0] = state_in[0] + a; + state_out[1] = state_in[1] + b; + state_out[2] = state_in[2] + c; + state_out[3] = state_in[3] + d; + state_out[4] = state_in[4] + e; + + /* Clean up */ + a = b = c = d = e = T1 = 0; +} + +#endif /* SHA2_UNROLL_TRANSFORM */ + +void sha1_Update(SHA1_CTX* context, const sha2_byte *data, size_t len) { + unsigned int freespace = 0, usedspace = 0; + + if (len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + usedspace = (context->bitcount >> 3) % SHA1_BLOCK_LENGTH; + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA1_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + MEMCPY_BCOPY(((uint8_t*)context->buffer) + usedspace, data, freespace); + context->bitcount += freespace << 3; + len -= freespace; + data += freespace; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 16; j++) { + REVERSE32(context->buffer[j],context->buffer[j]); + } +#endif + sha1_Transform(context->state, context->buffer, context->state); + } else { + /* The buffer is not yet full */ + MEMCPY_BCOPY(((uint8_t*)context->buffer) + usedspace, data, len); + context->bitcount += len << 3; + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= SHA1_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + MEMCPY_BCOPY(context->buffer, data, SHA1_BLOCK_LENGTH); +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 16; j++) { + REVERSE32(context->buffer[j],context->buffer[j]); + } +#endif + sha1_Transform(context->state, context->buffer, context->state); + context->bitcount += SHA1_BLOCK_LENGTH << 3; + len -= SHA1_BLOCK_LENGTH; + data += SHA1_BLOCK_LENGTH; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + MEMCPY_BCOPY(context->buffer, data, len); + context->bitcount += len << 3; + } + /* Clean up: */ + usedspace = freespace = 0; +} + +void sha1_Final(SHA1_CTX* context, sha2_byte digest[SHA1_DIGEST_LENGTH]) { + unsigned int usedspace = 0; + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + usedspace = (context->bitcount >> 3) % SHA1_BLOCK_LENGTH; + /* Begin padding with a 1 bit: */ + ((uint8_t*)context->buffer)[usedspace++] = 0x80; + + if (usedspace > SHA1_SHORT_BLOCK_LENGTH) { + memzero(((uint8_t*)context->buffer) + usedspace, SHA1_BLOCK_LENGTH - usedspace); + +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 16; j++) { + REVERSE32(context->buffer[j],context->buffer[j]); + } +#endif + /* Do second-to-last transform: */ + sha1_Transform(context->state, context->buffer, context->state); + + /* And prepare the last transform: */ + usedspace = 0; + } + /* Set-up for the last transform: */ + memzero(((uint8_t*)context->buffer) + usedspace, SHA1_SHORT_BLOCK_LENGTH - usedspace); + +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 14; j++) { + REVERSE32(context->buffer[j],context->buffer[j]); + } +#endif + /* Set the bit count: */ + context->buffer[14] = context->bitcount >> 32; + context->buffer[15] = context->bitcount & 0xffffffff; + + /* Final transform: */ + sha1_Transform(context->state, context->buffer, context->state); + +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + for (int j = 0; j < 5; j++) { + REVERSE32(context->state[j],context->state[j]); + } +#endif + MEMCPY_BCOPY(digest, context->state, SHA1_DIGEST_LENGTH); + } + + /* Clean up state data: */ + memzero(context, sizeof(SHA1_CTX)); + usedspace = 0; +} + +char *sha1_End(SHA1_CTX* context, char buffer[SHA1_DIGEST_STRING_LENGTH]) { + sha2_byte digest[SHA1_DIGEST_LENGTH] = {0}, *d = digest; + int i = 0; + + if (buffer != (char*)0) { + sha1_Final(context, digest); + + for (i = 0; i < SHA1_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + memzero(context, sizeof(SHA1_CTX)); + } + memzero(digest, SHA1_DIGEST_LENGTH); + return buffer; +} + +void sha1_Raw(const sha2_byte* data, size_t len, uint8_t digest[SHA1_DIGEST_LENGTH]) { + SHA1_CTX context = {0}; + sha1_Init(&context); + sha1_Update(&context, data, len); + sha1_Final(&context, digest); +} + +char* sha1_Data(const sha2_byte* data, size_t len, char digest[SHA1_DIGEST_STRING_LENGTH]) { + SHA1_CTX context = {0}; + + sha1_Init(&context); + sha1_Update(&context, data, len); + return sha1_End(&context, digest); +} + +/*** SHA-256: *********************************************************/ +void sha256_Init(SHA256_CTX* context) { + if (context == (SHA256_CTX*)0) { + return; + } + MEMCPY_BCOPY(context->state, sha256_initial_hash_value, SHA256_DIGEST_LENGTH); + memzero(context->buffer, SHA256_BLOCK_LENGTH); + context->bitcount = 0; +} + +#ifdef SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-256 round macros: */ + +#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ + K256[j] + (W256[j] = *data++); \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + +#define ROUND256(a,b,c,d,e,f,g,h) \ + s0 = W256[(j+1)&0x0f]; \ + s0 = sigma0_256(s0); \ + s1 = W256[(j+14)&0x0f]; \ + s1 = sigma1_256(s1); \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \ + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + +void sha256_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2_word32* state_out) { + sha2_word32 a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0, s0 = 0, s1 = 0; + sha2_word32 T1 = 0; + sha2_word32 W256[16] = {0}; + int j = 0; + + /* Initialize registers with the prev. intermediate value */ + a = state_in[0]; + b = state_in[1]; + c = state_in[2]; + d = state_in[3]; + e = state_in[4]; + f = state_in[5]; + g = state_in[6]; + h = state_in[7]; + + j = 0; + do { + /* Rounds 0 to 15 (unrolled): */ + ROUND256_0_TO_15(a,b,c,d,e,f,g,h); + ROUND256_0_TO_15(h,a,b,c,d,e,f,g); + ROUND256_0_TO_15(g,h,a,b,c,d,e,f); + ROUND256_0_TO_15(f,g,h,a,b,c,d,e); + ROUND256_0_TO_15(e,f,g,h,a,b,c,d); + ROUND256_0_TO_15(d,e,f,g,h,a,b,c); + ROUND256_0_TO_15(c,d,e,f,g,h,a,b); + ROUND256_0_TO_15(b,c,d,e,f,g,h,a); + } while (j < 16); + + /* Now for the remaining rounds to 64: */ + do { + ROUND256(a,b,c,d,e,f,g,h); + ROUND256(h,a,b,c,d,e,f,g); + ROUND256(g,h,a,b,c,d,e,f); + ROUND256(f,g,h,a,b,c,d,e); + ROUND256(e,f,g,h,a,b,c,d); + ROUND256(d,e,f,g,h,a,b,c); + ROUND256(c,d,e,f,g,h,a,b); + ROUND256(b,c,d,e,f,g,h,a); + } while (j < 64); + + /* Compute the current intermediate hash value */ + state_out[0] = state_in[0] + a; + state_out[1] = state_in[1] + b; + state_out[2] = state_in[2] + c; + state_out[3] = state_in[3] + d; + state_out[4] = state_in[4] + e; + state_out[5] = state_in[5] + f; + state_out[6] = state_in[6] + g; + state_out[7] = state_in[7] + h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; +} + +#else /* SHA2_UNROLL_TRANSFORM */ + +void sha256_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2_word32* state_out) { + sha2_word32 a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0, s0 = 0, s1 = 0; + sha2_word32 T1 = 0, T2 = 0 , W256[16] = {0}; + int j = 0; + + /* Initialize registers with the prev. intermediate value */ + a = state_in[0]; + b = state_in[1]; + c = state_in[2]; + d = state_in[3]; + e = state_in[4]; + f = state_in[5]; + g = state_in[6]; + h = state_in[7]; + + j = 0; + do { + /* Apply the SHA-256 compression function to update a..h with copy */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++); + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W256[(j+1)&0x0f]; + s0 = sigma0_256(s0); + s1 = W256[(j+14)&0x0f]; + s1 = sigma1_256(s1); + + /* Apply the SHA-256 compression function to update a..h */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 64); + + /* Compute the current intermediate hash value */ + state_out[0] = state_in[0] + a; + state_out[1] = state_in[1] + b; + state_out[2] = state_in[2] + c; + state_out[3] = state_in[3] + d; + state_out[4] = state_in[4] + e; + state_out[5] = state_in[5] + f; + state_out[6] = state_in[6] + g; + state_out[7] = state_in[7] + h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; +} + +#endif /* SHA2_UNROLL_TRANSFORM */ + +void sha256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { + unsigned int freespace = 0, usedspace = 0; + + if (len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA256_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + MEMCPY_BCOPY(((uint8_t*)context->buffer) + usedspace, data, freespace); + context->bitcount += freespace << 3; + len -= freespace; + data += freespace; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 16; j++) { + REVERSE32(context->buffer[j],context->buffer[j]); + } +#endif + sha256_Transform(context->state, context->buffer, context->state); + } else { + /* The buffer is not yet full */ + MEMCPY_BCOPY(((uint8_t*)context->buffer) + usedspace, data, len); + context->bitcount += len << 3; + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= SHA256_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + MEMCPY_BCOPY(context->buffer, data, SHA256_BLOCK_LENGTH); +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 16; j++) { + REVERSE32(context->buffer[j],context->buffer[j]); + } +#endif + sha256_Transform(context->state, context->buffer, context->state); + context->bitcount += SHA256_BLOCK_LENGTH << 3; + len -= SHA256_BLOCK_LENGTH; + data += SHA256_BLOCK_LENGTH; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + MEMCPY_BCOPY(context->buffer, data, len); + context->bitcount += len << 3; + } + /* Clean up: */ + usedspace = freespace = 0; +} + +void sha256_Final(SHA256_CTX* context, sha2_byte digest[SHA256_DIGEST_LENGTH]) { + unsigned int usedspace = 0; + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; + /* Begin padding with a 1 bit: */ + ((uint8_t*)context->buffer)[usedspace++] = 0x80; + + if (usedspace > SHA256_SHORT_BLOCK_LENGTH) { + memzero(((uint8_t*)context->buffer) + usedspace, SHA256_BLOCK_LENGTH - usedspace); + +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 16; j++) { + REVERSE32(context->buffer[j],context->buffer[j]); + } +#endif + /* Do second-to-last transform: */ + sha256_Transform(context->state, context->buffer, context->state); + + /* And prepare the last transform: */ + usedspace = 0; + } + /* Set-up for the last transform: */ + memzero(((uint8_t*)context->buffer) + usedspace, SHA256_SHORT_BLOCK_LENGTH - usedspace); + +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 14; j++) { + REVERSE32(context->buffer[j],context->buffer[j]); + } +#endif + /* Set the bit count: */ + context->buffer[14] = context->bitcount >> 32; + context->buffer[15] = context->bitcount & 0xffffffff; + + /* Final transform: */ + sha256_Transform(context->state, context->buffer, context->state); + +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + for (int j = 0; j < 8; j++) { + REVERSE32(context->state[j],context->state[j]); + } +#endif + MEMCPY_BCOPY(digest, context->state, SHA256_DIGEST_LENGTH); + } + + /* Clean up state data: */ + memzero(context, sizeof(SHA256_CTX)); + usedspace = 0; +} + +char *sha256_End(SHA256_CTX* context, char buffer[SHA256_DIGEST_STRING_LENGTH]) { + sha2_byte digest[SHA256_DIGEST_LENGTH] = {0}, *d = digest; + int i = 0; + + if (buffer != (char*)0) { + sha256_Final(context, digest); + + for (i = 0; i < SHA256_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + memzero(context, sizeof(SHA256_CTX)); + } + memzero(digest, SHA256_DIGEST_LENGTH); + return buffer; +} + +void sha256_Raw(const sha2_byte* data, size_t len, uint8_t digest[SHA256_DIGEST_LENGTH]) { + SHA256_CTX context = {0}; + sha256_Init(&context); + sha256_Update(&context, data, len); + sha256_Final(&context, digest); +} + +char* sha256_Data(const sha2_byte* data, size_t len, char digest[SHA256_DIGEST_STRING_LENGTH]) { + SHA256_CTX context = {0}; + + sha256_Init(&context); + sha256_Update(&context, data, len); + return sha256_End(&context, digest); +} + + +/*** SHA-512: *********************************************************/ +void sha512_Init(SHA512_CTX* context) { + if (context == (SHA512_CTX*)0) { + return; + } + MEMCPY_BCOPY(context->state, sha512_initial_hash_value, SHA512_DIGEST_LENGTH); + memzero(context->buffer, SHA512_BLOCK_LENGTH); + context->bitcount[0] = context->bitcount[1] = 0; +} + +#ifdef SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-512 round macros: */ +#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ + K512[j] + (W512[j] = *data++); \ + (d) += T1; \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ + j++ + +#define ROUND512(a,b,c,d,e,f,g,h) \ + s0 = W512[(j+1)&0x0f]; \ + s0 = sigma0_512(s0); \ + s1 = W512[(j+14)&0x0f]; \ + s1 = sigma1_512(s1); \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \ + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \ + (d) += T1; \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ + j++ + +void sha512_Transform(const sha2_word64* state_in, const sha2_word64* data, sha2_word64* state_out) { + sha2_word64 a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0, s0 = 0, s1 = 0; + sha2_word64 T1 = 0, W512[16] = {0}; + int j = 0; + + /* Initialize registers with the prev. intermediate value */ + a = state_in[0]; + b = state_in[1]; + c = state_in[2]; + d = state_in[3]; + e = state_in[4]; + f = state_in[5]; + g = state_in[6]; + h = state_in[7]; + + j = 0; + do { + ROUND512_0_TO_15(a,b,c,d,e,f,g,h); + ROUND512_0_TO_15(h,a,b,c,d,e,f,g); + ROUND512_0_TO_15(g,h,a,b,c,d,e,f); + ROUND512_0_TO_15(f,g,h,a,b,c,d,e); + ROUND512_0_TO_15(e,f,g,h,a,b,c,d); + ROUND512_0_TO_15(d,e,f,g,h,a,b,c); + ROUND512_0_TO_15(c,d,e,f,g,h,a,b); + ROUND512_0_TO_15(b,c,d,e,f,g,h,a); + } while (j < 16); + + /* Now for the remaining rounds up to 79: */ + do { + ROUND512(a,b,c,d,e,f,g,h); + ROUND512(h,a,b,c,d,e,f,g); + ROUND512(g,h,a,b,c,d,e,f); + ROUND512(f,g,h,a,b,c,d,e); + ROUND512(e,f,g,h,a,b,c,d); + ROUND512(d,e,f,g,h,a,b,c); + ROUND512(c,d,e,f,g,h,a,b); + ROUND512(b,c,d,e,f,g,h,a); + } while (j < 80); + + /* Compute the current intermediate hash value */ + state_out[0] = state_in[0] + a; + state_out[1] = state_in[1] + b; + state_out[2] = state_in[2] + c; + state_out[3] = state_in[3] + d; + state_out[4] = state_in[4] + e; + state_out[5] = state_in[5] + f; + state_out[6] = state_in[6] + g; + state_out[7] = state_in[7] + h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; +} + +#else /* SHA2_UNROLL_TRANSFORM */ + +void sha512_Transform(const sha2_word64* state_in, const sha2_word64* data, sha2_word64* state_out) { + sha2_word64 a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0, s0 = 0, s1 = 0; + sha2_word64 T1 = 0, T2 = 0, W512[16] = {0}; + int j = 0; + + /* Initialize registers with the prev. intermediate value */ + a = state_in[0]; + b = state_in[1]; + c = state_in[2]; + d = state_in[3]; + e = state_in[4]; + f = state_in[5]; + g = state_in[6]; + h = state_in[7]; + + j = 0; + do { + /* Apply the SHA-512 compression function to update a..h with copy */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++); + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W512[(j+1)&0x0f]; + s0 = sigma0_512(s0); + s1 = W512[(j+14)&0x0f]; + s1 = sigma1_512(s1); + + /* Apply the SHA-512 compression function to update a..h */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 80); + + /* Compute the current intermediate hash value */ + state_out[0] = state_in[0] + a; + state_out[1] = state_in[1] + b; + state_out[2] = state_in[2] + c; + state_out[3] = state_in[3] + d; + state_out[4] = state_in[4] + e; + state_out[5] = state_in[5] + f; + state_out[6] = state_in[6] + g; + state_out[7] = state_in[7] + h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; +} + +#endif /* SHA2_UNROLL_TRANSFORM */ + +void sha512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { + unsigned int freespace = 0, usedspace = 0; + + if (len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA512_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + MEMCPY_BCOPY(((uint8_t*)context->buffer) + usedspace, data, freespace); + ADDINC128(context->bitcount, freespace << 3); + len -= freespace; + data += freespace; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 16; j++) { + REVERSE64(context->buffer[j],context->buffer[j]); + } +#endif + sha512_Transform(context->state, context->buffer, context->state); + } else { + /* The buffer is not yet full */ + MEMCPY_BCOPY(((uint8_t*)context->buffer) + usedspace, data, len); + ADDINC128(context->bitcount, len << 3); + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= SHA512_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + MEMCPY_BCOPY(context->buffer, data, SHA512_BLOCK_LENGTH); +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 16; j++) { + REVERSE64(context->buffer[j],context->buffer[j]); + } +#endif + sha512_Transform(context->state, context->buffer, context->state); + ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3); + len -= SHA512_BLOCK_LENGTH; + data += SHA512_BLOCK_LENGTH; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + MEMCPY_BCOPY(context->buffer, data, len); + ADDINC128(context->bitcount, len << 3); + } + /* Clean up: */ + usedspace = freespace = 0; +} + +static void sha512_Last(SHA512_CTX* context) { + unsigned int usedspace = 0; + + usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; + /* Begin padding with a 1 bit: */ + ((uint8_t*)context->buffer)[usedspace++] = 0x80; + + if (usedspace > SHA512_SHORT_BLOCK_LENGTH) { + memzero(((uint8_t*)context->buffer) + usedspace, SHA512_BLOCK_LENGTH - usedspace); + +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 16; j++) { + REVERSE64(context->buffer[j],context->buffer[j]); + } +#endif + /* Do second-to-last transform: */ + sha512_Transform(context->state, context->buffer, context->state); + + /* And prepare the last transform: */ + usedspace = 0; + } + /* Set-up for the last transform: */ + memzero(((uint8_t*)context->buffer) + usedspace, SHA512_SHORT_BLOCK_LENGTH - usedspace); + +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 14; j++) { + REVERSE64(context->buffer[j],context->buffer[j]); + } +#endif + /* Store the length of input data (in bits): */ + context->buffer[14] = context->bitcount[1]; + context->buffer[15] = context->bitcount[0]; + + /* Final transform: */ + sha512_Transform(context->state, context->buffer, context->state); +} + +void sha512_Final(SHA512_CTX* context, sha2_byte digest[SHA512_DIGEST_LENGTH]) { + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + sha512_Last(context); + + /* Save the hash data for output: */ +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + for (int j = 0; j < 8; j++) { + REVERSE64(context->state[j],context->state[j]); + } +#endif + MEMCPY_BCOPY(digest, context->state, SHA512_DIGEST_LENGTH); + } + + /* Zero out state data */ + memzero(context, sizeof(SHA512_CTX)); +} + +char *sha512_End(SHA512_CTX* context, char buffer[SHA512_DIGEST_STRING_LENGTH]) { + sha2_byte digest[SHA512_DIGEST_LENGTH] = {0}, *d = digest; + int i = 0; + + if (buffer != (char*)0) { + sha512_Final(context, digest); + + for (i = 0; i < SHA512_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + memzero(context, sizeof(SHA512_CTX)); + } + memzero(digest, SHA512_DIGEST_LENGTH); + return buffer; +} + +void sha512_Raw(const sha2_byte* data, size_t len, uint8_t digest[SHA512_DIGEST_LENGTH]) { + SHA512_CTX context = {0}; + sha512_Init(&context); + sha512_Update(&context, data, len); + sha512_Final(&context, digest); +} + +char* sha512_Data(const sha2_byte* data, size_t len, char digest[SHA512_DIGEST_STRING_LENGTH]) { + SHA512_CTX context = {0}; + + sha512_Init(&context); + sha512_Update(&context, data, len); + return sha512_End(&context, digest); +} diff --git a/deps/crypto/trezor-crypto/sha2.h b/deps/crypto/trezor-crypto/sha2.h new file mode 100644 index 000000000..7f519c50b --- /dev/null +++ b/deps/crypto/trezor-crypto/sha2.h @@ -0,0 +1,116 @@ +/** + * Copyright (c) 2000-2001 Aaron D. Gifford + * Copyright (c) 2013-2014 Pavol Rusnak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __SHA2_H__ +#define __SHA2_H__ + +#include +#include + +#define SHA1_BLOCK_LENGTH 64 +#define SHA1_DIGEST_LENGTH 20 +#define SHA1_DIGEST_STRING_LENGTH (SHA1_DIGEST_LENGTH * 2 + 1) +#define SHA256_BLOCK_LENGTH 64 +#define SHA256_DIGEST_LENGTH 32 +#define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) +#define SHA512_BLOCK_LENGTH 128 +#define SHA512_DIGEST_LENGTH 64 +#define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) + +typedef struct _SHA1_CTX { + uint32_t state[5]; + uint64_t bitcount; + uint32_t buffer[SHA1_BLOCK_LENGTH/sizeof(uint32_t)]; +} SHA1_CTX; +typedef struct _SHA256_CTX { + uint32_t state[8]; + uint64_t bitcount; + uint32_t buffer[SHA256_BLOCK_LENGTH/sizeof(uint32_t)]; +} SHA256_CTX; +typedef struct _SHA512_CTX { + uint64_t state[8]; + uint64_t bitcount[2]; + uint64_t buffer[SHA512_BLOCK_LENGTH/sizeof(uint64_t)]; +} SHA512_CTX; + +/*** ENDIAN REVERSAL MACROS *******************************************/ +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN 1234 +#define BIG_ENDIAN 4321 +#endif + +#ifndef BYTE_ORDER +#define BYTE_ORDER LITTLE_ENDIAN +#endif + +#if BYTE_ORDER == LITTLE_ENDIAN +#define REVERSE32(w,x) { \ + uint32_t tmp = (w); \ + tmp = (tmp >> 16) | (tmp << 16); \ + (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \ +} +#define REVERSE64(w,x) { \ + uint64_t tmp = (w); \ + tmp = (tmp >> 32) | (tmp << 32); \ + tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \ + ((tmp & 0x00ff00ff00ff00ffULL) << 8); \ + (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \ + ((tmp & 0x0000ffff0000ffffULL) << 16); \ +} +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +extern const uint32_t sha256_initial_hash_value[8]; +extern const uint64_t sha512_initial_hash_value[8]; + +void sha1_Transform(const uint32_t* state_in, const uint32_t* data, uint32_t* state_out); +void sha1_Init(SHA1_CTX *); +void sha1_Update(SHA1_CTX*, const uint8_t*, size_t); +void sha1_Final(SHA1_CTX*, uint8_t[SHA1_DIGEST_LENGTH]); +char* sha1_End(SHA1_CTX*, char[SHA1_DIGEST_STRING_LENGTH]); +void sha1_Raw(const uint8_t*, size_t, uint8_t[SHA1_DIGEST_LENGTH]); +char* sha1_Data(const uint8_t*, size_t, char[SHA1_DIGEST_STRING_LENGTH]); + +void sha256_Transform(const uint32_t* state_in, const uint32_t* data, uint32_t* state_out); +void sha256_Init(SHA256_CTX *); +void sha256_Update(SHA256_CTX*, const uint8_t*, size_t); +void sha256_Final(SHA256_CTX*, uint8_t[SHA256_DIGEST_LENGTH]); +char* sha256_End(SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]); +void sha256_Raw(const uint8_t*, size_t, uint8_t[SHA256_DIGEST_LENGTH]); +char* sha256_Data(const uint8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]); + +void sha512_Transform(const uint64_t* state_in, const uint64_t* data, uint64_t* state_out); +void sha512_Init(SHA512_CTX*); +void sha512_Update(SHA512_CTX*, const uint8_t*, size_t); +void sha512_Final(SHA512_CTX*, uint8_t[SHA512_DIGEST_LENGTH]); +char* sha512_End(SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH]); +void sha512_Raw(const uint8_t*, size_t, uint8_t[SHA512_DIGEST_LENGTH]); +char* sha512_Data(const uint8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH]); + +#endif diff --git a/deps/crypto/trezor-crypto/sha3.c b/deps/crypto/trezor-crypto/sha3.c new file mode 100644 index 000000000..0a6eb4405 --- /dev/null +++ b/deps/crypto/trezor-crypto/sha3.c @@ -0,0 +1,399 @@ +/* sha3.c - an implementation of Secure Hash Algorithm 3 (Keccak). + * based on the + * The Keccak SHA-3 submission. Submission to NIST (Round 3), 2011 + * by Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche + * + * Copyright: 2013 Aleksey Kravchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk! + */ + +#include +#include + +#include "sha3.h" +#include "memzero.h" + +#define I64(x) x##LL +#define ROTL64(qword, n) ((qword) << (n) ^ ((qword) >> (64 - (n)))) +#define le2me_64(x) (x) +#define IS_ALIGNED_64(p) (0 == (((uintptr_t)(const void *)(p) & 0x7))) +# define me64_to_le_str(to, from, length) memcpy((to), (from), (length)) + +/* constants */ +#define NumberOfRounds 24 + +/* SHA3 (Keccak) constants for 24 rounds */ +static uint64_t keccak_round_constants[NumberOfRounds] = { + I64(0x0000000000000001), I64(0x0000000000008082), I64(0x800000000000808A), I64(0x8000000080008000), + I64(0x000000000000808B), I64(0x0000000080000001), I64(0x8000000080008081), I64(0x8000000000008009), + I64(0x000000000000008A), I64(0x0000000000000088), I64(0x0000000080008009), I64(0x000000008000000A), + I64(0x000000008000808B), I64(0x800000000000008B), I64(0x8000000000008089), I64(0x8000000000008003), + I64(0x8000000000008002), I64(0x8000000000000080), I64(0x000000000000800A), I64(0x800000008000000A), + I64(0x8000000080008081), I64(0x8000000000008080), I64(0x0000000080000001), I64(0x8000000080008008) +}; + +/* Initializing a sha3 context for given number of output bits */ +static void keccak_Init(SHA3_CTX *ctx, unsigned bits) +{ + /* NB: The Keccak capacity parameter = bits * 2 */ + unsigned rate = 1600 - bits * 2; + + memzero(ctx, sizeof(SHA3_CTX)); + ctx->block_size = rate / 8; + assert(rate <= 1600 && (rate % 64) == 0); +} + +/** + * Initialize context before calculating hash. + * + * @param ctx context to initialize + */ +void sha3_224_Init(SHA3_CTX *ctx) +{ + keccak_Init(ctx, 224); +} + +/** + * Initialize context before calculating hash. + * + * @param ctx context to initialize + */ +void sha3_256_Init(SHA3_CTX *ctx) +{ + keccak_Init(ctx, 256); +} + +/** + * Initialize context before calculating hash. + * + * @param ctx context to initialize + */ +void sha3_384_Init(SHA3_CTX *ctx) +{ + keccak_Init(ctx, 384); +} + +/** + * Initialize context before calculating hash. + * + * @param ctx context to initialize + */ +void sha3_512_Init(SHA3_CTX *ctx) +{ + keccak_Init(ctx, 512); +} + +/* Keccak theta() transformation */ +static void keccak_theta(uint64_t *A) +{ + unsigned int x = 0; + uint64_t C[5] = {0}, D[5] = {0}; + + for (x = 0; x < 5; x++) { + C[x] = A[x] ^ A[x + 5] ^ A[x + 10] ^ A[x + 15] ^ A[x + 20]; + } + D[0] = ROTL64(C[1], 1) ^ C[4]; + D[1] = ROTL64(C[2], 1) ^ C[0]; + D[2] = ROTL64(C[3], 1) ^ C[1]; + D[3] = ROTL64(C[4], 1) ^ C[2]; + D[4] = ROTL64(C[0], 1) ^ C[3]; + + for (x = 0; x < 5; x++) { + A[x] ^= D[x]; + A[x + 5] ^= D[x]; + A[x + 10] ^= D[x]; + A[x + 15] ^= D[x]; + A[x + 20] ^= D[x]; + } +} + +/* Keccak pi() transformation */ +static void keccak_pi(uint64_t *A) +{ + uint64_t A1 = 0; + A1 = A[1]; + A[ 1] = A[ 6]; + A[ 6] = A[ 9]; + A[ 9] = A[22]; + A[22] = A[14]; + A[14] = A[20]; + A[20] = A[ 2]; + A[ 2] = A[12]; + A[12] = A[13]; + A[13] = A[19]; + A[19] = A[23]; + A[23] = A[15]; + A[15] = A[ 4]; + A[ 4] = A[24]; + A[24] = A[21]; + A[21] = A[ 8]; + A[ 8] = A[16]; + A[16] = A[ 5]; + A[ 5] = A[ 3]; + A[ 3] = A[18]; + A[18] = A[17]; + A[17] = A[11]; + A[11] = A[ 7]; + A[ 7] = A[10]; + A[10] = A1; + /* note: A[ 0] is left as is */ +} + +/* Keccak chi() transformation */ +static void keccak_chi(uint64_t *A) +{ + int i = 0; + for (i = 0; i < 25; i += 5) { + uint64_t A0 = A[0 + i], A1 = A[1 + i]; + A[0 + i] ^= ~A1 & A[2 + i]; + A[1 + i] ^= ~A[2 + i] & A[3 + i]; + A[2 + i] ^= ~A[3 + i] & A[4 + i]; + A[3 + i] ^= ~A[4 + i] & A0; + A[4 + i] ^= ~A0 & A1; + } +} + +static void sha3_permutation(uint64_t *state) +{ + int round = 0; + for (round = 0; round < NumberOfRounds; round++) + { + keccak_theta(state); + + /* apply Keccak rho() transformation */ + state[ 1] = ROTL64(state[ 1], 1); + state[ 2] = ROTL64(state[ 2], 62); + state[ 3] = ROTL64(state[ 3], 28); + state[ 4] = ROTL64(state[ 4], 27); + state[ 5] = ROTL64(state[ 5], 36); + state[ 6] = ROTL64(state[ 6], 44); + state[ 7] = ROTL64(state[ 7], 6); + state[ 8] = ROTL64(state[ 8], 55); + state[ 9] = ROTL64(state[ 9], 20); + state[10] = ROTL64(state[10], 3); + state[11] = ROTL64(state[11], 10); + state[12] = ROTL64(state[12], 43); + state[13] = ROTL64(state[13], 25); + state[14] = ROTL64(state[14], 39); + state[15] = ROTL64(state[15], 41); + state[16] = ROTL64(state[16], 45); + state[17] = ROTL64(state[17], 15); + state[18] = ROTL64(state[18], 21); + state[19] = ROTL64(state[19], 8); + state[20] = ROTL64(state[20], 18); + state[21] = ROTL64(state[21], 2); + state[22] = ROTL64(state[22], 61); + state[23] = ROTL64(state[23], 56); + state[24] = ROTL64(state[24], 14); + + keccak_pi(state); + keccak_chi(state); + + /* apply iota(state, round) */ + *state ^= keccak_round_constants[round]; + } +} + +/** + * The core transformation. Process the specified block of data. + * + * @param hash the algorithm state + * @param block the message block to process + * @param block_size the size of the processed block in bytes + */ +static void sha3_process_block(uint64_t hash[25], const uint64_t *block, size_t block_size) +{ + /* expanded loop */ + hash[ 0] ^= le2me_64(block[ 0]); + hash[ 1] ^= le2me_64(block[ 1]); + hash[ 2] ^= le2me_64(block[ 2]); + hash[ 3] ^= le2me_64(block[ 3]); + hash[ 4] ^= le2me_64(block[ 4]); + hash[ 5] ^= le2me_64(block[ 5]); + hash[ 6] ^= le2me_64(block[ 6]); + hash[ 7] ^= le2me_64(block[ 7]); + hash[ 8] ^= le2me_64(block[ 8]); + /* if not sha3-512 */ + if (block_size > 72) { + hash[ 9] ^= le2me_64(block[ 9]); + hash[10] ^= le2me_64(block[10]); + hash[11] ^= le2me_64(block[11]); + hash[12] ^= le2me_64(block[12]); + /* if not sha3-384 */ + if (block_size > 104) { + hash[13] ^= le2me_64(block[13]); + hash[14] ^= le2me_64(block[14]); + hash[15] ^= le2me_64(block[15]); + hash[16] ^= le2me_64(block[16]); + /* if not sha3-256 */ + if (block_size > 136) { + hash[17] ^= le2me_64(block[17]); +#ifdef FULL_SHA3_FAMILY_SUPPORT + /* if not sha3-224 */ + if (block_size > 144) { + hash[18] ^= le2me_64(block[18]); + hash[19] ^= le2me_64(block[19]); + hash[20] ^= le2me_64(block[20]); + hash[21] ^= le2me_64(block[21]); + hash[22] ^= le2me_64(block[22]); + hash[23] ^= le2me_64(block[23]); + hash[24] ^= le2me_64(block[24]); + } +#endif + } + } + } + /* make a permutation of the hash */ + sha3_permutation(hash); +} + +#define SHA3_FINALIZED 0x80000000 + +/** + * Calculate message hash. + * Can be called repeatedly with chunks of the message to be hashed. + * + * @param ctx the algorithm context containing current hashing state + * @param msg message chunk + * @param size length of the message chunk + */ +void sha3_Update(SHA3_CTX *ctx, const unsigned char *msg, size_t size) +{ + if (size == 0) return; + + size_t idx = (size_t)ctx->rest; + size_t block_size = (size_t)ctx->block_size; + + if (ctx->rest & SHA3_FINALIZED) return; /* too late for additional input */ + ctx->rest = (unsigned)((ctx->rest + size) % block_size); + + /* fill partial block */ + if (idx) { + size_t left = block_size - idx; + memcpy((char*)ctx->message + idx, msg, (size < left ? size : left)); + if (size < left) return; + + /* process partial block */ + sha3_process_block(ctx->hash, ctx->message, block_size); + msg += left; + size -= left; + } + while (size >= block_size) { + uint64_t *aligned_message_block = NULL; + if (IS_ALIGNED_64(msg)) { + /* the most common case is processing of an already aligned message + without copying it */ + aligned_message_block = (uint64_t*)(void*)msg; + } else { + memcpy(ctx->message, msg, block_size); + aligned_message_block = ctx->message; + } + + sha3_process_block(ctx->hash, aligned_message_block, block_size); + msg += block_size; + size -= block_size; + } + if (size) { + memcpy(ctx->message, msg, size); /* save leftovers */ + } +} + +/** + * Store calculated hash into the given array. + * + * @param ctx the algorithm context containing current hashing state + * @param result calculated hash in binary form + */ +void sha3_Final(SHA3_CTX *ctx, unsigned char* result) +{ + size_t digest_length = 100 - ctx->block_size / 2; + const size_t block_size = ctx->block_size; + + if (!(ctx->rest & SHA3_FINALIZED)) + { + /* clear the rest of the data queue */ + memzero((char*)ctx->message + ctx->rest, block_size - ctx->rest); + ((char*)ctx->message)[ctx->rest] |= 0x06; + ((char*)ctx->message)[block_size - 1] |= 0x80; + + /* process final block */ + sha3_process_block(ctx->hash, ctx->message, block_size); + ctx->rest = SHA3_FINALIZED; /* mark context as finalized */ + } + + assert(block_size > digest_length); + if (result) me64_to_le_str(result, ctx->hash, digest_length); + memzero(ctx, sizeof(SHA3_CTX)); +} + +#if USE_KECCAK +/** +* Store calculated hash into the given array. +* +* @param ctx the algorithm context containing current hashing state +* @param result calculated hash in binary form +*/ +void keccak_Final(SHA3_CTX *ctx, unsigned char* result) +{ + size_t digest_length = 100 - ctx->block_size / 2; + const size_t block_size = ctx->block_size; + + if (!(ctx->rest & SHA3_FINALIZED)) + { + /* clear the rest of the data queue */ + memzero((char*)ctx->message + ctx->rest, block_size - ctx->rest); + ((char*)ctx->message)[ctx->rest] |= 0x01; + ((char*)ctx->message)[block_size - 1] |= 0x80; + + /* process final block */ + sha3_process_block(ctx->hash, ctx->message, block_size); + ctx->rest = SHA3_FINALIZED; /* mark context as finalized */ + } + + assert(block_size > digest_length); + if (result) me64_to_le_str(result, ctx->hash, digest_length); + memzero(ctx, sizeof(SHA3_CTX)); +} + +void keccak_256(const unsigned char* data, size_t len, unsigned char* digest) +{ + SHA3_CTX ctx = {0}; + keccak_256_Init(&ctx); + keccak_Update(&ctx, data, len); + keccak_Final(&ctx, digest); +} + +void keccak_512(const unsigned char* data, size_t len, unsigned char* digest) +{ + SHA3_CTX ctx = {0}; + keccak_512_Init(&ctx); + keccak_Update(&ctx, data, len); + keccak_Final(&ctx, digest); +} +#endif /* USE_KECCAK */ + +void sha3_256(const unsigned char* data, size_t len, unsigned char* digest) +{ + SHA3_CTX ctx = {0}; + sha3_256_Init(&ctx); + sha3_Update(&ctx, data, len); + sha3_Final(&ctx, digest); +} + +void sha3_512(const unsigned char* data, size_t len, unsigned char* digest) +{ + SHA3_CTX ctx = {0}; + sha3_512_Init(&ctx); + sha3_Update(&ctx, data, len); + sha3_Final(&ctx, digest); +} diff --git a/deps/crypto/trezor-crypto/sha3.h b/deps/crypto/trezor-crypto/sha3.h new file mode 100644 index 000000000..367369d4d --- /dev/null +++ b/deps/crypto/trezor-crypto/sha3.h @@ -0,0 +1,89 @@ +/* sha3.h - an implementation of Secure Hash Algorithm 3 (Keccak). + * based on the + * The Keccak SHA-3 submission. Submission to NIST (Round 3), 2011 + * by Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche + * + * Copyright: 2013 Aleksey Kravchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk! + */ + +#ifndef __SHA3_H__ +#define __SHA3_H__ + +#include +#include "options.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define sha3_224_hash_size 28 +#define sha3_256_hash_size 32 +#define sha3_384_hash_size 48 +#define sha3_512_hash_size 64 +#define sha3_max_permutation_size 25 +#define sha3_max_rate_in_qwords 24 + +#define SHA3_224_BLOCK_LENGTH 144 +#define SHA3_256_BLOCK_LENGTH 136 +#define SHA3_384_BLOCK_LENGTH 104 +#define SHA3_512_BLOCK_LENGTH 72 + +#define SHA3_224_DIGEST_LENGTH sha3_224_hash_size +#define SHA3_256_DIGEST_LENGTH sha3_256_hash_size +#define SHA3_384_DIGEST_LENGTH sha3_384_hash_size +#define SHA3_512_DIGEST_LENGTH sha3_512_hash_size + +/** + * SHA3 Algorithm context. + */ +typedef struct SHA3_CTX +{ + /* 1600 bits algorithm hashing state */ + uint64_t hash[sha3_max_permutation_size]; + /* 1536-bit buffer for leftovers */ + uint64_t message[sha3_max_rate_in_qwords]; + /* count of bytes in the message[] buffer */ + unsigned rest; + /* size of a message block processed at once */ + unsigned block_size; +} SHA3_CTX; + +/* methods for calculating the hash function */ + +void sha3_224_Init(SHA3_CTX *ctx); +void sha3_256_Init(SHA3_CTX *ctx); +void sha3_384_Init(SHA3_CTX *ctx); +void sha3_512_Init(SHA3_CTX *ctx); +void sha3_Update(SHA3_CTX *ctx, const unsigned char* msg, size_t size); +void sha3_Final(SHA3_CTX *ctx, unsigned char* result); + +#if USE_KECCAK +#define keccak_224_Init sha3_224_Init +#define keccak_256_Init sha3_256_Init +#define keccak_384_Init sha3_384_Init +#define keccak_512_Init sha3_512_Init +#define keccak_Update sha3_Update +void keccak_Final(SHA3_CTX *ctx, unsigned char* result); +void keccak_256(const unsigned char* data, size_t len, unsigned char* digest); +void keccak_512(const unsigned char* data, size_t len, unsigned char* digest); +#endif + +void sha3_256(const unsigned char* data, size_t len, unsigned char* digest); +void sha3_512(const unsigned char* data, size_t len, unsigned char* digest); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* __SHA3_H__ */ diff --git a/deps/crypto/trezor-crypto/shamir.c b/deps/crypto/trezor-crypto/shamir.c new file mode 100644 index 000000000..82b5e29a2 --- /dev/null +++ b/deps/crypto/trezor-crypto/shamir.c @@ -0,0 +1,335 @@ +/* + * Implementation of the hazardous parts of the SSS library + * + * Copyright (c) 2017 Daan Sprenkels + * Copyright (c) 2019 SatoshiLabs + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * This code contains the actual Shamir secret sharing functionality. The + * implementation of this code is based on the idea that the user likes to + * generate/combine 32 shares (in GF(2^8)) at the same time, because a 256 bit + * key will be exactly 32 bytes. Therefore we bitslice all the input and + * unbitslice the output right before returning. + * + * This bitslice approach optimizes natively on all architectures that are 32 + * bit or more. Care is taken to use not too many registers, to ensure that no + * values have to be leaked to the stack. + * + * All functions in this module are implemented constant time and constant + * lookup operations, as all proper crypto code must be. + */ + +#include "shamir.h" +#include +#include "memzero.h" + +static void bitslice(uint32_t r[8], const uint8_t *x, size_t len) { + size_t bit_idx = 0, arr_idx = 0; + uint32_t cur = 0; + + memset(r, 0, sizeof(uint32_t[8])); + for (arr_idx = 0; arr_idx < len; arr_idx++) { + cur = (uint32_t)x[arr_idx]; + for (bit_idx = 0; bit_idx < 8; bit_idx++) { + r[bit_idx] |= ((cur >> bit_idx) & 1) << arr_idx; + } + } +} + +static void unbitslice(uint8_t *r, const uint32_t x[8], size_t len) { + size_t bit_idx = 0, arr_idx = 0; + uint32_t cur = 0; + + memset(r, 0, sizeof(uint8_t) * len); + for (bit_idx = 0; bit_idx < 8; bit_idx++) { + cur = (uint32_t)x[bit_idx]; + for (arr_idx = 0; arr_idx < len; arr_idx++) { + r[arr_idx] |= ((cur >> arr_idx) & 1) << bit_idx; + } + } +} + +static void bitslice_setall(uint32_t r[8], const uint8_t x) { + size_t idx = 0; + for (idx = 0; idx < 8; idx++) { + r[idx] = -((x >> idx) & 1); + } +} + +/* + * Add (XOR) `r` with `x` and store the result in `r`. + */ +static void gf256_add(uint32_t r[8], const uint32_t x[8]) { + size_t idx = 0; + for (idx = 0; idx < 8; idx++) r[idx] ^= x[idx]; +} + +/* + * Safely multiply two bitsliced polynomials in GF(2^8) reduced by + * x^8 + x^4 + x^3 + x + 1. `r` and `a` may overlap, but overlapping of `r` + * and `b` will produce an incorrect result! If you need to square a polynomial + * use `gf256_square` instead. + */ +static void gf256_mul(uint32_t r[8], const uint32_t a[8], const uint32_t b[8]) { + /* This function implements Russian Peasant multiplication on two + * bitsliced polynomials. + * + * I personally think that these kinds of long lists of operations + * are often a bit ugly. A double for loop would be nicer and would + * take up a lot less lines of code. + * However, some compilers seem to fail in optimizing these kinds of + * loops. So we will just have to do this by hand. + */ + uint32_t a2[8] = {0}; + memcpy(a2, a, sizeof(uint32_t[8])); + + r[0] = a2[0] & b[0]; /* add (assignment, because r is 0) */ + r[1] = a2[1] & b[0]; + r[2] = a2[2] & b[0]; + r[3] = a2[3] & b[0]; + r[4] = a2[4] & b[0]; + r[5] = a2[5] & b[0]; + r[6] = a2[6] & b[0]; + r[7] = a2[7] & b[0]; + a2[0] ^= a2[7]; /* reduce */ + a2[2] ^= a2[7]; + a2[3] ^= a2[7]; + + r[0] ^= a2[7] & b[1]; /* add */ + r[1] ^= a2[0] & b[1]; + r[2] ^= a2[1] & b[1]; + r[3] ^= a2[2] & b[1]; + r[4] ^= a2[3] & b[1]; + r[5] ^= a2[4] & b[1]; + r[6] ^= a2[5] & b[1]; + r[7] ^= a2[6] & b[1]; + a2[7] ^= a2[6]; /* reduce */ + a2[1] ^= a2[6]; + a2[2] ^= a2[6]; + + r[0] ^= a2[6] & b[2]; /* add */ + r[1] ^= a2[7] & b[2]; + r[2] ^= a2[0] & b[2]; + r[3] ^= a2[1] & b[2]; + r[4] ^= a2[2] & b[2]; + r[5] ^= a2[3] & b[2]; + r[6] ^= a2[4] & b[2]; + r[7] ^= a2[5] & b[2]; + a2[6] ^= a2[5]; /* reduce */ + a2[0] ^= a2[5]; + a2[1] ^= a2[5]; + + r[0] ^= a2[5] & b[3]; /* add */ + r[1] ^= a2[6] & b[3]; + r[2] ^= a2[7] & b[3]; + r[3] ^= a2[0] & b[3]; + r[4] ^= a2[1] & b[3]; + r[5] ^= a2[2] & b[3]; + r[6] ^= a2[3] & b[3]; + r[7] ^= a2[4] & b[3]; + a2[5] ^= a2[4]; /* reduce */ + a2[7] ^= a2[4]; + a2[0] ^= a2[4]; + + r[0] ^= a2[4] & b[4]; /* add */ + r[1] ^= a2[5] & b[4]; + r[2] ^= a2[6] & b[4]; + r[3] ^= a2[7] & b[4]; + r[4] ^= a2[0] & b[4]; + r[5] ^= a2[1] & b[4]; + r[6] ^= a2[2] & b[4]; + r[7] ^= a2[3] & b[4]; + a2[4] ^= a2[3]; /* reduce */ + a2[6] ^= a2[3]; + a2[7] ^= a2[3]; + + r[0] ^= a2[3] & b[5]; /* add */ + r[1] ^= a2[4] & b[5]; + r[2] ^= a2[5] & b[5]; + r[3] ^= a2[6] & b[5]; + r[4] ^= a2[7] & b[5]; + r[5] ^= a2[0] & b[5]; + r[6] ^= a2[1] & b[5]; + r[7] ^= a2[2] & b[5]; + a2[3] ^= a2[2]; /* reduce */ + a2[5] ^= a2[2]; + a2[6] ^= a2[2]; + + r[0] ^= a2[2] & b[6]; /* add */ + r[1] ^= a2[3] & b[6]; + r[2] ^= a2[4] & b[6]; + r[3] ^= a2[5] & b[6]; + r[4] ^= a2[6] & b[6]; + r[5] ^= a2[7] & b[6]; + r[6] ^= a2[0] & b[6]; + r[7] ^= a2[1] & b[6]; + a2[2] ^= a2[1]; /* reduce */ + a2[4] ^= a2[1]; + a2[5] ^= a2[1]; + + r[0] ^= a2[1] & b[7]; /* add */ + r[1] ^= a2[2] & b[7]; + r[2] ^= a2[3] & b[7]; + r[3] ^= a2[4] & b[7]; + r[4] ^= a2[5] & b[7]; + r[5] ^= a2[6] & b[7]; + r[6] ^= a2[7] & b[7]; + r[7] ^= a2[0] & b[7]; + + memzero(a2, sizeof(a2)); +} + +/* + * Square `x` in GF(2^8) and write the result to `r`. `r` and `x` may overlap. + */ +static void gf256_square(uint32_t r[8], const uint32_t x[8]) { + uint32_t r8 = 0, r10 = 0, r12 = 0, r14 = 0; + /* Use the Freshman's Dream rule to square the polynomial + * Assignments are done from 7 downto 0, because this allows the user + * to execute this function in-place (e.g. `gf256_square(r, r);`). + */ + r14 = x[7]; + r12 = x[6]; + r10 = x[5]; + r8 = x[4]; + r[6] = x[3]; + r[4] = x[2]; + r[2] = x[1]; + r[0] = x[0]; + + /* Reduce with x^8 + x^4 + x^3 + x + 1 until order is less than 8 */ + r[7] = r14; /* r[7] was 0 */ + r[6] ^= r14; + r10 ^= r14; + /* Skip, because r13 is always 0 */ + r[4] ^= r12; + r[5] = r12; /* r[5] was 0 */ + r[7] ^= r12; + r8 ^= r12; + /* Skip, because r11 is always 0 */ + r[2] ^= r10; + r[3] = r10; /* r[3] was 0 */ + r[5] ^= r10; + r[6] ^= r10; + r[1] = r14; /* r[1] was 0 */ + r[2] ^= r14; /* Substitute r9 by r14 because they will always be equal*/ + r[4] ^= r14; + r[5] ^= r14; + r[0] ^= r8; + r[1] ^= r8; + r[3] ^= r8; + r[4] ^= r8; +} + +/* + * Invert `x` in GF(2^8) and write the result to `r` + */ +static void gf256_inv(uint32_t r[8], uint32_t x[8]) { + uint32_t y[8] = {0}, z[8] = {0}; + + gf256_square(y, x); // y = x^2 + gf256_square(y, y); // y = x^4 + gf256_square(r, y); // r = x^8 + gf256_mul(z, r, x); // z = x^9 + gf256_square(r, r); // r = x^16 + gf256_mul(r, r, z); // r = x^25 + gf256_square(r, r); // r = x^50 + gf256_square(z, r); // z = x^100 + gf256_square(z, z); // z = x^200 + gf256_mul(r, r, z); // r = x^250 + gf256_mul(r, r, y); // r = x^254 + + memzero(y, sizeof(y)); + memzero(z, sizeof(z)); +} + +bool shamir_interpolate(uint8_t *result, uint8_t result_index, + const uint8_t *share_indices, + const uint8_t **share_values, uint8_t share_count, + size_t len) { + size_t i = 0, j = 0; + uint32_t x[8] = {0}; + uint32_t xs[share_count][8]; + memset(xs, 0, sizeof(xs)); + uint32_t ys[share_count][8]; + memset(ys, 0, sizeof(ys)); + uint32_t num[8] = {~0}; /* num is the numerator (=1) */ + uint32_t denom[8] = {0}; + uint32_t tmp[8] = {0}; + uint32_t secret[8] = {0}; + bool ret = true; + + if (len > SHAMIR_MAX_LEN) return false; + + /* Collect the x and y values */ + for (i = 0; i < share_count; i++) { + bitslice_setall(xs[i], share_indices[i]); + bitslice(ys[i], share_values[i], len); + } + bitslice_setall(x, result_index); + + for (i = 0; i < share_count; i++) { + memcpy(tmp, x, sizeof(uint32_t[8])); + gf256_add(tmp, xs[i]); + gf256_mul(num, num, tmp); + } + + /* Use Lagrange basis polynomials to calculate the secret coefficient */ + for (i = 0; i < share_count; i++) { + /* The code below assumes that none of the share_indices are equal to + * result_index. We need to treat that as a special case. */ + if (share_indices[i] != result_index) { + memcpy(denom, x, sizeof(denom)); + gf256_add(denom, xs[i]); + } else { + bitslice_setall(denom, 1); + gf256_add(secret, ys[i]); + } + for (j = 0; j < share_count; j++) { + if (i == j) continue; + memcpy(tmp, xs[i], sizeof(uint32_t[8])); + gf256_add(tmp, xs[j]); + gf256_mul(denom, denom, tmp); + } + if ((denom[0] | denom[1] | denom[2] | denom[3] | denom[4] | denom[5] | + denom[6] | denom[7]) == 0) { + /* The share_indices are not unique. */ + ret = false; + break; + } + gf256_inv(tmp, denom); /* inverted denominator */ + gf256_mul(tmp, tmp, num); /* basis polynomial */ + gf256_mul(tmp, tmp, ys[i]); /* scaled coefficient */ + gf256_add(secret, tmp); + } + + if (ret == true) { + unbitslice(result, secret, len); + } + + memzero(x, sizeof(x)); + memzero(xs, sizeof(xs)); + memzero(ys, sizeof(ys)); + memzero(num, sizeof(num)); + memzero(denom, sizeof(denom)); + memzero(tmp, sizeof(tmp)); + memzero(secret, sizeof(secret)); + return ret; +} diff --git a/deps/crypto/trezor-crypto/shamir.h b/deps/crypto/trezor-crypto/shamir.h new file mode 100644 index 000000000..ef04a3063 --- /dev/null +++ b/deps/crypto/trezor-crypto/shamir.h @@ -0,0 +1,70 @@ +/* + * Low level API for Daan Sprenkels' Shamir secret sharing library + * Copyright (c) 2017 Daan Sprenkels + * Copyright (c) 2019 SatoshiLabs + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Usage of this API is hazardous and is only reserved for beings with a + * good understanding of the Shamir secret sharing scheme and who know how + * crypto code is implemented. If you are unsure about this, use the + * intermediate level API. You have been warned! + */ + +#ifndef __SHAMIR_H__ +#define __SHAMIR_H__ + +#include +#include +#include + +#define SHAMIR_MAX_LEN 32 + +/* + * Computes f(x) given the Shamir shares (x_1, f(x_1)), ... , (x_m, f(x_m)). + * The x coordinates of the shares must be pairwise distinct. Returns true on + * success, otherwise false. + * result: Array of length len where the evaluations of the polynomials in x + * will be written. + * result_index: The x coordinate of the result. + * share_indices: Points to the array of integers x_1, ... , x_m. + * share_values: Points to the array of y_1, ... , y_m, where each y_i is an + * array of bytes of length len representing the evaluations of the + * polynomials in x_i. + * share_count: The number of shares m. + * len: The length of the result array and of each of the y_1, ... , y_m arrays. + * + * The number of shares used to compute the result may be larger than the + * required threshold. + * + * This function does *not* do *any* checking for integrity. If any of the + * shares are not original, this will result in an invalid restored value. + * All values written to `result` should be treated as secret. Even if some of + * the shares that were provided as input were incorrect, the result *still* + * allows an attacker to gain information about the correct result. + * + * This function treats `shares_values`, `share_indices` and `result` as secret + * values. `share_count` is treated as a public value (for performance reasons). + */ +bool shamir_interpolate(uint8_t *result, uint8_t result_index, + const uint8_t *share_indices, + const uint8_t **share_values, uint8_t share_count, + size_t len); + +#endif /* __SHAMIR_H__ */ diff --git a/deps/crypto/trezor-crypto/slip39.c b/deps/crypto/trezor-crypto/slip39.c new file mode 100644 index 000000000..2dd39fa4a --- /dev/null +++ b/deps/crypto/trezor-crypto/slip39.c @@ -0,0 +1,151 @@ +/** + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "slip39.h" +#include +#include +#include "slip39_wordlist.h" + +/** + * Returns word at position `index`. + */ +const char* get_word(uint16_t index) { + if (index >= WORDS_COUNT) { + return NULL; + } + + return slip39_wordlist[index]; +} + +/** + * Finds the index of a given word. + * Returns true on success and stores result in `index`. + */ +bool word_index(uint16_t* index, const char* word, uint8_t word_length) { + uint16_t lo = 0; + uint16_t hi = WORDS_COUNT; + uint16_t mid = 0; + + while ((hi - lo) > 1) { + mid = (hi + lo) / 2; + if (strncmp(slip39_wordlist[mid], word, word_length) > 0) { + hi = mid; + } else { + lo = mid; + } + } + if (strncmp(slip39_wordlist[lo], word, word_length) != 0) { + return false; + } + *index = lo; + return true; +} + +/** + * Returns the index of the first sequence in words_button_seq[] which is not + * less than the given sequence. Returns WORDS_COUNT if there is no such + * sequence. + */ +static uint16_t find_sequence(uint16_t sequence) { + if (sequence <= words_button_seq[0].sequence) { + return 0; + } + + uint16_t lo = 0; + uint16_t hi = WORDS_COUNT; + + while (hi - lo > 1) { + uint16_t mid = (hi + lo) / 2; + if (words_button_seq[mid].sequence >= sequence) { + hi = mid; + } else { + lo = mid; + } + } + + return hi; +} + +/** + * Returns a word matching the button sequence prefix or NULL if no match is + * found. + */ +const char* button_sequence_to_word(uint16_t sequence) { + if (sequence == 0) { + return slip39_wordlist[words_button_seq[0].index]; + } + + uint16_t multiplier = 1; + while (sequence < 1000) { + sequence *= 10; + multiplier *= 10; + } + + uint16_t i = find_sequence(sequence); + if (i >= WORDS_COUNT || + words_button_seq[i].sequence - sequence >= multiplier) { + return NULL; + } + + return slip39_wordlist[words_button_seq[i].index]; +} + +/** + * Calculates which buttons on the T9 keyboard can still be pressed after the + * prefix was entered. Returns a 9-bit bitmask, where each bit specifies which + * buttons can be pressed (there are still words in this combination). The least + * significant bit corresponds to the first button. + * + * Example: 110000110 - second, third, eighth and ninth button still can be + * pressed. + */ +uint16_t slip39_word_completion_mask(uint16_t prefix) { + if (prefix >= 1000) { + // Four char prefix -> the mask is zero. + return 0; + } + + // Determine the range of sequences [min, max), which have the given prefix. + uint16_t min = prefix; + uint16_t max = prefix + 1; + uint16_t divider = 1; + while (max <= 1000) { + min *= 10; + max *= 10; + divider *= 10; + } + divider /= 10; + + // Determine the range we will be searching in words_button_seq[]. + min = find_sequence(min); + max = find_sequence(max); + + uint16_t bitmap = 0; + for (uint16_t i = min; i < max; ++i) { + uint8_t digit = (words_button_seq[i].sequence / divider) % 10; + bitmap |= 1 << (digit - 1); + } + + return bitmap; +} diff --git a/deps/crypto/trezor-crypto/slip39.h b/deps/crypto/trezor-crypto/slip39.h new file mode 100644 index 000000000..0bc24fa74 --- /dev/null +++ b/deps/crypto/trezor-crypto/slip39.h @@ -0,0 +1,39 @@ +/** + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __SLIP39_H__ +#define __SLIP39_H__ + +#include +#include + +const char* get_word(uint16_t index); + +bool word_index(uint16_t* index, const char* word, uint8_t word_length); + +uint16_t slip39_word_completion_mask(uint16_t prefix); + +const char* button_sequence_to_word(uint16_t prefix); + +#endif diff --git a/deps/crypto/trezor-crypto/slip39_wordlist.h b/deps/crypto/trezor-crypto/slip39_wordlist.h new file mode 100644 index 000000000..3464aae94 --- /dev/null +++ b/deps/crypto/trezor-crypto/slip39_wordlist.h @@ -0,0 +1,1246 @@ +/** + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __SLIP39_WORDLIST_H__ +#define __SLIP39_WORDLIST_H__ + +#include + +#define WORDS_COUNT 1024 + +static const char* const slip39_wordlist[WORDS_COUNT] = { + "academic", "acid", "acne", "acquire", "acrobat", "activity", + "actress", "adapt", "adequate", "adjust", "admit", "adorn", + "adult", "advance", "advocate", "afraid", "again", "agency", + "agree", "aide", "aircraft", "airline", "airport", "ajar", + "alarm", "album", "alcohol", "alien", "alive", "alpha", + "already", "alto", "aluminum", "always", "amazing", "ambition", + "amount", "amuse", "analysis", "anatomy", "ancestor", "ancient", + "angel", "angry", "animal", "answer", "antenna", "anxiety", + "apart", "aquatic", "arcade", "arena", "argue", "armed", + "artist", "artwork", "aspect", "auction", "august", "aunt", + "average", "aviation", "avoid", "award", "away", "axis", + "axle", "beam", "beard", "beaver", "become", "bedroom", + "behavior", "being", "believe", "belong", "benefit", "best", + "beyond", "bike", "biology", "birthday", "bishop", "black", + "blanket", "blessing", "blimp", "blind", "blue", "body", + "bolt", "boring", "born", "both", "boundary", "bracelet", + "branch", "brave", "breathe", "briefing", "broken", "brother", + "browser", "bucket", "budget", "building", "bulb", "bulge", + "bumpy", "bundle", "burden", "burning", "busy", "buyer", + "cage", "calcium", "camera", "campus", "canyon", "capacity", + "capital", "capture", "carbon", "cards", "careful", "cargo", + "carpet", "carve", "category", "cause", "ceiling", "center", + "ceramic", "champion", "change", "charity", "check", "chemical", + "chest", "chew", "chubby", "cinema", "civil", "class", + "clay", "cleanup", "client", "climate", "clinic", "clock", + "clogs", "closet", "clothes", "club", "cluster", "coal", + "coastal", "coding", "column", "company", "corner", "costume", + "counter", "course", "cover", "cowboy", "cradle", "craft", + "crazy", "credit", "cricket", "criminal", "crisis", "critical", + "crowd", "crucial", "crunch", "crush", "crystal", "cubic", + "cultural", "curious", "curly", "custody", "cylinder", "daisy", + "damage", "dance", "darkness", "database", "daughter", "deadline", + "deal", "debris", "debut", "decent", "decision", "declare", + "decorate", "decrease", "deliver", "demand", "density", "deny", + "depart", "depend", "depict", "deploy", "describe", "desert", + "desire", "desktop", "destroy", "detailed", "detect", "device", + "devote", "diagnose", "dictate", "diet", "dilemma", "diminish", + "dining", "diploma", "disaster", "discuss", "disease", "dish", + "dismiss", "display", "distance", "dive", "divorce", "document", + "domain", "domestic", "dominant", "dough", "downtown", "dragon", + "dramatic", "dream", "dress", "drift", "drink", "drove", + "drug", "dryer", "duckling", "duke", "duration", "dwarf", + "dynamic", "early", "earth", "easel", "easy", "echo", + "eclipse", "ecology", "edge", "editor", "educate", "either", + "elbow", "elder", "election", "elegant", "element", "elephant", + "elevator", "elite", "else", "email", "emerald", "emission", + "emperor", "emphasis", "employer", "empty", "ending", "endless", + "endorse", "enemy", "energy", "enforce", "engage", "enjoy", + "enlarge", "entrance", "envelope", "envy", "epidemic", "episode", + "equation", "equip", "eraser", "erode", "escape", "estate", + "estimate", "evaluate", "evening", "evidence", "evil", "evoke", + "exact", "example", "exceed", "exchange", "exclude", "excuse", + "execute", "exercise", "exhaust", "exotic", "expand", "expect", + "explain", "express", "extend", "extra", "eyebrow", "facility", + "fact", "failure", "faint", "fake", "false", "family", + "famous", "fancy", "fangs", "fantasy", "fatal", "fatigue", + "favorite", "fawn", "fiber", "fiction", "filter", "finance", + "findings", "finger", "firefly", "firm", "fiscal", "fishing", + "fitness", "flame", "flash", "flavor", "flea", "flexible", + "flip", "float", "floral", "fluff", "focus", "forbid", + "force", "forecast", "forget", "formal", "fortune", "forward", + "founder", "fraction", "fragment", "frequent", "freshman", "friar", + "fridge", "friendly", "frost", "froth", "frozen", "fumes", + "funding", "furl", "fused", "galaxy", "game", "garbage", + "garden", "garlic", "gasoline", "gather", "general", "genius", + "genre", "genuine", "geology", "gesture", "glad", "glance", + "glasses", "glen", "glimpse", "goat", "golden", "graduate", + "grant", "grasp", "gravity", "gray", "greatest", "grief", + "grill", "grin", "grocery", "gross", "group", "grownup", + "grumpy", "guard", "guest", "guilt", "guitar", "gums", + "hairy", "hamster", "hand", "hanger", "harvest", "have", + "havoc", "hawk", "hazard", "headset", "health", "hearing", + "heat", "helpful", "herald", "herd", "hesitate", "hobo", + "holiday", "holy", "home", "hormone", "hospital", "hour", + "huge", "human", "humidity", "hunting", "husband", "hush", + "husky", "hybrid", "idea", "identify", "idle", "image", + "impact", "imply", "improve", "impulse", "include", "income", + "increase", "index", "indicate", "industry", "infant", "inform", + "inherit", "injury", "inmate", "insect", "inside", "install", + "intend", "intimate", "invasion", "involve", "iris", "island", + "isolate", "item", "ivory", "jacket", "jerky", "jewelry", + "join", "judicial", "juice", "jump", "junction", "junior", + "junk", "jury", "justice", "kernel", "keyboard", "kidney", + "kind", "kitchen", "knife", "knit", "laden", "ladle", + "ladybug", "lair", "lamp", "language", "large", "laser", + "laundry", "lawsuit", "leader", "leaf", "learn", "leaves", + "lecture", "legal", "legend", "legs", "lend", "length", + "level", "liberty", "library", "license", "lift", "likely", + "lilac", "lily", "lips", "liquid", "listen", "literary", + "living", "lizard", "loan", "lobe", "location", "losing", + "loud", "loyalty", "luck", "lunar", "lunch", "lungs", + "luxury", "lying", "lyrics", "machine", "magazine", "maiden", + "mailman", "main", "makeup", "making", "mama", "manager", + "mandate", "mansion", "manual", "marathon", "march", "market", + "marvel", "mason", "material", "math", "maximum", "mayor", + "meaning", "medal", "medical", "member", "memory", "mental", + "merchant", "merit", "method", "metric", "midst", "mild", + "military", "mineral", "minister", "miracle", "mixed", "mixture", + "mobile", "modern", "modify", "moisture", "moment", "morning", + "mortgage", "mother", "mountain", "mouse", "move", "much", + "mule", "multiple", "muscle", "museum", "music", "mustang", + "nail", "national", "necklace", "negative", "nervous", "network", + "news", "nuclear", "numb", "numerous", "nylon", "oasis", + "obesity", "object", "observe", "obtain", "ocean", "often", + "olympic", "omit", "oral", "orange", "orbit", "order", + "ordinary", "organize", "ounce", "oven", "overall", "owner", + "paces", "pacific", "package", "paid", "painting", "pajamas", + "pancake", "pants", "papa", "paper", "parcel", "parking", + "party", "patent", "patrol", "payment", "payroll", "peaceful", + "peanut", "peasant", "pecan", "penalty", "pencil", "percent", + "perfect", "permit", "petition", "phantom", "pharmacy", "photo", + "phrase", "physics", "pickup", "picture", "piece", "pile", + "pink", "pipeline", "pistol", "pitch", "plains", "plan", + "plastic", "platform", "playoff", "pleasure", "plot", "plunge", + "practice", "prayer", "preach", "predator", "pregnant", "premium", + "prepare", "presence", "prevent", "priest", "primary", "priority", + "prisoner", "privacy", "prize", "problem", "process", "profile", + "program", "promise", "prospect", "provide", "prune", "public", + "pulse", "pumps", "punish", "puny", "pupal", "purchase", + "purple", "python", "quantity", "quarter", "quick", "quiet", + "race", "racism", "radar", "railroad", "rainbow", "raisin", + "random", "ranked", "rapids", "raspy", "reaction", "realize", + "rebound", "rebuild", "recall", "receiver", "recover", "regret", + "regular", "reject", "relate", "remember", "remind", "remove", + "render", "repair", "repeat", "replace", "require", "rescue", + "research", "resident", "response", "result", "retailer", "retreat", + "reunion", "revenue", "review", "reward", "rhyme", "rhythm", + "rich", "rival", "river", "robin", "rocky", "romantic", + "romp", "roster", "round", "royal", "ruin", "ruler", + "rumor", "sack", "safari", "salary", "salon", "salt", + "satisfy", "satoshi", "saver", "says", "scandal", "scared", + "scatter", "scene", "scholar", "science", "scout", "scramble", + "screw", "script", "scroll", "seafood", "season", "secret", + "security", "segment", "senior", "shadow", "shaft", "shame", + "shaped", "sharp", "shelter", "sheriff", "short", "should", + "shrimp", "sidewalk", "silent", "silver", "similar", "simple", + "single", "sister", "skin", "skunk", "slap", "slavery", + "sled", "slice", "slim", "slow", "slush", "smart", + "smear", "smell", "smirk", "smith", "smoking", "smug", + "snake", "snapshot", "sniff", "society", "software", "soldier", + "solution", "soul", "source", "space", "spark", "speak", + "species", "spelling", "spend", "spew", "spider", "spill", + "spine", "spirit", "spit", "spray", "sprinkle", "square", + "squeeze", "stadium", "staff", "standard", "starting", "station", + "stay", "steady", "step", "stick", "stilt", "story", + "strategy", "strike", "style", "subject", "submit", "sugar", + "suitable", "sunlight", "superior", "surface", "surprise", "survive", + "sweater", "swimming", "swing", "switch", "symbolic", "sympathy", + "syndrome", "system", "tackle", "tactics", "tadpole", "talent", + "task", "taste", "taught", "taxi", "teacher", "teammate", + "teaspoon", "temple", "tenant", "tendency", "tension", "terminal", + "testify", "texture", "thank", "that", "theater", "theory", + "therapy", "thorn", "threaten", "thumb", "thunder", "ticket", + "tidy", "timber", "timely", "ting", "tofu", "together", + "tolerate", "total", "toxic", "tracks", "traffic", "training", + "transfer", "trash", "traveler", "treat", "trend", "trial", + "tricycle", "trip", "triumph", "trouble", "true", "trust", + "twice", "twin", "type", "typical", "ugly", "ultimate", + "umbrella", "uncover", "undergo", "unfair", "unfold", "unhappy", + "union", "universe", "unkind", "unknown", "unusual", "unwrap", + "upgrade", "upstairs", "username", "usher", "usual", "valid", + "valuable", "vampire", "vanish", "various", "vegan", "velvet", + "venture", "verdict", "verify", "very", "veteran", "vexed", + "victim", "video", "view", "vintage", "violence", "viral", + "visitor", "visual", "vitamins", "vocal", "voice", "volume", + "voter", "voting", "walnut", "warmth", "warn", "watch", + "wavy", "wealthy", "weapon", "webcam", "welcome", "welfare", + "western", "width", "wildlife", "window", "wine", "wireless", + "wisdom", "withdraw", "wits", "wolf", "woman", "work", + "worthy", "wrap", "wrist", "writing", "wrote", "year", + "yelp", "yield", "yoga", "zero", +}; + +/** + * This array contains number representations of SLIP-39 words. + * These numbers are determined how the words were entered on a + * T9 keyboard with the following layout: + * ab (1) cd (2) ef (3) + * ghij (4) klm (5) nopq (6) + * rs (7) tuv (8) wxyz (9) + * + * Each word is uniquely defined by four buttons. + */ +static const struct { + uint16_t sequence; + uint16_t index; +} words_button_seq[WORDS_COUNT] = { + {1212, 0}, // academic + {1216, 7}, // adapt + {1236, 8}, // adequate + {1242, 1}, // acid + {1248, 9}, // adjust + {1254, 10}, // admit + {1263, 2}, // acne + {1267, 11}, // adorn + {1268, 3}, // acquire + {1276, 4}, // acrobat + {1281, 13}, // advance + {1284, 5}, // activity + {1285, 12}, // adult + {1286, 14}, // advocate + {1287, 6}, // actress + {1315, 67}, // beam + {1317, 68}, // beard + {1318, 69}, // beaver + {1326, 70}, // become + {1327, 71}, // bedroom + {1341, 72}, // behavior + {1346, 73}, // being + {1354, 74}, // believe + {1356, 75}, // belong + {1363, 76}, // benefit + {1371, 15}, // afraid + {1378, 77}, // best + {1396, 78}, // beyond + {1414, 16}, // again + {1417, 23}, // ajar + {1423, 19}, // aide + {1436, 17}, // agency + {1453, 79}, // bike + {1465, 80}, // biology + {1472, 20}, // aircraft + {1473, 18}, // agree + {1474, 82}, // bishop + {1475, 21}, // airline + {1476, 22}, // airport + {1478, 81}, // birthday + {1512, 83}, // black + {1514, 35}, // ambition + {1516, 84}, // blanket + {1517, 24}, // alarm + {1518, 25}, // album + {1519, 34}, // amazing + {1526, 26}, // alcohol + {1537, 85}, // blessing + {1543, 27}, // alien + {1545, 86}, // blimp + {1546, 87}, // blind + {1548, 28}, // alive + {1564, 29}, // alpha + {1568, 36}, // amount + {1573, 30}, // already + {1583, 88}, // blue + {1585, 32}, // aluminum + {1586, 31}, // alto + {1587, 37}, // amuse + {1591, 33}, // always + {1615, 38}, // analysis + {1617, 48}, // apart + {1618, 39}, // anatomy + {1623, 40}, // ancestor + {1624, 41}, // ancient + {1629, 89}, // body + {1643, 42}, // angel + {1645, 44}, // animal + {1647, 43}, // angry + {1658, 90}, // bolt + {1674, 91}, // boring + {1676, 92}, // born + {1679, 45}, // answer + {1681, 49}, // aquatic + {1683, 46}, // antenna + {1684, 93}, // both + {1686, 94}, // boundary + {1694, 47}, // anxiety + {1712, 95}, // bracelet + {1716, 96}, // branch + {1718, 97}, // brave + {1721, 50}, // arcade + {1731, 98}, // breathe + {1736, 51}, // arena + {1743, 99}, // briefing + {1748, 52}, // argue + {1753, 53}, // armed + {1763, 56}, // aspect + {1765, 100}, // broken + {1768, 101}, // brother + {1769, 102}, // browser + {1784, 54}, // artist + {1789, 55}, // artwork + {1824, 104}, // budget + {1825, 103}, // bucket + {1828, 57}, // auction + {1837, 60}, // average + {1841, 61}, // aviation + {1845, 105}, // building + {1848, 58}, // august + {1851, 106}, // bulb + {1854, 107}, // bulge + {1856, 108}, // bumpy + {1862, 109}, // bundle + {1864, 62}, // avoid + {1868, 59}, // aunt + {1872, 110}, // burden + {1876, 111}, // burning + {1879, 112}, // busy + {1893, 113}, // buyer + {1917, 63}, // award + {1919, 64}, // away + {1947, 65}, // axis + {1953, 66}, // axle + {2143, 114}, // cage + {2147, 185}, // daisy + {2151, 186}, // damage + {2152, 115}, // calcium + {2153, 116}, // camera + {2156, 117}, // campus + {2161, 119}, // capacity + {2162, 187}, // dance + {2164, 120}, // capital + {2168, 121}, // capture + {2169, 118}, // canyon + {2171, 122}, // carbon + {2172, 123}, // cards + {2173, 124}, // careful + {2174, 125}, // cargo + {2175, 188}, // darkness + {2176, 126}, // carpet + {2178, 127}, // carve + {2181, 189}, // database + {2183, 128}, // category + {2184, 190}, // daughter + {2187, 129}, // cause + {2312, 191}, // deadline + {2315, 192}, // deal + {2317, 193}, // debris + {2318, 194}, // debut + {2323, 195}, // decent + {2324, 196}, // decision + {2325, 197}, // declare + {2326, 198}, // decorate + {2327, 199}, // decrease + {2345, 130}, // ceiling + {2351, 201}, // demand + {2354, 200}, // deliver + {2361, 204}, // depart + {2363, 205}, // depend + {2364, 206}, // depict + {2365, 207}, // deploy + {2367, 202}, // density + {2368, 131}, // center + {2369, 203}, // deny + {2371, 132}, // ceramic + {2372, 208}, // describe + {2373, 209}, // desert + {2374, 210}, // desire + {2375, 211}, // desktop + {2378, 212}, // destroy + {2381, 213}, // detailed + {2383, 214}, // detect + {2384, 215}, // device + {2386, 216}, // devote + {2414, 217}, // diagnose + {2415, 133}, // champion + {2416, 134}, // change + {2417, 135}, // charity + {2428, 218}, // dictate + {2432, 136}, // check + {2435, 137}, // chemical + {2437, 138}, // chest + {2438, 219}, // diet + {2439, 139}, // chew + {2453, 220}, // dilemma + {2454, 221}, // diminish + {2463, 141}, // cinema + {2464, 222}, // dining + {2465, 223}, // diploma + {2471, 224}, // disaster + {2472, 225}, // discuss + {2473, 226}, // disease + {2474, 227}, // dish + {2475, 228}, // dismiss + {2476, 229}, // display + {2478, 230}, // distance + {2481, 140}, // chubby + {2483, 231}, // dive + {2484, 142}, // civil + {2486, 232}, // divorce + {2517, 143}, // class + {2519, 144}, // clay + {2531, 145}, // cleanup + {2543, 146}, // client + {2545, 147}, // climate + {2546, 148}, // clinic + {2562, 149}, // clock + {2564, 150}, // clogs + {2567, 151}, // closet + {2568, 152}, // clothes + {2581, 153}, // club + {2587, 154}, // cluster + {2615, 155}, // coal + {2617, 156}, // coastal + {2624, 157}, // coding + {2628, 233}, // document + {2651, 234}, // domain + {2653, 235}, // domestic + {2654, 236}, // dominant + {2656, 159}, // company + {2658, 158}, // column + {2676, 160}, // corner + {2678, 161}, // costume + {2683, 164}, // cover + {2684, 237}, // dough + {2686, 162}, // counter + {2687, 163}, // course + {2691, 165}, // cowboy + {2696, 238}, // downtown + {2712, 166}, // cradle + {2713, 167}, // craft + {2714, 239}, // dragon + {2715, 240}, // dramatic + {2719, 168}, // crazy + {2731, 241}, // dream + {2732, 169}, // credit + {2737, 242}, // dress + {2742, 170}, // cricket + {2743, 243}, // drift + {2745, 171}, // criminal + {2746, 244}, // drink + {2747, 172}, // crisis + {2748, 173}, // critical + {2768, 245}, // drove + {2769, 174}, // crowd + {2782, 175}, // crucial + {2784, 246}, // drug + {2786, 176}, // crunch + {2787, 177}, // crush + {2793, 247}, // dryer + {2797, 178}, // crystal + {2814, 179}, // cubic + {2825, 248}, // duckling + {2853, 249}, // duke + {2858, 180}, // cultural + {2871, 250}, // duration + {2874, 181}, // curious + {2875, 182}, // curly + {2878, 183}, // custody + {2917, 251}, // dwarf + {2954, 184}, // cylinder + {2961, 252}, // dynamic + {3124, 323}, // facility + {3128, 324}, // fact + {3145, 325}, // failure + {3146, 326}, // faint + {3153, 327}, // fake + {3154, 329}, // family + {3156, 330}, // famous + {3157, 328}, // false + {3162, 331}, // fancy + {3164, 332}, // fangs + {3168, 333}, // fantasy + {3173, 255}, // easel + {3175, 253}, // early + {3178, 254}, // earth + {3179, 256}, // easy + {3181, 334}, // fatal + {3184, 335}, // fatigue + {3186, 336}, // favorite + {3196, 337}, // fawn + {3243, 260}, // edge + {3246, 257}, // echo + {3248, 261}, // editor + {3254, 258}, // eclipse + {3265, 259}, // ecology + {3282, 262}, // educate + {3413, 338}, // fiber + {3428, 339}, // fiction + {3458, 340}, // filter + {3461, 341}, // finance + {3462, 342}, // findings + {3464, 343}, // finger + {3472, 346}, // fiscal + {3473, 344}, // firefly + {3474, 347}, // fishing + {3475, 345}, // firm + {3484, 263}, // either + {3486, 348}, // fitness + {3514, 273}, // email + {3515, 349}, // flame + {3516, 264}, // elbow + {3517, 350}, // flash + {3518, 351}, // flavor + {3523, 265}, // elder + {3531, 352}, // flea + {3532, 266}, // election + {3534, 267}, // elegant + {3535, 268}, // element + {3536, 269}, // elephant + {3537, 274}, // emerald + {3538, 270}, // elevator + {3539, 353}, // flexible + {3546, 354}, // flip + {3547, 275}, // emission + {3548, 271}, // elite + {3561, 355}, // float + {3563, 276}, // emperor + {3564, 277}, // emphasis + {3565, 278}, // employer + {3567, 356}, // floral + {3568, 279}, // empty + {3573, 272}, // else + {3583, 357}, // fluff + {3624, 280}, // ending + {3625, 281}, // endless + {3626, 282}, // endorse + {3628, 358}, // focus + {3635, 283}, // enemy + {3636, 285}, // enforce + {3637, 284}, // energy + {3641, 286}, // engage + {3642, 292}, // epidemic + {3646, 287}, // enjoy + {3647, 293}, // episode + {3651, 288}, // enlarge + {3671, 359}, // forbid + {3672, 360}, // force + {3673, 361}, // forecast + {3674, 362}, // forget + {3675, 363}, // formal + {3678, 364}, // fortune + {3679, 365}, // forward + {3681, 294}, // equation + {3683, 290}, // envelope + {3684, 295}, // equip + {3686, 366}, // founder + {3687, 289}, // entrance + {3689, 291}, // envy + {3712, 367}, // fraction + {3714, 368}, // fragment + {3717, 296}, // eraser + {3721, 298}, // escape + {3736, 369}, // frequent + {3737, 370}, // freshman + {3741, 371}, // friar + {3742, 372}, // fridge + {3743, 373}, // friendly + {3762, 297}, // erode + {3767, 374}, // frost + {3768, 375}, // froth + {3769, 376}, // frozen + {3781, 299}, // estate + {3784, 300}, // estimate + {3815, 301}, // evaluate + {3836, 302}, // evening + {3842, 303}, // evidence + {3845, 304}, // evil + {3853, 377}, // fumes + {3862, 378}, // funding + {3865, 305}, // evoke + {3873, 380}, // fused + {3875, 379}, // furl + {3912, 306}, // exact + {3915, 307}, // example + {3923, 308}, // exceed + {3924, 309}, // exchange + {3925, 310}, // exclude + {3928, 311}, // excuse + {3931, 322}, // eyebrow + {3932, 312}, // execute + {3937, 313}, // exercise + {3941, 314}, // exhaust + {3961, 316}, // expand + {3963, 317}, // expect + {3965, 318}, // explain + {3967, 319}, // express + {3968, 315}, // exotic + {3983, 320}, // extend + {3987, 321}, // extra + {4125, 483}, // jacket + {4147, 420}, // hairy + {4151, 381}, // galaxy + {4153, 382}, // game + {4157, 421}, // hamster + {4162, 422}, // hand + {4164, 423}, // hanger + {4171, 383}, // garbage + {4172, 384}, // garden + {4175, 385}, // garlic + {4176, 386}, // gasoline + {4178, 424}, // harvest + {4183, 425}, // have + {4184, 387}, // gather + {4186, 426}, // havoc + {4191, 428}, // hazard + {4195, 427}, // hawk + {4231, 452}, // idea + {4236, 453}, // identify + {4253, 454}, // idle + {4312, 429}, // headset + {4315, 430}, // health + {4317, 431}, // hearing + {4318, 432}, // heat + {4356, 433}, // helpful + {4363, 388}, // general + {4364, 389}, // genius + {4365, 392}, // geology + {4367, 390}, // genre + {4368, 391}, // genuine + {4371, 434}, // herald + {4372, 435}, // herd + {4374, 436}, // hesitate + {4375, 484}, // jerky + {4378, 393}, // gesture + {4393, 485}, // jewelry + {4512, 394}, // glad + {4514, 455}, // image + {4516, 395}, // glance + {4517, 396}, // glasses + {4536, 397}, // glen + {4545, 398}, // glimpse + {4561, 456}, // impact + {4565, 457}, // imply + {4567, 458}, // improve + {4568, 459}, // impulse + {4616, 437}, // hobo + {4618, 399}, // goat + {4623, 463}, // index + {4624, 464}, // indicate + {4625, 460}, // include + {4626, 461}, // income + {4627, 462}, // increase + {4628, 465}, // industry + {4631, 466}, // infant + {4636, 467}, // inform + {4643, 468}, // inherit + {4646, 486}, // join + {4648, 469}, // injury + {4651, 470}, // inmate + {4652, 400}, // golden + {4653, 440}, // home + {4654, 438}, // holiday + {4659, 439}, // holy + {4673, 471}, // insect + {4674, 472}, // inside + {4675, 441}, // hormone + {4676, 442}, // hospital + {4678, 473}, // install + {4681, 476}, // invasion + {4683, 474}, // intend + {4684, 475}, // intimate + {4686, 477}, // involve + {4687, 443}, // hour + {4712, 401}, // graduate + {4716, 402}, // grant + {4717, 403}, // grasp + {4718, 404}, // gravity + {4719, 405}, // gray + {4731, 406}, // greatest + {4743, 407}, // grief + {4745, 408}, // grill + {4746, 409}, // grin + {4747, 478}, // iris + {4751, 479}, // island + {4762, 410}, // grocery + {4765, 480}, // isolate + {4767, 411}, // gross + {4768, 412}, // group + {4769, 413}, // grownup + {4785, 414}, // grumpy + {4817, 415}, // guard + {4824, 487}, // judicial + {4835, 481}, // item + {4837, 416}, // guest + {4842, 488}, // juice + {4843, 444}, // huge + {4845, 417}, // guilt + {4848, 418}, // guitar + {4851, 445}, // human + {4854, 446}, // humidity + {4856, 489}, // jump + {4857, 419}, // gums + {4862, 490}, // junction + {4864, 491}, // junior + {4865, 492}, // junk + {4867, 482}, // ivory + {4868, 447}, // hunting + {4871, 448}, // husband + {4874, 449}, // hush + {4875, 450}, // husky + {4878, 494}, // justice + {4879, 493}, // jury + {4917, 451}, // hybrid + {5123, 502}, // laden + {5124, 549}, // machine + {5125, 503}, // ladle + {5129, 504}, // ladybug + {5141, 550}, // magazine + {5142, 551}, // maiden + {5145, 552}, // mailman + {5146, 553}, // main + {5147, 505}, // lair + {5151, 556}, // mama + {5153, 554}, // makeup + {5154, 555}, // making + {5156, 506}, // lamp + {5161, 557}, // manager + {5162, 558}, // mandate + {5164, 507}, // language + {5167, 559}, // mansion + {5168, 560}, // manual + {5171, 561}, // marathon + {5172, 562}, // march + {5173, 509}, // laser + {5174, 508}, // large + {5175, 563}, // market + {5176, 565}, // mason + {5178, 564}, // marvel + {5183, 566}, // material + {5184, 567}, // math + {5186, 510}, // laundry + {5194, 568}, // maximum + {5196, 569}, // mayor + {5197, 511}, // lawsuit + {5312, 512}, // leader + {5313, 513}, // leaf + {5316, 570}, // meaning + {5317, 514}, // learn + {5318, 515}, // leaves + {5321, 571}, // medal + {5324, 572}, // medical + {5328, 516}, // lecture + {5341, 517}, // legal + {5343, 518}, // legend + {5347, 519}, // legs + {5351, 573}, // member + {5356, 574}, // memory + {5362, 520}, // lend + {5364, 521}, // length + {5368, 575}, // mental + {5372, 576}, // merchant + {5374, 577}, // merit + {5376, 495}, // kernel + {5383, 522}, // level + {5384, 578}, // method + {5387, 579}, // metric + {5391, 496}, // keyboard + {5413, 523}, // liberty + {5417, 524}, // library + {5423, 525}, // license + {5426, 497}, // kidney + {5427, 580}, // midst + {5438, 526}, // lift + {5451, 528}, // lilac + {5452, 581}, // mild + {5453, 527}, // likely + {5454, 582}, // military + {5459, 529}, // lily + {5462, 498}, // kind + {5463, 583}, // mineral + {5464, 584}, // minister + {5467, 530}, // lips + {5468, 531}, // liquid + {5471, 585}, // miracle + {5478, 532}, // listen + {5482, 499}, // kitchen + {5483, 533}, // literary + {5484, 534}, // living + {5491, 535}, // lizard + {5493, 586}, // mixed + {5498, 587}, // mixture + {5613, 537}, // lobe + {5614, 588}, // mobile + {5616, 536}, // loan + {5621, 538}, // location + {5623, 589}, // modern + {5624, 590}, // modify + {5643, 500}, // knife + {5647, 591}, // moisture + {5648, 501}, // knit + {5653, 592}, // moment + {5674, 539}, // losing + {5676, 593}, // morning + {5678, 594}, // mortgage + {5682, 540}, // loud + {5683, 598}, // move + {5684, 595}, // mother + {5686, 596}, // mountain + {5687, 597}, // mouse + {5691, 541}, // loyalty + {5824, 599}, // much + {5825, 542}, // luck + {5853, 600}, // mule + {5858, 601}, // multiple + {5861, 543}, // lunar + {5862, 544}, // lunch + {5864, 545}, // lungs + {5872, 602}, // muscle + {5873, 603}, // museum + {5874, 604}, // music + {5878, 605}, // mustang + {5898, 546}, // luxury + {5946, 547}, // lying + {5974, 548}, // lyrics + {6123, 636}, // paces + {6124, 637}, // pacific + {6125, 638}, // package + {6137, 618}, // obesity + {6141, 641}, // pajamas + {6142, 639}, // paid + {6143, 619}, // object + {6145, 606}, // nail + {6146, 640}, // painting + {6161, 644}, // papa + {6162, 642}, // pancake + {6163, 645}, // paper + {6168, 643}, // pants + {6172, 646}, // parcel + {6173, 620}, // observe + {6174, 617}, // oasis + {6175, 647}, // parking + {6178, 648}, // party + {6181, 621}, // obtain + {6183, 649}, // patent + {6184, 607}, // national + {6187, 650}, // patrol + {6195, 651}, // payment + {6197, 652}, // payroll + {6231, 622}, // ocean + {6312, 653}, // peaceful + {6316, 654}, // peanut + {6317, 655}, // peasant + {6321, 656}, // pecan + {6325, 608}, // necklace + {6341, 609}, // negative + {6361, 657}, // penalty + {6362, 658}, // pencil + {6372, 659}, // percent + {6373, 660}, // perfect + {6375, 661}, // permit + {6378, 610}, // nervous + {6383, 623}, // often + {6384, 662}, // petition + {6389, 611}, // network + {6397, 612}, // news + {6416, 663}, // phantom + {6417, 664}, // pharmacy + {6425, 668}, // pickup + {6428, 669}, // picture + {6432, 670}, // piece + {6453, 671}, // pile + {6463, 673}, // pipeline + {6465, 672}, // pink + {6468, 665}, // photo + {6471, 666}, // phrase + {6478, 674}, // pistol + {6482, 675}, // pitch + {6497, 667}, // physics + {6514, 676}, // plains + {6516, 677}, // plan + {6517, 678}, // plastic + {6518, 679}, // platform + {6519, 680}, // playoff + {6531, 681}, // pleasure + {6548, 625}, // omit + {6568, 682}, // plot + {6586, 683}, // plunge + {6595, 624}, // olympic + {6712, 684}, // practice + {6714, 628}, // orbit + {6715, 626}, // oral + {6716, 627}, // orange + {6719, 685}, // prayer + {6723, 629}, // order + {6724, 630}, // ordinary + {6731, 686}, // preach + {6732, 687}, // predator + {6734, 688}, // pregnant + {6735, 689}, // premium + {6736, 690}, // prepare + {6737, 691}, // presence + {6738, 692}, // prevent + {6741, 631}, // organize + {6743, 693}, // priest + {6745, 694}, // primary + {6746, 695}, // priority + {6747, 696}, // prisoner + {6748, 697}, // privacy + {6749, 698}, // prize + {6761, 699}, // problem + {6762, 700}, // process + {6763, 701}, // profile + {6764, 702}, // program + {6765, 703}, // promise + {6767, 704}, // prospect + {6768, 705}, // provide + {6786, 706}, // prune + {6815, 707}, // public + {6816, 716}, // quantity + {6817, 717}, // quarter + {6825, 613}, // nuclear + {6836, 633}, // oven + {6837, 634}, // overall + {6842, 718}, // quick + {6843, 719}, // quiet + {6851, 614}, // numb + {6853, 615}, // numerous + {6856, 709}, // pumps + {6857, 708}, // pulse + {6861, 712}, // pupal + {6862, 632}, // ounce + {6864, 710}, // punish + {6869, 711}, // puny + {6872, 713}, // purchase + {6876, 714}, // purple + {6956, 616}, // nylon + {6963, 635}, // owner + {6984, 715}, // python + {7121, 722}, // radar + {7123, 720}, // race + {7124, 721}, // racism + {7125, 775}, // sack + {7131, 776}, // safari + {7145, 723}, // railroad + {7146, 724}, // rainbow + {7147, 725}, // raisin + {7151, 777}, // salary + {7156, 778}, // salon + {7158, 779}, // salt + {7162, 726}, // random + {7164, 728}, // rapids + {7165, 727}, // ranked + {7176, 729}, // raspy + {7183, 782}, // saver + {7184, 780}, // satisfy + {7186, 781}, // satoshi + {7197, 783}, // says + {7216, 784}, // scandal + {7217, 785}, // scared + {7218, 786}, // scatter + {7236, 787}, // scene + {7243, 789}, // science + {7246, 788}, // scholar + {7268, 790}, // scout + {7271, 791}, // scramble + {7273, 792}, // screw + {7274, 793}, // script + {7276, 794}, // scroll + {7312, 730}, // reaction + {7313, 795}, // seafood + {7315, 731}, // realize + {7316, 732}, // rebound + {7317, 796}, // season + {7318, 733}, // rebuild + {7321, 734}, // recall + {7323, 735}, // receiver + {7326, 736}, // recover + {7327, 797}, // secret + {7328, 798}, // security + {7343, 739}, // reject + {7345, 799}, // segment + {7347, 737}, // regret + {7348, 738}, // regular + {7351, 740}, // relate + {7353, 741}, // remember + {7354, 742}, // remind + {7356, 743}, // remove + {7361, 745}, // repair + {7362, 744}, // render + {7363, 746}, // repeat + {7364, 800}, // senior + {7365, 747}, // replace + {7368, 748}, // require + {7372, 749}, // rescue + {7373, 750}, // research + {7374, 751}, // resident + {7376, 752}, // response + {7378, 753}, // result + {7381, 754}, // retailer + {7383, 757}, // revenue + {7384, 758}, // review + {7386, 756}, // reunion + {7387, 755}, // retreat + {7391, 759}, // reward + {7412, 801}, // shadow + {7413, 802}, // shaft + {7415, 803}, // shame + {7416, 804}, // shaped + {7417, 805}, // sharp + {7423, 811}, // sidewalk + {7424, 762}, // rich + {7435, 806}, // shelter + {7437, 807}, // sheriff + {7453, 812}, // silent + {7454, 814}, // similar + {7456, 815}, // simple + {7458, 813}, // silver + {7464, 816}, // single + {7467, 808}, // short + {7468, 809}, // should + {7474, 810}, // shrimp + {7478, 817}, // sister + {7481, 763}, // rival + {7483, 764}, // river + {7495, 760}, // rhyme + {7498, 761}, // rhythm + {7516, 820}, // slap + {7517, 827}, // smart + {7518, 821}, // slavery + {7531, 828}, // smear + {7532, 822}, // sled + {7535, 829}, // smell + {7542, 823}, // slice + {7545, 824}, // slim + {7546, 818}, // skin + {7547, 830}, // smirk + {7548, 831}, // smith + {7565, 832}, // smoking + {7569, 825}, // slow + {7584, 833}, // smug + {7586, 819}, // skunk + {7587, 826}, // slush + {7612, 843}, // space + {7614, 765}, // robin + {7615, 834}, // snake + {7616, 835}, // snapshot + {7617, 844}, // spark + {7624, 837}, // society + {7625, 766}, // rocky + {7631, 845}, // speak + {7632, 846}, // species + {7635, 847}, // spelling + {7636, 848}, // spend + {7638, 838}, // software + {7639, 849}, // spew + {7642, 850}, // spider + {7643, 836}, // sniff + {7645, 851}, // spill + {7646, 852}, // spine + {7647, 853}, // spirit + {7648, 854}, // spit + {7651, 767}, // romantic + {7652, 839}, // soldier + {7656, 768}, // romp + {7658, 840}, // solution + {7671, 855}, // spray + {7674, 856}, // sprinkle + {7678, 769}, // roster + {7681, 857}, // square + {7683, 858}, // squeeze + {7685, 841}, // soul + {7686, 770}, // round + {7687, 842}, // source + {7691, 771}, // royal + {7812, 859}, // stadium + {7813, 860}, // staff + {7814, 873}, // subject + {7815, 874}, // submit + {7816, 861}, // standard + {7817, 862}, // starting + {7818, 863}, // station + {7819, 864}, // stay + {7831, 865}, // steady + {7836, 866}, // step + {7841, 875}, // sugar + {7842, 867}, // stick + {7845, 868}, // stilt + {7846, 772}, // ruin + {7848, 876}, // suitable + {7853, 773}, // ruler + {7856, 774}, // rumor + {7863, 878}, // superior + {7865, 877}, // sunlight + {7867, 869}, // story + {7871, 870}, // strategy + {7873, 879}, // surface + {7874, 871}, // strike + {7876, 880}, // surprise + {7878, 881}, // survive + {7895, 872}, // style + {7931, 882}, // sweater + {7945, 883}, // swimming + {7946, 884}, // swing + {7948, 885}, // switch + {7951, 886}, // symbolic + {7956, 887}, // sympathy + {7962, 888}, // syndrome + {7978, 889}, // system + {8125, 890}, // tackle + {8126, 892}, // tadpole + {8128, 891}, // tactics + {8153, 893}, // talent + {8154, 965}, // valid + {8156, 967}, // vampire + {8158, 966}, // valuable + {8164, 968}, // vanish + {8174, 969}, // various + {8175, 894}, // task + {8178, 895}, // taste + {8184, 896}, // taught + {8194, 897}, // taxi + {8312, 898}, // teacher + {8315, 899}, // teammate + {8317, 900}, // teaspoon + {8341, 970}, // vegan + {8356, 901}, // temple + {8358, 971}, // velvet + {8361, 902}, // tenant + {8362, 903}, // tendency + {8367, 904}, // tension + {8368, 972}, // venture + {8372, 973}, // verdict + {8374, 974}, // verify + {8375, 905}, // terminal + {8378, 906}, // testify + {8379, 975}, // very + {8383, 976}, // veteran + {8393, 977}, // vexed + {8398, 907}, // texture + {8416, 908}, // thank + {8418, 909}, // that + {8423, 979}, // video + {8425, 917}, // ticket + {8428, 978}, // victim + {8429, 918}, // tidy + {8431, 910}, // theater + {8436, 911}, // theory + {8437, 912}, // therapy + {8439, 980}, // view + {8451, 919}, // timber + {8453, 920}, // timely + {8459, 946}, // ugly + {8464, 921}, // ting + {8465, 982}, // violence + {8467, 913}, // thorn + {8468, 981}, // vintage + {8471, 983}, // viral + {8473, 914}, // threaten + {8474, 984}, // visitor + {8478, 985}, // visual + {8481, 986}, // vitamins + {8485, 915}, // thumb + {8486, 916}, // thunder + {8517, 948}, // umbrella + {8584, 947}, // ultimate + {8621, 987}, // vocal + {8623, 950}, // undergo + {8626, 949}, // uncover + {8631, 951}, // unfair + {8636, 952}, // unfold + {8638, 922}, // tofu + {8641, 953}, // unhappy + {8642, 988}, // voice + {8643, 923}, // together + {8646, 954}, // union + {8647, 960}, // upgrade + {8648, 955}, // universe + {8653, 924}, // tolerate + {8654, 956}, // unkind + {8656, 957}, // unknown + {8658, 989}, // volume + {8678, 961}, // upstairs + {8681, 925}, // total + {8683, 990}, // voter + {8684, 991}, // voting + {8687, 958}, // unusual + {8694, 926}, // toxic + {8697, 959}, // unwrap + {8712, 927}, // tracks + {8713, 928}, // traffic + {8714, 929}, // training + {8716, 930}, // transfer + {8717, 931}, // trash + {8718, 932}, // traveler + {8731, 933}, // treat + {8736, 934}, // trend + {8737, 962}, // username + {8741, 935}, // trial + {8742, 936}, // tricycle + {8743, 963}, // usher + {8746, 937}, // trip + {8748, 938}, // triumph + {8768, 939}, // trouble + {8781, 964}, // usual + {8783, 940}, // true + {8787, 941}, // trust + {8942, 942}, // twice + {8946, 943}, // twin + {8963, 944}, // type + {8964, 945}, // typical + {9156, 992}, // walnut + {9175, 993}, // warmth + {9176, 994}, // warn + {9182, 995}, // watch + {9189, 996}, // wavy + {9312, 999}, // webcam + {9315, 997}, // wealthy + {9316, 998}, // weapon + {9317, 1019}, // year + {9352, 1000}, // welcome + {9353, 1001}, // welfare + {9356, 1020}, // yelp + {9376, 1023}, // zero + {9378, 1002}, // western + {9428, 1003}, // width + {9435, 1021}, // yield + {9452, 1004}, // wildlife + {9462, 1005}, // window + {9463, 1006}, // wine + {9472, 1008}, // wisdom + {9473, 1007}, // wireless + {9484, 1009}, // withdraw + {9487, 1010}, // wits + {9641, 1022}, // yoga + {9651, 1012}, // woman + {9653, 1011}, // wolf + {9675, 1013}, // work + {9678, 1014}, // worthy + {9716, 1015}, // wrap + {9747, 1016}, // wrist + {9748, 1017}, // writing + {9768, 1018}, // wrote +}; + +#endif diff --git a/deps/crypto/trezor-crypto/tests/test_bignum.py b/deps/crypto/trezor-crypto/tests/test_bignum.py new file mode 100755 index 000000000..b99685a1a --- /dev/null +++ b/deps/crypto/trezor-crypto/tests/test_bignum.py @@ -0,0 +1,1032 @@ +#!/usr/bin/python +import ctypes +import itertools +import os +import random +from ctypes import ( + c_bool, + c_int, + c_size_t, + c_uint, + c_uint8, + c_uint16, + c_uint32, + c_uint64, +) +from math import floor, log, sqrt + +import pytest + +dir = os.path.abspath(os.path.dirname(__file__)) +lib = ctypes.cdll.LoadLibrary(os.path.join(dir, "libtrezor-crypto.so")) + +limbs_number = 9 +bits_per_limb = 29 + + +@pytest.fixture() +def prime(request): + return 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F + + +@pytest.fixture(params=range(limbs_number * bits_per_limb)) +def bignum_bit_index(request): + return request.param + + +max_decimal_digits = floor(limbs_number * bits_per_limb * log(2, 10)) + + +@pytest.fixture(params=range(max_decimal_digits)) +def bignum_decimal_digit_index(request): + return request.param + + +iterations = int(os.environ.get("ITERS", 1000)) + + +@pytest.fixture(params=range(iterations)) +def r(request): + return Random(request.param) + + +def implication(p, c): + return not p or c + + +def uint32_p_to_int(pointer): + return pointer.contents.value + + +def uint32_p(): + return ctypes.POINTER(c_int)(c_int()) + + +limb_type = c_uint32 + + +def bignum(limbs_number=limbs_number): + return (limbs_number * limb_type)() + + +def limbs_to_bignum(limbs): + return (limbs_number * limb_type)(*limbs) + + +def int_to_bignum(number, limbs_number=limbs_number): + assert number >= 0 + assert number.bit_length() <= limbs_number * bits_per_limb + + bn = (limbs_number * limb_type)() + for i in range(limbs_number): + bn[i] = number % 2 ** bits_per_limb + number //= 2 ** bits_per_limb + + return bn + + +def bignum_to_int(bignum, limbs_number=limbs_number): + number = 0 + + for i in reversed(range(limbs_number)): + number *= 2 ** bits_per_limb + number += bignum[i] + + return number + + +def raw_number(): + return (32 * c_uint8)() + + +def raw_number_to_integer(raw_number, endianess): + return int.from_bytes(raw_number, endianess) + + +def integer_to_raw_number(number, endianess): + return (32 * c_uint8)(*number.to_bytes(32, endianess)) + + +def bignum_is_normalised(bignum): + for limb in bignum: + if limb > 2 ** bits_per_limb: + return False + return True + + +def number_is_partly_reduced(number, prime): + return number < 2 * prime + + +def number_is_fully_reduced(number, prime): + return number < prime + + +class Random(random.Random): + def rand_int_normalized(self): + return self.randrange(0, 2 ** (limbs_number * bits_per_limb)) + + def rand_int_256(self): + return self.randrange(0, 2 ** 256) + + def rand_int_reduced(self, p): + return self.randrange(0, 2 * p) + + def rand_int_bitsize(self, bitsize): + return self.randrange(0, 2 ** bitsize) + + def rand_bit_index(self): + return self.randrange(0, limbs_number * bits_per_limb) + + def rand_bignum(self, limbs_number=limbs_number): + return (limb_type * limbs_number)( + *[self.randrange(0, 256 ** 4) for _ in range(limbs_number)] + ) + + +def assert_bn_read_be(in_number): + raw_in_number = integer_to_raw_number(in_number, "big") + bn_out_number = bignum() + lib.bn_read_be(raw_in_number, bn_out_number) + out_number = bignum_to_int(bn_out_number) + + assert bignum_is_normalised(bn_out_number) + assert out_number == in_number + + +def assert_bn_read_le(in_number): + raw_in_number = integer_to_raw_number(in_number, "little") + bn_out_number = bignum() + lib.bn_read_le(raw_in_number, bn_out_number) + out_number = bignum_to_int(bn_out_number) + + assert bignum_is_normalised(bn_out_number) + assert out_number == in_number + + +def assert_bn_write_be(in_number): + bn_in_number = int_to_bignum(in_number) + raw_out_number = raw_number() + lib.bn_write_be(bn_in_number, raw_out_number) + out_number = raw_number_to_integer(raw_out_number, "big") + + assert out_number == in_number + + +def assert_bn_write_le(in_number): + bn_in_number = int_to_bignum(in_number) + raw_out_number = raw_number() + lib.bn_write_le(bn_in_number, raw_out_number) + out_number = raw_number_to_integer(raw_out_number, "little") + + assert out_number == in_number + + +def assert_bn_read_uint32(x): + bn_out_number = bignum() + lib.bn_read_uint32(c_uint32(x), bn_out_number) + out_number = bignum_to_int(bn_out_number) + + assert bignum_is_normalised(bn_out_number) + assert out_number == x + + +def assert_bn_read_uint64(x): + bn_out_number = bignum() + lib.bn_read_uint64(c_uint64(x), bn_out_number) + out_number = bignum_to_int(bn_out_number) + + assert bignum_is_normalised(bn_out_number) + assert out_number == x + + +def assert_bn_bitcount(x): + bn_x = int_to_bignum(x) + return_value = lib.bn_bitcount(bn_x) + + assert return_value == x.bit_length() + + +def assert_bn_digitcount(x): + bn_x = int_to_bignum(x) + return_value = lib.bn_digitcount(bn_x) + + assert return_value == len(str(x)) + + +def assert_bn_zero(): + bn_x = bignum() + lib.bn_zero(bn_x) + x = bignum_to_int(bn_x) + + assert bignum_is_normalised(bn_x) + assert x == 0 + + +def assert_bn_one(): + bn_x = bignum() + lib.bn_one(bn_x) + x = bignum_to_int(bn_x) + + assert bignum_is_normalised(bn_x) + assert x == 1 + + +def assert_bn_is_zero(x): + bn_x = int_to_bignum(x) + return_value = lib.bn_is_zero(bn_x) + + assert return_value == (x == 0) + + +def assert_bn_is_one(x): + bn_x = int_to_bignum(x) + return_value = lib.bn_is_one(bn_x) + + assert return_value == (x == 1) + + +def assert_bn_is_less(x, y): + bn_x = int_to_bignum(x) + bn_y = int_to_bignum(y) + return_value = lib.bn_is_less(bn_x, bn_y) + + assert return_value == (x < y) + + +def assert_bn_is_equal(x, y): + bn_x = int_to_bignum(x) + bn_y = int_to_bignum(y) + return_value = lib.bn_is_equal(bn_x, bn_y) + + assert return_value == (x == y) + + +def assert_bn_cmov(cond, truecase, falsecase): + bn_res = bignum() + bn_truecase = int_to_bignum(truecase) + bn_falsecase = int_to_bignum(falsecase) + lib.bn_cmov(bn_res, c_uint32(cond), bn_truecase, bn_falsecase) + res = bignum_to_int(bn_res) + + assert res == truecase if cond else falsecase + + +def assert_bn_cnegate(cond, x_old, prime): + bn_x = int_to_bignum(x_old) + bn_prime = int_to_bignum(prime) + lib.bn_cnegate(c_uint32(cond), bn_x, bn_prime) + x_new = bignum_to_int(bn_x) + + assert bignum_is_normalised(bn_x) + assert number_is_partly_reduced(x_new, prime) + assert x_new % prime == -x_old % prime if cond else x_old % prime + + +def assert_bn_lshift(x_old): + bn_x = int_to_bignum(x_old) + lib.bn_lshift(bn_x) + x_new = bignum_to_int(bn_x) + + assert bignum_is_normalised(bn_x) + assert x_new == (x_old << 1) + + +def assert_bn_rshift(x_old): + bn_x = int_to_bignum(x_old) + lib.bn_rshift(bn_x) + x_new = bignum_to_int(bn_x) + + assert bignum_is_normalised(bn_x) + assert x_new == (x_old >> 1) + + +def assert_bn_setbit(x_old, i): + bn_x = int_to_bignum(x_old) + lib.bn_setbit(bn_x, c_uint16(i)) + x_new = bignum_to_int(bn_x) + + assert bignum_is_normalised(bn_x) + assert x_new == x_old | (1 << i) + + +def assert_bn_clearbit(x_old, i): + bn_x = int_to_bignum(x_old) + lib.bn_clearbit(bn_x, c_uint16(i)) + x_new = bignum_to_int(bn_x) + + assert bignum_is_normalised(bn_x) + assert x_new == x_old & ~(1 << i) + + +def assert_bn_testbit(x_old, i): + bn_x = int_to_bignum(x_old) + return_value = lib.bn_testbit(bn_x, c_uint16(i)) + + assert return_value == x_old >> i & 1 + + +def assert_bn_xor(x, y): + bn_res = bignum() + bn_x = int_to_bignum(x) + bn_y = int_to_bignum(y) + lib.bn_xor(bn_res, bn_x, bn_y) + res = bignum_to_int(bn_res) + + assert res == x ^ y + + +def assert_bn_mult_half(x_old, prime): + bn_x = int_to_bignum(x_old) + bn_prime = int_to_bignum(prime) + lib.bn_mult_half(bn_x, bn_prime) + x_new = bignum_to_int(bn_x) + + assert implication( + number_is_partly_reduced(x_old, prime), number_is_partly_reduced(x_new, prime) + ) + assert x_new == (x_old + prime) >> 1 if x_old & 1 else x_old >> 1 + + +def assert_bn_mult_k(x_old, k, prime): + bn_x = int_to_bignum(x_old) + bn_prime = int_to_bignum(prime) + lib.bn_mult_k(bn_x, c_uint8(k), bn_prime) + x_new = bignum_to_int(bn_x) + + assert bignum_is_normalised(bn_x) + assert number_is_partly_reduced(x_new, prime) + assert x_new == (x_old * k) % prime + + +def assert_bn_mod(x_old, prime): + bn_x = int_to_bignum(x_old) + bn_prime = int_to_bignum(prime) + lib.bn_mod(bn_x, bn_prime) + x_new = bignum_to_int(bn_x) + + assert bignum_is_normalised(bn_x) + assert number_is_fully_reduced(x_new, prime) + assert x_new == x_old % prime + + +def assert_bn_multiply_long(k_old, x_old): + bn_k = int_to_bignum(k_old) + bn_x = int_to_bignum(x_old) + bn_res = bignum(2 * limbs_number) + lib.bn_multiply_long(bn_k, bn_x, bn_res) + res = bignum_to_int(bn_res, 2 * limbs_number) + + assert res == k_old * x_old + + +def assert_bn_multiply_reduce_step(res_old, prime, d): + bn_res = int_to_bignum(res_old, 2 * limbs_number) + bn_prime = int_to_bignum(prime) + lib.bn_multiply_reduce_step(bn_res, bn_prime, d) + res_new = bignum_to_int(bn_res, 2 * limbs_number) + + assert bignum_is_normalised(bn_res) + assert res_new < 2 * prime * 2 ** (d * bits_per_limb) + + +def assert_bn_multiply(k, x_old, prime): + bn_k = int_to_bignum(k) + bn_x = int_to_bignum(x_old) + bn_prime = int_to_bignum(prime) + lib.bn_multiply(bn_k, bn_x, bn_prime) + x_new = bignum_to_int(bn_x) + + assert bignum_is_normalised(bn_x) + assert number_is_partly_reduced(x_new, prime) + assert x_new == (k * x_old) % prime + + +def assert_bn_fast_mod(x_old, prime): + bn_x = int_to_bignum(x_old) + bn_prime = int_to_bignum(prime) + lib.bn_fast_mod(bn_x, bn_prime) + x_new = bignum_to_int(bn_x) + + assert bignum_is_normalised(bn_x) + assert number_is_partly_reduced(x_new, prime) + assert x_new % prime == x_old % prime + + +def assert_bn_fast_mod_bn(bn_x, prime): + bn_x + x_old = bignum_to_int(bn_x) + bn_prime = int_to_bignum(prime) + lib.bn_fast_mod(bn_x, bn_prime) + x_new = bignum_to_int(bn_x) + + assert bignum_is_normalised(bn_x) + assert number_is_partly_reduced(x_new, prime) + assert x_new % prime == x_old % prime + + +def assert_bn_power_mod(x, e, prime): + bn_x = int_to_bignum(x) + bn_e = int_to_bignum(e) + bn_prime = int_to_bignum(prime) + bn_res_new = bignum() + lib.bn_power_mod(bn_x, bn_e, bn_prime, bn_res_new) + res_new = bignum_to_int(bn_res_new) + + assert bignum_is_normalised(bn_res_new) + assert number_is_partly_reduced(res_new, prime) + assert res_new % prime == pow(x, e, prime) + + +def assert_bn_sqrt(x_old, prime): + bn_x = int_to_bignum(x_old) + bn_prime = int_to_bignum(prime) + lib.bn_sqrt(bn_x, bn_prime) + x_new = bignum_to_int(bn_x) + + assert bignum_is_normalised(bn_x) + assert number_is_fully_reduced(x_new, prime) + assert x_new ** 2 % prime == x_old % prime + + +def assert_inverse_mod_power_two(x, m): + return_value = lib.inverse_mod_power_two(c_uint32(x), c_uint32(m)) + + assert return_value * x % 2 ** m == 1 + + +def assert_bn_divide_base(x_old, prime): + bn_x = int_to_bignum(x_old) + bn_prime = int_to_bignum(prime) + lib.bn_divide_base(bn_x, bn_prime) + x_new = bignum_to_int(bn_x) + + assert implication( + number_is_fully_reduced(x_old, prime), number_is_fully_reduced(x_new, prime) + ) + assert implication( + number_is_partly_reduced(x_old, prime), number_is_partly_reduced(x_new, prime) + ) + assert x_new * 2 ** bits_per_limb % prime == x_old % prime + + +def assert_bn_inverse(x_old, prime): + bn_x = int_to_bignum(x_old) + bn_prime = int_to_bignum(prime) + lib.bn_inverse(bn_x, bn_prime) + x_new = bignum_to_int(bn_x) + + assert bignum_is_normalised(bn_x) + assert number_is_fully_reduced(x_new, prime) + assert (x_old == 0 and x_new == 0) or (x_old != 0 and (x_old * x_new) % prime == 1) + + +def assert_bn_normalize(bn_x): + x_old = bignum_to_int(bn_x) + lib.bn_normalize(bn_x) + x_new = bignum_to_int(bn_x) + + assert x_new == x_old % 2 ** (bits_per_limb * limbs_number) + assert bignum_is_normalised(bn_x) + + +def assert_bn_add(x_old, y): + bn_x = int_to_bignum(x_old) + bn_y = int_to_bignum(y) + lib.bn_add(bn_x, bn_y) + x_new = bignum_to_int(bn_x) + y = bignum_to_int(bn_y) + + assert bignum_is_normalised(bn_x) + assert x_new == x_old + y + + +def assert_bn_addmod(x_old, y, prime): + bn_x = int_to_bignum(x_old) + bn_y = int_to_bignum(y) + bn_prime = int_to_bignum(prime) + lib.bn_addmod(bn_x, bn_y, bn_prime) + x_new = bignum_to_int(bn_x) + + assert bignum_is_normalised(bn_x) + assert number_is_partly_reduced(x_new, prime) + assert x_new % prime == (x_old + y) % prime + + +def assert_bn_addi(x_old, y): + bn_x = int_to_bignum(x_old) + lib.bn_addi(bn_x, c_uint32(y)) + x_new = bignum_to_int(bn_x) + + assert bignum_is_normalised(bn_x) + assert x_new == x_old + y + + +def assert_bn_subi(x_old, y, prime): + bn_x = int_to_bignum(x_old) + bn_prime = int_to_bignum(prime) + lib.bn_subi(bn_x, c_uint32(y), bn_prime) + x_new = bignum_to_int(bn_x) + + assert bignum_is_normalised(bn_x) + assert implication( + number_is_fully_reduced(x_old, prime), number_is_partly_reduced(x_new, prime) + ) + assert x_new % prime == (x_old - y) % prime + + +def assert_bn_subtractmod(x, y, prime): + bn_x = int_to_bignum(x) + bn_y = int_to_bignum(y) + bn_prime = int_to_bignum(prime) + bn_res = bignum() + lib.bn_subtractmod(bn_x, bn_y, bn_res, bn_prime) + res = bignum_to_int(bn_res) + + assert bignum_is_normalised(bn_x) + assert res % prime == (x - y) % prime + + +def assert_bn_subtract(x, y): + bn_x = int_to_bignum(x) + bn_y = int_to_bignum(y) + bn_res = bignum() + lib.bn_subtract(bn_x, bn_y, bn_res) + res = bignum_to_int(bn_res) + + assert bignum_is_normalised(bn_x) + assert res == x - y + + +def assert_bn_long_division(x, d): + bn_x = int_to_bignum(x) + bn_q = bignum() + uint32_p_r = uint32_p() + lib.bn_long_division(bn_x, d, bn_q, uint32_p_r) + r = uint32_p_to_int(uint32_p_r) + q = bignum_to_int(bn_q) + + assert bignum_is_normalised(bn_q) + assert q == x // d + assert r == x % d + + +def assert_bn_divmod58(x_old): + bn_x = int_to_bignum(x_old) + uint32_p_r = uint32_p() + lib.bn_divmod58(bn_x, uint32_p_r) + x_new = bignum_to_int(bn_x) + r = uint32_p_to_int(uint32_p_r) + + assert bignum_is_normalised(bn_x) + assert x_new == x_old // 58 + assert r == x_old % 58 + + +def assert_bn_divmod1000(x_old): + bn_x = int_to_bignum(x_old) + uint32_p_r = uint32_p() + lib.bn_divmod1000(bn_x, uint32_p_r) + x_new = bignum_to_int(bn_x) + r = uint32_p_to_int(uint32_p_r) + + assert bignum_is_normalised(bn_x) + assert x_new == x_old // 1000 + assert r == x_old % 1000 + + +def assert_bn_divmod10(x_old): + bn_x = int_to_bignum(x_old) + uint32_p_r = uint32_p() + lib.bn_divmod10(bn_x, uint32_p_r) + x_new = bignum_to_int(bn_x) + r = uint32_p_to_int(uint32_p_r) + + assert bignum_is_normalised(bn_x) + assert x_new == x_old // 10 + assert r == x_old % 10 + + +def assert_bn_format(x, prefix, suffix, decimals, exponent, trailing): + def format(amount, prefix, suffix, decimals, exponent, trailing): + if exponent >= 0: + amount *= 10 ** exponent + else: + amount //= 10 ** (-exponent) + + d = pow(10, decimals) + + if decimals: + output = "%d.%0*d" % (amount // d, decimals, amount % d) + if not trailing: + output = output.rstrip("0").rstrip(".") + else: + output = "%d" % (amount // d) + + return prefix + output + suffix + + def string_to_char_p(string): + return ctypes.create_string_buffer(string.encode("ascii")) + + def char_p_to_string(pointer): + return str(pointer.value, "ascii") + + bn_x = int_to_bignum(x) + output_length = 100 + output = string_to_char_p("?" * output_length) + return_value = lib.bn_format( + bn_x, + string_to_char_p(prefix), + string_to_char_p(suffix), + c_uint(decimals), + c_int(exponent), + c_bool(trailing), + output, + c_size_t(output_length), + ) + + correct_output = format(x, prefix, suffix, decimals, exponent, trailing) + correct_return_value = len(correct_output) + if len(correct_output) >= output_length: + correct_output = "" + correct_return_value = 0 + + assert char_p_to_string(output) == correct_output + assert return_value == correct_return_value + + +def test_bn_read_be(r): + assert_bn_read_be(r.rand_int_256()) + + +def test_bn_read_le(r): + assert_bn_read_le(r.rand_int_256()) + + +def test_bn_write_be(r): + assert_bn_write_be(r.rand_int_256()) + + +def test_bn_write_le(r): + assert_bn_write_le(r.rand_int_256()) + + +def test_bn_read_uint32(r): + assert_bn_read_uint32(r.rand_int_bitsize(32)) + + +def test_bn_read_uint64(r): + assert_bn_read_uint64(r.rand_int_bitsize(64)) + + +def test_bn_bitcount_1(r): + assert_bn_bitcount(r.rand_int_normalized()) + + +def test_bn_bitcount_2(bignum_bit_index): + assert_bn_bitcount(2 ** bignum_bit_index - 1) + assert_bn_bitcount(2 ** bignum_bit_index) + + +def test_bn_digitcount_1(r): + assert_bn_digitcount(r.rand_int_normalized()) + + +def test_bn_digitcount_2(bignum_decimal_digit_index): + assert_bn_digitcount(10 ** bignum_decimal_digit_index - 1) + assert_bn_digitcount(10 ** bignum_decimal_digit_index) + + +def test_bn_zero(): + assert_bn_zero() + + +def test_bn_one(): + assert_bn_one() + + +def test_bn_is_zero_1(): + assert_bn_is_zero(0) + assert_bn_is_zero(1) + + +def test_bn_is_zero_2(bignum_bit_index): + assert_bn_is_zero(2 ** bignum_bit_index) + + +def test_bn_is_one_1(): + assert_bn_is_one(0) + assert_bn_is_one(1) + + +def test_bn_is_one_2(bignum_bit_index): + assert_bn_is_one(2 ** bignum_bit_index) + + +def test_bn_is_less_1(r): + a = r.rand_int_normalized() + b = r.rand_int_normalized() + assert_bn_is_less(a, a) + assert_bn_is_less(a, b) + assert_bn_is_less(b, a) + + +def test_bn_is_less_2(r): + a = r.rand_int_normalized() + i = r.rand_bit_index() + b = a ^ 2 ** i + assert_bn_is_less(a, b) + + +def test_bn_is_less_3(): + assert_bn_is_less(0, 0) + assert_bn_is_less(1, 0) + assert_bn_is_less(0, 1) + assert_bn_is_less(1, 1) + + +def test_bn_is_equal_1(r): + a = r.rand_int_normalized() + b = r.rand_int_normalized() + assert_bn_is_equal(a, a) + assert_bn_is_equal(a, b) + + +def test_bn_is_equal_2(): + assert_bn_is_equal(0, 0) + assert_bn_is_equal(1, 0) + assert_bn_is_equal(0, 1) + assert_bn_is_equal(1, 1) + + +def test_bn_cmov(r): + a = r.rand_int_normalized() + b = r.rand_int_normalized() + assert_bn_cmov(0, a, b) + assert_bn_cmov(1, a, b) + + +def test_bn_cnegate(r, prime): + a = r.rand_int_reduced(prime) + assert_bn_cnegate(0, a, prime) + assert_bn_cnegate(1, a, prime) + + +def test_bn_lshift(r): + assert_bn_lshift(r.rand_int_normalized() // 2) + + +def test_bn_rshift(r): + assert_bn_rshift(r.rand_int_normalized()) + + +def test_bn_testbit(r): + assert_bn_testbit(r.rand_int_normalized(), r.rand_bit_index()) + + +def test_bn_setbit(r): + assert_bn_setbit(r.rand_int_normalized(), r.rand_bit_index()) + + +def test_bn_clearbit(r): + assert_bn_clearbit(r.rand_int_normalized(), r.rand_bit_index()) + + +def test_bn_xor(r): + assert_bn_xor(r.rand_int_normalized(), r.rand_int_normalized()) + + +def test_bn_mult_half_1(r, prime): + assert_bn_mult_half(r.rand_int_reduced(prime), prime) + + +def test_bn_mult_half_2(r, prime): + assert_bn_mult_half(r.rand_int_normalized(), prime) + + +def test_bn_mult_k(r, prime): + assert_bn_mult_k(r.rand_int_normalized(), r.randrange(9), prime) + + +def test_bn_mod_1(r, prime): + assert_bn_mod(r.rand_int_reduced(prime), prime) + + +def test_bn_mod_2(r, prime): + for x in [ + 0, + 1, + 2, + prime - 2, + prime - 1, + prime, + prime + 1, + prime + 2, + 2 * prime - 2, + 2 * prime - 1, + ]: + assert_bn_mod(x, prime) + + +def test_bn_multiply_long(r, prime): + x = r.randrange(floor(sqrt(2 ** 519))) + k = r.randrange(floor(sqrt(2 ** 519))) + assert_bn_multiply_long(k, x) + + +def test_bn_multiply_reduce_step(r, prime): + k = r.randrange(0, limbs_number) + res = r.randrange(2 ** (256 + 29 * k + 31)) + assert_bn_multiply_reduce_step(res, prime, k) + + +def test_bn_multiply(r, prime): + x = r.randrange(floor(sqrt(2 ** 519))) + k = r.randrange(floor(sqrt(2 ** 519))) + assert_bn_multiply(k, x, prime) + + +def test_bn_fast_mod_1(r, prime): + assert_bn_fast_mod(r.rand_int_normalized(), prime) + + +def test_bn_fast_mod_2(r, prime): + bn_x = r.rand_bignum() + assert_bn_fast_mod_bn(bn_x, prime) + + +def test_bn_power_mod(r, prime): + x = r.rand_int_bitsize(259) + e = r.rand_int_normalized() + assert_bn_power_mod(x, e, prime) + + +def test_bn_sqrt_1(prime): + assert_bn_sqrt(0, prime) + assert_bn_sqrt(1, prime) + + +def test_bn_sqrt_2(r, prime): + def is_quadratic_residuum(x, p): + return pow(x, (p - 1) // 2, p) == 1 + + while True: + x = r.rand_int_bitsize(259) + if is_quadratic_residuum(x, prime): + break + + assert_bn_sqrt(x, prime) + + +def test_inverse_mod_power_two(r): + m = r.randrange(1, 33) + i = r.randrange(1, 2 ** 29, 2) + assert_inverse_mod_power_two(i, m) + + +def test_bn_divide_base(r, prime): + assert_bn_divide_base(r.rand_int_256(), prime) + + +def test_bn_inverse_1(prime): + assert_bn_inverse(0, prime) + assert_bn_inverse(1, prime) + + +def test_bn_inverse_2(r, prime): + from math import gcd + + while True: + n = r.randrange(0, prime) + if gcd(n, prime) == 1: + break + + assert_bn_inverse(n, prime) + + +def test_bn_normalize(r): + assert_bn_normalize(r.rand_bignum()) + + +def test_bn_add_1(r): + assert_bn_add(r.rand_int_256(), r.rand_int_256()) + + +def test_bn_add_2(r): + while True: + a = r.rand_int_normalized() + b = r.rand_int_normalized() + if a + b < 2 ** (limbs_number * bits_per_limb): + break + assert_bn_add(a, b) + + +def test_bn_add_3(): + a = Random().rand_int_normalized() + b = 2 ** (limbs_number * bits_per_limb) - 1 - a + assert_bn_add(a, b) + + +def test_bn_addmod(r, prime): + assert_bn_addmod(r.rand_int_normalized(), r.rand_int_normalized(), prime) + + +def test_bn_addi_1(r): + while True: + a = r.rand_int_normalized() + b = r.randrange(2 ** 32 - 2 ** bits_per_limb + 1) + if a + b < 2 ** (limbs_number * bits_per_limb): + break + assert_bn_addi(a, b) + + +def test_bn_addi_2(): + b = 2 ** 32 - 2 ** bits_per_limb + a = 2 ** (limbs_number * bits_per_limb) - 1 - b + assert_bn_addi(a, b) + + +def test_bn_subi_1(r, prime): + while True: + a = r.rand_int_normalized() + b = r.randrange(prime % 2 ** bits_per_limb) + if a + prime - b < 2 ** (limbs_number * bits_per_limb): + break + assert_bn_subi(a, b, prime) + + +def test_bn_subi_2(prime): + b = (prime % 2 ** bits_per_limb) - 1 + a = 2 ** (limbs_number * bits_per_limb) - 1 - prime + b + assert_bn_subi(a, b, prime) + + +def test_bn_subtractmod_1(r, prime): + assert_bn_subtractmod(r.rand_int_256(), r.rand_int_256(), prime) + + +def test_bn_subtractmod_2(r, prime): + while True: + a = r.rand_int_normalized() + b = r.rand_int_reduced(prime) + if a + 2 * prime - b < 2 ** (limbs_number * bits_per_limb): + break + assert_bn_subtractmod(a, b, prime) + + +def test_bn_subtractmod_3(prime): + b = 2 * prime - 1 + a = 2 ** (limbs_number * bits_per_limb) - 1 - (2 * prime - b) + assert_bn_subtractmod(a, b, prime) + + +def test_bn_subtract_1(r): + a = r.rand_int_256() + b = r.rand_int_256() + if a < b: + a, b = b, a + assert_bn_subtract(a, b) + + +def test_bn_subtract_2(r): + a = r.rand_int_normalized() + b = r.rand_int_normalized() + if a < b: + a, b = b, a + assert_bn_subtract(a, b) + + +def test_bn_long_division(r): + x = r.rand_int_normalized() + d = r.randrange(1, 61304 + 1) + assert_bn_long_division(x, d) + + +def test_bn_divmod58(r): + x = r.rand_int_normalized() + assert_bn_divmod58(x) + + +def test_bn_divmod1000(r): + x = r.rand_int_normalized() + assert_bn_divmod1000(x) + + +def test_bn_divmod10(r): + x = r.rand_int_normalized() + assert_bn_divmod10(x) + + +@pytest.mark.parametrize( + "decimals,exponent,trailing,prefix,suffix,value", + itertools.product( + range(0, 5), + range(-5, 5), + [True, False], + ["", "prefix"], + ["", "suffix"], + [123, 120], + ), +) +def test_bn_format(decimals, exponent, trailing, prefix, suffix, value): + assert_bn_format(value, prefix, suffix, decimals, exponent, trailing) diff --git a/deps/crypto/trezor-crypto/tests/test_check.c b/deps/crypto/trezor-crypto/tests/test_check.c new file mode 100644 index 000000000..6192b6342 --- /dev/null +++ b/deps/crypto/trezor-crypto/tests/test_check.c @@ -0,0 +1,9514 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "check_mem.h" + +#if VALGRIND +#include +#include +#endif + +#include "options.h" + +#include "address.h" +#include "aes/aes.h" +#include "base32.h" +#include "base58.h" +#include "bignum.h" +#include "bip32.h" +#include "bip39.h" +#include "blake256.h" +#include "blake2b.h" +#include "blake2s.h" +#include "chacha_drbg.h" +#include "curves.h" +#include "ecdsa.h" +#include "ed25519-donna/ed25519-donna.h" +#include "ed25519-donna/ed25519-keccak.h" +#include "ed25519-donna/ed25519.h" +#include "hmac_drbg.h" +#include "memzero.h" +#include "monero/monero.h" +#include "nem.h" +#include "nist256p1.h" +#include "pbkdf2.h" +#include "rand.h" +#include "rc4.h" +#include "rfc6979.h" +#include "schnorr.h" +#include "script.h" +#include "secp256k1.h" +#include "sha2.h" +#include "sha3.h" +#include "shamir.h" +#include "slip39.h" +#include "slip39_wordlist.h" + +#if VALGRIND +/* + * This is a clever trick to make Valgrind's Memcheck verify code + * is constant-time with respect to secret data. + */ + +/* Call after secret data is written, before first use */ +#define MARK_SECRET_DATA(addr, len) VALGRIND_MAKE_MEM_UNDEFINED(addr, len) +/* Call before secret data is freed or to mark non-secret data (public keys or + * signatures) */ +#define UNMARK_SECRET_DATA(addr, len) VALGRIND_MAKE_MEM_DEFINED(addr, len) +#else +#define MARK_SECRET_DATA(addr, len) +#define UNMARK_SECRET_DATA(addr, len) +#endif + +#define FROMHEX_MAXLEN 512 + +#define VERSION_PUBLIC 0x0488b21e +#define VERSION_PRIVATE 0x0488ade4 + +#define DECRED_VERSION_PUBLIC 0x02fda926 +#define DECRED_VERSION_PRIVATE 0x02fda4e8 + +const uint8_t *fromhex(const char *str) { + static uint8_t buf[FROMHEX_MAXLEN]; + size_t len = strlen(str) / 2; + if (len > FROMHEX_MAXLEN) len = FROMHEX_MAXLEN; + for (size_t i = 0; i < len; i++) { + uint8_t c = 0; + if (str[i * 2] >= '0' && str[i * 2] <= '9') c += (str[i * 2] - '0') << 4; + if ((str[i * 2] & ~0x20) >= 'A' && (str[i * 2] & ~0x20) <= 'F') + c += (10 + (str[i * 2] & ~0x20) - 'A') << 4; + if (str[i * 2 + 1] >= '0' && str[i * 2 + 1] <= '9') + c += (str[i * 2 + 1] - '0'); + if ((str[i * 2 + 1] & ~0x20) >= 'A' && (str[i * 2 + 1] & ~0x20) <= 'F') + c += (10 + (str[i * 2 + 1] & ~0x20) - 'A'); + buf[i] = c; + } + return buf; +} + +void nem_private_key(const char *reversed_hex, ed25519_secret_key private_key) { + const uint8_t *reversed_key = fromhex(reversed_hex); + for (size_t j = 0; j < sizeof(ed25519_secret_key); j++) { + private_key[j] = reversed_key[sizeof(ed25519_secret_key) - j - 1]; + } +} + +START_TEST(test_bignum_read_be) { + bignum256 a; + uint8_t input[32]; + + memcpy( + input, + fromhex( + "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), + 32); + + bn_read_be(input, &a); + + bignum256 b = {{0x086d8bd5, 0x1018f82f, 0x11a8bb07, 0x0bc3f7af, 0x0437cd3b, + 0x14087f0a, 0x15498fe5, 0x10b161bb, 0xc55ece}}; + + for (int i = 0; i < 9; i++) { + ck_assert_uint_eq(a.val[i], b.val[i]); + } +} +END_TEST + +START_TEST(test_bignum_write_be) { + bignum256 a = {{0x086d8bd5, 0x1018f82f, 0x11a8bb07, 0x0bc3f7af, 0x0437cd3b, + 0x14087f0a, 0x15498fe5, 0x10b161bb, 0xc55ece}}; + uint8_t tmp[32]; + + bn_write_be(&a, tmp); + + ck_assert_mem_eq( + tmp, + fromhex( + "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), + 32); +} +END_TEST + +START_TEST(test_bignum_is_equal) { + bignum256 a = {{0x086d8bd5, 0x1018f82f, 0x11a8bb07, 0x0bc3f7af, 0x0437cd3b, + 0x14087f0a, 0x15498fe5, 0x10b161bb, 0xc55ece}}; + bignum256 b = {{0x086d8bd5, 0x1018f82f, 0x11a8bb07, 0x0bc3f7af, 0x0437cd3b, + 0x14087f0a, 0x15498fe5, 0x10b161bb, 0xc55ece}}; + bignum256 c = {{ + 0, + }}; + + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + ck_assert_int_eq(bn_is_equal(&c, &c), 1); + ck_assert_int_eq(bn_is_equal(&a, &c), 0); +} +END_TEST + +START_TEST(test_bignum_zero) { + bignum256 a; + bignum256 b; + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + &a); + bn_zero(&b); + + ck_assert_int_eq(bn_is_equal(&a, &b), 1); +} +END_TEST + +START_TEST(test_bignum_is_zero) { + bignum256 a; + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + &a); + ck_assert_int_eq(bn_is_zero(&a), 1); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000001"), + &a); + ck_assert_int_eq(bn_is_zero(&a), 0); + + bn_read_be( + fromhex( + "1000000000000000000000000000000000000000000000000000000000000000"), + &a); + ck_assert_int_eq(bn_is_zero(&a), 0); + + bn_read_be( + fromhex( + "f000000000000000000000000000000000000000000000000000000000000000"), + &a); + ck_assert_int_eq(bn_is_zero(&a), 0); +} +END_TEST + +START_TEST(test_bignum_one) { + bignum256 a; + bignum256 b; + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000001"), + &a); + bn_one(&b); + + ck_assert_int_eq(bn_is_equal(&a, &b), 1); +} +END_TEST + +START_TEST(test_bignum_read_le) { + bignum256 a; + bignum256 b; + + bn_read_be( + fromhex( + "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), + &a); + bn_read_le( + fromhex( + "d58b6de8051f031eeca2c6d7fbe1b5d37c4314fe1068f96352dd0d8b85ce5ec5"), + &b); + + ck_assert_int_eq(bn_is_equal(&a, &b), 1); +} +END_TEST + +START_TEST(test_bignum_write_le) { + bignum256 a; + bignum256 b; + uint8_t tmp[32]; + + bn_read_be( + fromhex( + "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), + &a); + bn_write_le(&a, tmp); + + bn_read_le(tmp, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + + bn_read_be( + fromhex( + "d58b6de8051f031eeca2c6d7fbe1b5d37c4314fe1068f96352dd0d8b85ce5ec5"), + &a); + bn_read_be(tmp, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); +} +END_TEST + +START_TEST(test_bignum_read_uint32) { + bignum256 a; + bignum256 b; + + // lowest 30 bits set + bn_read_be( + fromhex( + "000000000000000000000000000000000000000000000000000000003fffffff"), + &a); + bn_read_uint32(0x3fffffff, &b); + + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + + // bit 31 set + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000040000000"), + &a); + bn_read_uint32(0x40000000, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); +} +END_TEST + +START_TEST(test_bignum_read_uint64) { + bignum256 a; + bignum256 b; + + // lowest 30 bits set + bn_read_be( + fromhex( + "000000000000000000000000000000000000000000000000000000003fffffff"), + &a); + bn_read_uint64(0x3fffffff, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + + // bit 31 set + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000040000000"), + &a); + bn_read_uint64(0x40000000, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + + // bit 33 set + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000100000000"), + &a); + bn_read_uint64(0x100000000LL, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + + // bit 61 set + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000002000000000000000"), + &a); + bn_read_uint64(0x2000000000000000LL, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + + // all 64 bits set + bn_read_be( + fromhex( + "000000000000000000000000000000000000000000000000ffffffffffffffff"), + &a); + bn_read_uint64(0xffffffffffffffffLL, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); +} +END_TEST + +START_TEST(test_bignum_write_uint32) { + bignum256 a; + + // lowest 29 bits set + bn_read_be( + fromhex( + "000000000000000000000000000000000000000000000000000000001fffffff"), + &a); + ck_assert_uint_eq(bn_write_uint32(&a), 0x1fffffff); + + // lowest 30 bits set + bn_read_be( + fromhex( + "000000000000000000000000000000000000000000000000000000003fffffff"), + &a); + ck_assert_uint_eq(bn_write_uint32(&a), 0x3fffffff); + + // bit 31 set + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000040000000"), + &a); + ck_assert_uint_eq(bn_write_uint32(&a), 0x40000000); +} +END_TEST + +START_TEST(test_bignum_write_uint64) { + bignum256 a; + + // lowest 30 bits set + bn_read_be( + fromhex( + "000000000000000000000000000000000000000000000000000000003fffffff"), + &a); + ck_assert_uint_eq(bn_write_uint64(&a), 0x3fffffff); + + // bit 31 set + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000040000000"), + &a); + ck_assert_uint_eq(bn_write_uint64(&a), 0x40000000); + + // bit 33 set + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000100000000"), + &a); + ck_assert_uint_eq(bn_write_uint64(&a), 0x100000000LL); + + // bit 61 set + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000002000000000000000"), + &a); + ck_assert_uint_eq(bn_write_uint64(&a), 0x2000000000000000LL); + + // all 64 bits set + bn_read_be( + fromhex( + "000000000000000000000000000000000000000000000000ffffffffffffffff"), + &a); + ck_assert_uint_eq(bn_write_uint64(&a), 0xffffffffffffffffLL); +} +END_TEST + +START_TEST(test_bignum_copy) { + bignum256 a; + bignum256 b; + + bn_read_be( + fromhex( + "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), + &a); + bn_copy(&a, &b); + + ck_assert_int_eq(bn_is_equal(&a, &b), 1); +} +END_TEST + +START_TEST(test_bignum_is_even) { + bignum256 a; + + bn_read_be( + fromhex( + "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), + &a); + ck_assert_int_eq(bn_is_even(&a), 0); + + bn_read_be( + fromhex( + "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd2"), + &a); + ck_assert_int_eq(bn_is_even(&a), 1); + + bn_read_be( + fromhex( + "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd0"), + &a); + ck_assert_int_eq(bn_is_even(&a), 1); +} +END_TEST + +START_TEST(test_bignum_is_odd) { + bignum256 a; + + bn_read_be( + fromhex( + "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), + &a); + ck_assert_int_eq(bn_is_odd(&a), 1); + + bn_read_be( + fromhex( + "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd2"), + &a); + ck_assert_int_eq(bn_is_odd(&a), 0); + + bn_read_be( + fromhex( + "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd0"), + &a); + ck_assert_int_eq(bn_is_odd(&a), 0); +} +END_TEST + +START_TEST(test_bignum_is_less) { + bignum256 a; + bignum256 b; + + bn_read_uint32(0x1234, &a); + bn_read_uint32(0x8765, &b); + + ck_assert_int_eq(bn_is_less(&a, &b), 1); + ck_assert_int_eq(bn_is_less(&b, &a), 0); + + bn_zero(&a); + bn_read_be( + fromhex( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + &b); + + ck_assert_int_eq(bn_is_less(&a, &b), 1); + ck_assert_int_eq(bn_is_less(&b, &a), 0); +} +END_TEST + +START_TEST(test_bignum_bitcount) { + bignum256 a, b; + + bn_zero(&a); + ck_assert_int_eq(bn_bitcount(&a), 0); + + bn_one(&a); + ck_assert_int_eq(bn_bitcount(&a), 1); + + // test for 10000 and 11111 when i=5 + for (int i = 2; i <= 256; i++) { + bn_one(&a); + bn_one(&b); + for (int j = 2; j <= i; j++) { + bn_lshift(&a); + bn_lshift(&b); + bn_addi(&b, 1); + } + ck_assert_int_eq(bn_bitcount(&a), i); + ck_assert_int_eq(bn_bitcount(&b), i); + } + + bn_read_uint32(0x3fffffff, &a); + ck_assert_int_eq(bn_bitcount(&a), 30); + + bn_read_uint32(0xffffffff, &a); + ck_assert_int_eq(bn_bitcount(&a), 32); + + bn_read_be( + fromhex( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + &a); + ck_assert_int_eq(bn_bitcount(&a), 256); +} +END_TEST + +START_TEST(test_bignum_digitcount) { + bignum256 a; + + bn_zero(&a); + ck_assert_int_eq(bn_digitcount(&a), 1); + + // test for (10^i) and (10^i) - 1 + uint64_t m = 1; + for (int i = 0; i <= 19; i++, m *= 10) { + bn_read_uint64(m, &a); + ck_assert_int_eq(bn_digitcount(&a), i + 1); + + uint64_t n = m - 1; + bn_read_uint64(n, &a); + ck_assert_int_eq(bn_digitcount(&a), n == 0 ? 1 : i); + } + + bn_read_uint32(0x3fffffff, &a); + ck_assert_int_eq(bn_digitcount(&a), 10); + + bn_read_uint32(0xffffffff, &a); + ck_assert_int_eq(bn_digitcount(&a), 10); + + bn_read_be( + fromhex( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + &a); + ck_assert_int_eq(bn_digitcount(&a), 78); +} +END_TEST + +START_TEST(test_bignum_format_uint64) { + char buf[128], str[128]; + size_t r; + // test for (10^i) and (10^i) - 1 + uint64_t m = 1; + for (int i = 0; i <= 19; i++, m *= 10) { + sprintf(str, "%" PRIu64, m); + r = bn_format_uint64(m, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, strlen(str)); + ck_assert_str_eq(buf, str); + + uint64_t n = m - 1; + sprintf(str, "%" PRIu64, n); + r = bn_format_uint64(n, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, strlen(str)); + ck_assert_str_eq(buf, str); + } +} +END_TEST + +START_TEST(test_bignum_format) { + bignum256 a; + char buf[128]; + size_t r; + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 1); + ck_assert_str_eq(buf, "0"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + &a); + r = bn_format(&a, NULL, NULL, 20, 0, true, buf, sizeof(buf)); + ck_assert_uint_eq(r, 22); + ck_assert_str_eq(buf, "0.00000000000000000000"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + &a); + r = bn_format(&a, NULL, NULL, 0, 5, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 1); + ck_assert_str_eq(buf, "0"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + &a); + r = bn_format(&a, NULL, NULL, 0, -5, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 1); + ck_assert_str_eq(buf, "0"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + &a); + r = bn_format(&a, "", "", 0, 0, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 1); + ck_assert_str_eq(buf, "0"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + &a); + r = bn_format(&a, NULL, "SFFX", 0, 0, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 1 + 4); + ck_assert_str_eq(buf, "0SFFX"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + &a); + r = bn_format(&a, "PRFX", NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 4 + 1); + ck_assert_str_eq(buf, "PRFX0"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + &a); + r = bn_format(&a, "PRFX", "SFFX", 0, 0, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 4 + 1 + 4); + ck_assert_str_eq(buf, "PRFX0SFFX"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + &a); + r = bn_format(&a, NULL, NULL, 18, 0, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 1); + ck_assert_str_eq(buf, "0"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000001"), + &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 1); + ck_assert_str_eq(buf, "1"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000001"), + &a); + r = bn_format(&a, NULL, NULL, 6, 6, true, buf, sizeof(buf)); + ck_assert_uint_eq(r, 8); + ck_assert_str_eq(buf, "1.000000"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000002"), + &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 1); + ck_assert_str_eq(buf, "2"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000005"), + &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 1); + ck_assert_str_eq(buf, "5"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000009"), + &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 1); + ck_assert_str_eq(buf, "9"); + + bn_read_be( + fromhex( + "000000000000000000000000000000000000000000000000000000000000000a"), + &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 2); + ck_assert_str_eq(buf, "10"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000014"), + &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 2); + ck_assert_str_eq(buf, "20"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000032"), + &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 2); + ck_assert_str_eq(buf, "50"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000063"), + &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 2); + ck_assert_str_eq(buf, "99"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000000064"), + &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 3); + ck_assert_str_eq(buf, "100"); + + bn_read_be( + fromhex( + "00000000000000000000000000000000000000000000000000000000000000c8"), + &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 3); + ck_assert_str_eq(buf, "200"); + + bn_read_be( + fromhex( + "00000000000000000000000000000000000000000000000000000000000001f4"), + &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 3); + ck_assert_str_eq(buf, "500"); + + bn_read_be( + fromhex( + "00000000000000000000000000000000000000000000000000000000000003e7"), + &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 3); + ck_assert_str_eq(buf, "999"); + + bn_read_be( + fromhex( + "00000000000000000000000000000000000000000000000000000000000003e8"), + &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 4); + ck_assert_str_eq(buf, "1000"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000000000000989680"), + &a); + r = bn_format(&a, NULL, NULL, 7, 0, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 1); + ck_assert_str_eq(buf, "1"); + + bn_read_be( + fromhex( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + &a); + r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 78); + ck_assert_str_eq(buf, + "11579208923731619542357098500868790785326998466564056403945" + "7584007913129639935"); + + bn_read_be( + fromhex( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + &a); + r = bn_format(&a, NULL, NULL, 1, 0, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 79); + ck_assert_str_eq(buf, + "11579208923731619542357098500868790785326998466564056403945" + "758400791312963993.5"); + + bn_read_be( + fromhex( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + &a); + r = bn_format(&a, NULL, NULL, 2, 0, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 79); + ck_assert_str_eq(buf, + "11579208923731619542357098500868790785326998466564056403945" + "75840079131296399.35"); + + bn_read_be( + fromhex( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + &a); + r = bn_format(&a, NULL, NULL, 8, 0, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 79); + ck_assert_str_eq(buf, + "11579208923731619542357098500868790785326998466564056403945" + "75840079131.29639935"); + + bn_read_be( + fromhex( + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffe3bbb00"), + &a); + r = bn_format(&a, NULL, NULL, 8, 0, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 70); + ck_assert_str_eq(buf, + "11579208923731619542357098500868790785326998466564056403945" + "75840079131"); + + bn_read_be( + fromhex( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + &a); + r = bn_format(&a, NULL, NULL, 18, 0, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 79); + ck_assert_str_eq(buf, + "11579208923731619542357098500868790785326998466564056403945" + "7.584007913129639935"); + + bn_read_be( + fromhex( + "fffffffffffffffffffffffffffffffffffffffffffffffff7e52fe5afe40000"), + &a); + r = bn_format(&a, NULL, NULL, 18, 0, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 60); + ck_assert_str_eq( + buf, "115792089237316195423570985008687907853269984665640564039457"); + + bn_read_be( + fromhex( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + &a); + r = bn_format(&a, NULL, NULL, 78, 0, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 80); + ck_assert_str_eq(buf, + "0." + "11579208923731619542357098500868790785326998466564056403945" + "7584007913129639935"); + + bn_read_be( + fromhex( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + &a); + r = bn_format(&a, NULL, NULL, 0, 10, false, buf, sizeof(buf)); + ck_assert_uint_eq(r, 88); + ck_assert_str_eq(buf, + "11579208923731619542357098500868790785326998466564056403945" + "75840079131296399350000000000"); + + bn_read_be( + fromhex( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + &a); + r = bn_format(&a, "quite a long prefix", "even longer suffix", 60, 0, false, + buf, sizeof(buf)); + ck_assert_uint_eq(r, 116); + ck_assert_str_eq(buf, + "quite a long " + "prefix115792089237316195." + "42357098500868790785326998466564056403945758400791312963993" + "5even longer suffix"); + + bn_read_be( + fromhex( + "0000000000000000000000000000000000000000000000000123456789abcdef"), + &a); + memset(buf, 'a', sizeof(buf)); + r = bn_format(&a, "prefix", "suffix", 10, 0, false, buf, 31); + ck_assert_str_eq(buf, "prefix8198552.9216486895suffix"); + ck_assert_uint_eq(r, 30); + + memset(buf, 'a', sizeof(buf)); + r = bn_format(&a, "prefix", "suffix", 10, 0, false, buf, 30); + ck_assert_uint_eq(r, 0); + ck_assert_str_eq(buf, ""); +} +END_TEST + +START_TEST(test_bignum_sqrt) { + uint32_t quadratic_residua[] = { + 1, 2, 4, 8, 9, 11, 15, 16, 17, 18, 19, 21, 22, 25, 29, + 30, 31, 32, 34, 35, 36, 38, 39, 42, 43, 44, 47, 49, 50, 58, + 59, 60, 61, 62, 64, 65, 67, 68, 69, 70, 71, 72, 76, 78, 81, + 83, 84, 86, 88, 91, 94, 98, 99, 100, 103, 107, 111, 115, 116, 118, + 120, 121, 122, 123, 124, 127, 128, 130, 131, 134, 135, 136, 137, 138, 139, + 140, 142, 144, 149, 152, 153, 156, 159, 161, 162, 165, 166, 167, 168, 169, + 171, 172, 176, 181, 182, 185, 187, 188, 189, 191, 193, 196, 197, 198, 200, + 205, 206, 209, 214, 219, 222, 223, 225, 229, 230, 231, 232, 233, 236, 237, + 239, 240, 242, 244, 246, 248, 254, 255, 256, 259, 260, 261, 262, 265, 267, + 268, 269, 270, 272, 274, 275, 276, 277, 278, 279, 280, 281, 284, 285, 287, + 288, 289, 291, 293, 298, 299, 303, 304, 306, 311, 312, 315, 318, 319, 322, + 323, 324, 327, 330, 331, 332, 334, 336, 337, 338, 339, 341, 342, 344, 349, + 351, 352, 353, 357, 359, 361, 362, 364, 365, 370, 371, 373, 374, 375, 376, + 378, 379, 382, 383, 385, 386, 387, 389, 392, 394, 395, 396, 399, 400, 409, + 410, 412, 418, 421, 423, 425, 428, 429, 431, 435, 438, 439, 441, 443, 444, + 445, 446, 450, 453, 458, 460, 461, 462, 463, 464, 465, 466, 467, 471, 472, + 473, 474, 475, 478, 479, 480, 481, 484, 485, 487, 488, 489, 492, 493, 496, + 503, 505, 508, 510, 511, 512, 517, 518, 519, 520, 521, 522, 523, 524, 525, + 527, 529, 530, 531, 533, 534, 536, 537, 538, 539, 540, 541, 544, 545, 547, + 548, 549, 550, 551, 552, 553, 554, 556, 557, 558, 560, 562, 563, 565, 568, + 570, 571, 574, 576, 578, 582, 585, 586, 587, 589, 595, 596, 597, 598, 599, + 603, 606, 607, 608, 609, 612, 613, 619, 621, 622, 623, 624, 625, 630, 633, + 636, 638, 639, 644, 645, 646, 648, 649, 651, 653, 654, 660, 662, 663, 664, + 665, 668, 671, 672, 673, 674, 676, 678, 679, 681, 682, 684, 688, 689, 698, + 702, 704, 705, 706, 707, 714, 715, 718, 722, 723, 724, 725, 728, 729, 730, + 731, 733, 735, 737, 740, 741, 742, 746, 747, 748, 750, 751, 752, 753, 755, + 756, 758, 759, 761, 763, 764, 766, 769, 770, 771, 772, 774, 775, 778, 781, + 784, 785, 788, 789, 790, 791, 792, 797, 798, 799, 800, 813, 815, 817, 818, + 819, 820, 823, 824, 833, 836, 841, 842, 846, 849, 850, 851, 856, 857, 858, + 862, 865, 870, 875, 876, 878, 882, 885, 886, 887, 888, 890, 891, 892, 893, + 895, 899, 900, 903, 906, 907, 911, 913, 915, 916, 919, 920, 921, 922, 924, + 926, 927, 928, 930, 931, 932, 934, 937, 939, 942, 943, 944, 946, 948, 949, + 950, 951, 953, 956, 958, 960, 961, 962, 963, 968, 970, 971, 974, 975, 976, + 977, 978, 984, 986, 987, 992, 995, 999}; + + bignum256 a, b; + + bn_zero(&a); + b = a; + bn_sqrt(&b, &secp256k1.prime); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + + bn_one(&a); + b = a; + bn_sqrt(&b, &secp256k1.prime); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + + // test some quadratic residua + for (size_t i = 0; i < sizeof(quadratic_residua) / sizeof(*quadratic_residua); + i++) { + bn_read_uint32(quadratic_residua[i], &a); + b = a; + bn_sqrt(&b, &secp256k1.prime); + bn_multiply(&b, &b, &secp256k1.prime); + bn_mod(&b, &secp256k1.prime); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + } +} +END_TEST + +// https://tools.ietf.org/html/rfc4648#section-10 +START_TEST(test_base32_rfc4648) { + static const struct { + const char *decoded; + const char *encoded; + const char *encoded_lowercase; + } tests[] = { + {"", "", ""}, + {"f", "MY", "my"}, + {"fo", "MZXQ", "mzxq"}, + {"foo", "MZXW6", "mzxw6"}, + {"foob", "MZXW6YQ", "mzxw6yq"}, + {"fooba", "MZXW6YTB", "mzxw6ytb"}, + {"foobar", "MZXW6YTBOI", "mzxw6ytboi"}, + }; + + char buffer[64]; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + const char *in = tests[i].decoded; + const char *out = tests[i].encoded; + const char *out_lowercase = tests[i].encoded_lowercase; + + size_t inlen = strlen(in); + size_t outlen = strlen(out); + + ck_assert_uint_eq(outlen, base32_encoded_length(inlen)); + ck_assert_uint_eq(inlen, base32_decoded_length(outlen)); + + ck_assert(base32_encode((uint8_t *)in, inlen, buffer, sizeof(buffer), + BASE32_ALPHABET_RFC4648) != NULL); + ck_assert_str_eq(buffer, out); + + char *ret = (char *)base32_decode(out, outlen, (uint8_t *)buffer, + sizeof(buffer), BASE32_ALPHABET_RFC4648); + ck_assert(ret != NULL); + *ret = '\0'; + ck_assert_str_eq(buffer, in); + + ret = (char *)base32_decode(out_lowercase, outlen, (uint8_t *)buffer, + sizeof(buffer), BASE32_ALPHABET_RFC4648); + ck_assert(ret != NULL); + *ret = '\0'; + ck_assert_str_eq(buffer, in); + } +} +END_TEST + +// from +// https://github.com/bitcoin/bitcoin/blob/master/src/test/data/base58_keys_valid.json +START_TEST(test_base58) { + static const char *base58_vector[] = { + "0065a16059864a2fdbc7c99a4723a8395bc6f188eb", + "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", + "0574f209f6ea907e2ea48f74fae05782ae8a665257", + "3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou", + "6f53c0307d6851aa0ce7825ba883c6bd9ad242b486", + "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", + "c46349a418fc4578d10a372b54b45c280cc8c4382f", + "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br", + "80eddbdc1168f1daeadbd3e44c1e3f8f5a284c2029f78ad26af98583a499de5b19", + "5Kd3NBUAdUnhyzenEwVLy9pBKxSwXvE9FMPyR4UKZvpe6E3AgLr", + "8055c9bccb9ed68446d1b75273bbce89d7fe013a8acd1625514420fb2aca1a21c401", + "Kz6UJmQACJmLtaQj5A3JAge4kVTNQ8gbvXuwbmCj7bsaabudb3RD", + "ef36cb93b9ab1bdabf7fb9f2c04f1b9cc879933530ae7842398eef5a63a56800c2", + "9213qJab2HNEpMpYNBa7wHGFKKbkDn24jpANDs2huN3yi4J11ko", + "efb9f4892c9e8282028fea1d2667c4dc5213564d41fc5783896a0d843fc15089f301", + "cTpB4YiyKiBcPxnefsDpbnDxFDffjqJob8wGCEDXxgQ7zQoMXJdH", + "006d23156cbbdcc82a5a47eee4c2c7c583c18b6bf4", + "1Ax4gZtb7gAit2TivwejZHYtNNLT18PUXJ", + "05fcc5460dd6e2487c7d75b1963625da0e8f4c5975", + "3QjYXhTkvuj8qPaXHTTWb5wjXhdsLAAWVy", + "6ff1d470f9b02370fdec2e6b708b08ac431bf7a5f7", + "n3ZddxzLvAY9o7184TB4c6FJasAybsw4HZ", + "c4c579342c2c4c9220205e2cdc285617040c924a0a", + "2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n", + "80a326b95ebae30164217d7a7f57d72ab2b54e3be64928a19da0210b9568d4015e", + "5K494XZwps2bGyeL71pWid4noiSNA2cfCibrvRWqcHSptoFn7rc", + "807d998b45c219a1e38e99e7cbd312ef67f77a455a9b50c730c27f02c6f730dfb401", + "L1RrrnXkcKut5DEMwtDthjwRcTTwED36thyL1DebVrKuwvohjMNi", + "efd6bca256b5abc5602ec2e1c121a08b0da2556587430bcf7e1898af2224885203", + "93DVKyFYwSN6wEo3E2fCrFPUp17FtrtNi2Lf7n4G3garFb16CRj", + "efa81ca4e8f90181ec4b61b6a7eb998af17b2cb04de8a03b504b9e34c4c61db7d901", + "cTDVKtMGVYWTHCb1AFjmVbEbWjvKpKqKgMaR3QJxToMSQAhmCeTN", + "007987ccaa53d02c8873487ef919677cd3db7a6912", + "1C5bSj1iEGUgSTbziymG7Cn18ENQuT36vv", + "0563bcc565f9e68ee0189dd5cc67f1b0e5f02f45cb", + "3AnNxabYGoTxYiTEZwFEnerUoeFXK2Zoks", + "6fef66444b5b17f14e8fae6e7e19b045a78c54fd79", + "n3LnJXCqbPjghuVs8ph9CYsAe4Sh4j97wk", + "c4c3e55fceceaa4391ed2a9677f4a4d34eacd021a0", + "2NB72XtkjpnATMggui83aEtPawyyKvnbX2o", + "80e75d936d56377f432f404aabb406601f892fd49da90eb6ac558a733c93b47252", + "5KaBW9vNtWNhc3ZEDyNCiXLPdVPHCikRxSBWwV9NrpLLa4LsXi9", + "808248bd0375f2f75d7e274ae544fb920f51784480866b102384190b1addfbaa5c01", + "L1axzbSyynNYA8mCAhzxkipKkfHtAXYF4YQnhSKcLV8YXA874fgT", + "ef44c4f6a096eac5238291a94cc24c01e3b19b8d8cef72874a079e00a242237a52", + "927CnUkUbasYtDwYwVn2j8GdTuACNnKkjZ1rpZd2yBB1CLcnXpo", + "efd1de707020a9059d6d3abaf85e17967c6555151143db13dbb06db78df0f15c6901", + "cUcfCMRjiQf85YMzzQEk9d1s5A4K7xL5SmBCLrezqXFuTVefyhY7", + "00adc1cc2081a27206fae25792f28bbc55b831549d", + "1Gqk4Tv79P91Cc1STQtU3s1W6277M2CVWu", + "05188f91a931947eddd7432d6e614387e32b244709", + "33vt8ViH5jsr115AGkW6cEmEz9MpvJSwDk", + "6f1694f5bc1a7295b600f40018a618a6ea48eeb498", + "mhaMcBxNh5cqXm4aTQ6EcVbKtfL6LGyK2H", + "c43b9b3fd7a50d4f08d1a5b0f62f644fa7115ae2f3", + "2MxgPqX1iThW3oZVk9KoFcE5M4JpiETssVN", + "80091035445ef105fa1bb125eccfb1882f3fe69592265956ade751fd095033d8d0", + "5HtH6GdcwCJA4ggWEL1B3jzBBUB8HPiBi9SBc5h9i4Wk4PSeApR", + "80ab2b4bcdfc91d34dee0ae2a8c6b6668dadaeb3a88b9859743156f462325187af01", + "L2xSYmMeVo3Zek3ZTsv9xUrXVAmrWxJ8Ua4cw8pkfbQhcEFhkXT8", + "efb4204389cef18bbe2b353623cbf93e8678fbc92a475b664ae98ed594e6cf0856", + "92xFEve1Z9N8Z641KQQS7ByCSb8kGjsDzw6fAmjHN1LZGKQXyMq", + "efe7b230133f1b5489843260236b06edca25f66adb1be455fbd38d4010d48faeef01", + "cVM65tdYu1YK37tNoAyGoJTR13VBYFva1vg9FLuPAsJijGvG6NEA", + "00c4c1b72491ede1eedaca00618407ee0b772cad0d", + "1JwMWBVLtiqtscbaRHai4pqHokhFCbtoB4", + "05f6fe69bcb548a829cce4c57bf6fff8af3a5981f9", + "3QCzvfL4ZRvmJFiWWBVwxfdaNBT8EtxB5y", + "6f261f83568a098a8638844bd7aeca039d5f2352c0", + "mizXiucXRCsEriQCHUkCqef9ph9qtPbZZ6", + "c4e930e1834a4d234702773951d627cce82fbb5d2e", + "2NEWDzHWwY5ZZp8CQWbB7ouNMLqCia6YRda", + "80d1fab7ab7385ad26872237f1eb9789aa25cc986bacc695e07ac571d6cdac8bc0", + "5KQmDryMNDcisTzRp3zEq9e4awRmJrEVU1j5vFRTKpRNYPqYrMg", + "80b0bbede33ef254e8376aceb1510253fc3550efd0fcf84dcd0c9998b288f166b301", + "L39Fy7AC2Hhj95gh3Yb2AU5YHh1mQSAHgpNixvm27poizcJyLtUi", + "ef037f4192c630f399d9271e26c575269b1d15be553ea1a7217f0cb8513cef41cb", + "91cTVUcgydqyZLgaANpf1fvL55FH53QMm4BsnCADVNYuWuqdVys", + "ef6251e205e8ad508bab5596bee086ef16cd4b239e0cc0c5d7c4e6035441e7d5de01", + "cQspfSzsgLeiJGB2u8vrAiWpCU4MxUT6JseWo2SjXy4Qbzn2fwDw", + "005eadaf9bb7121f0f192561a5a62f5e5f54210292", + "19dcawoKcZdQz365WpXWMhX6QCUpR9SY4r", + "053f210e7277c899c3a155cc1c90f4106cbddeec6e", + "37Sp6Rv3y4kVd1nQ1JV5pfqXccHNyZm1x3", + "6fc8a3c2a09a298592c3e180f02487cd91ba3400b5", + "myoqcgYiehufrsnnkqdqbp69dddVDMopJu", + "c499b31df7c9068d1481b596578ddbb4d3bd90baeb", + "2N7FuwuUuoTBrDFdrAZ9KxBmtqMLxce9i1C", + "80c7666842503db6dc6ea061f092cfb9c388448629a6fe868d068c42a488b478ae", + "5KL6zEaMtPRXZKo1bbMq7JDjjo1bJuQcsgL33je3oY8uSJCR5b4", + "8007f0803fc5399e773555ab1e8939907e9badacc17ca129e67a2f5f2ff84351dd01", + "KwV9KAfwbwt51veZWNscRTeZs9CKpojyu1MsPnaKTF5kz69H1UN2", + "efea577acfb5d1d14d3b7b195c321566f12f87d2b77ea3a53f68df7ebf8604a801", + "93N87D6uxSBzwXvpokpzg8FFmfQPmvX4xHoWQe3pLdYpbiwT5YV", + "ef0b3b34f0958d8a268193a9814da92c3e8b58b4a4378a542863e34ac289cd830c01", + "cMxXusSihaX58wpJ3tNuuUcZEQGt6DKJ1wEpxys88FFaQCYjku9h", + "001ed467017f043e91ed4c44b4e8dd674db211c4e6", + "13p1ijLwsnrcuyqcTvJXkq2ASdXqcnEBLE", + "055ece0cadddc415b1980f001785947120acdb36fc", + "3ALJH9Y951VCGcVZYAdpA3KchoP9McEj1G", + 0, + 0, + }; + const char **raw = base58_vector; + const char **str = base58_vector + 1; + uint8_t rawn[34]; + char strn[53]; + int r; + while (*raw && *str) { + int len = strlen(*raw) / 2; + + memcpy(rawn, fromhex(*raw), len); + r = base58_encode_check(rawn, len, HASHER_SHA2D, strn, sizeof(strn)); + ck_assert_int_eq((size_t)r, strlen(*str) + 1); + ck_assert_str_eq(strn, *str); + + r = base58_decode_check(strn, HASHER_SHA2D, rawn, len); + ck_assert_int_eq(r, len); + ck_assert_mem_eq(rawn, fromhex(*raw), len); + + raw += 2; + str += 2; + } +} +END_TEST + +#if USE_GRAPHENE + +// Graphene Base85CheckEncoding +START_TEST(test_base58gph) { + static const char *base58_vector[] = { + "02e649f63f8e8121345fd7f47d0d185a3ccaa843115cd2e9392dcd9b82263bc680", + "6dumtt9swxCqwdPZBGXh9YmHoEjFFnNfwHaTqRbQTghGAY2gRz", + "021c7359cd885c0e319924d97e3980206ad64387aff54908241125b3a88b55ca16", + "5725vivYpuFWbeyTifZ5KevnHyqXCi5hwHbNU9cYz1FHbFXCxX", + "02f561e0b57a552df3fa1df2d87a906b7a9fc33a83d5d15fa68a644ecb0806b49a", + "6kZKHSuxqAwdCYsMvwTcipoTsNE2jmEUNBQufGYywpniBKXWZK", + "03e7595c3e6b58f907bee951dc29796f3757307e700ecf3d09307a0cc4a564eba3", + "8b82mpnH8YX1E9RHnU2a2YgLTZ8ooevEGP9N15c1yFqhoBvJur", + 0, + 0, + }; + const char **raw = base58_vector; + const char **str = base58_vector + 1; + uint8_t rawn[34]; + char strn[53]; + int r; + while (*raw && *str) { + int len = strlen(*raw) / 2; + + memcpy(rawn, fromhex(*raw), len); + r = base58gph_encode_check(rawn, len, strn, sizeof(strn)); + ck_assert_int_eq((size_t)r, strlen(*str) + 1); + ck_assert_str_eq(strn, *str); + + r = base58gph_decode_check(strn, rawn, len); + ck_assert_int_eq(r, len); + ck_assert_mem_eq(rawn, fromhex(*raw), len); + + raw += 2; + str += 2; + } +} +END_TEST + +#endif + +START_TEST(test_bignum_divmod) { + uint32_t r; + int i; + + bignum256 a; + uint32_t ar[] = {15, 14, 55, 29, 44, 24, 53, 49, 18, 55, 2, 28, 5, 4, 12, + 43, 18, 37, 28, 14, 30, 46, 12, 11, 17, 10, 10, 13, 24, 45, + 4, 33, 44, 42, 2, 46, 34, 43, 45, 28, 21, 18, 13, 17}; + + bn_read_be( + fromhex( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + &a); + + i = 0; + while (!bn_is_zero(&a) && i < 44) { + bn_divmod58(&a, &r); + ck_assert_uint_eq(r, ar[i]); + i++; + } + ck_assert_int_eq(i, 44); + + bignum256 b; + uint32_t br[] = {935, 639, 129, 913, 7, 584, 457, 39, 564, + 640, 665, 984, 269, 853, 907, 687, 8, 985, + 570, 423, 195, 316, 237, 89, 792, 115}; + + bn_read_be( + fromhex( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + &b); + i = 0; + while (!bn_is_zero(&b) && i < 26) { + bn_divmod1000(&b, &r); + ck_assert_uint_eq(r, br[i]); + i++; + } + ck_assert_int_eq(i, 26); +} +END_TEST + +// test vector 1 from +// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vector-1 +START_TEST(test_bip32_vector_1) { + HDNode node, node2, node3; + uint32_t fingerprint; + char str[XPUB_MAXLEN]; + int r; + + // init m + hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, + SECP256K1_NAME, &node); + + // [Chain m] + fingerprint = 0; + ck_assert_uint_eq(fingerprint, 0x00000000); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2"), + 33); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqji" + "ChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"); + r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2" + "gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"); + r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd_prime(&node, 0); + ck_assert_uint_eq(fingerprint, 0x3442193e); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56"), + 33); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4" + "cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7"); + r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP" + "6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw"); + r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'/1] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd(&node, 1); + ck_assert_uint_eq(fingerprint, 0x5c1bd648); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c"), + 33); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSx" + "qu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs"); + r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFH" + "KkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ"); + r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'/1/2'] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd_prime(&node, 2); + ck_assert_uint_eq(fingerprint, 0xbef5a2f9); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2"), + 33); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptW" + "mT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM"); + r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgq" + "FJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5"); + r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'/1/2'/2] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd(&node, 2); + ck_assert_uint_eq(fingerprint, 0xee7ab90c); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "0f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29"), + 33); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Ty" + "h8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334"); + r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJ" + "AyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV"); + r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'/1/2'/2/1000000000] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd(&node, 1000000000); + ck_assert_uint_eq(fingerprint, 0xd880d7d8); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011"), + 33); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8" + "kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76"); + r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNT" + "EcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy"); + r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); +} +END_TEST + +// test vector 2 from +// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vector-2 +START_TEST(test_bip32_vector_2) { + HDNode node, node2, node3; + uint32_t fingerprint; + char str[XPUB_MAXLEN]; + int r; + + // init m + hdnode_from_seed( + fromhex( + "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c" + "999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), + 64, SECP256K1_NAME, &node); + + // [Chain m] + fingerprint = 0; + ck_assert_uint_eq(fingerprint, 0x00000000); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "60499f801b896d83179a4374aeb7822aaeaceaa0db1f85ee3e904c4defbd9689"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "4b03d6fc340455b363f51020ad3ecca4f0850280cf436c70c727923f6db46c3e"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "03cbcaa9c98c877a26977d00825c956a238e8dddfbd322cce4f74b0b5bd6ace4a7"), + 33); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGds" + "o3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U"); + r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSC" + "Gu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB"); + r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd(&node, 0); + ck_assert_int_eq(r, 1); + ck_assert_uint_eq(fingerprint, 0xbd16bee5); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "abe74a98f6c7eabee0428f53798f0ab8aa1bd37873999041703c742f15ac7e1e"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"), + 33); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT" + "3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt"); + r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGm" + "XUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH"); + r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0/2147483647'] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd_prime(&node, 2147483647); + ck_assert_int_eq(r, 1); + ck_assert_uint_eq(fingerprint, 0x5a61ff8e); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "be17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d9"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "877c779ad9687164e9c2f4f0f4ff0340814392330693ce95a58fe18fd52e6e93"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "03c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b"), + 33); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYE" + "eEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9"); + r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ" + "85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a"); + r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0/2147483647'/1] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd(&node, 1); + ck_assert_int_eq(r, 1); + ck_assert_uint_eq(fingerprint, 0xd8ab4937); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "704addf544a06e5ee4bea37098463c23613da32020d604506da8c0518e1da4b7"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9"), + 33); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd" + "25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef"); + r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5Ew" + "VvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon"); + r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0/2147483647'/1/2147483646'] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd_prime(&node, 2147483646); + ck_assert_int_eq(r, 1); + ck_assert_uint_eq(fingerprint, 0x78412e3a); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e29"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "f1c7c871a54a804afe328b4c83a1c33b8e5ff48f5087273f04efa83b247d6a2d"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "02d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0"), + 33); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz" + "7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc"); + r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJ" + "bZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL"); + r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0/2147483647'/1/2147483646'/2] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd(&node, 2); + ck_assert_int_eq(r, 1); + ck_assert_uint_eq(fingerprint, 0x31a507b8); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "9452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58eedf394ed271"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "bb7d39bdb83ecf58f2fd82b6d918341cbef428661ef01ab97c28a4842125ac23"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c"), + 33); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw" + "7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j"); + r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLF" + "bdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt"); + r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // init m + hdnode_from_seed( + fromhex( + "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c" + "999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), + 64, SECP256K1_NAME, &node); + + // test public derivation + // [Chain m/0] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_public_ckd(&node, 0); + ck_assert_int_eq(r, 1); + ck_assert_uint_eq(fingerprint, 0xbd16bee5); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"), + 33); +} +END_TEST + +// test vector 3 from +// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vector-3 +START_TEST(test_bip32_vector_3) { + HDNode node, node2, node3; + uint32_t fingerprint; + char str[XPUB_MAXLEN]; + int r; + + // init m + hdnode_from_seed( + fromhex( + "4b381541583be4423346c643850da4b320e46a87ae3d2a4e6da11eba819cd4acba45" + "d239319ac14f863b8d5ab5a0d0c64d2e8a1e7d1457df2e5a3c51c73235be"), + 64, SECP256K1_NAME, &node); + + // [Chain m] + fingerprint = 0; + ck_assert_uint_eq(fingerprint, 0x00000000); + hdnode_fill_public_key(&node); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7" + "KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6"); + r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhR" + "oP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13"); + r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd_prime(&node, 0); + ck_assert_int_eq(r, 1); + hdnode_fill_public_key(&node); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu" + "2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L"); + r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrAD" + "WgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y"); + r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); +} +END_TEST + +// test vector 4 from +// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vector-4 +START_TEST(test_bip32_vector_4) { + HDNode node, node2, node3; + uint32_t fingerprint; + char str[XPUB_MAXLEN]; + int r; + + // init m + hdnode_from_seed( + fromhex( + "3ddd5602285899a946114506157c7997e5444528f3003f6134712147db19b678"), + 32, SECP256K1_NAME, &node); + + // [Chain m] + fingerprint = 0; + ck_assert_int_eq(fingerprint, 0x00000000); + hdnode_fill_public_key(&node); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprv9s21ZrQH143K48vGoLGRPxgo2JNkJ3J3fqkirQC2zVdk5Dgd5w14S7f" + "RDyHH4dWNHUgkvsvNDCkvAwcSHNAQwhwgNMgZhLtQC63zxwhQmRv"); + r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub661MyMwAqRbcGczjuMoRm6dXaLDEhW1u34gKenbeYqAix21mdUKJyuy" + "u5F1rzYGVxyL6tmgBUAEPrEz92mBXjByMRiJdba9wpnN37RLLAXa"); + r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd_prime(&node, 0); + ck_assert_int_eq(r, 1); + hdnode_fill_public_key(&node); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprv9vB7xEWwNp9kh1wQRfCCQMnZUEG21LpbR9NPCNN1dwhiZkjjeGRnaAL" + "mPXCX7SgjFTiCTT6bXes17boXtjq3xLpcDjzEuGLQBM5ohqkao9G"); + r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub69AUMk3qDBi3uW1sXgjCmVjJ2G6WQoYSnNHyzkmdCHEhSZ4tBok37xf" + "FEqHd2AddP56Tqp4o56AePAgCjYdvpW2PU2jbUPFKsav5ut6Ch1m"); + r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'/1'] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd_prime(&node, 1); + ck_assert_int_eq(r, 1); + hdnode_fill_public_key(&node); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprv9xJocDuwtYCMNAo3Zw76WENQeAS6WGXQ55RCy7tDJ8oALr4FWkuVoHJ" + "eHVAcAqiZLE7Je3vZJHxspZdFHfnBEjHqU5hG1Jaj32dVoS6XLT1"); + r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub6BJA1jSqiukeaesWfxe6sNK9CCGaujFFSJLomWHprUL9DePQ4JDkM5d" + "88n49sMGJxrhpjazuXYWdMf17C9T5XnxkopaeS7jGk1GyyVziaMt"); + r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); +} +END_TEST + +START_TEST(test_bip32_compare) { + HDNode node1, node2, node3; + int i, r; + hdnode_from_seed( + fromhex( + "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" + "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), + 64, SECP256K1_NAME, &node1); + hdnode_from_seed( + fromhex( + "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" + "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), + 64, SECP256K1_NAME, &node2); + hdnode_fill_public_key(&node2); + for (i = 0; i < 100; i++) { + memcpy(&node3, &node1, sizeof(HDNode)); + hdnode_fill_public_key(&node3); + r = hdnode_private_ckd(&node1, i); + ck_assert_int_eq(r, 1); + r = hdnode_public_ckd(&node2, i); + ck_assert_int_eq(r, 1); + r = hdnode_public_ckd(&node3, i); + ck_assert_int_eq(r, 1); + ck_assert_uint_eq(node1.depth, node2.depth); + ck_assert_uint_eq(node1.depth, node3.depth); + ck_assert_uint_eq(node1.child_num, node2.child_num); + ck_assert_uint_eq(node1.child_num, node3.child_num); + ck_assert_mem_eq(node1.chain_code, node2.chain_code, 32); + ck_assert_mem_eq(node1.chain_code, node3.chain_code, 32); + ck_assert_mem_eq( + node2.private_key, + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + 32); + ck_assert_mem_eq( + node3.private_key, + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + 32); + hdnode_fill_public_key(&node1); + ck_assert_mem_eq(node1.public_key, node2.public_key, 33); + ck_assert_mem_eq(node1.public_key, node3.public_key, 33); + } +} +END_TEST + +START_TEST(test_bip32_optimized) { + HDNode root; + hdnode_from_seed((uint8_t *)"NothingToSeeHere", 16, SECP256K1_NAME, &root); + hdnode_fill_public_key(&root); + + curve_point pub; + ecdsa_read_pubkey(&secp256k1, root.public_key, &pub); + + HDNode node; + char addr1[MAX_ADDR_SIZE], addr2[MAX_ADDR_SIZE]; + + for (int i = 0; i < 40; i++) { + // unoptimized + memcpy(&node, &root, sizeof(HDNode)); + hdnode_public_ckd(&node, i); + hdnode_fill_public_key(&node); + ecdsa_get_address(node.public_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, + addr1, sizeof(addr1)); + // optimized + hdnode_public_ckd_address_optimized(&pub, root.chain_code, i, 0, + HASHER_SHA2_RIPEMD, HASHER_SHA2D, addr2, + sizeof(addr2), 0); + // check + ck_assert_str_eq(addr1, addr2); + } +} +END_TEST + +START_TEST(test_bip32_cache_1) { + HDNode node1, node2; + int i, r; + + // test 1 .. 8 + hdnode_from_seed( + fromhex( + "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" + "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), + 64, SECP256K1_NAME, &node1); + hdnode_from_seed( + fromhex( + "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" + "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), + 64, SECP256K1_NAME, &node2); + + uint32_t ii[] = {0x80000001, 0x80000002, 0x80000003, 0x80000004, + 0x80000005, 0x80000006, 0x80000007, 0x80000008}; + + for (i = 0; i < 8; i++) { + r = hdnode_private_ckd(&node1, ii[i]); + ck_assert_int_eq(r, 1); + } + r = hdnode_private_ckd_cached(&node2, ii, 8, NULL); + ck_assert_int_eq(r, 1); + ck_assert_mem_eq(&node1, &node2, sizeof(HDNode)); + + hdnode_from_seed( + fromhex( + "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" + "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), + 64, SECP256K1_NAME, &node1); + hdnode_from_seed( + fromhex( + "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" + "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), + 64, SECP256K1_NAME, &node2); + + // test 1 .. 7, 20 + ii[7] = 20; + for (i = 0; i < 8; i++) { + r = hdnode_private_ckd(&node1, ii[i]); + ck_assert_int_eq(r, 1); + } + r = hdnode_private_ckd_cached(&node2, ii, 8, NULL); + ck_assert_int_eq(r, 1); + ck_assert_mem_eq(&node1, &node2, sizeof(HDNode)); + + // test different root node + hdnode_from_seed( + fromhex( + "000000002ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" + "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), + 64, SECP256K1_NAME, &node1); + hdnode_from_seed( + fromhex( + "000000002ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" + "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), + 64, SECP256K1_NAME, &node2); + + for (i = 0; i < 8; i++) { + r = hdnode_private_ckd(&node1, ii[i]); + ck_assert_int_eq(r, 1); + } + r = hdnode_private_ckd_cached(&node2, ii, 8, NULL); + ck_assert_int_eq(r, 1); + ck_assert_mem_eq(&node1, &node2, sizeof(HDNode)); +} +END_TEST + +START_TEST(test_bip32_cache_2) { + HDNode nodea[9], nodeb[9]; + int i, j, r; + + for (j = 0; j < 9; j++) { + hdnode_from_seed( + fromhex( + "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d627" + "88f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), + 64, SECP256K1_NAME, &(nodea[j])); + hdnode_from_seed( + fromhex( + "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d627" + "88f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), + 64, SECP256K1_NAME, &(nodeb[j])); + } + + uint32_t ii[] = {0x80000001, 0x80000002, 0x80000003, 0x80000004, + 0x80000005, 0x80000006, 0x80000007, 0x80000008}; + for (j = 0; j < 9; j++) { + // non cached + for (i = 1; i <= j; i++) { + r = hdnode_private_ckd(&(nodea[j]), ii[i - 1]); + ck_assert_int_eq(r, 1); + } + // cached + r = hdnode_private_ckd_cached(&(nodeb[j]), ii, j, NULL); + ck_assert_int_eq(r, 1); + } + + ck_assert_mem_eq(&(nodea[0]), &(nodeb[0]), sizeof(HDNode)); + ck_assert_mem_eq(&(nodea[1]), &(nodeb[1]), sizeof(HDNode)); + ck_assert_mem_eq(&(nodea[2]), &(nodeb[2]), sizeof(HDNode)); + ck_assert_mem_eq(&(nodea[3]), &(nodeb[3]), sizeof(HDNode)); + ck_assert_mem_eq(&(nodea[4]), &(nodeb[4]), sizeof(HDNode)); + ck_assert_mem_eq(&(nodea[5]), &(nodeb[5]), sizeof(HDNode)); + ck_assert_mem_eq(&(nodea[6]), &(nodeb[6]), sizeof(HDNode)); + ck_assert_mem_eq(&(nodea[7]), &(nodeb[7]), sizeof(HDNode)); + ck_assert_mem_eq(&(nodea[8]), &(nodeb[8]), sizeof(HDNode)); +} +END_TEST + +START_TEST(test_bip32_cache_overflow_regression) { + HDNode node1 = {0}; + HDNode node2 = {0}; + const uint8_t *seed = fromhex( + "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f1" + "74429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"); + uint32_t path[BIP32_CACHE_MAXDEPTH + 2] = {0}; + size_t depth = sizeof(path) / sizeof(path[0]); + + hdnode_from_seed(seed, 64, SECP256K1_NAME, &node1); + hdnode_from_seed(seed, 64, SECP256K1_NAME, &node2); + ck_assert_int_eq(hdnode_private_ckd_cached(&node1, path, depth, NULL), 1); + + // A path deeper than the cache must not corrupt the fixed-size cache key. + path[BIP32_CACHE_MAXDEPTH] = BIP32_CACHE_MAXDEPTH + 1; + ck_assert_int_eq(hdnode_private_ckd_cached(&node2, path, depth, NULL), 1); + ck_assert_mem_ne(node1.private_key, node2.private_key, + sizeof(node1.private_key)); +} +END_TEST + +START_TEST(test_bip32_depth_overflow_regression) { + HDNode node = {0}; + hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, + SECP256K1_NAME, &node); + hdnode_fill_public_key(&node); + node.depth = UINT32_MAX; + + ck_assert_int_eq(hdnode_private_ckd(&node, 1), 0); + ck_assert_uint_eq(node.depth, UINT32_MAX); + + memzero(node.private_key, sizeof(node.private_key)); + ck_assert_int_eq(hdnode_public_ckd(&node, 1), 0); + ck_assert_uint_eq(node.depth, UINT32_MAX); +} +END_TEST + +START_TEST(test_bip32_nist_seed) { + HDNode node; + + // init m + hdnode_from_seed( + fromhex( + "a7305bc8df8d0951f0cb224c0e95d7707cbdf2c6ce7e8d481fec69c7ff5e9446"), + 32, NIST256P1_NAME, &node); + + // [Chain m] + ck_assert_mem_eq( + node.private_key, + fromhex( + "3b8c18469a4634517d6d0b65448f8e6c62091b45540a1743c5846be55d47d88f"), + 32); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "7762f9729fed06121fd13f326884c82f59aa95c57ac492ce8c9654e60efd130c"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "0383619fadcde31063d8c5cb00dbfe1713f3e6fa169d8541a798752a1c1ca0cb20"), + 33); + + // init m + hdnode_from_seed( + fromhex( + "aa305bc8df8d0951f0cb29ad4568d7707cbdf2c6ce7e8d481fec69c7ff5e9446"), + 32, NIST256P1_NAME, &node); + + // [Chain m] + ck_assert_mem_eq( + node.chain_code, + fromhex( + "a81d21f36f987fa0be3b065301bfb6aa9deefbf3dfef6744c37b9a4abc3c68f1"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "0e49dc46ce1d8c29d9b80a05e40f5d0cd68cbf02ae98572186f5343be18084bf"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "03aaa4c89acd9a98935330773d3dae55122f3591bac4a40942681768de8df6ba63"), + 33); +} +END_TEST + +START_TEST(test_bip32_nist_vector_1) { + HDNode node; + uint32_t fingerprint; + + // init m + hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, + NIST256P1_NAME, &node); + + // [Chain m] + fingerprint = 0; + ck_assert_uint_eq(fingerprint, 0x00000000); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "beeb672fe4621673f722f38529c07392fecaa61015c80c34f29ce8b41b3cb6ea"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "612091aaa12e22dd2abef664f8a01a82cae99ad7441b7ef8110424915c268bc2"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "0266874dc6ade47b3ecd096745ca09bcd29638dd52c2c12117b11ed3e458cfa9e8"), + 33); + + // [Chain m/0'] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd_prime(&node, 0); + ck_assert_uint_eq(fingerprint, 0xbe6105b5); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "3460cea53e6a6bb5fb391eeef3237ffd8724bf0a40e94943c98b83825342ee11"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "6939694369114c67917a182c59ddb8cafc3004e63ca5d3b84403ba8613debc0c"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "0384610f5ecffe8fda089363a41f56a5c7ffc1d81b59a612d0d649b2d22355590c"), + 33); + + // [Chain m/0'/1] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd(&node, 1); + ck_assert_uint_eq(fingerprint, 0x9b02312f); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "4187afff1aafa8445010097fb99d23aee9f599450c7bd140b6826ac22ba21d0c"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "284e9d38d07d21e4e281b645089a94f4cf5a5a81369acf151a1c3a57f18b2129"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "03526c63f8d0b4bbbf9c80df553fe66742df4676b241dabefdef67733e070f6844"), + 33); + + // [Chain m/0'/1/2'] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd_prime(&node, 2); + ck_assert_uint_eq(fingerprint, 0xb98005c1); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "98c7514f562e64e74170cc3cf304ee1ce54d6b6da4f880f313e8204c2a185318"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "694596e8a54f252c960eb771a3c41e7e32496d03b954aeb90f61635b8e092aa7"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "0359cf160040778a4b14c5f4d7b76e327ccc8c4a6086dd9451b7482b5a4972dda0"), + 33); + + // [Chain m/0'/1/2'/2] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd(&node, 2); + ck_assert_uint_eq(fingerprint, 0x0e9f3274); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "ba96f776a5c3907d7fd48bde5620ee374d4acfd540378476019eab70790c63a0"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "5996c37fd3dd2679039b23ed6f70b506c6b56b3cb5e424681fb0fa64caf82aaa"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "029f871f4cb9e1c97f9f4de9ccd0d4a2f2a171110c61178f84430062230833ff20"), + 33); + + // [Chain m/0'/1/2'/2/1000000000] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd(&node, 1000000000); + ck_assert_uint_eq(fingerprint, 0x8b2b5c4b); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "b9b7b82d326bb9cb5b5b121066feea4eb93d5241103c9e7a18aad40f1dde8059"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "21c4f269ef0a5fd1badf47eeacebeeaa3de22eb8e5b0adcd0f27dd99d34d0119"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "02216cd26d31147f72427a453c443ed2cde8a1e53c9cc44e5ddf739725413fe3f4"), + 33); +} +END_TEST + +START_TEST(test_bip32_nist_vector_2) { + HDNode node; + uint32_t fingerprint; + int r; + + // init m + hdnode_from_seed( + fromhex( + "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c" + "999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), + 64, NIST256P1_NAME, &node); + + // [Chain m] + fingerprint = 0; + ck_assert_uint_eq(fingerprint, 0x00000000); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "96cd4465a9644e31528eda3592aa35eb39a9527769ce1855beafc1b81055e75d"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "eaa31c2e46ca2962227cf21d73a7ef0ce8b31c756897521eb6c7b39796633357"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "02c9e16154474b3ed5b38218bb0463e008f89ee03e62d22fdcc8014beab25b48fa"), + 33); + + // [Chain m/0] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd(&node, 0); + ck_assert_int_eq(r, 1); + ck_assert_uint_eq(fingerprint, 0x607f628f); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "84e9c258bb8557a40e0d041115b376dd55eda99c0042ce29e81ebe4efed9b86a"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "d7d065f63a62624888500cdb4f88b6d59c2927fee9e6d0cdff9cad555884df6e"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "039b6df4bece7b6c81e2adfeea4bcf5c8c8a6e40ea7ffa3cf6e8494c61a1fc82cc"), + 33); + + // [Chain m/0/2147483647'] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd_prime(&node, 2147483647); + ck_assert_int_eq(r, 1); + ck_assert_uint_eq(fingerprint, 0x946d2a54); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "f235b2bc5c04606ca9c30027a84f353acf4e4683edbd11f635d0dcc1cd106ea6"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "96d2ec9316746a75e7793684ed01e3d51194d81a42a3276858a5b7376d4b94b9"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "02f89c5deb1cae4fedc9905f98ae6cbf6cbab120d8cb85d5bd9a91a72f4c068c76"), + 33); + + // [Chain m/0/2147483647'/1] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd(&node, 1); + ck_assert_int_eq(r, 1); + ck_assert_uint_eq(fingerprint, 0x218182d8); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "7c0b833106235e452eba79d2bdd58d4086e663bc8cc55e9773d2b5eeda313f3b"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "974f9096ea6873a915910e82b29d7c338542ccde39d2064d1cc228f371542bbc"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "03abe0ad54c97c1d654c1852dfdc32d6d3e487e75fa16f0fd6304b9ceae4220c64"), + 33); + + // [Chain m/0/2147483647'/1/2147483646'] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd_prime(&node, 2147483646); + ck_assert_int_eq(r, 1); + ck_assert_uint_eq(fingerprint, 0x931223e4); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "5794e616eadaf33413aa309318a26ee0fd5163b70466de7a4512fd4b1a5c9e6a"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "da29649bbfaff095cd43819eda9a7be74236539a29094cd8336b07ed8d4eff63"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "03cb8cb067d248691808cd6b5a5a06b48e34ebac4d965cba33e6dc46fe13d9b933"), + 33); + + // [Chain m/0/2147483647'/1/2147483646'/2] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd(&node, 2); + ck_assert_int_eq(r, 1); + ck_assert_uint_eq(fingerprint, 0x956c4629); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "3bfb29ee8ac4484f09db09c2079b520ea5616df7820f071a20320366fbe226a7"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "bb0a77ba01cc31d77205d51d08bd313b979a71ef4de9b062f8958297e746bd67"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "020ee02e18967237cf62672983b253ee62fa4dd431f8243bfeccdf39dbe181387f"), + 33); + + // init m + hdnode_from_seed( + fromhex( + "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c" + "999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), + 64, NIST256P1_NAME, &node); + + // test public derivation + // [Chain m/0] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_public_ckd(&node, 0); + ck_assert_int_eq(r, 1); + ck_assert_uint_eq(fingerprint, 0x607f628f); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "84e9c258bb8557a40e0d041115b376dd55eda99c0042ce29e81ebe4efed9b86a"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + 32); + ck_assert_mem_eq( + node.public_key, + fromhex( + "039b6df4bece7b6c81e2adfeea4bcf5c8c8a6e40ea7ffa3cf6e8494c61a1fc82cc"), + 33); +} +END_TEST + +START_TEST(test_bip32_nist_compare) { + HDNode node1, node2, node3; + int i, r; + hdnode_from_seed( + fromhex( + "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" + "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), + 64, NIST256P1_NAME, &node1); + hdnode_from_seed( + fromhex( + "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" + "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), + 64, NIST256P1_NAME, &node2); + hdnode_fill_public_key(&node2); + for (i = 0; i < 100; i++) { + memcpy(&node3, &node1, sizeof(HDNode)); + hdnode_fill_public_key(&node3); + r = hdnode_private_ckd(&node1, i); + ck_assert_int_eq(r, 1); + r = hdnode_public_ckd(&node2, i); + ck_assert_int_eq(r, 1); + r = hdnode_public_ckd(&node3, i); + ck_assert_int_eq(r, 1); + ck_assert_uint_eq(node1.depth, node2.depth); + ck_assert_uint_eq(node1.depth, node3.depth); + ck_assert_uint_eq(node1.child_num, node2.child_num); + ck_assert_uint_eq(node1.child_num, node3.child_num); + ck_assert_mem_eq(node1.chain_code, node2.chain_code, 32); + ck_assert_mem_eq(node1.chain_code, node3.chain_code, 32); + ck_assert_mem_eq( + node2.private_key, + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + 32); + ck_assert_mem_eq( + node3.private_key, + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + 32); + hdnode_fill_public_key(&node1); + ck_assert_mem_eq(node1.public_key, node2.public_key, 33); + ck_assert_mem_eq(node1.public_key, node3.public_key, 33); + } +} +END_TEST + +START_TEST(test_bip32_nist_repeat) { + HDNode node, node2; + uint32_t fingerprint; + int r; + + // init m + hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, + NIST256P1_NAME, &node); + + // [Chain m/28578'] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd_prime(&node, 28578); + ck_assert_int_eq(r, 1); + ck_assert_uint_eq(fingerprint, 0xbe6105b5); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "e94c8ebe30c2250a14713212f6449b20f3329105ea15b652ca5bdfc68f6c65c2"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "06f0db126f023755d0b8d86d4591718a5210dd8d024e3e14b6159d63f53aa669"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "02519b5554a4872e8c9c1c847115363051ec43e93400e030ba3c36b52a3e70a5b7"), + 33); + + memcpy(&node2, &node, sizeof(HDNode)); + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd(&node2, 33941); + ck_assert_int_eq(r, 1); + ck_assert_uint_eq(fingerprint, 0x3e2b7bc6); + ck_assert_mem_eq( + node2.chain_code, + fromhex( + "9e87fe95031f14736774cd82f25fd885065cb7c358c1edf813c72af535e83071"), + 32); + ck_assert_mem_eq( + node2.private_key, + fromhex( + "092154eed4af83e078ff9b84322015aefe5769e31270f62c3f66c33888335f3a"), + 32); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq( + node2.public_key, + fromhex( + "0235bfee614c0d5b2cae260000bb1d0d84b270099ad790022c1ae0b2e782efe120"), + 33); + + memcpy(&node2, &node, sizeof(HDNode)); + memzero(&node2.private_key, 32); + r = hdnode_public_ckd(&node2, 33941); + ck_assert_int_eq(r, 1); + ck_assert_uint_eq(fingerprint, 0x3e2b7bc6); + ck_assert_mem_eq( + node2.chain_code, + fromhex( + "9e87fe95031f14736774cd82f25fd885065cb7c358c1edf813c72af535e83071"), + 32); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq( + node2.public_key, + fromhex( + "0235bfee614c0d5b2cae260000bb1d0d84b270099ad790022c1ae0b2e782efe120"), + 33); +} +END_TEST + +// test vector 1 from https://en.bitcoin.it/wiki/BIP_0032_TestVectors +START_TEST(test_bip32_ed25519_vector_1) { + HDNode node; + + // init m + hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, + ED25519_NAME, &node); + + // [Chain m] + ck_assert_mem_eq( + node.chain_code, + fromhex( + "90046a93de5380a72b5e45010748567d5ea02bbf6522f979e05c0d8d8ca9fffb"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "2b4be7f19ee27bbf30c667b642d5f4aa69fd169872f8fc3059c08ebae2eb19e7"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "01a4b2856bfec510abab89753fac1ac0e1112364e7d250545963f135f2a33188ed"), + 33); + + // [Chain m/0'] + hdnode_private_ckd_prime(&node, 0); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "8b59aa11380b624e81507a27fedda59fea6d0b779a778918a2fd3590e16e9c69"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "68e0fe46dfb67e368c75379acec591dad19df3cde26e63b93a8e704f1dade7a3"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "018c8a13df77a28f3445213a0f432fde644acaa215fc72dcdf300d5efaa85d350c"), + 33); + + // [Chain m/0'/1'] + hdnode_private_ckd_prime(&node, 1); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "a320425f77d1b5c2505a6b1b27382b37368ee640e3557c315416801243552f14"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "b1d0bad404bf35da785a64ca1ac54b2617211d2777696fbffaf208f746ae84f2"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "011932a5270f335bed617d5b935c80aedb1a35bd9fc1e31acafd5372c30f5c1187"), + 33); + + // [Chain m/0'/1'/2'] + hdnode_private_ckd_prime(&node, 2); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "2e69929e00b5ab250f49c3fb1c12f252de4fed2c1db88387094a0f8c4c9ccd6c"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "92a5b23c0b8a99e37d07df3fb9966917f5d06e02ddbd909c7e184371463e9fc9"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "01ae98736566d30ed0e9d2f4486a64bc95740d89c7db33f52121f8ea8f76ff0fc1"), + 33); + + // [Chain m/0'/1'/2'/2'] + hdnode_private_ckd_prime(&node, 2); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "8f6d87f93d750e0efccda017d662a1b31a266e4a6f5993b15f5c1f07f74dd5cc"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "30d1dc7e5fc04c31219ab25a27ae00b50f6fd66622f6e9c913253d6511d1e662"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "018abae2d66361c879b900d204ad2cc4984fa2aa344dd7ddc46007329ac76c429c"), + 33); + + // [Chain m/0'/1'/2'/2'/1000000000'] + hdnode_private_ckd_prime(&node, 1000000000); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "68789923a0cac2cd5a29172a475fe9e0fb14cd6adb5ad98a3fa70333e7afa230"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "8f94d394a8e8fd6b1bc2f3f49f5c47e385281d5c17e65324b0f62483e37e8793"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "013c24da049451555d51a7014a37337aa4e12d41e485abccfa46b47dfb2af54b7a"), + 33); +} +END_TEST + +// test vector 2 from https://en.bitcoin.it/wiki/BIP_0032_TestVectors +START_TEST(test_bip32_ed25519_vector_2) { + HDNode node; + int r; + + // init m + hdnode_from_seed( + fromhex( + "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c" + "999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), + 64, ED25519_NAME, &node); + + // [Chain m] + ck_assert_mem_eq( + node.chain_code, + fromhex( + "ef70a74db9c3a5af931b5fe73ed8e1a53464133654fd55e7a66f8570b8e33c3b"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "171cb88b1b3c1db25add599712e36245d75bc65a1a5c9e18d76f9f2b1eab4012"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "018fe9693f8fa62a4305a140b9764c5ee01e455963744fe18204b4fb948249308a"), + 33); + + // [Chain m/0'] + r = hdnode_private_ckd_prime(&node, 0); + ck_assert_int_eq(r, 1); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "0b78a3226f915c082bf118f83618a618ab6dec793752624cbeb622acb562862d"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "1559eb2bbec5790b0c65d8693e4d0875b1747f4970ae8b650486ed7470845635"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "0186fab68dcb57aa196c77c5f264f215a112c22a912c10d123b0d03c3c28ef1037"), + 33); + + // [Chain m/0'/2147483647'] + r = hdnode_private_ckd_prime(&node, 2147483647); + ck_assert_int_eq(r, 1); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "138f0b2551bcafeca6ff2aa88ba8ed0ed8de070841f0c4ef0165df8181eaad7f"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "ea4f5bfe8694d8bb74b7b59404632fd5968b774ed545e810de9c32a4fb4192f4"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "015ba3b9ac6e90e83effcd25ac4e58a1365a9e35a3d3ae5eb07b9e4d90bcf7506d"), + 33); + + // [Chain m/0'/2147483647'/1'] + r = hdnode_private_ckd_prime(&node, 1); + ck_assert_int_eq(r, 1); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "73bd9fff1cfbde33a1b846c27085f711c0fe2d66fd32e139d3ebc28e5a4a6b90"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "3757c7577170179c7868353ada796c839135b3d30554bbb74a4b1e4a5a58505c"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "012e66aa57069c86cc18249aecf5cb5a9cebbfd6fadeab056254763874a9352b45"), + 33); + + // [Chain m/0'/2147483647'/1'/2147483646'] + r = hdnode_private_ckd_prime(&node, 2147483646); + ck_assert_int_eq(r, 1); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "0902fe8a29f9140480a00ef244bd183e8a13288e4412d8389d140aac1794825a"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "5837736c89570de861ebc173b1086da4f505d4adb387c6a1b1342d5e4ac9ec72"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "01e33c0f7d81d843c572275f287498e8d408654fdf0d1e065b84e2e6f157aab09b"), + 33); + + // [Chain m/0'/2147483647'/1'/2147483646'/2'] + r = hdnode_private_ckd_prime(&node, 2); + ck_assert_int_eq(r, 1); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "5d70af781f3a37b829f0d060924d5e960bdc02e85423494afc0b1a41bbe196d4"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "551d333177df541ad876a60ea71f00447931c0a9da16f227c11ea080d7391b8d"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "0147150c75db263559a70d5778bf36abbab30fb061ad69f69ece61a72b0cfa4fc0"), + 33); +} +END_TEST + +// test vector 1 from +// https://github.com/decred/dcrd/blob/master/hdkeychain/extendedkey_test.go +START_TEST(test_bip32_decred_vector_1) { + HDNode node, node2, node3; + uint32_t fingerprint; + char str[XPUB_MAXLEN]; + int r; + + // init m + hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, + SECP256K1_NAME, &node); + + // secp256k1_decred_info.bip32_name != "Bitcoin seed" so we cannot use it in + // hdnode_from_seed + node.curve = &secp256k1_decred_info; + + // [Chain m] + fingerprint = 0; + ck_assert_uint_eq(fingerprint, 0x00000000); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2"), + 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "dprv3hCznBesA6jBtmoyVFPfyMSZ1qYZ3WdjdebquvkEfmRfxC9VFEFi2YD" + "aJqHnx7uGe75eGSa3Mn3oHK11hBW7KZUrPxwbCPBmuCi1nwm182s"); + r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, + sizeof(str)); + ck_assert_str_eq(str, + "dpubZ9169KDAEUnyoBhjjmT2VaEodr6pUTDoqCEAeqgbfr2JfkB88BbK77j" + "bTYbcYXb2FVz7DKBdW4P618yd51MwF8DjKVopSbS7Lkgi6bowX5w"); + r = hdnode_deserialize_public(str, DECRED_VERSION_PUBLIC, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd_prime(&node, 0); + ck_assert_uint_eq(fingerprint, 0xbc495588); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56"), + 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "dprv3kUQDBztdyjKuwnaL3hfKYpT7W6X2huYH5d61YSWFBebSYwEBHAXJkC" + "pQ7rvMAxPzKqxVCGLvBqWvGxXjAyMJsV1XwKkfnQCM9KctC8k8bk"); + r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, + sizeof(str)); + ck_assert_str_eq(str, + "dpubZCGVaKZBiMo7pMgLaZm1qmchjWenTeVcUdFQkTNsFGFEA6xs4EW8PKi" + "qYqP7HBAitt9Hw16VQkQ1tjsZQSHNWFc6bEK6bLqrbco24FzBTY4"); + r = hdnode_deserialize_public(str, DECRED_VERSION_PUBLIC, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'/1] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd(&node, 1); + ck_assert_uint_eq(fingerprint, 0xc67bc2ef); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c"), + 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "dprv3nRtCZ5VAoHW4RUwQgRafSNRPUDFrmsgyY71A5eoZceVfuyL9SbZe2r" + "cbwDW2UwpkEniE4urffgbypegscNchPajWzy9QS4cRxF8QYXsZtq"); + r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, + sizeof(str)); + ck_assert_str_eq(str, + "dpubZEDyZgdnFBMHxqNhfCUwBfAg1UmXHiTmB5jKtzbAZhF8PTzy2PwAicN" + "dkg1CmW6TARxQeUbgC7nAQenJts4YoG3KMiqcjsjgeMvwLc43w6C"); + r = hdnode_deserialize_public(str, DECRED_VERSION_PUBLIC, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'/1/2'] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd_prime(&node, 2); + ck_assert_uint_eq(fingerprint, 0xe7072187); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2"), + 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "dprv3pYtkZK168vgrU38gXkUSjHQ2LGpEUzQ9fXrR8fGUR59YviSnm6U82X" + "jQYhpJEUPnVcC9bguJBQU5xVM4VFcDHu9BgScGPA6mQMH4bn5Cth"); + r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, + sizeof(str)); + ck_assert_str_eq(str, + "dpubZGLz7gsJAWzUksvtw3opxx5eeLq5fRaUMDABA3bdUVfnGUk5fiS5Cc3" + "kZGTjWtYr3jrEavQQnAF6jv2WCpZtFX4uFgifXqev6ED1TM9rTCB"); + r = hdnode_deserialize_public(str, DECRED_VERSION_PUBLIC, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'/1/2'/2] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd(&node, 2); + ck_assert_uint_eq(fingerprint, 0xbcbbc1c4); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "0f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29"), + 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "dprv3r7zqYFjT3NiNzdnwGxGpYh6S1TJCp1zA6mSEGaqLBJFnCB94cRMp7Y" + "YLR49aTZHZ7ya1CXwQJ6rodKeU9NgQTxkPSK7pzgZRgjYkQ7rgJh"); + r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, + sizeof(str)); + ck_assert_str_eq(str, + "dpubZHv6Cfp2XRSWHQXZBo1dLmVM421Zdkc4MePkyBXCLFttVkCmwZkxth4" + "ZV9PzkFP3DtD5xcVq2CPSYpJMWMaoxu1ixz4GNZFVcE2xnHP6chJ"); + r = hdnode_deserialize_public(str, DECRED_VERSION_PUBLIC, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'/1/2'/2/1000000000] + fingerprint = hdnode_fingerprint(&node); + hdnode_private_ckd(&node, 1000000000); + ck_assert_uint_eq(fingerprint, 0xe58b52e4); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011"), + 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "dprv3tJXnTDSb3uE6Euo6WvvhFKfBMNfxuJt5smqyPoHEoomoBMQyhYoQSK" + "JAHWtWxmuqdUVb8q9J2NaTkF6rYm6XDrSotkJ55bM21fffa7VV97"); + r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, + sizeof(str)); + ck_assert_str_eq(str, + "dpubZL6d9amjfRy1zeoZM2zHDU7uoMvwPqtxHRQAiJjeEtQQWjP3retQV1q" + "KJyzUd6ZJNgbJGXjtc5pdoBcTTYTLoxQzvV9JJCzCjB2eCWpRf8T"); + r = hdnode_deserialize_public(str, DECRED_VERSION_PUBLIC, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); +} +END_TEST + +// test vector 2 from +// https://github.com/decred/dcrd/blob/master/hdkeychain/extendedkey_test.go +START_TEST(test_bip32_decred_vector_2) { + HDNode node, node2, node3; + uint32_t fingerprint; + char str[XPUB_MAXLEN]; + int r; + + // init m + hdnode_from_seed( + fromhex( + "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c" + "999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), + 64, SECP256K1_NAME, &node); + + // secp256k1_decred_info.bip32_name != "Bitcoin seed" so we cannot use it in + // hdnode_from_seed + node.curve = &secp256k1_decred_info; + + // [Chain m] + fingerprint = 0; + ck_assert_uint_eq(fingerprint, 0x00000000); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "60499f801b896d83179a4374aeb7822aaeaceaa0db1f85ee3e904c4defbd9689"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "4b03d6fc340455b363f51020ad3ecca4f0850280cf436c70c727923f6db46c3e"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "03cbcaa9c98c877a26977d00825c956a238e8dddfbd322cce4f74b0b5bd6ace4a7"), + 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "dprv3hCznBesA6jBtPKJbQTxRZAKG2gyj8tZKEPaCsV4e9YYFBAgRP2eTSP" + "Aeu4r8dTMt9q51j2Vdt5zNqj7jbtovvocrP1qLj6WUTLF9xYQt4y"); + r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, + sizeof(str)); + ck_assert_str_eq(str, + "dpubZ9169KDAEUnynoD4qvXJwmxZt3FFA5UdWn1twnRReE9AxjCKJLNFY1u" + "BoegbFmwzA4Du7yqnu8tLivhrCCH6P3DgBS1HH5vmf8MpNXvvYT9"); + r = hdnode_deserialize_public(str, DECRED_VERSION_PUBLIC, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd(&node, 0); + ck_assert_int_eq(r, 1); + ck_assert_uint_eq(fingerprint, 0x2524c9d3); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "abe74a98f6c7eabee0428f53798f0ab8aa1bd37873999041703c742f15ac7e1e"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"), + 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "dprv3jMy45BuuDETfxi59P8NTSjHPrNVq4wPRfLgRd57923L2hosj5NUEqi" + "LYQ4i7fJtUpiXZLr2wUeToJY2Tm5sCpAJdajEHDmieVJiPQNXwu9"); + r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, + sizeof(str)); + ck_assert_str_eq(str, + "dpubZBA4RCkCybJFaNbqPuBiyfXY1rvmG1XTdCy1AY1U96dxkFqWc2i5KRE" + "Mh7NYPpy7ZPMhdpFMAesex3JdFDfX4J5FEW3HjSacqEYPfwb9Cj7"); + r = hdnode_deserialize_public(str, DECRED_VERSION_PUBLIC, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0/2147483647'] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd_prime(&node, 2147483647); + ck_assert_int_eq(r, 1); + ck_assert_uint_eq(fingerprint, 0x6035c6ad); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "be17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d9"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "877c779ad9687164e9c2f4f0f4ff0340814392330693ce95a58fe18fd52e6e93"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "03c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b"), + 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "dprv3mgHPRgK838mLK6T1p6WeBoJoJtXA1pGTHjqFuyHekcM7UTuER8fGwe" + "RRsoLqSuHa98uskVPnJnfWZEBUC1AVmXnSCPDvUFKydXNnnPHTuQ"); + r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, + sizeof(str)); + ck_assert_str_eq(str, + "dpubZDUNkZEcCRCZEizDGL9sAQbZRKSnaxQLeqN9zpueeqCyq2VY7NUGMXA" + "SacsK96S8XzNjq3YgFgwLtj8MJBToW6To9U5zxuazEyh89bjR1xA"); + r = hdnode_deserialize_public(str, DECRED_VERSION_PUBLIC, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0/2147483647'/1] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd(&node, 1); + ck_assert_int_eq(r, 1); + ck_assert_uint_eq(fingerprint, 0x36fc7080); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "704addf544a06e5ee4bea37098463c23613da32020d604506da8c0518e1da4b7"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9"), + 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "dprv3oFqwZZ9bJcUmhAeJyyshvrTWtrAsHfcRYQbEzNiiH5nGvM6wVTDn6w" + "oQEz92b2EHTYZBtLi82jKEnxSouA3cVaW8YWBsw5c3f4mwAhA3d2"); + r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, + sizeof(str)); + ck_assert_str_eq(str, + "dpubZF3wJh7SfggGg74QZW3EE9ei8uQSJEFgd62uyuK5iMgQzUNjpSnprgT" + "pYz3d6Q3fXXtEEXQqpzWcP4LUVuXFsgA8JKt1Hot5kyUk4pPRhDz"); + r = hdnode_deserialize_public(str, DECRED_VERSION_PUBLIC, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0/2147483647'/1/2147483646'] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd_prime(&node, 2147483646); + ck_assert_int_eq(r, 1); + ck_assert_uint_eq(fingerprint, 0x45309b4c); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e29"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "f1c7c871a54a804afe328b4c83a1c33b8e5ff48f5087273f04efa83b247d6a2d"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "02d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0"), + 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "dprv3qF3177i87wMirg6sraDvqty8yZg6THpXFPSXuM5AShBiiUQbq8FhSZ" + "DGkYmBNR3RKfBrxzkKDBpsRFJfTnQfLsvpPPqRnakat6hHQA43X9"); + r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, + sizeof(str)); + ck_assert_str_eq(str, + "dpubZH38NEg1CW19dGZs8NdaT4hDkz7wXPstio1mGpHSAXHpSGW3UnTrn25" + "ERT1Mp8ae5GMoQHMbgQiPrChMXQMdx3UqS8YqFkT1pqait8fY92u"); + r = hdnode_deserialize_public(str, DECRED_VERSION_PUBLIC, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0/2147483647'/1/2147483646'/2] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd(&node, 2); + ck_assert_int_eq(r, 1); + ck_assert_uint_eq(fingerprint, 0x3491a5e6); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "9452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58eedf394ed271"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "bb7d39bdb83ecf58f2fd82b6d918341cbef428661ef01ab97c28a4842125ac23"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key, + fromhex( + "024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c"), + 33); + hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "dprv3s15tfqzxhw8Kmo7RBEqMeyvC7uGekLniSmvbs3bckpxQ6ks1KKqfmH" + "144Jgh3PLxkyZRcS367kp7DrtUmnG16NpnsoNhxSXRgKbJJ7MUQR"); + r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + hdnode_fill_public_key(&node2); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, + sizeof(str)); + ck_assert_str_eq(str, + "dpubZJoBFoQJ35zvEBgsfhJBssnAp8TY5gvruzQFLmyxcqRb7enVtGfSkLo" + "2CkAZJMpa6T2fx6fUtvTgXtUvSVgAZ56bEwGxQsToeZfFV8VadE1"); + r = hdnode_deserialize_public(str, DECRED_VERSION_PUBLIC, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // init m + hdnode_deserialize_public( + "dpubZF4LSCdF9YKZfNzTVYhz4RBxsjYXqms8AQnMBHXZ8GUKoRSigG7kQnKiJt5pzk93Q8Fx" + "cdVBEkQZruSXduGtWnkwXzGnjbSovQ97dCxqaXc", + DECRED_VERSION_PUBLIC, SECP256K1_DECRED_NAME, &node, NULL); + + // test public derivation + // [Chain m/0] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_public_ckd(&node, 0); + ck_assert_int_eq(r, 1); + ck_assert_uint_eq(fingerprint, 0x6a19cfb3); + ck_assert_mem_eq( + node.chain_code, + fromhex( + "dcfe00831741a3a4803955147cdfc7053d69b167b1d03b5f9e63934217a005fd"), + 32); + ck_assert_mem_eq( + node.public_key, + fromhex( + "029555ea7bde276cd2c42c4502f40b5d16469fb310ae3aeee2a9000455f41b0866"), + 33); + hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, + sizeof(str)); + ck_assert_str_eq(str, + "dpubZHJs2Z3PtHbbpaXQCi5wBKPhU8tC5ztBKUYBCYNGKk8eZ1EmBs3MhnL" + "JbxHFMAahGnDnZT7qZxC7AXKP8PB6BDNUZgkG77moNMRmXyQ6s6s"); + r = hdnode_deserialize_public(str, DECRED_VERSION_PUBLIC, + SECP256K1_DECRED_NAME, &node2, NULL); + ck_assert_int_eq(r, 0); + ck_assert_mem_eq(&node2, &node, sizeof(HDNode)); +} +END_TEST + +START_TEST(test_ecdsa_signature) { + int res; + uint8_t digest[32]; + uint8_t pubkey[65]; + uint8_t sig[64]; + const ecdsa_curve *curve = &secp256k1; + + // Signature verification for a digest which is equal to the group order. + // https://github.com/trezor/trezor-firmware/pull/1374 + memcpy( + pubkey, + fromhex( + "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179848" + "3ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"), + sizeof(pubkey)); + memcpy( + digest, + fromhex( + "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"), + sizeof(digest)); + memcpy(sig, + fromhex( + "a0b37f8fba683cc68f6574cd43b39f0343a50008bf6ccea9d13231d9e7e2e1e41" + "1edc8d307254296264aebfc3dc76cd8b668373a072fd64665b50000e9fcce52"), + sizeof(sig)); + res = ecdsa_verify_digest(curve, pubkey, sig, digest); + ck_assert_int_eq(res, 0); + + // sha2(sha2("\x18Bitcoin Signed Message:\n\x0cHello World!")) + memcpy( + digest, + fromhex( + "de4e9524586d6fce45667f9ff12f661e79870c4105fa0fb58af976619bb11432"), + 32); + // r = 2: Four points should exist + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "00000000000000000000000000000000000000000000000000000000000000020123" + "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), + digest, 0); + ck_assert_int_eq(res, 0); + ck_assert_mem_eq( + pubkey, + fromhex( + "043fc5bf5fec35b6ffe6fd246226d312742a8c296bfa57dd22da509a2e348529b7dd" + "b9faf8afe1ecda3c05e7b2bda47ee1f5a87e952742b22afca560b29d972fcf"), + 65); + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "00000000000000000000000000000000000000000000000000000000000000020123" + "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), + digest, 1); + ck_assert_int_eq(res, 0); + ck_assert_mem_eq( + pubkey, + fromhex( + "0456d8089137b1fd0d890f8c7d4a04d0fd4520a30b19518ee87bd168ea12ed809032" + "9274c4c6c0d9df04515776f2741eeffc30235d596065d718c3973e19711ad0"), + 65); + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "00000000000000000000000000000000000000000000000000000000000000020123" + "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), + digest, 2); + ck_assert_int_eq(res, 0); + ck_assert_mem_eq( + pubkey, + fromhex( + "04cee0e740f41aab39156844afef0182dea2a8026885b10454a2d539df6f6df9023a" + "bfcb0f01c50bef3c0fa8e59a998d07441e18b1c60583ef75cc8b912fb21a15"), + 65); + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "00000000000000000000000000000000000000000000000000000000000000020123" + "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), + digest, 3); + ck_assert_int_eq(res, 0); + ck_assert_mem_eq( + pubkey, + fromhex( + "0490d2bd2e9a564d6e1d8324fc6ad00aa4ae597684ecf4abea58bdfe7287ea4fa729" + "68c2e5b0b40999ede3d7898d94e82c3f8dc4536a567a4bd45998c826a4c4b2"), + 65); + // A recovered point at infinity is not a valid public key. + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "220cf4c7b6d568f2256a8c30cc1784a625a28c3627dac404aa9a9ecd08314ec81a88" + "828f20d69d102bab5de5f6ee7ef040cb0ff7b8e1ba3f29d79efb5250f47d"), + digest, 0); + ck_assert_int_eq(res, 1); + + memcpy( + digest, + fromhex( + "0000000000000000000000000000000000000000000000000000000000000000"), + 32); + // r = 7: No point P with P.x = 7, but P.x = (order + 7) exists + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "00000000000000000000000000000000000000000000000000000000000000070123" + "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), + digest, 2); + ck_assert_int_eq(res, 0); + ck_assert_mem_eq( + pubkey, + fromhex( + "044d81bb47a31ffc6cf1f780ecb1e201ec47214b651650867c07f13ad06e12a1b040" + "de78f8dbda700f4d3cd7ee21b3651a74c7661809699d2be7ea0992b0d39797"), + 65); + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "00000000000000000000000000000000000000000000000000000000000000070123" + "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), + digest, 3); + ck_assert_int_eq(res, 0); + ck_assert_mem_eq( + pubkey, + fromhex( + "044d81bb47a31ffc6cf1f780ecb1e201ec47214b651650867c07f13ad06e12a1b0bf" + "21870724258ff0b2c32811de4c9ae58b3899e7f69662d41815f66c4f2c6498"), + 65); + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "00000000000000000000000000000000000000000000000000000000000000070123" + "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), + digest, 0); + ck_assert_int_eq(res, 1); + + memcpy( + digest, + fromhex( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + 32); + // r = 1: Two points P with P.x = 1, but P.x = (order + 7) doesn't exist + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "00000000000000000000000000000000000000000000000000000000000000010123" + "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), + digest, 0); + ck_assert_int_eq(res, 0); + ck_assert_mem_eq( + pubkey, + fromhex( + "045d330b2f89dbfca149828277bae852dd4aebfe136982cb531a88e9e7a89463fe71" + "519f34ea8feb9490c707f14bc38c9ece51762bfd034ea014719b7c85d2871b"), + 65); + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "00000000000000000000000000000000000000000000000000000000000000010123" + "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), + digest, 1); + ck_assert_int_eq(res, 0); + ck_assert_mem_eq( + pubkey, + fromhex( + "049e609c3950e70d6f3e3f3c81a473b1d5ca72739d51debdd80230ae80cab05134a9" + "4285375c834a417e8115c546c41da83a263087b79ef1cae25c7b3c738daa2b"), + 65); + + // r = 0 is always invalid + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "00000000000000000000000000000000000000000000000000000000000000010123" + "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), + digest, 2); + ck_assert_int_eq(res, 1); + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "00000000000000000000000000000000000000000000000000000000000000000123" + "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), + digest, 0); + ck_assert_int_eq(res, 1); + // r >= order is always invalid + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410123" + "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), + digest, 0); + ck_assert_int_eq(res, 1); + // check that overflow of r is handled + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "000000000000000000000000000000014551231950B75FC4402DA1722FC9BAEE0123" + "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), + digest, 2); + ck_assert_int_eq(res, 1); + // s = 0 is always invalid + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "00000000000000000000000000000000000000000000000000000000000000020000" + "000000000000000000000000000000000000000000000000000000000000"), + digest, 0); + ck_assert_int_eq(res, 1); + // s >= order is always invalid + res = ecdsa_recover_pub_from_sig( + curve, pubkey, + fromhex( + "0000000000000000000000000000000000000000000000000000000000000002ffff" + "fffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"), + digest, 0); + ck_assert_int_eq(res, 1); +} +END_TEST + +#define test_deterministic(KEY, MSG, K) \ + do { \ + sha256_Raw((uint8_t *)MSG, strlen(MSG), buf); \ + init_rfc6979(fromhex(KEY), buf, NULL, &rng); \ + generate_k_rfc6979(&k, &rng); \ + bn_write_be(&k, buf); \ + ck_assert_mem_eq(buf, fromhex(K), 32); \ + } while (0) + +START_TEST(test_rfc6979) { + bignum256 k; + uint8_t buf[32]; + rfc6979_state rng; + + test_deterministic( + "c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721", + "sample", + "a6e3c57dd01abe90086538398355dd4c3b17aa873382b0f24d6129493d8aad60"); + test_deterministic( + "cca9fbcc1b41e5a95d369eaa6ddcff73b61a4efaa279cfc6567e8daa39cbaf50", + "sample", + "2df40ca70e639d89528a6b670d9d48d9165fdc0febc0974056bdce192b8e16a3"); + test_deterministic( + "0000000000000000000000000000000000000000000000000000000000000001", + "Satoshi Nakamoto", + "8f8a276c19f4149656b280621e358cce24f5f52542772691ee69063b74f15d15"); + test_deterministic( + "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "Satoshi Nakamoto", + "33a19b60e25fb6f4435af53a3d42d493644827367e6453928554f43e49aa6f90"); + test_deterministic( + "f8b8af8ce3c7cca5e300d33939540c10d45ce001b8f252bfbc57ba0342904181", + "Alan Turing", + "525a82b70e67874398067543fd84c83d30c175fdc45fdeee082fe13b1d7cfdf1"); + test_deterministic( + "0000000000000000000000000000000000000000000000000000000000000001", + "All those moments will be lost in time, like tears in rain. Time to " + "die...", + "38aa22d72376b4dbc472e06c3ba403ee0a394da63fc58d88686c611aba98d6b3"); + test_deterministic( + "e91671c46231f833a6406ccbea0e3e392c76c167bac1cb013f6f1013980455c2", + "There is a computer disease that anybody who works with computers knows " + "about. It's a very serious disease and it interferes completely with " + "the work. The trouble with computers is that you 'play' with them!", + "1f4b84c23a86a221d233f2521be018d9318639d5b8bbd6374a8a59232d16ad3d"); +} +END_TEST + +START_TEST(test_ecdsa_sign_digest_deterministic_regression) { + static const struct { + const char *priv_key; + const char *digest; + const char *sig; + } vectors[] = { + {"312155017c70a204106e034520e0cdf17b3e54516e2ece38e38e38e38e38e38e", + "ffffffffffffffffffffffffffffffff20202020202020202020202020202020", + "e3d70248ea2fc771fc8d5e62d76b9cfd5402c96990333549eaadce1ae9f737eb" + "5cfbdc7d1e0ec18cc9b57bbb18f0a57dc929ec3c4dfac9073c581705015f6a8a"}, + {"312155017c70a204106e034520e0cdf17b3e54516e2ece38e38e38e38e38e38e", + "2020202020202020202020202020202020202020202020202020202020202020", + "40666188895430715552a7e4c6b53851f37a93030fb94e043850921242db78e8" + "75aa2ac9fd7e5a19402973e60e64382cdc29a09ebf6cb37e92f23be5b9251aee"}, + }; + uint8_t priv_key[32] = {0}; + uint8_t digest[32] = {0}; + uint8_t sig[64] = {0}; + + for (size_t i = 0; i < sizeof(vectors) / sizeof(*vectors); i++) { + memcpy(priv_key, fromhex(vectors[i].priv_key), sizeof(priv_key)); + memcpy(digest, fromhex(vectors[i].digest), sizeof(digest)); + ck_assert_int_eq( + ecdsa_sign_digest(&secp256k1, priv_key, digest, sig, NULL, NULL), + 0); + ck_assert_mem_eq(sig, fromhex(vectors[i].sig), sizeof(sig)); + } +} +END_TEST + +// test vectors from +// http://www.inconteam.com/software-development/41-encryption/55-aes-test-vectors +START_TEST(test_aes) { + aes_encrypt_ctx ctxe; + aes_decrypt_ctx ctxd; + uint8_t ibuf[16], obuf[16], iv[16], cbuf[16]; + const char **ivp, **plainp, **cipherp; + + // ECB + static const char *ecb_vector[] = { + // plain cipher + "6bc1bee22e409f96e93d7e117393172a", + "f3eed1bdb5d2a03c064b5a7e3db181f8", + "ae2d8a571e03ac9c9eb76fac45af8e51", + "591ccb10d410ed26dc5ba74a31362870", + "30c81c46a35ce411e5fbc1191a0a52ef", + "b6ed21b99ca6f4f9f153e7b1beafed1d", + "f69f2445df4f9b17ad2b417be66c3710", + "23304b7a39f9f3ff067d8d8f9e24ecc7", + 0, + 0, + }; + plainp = ecb_vector; + cipherp = ecb_vector + 1; + while (*plainp && *cipherp) { + // encrypt + aes_encrypt_key256( + fromhex( + "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), + &ctxe); + memcpy(ibuf, fromhex(*plainp), 16); + aes_ecb_encrypt(ibuf, obuf, 16, &ctxe); + ck_assert_mem_eq(obuf, fromhex(*cipherp), 16); + // decrypt + aes_decrypt_key256( + fromhex( + "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), + &ctxd); + memcpy(ibuf, fromhex(*cipherp), 16); + aes_ecb_decrypt(ibuf, obuf, 16, &ctxd); + ck_assert_mem_eq(obuf, fromhex(*plainp), 16); + plainp += 2; + cipherp += 2; + } + + // CBC + static const char *cbc_vector[] = { + // iv plain cipher + "000102030405060708090A0B0C0D0E0F", + "6bc1bee22e409f96e93d7e117393172a", + "f58c4c04d6e5f1ba779eabfb5f7bfbd6", + "F58C4C04D6E5F1BA779EABFB5F7BFBD6", + "ae2d8a571e03ac9c9eb76fac45af8e51", + "9cfc4e967edb808d679f777bc6702c7d", + "9CFC4E967EDB808D679F777BC6702C7D", + "30c81c46a35ce411e5fbc1191a0a52ef", + "39f23369a9d9bacfa530e26304231461", + "39F23369A9D9BACFA530E26304231461", + "f69f2445df4f9b17ad2b417be66c3710", + "b2eb05e2c39be9fcda6c19078c6a9d1b", + 0, + 0, + 0, + }; + ivp = cbc_vector; + plainp = cbc_vector + 1; + cipherp = cbc_vector + 2; + while (*plainp && *cipherp) { + // encrypt + aes_encrypt_key256( + fromhex( + "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), + &ctxe); + memcpy(iv, fromhex(*ivp), 16); + memcpy(ibuf, fromhex(*plainp), 16); + aes_cbc_encrypt(ibuf, obuf, 16, iv, &ctxe); + ck_assert_mem_eq(obuf, fromhex(*cipherp), 16); + // decrypt + aes_decrypt_key256( + fromhex( + "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), + &ctxd); + memcpy(iv, fromhex(*ivp), 16); + memcpy(ibuf, fromhex(*cipherp), 16); + aes_cbc_decrypt(ibuf, obuf, 16, iv, &ctxd); + ck_assert_mem_eq(obuf, fromhex(*plainp), 16); + ivp += 3; + plainp += 3; + cipherp += 3; + } + + // CFB + static const char *cfb_vector[] = { + "000102030405060708090A0B0C0D0E0F", + "6bc1bee22e409f96e93d7e117393172a", + "DC7E84BFDA79164B7ECD8486985D3860", + "DC7E84BFDA79164B7ECD8486985D3860", + "ae2d8a571e03ac9c9eb76fac45af8e51", + "39ffed143b28b1c832113c6331e5407b", + "39FFED143B28B1C832113C6331E5407B", + "30c81c46a35ce411e5fbc1191a0a52ef", + "df10132415e54b92a13ed0a8267ae2f9", + "DF10132415E54B92A13ED0A8267AE2F9", + "f69f2445df4f9b17ad2b417be66c3710", + "75a385741ab9cef82031623d55b1e471", + 0, + 0, + 0, + }; + ivp = cfb_vector; + plainp = cfb_vector + 1; + cipherp = cfb_vector + 2; + while (*plainp && *cipherp) { + // encrypt + aes_encrypt_key256( + fromhex( + "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), + &ctxe); + memcpy(iv, fromhex(*ivp), 16); + memcpy(ibuf, fromhex(*plainp), 16); + aes_cfb_encrypt(ibuf, obuf, 16, iv, &ctxe); + ck_assert_mem_eq(obuf, fromhex(*cipherp), 16); + // decrypt (uses encryption) + aes_encrypt_key256( + fromhex( + "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), + &ctxe); + memcpy(iv, fromhex(*ivp), 16); + memcpy(ibuf, fromhex(*cipherp), 16); + aes_cfb_decrypt(ibuf, obuf, 16, iv, &ctxe); + ck_assert_mem_eq(obuf, fromhex(*plainp), 16); + ivp += 3; + plainp += 3; + cipherp += 3; + } + + // OFB + static const char *ofb_vector[] = { + "000102030405060708090A0B0C0D0E0F", + "6bc1bee22e409f96e93d7e117393172a", + "dc7e84bfda79164b7ecd8486985d3860", + "B7BF3A5DF43989DD97F0FA97EBCE2F4A", + "ae2d8a571e03ac9c9eb76fac45af8e51", + "4febdc6740d20b3ac88f6ad82a4fb08d", + "E1C656305ED1A7A6563805746FE03EDC", + "30c81c46a35ce411e5fbc1191a0a52ef", + "71ab47a086e86eedf39d1c5bba97c408", + "41635BE625B48AFC1666DD42A09D96E7", + "f69f2445df4f9b17ad2b417be66c3710", + "0126141d67f37be8538f5a8be740e484", + 0, + 0, + 0, + }; + ivp = ofb_vector; + plainp = ofb_vector + 1; + cipherp = ofb_vector + 2; + while (*plainp && *cipherp) { + // encrypt + aes_encrypt_key256( + fromhex( + "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), + &ctxe); + memcpy(iv, fromhex(*ivp), 16); + memcpy(ibuf, fromhex(*plainp), 16); + aes_ofb_encrypt(ibuf, obuf, 16, iv, &ctxe); + ck_assert_mem_eq(obuf, fromhex(*cipherp), 16); + // decrypt (uses encryption) + aes_encrypt_key256( + fromhex( + "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), + &ctxe); + memcpy(iv, fromhex(*ivp), 16); + memcpy(ibuf, fromhex(*cipherp), 16); + aes_ofb_decrypt(ibuf, obuf, 16, iv, &ctxe); + ck_assert_mem_eq(obuf, fromhex(*plainp), 16); + ivp += 3; + plainp += 3; + cipherp += 3; + } + + // CTR + static const char *ctr_vector[] = { + // plain cipher + "6bc1bee22e409f96e93d7e117393172a", + "601ec313775789a5b7a7f504bbf3d228", + "ae2d8a571e03ac9c9eb76fac45af8e51", + "f443e3ca4d62b59aca84e990cacaf5c5", + "30c81c46a35ce411e5fbc1191a0a52ef", + "2b0930daa23de94ce87017ba2d84988d", + "f69f2445df4f9b17ad2b417be66c3710", + "dfc9c58db67aada613c2dd08457941a6", + 0, + 0, + }; + // encrypt + plainp = ctr_vector; + cipherp = ctr_vector + 1; + memcpy(cbuf, fromhex("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"), 16); + aes_encrypt_key256( + fromhex( + "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), + &ctxe); + while (*plainp && *cipherp) { + memcpy(ibuf, fromhex(*plainp), 16); + aes_ctr_encrypt(ibuf, obuf, 16, cbuf, aes_ctr_cbuf_inc, &ctxe); + ck_assert_mem_eq(obuf, fromhex(*cipherp), 16); + plainp += 2; + cipherp += 2; + } + // decrypt (uses encryption) + plainp = ctr_vector; + cipherp = ctr_vector + 1; + memcpy(cbuf, fromhex("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"), 16); + aes_encrypt_key256( + fromhex( + "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), + &ctxe); + while (*plainp && *cipherp) { + memcpy(ibuf, fromhex(*cipherp), 16); + aes_ctr_decrypt(ibuf, obuf, 16, cbuf, aes_ctr_cbuf_inc, &ctxe); + ck_assert_mem_eq(obuf, fromhex(*plainp), 16); + plainp += 2; + cipherp += 2; + } +} +END_TEST + +#define TEST1 "abc" +#define TEST2_1 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" +#define TEST2_2a "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" +#define TEST2_2b "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" +#define TEST2_2 TEST2_2a TEST2_2b +#define TEST3 "a" /* times 1000000 */ +#define TEST4a "01234567012345670123456701234567" +#define TEST4b "01234567012345670123456701234567" +/* an exact multiple of 512 bits */ +#define TEST4 TEST4a TEST4b /* times 10 */ + +#define TEST7_1 "\x49\xb2\xae\xc2\x59\x4b\xbe\x3a\x3b\x11\x75\x42\xd9\x4a\xc8" +#define TEST8_1 \ + "\x9a\x7d\xfd\xf1\xec\xea\xd0\x6e\xd6\x46\xaa\x55\xfe\x75\x71\x46" +#define TEST9_1 \ + "\x65\xf9\x32\x99\x5b\xa4\xce\x2c\xb1\xb4\xa2\xe7\x1a\xe7\x02\x20" \ + "\xaa\xce\xc8\x96\x2d\xd4\x49\x9c\xbd\x7c\x88\x7a\x94\xea\xaa\x10" \ + "\x1e\xa5\xaa\xbc\x52\x9b\x4e\x7e\x43\x66\x5a\x5a\xf2\xcd\x03\xfe" \ + "\x67\x8e\xa6\xa5\x00\x5b\xba\x3b\x08\x22\x04\xc2\x8b\x91\x09\xf4" \ + "\x69\xda\xc9\x2a\xaa\xb3\xaa\x7c\x11\xa1\xb3\x2a" +#define TEST10_1 \ + "\xf7\x8f\x92\x14\x1b\xcd\x17\x0a\xe8\x9b\x4f\xba\x15\xa1\xd5\x9f" \ + "\x3f\xd8\x4d\x22\x3c\x92\x51\xbd\xac\xbb\xae\x61\xd0\x5e\xd1\x15" \ + "\xa0\x6a\x7c\xe1\x17\xb7\xbe\xea\xd2\x44\x21\xde\xd9\xc3\x25\x92" \ + "\xbd\x57\xed\xea\xe3\x9c\x39\xfa\x1f\xe8\x94\x6a\x84\xd0\xcf\x1f" \ + "\x7b\xee\xad\x17\x13\xe2\xe0\x95\x98\x97\x34\x7f\x67\xc8\x0b\x04" \ + "\x00\xc2\x09\x81\x5d\x6b\x10\xa6\x83\x83\x6f\xd5\x56\x2a\x56\xca" \ + "\xb1\xa2\x8e\x81\xb6\x57\x66\x54\x63\x1c\xf1\x65\x66\xb8\x6e\x3b" \ + "\x33\xa1\x08\xb0\x53\x07\xc0\x0a\xff\x14\xa7\x68\xed\x73\x50\x60" \ + "\x6a\x0f\x85\xe6\xa9\x1d\x39\x6f\x5b\x5c\xbe\x57\x7f\x9b\x38\x80" \ + "\x7c\x7d\x52\x3d\x6d\x79\x2f\x6e\xbc\x24\xa4\xec\xf2\xb3\xa4\x27" \ + "\xcd\xbb\xfb" +#define length(x) (sizeof(x) - 1) + +// test vectors from rfc-4634 +START_TEST(test_sha1) { + struct { + const char *test; + int length; + int repeatcount; + int extrabits; + int numberExtrabits; + const char *result; + } tests[] = { + /* 1 */ {TEST1, length(TEST1), 1, 0, 0, + "A9993E364706816ABA3E25717850C26C9CD0D89D"}, + /* 2 */ + {TEST2_1, length(TEST2_1), 1, 0, 0, + "84983E441C3BD26EBAAE4AA1F95129E5E54670F1"}, + /* 3 */ + {TEST3, length(TEST3), 1000000, 0, 0, + "34AA973CD4C4DAA4F61EEB2BDBAD27316534016F"}, + /* 4 */ + {TEST4, length(TEST4), 10, 0, 0, + "DEA356A2CDDD90C7A7ECEDC5EBB563934F460452"}, + /* 5 */ {"", 0, 0, 0x98, 5, "29826B003B906E660EFF4027CE98AF3531AC75BA"}, + /* 6 */ {"\x5e", 1, 1, 0, 0, "5E6F80A34A9798CAFC6A5DB96CC57BA4C4DB59C2"}, + /* 7 */ + {TEST7_1, length(TEST7_1), 1, 0x80, 3, + "6239781E03729919C01955B3FFA8ACB60B988340"}, + /* 8 */ + {TEST8_1, length(TEST8_1), 1, 0, 0, + "82ABFF6605DBE1C17DEF12A394FA22A82B544A35"}, + /* 9 */ + {TEST9_1, length(TEST9_1), 1, 0xE0, 3, + "8C5B2A5DDAE5A97FC7F9D85661C672ADBF7933D4"}, + /* 10 */ + {TEST10_1, length(TEST10_1), 1, 0, 0, + "CB0082C8F197D260991BA6A460E76E202BAD27B3"}}; + + for (int i = 0; i < 10; i++) { + SHA1_CTX ctx; + uint8_t digest[SHA1_DIGEST_LENGTH]; + sha1_Init(&ctx); + /* extra bits are not supported */ + if (tests[i].numberExtrabits) continue; + for (int j = 0; j < tests[i].repeatcount; j++) { + sha1_Update(&ctx, (const uint8_t *)tests[i].test, tests[i].length); + } + sha1_Final(&ctx, digest); + ck_assert_mem_eq(digest, fromhex(tests[i].result), SHA1_DIGEST_LENGTH); + } +} +END_TEST + +#define TEST7_256 "\xbe\x27\x46\xc6\xdb\x52\x76\x5f\xdb\x2f\x88\x70\x0f\x9a\x73" +#define TEST8_256 \ + "\xe3\xd7\x25\x70\xdc\xdd\x78\x7c\xe3\x88\x7a\xb2\xcd\x68\x46\x52" +#define TEST9_256 \ + "\x3e\x74\x03\x71\xc8\x10\xc2\xb9\x9f\xc0\x4e\x80\x49\x07\xef\x7c" \ + "\xf2\x6b\xe2\x8b\x57\xcb\x58\xa3\xe2\xf3\xc0\x07\x16\x6e\x49\xc1" \ + "\x2e\x9b\xa3\x4c\x01\x04\x06\x91\x29\xea\x76\x15\x64\x25\x45\x70" \ + "\x3a\x2b\xd9\x01\xe1\x6e\xb0\xe0\x5d\xeb\xa0\x14\xeb\xff\x64\x06" \ + "\xa0\x7d\x54\x36\x4e\xff\x74\x2d\xa7\x79\xb0\xb3" +#define TEST10_256 \ + "\x83\x26\x75\x4e\x22\x77\x37\x2f\x4f\xc1\x2b\x20\x52\x7a\xfe\xf0" \ + "\x4d\x8a\x05\x69\x71\xb1\x1a\xd5\x71\x23\xa7\xc1\x37\x76\x00\x00" \ + "\xd7\xbe\xf6\xf3\xc1\xf7\xa9\x08\x3a\xa3\x9d\x81\x0d\xb3\x10\x77" \ + "\x7d\xab\x8b\x1e\x7f\x02\xb8\x4a\x26\xc7\x73\x32\x5f\x8b\x23\x74" \ + "\xde\x7a\x4b\x5a\x58\xcb\x5c\x5c\xf3\x5b\xce\xe6\xfb\x94\x6e\x5b" \ + "\xd6\x94\xfa\x59\x3a\x8b\xeb\x3f\x9d\x65\x92\xec\xed\xaa\x66\xca" \ + "\x82\xa2\x9d\x0c\x51\xbc\xf9\x33\x62\x30\xe5\xd7\x84\xe4\xc0\xa4" \ + "\x3f\x8d\x79\xa3\x0a\x16\x5c\xba\xbe\x45\x2b\x77\x4b\x9c\x71\x09" \ + "\xa9\x7d\x13\x8f\x12\x92\x28\x96\x6f\x6c\x0a\xdc\x10\x6a\xad\x5a" \ + "\x9f\xdd\x30\x82\x57\x69\xb2\xc6\x71\xaf\x67\x59\xdf\x28\xeb\x39" \ + "\x3d\x54\xd6" + +// test vectors from rfc-4634 +START_TEST(test_sha256) { + struct { + const char *test; + int length; + int repeatcount; + int extrabits; + int numberExtrabits; + const char *result; + } tests[] = { + /* 1 */ {TEST1, length(TEST1), 1, 0, 0, + "BA7816BF8F01CFEA4141" + "40DE5DAE2223B00361A396177A9CB410FF61F20015AD"}, + /* 2 */ + {TEST2_1, length(TEST2_1), 1, 0, 0, + "248D6A61D20638B8" + "E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1"}, + /* 3 */ + {TEST3, length(TEST3), 1000000, 0, 0, + "CDC76E5C9914FB92" + "81A1C7E284D73E67F1809A48A497200E046D39CCC7112CD0"}, + /* 4 */ + {TEST4, length(TEST4), 10, 0, 0, + "594847328451BDFA" + "85056225462CC1D867D877FB388DF0CE35F25AB5562BFBB5"}, + /* 5 */ + {"", 0, 0, 0x68, 5, + "D6D3E02A31A84A8CAA9718ED6C2057BE" + "09DB45E7823EB5079CE7A573A3760F95"}, + /* 6 */ + {"\x19", 1, 1, 0, 0, + "68AA2E2EE5DFF96E3355E6C7EE373E3D" + "6A4E17F75F9518D843709C0C9BC3E3D4"}, + /* 7 */ + {TEST7_256, length(TEST7_256), 1, 0x60, 3, + "77EC1DC8" + "9C821FF2A1279089FA091B35B8CD960BCAF7DE01C6A7680756BEB972"}, + /* 8 */ + {TEST8_256, length(TEST8_256), 1, 0, 0, + "175EE69B02BA" + "9B58E2B0A5FD13819CEA573F3940A94F825128CF4209BEABB4E8"}, + /* 9 */ + {TEST9_256, length(TEST9_256), 1, 0xA0, 3, + "3E9AD646" + "8BBBAD2AC3C2CDC292E018BA5FD70B960CF1679777FCE708FDB066E9"}, + /* 10 */ + {TEST10_256, length(TEST10_256), 1, 0, 0, + "97DBCA7D" + "F46D62C8A422C941DD7E835B8AD3361763F7E9B2D95F4F0DA6E1CCBC"}, + }; + + for (int i = 0; i < 10; i++) { + SHA256_CTX ctx; + uint8_t digest[SHA256_DIGEST_LENGTH]; + sha256_Init(&ctx); + /* extra bits are not supported */ + if (tests[i].numberExtrabits) continue; + for (int j = 0; j < tests[i].repeatcount; j++) { + sha256_Update(&ctx, (const uint8_t *)tests[i].test, tests[i].length); + } + sha256_Final(&ctx, digest); + ck_assert_mem_eq(digest, fromhex(tests[i].result), SHA256_DIGEST_LENGTH); + } +} +END_TEST + +#define TEST7_512 "\x08\xec\xb5\x2e\xba\xe1\xf7\x42\x2d\xb6\x2b\xcd\x54\x26\x70" +#define TEST8_512 \ + "\x8d\x4e\x3c\x0e\x38\x89\x19\x14\x91\x81\x6e\x9d\x98\xbf\xf0\xa0" +#define TEST9_512 \ + "\x3a\xdd\xec\x85\x59\x32\x16\xd1\x61\x9a\xa0\x2d\x97\x56\x97\x0b" \ + "\xfc\x70\xac\xe2\x74\x4f\x7c\x6b\x27\x88\x15\x10\x28\xf7\xb6\xa2" \ + "\x55\x0f\xd7\x4a\x7e\x6e\x69\xc2\xc9\xb4\x5f\xc4\x54\x96\x6d\xc3" \ + "\x1d\x2e\x10\xda\x1f\x95\xce\x02\xbe\xb4\xbf\x87\x65\x57\x4c\xbd" \ + "\x6e\x83\x37\xef\x42\x0a\xdc\x98\xc1\x5c\xb6\xd5\xe4\xa0\x24\x1b" \ + "\xa0\x04\x6d\x25\x0e\x51\x02\x31\xca\xc2\x04\x6c\x99\x16\x06\xab" \ + "\x4e\xe4\x14\x5b\xee\x2f\xf4\xbb\x12\x3a\xab\x49\x8d\x9d\x44\x79" \ + "\x4f\x99\xcc\xad\x89\xa9\xa1\x62\x12\x59\xed\xa7\x0a\x5b\x6d\xd4" \ + "\xbd\xd8\x77\x78\xc9\x04\x3b\x93\x84\xf5\x49\x06" +#define TEST10_512 \ + "\xa5\x5f\x20\xc4\x11\xaa\xd1\x32\x80\x7a\x50\x2d\x65\x82\x4e\x31" \ + "\xa2\x30\x54\x32\xaa\x3d\x06\xd3\xe2\x82\xa8\xd8\x4e\x0d\xe1\xde" \ + "\x69\x74\xbf\x49\x54\x69\xfc\x7f\x33\x8f\x80\x54\xd5\x8c\x26\xc4" \ + "\x93\x60\xc3\xe8\x7a\xf5\x65\x23\xac\xf6\xd8\x9d\x03\xe5\x6f\xf2" \ + "\xf8\x68\x00\x2b\xc3\xe4\x31\xed\xc4\x4d\xf2\xf0\x22\x3d\x4b\xb3" \ + "\xb2\x43\x58\x6e\x1a\x7d\x92\x49\x36\x69\x4f\xcb\xba\xf8\x8d\x95" \ + "\x19\xe4\xeb\x50\xa6\x44\xf8\xe4\xf9\x5e\xb0\xea\x95\xbc\x44\x65" \ + "\xc8\x82\x1a\xac\xd2\xfe\x15\xab\x49\x81\x16\x4b\xbb\x6d\xc3\x2f" \ + "\x96\x90\x87\xa1\x45\xb0\xd9\xcc\x9c\x67\xc2\x2b\x76\x32\x99\x41" \ + "\x9c\xc4\x12\x8b\xe9\xa0\x77\xb3\xac\xe6\x34\x06\x4e\x6d\x99\x28" \ + "\x35\x13\xdc\x06\xe7\x51\x5d\x0d\x73\x13\x2e\x9a\x0d\xc6\xd3\xb1" \ + "\xf8\xb2\x46\xf1\xa9\x8a\x3f\xc7\x29\x41\xb1\xe3\xbb\x20\x98\xe8" \ + "\xbf\x16\xf2\x68\xd6\x4f\x0b\x0f\x47\x07\xfe\x1e\xa1\xa1\x79\x1b" \ + "\xa2\xf3\xc0\xc7\x58\xe5\xf5\x51\x86\x3a\x96\xc9\x49\xad\x47\xd7" \ + "\xfb\x40\xd2" + +// test vectors from rfc-4634 +START_TEST(test_sha512) { + struct { + const char *test; + int length; + int repeatcount; + int extrabits; + int numberExtrabits; + const char *result; + } tests[] = {/* 1 */ {TEST1, length(TEST1), 1, 0, 0, + "DDAF35A193617ABACC417349AE20413112E6FA4E89A97EA2" + "0A9EEEE64B55D39A2192992A274FC1A836BA3C23A3FEEBBD" + "454D4423643CE80E2A9AC94FA54CA49F"}, + /* 2 */ + {TEST2_2, length(TEST2_2), 1, 0, 0, + "8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA1" + "7299AEADB6889018501D289E4900F7E4331B99DEC4B5433A" + "C7D329EEB6DD26545E96E55B874BE909"}, + /* 3 */ + {TEST3, length(TEST3), 1000000, 0, 0, + "E718483D0CE769644E2E42C7BC15B4638E1F98B13B204428" + "5632A803AFA973EBDE0FF244877EA60A4CB0432CE577C31B" + "EB009C5C2C49AA2E4EADB217AD8CC09B"}, + /* 4 */ + {TEST4, length(TEST4), 10, 0, 0, + "89D05BA632C699C31231DED4FFC127D5A894DAD412C0E024" + "DB872D1ABD2BA8141A0F85072A9BE1E2AA04CF33C765CB51" + "0813A39CD5A84C4ACAA64D3F3FB7BAE9"}, + /* 5 */ + {"", 0, 0, 0xB0, 5, + "D4EE29A9E90985446B913CF1D1376C836F4BE2C1CF3CADA0" + "720A6BF4857D886A7ECB3C4E4C0FA8C7F95214E41DC1B0D2" + "1B22A84CC03BF8CE4845F34DD5BDBAD4"}, + /* 6 */ + {"\xD0", 1, 1, 0, 0, + "9992202938E882E73E20F6B69E68A0A7149090423D93C81B" + "AB3F21678D4ACEEEE50E4E8CAFADA4C85A54EA8306826C4A" + "D6E74CECE9631BFA8A549B4AB3FBBA15"}, + /* 7 */ + {TEST7_512, length(TEST7_512), 1, 0x80, 3, + "ED8DC78E8B01B69750053DBB7A0A9EDA0FB9E9D292B1ED71" + "5E80A7FE290A4E16664FD913E85854400C5AF05E6DAD316B" + "7359B43E64F8BEC3C1F237119986BBB6"}, + /* 8 */ + {TEST8_512, length(TEST8_512), 1, 0, 0, + "CB0B67A4B8712CD73C9AABC0B199E9269B20844AFB75ACBD" + "D1C153C9828924C3DDEDAAFE669C5FDD0BC66F630F677398" + "8213EB1B16F517AD0DE4B2F0C95C90F8"}, + /* 9 */ + {TEST9_512, length(TEST9_512), 1, 0x80, 3, + "32BA76FC30EAA0208AEB50FFB5AF1864FDBF17902A4DC0A6" + "82C61FCEA6D92B783267B21080301837F59DE79C6B337DB2" + "526F8A0A510E5E53CAFED4355FE7C2F1"}, + /* 10 */ + {TEST10_512, length(TEST10_512), 1, 0, 0, + "C665BEFB36DA189D78822D10528CBF3B12B3EEF726039909" + "C1A16A270D48719377966B957A878E720584779A62825C18" + "DA26415E49A7176A894E7510FD1451F5"}}; + + for (int i = 0; i < 10; i++) { + SHA512_CTX ctx; + uint8_t digest[SHA512_DIGEST_LENGTH]; + sha512_Init(&ctx); + /* extra bits are not supported */ + if (tests[i].numberExtrabits) continue; + for (int j = 0; j < tests[i].repeatcount; j++) { + sha512_Update(&ctx, (const uint8_t *)tests[i].test, tests[i].length); + } + sha512_Final(&ctx, digest); + ck_assert_mem_eq(digest, fromhex(tests[i].result), SHA512_DIGEST_LENGTH); + } +} +END_TEST + +// test vectors from http://www.di-mgt.com.au/sha_testvectors.html +START_TEST(test_sha3_256) { + static const struct { + const char *data; + const char *hash; + } tests[] = { + { + "", + "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", + }, + { + "abc", + "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", + }, + { + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376", + }, + { + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijkl" + "mnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", + "916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18", + }, + }; + + uint8_t digest[SHA3_256_DIGEST_LENGTH]; + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + size_t len = strlen(tests[i].data); + sha3_256((uint8_t *)tests[i].data, len, digest); + ck_assert_mem_eq(digest, fromhex(tests[i].hash), SHA3_256_DIGEST_LENGTH); + + // Test progressive hashing. + size_t part_len = len; + SHA3_CTX ctx; + sha3_256_Init(&ctx); + sha3_Update(&ctx, (uint8_t *)tests[i].data, part_len); + sha3_Update(&ctx, NULL, 0); + sha3_Update(&ctx, (uint8_t *)tests[i].data + part_len, len - part_len); + sha3_Final(&ctx, digest); + ck_assert_mem_eq(digest, fromhex(tests[i].hash), SHA3_256_DIGEST_LENGTH); + } +} +END_TEST + +// test vectors from http://www.di-mgt.com.au/sha_testvectors.html +START_TEST(test_sha3_512) { + static const struct { + const char *data; + const char *hash; + } tests[] = { + { + "", + "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2" + "123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26", + }, + { + "abc", + "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e1" + "16e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0", + }, + { + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "04a371e84ecfb5b8b77cb48610fca8182dd457ce6f326a0fd3d7ec2f1e91636dee69" + "1fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e", + }, + { + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijkl" + "mnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", + "afebb2ef542e6579c50cad06d2e578f9f8dd6881d7dc824d26360feebf18a4fa73e3" + "261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185", + }, + }; + + uint8_t digest[SHA3_512_DIGEST_LENGTH]; + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + size_t len = strlen(tests[i].data); + sha3_512((uint8_t *)tests[i].data, len, digest); + ck_assert_mem_eq(digest, fromhex(tests[i].hash), SHA3_512_DIGEST_LENGTH); + + // Test progressive hashing. + size_t part_len = len; + SHA3_CTX ctx; + sha3_512_Init(&ctx); + sha3_Update(&ctx, (const uint8_t *)tests[i].data, part_len); + sha3_Update(&ctx, NULL, 0); + sha3_Update(&ctx, (const uint8_t *)tests[i].data + part_len, + len - part_len); + sha3_Final(&ctx, digest); + ck_assert_mem_eq(digest, fromhex(tests[i].hash), SHA3_512_DIGEST_LENGTH); + } +} +END_TEST + +// test vectors from +// https://raw.githubusercontent.com/NemProject/nem-test-vectors/master/0.test-sha3-256.dat +START_TEST(test_keccak_256) { + static const struct { + const char *hash; + size_t length; + const char *data; + } tests[] = { + { + "4e9e79ab7434f6c7401fb3305d55052ee829b9e46d5d05d43b59fefb32e9a619", + 293, + "a6151d4904e18ec288243028ceda30556e6c42096af7150d6a7232ca5dba52bd2192" + "e23daa5fa2bea3d4bd95efa2389cd193fcd3376e70a5c097b32c1c62c80af9d71021" + "1545f7cdddf63747420281d64529477c61e721273cfd78f8890abb4070e97baa52ac" + "8ff61c26d195fc54c077def7a3f6f79b36e046c1a83ce9674ba1983ec2fb58947de6" + "16dd797d6499b0385d5e8a213db9ad5078a8e0c940ff0cb6bf92357ea5609f778c3d" + "1fb1e7e36c35db873361e2be5c125ea7148eff4a035b0cce880a41190b2e22924ad9" + "d1b82433d9c023924f2311315f07b88bfd42850047bf3be785c4ce11c09d7e02065d" + "30f6324365f93c5e7e423a07d754eb314b5fe9db4614275be4be26af017abdc9c338" + "d01368226fe9af1fb1f815e7317bdbb30a0f36dc69", + }, + { + "c1268babc42d00c3463dc388222100f7e525a74a64665c39f112f788ddb5da42", + 376, + "9db801077952c2324e0044a4994edfb09b3edfcf669bfdd029f4bf42d5b0eab3056b" + "0bf82708ca7bfadba43c9de806b10a19d0f00c2351ef1086b6b108f306e035c6b61b" + "2e70fd7087ba848601c8a3f626a66666423717ef305a1068bfa3a1f7ffc1e5a78cb6" + "182ffc8a577ca2a821630bf900d0fbba848bdf94b77c5946771b6c3f8c02269bc772" + "ca56098f724536d96be68c284ee1d81697989d40029b8ea63ac1fd85f8b3cae8b194" + "f6834ff65a5858f9498ddbb467995eb2d49cdfc6c05d92038c6e9aaeee85f8222b37" + "84165f12a2c3df4c7a142e26dddfd831d07e22dfecc0eded48a69c8a9e1b97f1a4e0" + "efcd4edd310de0edf82af38a6e4d5ab2a19da586e61210d4f75e7a07e2201f9c8154" + "ca52a414a70d2eb2ac1c5b9a2900b4d871f62fa56f70d03b3dd3704bd644808c45a1" + "3231918ea884645b8ec054e8bab2935a66811fe590ddc119ae901dfeb54fc2a87c1e" + "0a236778baab2fa8843709c6676d3c1888ba19d75ec52d73a7d035c143179b938237" + "26b7", + }, + { + "e83b50e8c83cb676a7dd64c055f53e5110d5a4c62245ceb8f683fd87b2b3ec77", + 166, + "c070a957550b7b34113ee6543a1918d96d241f27123425db7f7b9004e047ffbe0561" + "2e7fa8c54b23c83ea427e625e97b7a28b09a70bf6d91e478eeed01d7907931c29ea8" + "6e70f2cdcfb243ccf7f24a1619abf4b5b9e6f75cbf63fc02baf4a820a9790a6b053e" + "50fd94e0ed57037cfc2bab4d95472b97d3c25f434f1cc0b1ede5ba7f15907a42a223" + "933e5e2dfcb518c3531975268c326d60fa911fbb7997eee3ba87656c4fe7", + }, + { + "8ebd2c9d4ff00e285a9b6b140bfc3cef672016f0098100e1f6f250220af7ce1a", + 224, + "b502fbdce4045e49e147eff5463d4b3f37f43461518868368e2c78008c84c2db79d1" + "2b58107034f67e7d0abfee67add0342dd23dce623f26b9156def87b1d7ac15a6e073" + "01f832610fe869ada13a2b0e3d60aa6bb81bc04487e2e800f5106b0402ee0331df74" + "5e021b5ea5e32faf1c7fc1322041d221a54191c0af19948b5f34411937182e30d5cd" + "39b5a6c959d77d92d21bb1de51f1b3411cb6eec00600429916227fb62d2c88e69576" + "f4ac8e5efcde8efa512cc80ce7fb0dfaa6c74d26e898cefe9d4f7dce232a69f2a6a9" + "477aa08366efcdfca117c89cb79eba15a23755e0", + }, + { + "db3961fdddd0c314289efed5d57363459a6700a7bd015e7a03d3e1d03f046401", + 262, + "22e203a98ba2c43d8bc3658f0a48a35766df356d6a5e98b0c7222d16d85a00b31720" + "7d4aef3fc7cabb67b9d8f5838de0b733e1fd59c31f0667e53286972d7090421ad90d" + "54db2ea40047d0d1700c86f53dbf48da532396307e68edad877dcae481848801b0a5" + "db44dbdba6fc7c63b5cd15281d57ca9e6be96f530b209b59d6127ad2bd8750f3f807" + "98f62521f0d5b42633c2f5a9aaefbed38779b7aded2338d66850b0bb0e33c48e040c" + "99f2dcee7a7ebb3d7416e1c5bf038c19d09682dab67c96dbbfad472e45980aa27d1b" + "301b15f7de4d4f549bad2501931c9d4f1a3b1692dcb4b1b834ddd4a636126702307d" + "daeec61841693b21887d56e76cc2069dafb557fd6682160f", + }, + { + "25dd3acacd6bf688c0eace8d33eb7cc550271969142deb769a05b4012f7bb722", + 122, + "99e7f6e0ed46ec866c43a1ab494998d47e9309a79fde2a629eb63bb2160a5ffd0f22" + "06de9c32dd20e9b23e57ab7422cf82971cc2873ec0e173fe93281c7b33e1c76ac792" + "23a6f435f230bdd30260c00d00986c72a399d3ba70f6e783d834bbf8a6127844def5" + "59b8b6db742b2cfd715f7ff29e7b42bf7d567beb", + }, + { + "00d747c9045c093484290afc161437f11c2ddf5f8a9fc2acae9c7ef5fcf511e5", + 440, + "50c392f97f8788377f0ab2e2aab196cb017ad157c6f9d022673d39072cc198b06622" + "a5cbd269d1516089fa59e28c3373a92bd54b2ebf1a79811c7e40fdd7bce200e80983" + "fda6e77fc44c44c1b5f87e01cef2f41e1141103f73364e9c2f25a4597e6517ef31b3" + "16300b770c69595e0fa6d011df1566a8676a88c7698562273bbfa217cc69d4b5c89a" + "8907b902f7dc14481fefc7da4a810c15a60f5641aae854d2f8cc50cbc393015560f0" + "1c94e0d0c075dbcb150ad6eba29dc747919edcaf0231dba3eb3f2b1a87e136a1f0fd" + "4b3d8ee61bad2729e9526a32884f7bcfa41e361add1b4c51dc81463528372b4ec321" + "244de0c541ba00df22b8773cdf4cf898510c867829fa6b4ff11f9627338b9686d905" + "cb7bcdf085080ab842146e0035c808be58cce97827d8926a98bd1ff7c529be3bc14f" + "68c91b2ca4d2f6fc748f56bcf14853b7f8b9aa6d388f0fd82f53fdc4bacf9d9ba10a" + "165f404cf427e199f51bf6773b7c82531e17933f6d8b8d9181e22f8921a2dbb20fc7" + "c8023a87e716e245017c399d0942934f5e085219b3f8d26a196bf8b239438b8e561c" + "28a61ff08872ecb052c5fcb19e2fdbc09565924a50ebee1461c4b414219d4257", + }, + { + "dadcde7c3603ef419d319ba3d50cf00ad57f3e81566fd11b9b6f461cbb9dcb0f", + 338, + "18e1df97abccc91e07dc7b7ffab5ee8919d5610721453176aa2089fb96d9a477e147" + "6f507fa1129f04304e960e8017ff41246cacc0153055fc4b1dc6168a74067ebb077c" + "b5aa80a9df6e8b5b821e906531159668c4c164b9e511d8724aedbe17c1f41da88094" + "17d3c30b79ea5a2e3c961f6bac5436d9af6be24a36eebcb17863fed82c0eb8962339" + "eb612d58659dddd2ea06a120b3a2d8a17050be2de367db25a5bef4290c209bdb4c16" + "c4df5a1fe1ead635169a1c35f0a56bc07bcf6ef0e4c2d8573ed7a3b58030fa268c1a" + "5974b097288f01f34d5a1087946410688016882c6c7621aad680d9a25c7a3e5dbcbb" + "07ffdb7243b91031c08a121b40785e96b7ee46770c760f84aca8f36b7c7da64d25c8" + "f73b4d88ff3acb7eeefc0b75144dffea66d2d1f6b42b905b61929ab3f38538393ba5" + "ca9d3c62c61f46fa63789cac14e4e1d8722bf03cceef6e3de91f783b0072616c", + }, + { + "d184e84a2507fc0f187b640dd5b849a366c0383d9cbdbc6fa30904f054111255", + 141, + "13b8df9c1bcfddd0aa39b3055f52e2bc36562b6677535994b173f07041d141699db4" + "2589d6091ef0e71b645b41ab57577f58c98da966562d24823158f8e1d43b54edea4e" + "61dd66fe8c59ad8405f5a0d9a3eb509a77ae3d8ae4adf926fd3d8d31c3dcccfc1408" + "14541010937024cc554e1daaee1b333a66316e7fbebb07ac8dfb134a918b9090b141" + "68012c4824", + }, + { + "20c19635364a00b151d0168fe5ae03bac6dd7d06030475b40d2e8c577a192f53", + 84, + "e1e96da4b7d8dcc2b316006503a990ea26a5b200cb7a7edfc14f5ce827f06d8d232e" + "c95b1acdc1422ffc16da11d258f0c7b378f026d64c74b2fb41df8bfd3cd30066caec" + "dc6f76c8163de9309d9fd0cf33d54a29", + }, + { + "86cc2c428d469e43fb4ee8d38dffbf5128d20d1659dbc45edf4a855399ca730e", + 319, + "30391840ad14e66c53e1a5aaa03989ff059940b60c44c3b21295a93d023f2e6c7cdc" + "f60208b7d87a7605fb5cee94630d94cad90bc6955328357fa37fea47c09f9cee759c" + "31537187321c7d572e3554eeb90f441a9494575454dfbf8cfd86128da15de9418821" + "ca158856eb84ff6a29a2c8380711e9e6d4955388374fcd3c1ca45b49e0679fc7157f" + "96bc6e4f86ce20a89c12d4449b1ca7056e0b7296fc646f68f6ddbfa6a48e384d63ab" + "68bc75fd69a2add59b8e41c4a0f753935df9a703d7df82a430798b0a67710a780614" + "85a9d15de16f154582082459b4462485ce8a82d35ac6b9498ae40df3a23d5f00e0e8" + "6661cb02c52f677fd374c32969ec63028b5dd2c1d4bce67a6d9f79ba5e7eeb5a2763" + "dc9fe2a05aa2ebaad36aaec2541e343a677fb4e6b6a180eff33c93744a4624f6a79f" + "054c6c9e9c5b6928dbe7ba5fca", + }, + { + "e80eee72a76e6957f7cb7f68c41b92f0ad9aac6e58aa8fc272c1e7364af11c70", + 108, + "3c210ed15889ae938781d2cebd49d4a8007f163ffba1f7669bccdccf6ad5a1418299" + "d5f4348f5cd03b0ba9e6999ab154e46836c3546feb395d17bcc60f23d7ba0e8efe6a" + "a616c00b6bf552fe1cb5e28e3e7bc39dfc20c63ae3901035e91ddd110e43fe59ed74" + "4beeedb6bc1e", + }, + { + "f971bbae97dd8a034835269fb246867de358a889de6de13672e771d6fb4c89b7", + 468, + "64e9a3a99c021df8bea59368cfe1cd3b0a4aca33ffcd5cf6028d9307c0b904b8037d" + "056a3c12803f196f74c4d360a3132452d365922b1157e5b0d76f91fb94bebfdcb4d5" + "0fa23ed5be3d3c5712219e8666debc8abcd5e6c69a542761a6cbbd1b3c0f05248752" + "04b64d2788465f90cb19b6f6da9f8bec6d6e684196e713549ec83e47cbaeff77838a" + "c4936b312562e2de17c970449d49d214ec2597c6d4f642e6c94a613a0c53285abccd" + "7794a3d72241808594fb4e6e4d5d2c310ef1cdcbfd34805ca2408f554797a6cfd49d" + "0f25ed8927f206acb127e6436e1234902489ec2e7f3058e26c0eba80341bc7ad0da8" + "b8bd80bd1b43c9099269e3f8b68445c69b79d8cf5693d4a0d47a44f9e9114dbb3399" + "2d2ea9d3b5b86e4ea57a44a638848de4ac365bb6bb7855305ade62b07ebf0954d70b" + "7c2fb5e6fcc154c7a36fb1756df5f20a84d35696627ebf22d44f40f805c0878ad110" + "bc17dcd66821084ca87902e05bc0afa61161086956b85a6ea900d35c7784d4c361a4" + "3fe294e267d5762408be58962cdb4f45a9c0efd7d2335916df3acb98ccfbcf5ee395" + "30540e5f3d3c5f3326a9a536d7bfa37aae2b143e2499b81bf0670e3a418c26c7dc82" + "b293d9bd182dd6435670514237df88d8286e19ce93e0a0db2790", + }, + { + "b97fd51f4e4eaa40c7a2853010fc46be5be2f43b9520ea0c533b68f728c978a2", + 214, + "ced3a43193caceb269d2517f4ecb892bb7d57d7201869e28e669b0b17d1c44d286e0" + "2734e2210ea9009565832975cc6303b9b6008fe1165b99ae5f1b29962ef042ebad8b" + "676d7433ed2fe0d0d6f4f32b2cb4c519da61552328c2caea799bb2fd907308173a1c" + "d2b798fb0df7d2eaf2ff0be733af74f42889e211843fc80b09952ae7eb246725b91d" + "31c1f7a5503fdf3bc9c269c76519cf2dc3225e862436b587bb74adbad88c773056cf" + "ea3bddb1f6533c01125eeae0986e5c817359912c9d0472bf8320b824ee097f82a8e0" + "5b9f53a5be7d153225de", + }, + { + "f0fecf766e4f7522568b3be71843cce3e5fcb10ea96b1a236c8c0a71c9ad55c9", + 159, + "8aca4de41275f5c4102f66266d70cff1a2d56f58df8d12061c64cb6cd8f616a5bf19" + "c2bb3c91585c695326f561a2d0eb4eef2e202d82dcc9089e4bee82b62a199a11963c" + "d08987d3abd5914def2cdd3c1e4748d46b654f338e3959121e869c18d5327e88090d" + "0ba0ac6762a2b14514cc505af7499f1a22f421dbe978494f9ffe1e88f1c59228f21d" + "a5bc9fcc911d022300a443bca17258bdd6cfbbf52fde61", + }, + { + "5c4f16043c0084bf98499fc7dc4d674ce9c730b7135210acdbf5e41d3dcf317b", + 87, + "01bbc193d0ee2396a7d8267ad63f18149667b31d8f7f48c8bb0c634755febc9ef1a7" + "9e93c475f6cd137ee37d4dc243ea2fdcdc0d098844af2208337b7bbf6930e39e74e2" + "3952ac1a19b4d38b83810a10c3b069e4fafb06", + }, + { + "14b61fc981f7d9449b7b6a2d57eb48cc8f7896f4dced2005291b2a2f38cb4a63", + 358, + "cbc1709a531438d5ead32cea20a9e4ddc0101ec555ab42b2e378145013cc05a97b9e" + "2c43c89bfa63ae5e9e9ce1fc022035c6b68f0a906ee1f53396d9dbe41cb2bc4bfeb1" + "44b005b0f40e0fec872d9c4aca9929ba3cbacd84c58ab43c26f10d345a24692bbd55" + "a76506876768e8e32a461bf160cee953da88920d36ad4aff6eea7126aa6f44a7a6fc" + "e770ce43f0f90a20590bdaad3ffcda30ca8e3700f832c62caa5df030c16bcf74aff4" + "92466f781eb69863a80663535fc154abd7cfdd02eef1019221cf608b9780f807e507" + "fbbf559b1dfe4e971b4d08fe45263a3c697ba90f9f71bec97e12438b4b12f6a84ab6" + "6872b888097089d76c9c2502d9ed2eece6bef8eee1d439782e218f5cc75d38f98860" + "12cdcb4bbe6caf812e97c5a336bcceae38b1109e3243a291ce23d097aaee7d9a711d" + "e6886749a7a6d15d7e7cbc4a51b1b4da9fcf139e4a6fd7dc0bc017db624b17fc9b8f" + "847592ed42467c25ad9fe96acbf20c0ffd18", + }, + { + "47ec7f3a362becbb110867995a0f066a66152603c4d433f11bf51870c67e2864", + 354, + "0636983353c9ea3f75256ed00b70e8b7cfc6f4e4c0ba3aa9a8da59b6e6ad9dfb5bc2" + "c49f48cc0b4237f87dedf34b888e54ecebf1d435bcd4aab72eb4ce39e5262fb68c6f" + "86423dac123bf59e903989eda7df4a982822d0831521403cedcfe9a5bbea648bb2e7" + "ef8cd81442ea5abe468b3ee8b06376ef8099447255c2fdc1b73af37fe0e0b852ffbc" + "9339868db756680db99e6e9837dbd28c39a69f229044ad7ec772524a6e01f679d25f" + "dc2e736a2418e5dfd7c2ab1348d0f821b777c975244c6cfc2fca5c36ccae7cf1d07b" + "190a9d17a088a1276bd096250b92f53b29b6ef88ef69d744b56fb2ec5078cc0b68a9" + "106943ef242b466097b9e29df11eb5cb0c06c29d7917410ba1097215d6aa4dafd90a" + "dff0c3e7221b9e8832613bd9aca8bcc6b2aa7b43acedcbc11aee1b5ba56f77a210be" + "7cf3485ee813e1126c3eeccd8419bbf22c412cad32cc0fc7a73aca4e379651caac3d" + "13d6cf5ca05508fd2d96f3ad94e7", + }, + { + "73778e7f1943646a89d3c78909e0afbe584071ba5230546a39cd73e44e36d78a", + 91, + "6217504a26b3395855eab6ddeb79f2e3490d74b80eff343721150ee0c1c02b071867" + "43589f93c22a03dc5ed29fb5bf592de0a089763e83e5b95f9dd524d66c8da3e04c18" + "14e65e68b2810c1b517648aabc266ad62896c51864a7f4", + }, + { + "35ef6868e750cf0c1d5285992c231d93ec644670fb79cf85324067a9f77fde78", + 185, + "0118b7fb15f927a977e0b330b4fa351aeeec299d6ba090eb16e5114fc4a6749e5915" + "434a123c112697390c96ea2c26dc613eb5c75f5ecfb6c419317426367e34da0ddc6d" + "7b7612cefa70a22fea0025f5186593b22449dab71f90a49f7de7352e54e0c0bd8837" + "e661ca2127c3313a7268cafdd5ccfbf3bdd7c974b0e7551a2d96766579ef8d2e1f37" + "6af74cd1ab62162fc2dc61a8b7ed4163c1caccf20ed73e284da2ed257ec974eee96b" + "502acb2c60a04886465e44debb0317", + }, + }; + + uint8_t hash[SHA3_256_DIGEST_LENGTH]; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + keccak_256(fromhex(tests[i].data), tests[i].length, hash); + ck_assert_mem_eq(hash, fromhex(tests[i].hash), SHA3_256_DIGEST_LENGTH); + + // Test progressive hashing. + size_t part_len = tests[i].length / 2; + SHA3_CTX ctx = {0}; + keccak_256_Init(&ctx); + keccak_Update(&ctx, fromhex(tests[i].data), part_len); + keccak_Update(&ctx, fromhex(tests[i].data), 0); + keccak_Update(&ctx, fromhex(tests[i].data) + part_len, + tests[i].length - part_len); + keccak_Final(&ctx, hash); + ck_assert_mem_eq(hash, fromhex(tests[i].hash), SHA3_256_DIGEST_LENGTH); + } +} +END_TEST + +// test vectors from +// https://raw.githubusercontent.com/monero-project/monero/master/tests/hash/tests-extra-blake.txt +START_TEST(test_blake256) { + static const struct { + const char *hash; + const char *data; + } tests[] = { + { + "716f6e863f744b9ac22c97ec7b76ea5f5908bc5b2f67c61510bfc4751384ea7a", + "", + }, + { + "e104256a2bc501f459d03fac96b9014f593e22d30f4de525fa680c3aa189eb4f", + "cc", + }, + { + "8f341148be7e354fdf38b693d8c6b4e0bd57301a734f6fd35cd85b8491c3ddcd", + "41fb", + }, + { + "bc334d1069099f10c601883ac6f3e7e9787c6aa53171f76a21923cc5ad3ab937", + "1f877c", + }, + { + "b672a16f53982bab1e77685b71c0a5f6703ffd46a1c834be69f614bd128d658e", + "c1ecfdfc", + }, + { + "d9134b2899057a7d8d320cc99e3e116982bc99d3c69d260a7f1ed3da8be68d99", + "21f134ac57", + }, + { + "637923bd29a35aa3ecbbd2a50549fc32c14cf0fdcaf41c3194dd7414fd224815", + "c6f50bb74e29", + }, + { + "70c092fd5c8c21e9ef4bbc82a5c7819e262a530a748caf285ff0cba891954f1e", + "119713cc83eeef", + }, + { + "fdf092993edbb7a0dc7ca67f04051bbd14481639da0808947aff8bfab5abed4b", + "4a4f202484512526", + }, + { + "6f6fc234bf35beae1a366c44c520c59ad5aa70351b5f5085e21e1fe2bfcee709", + "1f66ab4185ed9b6375", + }, + { + "4fdaf89e2a0e78c000061b59455e0ea93a4445b440e7562c8f0cfa165c93de2e", + "eed7422227613b6f53c9", + }, + { + "d6b780eee9c811f664393dc2c58b5a68c92b3c9fe9ceb70371d33ece63b5787e", + "eaeed5cdffd89dece455f1", + }, + { + "d0015071d3e7ed048c764850d76406eceae52b8e2e6e5a2c3aa92ae880485b34", + "5be43c90f22902e4fe8ed2d3", + }, + { + "9b0207902f9932f7a85c24722e93e31f6ed2c75c406509aa0f2f6d1cab046ce4", + "a746273228122f381c3b46e4f1", + }, + { + "258020d5b04a814f2b72c1c661e1f5a5c395d9799e5eee8b8519cf7300e90cb1", + "3c5871cd619c69a63b540eb5a625", + }, + { + "4adae3b55baa907fefc253365fdd99d8398befd0551ed6bf9a2a2784d3c304d1", + "fa22874bcc068879e8ef11a69f0722", + }, + { + "6dd10d772f8d5b4a96c3c5d30878cd9a1073fa835bfe6d2b924fa64a1fab1711", + "52a608ab21ccdd8a4457a57ede782176", + }, + { + "0b8741ddf2259d3af2901eb1ae354f22836442c965556f5c1eb89501191cb46a", + "82e192e4043ddcd12ecf52969d0f807eed", + }, + { + "f48a754ca8193a82643150ab94038b5dd170b4ebd1e0751b78cfb0a98fa5076a", + "75683dcb556140c522543bb6e9098b21a21e", + }, + { + "5698409ab856b74d9fa5e9b259dfa46001f89041752da424e56e491577b88c86", + "06e4efe45035e61faaf4287b4d8d1f12ca97e5", + }, + }; + + uint8_t hash[BLAKE256_DIGEST_LENGTH]; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + size_t len = strlen(tests[i].data) / 2; + blake256(fromhex(tests[i].data), len, hash); + ck_assert_mem_eq(hash, fromhex(tests[i].hash), BLAKE256_DIGEST_LENGTH); + + // Test progressive hashing. + size_t part_len = len / 2; + BLAKE256_CTX ctx; + blake256_Init(&ctx); + blake256_Update(&ctx, fromhex(tests[i].data), part_len); + blake256_Update(&ctx, NULL, 0); + blake256_Update(&ctx, fromhex(tests[i].data) + part_len, len - part_len); + blake256_Final(&ctx, hash); + ck_assert_mem_eq(hash, fromhex(tests[i].hash), BLAKE256_DIGEST_LENGTH); + } +} +END_TEST + +// test vectors from +// https://raw.githubusercontent.com/BLAKE2/BLAKE2/master/testvectors/blake2b-kat.txt +START_TEST(test_blake2b) { + static const struct { + const char *msg; + const char *hash; + } tests[] = { + { + "", + "10ebb67700b1868efb4417987acf4690ae9d972fb7a590c2f02871799aaa4786b5e9" + "96e8f0f4eb981fc214b005f42d2ff4233499391653df7aefcbc13fc51568", + }, + { + "000102", + "33d0825dddf7ada99b0e7e307104ad07ca9cfd9692214f1561356315e784f3e5a17e" + "364ae9dbb14cb2036df932b77f4b292761365fb328de7afdc6d8998f5fc1", + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021" + "22232425262728292a2b2c2d2e2f3031323334353637", + "f8f3726ac5a26cc80132493a6fedcb0e60760c09cfc84cad178175986819665e7684" + "2d7b9fedf76dddebf5d3f56faaad4477587af21606d396ae570d8e719af2", + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021" + "22232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243" + "4445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465" + "666768696a6b6c6d6e6f", + "227e3aed8d2cb10b918fcb04f9de3e6d0a57e08476d93759cd7b2ed54a1cbf0239c5" + "28fb04bbf288253e601d3bc38b21794afef90b17094a182cac557745e75f", + }, + }; + + uint8_t key[BLAKE2B_KEY_LENGTH]; + memcpy(key, + fromhex( + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2" + "02122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"), + BLAKE2B_KEY_LENGTH); + + uint8_t digest[BLAKE2B_DIGEST_LENGTH]; + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + size_t msg_len = strlen(tests[i].msg) / 2; + blake2b_Key(fromhex(tests[i].msg), msg_len, key, sizeof(key), digest, + sizeof(digest)); + ck_assert_mem_eq(digest, fromhex(tests[i].hash), sizeof(digest)); + + // Test progressive hashing. + size_t part_len = msg_len / 2; + BLAKE2B_CTX ctx; + ck_assert_int_eq(blake2b_InitKey(&ctx, sizeof(digest), key, sizeof(key)), + 0); + ck_assert_int_eq(blake2b_Update(&ctx, fromhex(tests[i].msg), part_len), 0); + ck_assert_int_eq(blake2b_Update(&ctx, NULL, 0), 0); + ck_assert_int_eq(blake2b_Update(&ctx, fromhex(tests[i].msg) + part_len, + msg_len - part_len), + 0); + ck_assert_int_eq(blake2b_Final(&ctx, digest, sizeof(digest)), 0); + ck_assert_mem_eq(digest, fromhex(tests[i].hash), BLAKE2B_DIGEST_LENGTH); + } +} +END_TEST + +// test vectors from +// https://raw.githubusercontent.com/BLAKE2/BLAKE2/master/testvectors/blake2s-kat.txt +START_TEST(test_blake2s) { + static const struct { + const char *msg; + const char *hash; + } tests[] = { + { + "", + "48a8997da407876b3d79c0d92325ad3b89cbb754d86ab71aee047ad345fd2c49", + }, + { + "000102", + "1d220dbe2ee134661fdf6d9e74b41704710556f2f6e5a091b227697445dbea6b", + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021" + "22232425262728292a2b2c2d2e2f3031323334353637", + "2966b3cfae1e44ea996dc5d686cf25fa053fb6f67201b9e46eade85d0ad6b806", + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021" + "22232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243" + "4445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465" + "666768696a6b6c6d6e6f", + "90a83585717b75f0e9b725e055eeeeb9e7a028ea7e6cbc07b20917ec0363e38c", + }, + }; + + uint8_t key[BLAKE2S_KEY_LENGTH]; + memcpy( + key, + fromhex( + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"), + BLAKE2S_KEY_LENGTH); + + uint8_t digest[BLAKE2S_DIGEST_LENGTH]; + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + size_t msg_len = strlen(tests[i].msg) / 2; + blake2s_Key(fromhex(tests[i].msg), msg_len, key, sizeof(key), digest, + sizeof(digest)); + ck_assert_mem_eq(digest, fromhex(tests[i].hash), sizeof(digest)); + + // Test progressive hashing. + size_t part_len = msg_len / 2; + BLAKE2S_CTX ctx; + ck_assert_int_eq(blake2s_InitKey(&ctx, sizeof(digest), key, sizeof(key)), + 0); + ck_assert_int_eq(blake2s_Update(&ctx, fromhex(tests[i].msg), part_len), 0); + ck_assert_int_eq(blake2s_Update(&ctx, NULL, 0), 0); + ck_assert_int_eq(blake2s_Update(&ctx, fromhex(tests[i].msg) + part_len, + msg_len - part_len), + 0); + ck_assert_int_eq(blake2s_Final(&ctx, digest, sizeof(digest)), 0); + ck_assert_mem_eq(digest, fromhex(tests[i].hash), BLAKE2S_DIGEST_LENGTH); + } +} +END_TEST + +#include + +START_TEST(test_chacha_drbg) { + char entropy[] = + "06032cd5eed33f39265f49ecb142c511da9aff2af71203bffaf34a9ca5bd9c0d"; + char nonce[] = "0e66f71edc43e42a45ad3c6fc6cdc4df"; + char reseed[] = + "01920a4e669ed3a85ae8a33b35a74ad7fb2a6bb4cf395ce00334a9c9a5a5d552"; + char expected[] = + "e172c5d18f3e8c77e9f66f9e1c24560772117161a9a0a237ab490b0769ad5d910f5dfb36" + "22edc06c18be0495c52588b200893d90fd80ff2149ead0c45d062c90f5890149c0f9591c" + "41bf4110865129a0fe524f210cca1340bd16f71f57906946cbaaf1fa863897d70d203b5a" + "f9996f756eec08861ee5875f9d915adcddc38719"; + uint8_t result[128]; + uint8_t null_bytes[128] = {0}; + + uint8_t nonce_bytes[16]; + memcpy(nonce_bytes, fromhex(nonce), sizeof(nonce_bytes)); + CHACHA_DRBG_CTX ctx; + chacha_drbg_init(&ctx, fromhex(entropy), strlen(entropy) / 2, nonce_bytes, + strlen(nonce) / 2); + chacha_drbg_reseed(&ctx, fromhex(reseed), strlen(reseed) / 2, NULL, 0); + chacha_drbg_generate(&ctx, result, sizeof(result)); + chacha_drbg_generate(&ctx, result, sizeof(result)); + ck_assert_mem_eq(result, fromhex(expected), sizeof(result)); + + for (size_t i = 0; i <= sizeof(result); ++i) { + chacha_drbg_init(&ctx, fromhex(entropy), strlen(entropy) / 2, nonce_bytes, + strlen(nonce) / 2); + chacha_drbg_reseed(&ctx, fromhex(reseed), strlen(reseed) / 2, NULL, 0); + chacha_drbg_generate(&ctx, result, sizeof(result) - 13); + memset(result, 0, sizeof(result)); + chacha_drbg_generate(&ctx, result, i); + ck_assert_mem_eq(result, fromhex(expected), i); + ck_assert_mem_eq(result + i, null_bytes, sizeof(result) - i); + } +} +END_TEST + +START_TEST(test_pbkdf2_hmac_sha256) { + uint8_t k[64]; + + // test vectors from + // https://stackoverflow.com/questions/5130513/pbkdf2-hmac-sha2-test-vectors + pbkdf2_hmac_sha256((const uint8_t *)"password", 8, (const uint8_t *)"salt", 4, + 1, k, 32); + ck_assert_mem_eq( + k, + fromhex( + "120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b"), + 32); + + pbkdf2_hmac_sha256((const uint8_t *)"password", 8, (const uint8_t *)"salt", 4, + 2, k, 32); + ck_assert_mem_eq( + k, + fromhex( + "ae4d0c95af6b46d32d0adff928f06dd02a303f8ef3c251dfd6e2d85a95474c43"), + 32); + + pbkdf2_hmac_sha256((const uint8_t *)"password", 8, (const uint8_t *)"salt", 4, + 4096, k, 32); + ck_assert_mem_eq( + k, + fromhex( + "c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a"), + 32); + + pbkdf2_hmac_sha256((const uint8_t *)"passwordPASSWORDpassword", 3 * 8, + (const uint8_t *)"saltSALTsaltSALTsaltSALTsaltSALTsalt", + 9 * 4, 4096, k, 40); + ck_assert_mem_eq(k, + fromhex("348c89dbcbd32b2f32d814b8116e84cf2b17347ebc1800181c4" + "e2a1fb8dd53e1c635518c7dac47e9"), + 40); + + pbkdf2_hmac_sha256((const uint8_t *)"pass\x00word", 9, + (const uint8_t *)"sa\x00lt", 5, 4096, k, 16); + ck_assert_mem_eq(k, fromhex("89b69d0516f829893c696226650a8687"), 16); + + // test vector from https://tools.ietf.org/html/rfc7914.html#section-11 + pbkdf2_hmac_sha256((const uint8_t *)"passwd", 6, (const uint8_t *)"salt", 4, + 1, k, 64); + ck_assert_mem_eq( + k, + fromhex( + "55ac046e56e3089fec1691c22544b605f94185216dde0465e68b9d57c20dacbc49ca" + "9cccf179b645991664b39d77ef317c71b845b1e30bd509112041d3a19783"), + 64); +} +END_TEST + +// test vectors from +// http://stackoverflow.com/questions/15593184/pbkdf2-hmac-sha-512-test-vectors +START_TEST(test_pbkdf2_hmac_sha512) { + uint8_t k[64]; + + pbkdf2_hmac_sha512((uint8_t *)"password", 8, (const uint8_t *)"salt", 4, 1, k, + 64); + ck_assert_mem_eq( + k, + fromhex( + "867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5d513554e1c8cf252c02d" + "470a285a0501bad999bfe943c08f050235d7d68b1da55e63f73b60a57fce"), + 64); + + pbkdf2_hmac_sha512((uint8_t *)"password", 8, (const uint8_t *)"salt", 4, 2, k, + 64); + ck_assert_mem_eq( + k, + fromhex( + "e1d9c16aa681708a45f5c7c4e215ceb66e011a2e9f0040713f18aefdb866d53cf76c" + "ab2868a39b9f7840edce4fef5a82be67335c77a6068e04112754f27ccf4e"), + 64); + + pbkdf2_hmac_sha512((uint8_t *)"password", 8, (const uint8_t *)"salt", 4, 4096, + k, 64); + ck_assert_mem_eq( + k, + fromhex( + "d197b1b33db0143e018b12f3d1d1479e6cdebdcc97c5c0f87f6902e072f457b5143f" + "30602641b3d55cd335988cb36b84376060ecd532e039b742a239434af2d5"), + 64); + + pbkdf2_hmac_sha512((uint8_t *)"passwordPASSWORDpassword", 3 * 8, + (const uint8_t *)"saltSALTsaltSALTsaltSALTsaltSALTsalt", + 9 * 4, 4096, k, 64); + ck_assert_mem_eq( + k, + fromhex( + "8c0511f4c6e597c6ac6315d8f0362e225f3c501495ba23b868c005174dc4ee71115b" + "59f9e60cd9532fa33e0f75aefe30225c583a186cd82bd4daea9724a3d3b8"), + 64); +} +END_TEST + +START_TEST(test_hmac_drbg) { + char entropy[] = + "06032cd5eed33f39265f49ecb142c511da9aff2af71203bffaf34a9ca5bd9c0d"; + char nonce[] = "0e66f71edc43e42a45ad3c6fc6cdc4df"; + char reseed[] = + "01920a4e669ed3a85ae8a33b35a74ad7fb2a6bb4cf395ce00334a9c9a5a5d552"; + char expected[] = + "76fc79fe9b50beccc991a11b5635783a83536add03c157fb30645e611c2898bb2b1bc215" + "000209208cd506cb28da2a51bdb03826aaf2bd2335d576d519160842e7158ad0949d1a9e" + "c3e66ea1b1a064b005de914eac2e9d4f2d72a8616a80225422918250ff66a41bd2f864a6" + "a38cc5b6499dc43f7f2bd09e1e0f8f5885935124"; + uint8_t result[128]; + uint8_t null_bytes[128] = {0}; + + uint8_t nonce_bytes[16]; + memcpy(nonce_bytes, fromhex(nonce), sizeof(nonce_bytes)); + HMAC_DRBG_CTX ctx; + hmac_drbg_init(&ctx, fromhex(entropy), strlen(entropy) / 2, nonce_bytes, + strlen(nonce) / 2); + hmac_drbg_reseed(&ctx, fromhex(reseed), strlen(reseed) / 2, NULL, 0); + hmac_drbg_generate(&ctx, result, sizeof(result)); + hmac_drbg_generate(&ctx, result, sizeof(result)); + ck_assert_mem_eq(result, fromhex(expected), sizeof(result)); + + for (size_t i = 0; i <= sizeof(result); ++i) { + hmac_drbg_init(&ctx, fromhex(entropy), strlen(entropy) / 2, nonce_bytes, + strlen(nonce) / 2); + hmac_drbg_reseed(&ctx, fromhex(reseed), strlen(reseed) / 2, NULL, 0); + hmac_drbg_generate(&ctx, result, sizeof(result) - 13); + memset(result, 0, sizeof(result)); + hmac_drbg_generate(&ctx, result, i); + ck_assert_mem_eq(result, fromhex(expected), i); + ck_assert_mem_eq(result + i, null_bytes, sizeof(result) - i); + } +} +END_TEST + +START_TEST(test_mnemonic) { + static const char *vectors[] = { + "00000000000000000000000000000000", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon about", + "c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e53495531f09a698" + "7599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04", + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "legal winner thank year wave sausage worth useful legal winner thank " + "yellow", + "2e8905819b8723fe2c1d161860e5ee1830318dbf49a83bd451cfb8440c28bd6fa457fe12" + "96106559a3c80937a1c1069be3a3a5bd381ee6260e8d9739fce1f607", + "80808080808080808080808080808080", + "letter advice cage absurd amount doctor acoustic avoid letter advice " + "cage above", + "d71de856f81a8acc65e6fc851a38d4d7ec216fd0796d0a6827a3ad6ed5511a30fa280f12" + "eb2e47ed2ac03b5c462a0358d18d69fe4f985ec81778c1b370b652a8", + "ffffffffffffffffffffffffffffffff", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", + "ac27495480225222079d7be181583751e86f571027b0497b5b5d11218e0a8a1333257291" + "7f0f8e5a589620c6f15b11c61dee327651a14c34e18231052e48c069", + "000000000000000000000000000000000000000000000000", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon abandon abandon abandon agent", + "035895f2f481b1b0f01fcf8c289c794660b289981a78f8106447707fdd9666ca06da5a9a" + "565181599b79f53b844d8a71dd9f439c52a3d7b3e8a79c906ac845fa", + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "legal winner thank year wave sausage worth useful legal winner thank " + "year wave sausage worth useful legal will", + "f2b94508732bcbacbcc020faefecfc89feafa6649a5491b8c952cede496c214a0c7b3c39" + "2d168748f2d4a612bada0753b52a1c7ac53c1e93abd5c6320b9e95dd", + "808080808080808080808080808080808080808080808080", + "letter advice cage absurd amount doctor acoustic avoid letter advice " + "cage absurd amount doctor acoustic avoid letter always", + "107d7c02a5aa6f38c58083ff74f04c607c2d2c0ecc55501dadd72d025b751bc27fe913ff" + "b796f841c49b1d33b610cf0e91d3aa239027f5e99fe4ce9e5088cd65", + "ffffffffffffffffffffffffffffffffffffffffffffffff", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " + "when", + "0cd6e5d827bb62eb8fc1e262254223817fd068a74b5b449cc2f667c3f1f985a76379b433" + "48d952e2265b4cd129090758b3e3c2c49103b5051aac2eaeb890a528", + "0000000000000000000000000000000000000000000000000000000000000000", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon art", + "bda85446c68413707090a52022edd26a1c9462295029f2e60cd7c4f2bbd3097170af7a4d" + "73245cafa9c3cca8d561a7c3de6f5d4a10be8ed2a5e608d68f92fcc8", + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "legal winner thank year wave sausage worth useful legal winner thank " + "year wave sausage worth useful legal winner thank year wave sausage " + "worth title", + "bc09fca1804f7e69da93c2f2028eb238c227f2e9dda30cd63699232578480a4021b146ad" + "717fbb7e451ce9eb835f43620bf5c514db0f8add49f5d121449d3e87", + "8080808080808080808080808080808080808080808080808080808080808080", + "letter advice cage absurd amount doctor acoustic avoid letter advice " + "cage absurd amount doctor acoustic avoid letter advice cage absurd " + "amount doctor acoustic bless", + "c0c519bd0e91a2ed54357d9d1ebef6f5af218a153624cf4f2da911a0ed8f7a09e2ef61af" + "0aca007096df430022f7a2b6fb91661a9589097069720d015e4e982f", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " + "zoo zoo zoo zoo zoo vote", + "dd48c104698c30cfe2b6142103248622fb7bb0ff692eebb00089b32d22484e1613912f0a" + "5b694407be899ffd31ed3992c456cdf60f5d4564b8ba3f05a69890ad", + "77c2b00716cec7213839159e404db50d", + "jelly better achieve collect unaware mountain thought cargo oxygen act " + "hood bridge", + "b5b6d0127db1a9d2226af0c3346031d77af31e918dba64287a1b44b8ebf63cdd52676f67" + "2a290aae502472cf2d602c051f3e6f18055e84e4c43897fc4e51a6ff", + "b63a9c59a6e641f288ebc103017f1da9f8290b3da6bdef7b", + "renew stay biology evidence goat welcome casual join adapt armor " + "shuffle fault little machine walk stumble urge swap", + "9248d83e06f4cd98debf5b6f010542760df925ce46cf38a1bdb4e4de7d21f5c39366941c" + "69e1bdbf2966e0f6e6dbece898a0e2f0a4c2b3e640953dfe8b7bbdc5", + "3e141609b97933b66a060dcddc71fad1d91677db872031e85f4c015c5e7e8982", + "dignity pass list indicate nasty swamp pool script soccer toe leaf " + "photo multiply desk host tomato cradle drill spread actor shine dismiss " + "champion exotic", + "ff7f3184df8696d8bef94b6c03114dbee0ef89ff938712301d27ed8336ca89ef9635da20" + "af07d4175f2bf5f3de130f39c9d9e8dd0472489c19b1a020a940da67", + "0460ef47585604c5660618db2e6a7e7f", + "afford alter spike radar gate glance object seek swamp infant panel " + "yellow", + "65f93a9f36b6c85cbe634ffc1f99f2b82cbb10b31edc7f087b4f6cb9e976e9faf76ff41f" + "8f27c99afdf38f7a303ba1136ee48a4c1e7fcd3dba7aa876113a36e4", + "72f60ebac5dd8add8d2a25a797102c3ce21bc029c200076f", + "indicate race push merry suffer human cruise dwarf pole review arch " + "keep canvas theme poem divorce alter left", + "3bbf9daa0dfad8229786ace5ddb4e00fa98a044ae4c4975ffd5e094dba9e0bb289349dbe" + "2091761f30f382d4e35c4a670ee8ab50758d2c55881be69e327117ba", + "2c85efc7f24ee4573d2b81a6ec66cee209b2dcbd09d8eddc51e0215b0b68e416", + "clutch control vehicle tonight unusual clog visa ice plunge glimpse " + "recipe series open hour vintage deposit universe tip job dress radar " + "refuse motion taste", + "fe908f96f46668b2d5b37d82f558c77ed0d69dd0e7e043a5b0511c48c2f1064694a956f8" + "6360c93dd04052a8899497ce9e985ebe0c8c52b955e6ae86d4ff4449", + "eaebabb2383351fd31d703840b32e9e2", + "turtle front uncle idea crush write shrug there lottery flower risk " + "shell", + "bdfb76a0759f301b0b899a1e3985227e53b3f51e67e3f2a65363caedf3e32fde42a66c40" + "4f18d7b05818c95ef3ca1e5146646856c461c073169467511680876c", + "7ac45cfe7722ee6c7ba84fbc2d5bd61b45cb2fe5eb65aa78", + "kiss carry display unusual confirm curtain upgrade antique rotate hello " + "void custom frequent obey nut hole price segment", + "ed56ff6c833c07982eb7119a8f48fd363c4a9b1601cd2de736b01045c5eb8ab4f57b0794" + "03485d1c4924f0790dc10a971763337cb9f9c62226f64fff26397c79", + "4fa1a8bc3e6d80ee1316050e862c1812031493212b7ec3f3bb1b08f168cabeef", + "exile ask congress lamp submit jacket era scheme attend cousin alcohol " + "catch course end lucky hurt sentence oven short ball bird grab wing top", + "095ee6f817b4c2cb30a5a797360a81a40ab0f9a4e25ecd672a3f58a0b5ba0687c096a6b1" + "4d2c0deb3bdefce4f61d01ae07417d502429352e27695163f7447a8c", + "18ab19a9f54a9274f03e5209a2ac8a91", + "board flee heavy tunnel powder denial science ski answer betray cargo " + "cat", + "6eff1bb21562918509c73cb990260db07c0ce34ff0e3cc4a8cb3276129fbcb300bddfe00" + "5831350efd633909f476c45c88253276d9fd0df6ef48609e8bb7dca8", + "18a2e1d81b8ecfb2a333adcb0c17a5b9eb76cc5d05db91a4", + "board blade invite damage undo sun mimic interest slam gaze truly " + "inherit resist great inject rocket museum chief", + "f84521c777a13b61564234bf8f8b62b3afce27fc4062b51bb5e62bdfecb23864ee6ecf07" + "c1d5a97c0834307c5c852d8ceb88e7c97923c0a3b496bedd4e5f88a9", + "15da872c95a13dd738fbf50e427583ad61f18fd99f628c417a61cf8343c90419", + "beyond stage sleep clip because twist token leaf atom beauty genius " + "food business side grid unable middle armed observe pair crouch tonight " + "away coconut", + "b15509eaa2d09d3efd3e006ef42151b30367dc6e3aa5e44caba3fe4d3e352e65101fbdb8" + "6a96776b91946ff06f8eac594dc6ee1d3e82a42dfe1b40fef6bcc3fd", + 0, + 0, + 0, + }; + + const char **a, **b, **c, *m; + uint8_t seed[64]; + + a = vectors; + b = vectors + 1; + c = vectors + 2; + while (*a && *b && *c) { + m = mnemonic_from_data(fromhex(*a), strlen(*a) / 2); + ck_assert_str_eq(m, *b); + mnemonic_to_seed(m, "TREZOR", seed, 0); + ck_assert_mem_eq(seed, fromhex(*c), strlen(*c) / 2); +#if USE_BIP39_CACHE + // try second time to check whether caching results work + mnemonic_to_seed(m, "TREZOR", seed, 0); + ck_assert_mem_eq(seed, fromhex(*c), strlen(*c) / 2); +#endif + a += 3; + b += 3; + c += 3; + } +} +END_TEST + +START_TEST(test_mnemonic_check) { + static const char *vectors_ok[] = { + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon about", + "legal winner thank year wave sausage worth useful legal winner thank " + "yellow", + "letter advice cage absurd amount doctor acoustic avoid letter advice " + "cage above", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon abandon abandon abandon agent", + "legal winner thank year wave sausage worth useful legal winner thank " + "year wave sausage worth useful legal will", + "letter advice cage absurd amount doctor acoustic avoid letter advice " + "cage absurd amount doctor acoustic avoid letter always", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " + "when", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon art", + "legal winner thank year wave sausage worth useful legal winner thank " + "year wave sausage worth useful legal winner thank year wave sausage " + "worth title", + "letter advice cage absurd amount doctor acoustic avoid letter advice " + "cage absurd amount doctor acoustic avoid letter advice cage absurd " + "amount doctor acoustic bless", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " + "zoo zoo zoo zoo zoo vote", + "jelly better achieve collect unaware mountain thought cargo oxygen act " + "hood bridge", + "renew stay biology evidence goat welcome casual join adapt armor " + "shuffle fault little machine walk stumble urge swap", + "dignity pass list indicate nasty swamp pool script soccer toe leaf " + "photo multiply desk host tomato cradle drill spread actor shine dismiss " + "champion exotic", + "afford alter spike radar gate glance object seek swamp infant panel " + "yellow", + "indicate race push merry suffer human cruise dwarf pole review arch " + "keep canvas theme poem divorce alter left", + "clutch control vehicle tonight unusual clog visa ice plunge glimpse " + "recipe series open hour vintage deposit universe tip job dress radar " + "refuse motion taste", + "turtle front uncle idea crush write shrug there lottery flower risk " + "shell", + "kiss carry display unusual confirm curtain upgrade antique rotate hello " + "void custom frequent obey nut hole price segment", + "exile ask congress lamp submit jacket era scheme attend cousin alcohol " + "catch course end lucky hurt sentence oven short ball bird grab wing top", + "board flee heavy tunnel powder denial science ski answer betray cargo " + "cat", + "board blade invite damage undo sun mimic interest slam gaze truly " + "inherit resist great inject rocket museum chief", + "beyond stage sleep clip because twist token leaf atom beauty genius " + "food business side grid unable middle armed observe pair crouch tonight " + "away coconut", + 0, + }; + static const char *vectors_fail[] = { + "above abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon about", + "above winner thank year wave sausage worth useful legal winner thank " + "yellow", + "above advice cage absurd amount doctor acoustic avoid letter advice " + "cage above", + "above zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", + "above abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon abandon abandon abandon agent", + "above winner thank year wave sausage worth useful legal winner thank " + "year wave sausage worth useful legal will", + "above advice cage absurd amount doctor acoustic avoid letter advice " + "cage absurd amount doctor acoustic avoid letter always", + "above zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " + "when", + "above abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon art", + "above winner thank year wave sausage worth useful legal winner thank " + "year wave sausage worth useful legal winner thank year wave sausage " + "worth title", + "above advice cage absurd amount doctor acoustic avoid letter advice " + "cage absurd amount doctor acoustic avoid letter advice cage absurd " + "amount doctor acoustic bless", + "above zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " + "zoo zoo zoo zoo zoo zoo vote", + "above better achieve collect unaware mountain thought cargo oxygen act " + "hood bridge", + "above stay biology evidence goat welcome casual join adapt armor " + "shuffle fault little machine walk stumble urge swap", + "above pass list indicate nasty swamp pool script soccer toe leaf photo " + "multiply desk host tomato cradle drill spread actor shine dismiss " + "champion exotic", + "above alter spike radar gate glance object seek swamp infant panel " + "yellow", + "above race push merry suffer human cruise dwarf pole review arch keep " + "canvas theme poem divorce alter left", + "above control vehicle tonight unusual clog visa ice plunge glimpse " + "recipe series open hour vintage deposit universe tip job dress radar " + "refuse motion taste", + "above front uncle idea crush write shrug there lottery flower risk " + "shell", + "above carry display unusual confirm curtain upgrade antique rotate " + "hello void custom frequent obey nut hole price segment", + "above ask congress lamp submit jacket era scheme attend cousin alcohol " + "catch course end lucky hurt sentence oven short ball bird grab wing top", + "above flee heavy tunnel powder denial science ski answer betray cargo " + "cat", + "above blade invite damage undo sun mimic interest slam gaze truly " + "inherit resist great inject rocket museum chief", + "above stage sleep clip because twist token leaf atom beauty genius food " + "business side grid unable middle armed observe pair crouch tonight away " + "coconut", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon about", + "winner thank year wave sausage worth useful legal winner thank yellow", + "advice cage absurd amount doctor acoustic avoid letter advice cage " + "above", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon abandon abandon agent", + "winner thank year wave sausage worth useful legal winner thank year " + "wave sausage worth useful legal will", + "advice cage absurd amount doctor acoustic avoid letter advice cage " + "absurd amount doctor acoustic avoid letter always", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon art", + "winner thank year wave sausage worth useful legal winner thank year " + "wave sausage worth useful legal winner thank year wave sausage worth " + "title", + "advice cage absurd amount doctor acoustic avoid letter advice cage " + "absurd amount doctor acoustic avoid letter advice cage absurd amount " + "doctor acoustic bless", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " + "zoo zoo zoo zoo vote", + "better achieve collect unaware mountain thought cargo oxygen act hood " + "bridge", + "stay biology evidence goat welcome casual join adapt armor shuffle " + "fault little machine walk stumble urge swap", + "pass list indicate nasty swamp pool script soccer toe leaf photo " + "multiply desk host tomato cradle drill spread actor shine dismiss " + "champion exotic", + "alter spike radar gate glance object seek swamp infant panel yellow", + "race push merry suffer human cruise dwarf pole review arch keep canvas " + "theme poem divorce alter left", + "control vehicle tonight unusual clog visa ice plunge glimpse recipe " + "series open hour vintage deposit universe tip job dress radar refuse " + "motion taste", + "front uncle idea crush write shrug there lottery flower risk shell", + "carry display unusual confirm curtain upgrade antique rotate hello void " + "custom frequent obey nut hole price segment", + "ask congress lamp submit jacket era scheme attend cousin alcohol catch " + "course end lucky hurt sentence oven short ball bird grab wing top", + "flee heavy tunnel powder denial science ski answer betray cargo cat", + "blade invite damage undo sun mimic interest slam gaze truly inherit " + "resist great inject rocket museum chief", + "stage sleep clip because twist token leaf atom beauty genius food " + "business side grid unable middle armed observe pair crouch tonight away " + "coconut", + 0, + }; + + const char **m; + int r; + m = vectors_ok; + while (*m) { + r = mnemonic_check(*m); + ck_assert_int_eq(r, 1); + m++; + } + m = vectors_fail; + while (*m) { + r = mnemonic_check(*m); + ck_assert_int_eq(r, 0); + m++; + } +} +END_TEST + +START_TEST(test_mnemonic_to_bits) { + static const char *vectors[] = { + "00000000000000000000000000000000", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon about", + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "legal winner thank year wave sausage worth useful legal winner thank " + "yellow", + "80808080808080808080808080808080", + "letter advice cage absurd amount doctor acoustic avoid letter advice " + "cage above", + "ffffffffffffffffffffffffffffffff", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", + "000000000000000000000000000000000000000000000000", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon abandon abandon abandon agent", + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "legal winner thank year wave sausage worth useful legal winner thank " + "year wave sausage worth useful legal will", + "808080808080808080808080808080808080808080808080", + "letter advice cage absurd amount doctor acoustic avoid letter advice " + "cage absurd amount doctor acoustic avoid letter always", + "ffffffffffffffffffffffffffffffffffffffffffffffff", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " + "when", + "0000000000000000000000000000000000000000000000000000000000000000", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon art", + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "legal winner thank year wave sausage worth useful legal winner thank " + "year wave sausage worth useful legal winner thank year wave sausage " + "worth title", + "8080808080808080808080808080808080808080808080808080808080808080", + "letter advice cage absurd amount doctor acoustic avoid letter advice " + "cage absurd amount doctor acoustic avoid letter advice cage absurd " + "amount doctor acoustic bless", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " + "zoo zoo zoo zoo zoo vote", + "77c2b00716cec7213839159e404db50d", + "jelly better achieve collect unaware mountain thought cargo oxygen act " + "hood bridge", + "b63a9c59a6e641f288ebc103017f1da9f8290b3da6bdef7b", + "renew stay biology evidence goat welcome casual join adapt armor " + "shuffle fault little machine walk stumble urge swap", + "3e141609b97933b66a060dcddc71fad1d91677db872031e85f4c015c5e7e8982", + "dignity pass list indicate nasty swamp pool script soccer toe leaf " + "photo multiply desk host tomato cradle drill spread actor shine dismiss " + "champion exotic", + "0460ef47585604c5660618db2e6a7e7f", + "afford alter spike radar gate glance object seek swamp infant panel " + "yellow", + "72f60ebac5dd8add8d2a25a797102c3ce21bc029c200076f", + "indicate race push merry suffer human cruise dwarf pole review arch " + "keep canvas theme poem divorce alter left", + "2c85efc7f24ee4573d2b81a6ec66cee209b2dcbd09d8eddc51e0215b0b68e416", + "clutch control vehicle tonight unusual clog visa ice plunge glimpse " + "recipe series open hour vintage deposit universe tip job dress radar " + "refuse motion taste", + "eaebabb2383351fd31d703840b32e9e2", + "turtle front uncle idea crush write shrug there lottery flower risk " + "shell", + "7ac45cfe7722ee6c7ba84fbc2d5bd61b45cb2fe5eb65aa78", + "kiss carry display unusual confirm curtain upgrade antique rotate hello " + "void custom frequent obey nut hole price segment", + "4fa1a8bc3e6d80ee1316050e862c1812031493212b7ec3f3bb1b08f168cabeef", + "exile ask congress lamp submit jacket era scheme attend cousin alcohol " + "catch course end lucky hurt sentence oven short ball bird grab wing top", + "18ab19a9f54a9274f03e5209a2ac8a91", + "board flee heavy tunnel powder denial science ski answer betray cargo " + "cat", + "18a2e1d81b8ecfb2a333adcb0c17a5b9eb76cc5d05db91a4", + "board blade invite damage undo sun mimic interest slam gaze truly " + "inherit resist great inject rocket museum chief", + "15da872c95a13dd738fbf50e427583ad61f18fd99f628c417a61cf8343c90419", + "beyond stage sleep clip because twist token leaf atom beauty genius " + "food business side grid unable middle armed observe pair crouch tonight " + "away coconut", + 0, + 0, + }; + + const char **a, **b; + uint8_t mnemonic_bits[64]; + + a = vectors; + b = vectors + 1; + while (*a && *b) { + int mnemonic_bits_len = mnemonic_to_bits(*b, mnemonic_bits); + ck_assert_int_eq(mnemonic_bits_len % 33, 0); + mnemonic_bits_len = mnemonic_bits_len * 4 / 33; + ck_assert_uint_eq((size_t)mnemonic_bits_len, strlen(*a) / 2); + ck_assert_mem_eq(mnemonic_bits, fromhex(*a), mnemonic_bits_len); + a += 2; + b += 2; + } +} +END_TEST + +START_TEST(test_mnemonic_find_word) { + ck_assert_int_eq(-1, mnemonic_find_word("aaaa")); + ck_assert_int_eq(-1, mnemonic_find_word("zzzz")); + for (int i = 0; i < BIP39_WORDS; i++) { + const char *word = mnemonic_get_word(i); + int index = mnemonic_find_word(word); + ck_assert_int_eq(i, index); + } +} +END_TEST + +START_TEST(test_slip39_get_word) { + static const struct { + const int index; + const char *expected_word; + } vectors[] = {{573, "member"}, + {0, "academic"}, + {1023, "zero"}, + {245, "drove"}, + {781, "satoshi"}}; + for (size_t i = 0; i < (sizeof(vectors) / sizeof(*vectors)); i++) { + const char *a = get_word(vectors[i].index); + ck_assert_str_eq(a, vectors[i].expected_word); + } +} +END_TEST + +START_TEST(test_slip39_word_index) { + uint16_t index; + static const struct { + const char *word; + bool expected_result; + uint16_t expected_index; + } vectors[] = {{"academic", true, 0}, + {"zero", true, 1023}, + {"drove", true, 245}, + {"satoshi", true, 781}, + {"member", true, 573}, + // 9999 value is never checked since the word is not in list + {"fakeword", false, 9999}}; + for (size_t i = 0; i < (sizeof(vectors) / sizeof(*vectors)); i++) { + bool result = word_index(&index, vectors[i].word, sizeof(vectors[i].word)); + ck_assert_int_eq(result, vectors[i].expected_result); + if (result) { + ck_assert_uint_eq(index, vectors[i].expected_index); + } + } +} +END_TEST + +START_TEST(test_slip39_word_completion_mask) { + static const struct { + const uint16_t prefix; + const uint16_t expected_mask; + } vectors[] = { + {12, 0xFD}, // 011111101 + {21, 0xF8}, // 011111000 + {75, 0xAD}, // 010101101 + {4, 0x1F7}, // 111110111 + {738, 0x6D}, // 001101101 + {9, 0x6D}, // 001101101 + {0, 0x1FF}, // 111111111 + {10, 0x00}, // 000000000 + {255, 0x00}, // 000000000 + {203, 0x00}, // 000000000 + {9999, 0x00}, // 000000000 + {20000, 0x00}, // 000000000 + }; + for (size_t i = 0; i < (sizeof(vectors) / sizeof(*vectors)); i++) { + uint16_t mask = slip39_word_completion_mask(vectors[i].prefix); + ck_assert_uint_eq(mask, vectors[i].expected_mask); + } +} +END_TEST + +START_TEST(test_slip39_sequence_to_word) { + static const struct { + const uint16_t prefix; + const char *expected_word; + } vectors[] = { + {7945, "swimming"}, {646, "pipeline"}, {5, "laden"}, {34, "fiber"}, + {62, "ocean"}, {0, "academic"}, {10, NULL}, {255, NULL}, + {203, NULL}, {9999, NULL}, {20000, NULL}, + }; + for (size_t i = 0; i < (sizeof(vectors) / sizeof(*vectors)); i++) { + const char *word = button_sequence_to_word(vectors[i].prefix); + if (vectors[i].expected_word != NULL) { + ck_assert_str_eq(word, vectors[i].expected_word); + } else { + ck_assert_ptr_eq(word, NULL); + } + } +} +END_TEST + +START_TEST(test_slip39_word_completion) { + const char t9[] = {1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 5, + 6, 6, 6, 6, 7, 7, 8, 8, 8, 9, 9, 9, 9}; + for (size_t i = 0; i < WORDS_COUNT; ++i) { + const char *word = slip39_wordlist[i]; + uint16_t prefix = t9[word[0] - 'a']; + for (size_t j = 1; j < 4; ++j) { + uint16_t mask = slip39_word_completion_mask(prefix); + uint8_t next = t9[word[j] - 'a']; + ck_assert_uint_ne(mask & (1 << (next - 1)), 0); + prefix = prefix * 10 + next; + } + ck_assert_str_eq(button_sequence_to_word(prefix), word); + } +} +END_TEST + +START_TEST(test_shamir) { +#define SHAMIR_MAX_COUNT 16 + static const struct { + const uint8_t result[SHAMIR_MAX_LEN]; + uint8_t result_index; + const uint8_t share_indices[SHAMIR_MAX_COUNT]; + const uint8_t share_values[SHAMIR_MAX_COUNT][SHAMIR_MAX_LEN]; + uint8_t share_count; + size_t len; + bool ret; + } vectors[] = {{{7, 151, 168, 57, 186, 104, 218, 21, 209, 96, 106, + 152, 252, 35, 210, 208, 43, 47, 13, 21, 142, 122, + 24, 42, 149, 192, 95, 24, 240, 24, 148, 110}, + 0, + {2}, + { + {7, 151, 168, 57, 186, 104, 218, 21, 209, 96, 106, + 152, 252, 35, 210, 208, 43, 47, 13, 21, 142, 122, + 24, 42, 149, 192, 95, 24, 240, 24, 148, 110}, + }, + 1, + 32, + true}, + + {{53}, + 255, + {14, 10, 1, 13, 8, 7, 3, 11, 9, 4, 6, 0, 5, 12, 15, 2}, + { + {114}, + {41}, + {116}, + {67}, + {198}, + {109}, + {232}, + {39}, + {90}, + {241}, + {156}, + {75}, + {46}, + {181}, + {144}, + {175}, + }, + 16, + 1, + true}, + + {{91, 188, 226, 91, 254, 197, 225}, + 1, + {5, 1, 10}, + { + {129, 18, 104, 86, 236, 73, 176}, + {91, 188, 226, 91, 254, 197, 225}, + {69, 53, 151, 204, 224, 37, 19}, + }, + 3, + 7, + true}, + + {{0}, + 1, + {5, 1, 1}, + { + {129, 18, 104, 86, 236, 73, 176}, + {91, 188, 226, 91, 254, 197, 225}, + {69, 53, 151, 204, 224, 37, 19}, + }, + 3, + 7, + false}, + + {{0}, + 255, + {3, 12, 3}, + { + {100, 176, 99, 142, 115, 192, 138}, + {54, 139, 99, 172, 29, 137, 58}, + {216, 119, 222, 40, 87, 25, 147}, + }, + 3, + 7, + false}, + + {{163, 120, 30, 243, 179, 172, 196, 137, 119, 17}, + 3, + {1, 0, 12}, + {{80, 180, 198, 131, 111, 251, 45, 181, 2, 242}, + {121, 9, 79, 98, 132, 164, 9, 165, 19, 230}, + {86, 52, 173, 138, 189, 223, 122, 102, 248, 157}}, + 3, + 10, + true}}; + + for (size_t i = 0; i < (sizeof(vectors) / sizeof(*vectors)); ++i) { + uint8_t result[SHAMIR_MAX_LEN]; + const uint8_t *share_values[SHAMIR_MAX_COUNT]; + for (size_t j = 0; j < vectors[i].share_count; ++j) { + share_values[j] = vectors[i].share_values[j]; + } + ck_assert_int_eq(shamir_interpolate(result, vectors[i].result_index, + vectors[i].share_indices, share_values, + vectors[i].share_count, vectors[i].len), + vectors[i].ret); + if (vectors[i].ret == true) { + ck_assert_mem_eq(result, vectors[i].result, vectors[i].len); + } + } +} +END_TEST + +START_TEST(test_address) { + char address[36]; + uint8_t pub_key[65]; + + memcpy( + pub_key, + fromhex( + "0226659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), + 33); + ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "139MaMHp3Vjo8o4x8N1ZLWEtovLGvBsg6s"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "mhfJsQNnrXB3uuYZqvywARTDfuvyjg4RBh"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "MxiimznnxsqMfLKTQBL8Z2PoY9jKpjgkCu"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "LMNJqZbe89yrPbm7JVzrcXJf28hZ1rKPaH"); + ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, + address, sizeof(address)); + ck_assert_str_eq(address, "FXK52G2BbzRLaQ651U12o23DU5cEQdhvU6"); + ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2_RIPEMD, HASHER_SHA2D, + address, sizeof(address)); + ck_assert_str_eq(address, "34PyTHn74syS796eTgsyoLfwoBC3cwLn6p"); + + memcpy( + pub_key, + fromhex( + "025b1654a0e78d28810094f6c5a96b8efb8a65668b578f170ac2b1f83bc63ba856"), + 33); + ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "19Ywfm3witp6C1yBMy4NRYHY2347WCRBfQ"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "mp4txp8vXvFLy8So5Y2kFTVrt2epN6YzdP"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "N58JsQYveGueiZDgdnNwe4SSkGTAToutAY"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "LTmtvyMmoZ49SpfLY73fhZMJEFRPdyohKh"); + ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, + address, sizeof(address)); + ck_assert_str_eq(address, "Fdif7fnKHPVddczJF53qt45rgCL51yWN6x"); + ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2_RIPEMD, HASHER_SHA2D, + address, sizeof(address)); + ck_assert_str_eq(address, "35trq6eeuHf6VL9L8pQv46x3vegHnHoTuB"); + + memcpy( + pub_key, + fromhex( + "03433f246a12e6486a51ff08802228c61cf895175a9b49ed4766ea9a9294a3c7fe"), + 33); + ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "1FWE2bn3MWhc4QidcF6AvEWpK77sSi2cAP"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "mv2BKes2AY8rqXCFKp4Yk9j9B6iaMfWRLN"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "NB5bEFH2GtoAawy8t4Qk8kfj3LWvQs3MhB"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "LZjBHp5sSAwfKDQnnP5UCFaaXKV9YheGxQ"); + ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, + address, sizeof(address)); + ck_assert_str_eq(address, "FjfwUWWQv1P9W1jkVM5eNkK8yGPq5XyZZy"); + ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2_RIPEMD, HASHER_SHA2D, + address, sizeof(address)); + ck_assert_str_eq(address, "3456DYaKUWuY6RWWw8Hp5CftHLcQN29h9Y"); + + memcpy( + pub_key, + fromhex( + "03aeb03abeee0f0f8b4f7a5d65ce31f9570cef9f72c2dd8a19b4085a30ab033d48"), + 33); + ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "1yrZb8dhdevoqpUEGi2tUccUEeiMKeLcs"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "mgVoreDcWf6BaxJ5wqgQiPpwLEFRLSr8U8"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "MwZDmEdcd1kVLP4yW62c6zmXCU3mNbveDo"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "LLCopoSTnHtz4eWdQQhLAVgNgT1zTi4QBK"); + ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, + address, sizeof(address)); + ck_assert_str_eq(address, "FW9a1Vs1G8LUFSqb7NhWLzQw8PvfwAxmxA"); + ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2_RIPEMD, HASHER_SHA2D, + address, sizeof(address)); + ck_assert_str_eq(address, "3DBU4tJ9tkMR9fnmCtjW48kjvseoNLQZXd"); + + memcpy( + pub_key, + fromhex( + "0496e8f2093f018aff6c2e2da5201ee528e2c8accbf9cac51563d33a7bb74a016054" + "201c025e2a5d96b1629b95194e806c63eb96facaedc733b1a4b70ab3b33e3a"), + 65); + ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "194SZbL75xCCGBbKtMsyWLE5r9s2V6mhVM"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "moaPreR5tydT3J4wbvrMLFSQi9TjPCiZc6"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "N4domEq61LHkniqqABCYirNzaPG5NRU8GH"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "LTHPpodwAcSFWzHV4VsGnMHr4NEJajMnKX"); + ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, + address, sizeof(address)); + ck_assert_str_eq(address, "FdEA1W4UeSsjhncSmTsSxr2QWK8z2xGkjc"); + + memcpy( + pub_key, + fromhex( + "0498010f8a687439ff497d3074beb4519754e72c4b6220fb669224749591dde416f3" + "961f8ece18f8689bb32235e436874d2174048b86118a00afbd5a4f33a24f0f"), + 65); + ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "1A2WfBD4BJFwYHFPc5KgktqtbdJLBuVKc4"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "mpYTxEJ2zKhCKPj1KeJ4ap4DTcu39T3uzD"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "N5bsrpi36gMW4pVtsteFyQzoKrhPE7nkxK"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "LUFTvPWtFxVzo5wYnDJz2uueoqfcMYiuxH"); + ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, + address, sizeof(address)); + ck_assert_str_eq(address, "FeCE75wRjnwUytGWVBKADQeDFnaHpJ8t3B"); + + memcpy( + pub_key, + fromhex( + "04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2" + "a59ebddbdac9e87b816307a7ed5b826b8f40b92719086238e1bebf19b77a4d"), + 65); + ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "19J81hrPnQxg9UGx45ibTieCkb2ttm8CLL"); + ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "mop5JkwNbSPvvakZmegyHdrXcadbjLazww"); + ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "N4sVDMMNho4Eg1XTKu3AgEo7UpRwq3aNbn"); + ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "LTX5GvADs5CjQGy7EDhtjjhxxoQB2Uhicd"); + ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, + address, sizeof(address)); + ck_assert_str_eq(address, "FdTqTcamLueDb5J4wBi4vESXQkJrS54H6k"); +} +END_TEST + +START_TEST(test_pubkey_validity) { + uint8_t pub_key[65]; + curve_point pub; + int res; + const ecdsa_curve *curve = &secp256k1; + + memcpy( + pub_key, + fromhex( + "0226659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), + 33); + res = ecdsa_read_pubkey(curve, pub_key, &pub); + ck_assert_int_eq(res, 1); + + memcpy( + pub_key, + fromhex( + "025b1654a0e78d28810094f6c5a96b8efb8a65668b578f170ac2b1f83bc63ba856"), + 33); + res = ecdsa_read_pubkey(curve, pub_key, &pub); + ck_assert_int_eq(res, 1); + + memcpy( + pub_key, + fromhex( + "03433f246a12e6486a51ff08802228c61cf895175a9b49ed4766ea9a9294a3c7fe"), + 33); + res = ecdsa_read_pubkey(curve, pub_key, &pub); + ck_assert_int_eq(res, 1); + + memcpy( + pub_key, + fromhex( + "03aeb03abeee0f0f8b4f7a5d65ce31f9570cef9f72c2dd8a19b4085a30ab033d48"), + 33); + res = ecdsa_read_pubkey(curve, pub_key, &pub); + ck_assert_int_eq(res, 1); + + memcpy( + pub_key, + fromhex( + "0496e8f2093f018aff6c2e2da5201ee528e2c8accbf9cac51563d33a7bb74a016054" + "201c025e2a5d96b1629b95194e806c63eb96facaedc733b1a4b70ab3b33e3a"), + 65); + res = ecdsa_read_pubkey(curve, pub_key, &pub); + ck_assert_int_eq(res, 1); + + memcpy( + pub_key, + fromhex( + "0498010f8a687439ff497d3074beb4519754e72c4b6220fb669224749591dde416f3" + "961f8ece18f8689bb32235e436874d2174048b86118a00afbd5a4f33a24f0f"), + 65); + res = ecdsa_read_pubkey(curve, pub_key, &pub); + ck_assert_int_eq(res, 1); + + memcpy( + pub_key, + fromhex( + "04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2" + "a59ebddbdac9e87b816307a7ed5b826b8f40b92719086238e1bebf19b77a4d"), + 65); + res = ecdsa_read_pubkey(curve, pub_key, &pub); + ck_assert_int_eq(res, 1); + + memcpy( + pub_key, + fromhex( + "04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2" + "a59ebddbdac9e87b816307a7ed5b826b8f40b92719086238e1bebf00000000"), + 65); + res = ecdsa_read_pubkey(curve, pub_key, &pub); + ck_assert_int_eq(res, 0); + + memcpy( + pub_key, + fromhex( + "04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2" + "a59ebddbdac9e87b816307a7ed5b8211111111111111111111111111111111"), + 65); + res = ecdsa_read_pubkey(curve, pub_key, &pub); + ck_assert_int_eq(res, 0); + + memcpy(pub_key, fromhex("00"), 1); + res = ecdsa_read_pubkey(curve, pub_key, &pub); + ck_assert_int_eq(res, 0); +} +END_TEST + +START_TEST(test_pubkey_uncompress) { + uint8_t pub_key[65]; + uint8_t uncompressed[65]; + int res; + const ecdsa_curve *curve = &secp256k1; + + memcpy( + pub_key, + fromhex( + "0226659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), + 33); + res = ecdsa_uncompress_pubkey(curve, pub_key, uncompressed); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq( + uncompressed, + fromhex( + "0426659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37b3" + "cfbad6b39a8ce8cb3a675f53b7b57e120fe067b8035d771fd99e3eba7cf4de"), + 65); + + memcpy( + pub_key, + fromhex( + "03433f246a12e6486a51ff08802228c61cf895175a9b49ed4766ea9a9294a3c7fe"), + 33); + res = ecdsa_uncompress_pubkey(curve, pub_key, uncompressed); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq( + uncompressed, + fromhex( + "04433f246a12e6486a51ff08802228c61cf895175a9b49ed4766ea9a9294a3c7feeb" + "4c25bcb840f720a16e8857a011e6b91e0ab2d03dbb5f9762844bb21a7b8ca7"), + 65); + + memcpy( + pub_key, + fromhex( + "0496e8f2093f018aff6c2e2da5201ee528e2c8accbf9cac51563d33a7bb74a016054" + "201c025e2a5d96b1629b95194e806c63eb96facaedc733b1a4b70ab3b33e3a"), + 65); + res = ecdsa_uncompress_pubkey(curve, pub_key, uncompressed); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq( + uncompressed, + fromhex( + "0496e8f2093f018aff6c2e2da5201ee528e2c8accbf9cac51563d33a7bb74a016054" + "201c025e2a5d96b1629b95194e806c63eb96facaedc733b1a4b70ab3b33e3a"), + 65); + + memcpy(pub_key, fromhex("00"), 1); + res = ecdsa_uncompress_pubkey(curve, pub_key, uncompressed); + ck_assert_int_eq(res, 0); +} +END_TEST + +START_TEST(test_wif) { + uint8_t priv_key[32]; + char wif[53]; + + memcpy( + priv_key, + fromhex( + "1111111111111111111111111111111111111111111111111111111111111111"), + 32); + ecdsa_get_wif(priv_key, 0x80, HASHER_SHA2D, wif, sizeof(wif)); + ck_assert_str_eq(wif, "KwntMbt59tTsj8xqpqYqRRWufyjGunvhSyeMo3NTYpFYzZbXJ5Hp"); + ecdsa_get_wif(priv_key, 0xEF, HASHER_SHA2D, wif, sizeof(wif)); + ck_assert_str_eq(wif, "cN9spWsvaxA8taS7DFMxnk1yJD2gaF2PX1npuTpy3vuZFJdwavaw"); + + memcpy( + priv_key, + fromhex( + "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"), + 32); + ecdsa_get_wif(priv_key, 0x80, HASHER_SHA2D, wif, sizeof(wif)); + ck_assert_str_eq(wif, "L4ezQvyC6QoBhxB4GVs9fAPhUKtbaXYUn8YTqoeXwbevQq4U92vN"); + ecdsa_get_wif(priv_key, 0xEF, HASHER_SHA2D, wif, sizeof(wif)); + ck_assert_str_eq(wif, "cV1ysqy3XUVSsPeKeugH2Utm6ZC1EyeArAgvxE73SiJvfa6AJng7"); + + memcpy( + priv_key, + fromhex( + "47f7616ea6f9b923076625b4488115de1ef1187f760e65f89eb6f4f7ff04b012"), + 32); + ecdsa_get_wif(priv_key, 0x80, HASHER_SHA2D, wif, sizeof(wif)); + ck_assert_str_eq(wif, "KydbzBtk6uc7M6dXwEgTEH2sphZxSPbmDSz6kUUHi4eUpSQuhEbq"); + ecdsa_get_wif(priv_key, 0xEF, HASHER_SHA2D, wif, sizeof(wif)); + ck_assert_str_eq(wif, "cPzbT6tbXyJNWY6oKeVabbXwSvsN6qhTHV8ZrtvoDBJV5BRY1G5Q"); +} +END_TEST + +START_TEST(test_address_decode) { + int res; + uint8_t decode[MAX_ADDR_RAW_SIZE]; + + res = ecdsa_address_decode("1JwSSubhmg6iPtRjtyqhUYYH7bZg3Lfy1T", 0, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, + fromhex("00c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); + + res = ecdsa_address_decode("myTPjxggahXyAzuMcYp5JTkbybANyLsYBW", 111, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, + fromhex("6fc4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); + + res = ecdsa_address_decode("NEWoeZ6gh4CGvRgFAoAGh4hBqpxizGT6gZ", 52, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, + fromhex("34c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); + + res = ecdsa_address_decode("LdAPi7uXrLLmeh7u57pzkZc3KovxEDYRJq", 48, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, + fromhex("30c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); + + res = ecdsa_address_decode("1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8", 0, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, + fromhex("0079fbfc3f34e7745860d76137da68f362380c606c"), 21); + + res = ecdsa_address_decode("mrdwvWkma2D6n9mGsbtkazedQQuoksnqJV", 111, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, + fromhex("6f79fbfc3f34e7745860d76137da68f362380c606c"), 21); + + res = ecdsa_address_decode("N7hMq7AmgNsQXaYARrEwybbDGei9mcPNqr", 52, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, + fromhex("3479fbfc3f34e7745860d76137da68f362380c606c"), 21); + + res = ecdsa_address_decode("LWLwtfycqf1uFqypLAug36W4kdgNwrZdNs", 48, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, + fromhex("3079fbfc3f34e7745860d76137da68f362380c606c"), 21); + + // invalid char + res = ecdsa_address_decode("1JwSSubhmg6i000jtyqhUYYH7bZg3Lfy1T", 0, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 0); + + // invalid address + res = ecdsa_address_decode("1111Subhmg6iPtRjtyqhUYYH7bZg3Lfy1T", 0, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 0); + + // invalid version + res = ecdsa_address_decode("LWLwtfycqf1uFqypLAug36W4kdgNwrZdNs", 0, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 0); +} +END_TEST + +START_TEST(test_ecdsa_der) { + static const struct { + const char *r; + const char *s; + const char *der; + } vectors[] = { + { + "9a0b7be0d4ed3146ee262b42202841834698bb3ee39c24e7437df208b8b70771", + "2b79ab1e7736219387dffe8d615bbdba87e11477104b867ef47afed1a5ede781", + "30450221009a0b7be0d4ed3146ee262b42202841834698bb3ee39c24e7437df208b8" + "b7077102202b79ab1e7736219387dffe8d615bbdba87e11477104b867ef47afed1a5" + "ede781", + }, + { + "6666666666666666666666666666666666666666666666666666666666666666", + "7777777777777777777777777777777777777777777777777777777777777777", + "30440220666666666666666666666666666666666666666666666666666666666666" + "66660220777777777777777777777777777777777777777777777777777777777777" + "7777", + }, + { + "6666666666666666666666666666666666666666666666666666666666666666", + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "30450220666666666666666666666666666666666666666666666666666666666666" + "6666022100eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + "eeeeee", + }, + { + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "7777777777777777777777777777777777777777777777777777777777777777", + "3045022100eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + "eeeeee02207777777777777777777777777777777777777777777777777777777777" + "777777", + }, + { + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "3046022100eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + "eeeeee022100ffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "ffffffff", + }, + { + "0000000000000000000000000000000000000000000000000000000000000066", + "0000000000000000000000000000000000000000000000000000000000000077", + "3006020166020177", + }, + { + "0000000000000000000000000000000000000000000000000000000000000066", + "00000000000000000000000000000000000000000000000000000000000000ee", + "3007020166020200ee", + }, + { + "00000000000000000000000000000000000000000000000000000000000000ee", + "0000000000000000000000000000000000000000000000000000000000000077", + "3007020200ee020177", + }, + { + "00000000000000000000000000000000000000000000000000000000000000ee", + "00000000000000000000000000000000000000000000000000000000000000ff", + "3008020200ee020200ff", + }, + { + "0000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000", + "3006020100020100", + }, + }; + + uint8_t sig[64]; + uint8_t der[72]; + uint8_t out[72]; + for (size_t i = 0; i < (sizeof(vectors) / sizeof(*vectors)); ++i) { + size_t der_len = strlen(vectors[i].der) / 2; + memcpy(der, fromhex(vectors[i].der), der_len); + memcpy(sig, fromhex(vectors[i].r), 32); + memcpy(sig + 32, fromhex(vectors[i].s), 32); + ck_assert_int_eq(ecdsa_sig_to_der(sig, out), der_len); + ck_assert_mem_eq(out, der, der_len); + ck_assert_int_eq(ecdsa_sig_from_der(der, der_len, out), 0); + ck_assert_mem_eq(out, sig, 64); + } +} +END_TEST + +static void test_codepoints_curve(const ecdsa_curve *curve) { + int i, j; + bignum256 a; + curve_point p, p1; + for (i = 0; i < 64; i++) { + for (j = 0; j < 8; j++) { + bn_zero(&a); + a.val[(4 * i) / BN_BITS_PER_LIMB] = (uint32_t)(2 * j + 1) + << (4 * i % BN_BITS_PER_LIMB); + bn_normalize(&a); + // note that this is not a trivial test. We add 64 curve + // points in the table to get that particular curve point. + scalar_multiply(curve, &a, &p); + ck_assert_mem_eq(&p, &curve->cp[i][j], sizeof(curve_point)); + bn_zero(&p.y); // test that point_multiply curve, is not a noop + point_multiply(curve, &a, &curve->G, &p); + ck_assert_mem_eq(&p, &curve->cp[i][j], sizeof(curve_point)); + // mul 2 test. this should catch bugs + bn_lshift(&a); + bn_mod(&a, &curve->order); + p1 = curve->cp[i][j]; + point_double(curve, &p1); + // note that this is not a trivial test. We add 64 curve + // points in the table to get that particular curve point. + scalar_multiply(curve, &a, &p); + ck_assert_mem_eq(&p, &p1, sizeof(curve_point)); + bn_zero(&p.y); // test that point_multiply curve, is not a noop + point_multiply(curve, &a, &curve->G, &p); + ck_assert_mem_eq(&p, &p1, sizeof(curve_point)); + } + } +} + +START_TEST(test_codepoints_secp256k1) { test_codepoints_curve(&secp256k1); } +END_TEST +START_TEST(test_codepoints_nist256p1) { test_codepoints_curve(&nist256p1); } +END_TEST + +static void test_mult_border_cases_curve(const ecdsa_curve *curve) { + bignum256 a; + curve_point p; + curve_point expected; + bn_zero(&a); // a == 0 + scalar_multiply(curve, &a, &p); + ck_assert(point_is_infinity(&p)); + point_multiply(curve, &a, &p, &p); + ck_assert(point_is_infinity(&p)); + point_multiply(curve, &a, &curve->G, &p); + ck_assert(point_is_infinity(&p)); + + bn_addi(&a, 1); // a == 1 + scalar_multiply(curve, &a, &p); + ck_assert_mem_eq(&p, &curve->G, sizeof(curve_point)); + point_multiply(curve, &a, &curve->G, &p); + ck_assert_mem_eq(&p, &curve->G, sizeof(curve_point)); + + bn_subtract(&curve->order, &a, &a); // a == -1 + expected = curve->G; + bn_subtract(&curve->prime, &expected.y, &expected.y); + scalar_multiply(curve, &a, &p); + ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); + point_multiply(curve, &a, &curve->G, &p); + ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); + + bn_subtract(&curve->order, &a, &a); + bn_addi(&a, 1); // a == 2 + expected = curve->G; + point_add(curve, &expected, &expected); + scalar_multiply(curve, &a, &p); + ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); + point_multiply(curve, &a, &curve->G, &p); + ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); + + bn_subtract(&curve->order, &a, &a); // a == -2 + expected = curve->G; + point_add(curve, &expected, &expected); + bn_subtract(&curve->prime, &expected.y, &expected.y); + scalar_multiply(curve, &a, &p); + ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); + point_multiply(curve, &a, &curve->G, &p); + ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); +} + +START_TEST(test_mult_border_cases_secp256k1) { + test_mult_border_cases_curve(&secp256k1); +} +END_TEST +START_TEST(test_mult_border_cases_nist256p1) { + test_mult_border_cases_curve(&nist256p1); +} +END_TEST + +static void test_scalar_mult_curve(const ecdsa_curve *curve) { + int i; + // get two "random" numbers + bignum256 a = curve->G.x; + bignum256 b = curve->G.y; + curve_point p1, p2, p3; + for (i = 0; i < 1000; i++) { + /* test distributivity: (a + b)G = aG + bG */ + bn_mod(&a, &curve->order); + bn_mod(&b, &curve->order); + scalar_multiply(curve, &a, &p1); + scalar_multiply(curve, &b, &p2); + bn_addmod(&a, &b, &curve->order); + bn_mod(&a, &curve->order); + scalar_multiply(curve, &a, &p3); + point_add(curve, &p1, &p2); + ck_assert_mem_eq(&p2, &p3, sizeof(curve_point)); + // new "random" numbers + a = p3.x; + b = p3.y; + } +} + +START_TEST(test_scalar_mult_secp256k1) { test_scalar_mult_curve(&secp256k1); } +END_TEST +START_TEST(test_scalar_mult_nist256p1) { test_scalar_mult_curve(&nist256p1); } +END_TEST + +static void test_point_mult_curve(const ecdsa_curve *curve) { + int i; + // get two "random" numbers and a "random" point + bignum256 a = curve->G.x; + bignum256 b = curve->G.y; + curve_point p = curve->G; + curve_point p1, p2, p3; + for (i = 0; i < 200; i++) { + /* test distributivity: (a + b)P = aP + bP */ + bn_mod(&a, &curve->order); + bn_mod(&b, &curve->order); + point_multiply(curve, &a, &p, &p1); + point_multiply(curve, &b, &p, &p2); + bn_addmod(&a, &b, &curve->order); + bn_mod(&a, &curve->order); + point_multiply(curve, &a, &p, &p3); + point_add(curve, &p1, &p2); + ck_assert_mem_eq(&p2, &p3, sizeof(curve_point)); + // new "random" numbers and a "random" point + a = p1.x; + b = p1.y; + p = p3; + } +} + +START_TEST(test_point_mult_secp256k1) { test_point_mult_curve(&secp256k1); } +END_TEST +START_TEST(test_point_mult_nist256p1) { test_point_mult_curve(&nist256p1); } +END_TEST + +static void test_scalar_point_mult_curve(const ecdsa_curve *curve) { + int i; + // get two "random" numbers + bignum256 a = curve->G.x; + bignum256 b = curve->G.y; + curve_point p1, p2; + for (i = 0; i < 200; i++) { + /* test commutativity and associativity: + * a(bG) = (ab)G = b(aG) + */ + bn_mod(&a, &curve->order); + bn_mod(&b, &curve->order); + scalar_multiply(curve, &a, &p1); + point_multiply(curve, &b, &p1, &p1); + + scalar_multiply(curve, &b, &p2); + point_multiply(curve, &a, &p2, &p2); + + ck_assert_mem_eq(&p1, &p2, sizeof(curve_point)); + + bn_multiply(&a, &b, &curve->order); + bn_mod(&b, &curve->order); + scalar_multiply(curve, &b, &p2); + + ck_assert_mem_eq(&p1, &p2, sizeof(curve_point)); + + // new "random" numbers + a = p1.x; + b = p1.y; + } +} + +START_TEST(test_scalar_point_mult_secp256k1) { + test_scalar_point_mult_curve(&secp256k1); +} +END_TEST +START_TEST(test_scalar_point_mult_nist256p1) { + test_scalar_point_mult_curve(&nist256p1); +} +END_TEST + +START_TEST(test_ed25519) { + // test vectors from + // https://github.com/torproject/tor/blob/master/src/test/ed25519_vectors.inc + static const char *vectors[] = { + "26c76712d89d906e6672dafa614c42e5cb1caac8c6568e4d2493087db51f0d3" + "6", // secret + "c2247870536a192d142d056abefca68d6193158e7c1a59c1654c954eccaff89" + "4", // public + "d23188eac3773a316d46006fa59c095060be8b1a23582a0dd99002a82a0662bd" + "246d8449e172e04c5f46ac0d1404cebe4aabd8a75a1457aa06cae41f3334f10" + "4", // selfsig + "fba7a5366b5cb98c2667a18783f5cf8f4f8d1a2ce939ad22a6e685edde85128" + "d", + "1519a3b15816a1aafab0b213892026ebf5c0dc232c58b21088d88cb90e9b940" + "d", + "3a785ac1201c97ee5f6f0d99323960d5f264c7825e61aa7cc81262f15bef75eb" + "4fa5723add9b9d45b12311b6d403eb3ac79ff8e4e631fc3cd51e4ad2185b200" + "b", + "67e3aa7a14fac8445d15e45e38a523481a69ae35513c9e4143eb1c2196729a0" + "e", + "081faa81992e360ea22c06af1aba096e7a73f1c665bc8b3e4e531c46455fd1d" + "d", + "cf431fd0416bfbd20c9d95ef9b723e2acddffb33900edc72195dea95965d52d8" + "88d30b7b8a677c0bd8ae1417b1e1a0ec6700deadd5d8b54b6689275e04a0450" + "9", + "d51385942033a76dc17f089a59e6a5a7fe80d9c526ae8ddd8c3a506b99d3d0a" + "6", + "73cfa1189a723aad7966137cbffa35140bb40d7e16eae4c40b79b5f0360dd65" + "a", + "2375380cd72d1a6c642aeddff862be8a5804b916acb72c02d9ed052c1561881a" + "a658a5af856fcd6d43113e42f698cd6687c99efeef7f2ce045824440d26c5d0" + "0", + "5c8eac469bb3f1b85bc7cd893f52dc42a9ab66f1b02b5ce6a68e9b175d3bb43" + "3", + "66c1a77104d86461b6f98f73acf3cd229c80624495d2d74d6fda1e940080a96" + "b", + "2385a472f599ca965bbe4d610e391cdeabeba9c336694b0d6249e551458280be" + "122c2441dd9746a81bbfb9cd619364bab0df37ff4ceb7aefd24469c39d3bc50" + "8", + "eda433d483059b6d1ff8b7cfbd0fe406bfb23722c8f3c8252629284573b61b8" + "6", + "d21c294db0e64cb2d8976625786ede1d9754186ae8197a64d72f68c792eecc1" + "9", + "e500cd0b8cfff35442f88008d894f3a2fa26ef7d3a0ca5714ae0d3e2d40caae5" + "8ba7cdf69dd126994dad6be536fcda846d89dd8138d1683cc144c8853dce760" + "7", + "4377c40431c30883c5fbd9bc92ae48d1ed8a47b81d13806beac5351739b5533" + "d", + "c4d58b4cf85a348ff3d410dd936fa460c4f18da962c01b1963792b9dcc8a6ea" + "6", + "d187b9e334b0050154de10bf69b3e4208a584e1a65015ec28b14bcc252cf84b8" + "baa9c94867daa60f2a82d09ba9652d41e8dde292b624afc8d2c26441b95e3c0" + "e", + "c6bbcce615839756aed2cc78b1de13884dd3618f48367a17597a16c1cd7a290" + "b", + "95126f14d86494020665face03f2d42ee2b312a85bc729903eb17522954a1c4" + "a", + "815213640a643d198bd056e02bba74e1c8d2d931643e84497adf3347eb485079" + "c9afe0afce9284cdc084946b561abbb214f1304ca11228ff82702185cf28f60" + "d", + 0, + 0, + 0, + }; + const char **ssk, **spk, **ssig; + ssk = vectors; + spk = vectors + 1; + ssig = vectors + 2; + ed25519_public_key pk; + ed25519_secret_key sk; + ed25519_signature sig; + while (*ssk && *spk && *ssig) { + memcpy(sk, fromhex(*ssk), 32); + MARK_SECRET_DATA(sk, sizeof(sk)); + + ed25519_publickey(sk, pk); + UNMARK_SECRET_DATA(pk, sizeof(pk)); + ck_assert_mem_eq(pk, fromhex(*spk), 32); + + ed25519_sign(pk, 32, sk, sig); + UNMARK_SECRET_DATA(sig, sizeof(sig)); + ck_assert_mem_eq(sig, fromhex(*ssig), 64); + + ssk += 3; + spk += 3; + ssig += 3; + + UNMARK_SECRET_DATA(sk, sizeof(sk)); + } +} +END_TEST + +// test vectors from +// https://raw.githubusercontent.com/NemProject/nem-test-vectors/master/2.test-sign.dat +START_TEST(test_ed25519_keccak) { + static const struct { + const char *private_key; + const char *public_key; + const char *signature; + size_t length; + const char *data; + } tests[] = { + { + "abf4cf55a2b3f742d7543d9cc17f50447b969e6e06f5ea9195d428ab12b7318d", + "8a558c728c21c126181e5e654b404a45b4f0137ce88177435a69978cc6bec1f4", + "d9cec0cc0e3465fab229f8e1d6db68ab9cc99a18cb0435f70deb6100948576cd5c0a" + "a1feb550bdd8693ef81eb10a556a622db1f9301986827b96716a7134230c", + 41, + "8ce03cd60514233b86789729102ea09e867fc6d964dea8c2018ef7d0a2e0e24bf7e3" + "48e917116690b9", + }, + { + "6aa6dad25d3acb3385d5643293133936cdddd7f7e11818771db1ff2f9d3f9215", + "bbc8cbb43dda3ecf70a555981a351a064493f09658fffe884c6fab2a69c845c6", + "98bca58b075d1748f1c3a7ae18f9341bc18e90d1beb8499e8a654c65d8a0b4fbd2e0" + "84661088d1e5069187a2811996ae31f59463668ef0f8cb0ac46a726e7902", + 49, + "e4a92208a6fc52282b620699191ee6fb9cf04daf48b48fd542c5e43daa9897763a19" + "9aaa4b6f10546109f47ac3564fade0", + }, + { + "8e32bc030a4c53de782ec75ba7d5e25e64a2a072a56e5170b77a4924ef3c32a9", + "72d0e65f1ede79c4af0ba7ec14204e10f0f7ea09f2bc43259cd60ea8c3a087e2", + "ef257d6e73706bb04878875c58aa385385bf439f7040ea8297f7798a0ea30c1c5eff" + "5ddc05443f801849c68e98111ae65d088e726d1d9b7eeca2eb93b677860c", + 40, + "13ed795344c4448a3b256f23665336645a853c5c44dbff6db1b9224b5303b6447fbf" + "8240a2249c55", + }, + { + "c83ce30fcb5b81a51ba58ff827ccbc0142d61c13e2ed39e78e876605da16d8d7", + "3ec8923f9ea5ea14f8aaa7e7c2784653ed8c7de44e352ef9fc1dee81fc3fa1a3", + "0c684e71b35fed4d92b222fc60561db34e0d8afe44bdd958aaf4ee965911bef59912" + "36f3e1bced59fc44030693bcac37f34d29e5ae946669dc326e706e81b804", + 49, + "a2704638434e9f7340f22d08019c4c8e3dbee0df8dd4454a1d70844de11694f4c8ca" + "67fdcb08fed0cec9abb2112b5e5f89", + }, + { + "2da2a0aae0f37235957b51d15843edde348a559692d8fa87b94848459899fc27", + "d73d0b14a9754eec825fcb25ef1cfa9ae3b1370074eda53fc64c22334a26c254", + "6f17f7b21ef9d6907a7ab104559f77d5a2532b557d95edffd6d88c073d87ac00fc83" + "8fc0d05282a0280368092a4bd67e95c20f3e14580be28d8b351968c65e03", + 40, + "d2488e854dbcdfdb2c9d16c8c0b2fdbc0abb6bac991bfe2b14d359a6bc99d66c00fd" + "60d731ae06d0", + }, + { + "0c066261fb1b18ebf2a9bcdeda81eb47d5a3745438b3d0b9d19b75885ad0a154", + "2e5773f0e725024bc0359ce93a44e15d6507e7b160b6c592200385fee4a269cf", + "13b5d2dd1b04f62cc2ec1544fed256423684f2dbca4538ceddda1d15c59dc7196c87" + "840ea303ea30f4f6914a6ec9167841980c1d717f47fd641225068de88507", + 41, + "f15cb706e29fcfbcb324e38cbac62bb355deddb845c142e970f0c029ea4d05e59fd6" + "adf85573cf1775", + }, + { + "ef3d8e22a592f04c3a31aa736e10901757a821d053f1a49a525b4ec91eacdee3", + "72a2b4910a502b30e13a96aba643c59c79328c1ba1462be6f254e817ef157fee", + "95f2437a0210d2d2f125a3c377ed666c0d596cd104185e70204924a182a11a6eb3bd" + "ba4395bbfc3f4e827d38805752657ee52d1ce0f17e70f59bfd4999282509", + 50, + "6c3e4387345740b8d62cf0c9dec48f98c292539431b2b54020d8072d9cb55f0197f7" + "d99ff066afcf9e41ea8b7aea78eb082d", + }, + { + "f7fb79743e9ba957d2a4f1bd95ceb1299552abecaf758bf840d2dc2c09f3e3cb", + "8b7d7531280f76a8abac8293d87508e3953894087112ae01b6ad32485d4e9b67", + "c868ecf31cee783fe8799ac7e6a662431c822967351d8b79687f4ddf608f79a080c4" + "ff9eed4fdee8c99fe1be905f734cae2a172f1cfdb00771625c0695a5260e", + 42, + "55d8e60c307ee533b1af9ff677a2de40a6eace722bcc9eb5d79907b420e533bc06db" + "674dafbd9f43d672", + }, + { + "8cc9a2469a77fad18b44b871b2b6932cd354641d2d1e84403f746c4fff829791", + "aed5da202d4983dac560faf6704dc76ac111616318570e244043e82ed1bbcd2b", + "aee9616db4135150818eaffa3e4503c2d7e9e834847a4c7d0a8856e952761d361a65" + "7104d36950c9b75770ded00d56a96e06f383fa2406bc935dcf51f272300e", + 42, + "d9b8be2f71b83261304e333d6e35563dc3c36c2eb5a23e1461b6e95aa7c6f381f9c3" + "bd39deaa1b6df2f9", + }, + { + "a247abbef0c1affbf021d1aff128888550532fc0edd77bc39f6ef5312317ec47", + "98ededbad1e5ad7a0d5a0cf4fcd7a794eb5c6900a65e7e921884a636f19b131d", + "f8cc02933851432f0c5df0b70f2067f740ccb72de7d6fa1e9a9b0d6de1402b9c6c52" + "5fd848e45aaaac1423b52880ec3474a2f64b38db6fc8e008d95a310e6e0c", + 47, + "4a5f07eb713932532fc3132c96efdc45862fe7a954c1d2ae4640afdf4728fb58c65e" + "8a4ebfe0d53d5797d5146442b9", + }, + { + "163d69079ddad1f16695c47d81c3b72f869b2fdd50e6e47113db6c85051a6ede", + "93fe602642ee5773f4aaf6a3bc21e98e354035225353f419e78e43c3ec36c88a", + "da747fa2cb47aae1effc1e4cfde0e39fa79937948592a712a7665bf948b8311e7f3f" + "80f966301679520d5c2afa3eadd60e061f0d264887500d8d03a17e10fd02", + 41, + "65fe5c1a0214a59644892e5ac4216f09fbb4e191b89bfb63d6540177d25ef9e37148" + "50b8453bd6b2b6", + }, + { + "7b061bf90eb760971b9ec66a96fd6609635ca4b531f33e3c126b9ae6fdb3d491", + "cb392ebb6912df4111efeeb1278160daf9da396e9291b83979a5ac479f7276d2", + "f6eebe86f7ea672e0707ee518e1798d6fbd118c11b2aa30be07d10e3882e3721f203" + "0f9f044b77c3a7a9a2f1feba7e7ce75d1f7f3807a96a764fded35d341d02", + 45, + "a17f5ce39b9ba7b7cf1147e515d6aa84b22fd0e2d8323a91367198fc6c3aff04ebb2" + "1fc2bdbe7bc0364e8040a9", + }, + { + "c9f8ccbf761cec00ab236c52651e76b5f46d90f8936d44d40561ed5c277104de", + "a3192641e343b669ffd43677c2e5cd4efaed174e876141f1d773bd6cfe30d875", + "d44f884ec9eae2e99e74194b5acc769b7aa369aaad359e92ba6ff0fe629af2a9a715" + "6c19b720e7de8c7f03c039563f160948073cab6f99b26a56a8bb1023ba08", + 47, + "3d7e33b0ecead8269966e9dcd192b73eb8a12573fc8a5fdfbe5753541026ef2e49f5" + "280cba9bc2515a049b3a1c1b49", + }, + { + "ebfa409ac6f987df476858dd35310879bf564eeb62984a52115d2e6c24590124", + "7bb1601fe7215f3f4da9c8ab5e804dc58f57ba41b03223f57ec80d9c9a2dd0e1", + "f3e7c1abfcc9f35556cb1e4c5a2b34445177ac188312d9148f1d1d8467ea8411fa3c" + "da031d023034e45bbe407ef7d1b937bfb098266138857d35cb4efe407306", + 52, + "0c37564f718eda683aa6f3e9ab2487620b1a8b5c8f20adb3b2d7550af0d635371e53" + "1f27cebe76a2abcc96de0875bdae987a45ac", + }, + { + "f993f61902b7da332f2bb001baa7accaf764d824eb0cd073315f7ec43158b8fb", + "55fc8e0da1b454cab6ddefb235311db2b01504bf9ac3f71c7e3f3d0d1f09f80b", + "178bd147673c0ca330e45da63cbd1f1811906bd5284bb44e4bb00f7d7163d1f39697" + "5610b6f71c1ae4686466fad4c5e7bb9685099e21ca4f1a45bb3fcf56ae0c", + 42, + "b7dd613bc9c364d9eeb9a52636d72bc881dfc81a836b6537bbb928bff5b738313589" + "47ea9edea1570550", + }, + { + "05188c09c31b4bb63f0d49b47ccc1654c2aba907b8c6c0a82ee403e950169167", + "e096d808dfabe8e44eb74950199dadcd586f9de6b141a0ce85ab94b3d97866eb", + "669491c8eb7cedbbc0252f3eafb048b39a2a37f60ac87837777c72c879ac8b726c39" + "e10060750c2f539102999b71889746111bc5f71ec8c158cc81cf566aef03", + 44, + "bb8e22469d1c7f1d5418563e8781f69eccb56678bd36d8919f358c2778562ff6b50d" + "e916c12d44f1a778a7f3", + }, + { + "eabe57e1a916ebbffa4ba7abc7f23e83d4deb1338816cc1784d7495d92e98d0b", + "3aad275642f48a46ed1032f3de9f4053e0fd35cf217e065d2e4579c3683932f7", + "b2e9dac2c83942ca374f29c8eff5a30c377c3db3c1c645e593e524d17484e7705b11" + "f79573e2d63495fc3ce3bf216a209f0cb7bea477ae0f8bd297f193af8805", + 44, + "3f2c2d6682ee597f2a92d7e560ac53d5623550311a4939d68adfb904045ed8d215a9" + "fdb757a2368ea4d89f5f", + }, + { + "fef7b893b4b517fab68ca12d36b603bc00826bf3c9b31a05149642ae10bb3f55", + "b3fb891868708dfa5da5b9b5234058767ab42c117f12c3228c02a1976d1c0f83", + "6243e289314b7c7587802909a9be6173a916b36f9de1e164954dfe5d1ebd57c869a7" + "9552d770e13b51855502be6b15e7be42a3675298a81284df58e609b06503", + 47, + "38c69f884045cdbeebe4478fdbd1ccc6cf00a08d8a3120c74e7167d3a2e26a67a043" + "b8e5bd198f7b0ce0358cef7cf9", + }, + { + "16228bec9b724300a37e88e535fc1c58548d34d7148b57c226f2b3af974c1822", + "3c92423a8360c9a5d9a093730d72831bec4601dcadfe84de19fc8c8f91fc3d4b", + "6aebfa9a4294ec888d54bcb517fcb6821e4c16d2708a2afe701f431a28149ff4f139" + "f9d16a52a63f1f91baf4c8dea37710c73f25c263a8035a39cc118ad0280f", + 44, + "a3d7b122cd4431b396b20d8cc46cc73ed4a5253a44a76fc83db62cdc845a2bf7081d" + "069a857955a161cccf84", + }, + { + "2dc3f5f0a0bc32c6632534e1e8f27e59cbe0bf7617d31aff98098e974c828be7", + "b998a416edc28ded988dcacb1caf2bd96c87354b0d1eeccb6980e54a3104f21f", + "76a2ddfc4bea48c47e0c82bcbfee28a37c61ec626af39a468e643e0ef9f6533056a5" + "a0b44e64d614ba3c641a40e5b003a99463445ae2c3c8e1e9882092d74b07", + 42, + "bdae276d738b9758ea3d322b54fd12fe82b767e8d817d8ef3d41f78705748e28d15e" + "9c506962a1b85901", + }, + }; + + ed25519_secret_key private_key; + ed25519_public_key public_key; + ed25519_signature signature; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + nem_private_key(tests[i].private_key, private_key); + MARK_SECRET_DATA(private_key, sizeof(private_key)); + + ed25519_publickey_keccak(private_key, public_key); + UNMARK_SECRET_DATA(public_key, sizeof(public_key)); + ck_assert_mem_eq(public_key, fromhex(tests[i].public_key), 32); + + ed25519_sign_keccak(fromhex(tests[i].data), tests[i].length, private_key, + signature); + UNMARK_SECRET_DATA(signature, sizeof(signature)); + ck_assert_mem_eq(signature, fromhex(tests[i].signature), 64); + + UNMARK_SECRET_DATA(private_key, sizeof(private_key)); + } +} +END_TEST + +START_TEST(test_ed25519_cosi) { + enum { MAXN = 10 }; + ed25519_secret_key keys[MAXN]; + ed25519_public_key pubkeys[MAXN]; + ed25519_secret_key nonces[MAXN]; + ed25519_public_key Rs[MAXN]; + ed25519_cosi_signature sigs[MAXN]; + uint8_t msg[32]; + rfc6979_state rng; + int res; + + init_rfc6979( + fromhex( + "26c76712d89d906e6672dafa614c42e5cb1caac8c6568e4d2493087db51f0d36"), + fromhex( + "26659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), + NULL, &rng); + + for (int N = 1; N < 11; N++) { + ed25519_public_key pk; + ed25519_public_key R; + ed25519_signature sig; + /* phase 0: create priv/pubkeys and combine pubkeys */ + for (int j = 0; j < N; j++) { + generate_rfc6979(keys[j], &rng); + ed25519_publickey(keys[j], pubkeys[j]); + } + res = ed25519_cosi_combine_publickeys(pk, pubkeys, N); + ck_assert_int_eq(res, 0); + + generate_rfc6979(msg, &rng); + + /* phase 1: create nonces, commitments (R values) and combine commitments */ + for (int j = 0; j < N; j++) { + ed25519_cosi_commit(nonces[j], Rs[j]); + } + res = ed25519_cosi_combine_publickeys(R, Rs, N); + ck_assert_int_eq(res, 0); + + MARK_SECRET_DATA(keys, sizeof(keys)); + /* phase 2: sign and combine signatures */ + for (int j = 0; j < N; j++) { + res = + ed25519_cosi_sign(msg, sizeof(msg), keys[j], nonces[j], R, pk, + sigs[j]); + ck_assert_int_eq(res, 0); + } + UNMARK_SECRET_DATA(sigs, sizeof(sigs)); + + ed25519_cosi_combine_signatures(sig, R, sigs, N); + + /* check signature */ + res = ed25519_sign_open(msg, sizeof(msg), pk, sig); + ck_assert_int_eq(res, 0); + + UNMARK_SECRET_DATA(keys, sizeof(keys)); + } +} +END_TEST + +START_TEST(test_ed25519_modl_add) { + char tests[][3][65] = { + { + "0000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000", + }, + + {"eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a", + "0000000000000000000000000000000000000000000000000000000000000000", + "eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a"}, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a", + "eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a"}, + + {"0100000000000000000000000000000000000000000000000000000000000000", + "0200000000000000000000000000000000000000000000000000000000000000", + "0300000000000000000000000000000000000000000000000000000000000000"}, + + {"e3d3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", + "0a00000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000"}, + + {"f7bb3bf42b3e58e2edd06f173fc7bfbc7aaf657217946b75648447101136aa08", + "3c16b013109cc27ff39805be2abe04ba4cd6a8526a1d3023047693e950936c06", + "33d2eb073cda1a62e16975d56985c476c7850ec581b19b9868fadaf961c9160f"}, + }; + + unsigned char buff[32]; + bignum256modm a = {0}, b = {0}, c = {0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(a, fromhex(tests[i][0]), 32); + expand256_modm(b, fromhex(tests[i][1]), 32); + add256_modm(c, a, b); + contract256_modm(buff, c); + ck_assert_mem_eq(buff, fromhex(tests[i][2]), 32); + } +} +END_TEST + +START_TEST(test_ed25519_modl_neg) { + char tests[][2][65] = { + {"05d0f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", + "e803000000000000000000000000000000000000000000000000000000000000"}, + + {"4d4df45c1a631258d69cf7a2def9de1400000000000000000000000000000010", + "a086010000000000000000000000000000000000000000000000000000000000"}, + + {"25958944a1b7d4073975ca48996a1d740d0ed98ceec366760c5358da681e9608", + "c83e6c1879ab3d509d272d5a458fc1a0f2f12673113c9989f3aca72597e16907"}, + + {"0100000000000000000000000000000000000000000000000000000000000000", + "ecd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010"}, + + {"ecd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", + "0100000000000000000000000000000000000000000000000000000000000000"}, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000"}, + }; + + unsigned char buff[32]; + bignum256modm a = {0}, b = {0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(a, fromhex(tests[i][0]), 32); + neg256_modm(b, a); + contract256_modm((unsigned char *)buff, b); + ck_assert_mem_eq(buff, fromhex(tests[i][1]), 32); + } +} +END_TEST + +START_TEST(test_ed25519_modl_sub) { + char tests[][3][65] = { + { + "0000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000", + }, + + {"eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a", + "53732f60e51ee3a48d21d2d526548c0dadbb79a185678fd7710613d0e76aad0c", + "8859d1d1deee0767a4ff1b72a3e0d0327573c69bbff5fc07cfa61414e6ef3b0e"}, + + {"9d91e26dbe7a14fdca9f5b20d13e828dc8c1ffe03fe90136a6bba507436ce500", + "9ca406705ccce65eb8cbf63706d3df09fcc67216c0dc3990270731aacbb2e607", + "eec0d15a7c1140f6e8705c8ba9658198ccfa8cca7f0cc8a57eb4745d77b9fe08"}, + + {"eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a", + "0000000000000000000000000000000000000000000000000000000000000000", + "eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a"}, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "39897fbebf137a34572b014b0638ac0186d17874e3cc142ebdfe24327f5b8509", + "b44a769e5a4f98237f71f657d8c132137a2e878b1c33ebd14201dbcd80a47a06"}, + + {"0200000000000000000000000000000000000000000000000000000000000000", + "e3d3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", + "0c00000000000000000000000000000000000000000000000000000000000000"}, + + {"e3d3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", + "0800000000000000000000000000000000000000000000000000000000000000", + "dbd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010"}, + + {"ecd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", + "0000000000000000000000000000000000000000000000000000000000000000", + "ecd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010"}, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "ecd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", + "0100000000000000000000000000000000000000000000000000000000000000"}, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000010", + "edd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000000"}, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "ffffff3f00000000000000000000000000000000000000000000000000000010", + "eed3f51c1a631258d69cf7a2def9de1400000000000000000000000000000000"}, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "edd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000010"}, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "e75f947f11d49d25a137fac8757538a980dec23811235cf63c48ee6bc6e4ed03", + "067461dd088f74323565fdd96884a66b7f213dc7eedca309c3b71194391b120c"}, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "ecd3f55c1a631258d69cf7a2def9de140000000000000000000000000000ff0f", + "0100000000000000000000000000000000000000000000000000000000000100"}, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "edd3f55c1a631258d69cf7a2def9de140000000000000000000004000000ff0f", + "0000000000000000000000000000000000000000000000000000fcffffff0000"}, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "edd3f55c1a631258d69cf7a2def9de150000c0ffffffffffffffffffffffff0f", + "000000000000000000000000000000ffffff3f00000000000000000000000000"}, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "edd3f55c1a631258d69cf7a2def9de1200000000000000000000000000000110", + "edd3f55c1a631258d69cf7a2def9de160000000000000000000000000000ff0f"}, + + {"0000000000000000000000000000000000000000000000000000000000000000", + "edd3f55c1a631258d69cf7a2def9de1300000000000000000000000000000010", + "0000000000000000000000000000000100000000000000000000000000000000"}, + }; + + unsigned char buff[32]; + bignum256modm a = {0}, b = {0}, c = {0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(a, fromhex(tests[i][0]), 32); + expand256_modm(b, fromhex(tests[i][1]), 32); + sub256_modm(c, a, b); + contract256_modm(buff, c); + ck_assert_mem_eq(buff, fromhex(tests[i][2]), 32); + } +} +END_TEST + +START_TEST(test_ge25519_double_scalarmult_vartime2) { + char tests[][5][65] = { + {"c537208ed4985e66e9f7a35c9a69448a732ba93960bbbd2823604f7ae9e3ed08", + "365233e5af17c8888d5ce508787464f4642e91a6212b1b104e6c3769535601b1", + "a84f871580176708b4ac21843cb197ad96e8456034442b50859c83c5807b9901", + "f022360d1bce903fa3ac58ae42f997328b31f477b8d576a9f6d26fc1d08f14ea", + "bf25da82c6b210948b823ae48422a2dcd205d3c94842e68ac27e5cbeaa704ebc"}, + {"4abfabc0dda33588a98127ef3bfe724fed286395fe15932e898b5621661ea102", + "e5fd79d03f5df8edfc8def663dcb96bba6cadf857f2ae6f6f51f52f8d14079b7", + "4754c286b23e3c1b50054fe3937ebdc4ec01b28da5d05fb6111798b42fc5bf06", + "b7e7f9464b98de5bfcf6b02c1b7053cc359df407ad59d943523c6d2ee773b2f6", + "6d7d5f729bfa4882dbff8e477cd2b4c354ba347f10e7b178a24f3f16a4e0fec6"}, + {"19f2af4d04cb8181f1fe0d01fe9bb9ecc476c67ceb4a9830dae1bc7fe5fe3b04", + "d3c462f4f30991220387a1fbbd1ba1dc45ce058c70a8fb1475071e7b4f0fc463", + "577790e025c1fd2014db44a8d613c4e2ab1f248a4a6d14b5d39cbbafd7b20f06", + "1376c6837f131f6cd1a45b1056297d2314aa0ac5f7d581d2d878261eb3259b4d", + "ce790760ada87dd819b59e4f6765d836d346567ec34f02bbcfcae0585c1d758f"}, + {"cf209db9e7ee85f1e648924ec97edd86b56a833b25707519d4fbe64fd50e150a", + "804f0806087dc665a26230ed5fd44c062980ee182a6bd7dbdb33df018c983778", + "30d3c448cb08935309753b3051366f52328ca1d9a0b63c72b989edee0da32b0e", + "98e3c973a7e85b5eab8111521c66ca584bed5597f060ab0c6b5cdeece502ac48", + "2646276e1305396a1b2473690066011a39789570a09e10ce1a013c8f32cd5bea"}, + {"b0a0ffeea67b656c4c585ba58ff528a6f45d2f915db98e4a14a8ff17f27fc105", + "4fabe16274f6af526ee053028485db6acd13804e02dcdddccc4183a319ab9e1c", + "1e140bb08a936ac6b7437644ca0769f3c165c7aa5501d49f064a0346179b4008", + "68fc1be64fb68761542a655b8dbebf50980f1fbc1845528df8d8a06bf89a1495", + "7dab86994b47014efe38493fc2b62ffcead806da6e0d73c992db8cb5618a19dc"}, + {"0fee422c2294b06ca83bc3704384dffc580e7ff5921881e51a755e5f9b80af03", + "4359a663ead3f7ffc3a0ead5c3c2bde348017e7bfa620f21759c32e469a16dfe", + "532066e3eec29334fffc37b17178dfbac3bee15f7845f01449ddbaf5e57a7b0c", + "32e46c2fb99402837631c8175db31cdd334c145f922be9070d62e6d9c493c3ea", + "8c7b7d2d61cdb648960434d894787426a76d16dd46949c7aa4b85dcf1054b4d5"}, + {"3a712d5b7ceb5257dcf6e6bb06548de6ef3deba5d456cd91fc305a12b46b5d01", + "5e7da62e3ec42cf3e554639dd4d2006754ee6839b720cadba94a26b73b1665ee", + "2a518ecab17a2d9dde219c775bcf4f2306b190bef2dea34fb65b8e4dccc13405", + "3b5d66a4dfb068923b3bc21cc8b40b59e12f845e0b85a86d394db0fa310bf185", + "2ec17f1cc0be093e9cdb741a991c0f417230dea275cd7babdad35e949e250521"}, + {"5f815f2d65cef584c5e5d48b2d3d3e4cae310d70b328f88af6e9f63c52b4c90d", + "8a539a8c6b2339922b31cf4bc064f1fedeb3912fd89585d79dfcff2a60aee295", + "385f7132b72db04146b9e472736b32adfca29556b4775a743c18e2bfab939007", + "884aaf96d625968ddb2582922a87abca131272884c47f6b86890ebccf0a79d5b", + "a7afdaf24fe8472d8b89e95c3ce4a40bdf700af7cedee44ed3aa5ccca09839bd"}, + {"a043340d072df16a8ab5135f8c1d601bff14c5aba01b9212b886ad71fe164506", + "52f6de5fa0fae32d4020a54d395319509d6b92092a0bf849fb34e73f8e71fc99", + "37d7472d360164da29e6dcb8f9796976022571c5df4ddf7e30e9a579ba13d509", + "8c369e3fd5b1112e4437b1f09e987acca4966f2f8c5227eb15ace240a2c64cc7", + "fc795fe7baff5c3ac98366e6882f25874ea2b0a649d16f139e5c54ea47042a1e"}, + {"97a3268db03fa184c8cba020bf216fc789292fa9615a28962385b86870ffd70f", + "a76c215587022bb9252ece4c5afeb0e65b820834cd41ac76e6c062d3eea75dc6", + "8310271017154cbddf7005e24eb9a9a86777b3f42fa5e35095eafaac4eb24802", + "b822665c2406083c851ecaa91ea67aa740c057e7679b5755cee60a6c63f17fd6", + "f83e2444527056eba595d49bde40b2e8da76d2c145f203331d26e94560993fbc"}, + {"edaad13efad39f26298e86ba8d06a46e59122232c9529bd22f2f656595421e00", + "f38e56a79f5159eb3b581dea537ec12c9c6fac381b2cf6073e27fc621197cb62", + "1eea79485954b5958d9d5478f86133af1088806d923535d483b115ab23099a0f", + "b32c5e57d57db7a349f4ab845f12a5045c52b4a7a5bce7fd54a1a255b0118185", + "3bfb42b4ffd2c6cfc8cce9e4187dc6fbcaecd9d44a4ca1d2b68b97410bb25b81"}, + {"b15eaebe0fc83cb11d755a6f067b710204d4a59101078d8286454b652879080a", + "4667a2e61d9df1690f5c33c4168e480f7e26d2f0998168ebdc0a39712946f741", + "125379da1a88bfdf5b928f8795d3ea5415ef8c3d9106eb16934c3842873fd707", + "8727a692a25e38b1afa98e3dd5bf88815dec6d9810c1fd8a31b56b3de8630f1e", + "540883dde400b909e9955a276c20e13d99252ebe542750b8bfbbe5c3b87c51e3"}, + {"e42bdd4af3121bea644a90a76b2007615621ee5b842b9a74c4334ac309478706", + "6dc4ab715d3bb975ebfd0f08e2b6f3f39922d0121ae518a8f8d2952ea2fe0b5d", + "0285059b0095c97f4a50d43c7726c64c2830bf2b55dfa934ebba7ad71064dc07", + "f738c0a3cee31fd8f438f282aa6c823fccfa49cf7b5c86fbf9d56bf0394b6d8d", + "a1bd106841e55010decd95a170a1d0dd11780fd00759819e024b15ea3a83b4be"}, + {"5077c30fd08795dbdc7a230c050ca07e316fa3b040fd0dac45907036ab25dd0e", + "96f0897f000e49e2439a9166cab40ebc125a31b82851f0541516c19683e7bfaf", + "2b67d79a2efdc6451508e7f3c97c4a61b135bb839c02338bb444ef8208dd970b", + "7ef4cd7cdc29c2b88ccff49898b5d0b7be5993f93c5772476feec9dc57d7b6e3", + "62449b901b25760c964704b28efc184fbd5947e83851ebaf3bbfeb6f742f679f"}, + {"a4b3ce6928fe8f77d13e65ae255eee8310ab0d75bca47028b4570f0511a66006", + "4e9da8d77ee337e3bcce3730ccfff2121728641c7bb4fdeb2155890f998af09a", + "ff01a5075569d0f6afee45da065c72f5841f46ce772917ef75eb4d230473580f", + "36ca32da8a10f4083f5a60ee21868d9d448548d49c56f19cbe6005005e34f816", + "99df362a3b762cc1cbb70bc5ddff3c8614ed306037013102e387ef32e7f2494f"}, + {"074aa76351dceb752aa09887d9aca932d5821f58eedb4988fd64d8548e3f2c09", + "588b4552f3b98b2f77aee2ef8cc72f88acd424c4373b3e3626393ed2ea24cbda", + "f2d9175633f2e3c661b01172b4b4176850cd5b3098ffb0f927e0a5e19c1c8a02", + "a6c34868736b2517fd46f57a4e30805ffd475e44a8b1413078f43d9cb3d6edd6", + "46e1e7d7b1e939dd5c07c8363af01f4f9dae7c3d10f237ff9776ddc4a1903771"}, + {"ae1c8abd5a542208ee0aa93ffbf0b8e5a957edc4854fe2b48153c5c85bbf3d08", + "5e084b9541a70bd5bef400be6525c5a806a5b7fb12de38b07dcd35a22c57edbe", + "d95f179a215fb322d81720bf3aecde78d6d676d6f941455d0e0920f1e3619707", + "c3e5d43221824de51d8f95705de69c80a2440c0483ca88549d639aee15390429", + "df9fea42d3b5ac243244abb4ca4948a69493becddc5d5906f9a4e4c5645b0eab"}, + {"2f1c5adedb7341dc7638bafacc6024bd48255197ea2347fc05714b9341dd4403", + "47f55263001542f796c928988f641f59d0cd43294fc8d8616b184bfe9dddf368", + "aa5e884e782ab116151c609680c37b1a49b52f23bce5e2ebf28dd8532510d20b", + "ef2d6d97ad1a18edfce6450c1e70295b2c7ed2bc749ea8b438a523eae078d1f3", + "2396a355c6ae8e2ac24da8f55a674c96fc4cc69b38678b2bd8eb91b96f462bca"}, + {"0242e14105ced74e91cf4d4dcd22a9c09279018901d2fb8319eb54c2a1c4900a", + "fcb62a6c520d31fa46efeb4a1000330653b3402f575c2ddc0c688f527e7b97be", + "73a7e2e0602e5345f040dedc4db67f6d8e37c5fca3bbb124fa43963d76dbbb08", + "152bf4a3305c656f77e292b1256cc470da4d3f6efc3667199db4316d7f431174", + "c21ba2080013dfb225e06378d9ac27df623df552526cfddbf9e71bb1d4705dd9"}, + {"07fab4fc7b02fbcf868ffb0326cf60425fef2af1fbad83a8926cc62c2b5dff05", + "29ff12c5e052eb5829e8334e0e082c5edde1f293d2b4ed499a79bcca20e48010", + "97afb3dd9167877b432a23503aad1ab39188b9be07cc124ceb3fbdbd8d8b890a", + "ed121240a2f4591eeedbfd880305ccd17e522673900b03279fb66e73583514ae", + "b27f209e88ce5701766565e231e8123adb1df9c9f1dc461920acbc2b38d9f6d7"}, + }; + + unsigned char buff[32]; + bignum256modm a = {0}, b = {0}; + ge25519 A, B, R; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(a, fromhex(tests[i][0]), 32); + expand256_modm(b, fromhex(tests[i][2]), 32); + ge25519_unpack_negative_vartime(&A, fromhex(tests[i][1])); + curve25519_neg(A.x, A.x); + curve25519_neg(A.t, A.t); + ge25519_unpack_negative_vartime(&B, fromhex(tests[i][3])); + curve25519_neg(B.x, B.x); + curve25519_neg(B.t, B.t); + ge25519_double_scalarmult_vartime2(&R, &A, a, &B, b); + ge25519_pack(buff, &R); + ck_assert_mem_eq(buff, fromhex(tests[i][4]), 32); + } +} +END_TEST + +static void test_bip32_ecdh_init_node(HDNode *node, const char *seed_str, + const char *curve_name) { + hdnode_from_seed((const uint8_t *)seed_str, strlen(seed_str), curve_name, + node); + hdnode_fill_public_key(node); + if (node->public_key[0] == 1) { + node->public_key[0] = 0x40; // Curve25519 public keys start with 0x40 byte + } +} + +static void test_bip32_ecdh(const char *curve_name, int expected_key_size, + const uint8_t *expected_key) { + int res, key_size; + HDNode alice, bob; + uint8_t session_key1[expected_key_size], session_key2[expected_key_size]; + + test_bip32_ecdh_init_node(&alice, "Alice", curve_name); + test_bip32_ecdh_init_node(&bob, "Bob", curve_name); + + // Generate shared key from Alice's secret key and Bob's public key + res = hdnode_get_shared_key(&alice, bob.public_key, session_key1, &key_size); + ck_assert_int_eq(res, 0); + ck_assert_int_eq(key_size, expected_key_size); + ck_assert_mem_eq(session_key1, expected_key, key_size); + + // Generate shared key from Bob's secret key and Alice's public key + res = hdnode_get_shared_key(&bob, alice.public_key, session_key2, &key_size); + ck_assert_int_eq(res, 0); + ck_assert_int_eq(key_size, expected_key_size); + ck_assert_mem_eq(session_key2, expected_key, key_size); +} + +START_TEST(test_bip32_ecdh_nist256p1) { + test_bip32_ecdh( + NIST256P1_NAME, 65, + fromhex( + "044aa56f917323f071148cd29aa423f6bee96e7fe87f914d0b91a0f95388c6631646" + "ea92e882773d7b0b1bec356b842c8559a1377673d3965fb931c8fe51e64873")); +} +END_TEST + +START_TEST(test_bip32_ecdh_curve25519) { + test_bip32_ecdh(CURVE25519_NAME, 33, + fromhex("04f34e35516325bb0d4a58507096c444a05ba13524ccf66910f1" + "1ce96c62224169")); +} +END_TEST + +START_TEST(test_bip32_ecdh_errors) { + HDNode node; + const uint8_t peer_public_key[65] = {0}; // invalid public key + uint8_t session_key[65]; + int res, key_size = 0; + + test_bip32_ecdh_init_node(&node, "Seed", ED25519_NAME); + res = hdnode_get_shared_key(&node, peer_public_key, session_key, &key_size); + ck_assert_int_eq(res, 1); + ck_assert_int_eq(key_size, 0); + + test_bip32_ecdh_init_node(&node, "Seed", CURVE25519_NAME); + res = hdnode_get_shared_key(&node, peer_public_key, session_key, &key_size); + ck_assert_int_eq(res, 1); + ck_assert_int_eq(key_size, 0); + + test_bip32_ecdh_init_node(&node, "Seed", NIST256P1_NAME); + res = hdnode_get_shared_key(&node, peer_public_key, session_key, &key_size); + ck_assert_int_eq(res, 1); + ck_assert_int_eq(key_size, 0); +} +END_TEST + +START_TEST(test_output_script) { + static const char *vectors[] = { + "76A914010966776006953D5567439E5E39F86A0D273BEE88AC", + "16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM", + "A914010966776006953D5567439E5E39F86A0D273BEE87", + "31nVrspaydBz8aMpxH9WkS2DuhgqS1fCuG", + "0014010966776006953D5567439E5E39F86A0D273BEE", + "p2xtZoXeX5X8BP8JfFhQK2nD3emtjch7UeFm", + "00200102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20", + "7XhPD7te3C6CVKnJWUhrTJbFTwudhHqfrjpS59AS6sMzL4RYFiCNg", + 0, + 0, + }; + const char **scr, **adr; + scr = vectors; + adr = vectors + 1; + char address[60]; + while (*scr && *adr) { + int r = + script_output_to_address(fromhex(*scr), strlen(*scr) / 2, address, 60); + ck_assert_uint_eq((size_t)r, strlen(*adr) + 1); + ck_assert_str_eq(address, *adr); + scr += 2; + adr += 2; + } +} +END_TEST + +START_TEST(test_ethereum_pubkeyhash) { + uint8_t pubkeyhash[20]; + int res; + HDNode node; + + // init m + hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, + SECP256K1_NAME, &node); + + // [Chain m] + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, + fromhex("056db290f8ba3250ca64a45d16284d04bc6f5fbf"), 20); + + // [Chain m/0'] + hdnode_private_ckd_prime(&node, 0); + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, + fromhex("bf6e48966d0dcf553b53e7b56cb2e0e72dca9e19"), 20); + + // [Chain m/0'/1] + hdnode_private_ckd(&node, 1); + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, + fromhex("29379f45f515c494483298225d1b347f73d1babf"), 20); + + // [Chain m/0'/1/2'] + hdnode_private_ckd_prime(&node, 2); + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, + fromhex("d8e85fbbb4b3b3c71c4e63a5580d0c12fb4d2f71"), 20); + + // [Chain m/0'/1/2'/2] + hdnode_private_ckd(&node, 2); + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, + fromhex("1d3462d2319ac0bfc1a52e177a9d372492752130"), 20); + + // [Chain m/0'/1/2'/2/1000000000] + hdnode_private_ckd(&node, 1000000000); + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, + fromhex("73659c60270d326c06ac204f1a9c63f889a3d14b"), 20); + + // init m + hdnode_from_seed( + fromhex( + "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c" + "999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), + 64, SECP256K1_NAME, &node); + + // [Chain m] + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, + fromhex("6dd2a6f3b05fd15d901fbeec61b87a34bdcfb843"), 20); + + // [Chain m/0] + hdnode_private_ckd(&node, 0); + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, + fromhex("abbcd4471a0b6e76a2f6fdc44008fe53831e208e"), 20); + + // [Chain m/0/2147483647'] + hdnode_private_ckd_prime(&node, 2147483647); + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, + fromhex("40ef2cef1b2588ae862e7a511162ec7ff33c30fd"), 20); + + // [Chain m/0/2147483647'/1] + hdnode_private_ckd(&node, 1); + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, + fromhex("3f2e8905488f795ebc84a39560d133971ccf9b50"), 20); + + // [Chain m/0/2147483647'/1/2147483646'] + hdnode_private_ckd_prime(&node, 2147483646); + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, + fromhex("a5016fdf975f767e4e6f355c7a82efa69bf42ea7"), 20); + + // [Chain m/0/2147483647'/1/2147483646'/2] + hdnode_private_ckd(&node, 2); + res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(pubkeyhash, + fromhex("8ff2a9f7e7917804e8c8ec150d931d9c5a6fbc50"), 20); +} +END_TEST + +START_TEST(test_ethereum_address) { + static const char *vectors[] = {"52908400098527886E0F7030069857D2E4169EE7", + "8617E340B3D01FA5F11F306F4090FD50E238070D", + "de709f2102306220921060314715629080e2fb77", + "27b1fdb04752bbc536007a920d24acb045561c26", + "5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed", + "fB6916095ca1df60bB79Ce92cE3Ea74c37c5d359", + "dbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB", + "D1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb", + "5A4EAB120fB44eb6684E5e32785702FF45ea344D", + "5be4BDC48CeF65dbCbCaD5218B1A7D37F58A0741", + "a7dD84573f5ffF821baf2205745f768F8edCDD58", + "027a49d11d118c0060746F1990273FcB8c2fC196", + "CD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", + 0}; + uint8_t addr[20]; + char address[41]; + const char **vec = vectors; + while (*vec) { + memcpy(addr, fromhex(*vec), 20); + ethereum_address_checksum(addr, address, false, 0); + ck_assert_str_eq(address, *vec); + vec++; + } +} +END_TEST + +// test vectors from +// https://github.com/rsksmart/RSKIPs/blob/master/IPs/RSKIP60.md +START_TEST(test_rsk_address) { + uint8_t addr[20]; + char address[41]; + + static const char *rskip60_chain30[] = { + "5aaEB6053f3e94c9b9a09f33669435E7ef1bEAeD", + "Fb6916095cA1Df60bb79ce92cE3EA74c37c5d359", + "DBF03B407c01E7CD3cBea99509D93F8Dddc8C6FB", + "D1220A0Cf47c7B9BE7a2e6ba89F429762E7B9adB", 0}; + const char **vec = rskip60_chain30; + while (*vec) { + memcpy(addr, fromhex(*vec), 20); + ethereum_address_checksum(addr, address, true, 30); + ck_assert_str_eq(address, *vec); + vec++; + } + + static const char *rskip60_chain31[] = { + "5aAeb6053F3e94c9b9A09F33669435E7EF1BEaEd", + "Fb6916095CA1dF60bb79CE92ce3Ea74C37c5D359", + "dbF03B407C01E7cd3cbEa99509D93f8dDDc8C6fB", + "d1220a0CF47c7B9Be7A2E6Ba89f429762E7b9adB", 0}; + vec = rskip60_chain31; + while (*vec) { + memcpy(addr, fromhex(*vec), 20); + ethereum_address_checksum(addr, address, true, 31); + ck_assert_str_eq(address, *vec); + vec++; + } +} +END_TEST + +// test vectors from +// https://raw.githubusercontent.com/NemProject/nem-test-vectors/master/1.test-keys.dat +START_TEST(test_nem_address) { + static const struct { + const char *private_key; + const char *public_key; + const char *address; + } tests[] = { + { + "575dbb3062267eff57c970a336ebbc8fbcfe12c5bd3ed7bc11eb0481d7704ced", + "c5f54ba980fcbb657dbaaa42700539b207873e134d2375efeab5f1ab52f87844", + "NDD2CT6LQLIYQ56KIXI3ENTM6EK3D44P5JFXJ4R4", + }, + { + "5b0e3fa5d3b49a79022d7c1e121ba1cbbf4db5821f47ab8c708ef88defc29bfe", + "96eb2a145211b1b7ab5f0d4b14f8abc8d695c7aee31a3cfc2d4881313c68eea3", + "NABHFGE5ORQD3LE4O6B7JUFN47ECOFBFASC3SCAC", + }, + { + "738ba9bb9110aea8f15caa353aca5653b4bdfca1db9f34d0efed2ce1325aeeda", + "2d8425e4ca2d8926346c7a7ca39826acd881a8639e81bd68820409c6e30d142a", + "NAVOZX4HDVOAR4W6K4WJHWPD3MOFU27DFHC7KZOZ", + }, + { + "e8bf9bc0f35c12d8c8bf94dd3a8b5b4034f1063948e3cc5304e55e31aa4b95a6", + "4feed486777ed38e44c489c7c4e93a830e4c4a907fa19a174e630ef0f6ed0409", + "NBZ6JK5YOCU6UPSSZ5D3G27UHAPHTY5HDQMGE6TT", + }, + { + "c325ea529674396db5675939e7988883d59a5fc17a28ca977e3ba85370232a83", + "83ee32e4e145024d29bca54f71fa335a98b3e68283f1a3099c4d4ae113b53e54", + "NCQW2P5DNZ5BBXQVGS367DQ4AHC3RXOEVGRCLY6V", + }, + { + "a811cb7a80a7227ae61f6da536534ee3c2744e3c7e4b85f3e0df3c6a9c5613df", + "6d34c04f3a0e42f0c3c6f50e475ae018cfa2f56df58c481ad4300424a6270cbb", + "NA5IG3XFXZHIPJ5QLKX2FBJPEZYPMBPPK2ZRC3EH", + }, + { + "9c66de1ec77f4dfaaebdf9c8bc599ca7e8e6f0bc71390ffee2c9dd3f3619242a", + "a8fefd72a3b833dc7c7ed7d57ed86906dac22f88f1f4331873eb2da3152a3e77", + "NAABHVFJDBM74XMJJ52R7QN2MTTG2ZUXPQS62QZ7", + }, + { + "c56bc16ecf727878c15e24f4ae68569600ac7b251218a44ef50ce54175776edc", + "c92f761e6d83d20068fd46fe4bd5b97f4c6ba05d23180679b718d1f3e4fb066e", + "NCLK3OLMHR3F2E3KSBUIZ4K5PNWUDN37MLSJBJZP", + }, + { + "9dd73599283882fa1561ddfc9be5830b5dd453c90465d3fe5eeb646a3606374e", + "eaf16a4833e59370a04ccd5c63395058de34877b48c17174c71db5ed37b537ed", + "ND3AHW4VTI5R5QE5V44KIGPRU5FBJ5AFUCJXOY5H", + }, + { + "d9639dc6f49dad02a42fd8c217f1b1b4f8ce31ccd770388b645e639c72ff24fa", + "0f74a2f537cd9c986df018994dde75bdeee05e35eb9fe27adf506ca8475064f7", + "NCTZ4YAP43ONK3UYTASQVNDMBO24ZHJE65F3QPYE", + }, + { + "efc1992cd50b70ca55ac12c07aa5d026a8b78ffe28a7dbffc9228b26e02c38c1", + "2ebff201255f6cf948c78f528658b99a7c13ac791942fa22d59af610558111f5", + "NDQ2TMCMXBSFPZQPE2YKH6XLC24HD6LUMN6Z4GIC", + }, + { + "143a815e92e43f3ed1a921ee48cd143931b88b7c3d8e1e981f743c2a5be3c5ba", + "419ed11d48730e4ae2c93f0ea4df853b8d578713a36dab227517cf965861af4e", + "NA32IDDW2C53BDSBJNFL3Z6UU3J5CJZJMCZDXCF4", + }, + { + "bc1a082f5ac6fdd3a83ade211e5986ac0551bad6c7da96727ec744e5df963e2a", + "a160e6f9112233a7ce94202ed7a4443e1dac444b5095f9fecbb965fba3f92cac", + "NADUCEQLC3FTGB25GTA5HOUTB53CBVQNVOIP7NTJ", + }, + { + "4e47b4c6f4c7886e49ec109c61f4af5cfbb1637283218941d55a7f9fe1053f72", + "fbb91b16df828e21a9802980a44fc757c588bc1382a4cea429d6fa2ae0333f56", + "NBAF3BFLLPWH33MYE6VUPP5T6DQBZBKIDEQKZQOE", + }, + { + "efc4389da48ce49f85365cfa578c746530e9eac42db1b64ec346119b1becd347", + "2232f24dda0f2ded3ecd831210d4e8521a096b50cadd5a34f3f7083374e1ec12", + "NBOGTK2I2ATOGGD7ZFJHROG5MWL7XCKAUKSWIVSA", + }, + { + "bdba57c78ca7da16a3360efd13f06276284db8c40351de7fcd38ba0c35ac754d", + "c334c6c0dad5aaa2a0d0fb4c6032cb6a0edd96bf61125b5ea9062d5a00ee0eee", + "NCLERTEFYXKLK7RA4MVACEFMXMK3P7QMWTM7FBW2", + }, + { + "20694c1ec3c4a311bcdb29ed2edc428f6d4f9a4c429ad6a5bf3222084e35695f", + "518c4de412efa93de06a55947d11f697639443916ec8fcf04ebc3e6d17d0bd93", + "NB5V4BPIJHXVONO7UGMJDPFARMFA73BOBNOOYCOV", + }, + { + "e0d4f3760ac107b33c22c2cac24ab2f520b282684f5f66a4212ff95d926323ce", + "b3d16f4ead9de67c290144da535a0ed2504b03c05e5f1ceb8c7863762f786857", + "NC4PBAO5TPCAVQKBVOC4F6DMZP3CFSQBU46PSKBD", + }, + { + "efa9afc617412093c9c7a7c211a5332dd556f941e1a88c494ec860608610eea2", + "7e7716e4cebceb731d6f1fd28676f34888e9a0000fcfa1471db1c616c2ddf559", + "NCFW2LPXIWLBWAQN2QVIWEOD7IVDO3HQBD2OU56K", + }, + { + "d98499b3db61944684ce06a91735af4e14105338473fcf6ebe2b0bcada3dfd21", + "114171230ad6f8522a000cdc73fbc5c733b30bb71f2b146ccbdf34499f79a810", + "NCUKWDY3J3THKQHAKOK5ALF6ANJQABZHCH7VN6DP", + }, + }; + + HDNode node; + ed25519_secret_key private_key; + uint8_t chain_code[32]; + char address[41]; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + nem_private_key(tests[i].private_key, private_key); + + ck_assert(hdnode_from_xprv(0, 0, chain_code, private_key, + ED25519_KECCAK_NAME, &node)); + + ck_assert(hdnode_get_nem_address(&node, NEM_NETWORK_MAINNET, address)); + ck_assert_str_eq(address, tests[i].address); + + ck_assert_mem_eq(&node.public_key[1], fromhex(tests[i].public_key), 32); + } +} +END_TEST + +// test vectors from +// https://raw.githubusercontent.com/NemProject/nem-test-vectors/master/3.test-derive.dat +START_TEST(test_nem_derive) { + static const struct { + const char *salt; + const char *private_key; + const char *public_key; + const char *mul; + const char *shared_key; + } tests[] = { + { + "ad63ac08f9afc85eb0bf4f8881ca6eaa0215924c87aa2f137d56109bb76c6f98", + "e8857f8e488d4e6d4b71bcd44bb4cff49208c32651e1f6500c3b58cafeb8def6", + "9d8e5f200b05a2638fb084a375408cabd6d5989590d96e3eea5f2cb34668178e", + "a8352060ba5718745ee4d78b9df564e0fbe13f50d50ab15a8dd524159d81d18b", + "990a5f611c65fbcde735378bdec38e1039c5466503511e8c645bbe42795c752b", + }, + { + "96104f0a28f9cca40901c066cd435134662a3b053eb6c8df80ee0d05dc941963", + "d7f67b5f52cbcd1a1367e0376a8eb1012b634acfcf35e8322bae8b22bb9e8dea", + "9735c92d150dcee0ade5a8d1822f46a4db22c9cda25f33773ae856fe374a3e8a", + "ea14d521d83328dba70982d42094300585818cc2da609fdb1f73bb32235576ff", + "b498aa21d4ba4879ea9fd4225e93bacc760dcd9c119f8f38ab0716457d1a6f85", + }, + { + "d8f94a0bbb1de80aea17aab42e2ffb982e73fc49b649a318479e951e392d8728", + "d026ddb445fb3bbf3020e4b55ed7b5f9b7fd1278c34978ca1a6ed6b358dadbae", + "d19e6beca3b26b9d1abc127835ebeb7a6c19c33dec8ec472e1c4d458202f4ec8", + "0d561f54728ad837ae108ec66c2ece2bb3b26041d3ee9b77fdc6d36d9ebfb2e3", + "d012afe3d1d932304e613c91545bf571cf2c7281d6cafa8e81393a551f675540", + }, + { + "3f8c969678a8abdbfb76866a142c284a6f01636c1c1607947436e0d2c30d5245", + "c522b38c391d1c3fa539cc58802bc66ac34bb3c73accd7f41b47f539bedcd016", + "ea5b6a0053237f7712b1d2347c447d3e83e0f2191762d07e1f53f8eb7f2dfeaa", + "23cccd3b63a9456e4425098b6df36f28c8999461a85e4b2b0c8d8f53c62c9ea9", + "7e27efa50eed1c2ac51a12089cbab6a192624709c7330c016d5bc9af146584c1", + }, + { + "e66415c58b981c7f1f2b8f45a42149e9144616ff6de49ff83d97000ac6f6f992", + "2f1b82be8e65d610a4e588f000a89a733a9de98ffc1ac9d55e138b3b0a855da0", + "65aeda1b47f66c978a4a41d4dcdfbd8eab5cdeb135695c2b0c28f54417b1486d", + "43e5b0a5cc8146c03ac63e6f8cf3d8825a9ca1ed53ea4a88304af4ddf5461b33", + "bb4ab31c334e55d378937978c90bb33779b23cd5ef4c68342a394f4ec8fa1ada", + }, + { + "58487c9818c9d28ddf97cb09c13331941e05d0b62bf4c35ee368de80b552e4d1", + "f3869b68183b2e4341307653e8f659bd7cd20e37ea5c00f5a9e203a8fa92359a", + "c7e4153a18b4162f5c1f60e1ba483264aa5bb3f4889dca45b434fcd30b9cf56f", + "5ae9408ab3156b8828c3e639730bd5e5db93d7afe2cee3fcda98079316c5bb3a", + "0224d85ae8f17bfe127ec24b8960b7639a0dbde9c8c39a0575b939448687bb14", + }, + { + "ad66f3b654844e53d6fb3568134fae75672ba63868c113659d3ca58c2c39d24f", + "d38f2ef8dfdc7224fef596130c3f4ff68ac83d3f932a56ee908061466ac28572", + "d0c79d0340dc66f0a895ce5ad60a933cf6be659569096fb9d4b81e5d32292372", + "1ea22db4708ed585ab541a4c70c3069f8e2c0c1faa188ddade3efaa53c8329f6", + "886a7187246934aedf2794748deadfe038c9fd7e78d4b7be76c5a651440ac843", + }, + { + "eed48604eab279c6ad8128aa83483a3da0928271a4cae1a5745671284e1fb89d", + "e2342a8450fc0adfa0ea2fbd0b1d28f100f0a3a905a3da29de34d1353afa7df7", + "d2dbe07e0f2dbc3dbb01c70092e3c4247d12827ddcd8d76534fd740a65c30de2", + "4c4b30eb6a2bfa17312f5729b4212cb51c2eee8fbfaea82a0e957ca68f4f6a30", + "dcae613ac5641ff9d4c3ca58632245f93b0b8657fe4d48bac7b062cc53dd21ad", + }, + { + "f35b315287b268c0d0b386fb5b31810f65e1c4497cffae24527f69a3abac3884", + "049016230dbef7a14a439e5ab2f6d12e78cb8df127db4e0c312673b3c361e350", + "1b3b1925a8a535cd7d78725d25298f45bba8ca3dee2cdaabf14241c9b51b37c4", + "04c9685dae1f8eb72a6438f24a87dc83a56d79c9024edf7e01aa1ae34656f29e", + "b48469d0428c223b93cd1fe34bb2cafd3fb78a8fa15f98f89f1ac9c0ce7c9001", + }, + { + "d6cf082c5d9a96e756a94a2e27703138580a7c7c1af505c96c3abf7ab6802e1d", + "67cd02b0b8b0adcf6fdd4d4d64a1f4193ced68bb8605d0ec941a62011326d140", + "a842d5127c93a435e4672dcadd9fccbfd0e9208c79c5404848b298597eccdbdb", + "d5c6bd6d81b99659d0bafe91025b6ecf73b16c6b07931cf44718b13f00fde3f7", + "8aa160795b587f4be53aa35d26e9b618b4cd6ec765b523bc908e53c258ca8fd4", + }, + { + "dda32c91c95527a645b00dd05d13f0b98ed612a726ce5f5221431430b7660944", + "eba026f92a8ffb5e95060a22e15d597fe838a99a0b2bbcb423c933b6bc718c50", + "7dbaf9c313a1ff9128c54d6cd740c7d0cc46bca588e7910d438dd619ca4fd69a", + "5bb20a145de83ba27a0c261e1f54bfd7dcea61888fc2eebbe6166876f7b000b8", + "3a96f152ad8bf355cccb307e4a40108aa17f8e925522a2b5bb0b3f1e1a262914", + }, + { + "63c500acbd4ff747f7dadde7d3286482894ac4d7fe68f396712bca29879aa65c", + "9663cd3c2030a5fe4a3ea3cc9a1d182b3a63ade68616aaeb4caf40b495f6f227", + "b1e7d9070ac820d986d839b79f7aa594dcf708473529dad87af8682cc6197374", + "1f7a97584d8db9f395b9ac4447de4b33c5c1f5020187cd4996286a49b07eb8a7", + "4d2a974ec12dcf525b5654d31053460850c3092648b7e15598b7131d2930e9fb", + }, + { + "91f340961029398cc8bcd906388044a6801d24328efdf919d8ed0c609862a073", + "45a588500d00142e2226231c01fd11ac6f842ab6a85872418f5b6a1999f8bd98", + "397233c96069b6f4a57d6e93f759fa327222eaef71fc981afa673b248206df3f", + "062123ef9782e3893f7b2e1d557b4ecce92b9f9aa8577e76380f228b75152f84", + "235848cb04230a16d8978aa7c19fe7fbff3ebe29389ea6eb24fb8bc3cb50afc6", + }, + { + "46120b4da6ba4eb54fb65213cfef99b812c86f7c42a1de1107f8e8c12c0c3b6b", + "cc19a97a99ad71ce348bcf831c0218e6a1f0a8d52186cabe6298b56f24e640f9", + "c54631bb62f0f9d86b3301fcb2a671621e655e578c95504af5f78da83f7fec4f", + "ab73cc20c75260ff3a7cefea8039291d4d15114a07a9250375628cca32225bb6", + "70040a360b6a2dfa881272ef4fa6616e2e8fcc45194fa2a21a1eef1160271cd5", + }, + { + "f0a69ded09f1d731ab9561d0c3a40b7ef30bcb2bf60f92beccd8734e2441403d", + "ea732822a381c46a7ac9999bf5ef85e16b7460b26aaf6c1a1c6ffa8c8c82c923", + "110decbff79c382b1e60af4259564a3c473087792350b24fca98ae9a74ba9dd9", + "81bdee95aecdcf821a9d682f79056f1abdcf1245d2f3b55244447881a283e0d4", + "1bc29d4470ccf97d4e35e8d3cd4b12e3ebf2cb0a82425d35984aeedf7ad0f6f9", + }, + { + "e79cf4536fb1547e57626c0f1a87f71a396fdfb985b00731c0c2876a00645eda", + "04213fc02b59c372e3e7f53faa71a2f73b31064102cb6fc8b68432ba7cdf7eb4", + "ca1c750aaed53bc30dac07d0696ed86bcd7cdbbcbd3d15bb90d90cb5c6117bac", + "c68cd0872a42a3a64e8a229ef7fcad3d722047d5af966f7dda4d4e32d0d57203", + "bfdd3d07563d966d95afe4b8abea4b567265fceea8c4ecddb0946256c33e07b2", + }, + { + "81a40db4cddaf076e0206bd2b0fa7470a72cc456bad34aa3a0469a4859f286be", + "52156799fd86cc63345cdbffd65ef4f5f8df0ffd9906a40af5f41d269bbcff5d", + "54d61aa0b0b17a87f1376fe89cd8cd6b314827c1f1b9e5e7b20e7a7eee2a8335", + "4553fb2cab8555068c32f86ceb692bbf1c2beeaf21627ef1b1be57344b52eea8", + "55096b6710ade3bbe38702458ee13faa10c24413261bc076f17675dcbf2c4ee6", + }, + { + "d28e4a9e6832a3a4dad014a2bf1f666f01093cbba8b9ad4d1dcad3ea10cb42b9", + "8ca134404c8fa199b0c72cb53cfa0adcf196dfa560fb521017cce5cbace3ba59", + "3a6c39a1e5f9f550f1debedd9a0bc84210cce5f9834797db8f14122bf5817e45", + "eb632ca818b4f659630226a339a3ce536b31c8e1e686fea8da3760e8abc20b8e", + "9fbb3fbaf1cd54ee0cd90685f59b082545983f1f662ef701332379306a6ad546", + }, + { + "f9c4bfad9e2a3d98c44c12734881a6f217d6c9523cc210772fad1297993454b4", + "b85960fcadda8d0a0960559b6b7818a0d8d4574b4e928b17c9b498fa9ffab4ef", + "6a1d0ef23ce0b40a7077ecb7b7264945054e3bdb58ee25e1b0ee8b3e19dbfcdc", + "bb145dddcb75074a6a03249fca1aa7d6fa9549e3ed965f138ca5e7071b7878f2", + "87d3faea4a98e41009eb8625611ea0fc12094c295af540c126c14a0f55afa76e", + }, + { + "656df4789a369d220aceb7b318517787d27004ecccedea019d623bcb2d79f5ff", + "acf83e30afb2a5066728ec5d93564c08abe5e68e3a2a2ff953bdcf4d44f9da06", + "bdda65efe56d7890286aada1452f62f85ba157d0b4621ba641de15d8d1c9e331", + "958beef5dc6babc6de383c32ad7dd3a6d6eb8bb3236ed5558eec0f9eb31e5458", + "6f6d4ee36d9d76e462c9635adfbb6073134a276cfc7cb86762004ec47197afa0", + }, + }; + + HDNode node; + ed25519_secret_key private_key; + uint8_t chain_code[32]; + ed25519_public_key public_key, mul; + uint8_t shared_key[SHA3_256_DIGEST_LENGTH]; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + nem_private_key(tests[i].private_key, private_key); + + ck_assert(hdnode_from_xprv(0, 0, chain_code, private_key, + ED25519_KECCAK_NAME, &node)); + memcpy(public_key, fromhex(tests[i].public_key), 32); + + ck_assert(hdnode_get_nem_shared_key( + &node, public_key, fromhex(tests[i].salt), mul, shared_key)); + ck_assert_mem_eq(mul, fromhex(tests[i].mul), sizeof(mul)); + ck_assert_mem_eq(shared_key, fromhex(tests[i].shared_key), + sizeof(shared_key)); + } +} +END_TEST + +// test vectors from +// https://raw.githubusercontent.com/NemProject/nem-test-vectors/master/4.test-cipher.dat +START_TEST(test_nem_cipher) { + static const struct { + const char *private_key; + const char *public_key; + const char *salt; + const char *iv; + const char *input; + const char *output; + } tests[] = { + { + "3140f94c79f249787d1ec75a97a885980eb8f0a7d9b7aa03e7200296e422b2b6", + "57a70eb553a7b3fd621f0dba6abf51312ea2e2a2a1e19d0305516730f4bcbd21", + "83616c67f076d356fd1288a6e0fd7a60488ba312a3adf0088b1b33c7655c3e6a", + "a73ff5c32f8fd055b09775817a6a3f95", + "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", + "70815da779b1b954d7a7f00c16940e9917a0412a06a444b539bf147603eef87f", + }, + { + "3140f94c79f249787d1ec75a97a885980eb8f0a7d9b7aa03e7200296e422b2b6", + "57a70eb553a7b3fd621f0dba6abf51312ea2e2a2a1e19d0305516730f4bcbd21", + "703ce0b1d276b10eef35672df03234385a903460db18ba9d4e05b3ad31abb284", + "91246c2d5493867c4fa3e78f85963677", + "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", + "564b2f40d42c0efc1bd6f057115a5abd1564cae36d7ccacf5d825d38401aa894", + }, + { + "3140f94c79f249787d1ec75a97a885980eb8f0a7d9b7aa03e7200296e422b2b6", + "57a70eb553a7b3fd621f0dba6abf51312ea2e2a2a1e19d0305516730f4bcbd21", + "b22e8e8e7373ac31ca7f0f6eb8b93130aba5266772a658593f3a11792e7e8d92", + "9f8e33d82374dad6aac0e3dbe7aea704", + "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", + "7cab88d00a3fc656002eccbbd966e1d5d14a3090d92cf502cdbf843515625dcf", + }, + { + "3140f94c79f249787d1ec75a97a885980eb8f0a7d9b7aa03e7200296e422b2b6", + "57a70eb553a7b3fd621f0dba6abf51312ea2e2a2a1e19d0305516730f4bcbd21", + "af646c54cd153dffe453b60efbceeb85c1e95a414ea0036c4da94afb3366f5d9", + "6acdf8e01acc8074ddc807281b6af888", + "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", + "aa70543a485b63a4dd141bb7fd78019092ac6fad731e914280a287c7467bae1a", + }, + { + "3140f94c79f249787d1ec75a97a885980eb8f0a7d9b7aa03e7200296e422b2b6", + "57a70eb553a7b3fd621f0dba6abf51312ea2e2a2a1e19d0305516730f4bcbd21", + "d9c0d386636c8a024935c024589f9cd39e820a16485b14951e690a967830e269", + "f2e9f18aeb374965f54d2f4e31189a8f", + "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", + "33d97c216ea6498dfddabf94c2e2403d73efc495e9b284d9d90aaff840217d25", + }, + { + "d5c0762ecea2cd6b5c56751b58debcb32713aab348f4a59c493e38beb3244f3a", + "66a35941d615b5644d19c2a602c363ada8b1a8a0dac3682623852dcab4afac04", + "06c227baac1ae3b0b1dc583f4850f13f9ba5d53be4a98fa5c3ea16217847530d", + "3735123e78c44895df6ea33fa57e9a72", + "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", + "d5b5d66ba8cee0eb7ecf95b143fa77a46d6de13749e12eff40f5a7e649167ccb", + }, + { + "d5c0762ecea2cd6b5c56751b58debcb32713aab348f4a59c493e38beb3244f3a", + "66a35941d615b5644d19c2a602c363ada8b1a8a0dac3682623852dcab4afac04", + "92f55ba5bc6fc2f23e3eedc299357c71518e36ba2447a4da7a9dfe9dfeb107b5", + "1cbc4982e53e370052af97ab088fa942", + "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", + "d48ef1ef526d805656cfc932aff259eadb17aa3391dde1877a722cba31d935b2", + }, + { + "d5c0762ecea2cd6b5c56751b58debcb32713aab348f4a59c493e38beb3244f3a", + "66a35941d615b5644d19c2a602c363ada8b1a8a0dac3682623852dcab4afac04", + "10f15a39ba49866292a43b7781bc71ca8bbd4889f1616461caf056bcb91b0158", + "c40d531d92bfee969dce91417346c892", + "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a" + "4", + "e6d75afdb542785669b42198577c5b358d95397d71ec6f5835dca46d332cc08dbf73" + "ea790b7bcb169a65719c0d55054c", + }, + { + "d5c0762ecea2cd6b5c56751b58debcb32713aab348f4a59c493e38beb3244f3a", + "66a35941d615b5644d19c2a602c363ada8b1a8a0dac3682623852dcab4afac04", + "9c01ed42b219b3bbe1a43ae9d7af5c1dd09363baacfdba8f4d03d1046915e26e", + "059a35d5f83249e632790015ed6518b9", + "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a" + "4", + "5ef11aadff2eccee8b712dab968fa842eb770818ec0e6663ed242ea8b6bbc1c66d62" + "85ee5b5f03d55dfee382fb4fa25d", + }, + { + "d5c0762ecea2cd6b5c56751b58debcb32713aab348f4a59c493e38beb3244f3a", + "66a35941d615b5644d19c2a602c363ada8b1a8a0dac3682623852dcab4afac04", + "bc1067e2a7415ea45ff1ca9894338c591ff15f2e57ae2789ae31b9d5bea0f11e", + "8c73f0d6613898daeefa3cf8b0686d37", + "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a" + "4", + "6d220213b1878cd40a458f2a1e6e3b48040455fdf504dcd857f4f2ca1ad642e3a44f" + "c401d04e339d302f66a9fad3d919", + }, + { + "9ef87ba8aa2e664bdfdb978b98bc30fb61773d9298e7b8c72911683eeff41921", + "441e76d7e53be0a967181076a842f69c20fd8c0e3f0ce3aa421b490b059fe094", + "cf4a21cb790552165827b678ca9695fcaf77566d382325112ff79483455de667", + "bfbf5482e06f55b88bdd9e053b7eee6e", + "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a" + "4", + "1198a78c29c215d5c450f7b8513ead253160bc9fde80d9cc8e6bee2efe9713cf5a09" + "d6293c41033271c9e8c22036a28b", + }, + { + "9ef87ba8aa2e664bdfdb978b98bc30fb61773d9298e7b8c72911683eeff41921", + "441e76d7e53be0a967181076a842f69c20fd8c0e3f0ce3aa421b490b059fe094", + "eba5eae8aef79114082c3e70baef95bb02edf13b3897e8be7a70272962ef8838", + "af9a56da3da18e2fbd2948a16332532b", + "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a" + "4", + "1062ab5fbbdee9042ad35bdadfd3047c0a2127fe0f001da1be1b0582185edfc9687b" + "e8d68f85795833bb04af9cedd3bb", + }, + { + "9ef87ba8aa2e664bdfdb978b98bc30fb61773d9298e7b8c72911683eeff41921", + "441e76d7e53be0a967181076a842f69c20fd8c0e3f0ce3aa421b490b059fe094", + "518f8dfd0c138f1ffb4ea8029db15441d70abd893c3d767dc668f23ba7770e27", + "42d28307974a1b2a2d921d270cfce03b", + "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a" + "4", + "005e49fb7c5da540a84b034c853fc9f78a6b901ea495aed0c2abd4f08f1a96f9ffef" + "c6a57f1ac09e0aea95ca0f03ffd8", + }, + { + "9ef87ba8aa2e664bdfdb978b98bc30fb61773d9298e7b8c72911683eeff41921", + "441e76d7e53be0a967181076a842f69c20fd8c0e3f0ce3aa421b490b059fe094", + "582fdf58b53715c26e10ba809e8f2ab70502e5a3d4e9a81100b7227732ab0bbc", + "91f2aad3189bb2edc93bc891e73911ba", + "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a" + "4", + "821a69cb16c57f0cb866e590b38069e35faec3ae18f158bb067db83a11237d29ab1e" + "6b868b3147236a0958f15c2e2167", + }, + { + "9ef87ba8aa2e664bdfdb978b98bc30fb61773d9298e7b8c72911683eeff41921", + "441e76d7e53be0a967181076a842f69c20fd8c0e3f0ce3aa421b490b059fe094", + "a415b4c006118fb72fc37b2746ef288e23ac45c8ff7ade5f368a31557b6ac93a", + "2b7c5f75606c0b8106c6489ea5657a9e", + "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", + "2781d5ee8ef1cb1596f8902b33dfae5045f84a987ca58173af5830dbce386062", + }, + { + "ed93c5a101ab53382ceee4f7e6b5aa112621d3bb9d18891509b1834ede235bcc", + "5a5e14c633d7d269302849d739d80344ff14db51d7bcda86045723f05c4e4541", + "47e73ec362ea82d3a7c5d55532ad51d2cdf5316b981b2b2bd542b0efa027e8ea", + "b2193f59030c8d05a7d3577b7f64dd33", + "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", + "3f43912db8dd6672b9996e5272e18c4b88fec9d7e8372db9c5f4709a4af1d86f", + }, + { + "ed93c5a101ab53382ceee4f7e6b5aa112621d3bb9d18891509b1834ede235bcc", + "5a5e14c633d7d269302849d739d80344ff14db51d7bcda86045723f05c4e4541", + "aaa006c57b6d1e402650577fe9787d8d285f4bacd7c01f998be49c766f8860c7", + "130304ddb9adc8870cf56bcae9487b7f", + "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", + "878cc7d8c0ef8dac0182a78eedc8080a402f59d8062a6b4ca8f4a74f3c3b3de7", + }, + { + "ed93c5a101ab53382ceee4f7e6b5aa112621d3bb9d18891509b1834ede235bcc", + "5a5e14c633d7d269302849d739d80344ff14db51d7bcda86045723f05c4e4541", + "28dc7ccd6c2a939eef64b8be7b9ae248295e7fcd8471c22fa2f98733fea97611", + "cb13890d3a11bc0a7433738263006710", + "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", + "e74ded846bebfa912fa1720e4c1415e6e5df7e7a1a7fedb5665d68f1763209a4", + }, + { + "ed93c5a101ab53382ceee4f7e6b5aa112621d3bb9d18891509b1834ede235bcc", + "5a5e14c633d7d269302849d739d80344ff14db51d7bcda86045723f05c4e4541", + "79974fa2cad95154d0873902c153ccc3e7d54b17f2eeb3f29b6344cad9365a9a", + "22123357979d20f44cc8eb0263d84e0e", + "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", + "eb14dec7b8b64d81a2ee4db07b0adf144d4f79a519bbf332b823583fa2d45405", + }, + { + "ed93c5a101ab53382ceee4f7e6b5aa112621d3bb9d18891509b1834ede235bcc", + "5a5e14c633d7d269302849d739d80344ff14db51d7bcda86045723f05c4e4541", + "3409a6f8c4dcd9bd04144eb67e55a98696b674735b01bf1196191f29871ef966", + "a823a0965969380ea1f8659ea5fd8fdd", + "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", + "00a7eb708eae745847173f8217efb05be13059710aee632e3f471ac3c6202b51", + }, + { + "a73a0b2686f7d699c018b6b08a352856e556070caa329c26241aec889eefde10", + "9b493403bee45ae6277430ef8d0c4163ffd81ace2db6c7821205da09a664a86c", + "c25701b9b7328c4ac3d23223d10623bd527c0a98e38ae9c62fbc403c80ab20ae", + "4b4ee0e4443779f3af429a749212f476", + "b6926d0ec82cec86c0d27ec9a33a0e0f", + "f39f7d66e0fde39ecdf58be2c0ef361a17cfd6843e310adbe0ec3118cd72800d", + }, + { + "a73a0b2686f7d699c018b6b08a352856e556070caa329c26241aec889eefde10", + "9b493403bee45ae6277430ef8d0c4163ffd81ace2db6c7821205da09a664a86c", + "31d18fdffc480310828778496ff817039df5d6f30bf6d9edd0b4396863d05f93", + "418bcbdf52860a450bfacc96920d02cf", + "b6926d0ec82cec86c0d27ec9a33a0e0f", + "0e6ce9889fe7b3cd82794b0ae27c1f5985d2f2a1f398371a138f8db1df1f54de", + }, + { + "e2e4dee102fad0f47f60202269605589cd9cf70f816b34016796c74b766f3041", + "c5ce283033a3255ae14d42dff1e4c18a224ac79d084b285123421b105ee654c9", + "56b4c645f81dbfb6ba0c6d3f1626e1e5cd648eeb36562715f7cd7e9ea86a0d7f", + "dc9bdce76d68d2e4d72267cf4e72b022", + "b6926d0ec82cec86c0d27ec9a33a0e0f", + "dc6f046c3008002041517a7c4f3ababe609cf02616fcccda39c075d1be4175f5", + }, + { + "e2e4dee102fad0f47f60202269605589cd9cf70f816b34016796c74b766f3041", + "c5ce283033a3255ae14d42dff1e4c18a224ac79d084b285123421b105ee654c9", + "df180b91986c8c7000792f96d1faa61e30138330430a402322be1855089b0e7f", + "ccf9b77341c866465b474e2f4a3b1cf8", + "b6926d0ec82cec86c0d27ec9a33a0e0f", + "94e4ae89041437f39826704f02cb5d775226f34344635e592846417497a5020b", + }, + { + "e2e4dee102fad0f47f60202269605589cd9cf70f816b34016796c74b766f3041", + "c5ce283033a3255ae14d42dff1e4c18a224ac79d084b285123421b105ee654c9", + "a0eee7e84c76e63fdae6e938b43330775eaf17d260e40b98c9e6616b668102a7", + "662c681cfec6f6d052ff0e2c1255f2c2", + "b6926d0ec82cec86c0d27ec9a33a0e0f", + "70bba3c48be9c75a144b1888ca3d21a6b21f52eec133981a024390a6a0ba36f9", + }, + { + "e2e4dee102fad0f47f60202269605589cd9cf70f816b34016796c74b766f3041", + "c5ce283033a3255ae14d42dff1e4c18a224ac79d084b285123421b105ee654c9", + "c6acd2d90eb782c3053b366680ffa0e148de81fea198c87bb643869fd97e5cb0", + "908dc33ba80520f2f0f04e7890e3a3c0", + "b6926d0ec82cec86c0d27ec9a33a0e0f", + "f6efe1d76d270aac264aa35d03049d9ce63be1996d543aef00559219c8666f71", + }, + }; + + HDNode node; + ed25519_secret_key private_key; + uint8_t chain_code[32]; + ed25519_public_key public_key; + uint8_t salt[sizeof(public_key)]; + + uint8_t iv[AES_BLOCK_SIZE]; + uint8_t buffer[FROMHEX_MAXLEN]; + + uint8_t input[FROMHEX_MAXLEN]; + uint8_t output[FROMHEX_MAXLEN]; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + nem_private_key(tests[i].private_key, private_key); + + ck_assert(hdnode_from_xprv(0, 0, chain_code, private_key, + ED25519_KECCAK_NAME, &node)); + memcpy(public_key, fromhex(tests[i].public_key), 32); + memcpy(salt, fromhex(tests[i].salt), sizeof(salt)); + + size_t input_size = strlen(tests[i].input) / 2; + size_t output_size = strlen(tests[i].output) / 2; + + memcpy(input, fromhex(tests[i].input), input_size); + memcpy(output, fromhex(tests[i].output), output_size); + + memcpy(iv, fromhex(tests[i].iv), sizeof(iv)); + ck_assert(hdnode_nem_encrypt(&node, public_key, iv, salt, input, input_size, + buffer)); + ck_assert_uint_eq(output_size, NEM_ENCRYPTED_SIZE(input_size)); + ck_assert_mem_eq(buffer, output, output_size); + + memcpy(iv, fromhex(tests[i].iv), sizeof(iv)); + ck_assert(hdnode_nem_decrypt(&node, public_key, iv, salt, output, + output_size, buffer)); + ck_assert_uint_eq(input_size, NEM_DECRYPTED_SIZE(buffer, output_size)); + ck_assert_mem_eq(buffer, input, input_size); + } +} +END_TEST + +START_TEST(test_nem_transaction_transfer) { + nem_transaction_ctx ctx; + + uint8_t buffer[1024], hash[SHA3_256_DIGEST_LENGTH]; + + // http://bob.nem.ninja:8765/#/transfer/0acbf8df91e6a65dc56c56c43d65f31ff2a6a48d06fc66e78c7f3436faf3e74f + + nem_transaction_start( + &ctx, + fromhex( + "e59ef184a612d4c3c4d89b5950eb57262c69862b2f96e59c5043bf41765c482f"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_transfer( + &ctx, NEM_NETWORK_TESTNET, 0, NULL, 0, 0, + "TBGIMRE4SBFRUJXMH7DVF2IBY36L2EDWZ37GVSC4", 50000000000000, NULL, 0, + false, 0)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "0acbf8df91e6a65dc56c56c43d65f31ff2a6a48d06fc66e78c7f3436faf3e74f"), + sizeof(hash)); + + // http://bob.nem.ninja:8765/#/transfer/3409d9ece28d6296d6d5e220a7e3cb8641a3fb235ffcbd20c95da64f003ace6c + + nem_transaction_start( + &ctx, + fromhex( + "994793ba1c789fa9bdea918afc9b06e2d0309beb1081ac5b6952991e4defd324"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_transfer( + &ctx, NEM_NETWORK_TESTNET, 14072100, NULL, 194000000, 14075700, + "TBLOODPLWOWMZ2TARX4RFPOSOWLULHXMROBN2WXI", 3000000, + (uint8_t *)"sending you 3 pairs of paddles\n", 31, false, 2)); + + ck_assert( + nem_transaction_write_mosaic(&ctx, "gimre.games.pong", "paddles", 2)); + + ck_assert(nem_transaction_write_mosaic(&ctx, "nem", "xem", 44000000)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "3409d9ece28d6296d6d5e220a7e3cb8641a3fb235ffcbd20c95da64f003ace6c"), + sizeof(hash)); + + // http://chain.nem.ninja/#/transfer/e90e98614c7598fbfa4db5411db1b331d157c2f86b558fb7c943d013ed9f71cb + + nem_transaction_start( + &ctx, + fromhex( + "8d07f90fb4bbe7715fa327c926770166a11be2e494a970605f2e12557f66c9b9"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_transfer( + &ctx, NEM_NETWORK_MAINNET, 0, NULL, 0, 0, + "NBT3WHA2YXG2IR4PWKFFMO772JWOITTD2V4PECSB", 5175000000000, + (uint8_t *)"Good luck!", 10, false, 0)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "e90e98614c7598fbfa4db5411db1b331d157c2f86b558fb7c943d013ed9f71cb"), + sizeof(hash)); + + // http://chain.nem.ninja/#/transfer/40e89160e6f83d37f7c82defc0afe2c1605ae8c919134570a51dd27ea1bb516c + + nem_transaction_start( + &ctx, + fromhex( + "f85ab43dad059b9d2331ddacc384ad925d3467f03207182e01296bacfb242d01"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_transfer( + &ctx, NEM_NETWORK_MAINNET, 77229, NULL, 30000000, 80829, + "NALICEPFLZQRZGPRIJTMJOCPWDNECXTNNG7QLSG3", 30000000, + fromhex("4d9dcf9186967d30be93d6d5404ded22812dbbae7c3f0de5" + "01bcd7228cba45bded13000eec7b4c6215fc4d3588168c92" + "18167cec98e6977359153a4132e050f594548e61e0dc61c1" + "53f0f53c5e65c595239c9eb7c4e7d48e0f4bb8b1dd2f5ddc"), + 96, true, 0)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "40e89160e6f83d37f7c82defc0afe2c1605ae8c919134570a51dd27ea1bb516c"), + sizeof(hash)); + + // http://chain.nem.ninja/#/transfer/882dca18dcbe075e15e0ec5a1d7e6ccd69cc0f1309ffd3fde227bfbc107b3f6e + + nem_transaction_start( + &ctx, + fromhex( + "f85ab43dad059b9d2331ddacc384ad925d3467f03207182e01296bacfb242d01"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_transfer( + &ctx, NEM_NETWORK_MAINNET, 26730750, NULL, 179500000, 26734350, + "NBE223WPKEBHQPCYUC4U4CDUQCRRFMPZLOQLB5OP", 1000000, + (uint8_t *)"enjoy! :)", 9, false, 1)); + + ck_assert(nem_transaction_write_mosaic(&ctx, "imre.g", "tokens", 1)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "882dca18dcbe075e15e0ec5a1d7e6ccd69cc0f1309ffd3fde227bfbc107b3f6e"), + sizeof(hash)); +} +END_TEST + +START_TEST(test_nem_transaction_multisig) { + nem_transaction_ctx ctx, other_trans; + + uint8_t buffer[1024], inner[1024]; + const uint8_t *signature; + + // http://bob.nem.ninja:8765/#/multisig/7d3a7087023ee29005262016706818579a2b5499eb9ca76bad98c1e6f4c46642 + + nem_transaction_start( + &other_trans, + fromhex( + "abac2ee3d4aaa7a3bfb65261a00cc04c761521527dd3f2cf741e2815cbba83ac"), + inner, sizeof(inner)); + + ck_assert(nem_transaction_create_aggregate_modification( + &other_trans, NEM_NETWORK_TESTNET, 3939039, NULL, 16000000, 3960639, 1, + false)); + + ck_assert(nem_transaction_write_cosignatory_modification( + &other_trans, 2, + fromhex( + "e6cff9b3725a91f31089c3acca0fac3e341c00b1c8c6e9578f66c4514509c3b3"))); + + nem_transaction_start( + &ctx, + fromhex( + "59d89076964742ef2a2089d26a5aa1d2c7a7bb052a46c1de159891e91ad3d76e"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_multisig(&ctx, NEM_NETWORK_TESTNET, 3939039, + NULL, 6000000, 3960639, + &other_trans)); + + signature = fromhex( + "933930a8828b560168bddb3137df9252048678d829aa5135fa27bb306ff6562efb927554" + "62988b852b0314bde058487d00e47816b6fb7df6bcfd7e1f150d1d00"); + ck_assert_int_eq(ed25519_sign_open_keccak(ctx.buffer, ctx.offset, + ctx.public_key, signature), + 0); + + nem_transaction_start( + &ctx, + fromhex( + "71cba4f2a28fd19f902ba40e9937994154d9eeaad0631d25d525ec37922567d4"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_multisig_signature(&ctx, NEM_NETWORK_TESTNET, + 3939891, NULL, 6000000, + 3961491, &other_trans)); + + signature = fromhex( + "a849f13bfeeba808a8a4a79d579febe584d831a3a6ad03da3b9d008530b3d7a79fcf7156" + "121cd7ee847029d94af7ea7a683ca8e643dc5e5f489557c2054b830b"); + ck_assert_int_eq(ed25519_sign_open_keccak(ctx.buffer, ctx.offset, + ctx.public_key, signature), + 0); + + // http://chain.nem.ninja/#/multisig/1016cf3bdd61bd57b9b2b07b6ff2dee390279d8d899265bdc23d42360abe2e6c + + nem_transaction_start( + &other_trans, + fromhex( + "a1df5306355766bd2f9a64efdc089eb294be265987b3359093ae474c051d7d5a"), + inner, sizeof(inner)); + + ck_assert(nem_transaction_create_provision_namespace( + &other_trans, NEM_NETWORK_MAINNET, 59414272, NULL, 20000000, 59500672, + "dim", NULL, "NAMESPACEWH4MKFMBCVFERDPOOP4FK7MTBXDPZZA", 5000000000)); + + nem_transaction_start( + &ctx, + fromhex( + "cfe58463f0eaebceb5d00717f8aead49171a5d7c08f6b1299bd534f11715acc9"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_multisig(&ctx, NEM_NETWORK_MAINNET, 59414272, + NULL, 6000000, 59500672, + &other_trans)); + + signature = fromhex( + "52a876a37511068fe214bd710b2284823921ec7318c01e083419a062eae5369c9c11c3ab" + "fdb590f65c717fab82873431d52be62e10338cb5656d1833bbdac70c"); + ck_assert_int_eq(ed25519_sign_open_keccak(ctx.buffer, ctx.offset, + ctx.public_key, signature), + 0); + + nem_transaction_start( + &ctx, + fromhex( + "1b49b80203007117d034e45234ffcdf402c044aeef6dbb06351f346ca892bce2"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_multisig_signature(&ctx, NEM_NETWORK_MAINNET, + 59414342, NULL, 6000000, + 59500742, &other_trans)); + + signature = fromhex( + "b9a59239e5d06992c28840034ff7a7f13da9c4e6f4a6f72c1b1806c3b602f83a7d727a34" + "5371f5d15abf958208a32359c6dd77bde92273ada8ea6fda3dc76b00"); + ck_assert_int_eq(ed25519_sign_open_keccak(ctx.buffer, ctx.offset, + ctx.public_key, signature), + 0); + + nem_transaction_start( + &ctx, + fromhex( + "7ba4b39209f1b9846b098fe43f74381e43cb2882ccde780f558a63355840aa87"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_multisig_signature(&ctx, NEM_NETWORK_MAINNET, + 59414381, NULL, 6000000, + 59500781, &other_trans)); + + signature = fromhex( + "e874ae9f069f0538008631d2df9f2e8a59944ff182e8672f743d2700fb99224aafb7a0ab" + "09c4e9ea39ee7c8ca04a8a3d6103ae1122d87772e871761d4f00ca01"); + ck_assert_int_eq(ed25519_sign_open_keccak(ctx.buffer, ctx.offset, + ctx.public_key, signature), + 0); +} +END_TEST + +START_TEST(test_nem_transaction_provision_namespace) { + nem_transaction_ctx ctx; + + uint8_t buffer[1024], hash[SHA3_256_DIGEST_LENGTH]; + + // http://bob.nem.ninja:8765/#/namespace/f7cab28da57204d01a907c697836577a4ae755e6c9bac60dcc318494a22debb3 + + nem_transaction_start( + &ctx, + fromhex( + "84afa1bbc993b7f5536344914dde86141e61f8cbecaf8c9cefc07391f3287cf5"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_provision_namespace( + &ctx, NEM_NETWORK_TESTNET, 56999445, NULL, 20000000, 57003045, "gimre", + NULL, "TAMESPACEWH4MKFMBCVFERDPOOP4FK7MTDJEYP35", 5000000000)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "f7cab28da57204d01a907c697836577a4ae755e6c9bac60dcc318494a22debb3"), + sizeof(hash)); + + // http://bob.nem.ninja:8765/#/namespace/7ddd5fe607e1bfb5606e0ac576024c318c8300d237273117d4db32a60c49524d + + nem_transaction_start( + &ctx, + fromhex( + "244fa194e2509ac0d2fbc18779c2618d8c2ebb61c16a3bcbebcf448c661ba8dc"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_provision_namespace( + &ctx, NEM_NETWORK_TESTNET, 21496797, NULL, 108000000, 21500397, "misc", + "alice", "TAMESPACEWH4MKFMBCVFERDPOOP4FK7MTDJEYP35", 5000000000)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "7ddd5fe607e1bfb5606e0ac576024c318c8300d237273117d4db32a60c49524d"), + sizeof(hash)); + + // http://chain.nem.ninja/#/namespace/57071aad93ca125dc231dc02c07ad8610cd243d35068f9b36a7d231383907569 + + nem_transaction_start( + &ctx, + fromhex( + "9f3c14f304309c8b72b2821339c4428793b1518bea72d58dd01f19d523518614"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_provision_namespace( + &ctx, NEM_NETWORK_MAINNET, 26699717, NULL, 108000000, 26703317, "sex", + NULL, "NAMESPACEWH4MKFMBCVFERDPOOP4FK7MTBXDPZZA", 50000000000)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "57071aad93ca125dc231dc02c07ad8610cd243d35068f9b36a7d231383907569"), + sizeof(hash)); +} +END_TEST + +START_TEST(test_nem_transaction_mosaic_creation) { + nem_transaction_ctx ctx; + + uint8_t buffer[1024], hash[SHA3_256_DIGEST_LENGTH]; + + // http://bob.nem.ninja:8765/#/mosaic/68364353c29105e6d361ad1a42abbccbf419cfc7adb8b74c8f35d8f8bdaca3fa/0 + + nem_transaction_start( + &ctx, + fromhex( + "994793ba1c789fa9bdea918afc9b06e2d0309beb1081ac5b6952991e4defd324"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_mosaic_creation( + &ctx, NEM_NETWORK_TESTNET, 14070896, NULL, 108000000, 14074496, + "gimre.games.pong", "paddles", "Paddles for the bong game.\n", 0, 10000, + true, true, 0, 0, NULL, NULL, NULL, + "TBMOSAICOD4F54EE5CDMR23CCBGOAM2XSJBR5OLC", 50000000000)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "68364353c29105e6d361ad1a42abbccbf419cfc7adb8b74c8f35d8f8bdaca3fa"), + sizeof(hash)); + + // http://bob.nem.ninja:8765/#/mosaic/b2f4a98113ff1f3a8f1e9d7197aa982545297fe0aa3fa6094af8031569953a55/0 + + nem_transaction_start( + &ctx, + fromhex( + "244fa194e2509ac0d2fbc18779c2618d8c2ebb61c16a3bcbebcf448c661ba8dc"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_mosaic_creation( + &ctx, NEM_NETWORK_TESTNET, 21497248, NULL, 108000000, 21500848, + "alice.misc", "bar", "Special offer: get one bar extra by bying one foo!", + 0, 1000, false, true, 1, 1, "TALICE2GMA34CXHD7XLJQ536NM5UNKQHTORNNT2J", + "nem", "xem", "TBMOSAICOD4F54EE5CDMR23CCBGOAM2XSJBR5OLC", 50000000000)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "b2f4a98113ff1f3a8f1e9d7197aa982545297fe0aa3fa6094af8031569953a55"), + sizeof(hash)); + + // http://chain.nem.ninja/#/mosaic/269c6fda657aba3053a0e5b138c075808cc20e244e1182d9b730798b60a1f77b/0 + + nem_transaction_start( + &ctx, + fromhex( + "58956ac77951622dc5f1c938affbf017c458e30e6b21ddb5783d38b302531f23"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_mosaic_creation( + &ctx, NEM_NETWORK_MAINNET, 26729938, NULL, 108000000, 26733538, "jabo38", + "red_token", + "This token is to celebrate the release of Namespaces and Mosaics on the " + "NEM system. " + "This token was the fist ever mosaic created other than nem.xem. " + "There are only 10,000 Red Tokens that will ever be created. " + "It has no levy and can be traded freely among third parties.", + 2, 10000, false, true, 0, 0, NULL, NULL, NULL, + "NBMOSAICOD4F54EE5CDMR23CCBGOAM2XSIUX6TRS", 50000000000)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "269c6fda657aba3053a0e5b138c075808cc20e244e1182d9b730798b60a1f77b"), + sizeof(hash)); + + // http://chain.nem.ninja/#/mosaic/e8dc14821dbea4831d9051f86158ef348001447968fc22c01644fdaf2bda75c6/0 + + nem_transaction_start( + &ctx, + fromhex( + "a1df5306355766bd2f9a64efdc089eb294be265987b3359093ae474c051d7d5a"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_mosaic_creation( + &ctx, NEM_NETWORK_MAINNET, 69251020, NULL, 20000000, 69337420, "dim", + "coin", "DIM COIN", 6, 9000000000, false, true, 2, 10, + "NCGGLVO2G3CUACVI5GNX2KRBJSQCN4RDL2ZWJ4DP", "dim", "coin", + "NBMOSAICOD4F54EE5CDMR23CCBGOAM2XSIUX6TRS", 500000000)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "e8dc14821dbea4831d9051f86158ef348001447968fc22c01644fdaf2bda75c6"), + sizeof(hash)); +} +END_TEST + +START_TEST(test_nem_transaction_mosaic_supply_change) { + nem_transaction_ctx ctx; + + uint8_t buffer[1024], hash[SHA3_256_DIGEST_LENGTH]; + + // http://bigalice2.nem.ninja:7890/transaction/get?hash=33a50fdd4a54913643a580b2af08b9a5b51b7cee922bde380e84c573a7969c50 + + nem_transaction_start( + &ctx, + fromhex( + "994793ba1c789fa9bdea918afc9b06e2d0309beb1081ac5b6952991e4defd324"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_mosaic_supply_change( + &ctx, NEM_NETWORK_TESTNET, 14071648, NULL, 108000000, 14075248, + "gimre.games.pong", "paddles", 1, 1234)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "33a50fdd4a54913643a580b2af08b9a5b51b7cee922bde380e84c573a7969c50"), + sizeof(hash)); + + // http://bigalice2.nem.ninja:7890/transaction/get?hash=1ce8e8894d077a66ff22294b000825d090a60742ec407efd80eb8b19657704f2 + + nem_transaction_start( + &ctx, + fromhex( + "84afa1bbc993b7f5536344914dde86141e61f8cbecaf8c9cefc07391f3287cf5"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_mosaic_supply_change( + &ctx, NEM_NETWORK_TESTNET, 14126909, NULL, 108000000, 14130509, + "jabo38_ltd.fuzzy_kittens_cafe", "coupons", 2, 1)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "1ce8e8894d077a66ff22294b000825d090a60742ec407efd80eb8b19657704f2"), + sizeof(hash)); + + // http://bigalice3.nem.ninja:7890/transaction/get?hash=694e493e9576d2bcf60d85747e302ac2e1cc27783187947180d4275a713ff1ff + + nem_transaction_start( + &ctx, + fromhex( + "b7ccc27b21ba6cf5c699a8dc86ba6ba98950442597ff9fa30e0abe0f5f4dd05d"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_mosaic_supply_change( + &ctx, NEM_NETWORK_MAINNET, 53377685, NULL, 20000000, 53464085, "abvapp", + "abv", 1, 9000000)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "694e493e9576d2bcf60d85747e302ac2e1cc27783187947180d4275a713ff1ff"), + sizeof(hash)); + + // http://bigalice3.nem.ninja:7890/transaction/get?hash=09836334e123970e068d5b411e4d1df54a3ead10acf1ad5935a2cdd9f9680185 + + nem_transaction_start( + &ctx, + fromhex( + "75f001a8641e2ce5c4386883dda561399ed346177411b492a677b73899502f13"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_mosaic_supply_change( + &ctx, NEM_NETWORK_MAINNET, 55176304, NULL, 20000000, 55262704, "sushi", + "wasabi", 2, 20)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "09836334e123970e068d5b411e4d1df54a3ead10acf1ad5935a2cdd9f9680185"), + sizeof(hash)); +} +END_TEST + +START_TEST(test_nem_transaction_aggregate_modification) { + nem_transaction_ctx ctx; + + uint8_t buffer[1024], hash[SHA3_256_DIGEST_LENGTH]; + + // http://bob.nem.ninja:8765/#/aggregate/6a55471b17159e5b6cd579c421e95a4e39d92e3f78b0a55ee337e785a601d3a2 + + nem_transaction_start( + &ctx, + fromhex( + "462ee976890916e54fa825d26bdd0235f5eb5b6a143c199ab0ae5ee9328e08ce"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_aggregate_modification( + &ctx, NEM_NETWORK_TESTNET, 0, NULL, 22000000, 0, 2, false)); + + ck_assert(nem_transaction_write_cosignatory_modification( + &ctx, 1, + fromhex( + "994793ba1c789fa9bdea918afc9b06e2d0309beb1081ac5b6952991e4defd324"))); + ck_assert(nem_transaction_write_cosignatory_modification( + &ctx, 1, + fromhex( + "c54d6e33ed1446eedd7f7a80a588dd01857f723687a09200c1917d5524752f8b"))); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "6a55471b17159e5b6cd579c421e95a4e39d92e3f78b0a55ee337e785a601d3a2"), + sizeof(hash)); + + // http://bob.nem.ninja:8765/#/aggregate/1fbdae5ba753e68af270930413ae90f671eb8ab58988116684bac0abd5726584 + + nem_transaction_start( + &ctx, + fromhex( + "6bf7849c1eec6a2002995cc457dc00c4e29bad5c88de63f51e42dfdcd7b2131d"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_aggregate_modification( + &ctx, NEM_NETWORK_TESTNET, 6542254, NULL, 40000000, 6545854, 4, true)); + + ck_assert(nem_transaction_write_cosignatory_modification( + &ctx, 1, + fromhex( + "5f53d076c8c3ec3110b98364bc423092c3ec2be2b1b3c40fd8ab68d54fa39295"))); + ck_assert(nem_transaction_write_cosignatory_modification( + &ctx, 1, + fromhex( + "9eb199c2b4d406f64cb7aa5b2b0815264b56ba8fe44d558a6cb423a31a33c4c2"))); + ck_assert(nem_transaction_write_cosignatory_modification( + &ctx, 1, + fromhex( + "94b2323dab23a3faba24fa6ddda0ece4fbb06acfedd74e76ad9fae38d006882b"))); + ck_assert(nem_transaction_write_cosignatory_modification( + &ctx, 1, + fromhex( + "d88c6ee2a2cd3929d0d76b6b14ecb549d21296ab196a2b3a4cb2536bcce32e87"))); + + ck_assert(nem_transaction_write_minimum_cosignatories(&ctx, 2)); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "1fbdae5ba753e68af270930413ae90f671eb8ab58988116684bac0abd5726584"), + sizeof(hash)); + + // http://chain.nem.ninja/#/aggregate/cc64ca69bfa95db2ff7ac1e21fe6d27ece189c603200ebc9778d8bb80ca25c3c + + nem_transaction_start( + &ctx, + fromhex( + "f41b99320549741c5cce42d9e4bb836d98c50ed5415d0c3c2912d1bb50e6a0e5"), + buffer, sizeof(buffer)); + + ck_assert(nem_transaction_create_aggregate_modification( + &ctx, NEM_NETWORK_MAINNET, 0, NULL, 40000000, 0, 5, false)); + + ck_assert(nem_transaction_write_cosignatory_modification( + &ctx, 1, + fromhex( + "1fbdbdde28daf828245e4533765726f0b7790e0b7146e2ce205df3e86366980b"))); + ck_assert(nem_transaction_write_cosignatory_modification( + &ctx, 1, + fromhex( + "f94e8702eb1943b23570b1b83be1b81536df35538978820e98bfce8f999e2d37"))); + ck_assert(nem_transaction_write_cosignatory_modification( + &ctx, 1, + fromhex( + "826cedee421ff66e708858c17815fcd831a4bb68e3d8956299334e9e24380ba8"))); + ck_assert(nem_transaction_write_cosignatory_modification( + &ctx, 1, + fromhex( + "719862cd7d0f4e875a6a0274c9a1738f38f40ad9944179006a54c34724c1274d"))); + ck_assert(nem_transaction_write_cosignatory_modification( + &ctx, 1, + fromhex( + "43aa69177018fc3e2bdbeb259c81cddf24be50eef9c5386db51d82386c41475a"))); + + keccak_256(ctx.buffer, ctx.offset, hash); + ck_assert_mem_eq( + hash, + fromhex( + "cc64ca69bfa95db2ff7ac1e21fe6d27ece189c603200ebc9778d8bb80ca25c3c"), + sizeof(hash)); +} +END_TEST + +START_TEST(test_multibyte_address) { + uint8_t priv_key[32]; + char wif[57]; + uint8_t pub_key[33]; + char address[40]; + uint8_t decode[24]; + int res; + + memcpy( + priv_key, + fromhex( + "47f7616ea6f9b923076625b4488115de1ef1187f760e65f89eb6f4f7ff04b012"), + 32); + ecdsa_get_wif(priv_key, 0, HASHER_SHA2D, wif, sizeof(wif)); + ck_assert_str_eq(wif, "13QtoXmbhELWcrwD9YA9KzvXy5rTaptiNuFR8L8ArpBNn4xmQj4N"); + ecdsa_get_wif(priv_key, 0x12, HASHER_SHA2D, wif, sizeof(wif)); + ck_assert_str_eq(wif, "3hrF6SFnqzpzABB36uGDf8dJSuUCcMmoJrTmCWMshRkBr2Vx86qJ"); + ecdsa_get_wif(priv_key, 0x1234, HASHER_SHA2D, wif, sizeof(wif)); + ck_assert_str_eq(wif, + "CtPTF9awbVbfDWGepGdVhB3nBhr4HktUGya8nf8dLxgC8tbqBreB9"); + ecdsa_get_wif(priv_key, 0x123456, HASHER_SHA2D, wif, sizeof(wif)); + ck_assert_str_eq(wif, + "uTrDevVQt5QZgoL3iJ1cPWHaCz7ZMBncM7QXZfCegtxiMHqBvWoYJa"); + ecdsa_get_wif(priv_key, 0x12345678, HASHER_SHA2D, wif, sizeof(wif)); + ck_assert_str_eq(wif, + "4zZWMzv1SVbs95pmLXWrXJVp9ntPEam1mfwb6CXBLn9MpWNxLg9huYgv"); + ecdsa_get_wif(priv_key, 0xffffffff, HASHER_SHA2D, wif, sizeof(wif)); + ck_assert_str_eq(wif, + "y9KVfV1RJXcTxpVjeuh6WYWh8tMwnAUeyUwDEiRviYdrJ61njTmnfUjE"); + + memcpy( + pub_key, + fromhex( + "0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71"), + 33); + ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8"); + ecdsa_get_address(pub_key, 0x12, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "8SCrMR2yYF7ciqoDbav7VLLTsVx5dTVPPq"); + ecdsa_get_address(pub_key, 0x1234, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, + sizeof(address)); + ck_assert_str_eq(address, "ZLH8q1UgMPg8o2s1MD55YVMpPV7vqms9kiV"); + ecdsa_get_address(pub_key, 0x123456, HASHER_SHA2_RIPEMD, HASHER_SHA2D, + address, sizeof(address)); + ck_assert_str_eq(address, "3ThqvsQVFnbiF66NwHtfe2j6AKn75DpLKpQSq"); + ecdsa_get_address(pub_key, 0x12345678, HASHER_SHA2_RIPEMD, HASHER_SHA2D, + address, sizeof(address)); + ck_assert_str_eq(address, "BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44"); + ecdsa_get_address(pub_key, 0xffffffff, HASHER_SHA2_RIPEMD, HASHER_SHA2D, + address, sizeof(address)); + ck_assert_str_eq(address, "3diW7paWGJyZRLGqMJZ55DMfPExob8QxQHkrfYT"); + + res = ecdsa_address_decode("1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8", 0, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, + fromhex("0079fbfc3f34e7745860d76137da68f362380c606c"), 21); + res = ecdsa_address_decode("8SCrMR2yYF7ciqoDbav7VLLTsVx5dTVPPq", 0x12, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, + fromhex("1279fbfc3f34e7745860d76137da68f362380c606c"), 21); + res = ecdsa_address_decode("ZLH8q1UgMPg8o2s1MD55YVMpPV7vqms9kiV", 0x1234, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, + fromhex("123479fbfc3f34e7745860d76137da68f362380c606c"), 21); + res = ecdsa_address_decode("3ThqvsQVFnbiF66NwHtfe2j6AKn75DpLKpQSq", 0x123456, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq( + decode, fromhex("12345679fbfc3f34e7745860d76137da68f362380c606c"), 21); + res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", + 0x12345678, HASHER_SHA2D, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq( + decode, fromhex("1234567879fbfc3f34e7745860d76137da68f362380c606c"), 21); + res = ecdsa_address_decode("3diW7paWGJyZRLGqMJZ55DMfPExob8QxQHkrfYT", + 0xffffffff, HASHER_SHA2D, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq( + decode, fromhex("ffffffff79fbfc3f34e7745860d76137da68f362380c606c"), 21); + + // wrong length + res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", 0x123456, + HASHER_SHA2D, decode); + ck_assert_int_eq(res, 0); + + // wrong address prefix + res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", + 0x22345678, HASHER_SHA2D, decode); + ck_assert_int_eq(res, 0); + + // wrong checksum + res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL45", + 0x12345678, HASHER_SHA2D, decode); + ck_assert_int_eq(res, 0); +} +END_TEST + +// https://tools.ietf.org/html/rfc6229#section-2 +START_TEST(test_rc4_rfc6229) { + static const size_t offsets[] = { + 0x0, 0xf0, 0x1f0, 0x2f0, 0x3f0, 0x5f0, 0x7f0, 0xbf0, 0xff0, + }; + + static const struct { + char key[65]; + char vectors[sizeof(offsets) / sizeof(*offsets)][65]; + } tests[] = { + {"0102030405", + { + "b2396305f03dc027ccc3524a0a1118a8" + "6982944f18fc82d589c403a47a0d0919", + "28cb1132c96ce286421dcaadb8b69eae" + "1cfcf62b03eddb641d77dfcf7f8d8c93", + "42b7d0cdd918a8a33dd51781c81f4041" + "6459844432a7da923cfb3eb4980661f6", + "ec10327bde2beefd18f9277680457e22" + "eb62638d4f0ba1fe9fca20e05bf8ff2b", + "45129048e6a0ed0b56b490338f078da5" + "30abbcc7c20b01609f23ee2d5f6bb7df", + "3294f744d8f9790507e70f62e5bbceea" + "d8729db41882259bee4f825325f5a130", + "1eb14a0c13b3bf47fa2a0ba93ad45b8b" + "cc582f8ba9f265e2b1be9112e975d2d7", + "f2e30f9bd102ecbf75aaade9bc35c43c" + "ec0e11c479dc329dc8da7968fe965681", + "068326a2118416d21f9d04b2cd1ca050" + "ff25b58995996707e51fbdf08b34d875", + }}, + {"01020304050607", + { + "293f02d47f37c9b633f2af5285feb46b" + "e620f1390d19bd84e2e0fd752031afc1", + "914f02531c9218810df60f67e338154c" + "d0fdb583073ce85ab83917740ec011d5", + "75f81411e871cffa70b90c74c592e454" + "0bb87202938dad609e87a5a1b079e5e4", + "c2911246b612e7e7b903dfeda1dad866" + "32828f91502b6291368de8081de36fc2", + "f3b9a7e3b297bf9ad804512f9063eff1" + "8ecb67a9ba1f55a5a067e2b026a3676f", + "d2aa902bd42d0d7cfd340cd45810529f" + "78b272c96e42eab4c60bd914e39d06e3", + "f4332fd31a079396ee3cee3f2a4ff049" + "05459781d41fda7f30c1be7e1246c623", + "adfd3868b8e51485d5e610017e3dd609" + "ad26581c0c5be45f4cea01db2f3805d5", + "f3172ceffc3b3d997c85ccd5af1a950c" + "e74b0b9731227fd37c0ec08a47ddd8b8", + }}, + {"0102030405060708", + { + "97ab8a1bf0afb96132f2f67258da15a8" + "8263efdb45c4a18684ef87e6b19e5b09", + "9636ebc9841926f4f7d1f362bddf6e18" + "d0a990ff2c05fef5b90373c9ff4b870a", + "73239f1db7f41d80b643c0c52518ec63" + "163b319923a6bdb4527c626126703c0f", + "49d6c8af0f97144a87df21d91472f966" + "44173a103b6616c5d5ad1cee40c863d0", + "273c9c4b27f322e4e716ef53a47de7a4" + "c6d0e7b226259fa9023490b26167ad1d", + "1fe8986713f07c3d9ae1c163ff8cf9d3" + "8369e1a965610be887fbd0c79162aafb", + "0a0127abb44484b9fbef5abcae1b579f" + "c2cdadc6402e8ee866e1f37bdb47e42c", + "26b51ea37df8e1d6f76fc3b66a7429b3" + "bc7683205d4f443dc1f29dda3315c87b", + "d5fa5a3469d29aaaf83d23589db8c85b" + "3fb46e2c8f0f068edce8cdcd7dfc5862", + }}, + {"0102030405060708090a", + { + "ede3b04643e586cc907dc21851709902" + "03516ba78f413beb223aa5d4d2df6711", + "3cfd6cb58ee0fdde640176ad0000044d" + "48532b21fb6079c9114c0ffd9c04a1ad", + "3e8cea98017109979084b1ef92f99d86" + "e20fb49bdb337ee48b8d8dc0f4afeffe", + "5c2521eacd7966f15e056544bea0d315" + "e067a7031931a246a6c3875d2f678acb", + "a64f70af88ae56b6f87581c0e23e6b08" + "f449031de312814ec6f319291f4a0516", + "bdae85924b3cb1d0a2e33a30c6d79599" + "8a0feddbac865a09bcd127fb562ed60a", + "b55a0a5b51a12a8be34899c3e047511a" + "d9a09cea3ce75fe39698070317a71339", + "552225ed1177f44584ac8cfa6c4eb5fc" + "7e82cbabfc95381b080998442129c2f8", + "1f135ed14ce60a91369d2322bef25e3c" + "08b6be45124a43e2eb77953f84dc8553", + }}, + {"0102030405060708090a0b0c0d0e0f10", + { + "9ac7cc9a609d1ef7b2932899cde41b97" + "5248c4959014126a6e8a84f11d1a9e1c", + "065902e4b620f6cc36c8589f66432f2b" + "d39d566bc6bce3010768151549f3873f", + "b6d1e6c4a5e4771cad79538df295fb11" + "c68c1d5c559a974123df1dbc52a43b89", + "c5ecf88de897fd57fed301701b82a259" + "eccbe13de1fcc91c11a0b26c0bc8fa4d", + "e7a72574f8782ae26aabcf9ebcd66065" + "bdf0324e6083dcc6d3cedd3ca8c53c16", + "b40110c4190b5622a96116b0017ed297" + "ffa0b514647ec04f6306b892ae661181", + "d03d1bc03cd33d70dff9fa5d71963ebd" + "8a44126411eaa78bd51e8d87a8879bf5", + "fabeb76028ade2d0e48722e46c4615a3" + "c05d88abd50357f935a63c59ee537623", + "ff38265c1642c1abe8d3c2fe5e572bf8" + "a36a4c301ae8ac13610ccbc12256cacc", + }}, + {"0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20", + { + "eaa6bd25880bf93d3f5d1e4ca2611d91" + "cfa45c9f7e714b54bdfa80027cb14380", + "114ae344ded71b35f2e60febad727fd8" + "02e1e7056b0f623900496422943e97b6", + "91cb93c787964e10d9527d999c6f936b" + "49b18b42f8e8367cbeb5ef104ba1c7cd", + "87084b3ba700bade955610672745b374" + "e7a7b9e9ec540d5ff43bdb12792d1b35", + "c799b596738f6b018c76c74b1759bd90" + "7fec5bfd9f9b89ce6548309092d7e958", + "40f250b26d1f096a4afd4c340a588815" + "3e34135c79db010200767651cf263073", + "f656abccf88dd827027b2ce917d464ec" + "18b62503bfbc077fbabb98f20d98ab34", + "8aed95ee5b0dcbfbef4eb21d3a3f52f9" + "625a1ab00ee39a5327346bddb01a9c18", + "a13a7c79c7e119b5ab0296ab28c300b9" + "f3e4c0a2e02d1d01f7f0a74618af2b48", + }}, + {"833222772a", + { + "80ad97bdc973df8a2e879e92a497efda" + "20f060c2f2e5126501d3d4fea10d5fc0", + "faa148e99046181fec6b2085f3b20ed9" + "f0daf5bab3d596839857846f73fbfe5a", + "1c7e2fc4639232fe297584b296996bc8" + "3db9b249406cc8edffac55ccd322ba12", + "e4f9f7e0066154bbd125b745569bc897" + "75d5ef262b44c41a9cf63ae14568e1b9", + "6da453dbf81e82334a3d8866cb50a1e3" + "7828d074119cab5c22b294d7a9bfa0bb", + "adb89cea9a15fbe617295bd04b8ca05c" + "6251d87fd4aaae9a7e4ad5c217d3f300", + "e7119bd6dd9b22afe8f89585432881e2" + "785b60fd7ec4e9fcb6545f350d660fab", + "afecc037fdb7b0838eb3d70bcd268382" + "dbc1a7b49d57358cc9fa6d61d73b7cf0", + "6349d126a37afcba89794f9804914fdc" + "bf42c3018c2f7c66bfde524975768115", + }}, + {"1910833222772a", + { + "bc9222dbd3274d8fc66d14ccbda6690b" + "7ae627410c9a2be693df5bb7485a63e3", + "3f0931aa03defb300f060103826f2a64" + "beaa9ec8d59bb68129f3027c96361181", + "74e04db46d28648d7dee8a0064b06cfe" + "9b5e81c62fe023c55be42f87bbf932b8", + "ce178fc1826efecbc182f57999a46140" + "8bdf55cd55061c06dba6be11de4a578a", + "626f5f4dce652501f3087d39c92cc349" + "42daac6a8f9ab9a7fd137c6037825682", + "cc03fdb79192a207312f53f5d4dc33d9" + "f70f14122a1c98a3155d28b8a0a8a41d", + "2a3a307ab2708a9c00fe0b42f9c2d6a1" + "862617627d2261eab0b1246597ca0ae9", + "55f877ce4f2e1ddbbf8e13e2cde0fdc8" + "1b1556cb935f173337705fbb5d501fc1", + "ecd0e96602be7f8d5092816cccf2c2e9" + "027881fab4993a1c262024a94fff3f61", + }}, + {"641910833222772a", + { + "bbf609de9413172d07660cb680716926" + "46101a6dab43115d6c522b4fe93604a9", + "cbe1fff21c96f3eef61e8fe0542cbdf0" + "347938bffa4009c512cfb4034b0dd1a7", + "7867a786d00a7147904d76ddf1e520e3" + "8d3e9e1caefcccb3fbf8d18f64120b32", + "942337f8fd76f0fae8c52d7954810672" + "b8548c10f51667f6e60e182fa19b30f7", + "0211c7c6190c9efd1237c34c8f2e06c4" + "bda64f65276d2aacb8f90212203a808e", + "bd3820f732ffb53ec193e79d33e27c73" + "d0168616861907d482e36cdac8cf5749", + "97b0f0f224b2d2317114808fb03af7a0" + "e59616e469787939a063ceea9af956d1", + "c47e0dc1660919c11101208f9e69aa1f" + "5ae4f12896b8379a2aad89b5b553d6b0", + "6b6b098d0c293bc2993d80bf0518b6d9" + "8170cc3ccd92a698621b939dd38fe7b9", + }}, + {"8b37641910833222772a", + { + "ab65c26eddb287600db2fda10d1e605c" + "bb759010c29658f2c72d93a2d16d2930", + "b901e8036ed1c383cd3c4c4dd0a6ab05" + "3d25ce4922924c55f064943353d78a6c", + "12c1aa44bbf87e75e611f69b2c38f49b" + "28f2b3434b65c09877470044c6ea170d", + "bd9ef822de5288196134cf8af7839304" + "67559c23f052158470a296f725735a32", + "8bab26fbc2c12b0f13e2ab185eabf241" + "31185a6d696f0cfa9b42808b38e132a2", + "564d3dae183c5234c8af1e51061c44b5" + "3c0778a7b5f72d3c23a3135c7d67b9f4", + "f34369890fcf16fb517dcaae4463b2dd" + "02f31c81e8200731b899b028e791bfa7", + "72da646283228c14300853701795616f" + "4e0a8c6f7934a788e2265e81d6d0c8f4", + "438dd5eafea0111b6f36b4b938da2a68" + "5f6bfc73815874d97100f086979357d8", + }}, + {"ebb46227c6cc8b37641910833222772a", + { + "720c94b63edf44e131d950ca211a5a30" + "c366fdeacf9ca80436be7c358424d20b", + "b3394a40aabf75cba42282ef25a0059f" + "4847d81da4942dbc249defc48c922b9f", + "08128c469f275342adda202b2b58da95" + "970dacef40ad98723bac5d6955b81761", + "3cb89993b07b0ced93de13d2a11013ac" + "ef2d676f1545c2c13dc680a02f4adbfe", + "b60595514f24bc9fe522a6cad7393644" + "b515a8c5011754f59003058bdb81514e", + "3c70047e8cbc038e3b9820db601da495" + "1175da6ee756de46a53e2b075660b770", + "00a542bba02111cc2c65b38ebdba587e" + "5865fdbb5b48064104e830b380f2aede", + "34b21ad2ad44e999db2d7f0863f0d9b6" + "84a9218fc36e8a5f2ccfbeae53a27d25", + "a2221a11b833ccb498a59540f0545f4a" + "5bbeb4787d59e5373fdbea6c6f75c29b", + }}, + {"c109163908ebe51debb46227c6cc8b37641910833222772a", + { + "54b64e6b5a20b5e2ec84593dc7989da7" + "c135eee237a85465ff97dc03924f45ce", + "cfcc922fb4a14ab45d6175aabbf2d201" + "837b87e2a446ad0ef798acd02b94124f", + "17a6dbd664926a0636b3f4c37a4f4694" + "4a5f9f26aeeed4d4a25f632d305233d9", + "80a3d01ef00c8e9a4209c17f4eeb358c" + "d15e7d5ffaaabc0207bf200a117793a2", + "349682bf588eaa52d0aa1560346aeafa" + "f5854cdb76c889e3ad63354e5f7275e3", + "532c7ceccb39df3236318405a4b1279c" + "baefe6d9ceb651842260e0d1e05e3b90", + "e82d8c6db54e3c633f581c952ba04207" + "4b16e50abd381bd70900a9cd9a62cb23", + "3682ee33bd148bd9f58656cd8f30d9fb" + "1e5a0b8475045d9b20b2628624edfd9e", + "63edd684fb826282fe528f9c0e9237bc" + "e4dd2e98d6960fae0b43545456743391", + }}, + {"1ada31d5cf688221c109163908ebe51debb46227c6cc8b37641910833222772a", + { + "dd5bcb0018e922d494759d7c395d02d3" + "c8446f8f77abf737685353eb89a1c9eb", + "af3e30f9c095045938151575c3fb9098" + "f8cb6274db99b80b1d2012a98ed48f0e", + "25c3005a1cb85de076259839ab7198ab" + "9dcbc183e8cb994b727b75be3180769c", + "a1d3078dfa9169503ed9d4491dee4eb2" + "8514a5495858096f596e4bcd66b10665", + "5f40d59ec1b03b33738efa60b2255d31" + "3477c7f764a41baceff90bf14f92b7cc", + "ac4e95368d99b9eb78b8da8f81ffa795" + "8c3c13f8c2388bb73f38576e65b7c446", + "13c4b9c1dfb66579eddd8a280b9f7316" + "ddd27820550126698efaadc64b64f66e", + "f08f2e66d28ed143f3a237cf9de73559" + "9ea36c525531b880ba124334f57b0b70", + "d5a39e3dfcc50280bac4a6b5aa0dca7d" + "370b1c1fe655916d97fd0d47ca1d72b8", + }}}; + + RC4_CTX ctx; + uint8_t key[64]; + uint8_t buffer[0x1010]; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + size_t length = strlen(tests[i].key) / 2; + memcpy(key, fromhex(tests[i].key), length); + memzero(buffer, sizeof(buffer)); + + rc4_init(&ctx, key, length); + rc4_encrypt(&ctx, buffer, sizeof(buffer)); + + for (size_t j = 0; j < (sizeof(offsets) / sizeof(*offsets)); j++) { + size_t size = strlen(tests[i].vectors[j]) / 2; + ck_assert_mem_eq(&buffer[offsets[j]], fromhex(tests[i].vectors[j]), size); + } + } +} +END_TEST + +static void test_compress_coord(const char *k_raw) { + const ecdsa_curve *curve = &secp256k1; + curve_point expected_coords; + + bignum256 k = {0}; + + bn_read_be(fromhex(k_raw), &k); + + point_multiply(curve, &k, &curve->G, &expected_coords); + + uint8_t compress[33] = {0}; + compress_coords(&expected_coords, compress); + + bignum256 x = {0}, y = {0}; + bn_read_be(compress + 1, &x); + uncompress_coords(curve, compress[0], &x, &y); + + ck_assert(bn_is_equal(&expected_coords.x, &x)); + ck_assert(bn_is_equal(&expected_coords.y, &y)); +} + +START_TEST(test_compress_coords) { + static const char *k_raw[] = { + "dc05960ac673fd59554c98655e26722d007bb7ada0c8ff00883fdee70783d0be", + "41e41e0a218c980411108a0a58cf88f528c828b4d6f0d2c86234bc2504bdc3cd", + "1d963ddcb79f6028a32cadd2421ff7fff969bff5774f73063dab41519b3da175", + "2414141f96da0874dbc374b58861589935b7f940806ddf8d2e6b911f62e240f3", + "01cc1fb182e29f60fe43e22d250de34f2d3f956bbef2aa9b182d09e5d9176873", + "89b3d621d813682692fd61b2baea6b2ea696a44abc76925d29c4887fc4db9367", + "20c80c633e05a3a7dfac05fa0e0a7c7a6b708b02323e687735cff81ea5944f59", + "5a803c263aa93a4f74648066c03e63fb00641193bae93dfa254dabd634e8b49c", + "05efbcc87007797dca68315b9271ac8fb75bddbece53f4dcbfb83fc21cb91fc0", + "0bed78ef43474630bd646eef2d7ec19a1acb8e9eecf6a0a3ac7241ac40a7706f", + }; + + for (int i = 0; i < (int)(sizeof(k_raw) / sizeof(*k_raw)); i++) + test_compress_coord(k_raw[i]); +} +END_TEST + +START_TEST(test_schnorr_sign_verify_digest) { + static struct { + const char *digest; + const char *priv_key; + const char *sig; + } tests[] = { + { + /* Very deterministic message */ + "5255683DA567900BFD3E786ED8836A4E7763C221BF1AC20ECE2A5171B9199E8A", + "12B004FFF7F4B69EF8650E767F18F11EDE158148B425660723B9F9A66E61F747", + "2C56731AC2F7A7E7F11518FC7722A166B02438924CA9D8B4D111347B81D07175" + "71846DE67AD3D913A8FDF9D8F3F73161A4C48AE81CB183B214765FEB86E255CE", + }, + }; + + const ecdsa_curve *curve = &secp256k1; + uint8_t digest[SHA256_DIGEST_LENGTH] = {0}; + uint8_t priv_key[32] = {0}; + uint8_t pub_key[33] = {0}; + uint8_t result[SCHNORR_SIG_LENGTH] = {0}; + uint8_t expected[SCHNORR_SIG_LENGTH] = {0}; + int res = 0; + + for (size_t i = 0; i < sizeof(tests) / sizeof(*tests); i++) { + memcpy(digest, fromhex(tests[i].digest), SHA256_DIGEST_LENGTH); + memcpy(priv_key, fromhex(tests[i].priv_key), 32); + memcpy(expected, fromhex(tests[i].sig), SCHNORR_SIG_LENGTH); + + ecdsa_get_public_key33(curve, priv_key, pub_key); + + schnorr_sign_digest(curve, priv_key, digest, result); + + ck_assert_mem_eq(expected, result, SCHNORR_SIG_LENGTH); + + res = schnorr_verify_digest(curve, pub_key, digest, result); + ck_assert_int_eq(res, 0); + } +} +END_TEST + +START_TEST(test_schnorr_verify_digest) { + static struct { + const char *digest; + const char *pub_key; + const char *sig; + const int res; + } tests[] = { + { + /* Very deterministic message */ + "5255683DA567900BFD3E786ED8836A4E7763C221BF1AC20ECE2A5171B9199E8A", + "030B4C866585DD868A9D62348A9CD008D6A312937048FFF31670E7E920CFC7A744", + "2C56731AC2F7A7E7F11518FC7722A166B02438924CA9D8B4D111347B81D07175" + "71846DE67AD3D913A8FDF9D8F3F73161A4C48AE81CB183B214765FEB86E255CE", + 0, /* Success */ + }, + { + /* + * From Bitcoin ABC libsecp256k1, test vector 1. + * https://github.com/Bitcoin-ABC/secp256k1/blob/master/src/modules/schnorr/tests_impl.h + */ + "0000000000000000000000000000000000000000000000000000000000000000", + "0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", + "787A848E71043D280C50470E8E1532B2DD5D20EE912A45DBDD2BD1DFBF187EF6" + "7031A98831859DC34DFFEEDDA86831842CCD0079E1F92AF177F7F22CC1DCED05", + 0, /* Success */ + }, + { + /* + * From Bitcoin ABC libsecp256k1, test vector 2. + * https://github.com/Bitcoin-ABC/secp256k1/blob/master/src/modules/schnorr/tests_impl.h + */ + "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", + "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", + "2A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D" + "1E51A22CCEC35599B8F266912281F8365FFC2D035A230434A1A64DC59F7013FD", + 0, /* Success */ + }, + { + /* + * From Bitcoin ABC libsecp256k1, test vector 3. + * https://github.com/Bitcoin-ABC/secp256k1/blob/master/src/modules/schnorr/tests_impl.h + */ + "5E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C", + "03FAC2114C2FBB091527EB7C64ECB11F8021CB45E8E7809D3C0938E4B8C0E5F84B", + "00DA9B08172A9B6F0466A2DEFD817F2D7AB437E0D253CB5395A963866B3574BE" + "00880371D01766935B92D2AB4CD5C8A2A5837EC57FED7660773A05F0DE142380", + 0, /* Success */ + }, + { + /* + * From Bitcoin ABC libsecp256k1, test vector 4. + * https://github.com/Bitcoin-ABC/secp256k1/blob/master/src/modules/schnorr/tests_impl.h + */ + "4DF3C3F68FCC83B27E9D42C90431A72499F17875C81A599B566C9889B9696703", + "03DEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34", + "00000000000000000000003B78CE563F89A0ED9414F5AA28AD0D96D6795F9C63" + "02A8DC32E64E86A333F20EF56EAC9BA30B7246D6D25E22ADB8C6BE1AEB08D49D", + 0, /* Success */ + }, + { + /* + * From Bitcoin ABC libsecp256k1, test vector 4b. + * https://github.com/Bitcoin-ABC/secp256k1/blob/master/src/modules/schnorr/tests_impl.h + */ + "0000000000000000000000000000000000000000000000000000000000000000", + "031B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F", + "52818579ACA59767E3291D91B76B637BEF062083284992F2D95F564CA6CB4E35" + "30B1DA849C8E8304ADC0CFE870660334B3CFC18E825EF1DB34CFAE3DFC5D8187", + 0, /* Success */ + }, + { + /* + * From Bitcoin ABC libsecp256k1, test vector 6. + * https://github.com/Bitcoin-ABC/secp256k1/blob/master/src/modules/schnorr/tests_impl.h + */ + "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", + "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", + "2A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D" + "FA16AEE06609280A19B67A24E1977E4697712B5FD2943914ECD5F730901B4AB7", + 6, /* R.y is not a quadratic residue */ + }, + { + /* + * From Bitcoin ABC libsecp256k1, test vector 7. + * https://github.com/Bitcoin-ABC/secp256k1/blob/master/src/modules/schnorr/tests_impl.h + */ + "5E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C", + "03FAC2114C2FBB091527EB7C64ECB11F8021CB45E8E7809D3C0938E4B8C0E5F84B", + "00DA9B08172A9B6F0466A2DEFD817F2D7AB437E0D253CB5395A963866B3574BE" + "D092F9D860F1776A1F7412AD8A1EB50DACCC222BC8C0E26B2056DF2F273EFDEC", + 5, /* Negated message hash, R.x mismatch */ + }, + { + /* + * From Bitcoin ABC libsecp256k1, test vector 8. + * https://github.com/Bitcoin-ABC/secp256k1/blob/master/src/modules/schnorr/tests_impl.h + */ + "0000000000000000000000000000000000000000000000000000000000000000", + "0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", + "787A848E71043D280C50470E8E1532B2DD5D20EE912A45DBDD2BD1DFBF187EF6" + "8FCE5677CE7A623CB20011225797CE7A8DE1DC6CCD4F754A47DA6C600E59543C", + 5, /* Negated s, R.x mismatch */ + }, + { + /* + * From Bitcoin ABC libsecp256k1, test vector 9. + * https://github.com/Bitcoin-ABC/secp256k1/blob/master/src/modules/schnorr/tests_impl.h + */ + "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", + "03DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", + "2A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D" + "1E51A22CCEC35599B8F266912281F8365FFC2D035A230434A1A64DC59F7013FD", + 5, /* Negated P, R.x mismatch */ + }, + { + /* + * From Bitcoin ABC libsecp256k1, test vector 10. + * https://github.com/Bitcoin-ABC/secp256k1/blob/master/src/modules/schnorr/tests_impl.h + */ + "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", + "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", + "2A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D" + "8C3428869A663ED1E954705B020CBB3E7BB6AC31965B9EA4C73E227B17C5AF5A", + 4, /* s * G = e * P, R = 0 */ + }, + { + /* + * From Bitcoin ABC libsecp256k1, test vector 11. + * https://github.com/Bitcoin-ABC/secp256k1/blob/master/src/modules/schnorr/tests_impl.h + */ + "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", + "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", + "4A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D" + "1E51A22CCEC35599B8F266912281F8365FFC2D035A230434A1A64DC59F7013FD", + 5, /* R.x not on the curve, R.x mismatch */ + }, + { + /* + * From Bitcoin ABC libsecp256k1, test vector 12. + * https://github.com/Bitcoin-ABC/secp256k1/blob/master/src/modules/schnorr/tests_impl.h + */ + "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", + "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC2F" + "1E51A22CCEC35599B8F266912281F8365FFC2D035A230434A1A64DC59F7013FD", + 1, /* r = p */ + }, + { + /* + * From Bitcoin ABC libsecp256k1, test vector 13. + * https://github.com/Bitcoin-ABC/secp256k1/blob/master/src/modules/schnorr/tests_impl.h + */ + "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", + "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", + "2A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D" + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", + 1, /* s = n */ + }, + { + /* Very deterministic message */ + "5255683DA567900BFD3E786ED8836A4E7763C221BF1AC20ECE2A5171B9199E8A", + "010B4C866585DD868A9D62348A9CD008D6A312937048FFF31670E7E920CFC7A744", + "2C56731AC2F7A7E7F11518FC7722A166B02438924CA9D8B4D111347B81D07175" + "71846DE67AD3D913A8FDF9D8F3F73161A4C48AE81CB183B214765FEB86E255CE", + 2, /* Invalid public key */ + }, + }; + + const ecdsa_curve *curve = &secp256k1; + uint8_t digest[SHA256_DIGEST_LENGTH] = {0}; + uint8_t pub_key[33] = {0}; + uint8_t signature[SCHNORR_SIG_LENGTH] = {0}; + int res = 0; + + for (size_t i = 0; i < sizeof(tests) / sizeof(*tests); i++) { + memcpy(digest, fromhex(tests[i].digest), SHA256_DIGEST_LENGTH); + memcpy(pub_key, fromhex(tests[i].pub_key), 33); + memcpy(signature, fromhex(tests[i].sig), SCHNORR_SIG_LENGTH); + + res = schnorr_verify_digest(curve, pub_key, digest, signature); + ck_assert_int_eq(res, tests[i].res); + } +} +END_TEST + +static int my_strncasecmp(const char *s1, const char *s2, size_t n) { + size_t i = 0; + while (i < n) { + char c1 = s1[i]; + char c2 = s2[i]; + if (c1 >= 'A' && c1 <= 'Z') c1 = (c1 - 'A') + 'a'; + if (c2 >= 'A' && c2 <= 'Z') c2 = (c2 - 'A') + 'a'; + if (c1 < c2) return -1; + if (c1 > c2) return 1; + if (c1 == 0) return 0; + ++i; + } + return 0; +} + +#include "test_check_cashaddr.h" +#include "test_check_segwit.h" + +#if USE_CARDANO +#include "test_check_cardano.h" +#endif + +#if USE_MONERO +#include "test_check_monero.h" +#endif + +// define test suite and cases +Suite *test_suite(void) { + Suite *s = suite_create("trezor-crypto"); + TCase *tc; + + tc = tcase_create("bignum"); + tcase_add_test(tc, test_bignum_read_be); + tcase_add_test(tc, test_bignum_write_be); + tcase_add_test(tc, test_bignum_is_equal); + tcase_add_test(tc, test_bignum_zero); + tcase_add_test(tc, test_bignum_is_zero); + tcase_add_test(tc, test_bignum_one); + tcase_add_test(tc, test_bignum_read_le); + tcase_add_test(tc, test_bignum_write_le); + tcase_add_test(tc, test_bignum_read_uint32); + tcase_add_test(tc, test_bignum_read_uint64); + tcase_add_test(tc, test_bignum_write_uint32); + tcase_add_test(tc, test_bignum_write_uint64); + tcase_add_test(tc, test_bignum_copy); + tcase_add_test(tc, test_bignum_is_even); + tcase_add_test(tc, test_bignum_is_odd); + tcase_add_test(tc, test_bignum_bitcount); + tcase_add_test(tc, test_bignum_digitcount); + tcase_add_test(tc, test_bignum_is_less); + tcase_add_test(tc, test_bignum_format); + tcase_add_test(tc, test_bignum_format_uint64); + tcase_add_test(tc, test_bignum_sqrt); + suite_add_tcase(s, tc); + + tc = tcase_create("base32"); + tcase_add_test(tc, test_base32_rfc4648); + suite_add_tcase(s, tc); + + tc = tcase_create("base58"); + tcase_add_test(tc, test_base58); + suite_add_tcase(s, tc); + +#if USE_GRAPHENE + tc = tcase_create("base58gph"); + tcase_add_test(tc, test_base58gph); + suite_add_tcase(s, tc); +#endif + + tc = tcase_create("bignum_divmod"); + tcase_add_test(tc, test_bignum_divmod); + suite_add_tcase(s, tc); + + tc = tcase_create("bip32"); + tcase_add_test(tc, test_bip32_vector_1); + tcase_add_test(tc, test_bip32_vector_2); + tcase_add_test(tc, test_bip32_vector_3); + tcase_add_test(tc, test_bip32_vector_4); + tcase_add_test(tc, test_bip32_compare); + tcase_add_test(tc, test_bip32_optimized); + tcase_add_test(tc, test_bip32_cache_1); + tcase_add_test(tc, test_bip32_cache_2); + tcase_add_test(tc, test_bip32_cache_overflow_regression); + tcase_add_test(tc, test_bip32_depth_overflow_regression); + suite_add_tcase(s, tc); + + tc = tcase_create("bip32-nist"); + tcase_add_test(tc, test_bip32_nist_seed); + tcase_add_test(tc, test_bip32_nist_vector_1); + tcase_add_test(tc, test_bip32_nist_vector_2); + tcase_add_test(tc, test_bip32_nist_compare); + tcase_add_test(tc, test_bip32_nist_repeat); + suite_add_tcase(s, tc); + + tc = tcase_create("bip32-ed25519"); + tcase_add_test(tc, test_bip32_ed25519_vector_1); + tcase_add_test(tc, test_bip32_ed25519_vector_2); + suite_add_tcase(s, tc); + + tc = tcase_create("bip32-ecdh"); + tcase_add_test(tc, test_bip32_ecdh_nist256p1); + tcase_add_test(tc, test_bip32_ecdh_curve25519); + tcase_add_test(tc, test_bip32_ecdh_errors); + suite_add_tcase(s, tc); + + tc = tcase_create("bip32-decred"); + tcase_add_test(tc, test_bip32_decred_vector_1); + tcase_add_test(tc, test_bip32_decred_vector_2); + suite_add_tcase(s, tc); + + tc = tcase_create("ecdsa"); + tcase_add_test(tc, test_ecdsa_signature); + tcase_add_test(tc, test_ecdsa_sign_digest_deterministic_regression); + suite_add_tcase(s, tc); + + tc = tcase_create("rfc6979"); + tcase_add_test(tc, test_rfc6979); + suite_add_tcase(s, tc); + + tc = tcase_create("address"); + tcase_add_test(tc, test_address); + suite_add_tcase(s, tc); + + tc = tcase_create("address_decode"); + tcase_add_test(tc, test_address_decode); + suite_add_tcase(s, tc); + + tc = tcase_create("ethereum_address"); + tcase_add_test(tc, test_ethereum_address); + suite_add_tcase(s, tc); + + tc = tcase_create("rsk_address"); + tcase_add_test(tc, test_rsk_address); + suite_add_tcase(s, tc); + + tc = tcase_create("wif"); + tcase_add_test(tc, test_wif); + suite_add_tcase(s, tc); + + tc = tcase_create("ecdsa_der"); + tcase_add_test(tc, test_ecdsa_der); + suite_add_tcase(s, tc); + + tc = tcase_create("aes"); + tcase_add_test(tc, test_aes); + suite_add_tcase(s, tc); + + tc = tcase_create("sha2"); + tcase_add_test(tc, test_sha1); + tcase_add_test(tc, test_sha256); + tcase_add_test(tc, test_sha512); + suite_add_tcase(s, tc); + + tc = tcase_create("sha3"); + tcase_add_test(tc, test_sha3_256); + tcase_add_test(tc, test_sha3_512); + tcase_add_test(tc, test_keccak_256); + suite_add_tcase(s, tc); + + tc = tcase_create("blake"); + tcase_add_test(tc, test_blake256); + suite_add_tcase(s, tc); + + tc = tcase_create("blake2"); + tcase_add_test(tc, test_blake2b); + tcase_add_test(tc, test_blake2s); + suite_add_tcase(s, tc); + + tc = tcase_create("chacha_drbg"); + tcase_add_test(tc, test_chacha_drbg); + suite_add_tcase(s, tc); + + tc = tcase_create("pbkdf2"); + tcase_add_test(tc, test_pbkdf2_hmac_sha256); + tcase_add_test(tc, test_pbkdf2_hmac_sha512); + suite_add_tcase(s, tc); + + tc = tcase_create("hmac_drbg"); + tcase_add_test(tc, test_hmac_drbg); + suite_add_tcase(s, tc); + + tc = tcase_create("bip39"); + tcase_add_test(tc, test_mnemonic); + tcase_add_test(tc, test_mnemonic_check); + tcase_add_test(tc, test_mnemonic_to_bits); + tcase_add_test(tc, test_mnemonic_find_word); + suite_add_tcase(s, tc); + + tc = tcase_create("slip39"); + tcase_add_test(tc, test_slip39_get_word); + tcase_add_test(tc, test_slip39_word_index); + tcase_add_test(tc, test_slip39_word_completion_mask); + tcase_add_test(tc, test_slip39_sequence_to_word); + tcase_add_test(tc, test_slip39_word_completion); + suite_add_tcase(s, tc); + + tc = tcase_create("shamir"); + tcase_add_test(tc, test_shamir); + suite_add_tcase(s, tc); + + tc = tcase_create("pubkey_validity"); + tcase_add_test(tc, test_pubkey_validity); + suite_add_tcase(s, tc); + + tc = tcase_create("pubkey_uncompress"); + tcase_add_test(tc, test_pubkey_uncompress); + suite_add_tcase(s, tc); + + tc = tcase_create("codepoints"); + tcase_add_test(tc, test_codepoints_secp256k1); + tcase_add_test(tc, test_codepoints_nist256p1); + suite_add_tcase(s, tc); + + tc = tcase_create("mult_border_cases"); + tcase_add_test(tc, test_mult_border_cases_secp256k1); + tcase_add_test(tc, test_mult_border_cases_nist256p1); + suite_add_tcase(s, tc); + + tc = tcase_create("scalar_mult"); + tcase_add_test(tc, test_scalar_mult_secp256k1); + tcase_add_test(tc, test_scalar_mult_nist256p1); + suite_add_tcase(s, tc); + + tc = tcase_create("point_mult"); + tcase_add_test(tc, test_point_mult_secp256k1); + tcase_add_test(tc, test_point_mult_nist256p1); + suite_add_tcase(s, tc); + + tc = tcase_create("scalar_point_mult"); + tcase_add_test(tc, test_scalar_point_mult_secp256k1); + tcase_add_test(tc, test_scalar_point_mult_nist256p1); + suite_add_tcase(s, tc); + + tc = tcase_create("ed25519"); + tcase_add_test(tc, test_ed25519); + suite_add_tcase(s, tc); + + tc = tcase_create("ed25519_keccak"); + tcase_add_test(tc, test_ed25519_keccak); + suite_add_tcase(s, tc); + + tc = tcase_create("ed25519_cosi"); + tcase_add_test(tc, test_ed25519_cosi); + suite_add_tcase(s, tc); + + tc = tcase_create("ed25519_modm"); + tcase_add_test(tc, test_ed25519_modl_add); + tcase_add_test(tc, test_ed25519_modl_neg); + tcase_add_test(tc, test_ed25519_modl_sub); + suite_add_tcase(s, tc); + +#if USE_MONERO + tc = tcase_create("ed25519_ge"); + tcase_add_test(tc, test_ge25519_double_scalarmult_vartime2); + suite_add_tcase(s, tc); +#endif + + tc = tcase_create("script"); + tcase_add_test(tc, test_output_script); + suite_add_tcase(s, tc); + + tc = tcase_create("ethereum_pubkeyhash"); + tcase_add_test(tc, test_ethereum_pubkeyhash); + suite_add_tcase(s, tc); + + tc = tcase_create("nem_address"); + tcase_add_test(tc, test_nem_address); + suite_add_tcase(s, tc); + + tc = tcase_create("nem_encryption"); + tcase_add_test(tc, test_nem_derive); + tcase_add_test(tc, test_nem_cipher); + suite_add_tcase(s, tc); + + tc = tcase_create("nem_transaction"); + tcase_add_test(tc, test_nem_transaction_transfer); + tcase_add_test(tc, test_nem_transaction_multisig); + tcase_add_test(tc, test_nem_transaction_provision_namespace); + tcase_add_test(tc, test_nem_transaction_mosaic_creation); + tcase_add_test(tc, test_nem_transaction_mosaic_supply_change); + tcase_add_test(tc, test_nem_transaction_aggregate_modification); + suite_add_tcase(s, tc); + + tc = tcase_create("multibyte_address"); + tcase_add_test(tc, test_multibyte_address); + suite_add_tcase(s, tc); + + tc = tcase_create("rc4"); + tcase_add_test(tc, test_rc4_rfc6229); + suite_add_tcase(s, tc); + + tc = tcase_create("segwit"); + tcase_add_test(tc, test_segwit); + suite_add_tcase(s, tc); + + tc = tcase_create("cashaddr"); + tcase_add_test(tc, test_cashaddr); + suite_add_tcase(s, tc); + + tc = tcase_create("compress_coords"); + tcase_add_test(tc, test_compress_coords); + suite_add_tcase(s, tc); + + tc = tcase_create("schnorr"); + tcase_add_test(tc, test_schnorr_sign_verify_digest); + tcase_add_test(tc, test_schnorr_verify_digest); + suite_add_tcase(s, tc); + +#if USE_CARDANO + tc = tcase_create("bip32-cardano"); + + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_1); + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_2); + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_3); + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_4); + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_5); + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_6); + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_7); + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_8); + tcase_add_test(tc, test_bip32_cardano_hdnode_vector_9); + + tcase_add_test(tc, test_ed25519_cardano_sign_vectors); + suite_add_tcase(s, tc); +#endif + +#if USE_MONERO + tc = tcase_create("xmr_base58"); + tcase_add_test(tc, test_xmr_base58); + suite_add_tcase(s, tc); + + tc = tcase_create("xmr_crypto"); + tcase_add_test(tc, test_xmr_getset256_modm); + tcase_add_test(tc, test_xmr_cmp256_modm); + tcase_add_test(tc, test_xmr_copy_check_modm); + tcase_add_test(tc, test_xmr_mulsub256_modm); + tcase_add_test(tc, test_xmr_muladd256_modm); + tcase_add_test(tc, test_xmr_curve25519_set); + tcase_add_test(tc, test_xmr_curve25519_consts); + tcase_add_test(tc, test_xmr_curve25519_tests); + tcase_add_test(tc, test_xmr_curve25519_expand_reduce); + tcase_add_test(tc, test_xmr_ge25519_base); + tcase_add_test(tc, test_xmr_ge25519_check); + tcase_add_test(tc, test_xmr_ge25519_scalarmult_base_wrapper); + tcase_add_test(tc, test_xmr_ge25519_scalarmult); + tcase_add_test(tc, test_xmr_ge25519_ops); + suite_add_tcase(s, tc); + + tc = tcase_create("xmr_xmr"); + tcase_add_test(tc, test_xmr_check_point); + tcase_add_test(tc, test_xmr_h); + tcase_add_test(tc, test_xmr_fast_hash); + tcase_add_test(tc, test_xmr_hasher); + tcase_add_test(tc, test_xmr_hash_to_scalar); + tcase_add_test(tc, test_xmr_hash_to_ec); + tcase_add_test(tc, test_xmr_derivation_to_scalar); + tcase_add_test(tc, test_xmr_generate_key_derivation); + tcase_add_test(tc, test_xmr_derive_private_key); + tcase_add_test(tc, test_xmr_derive_public_key); + tcase_add_test(tc, test_xmr_add_keys2); + tcase_add_test(tc, test_xmr_add_keys3); + tcase_add_test(tc, test_xmr_get_subaddress_secret_key); + tcase_add_test(tc, test_xmr_gen_c); + tcase_add_test(tc, test_xmr_varint); + tcase_add_test(tc, test_xmr_gen_range_sig); + suite_add_tcase(s, tc); +#endif + return s; +} + +// run suite +int main(void) { + int number_failed; + Suite *s = test_suite(); + SRunner *sr = srunner_create(s); + srunner_run_all(sr, CK_VERBOSE); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + if (number_failed == 0) { + printf("PASSED ALL TESTS\n"); + } + return number_failed; +} diff --git a/deps/crypto/trezor-crypto/tests/test_check_cardano.h b/deps/crypto/trezor-crypto/tests/test_check_cardano.h new file mode 100644 index 000000000..3abe5c715 --- /dev/null +++ b/deps/crypto/trezor-crypto/tests/test_check_cardano.h @@ -0,0 +1,468 @@ +// https://github.com/input-output-hk/cardano-crypto/blob/master/tests/goldens/cardano/crypto/wallet/BIP39-128 +START_TEST(test_ed25519_cardano_sign_vectors) { + ed25519_public_key public_key; + ed25519_secret_key secret_key; + ed25519_secret_key secret_key_extension; + ed25519_signature signature; + + static const char *vectors[] = { + "6065a956b1b34145c4416fdc3ba3276801850e91a77a31a7be782463288aea5" + "3", // private key + "60ba6e25b1a02157fb69c5d1d7b96c4619736e545447069a6a6f0ba90844bc8" + "e", // private key extension + "64b20fa082b3143d6b5eed42c6ef63f99599d0888afe060620abc1b319935fe" + "1", // public key + "45b1a75fe3119e13c6f60ab9ba674b42f946fdc558e07c83dfa0751c2eba69c7" + "9331bd8a4a975662b23628a438a0eba76367e44c12ca91b39ec59063f860f10" + "d", // signature + + "e7d27516538403a53a8b041656a3f570909df641a0ab811fe7d87c9ba02a830" + "c", // private key + "794a2c54ad8b525b781773c87d38cbf4197636bc427a9d551368286fe4c294a" + "4", // private key extension + "95bb82ffd5707716bc65170ab4e8dafeed90fbe0ce9258713b7751e962d931d" + "f", // public key + "f2c9171782e7df7665126ac545ae53b05964b0160536efdb545e2460dbbec2b1" + "9ec6b338b8f1bf4dfee94360ed024b115e37b1d7e6f3f9ae4beb79539428560" + "f", // signature + + "9b5a3d9a4c60bcd49bb64b72c082b164314d0f61d842f2575fd1d4fb30a28a0" + "c", // private key + "b093e376f41eb7bf80abcd0073a52455d25b5d21815bc758e5f6f81536aedeb" + "b", // private key extension + "79fc8154554b97e4c56ef2f9dbb4c1421ff19509688931a1e964bda5dec0f19" + "f", // public key + "2ba1439ae648a7e8da7c9ab1ee6da94fd4ebe37abd0978306e8fba2afa8f111a" + "88a993dbf008bedae9167f4f68409e4c9ddaf02cba12418447b1848907ad800" + "f", // signature + + "52e0c98aa600cfdcd1ff28fcda5227ed87063f4a98547a78b771052cf102b40" + "c", // private key + "6c18d9f8075b1a6a1833540607479bd58b7beb8a83d2bb01ca7ae02452a2580" + "3", // private key extension + "dc907c7c06e6314eedd9e18c9f6c6f9cc4e205fb1c70da608234c319f1f7b0d" + "6", // public key + "0cd34f84e0d2fcb1800bdb0e869b9041349955ced66aedbe6bda187ebe8d36a6" + "2a05b39647e92fcc42aa7a7368174240afba08b8c81f981a22f942d6bd78160" + "2", // signature + + "11fd6462a3a92b35c22703f6f1c124ddcf36b7c2b09cc2784f320e1cfa12ec0" + "4", // private key + "c2785803c61c46aeca192a1bb1b7b20a8c4cc7fa01db57fc5d1d8a547340235" + "2", // private key extension + "839775a41876e328986aa26168958bba1176e67819b357eea84afceab8b1db7" + "8", // public key + "e41f73db2f8d2896a687802b2be76b7cabb73dfbb4891494883a0cbd9bbb9e5f" + "9d3e14d2d0b06c6674333508496db660936737c0efd9511514147dac79fa490" + "5", // signature + + "5b1e5cad02274ba461f4708d8598d3497faf8fe3e894a379573aa6ac3a03e50" + "5", // private key + "ba179d2e3c67aabb486c48d16002b51ad32eab434c738a1550962313b07098c" + "d", // private key extension + "75eb8d197ec8627c85af88e66aa1e49065dd8ac98ed8991db52ece01635dfb7" + "6", // public key + "631015357cee3051116b4c2ff4d1c5beb13b6e5023635aa1eeb0563cadf0d4fb" + "c10bd5e31b4a4220c67875558c41b5cc0328104ae39cc7ff20ff0c2bda59890" + "6", // signature + + "624b47150f58dfa44284fbc63c9f99b9b79f808c4955a461f0e2be44eb0be50" + "d", // private key + "097aa006d694b165ef37cf23562e5967c96e49255d2f20faae478dee83aa5b0" + "2", // private key extension + "0588589cd9b51dfc028cf225674069cbe52e0e70deb02dc45b79b26ee3548b0" + "0", // public key + "1de1d275428ba9491a433cd473cd076c027f61e7a8b5391df9dea5cb4bc88d8a" + "57b095906a30b13e68259851a8dd3f57b6f0ffa37a5d3ffc171240f2d404f90" + "1", // signature + + 0, + 0, + }; + + const char **test_data; + test_data = vectors; + while (*test_data) { + memcpy(secret_key, fromhex(*test_data), 32); + MARK_SECRET_DATA(secret_key, sizeof(secret_key)); + + memcpy(secret_key_extension, fromhex(*(test_data + 1)), 32); + MARK_SECRET_DATA(secret_key_extension, sizeof(secret_key_extension)); + + ed25519_publickey_ext(secret_key, secret_key_extension, public_key); + UNMARK_SECRET_DATA(public_key, sizeof(public_key)); + + ck_assert_mem_eq(public_key, fromhex(*(test_data + 2)), 32); + + const uint8_t *message = (const uint8_t *)"Hello World"; + ed25519_sign_ext(message, 11, secret_key, secret_key_extension, signature); + UNMARK_SECRET_DATA(signature, sizeof(signature)); + + ck_assert_mem_eq(signature, fromhex(*(test_data + 3)), 64); + + UNMARK_SECRET_DATA(secret_key, sizeof(secret_key)); + UNMARK_SECRET_DATA(secret_key_extension, sizeof(secret_key_extension)); + + test_data += 4; + } +} +END_TEST + +START_TEST(test_bip32_cardano_hdnode_vector_1) { + HDNode node; + + uint8_t mnemonic_bits[66]; + int mnemonic_bits_len = mnemonic_to_bits( + "ring crime symptom enough erupt lady behave ramp apart settle citizen " + "junk", + mnemonic_bits); + ck_assert_int_eq(mnemonic_bits_len, 132); + hdnode_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, + mnemonic_bits_len / 8, &node); + + ck_assert_mem_eq( + node.chain_code, + fromhex( + "affbc325d9027c0f2d9f925b1dcf6c12bf5c1dd08904474066a4f2c00db56173"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "08a14df748e477a69d21c97c56db151fc19e2521f31dd0ac5360f269e5b6ea46"), + 32); + ck_assert_mem_eq( + node.private_key_extension, + fromhex( + "daeb991f2d2128e2525415c56a07f4366baa26c1e48572a5e073934b6de35fbc"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key + 1, + fromhex( + "9a1d04808b4c0682816961cf666e82a7fd35949658aba5354c517eccf12aacb4"), + 32); +} +END_TEST + +START_TEST(test_bip32_cardano_hdnode_vector_2) { + HDNode node; + + uint8_t mnemonic_bits[66]; + int mnemonic_bits_len = mnemonic_to_bits( + "ring crime symptom enough erupt lady behave ramp apart settle citizen " + "junk", + mnemonic_bits); + ck_assert_int_eq(mnemonic_bits_len, 132); + hdnode_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, + mnemonic_bits_len / 8, &node); + + hdnode_private_ckd_cardano(&node, 0x80000000); + + ck_assert_mem_eq( + node.chain_code, + fromhex( + "104c6a0736e501c9bfe2966ba3773f5320495b19c3f2ed222234850af2ccd5b1"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "6064bf06b2e981d7c9792b1482eeecd40ec3cfa12143f4a1f149d48ce8b6ea46"), + 32); + ck_assert_mem_eq( + node.private_key_extension, + fromhex( + "64aa9a16331f14c981b769efcf96addcc4c6db44047fe7a7feae0be23d33bf54"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key + 1, + fromhex( + "c651c14a13c2311fc30a7acf244add1fdac3683e7ba89b4571e4cbcab509b915"), + 32); +} +END_TEST + +START_TEST(test_bip32_cardano_hdnode_vector_3) { + HDNode node; + + uint8_t mnemonic_bits[66]; + int mnemonic_bits_len = mnemonic_to_bits( + "ring crime symptom enough erupt lady behave ramp apart settle citizen " + "junk", + mnemonic_bits); + ck_assert_int_eq(mnemonic_bits_len, 132); + hdnode_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, + mnemonic_bits_len / 8, &node); + + hdnode_private_ckd_cardano(&node, 0x80000001); + + ck_assert_mem_eq( + node.chain_code, + fromhex( + "da99870d7e69de2a76f255ba8c7ed22428c7e5b0a8df978753c707c95ec3d4ca"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "c85fa69f4a1891fd98d1d1fc5f0cf9b1d6e44b0e6906744ab23ea766edb6ea46"), + 32); + ck_assert_mem_eq( + node.private_key_extension, + fromhex( + "b4fc241feffe840b8a54a26ab447f5a5caa31032db3a8091fca14f38b86ed539"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key + 1, + fromhex( + "5a5b0c92530cd366f05cf072509c806f904262c259e79a0080bbd5ee35706bb1"), + 32); +} +END_TEST + +START_TEST(test_bip32_cardano_hdnode_vector_4) { + HDNode node; + + uint8_t mnemonic_bits[66]; + int mnemonic_bits_len = mnemonic_to_bits( + "ring crime symptom enough erupt lady behave ramp apart settle citizen " + "junk", + mnemonic_bits); + ck_assert_int_eq(mnemonic_bits_len, 132); + hdnode_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, + mnemonic_bits_len / 8, &node); + + hdnode_private_ckd_cardano(&node, 0x80000000); + hdnode_private_ckd_cardano(&node, 0x80000001); + + ck_assert_mem_eq( + node.chain_code, + fromhex( + "b40c44dfd9be08591b62be7f9991c85f812d8196927f3c824d9fcb17d275089e"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "d064dcf1449d9c3e47f5b422680343561989035bf2e4e23fc34cb61fedb6ea46"), + 32); + ck_assert_mem_eq( + node.private_key_extension, + fromhex( + "a3071959013af95aaecf78a7a2e1b9838bbbc4864d6a8a2295243782078345cd"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key + 1, + fromhex( + "aaaca5e7adc69a03ef1f5c017ed02879e8ca871df028461ed9bf19fb8fa15038"), + 32); +} +END_TEST + +START_TEST(test_bip32_cardano_hdnode_vector_5) { + HDNode node; + + uint8_t mnemonic_bits[66]; + int mnemonic_bits_len = mnemonic_to_bits( + "ring crime symptom enough erupt lady behave ramp apart settle citizen " + "junk", + mnemonic_bits); + ck_assert_int_eq(mnemonic_bits_len, 132); + hdnode_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, + mnemonic_bits_len / 8, &node); + + hdnode_private_ckd_cardano(&node, 0x80000000); + hdnode_private_ckd_cardano(&node, 0x80000001); + hdnode_private_ckd_cardano(&node, 0x80000002); + + ck_assert_mem_eq( + node.chain_code, + fromhex( + "2593896baf92f6ab2c0f253787ab16be0244ba95e0d48ba09da1a7fd3f926c72"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "0811b6d5d6f7120cb05d4ce5453d6ce42825c2a8e53b6d370a6b05ccf4b6ea46"), + 32); + ck_assert_mem_eq( + node.private_key_extension, + fromhex( + "5bebf1eea68acd04932653d944b064b10baaf5886dd73c185cc285059bf93363"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key + 1, + fromhex( + "1c87a32c5babad2fe33e0586bdc523574c6126f8368bc76598e17ea46201f980"), + 32); +} +END_TEST + +START_TEST(test_bip32_cardano_hdnode_vector_6) { + HDNode node; + + uint8_t mnemonic_bits[66]; + int mnemonic_bits_len = mnemonic_to_bits( + "ring crime symptom enough erupt lady behave ramp apart settle citizen " + "junk", + mnemonic_bits); + ck_assert_int_eq(mnemonic_bits_len, 132); + hdnode_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, + mnemonic_bits_len / 8, &node); + + hdnode_private_ckd_cardano(&node, 0x80000000); + hdnode_private_ckd_cardano(&node, 0x80000001); + hdnode_private_ckd_cardano(&node, 0x80000002); + hdnode_private_ckd_cardano(&node, 0x80000002); + + ck_assert_mem_eq( + node.chain_code, + fromhex( + "fe8c6c2ab1e30385513fcffb49dcfe3e7805260425ea76b3b72b9f5bbe3b3d40"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "6019b9f5ef6ca530b657bcdb500de5455db8d51afb951fa045b6fbb3f6b6ea46"), + 32); + ck_assert_mem_eq( + node.private_key_extension, + fromhex( + "466332cb097934b43008701e7e27044aa56c7859019e4eba18d91a3bea23dff7"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key + 1, + fromhex( + "0b8f04755481ced76b4e5795aaafdb3cbd757c10fe60e9c58f48cf29a7ec3575"), + 32); +} +END_TEST + +START_TEST(test_bip32_cardano_hdnode_vector_7) { + HDNode node; + + uint8_t mnemonic_bits[66]; + int mnemonic_bits_len = mnemonic_to_bits( + "ring crime symptom enough erupt lady behave ramp apart settle citizen " + "junk", + mnemonic_bits); + ck_assert_int_eq(mnemonic_bits_len, 132); + hdnode_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, + mnemonic_bits_len / 8, &node); + + hdnode_private_ckd_cardano(&node, 0x80000000); + hdnode_private_ckd_cardano(&node, 0x80000001); + hdnode_private_ckd_cardano(&node, 0x80000002); + hdnode_private_ckd_cardano(&node, 0x80000002); + hdnode_private_ckd_cardano(&node, 0xBB9ACA00); + + ck_assert_mem_eq( + node.chain_code, + fromhex( + "ff77c08d37471c1d4cedd3fae2642c009324d9712492efc74dedab09c9bf973c"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "488f34840bba516f7920f91676b8681d0dd833b4ce14468e0810b255f9b6ea46"), + 32); + ck_assert_mem_eq( + node.private_key_extension, + fromhex( + "01eccef768a79859f824a1d3c3e35e131184e2940c3fca9a4c9b307741f65363"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key + 1, + fromhex( + "148605be54585773b44ba87e79265149ae444c4cc37cb1f8db8c08482fba293b"), + 32); +} +END_TEST + +START_TEST(test_bip32_cardano_hdnode_vector_8) { + HDNode node; + + uint8_t mnemonic_bits[66]; + int mnemonic_bits_len = mnemonic_to_bits( + "found differ bulb shadow wrist blue bind vessel deposit tip pelican " + "action surprise weapon check fiction muscle this", + mnemonic_bits); + ck_assert_int_eq(mnemonic_bits_len, 198); + hdnode_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, + mnemonic_bits_len / 8, &node); + + hdnode_private_ckd_cardano(&node, 0x80000000); + hdnode_private_ckd_cardano(&node, 0x80000001); + hdnode_private_ckd_cardano(&node, 0x80000002); + hdnode_private_ckd_cardano(&node, 0x80000002); + hdnode_private_ckd_cardano(&node, 0xBB9ACA00); + + ck_assert_mem_eq( + node.chain_code, + fromhex( + "6fb22a4531ad79e828c4907c5fff3ecf686c16cb195f81243f1f0330173380e4"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "a0baa34e4e24f0500ed6e5e90ab41984b965b7464b0b28640528778dd8a6b854"), + 32); + ck_assert_mem_eq( + node.private_key_extension, + fromhex( + "170e0d3b65ba8d71f27a6db60d0ac26dcb16e52e08cc259db72066f206b258d5"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key + 1, + fromhex( + "3dae0c06d87db618d73ee808425898cdd882f9eb43bf139c6b3a4760551ee89f"), + 32); +} +END_TEST + +START_TEST(test_bip32_cardano_hdnode_vector_9) { + HDNode node; + + uint8_t mnemonic_bits[66]; + int mnemonic_bits_len = mnemonic_to_bits( + "balance exotic ranch knife glory slow tape favorite yard gym awake " + "ill exist useless parent aim pig stay effort into square gasp credit " + "butter", + mnemonic_bits); + ck_assert_int_eq(mnemonic_bits_len, 264); + hdnode_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, + mnemonic_bits_len / 8, &node); + + hdnode_private_ckd_cardano(&node, 0x80000000); + hdnode_private_ckd_cardano(&node, 0x80000001); + hdnode_private_ckd_cardano(&node, 0x80000002); + hdnode_private_ckd_cardano(&node, 0x80000002); + hdnode_private_ckd_cardano(&node, 0xBB9ACA00); + + ck_assert_mem_eq( + node.chain_code, + fromhex( + "9b226add79f90086ea18b260da633089fe121db758aa31284ad1affaf3c9bb68"), + 32); + ck_assert_mem_eq( + node.private_key, + fromhex( + "38eb2a79486e516cb6658700503a3e2c870c03e9d1aec731f780aa6fb7f7de44"), + 32); + ck_assert_mem_eq( + node.private_key_extension, + fromhex( + "80d2c677638e5dbd4395cdec279bf2a42077f2797c9e887949d37cdb317fce6a"), + 32); + hdnode_fill_public_key(&node); + ck_assert_mem_eq( + node.public_key + 1, + fromhex( + "115a365b2aad1d8eba7d379de518f1fa8553855110af24e5695011c32ce9a300"), + 32); +} +END_TEST diff --git a/deps/crypto/trezor-crypto/tests/test_check_cashaddr.h b/deps/crypto/trezor-crypto/tests/test_check_cashaddr.h new file mode 100644 index 000000000..7f2a68c55 --- /dev/null +++ b/deps/crypto/trezor-crypto/tests/test_check_cashaddr.h @@ -0,0 +1,68 @@ +#include "cash_addr.h" + +static const char* valid_cashchecksum[] = { + "prefix:x64nx6hz", + "p:gpf8m4h7", + "bitcoincash:qpzry9x8gf2tvdw0s3jn54khce6mua7lcw20ayyn", + "bchtest:testnetaddress4d6njnut", + "bchreg:555555555555555555555555555555555555555555555udxmlmrz", +}; + +struct valid_cashaddr_data { + const char* legacy; + const char* cashaddress; +}; + +static struct valid_cashaddr_data valid_cashaddr[] = { + {"1BpEi6DfDAUFd7GtittLSdBeYJvcoaVggu", + "bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a"}, + {"1KXrWXciRDZUpQwQmuM1DbwsKDLYAYsVLR", + "bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy"}, + {"16w1D5WRVKJuZUsSRzdLp9w3YGcgoxDXb", + "bitcoincash:qqq3728yw0y47sqn6l2na30mcw6zm78dzqre909m2r"}, + {"3CWFddi6m4ndiGyKqzYvsFYagqDLPVMTzC", + "bitcoincash:ppm2qsznhks23z7629mms6s4cwef74vcwvn0h829pq"}, + {"3LDsS579y7sruadqu11beEJoTjdFiFCdX4", + "bitcoincash:pr95sy3j9xwd2ap32xkykttr4cvcu7as4yc93ky28e"}, + {"31nwvkZwyPdgzjBJZXfDmSWsC4ZLKpYyUw", + "bitcoincash:pqq3728yw0y47sqn6l2na30mcw6zm78dzq5ucqzc37"}}; + +START_TEST(test_cashaddr) { + size_t i; + for (i = 0; i < sizeof(valid_cashchecksum) / sizeof(valid_cashchecksum[0]); + ++i) { + uint8_t data[82]; + char rebuild[92]; + char hrp[84]; + size_t data_len; + int res = cash_decode(hrp, data, &data_len, valid_cashchecksum[i]); + ck_assert_int_eq(res, 1); + res = cash_encode(rebuild, hrp, data, data_len); + ck_assert_int_eq(res, 1); + ck_assert_int_eq(my_strncasecmp(rebuild, valid_cashchecksum[i], 92), 0); + } + for (i = 0; i < sizeof(valid_cashaddr) / sizeof(valid_cashaddr[0]); ++i) { + uint8_t prog[65]; + size_t prog_len; + const char* hrp = "bitcoincash"; + uint8_t rawdata[65]; + size_t rawdata_len; + char rebuild[93]; + int ret = + cash_addr_decode(prog, &prog_len, hrp, valid_cashaddr[i].cashaddress); + ck_assert_int_eq(ret, 1); + ck_assert_uint_eq(prog_len, 21); + rawdata_len = base58_decode_check(valid_cashaddr[i].legacy, HASHER_SHA2D, + rawdata, sizeof(rawdata)); + ck_assert_uint_eq(rawdata_len, 21); + ck_assert_uint_eq(prog[0], rawdata[0] == 0 ? 0x00 + : rawdata[0] == 5 ? 0x08 + : -1); + ck_assert_int_eq(memcmp(rawdata + 1, prog + 1, 20), 0); + ret = cash_addr_encode(rebuild, hrp, prog, 21); + ck_assert_int_eq(ret, 1); + ck_assert_int_eq(my_strncasecmp(rebuild, valid_cashaddr[i].cashaddress, 92), + 0); + } +} +END_TEST diff --git a/deps/crypto/trezor-crypto/tests/test_check_monero.h b/deps/crypto/trezor-crypto/tests/test_check_monero.h new file mode 100644 index 000000000..eb247d939 --- /dev/null +++ b/deps/crypto/trezor-crypto/tests/test_check_monero.h @@ -0,0 +1,1180 @@ +#if USE_MONERO +START_TEST(test_xmr_base58) { + static const struct { + uint64_t tag; + char *v1; + char *v2; + } tests[] = { + {0x12, + "3bec484c5d7f0246af520aab550452b5b6013733feabebd681c4a60d457b7fc12d5918e" + "31d3c003da3c778592c07b398ad6f961a67082a75fd49394d51e69bbe", + "43tpGG9PKbwCpjRvNLn1jwXPpnacw2uVUcszAtgmDiVcZK4VgHwjJT9BJz1WGF9eMxSYASp" + "8yNMkuLjeQfWqJn3CNWdWfzV"}, + {0x12, + "639050436fa36c8288706771412c5972461578d564188cd7fc6f81d6973d064fa461afe" + "66fb23879936d7225051bebbf7f3ae0c801a90bb99fbb346b2fd4d702", + "45PwgoUKaDHNqLL8o3okzLL7biv7GqPVmd8LTcTrYVrMEKdSYwFcyJfMLSRpfU3nh8Z2m81" + "FJD4sUY3nXCdGe61k1HAp8T1"}, + {53, + "5a10cca900ee47a7f412cd661b29f5ab356d6a1951884593bb170b5ec8b6f2e83b1da41" + "1527d062c9fedeb2dad669f2f5585a00a88462b8c95c809a630e5734c", + "9vacMKaj8JJV6MnwDzh2oNVdwTLJfTDyNRiB6NzV9TT7fqvzLivH2dB8Tv7VYR3ncn8vCb3" + "KdNMJzQWrPAF1otYJ9cPKpkr"}, + }; + + uint8_t rawn[512]; + char strn[512]; + int r; + uint64_t tag; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + const char *raw = tests[i].v1; + const char *str = tests[i].v2; + const size_t len = strlen(raw) / 2; + + memcpy(rawn, fromhex(raw), len); + + r = xmr_base58_addr_encode_check(tests[i].tag, rawn, len, strn, + sizeof(strn)); + ck_assert_uint_eq((size_t)r, strlen(str)); + ck_assert_mem_eq(strn, str, r); + + r = xmr_base58_addr_decode_check(strn, r, &tag, rawn, len); + ck_assert_uint_eq((size_t)r, len); + ck_assert_mem_eq(rawn, fromhex(raw), len); + } +} +END_TEST + +START_TEST(test_xmr_getset256_modm) { + static const struct { + uint64_t val; + int r; + char *a; + } tests[] = { + {0x0, 1, + "0000000000000000000000000000000000000000000000000000000000000000"}, + {0x7fffffffULL, 1, + "ffffff7f00000000000000000000000000000000000000000000000000000000"}, + {0x7fffffffffffffffULL, 1, + "ffffffffffffff7f000000000000000000000000000000000000000000000000"}, + {0xdeadc0deULL, 1, + "dec0adde00000000000000000000000000000000000000000000000000000000"}, + {0x0, 0, + "dec0adde000000000000000000000000000000000000000000000000000000ff"}, + {0x0, 0, + "ffffffffffffffffff0000000000000000000000000000000000000000000000"}, + }; + + uint8_t rawn[32]; + uint64_t v1; + bignum256modm a1 = {0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + int get_res = tests[i].r; + if (get_res) { + set256_modm(a1, tests[i].val); + ck_assert_int_eq(get256_modm(&v1, a1), 1); + ck_assert(v1 == tests[i].val); + + contract256_modm(rawn, a1); + ck_assert_mem_eq(rawn, fromhex(tests[i].a), 32); + + } else { + expand256_modm(a1, fromhex(tests[i].a), 32); + ck_assert_int_eq(get256_modm(&v1, a1), 0); + } + } +} +END_TEST + +START_TEST(test_xmr_cmp256_modm) { + static const struct { + char *a; + char *b; + int res_eq; + int res_cmp; + int res_is_zero_a; + } tests[] = { + {"0000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000", 1, 0, + 1}, + {"0000000000000000000000000000000000000000000000000000000000000000", + "0100000000000000000000000000000000000000000000000000000000000000", 0, + -1, 1}, + {"dec0adde00000000000000000000000000000000000000000000000000000000", + "dec0adde00000000000000000000000000000000000000000000000000000000", 1, 0, + 0}, + {"863346d8863c461cde2ec7c2759352c2b952228f33a86ca06bb79574bbe5c30d", + "3ddbd65a6d3ba5e2ab120603685a353a27ce3fd21dfdbea7952d2dd26f1ca00a", 0, 1, + 0}, + {"f7667f392edbea6e224b1aa9fbf2a3b238b4f977fb4a8f39130cc45f49b5c40a", + "b41b9b1e7e80be71cf290ed4bded58924086b8ac6bdfa1faa0c80c255f074d07", 0, 1, + 0}, + {"0e4005c7826de8f9978749903f40efd140e4ae6d3bed09e558fcce8367b27501", + "0e4005c7826de8f9978749903f40efd140e4ae6d3bed09e558fcce8367b27504", 0, + -1, 0}, + {"0e4005c7826de8f9978749903f40efd140e4ae6d3bed09e558fcce8367b27504", + "0e4005c7826de8f9978749903f40efd140e4ae6d3bed09e558fcce8367b27504", 1, 0, + 0}, + {"0e4005c7826de8f9978749903f40efd140e4ae6d3bed09e558fcce8367b27504", + "0e4005c7826de8f9978749903f41efd140e4ae6d3bed09e558fcce8367b27504", 0, + -1, 0}, + }; + + bignum256modm a1 = {0}, a2 = {0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(a1, fromhex(tests[i].a), 32); + expand256_modm(a2, fromhex(tests[i].b), 32); + + ck_assert_int_eq(eq256_modm(a1, a2), tests[i].res_eq); + ck_assert_int_eq(cmp256_modm(a1, a2), tests[i].res_cmp); + ck_assert_int_eq(iszero256_modm(a1), tests[i].res_is_zero_a); + } +} +END_TEST + +START_TEST(test_xmr_copy_check_modm) { + static const struct { + int check; + char *a; + } tests[] = { + {0, "0000000000000000000000000000000000000000000000000000000000000000"}, + {1, "ffffff7f00000000000000000000000000000000000000000000000000000000"}, + {1, "ffffffffffffff7f000000000000000000000000000000000000000000000000"}, + {1, "dec0adde00000000000000000000000000000000000000000000000000000000"}, + {0, "dec0adde000000000000000000000fffffffffffffffffffffffffffffffffff"}, + }; + + bignum256modm a1 = {0}, a2 = {0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand_raw256_modm(a1, fromhex(tests[i].a)); + copy256_modm(a2, a1); + ck_assert_int_eq(eq256_modm(a1, a2), 1); + ck_assert_int_eq(check256_modm(a1), tests[i].check); + } +} +END_TEST + +START_TEST(test_xmr_mulsub256_modm) { + static const struct { + char *a; + char *b; + char *c; + char *r; + } tests[] = { + { + "713c199348cf7d14b67ae6265ea49c02c8647f07afcbcb6f8d3254b3db972e02", + "4e48a7b7a03ab1106fdfa9441a03c97c644395a12ac4b8effac7344e0719c200", + "1a5711b8c43bcab0161a620368d82727e1d027dc248f420d9bb4db2486c16405", + "6edcc08aa6ec3a5b3d333b5f826be7de9c268be8aaf9521586fbcccbed3b1c0c", + }, + { + "d4ade2c62d34af8cfd9daec6f46bf7e57962a8aa46935cb11fab64fa599b4700", + "22ea7989a9f4d34cd8c9442e03b5062dfe8493757cd18a63411cb1a25e44960f", + "772053e613f0859387badcefeb7fbe551a05b00b9337539c8d72661de5929806", + "a5063258df4520b33e97c0a46d80feeace5c251fc7ef7a938d160b8f25795106", + }, + { + "01fd2ef25c8221277a2b6daf1f1642bacb8d6ac0dd4f62731cdd73e26eb77900", + "0611b9357530aa638428002769ce0ad553421e971bea1f10d7009bf26d9af805", + "dfece232068b2f8059ca569f345baaed13ab464eb3bebb99de5625dc90a8cf03", + "85752e62bd8085c7c02d5edeb74969d22f1a5bb34349258d2e96de300176bb07", + }, + }; + + bignum256modm a = {0}, b = {0}, c = {0}, r = {0}, r2 = {0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(a, fromhex(tests[i].a), 32); + expand256_modm(b, fromhex(tests[i].b), 32); + expand256_modm(c, fromhex(tests[i].c), 32); + expand256_modm(r, fromhex(tests[i].r), 32); + mulsub256_modm(r2, a, b, c); + ck_assert_int_eq(eq256_modm(r, r2), 1); + } +} +END_TEST + +START_TEST(test_xmr_muladd256_modm) { + static const struct { + char *a; + char *b; + char *c; + char *r; + } tests[] = { + { + "7c3fd8abfbe2be3739d91679ac8dbda086961b941e0d4a00561f758927d8aa09", + "ac2d8d37e4f344aa4040d0f0fc29d45423ab7e69ecacb94ca9fc36819e0e990e", + "2f03f1bac09bc7d002848b68be069dc98b2db028390ae37e13a5166fcae08105", + "dce113add3392f08e3b38b7d31e237eba5066e5a95a1fdbf755b92d05e1ec70b", + }, + { + "6979b70f6198d043f4b14e2069f7b89cc9f09e3465e71d472946443989e0e80c", + "8dd5177bc8d7c5bd58c0be74b336952a73ac259ebb812ac8cd755773c6aab807", + "d7658e508a7454ccfb29e2890d6156ac10e18ebe6e00cc5a2d2d87a5080c7f06", + "51b33f6263772781cdbab26ef48870eaf94899894a437dac39496f15b9d0ae00", + }, + { + "ebfdb4eabedb1fb9a45b3204735b0511871e20358392fa16a851c519e3a29b09", + "59d98831e9f9e24260158986c4d4035438de9b8876cc11bdcf4c364c75f72908", + "93bce4764eee97dc67f2e37da40bc5641f2cdc637285d273287a3d4383b68f02", + "21547ca6855c85d5adcd673b9d801d0cb0f10dced8f8b68a8c2f74163defde0e", + }, + }; + + bignum256modm a = {0}, b = {0}, c = {0}, r = {0}, r2 = {0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(a, fromhex(tests[i].a), 32); + expand256_modm(b, fromhex(tests[i].b), 32); + expand256_modm(c, fromhex(tests[i].c), 32); + expand256_modm(r, fromhex(tests[i].r), 32); + muladd256_modm(r2, a, b, c); + ck_assert_int_eq(eq256_modm(r, r2), 1); + } +} +END_TEST + +START_TEST(test_xmr_curve25519_set) { + static const struct { + uint32_t val; + char *a; + } tests[] = { + {0x0, "0000000000000000000000000000000000000000000000000000000000000000"}, + {0x1, "0100000000000000000000000000000000000000000000000000000000000000"}, + {0xdeadc0deUL, + "dec0adde00000000000000000000000000000000000000000000000000000000"}, + }; + + unsigned char buff[32]; + bignum25519 a = {0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + curve25519_set(a, tests[i].val); + curve25519_contract(buff, a); + ck_assert_mem_eq(buff, fromhex(tests[i].a), 32); + } +} +END_TEST + +START_TEST(test_xmr_curve25519_consts) { + char *d = "a3785913ca4deb75abd841414d0a700098e879777940c78c73fe6f2bee6c0352"; + char *d2 = "59f1b226949bd6eb56b183829a14e00030d1f3eef2808e19e7fcdf56dcd90624"; + char *sqrtneg1 = + "b0a00e4a271beec478e42fad0618432fa7d7fb3d99004d2b0bdfc14f8024832b"; + + unsigned char buff[32]; + bignum25519 a = {0}; + + curve25519_set_d(a); + curve25519_contract(buff, a); + ck_assert_mem_eq(buff, fromhex(d), 32); + + curve25519_set_2d(a); + curve25519_contract(buff, a); + ck_assert_mem_eq(buff, fromhex(d2), 32); + + curve25519_set_sqrtneg1(a); + curve25519_contract(buff, a); + ck_assert_mem_eq(buff, fromhex(sqrtneg1), 32); +} +END_TEST + +START_TEST(test_xmr_curve25519_tests) { + static const struct { + char *a; + int res_neg; + int res_nonzero; + } tests[] = { + { + "0000000000000000000000000000000000000000000000000000000000000000", + 0, + 0, + }, + { + "0100000000000000000000000000000000000000000000000000000000000000", + 1, + 1, + }, + { + "05737aa6100ee54283dc0d483b8e39e61846f6b3736908243d0c824d250b3139", + 1, + 1, + }, + { + "95587a5ef6900fa8e32d6a41bd8090b1e33e694284323d1d1f02d69865f2bc15", + 1, + 1, + }, + { + "02587a5ef6900fa8e32d6a41bd8090b1e33e694284323d1d1f02d69865f2bc15", + 0, + 1, + }, + }; + + bignum25519 a = {0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + curve25519_expand(a, fromhex(tests[i].a)); + ck_assert_int_eq(curve25519_isnegative(a), tests[i].res_neg); + ck_assert_int_eq(curve25519_isnonzero(a), tests[i].res_nonzero); + } +} +END_TEST + +START_TEST(test_xmr_curve25519_expand_reduce) { + static const struct { + char *a; + char *b; + } tests[] = { + {"dec0adde00000000000000000000000000000000000000000000000000000000", + "dec0adde00000000000000000000000000000000000000000000000000000000"}, + {"95587a5ef6900fa8e32d6a41bd8090b1e33e694284323d1d1f02d69865f2bc15", + "95587a5ef6900fa8e32d6a41bd8090b1e33e694284323d1d1f02d69865f2bc15"}, + {"95587a5ef6900fa8e32d6a41bd8090b1e33e694284323d1d1f02d69865f2bcff", + "a8587a5ef6900fa8e32d6a41bd8090b1e33e694284323d1d1f02d69865f2bc7f"}, + {"95587a5ef6900fa8e32d6affbd8090b1e33e694284323fffff02d69865f2bcff", + "a8587a5ef6900fa8e32d6affbd8090b1e33e694284323fffff02d69865f2bc7f"}, + }; + + unsigned char buff[32]; + bignum25519 a = {0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + curve25519_expand_reduce(a, fromhex(tests[i].a)); + curve25519_contract(buff, a); + ck_assert_mem_eq(buff, fromhex(tests[i].b), 32); + } +} +END_TEST + +START_TEST(test_xmr_ge25519_base) { + unsigned char buff[32]; + char *base = + "5866666666666666666666666666666666666666666666666666666666666666"; + ge25519 b; + ge25519_set_base(&b); + ge25519_pack(buff, &b); + ck_assert_mem_eq(buff, fromhex(base), 32); +} +END_TEST + +START_TEST(test_xmr_ge25519_check) { + static const struct { + char *x; + char *y; + char *z; + char *t; + int r; + } tests[] = { + {"4ff97748221f954414f836d84e8e7e207786bcd20eb67044756dca307e792c60", + "2c7be86ab07488ba43e8e03d85a67625cfbf98c8544de4c877241b7aaafc7f63", + "0100000000000000000000000000000000000000000000000000000000000000", + "3ec65b03954ce7432525b9b3f4a9f5747f57b40903d1bf8892527366325fe036", 1}, + {"358fd25e4b84397d207e23cf3a75819bd6b2254cabc990b31ad63873cc38fc7c", + "ca48045f790145a1eec3946dfd73747fde0fdb4238607e0a203f8ef5bef90e0e", + "0100000000000000000000000000000000000000000000000000000000000000", + "6c5e5cbae4b05e149d0aca50bf7b4112acbbe6233ace9c8bd5bcedf34df9ce0b", 1}, + {"4ff97748221f954414f836d84e8e7e207786bcd20eb6704475ffca307e792c60", + "2c7be86ab07488ba43e8e03d85a67625cfbf98c8544de4c877241b7aaafc7f63", + "0100000000000000000000000000000000000000000000000000000000000000", + "3ec65b03954ce7432525b9b3f4a9f5747f57b40903d1bf8892527366325fe036", 0}, + {"358fd25e4b84397d207e23cf3a75819bd6b2254cabc990b31ad63873cc38fc7c", + "ca48045f790145a1eec3946dfd73747fdfffdb4238607e0a203f8ef5bef90e0e", + "0100000000000000000000000000000000000000000000000000000000000000", + "6c5e5cbae4b05e149d0aca50bf7b4112acbbe6233ace9c8bd5bcedf34df9ce0b", 0}, + {"358fd25e4b84397d207e23cf3a75819bd6b2254cabc990b31ad63873cc38fc7c", + "ca48045f790145a1eec3946dfd73747fdfffdb4238607e0a203f8ef5bef90e0e", + "0100000000000000000000000000000000000000000000000000000000000000", + "6c5e5ffae4b05e149d0aca50bf7b4112acbbe6233ace9c8bd5bcedf34df9ce0b", 0}, + }; + + struct ge25519_t p; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + curve25519_expand_reduce(p.x, fromhex(tests[i].x)); + curve25519_expand_reduce(p.y, fromhex(tests[i].y)); + curve25519_expand_reduce(p.z, fromhex(tests[i].z)); + curve25519_expand_reduce(p.t, fromhex(tests[i].t)); + ck_assert_int_eq(ge25519_check(&p), tests[i].r); + } +} +END_TEST + +START_TEST(test_xmr_ge25519_scalarmult_base_wrapper) { + static const struct { + char *sc; + char *pt; + } tests[] = { + { + "40be740e26bd1c84f5a8fec737c0ed30e87bd45adfcd91e320f8dfb68b1a870e", + "b7a8b2f3dbfd41b38d20aec733a316dbfc2633503799cd36f38570cafc8ea887", + }, + { + "1b3746add992215d427e43a58354c11ff9e6dfa1c187250938f7f9334fa41d05", + "e2a1bfbe38a9749fe6ede79d923b778fa4c89393473d633bec01fa68617d0828", + }, + { + "69af25c54090a9746d3f6043348452429ffd53c1530fa114fd0055b70d61020f", + "6bf1783b0a7495d5f6c36605dca95e723ca120a306c255084787f09b12771124", + }, + { + "0000000000000000000000000000000000000000000000000000000000000000", + "0100000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000000", + "5866666666666666666666666666666666666666666666666666666666666666", + }, + { + "0800000000000000000000000000000000000000000000000000000000000000", + "b4b937fca95b2f1e93e41e62fc3c78818ff38a66096fad6e7973e5c90006d321", + }, + { + "ffffffffffffffff000000000000000000000000000000000000000000000000", + "e185757a3fdc6519a6e7bebd97aa52bdc999e4c87d5c3aad0d995763ab6c6985", + }, + }; + + ge25519 pt, pt2; + bignum256modm sc; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(sc, fromhex(tests[i].sc), 32); + ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); + ge25519_scalarmult_base_wrapper(&pt2, sc); + ck_assert_int_eq(ge25519_eq(&pt, &pt2), 1); + } +} +END_TEST + +START_TEST(test_xmr_ge25519_scalarmult) { + static const struct { + char *sc; + char *pt; + char *pt2; + } tests[] = { + { + "0000000000000000000000000000000000000000000000000000000000000000", + "5cbb3b2784c16f0e7eb4f2a7f93288552bb24ec51c5e01504c1e6885cfbca6d0", + "0100000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000000", + "f39b6770008d069acb92eb95329dec2cb0054da024e437a1bdf1ae06527deff6", + "f39b6770008d069acb92eb95329dec2cb0054da024e437a1bdf1ae06527deff6", + }, + { + "3930000000000000000000000000000000000000000000000000000000000000", + "2835b3983e3cc01a640fd188bf6bbbafbf997a3344d800eed22e4e82a412941c", + "2fe8b2dd0f23e02fca6989e170135584d684583c0a44f6a7d3ebd964685d36c7", + }, + { + "ffffffffffffffff000000000000000000000000000000000000000000000000", + "bb8af7a53a8f1b477c810e833a84cdc789a6b81a6b6417be4f97ffd9ae0fe0b8", + "3a5c9a7dacca9dd8827881f38c36aad7d402a5efc2cab58c7553b903876e1491", + }, + { + "864203a09e1c788a482685c739af07355ebb2c840b7de6af87eff5f19ee3b807", + "d404a9bbf351e7320ea6d11cdeeccaf505f706731cb5e5d839b950edb7ba6286", + "11e09c89e0be7663e0e2d4a01fb05d6a3fd84a78a6fa4fd7daaacf2d19311a38", + }, + { + "3e01f05920a238e33766814d10f0c3a3e975072399ad90a823d4808db1d85209", + "52a2d35798a0ac209b8fa194fe398b869aba5f20d80ee3d8ca77759a8e0bae0d", + "4256addc2f036150f3fdc0a7905f01285239d6dd4eecc4be8e3b134eef4639fe", + }, + { + "ad63d591716a9e89a024a074bc6ce661268d1bb3665f91e8b981f189b1a49507", + "3928bde7a92e1341c3dfee35a66fa5639204f5b9747963278af430145028648d", + "9c959003ba91004956df98800a5024d94031db5ac659675b26350657d93c34f9", + }, + }; + + ge25519 pt, pt2, pt3; + bignum256modm sc; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(sc, fromhex(tests[i].sc), 32); + ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); + ge25519_unpack_vartime(&pt2, fromhex(tests[i].pt2)); + ge25519_scalarmult(&pt3, &pt, sc); + ck_assert_int_eq(ge25519_eq(&pt3, &pt2), 1); + } +} +END_TEST + +START_TEST(test_xmr_ge25519_ops) { + int tests[] = {1, 2, 7, 8, 637, 9912, 12345}; + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + struct ge25519_t a, b, c, d; + bignum256modm s1 = {0}, s2 = {0}, s3 = {0}, s4 = {0}; + + set256_modm(s1, tests[i]); + set256_modm(s2, 8 * tests[i]); + set256_modm(s3, 8); + set256_modm(s4, 2); + + ge25519_scalarmult_base_niels(&a, ge25519_niels_base_multiples, s1); + ge25519_scalarmult_base_niels(&b, ge25519_niels_base_multiples, s2); + ge25519_scalarmult(&c, &a, s4); + ge25519_scalarmult(&c, &c, s4); + ge25519_scalarmult(&c, &c, s4); + ck_assert_int_eq(ge25519_eq(&c, &b), 1); + ck_assert_int_eq(ge25519_eq(&a, &b), 0); + + ge25519_scalarmult_base_wrapper(&a, s1); + ge25519_mul8(&b, &a); + ge25519_scalarmult_base_wrapper(&c, s2); + ck_assert_int_eq(ge25519_eq(&b, &c), 1); + + ge25519_scalarmult(&d, &a, s3); + ck_assert_int_eq(ge25519_eq(&d, &c), 1); + + ge25519_copy(&a, &b); + ge25519_neg_full(&b); + ck_assert_int_eq(ge25519_eq(&b, &c), 0); + + ge25519_add(&c, &a, &b, 0); + set256_modm(s2, 0); + ge25519_scalarmult_base_wrapper(&a, s2); + ck_assert_int_eq(ge25519_eq(&a, &c), 1); + } +} +END_TEST + +START_TEST(test_xmr_check_point) { + static const struct { + char *p; + bool on; + } tests[] = { + {"001000a93e0e6937b4feaf079e418a028ca85459aa39ac3871b94076f88ca608", + true}, + {"54863a0464c008acc99cffb179bc6cf34eb1bbdf6c29f7a070a7c6376ae30ab5", + true}, + {"bebe3c84092c0f7a92704cafb16562cc45c47f45e84baec8d4bba3559d1c1808", + true}, + {"00000000000000c60073ec000000000000ff0000000000000000000000000080", + false}, + {"00000000000000004e0000000000000000000000000000000000000000000000", + false}, + {"0000008b0000000000000000b200000000000000000000000000000000000080", + false}, + {"a0953eebe2f676256c37af4f6f84f32d397aaf3b73606e96c5ddfcecbb1ceec8", + false}, + {"a82cd837efee505ec8425769ea925bee869ec3c78a57708c64c2ef2bd6ad3b88", + false}, + {"031c56cfc99758f6f025630e77c6dea0b853c3ab0bf6cf8c8dab03d1a4618178", + false}, + }; + + ge25519 tmp; + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + int res = ge25519_unpack_negative_vartime(&tmp, fromhex(tests[i].p)); + ck_assert_int_eq(ge25519_check(&tmp), tests[i].on); + ck_assert_int_eq(res, tests[i].on); + } +} +END_TEST + +START_TEST(test_xmr_h) { + char *H = "8b655970153799af2aeadc9ff1add0ea6c7251d54154cfa92c173a0dd39c1f94"; + ge25519 H2, Z; + ge25519_p1p1 P_11; + ge25519_pniels P_ni; + uint8_t buff[32] = {0}; + + ge25519_pack(buff, &xmr_h); + ck_assert_mem_eq(buff, fromhex(H), 32); + + int res = ge25519_unpack_vartime(&H2, buff); + ck_assert_int_eq(res, 1); + ck_assert_int_eq(ge25519_eq(&xmr_h, &xmr_h), 1); + ck_assert_int_eq(ge25519_eq(&H2, &xmr_h), 1); + + res = ge25519_unpack_negative_vartime(&H2, buff); + ck_assert_int_eq(res, 1); + ck_assert_int_eq(ge25519_eq(&H2, &xmr_h), 0); + ge25519_neg_full(&H2); + ck_assert_int_eq(ge25519_eq(&H2, &xmr_h), 1); + + ge25519_full_to_pniels(&P_ni, &xmr_h); + ge25519_pnielsadd_p1p1(&P_11, &H2, &P_ni, 1); + ge25519_p1p1_to_full(&H2, &P_11); + ge25519_set_neutral(&Z); + ck_assert_int_eq(ge25519_eq(&Z, &H2), 1); +} +END_TEST + +START_TEST(test_xmr_fast_hash) { + uint8_t hash[32]; + char tests[][2][65] = { + {"", "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"}, + {"00", + "bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a"}, + {"000102", + "f84a97f1f0a956e738abd85c2e0a5026f8874e3ec09c8f012159dfeeaab2b156"}, + {"000102030405", + "51e8babe8b42352100dffa7f7b3843c95245d3d545c6cbf5052e80258ae80627"}, + {"000102030406", + "74e7a0111ee2390dc68269a549a76dcfb553ca1260035eae982d669ff6494f32"}, + {"000102030407", + "3a81c5d02a87786343f88414aae150a09f6933b1d3bb660d0a9ac54e12e5cd86"}, + {"259ef2aba8feb473cf39058a0fe30b9ff6d245b42b6826687ebd6b63128aff64", + "7fb4d1c8e32f7414fe8c7b2774ec05bff6845e4278565d17f95559513a244da2"}, + {"44caa1c26187afe8dacc5d91cb8a51282334d9308a818fe4d3607275e2a61f05", + "2998fe52f8b9883149babd9c546912c3edfbd3cd98896a0e57b1b5929fa5ff7b"}, + }; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + xmr_fast_hash(hash, fromhex(tests[i][0]), strlen(tests[i][0]) / 2); + ck_assert_mem_eq(hash, fromhex(tests[i][1]), 32); + } +} +END_TEST + +START_TEST(test_xmr_hasher) { + Hasher hasher; + uint8_t hash[32]; + + static const struct { + char *chunk[3]; + char *hash; + } tests[] = { + {{"00", "01", "02"}, + "f84a97f1f0a956e738abd85c2e0a5026f8874e3ec09c8f012159dfeeaab2b156"}, + {{"001122334455667788", "00", ""}, + "72a228ee8d0d01c815f112ce315cfc215a0594abcec24162304ae0ffda139d9e"}, + {{"001000a93e0e6937b4feaf079e418a028ca85459aa39ac3871b94076f88ca608", "", + "00112233445566"}, + "c3deafd96ff10cc190c6024548c344f6401cfe5151ab2fcd40df7cc501147e01"}, + }; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + xmr_hasher_init(&hasher); + for (int j = 0; j < 3; j++) { + xmr_hasher_update(&hasher, fromhex(tests[i].chunk[j]), + strlen(tests[i].chunk[j]) / 2); + } + xmr_hasher_final(&hasher, hash); + ck_assert_mem_eq(hash, fromhex(tests[i].hash), 32); + } +} +END_TEST + +START_TEST(test_xmr_hash_to_scalar) { + bignum256modm a1; + unsigned char out[32]; + char tests[][2][65] = { + {"", "4a078e76cd41a3d3b534b83dc6f2ea2de500b653ca82273b7bfad8045d85a400"}, + {"00", + "5497c9b6a7059553835f85118dc089d66512f7b477d66591ff96a9e064bcc90a"}, + {"000102", + "5727ca206dbafa2e099b022ed528f5bdf7874e3ec09c8f012159dfeeaab2b106"}, + {"000102030405", + "7740cf04577c107153a50b3abe44859f5245d3d545c6cbf5052e80258ae80607"}, + {"000102030406", + "ad6bbffaceb8020543ac82bcadb9d090b553ca1260035eae982d669ff6494f02"}, + {"000102030407", + "d2e116e9576ee5a29011c8fcb41259f99e6933b1d3bb660d0a9ac54e12e5cd06"}, + {"259ef2aba8feb473cf39058a0fe30b9ff6d245b42b6826687ebd6b63128aff64", + "3d6d3727dc50bca39e6ccfc9c12950eef5845e4278565d17f95559513a244d02"}, + {"44caa1c26187afe8dacc5d91cb8a51282334d9308a818fe4d3607275e2a61f05", + "aecc45c83f0408c96c70f8273e94f930edfbd3cd98896a0e57b1b5929fa5ff0b"}, + }; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + xmr_hash_to_scalar(a1, fromhex(tests[i][0]), strlen(tests[i][0]) / 2); + contract256_modm(out, a1); + ck_assert_mem_eq(out, fromhex(tests[i][1]), 32); + } +} +END_TEST + +START_TEST(test_xmr_hash_to_ec) { + ge25519 p1; + unsigned char out[32]; + char tests[][2][65] = { + {"", "d6d7d783ab18e1be65586adb7902a4175b737ef0b902875e1d1d5c5cf0478c0b"}, + {"00", + "8e2fecb36320bc4e192e10ef54afc7c83fbeb0c38b7debd4fea51301f0bd4f3d"}, + {"000102", + "73b233e2e75d81b9657a857e38e7ab2bc3600e5c56622b9fe4b976ff312220fa"}, + {"000102030405", + "bebe3c84092c0f7a92704cafb16562cc45c47f45e84baec8d4bba3559d1c1808"}, + {"000102030406", + "525567a6a40a94f2d916bc1efea234bbd3b9162403ec2faba871a90f8d0d487e"}, + {"000102030407", + "99b1be2a92cbd22b24b48fb7a9daadd4d13a56915c4f6ed696f271ad5bdbc149"}, + {"42f6835bf83114a1f5f6076fe79bdfa0bd67c74b88f127d54572d3910dd09201", + "54863a0464c008acc99cffb179bc6cf34eb1bbdf6c29f7a070a7c6376ae30ab5"}, + {"44caa1c26187afe8dacc5d91cb8a51282334d9308a818fe4d3607275e2a61f05", + "001000a93e0e6937b4feaf079e418a028ca85459aa39ac3871b94076f88ca608"}, + }; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + xmr_hash_to_ec(&p1, fromhex(tests[i][0]), strlen(tests[i][0]) / 2); + ge25519_pack(out, &p1); + ck_assert_mem_eq(out, fromhex(tests[i][1]), 32); + } +} +END_TEST + +START_TEST(test_xmr_derivation_to_scalar) { + static const struct { + char *pt; + uint32_t idx; + char *sc; + } tests[] = { + { + "c655b2d9d2670a1c9f26f7586b6d6b1ec5173b8b33bca64c3d305a42d66738b1", + 0, + "ca7ce31b273dd1ac00dc3553e654fb66036804800e27c826bd2b78649243900b", + }, + { + "2b1dbd7a007dcc4d729fa8359705595599737fcef60afb36b379fe033095dca7", + 1, + "60afd5a63b14845d3b92d16eac386713e4ff617fdc5c1a07c3212098c1f5610c", + }, + { + "a48ed3797225dab4b4316b5e40107b6bd63e5f4dc517ba602774d703576ec771", + 24, + "fe81804091e50a5c2233faa6277360fbe1948ea15dddbae62c1d40bbd1918606", + }, + { + "fa27b5b39741f5341b4e89269e3a05ff7e76ec7739843872468fc4bec8475410", + 65537, + "1ba36841f57aa8b799c4dd02b39d53e5fb7780d3f09f91a57a86dcb418d8d506", + }, + }; + + ge25519 pt; + bignum256modm sc, sc2; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(sc, fromhex(tests[i].sc), 32); + ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); + + xmr_derivation_to_scalar(sc2, &pt, tests[i].idx); + ck_assert_int_eq(eq256_modm(sc, sc2), 1); + + xmr_derivation_to_scalar(sc2, &pt, tests[i].idx + 1); + ck_assert_int_eq(eq256_modm(sc, sc2), 0); + } +} +END_TEST + +START_TEST(test_xmr_generate_key_derivation) { + static const struct { + char *pt; + char *sc; + char *r; + } tests[] = { + { + "38f94f27c8037aff025e365275ed1029fd636dda5f69e5f98fdcf92e0a28f31a", + "8f1c73ee5327a43264a7b60b9e7882312b582f33e89846a8694dbf094bb3a90a", + "1fbfe4dcc8c824c274649545f297fa320cd4c1689b1d0ff4887567c4d4a75649", + }, + { + "26785c3941a32f194228eb659c5ee305e63868896defc50ee6c4e0e92d1e246a", + "dbbffec4686ba8ab25e2f1b04c0e7ae51c5143c91353bfb5998430ebe365a609", + "cca34db8dd682ec164d8973b555253934596b77849ef7709d9321121c25aba02", + }, + { + "43505a8ce7248f70d3aae4f57fb59c254ce2b2a0cc2bcf50f2344e51d59b36b3", + "19a802e35f6ff94efe96ec016effe04e635bbd9c1ce2612d5ba2ee4659456b06", + "fc6c93a93f77ff89c18b9abf95b28ec8591ab97eee8e4afee93aa766a4bd3934", + }, + }; + + ge25519 pt, pt2, pt3; + bignum256modm sc; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(sc, fromhex(tests[i].sc), 32); + ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); + ge25519_unpack_vartime(&pt2, fromhex(tests[i].r)); + xmr_generate_key_derivation(&pt3, &pt, sc); + ck_assert_int_eq(ge25519_eq(&pt3, &pt2), 1); + ck_assert_int_eq(ge25519_eq(&pt3, &pt), 0); + } +} +END_TEST + +START_TEST(test_xmr_derive_private_key) { + static const struct { + char *pt; + uint32_t idx; + char *base; + char *r; + } tests[] = { + { + "0541d8f069e5e80a892e39bbf1944ef578008cf9ecf1d100760a05858c1b709e", + 0, + "76967eeb0a3d181bb0b384be71c680a4287599f27b2ddbd07f8e06ab6f2c880e", + "45728c5cb658e470790f124a01699d2126832b7e5c6b7760b6f11119b96ad603", + }, + { + "fc6e0bd785a84e62c9ac8a97e0e604a79494bc2cf7b3b38ef8af7791c87b5bb8", + 1, + "32fbe149562b7ccb34bc4105b87b2a834024799336c8eea5e94df77f1ae9a807", + "64508e83bbadf63f8ecfae4d9dcdd39a4ba23508a545e1a37026f0fa2539d601", + }, + { + "f6bd7a72dc9444dc7e09a0eb4d312d36fe173693d6405b132a5b090297a04ea9", + 65537, + "333a8fcce6726457e4222a87b9b475c1fcf985f756c2029fcb39184c0a5c4804", + "37c16a22da4c0082ebf4bf807403b169f75142a9bd8560ed45f3f9347218260e", + }, + }; + + ge25519 pt; + bignum256modm base, res, res_exp; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(base, fromhex(tests[i].base), 32); + expand256_modm(res_exp, fromhex(tests[i].r), 32); + ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); + + xmr_derive_private_key(res, &pt, tests[i].idx, base); + ck_assert_int_eq(eq256_modm(res, res_exp), 1); + ck_assert_int_eq(eq256_modm(res, base), 0); + } +} +END_TEST + +START_TEST(test_xmr_derive_public_key) { + static const struct { + char *pt; + uint32_t idx; + char *base; + char *r; + } tests[] = { + { + "653f03e7766d472826aa49793bc0cfde698e6745ae5e4217980ba307739f2ed9", + 0, + "2a393f0858732970ac8dea003b17e1ce9371f0a045bd9b7af0d998262739f4cc", + "f7a3db27c45f265f6a68a30137ca44289a6cf1a6db2cf482c59ebfb0142ad419", + }, + { + "338e93f61e6470a5cc71c07b8caedd1a9a28da037aab65c1ca5538501b012c81", + 1, + "af3a1d39397d778731c4510110fd117dc02f756e390713d58f94a06203ce39eb", + "779e2a043c881f06aba1952741fd753098615c4fafa8f62748467ab9bac43241", + }, + { + "7735e9476440927b89b18d7a1e0645b218a1a6d28c642aebb16c1dba0926d5e4", + 65537, + "62c3eed062bd602f7f2164c69ad0b5a8eb3ea560c930f6b41abfc1c4839ea432", + "6da4ebd29498d16c4e813abb3e328c83f9b01a7ba1da6e818071f8ec563626c8", + }, + }; + + ge25519 pt, base, res, res_exp; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); + ge25519_unpack_vartime(&base, fromhex(tests[i].base)); + ge25519_unpack_vartime(&res_exp, fromhex(tests[i].r)); + + xmr_derive_public_key(&res, &pt, tests[i].idx, &base); + + ck_assert_int_eq(ge25519_eq(&res, &res_exp), 1); + ck_assert_int_eq(ge25519_eq(&res, &base), 0); + } +} +END_TEST + +START_TEST(test_xmr_add_keys2) { + static const struct { + char *a; + char *b; + char *B; + char *r; + } tests[] = { + { + "631238da9578d7cb8db16fc4322671bfcb251cc5228b060664800ec1895be608", + "f9a73fca0be058415a148f9e2871be59e1fc7ae6f6193199125237e0d7c1630f", + "ef5ca4fc90f330e825adcdc953da0b3becd853aa819219842790bb39775f2255", + "06623fd0e7a3d787a4d224f6ca2fdab2dcd9d1221578515974b9c4dee65fdcf5", + }, + { + "dac2e629e5c75c312253b19d1d3a0a423158fdd9cdcf4c7a7bf2717d0b748602", + "0483d98d750d4977b499cefd558a0a61580823a37da2b011501e24718e6c7f0a", + "51fd3cd2f1a603ec7be3b35da9c105d91c4304e6a63facf48d7730712cedc0ee", + "f7a5d645ba01a5b7ccbe9636d14422bb587fc529317b23761f0e39222b783b87", + }, + { + "817c4d2fd3e841d860bdab6b7ccf098f3e637eca468d0a3825c50b71f61d0e0c", + "1f6c4795d7fb0d53b5775874ac4c0963607d2b7bd11a7c5d10735badc4a27207", + "bef0e0ed09d602bbe1dd38358b5f8fca27fcad60a69440f104441c3fc68df9c7", + "bc0fc824d74eca0e10eacd0bc2f3322e0bcb02a44ce53f2f5f1fc472f99be8d2", + }, + }; + + bignum256modm a, b; + ge25519 B, res, res_exp; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(a, fromhex(tests[i].a), 32); + expand256_modm(b, fromhex(tests[i].b), 32); + ge25519_unpack_vartime(&B, fromhex(tests[i].B)); + ge25519_unpack_vartime(&res_exp, fromhex(tests[i].r)); + + xmr_add_keys2(&res, a, b, &B); + ck_assert_int_eq(ge25519_eq(&res, &res_exp), 1); + ck_assert_int_eq(ge25519_eq(&res, &B), 0); + + xmr_add_keys2_vartime(&res, a, b, &B); + ck_assert_int_eq(ge25519_eq(&res, &res_exp), 1); + ck_assert_int_eq(ge25519_eq(&res, &B), 0); + } +} +END_TEST + +START_TEST(test_xmr_add_keys3) { + static const struct { + char *a; + char *A; + char *b; + char *B; + char *r; + } tests[] = { + { + "7048b8c4603ae194c502fa458b0e11a4c7a330852bbef66b7c1d67e9f919f509", + "9167c5b182758699baeb421e7f1200272fc775e4c7c7c183cc47261dccbb569f", + "c2cb2bc0249fc7be8eb9b3bed7d37aa6f2c3f433abb3a4a00b13bed64b61f30b", + "b3ec53b07a1be70ac8d0fa365b86f0d6d4cbf98641e7704b3d684558e2ea59ef", + "4dc016d702d599bde5eaeb2bf0c2d0d3f6b9cede961bc539bcb369c3b3086358", + }, + { + "e9794a6652940474958936f07f3904d514228553247633cfb7ae8ffa9fa0f406", + "0e51cea6df2f6f56a9935689364f0d295a7c89f51d40efb2518c17d1b9db792b", + "c132e7be08afdd93984c52c6e1c596edc6b8fc8f1faed95f55e2f819ee806706", + "1a0e03c6858f6cf1b43f4b8456c03144af553bbbd050e152834fd1615b577cb3", + "088f19c6727f8704373d391a36c230395d386f69edb4151ecf8afcd27793fff5", + }, + { + "88920b0c96b15cc04e879f53a76f85f3c7a2a5f275b2772b5b74ee83372aea00", + "e95731ab61a98fedcded475cf21b4ecf2ef9f1adecefba8fdc476a5bb1cf60f9", + "c86026b66c1045fb69e4f24ff6c15d4fad4d565e646938a2ffb7db37ccb4100d", + "d80cbf2986c12e4c7ebac1e55abbdfc4212c00aec8bc90c965becf863262a074", + "047cebaeb3ec2132e7386ba52531b04070206ba1106565c0fbd7d7280694568a", + }, + }; + + bignum256modm a, b; + ge25519 A, B, res, res_exp; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(a, fromhex(tests[i].a), 32); + expand256_modm(b, fromhex(tests[i].b), 32); + ge25519_unpack_vartime(&A, fromhex(tests[i].A)); + ge25519_unpack_vartime(&B, fromhex(tests[i].B)); + ge25519_unpack_vartime(&res_exp, fromhex(tests[i].r)); + + xmr_add_keys3(&res, a, &A, b, &B); + ck_assert_int_eq(ge25519_eq(&res, &res_exp), 1); + ck_assert_int_eq(ge25519_eq(&res, &B), 0); + + xmr_add_keys3_vartime(&res, a, &A, b, &B); + ck_assert_int_eq(ge25519_eq(&res, &res_exp), 1); + ck_assert_int_eq(ge25519_eq(&res, &B), 0); + } +} +END_TEST + +START_TEST(test_xmr_get_subaddress_secret_key) { + static const struct { + uint32_t major, minor; + char *m; + char *r; + } tests[] = { + { + 0, + 0, + "36fad9f7bff465c15a755f1482fb2ecc3a4e434303df906882234e42b5813207", + "8a510a9fe1824b49abbae05958084f9c9098775f29e15427309177882471cf01", + }, + { + 0, + 1, + "36fad9f7bff465c15a755f1482fb2ecc3a4e434303df906882234e42b5813207", + "2bbc9366c04abb0523e2b2d6e709670ffe6645bacedfee968d9c6bc8eefe9c0f", + }, + { + 100, + 100, + "36fad9f7bff465c15a755f1482fb2ecc3a4e434303df906882234e42b5813207", + "c3837d41fedeaed126cf4fc1a5ea47b8b7f38f6a64aa534e3dd45a3c93f37600", + }, + }; + + bignum256modm m, res, res_exp; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(m, fromhex(tests[i].m), 32); + expand256_modm(res_exp, fromhex(tests[i].r), 32); + xmr_get_subaddress_secret_key(res, tests[i].major, tests[i].minor, m); + + ck_assert_int_eq(eq256_modm(res, res_exp), 1); + ck_assert_int_eq(eq256_modm(res, m), 0); + } +} +END_TEST + +START_TEST(test_xmr_gen_c) { + static const struct { + char *a; + uint64_t amount; + char *r; + } tests[] = { + { + "e3e6558c291bbb98aa691d068b67d59dc520afb23fdd51bf65283626fc2ad903", + 0, + "ef19d73bdf3749240b80ee7695f53ad7c2fc2cf868a93209799f41212d099750", + }, + { + "6788c9579c377f3228680bd0e6d01b1ee0c763b35ed39d36fa2146cc2ee16e0e", + 1, + "4913b9af4f2725d87a4404c22cf366597d1c1e6a1f510ae14081d8b7c5a9de77", + }, + { + "ad9e89d67012935540427c241756d6a9d260c5e134603c41d31e24f8651bef08", + 65537, + "f005721da08f24e68314abed3ddfd94165e4be3813398fb126e3f366820b9c90", + }, + { + "fdbb70ff07be24d98de3bffa0a33756646497224318fb7fe136f0e7789d12607", + 0xffffffffffffffffULL, + "a9c38927f299c5f14c98a1a9c9981e59c606ff597274b9b709e1356f12e1498c", + }, + }; + + bignum256modm a; + ge25519 res, res_exp; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + expand256_modm(a, fromhex(tests[i].a), 32); + ge25519_unpack_vartime(&res_exp, fromhex(tests[i].r)); + xmr_gen_c(&res, a, tests[i].amount); + + ck_assert_int_eq(ge25519_eq(&res, &res_exp), 1); + } +} +END_TEST + +START_TEST(test_xmr_varint) { + static const struct { + uint64_t x; + char *r; + } tests[] = { + { + 0, + "00", + }, + { + 24, + "18", + }, + { + 65535, + "ffff03", + }, + { + 65537, + "818004", + }, + { + 0x7fffffffULL, + "ffffffff07", + }, + { + 0xffffffffULL, + "ffffffff0f", + }, + { + 0xffffffffffffffffULL, + "ffffffffffffffffff01", + }, + { + 0xdeadc0deULL, + "de81b7f50d", + }, + }; + + uint64_t val; + unsigned char buff[64]; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + int s1 = xmr_size_varint(tests[i].x); + int written = 0; + int read = 0; + + ck_assert_uint_eq((size_t)s1, strlen(tests[i].r) / 2); + written = xmr_write_varint(buff, sizeof(buff), tests[i].x); + ck_assert_int_eq(s1, written); + ck_assert_mem_eq(buff, fromhex(tests[i].r), strlen(tests[i].r) / 2); + + read = xmr_read_varint(buff, sizeof(buff), &val); + ck_assert_int_eq(read, written); + ck_assert(tests[i].x == val); + } +} +END_TEST + +START_TEST(test_xmr_gen_range_sig) { + uint64_t tests[] = { + 0, 1, 65535, 65537, 0xffffffffffffffffULL, 0xdeadc0deULL, + }; + + unsigned char buff[32]; + xmr_range_sig_t sig; + ge25519 C, Ctmp, Cb, Ch, P1, P2, LL; + bignum256modm mask, hsh, ee, s, ee_comp; + Hasher hasher; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + xmr_gen_range_sig(&sig, &C, mask, tests[i], NULL); + + ge25519_set_neutral(&Ctmp); + for (int j = 0; j < XMR_ATOMS; j++) { + ge25519_unpack_vartime(&Cb, sig.Ci[j]); + ge25519_add(&Ctmp, &Ctmp, &Cb, 0); + } + + ck_assert_int_eq(ge25519_eq(&C, &Ctmp), 1); + + xmr_hasher_init(&hasher); + ge25519_set_xmr_h(&Ch); + expand256_modm(ee, sig.asig.ee, 32); + + for (int j = 0; j < XMR_ATOMS; j++) { + ge25519_unpack_vartime(&P1, sig.Ci[j]); + ge25519_add(&P2, &P1, &Ch, 1); + expand256_modm(s, sig.asig.s0[j], 32); + + xmr_add_keys2(&LL, s, ee, &P1); + ge25519_pack(buff, &LL); + xmr_hash_to_scalar(hsh, buff, 32); + + expand256_modm(s, sig.asig.s1[j], 32); + xmr_add_keys2(&LL, s, hsh, &P2); + + ge25519_pack(buff, &LL); + xmr_hasher_update(&hasher, buff, 32); + + ge25519_double(&Ch, &Ch); + } + + xmr_hasher_final(&hasher, buff); + expand256_modm(ee_comp, buff, 32); + ck_assert_int_eq(eq256_modm(ee, ee_comp), 1); + } +} +END_TEST +#endif diff --git a/deps/crypto/trezor-crypto/tests/test_check_nano.h b/deps/crypto/trezor-crypto/tests/test_check_nano.h new file mode 100644 index 000000000..7f4a98873 --- /dev/null +++ b/deps/crypto/trezor-crypto/tests/test_check_nano.h @@ -0,0 +1,111 @@ +#if USE_NANO +#include "nano.h" + +START_TEST(test_bip32_nano_vector_1) +{ + const char *mnemonic = "edge defense waste choose enrich upon flee junk siren film clown finish luggage leader kid quick brick print evidence swap drill paddle truly occur"; + const char *password = "some password"; + + uint8_t seed[64]; + mnemonic_to_seed(mnemonic, password, seed, NULL); + + HDNode node; + hdnode_from_seed(seed, sizeof(seed), ED25519_BLAKE2B_NANO_NAME, &node); + hdnode_private_ckd_prime(&node, 44); + hdnode_private_ckd_prime(&node, 165); + hdnode_private_ckd_prime(&node, 0); + hdnode_fill_public_key(&node); + + ck_assert_mem_eq(node.private_key, fromhex("3be4fc2ef3f3b7374e6fc4fb6e7bb153f8a2998b3b3dab50853eabe128024143"), 32); + ck_assert_mem_eq(node.public_key+1, fromhex("5b65b0e8173ee0802c2c3e6c9080d1a16b06de1176c938a924f58670904e82c4"), 32); +} +END_TEST + +START_TEST(test_base32_nano) +{ + const char *in_hex = "0000005114aad86a390897d2a91b33b931b3a59a7df9e63eb3694f9430122f5622ae505c6ff6b58e"; + const char *out = "11111nanode8ngaakzbck8smq6ru9bethqwyehomf79sae1k7xd47dkidjqzffeg"; + + uint8_t in[40]; + memcpy(in, fromhex(in_hex), sizeof(in)); + + char buffer[96]; + + ck_assert(base32_encode(in, sizeof(in), buffer, sizeof(buffer), BASE32_ALPHABET_NANO) != NULL); + ck_assert_str_eq(buffer, out); + + ck_assert(base32_decode(out, strlen(out), (uint8_t *)buffer, sizeof(buffer), BASE32_ALPHABET_NANO) != NULL); + ck_assert_mem_eq(buffer, in, sizeof(in)); +} +END_TEST + +START_TEST(test_nano_get_address) +{ + const char *prefix = "nano_"; + + struct { + const char *pk_hex; + const char *address; + } tests[] = { + /* 1 */ { "5114aad86a390897d2a91b33b931b3a59a7df9e63eb3694f9430122f5622ae50", + "nano_1nanode8ngaakzbck8smq6ru9bethqwyehomf79sae1k7xd47dkidjqzffeg" }, + /* 2 */ { "ea6f44048f04bf1f7083f5ad115a9f4e62ecb61b89a83e8bc68ad1e4d9575469", + "nano_3tmhai4ay37z5xra9xff47fbymm4xku3q4fa9t7wf4pjwmeogo5ba8wyccku" }, + /* 3 */ { "0000000000000000000000000000000000000000000000000000000000000000", + "nano_1111111111111111111111111111111111111111111111111111hifc8npp" }, + /* 4 */ { "e89208dd038fbb269987689621d52292ae9c35941a7484756ecced92a65093ba", + "nano_3t6k35gi95xu6tergt6p69ck76ogmitsa8mnijtpxm9fkcm736xtoncuohr3" }, + }; + + for (int i = 0; i < 4; i++) { + ed25519_public_key public_key; + memcpy(public_key, fromhex(tests[i].pk_hex), sizeof(public_key)); + + char buffer[96]; + size_t count; + count = nano_get_address( + public_key, + prefix, strlen(prefix), + buffer, sizeof(buffer) + ); + ck_assert_int_eq(count, 66); + ck_assert_str_eq(buffer, tests[i].address); + } +} + +END_TEST +START_TEST(test_nano_validate_address) +{ + const char *prefix = "nano_"; + + struct { + const char *address; + const char *pk_hex; + } tests[] = { + /* 1 */ { "nano_1nanode8ngaakzbck8smq6ru9bethqwyehomf79sae1k7xd47dkidjqzffeg", + "5114aad86a390897d2a91b33b931b3a59a7df9e63eb3694f9430122f5622ae50" }, + /* 2 */ { "xrb_1nanode8ngaakzbck8smq6ru9bethqwyehomf79sae1k7xd47dkidjqzffeg", + NULL }, + /* 3 */ { "nano_1nanode7ngaakzbck8smq6ru9bethqwyehomf79sae1k7xd47dkidjqzffeg", + NULL }, + }; + + for (int i = 0; i < 3; i++) { + ed25519_public_key public_key; + bool is_valid; + is_valid = nano_validate_address( + prefix, strlen(prefix), + tests[i].address, strlen(tests[i].address), + &public_key + ); + if (tests[i].pk_hex == NULL) { + ck_assert(is_valid == false); + } else { + ck_assert(is_valid == true); + ck_assert_mem_eq(public_key, fromhex(tests[i].pk_hex), sizeof(public_key)); + } + } +} + +END_TEST +#endif diff --git a/deps/crypto/trezor-crypto/tests/test_check_segwit.h b/deps/crypto/trezor-crypto/tests/test_check_segwit.h new file mode 100644 index 000000000..6cd618092 --- /dev/null +++ b/deps/crypto/trezor-crypto/tests/test_check_segwit.h @@ -0,0 +1,149 @@ +#include "segwit_addr.h" + +static const char* valid_checksum[] = { + "A12UEL5L", + "an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedchar" + "actersbio1tt5tgs", + "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", + "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq" + "qqqqqqqqqqc8247j", + "split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", +}; + +static const char* invalid_checksum[] = { + " 1nwldj5", + "\x7f" + "1axkwrx", + "an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcha" + "ractersbio1569pvx", + "pzry9x0s0muk", + "1pzry9x0s0muk", + "x1b4n0q5v", + "li1dgmt3", + "de1lg7wt\xff", +}; + +struct valid_address_data { + const char* address; + size_t scriptPubKeyLen; + const uint8_t scriptPubKey[42]; +}; + +struct invalid_address_data { + const char* hrp; + int version; + size_t program_length; +}; + +static struct valid_address_data valid_address[] = { + {"BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4", + 22, + {0x00, 0x14, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, + 0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6}}, + {"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7", + 34, + {0x00, 0x20, 0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68, 0x04, 0xbd, + 0x19, 0x20, 0x33, 0x56, 0xda, 0x13, 0x6c, 0x98, 0x56, 0x78, 0xcd, 0x4d, + 0x27, 0xa1, 0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32, 0x62}}, + {"tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy", + 34, + {0x00, 0x20, 0x00, 0x00, 0x00, 0xc4, 0xa5, 0xca, 0xd4, 0x62, 0x21, 0xb2, + 0xa1, 0x87, 0x90, 0x5e, 0x52, 0x66, 0x36, 0x2b, 0x99, 0xd5, 0xe9, 0x1c, + 0x6c, 0xe2, 0x4d, 0x16, 0x5d, 0xab, 0x93, 0xe8, 0x64, 0x33}}}; + +static const char* invalid_address[] = { + "tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty", + "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5", + "BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2", + "bc1rw5uspcuh", + ("bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs" + "90"), + "BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P", + "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7", + "bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du", + "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv", + "bc1gmk9yu", +}; + +static struct invalid_address_data invalid_address_enc[] = { + {"BC", 0, 20}, {"bc", 0, 21}, {"bc", 17, 32}, {"bc", 1, 1}, {"bc", 16, 41}, +}; + +static void segwit_scriptpubkey(uint8_t* scriptpubkey, size_t* scriptpubkeylen, + int witver, const uint8_t* witprog, + size_t witprog_len) { + scriptpubkey[0] = witver ? (0x50 + witver) : 0; + scriptpubkey[1] = witprog_len; + memcpy(scriptpubkey + 2, witprog, witprog_len); + *scriptpubkeylen = witprog_len + 2; +} + +START_TEST(test_segwit) { + size_t i; + for (i = 0; i < sizeof(valid_checksum) / sizeof(valid_checksum[0]); ++i) { + uint8_t data[82]; + char rebuild[92]; + char hrp[84]; + size_t data_len; + int res = bech32_decode(hrp, data, &data_len, valid_checksum[i]); + ck_assert_int_eq(res, 1); + res = bech32_encode(rebuild, hrp, data, data_len, + BECH32_ENCODING_BECH32); + ck_assert_int_eq(res, 1); + ck_assert_int_eq(my_strncasecmp(rebuild, valid_checksum[i], 92), 0); + } + for (i = 0; i < sizeof(invalid_checksum) / sizeof(invalid_checksum[0]); ++i) { + uint8_t data[82]; + char hrp[84]; + size_t data_len; + int res = bech32_decode(hrp, data, &data_len, invalid_checksum[i]); + ck_assert_int_eq(res, 0); + } + for (i = 0; i < sizeof(valid_address) / sizeof(valid_address[0]); ++i) { + uint8_t witprog[40]; + size_t witprog_len; + int witver; + const char* hrp = "bc"; + uint8_t scriptpubkey[42]; + size_t scriptpubkey_len; + char rebuild[93]; + int ret = segwit_addr_decode(&witver, witprog, &witprog_len, hrp, + valid_address[i].address); + if (!ret) { + hrp = "tb"; + ret = segwit_addr_decode(&witver, witprog, &witprog_len, hrp, + valid_address[i].address); + } + ck_assert_int_eq(ret, 1); + segwit_scriptpubkey(scriptpubkey, &scriptpubkey_len, witver, witprog, + witprog_len); + ck_assert_uint_eq(scriptpubkey_len, valid_address[i].scriptPubKeyLen); + ck_assert_int_eq( + memcmp(scriptpubkey, valid_address[i].scriptPubKey, scriptpubkey_len), + 0); + ck_assert_int_eq( + segwit_addr_encode(rebuild, hrp, witver, witprog, witprog_len), 1); + ck_assert_int_eq(my_strncasecmp(valid_address[i].address, rebuild, 93), 0); + } + for (i = 0; i < sizeof(invalid_address) / sizeof(invalid_address[0]); ++i) { + uint8_t witprog[40]; + size_t witprog_len; + int witver; + int ret = segwit_addr_decode(&witver, witprog, &witprog_len, "bc", + invalid_address[i]); + ck_assert_int_eq(ret, 0); + ret = segwit_addr_decode(&witver, witprog, &witprog_len, "tb", + invalid_address[i]); + ck_assert_int_eq(ret, 0); + } + for (i = 0; i < sizeof(invalid_address_enc) / sizeof(invalid_address_enc[0]); + ++i) { + char rebuild[93]; + static const uint8_t program[42] = {0}; + int ret = segwit_addr_encode(rebuild, invalid_address_enc[i].hrp, + invalid_address_enc[i].version, program, + invalid_address_enc[i].program_length); + ck_assert_int_eq(ret, 0); + } +} +END_TEST diff --git a/deps/crypto/trezor-crypto/tests/test_curves.py b/deps/crypto/trezor-crypto/tests/test_curves.py new file mode 100755 index 000000000..6897cea87 --- /dev/null +++ b/deps/crypto/trezor-crypto/tests/test_curves.py @@ -0,0 +1,353 @@ +#!/usr/bin/py.test +import binascii +import ctypes as c +import hashlib +import os +import random + +import curve25519 +import ecdsa +import pytest + + +def bytes2num(s): + res = 0 + for i, b in enumerate(reversed(bytearray(s))): + res += b << (i * 8) + return res + + +curves = {"nist256p1": ecdsa.curves.NIST256p, "secp256k1": ecdsa.curves.SECP256k1} + + +class Point: + def __init__(self, name, x, y): + self.curve = name + self.x = x + self.y = y + + +points = [ + Point( + "secp256k1", + 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798, + 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8, + ), + Point( + "secp256k1", + 0x1, + 0x4218F20AE6C646B363DB68605822FB14264CA8D2587FDD6FBC750D587E76A7EE, + ), + Point( + "secp256k1", + 0x2, + 0x66FBE727B2BA09E09F5A98D70A5EFCE8424C5FA425BBDA1C511F860657B8535E, + ), + Point( + "secp256k1", + 0x1B, + 0x1ADCEA1CF831B0AD1653E769D1A229091D0CC68D4B0328691B9CAACC76E37C90, + ), + Point( + "nist256p1", + 0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296, + 0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5, + ), + Point( + "nist256p1", + 0x0, + 0x66485C780E2F83D72433BD5D84A06BB6541C2AF31DAE871728BF856A174F93F4, + ), + Point( + "nist256p1", + 0x0, + 0x99B7A386F1D07C29DBCC42A27B5F9449ABE3D50DE25178E8D7407A95E8B06C0B, + ), + Point( + "nist256p1", + 0xAF8BBDFE8CDD5577ACBF345B543D28CF402F4E94D3865B97EA0787F2D3AA5D22, + 0x35802B8B376B995265918B078BC109C21A535176585C40F519ACA52D6AFC147C, + ), + Point( + "nist256p1", + 0x80000, + 0x580610071F440F0DCC14A22E2D5D5AFC1224C0CD11A3B4B51B8ECD2224EE1CE2, + ), +] + +random_iters = int(os.environ.get("ITERS", 1)) + +DIR = os.path.abspath(os.path.dirname(__file__)) +lib = c.cdll.LoadLibrary(os.path.join(DIR, "libtrezor-crypto.so")) + +BIGNUM = c.c_uint32 * 9 + + +class curve_info(c.Structure): + _fields_ = [("bip32_name", c.c_char_p), ("params", c.c_void_p)] + + +class curve_point(c.Structure): + _fields_ = [("x", BIGNUM), ("y", BIGNUM)] + + +class ecdsa_curve(c.Structure): + _fields_ = [ + ("prime", BIGNUM), + ("G", curve_point), + ("order", BIGNUM), + ("order_half", BIGNUM), + ("a", c.c_int), + ("b", BIGNUM), + ] + + +lib.get_curve_by_name.restype = c.POINTER(curve_info) + + +class Random(random.Random): + def randbytes(self, n): + buf = (c.c_uint8 * n)() + for i in range(n): + buf[i] = self.randrange(0, 256) + return buf + + def randpoint(self, curve): + k = self.randrange(0, curve.order) + return k * curve.generator + + +def int2bn(x, bn_type=BIGNUM): + b = bn_type() + b._int = x + for i in range(len(b)): + b[i] = x % (1 << 29) + x = x >> 29 + return b + + +def bn2int(b): + x = 0 + for i in range(len(b)): + x += b[i] << (29 * i) + return x + + +@pytest.fixture(params=range(random_iters)) +def r(request): + seed = request.param + return Random(seed + int(os.environ.get("SEED", 0))) + + +@pytest.fixture(params=list(sorted(curves))) +def curve(request): + name = request.param + curve_ptr = lib.get_curve_by_name(bytes(name, "ascii")).contents.params + assert curve_ptr, "curve {} not found".format(name) + curve_obj = curves[name] + curve_obj.ptr = c.cast(curve_ptr, c.POINTER(ecdsa_curve)) + curve_obj.p = curve_obj.curve.p() # shorthand + return curve_obj + + +@pytest.fixture(params=points) +def point(request): + name = request.param.curve + curve_ptr = lib.get_curve_by_name(bytes(name, "ascii")).contents.params + assert curve_ptr, "curve {} not found".format(name) + curve_obj = curves[name] + curve_obj.ptr = c.c_void_p(curve_ptr) + curve_obj.p = ecdsa.ellipticcurve.Point( + curve_obj.curve, request.param.x, request.param.y + ) + return curve_obj + + +POINT = BIGNUM * 2 + + +def to_POINT(p): + return POINT(int2bn(p.x()), int2bn(p.y())) + + +def from_POINT(p): + return (bn2int(p[0]), bn2int(p[1])) + + +JACOBIAN = BIGNUM * 3 + + +def to_JACOBIAN(jp): + return JACOBIAN(int2bn(jp[0]), int2bn(jp[1]), int2bn(jp[2])) + + +def from_JACOBIAN(p): + return (bn2int(p[0]), bn2int(p[1]), bn2int(p[2])) + + +def test_curve_parameters(curve): + assert curve.curve.p() == bn2int(curve.ptr.contents.prime) + assert curve.generator.x() == bn2int(curve.ptr.contents.G.x) + assert curve.generator.y() == bn2int(curve.ptr.contents.G.y) + assert curve.order == bn2int(curve.ptr.contents.order) + assert curve.order // 2 == bn2int(curve.ptr.contents.order_half) + assert curve.curve.a() == curve.ptr.contents.a + assert curve.curve.b() == bn2int(curve.ptr.contents.b) + + +def test_point_multiply(curve, r): + p = r.randpoint(curve) + k = r.randrange(0, 2 ** 256) + kp = k * p + res = POINT(int2bn(0), int2bn(0)) + lib.point_multiply(curve.ptr, int2bn(k), to_POINT(p), res) + res = from_POINT(res) + assert res == (kp.x(), kp.y()) + + +def test_point_add(curve, r): + p1 = r.randpoint(curve) + p2 = r.randpoint(curve) + # print '-' * 80 + q = p1 + p2 + q1 = to_POINT(p1) + q2 = to_POINT(p2) + lib.point_add(curve.ptr, q1, q2) + q_ = from_POINT(q2) + assert q_ == (q.x(), q.y()) + + +def test_point_double(curve, r): + p = r.randpoint(curve) + q = p.double() + q_ = to_POINT(p) + lib.point_double(curve.ptr, q_) + q_ = from_POINT(q_) + assert q_ == (q.x(), q.y()) + + +def test_point_to_jacobian(curve, r): + p = r.randpoint(curve) + jp = JACOBIAN() + lib.curve_to_jacobian(to_POINT(p), jp, int2bn(curve.p)) + jx, jy, jz = from_JACOBIAN(jp) + assert jx % curve.p == (p.x() * jz ** 2) % curve.p + assert jy % curve.p == (p.y() * jz ** 3) % curve.p + + q = POINT() + lib.jacobian_to_curve(jp, q, int2bn(curve.p)) + q = from_POINT(q) + assert q == (p.x(), p.y()) + + +def test_jacobian_add(curve, r): + p1 = r.randpoint(curve) + p2 = r.randpoint(curve) + prime = int2bn(curve.p) + q = POINT() + jp2 = JACOBIAN() + lib.curve_to_jacobian(to_POINT(p2), jp2, prime) + lib.point_jacobian_add(to_POINT(p1), jp2, curve.ptr) + lib.jacobian_to_curve(jp2, q, prime) + q = from_POINT(q) + p_ = p1 + p2 + assert (p_.x(), p_.y()) == q + + +def test_jacobian_add_double(curve, r): + p1 = r.randpoint(curve) + p2 = p1 + prime = int2bn(curve.p) + q = POINT() + jp2 = JACOBIAN() + lib.curve_to_jacobian(to_POINT(p2), jp2, prime) + lib.point_jacobian_add(to_POINT(p1), jp2, curve.ptr) + lib.jacobian_to_curve(jp2, q, prime) + q = from_POINT(q) + p_ = p1 + p2 + assert (p_.x(), p_.y()) == q + + +def test_jacobian_double(curve, r): + p = r.randpoint(curve) + p2 = p.double() + prime = int2bn(curve.p) + q = POINT() + jp = JACOBIAN() + lib.curve_to_jacobian(to_POINT(p), jp, prime) + lib.point_jacobian_double(jp, curve.ptr) + lib.jacobian_to_curve(jp, q, prime) + q = from_POINT(q) + assert (p2.x(), p2.y()) == q + + +def sigdecode(sig, _): + return map(bytes2num, [sig[:32], sig[32:]]) + + +def test_sign(curve, r): + priv = r.randbytes(32) + digest = r.randbytes(32) + sig = r.randbytes(64) + + lib.ecdsa_sign_digest(curve.ptr, priv, digest, sig, c.c_void_p(0), c.c_void_p(0)) + + exp = bytes2num(priv) + sk = ecdsa.SigningKey.from_secret_exponent(exp, curve, hashfunc=hashlib.sha256) + vk = sk.get_verifying_key() + + sig_ref = sk.sign_digest_deterministic( + digest, hashfunc=hashlib.sha256, sigencode=ecdsa.util.sigencode_string_canonize + ) + assert binascii.hexlify(sig) == binascii.hexlify(sig_ref) + + assert vk.verify_digest(sig, digest, sigdecode) + + +def test_validate_pubkey(curve, r): + p = r.randpoint(curve) + assert lib.ecdsa_validate_pubkey(curve.ptr, to_POINT(p)) + + +def test_validate_pubkey_direct(point): + assert lib.ecdsa_validate_pubkey(point.ptr, to_POINT(point.p)) + + +def test_curve25519(r): + sec1 = bytes(bytearray(r.randbytes(32))) + sec2 = bytes(bytearray(r.randbytes(32))) + pub1 = curve25519.Private(sec1).get_public() + pub2 = curve25519.Private(sec2).get_public() + + session1 = r.randbytes(32) + lib.curve25519_scalarmult(session1, sec2, pub1.public) + session2 = r.randbytes(32) + lib.curve25519_scalarmult(session2, sec1, pub2.public) + assert bytearray(session1) == bytearray(session2) + + shared1 = curve25519.Private(sec2).get_shared_key(pub1, hashfunc=lambda x: x) + shared2 = curve25519.Private(sec1).get_shared_key(pub2, hashfunc=lambda x: x) + assert shared1 == shared2 + assert bytearray(session1) == shared1 + assert bytearray(session2) == shared2 + + +def test_curve25519_pubkey(r): + sec = bytes(bytearray(r.randbytes(32))) + pub = curve25519.Private(sec).get_public() + res = r.randbytes(32) + lib.curve25519_scalarmult_basepoint(res, sec) + assert bytearray(res) == pub.public + + +def test_curve25519_scalarmult_from_gpg(r): + sec = binascii.unhexlify( + "4a1e76f133afb29dbc7860bcbc16d0e829009cc15c2f81ed26de1179b1d9c938" + ) + pub = binascii.unhexlify( + "5d6fc75c016e85b17f54e0128a216d5f9229f25bac1ec85cecab8daf48621b31" + ) + res = r.randbytes(32) + lib.curve25519_scalarmult(res, sec[::-1], pub[::-1]) + expected = "a93dbdb23e5c99da743e203bd391af79f2b83fb8d0fd6ec813371c71f08f2d4d" + assert binascii.hexlify(bytearray(res)) == bytes(expected, "ascii") diff --git a/deps/crypto/trezor-crypto/tests/test_openssl.c b/deps/crypto/trezor-crypto/tests/test_openssl.c new file mode 100644 index 000000000..c6ce47894 --- /dev/null +++ b/deps/crypto/trezor-crypto/tests/test_openssl.c @@ -0,0 +1,143 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/* OpenSSL's SHA256_CTX/SHA512_CTX conflicts with our own */ +#define SHA256_CTX _openssl_SHA256_CTX +#define SHA512_CTX _openssl_SHA512_CTX +#include +#include +#include +#include +#include +#undef SHA256_CTX +#undef SHA512_CTX + +#include +#include +#include + +#include "ecdsa.h" +#include "hasher.h" +#include "rand.h" + +#include "nist256p1.h" +#include "secp256k1.h" + +#include "memzero.h" + +void openssl_check(unsigned int iterations, int nid, const ecdsa_curve *curve) { + uint8_t sig[64], pub_key33[33], pub_key65[65], priv_key[32], msg[256], + hash[32]; + struct SHA256state_st sha256; + EC_GROUP *ecgroup; + + ecgroup = EC_GROUP_new_by_curve_name(nid); + + for (unsigned int iter = 0; iter < iterations; iter++) { + // random message len between 1 and 256 + int msg_len = (random32() & 0xFF) + 1; + // create random message + random_buffer(msg, msg_len); + + // new ECDSA key + EC_KEY *eckey = EC_KEY_new(); + EC_KEY_set_group(eckey, ecgroup); + + // generate the key + EC_KEY_generate_key(eckey); + // copy key to buffer + const BIGNUM *K = EC_KEY_get0_private_key(eckey); + int bn_off = sizeof(priv_key) - BN_num_bytes(K); + memzero(priv_key, bn_off); + BN_bn2bin(K, priv_key + bn_off); + + // use our ECDSA signer to sign the message with the key + if (ecdsa_sign(curve, HASHER_SHA2, priv_key, msg, msg_len, sig, NULL, + NULL) != 0) { + printf("trezor-crypto signing failed\n"); + return; + } + + // generate public key from private key + ecdsa_get_public_key33(curve, priv_key, pub_key33); + ecdsa_get_public_key65(curve, priv_key, pub_key65); + + // use our ECDSA verifier to verify the message signature + if (ecdsa_verify(curve, HASHER_SHA2, pub_key65, sig, msg, msg_len) != 0) { + printf("trezor-crypto verification failed (pub_key_len = 65)\n"); + return; + } + if (ecdsa_verify(curve, HASHER_SHA2, pub_key33, sig, msg, msg_len) != 0) { + printf("trezor-crypto verification failed (pub_key_len = 33)\n"); + return; + } + + // copy signature to the OpenSSL struct + ECDSA_SIG *signature = ECDSA_SIG_new(); +#if OPENSSL_VERSION_NUMBER < 0x10100000L + BN_bin2bn(sig, 32, signature->r); + BN_bin2bn(sig + 32, 32, signature->s); +#else + BIGNUM *R = BN_bin2bn(sig, 32, NULL); + BIGNUM *S = BN_bin2bn(sig + 32, 32, NULL); + ECDSA_SIG_set0(signature, R, S); +#endif + + // compute the digest of the message + // note: these are OpenSSL functions, not our own + SHA256_Init(&sha256); + SHA256_Update(&sha256, msg, msg_len); + SHA256_Final(hash, &sha256); + + // verify all went well, i.e. we can decrypt our signature with OpenSSL + int v = ECDSA_do_verify(hash, 32, signature, eckey); + if (v != 1) { + printf("OpenSSL verification failed (%d)\n", v); + return; + } + + ECDSA_SIG_free(signature); + EC_KEY_free(eckey); + if (((iter + 1) % 100) == 0) printf("Passed ... %d\n", iter + 1); + } + EC_GROUP_free(ecgroup); + printf("All OK\n"); +} + +int main(int argc, char *argv[]) { + if (argc != 2) { + printf("Usage: test_openssl iterations\n"); + return 1; + } + + unsigned int iterations; + sscanf(argv[1], "%u", &iterations); + + printf("Testing secp256k1:\n"); + openssl_check(iterations, NID_secp256k1, &secp256k1); + + printf("Testing nist256p1:\n"); + openssl_check(iterations, NID_X9_62_prime256v1, &nist256p1); + + return 0; +} diff --git a/deps/crypto/trezor-crypto/tests/test_speed.c b/deps/crypto/trezor-crypto/tests/test_speed.c new file mode 100644 index 000000000..4d29e0c46 --- /dev/null +++ b/deps/crypto/trezor-crypto/tests/test_speed.c @@ -0,0 +1,233 @@ +#include +#include +#include +#include +#include +#include "bip32.h" +#include "curves.h" +#include "ecdsa.h" +#include "ed25519-donna/ed25519.h" +#include "hasher.h" +#include "nist256p1.h" +#include "secp256k1.h" + +static uint8_t msg[256]; + +void prepare_msg(void) { + for (size_t i = 0; i < sizeof(msg); i++) { + msg[i] = i * 1103515245; + } +} + +void bench_sign_secp256k1(int iterations) { + uint8_t sig[64], priv[32], pby; + + const ecdsa_curve *curve = &secp256k1; + + memcpy(priv, + "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3" + "\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", + 32); + + for (int i = 0; i < iterations; i++) { + ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL); + } +} + +void bench_sign_nist256p1(int iterations) { + uint8_t sig[64], priv[32], pby; + + const ecdsa_curve *curve = &nist256p1; + + memcpy(priv, + "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3" + "\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", + 32); + + for (int i = 0; i < iterations; i++) { + ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL); + } +} + +void bench_sign_ed25519(int iterations) { + ed25519_public_key pk; + ed25519_secret_key sk; + ed25519_signature sig; + + memcpy(pk, + "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3" + "\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", + 32); + ed25519_publickey(sk, pk); + + for (int i = 0; i < iterations; i++) { + ed25519_sign(msg, sizeof(msg), sk, sig); + } +} + +void bench_verify_secp256k1_33(int iterations) { + uint8_t sig[64], pub[33], priv[32], pby; + + const ecdsa_curve *curve = &secp256k1; + + memcpy(priv, + "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3" + "\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", + 32); + ecdsa_get_public_key33(curve, priv, pub); + ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL); + + for (int i = 0; i < iterations; i++) { + ecdsa_verify(curve, HASHER_SHA2, pub, sig, msg, sizeof(msg)); + } +} + +void bench_verify_secp256k1_65(int iterations) { + uint8_t sig[64], pub[65], priv[32], pby; + + const ecdsa_curve *curve = &secp256k1; + + memcpy(priv, + "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3" + "\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", + 32); + ecdsa_get_public_key65(curve, priv, pub); + ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL); + + for (int i = 0; i < iterations; i++) { + ecdsa_verify(curve, HASHER_SHA2, pub, sig, msg, sizeof(msg)); + } +} + +void bench_verify_nist256p1_33(int iterations) { + uint8_t sig[64], pub[33], priv[32], pby; + + const ecdsa_curve *curve = &nist256p1; + + memcpy(priv, + "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3" + "\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", + 32); + ecdsa_get_public_key33(curve, priv, pub); + ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL); + + for (int i = 0; i < iterations; i++) { + ecdsa_verify(curve, HASHER_SHA2, pub, sig, msg, sizeof(msg)); + } +} + +void bench_verify_nist256p1_65(int iterations) { + uint8_t sig[64], pub[65], priv[32], pby; + + const ecdsa_curve *curve = &nist256p1; + + memcpy(priv, + "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3" + "\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", + 32); + ecdsa_get_public_key65(curve, priv, pub); + ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL); + + for (int i = 0; i < iterations; i++) { + ecdsa_verify(curve, HASHER_SHA2, pub, sig, msg, sizeof(msg)); + } +} + +void bench_verify_ed25519(int iterations) { + ed25519_public_key pk; + ed25519_secret_key sk; + ed25519_signature sig; + + memcpy(pk, + "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3" + "\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", + 32); + ed25519_publickey(sk, pk); + ed25519_sign(msg, sizeof(msg), sk, sig); + + for (int i = 0; i < iterations; i++) { + ed25519_sign_open(msg, sizeof(msg), pk, sig); + } +} + +void bench_multiply_curve25519(int iterations) { + uint8_t result[32]; + uint8_t secret[32]; + uint8_t basepoint[32]; + + memcpy(secret, + "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3" + "\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", + 32); + memcpy(basepoint, + "\x96\x47\xda\xbe\x1e\xea\xaf\x25\x47\x1e\x68\x0b\x4d\x7c\x6f\xd1\x14" + "\x38\x76\xbb\x77\x59\xd8\x3d\x0f\xf7\xa2\x49\x08\xfd\xda\xbc", + 32); + + for (int i = 0; i < iterations; i++) { + curve25519_scalarmult(result, secret, basepoint); + } +} + +static HDNode root; + +void prepare_node(void) { + hdnode_from_seed((uint8_t *)"NothingToSeeHere", 16, SECP256K1_NAME, &root); + hdnode_fill_public_key(&root); +} + +void bench_ckd_normal(int iterations) { + char addr[MAX_ADDR_SIZE]; + HDNode node; + for (int i = 0; i < iterations; i++) { + memcpy(&node, &root, sizeof(HDNode)); + hdnode_public_ckd(&node, i); + hdnode_fill_public_key(&node); + ecdsa_get_address(node.public_key, HASHER_SHA2, HASHER_SHA2D, 0, addr, + sizeof(addr)); + } +} + +void bench_ckd_optimized(int iterations) { + char addr[MAX_ADDR_SIZE]; + curve_point pub; + ecdsa_read_pubkey(&secp256k1, root.public_key, &pub); + for (int i = 0; i < iterations; i++) { + hdnode_public_ckd_address_optimized(&pub, root.chain_code, i, 0, + HASHER_SHA2, HASHER_SHA2D, addr, + sizeof(addr), false); + } +} + +void bench(void (*func)(int), const char *name, int iterations) { + clock_t t = clock(); + func(iterations); + float speed = iterations / ((float)(clock() - t) / CLOCKS_PER_SEC); + printf("%25s: %8.2f ops/s\n", name, speed); +} + +#define BENCH(FUNC, ITER) bench(FUNC, #FUNC, ITER) + +int main(void) { + prepare_msg(); + + BENCH(bench_sign_secp256k1, 500); + BENCH(bench_verify_secp256k1_33, 500); + BENCH(bench_verify_secp256k1_65, 500); + + BENCH(bench_sign_nist256p1, 500); + BENCH(bench_verify_nist256p1_33, 500); + BENCH(bench_verify_nist256p1_65, 500); + + BENCH(bench_sign_ed25519, 4000); + BENCH(bench_verify_ed25519, 4000); + + BENCH(bench_multiply_curve25519, 4000); + + prepare_node(); + + BENCH(bench_ckd_normal, 1000); + BENCH(bench_ckd_optimized, 1000); + + return 0; +} diff --git a/deps/crypto/trezor-crypto/tests/test_wycheproof.py b/deps/crypto/trezor-crypto/tests/test_wycheproof.py new file mode 100755 index 000000000..c449b29c8 --- /dev/null +++ b/deps/crypto/trezor-crypto/tests/test_wycheproof.py @@ -0,0 +1,721 @@ +#!/usr/bin/env python +import ctypes +import json +import os +from binascii import hexlify, unhexlify + +import pytest +from pyasn1.codec.ber.decoder import decode as ber_decode +from pyasn1.codec.der.decoder import decode as der_decode +from pyasn1.codec.der.encoder import encode as der_encode +from pyasn1.type import namedtype, univ + + +class EcSignature(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType("r", univ.Integer()), + namedtype.NamedType("s", univ.Integer()), + ) + + +class EcKeyInfo(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType("key_type", univ.ObjectIdentifier()), + namedtype.NamedType("curve_name", univ.ObjectIdentifier()), + ) + + +class EcPublicKey(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType("key_info", EcKeyInfo()), + namedtype.NamedType("public_key", univ.BitString()), + ) + + +class EdKeyInfo(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType("key_type", univ.ObjectIdentifier()) + ) + + +class EdPublicKey(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType("key_info", EdKeyInfo()), + namedtype.NamedType("public_key", univ.BitString()), + ) + + +class ParseError(Exception): + pass + + +class NotSupported(Exception): + pass + + +class DataError(Exception): + pass + + +class curve_info(ctypes.Structure): + _fields_ = [("bip32_name", ctypes.c_char_p), ("params", ctypes.c_void_p)] + + +def keys_in_dict(dictionary, keys): + return keys <= set(dictionary.keys()) + + +def parse_eddsa_signature(signature): + if len(signature) != 64: + raise ParseError("Not a valid EdDSA signature") + return signature + + +def parse_ecdh256_privkey(private_key): + if private_key < 0 or private_key.bit_length() > 256: + raise ParseError("Not a valid 256 bit ECDH private key") + return private_key.to_bytes(32, byteorder="big") + + +def parse_signed_hex(string): + if len(string) % 2 == 1: + string = "0" + string + number = int(string, 16) + if int(string[0], 16) & 8: + return -number + else: + return number + + +def parse_result(result): + if result == "valid": + return True + elif result == "invalid": + return False + elif result == "acceptable": + return None + else: + raise DataError() + + +def is_valid_der(data): + try: + structure, _ = der_decode(data) + return data == der_encode(structure) + except Exception: + return False + + +def parse_ed_pubkey(public_key): + try: + public_key, _ = ber_decode(public_key, asn1Spec=EdPublicKey()) + except Exception: + raise ParseError("Not a BER encoded Edwards curve public key") + + if not public_key["key_info"]["key_type"] == univ.ObjectIdentifier("1.3.101.112"): + raise ParseError("Not a BER encoded Edwards curve public key") + + public_key = bytes(public_key["public_key"].asOctets()) + + return public_key + + +def parse_ec_pubkey(public_key): + try: + public_key, _ = ber_decode(public_key, asn1Spec=EcPublicKey()) + except Exception: + raise ParseError("Not a BER encoded named elliptic curve public key") + + if not public_key["key_info"]["key_type"] == univ.ObjectIdentifier( + "1.2.840.10045.2.1" + ): + raise ParseError("Not a BER encoded named elliptic curve public key") + curve_identifier = public_key["key_info"]["curve_name"] + curve_name = get_curve_name_by_identifier(curve_identifier) + + if curve_name is None: + raise NotSupported( + "Unsupported named elliptic curve: {}".format(curve_identifier) + ) + + try: + public_key = bytes(public_key["public_key"].asOctets()) + except Exception: + raise ParseError("Not a BER encoded named elliptic curve public key") + + return curve_name, public_key + + +def parse_ecdsa256_signature(signature): + s = signature + if not is_valid_der(signature): + raise ParseError("Not a valid DER") + try: + signature, _ = der_decode(signature, asn1Spec=EcSignature()) + except Exception: + raise ParseError("Not a valid DER encoded ECDSA signature") + try: + r = int(signature["r"]).to_bytes(32, byteorder="big") + s = int(signature["s"]).to_bytes(32, byteorder="big") + signature = r + s + except Exception: + raise ParseError("Not a valid DER encoded 256 bit ECDSA signature") + return signature + + +def parse_digest(name): + if name == "SHA-256": + return 0 + else: + raise NotSupported("Unsupported hash function: {}".format(name)) + + +def get_curve_by_name(name): + lib.get_curve_by_name.restype = ctypes.c_void_p + curve = lib.get_curve_by_name(bytes(name, "ascii")) + if curve is None: + return None + curve = ctypes.cast(curve, ctypes.POINTER(curve_info)) + return ctypes.c_void_p(curve.contents.params) + + +def parse_curve_name(name): + if name == "secp256r1": + return "nist256p1" + elif name == "secp256k1": + return "secp256k1" + elif name == "curve25519": + return "curve25519" + else: + return None + + +def get_curve_name_by_identifier(identifier): + if identifier == univ.ObjectIdentifier("1.3.132.0.10"): + return "secp256k1" + elif identifier == univ.ObjectIdentifier("1.2.840.10045.3.1.7"): + return "nist256p1" + else: + return None + + +def chacha_poly_encrypt(key, iv, associated_data, plaintext): + context = bytes(context_structure_length) + tag = bytes(16) + ciphertext = bytes(len(plaintext)) + lib.rfc7539_init(context, key, iv) + lib.rfc7539_auth(context, associated_data, len(associated_data)) + lib.chacha20poly1305_encrypt(context, plaintext, ciphertext, len(plaintext)) + lib.rfc7539_finish(context, len(associated_data), len(plaintext), tag) + return ciphertext, tag + + +def chacha_poly_decrypt(key, iv, associated_data, ciphertext, tag): + context = bytes(context_structure_length) + computed_tag = bytes(16) + plaintext = bytes(len(ciphertext)) + lib.rfc7539_init(context, key, iv) + lib.rfc7539_auth(context, associated_data, len(associated_data)) + lib.chacha20poly1305_decrypt(context, ciphertext, plaintext, len(ciphertext)) + lib.rfc7539_finish(context, len(associated_data), len(ciphertext), computed_tag) + return plaintext if tag == computed_tag else False + + +def add_pkcs_padding(data): + padding_length = 16 - len(data) % 16 + return data + bytes([padding_length] * padding_length) + + +def remove_pkcs_padding(data): + padding_length = data[-1] + if not ( + 0 < padding_length <= 16 + and data[-padding_length:] == bytes([padding_length] * padding_length) + ): + return False + else: + return data[:-padding_length] + + +def aes_encrypt_initialise(key, context): + if len(key) == (128 / 8): + lib.aes_encrypt_key128(key, context) + elif len(key) == (192 / 8): + lib.aes_encrypt_key192(key, context) + elif len(key) == (256 / 8): + lib.aes_encrypt_key256(key, context) + else: + raise NotSupported("Unsupported key length: {}".format(len(key) * 8)) + + +def aes_cbc_encrypt(key, iv, plaintext): + plaintext = add_pkcs_padding(plaintext) + context = bytes(context_structure_length) + ciphertext = bytes(len(plaintext)) + aes_encrypt_initialise(key, context) + lib.aes_cbc_encrypt( + plaintext, ciphertext, len(plaintext), bytes(bytearray(iv)), context + ) + return ciphertext + + +def aes_decrypt_initialise(key, context): + if len(key) == (128 / 8): + lib.aes_decrypt_key128(key, context) + elif len(key) == (192 / 8): + lib.aes_decrypt_key192(key, context) + elif len(key) == (256 / 8): + lib.aes_decrypt_key256(key, context) + else: + raise NotSupported("Unsupported AES key length: {}".format(len(key) * 8)) + + +def aes_cbc_decrypt(key, iv, ciphertext): + context = bytes(context_structure_length) + plaintext = bytes(len(ciphertext)) + aes_decrypt_initialise(key, context) + lib.aes_cbc_decrypt(ciphertext, plaintext, len(ciphertext), iv, context) + return remove_pkcs_padding(plaintext) + + +def load_json_testvectors(filename): + try: + result = json.loads(open(os.path.join(testvectors_directory, filename)).read()) + except Exception: + raise DataError() + return result + + +def generate_aes(filename): + vectors = [] + + data = load_json_testvectors(filename) + + if not keys_in_dict(data, {"algorithm", "testGroups"}): + raise DataError() + + if data["algorithm"] != "AES-CBC-PKCS5": + raise DataError() + + for test_group in data["testGroups"]: + if not keys_in_dict(test_group, {"tests"}): + raise DataError() + + for test in test_group["tests"]: + if not keys_in_dict(test, {"key", "iv", "msg", "ct", "result"}): + raise DataError() + try: + key = unhexlify(test["key"]) + iv = unhexlify(test["iv"]) + plaintext = unhexlify(test["msg"]) + ciphertext = unhexlify(test["ct"]) + result = parse_result(test["result"]) + except Exception: + raise DataError() + + if len(key) not in [128 / 8, 192 / 8, 256 / 8]: + continue + + if result is None: + continue + + vectors.append( + ( + hexlify(key), + hexlify(iv), + hexlify(plaintext), + hexlify(ciphertext), + result, + ) + ) + return vectors + + +def generate_chacha_poly(filename): + vectors = [] + + data = load_json_testvectors(filename) + + if not keys_in_dict(data, {"algorithm", "testGroups"}): + raise DataError() + + if data["algorithm"] != "CHACHA20-POLY1305": + raise DataError() + + for test_group in data["testGroups"]: + if not keys_in_dict(test_group, {"tests"}): + raise DataError() + + for test in test_group["tests"]: + if not keys_in_dict( + test, {"key", "iv", "aad", "msg", "ct", "tag", "result"} + ): + raise DataError() + try: + key = unhexlify(test["key"]) + iv = unhexlify(test["iv"]) + associated_data = unhexlify(test["aad"]) + plaintext = unhexlify(test["msg"]) + ciphertext = unhexlify(test["ct"]) + tag = unhexlify(test["tag"]) + result = parse_result(test["result"]) + except Exception: + raise DataError() + + if result is None: + continue + + vectors.append( + ( + hexlify(key), + hexlify(iv), + hexlify(associated_data), + hexlify(plaintext), + hexlify(ciphertext), + hexlify(tag), + result, + ) + ) + return vectors + + +def generate_curve25519_dh(filename): + vectors = [] + + data = load_json_testvectors(filename) + + if not keys_in_dict(data, {"algorithm", "testGroups"}): + raise DataError() + + if data["algorithm"] != "X25519": + raise DataError() + + for test_group in data["testGroups"]: + if not keys_in_dict(test_group, {"tests"}): + raise DataError() + + for test in test_group["tests"]: + if not keys_in_dict( + test, {"public", "private", "shared", "result", "curve"} + ): + raise DataError() + + try: + public_key = unhexlify(test["public"]) + curve_name = parse_curve_name(test["curve"]) + private_key = unhexlify(test["private"]) + shared = unhexlify(test["shared"]) + result = parse_result(test["result"]) + except Exception: + raise DataError() + + if curve_name != "curve25519": + continue + if result is None: + continue + + vectors.append( + (hexlify(public_key), hexlify(private_key), hexlify(shared), result) + ) + + return vectors + + +def generate_ecdh(filename): + vectors = [] + + data = load_json_testvectors(filename) + + if not keys_in_dict(data, {"algorithm", "testGroups"}): + raise DataError() + + if data["algorithm"] != "ECDH": + raise DataError() + + for test_group in data["testGroups"]: + if not keys_in_dict(test_group, {"tests"}): + raise DataError() + + for test in test_group["tests"]: + if not keys_in_dict( + test, {"public", "private", "shared", "result", "curve"} + ): + raise DataError() + + try: + public_key = unhexlify(test["public"]) + curve_name = parse_curve_name(test["curve"]) + private_key = parse_signed_hex(test["private"]) + shared = unhexlify(test["shared"]) + result = parse_result(test["result"]) + except Exception: + raise DataError() + + try: + private_key = parse_ecdh256_privkey(private_key) + except ParseError: + continue + + try: + key_curve_name, public_key = parse_ec_pubkey(public_key) + except NotSupported: + continue + except ParseError: + continue + + if key_curve_name != curve_name: + continue + if result is None: + continue + + vectors.append( + ( + curve_name, + hexlify(public_key), + hexlify(private_key), + hexlify(shared), + result, + ) + ) + + return vectors + + +def generate_ecdsa(filename): + vectors = [] + + data = load_json_testvectors(filename) + + if not keys_in_dict(data, {"algorithm", "testGroups"}): + raise DataError() + + if data["algorithm"] != "ECDSA": + raise DataError() + + for test_group in data["testGroups"]: + if not keys_in_dict(test_group, {"tests", "keyDer", "sha"}): + raise DataError() + + try: + public_key = unhexlify(test_group["keyDer"]) + except Exception: + raise DataError() + + try: + curve_name, public_key = parse_ec_pubkey(public_key) + except NotSupported: + continue + except ParseError: + continue + + try: + hasher = parse_digest(test_group["sha"]) + except NotSupported: + continue + + for test in test_group["tests"]: + if not keys_in_dict(test, {"sig", "msg", "result"}): + raise DataError() + + try: + signature = unhexlify(test["sig"]) + message = unhexlify(test["msg"]) + result = parse_result(test["result"]) + except Exception: + raise DataError() + + if result is None: + continue + + try: + signature = parse_ecdsa256_signature(signature) + except ParseError: + continue + + vectors.append( + ( + curve_name, + hexlify(public_key), + hasher, + hexlify(message), + hexlify(signature), + result, + ) + ) + + return vectors + + +def generate_eddsa(filename): + vectors = [] + + data = load_json_testvectors(filename) + + if not keys_in_dict(data, {"algorithm", "testGroups"}): + raise DataError() + + if data["algorithm"] != "EDDSA": + raise DataError() + + for test_group in data["testGroups"]: + if not keys_in_dict(test_group, {"tests", "keyDer"}): + raise DataError() + + try: + public_key = unhexlify(test_group["keyDer"]) + except Exception: + raise DataError() + + try: + public_key = parse_ed_pubkey(public_key) + except ParseError: + continue + + for test in test_group["tests"]: + if not keys_in_dict(test, {"sig", "msg", "result"}): + raise DataError() + + try: + signature = unhexlify(test["sig"]) + message = unhexlify(test["msg"]) + result = parse_result(test["result"]) + except Exception: + raise DataError() + + if result is None: + continue + + try: + signature = parse_eddsa_signature(signature) + except ParseError: + continue + + vectors.append( + (hexlify(public_key), hexlify(message), hexlify(signature), result) + ) + + return vectors + + +dir = os.path.abspath(os.path.dirname(__file__)) +lib = ctypes.cdll.LoadLibrary(os.path.join(dir, "libtrezor-crypto.so")) +testvectors_directory = os.path.join(dir, "wycheproof/testvectors") +context_structure_length = 1024 + +ecdh_vectors = generate_ecdh("ecdh_test.json") +curve25519_dh_vectors = generate_curve25519_dh("x25519_test.json") +eddsa_vectors = generate_eddsa("eddsa_test.json") +ecdsa_vectors = ( + generate_ecdsa("ecdsa_test.json") + + generate_ecdsa("ecdsa_secp256k1_sha256_test.json") + + generate_ecdsa("ecdsa_secp256r1_sha256_test.json") +) +ecdh_vectors = ( + generate_ecdh("ecdh_test.json") + + generate_ecdh("ecdh_secp256k1_test.json") + + generate_ecdh("ecdh_secp256r1_test.json") +) +chacha_poly_vectors = generate_chacha_poly("chacha20_poly1305_test.json") +aes_vectors = generate_aes("aes_cbc_pkcs5_test.json") + + +@pytest.mark.parametrize("public_key, message, signature, result", eddsa_vectors) +def test_eddsa(public_key, message, signature, result): + public_key = unhexlify(public_key) + signature = unhexlify(signature) + message = unhexlify(message) + + computed_result = ( + lib.ed25519_sign_open(message, len(message), public_key, signature) == 0 + ) + assert result == computed_result + + +@pytest.mark.parametrize( + "curve_name, public_key, hasher, message, signature, result", ecdsa_vectors +) +def test_ecdsa(curve_name, public_key, hasher, message, signature, result): + curve = get_curve_by_name(curve_name) + if curve is None: + raise NotSupported("Curve not supported: {}".format(curve_name)) + + public_key = unhexlify(public_key) + signature = unhexlify(signature) + message = unhexlify(message) + + computed_result = ( + lib.ecdsa_verify(curve, hasher, public_key, signature, message, len(message)) + == 0 + ) + assert result == computed_result + + +@pytest.mark.parametrize( + "public_key, private_key, shared, result", curve25519_dh_vectors +) +def test_curve25519_dh(public_key, private_key, shared, result): + public_key = unhexlify(public_key) + private_key = unhexlify(private_key) + shared = unhexlify(shared) + + computed_shared = bytes([0] * 32) + lib.curve25519_scalarmult(computed_shared, private_key, public_key) + computed_result = shared == computed_shared + assert result == computed_result + + +@pytest.mark.parametrize( + "curve_name, public_key, private_key, shared, result", ecdh_vectors +) +def test_ecdh(curve_name, public_key, private_key, shared, result): + curve = get_curve_by_name(curve_name) + if curve is None: + raise NotSupported("Curve not supported: {}".format(curve_name)) + + public_key = unhexlify(public_key) + private_key = unhexlify(private_key) + shared = unhexlify(shared) + + computed_shared = bytes([0] * 2 * 32) + lib.ecdh_multiply(curve, private_key, public_key, computed_shared) + computed_shared = computed_shared[1:33] + computed_result = shared == computed_shared + assert result == computed_result + + +@pytest.mark.parametrize( + "key, iv, associated_data, plaintext, ciphertext, tag, result", chacha_poly_vectors +) +def test_chacha_poly(key, iv, associated_data, plaintext, ciphertext, tag, result): + key = unhexlify(key) + iv = unhexlify(iv) + associated_data = unhexlify(associated_data) + plaintext = unhexlify(plaintext) + ciphertext = unhexlify(ciphertext) + tag = unhexlify(tag) + + computed_ciphertext, computed_tag = chacha_poly_encrypt( + key, iv, associated_data, plaintext + ) + computed_result = ciphertext == computed_ciphertext and tag == computed_tag + assert result == computed_result + + computed_plaintext = chacha_poly_decrypt(key, iv, associated_data, ciphertext, tag) + computed_result = plaintext == computed_plaintext + assert result == computed_result + + +@pytest.mark.parametrize("key, iv, plaintext, ciphertext, result", aes_vectors) +def test_aes(key, iv, plaintext, ciphertext, result): + key = unhexlify(key) + iv = unhexlify(iv) + plaintext = unhexlify(plaintext) + ciphertext = unhexlify(ciphertext) + + computed_ciphertext = aes_cbc_encrypt(key, iv, plaintext) + computed_result = ciphertext == computed_ciphertext + assert result == computed_result + + computed_plaintext = aes_cbc_decrypt(key, bytes(iv), ciphertext) + computed_result = plaintext == computed_plaintext + assert result == computed_result diff --git a/deps/crypto/trezor-crypto/tools/.gitignore b/deps/crypto/trezor-crypto/tools/.gitignore new file mode 100644 index 000000000..da1bc3702 --- /dev/null +++ b/deps/crypto/trezor-crypto/tools/.gitignore @@ -0,0 +1,3 @@ +xpubaddrgen +mktable +bip39bruteforce diff --git a/deps/crypto/trezor-crypto/tools/README.md b/deps/crypto/trezor-crypto/tools/README.md new file mode 100644 index 000000000..7786244de --- /dev/null +++ b/deps/crypto/trezor-crypto/tools/README.md @@ -0,0 +1,54 @@ +trezor-crypto tools +=================== + +Set of small utilities using the trezor-crypto library. + +xpubaddrgen +----------- + +xpubaddrgen reads job specification from stdin in format: + +``` + +``` + +and prints the results to stdout in format: + +``` +
+``` + +Example input: + +``` +23 xpub6BcjTvRCYD4VvFQ8whztSXhbNyhS56eTd5P3g9Zvd3zPEeUeL5CUqBYX8NSd1b6Thitr8bZcSnesmXZH7KerMcc4tUkenBShYCtQ1L8ebVe 0 0 5 +42 xpub6AT2YrLinU4Be5UWUxMaUz3zTA99CSGvXt1jt2Lgym8PqXbTzmpQ8MHjoLnx8YJiMMUP5iEfR97YQVmgF6B2tAhbCZrXqn65ur526NkZ6ey 1 1000 1005 +``` + +Example output: + +``` +23 0 14vb5Cws75p2i5rmSiF5CKMyezUX4hxSb9 +23 1 1Lf4ciA36dsi1niF6smVcpCiHcpj2skaPq +23 2 1LraByp7gQAipvHnFS1gTSzixBtYaVyQGp +23 3 1Hy6n56qZj1EefLVfDAeEpmveNteY9jpiG +23 4 183Nn4mrUjPizM3xu8C6SrmViaWrk8YyRS +42 1000 12eAFGAqGUtszc9R7euRqk7DUcQNXvQZSg +42 1001 1BrLbFCD3MNYedJaz92U9iqy9ukHrtQ1A6 +42 1002 1Jhv33bJy229ThM7HKxUa92cMK5gi7DyPC +42 1003 13LxbTjQPByisj4F4sZEivUBdnJwigzg6R +42 1004 1BWBpSWkPwcKxVr2WDyUqQbmvk5SGihcx9 +``` + +It will print ``` error``` when there was an error processing job jobid. + +It will print ```error``` when it encountered a malformed line. + + +mktable +----------- + +mktable computes the points of the form `(2*j+1)*16^i*G` and prints them in the format to be included in `secp256k1.c` and `nist256p1.c`. +These points are used by the fast ECC multiplication. + +It is only meant to be run if the `scalar_mult` algorithm changes. diff --git a/deps/crypto/trezor-crypto/tools/bip39bruteforce.c b/deps/crypto/trezor-crypto/tools/bip39bruteforce.c new file mode 100644 index 000000000..d15132b14 --- /dev/null +++ b/deps/crypto/trezor-crypto/tools/bip39bruteforce.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include "bip32.h" +#include "bip39.h" +#include "curves.h" +#include "ecdsa.h" +#include "secp256k1.h" + +char iter[256]; +uint8_t seed[512 / 8]; +char addr[MAX_ADDR_SIZE]; +int count = 0, found = 0; +HDNode node; +clock_t start; + +#define ACCOUNT_LEGACY 0 + +// around 280 tries per second + +// testing data: +// +// mnemonic: "all all all all all all all all all all all all" +// address: legacy: "1JAd7XCBzGudGpJQSDSfpmJhiygtLQWaGL" +// segwit: "3L6TyTisPBmrDAj6RoKmDzNnj4eQi54gD2" +// passphrase: "" +// +// mnemonic: "all all all all all all all all all all all all" +// address: legacy: "1N3uJ5AU3FTYQ1ZQgTMtYmgSvMBmQiGVBS" +// segwit: "3NcXPfbDP4UHSbuHASALJEBtDeAcWYMMcS" +// passphrase: "testing" + +int main(int argc, char **argv) { + if (argc != 2 && argc != 3) { + fprintf(stderr, "Usage: bip39bruteforce address [mnemonic]\n"); + return 1; + } + const char *address = argv[1]; + const char *mnemonic, *item; + if (argc == 3) { + mnemonic = argv[2]; + item = "passphrase"; + } else { + mnemonic = NULL; + item = "mnemonic"; + } + if (mnemonic && !mnemonic_check(mnemonic)) { + fprintf(stderr, "\"%s\" is not a valid mnemonic\n", mnemonic); + return 2; + } + printf("Reading %ss from stdin ...\n", item); + start = clock(); + for (;;) { + if (fgets(iter, 256, stdin) == NULL) break; + int len = strlen(iter); + if (len <= 0) { + continue; + } + count++; + iter[len - 1] = 0; + if (mnemonic) { + mnemonic_to_seed(mnemonic, iter, seed, NULL); + } else { + mnemonic_to_seed(iter, "", seed, NULL); + } + hdnode_from_seed(seed, 512 / 8, SECP256K1_NAME, &node); +#if ACCOUNT_LEGACY + hdnode_private_ckd_prime(&node, 44); +#else + hdnode_private_ckd_prime(&node, 49); +#endif + hdnode_private_ckd_prime(&node, 0); + hdnode_private_ckd_prime(&node, 0); + hdnode_private_ckd(&node, 0); + hdnode_private_ckd(&node, 0); + hdnode_fill_public_key(&node); +#if ACCOUNT_LEGACY + // Legacy address + ecdsa_get_address(node.public_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, + addr, sizeof(addr)); +#else + // Segwit-in-P2SH + ecdsa_get_address_segwit_p2sh(node.public_key, 5, HASHER_SHA2_RIPEMD, + HASHER_SHA2D, addr, sizeof(addr)); +#endif + if (strcmp(address, addr) == 0) { + found = 1; + break; + } + } + float dur = (float)(clock() - start) / CLOCKS_PER_SEC; + printf("Tried %d %ss in %f seconds = %f tries/second\n", count, item, dur, + (float)count / dur); + if (found) { + printf("Correct %s found! :-)\n\"%s\"\n", item, iter); + return 0; + } + printf("Correct %s not found. :-(\n", item); + return 4; +} diff --git a/deps/crypto/trezor-crypto/tools/mktable.c b/deps/crypto/trezor-crypto/tools/mktable.c new file mode 100644 index 000000000..2760d7495 --- /dev/null +++ b/deps/crypto/trezor-crypto/tools/mktable.c @@ -0,0 +1,69 @@ +#include +#include +#include "bignum.h" +#include "bip32.h" +#include "ecdsa.h" +#include "rand.h" + +/* + * This program prints the contents of the ecdsa_curve.cp array. + * The entry cp[i][j] contains the number (2*j+1)*16^i*G, + * where G is the generator of the specified elliptic curve. + */ +int main(int argc, char **argv) { + int i, j, k; + if (argc != 2) { + printf("Usage: %s CURVE_NAME\n", argv[0]); + return 1; + } + const char *name = argv[1]; + const curve_info *info = get_curve_by_name(name); + const ecdsa_curve *curve = info->params; + if (curve == 0) { + printf("Unknown curve '%s'\n", name); + return 1; + } + + curve_point ng = curve->G; + curve_point pow2ig = curve->G; + for (i = 0; i < 64; i++) { + // invariants: + // pow2ig = 16^i * G + // ng = pow2ig + printf("\t{\n"); + for (j = 0; j < 8; j++) { + // invariants: + // pow2ig = 16^i * G + // ng = (2*j+1) * 16^i * G +#ifndef NDEBUG + curve_point checkresult; + bignum256 a; + bn_zero(&a); + a.val[(4 * i) / BN_BITS_PER_LIMB] = ((uint32_t)2 * j + 1) + << ((4 * i) % BN_BITS_PER_LIMB); + bn_normalize(&a); + point_multiply(curve, &a, &curve->G, &checkresult); + assert(point_is_equal(&checkresult, &ng)); +#endif + printf("\t\t/* %2d*16^%d*G: */\n\t\t{{{", 2 * j + 1, i); + // print x coordinate + for (k = 0; k < 9; k++) { + printf((k < 8 ? "0x%08x, " : "0x%04x"), ng.x.val[k]); + } + printf("}},\n\t\t {{"); + // print y coordinate + for (k = 0; k < 9; k++) { + printf((k < 8 ? "0x%08x, " : "0x%04x"), ng.y.val[k]); + } + if (j == 7) { + printf("}}}\n\t},\n"); + } else { + printf("}}},\n"); + point_add(curve, &pow2ig, &ng); + } + point_add(curve, &pow2ig, &ng); + } + pow2ig = ng; + } + return 0; +} diff --git a/deps/crypto/trezor-crypto/tools/nem_test_vectors.erb b/deps/crypto/trezor-crypto/tools/nem_test_vectors.erb new file mode 100644 index 000000000..0e7ed946e --- /dev/null +++ b/deps/crypto/trezor-crypto/tools/nem_test_vectors.erb @@ -0,0 +1,18 @@ +// test vectors from <%= source_url %> +START_TEST(<%= test_name %>) +{ + static const struct { +<% fields.each do |(name, type)| -%> + <%= if type.nil? then 'const char *' else "#{type} " end %><%= name %>; +<% end -%> + } tests[] = { +<% data.each do |values| -%> + { <% values.each do |value| %><%= value %>, <% end %>}, +<% end -%> + }; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + // TODO: Implement test + } +} +END_TEST diff --git a/deps/crypto/trezor-crypto/tools/nem_test_vectors.rb b/deps/crypto/trezor-crypto/tools/nem_test_vectors.rb new file mode 100755 index 000000000..9bb487927 --- /dev/null +++ b/deps/crypto/trezor-crypto/tools/nem_test_vectors.rb @@ -0,0 +1,126 @@ +#!/usr/bin/env ruby +require 'highline' +require 'open-uri' + +TEMPLATE_NAME = (Pathname.new(__FILE__).sub_ext '.erb').to_s.freeze + +@terminal = HighLine.new($stdin, $stderr) + +def github_files + require 'octokit' + + @github_files ||= Octokit.contents('NemProject/nem-test-vectors') + .select do |file| + file.name.end_with? '.dat' + end +end + +def choose_data_file + @terminal.choose do |menu| + github_files.each do |file| + menu.choice(file.name) { file.download_url } + end + + menu.prompt = 'Which file? ' + + menu.index = :none + menu.select_by = :name + end +end + +def load_header(line) + line = line.dup + abort 'Header is not a comment' unless line.slice!(0) == '#' + + header = line.split(':').each(&:strip!) + header.shift if header.first.empty? + + header +end + +def parse_field_answer(answer) + if answer.empty? + nil + elsif /^(?:(?\w+) )?(?\w+)$/ =~ answer + [identifier, type] + else + raise NotValidQuestionError + end +end + +def ask_fields(header) + header.map do |name| + @terminal.ask "Field for `#{name}'? " do |question| + question.answer_type = lambda(&method(:parse_field_answer)) + end + end +end + +def load_data_line(line) + abort 'Line does not begin with colon' unless line.slice!(0) == ':' + + line.strip! + line.chomp!(',') + + values = line.split(':').each(&:strip!) + values.pop if values.last.empty? + + values +end + +def load_data(file, count) + file.each_line.lazy.reject { |line| line.start_with? '#' } + .take(count) + .map(&method(:load_data_line)) + .to_a +end + +def remove_skipped_fields(fields, data) + data.each do |values| + abort 'Line does not match header' unless values.size == fields.size + + values.reject!.each_with_index { |_, index| fields[index].nil? } + end + + fields.compact! +end + +def format_data_fields(fields, data) + data.each do |values| + fields.each_with_index do |(_, type), index| + values[index] = values[index].dump if type.nil? + end + end +end + +def template(source_url, fields, data) + test_name = @terminal.ask('Name for test? ') do |question| + question.validate = /./ + end + + erb = ERB.new(File.read(TEMPLATE_NAME), nil, '-') + erb.filename = TEMPLATE_NAME + + erb.result(binding) +end + +download_url = choose_data_file + +source_code = open download_url do |file| + line = file.readline + + header = load_header(line) + @terminal.say line + + count = @terminal.ask('How many vectors to import? ', Integer) + + fields = ask_fields(header) + data = load_data(file, count) + + remove_skipped_fields(fields, data) + format_data_fields(fields, data) + + template(download_url, fields, data) +end + +puts source_code diff --git a/deps/crypto/trezor-crypto/tools/xpubaddrgen.c b/deps/crypto/trezor-crypto/tools/xpubaddrgen.c new file mode 100644 index 000000000..cce472923 --- /dev/null +++ b/deps/crypto/trezor-crypto/tools/xpubaddrgen.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include "bip32.h" +#include "curves.h" +#include "ecdsa.h" + +#define VERSION_PUBLIC 0x0488b21e + +void process_job(uint32_t jobid, const char *xpub, uint32_t change, + uint32_t from, uint32_t to) { + HDNode node, child; + if (change > 1 || to <= from || + hdnode_deserialize_public(xpub, VERSION_PUBLIC, SECP256K1_NAME, &node, + NULL) != 0) { + printf("%d error\n", jobid); + return; + } + hdnode_public_ckd(&node, change); + uint32_t i; + char address[36]; + for (i = from; i < to; i++) { + memcpy(&child, &node, sizeof(HDNode)); + hdnode_public_ckd(&child, i); + ecdsa_get_address(child.public_key, 0, HASHER_SHA2, HASHER_SHA2D, address, + sizeof(address)); + printf("%d %d %s\n", jobid, i, address); + } +} + +int main(void) { + char line[1024], xpub[1024]; + uint32_t jobid, change, from, to; + int r; + for (;;) { + if (!fgets(line, sizeof(line), stdin)) break; + r = sscanf(line, "%u %s %u %u %u\n", &jobid, xpub, &change, &from, &to); + if (r < 1) { + printf("error\n"); + } else if (r != 5) { + printf("%d error\n", jobid); + } else { + process_job(jobid, xpub, change, from, to); + } + } + return 0; +} diff --git a/deps/crypto/trezor-crypto/zcash_zip316.c b/deps/crypto/trezor-crypto/zcash_zip316.c new file mode 100644 index 000000000..c5a6e33b4 --- /dev/null +++ b/deps/crypto/trezor-crypto/zcash_zip316.c @@ -0,0 +1,271 @@ +/** + * Copyright (c) 2026 KeepKey + * + * Minimal ZIP-316 helpers needed for Orchard-only unified addresses. + */ + +#include "zcash_zip316.h" + +#include +#include + +#include "blake2b.h" +#include "memzero.h" + +#define ZCASH_ZIP316_BLAKE2B_OUT_LEN 64 + +static const char BECH32_CHARSET[] = + "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; + +static size_t min_size(size_t a, size_t b) { return a < b ? a : b; } + +static size_t ceil_div(size_t num, size_t den) { + return (num + den - 1) / den; +} + +static int valid_f4jumble_len(size_t len) { + return len >= ZCASH_ZIP316_F4JUMBLE_MIN_LEN && + len <= ZCASH_ZIP316_F4JUMBLE_MAX_LEN; +} + +static void xor_bytes(uint8_t *target, size_t target_len, const uint8_t *source, + size_t source_len) { + size_t len = min_size(target_len, source_len); + for (size_t i = 0; i < len; i++) { + target[i] ^= source[i]; + } +} + +static int h_round(uint8_t *left, size_t left_len, const uint8_t *right, + size_t right_len, uint8_t round) { + uint8_t personal[BLAKE2B_PERSONALBYTES] = { + 'U', 'A', '_', 'F', '4', 'J', 'u', 'm', + 'b', 'l', 'e', '_', 'H', round, 0, 0, + }; + uint8_t hash[ZCASH_ZIP316_BLAKE2B_OUT_LEN]; + BLAKE2B_CTX ctx; + + if (blake2b_InitPersonal(&ctx, left_len, personal, sizeof(personal)) != 0) { + memzero(hash, sizeof(hash)); + memzero(&ctx, sizeof(ctx)); + return -1; + } + if (blake2b_Update(&ctx, right, right_len) != 0 || + blake2b_Final(&ctx, hash, left_len) != 0) { + memzero(hash, sizeof(hash)); + memzero(&ctx, sizeof(ctx)); + return -1; + } + xor_bytes(left, left_len, hash, left_len); + + memzero(hash, sizeof(hash)); + memzero(&ctx, sizeof(ctx)); + return 0; +} + +static int g_round(const uint8_t *left, size_t left_len, uint8_t *right, + size_t right_len, uint8_t round) { + uint8_t hash[ZCASH_ZIP316_BLAKE2B_OUT_LEN]; + for (size_t j = 0; j < ceil_div(right_len, ZCASH_ZIP316_BLAKE2B_OUT_LEN); + j++) { + uint8_t personal[BLAKE2B_PERSONALBYTES] = { + 'U', + 'A', + '_', + 'F', + '4', + 'J', + 'u', + 'm', + 'b', + 'l', + 'e', + '_', + 'G', + round, + (uint8_t)(j & 0xff), + (uint8_t)(j >> 8), + }; + BLAKE2B_CTX ctx; + + if (j > 0xffff) { + memzero(hash, sizeof(hash)); + return -1; + } + if (blake2b_InitPersonal(&ctx, sizeof(hash), personal, sizeof(personal)) != + 0) { + memzero(hash, sizeof(hash)); + memzero(&ctx, sizeof(ctx)); + return -1; + } + if (blake2b_Update(&ctx, left, left_len) != 0 || + blake2b_Final(&ctx, hash, sizeof(hash)) != 0) { + memzero(hash, sizeof(hash)); + memzero(&ctx, sizeof(ctx)); + return -1; + } + xor_bytes(right + j * ZCASH_ZIP316_BLAKE2B_OUT_LEN, + right_len - j * ZCASH_ZIP316_BLAKE2B_OUT_LEN, hash, + sizeof(hash)); + memzero(&ctx, sizeof(ctx)); + } + + memzero(hash, sizeof(hash)); + return 0; +} + +static int f4jumble_apply(uint8_t *message, size_t message_len, int inverse) { + if (!message || !valid_f4jumble_len(message_len)) return -1; + + size_t left_len = min_size(ZCASH_ZIP316_BLAKE2B_OUT_LEN, message_len / 2); + uint8_t *left = message; + uint8_t *right = message + left_len; + size_t right_len = message_len - left_len; + + if (inverse) { + return h_round(left, left_len, right, right_len, 1) == 0 && + g_round(left, left_len, right, right_len, 1) == 0 && + h_round(left, left_len, right, right_len, 0) == 0 && + g_round(left, left_len, right, right_len, 0) == 0 + ? 0 + : -1; + } + + return g_round(left, left_len, right, right_len, 0) == 0 && + h_round(left, left_len, right, right_len, 0) == 0 && + g_round(left, left_len, right, right_len, 1) == 0 && + h_round(left, left_len, right, right_len, 1) == 0 + ? 0 + : -1; +} + +int zcash_zip316_f4jumble(uint8_t *message, size_t message_len) { + return f4jumble_apply(message, message_len, 0); +} + +int zcash_zip316_f4jumble_inv(uint8_t *message, size_t message_len) { + return f4jumble_apply(message, message_len, 1); +} + +static uint32_t bech32_polymod_step(uint32_t pre) { + uint8_t b = pre >> 25; + return ((pre & 0x1FFFFFF) << 5) ^ + (-((b >> 0) & 1) & 0x3b6a57b2UL) ^ + (-((b >> 1) & 1) & 0x26508e6dUL) ^ + (-((b >> 2) & 1) & 0x1ea119faUL) ^ + (-((b >> 3) & 1) & 0x3d4233ddUL) ^ + (-((b >> 4) & 1) & 0x2a1462b3UL); +} + +static int convert_bits_8_to_5(uint8_t *out, size_t *out_len, + size_t out_capacity, const uint8_t *in, + size_t in_len) { + uint32_t val = 0; + int bits = 0; + *out_len = 0; + + while (in_len--) { + val = (val << 8) | *(in++); + bits += 8; + while (bits >= 5) { + bits -= 5; + if (*out_len >= out_capacity) return -1; + out[(*out_len)++] = (val >> bits) & 0x1f; + } + } + if (bits) { + if (*out_len >= out_capacity) return -1; + out[(*out_len)++] = (val << (5 - bits)) & 0x1f; + } + return 0; +} + +static int bech32m_encode_5bit(char *output, size_t output_len, + const char *hrp, const uint8_t *data, + size_t data_len) { + uint32_t chk = 1; + size_t hrp_len = 0; + while (hrp[hrp_len] != 0) { + int ch = hrp[hrp_len]; + if (ch < 33 || ch > 126 || (ch >= 'A' && ch <= 'Z')) { + return -1; + } + chk = bech32_polymod_step(chk) ^ (ch >> 5); + hrp_len++; + } + + if (hrp_len == 0 || output_len < hrp_len + 1 + data_len + 6 + 1) { + return -1; + } + + chk = bech32_polymod_step(chk); + for (size_t i = 0; i < hrp_len; i++) { + chk = bech32_polymod_step(chk) ^ (hrp[i] & 0x1f); + output[i] = hrp[i]; + } + output[hrp_len] = '1'; + + for (size_t i = 0; i < data_len; i++) { + if (data[i] >> 5) return -1; + chk = bech32_polymod_step(chk) ^ data[i]; + output[hrp_len + 1 + i] = BECH32_CHARSET[data[i]]; + } + + for (size_t i = 0; i < 6; i++) { + chk = bech32_polymod_step(chk); + } + chk ^= 0x2bc830a3UL; + + for (size_t i = 0; i < 6; i++) { + output[hrp_len + 1 + data_len + i] = + BECH32_CHARSET[(chk >> ((5 - i) * 5)) & 0x1f]; + } + output[hrp_len + 1 + data_len + 6] = 0; + return 0; +} + +static int bech32m_encode_bytes(char *output, size_t output_len, + const char *hrp, const uint8_t *data, + size_t data_len) { + if (!output || !hrp || (!data && data_len != 0)) return -1; + + size_t data5_capacity = (data_len * 8 + 4) / 5; + uint8_t data5[ZCASH_ZIP316_ORCHARD_ONLY_DATA5_LEN]; + if (data5_capacity > sizeof(data5)) return -1; + + size_t data5_len = 0; + if (convert_bits_8_to_5(data5, &data5_len, sizeof(data5), data, data_len) != + 0) { + memzero(data5, sizeof(data5)); + return -1; + } + + int ret = bech32m_encode_5bit(output, output_len, hrp, data5, data5_len); + memzero(data5, sizeof(data5)); + return ret; +} + +int zcash_zip316_encode_orchard_unified_address( + const char *hrp, + const uint8_t receiver[ZCASH_ZIP316_ORCHARD_RAW_RECEIVER_LEN], + char *output, size_t output_len) { + if (!hrp || !receiver || !output) return -1; + + size_t hrp_len = strlen(hrp); + if (hrp_len == 0 || hrp_len > ZCASH_ZIP316_PADDING_LEN) return -1; + + uint8_t payload[ZCASH_ZIP316_ORCHARD_ONLY_PAYLOAD_LEN] = {0}; + payload[0] = 0x03; /* Orchard receiver typecode. */ + payload[1] = ZCASH_ZIP316_ORCHARD_RAW_RECEIVER_LEN; + memcpy(payload + 2, receiver, ZCASH_ZIP316_ORCHARD_RAW_RECEIVER_LEN); + memcpy(payload + 2 + ZCASH_ZIP316_ORCHARD_RAW_RECEIVER_LEN, hrp, hrp_len); + + int ret = zcash_zip316_f4jumble(payload, sizeof(payload)); + if (ret == 0) { + ret = bech32m_encode_bytes(output, output_len, hrp, payload, + sizeof(payload)); + } + + memzero(payload, sizeof(payload)); + return ret; +} diff --git a/deps/crypto/trezor-crypto/zcash_zip316.h b/deps/crypto/trezor-crypto/zcash_zip316.h new file mode 100644 index 000000000..b48cbd72a --- /dev/null +++ b/deps/crypto/trezor-crypto/zcash_zip316.h @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2026 KeepKey + * + * ZIP-316 helpers for Zcash unified address encoding. + */ + +#ifndef __ZCASH_ZIP316_H__ +#define __ZCASH_ZIP316_H__ + +#include +#include + +#define ZCASH_ZIP316_F4JUMBLE_MIN_LEN 48 +#define ZCASH_ZIP316_F4JUMBLE_MAX_LEN 4194368 + +#define ZCASH_ZIP316_ORCHARD_RAW_RECEIVER_LEN 43 +#define ZCASH_ZIP316_PADDING_LEN 16 +#define ZCASH_ZIP316_ORCHARD_ONLY_PAYLOAD_LEN \ + (2 + ZCASH_ZIP316_ORCHARD_RAW_RECEIVER_LEN + ZCASH_ZIP316_PADDING_LEN) +#define ZCASH_ZIP316_ORCHARD_ONLY_DATA5_LEN \ + ((ZCASH_ZIP316_ORCHARD_ONLY_PAYLOAD_LEN * 8 + 4) / 5) +#define ZCASH_ZIP316_ORCHARD_ONLY_MAX_HRP_LEN ZCASH_ZIP316_PADDING_LEN +#define ZCASH_ZIP316_ORCHARD_ONLY_MAX_ADDRESS_LEN \ + (ZCASH_ZIP316_ORCHARD_ONLY_MAX_HRP_LEN + 1 + \ + ZCASH_ZIP316_ORCHARD_ONLY_DATA5_LEN + 6) +#define ZCASH_ZIP316_ORCHARD_ONLY_MAX_ADDRESS_SIZE \ + (ZCASH_ZIP316_ORCHARD_ONLY_MAX_ADDRESS_LEN + 1) + +int zcash_zip316_f4jumble(uint8_t *message, size_t message_len); +int zcash_zip316_f4jumble_inv(uint8_t *message, size_t message_len); + +int zcash_zip316_encode_orchard_unified_address( + const char *hrp, + const uint8_t receiver[ZCASH_ZIP316_ORCHARD_RAW_RECEIVER_LEN], + char *output, size_t output_len); + +#endif diff --git a/deps/crypto/trezor-firmware b/deps/crypto/trezor-firmware deleted file mode 160000 index 56f404e45..000000000 --- a/deps/crypto/trezor-firmware +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 56f404e452bc7738cd3b3e14454dfecb25c083bf diff --git a/include/trezor/crypto b/include/trezor/crypto index 5bac4fafe..9e26be76d 120000 --- a/include/trezor/crypto +++ b/include/trezor/crypto @@ -1 +1 @@ -../../deps/crypto/trezor-firmware/crypto \ No newline at end of file +../../deps/crypto/trezor-crypto \ No newline at end of file diff --git a/lib/firmware/fsm_msg_solana.h b/lib/firmware/fsm_msg_solana.h index 675219449..bfe49e559 100644 --- a/lib/firmware/fsm_msg_solana.h +++ b/lib/firmware/fsm_msg_solana.h @@ -851,8 +851,7 @@ void fsm_msgSolanaSignMessage(const SolanaSignMessage* msg) { /* Ed25519 sign */ uint8_t sig[SOL_SIG_SIZE]; - ed25519_sign(msg->message.bytes, msg->message.size, node->private_key, - node->public_key + 1, sig); + ed25519_sign(msg->message.bytes, msg->message.size, node->private_key, sig); resp->has_signature = true; resp->signature.size = SOL_SIG_SIZE; diff --git a/lib/firmware/solana.c b/lib/firmware/solana.c index 302a1340f..b049118ac 100644 --- a/lib/firmware/solana.c +++ b/lib/firmware/solana.c @@ -831,8 +831,7 @@ bool solana_signTx(const HDNode* node, const SolanaSignTx* msg, &message_len); uint8_t sig[SOL_SIG_SIZE]; - ed25519_sign(message, message_len, node->private_key, node->public_key + 1, - sig); + ed25519_sign(message, message_len, node->private_key, sig); #if !ZCASH_PRIVACY /* Defense-in-depth: refuse to emit a signature that does not verify over @@ -917,7 +916,7 @@ bool solana_offchain_message_sign(const HDNode* node, off += msg->message.size; uint8_t sig[SOL_SIG_SIZE]; - ed25519_sign(envelope, off, node->private_key, node->public_key + 1, sig); + ed25519_sign(envelope, off, node->private_key, sig); resp->has_public_key = true; resp->public_key.size = SOL_PUBKEY_SIZE; diff --git a/lib/firmware/storage.c b/lib/firmware/storage.c index 975899444..a4b4a3a0d 100644 --- a/lib/firmware/storage.c +++ b/lib/firmware/storage.c @@ -1529,6 +1529,9 @@ void storage_resetUuid_impl(ConfigFlash* cfg) { void storage_reset(void) { storage_reset_impl(&session, &shadow_config); } void storage_reset_impl(SessionState* ss, ConfigFlash* cfg) { + bip32_cache_clear(); + bip39_cache_clear(); + memset(&cfg->storage, 0, sizeof(cfg->storage)); storage_resetPolicies(&cfg->storage); @@ -1587,6 +1590,9 @@ pintest_t session_clear_impl(SessionState* ss, Storage* storage, */ pintest_t ret = PIN_WRONG; + bip32_cache_clear(); + bip39_cache_clear(); + ss->seedCached = false; memset(&ss->seed, 0, sizeof(ss->seed)); diff --git a/lib/firmware/ton.c b/lib/firmware/ton.c index 043e41c9d..354d7a4b4 100644 --- a/lib/firmware/ton.c +++ b/lib/firmware/ton.c @@ -240,7 +240,7 @@ bool ton_signTx(const HDNode* node, const TonSignTx* msg, TonSignedTx* resp) { // Ed25519 sign the transaction ed25519_signature signature; ed25519_sign(msg->raw_tx.bytes, msg->raw_tx.size, node->private_key, - &node->public_key[1], signature); + signature); // Copy signature to response (64 bytes) resp->has_signature = true; @@ -273,7 +273,7 @@ bool ton_message_sign(const HDNode* node, const TonSignMessage* msg, ed25519_signature signature; ed25519_sign(msg->message.bytes, msg->message.size, node->private_key, - &node->public_key[1], signature); + signature); resp->has_public_key = true; resp->public_key.size = 32; diff --git a/unittests/crypto/CMakeLists.txt b/unittests/crypto/CMakeLists.txt index 7c9898e38..2edbb9e3a 100644 --- a/unittests/crypto/CMakeLists.txt +++ b/unittests/crypto/CMakeLists.txt @@ -31,8 +31,8 @@ if(${KK_ZCASH_PRIVACY}) target_include_directories(zcash-crypto-unit PRIVATE ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/lib/firmware - ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-firmware/crypto - ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-firmware/crypto/ed25519-donna) + ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-crypto + ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-crypto/ed25519-donna) target_link_libraries(zcash-crypto-unit gtest_main trezorcrypto From 6b8cfbe02819703207c26cd0e02fd35d149c3068 Mon Sep 17 00:00:00 2001 From: highlander Date: Sat, 25 Jul 2026 14:29:02 -0300 Subject: [PATCH 03/22] ci: scope vendored crypto secret-scan exceptions Retain the complete default Gitleaks ruleset while excluding only published AES vectors and Ed25519 C declarations from the generic-api-key heuristic. --- .gitleaks.toml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .gitleaks.toml diff --git a/.gitleaks.toml b/.gitleaks.toml new file mode 100644 index 000000000..a8ac90a02 --- /dev/null +++ b/.gitleaks.toml @@ -0,0 +1,23 @@ +title = "KeepKey firmware Gitleaks configuration" + +[extend] +useDefault = true + +[[allowlists]] +description = "Published AES test vectors in vendored trezor-crypto" +targetRules = ["generic-api-key"] +condition = "AND" +regexTarget = "line" +paths = ['''^deps/crypto/trezor-crypto/aes/aestst\.c$'''] +regexes = ['''(?i)^[[:space:]]*//[[:space:]]*key[[:space:]]*=[[:space:]]*[0-9a-f]+[[:space:]]*$'''] + +[[allowlists]] +description = "Ed25519 C type names in vendored trezor-crypto" +targetRules = ["generic-api-key"] +condition = "AND" +regexTarget = "line" +paths = [ + '''^deps/crypto/trezor-crypto/ed25519-donna/ed25519-(blake2b|keccak|sha3)\.h$''', + '''^deps/crypto/trezor-crypto/ed25519-donna/ed25519\.[ch]$''', +] +regexes = ['''ed25519.*secret_key.*signature'''] From 5e94bc6e1b4af28b1932edadbf3fb266818e6526 Mon Sep 17 00:00:00 2001 From: highlander Date: Sat, 25 Jul 2026 14:41:07 -0300 Subject: [PATCH 04/22] ci: give cppcheck headroom for vendored includes The first hosted run completed cppcheck in 9m40s under a 10-minute job timeout. Raise the bound to 15 minutes to avoid timing-dependent RC18 gate failures. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index adc1b2d94..558172891 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -101,7 +101,7 @@ jobs: static-analysis: runs-on: ubuntu-latest - timeout-minutes: 10 + timeout-minutes: 15 steps: - name: Checkout uses: actions/checkout@v6 From 2d1bac0e6efe441613e1ee44b7e0f8294dfcb494 Mon Sep 17 00:00:00 2001 From: highlander Date: Sat, 25 Jul 2026 17:41:08 -0300 Subject: [PATCH 05/22] fix(security): close RC18 release audit findings --- .github/workflows/ci.yml | 100 ++++++++++------ .github/workflows/release.yml | 41 +++++-- CMakeLists.txt | 29 +++-- deps/device-protocol | 2 +- deps/python-keepkey | 2 +- docs/security/7.15.0-rc18-release-shape.md | 35 ++++-- include/keepkey/firmware/signed_metadata.h | 16 ++- lib/board/draw.c | 2 +- lib/emulator/setup.c | 23 +++- lib/firmware/fsm_msg_ethereum.h | 23 ++-- lib/firmware/signed_metadata.c | 132 +++++---------------- lib/firmware/storage.c | 96 ++------------- lib/firmware/storage.h | 23 +--- lib/rand/rng.c | 33 ++---- scripts/build/docker/device/debug.sh | 2 +- scripts/build/docker/device/release.sh | 2 +- scripts/build/docker/emulator/debug.sh | 2 +- scripts/emulator/Dockerfile | 3 +- scripts/emulator/python-keepkey-tests.sh | 2 + scripts/emulator/python-keepkey.Dockerfile | 2 +- unittests/board/CMakeLists.txt | 2 +- unittests/crypto/CMakeLists.txt | 2 +- unittests/firmware/CMakeLists.txt | 2 +- unittests/firmware/signed_metadata.cpp | 10 ++ unittests/firmware/storage.cpp | 79 +++++------- 25 files changed, 275 insertions(+), 390 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 558172891..4af173e10 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,7 +37,7 @@ on: default: false env: - BASE_IMAGE: kktech/firmware:v15 + BASE_IMAGE: kktech/firmware@sha256:7438e53933d47d53157ed6d96d864cb208597e62dce26235ace09d1063427fa2 EMU_IMAGE: kkemu-ci jobs: @@ -50,7 +50,7 @@ jobs: timeout-minutes: 3 steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 with: ref: ${{ github.event.pull_request.head.sha || github.sha }} @@ -83,7 +83,7 @@ jobs: timeout-minutes: 2 steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 with: ref: ${{ github.event.pull_request.head.sha || github.sha }} fetch-depth: 0 @@ -104,7 +104,7 @@ jobs: timeout-minutes: 15 steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 with: ref: ${{ github.event.pull_request.head.sha || github.sha }} submodules: false @@ -171,7 +171,7 @@ jobs: echo "cppcheck: clean — zero findings" - name: Upload cppcheck report - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 if: always() with: name: cppcheck-report @@ -183,7 +183,7 @@ jobs: timeout-minutes: 2 steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 with: ref: ${{ github.event.pull_request.head.sha || github.sha }} @@ -208,12 +208,44 @@ jobs: done [ "$FAILED" = "0" ] || exit 1 + - name: Enforce RC18 security invariants + run: | + if grep -REn \ + 'uses:[[:space:]]+[^#[:space:]]+@(v[0-9]+|main|master)([[:space:]#]|$)' \ + .github/workflows; then + echo "::error::Every GitHub Action must be pinned to a full commit SHA" + exit 1 + fi + if grep -REn 'kktech/firmware:v[0-9]+' \ + .github/workflows scripts/build/docker scripts/emulator; then + echo "::error::The firmware builder must be pinned by manifest digest" + exit 1 + fi + if grep -En 'return[[:space:]]+random\(\)' lib/rand/rng.c; then + echo "::error::Emulator cryptography must not use libc random()" + exit 1 + fi + if grep -REn \ + 'storage_(get|upsert)ClearsignIdentity|persistent_identity_for' \ + lib include; then + echo "::error::Unauthenticated persistent clearsign trust is retired" + exit 1 + fi + if cmake -S . -B /tmp/orchard-release-gate \ + -DKK_ZCASH_PRIVACY=ON > /tmp/orchard-release-gate.log 2>&1; then + cat /tmp/orchard-release-gate.log + echo "::error::Orchard release gate unexpectedly allowed a build" + exit 1 + fi + grep -q 'requires a reviewed constant-time Pallas backend' \ + /tmp/orchard-release-gate.log + crypto-tests: runs-on: ubuntu-latest timeout-minutes: 10 steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 with: ref: ${{ github.event.pull_request.head.sha || github.sha }} @@ -249,8 +281,8 @@ jobs: fail-fast: false matrix: include: - # Regular/full includes every supported chain, including Zcash - # shielded/Orchard. Bitcoin-only is the sole reduced build. + # Regular/full is multi-chain with transparent Zcash. Orchard is + # release-blocked; bitcoin-only is the sole reduced build. - variant: full label: "" cmake_flags: "" @@ -259,7 +291,7 @@ jobs: cmake_flags: "-DKK_BITCOIN_ONLY=ON" steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 with: ref: ${{ github.event.pull_request.head.sha || github.sha }} @@ -272,11 +304,11 @@ jobs: git submodule update --init deps/sca-hardening/SecAESSTM32 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v4 + uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4 - name: Cache base image id: cache-base - uses: actions/cache@v5 + uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5 with: path: /tmp/base-image.tar key: base-image-${{ env.BASE_IMAGE }} @@ -303,7 +335,7 @@ jobs: run: docker save ${{ env.EMU_IMAGE }}-${{ matrix.variant }} -o /tmp/emu-image.tar - name: Upload emulator image artifact - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: emu-image-${{ matrix.variant }} path: /tmp/emu-image.tar @@ -326,7 +358,7 @@ jobs: cmake_flags: "-DKK_BITCOIN_ONLY=ON" steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 with: ref: ${{ github.event.pull_request.head.sha || github.sha }} @@ -340,7 +372,7 @@ jobs: - name: Cache base image id: cache-base - uses: actions/cache@v5 + uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5 with: path: /tmp/base-image.tar key: base-image-${{ env.BASE_IMAGE }} @@ -412,7 +444,7 @@ jobs: echo "::notice::Firmware v${{ steps.version.outputs.fw_version }} (${{ matrix.variant }}) built successfully" - name: Upload firmware artifacts - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: firmware-v${{ steps.version.outputs.fw_version }}-${{ steps.version.outputs.git_short }}-${{ matrix.variant }} path: | @@ -444,7 +476,7 @@ jobs: cmake_flags: "-DKK_BITCOIN_ONLY=ON" steps: - name: Download emulator image - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 with: name: emu-image-${{ matrix.variant }} path: /tmp @@ -466,7 +498,7 @@ jobs: exit \$RC" - name: Upload unit test results - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 if: always() with: name: unit-test-results-${{ matrix.variant }} @@ -479,7 +511,7 @@ jobs: timeout-minutes: 30 steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 with: ref: ${{ github.event.pull_request.head.sha || github.sha }} @@ -525,7 +557,7 @@ jobs: [ "$FW_RC" -eq 0 ] && [ "$PY_RC" -eq 0 ] || exit 1 - name: Upload Python test results - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 if: always() with: name: python-test-results @@ -533,7 +565,7 @@ jobs: retention-days: 30 - name: Upload OLED screenshots - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 if: always() with: name: oled-screenshots @@ -583,7 +615,7 @@ jobs: timeout-minutes: 25 steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 with: ref: ${{ github.event.pull_request.head.sha || github.sha }} @@ -599,7 +631,7 @@ jobs: git submodule update --init deps/googletest - name: Setup Python 3.10 - uses: actions/setup-python@v5 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 with: python-version: '3.10' @@ -706,7 +738,7 @@ jobs: # PR. Tagged with the short commit SHA so multiple PR pushes # don't overwrite each other when a reviewer downloads them. if: always() && env.DYLIB_PATH != '' - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: libkkemu-${{ github.sha }} path: ${{ env.DYLIB_PATH }} @@ -739,7 +771,7 @@ jobs: -v --tb=short --junit-xml=../../../test-reports/dylib-junit.xml - name: Upload dylib test results - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 if: always() with: name: python-dylib-test-results @@ -758,12 +790,12 @@ jobs: timeout-minutes: 5 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 with: ref: ${{ github.event.pull_request.head.sha || github.sha }} - name: Download unit test results - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 continue-on-error: true with: # Report covers the regular/full build. Bitcoin-only is built and @@ -772,14 +804,14 @@ jobs: path: test-reports/firmware-unit/ - name: Download python test results - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 continue-on-error: true with: name: python-test-results path: test-reports/python-keepkey/ - name: Download OLED screenshots - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 continue-on-error: true with: name: oled-screenshots @@ -801,7 +833,7 @@ jobs: run: python3 scripts/generate-test-report.py - name: Upload test report - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 if: always() with: name: test-report @@ -821,14 +853,14 @@ jobs: timeout-minutes: 10 steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 with: ref: ${{ github.event.pull_request.head.sha || github.sha }} - name: Download emulator image - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 with: - # Publish the regular/full image, including Zcash privacy support. + # Publish the regular/full image. Orchard is release-blocked. name: emu-image-full path: /tmp @@ -848,7 +880,7 @@ jobs: docker tag ${{ env.EMU_IMAGE }}-full kktech/kkemu:v${{ steps.version.outputs.fw_version }} - name: Login to DockerHub - uses: docker/login-action@v4 + uses: docker/login-action@abd2ef45e78c5afb21d64d4ca52ee8550d9572c7 # v4 with: username: ${{ secrets.KK_DOCKERHUB_USER }} password: ${{ secrets.KK_DOCKERHUB_PASS }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index dffe07f07..b1ba08c07 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,7 @@ on: - 'v*' env: - BASE_IMAGE: kktech/firmware:v15 + BASE_IMAGE: kktech/firmware@sha256:7438e53933d47d53157ed6d96d864cb208597e62dce26235ace09d1063427fa2 permissions: contents: write @@ -32,7 +32,7 @@ jobs: tag_name: ${{ steps.version.outputs.tag_name }} is_prerelease: ${{ steps.version.outputs.is_prerelease }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - name: Extract and verify version id: version @@ -92,7 +92,7 @@ jobs: - variant: bitcoin-only cmake_flags: "-DKK_BITCOIN_ONLY=ON" steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - name: Init required submodules run: | @@ -104,7 +104,7 @@ jobs: - name: Cache base image id: cache-base - uses: actions/cache@v5 + uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5 with: path: /tmp/base-image.tar key: base-image-${{ env.BASE_IMAGE }} @@ -177,8 +177,24 @@ jobs: mv HASHES.txt "HASHES-${VARIANT}.txt" ls -lh + - name: Record build provenance + working-directory: release + run: | + VARIANT="${{ matrix.variant }}" + { + echo "firmware_commit=${GITHUB_SHA}" + echo "source_repository=${GITHUB_REPOSITORY}" + echo "source_ref=${GITHUB_REF}" + echo "workflow_ref=${GITHUB_WORKFLOW_REF}" + echo "builder_image=${BASE_IMAGE}" + echo "runner_image=${ImageOS:-unknown}" + echo "variant=${VARIANT}" + echo "cmake_flags=${{ matrix.cmake_flags }}" + } > "PROVENANCE-${VARIANT}.txt" + cat "PROVENANCE-${VARIANT}.txt" + - name: Upload release artifacts - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: release-firmware-${{ matrix.variant }} path: release/* @@ -197,7 +213,7 @@ jobs: - variant: bitcoin-only cmake_flags: "-DKK_BITCOIN_ONLY=ON" steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - name: Init required submodules run: | @@ -209,7 +225,7 @@ jobs: - name: Cache base image id: cache-base - uses: actions/cache@v5 + uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5 with: path: /tmp/base-image.tar key: base-image-${{ env.BASE_IMAGE }} @@ -237,10 +253,10 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 5 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - name: Download firmware artifacts - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 with: pattern: release-firmware-* path: artifacts @@ -249,7 +265,8 @@ jobs: - name: Prepare release assets run: | mkdir -p release-assets - cp artifacts/*.bin artifacts/*.elf artifacts/HASHES-*.txt release-assets/ + cp artifacts/*.bin artifacts/*.elf artifacts/HASHES-*.txt \ + artifacts/PROVENANCE-*.txt release-assets/ ls -lh release-assets/ - name: Generate release body @@ -259,7 +276,7 @@ jobs: ## KeepKey Firmware ${{ needs.validate.outputs.tag_name }} ### Variants - - **full (regular)** — \`firmware.keepkey.v${VER}-full.bin\` — all supported chains, including Zcash shielded/Orchard + - **full (regular)** — \`firmware.keepkey.v${VER}-full.bin\` — all supported chains; Zcash transparent only (Orchard release-blocked pending a reviewed constant-time backend) - **bitcoin-only** — \`firmware.keepkey.v${VER}-bitcoin-only.bin\` — BTC-only, non-BTC coins stripped ### Reproducible Build Verification @@ -285,7 +302,7 @@ jobs: EOF - name: Create draft release - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2 with: draft: true prerelease: ${{ needs.validate.outputs.is_prerelease }} diff --git a/CMakeLists.txt b/CMakeLists.txt index be14c23c2..711bcc42b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,15 +21,19 @@ option(KK_BUILD_DYLIB "Build libkkemu shared library (.dylib/.so)" OFF) option(KK_DEBUG_LINK "Build with debug-link enabled" OFF) option(KK_BUILD_FUZZERS "Build the fuzzers?" OFF) option(KK_BITCOIN_ONLY "Build Bitcoin-only firmware (strip all non-BTC coins)" OFF) -# Zcash shielded/Orchard support is part of the regular firmware. It is an -# internal compile selection, not a third release variant: bitcoin-only strips -# the Zcash coin and privacy engine; every regular device/emulator build ships -# both. Keep the value macro below so bitcoin-only can compile the sources out. -if(KK_BITCOIN_ONLY) - set(KK_ZCASH_PRIVACY OFF) -else() - set(KK_ZCASH_PRIVACY ON) +# RC18 release gate: the vendored Pallas scalar-multiplication path is variable +# time and is reached with Orchard spending secrets. Do not expose that path in +# any firmware or emulator build until it has been replaced by an independently +# reviewed constant-time backend. Transparent Zcash remains in the regular +# multi-chain firmware and does not depend on this engine. +option(KK_ZCASH_PRIVACY "Build the disabled Orchard privacy engine" OFF) +if(KK_ZCASH_PRIVACY) + message( + FATAL_ERROR + "KK_ZCASH_PRIVACY is release-blocked: Orchard requires a reviewed constant-time Pallas backend" + ) endif() +set(KK_ZCASH_PRIVACY OFF) # When building the dylib, every static lib it links (kkfirmware, kkboard, # trezorcrypto, kkrand, kktransport, qrcodegenerator, SecAESSTM32, ...) must @@ -148,9 +152,8 @@ add_definitions(-DBIP39_WORDLIST_PADDED=1) add_definitions(-DAES_128=1) -# NOTE: AES table size is selected per release product below. The regular -# image includes Zcash and its Pallas curve arithmetic, so it uses the smaller -# AES tables to preserve flash headroom. Bitcoin-only keeps FOUR_TABLES AES. +# NOTE: AES table size was previously selected for the Orchard image. RC18 has +# no Orchard image, so both shipped variants use the normal FOUR_TABLES AES. if(${KK_DEBUG_LINK}) add_definitions(-DDEBUG_LINK=1) @@ -168,10 +171,6 @@ endif() if(${KK_ZCASH_PRIVACY}) add_definitions(-DZCASH_PRIVACY=1) - # The Orchard engine leaves the regular image tightest on flash; shrink the - # Gladman AES lookup tables from 4KB to 1KB each (-15,360 bytes ROM, - # slightly slower AES). Bitcoin-only keeps the fast FOUR_TABLES. - add_definitions(-DAES_SMALL_TABLES) else() add_definitions(-DZCASH_PRIVACY=0) endif() diff --git a/deps/device-protocol b/deps/device-protocol index 47e19d8b0..e31cddfe7 160000 --- a/deps/device-protocol +++ b/deps/device-protocol @@ -1 +1 @@ -Subproject commit 47e19d8b0816db20e15d9b1e27da83c70d5ed88d +Subproject commit e31cddfe7f5c72c983d06a889ac7db649b9811df diff --git a/deps/python-keepkey b/deps/python-keepkey index 892ae04ff..9ce1aeb48 160000 --- a/deps/python-keepkey +++ b/deps/python-keepkey @@ -1 +1 @@ -Subproject commit 892ae04ff3cefea5f57c516e7f796bf1939eb810 +Subproject commit 9ce1aeb480333176b3ed098066f51b22fd40a9d7 diff --git a/docs/security/7.15.0-rc18-release-shape.md b/docs/security/7.15.0-rc18-release-shape.md index d63fae18d..37ed95558 100644 --- a/docs/security/7.15.0-rc18-release-shape.md +++ b/docs/security/7.15.0-rc18-release-shape.md @@ -1,25 +1,26 @@ # Firmware 7.15.0 RC18 Release Shape -Date: 2026-07-24 +Date: 2026-07-25 RC18 collapses the former three-product build into two release products: | Product | Contents | | --- | --- | -| Regular (`full`) | Every supported chain, including Zcash shielded/Orchard | +| Regular (`full`) | Every supported chain; Zcash transparent only | | Bitcoin-only | Bitcoin only; all non-Bitcoin coins and Zcash privacy code removed | -There is no separate `zcash-privacy` artifact. Zcash privacy is part of the -regular firmware and cannot be disabled as a release choice. The internal -`ZCASH_PRIVACY` compile value remains only so bitcoin-only can compile the -privacy sources out. +There is no separate `zcash-privacy` artifact. RC18 release-blocks the Orchard +engine in every build because its Pallas secret-scalar path is variable-time. +`-DKK_ZCASH_PRIVACY=ON` fails configuration until that path is replaced by an +independently reviewed constant-time backend. Transparent Zcash remains in the +regular firmware. ## Release and CI invariants - Device, emulator, unit-test, SRAM, and tagged-release matrices contain only `full` and `bitcoin-only`. - An unflagged CMake build is the regular product and sets - `BITCOIN_ONLY=0`, `ZCASH_PRIVACY=1`, and `AES_SMALL_TABLES`. + `BITCOIN_ONLY=0` and `ZCASH_PRIVACY=0`. - `-DKK_BITCOIN_ONLY=ON` sets `BITCOIN_ONLY=1` and `ZCASH_PRIVACY=0`. - The published emulator is the regular/full image. - Release notes and reproducible-build instructions name only the regular and @@ -27,17 +28,27 @@ privacy sources out. ## Automated evidence -Both ARM builds used the pinned `kktech/firmware:v15` toolchain image. +Both ARM builds use the toolchain image pinned by manifest digest in CI and the +release workflow. Each release artifact set includes its exact builder digest +and source/workflow identity in `PROVENANCE-.txt`. | Product | ARM build | Firmware tests | Board tests | Crypto tests | SRAM reserve | Largest frame | Reserve after frame | | --- | --- | ---: | ---: | ---: | ---: | ---: | ---: | -| Regular (`full`) | Pass | 363/363 | 2/2 | 4/4 | 19,064 B | 7,664 B | 11,400 B | -| Bitcoin-only | Pass | 28/28 | 2/2 | 4/4 | 32,908 B | 7,664 B | 25,244 B | +| Regular (`full`) | Pass | 307/307 | 2/2 | 4/4 | 23,364 B | 7,664 B | 15,700 B | +| Bitcoin-only | Pass | 30/30 | 2/2 | 4/4 | 32,908 B | 7,664 B | 25,244 B | -The regular ARM build produced `zcash.c.obj`; the bitcoin-only build did not. -Both products pass the 16,384-byte minimum SRAM reserve and 4,096-byte +Neither release build compiles the Orchard privacy engine. Both products pass +the 16,384-byte minimum SRAM reserve and 4,096-byte reserve-after-largest-frame gates. +The canonical full-image integration rehearsal used device-protocol +`e31cddfe7f5c72c983d06a889ac7db649b9811df` and python-keepkey +`9ce1aeb480333176b3ed098066f51b22fd40a9d7`. Its JUnit result was 592 tests: +560 passed, 32 intentionally skipped, 0 failed, and 0 errors. Both the +host-side and raw-device persistence rejection tests passed, and the +report-driven run captured 898 OLED screenshots. Orchard-specific cases skip +because RC18 does not advertise those handlers; transparent Zcash tests pass. + Workflow YAML parsing, SRAM-budget JSON parsing, Python syntax compilation, `git diff --check`, and the release-shape search for stale `zcash-privacy` matrix entries also pass. diff --git a/include/keepkey/firmware/signed_metadata.h b/include/keepkey/firmware/signed_metadata.h index 0f50a32ca..4029b7bad 100644 --- a/include/keepkey/firmware/signed_metadata.h +++ b/include/keepkey/firmware/signed_metadata.h @@ -125,18 +125,17 @@ bool signed_metadata_signer_valid(uint8_t key_id, const uint8_t* pubkey, * first — this function is the post-consent write, nothing more. * * icon (optional, icon_len<=384, 1bpp mono RLE) is kept as the session icon for - * the slot; icon_len==0 => text-only identity. When persist=true the signer - * (incl. icon) is ALSO written to flash so it survives reboot. Returns false - * only when persist was requested but every persistent slot is occupied by a - * different identity — the RAM (session) signer is stored regardless. */ + * the slot; icon_len==0 => text-only identity. RC18 rejects persist=true before + * changing the session slot because public storage lacks authenticated + * integrity. */ bool signed_metadata_store_signer(uint8_t key_id, const uint8_t* pubkey, const char* alias, const uint8_t* icon, uint8_t icon_w, uint8_t icon_h, uint16_t icon_len, bool persist); -/* Resolve a slot's alias / icon from the RAM session copy, else a persisted - * identity that survived reboot. alias returns NULL and icon returns false when - * the slot has no signer / no icon (text-only). Used by the per-tx confirm. */ +/* Resolve a slot's alias / icon from the RAM session copy. alias returns NULL + * and icon returns false when the slot has no signer / no icon (text-only). + * Used by the per-tx confirm. */ const char* signed_metadata_signer_alias(uint8_t key_id); bool signed_metadata_signer_icon(uint8_t key_id, const uint8_t** icon_out, uint8_t* w_out, uint8_t* h_out, @@ -147,8 +146,7 @@ bool signed_metadata_signer_icon(uint8_t key_id, const uint8_t** icon_out, * handler calls this before storing the signer. */ bool signed_metadata_confirm_load(const char* alias, const char* fingerprint, const uint8_t* icon, uint8_t icon_w, - uint8_t icon_h, uint16_t icon_len, - bool persist); + uint8_t icon_h, uint16_t icon_len); /* Drop all runtime-loaded signers (and any metadata they verified). */ void signed_metadata_clear_signers(void); diff --git a/lib/board/draw.c b/lib/board/draw.c index 6b94907fc..14c2a070f 100644 --- a/lib/board/draw.c +++ b/lib/board/draw.c @@ -292,7 +292,7 @@ void draw_box_simple(Canvas* canvas, uint8_t color, uint16_t x, uint16_t y, * writes nothing. The drawing path below stops as soon as the canvas is full, * so it cannot tell a well-formed stream from one whose last run straddles the * image or that carries trailing packets. Host-supplied icons must be checked - * here, at the trust boundary, before they are shown or persisted. + * here, at the trust boundary, before they are shown or cached for a session. */ bool draw_bitmap_mono_rle_valid(const uint8_t* data, uint32_t length, uint16_t w, uint16_t h) { diff --git a/lib/emulator/setup.c b/lib/emulator/setup.c index 69b9a65dd..8ae69febe 100644 --- a/lib/emulator/setup.c +++ b/lib/emulator/setup.c @@ -70,16 +70,31 @@ void emulatorRandom(void* buffer, size_t size) { exit(1); } #else - ssize_t n = read(urandom, buffer, size); - if (n < 0 || ((size_t)n) != size) { - perror("Failed to read /dev/urandom"); - exit(1); + if (urandom < 0) { + setup_urandom(); + } + unsigned char* out = (unsigned char*)buffer; + size_t remaining = size; + while (remaining > 0) { + ssize_t n = read(urandom, out, remaining); + if (n < 0 && errno == EINTR) { + continue; + } + if (n <= 0) { + perror("Failed to read /dev/urandom"); + exit(1); + } + out += (size_t)n; + remaining -= (size_t)n; } #endif } static void setup_urandom(void) { #ifndef _WIN32 + if (urandom >= 0) { + return; + } urandom = open("/dev/urandom", O_RDONLY); if (urandom < 0) { perror("Failed to open /dev/urandom"); diff --git a/lib/firmware/fsm_msg_ethereum.h b/lib/firmware/fsm_msg_ethereum.h index 643d652db..00c7ca6c6 100644 --- a/lib/firmware/fsm_msg_ethereum.h +++ b/lib/firmware/fsm_msg_ethereum.h @@ -93,9 +93,7 @@ void fsm_msgLoadClearsignSigner(const LoadClearsignSigner* msg) { * host-supplied icon would paint over the alias, fingerprint and the * "NOT verified by KeepKey" warning — on the very screen that exists to * carry that warning. This is the trust boundary for icons arriving on the - * wire; icons READ BACK from flash are re-checked independently in - * signed_metadata_signer_icon(), since a record persisted by older firmware - * never passes through here again after a reboot. */ + * wire; signed_metadata_signer_icon() rechecks the session copy at use. */ CHECK_PARAM(msg->has_icon_width && msg->has_icon_height && msg->icon_width > 0 && msg->icon_width <= LEFT_MARGIN_WITH_ICON && @@ -103,10 +101,11 @@ void fsm_msgLoadClearsignSigner(const LoadClearsignSigner* msg) { _("icon dimensions out of range")); /* Reject a malformed RLE stream HERE rather than discovering it at draw * time. The render path returns a bool that layout_add_icon() discards, so - * an undecodable icon would otherwise show no logo, still return Success, - * and be persisted to flash — the user consents to an identity whose logo - * silently does not exist. Validation is exact (every packet well-formed, - * no run straddling the image, whole input consumed) and side-effect-free. + * an undecodable icon would otherwise show no logo while still returning + * Success — the user would consent to an identity + * whose logo silently does not exist. Validation is exact (every packet + * well-formed, no run straddling the image, whole input consumed) and + * side-effect-free. */ CHECK_PARAM(draw_bitmap_mono_rle_valid( msg->icon.bytes, (uint32_t)msg->icon.size, @@ -118,15 +117,15 @@ void fsm_msgLoadClearsignSigner(const LoadClearsignSigner* msg) { icon_h = (uint8_t)msg->icon_height; } bool persist = msg->has_persist && msg->persist; + CHECK_PARAM(!persist, _("Persistent clearsign signers are disabled")); /* Mandatory on-device consent — leads with the identity's logo (if any) + * alias + fingerprint. The whole trust model hangs on this confirm; the same - * fingerprint reappears on every per-tx identity screen. persist makes the - * trust anchor durable across reboots, so it's called out. */ + * fingerprint reappears on every per-tx identity screen. */ char fingerprint[METADATA_FINGERPRINT_LEN]; signed_metadata_pubkey_fingerprint(msg->pubkey.bytes, fingerprint); if (!signed_metadata_confirm_load(msg->alias, fingerprint, icon, icon_w, - icon_h, icon_len, persist)) { + icon_h, icon_len)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Load clearsign signer cancelled")); layoutHome(); @@ -136,10 +135,8 @@ void fsm_msgLoadClearsignSigner(const LoadClearsignSigner* msg) { if (!signed_metadata_store_signer((uint8_t)msg->key_id, msg->pubkey.bytes, msg->alias, icon, icon_w, icon_h, icon_len, persist)) { - /* Session signer stored, but no persistent slot was free. Tell the truth - * rather than silently keeping it RAM-only under a persist request. */ fsm_sendFailure(FailureType_Failure_Other, - _("No free persistent identity slot — wipe an old one")); + _("Clearsign signer could not be loaded")); layoutHome(); return; } diff --git a/lib/firmware/signed_metadata.c b/lib/firmware/signed_metadata.c index cbb95a3f9..d71ff6430 100644 --- a/lib/firmware/signed_metadata.c +++ b/lib/firmware/signed_metadata.c @@ -1,6 +1,5 @@ #include "keepkey/firmware/signed_metadata.h" -#include "storage.h" // ClearsignIdentity + persistent-slot accessors #include "keepkey/board/confirm_sm.h" #include "keepkey/board/draw.h" // draw_bitmap_mono_rle_valid #include "keepkey/board/layout.h" // RUNTIME_ICON + layout_set_runtime_icon @@ -33,36 +32,16 @@ static SignedMetadata stored_metadata; * loaded at runtime via LoadClearsignSigner. Phase 2 restores the production * key. */ -/* Runtime-loaded signers. RAM only — cleared on reboot by construction. - * A signer loaded with persist=true is ALSO written to flash (V18 storage) and - * reconsulted after reboot via storage_getClearsignIdentity(). The RAM slot is - * the session working copy; the flash slot is the durable trust anchor. */ +/* Runtime-loaded signers. RAM only — cleared on reboot by construction. RC18 + * deliberately rejects persistent trust anchors: the public storage section + * has no authenticated integrity against physical flash modification. */ static uint8_t loaded_pubkeys[METADATA_MAX_KEYS][33]; static char loaded_aliases[METADATA_MAX_KEYS][METADATA_ALIAS_MAX_LEN + 1]; /* Per-slot session icon (1bpp mono RLE). icon_len==0 => text-only identity. */ -_Static_assert(CLEARSIGN_ICON_MAX == METADATA_ICON_MAX, - "storage icon cap must match the clearsign icon cap"); -#if !ZCASH_PRIVACY -/* Session icon cache for ephemeral (RAM-only) signers. The zcash-privacy - * variant compiles this out to fit SRAM (the Orchard engine leaves it the - * tightest variant): ephemeral signers render text-only there, while - * PERSISTENT identity icons still render straight from the storage shadow. - * Hosts detect this from firmware_variant (KeepKeyZcash/EmulatorZcash). */ -static uint8_t loaded_icons[METADATA_MAX_KEYS][CLEARSIGN_ICON_MAX]; +static uint8_t loaded_icons[METADATA_MAX_KEYS][METADATA_ICON_MAX]; static uint8_t loaded_icon_w[METADATA_MAX_KEYS]; static uint8_t loaded_icon_h[METADATA_MAX_KEYS]; static uint16_t loaded_icon_len[METADATA_MAX_KEYS]; -#endif - -/* Find the persistent identity that reloads into `key_id`, or NULL. */ -static const ClearsignIdentity* persistent_identity_for(uint8_t key_id) { - int n = storage_clearsignIdentityCount(); - for (int i = 0; i < n; i++) { - const ClearsignIdentity* id = storage_getClearsignIdentity(i); - if (id && id->key_id == key_id) return id; - } - return NULL; -} static bool read_u8(const uint8_t** cursor, const uint8_t* end, uint8_t* out) { if ((size_t)(end - *cursor) < 1) { @@ -423,15 +402,11 @@ void signed_metadata_clear(void) { void signed_metadata_clear_signers(void) { memzero(loaded_pubkeys, sizeof(loaded_pubkeys)); memzero(loaded_aliases, sizeof(loaded_aliases)); -#if !ZCASH_PRIVACY memzero(loaded_icons, sizeof(loaded_icons)); memzero(loaded_icon_w, sizeof(loaded_icon_w)); memzero(loaded_icon_h, sizeof(loaded_icon_h)); memzero(loaded_icon_len, sizeof(loaded_icon_len)); -#endif - /* Metadata verified by a now-dropped signer must not outlive it. NB: this - * clears only the RAM session copies; persisted identities live in flash and - * are cleared by WipeDevice, not here. */ + /* Metadata verified by a now-dropped signer must not outlive it. */ signed_metadata_clear(); } @@ -476,7 +451,10 @@ bool signed_metadata_store_signer(uint8_t key_id, const uint8_t* pubkey, const char* alias, const uint8_t* icon, uint8_t icon_w, uint8_t icon_h, uint16_t icon_len, bool persist) { - if (key_id >= METADATA_MAX_KEYS) { + /* Fail before changing the RAM slot. A caller asking for persistence must + * never receive a session-only downgrade it could mistake for durable trust. + * Persistence can return only after authenticated storage binding exists. */ + if (persist || key_id >= METADATA_MAX_KEYS) { return false; } memcpy(loaded_pubkeys[key_id], pubkey, sizeof(loaded_pubkeys[key_id])); @@ -484,12 +462,9 @@ bool signed_metadata_store_signer(uint8_t key_id, const uint8_t* pubkey, /* A load without an icon clears any prior one for the slot (icon_len * already validated <= max by the caller — belt-and-braces here). */ - bool has_icon = icon && icon_len > 0 && icon_len <= CLEARSIGN_ICON_MAX; + bool has_icon = icon && icon_len > 0 && icon_len <= METADATA_ICON_MAX; -#if !ZCASH_PRIVACY - /* Session icon into the RAM working slot. The zcash-privacy variant has no - * session icon cache (SRAM); persist below still stores the icon bytes, so - * persistent identities keep their logo across variants. */ + /* Session icon into the RAM working slot. */ memzero(loaded_icons[key_id], sizeof(loaded_icons[key_id])); if (has_icon) { memcpy(loaded_icons[key_id], icon, icon_len); @@ -501,51 +476,27 @@ bool signed_metadata_store_signer(uint8_t key_id, const uint8_t* pubkey, loaded_icon_h[key_id] = 0; loaded_icon_len[key_id] = 0; } -#endif - - bool persisted = true; - if (persist) { - ClearsignIdentity id; - memzero(&id, sizeof(id)); - id.present = true; - id.key_id = key_id; - memcpy(id.pubkey, pubkey, sizeof(id.pubkey)); - strlcpy(id.alias, alias, sizeof(id.alias)); - if (has_icon) { - id.icon_w = icon_w; - id.icon_h = icon_h; - id.icon_len = icon_len; - memcpy(id.icon, icon, icon_len); - } - persisted = storage_upsertClearsignIdentity(&id); - memzero(&id, sizeof(id)); - } /* Replacing a signer invalidates anything the old one verified. */ signed_metadata_clear(); - return persisted; + return true; } -/* Resolve the alias for a slot (RAM working copy, else a persisted identity). - * Returns NULL if the slot has no loaded/persisted signer. */ +/* Resolve the alias for a session slot. */ const char* signed_metadata_signer_alias(uint8_t key_id) { if (key_id >= METADATA_MAX_KEYS) return NULL; if (loaded_pubkeys[key_id][0] != 0x00) return loaded_aliases[key_id]; - const ClearsignIdentity* pid = persistent_identity_for(key_id); - return pid ? pid->alias : NULL; + return NULL; } -/* Resolve the icon for a slot (RAM working copy, else a persisted identity). - * Returns false when the slot has no icon (text-only identity). */ +/* Resolve the icon for a session slot. Returns false for a text-only slot. */ /* An icon is renderable only if its geometry fits the confirm's icon column * AND its RLE stream decodes exactly to that geometry. This is the single - * choke point for STORED icons: signed_metadata_signer_icon() is what both the + * choke point for session icons: signed_metadata_signer_icon() is what both the * load-confirm and the per-tx identity screen call, and the per-tx screen - * stages the frame itself (it never goes through stage_runtime_icon), so - * validating in the staging helper alone would leave that path — and every - * legacy flash record — unchecked. Fail closed to a text-only identity: a - * missing logo is cosmetic, an over-wide one erases the alias, fingerprint and - * the "NOT verified by KeepKey" warning. */ + * stages the frame itself (it never goes through stage_runtime_icon). Fail + * closed to a text-only identity: a missing logo is cosmetic, an over-wide one + * erases the alias, fingerprint and the "NOT verified by KeepKey" warning. */ static bool icon_renderable(const uint8_t* icon, uint16_t icon_len, uint8_t icon_w, uint8_t icon_h) { if (!icon || icon_len == 0) return false; @@ -559,12 +510,6 @@ bool signed_metadata_signer_icon(uint8_t key_id, const uint8_t** icon_out, uint16_t* len_out) { if (key_id >= METADATA_MAX_KEYS) return false; if (loaded_pubkeys[key_id][0] != 0x00) { -#if ZCASH_PRIVACY - /* No session icon cache in this variant — an ephemeral signer renders - * text-only. It must NOT fall through to the persistent slot below: that - * would put a different identity's logo on this signer's screens. */ - return false; -#else if (loaded_icon_len[key_id] == 0) return false; if (!icon_renderable(loaded_icons[key_id], loaded_icon_len[key_id], loaded_icon_w[key_id], loaded_icon_h[key_id])) { @@ -575,21 +520,8 @@ bool signed_metadata_signer_icon(uint8_t key_id, const uint8_t** icon_out, if (h_out) *h_out = loaded_icon_h[key_id]; if (len_out) *len_out = loaded_icon_len[key_id]; return true; -#endif - } - const ClearsignIdentity* pid = persistent_identity_for(key_id); - if (!pid || pid->icon_len == 0) return false; - /* Flash records predate the geometry/encoding rules and are NOT re-validated - * by the load handler after a reboot, so an identity persisted by older - * firmware can carry a 41-64px or malformed icon. Check it here. */ - if (!icon_renderable(pid->icon, pid->icon_len, pid->icon_w, pid->icon_h)) { - return false; } - if (icon_out) *icon_out = pid->icon; - if (w_out) *w_out = pid->icon_w; - if (h_out) *h_out = pid->icon_h; - if (len_out) *len_out = pid->icon_len; - return true; + return false; } /* Render an AnimationFrame from a stored icon into the confirm's left column. @@ -603,11 +535,9 @@ static IconType stage_runtime_icon(Image* img, AnimationFrame* frame, /* Fail closed on an over-wide icon rather than drawing it at x=0: text begins * at x=40 and the icon is drawn AFTER the text, so a wider icon would paint * over the alias, fingerprint and the "NOT verified by KeepKey" warning. - * fsm_msgLoadClearsignSigner already rejects width > LEFT_MARGIN_WITH_ICON, - * but an icon persisted to flash by older firmware re-enters here straight - * from storage without passing that check — so enforce it again at the point - * of use. Dropping the logo degrades to a text-only identity; letting it - * erase the warning does not. */ + * The load handler already checks this, but enforce it again at the point of + * use. Dropping the logo degrades to a text-only identity; letting it erase + * the warning does not. */ if (icon_w == 0 || icon_w > LEFT_MARGIN_WITH_ICON || icon_h == 0 || icon_h > 64) { return NO_ICON; @@ -630,8 +560,7 @@ static IconType stage_runtime_icon(Image* img, AnimationFrame* frame, bool signed_metadata_confirm_load(const char* alias, const char* fingerprint, const uint8_t* icon, uint8_t icon_w, - uint8_t icon_h, uint16_t icon_len, - bool persist) { + uint8_t icon_h, uint16_t icon_len) { Image icon_img; AnimationFrame icon_frame; IconType id_icon = stage_runtime_icon(&icon_img, &icon_frame, icon, icon_w, @@ -642,9 +571,9 @@ bool signed_metadata_confirm_load(const char* alias, const char* fingerprint, /* Lead with the identity (its logo + alias + fingerprint). The trust model * hangs on this consent; the fingerprint reappears on every per-tx screen. */ snprintf(body, sizeof(body), - "Trust '%s' (%s) to describe transactions?%s NOT verified by " - "KeepKey.", - alias, fingerprint, persist ? " Kept until wiped." : ""); + "Trust '%s' (%s) for this session to describe transactions? NOT " + "verified by KeepKey.", + alias, fingerprint); bool ok = confirm_with_icon(ButtonRequestType_ButtonRequest_Other, id_icon, _("Load Clearsigner"), "%s", body); layout_set_runtime_icon(NULL); @@ -673,13 +602,6 @@ static const uint8_t* metadata_pubkey_for(uint8_t key_id, bool* is_loaded) { *is_loaded = true; return loaded_pubkeys[key_id]; } - /* Not in a RAM slot this session — fall back to a persisted identity that - * survived reboot. (A fresh load into the same slot supersedes it above.) */ - const ClearsignIdentity* pid = persistent_identity_for(key_id); - if (pid) { - *is_loaded = true; - return pid->pubkey; - } return NULL; } diff --git a/lib/firmware/storage.c b/lib/firmware/storage.c index a4b4a3a0d..546b51aef 100644 --- a/lib/firmware/storage.c +++ b/lib/firmware/storage.c @@ -199,18 +199,6 @@ static void write_u32_le(char* ptr, uint32_t val) { ptr[3] = (val >> 24) & 0xff; } -/* Cast each byte through uint8_t first: on the emulator (signed char) a raw - * (uint16_t)ptr[i] would sign-extend a 0x80+ low byte (icon_len reaches 384). - */ -static uint16_t read_u16_le(const char* ptr) { - return (uint16_t)((uint8_t)ptr[0]) | ((uint16_t)((uint8_t)ptr[1]) << 8); -} - -static void write_u16_le(char* ptr, uint16_t val) { - ptr[0] = val & 0xff; - ptr[1] = (val >> 8) & 0xff; -} - static bool read_bool(const char* ptr) { return *ptr; } static void write_bool(char* ptr, bool val) { *ptr = val ? 1 : 0; } @@ -1127,9 +1115,10 @@ void storage_readStorageV17(Storage* storage, const char* ptr, size_t len) { memcpy(storage->encrypted_sec, ptr + 1501, sizeof(storage->encrypted_sec)); } -// V18 appends the persistent clear-sign identities block immediately after the -// V17 encrypted_sec (which ends at ptr + 1501 + V17_ENCSEC_SIZE = ptr + 2525). -// Everything before it is the byte-identical V17 layout — never reorder it. +// V18 appended a clear-sign identity block immediately after encrypted_sec. +// RC18 retains the byte layout for compatibility but retires those records: +// public storage has no authenticated integrity, so they are zeroed on both +// read and write and are never consulted as trust anchors. // One identity serializes to CLEARSIGN_IDENTITY_SERIALIZED_LEN bytes: // +0 present(u8) +1 key_id(u8) +2 pubkey[33] +35 alias[32] +67 icon_w(u8) // +68 icon_h(u8) +69 icon_len(u16 le) +71 icon[CLEARSIGN_ICON_MAX] = 71+384 @@ -1138,42 +1127,14 @@ void storage_readStorageV17(Storage* storage, const char* ptr, size_t len) { void storage_writeStorageV18(char* ptr, size_t len, const Storage* storage) { storage_writeStorageV17(ptr, len, storage); - - for (int i = 0; i < PERSISTENT_IDENTITY_COUNT; i++) { - const ClearsignIdentity* id = &storage->pub.clearsign_identities[i]; - char* p = ptr + CLEARSIGN_IDENTITY_BLOCK_OFF + - (size_t)i * CLEARSIGN_IDENTITY_SERIALIZED_LEN; - write_u8(p + 0, id->present ? 1 : 0); - write_u8(p + 1, id->key_id); - memcpy(p + 2, id->pubkey, sizeof(id->pubkey)); // 33 - memcpy(p + 35, id->alias, sizeof(id->alias)); // 32 - write_u8(p + 67, id->icon_w); - write_u8(p + 68, id->icon_h); - write_u16_le(p + 69, id->icon_len); - memcpy(p + 71, id->icon, sizeof(id->icon)); // CLEARSIGN_ICON_MAX - } + memzero(ptr + CLEARSIGN_IDENTITY_BLOCK_OFF, + PERSISTENT_IDENTITY_COUNT * CLEARSIGN_IDENTITY_SERIALIZED_LEN); } void storage_readStorageV18(Storage* storage, const char* ptr, size_t len) { storage_readStorageV17(storage, ptr, len); - - for (int i = 0; i < PERSISTENT_IDENTITY_COUNT; i++) { - ClearsignIdentity* id = &storage->pub.clearsign_identities[i]; - const char* p = ptr + CLEARSIGN_IDENTITY_BLOCK_OFF + - (size_t)i * CLEARSIGN_IDENTITY_SERIALIZED_LEN; - id->present = read_u8(p + 0) != 0; - id->key_id = read_u8(p + 1); - memcpy(id->pubkey, p + 2, sizeof(id->pubkey)); - memcpy(id->alias, p + 35, sizeof(id->alias)); - id->alias[sizeof(id->alias) - 1] = - '\0'; // never trust flash to be NUL-term - id->icon_w = read_u8(p + 67); - id->icon_h = read_u8(p + 68); - id->icon_len = read_u16_le(p + 69); - if (id->icon_len > CLEARSIGN_ICON_MAX) - id->icon_len = 0; // corrupt => no icon - memcpy(id->icon, p + 71, sizeof(id->icon)); - } + memzero(storage->pub.clearsign_identities, + sizeof(storage->pub.clearsign_identities)); } void storage_readCacheV1(Cache* cache, const char* ptr, size_t len) { @@ -1636,7 +1597,7 @@ void storage_commit(void) { if (btc_only_locked) return; // Temporary storage for marshalling secrets in & out of flash. - // V18 storage layout = V17 (2525 bytes) + persistent identities block + // V18 storage layout = V17 (2525 bytes) + retired identity block // (PERSISTENT_IDENTITY_COUNT * CLEARSIGN_IDENTITY_SERIALIZED_LEN = 2*455 = // 910) = 3435; + meta (44) = 3479. Rounded up to a multiple of 4 (the CRC // below iterates uint32_t words) => 3480 (1 byte of slack). @@ -1839,45 +1800,6 @@ const char* storage_getLabel(void) { return shadow_config.storage.pub.label; } -// ── Persistent clear-sign identities (V18) ─────────────────────────────── - -int storage_clearsignIdentityCount(void) { return PERSISTENT_IDENTITY_COUNT; } - -const ClearsignIdentity* storage_getClearsignIdentity(int slot) { - if (slot < 0 || slot >= PERSISTENT_IDENTITY_COUNT) return NULL; - const ClearsignIdentity* id = - &shadow_config.storage.pub.clearsign_identities[slot]; - return id->present ? id : NULL; -} - -// Write an identity to a persistent slot and commit. Reuses the slot already -// holding this pubkey (re-load with a new icon/alias), else the first free -// slot. Returns false if all slots are taken by other identities (caller keeps -// the RAM-only signer working — persistence just didn't happen). -bool storage_upsertClearsignIdentity(const ClearsignIdentity* id) { - if (!id) return false; - int free_slot = -1; - int target = -1; - for (int i = 0; i < PERSISTENT_IDENTITY_COUNT; i++) { - const ClearsignIdentity* cur = - &shadow_config.storage.pub.clearsign_identities[i]; - if (cur->present && memcmp(cur->pubkey, id->pubkey, 33) == 0) { - target = i; - break; - } - if (!cur->present && free_slot < 0) free_slot = i; - } - if (target < 0) target = free_slot; - if (target < 0) return false; // no room - - ClearsignIdentity* dst = - &shadow_config.storage.pub.clearsign_identities[target]; - memcpy(dst, id, sizeof(*dst)); - dst->present = true; - storage_commit(); - return true; -} - void storage_setLanguage(const char* lang) { if (!lang) { return; diff --git a/lib/firmware/storage.h b/lib/firmware/storage.h index 220afa493..64be0671b 100644 --- a/lib/firmware/storage.h +++ b/lib/firmware/storage.h @@ -32,10 +32,10 @@ #define V16_ENCSEC_SIZE 512 // for reading old encrypted sec size #define V17_ENCSEC_SIZE 1024 -/* Persistent clear-sign identities (the "KeepKey + identity" trust anchors). - * A loaded signer whose LoadClearsignSigner carried persist=true is written to - * flash here so it survives reboot; RAM-only signers (signed_metadata.c) are - * unaffected. WipeDevice clears these along with the rest of storage. +/* Retired V18 clear-sign identity record. The fixed-size fields remain in the + * in-memory/storage layout for backward compatibility, but RC18 never trusts, + * returns, or writes their contents: this public section lacks authenticated + * integrity against physical flash modification. * pubkey : 33-byte compressed secp256k1 (matches signed_metadata slots) * alias : METADATA_ALIAS_MAX_LEN(31)+1, printable [A-Za-z0-9 _-] * icon : 1bpp mono row-major bitmap, <= CLEARSIGN_ICON_MAX bytes, @@ -95,8 +95,7 @@ typedef struct _Storage { bool authdata_encrypted; uint8_t random_salt[32]; uint8_t authdata_fingerprint[32]; - /* V18: persistent clear-sign identities. Zero-initialized (present=false) - * for wallets migrated up from V17 — no data loss. */ + /* V18 legacy clear-sign records. Always scrubbed on read and write. */ ClearsignIdentity clearsign_identities[PERSISTENT_IDENTITY_COUNT]; } pub; @@ -209,18 +208,6 @@ pintest_t session_clear_impl(SessionState* ss, Storage* storage, /// \returns NULL on error, otherwise \returns the private seed. const uint8_t* storage_getSeed(const ConfigFlash* cfg, bool usePassphrase); -/// \brief Number of persistent clear-sign identity slots. -int storage_clearsignIdentityCount(void); - -/// \brief The persistent clear-sign identity in `slot`, or NULL if empty/out -/// of range. Pointer into shadow storage — valid until the next commit. -const ClearsignIdentity* storage_getClearsignIdentity(int slot); - -/// \brief Persist a clear-sign identity (reuse its pubkey's slot, else the -/// first free one) and commit. Returns false if all slots are occupied -/// by other identities. -bool storage_upsertClearsignIdentity(const ClearsignIdentity* id); - typedef enum { SUS_Invalid, SUS_Valid, diff --git a/lib/rand/rng.c b/lib/rand/rng.c index 9e61f3e82..8f93faccb 100644 --- a/lib/rand/rng.c +++ b/lib/rand/rng.c @@ -21,20 +21,16 @@ #include "trezor/crypto/rand.h" +#ifdef EMULATOR +#include "keepkey/emulator/emulator.h" +#endif + #ifndef EMULATOR #include #include #include #endif -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN /* exclude winsock.h — it declares \ - shutdown(SOCKET,int) */ -#include -#include -#include -#endif - void reset_rng(void) { #ifndef EMULATOR /* disable RNG */ @@ -85,18 +81,13 @@ uint32_t random32(void) { } last = new; return new; -#elif defined(_WIN32) - /* Windows has no POSIX random(); use the system CSPRNG (stronger than the - * macOS/Linux emulator's random() PRNG anyway). Resolves via the bcrypt link - * on kkemulator_dylib (tools/emulator/CMakeLists.txt). */ +#else + /* Emulator cryptography must use the host OS CSPRNG. emulatorRandom() is + * backed by /dev/urandom on POSIX and BCryptGenRandom on Windows and aborts + * the process on failure; never fall back to libc random(). */ uint32_t v = 0; - if (BCryptGenRandom(NULL, (PUCHAR)&v, (ULONG)sizeof(v), - BCRYPT_USE_SYSTEM_PREFERRED_RNG) != 0) { - abort(); - } + emulatorRandom(&v, sizeof(v)); return v; -#else - return random(); #endif } @@ -107,7 +98,7 @@ uint32_t random32(void) { * which breaks the Linux .so and Windows .dll links. Provide a strong * definition here — identical to trezor-crypto's, built on our random32(). * macOS ld64 resolves the weak one fine, so it's left untouched there. */ -void random_buffer(uint8_t *buf, size_t len) { +void random_buffer(uint8_t* buf, size_t len) { uint32_t r = 0; for (size_t i = 0; i < len; i++) { if (i % 4 == 0) r = random32(); @@ -127,9 +118,9 @@ void random_buffer(uint8_t *buf, size_t len) { } \ } while (0) -void random_permute_char(char *str, size_t len) { RANDOM_PERMUTE(str, len); } +void random_permute_char(char* str, size_t len) { RANDOM_PERMUTE(str, len); } -void random_permute_u16(uint16_t *buf, size_t count) { +void random_permute_u16(uint16_t* buf, size_t count) { RANDOM_PERMUTE(buf, count); } diff --git a/scripts/build/docker/device/debug.sh b/scripts/build/docker/device/debug.sh index 0150e9138..8e0ca528d 100755 --- a/scripts/build/docker/device/debug.sh +++ b/scripts/build/docker/device/debug.sh @@ -3,7 +3,7 @@ KEEPKEY_FIRMWARE="$(dirname "$(dirname "$(dirname "$(dirname "$( cd "$(dirname "$0")" ; pwd -P )")")")")" cd $KEEPKEY_FIRMWARE -IMAGETAG=kktech/firmware:v15 +IMAGETAG=kktech/firmware@sha256:7438e53933d47d53157ed6d96d864cb208597e62dce26235ace09d1063427fa2 docker image inspect $IMAGETAG > /dev/null || docker pull $IMAGETAG diff --git a/scripts/build/docker/device/release.sh b/scripts/build/docker/device/release.sh index 50fbc9d4c..86ce7dc1d 100755 --- a/scripts/build/docker/device/release.sh +++ b/scripts/build/docker/device/release.sh @@ -3,7 +3,7 @@ KEEPKEY_FIRMWARE="$(dirname "$(dirname "$(dirname "$(dirname "$( cd "$(dirname "$0")" ; pwd -P )")")")")" cd $KEEPKEY_FIRMWARE -IMAGETAG=kktech/firmware:v15 +IMAGETAG=kktech/firmware@sha256:7438e53933d47d53157ed6d96d864cb208597e62dce26235ace09d1063427fa2 docker image inspect $IMAGETAG > /dev/null || docker pull $IMAGETAG diff --git a/scripts/build/docker/emulator/debug.sh b/scripts/build/docker/emulator/debug.sh index 9fec8264d..e4ad8ace0 100755 --- a/scripts/build/docker/emulator/debug.sh +++ b/scripts/build/docker/emulator/debug.sh @@ -3,7 +3,7 @@ KEEPKEY_FIRMWARE="$(dirname "$(dirname "$(dirname "$(dirname "$( cd "$(dirname "$0")" ; pwd -P )")")")")" cd $KEEPKEY_FIRMWARE -IMAGETAG=kktech/firmware:v15 +IMAGETAG=kktech/firmware@sha256:7438e53933d47d53157ed6d96d864cb208597e62dce26235ace09d1063427fa2 docker pull $IMAGETAG diff --git a/scripts/emulator/Dockerfile b/scripts/emulator/Dockerfile index 53c6bdd99..81e325ee8 100644 --- a/scripts/emulator/Dockerfile +++ b/scripts/emulator/Dockerfile @@ -1,4 +1,4 @@ -FROM kktech/firmware:v15 +FROM kktech/firmware@sha256:7438e53933d47d53157ed6d96d864cb208597e62dce26235ace09d1063427fa2 WORKDIR /kkemu COPY ./ /kkemu @@ -17,4 +17,3 @@ RUN make -j EXPOSE 11044/udp 11045/udp EXPOSE 5000 CMD ["/kkemu/scripts/emulator/run.sh"] - diff --git a/scripts/emulator/python-keepkey-tests.sh b/scripts/emulator/python-keepkey-tests.sh index bbbce7519..63fc4ec82 100755 --- a/scripts/emulator/python-keepkey-tests.sh +++ b/scripts/emulator/python-keepkey-tests.sh @@ -60,6 +60,7 @@ fi echo "Filter: $SCREENSHOT_FILTER" KEEPKEY_SCREENSHOT=1 \ SCREENSHOT_DIR=/kkemu/test-reports/screenshots \ +KK_EXPECT_PERSIST_REJECTED=1 \ KK_TRANSPORT_MAIN=kkemu:11044 \ KK_TRANSPORT_DEBUG=kkemu:11045 \ pytest -v --tb=short \ @@ -87,6 +88,7 @@ fi # Tests that skip via requires_message/requires_firmware are OK. # Tests that fail or are missing from JUnit = CI failure. echo "=== Phase 2: Full test suite ===" +KK_EXPECT_PERSIST_REJECTED=1 \ KK_TRANSPORT_MAIN=kkemu:11044 \ KK_TRANSPORT_DEBUG=kkemu:11045 \ pytest -v --junitxml=/kkemu/test-reports/python-keepkey/junit.xml diff --git a/scripts/emulator/python-keepkey.Dockerfile b/scripts/emulator/python-keepkey.Dockerfile index f67f9ba0d..0ba90447e 100644 --- a/scripts/emulator/python-keepkey.Dockerfile +++ b/scripts/emulator/python-keepkey.Dockerfile @@ -1,4 +1,4 @@ -FROM kktech/firmware:v15 +FROM kktech/firmware@sha256:7438e53933d47d53157ed6d96d864cb208597e62dce26235ace09d1063427fa2 # Extra Python deps needed by tests that aren't in the shared base image. # - rlp + eth-keys + eth-utils: build the canonical EIP-1559 type-2 pre-image diff --git a/unittests/board/CMakeLists.txt b/unittests/board/CMakeLists.txt index 81e294dec..ddad5512d 100644 --- a/unittests/board/CMakeLists.txt +++ b/unittests/board/CMakeLists.txt @@ -20,6 +20,6 @@ target_link_libraries(board-unit trezorcrypto qrcodegenerator SecAESSTM32 - kkemulator kkrand + kkemulator kktransport) diff --git a/unittests/crypto/CMakeLists.txt b/unittests/crypto/CMakeLists.txt index 2edbb9e3a..174287bc0 100644 --- a/unittests/crypto/CMakeLists.txt +++ b/unittests/crypto/CMakeLists.txt @@ -17,9 +17,9 @@ target_link_libraries(crypto-unit kkvariant.keepkey kkvariant.salt kkboard + kkrand kkemulator qrcodegenerator - kkrand trezorcrypto kktransport) diff --git a/unittests/firmware/CMakeLists.txt b/unittests/firmware/CMakeLists.txt index f2c47a261..26052ac2f 100644 --- a/unittests/firmware/CMakeLists.txt +++ b/unittests/firmware/CMakeLists.txt @@ -51,9 +51,9 @@ target_link_libraries(firmware-unit kkvariant.keepkey kkvariant.salt kkboard - kkemulator trezorcrypto qrcodegenerator SecAESSTM32 kkrand + kkemulator kktransport) diff --git a/unittests/firmware/signed_metadata.cpp b/unittests/firmware/signed_metadata.cpp index b580ad0dd..26de8d013 100644 --- a/unittests/firmware/signed_metadata.cpp +++ b/unittests/firmware/signed_metadata.cpp @@ -973,6 +973,16 @@ TEST(SignedMetadataSignerValid, RejectsBadAlias) { signed_metadata_signer_valid(0, EXPECTED_SLOT3_PUB, 33, "trust(me)")); } +TEST(SignedMetadataSignerStore, RejectsPersistenceBeforeSessionMutation) { + signed_metadata_clear_signers(); + EXPECT_FALSE(signed_metadata_store_signer( + TEST_KEY_ID, EXPECTED_SLOT3_PUB, TEST_ALIAS, nullptr, 0, 0, 0, true)); + EXPECT_EQ(signed_metadata_signer_alias(TEST_KEY_ID), nullptr); + char fingerprint[METADATA_FINGERPRINT_LEN]; + EXPECT_FALSE(signed_metadata_signer_fingerprint(TEST_KEY_ID, fingerprint)); + signed_metadata_clear_signers(); +} + /* ---- signed_metadata_pubkey_fingerprint -------------------------------- */ TEST(SignedMetadataFingerprint, IsSha256Prefix) { diff --git a/unittests/firmware/storage.cpp b/unittests/firmware/storage.cpp index 1dc4fdb7e..707920f49 100644 --- a/unittests/firmware/storage.cpp +++ b/unittests/firmware/storage.cpp @@ -1006,66 +1006,49 @@ TEST(Storage, Reset) { ASSERT_TRUE(memcmp(session.storageKey, new_storage_key, 64) == 0); } -// V18 storage adds a persistent clear-sign identities block appended after the -// V17 encrypted_sec. Prove the field-by-field serializer round-trips every -// field (incl. a real icon + a text-only identity), and that a corrupt on-flash -// icon_len is clamped on read. -TEST(Storage, ClearsignIdentityV18RoundTrip) { +// The V18 record layout remains reserved for compatibility, but RC18 must +// neither write nor accept those unauthenticated public-storage trust anchors. +TEST(Storage, ClearsignIdentityV18RecordsAreRetired) { ConfigFlash start; - memset(&start, 0xAB, sizeof(start)); + memset(&start, 0, sizeof(start)); memcpy(start.meta.magic, "stor", 4); start.storage.version = STORAGE_VERSION; start.storage.encrypted_sec_version = STORAGE_VERSION; - // Identity 0: full, with an icon. - ClearsignIdentity *a = &start.storage.pub.clearsign_identities[0]; - memset(a, 0, sizeof(*a)); + // Even a populated in-memory legacy record is serialized as zeros. + ClearsignIdentity* a = &start.storage.pub.clearsign_identities[0]; a->present = true; a->key_id = 1; - for (int i = 0; i < 33; i++) a->pubkey[i] = (uint8_t)(i + 1); + memset(a->pubkey, 0x42, sizeof(a->pubkey)); strcpy(a->alias, "CI Test"); - a->icon_w = 48; - a->icon_h = 48; - a->icon_len = 120; - for (int i = 0; i < a->icon_len; i++) a->icon[i] = (uint8_t)(0xF0 ^ i); - - // Identity 1: text-only (no icon). - ClearsignIdentity *b = &start.storage.pub.clearsign_identities[1]; - memset(b, 0, sizeof(*b)); - b->present = true; - b->key_id = 2; - for (int i = 0; i < 33; i++) b->pubkey[i] = (uint8_t)(0x80 + i); - strcpy(b->alias, "Pioneer Insight"); + a->icon_w = 32; + a->icon_h = 32; + a->icon_len = 2; + a->icon[0] = 0x01; + a->icon[1] = 0xFF; std::vector flash(3480, 0); - storage_writeV18((char *)&flash[0], flash.size(), &start); + storage_writeV18((char*)&flash[0], flash.size(), &start); + const size_t identity_block_off = 44 + 1501 + V17_ENCSEC_SIZE; + const size_t identity_block_len = + PERSISTENT_IDENTITY_COUNT * (71 + CLEARSIGN_ICON_MAX); + for (size_t i = 0; i < identity_block_len; i++) { + ASSERT_EQ(0, flash[identity_block_off + i]) << "byte " << i; + } + // Simulate attacker-controlled legacy flash. Deserialization must scrub the + // full in-memory block rather than parse or expose any of it. + memset(&flash[identity_block_off], 0xA5, identity_block_len); ConfigFlash end; - memset(&end, 0x00, sizeof(end)); - storage_readV18(&end, (const char *)&flash[0], flash.size()); - + memset(&end, 0xCC, sizeof(end)); + storage_readV18(&end, (const char*)&flash[0], flash.size()); + const uint8_t* retired = + reinterpret_cast(end.storage.pub.clearsign_identities); + for (size_t i = 0; i < sizeof(end.storage.pub.clearsign_identities); i++) { + ASSERT_EQ(0, retired[i]) << "byte " << i; + } for (int k = 0; k < PERSISTENT_IDENTITY_COUNT; k++) { - const ClearsignIdentity *s = &start.storage.pub.clearsign_identities[k]; - const ClearsignIdentity *r = &end.storage.pub.clearsign_identities[k]; - ASSERT_EQ(s->present, r->present) << "present " << k; - ASSERT_EQ(s->key_id, r->key_id) << "key_id " << k; - ASSERT_EQ(0, memcmp(s->pubkey, r->pubkey, 33)) << "pubkey " << k; - ASSERT_STREQ(s->alias, r->alias) << "alias " << k; - ASSERT_EQ(s->icon_w, r->icon_w) << "icon_w " << k; - ASSERT_EQ(s->icon_h, r->icon_h) << "icon_h " << k; - ASSERT_EQ(s->icon_len, r->icon_len) << "icon_len " << k; - ASSERT_EQ(0, memcmp(s->icon, r->icon, CLEARSIGN_ICON_MAX)) << "icon " << k; + const ClearsignIdentity* r = &end.storage.pub.clearsign_identities[k]; + ASSERT_FALSE(r->present) << "present " << k; } - - // A corrupt on-flash icon_len (> CLEARSIGN_ICON_MAX) must clamp to 0 on read - // so downstream renderers never index past the icon buffer. Identity 0's - // icon_len lives at flash[44 + 2525 + 69] (present, key_id, pubkey[33], - // alias[32], icon_w, icon_h => 69). - const size_t id0_icon_len_off = 44 + 1501 + V17_ENCSEC_SIZE + 69; - flash[id0_icon_len_off] = 0xFF; - flash[id0_icon_len_off + 1] = 0xFF; - ConfigFlash corrupt; - memset(&corrupt, 0x00, sizeof(corrupt)); - storage_readV18(&corrupt, (const char *)&flash[0], flash.size()); - ASSERT_EQ(0, corrupt.storage.pub.clearsign_identities[0].icon_len); } From faae5553533d75999f76ece2fe0d6eec7506ba45 Mon Sep 17 00:00:00 2001 From: highlander Date: Sat, 25 Jul 2026 17:46:00 -0300 Subject: [PATCH 06/22] fix(ci): make RC18 invariant gate checkout-safe --- .github/workflows/ci.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4af173e10..febf23075 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -210,24 +210,25 @@ jobs: - name: Enforce RC18 security invariants run: | - if grep -REn \ + if git grep -n -E \ 'uses:[[:space:]]+[^#[:space:]]+@(v[0-9]+|main|master)([[:space:]#]|$)' \ - .github/workflows; then + -- .github/workflows; then echo "::error::Every GitHub Action must be pinned to a full commit SHA" exit 1 fi - if grep -REn 'kktech/firmware:v[0-9]+' \ + if git grep -n -E 'kktech/firmware:v[0-9]+' -- \ .github/workflows scripts/build/docker scripts/emulator; then echo "::error::The firmware builder must be pinned by manifest digest" exit 1 fi - if grep -En 'return[[:space:]]+random\(\)' lib/rand/rng.c; then + if git grep -n -E 'return[[:space:]]+random\(\)' -- \ + lib/rand/rng.c; then echo "::error::Emulator cryptography must not use libc random()" exit 1 fi - if grep -REn \ + if git grep -n -E \ 'storage_(get|upsert)ClearsignIdentity|persistent_identity_for' \ - lib include; then + -- lib include; then echo "::error::Unauthenticated persistent clearsign trust is retired" exit 1 fi @@ -237,7 +238,7 @@ jobs: echo "::error::Orchard release gate unexpectedly allowed a build" exit 1 fi - grep -q 'requires a reviewed constant-time Pallas backend' \ + grep -q 'constant-time Pallas backend' \ /tmp/orchard-release-gate.log crypto-tests: From 727fb3b3f5eeb3a0232a1ea769818d2d2b47006f Mon Sep 17 00:00:00 2001 From: highlander Date: Sat, 25 Jul 2026 17:52:11 -0300 Subject: [PATCH 07/22] fix(ci): allow sanitizer codepoint tests to finish --- .github/workflows/ci.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index febf23075..5aaf4fc49 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -266,7 +266,11 @@ jobs: make clean make CC='gcc -fsanitize=address,undefined' VALGRIND=0 \ OPTFLAGS='-O1 -g -fno-omit-frame-pointer' tests/test_check - ASAN_OPTIONS=detect_leaks=0:halt_on_error=1 \ + # Check's default per-test timeout is too short for the two exhaustive + # codepoint tests under sanitizer instrumentation on shared runners. + # Keep the job-level timeout as the hard upper bound. + CK_DEFAULT_TIMEOUT=30 \ + ASAN_OPTIONS=detect_leaks=0:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 ./tests/test_check # ═══════════════════════════════════════════════════════════ From 73459b20fbdabf6dad99e75b6a9a4a967a0ff287 Mon Sep 17 00:00:00 2001 From: highlander Date: Sat, 25 Jul 2026 18:46:01 -0300 Subject: [PATCH 08/22] fix(release): restore Zcash privacy to regular RC18 --- .github/workflows/ci.yml | 16 +++-- .github/workflows/release.yml | 2 +- CMakeLists.txt | 30 +++++----- docs/security/7.15.0-rc18-release-shape.md | 31 ++++++---- lib/emulator/CMakeLists.txt | 4 +- lib/emulator/random.c | 69 ++++++++++++++++++++++ lib/emulator/setup.c | 61 +------------------ lib/firmware/signed_metadata.c | 24 +++++++- tools/emulator/CMakeLists.txt | 2 +- unittests/crypto/CMakeLists.txt | 6 +- 10 files changed, 146 insertions(+), 99 deletions(-) create mode 100644 lib/emulator/random.c diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5aaf4fc49..32099e038 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -232,14 +232,12 @@ jobs: echo "::error::Unauthenticated persistent clearsign trust is retired" exit 1 fi - if cmake -S . -B /tmp/orchard-release-gate \ - -DKK_ZCASH_PRIVACY=ON > /tmp/orchard-release-gate.log 2>&1; then - cat /tmp/orchard-release-gate.log - echo "::error::Orchard release gate unexpectedly allowed a build" + if git grep -n -F 'option(KK_ZCASH_PRIVACY' -- CMakeLists.txt; then + echo "::error::Zcash privacy must not become a third release choice" exit 1 fi - grep -q 'constant-time Pallas backend' \ - /tmp/orchard-release-gate.log + grep -q 'set(KK_ZCASH_PRIVACY ON)' CMakeLists.txt + grep -q 'set(KK_ZCASH_PRIVACY OFF)' CMakeLists.txt crypto-tests: runs-on: ubuntu-latest @@ -286,8 +284,8 @@ jobs: fail-fast: false matrix: include: - # Regular/full is multi-chain with transparent Zcash. Orchard is - # release-blocked; bitcoin-only is the sole reduced build. + # Regular/full includes every supported chain, including Zcash + # shielded/Orchard. Bitcoin-only is the sole reduced build. - variant: full label: "" cmake_flags: "" @@ -865,7 +863,7 @@ jobs: - name: Download emulator image uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 with: - # Publish the regular/full image. Orchard is release-blocked. + # Publish the regular/full image, including Zcash privacy support. name: emu-image-full path: /tmp diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b1ba08c07..bc70241cd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -276,7 +276,7 @@ jobs: ## KeepKey Firmware ${{ needs.validate.outputs.tag_name }} ### Variants - - **full (regular)** — \`firmware.keepkey.v${VER}-full.bin\` — all supported chains; Zcash transparent only (Orchard release-blocked pending a reviewed constant-time backend) + - **full (regular)** — \`firmware.keepkey.v${VER}-full.bin\` — all supported chains, including Zcash shielded/Orchard - **bitcoin-only** — \`firmware.keepkey.v${VER}-bitcoin-only.bin\` — BTC-only, non-BTC coins stripped ### Reproducible Build Verification diff --git a/CMakeLists.txt b/CMakeLists.txt index 711bcc42b..53b58930a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,19 +21,16 @@ option(KK_BUILD_DYLIB "Build libkkemu shared library (.dylib/.so)" OFF) option(KK_DEBUG_LINK "Build with debug-link enabled" OFF) option(KK_BUILD_FUZZERS "Build the fuzzers?" OFF) option(KK_BITCOIN_ONLY "Build Bitcoin-only firmware (strip all non-BTC coins)" OFF) -# RC18 release gate: the vendored Pallas scalar-multiplication path is variable -# time and is reached with Orchard spending secrets. Do not expose that path in -# any firmware or emulator build until it has been replaced by an independently -# reviewed constant-time backend. Transparent Zcash remains in the regular -# multi-chain firmware and does not depend on this engine. -option(KK_ZCASH_PRIVACY "Build the disabled Orchard privacy engine" OFF) -if(KK_ZCASH_PRIVACY) - message( - FATAL_ERROR - "KK_ZCASH_PRIVACY is release-blocked: Orchard requires a reviewed constant-time Pallas backend" - ) +# Zcash shielded/Orchard support is part of the regular firmware. It is an +# internal compile selection, not a third release variant: bitcoin-only strips +# the Zcash coin and privacy engine; every regular device/emulator build ships +# both. The open constant-time Pallas audit finding remains a release gate for +# RC18, but it must not silently change the product being audited. +if(KK_BITCOIN_ONLY) + set(KK_ZCASH_PRIVACY OFF) +else() + set(KK_ZCASH_PRIVACY ON) endif() -set(KK_ZCASH_PRIVACY OFF) # When building the dylib, every static lib it links (kkfirmware, kkboard, # trezorcrypto, kkrand, kktransport, qrcodegenerator, SecAESSTM32, ...) must @@ -152,8 +149,9 @@ add_definitions(-DBIP39_WORDLIST_PADDED=1) add_definitions(-DAES_128=1) -# NOTE: AES table size was previously selected for the Orchard image. RC18 has -# no Orchard image, so both shipped variants use the normal FOUR_TABLES AES. +# NOTE: AES table size is selected per release product below. The regular +# image includes Zcash and its Pallas curve arithmetic, so it uses the smaller +# AES tables to preserve flash headroom. Bitcoin-only keeps FOUR_TABLES AES. if(${KK_DEBUG_LINK}) add_definitions(-DDEBUG_LINK=1) @@ -171,6 +169,10 @@ endif() if(${KK_ZCASH_PRIVACY}) add_definitions(-DZCASH_PRIVACY=1) + # The Orchard engine leaves the regular image tightest on flash; shrink the + # Gladman AES lookup tables from 4KB to 1KB each (-15,360 bytes ROM, + # slightly slower AES). Bitcoin-only keeps the fast FOUR_TABLES. + add_definitions(-DAES_SMALL_TABLES) else() add_definitions(-DZCASH_PRIVACY=0) endif() diff --git a/docs/security/7.15.0-rc18-release-shape.md b/docs/security/7.15.0-rc18-release-shape.md index 37ed95558..9d93caf92 100644 --- a/docs/security/7.15.0-rc18-release-shape.md +++ b/docs/security/7.15.0-rc18-release-shape.md @@ -6,21 +6,24 @@ RC18 collapses the former three-product build into two release products: | Product | Contents | | --- | --- | -| Regular (`full`) | Every supported chain; Zcash transparent only | +| Regular (`full`) | Every supported chain, including Zcash shielded/Orchard | | Bitcoin-only | Bitcoin only; all non-Bitcoin coins and Zcash privacy code removed | -There is no separate `zcash-privacy` artifact. RC18 release-blocks the Orchard -engine in every build because its Pallas secret-scalar path is variable-time. -`-DKK_ZCASH_PRIVACY=ON` fails configuration until that path is replaced by an -independently reviewed constant-time backend. Transparent Zcash remains in the -regular firmware. +There is no separate `zcash-privacy` artifact. Zcash privacy is part of the +regular firmware and cannot be disabled as a release choice. The internal +`ZCASH_PRIVACY` compile value remains only so bitcoin-only can compile the +privacy sources out. + +The variable-time Pallas secret-scalar finding remains an explicit RC18 +release blocker. It requires a reviewed constant-time implementation; it does +not authorize removing Orchard from the regular product. ## Release and CI invariants - Device, emulator, unit-test, SRAM, and tagged-release matrices contain only `full` and `bitcoin-only`. - An unflagged CMake build is the regular product and sets - `BITCOIN_ONLY=0` and `ZCASH_PRIVACY=0`. + `BITCOIN_ONLY=0`, `ZCASH_PRIVACY=1`, and `AES_SMALL_TABLES`. - `-DKK_BITCOIN_ONLY=ON` sets `BITCOIN_ONLY=1` and `ZCASH_PRIVACY=0`. - The published emulator is the regular/full image. - Release notes and reproducible-build instructions name only the regular and @@ -34,20 +37,22 @@ and source/workflow identity in `PROVENANCE-.txt`. | Product | ARM build | Firmware tests | Board tests | Crypto tests | SRAM reserve | Largest frame | Reserve after frame | | --- | --- | ---: | ---: | ---: | ---: | ---: | ---: | -| Regular (`full`) | Pass | 307/307 | 2/2 | 4/4 | 23,364 B | 7,664 B | 15,700 B | +| Regular (`full`) | Pass | 366/366 | 2/2 | 4/4 | 19,064 B | 7,664 B | 11,400 B | | Bitcoin-only | Pass | 30/30 | 2/2 | 4/4 | 32,908 B | 7,664 B | 25,244 B | -Neither release build compiles the Orchard privacy engine. Both products pass -the 16,384-byte minimum SRAM reserve and 4,096-byte -reserve-after-largest-frame gates. +The regular release compiles the Orchard privacy engine; bitcoin-only does +not. The regular firmware suite includes 59 Zcash tests. Exact build and SRAM +figures must be refreshed after the constant-time Pallas implementation lands. +Both release gates remain mandatory. The canonical full-image integration rehearsal used device-protocol `e31cddfe7f5c72c983d06a889ac7db649b9811df` and python-keepkey `9ce1aeb480333176b3ed098066f51b22fd40a9d7`. Its JUnit result was 592 tests: 560 passed, 32 intentionally skipped, 0 failed, and 0 errors. Both the host-side and raw-device persistence rejection tests passed, and the -report-driven run captured 898 OLED screenshots. Orchard-specific cases skip -because RC18 does not advertise those handlers; transparent Zcash tests pass. +report-driven run captured 898 OLED screenshots. This evidence predates the +restoration of Orchard in the regular image and must not be used to approve the +final privacy-capable RC18 candidate. Workflow YAML parsing, SRAM-budget JSON parsing, Python syntax compilation, `git diff --check`, and the release-shape search for stale `zcash-privacy` diff --git a/lib/emulator/CMakeLists.txt b/lib/emulator/CMakeLists.txt index c1fcdcb4d..51eba7e81 100644 --- a/lib/emulator/CMakeLists.txt +++ b/lib/emulator/CMakeLists.txt @@ -3,7 +3,8 @@ if(${KK_EMULATOR}) set(sources oled.c udp.c - setup.c) + setup.c + random.c) @@ -19,6 +20,7 @@ if(${KK_EMULATOR}) oled.c udp.c setup.c + random.c ringbuf.c libkkemu.c) diff --git a/lib/emulator/random.c b/lib/emulator/random.c new file mode 100644 index 000000000..f05fdb1fd --- /dev/null +++ b/lib/emulator/random.c @@ -0,0 +1,69 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2017 Saleem Rashid + * + * 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. + */ + +#include "keepkey/emulator/emulator.h" +#include "keepkey/emulator/setup.h" + +#include +#include +#include + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#include +#else +#include +#include + +static int urandom = -1; + +static void setup_urandom(void) { + if (urandom >= 0) return; + + urandom = open("/dev/urandom", O_RDONLY); + if (urandom < 0) { + perror("Failed to open /dev/urandom"); + exit(1); + } +} +#endif + +void setup_urandom_only(void) { +#ifndef _WIN32 + setup_urandom(); +#endif +} + +void emulatorRandom(void* buffer, size_t size) { +#ifdef _WIN32 + /* Windows has no /dev/urandom — use the system CSPRNG. */ + if (BCryptGenRandom(NULL, (PUCHAR)buffer, (ULONG)size, + BCRYPT_USE_SYSTEM_PREFERRED_RNG) != 0) { + fprintf(stderr, "BCryptGenRandom failed\n"); + exit(1); + } +#else + setup_urandom(); + unsigned char* out = (unsigned char*)buffer; + size_t remaining = size; + while (remaining > 0) { + ssize_t n = read(urandom, out, remaining); + if (n < 0 && errno == EINTR) continue; + if (n <= 0) { + perror("Failed to read /dev/urandom"); + exit(1); + } + out += (size_t)n; + remaining -= (size_t)n; + } +#endif +} diff --git a/lib/emulator/setup.c b/lib/emulator/setup.c index 8ae69febe..58ad9933a 100644 --- a/lib/emulator/setup.c +++ b/lib/emulator/setup.c @@ -19,18 +19,12 @@ #include "keepkey/board/memory.h" #include "keepkey/board/timer.h" -#include "keepkey/rand/rng.h" +#include "keepkey/emulator/setup.h" -#include #include #include #include -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN /* exclude winsock.h — it declares \ - shutdown(SOCKET,int) */ -#include -#include -#else +#ifndef _WIN32 #include #include #include @@ -45,64 +39,15 @@ * blocked the Linux .so and Windows .dll builds. Removed — the board copy is * canonical. */ -static int urandom = -1; - -static void setup_urandom(void); - #ifndef _WIN32 static void setup_flash(void); void setup(void) { - setup_urandom(); + setup_urandom_only(); setup_flash(); } #endif -/* For libkkemu: init RNG only (flash buffer provided by host) */ -void setup_urandom_only(void) { setup_urandom(); } - -void emulatorRandom(void* buffer, size_t size) { -#ifdef _WIN32 - /* Windows has no /dev/urandom — use the system CSPRNG. */ - if (BCryptGenRandom(NULL, (PUCHAR)buffer, (ULONG)size, - BCRYPT_USE_SYSTEM_PREFERRED_RNG) != 0) { - fprintf(stderr, "BCryptGenRandom failed\n"); - exit(1); - } -#else - if (urandom < 0) { - setup_urandom(); - } - unsigned char* out = (unsigned char*)buffer; - size_t remaining = size; - while (remaining > 0) { - ssize_t n = read(urandom, out, remaining); - if (n < 0 && errno == EINTR) { - continue; - } - if (n <= 0) { - perror("Failed to read /dev/urandom"); - exit(1); - } - out += (size_t)n; - remaining -= (size_t)n; - } -#endif -} - -static void setup_urandom(void) { -#ifndef _WIN32 - if (urandom >= 0) { - return; - } - urandom = open("/dev/urandom", O_RDONLY); - if (urandom < 0) { - perror("Failed to open /dev/urandom"); - exit(1); - } -#endif -} - #ifndef _WIN32 static void setup_flash(void) { int fd = open(EMULATOR_FLASH_FILE, O_RDWR | O_SYNC | O_CREAT, 0644); diff --git a/lib/firmware/signed_metadata.c b/lib/firmware/signed_metadata.c index d71ff6430..bb4929083 100644 --- a/lib/firmware/signed_metadata.c +++ b/lib/firmware/signed_metadata.c @@ -38,10 +38,12 @@ static SignedMetadata stored_metadata; static uint8_t loaded_pubkeys[METADATA_MAX_KEYS][33]; static char loaded_aliases[METADATA_MAX_KEYS][METADATA_ALIAS_MAX_LEN + 1]; /* Per-slot session icon (1bpp mono RLE). icon_len==0 => text-only identity. */ +#if !ZCASH_PRIVACY static uint8_t loaded_icons[METADATA_MAX_KEYS][METADATA_ICON_MAX]; static uint8_t loaded_icon_w[METADATA_MAX_KEYS]; static uint8_t loaded_icon_h[METADATA_MAX_KEYS]; static uint16_t loaded_icon_len[METADATA_MAX_KEYS]; +#endif static bool read_u8(const uint8_t** cursor, const uint8_t* end, uint8_t* out) { if ((size_t)(end - *cursor) < 1) { @@ -402,10 +404,12 @@ void signed_metadata_clear(void) { void signed_metadata_clear_signers(void) { memzero(loaded_pubkeys, sizeof(loaded_pubkeys)); memzero(loaded_aliases, sizeof(loaded_aliases)); +#if !ZCASH_PRIVACY memzero(loaded_icons, sizeof(loaded_icons)); memzero(loaded_icon_w, sizeof(loaded_icon_w)); memzero(loaded_icon_h, sizeof(loaded_icon_h)); memzero(loaded_icon_len, sizeof(loaded_icon_len)); +#endif /* Metadata verified by a now-dropped signer must not outlive it. */ signed_metadata_clear(); } @@ -464,7 +468,10 @@ bool signed_metadata_store_signer(uint8_t key_id, const uint8_t* pubkey, * already validated <= max by the caller — belt-and-braces here). */ bool has_icon = icon && icon_len > 0 && icon_len <= METADATA_ICON_MAX; - /* Session icon into the RAM working slot. */ + /* Session icon into the RAM working slot. The Orchard build omits this + * cosmetic cache to preserve its tight SRAM margin; signers remain usable + * and render text-only after the mandatory load confirmation. */ +#if !ZCASH_PRIVACY memzero(loaded_icons[key_id], sizeof(loaded_icons[key_id])); if (has_icon) { memcpy(loaded_icons[key_id], icon, icon_len); @@ -476,6 +483,11 @@ bool signed_metadata_store_signer(uint8_t key_id, const uint8_t* pubkey, loaded_icon_h[key_id] = 0; loaded_icon_len[key_id] = 0; } +#else + (void)has_icon; + (void)icon_w; + (void)icon_h; +#endif /* Replacing a signer invalidates anything the old one verified. */ signed_metadata_clear(); @@ -497,6 +509,7 @@ const char* signed_metadata_signer_alias(uint8_t key_id) { * stages the frame itself (it never goes through stage_runtime_icon). Fail * closed to a text-only identity: a missing logo is cosmetic, an over-wide one * erases the alias, fingerprint and the "NOT verified by KeepKey" warning. */ +#if !ZCASH_PRIVACY static bool icon_renderable(const uint8_t* icon, uint16_t icon_len, uint8_t icon_w, uint8_t icon_h) { if (!icon || icon_len == 0) return false; @@ -504,12 +517,20 @@ static bool icon_renderable(const uint8_t* icon, uint16_t icon_len, if (icon_h == 0 || icon_h > 64) return false; return draw_bitmap_mono_rle_valid(icon, (uint32_t)icon_len, icon_w, icon_h); } +#endif bool signed_metadata_signer_icon(uint8_t key_id, const uint8_t** icon_out, uint8_t* w_out, uint8_t* h_out, uint16_t* len_out) { if (key_id >= METADATA_MAX_KEYS) return false; if (loaded_pubkeys[key_id][0] != 0x00) { +#if ZCASH_PRIVACY + (void)icon_out; + (void)w_out; + (void)h_out; + (void)len_out; + return false; +#else if (loaded_icon_len[key_id] == 0) return false; if (!icon_renderable(loaded_icons[key_id], loaded_icon_len[key_id], loaded_icon_w[key_id], loaded_icon_h[key_id])) { @@ -520,6 +541,7 @@ bool signed_metadata_signer_icon(uint8_t key_id, const uint8_t** icon_out, if (h_out) *h_out = loaded_icon_h[key_id]; if (len_out) *len_out = loaded_icon_len[key_id]; return true; +#endif } return false; } diff --git a/tools/emulator/CMakeLists.txt b/tools/emulator/CMakeLists.txt index 9f14af996..3ef8bc442 100644 --- a/tools/emulator/CMakeLists.txt +++ b/tools/emulator/CMakeLists.txt @@ -49,7 +49,7 @@ if(${KK_EMULATOR}) # 3.7.2. macOS ld64 is multi-pass and needs neither. # Also: MinGW exports nothing from a DLL by default (unlike Mach-O/ELF), # so export the kkemu_* FFI entry points; and link the Windows CSPRNG - # (bcrypt, BCryptGenRandom) used by setup.c / rng.c on _WIN32. + # (bcrypt, BCryptGenRandom) used by emulator/random.c on _WIN32. target_link_libraries(kkemulator_dylib -Wl,--start-group ${FIRMWARE_LIBS} -Wl,--end-group bcrypt) target_link_options(kkemulator_dylib PRIVATE "-Wl,--export-all-symbols") diff --git a/unittests/crypto/CMakeLists.txt b/unittests/crypto/CMakeLists.txt index 174287bc0..9f5df0193 100644 --- a/unittests/crypto/CMakeLists.txt +++ b/unittests/crypto/CMakeLists.txt @@ -27,7 +27,8 @@ target_link_libraries(crypto-unit if(${KK_ZCASH_PRIVACY}) add_executable(zcash-crypto-unit ../firmware/zcash.cpp - ${CMAKE_SOURCE_DIR}/lib/firmware/zcash.c) + ${CMAKE_SOURCE_DIR}/lib/firmware/zcash.c + ${CMAKE_SOURCE_DIR}/lib/emulator/random.c) target_include_directories(zcash-crypto-unit PRIVATE ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/lib/firmware @@ -37,4 +38,7 @@ if(${KK_ZCASH_PRIVACY}) gtest_main trezorcrypto kkrand) + if(WIN32) + target_link_libraries(zcash-crypto-unit bcrypt) + endif() endif() From bfc0f3e9f7bd64a779e039fc3aa02f4ab4a855d9 Mon Sep 17 00:00:00 2001 From: highlander Date: Sat, 25 Jul 2026 20:44:53 -0300 Subject: [PATCH 09/22] fix(zcash): make Pallas secret scalar path constant-time --- .github/workflows/ci.yml | 21 +- CMakeLists.txt | 10 + deps/crypto/CMakeLists.txt | 1 + deps/crypto/trezor-crypto/Makefile | 8 +- deps/crypto/trezor-crypto/pallas.c | 464 ++------------- deps/crypto/trezor-crypto/pallas.h | 50 +- deps/crypto/trezor-crypto/pallas_ct.c | 562 ++++++++++++++++++ deps/crypto/trezor-crypto/pallas_ct.h | 49 ++ deps/crypto/trezor-crypto/redpallas.c | 12 +- .../trezor-crypto/tests/test_pallas_ct.c | 119 ++++ tools/check_pallas_ct_disassembly.py | 237 ++++++++ unittests/crypto/CMakeLists.txt | 14 + unittests/crypto/pallas_ct.cpp | 242 ++++++++ 13 files changed, 1337 insertions(+), 452 deletions(-) create mode 100644 deps/crypto/trezor-crypto/pallas_ct.c create mode 100644 deps/crypto/trezor-crypto/pallas_ct.h create mode 100644 deps/crypto/trezor-crypto/tests/test_pallas_ct.c create mode 100644 tools/check_pallas_ct_disassembly.py create mode 100644 unittests/crypto/pallas_ct.cpp diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 32099e038..d6a733035 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -249,27 +249,39 @@ jobs: ref: ${{ github.event.pull_request.head.sha || github.sha }} - name: Install crypto test dependencies - run: sudo apt-get update && sudo apt-get install -y check libssl-dev pkg-config + run: sudo apt-get update && sudo apt-get install -y check libssl-dev pkg-config valgrind - name: Run optimized crypto suite working-directory: deps/crypto/trezor-crypto run: | make clean - make VALGRIND=0 tests/test_check + make VALGRIND=0 tests/test_check tests/test_pallas_ct ./tests/test_check + ./tests/test_pallas_ct + + - name: Verify Pallas secret flow with Valgrind + working-directory: deps/crypto/trezor-crypto + run: | + make clean + make VALGRIND=1 OPTFLAGS='-O2 -g' tests/test_pallas_ct + valgrind --quiet --error-exitcode=1 --track-origins=yes \ + ./tests/test_pallas_ct - name: Run crypto suite with ASan and UBSan working-directory: deps/crypto/trezor-crypto run: | make clean make CC='gcc -fsanitize=address,undefined' VALGRIND=0 \ - OPTFLAGS='-O1 -g -fno-omit-frame-pointer' tests/test_check + OPTFLAGS='-O1 -g -fno-omit-frame-pointer' \ + tests/test_check tests/test_pallas_ct # Check's default per-test timeout is too short for the two exhaustive # codepoint tests under sanitizer instrumentation on shared runners. # Keep the job-level timeout as the hard upper bound. CK_DEFAULT_TIMEOUT=30 \ ASAN_OPTIONS=detect_leaks=0:halt_on_error=1 \ UBSAN_OPTIONS=halt_on_error=1 ./tests/test_check + ASAN_OPTIONS=detect_leaks=0:halt_on_error=1 \ + UBSAN_OPTIONS=halt_on_error=1 ./tests/test_pallas_ct # ═══════════════════════════════════════════════════════════ # STAGE 2: BUILD — compile only after gate passes @@ -410,6 +422,9 @@ jobs: -DCMAKE_COLOR_MAKEFILE=ON \ ${{ matrix.cmake_flags }} && \ make && \ + python3 /root/keepkey-firmware/tools/check_pallas_ct_disassembly.py \ + --elf bin/firmware.keepkey.elf \ + --variant '${{ matrix.variant }}' && \ mkdir -p /root/keepkey-firmware/bin && \ cp bin/*.bin /root/keepkey-firmware/bin/ && \ cp bin/*.elf /root/keepkey-firmware/bin/ && \ diff --git a/CMakeLists.txt b/CMakeLists.txt index 53b58930a..58b964696 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -243,6 +243,10 @@ if(${KK_EMULATOR}) add_test(test-firmware ${CMAKE_BINARY_DIR}/bin/firmware-unit) add_test(test-board ${CMAKE_BINARY_DIR}/bin/board-unit) add_test(test-crypto ${CMAKE_BINARY_DIR}/bin/crypto-unit) + if(${KK_ZCASH_PRIVACY}) + add_test(test-pallas-ct ${CMAKE_BINARY_DIR}/bin/pallas-ct-unit) + add_test(test-zcash-crypto ${CMAKE_BINARY_DIR}/bin/zcash-crypto-unit) + endif() add_custom_target( xunit @@ -253,4 +257,10 @@ if(${KK_EMULATOR}) COMMAND ${CMAKE_BINARY_DIR}/bin/crypto-unit --gtest_output=xml:${CMAKE_BINARY_DIR}/unittests/crypto.xml) + if(${KK_ZCASH_PRIVACY}) + add_custom_command(TARGET xunit POST_BUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/pallas-ct-unit + --gtest_output=xml:${CMAKE_BINARY_DIR}/unittests/pallas-ct.xml) + endif() + endif() diff --git a/deps/crypto/CMakeLists.txt b/deps/crypto/CMakeLists.txt index 8df7775cc..7b238328f 100644 --- a/deps/crypto/CMakeLists.txt +++ b/deps/crypto/CMakeLists.txt @@ -62,6 +62,7 @@ set(sources if(${KK_ZCASH_PRIVACY}) list(APPEND sources trezor-crypto/pallas.c + trezor-crypto/pallas_ct.c trezor-crypto/pallas_sinsemilla.c trezor-crypto/pallas_swu.c trezor-crypto/redpallas.c diff --git a/deps/crypto/trezor-crypto/Makefile b/deps/crypto/trezor-crypto/Makefile index 6c8fc9427..4cef4f4c1 100644 --- a/deps/crypto/trezor-crypto/Makefile +++ b/deps/crypto/trezor-crypto/Makefile @@ -105,6 +105,12 @@ tests/test_check.o: tests/test_check_cardano.h tests/test_check_nano.h tests/tes tests/test_check: tests/test_check.o $(OBJS) $(CC) tests/test_check.o $(OBJS) $(TESTLIBS) -o tests/test_check +# Standalone Pallas secret-flow harness. It deliberately has no dependency on +# Check/OpenSSL so CI can run it under ASan/UBSan and Valgrind's constant-time +# taint check without building the rest of the test suite. +tests/test_pallas_ct: tests/test_pallas_ct.c pallas_ct.c pallas_ct.h memzero.c options.h + $(CC) $(CFLAGS) tests/test_pallas_ct.c pallas_ct.c memzero.c -o tests/test_pallas_ct + tests/test_speed: tests/test_speed.o $(OBJS) $(CC) tests/test_speed.o $(OBJS) -o tests/test_speed @@ -130,7 +136,7 @@ fuzzer: fuzzer/fuzzer.o $(OBJS) clean: rm -f *.o aes/*.o chacha20poly1305/*.o ed25519-donna/*.o monero/*.o - rm -f tests/*.o tests/test_check tests/test_speed tests/test_openssl tests/libtrezor-crypto.so tests/aestst + rm -f tests/*.o tests/test_check tests/test_pallas_ct tests/test_speed tests/test_openssl tests/libtrezor-crypto.so tests/aestst rm -f tools/*.o tools/xpubaddrgen tools/mktable tools/bip39bruteforce rm -f fuzzer/*.o fuzzer/fuzzer diff --git a/deps/crypto/trezor-crypto/pallas.c b/deps/crypto/trezor-crypto/pallas.c index 9b23f091d..20cd3f145 100644 --- a/deps/crypto/trezor-crypto/pallas.c +++ b/deps/crypto/trezor-crypto/pallas.c @@ -9,8 +9,8 @@ * IMPORTANT: The trezor-crypto bignum library assumes primes in the range * [2^256 - 2^224, 2^256]. The Pallas prime (~2^254) falls outside this range, * so bn_multiply/bn_inverse/bn_fast_mod produce incorrect results. - * This file implements custom field arithmetic using Barrett reduction - * to correctly handle the Pallas prime. + * pallas_ct.c implements fixed-width Montgomery field arithmetic and the + * fixed-schedule projective path used for secret scalar multiplication. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the "Software"), @@ -37,14 +37,9 @@ #include "blake2b.h" #include "memzero.h" +#include "pallas_ct.h" -/* bn_multiply_long is defined in bignum.c (non-static) */ -extern void bn_multiply_long(const bignum256 *k, const bignum256 *x, - uint32_t res[2 * 9]); - -#define BN_LIMBS 9 #define BN_BITS_PER_LIMB 29 -#define BN_LIMB_MASK ((1u << BN_BITS_PER_LIMB) - 1) /* ==================================================================== * Constants @@ -66,22 +61,6 @@ const curve_point pallas_G = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}}}; -/* - * Barrett reduction constant for the Pallas prime: - * mu_p = floor(2^510 / p) - */ -static const bignum256 mu_p = { - /*.val =*/{0x1ffffffc, 0x1a59e25f, 0x1306e466, 0x0b381fb5, 0x1ffff76e, - 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x00ffffff}}; - -/* - * Barrett reduction constant for the Pallas order: - * mu_q = floor(2^510 / q) - */ -static const bignum256 mu_q = { - /*.val =*/{0x1ffffffc, 0x17229bdf, 0x0b572273, 0x0b381fb3, 0x1ffff76e, - 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x00ffffff}}; - /* * Full ecdsa_curve struct (kept for compatibility, but point_multiply * from ecdsa.c should NOT be used with Pallas - use pallas_scalar_mult_G). @@ -112,114 +91,6 @@ const ecdsa_curve pallas = { #endif }; -/* ==================================================================== - * Barrett Reduction for ~254-bit primes - * - * Given an 18-limb product (up to ~510 bits), reduce mod prime. - * Uses Barrett: q_hat = floor(floor(x / 2^254) * mu / 2^256) - * r = x - q_hat * prime - * while r >= prime: r -= prime - * ==================================================================== */ - -/* - * Shift an 18-limb number right by 254 bits. - * 254 = 8*29 + 22, so we skip 8 limbs and shift remaining by 22 bits. - */ -static void shift_right_254(const uint32_t in[18], bignum256 *out) { - for (int i = 0; i < BN_LIMBS; i++) { - uint32_t lo = in[i + 8] >> 22; - uint32_t hi = (i + 9 < 18) ? (in[i + 9] << 7) : 0; - out->val[i] = (lo | hi) & BN_LIMB_MASK; - } -} - -/* - * Shift an 18-limb number right by 256 bits. - * 256 = 8*29 + 24, so we skip 8 limbs and shift remaining by 24 bits. - */ -static void shift_right_256(const uint32_t in[18], bignum256 *out) { - for (int i = 0; i < BN_LIMBS; i++) { - uint32_t lo = in[i + 8] >> 24; - uint32_t hi = (i + 9 < 18) ? (in[i + 9] << 5) : 0; - out->val[i] = (lo | hi) & BN_LIMB_MASK; - } -} - -/* - * Compare two bignum256 values (both must be normalized). - * Returns 1 if a >= b, 0 otherwise. - */ -static int bn_gte(const bignum256 *a, const bignum256 *b) { - for (int i = BN_LIMBS - 1; i >= 0; i--) { - if (a->val[i] > b->val[i]) return 1; - if (a->val[i] < b->val[i]) return 0; - } - return 1; /* equal */ -} - -/* - * Subtract b from a, storing result in res. Assumes a >= b. - * All operands must be normalized. - */ -static void bn_sub(const bignum256 *a, const bignum256 *b, bignum256 *res) { - int32_t borrow = 0; - for (int i = 0; i < BN_LIMBS; i++) { - int32_t diff = (int32_t)a->val[i] - (int32_t)b->val[i] + borrow; - if (diff < 0) { - diff += (1 << BN_BITS_PER_LIMB); - borrow = -1; - } else { - borrow = 0; - } - res->val[i] = (uint32_t)diff; - } -} - -/* - * Barrett reduction: reduce an 18-limb product mod a ~254-bit prime. - * - * prime: the modulus (~254-255 bits) - * mu: precomputed floor(2^510 / prime) (~256 bits) - * res[18]: input product (up to ~510 bits) - * out: output, reduced to [0, prime) - */ -static void pallas_barrett_reduce(const uint32_t res[18], - const bignum256 *prime, - const bignum256 *mu, bignum256 *out) { - /* Step 1: q_hat = floor(floor(x / 2^254) * mu / 2^256) */ - bignum256 x_shifted; - shift_right_254(res, &x_shifted); - bn_normalize(&x_shifted); - - uint32_t qmu[18] = {0}; - bn_multiply_long(&x_shifted, mu, qmu); - - bignum256 q_hat; - shift_right_256(qmu, &q_hat); - bn_normalize(&q_hat); - - /* Step 2: r = x - q_hat * prime (low 9 limbs only) */ - uint32_t qp[18] = {0}; - bn_multiply_long(&q_hat, prime, qp); - - /* Compute r = x - q*p using 9 low limbs. - * The true result fits in ~256 bits (< 3*prime). */ - int64_t borrow = 0; - for (int i = 0; i < BN_LIMBS; i++) { - int64_t diff = (int64_t)res[i] - (int64_t)qp[i] + borrow; - out->val[i] = (uint32_t)(diff & BN_LIMB_MASK); - borrow = diff >> BN_BITS_PER_LIMB; - } - bn_normalize(out); - - /* Step 3: while r >= prime, r -= prime (at most 3 times) */ - for (int i = 0; i < 3; i++) { - if (bn_gte(out, prime)) { - bn_sub(out, prime, out); - } - } -} - /* ==================================================================== * Pallas Field Arithmetic * ==================================================================== */ @@ -227,132 +98,62 @@ static void pallas_barrett_reduce(const uint32_t res[18], /* * Field multiplication: x = k * x mod pallas_prime */ -void pallas_mul_mod_p(bignum256 *x, const bignum256 *k) { - uint32_t res[18] = {0}; - bn_multiply_long(k, x, res); - pallas_barrett_reduce(res, &pallas_prime, &mu_p, x); +void pallas_mul_mod_p(bignum256* x, const bignum256* k) { + pallas_ct_mul_mod_p(x, k); } /* * Scalar multiplication: x = k * x mod pallas_order */ -void pallas_mul_mod_q(bignum256 *x, const bignum256 *k) { - uint32_t res[18] = {0}; - bn_multiply_long(k, x, res); - pallas_barrett_reduce(res, &pallas_order, &mu_q, x); +void pallas_mul_mod_q(bignum256* x, const bignum256* k) { + pallas_ct_mul_mod_q(x, k); } /* * Field addition: x = (a + b) mod pallas_prime */ -void pallas_add_mod_p(const bignum256 *a, const bignum256 *b, - bignum256 *res) { - uint32_t carry = 0; - for (int i = 0; i < BN_LIMBS; i++) { - carry += a->val[i] + b->val[i]; - res->val[i] = carry & BN_LIMB_MASK; - carry >>= BN_BITS_PER_LIMB; - } - bn_normalize(res); - if (bn_gte(res, &pallas_prime)) { - bn_sub(res, &pallas_prime, res); - } +void pallas_add_mod_p(const bignum256* a, const bignum256* b, bignum256* res) { + pallas_ct_add_mod_p(a, b, res); } /* * Field subtraction: res = (a - b) mod pallas_prime */ -void pallas_sub_mod_p(const bignum256 *a, const bignum256 *b, - bignum256 *res) { - if (bn_gte(a, b)) { - bn_sub(a, b, res); - } else { - /* a < b: res = a + prime - b = prime - (b - a) */ - bignum256 tmp; - bn_sub(b, a, &tmp); - bn_sub(&pallas_prime, &tmp, res); - } +void pallas_sub_mod_p(const bignum256* a, const bignum256* b, bignum256* res) { + pallas_ct_sub_mod_p(a, b, res); } /* * Field inversion: x = x^(-1) mod pallas_prime * Uses Fermat's little theorem: x^(-1) = x^(p-2) mod p */ -void pallas_inv_mod_p(bignum256 *x) { - /* Compute e = p - 2 with proper borrow (since p.val[0] = 1 < 2) */ - bignum256 e; - bn_copy(&pallas_prime, &e); - /* val[0] = 1, so 1 - 2 requires borrow from val[1] */ - e.val[0] = e.val[0] + (1u << BN_BITS_PER_LIMB) - 2; /* 1 + 2^29 - 2 = 0x1FFFFFFF */ - e.val[1] -= 1; /* borrow */ - - /* Square-and-multiply: result = x^e mod p */ - bignum256 result; - bn_one(&result); - - bignum256 base; - bn_copy(x, &base); - - /* Process each bit of e from LSB to MSB */ - for (int bit = 0; bit < 255; bit++) { - int limb_idx = bit / BN_BITS_PER_LIMB; - int bit_idx = bit % BN_BITS_PER_LIMB; - - if ((e.val[limb_idx] >> bit_idx) & 1) { - pallas_mul_mod_p(&result, &base); - } - /* Square the base */ - bignum256 tmp; - bn_copy(&base, &tmp); - pallas_mul_mod_p(&base, &tmp); - } - - bn_copy(&result, x); - memzero(&result, sizeof(result)); - memzero(&base, sizeof(base)); -} +void pallas_inv_mod_p(bignum256* x) { pallas_ct_inv_mod_p(x); } /* * Simple modular reduction: x = x mod pallas_prime - * For values already < 2^261 (bignum256 range). + * The input is a canonical 256-bit value represented as a bignum256. */ -void pallas_mod_p(bignum256 *x) { - bn_normalize(x); - while (bn_gte(x, &pallas_prime)) { - bn_sub(x, &pallas_prime, x); - } -} +void pallas_mod_p(bignum256* x) { pallas_ct_mod_p(x); } /* * Simple modular reduction: x = x mod pallas_order - * For values already < 2^261 (bignum256 range). + * The input is a canonical 256-bit value represented as a bignum256. */ -void pallas_mod_q(bignum256 *x) { - bn_normalize(x); - while (bn_gte(x, &pallas_order)) { - bn_sub(x, &pallas_order, x); - } -} +void pallas_mod_q(bignum256* x) { pallas_ct_mod_q(x); } /* * Scalar addition: a = (a + b) mod pallas_order */ -void pallas_add_mod_q(bignum256 *a, const bignum256 *b) { - uint32_t carry = 0; - for (int i = 0; i < BN_LIMBS; i++) { - carry += a->val[i] + b->val[i]; - a->val[i] = carry & BN_LIMB_MASK; - carry >>= BN_BITS_PER_LIMB; - } - pallas_mod_q(a); +void pallas_add_mod_q(bignum256* a, const bignum256* b) { + pallas_ct_add_mod_q(a, b); } /* * Modular exponentiation: result = base^exp mod pallas_prime * Uses square-and-multiply (LSB to MSB). */ -static void pallas_pow_mod_p(const bignum256 *base, const bignum256 *exp, - bignum256 *result) { +static void pallas_pow_mod_p(const bignum256* base, const bignum256* exp, + bignum256* result) { bn_zero(result); result->val[0] = 1; @@ -380,7 +181,7 @@ static void pallas_pow_mod_p(const bignum256 *base, const bignum256 *exp, * * Returns 0 on success (n modified to sqrt), -1 if n is not a QR. */ -int pallas_sqrt_mod_p(bignum256 *n) { +int pallas_sqrt_mod_p(bignum256* n) { if (bn_is_zero(n)) return 0; /* p - 1 */ @@ -403,7 +204,8 @@ int pallas_sqrt_mod_p(bignum256 *n) { bignum256 half_pm1; bn_copy(&pm1, &half_pm1); for (i = 0; i < 8; i++) { - half_pm1.val[i] = (half_pm1.val[i] >> 1) | ((half_pm1.val[i + 1] & 0x1) << 28); + half_pm1.val[i] = + (half_pm1.val[i] >> 1) | ((half_pm1.val[i + 1] & 0x1) << 28); } half_pm1.val[8] >>= 1; @@ -420,22 +222,22 @@ int pallas_sqrt_mod_p(bignum256 *n) { /* Tonelli-Shanks initialization */ int M = 32; bignum256 c; - pallas_pow_mod_p(&z, &Q, &c); /* c = z^Q mod p */ + pallas_pow_mod_p(&z, &Q, &c); /* c = z^Q mod p */ bignum256 t; - pallas_pow_mod_p(n, &Q, &t); /* t = n^Q mod p */ + pallas_pow_mod_p(n, &Q, &t); /* t = n^Q mod p */ /* (Q+1)/2 */ bignum256 Q_half; bn_copy(&Q, &Q_half); - Q_half.val[0]++; /* Q is odd, so Q+1 is even */ + Q_half.val[0]++; /* Q is odd, so Q+1 is even */ for (i = 0; i < 8; i++) { Q_half.val[i] = (Q_half.val[i] >> 1) | ((Q_half.val[i + 1] & 0x1) << 28); } Q_half.val[8] >>= 1; bignum256 R; - pallas_pow_mod_p(n, &Q_half, &R); /* R = n^((Q+1)/2) mod p */ + pallas_pow_mod_p(n, &Q_half, &R); /* R = n^((Q+1)/2) mod p */ bignum256 one; bn_zero(&one); @@ -460,13 +262,13 @@ int pallas_sqrt_mod_p(bignum256 *n) { for (ii = 1; ii < M; ii++) { bignum256 sq; bn_copy(&tmp, &sq); - pallas_mul_mod_p(&tmp, &sq); /* tmp = tmp^2 */ + pallas_mul_mod_p(&tmp, &sq); /* tmp = tmp^2 */ bn_normalize(&tmp); if (bn_is_equal(&tmp, &one)) break; } if (ii >= M) { - return -1; /* n is not a quadratic residue */ + return -1; /* n is not a quadratic residue */ } /* b = c^(2^(M-ii-1)) */ @@ -475,7 +277,7 @@ int pallas_sqrt_mod_p(bignum256 *n) { for (int j = 0; j < M - ii - 1; j++) { bignum256 sq; bn_copy(&b, &sq); - pallas_mul_mod_p(&b, &sq); /* b = b^2 */ + pallas_mul_mod_p(&b, &sq); /* b = b^2 */ } /* Update M, c, t, R */ @@ -486,14 +288,14 @@ int pallas_sqrt_mod_p(bignum256 *n) { { bignum256 sq; bn_copy(&c, &sq); - pallas_mul_mod_p(&c, &sq); /* c = c^2 = b^2 */ + pallas_mul_mod_p(&c, &sq); /* c = c^2 = b^2 */ } /* t = t * c (where c = b^2) */ - pallas_mul_mod_p(&t, &c); /* t = c * t = b^2 * t */ + pallas_mul_mod_p(&t, &c); /* t = c * t = b^2 * t */ /* R = R * b */ - pallas_mul_mod_p(&R, &b); /* R = b * R */ + pallas_mul_mod_p(&R, &b); /* R = b * R */ } } @@ -501,202 +303,35 @@ int pallas_sqrt_mod_p(bignum256 *n) { * Pallas Point Operations (affine coordinates) * ==================================================================== */ -static int pallas_point_is_infinity(const curve_point *p) { +static int pallas_point_is_infinity(const curve_point* p) { return bn_is_zero(&p->x) && bn_is_zero(&p->y); } -static void pallas_point_set_infinity(curve_point *p) { - bn_zero(&p->x); - bn_zero(&p->y); -} - -/* - * Point doubling: res = 2*P on Pallas curve (y^2 = x^3 + 5, a=0) - * Formula: lambda = 3*x^2 / (2*y) - * xr = lambda^2 - 2*x - * yr = lambda*(x - xr) - y - */ -static void pallas_point_dbl(const curve_point *p, curve_point *res) { - if (pallas_point_is_infinity(p) || bn_is_zero(&p->y)) { - pallas_point_set_infinity(res); - return; - } - - bignum256 lambda, xr, yr, tmp, tmp2; - - /* lambda = 3*x^2 / (2*y) mod p */ - /* Numerator: 3*x^2 */ - bn_copy(&p->x, &tmp); - pallas_mul_mod_p(&tmp, &p->x); /* tmp = x^2 */ - bn_copy(&tmp, &tmp2); - pallas_add_mod_p(&tmp, &tmp2, &lambda); /* lambda = 2*x^2 */ - pallas_add_mod_p(&lambda, &tmp2, &lambda); /* lambda = 3*x^2 */ - - /* Denominator: 2*y */ - pallas_add_mod_p(&p->y, &p->y, &tmp); /* tmp = 2*y */ - - /* Invert denominator */ - pallas_inv_mod_p(&tmp); /* tmp = 1/(2*y) */ - - /* lambda = 3*x^2 * (1/(2*y)) */ - pallas_mul_mod_p(&lambda, &tmp); - - /* xr = lambda^2 - 2*x */ - bn_copy(&lambda, &xr); - pallas_mul_mod_p(&xr, &lambda); /* xr = lambda^2 */ - pallas_add_mod_p(&p->x, &p->x, &tmp); /* tmp = 2*x */ - pallas_sub_mod_p(&xr, &tmp, &xr); /* xr = lambda^2 - 2*x */ - - /* yr = lambda*(x - xr) - y */ - pallas_sub_mod_p(&p->x, &xr, &yr); /* yr = x - xr */ - pallas_mul_mod_p(&yr, &lambda); /* yr = lambda*(x - xr) */ - pallas_sub_mod_p(&yr, &p->y, &yr); /* yr = lambda*(x-xr) - y */ - - bn_copy(&xr, &res->x); - bn_copy(&yr, &res->y); -} - -/* - * Point addition: res = P + Q on Pallas curve - */ -void pallas_point_add(const curve_point *p, const curve_point *q, - curve_point *res) { - if (pallas_point_is_infinity(p)) { - *res = *q; - return; - } - if (pallas_point_is_infinity(q)) { - *res = *p; - return; - } - - /* Check if P == Q (use doubling) */ - bignum256 px_norm, qx_norm, py_norm, qy_norm; - bn_copy(&p->x, &px_norm); - bn_copy(&q->x, &qx_norm); - bn_copy(&p->y, &py_norm); - bn_copy(&q->y, &qy_norm); - bn_normalize(&px_norm); - bn_normalize(&qx_norm); - bn_normalize(&py_norm); - bn_normalize(&qy_norm); - - int x_equal = 1, y_equal = 1; - for (int i = 0; i < BN_LIMBS; i++) { - if (px_norm.val[i] != qx_norm.val[i]) { x_equal = 0; break; } - } - if (x_equal) { - for (int i = 0; i < BN_LIMBS; i++) { - if (py_norm.val[i] != qy_norm.val[i]) { y_equal = 0; break; } - } - if (y_equal) { - pallas_point_dbl(p, res); - return; - } - /* P.x == Q.x but P.y != Q.y → P + Q = O (point at infinity) */ - pallas_point_set_infinity(res); - return; - } - - bignum256 lambda, xr, yr, tmp; - - /* lambda = (Q.y - P.y) / (Q.x - P.x) mod p */ - pallas_sub_mod_p(&q->y, &p->y, &lambda); /* num = Q.y - P.y */ - pallas_sub_mod_p(&q->x, &p->x, &tmp); /* den = Q.x - P.x */ - pallas_inv_mod_p(&tmp); /* den = 1/(Q.x - P.x) */ - pallas_mul_mod_p(&lambda, &tmp); /* lambda = num/den */ - - /* xr = lambda^2 - P.x - Q.x */ - bn_copy(&lambda, &xr); - pallas_mul_mod_p(&xr, &lambda); /* xr = lambda^2 */ - pallas_sub_mod_p(&xr, &p->x, &xr); /* xr -= P.x */ - pallas_sub_mod_p(&xr, &q->x, &xr); /* xr -= Q.x */ - - /* yr = lambda*(P.x - xr) - P.y */ - pallas_sub_mod_p(&p->x, &xr, &yr); /* yr = P.x - xr */ - pallas_mul_mod_p(&yr, &lambda); /* yr *= lambda */ - pallas_sub_mod_p(&yr, &p->y, &yr); /* yr -= P.y */ - - bn_copy(&xr, &res->x); - bn_copy(&yr, &res->y); -} - -/* ==================================================================== - * Scalar Multiplication (double-and-add, left-to-right) - * ==================================================================== */ - -/* - * Compute res = k * P on Pallas. - * Uses the double-and-add algorithm. - * k must be in [1, order-1]. - */ -static void pallas_scalar_mult_impl(const bignum256 *k, const curve_point *p, - curve_point *res) { - /* Find the highest set bit */ - int highest_bit = -1; - for (int i = BN_LIMBS - 1; i >= 0; i--) { - if (k->val[i] != 0) { - uint32_t v = k->val[i]; - int bit = BN_BITS_PER_LIMB - 1; - while (bit >= 0 && !((v >> bit) & 1)) bit--; - highest_bit = i * BN_BITS_PER_LIMB + bit; - break; - } - } - - if (highest_bit < 0) { - /* k == 0 */ - pallas_point_set_infinity(res); - return; - } - - /* Initialize res = P (for the highest bit) */ - *res = *p; - - /* Process remaining bits from second-highest down to 0 */ - for (int bit = highest_bit - 1; bit >= 0; bit--) { - /* Double */ - curve_point tmp; - pallas_point_dbl(res, &tmp); - *res = tmp; - - /* Add if bit is set */ - int limb_idx = bit / BN_BITS_PER_LIMB; - int bit_idx = bit % BN_BITS_PER_LIMB; - if ((k->val[limb_idx] >> bit_idx) & 1) { - pallas_point_add(res, p, &tmp); - *res = tmp; - } - } +/* Point addition uses the constant-time projective implementation. */ +void pallas_point_add(const curve_point* p, const curve_point* q, + curve_point* res) { + pallas_ct_point_add(p, q, res); } /* ==================================================================== * Public API * ==================================================================== */ -void pallas_scalar_mult_G(const bignum256 *k, curve_point *res) { - if (bn_is_zero(k)) { - pallas_point_set_infinity(res); - return; - } - pallas_scalar_mult_impl(k, &pallas_G, res); +void pallas_scalar_mult_G(const bignum256* k, curve_point* res) { + pallas_ct_point_mult(k, &pallas_G, res); } -void pallas_point_mult(const bignum256 *k, const curve_point *p, - curve_point *res) { - if (bn_is_zero(k)) { - pallas_point_set_infinity(res); - return; - } - pallas_scalar_mult_impl(k, p, res); +void pallas_point_mult(const bignum256* k, const curve_point* p, + curve_point* res) { + pallas_ct_point_mult(k, p, res); } -int pallas_point_is_identity(const curve_point *p) { +int pallas_point_is_identity(const curve_point* p) { if (!p) return 1; return pallas_point_is_infinity(p); } -void pallas_point_encode(const curve_point *p, uint8_t out[32]) { +void pallas_point_encode(const curve_point* p, uint8_t out[32]) { if (!p || !out) return; memset(out, 0, 32); @@ -711,9 +346,9 @@ void pallas_point_encode(const curve_point *p, uint8_t out[32]) { memzero(&x, sizeof(x)); } -int pallas_expand_message_xmd_blake2b(const uint8_t *msg, size_t msg_len, - const uint8_t *dst, size_t dst_len, - uint8_t *out, size_t out_len) { +int pallas_expand_message_xmd_blake2b(const uint8_t* msg, size_t msg_len, + const uint8_t* dst, size_t dst_len, + uint8_t* out, size_t out_len) { enum { B_IN_BYTES = 64, R_IN_BYTES = 128, @@ -778,7 +413,8 @@ int pallas_expand_message_xmd_blake2b(const uint8_t *msg, size_t msg_len, } ctr = (uint8_t)i; - if (blake2b_InitPersonal(&ctx, B_IN_BYTES, personal, sizeof(personal)) != 0) { + if (blake2b_InitPersonal(&ctx, B_IN_BYTES, personal, sizeof(personal)) != + 0) { memzero(&ctx, sizeof(ctx)); return -1; } diff --git a/deps/crypto/trezor-crypto/pallas.h b/deps/crypto/trezor-crypto/pallas.h index 7fc986e2c..9fc0cbe2f 100644 --- a/deps/crypto/trezor-crypto/pallas.h +++ b/deps/crypto/trezor-crypto/pallas.h @@ -50,58 +50,58 @@ extern const bignum256 pallas_order; extern const curve_point pallas_G; /* expand_message_xmd using BLAKE2b-512, per RFC 9380 §5.3.1. */ -int pallas_expand_message_xmd_blake2b(const uint8_t *msg, size_t msg_len, - const uint8_t *dst, size_t dst_len, - uint8_t *out, size_t out_len); +int pallas_expand_message_xmd_blake2b(const uint8_t* msg, size_t msg_len, + const uint8_t* dst, size_t dst_len, + uint8_t* out, size_t out_len); -/* --- Field arithmetic mod p (Barrett reduction) --- */ +/* --- Field arithmetic mod p (fixed-width Montgomery arithmetic) --- */ /* x = k * x mod p */ -void pallas_mul_mod_p(bignum256 *x, const bignum256 *k); +void pallas_mul_mod_p(bignum256* x, const bignum256* k); -/* x = x mod p (simple reduction for values < 2^261) */ -void pallas_mod_p(bignum256 *x); +/* x = x mod p */ +void pallas_mod_p(bignum256* x); /* x = x^(-1) mod p (Fermat's little theorem) */ -void pallas_inv_mod_p(bignum256 *x); +void pallas_inv_mod_p(bignum256* x); /* res = (a + b) mod p */ -void pallas_add_mod_p(const bignum256 *a, const bignum256 *b, bignum256 *res); +void pallas_add_mod_p(const bignum256* a, const bignum256* b, bignum256* res); /* res = (a - b) mod p */ -void pallas_sub_mod_p(const bignum256 *a, const bignum256 *b, bignum256 *res); +void pallas_sub_mod_p(const bignum256* a, const bignum256* b, bignum256* res); /* n = sqrt(n) mod p (Tonelli-Shanks). Returns 0 on success, -1 if no sqrt. */ -int pallas_sqrt_mod_p(bignum256 *n); +int pallas_sqrt_mod_p(bignum256* n); -/* --- Scalar arithmetic mod q (Barrett reduction) --- */ +/* --- Scalar arithmetic mod q (fixed-width Montgomery arithmetic) --- */ /* x = k * x mod q */ -void pallas_mul_mod_q(bignum256 *x, const bignum256 *k); +void pallas_mul_mod_q(bignum256* x, const bignum256* k); -/* x = x mod q (simple reduction for values < 2^261) */ -void pallas_mod_q(bignum256 *x); +/* x = x mod q */ +void pallas_mod_q(bignum256* x); /* a = (a + b) mod q */ -void pallas_add_mod_q(bignum256 *a, const bignum256 *b); +void pallas_add_mod_q(bignum256* a, const bignum256* b); /* --- Point operations on Pallas curve --- */ -/* res = k * G */ -void pallas_scalar_mult_G(const bignum256 *k, curve_point *res); +/* res = k * G, using a fixed 255-round branchless projective path */ +void pallas_scalar_mult_G(const bignum256* k, curve_point* res); -/* res = k * P */ -void pallas_point_mult(const bignum256 *k, const curve_point *p, - curve_point *res); +/* res = k * P, using a fixed 255-round branchless projective path */ +void pallas_point_mult(const bignum256* k, const curve_point* p, + curve_point* res); /* res = P + Q */ -void pallas_point_add(const curve_point *p, const curve_point *q, - curve_point *res); +void pallas_point_add(const curve_point* p, const curve_point* q, + curve_point* res); /* Returns nonzero if P is the point at infinity in this implementation. */ -int pallas_point_is_identity(const curve_point *p); +int pallas_point_is_identity(const curve_point* p); /* Serialize Pallas point as LE x-coordinate with y parity in bit 255. */ -void pallas_point_encode(const curve_point *p, uint8_t out[32]); +void pallas_point_encode(const curve_point* p, uint8_t out[32]); #endif diff --git a/deps/crypto/trezor-crypto/pallas_ct.c b/deps/crypto/trezor-crypto/pallas_ct.c new file mode 100644 index 000000000..306c433e1 --- /dev/null +++ b/deps/crypto/trezor-crypto/pallas_ct.c @@ -0,0 +1,562 @@ +/** + * Constant-time Pallas arithmetic for Zcash Orchard secret scalars. + * + * The field representation and Montgomery constants are derived from + * zcash/pasta_curves 0.5.1. Point formulas follow its Jacobian formulas, but + * exceptional cases are computed and selected with masks rather than secret- + * dependent branches. Scalar multiplication always executes 255 rounds and + * computes both the double and add result in every round. + * + * Constant-time here means control flow and memory access do not depend on + * secret scalar or field values. Physical leakage resistance still requires + * inspection of the compiled target and measurement on the device. + * The radix-2^16 multiplier deliberately avoids the Cortex-M3's + * operand-dependent UMULL/UMLAL instructions. + */ + +#include "pallas_ct.h" + +#include +#include +#include + +#include "memzero.h" + +enum { CT_LIMBS = 8 }; + +typedef struct { + uint32_t v[CT_LIMBS]; +} ct_fe; + +typedef struct { + ct_fe x; + ct_fe y; + ct_fe z; +} ct_point; + +typedef struct { + ct_fe modulus; + ct_fe r2; + ct_fe one; +} ct_modulus; + +static const ct_modulus CT_P = { + /* p */ {{0x00000001, 0x992d30ed, 0x094cf91b, 0x224698fc, 0x00000000, + 0x00000000, 0x00000000, 0x40000000}}, + /* R^2 mod p */ + {{0x0000000f, 0x8c78ecb3, 0x8b0de0e7, 0xd7d30dbd, 0xc3c95d18, 0x7797a99b, + 0x7b9cb714, 0x096d41af}}, + /* R mod p */ + {{0xfffffffd, 0x34786d38, 0xe41914ad, 0x992c350b, 0xffffffff, 0xffffffff, + 0xffffffff, 0x3fffffff}}, +}; + +static const ct_modulus CT_Q = { + /* q */ {{0x00000001, 0x8c46eb21, 0x0994a8dd, 0x224698fc, 0x00000000, + 0x00000000, 0x00000000, 0x40000000}}, + /* R^2 mod q */ + {{0x0000000f, 0xfc9678ff, 0x891a16e3, 0x67bb433d, 0x04ccf590, 0x7fae2310, + 0x7ccfdaa9, 0x096d41af}}, + /* R mod q */ + {{0xfffffffd, 0x5b2b3e9c, 0xe3420567, 0x992c350b, 0xffffffff, 0xffffffff, + 0xffffffff, 0x3fffffff}}, +}; + +/* p - 2, in normal little-endian 32-bit limbs. */ +static const uint32_t CT_P_MINUS_2[CT_LIMBS] = { + 0xffffffff, 0x992d30ec, 0x094cf91b, 0x224698fc, + 0x00000000, 0x00000000, 0x00000000, 0x40000000, +}; + +#ifdef PALLAS_CT_TESTING +static pallas_ct_counts ct_counts; +#define CT_COUNT(member) (ct_counts.member++) + +void pallas_ct_test_reset_counts(void) { + memset(&ct_counts, 0, sizeof(ct_counts)); +} + +void pallas_ct_test_get_counts(pallas_ct_counts* counts) { + if (counts != NULL) { + *counts = ct_counts; + } +} +#else +#define CT_COUNT(member) ((void)0) +#endif + +static uint32_t ct_mask(uint32_t choice) { return 0u - (choice & 1u); } + +static uint32_t ct_u32_is_zero(uint32_t value) { + return ((value | (0u - value)) >> 31) ^ 1u; +} + +/* Keep this materialization out of its caller so ARM emits arithmetic rather + * than a secret-conditioned IT block for the zero-nonce normalization. */ +__attribute__((noinline)) static uint32_t ct_secret_u32_is_zero( + uint32_t value) { + return ((value | (0u - value)) >> 31) ^ 1u; +} + +static uint32_t ct_fe_is_zero(const ct_fe* a) { + uint32_t diff = 0; + for (size_t i = 0; i < CT_LIMBS; i++) { + diff |= a->v[i]; + } + return ct_u32_is_zero(diff); +} + +static uint32_t ct_fe_equal(const ct_fe* a, const ct_fe* b) { + uint32_t diff = 0; + for (size_t i = 0; i < CT_LIMBS; i++) { + diff |= a->v[i] ^ b->v[i]; + } + return ct_u32_is_zero(diff); +} + +static void ct_fe_select(ct_fe* out, const ct_fe* a, const ct_fe* b, + uint32_t choice) { + const uint32_t mask = ct_mask(choice); + CT_COUNT(field_select); + for (size_t i = 0; i < CT_LIMBS; i++) { + out->v[i] = (a->v[i] & ~mask) | (b->v[i] & mask); + } +} + +static void ct_point_select(ct_point* out, const ct_point* a, const ct_point* b, + uint32_t choice) { + ct_fe_select(&out->x, &a->x, &b->x, choice); + ct_fe_select(&out->y, &a->y, &b->y, choice); + ct_fe_select(&out->z, &a->z, &b->z, choice); +} + +/* out = a - b. Returns 1 on underflow and 0 otherwise. */ +static uint32_t ct_sub_raw(ct_fe* out, const ct_fe* a, const ct_fe* b) { + uint64_t borrow = 0; + for (size_t i = 0; i < CT_LIMBS; i++) { + const uint64_t diff = (uint64_t)a->v[i] - b->v[i] - borrow; + out->v[i] = (uint32_t)diff; + borrow = diff >> 63; + } + return (uint32_t)borrow; +} + +static void ct_add_raw(ct_fe* out, const ct_fe* a, const ct_fe* b) { + uint64_t carry = 0; + for (size_t i = 0; i < CT_LIMBS; i++) { + const uint64_t sum = (uint64_t)a->v[i] + b->v[i] + carry; + out->v[i] = (uint32_t)sum; + carry = sum >> 32; + } +} + +static void ct_fe_add_mod(ct_fe* out, const ct_fe* a, const ct_fe* b, + const ct_modulus* mod) { + ct_fe sum; + ct_fe reduced; + CT_COUNT(field_add); + ct_add_raw(&sum, a, b); + const uint32_t borrow = ct_sub_raw(&reduced, &sum, &mod->modulus); + ct_fe_select(out, &reduced, &sum, borrow); +} + +static void ct_fe_sub_mod(ct_fe* out, const ct_fe* a, const ct_fe* b, + const ct_modulus* mod) { + ct_fe diff; + ct_fe corrected; + CT_COUNT(field_sub); + const uint32_t borrow = ct_sub_raw(&diff, a, b); + ct_add_raw(&corrected, &diff, &mod->modulus); + ct_fe_select(out, &diff, &corrected, borrow); +} + +/* Return one public-indexed 16-bit half-limb. */ +static uint32_t ct_half_limb(const ct_fe* value, size_t index) { + return (value->v[index / 2] >> ((index & 1u) * 16)) & UINT32_C(0xffff); +} + +/* + * Montgomery multiplication with radix 2^16 and sixteen limbs. + * + * Cortex-M3 UMULL/UMLAL instructions have operand-dependent early + * termination. Using 16-bit limbs keeps each product-plus-carry at or below + * UINT32_MAX, so the compiler can use the fixed-latency 32-bit MUL/MLA path. + * Both Pallas moduli have low half-limb 1, hence -m^-1 mod 2^16 = 0xffff. + * All carry propagation loops have public, fixed bounds. + */ +static void ct_fe_mul_mod(ct_fe* out, const ct_fe* a, const ct_fe* b, + const ct_modulus* mod) { + enum { CT_HALF_LIMBS = 2 * CT_LIMBS }; + uint16_t t[2 * CT_HALF_LIMBS + 1] = {0}; + CT_COUNT(field_mul); + + for (size_t i = 0; i < CT_HALF_LIMBS; i++) { + uint32_t carry = 0; + const uint32_t lhs = ct_half_limb(a, i); + for (size_t j = 0; j < CT_HALF_LIMBS; j++) { + const size_t k = i + j; + const uint32_t accum = lhs * ct_half_limb(b, j) + t[k] + carry; + t[k] = (uint16_t)accum; + carry = accum >> 16; + } + for (size_t k = i + CT_HALF_LIMBS; k <= 2 * CT_HALF_LIMBS; k++) { + const uint32_t accum = (uint32_t)t[k] + carry; + t[k] = (uint16_t)accum; + carry = accum >> 16; + } + } + + for (size_t i = 0; i < CT_HALF_LIMBS; i++) { + const uint32_t factor = (UINT32_C(0x10000) - t[i]) & UINT32_C(0xffff); + uint32_t carry = 0; + for (size_t j = 0; j < CT_HALF_LIMBS; j++) { + const size_t k = i + j; + const uint32_t accum = + factor * ct_half_limb(&mod->modulus, j) + t[k] + carry; + t[k] = (uint16_t)accum; + carry = accum >> 16; + } + for (size_t k = i + CT_HALF_LIMBS; k <= 2 * CT_HALF_LIMBS; k++) { + const uint32_t accum = (uint32_t)t[k] + carry; + t[k] = (uint16_t)accum; + carry = accum >> 16; + } + } + + ct_fe candidate; + ct_fe reduced; + for (size_t i = 0; i < CT_LIMBS; i++) { + candidate.v[i] = (uint32_t)t[2 * (i + CT_LIMBS)] | + (uint32_t)t[2 * (i + CT_LIMBS) + 1] << 16; + } + const uint32_t borrow = ct_sub_raw(&reduced, &candidate, &mod->modulus); + ct_fe_select(out, &reduced, &candidate, borrow); + memzero(t, sizeof(t)); +} + +static void ct_fe_square_mod(ct_fe* out, const ct_fe* a, + const ct_modulus* mod) { + ct_fe_mul_mod(out, a, a, mod); +} + +static void ct_words_from_bn(const bignum256* in, ct_fe* out) { + memset(out, 0, sizeof(*out)); + for (size_t i = 0; i < BN_LIMBS - 1; i++) { + const uint64_t value = in->val[i] & BN_LIMB_MASK; + const size_t bit = i * BN_BITS_PER_LIMB; + const size_t word = bit / 32; + const unsigned shift = bit % 32; + const uint64_t shifted = value << shift; + out->v[word] |= (uint32_t)shifted; + out->v[word + 1] |= (uint32_t)(shifted >> 32); + } + /* A canonical 256-bit bignum uses only the low 24 bits of limb eight. */ + out->v[CT_LIMBS - 1] |= (in->val[BN_LIMBS - 1] & UINT32_C(0x00ffffff)) << 8; +} + +static void ct_words_to_bn(const ct_fe* in, bignum256* out) { + for (size_t i = 0; i < BN_LIMBS; i++) { + const size_t bit = i * BN_BITS_PER_LIMB; + const size_t word = bit / 32; + const unsigned shift = bit % 32; + uint64_t pair = in->v[word]; + if (word + 1 < CT_LIMBS) { + pair |= (uint64_t)in->v[word + 1] << 32; + } + out->val[i] = (uint32_t)(pair >> shift) & BN_LIMB_MASK; + } +} + +static void ct_fe_from_bn(ct_fe* out, const bignum256* in, + const ct_modulus* mod) { + ct_fe words; + ct_words_from_bn(in, &words); + ct_fe_mul_mod(out, &words, &mod->r2, mod); + memzero(&words, sizeof(words)); +} + +static void ct_fe_to_bn(bignum256* out, const ct_fe* in, + const ct_modulus* mod) { + static const ct_fe raw_one = {{1, 0, 0, 0, 0, 0, 0, 0}}; + ct_fe words; + ct_fe_mul_mod(&words, in, &raw_one, mod); + ct_words_to_bn(&words, out); + memzero(&words, sizeof(words)); +} + +static void ct_fe_inv_p(ct_fe* out, const ct_fe* a) { + ct_fe result = CT_P.one; + for (int bit = 254; bit >= 0; bit--) { + ct_fe squared; + ct_fe multiplied; + const uint32_t exponent_bit = + (CT_P_MINUS_2[(unsigned)bit / 32] >> ((unsigned)bit % 32)) & 1u; + ct_fe_square_mod(&squared, &result, &CT_P); + ct_fe_mul_mod(&multiplied, &squared, a, &CT_P); + ct_fe_select(&result, &squared, &multiplied, exponent_bit); + } + *out = result; +} + +static void ct_point_identity(ct_point* p) { + memset(p, 0, sizeof(*p)); + p->y = CT_P.one; +} + +static uint32_t ct_point_is_identity(const ct_point* p) { + return ct_fe_is_zero(&p->z); +} + +static void ct_point_from_affine(ct_point* out, const curve_point* in) { + ct_fe_from_bn(&out->x, &in->x, &CT_P); + ct_fe_from_bn(&out->y, &in->y, &CT_P); + const uint32_t identity = ct_fe_is_zero(&out->x) & ct_fe_is_zero(&out->y); + ct_fe zero = {{0}}; + ct_fe_select(&out->z, &CT_P.one, &zero, identity); +} + +static void ct_point_to_affine(curve_point* out, const ct_point* in) { + const uint32_t identity = ct_point_is_identity(in); + ct_fe z_inv; + ct_fe z2; + ct_fe z3; + ct_fe x; + ct_fe y; + ct_fe zero = {{0}}; + + ct_fe_inv_p(&z_inv, &in->z); + ct_fe_square_mod(&z2, &z_inv, &CT_P); + ct_fe_mul_mod(&z3, &z2, &z_inv, &CT_P); + ct_fe_mul_mod(&x, &in->x, &z2, &CT_P); + ct_fe_mul_mod(&y, &in->y, &z3, &CT_P); + ct_fe_select(&x, &x, &zero, identity); + ct_fe_select(&y, &y, &zero, identity); + ct_fe_to_bn(&out->x, &x, &CT_P); + ct_fe_to_bn(&out->y, &y, &CT_P); + + memzero(&z_inv, sizeof(z_inv)); + memzero(&z2, sizeof(z2)); + memzero(&z3, sizeof(z3)); + memzero(&x, sizeof(x)); + memzero(&y, sizeof(y)); +} + +/* Jacobian doubling for y^2 = x^3 + 5 (dbl-2009-l). */ +static void ct_point_double(ct_point* out, const ct_point* p) { + ct_fe a, b, c, d, e, f, t0, t1; + ct_point result; + ct_point identity; + CT_COUNT(point_double); + + ct_fe_square_mod(&a, &p->x, &CT_P); + ct_fe_square_mod(&b, &p->y, &CT_P); + ct_fe_square_mod(&c, &b, &CT_P); + ct_fe_add_mod(&t0, &p->x, &b, &CT_P); + ct_fe_square_mod(&d, &t0, &CT_P); + ct_fe_sub_mod(&d, &d, &a, &CT_P); + ct_fe_sub_mod(&d, &d, &c, &CT_P); + ct_fe_add_mod(&d, &d, &d, &CT_P); + ct_fe_add_mod(&e, &a, &a, &CT_P); + ct_fe_add_mod(&e, &e, &a, &CT_P); + ct_fe_square_mod(&f, &e, &CT_P); + ct_fe_mul_mod(&t0, &p->z, &p->y, &CT_P); + ct_fe_add_mod(&result.z, &t0, &t0, &CT_P); + ct_fe_add_mod(&t0, &d, &d, &CT_P); + ct_fe_sub_mod(&result.x, &f, &t0, &CT_P); + ct_fe_sub_mod(&t0, &d, &result.x, &CT_P); + ct_fe_mul_mod(&t1, &e, &t0, &CT_P); + ct_fe_add_mod(&t0, &c, &c, &CT_P); + ct_fe_add_mod(&t0, &t0, &t0, &CT_P); + ct_fe_add_mod(&t0, &t0, &t0, &CT_P); + ct_fe_sub_mod(&result.y, &t1, &t0, &CT_P); + + ct_point_identity(&identity); + ct_point_select(out, &result, &identity, ct_point_is_identity(p)); +} + +/* + * Complete-by-selection Jacobian addition. The generic formula, doubling, + * opposite-point result, and identity cases are all computed before masks + * select the correct result. + */ +static void ct_point_add_internal(ct_point* out, const ct_point* p, + const ct_point* q) { + ct_fe z1z1, z2z2, u1, u2, s1, s2, h, i, j, r, v, t0, t1; + ct_point generic; + ct_point doubled; + ct_point identity; + CT_COUNT(point_add); + + ct_fe_square_mod(&z1z1, &p->z, &CT_P); + ct_fe_square_mod(&z2z2, &q->z, &CT_P); + ct_fe_mul_mod(&u1, &p->x, &z2z2, &CT_P); + ct_fe_mul_mod(&u2, &q->x, &z1z1, &CT_P); + ct_fe_mul_mod(&t0, &z2z2, &q->z, &CT_P); + ct_fe_mul_mod(&s1, &p->y, &t0, &CT_P); + ct_fe_mul_mod(&t0, &z1z1, &p->z, &CT_P); + ct_fe_mul_mod(&s2, &q->y, &t0, &CT_P); + + ct_fe_sub_mod(&h, &u2, &u1, &CT_P); + ct_fe_add_mod(&t0, &h, &h, &CT_P); + ct_fe_square_mod(&i, &t0, &CT_P); + ct_fe_mul_mod(&j, &h, &i, &CT_P); + ct_fe_sub_mod(&r, &s2, &s1, &CT_P); + ct_fe_add_mod(&r, &r, &r, &CT_P); + ct_fe_mul_mod(&v, &u1, &i, &CT_P); + ct_fe_square_mod(&generic.x, &r, &CT_P); + ct_fe_sub_mod(&generic.x, &generic.x, &j, &CT_P); + ct_fe_sub_mod(&generic.x, &generic.x, &v, &CT_P); + ct_fe_sub_mod(&generic.x, &generic.x, &v, &CT_P); + ct_fe_sub_mod(&t0, &v, &generic.x, &CT_P); + ct_fe_mul_mod(&t0, &r, &t0, &CT_P); + ct_fe_mul_mod(&t1, &s1, &j, &CT_P); + ct_fe_add_mod(&t1, &t1, &t1, &CT_P); + ct_fe_sub_mod(&generic.y, &t0, &t1, &CT_P); + ct_fe_add_mod(&t0, &p->z, &q->z, &CT_P); + ct_fe_square_mod(&generic.z, &t0, &CT_P); + ct_fe_sub_mod(&generic.z, &generic.z, &z1z1, &CT_P); + ct_fe_sub_mod(&generic.z, &generic.z, &z2z2, &CT_P); + ct_fe_mul_mod(&generic.z, &generic.z, &h, &CT_P); + + ct_point_double(&doubled, p); + ct_point_identity(&identity); + + const uint32_t p_identity = ct_point_is_identity(p); + const uint32_t q_identity = ct_point_is_identity(q); + const uint32_t same_x = ct_fe_equal(&u1, &u2); + const uint32_t same_y = ct_fe_equal(&s1, &s2); + const uint32_t neither_identity = (p_identity | q_identity) ^ 1u; + const uint32_t same = same_x & same_y & neither_identity; + const uint32_t opposite = same_x & (same_y ^ 1u) & neither_identity; + + *out = generic; + ct_point_select(out, out, &doubled, same); + ct_point_select(out, out, &identity, opposite); + ct_point_select(out, out, q, p_identity); + ct_point_select(out, out, p, q_identity); +} + +void pallas_ct_point_mult(const bignum256* k, const curve_point* p, + curve_point* res) { + ct_fe scalar_mont; + ct_fe scalar; + ct_point base; + ct_point acc; + static const ct_fe raw_one = {{1, 0, 0, 0, 0, 0, 0, 0}}; + + /* Canonicalize k modulo the Pallas group order without a data branch. */ + ct_fe_from_bn(&scalar_mont, k, &CT_Q); + ct_fe_mul_mod(&scalar, &scalar_mont, &raw_one, &CT_Q); + ct_point_from_affine(&base, p); + ct_point_identity(&acc); + + for (int bit = 254; bit >= 0; bit--) { + ct_point doubled; + ct_point added; + const uint32_t scalar_bit = + (scalar.v[(unsigned)bit / 32] >> ((unsigned)bit % 32)) & 1u; + CT_COUNT(scalar_round); + ct_point_double(&doubled, &acc); + ct_point_add_internal(&added, &doubled, &base); + ct_point_select(&acc, &doubled, &added, scalar_bit); + } + + ct_point_to_affine(res, &acc); + memzero(&scalar_mont, sizeof(scalar_mont)); + memzero(&scalar, sizeof(scalar)); + memzero(&base, sizeof(base)); + memzero(&acc, sizeof(acc)); +} + +void pallas_ct_point_add(const curve_point* p, const curve_point* q, + curve_point* res) { + ct_point lhs; + ct_point rhs; + ct_point sum; + ct_point_from_affine(&lhs, p); + ct_point_from_affine(&rhs, q); + ct_point_add_internal(&sum, &lhs, &rhs); + ct_point_to_affine(res, &sum); + memzero(&lhs, sizeof(lhs)); + memzero(&rhs, sizeof(rhs)); + memzero(&sum, sizeof(sum)); +} + +void pallas_ct_mul_mod_p(bignum256* x, const bignum256* k) { + ct_fe lhs, rhs, result; + ct_fe_from_bn(&lhs, x, &CT_P); + ct_fe_from_bn(&rhs, k, &CT_P); + ct_fe_mul_mod(&result, &lhs, &rhs, &CT_P); + ct_fe_to_bn(x, &result, &CT_P); + memzero(&lhs, sizeof(lhs)); + memzero(&rhs, sizeof(rhs)); + memzero(&result, sizeof(result)); +} + +void pallas_ct_add_mod_p(const bignum256* a, const bignum256* b, + bignum256* res) { + ct_fe lhs, rhs, result; + ct_fe_from_bn(&lhs, a, &CT_P); + ct_fe_from_bn(&rhs, b, &CT_P); + ct_fe_add_mod(&result, &lhs, &rhs, &CT_P); + ct_fe_to_bn(res, &result, &CT_P); +} + +void pallas_ct_sub_mod_p(const bignum256* a, const bignum256* b, + bignum256* res) { + ct_fe lhs, rhs, result; + ct_fe_from_bn(&lhs, a, &CT_P); + ct_fe_from_bn(&rhs, b, &CT_P); + ct_fe_sub_mod(&result, &lhs, &rhs, &CT_P); + ct_fe_to_bn(res, &result, &CT_P); +} + +void pallas_ct_inv_mod_p(bignum256* x) { + ct_fe value, inverse; + ct_fe_from_bn(&value, x, &CT_P); + ct_fe_inv_p(&inverse, &value); + ct_fe_to_bn(x, &inverse, &CT_P); + memzero(&value, sizeof(value)); + memzero(&inverse, sizeof(inverse)); +} + +void pallas_ct_mod_p(bignum256* x) { + ct_fe value; + ct_fe_from_bn(&value, x, &CT_P); + ct_fe_to_bn(x, &value, &CT_P); + memzero(&value, sizeof(value)); +} + +void pallas_ct_mul_mod_q(bignum256* x, const bignum256* k) { + ct_fe lhs, rhs, result; + ct_fe_from_bn(&lhs, x, &CT_Q); + ct_fe_from_bn(&rhs, k, &CT_Q); + ct_fe_mul_mod(&result, &lhs, &rhs, &CT_Q); + ct_fe_to_bn(x, &result, &CT_Q); + memzero(&lhs, sizeof(lhs)); + memzero(&rhs, sizeof(rhs)); + memzero(&result, sizeof(result)); +} + +void pallas_ct_add_mod_q(bignum256* a, const bignum256* b) { + ct_fe lhs, rhs, result; + ct_fe_from_bn(&lhs, a, &CT_Q); + ct_fe_from_bn(&rhs, b, &CT_Q); + ct_fe_add_mod(&result, &lhs, &rhs, &CT_Q); + ct_fe_to_bn(a, &result, &CT_Q); +} + +void pallas_ct_mod_q(bignum256* x) { + ct_fe value; + ct_fe_from_bn(&value, x, &CT_Q); + ct_fe_to_bn(x, &value, &CT_Q); + memzero(&value, sizeof(value)); +} + +void pallas_ct_scalar_replace_zero_with_one(bignum256* scalar) { + uint32_t nonzero = 0; + for (size_t i = 0; i < BN_LIMBS; i++) { + nonzero |= scalar->val[i]; + } + scalar->val[0] |= ct_secret_u32_is_zero(nonzero); +} diff --git a/deps/crypto/trezor-crypto/pallas_ct.h b/deps/crypto/trezor-crypto/pallas_ct.h new file mode 100644 index 000000000..f685676fc --- /dev/null +++ b/deps/crypto/trezor-crypto/pallas_ct.h @@ -0,0 +1,49 @@ +/** + * Constant-time Pallas arithmetic for secret-scalar operations. + * + * This module intentionally has a narrow interface matching the legacy Pallas + * API types. Internally it uses fixed-width Montgomery arithmetic and + * branchless Jacobian point operations. It must be used for every operation + * whose inputs include Orchard secret scalars. + */ + +#ifndef __PALLAS_CT_H__ +#define __PALLAS_CT_H__ + +#include "bignum.h" +#include "ecdsa.h" + +void pallas_ct_mul_mod_p(bignum256* x, const bignum256* k); +void pallas_ct_add_mod_p(const bignum256* a, const bignum256* b, + bignum256* res); +void pallas_ct_sub_mod_p(const bignum256* a, const bignum256* b, + bignum256* res); +void pallas_ct_inv_mod_p(bignum256* x); +void pallas_ct_mod_p(bignum256* x); + +void pallas_ct_mul_mod_q(bignum256* x, const bignum256* k); +void pallas_ct_add_mod_q(bignum256* a, const bignum256* b); +void pallas_ct_mod_q(bignum256* x); +void pallas_ct_scalar_replace_zero_with_one(bignum256* scalar); + +void pallas_ct_point_add(const curve_point* p, const curve_point* q, + curve_point* res); +void pallas_ct_point_mult(const bignum256* k, const curve_point* p, + curve_point* res); + +#ifdef PALLAS_CT_TESTING +typedef struct { + uint32_t field_add; + uint32_t field_sub; + uint32_t field_mul; + uint32_t field_select; + uint32_t point_add; + uint32_t point_double; + uint32_t scalar_round; +} pallas_ct_counts; + +void pallas_ct_test_reset_counts(void); +void pallas_ct_test_get_counts(pallas_ct_counts* counts); +#endif + +#endif diff --git a/deps/crypto/trezor-crypto/redpallas.c b/deps/crypto/trezor-crypto/redpallas.c index 6694c6f14..277b42307 100644 --- a/deps/crypto/trezor-crypto/redpallas.c +++ b/deps/crypto/trezor-crypto/redpallas.c @@ -36,6 +36,7 @@ #include "ecdsa.h" #include "memzero.h" #include "pallas.h" +#include "pallas_ct.h" #include "rand.h" /* @@ -139,11 +140,6 @@ static void pallas_scalar_mult_spendauth(const bignum256 *k, curve_point *res) { pallas_point_deserialize(pallas_spendauth_G_bytes, &spendauth_G_cache); spendauth_G_initialized = 1; } - if (bn_is_zero(k)) { - bn_zero(&res->x); - bn_zero(&res->y); - return; - } pallas_point_mult(k, &spendauth_G_cache, res); } @@ -255,10 +251,8 @@ int redpallas_sign_digest(const uint8_t *ask, const uint8_t *alpha, bn_read_le(rbuf, &r); pallas_mod_q(&r); - /* Ensure r is not zero */ - if (bn_is_zero(&r)) { - r.val[0] = 1; - } + /* Ensure r is not zero without branching on the secret nonce. */ + pallas_ct_scalar_replace_zero_with_one(&r); /* R = [r]G_spendauth - nonce commitment */ pallas_scalar_mult_spendauth(&r, &R_point); diff --git a/deps/crypto/trezor-crypto/tests/test_pallas_ct.c b/deps/crypto/trezor-crypto/tests/test_pallas_ct.c new file mode 100644 index 000000000..d0e810a01 --- /dev/null +++ b/deps/crypto/trezor-crypto/tests/test_pallas_ct.c @@ -0,0 +1,119 @@ +/* + * Secret-flow regression harness for Pallas scalar multiplication. + * + * With VALGRIND=1, scalar bytes are marked undefined before multiplication. + * Memcheck then reports any conditional branch or memory address derived from + * the scalar (the standard ctgrind technique already used by test_check.c). + */ + +#include +#include +#include + +#if VALGRIND +#include +#include +#endif + +#include "pallas_ct.h" + +static const curve_point PALLAS_GENERATOR = { + {/* x = p - 1 */ {0x00000000, 0x09698768, 0x133e46e6, 0x0d31f812, + 0x00000224, 0x00000000, 0x00000000, 0x00000000, + 0x00400000}}, + {/* y = 2 */ {0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000}}, +}; + +static bignum256 scalar_with_bit(unsigned bit) { + bignum256 scalar = {{0}}; + scalar.val[bit / BN_BITS_PER_LIMB] = UINT32_C(1) << (bit % BN_BITS_PER_LIMB); + return scalar; +} + +static bignum256 dense_scalar(void) { + bignum256 scalar; + size_t i; + for (i = 0; i < BN_LIMBS - 1; ++i) { + scalar.val[i] = BN_LIMB_MASK; + } + scalar.val[BN_LIMBS - 1] = (UINT32_C(1) << 22) - 1; + return scalar; +} + +static bignum256 max_256(void) { + bignum256 value; + size_t i; + for (i = 0; i < BN_LIMBS - 1; ++i) { + value.val[i] = BN_LIMB_MASK; + } + value.val[BN_LIMBS - 1] = UINT32_C(0x00ffffff); + return value; +} + +static void multiply_secret(const bignum256* input, curve_point* result) { + bignum256 scalar = *input; +#if VALGRIND + VALGRIND_MAKE_MEM_UNDEFINED(&scalar, sizeof(scalar)); +#endif + pallas_ct_point_mult(&scalar, &PALLAS_GENERATOR, result); +#if VALGRIND + VALGRIND_MAKE_MEM_DEFINED(&scalar, sizeof(scalar)); + VALGRIND_MAKE_MEM_DEFINED(result, sizeof(*result)); +#endif + memset(&scalar, 0, sizeof(scalar)); +} + +static void normalize_secret(const bignum256* input) { + bignum256 scalar = *input; +#if VALGRIND + VALGRIND_MAKE_MEM_UNDEFINED(&scalar, sizeof(scalar)); +#endif + pallas_ct_scalar_replace_zero_with_one(&scalar); +#if VALGRIND + VALGRIND_MAKE_MEM_DEFINED(&scalar, sizeof(scalar)); +#endif + memset(&scalar, 0, sizeof(scalar)); +} + +int main(void) { + const bignum256 scalars[] = { + {{0}}, + scalar_with_bit(0), + scalar_with_bit(17), + scalar_with_bit(254), + dense_scalar(), + max_256(), + }; + const curve_point identity = {{{0}}, {{0}}}; + curve_point result; + size_t i; + +#if VALGRIND + if (!RUNNING_ON_VALGRIND) { + fprintf(stderr, "VALGRIND=1 harness must run under Valgrind\n"); + return 2; + } +#endif + + for (i = 0; i < sizeof(scalars) / sizeof(scalars[0]); ++i) { + normalize_secret(&scalars[i]); + multiply_secret(&scalars[i], &result); + } + + multiply_secret(&scalars[0], &result); + if (memcmp(&result, &identity, sizeof(result)) != 0) { + fprintf(stderr, "zero scalar did not produce the identity\n"); + return 1; + } + + multiply_secret(&scalars[1], &result); + if (memcmp(&result, &PALLAS_GENERATOR, sizeof(result)) != 0) { + fprintf(stderr, "one scalar did not reproduce the generator\n"); + return 1; + } + + memset(&result, 0, sizeof(result)); + puts("Pallas constant-time secret-flow harness: PASS"); + return 0; +} diff --git a/tools/check_pallas_ct_disassembly.py b/tools/check_pallas_ct_disassembly.py new file mode 100644 index 000000000..f8308c526 --- /dev/null +++ b/tools/check_pallas_ct_disassembly.py @@ -0,0 +1,237 @@ +#!/usr/bin/env python3 +"""Enforce the fixed-schedule shape of the ARM Pallas scalar multiplier.""" + +import argparse +import re +import subprocess +import sys +from pathlib import Path + + +SYMBOL_RE = re.compile(r"^([0-9a-fA-F]+) <([^>]+)>:$") +CONDITIONAL_BRANCHES = { + "beq", + "bne", + "bcs", + "bcc", + "bmi", + "bpl", + "bvs", + "bvc", + "bhi", + "bls", + "bge", + "blt", + "bgt", + "ble", + "cbz", + "cbnz", +} +FORBIDDEN_VARIABLE_LATENCY = {"umull", "umlal", "smull", "smlal", "udiv", "sdiv"} + + +def parse_instruction(line): + parts = [part.strip() for part in line.split("\t") if part.strip()] + if len(parts) < 3 or not parts[0].endswith(":"): + return None + try: + address = int(parts[0][:-1], 16) + except ValueError: + return None + mnemonic = parts[2].split(".", 1)[0] + operands = parts[3] if len(parts) > 3 else "" + return address, mnemonic, operands + + +def symbol_instructions(disassembly, symbol): + lines = disassembly.splitlines() + start = None + for index, line in enumerate(lines): + match = SYMBOL_RE.match(line) + if match and match.group(2) == symbol: + start = index + 1 + break + if start is None: + return None + + instructions = [] + for line in lines[start:]: + if SYMBOL_RE.match(line): + break + instruction = parse_instruction(line) + if instruction is not None: + instructions.append(instruction) + return instructions + + +def branch_target(operands): + match = re.match(r"([0-9a-fA-F]+)", operands) + return int(match.group(1), 16) if match else None + + +def verify_full(disassembly): + symbol = "pallas_ct_point_mult" + instructions = symbol_instructions(disassembly, symbol) + if instructions is None: + raise ValueError(f"missing required ARM symbol: {symbol}") + + non_canary_branches = [] + for index, instruction in enumerate(instructions): + address, mnemonic, operands = instruction + if mnemonic not in CONDITIONAL_BRANCHES: + continue + + next_instruction = ( + instructions[index + 1] if index + 1 < len(instructions) else None + ) + if ( + next_instruction is not None + and next_instruction[1] == "bl" + and "<__stack_chk_fail>" in next_instruction[2] + ): + continue + non_canary_branches.append((address, mnemonic, branch_target(operands))) + + if len(non_canary_branches) != 1: + raise ValueError( + f"{symbol} must have one fixed loop branch; found " + f"{non_canary_branches}" + ) + + branch_address, mnemonic, target = non_canary_branches[0] + if target is None or target >= branch_address: + raise ValueError(f"{symbol} loop branch is not backward: {non_canary_branches[0]}") + + required_calls = { + "ct_point_double": None, + "ct_point_add_internal": None, + "ct_point_select": None, + } + for address, instruction_mnemonic, operands in instructions: + if instruction_mnemonic != "bl": + continue + for required in required_calls: + if f"<{required}>" in operands: + required_calls[required] = address + + missing = [name for name, address in required_calls.items() if address is None] + if missing: + raise ValueError(f"{symbol} is missing fixed-round calls: {missing}") + outside_loop = [ + name + for name, address in required_calls.items() + if not target <= address < branch_address + ] + if outside_loop: + raise ValueError(f"fixed-round calls moved outside scalar loop: {outside_loop}") + + # Secret-dependent selects are written as masks. On the pinned ARM build, + # every remaining conditional branch in this module must therefore be a + # backward, fixed-bound loop (apart from stack-canary failure branches). + unexpected_branches = [] + ct_symbols = [] + for line in disassembly.splitlines(): + match = SYMBOL_RE.match(line) + if match and match.group(2).startswith(("ct_", "pallas_ct_")): + ct_symbols.append(match.group(2)) + for ct_symbol in ct_symbols: + ct_instructions = symbol_instructions(disassembly, ct_symbol) + for index, instruction in enumerate(ct_instructions): + address, instruction_mnemonic, operands = instruction + if instruction_mnemonic not in CONDITIONAL_BRANCHES: + continue + next_instruction = ( + ct_instructions[index + 1] + if index + 1 < len(ct_instructions) + else None + ) + if ( + next_instruction is not None + and next_instruction[1] == "bl" + and "<__stack_chk_fail>" in next_instruction[2] + ): + continue + ct_target = branch_target(operands) + if ct_target is None or ct_target >= address: + unexpected_branches.append((ct_symbol, instruction)) + if unexpected_branches: + raise ValueError( + "secret arithmetic contains a non-loop conditional branch: " + f"{unexpected_branches}" + ) + + current_symbol = None + forbidden_instructions = [] + forbidden_conditional_execution = [] + for line in disassembly.splitlines(): + symbol_match = SYMBOL_RE.match(line) + if symbol_match: + current_symbol = symbol_match.group(2) + continue + if current_symbol is None or not current_symbol.startswith(("ct_", "pallas_ct_")): + continue + instruction = parse_instruction(line) + if instruction is None: + continue + if instruction[1] in FORBIDDEN_VARIABLE_LATENCY: + forbidden_instructions.append((current_symbol, instruction)) + if instruction[1].startswith("it") and current_symbol != "ct_fe_to_bn": + forbidden_conditional_execution.append((current_symbol, instruction)) + if forbidden_instructions: + raise ValueError( + "secret arithmetic contains variable-latency long multiply/divide: " + f"{forbidden_instructions}" + ) + if forbidden_conditional_execution: + raise ValueError( + "secret arithmetic contains conditional execution: " + f"{forbidden_conditional_execution}" + ) + + print( + "Pallas ARM disassembly gate: PASS " + f"(one backward {mnemonic} loop; double/add/select all inside; " + "only fixed backward loops; no secret IT; no long multiply/divide)" + ) + + +def verify_bitcoin_only(disassembly): + forbidden = ("pallas_ct_", "redpallas_", "pallas_point_") + present = [name for name in forbidden if f"<{name}" in disassembly] + if present: + raise ValueError(f"bitcoin-only image contains privacy symbols: {present}") + print("Pallas ARM disassembly gate: PASS (privacy code absent from bitcoin-only)") + + +def main(): + parser = argparse.ArgumentParser() + source = parser.add_mutually_exclusive_group(required=True) + source.add_argument("--elf", type=Path) + source.add_argument("--disassembly", type=Path) + parser.add_argument("--objdump", default="arm-none-eabi-objdump") + parser.add_argument("--variant", choices=("full", "bitcoin-only"), required=True) + args = parser.parse_args() + + if args.disassembly: + disassembly = args.disassembly.read_text(encoding="utf-8") + else: + result = subprocess.run( + [args.objdump, "-d", str(args.elf)], + check=True, + stdout=subprocess.PIPE, + universal_newlines=True, + ) + disassembly = result.stdout + + if args.variant == "full": + verify_full(disassembly) + else: + verify_bitcoin_only(disassembly) + + +if __name__ == "__main__": + try: + main() + except (OSError, subprocess.CalledProcessError, ValueError) as error: + print(f"Pallas ARM disassembly gate: FAIL: {error}", file=sys.stderr) + sys.exit(1) diff --git a/unittests/crypto/CMakeLists.txt b/unittests/crypto/CMakeLists.txt index 9f5df0193..7b32fab34 100644 --- a/unittests/crypto/CMakeLists.txt +++ b/unittests/crypto/CMakeLists.txt @@ -25,6 +25,20 @@ target_link_libraries(crypto-unit # Orchard/Pallas engine + its unit test only exist when privacy is built in. if(${KK_ZCASH_PRIVACY}) + # Compile the constant-time implementation a second time with test-only + # operation counters. Keeping this separate from trezorcrypto ensures the + # counters are never present in firmware or the normal emulator binary. + add_executable(pallas-ct-unit + pallas_ct.cpp + ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-crypto/pallas_ct.c + ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-crypto/memzero.c) + target_compile_definitions(pallas-ct-unit PRIVATE PALLAS_CT_TESTING) + target_include_directories(pallas-ct-unit PRIVATE + ${CMAKE_SOURCE_DIR}/include + ${CMAKE_BINARY_DIR}/include + ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-crypto) + target_link_libraries(pallas-ct-unit gtest_main) + add_executable(zcash-crypto-unit ../firmware/zcash.cpp ${CMAKE_SOURCE_DIR}/lib/firmware/zcash.c diff --git a/unittests/crypto/pallas_ct.cpp b/unittests/crypto/pallas_ct.cpp new file mode 100644 index 000000000..9c94eb250 --- /dev/null +++ b/unittests/crypto/pallas_ct.cpp @@ -0,0 +1,242 @@ +extern "C" { +#include "pallas_ct.h" +} + +#include +#include +#include + +#include "gtest/gtest.h" + +namespace { + +const curve_point kPallasGenerator = { + {/* x = p - 1 */ {0x00000000, 0x09698768, 0x133e46e6, 0x0d31f812, + 0x00000224, 0x00000000, 0x00000000, 0x00000000, + 0x00400000}}, + {/* y = 2 */ {0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000}}, +}; + +const bignum256 kPallasPrime = {{0x00000001, 0x09698768, 0x133e46e6, 0x0d31f812, + 0x00000224, 0x00000000, 0x00000000, 0x00000000, + 0x00400000}}; + +const bignum256 kPallasOrder = {{0x00000001, 0x02375908, 0x052a3763, 0x0d31f813, + 0x00000224, 0x00000000, 0x00000000, 0x00000000, + 0x00400000}}; + +bignum256 ScalarWithBit(unsigned bit) { + bignum256 scalar = {{0}}; + scalar.val[bit / BN_BITS_PER_LIMB] = UINT32_C(1) << (bit % BN_BITS_PER_LIMB); + return scalar; +} + +bignum256 DenseScalar() { + bignum256 scalar; + for (size_t i = 0; i < BN_LIMBS - 1; ++i) { + scalar.val[i] = BN_LIMB_MASK; + } + scalar.val[BN_LIMBS - 1] = (UINT32_C(1) << 22) - 1; + return scalar; +} + +bignum256 Max256() { + bignum256 value; + for (size_t i = 0; i < BN_LIMBS - 1; ++i) { + value.val[i] = BN_LIMB_MASK; + } + value.val[BN_LIMBS - 1] = UINT32_C(0x00ffffff); + return value; +} + +bool PointsEqual(const curve_point& lhs, const curve_point& rhs) { + return std::memcmp(&lhs, &rhs, sizeof(lhs)) == 0; +} + +bool BignumsEqual(const bignum256& lhs, const bignum256& rhs) { + return std::memcmp(&lhs, &rhs, sizeof(lhs)) == 0; +} + +void ExpectCountsEqual(const pallas_ct_counts& lhs, + const pallas_ct_counts& rhs) { + EXPECT_EQ(lhs.field_add, rhs.field_add); + EXPECT_EQ(lhs.field_sub, rhs.field_sub); + EXPECT_EQ(lhs.field_mul, rhs.field_mul); + EXPECT_EQ(lhs.field_select, rhs.field_select); + EXPECT_EQ(lhs.point_add, rhs.point_add); + EXPECT_EQ(lhs.point_double, rhs.point_double); + EXPECT_EQ(lhs.scalar_round, rhs.scalar_round); +} + +pallas_ct_counts MultiplyAndCount(const bignum256& scalar, + curve_point* result) { + pallas_ct_counts counts; + pallas_ct_test_reset_counts(); + pallas_ct_point_mult(&scalar, &kPallasGenerator, result); + pallas_ct_test_get_counts(&counts); + return counts; +} + +TEST(PallasConstantTime, ScalarScheduleDoesNotDependOnSecretBits) { + const bignum256 zero = {{0}}; + const bignum256 one = ScalarWithBit(0); + const bignum256 low_sparse = ScalarWithBit(17); + const bignum256 high_sparse = ScalarWithBit(254); + const bignum256 dense = DenseScalar(); + const bignum256 max_256 = Max256(); + bignum256 order_plus_one = kPallasOrder; + ++order_plus_one.val[0]; + const std::array scalars = { + zero, one, low_sparse, high_sparse, + dense, max_256, kPallasOrder, order_plus_one, + }; + + curve_point result; + const pallas_ct_counts baseline = MultiplyAndCount(scalars[0], &result); + EXPECT_EQ(255u, baseline.scalar_round); + EXPECT_EQ(255u, baseline.point_add); + EXPECT_EQ(510u, baseline.point_double); + + for (size_t i = 1; i < scalars.size(); ++i) { + const pallas_ct_counts counts = MultiplyAndCount(scalars[i], &result); + ExpectCountsEqual(baseline, counts); + } +} + +TEST(PallasConstantTime, ZeroAndOneScalarResultsAreCanonical) { + const bignum256 zero = {{0}}; + const bignum256 one = ScalarWithBit(0); + const curve_point identity = {{{0}}, {{0}}}; + curve_point result; + + MultiplyAndCount(zero, &result); + EXPECT_TRUE(PointsEqual(identity, result)); + + MultiplyAndCount(one, &result); + EXPECT_TRUE(PointsEqual(kPallasGenerator, result)); +} + +TEST(PallasConstantTime, PointAdditionHandlesExceptionalCases) { + const curve_point identity = {{{0}}, {{0}}}; + curve_point result; + + pallas_ct_point_add(&identity, &kPallasGenerator, &result); + EXPECT_TRUE(PointsEqual(kPallasGenerator, result)); + + pallas_ct_point_add(&kPallasGenerator, &identity, &result); + EXPECT_TRUE(PointsEqual(kPallasGenerator, result)); + + curve_point inverse = kPallasGenerator; + inverse.y.val[0] = 0x1fffffff; + inverse.y.val[1] = 0x09698767; + inverse.y.val[2] = 0x133e46e6; + inverse.y.val[3] = 0x0d31f812; + inverse.y.val[4] = 0x00000224; + inverse.y.val[8] = 0x00400000; + pallas_ct_point_add(&kPallasGenerator, &inverse, &result); + EXPECT_TRUE(PointsEqual(identity, result)); +} + +TEST(PallasConstantTime, FieldArithmeticCanonicalizesBoundaryValues) { + const bignum256 zero = {{0}}; + const bignum256 one = ScalarWithBit(0); + bignum256 prime_plus_one = kPallasPrime; + bignum256 prime_minus_one = kPallasPrime; + bignum256 prime_minus_two = kPallasPrime; + const bignum256 max_256 = Max256(); + const bignum256 max_reduced = {{0x1ffffffc, 0x03c369c7, 0x06452b4d, + 0x186a17c8, 0x1ffff992, 0x1fffffff, + 0x1fffffff, 0x1fffffff, 0x003fffff}}; + bignum256 result; + ++prime_plus_one.val[0]; + --prime_minus_one.val[0]; + prime_minus_two.val[0] = BN_LIMB_MASK; + --prime_minus_two.val[1]; + + result = kPallasPrime; + pallas_ct_mod_p(&result); + EXPECT_TRUE(BignumsEqual(zero, result)); + + result = prime_plus_one; + pallas_ct_mod_p(&result); + EXPECT_TRUE(BignumsEqual(one, result)); + + result = max_256; + pallas_ct_mod_p(&result); + EXPECT_TRUE(BignumsEqual(max_reduced, result)); + + result = prime_minus_one; + pallas_ct_mul_mod_p(&result, &prime_minus_one); + EXPECT_TRUE(BignumsEqual(one, result)); + + result = prime_minus_one; + pallas_ct_inv_mod_p(&result); + EXPECT_TRUE(BignumsEqual(prime_minus_one, result)); + + pallas_ct_add_mod_p(&prime_minus_one, &prime_minus_one, &result); + EXPECT_TRUE(BignumsEqual(prime_minus_two, result)); + + pallas_ct_sub_mod_p(&zero, &one, &result); + EXPECT_TRUE(BignumsEqual(prime_minus_one, result)); +} + +TEST(PallasConstantTime, ScalarArithmeticAndMultiplicationReduceModOrder) { + const bignum256 zero = {{0}}; + const bignum256 one = ScalarWithBit(0); + bignum256 order_plus_one = kPallasOrder; + bignum256 order_minus_one = kPallasOrder; + const bignum256 max_256 = Max256(); + const bignum256 max_reduced = {{0x1ffffffc, 0x1959f4e7, 0x108159d6, + 0x186a17c6, 0x1ffff992, 0x1fffffff, + 0x1fffffff, 0x1fffffff, 0x003fffff}}; + bignum256 result; + curve_point point; + const curve_point identity = {{{0}}, {{0}}}; + ++order_plus_one.val[0]; + --order_minus_one.val[0]; + + result = kPallasOrder; + pallas_ct_mod_q(&result); + EXPECT_TRUE(BignumsEqual(zero, result)); + + result = order_plus_one; + pallas_ct_mod_q(&result); + EXPECT_TRUE(BignumsEqual(one, result)); + + result = max_256; + pallas_ct_mod_q(&result); + EXPECT_TRUE(BignumsEqual(max_reduced, result)); + + result = order_minus_one; + pallas_ct_mul_mod_q(&result, &order_minus_one); + EXPECT_TRUE(BignumsEqual(one, result)); + + result = order_minus_one; + pallas_ct_add_mod_q(&result, &one); + EXPECT_TRUE(BignumsEqual(zero, result)); + + MultiplyAndCount(kPallasOrder, &point); + EXPECT_TRUE(PointsEqual(identity, point)); + + MultiplyAndCount(order_plus_one, &point); + EXPECT_TRUE(PointsEqual(kPallasGenerator, point)); +} + +TEST(PallasConstantTime, NonzeroScalarNormalizationIsBranchlessAndCanonical) { + bignum256 zero = {{0}}; + bignum256 one = ScalarWithBit(0); + bignum256 max_256 = Max256(); + const bignum256 expected_one = one; + const bignum256 expected_max = max_256; + + pallas_ct_scalar_replace_zero_with_one(&zero); + pallas_ct_scalar_replace_zero_with_one(&one); + pallas_ct_scalar_replace_zero_with_one(&max_256); + + EXPECT_TRUE(BignumsEqual(expected_one, zero)); + EXPECT_TRUE(BignumsEqual(expected_one, one)); + EXPECT_TRUE(BignumsEqual(expected_max, max_256)); +} + +} // namespace From 030c43e0dbcb0a2c28a5239a072ef5f993454fad Mon Sep 17 00:00:00 2001 From: highlander Date: Sat, 25 Jul 2026 21:45:06 -0300 Subject: [PATCH 10/22] fix(zcash): restore practical Orchard signing latency --- .github/workflows/ci.yml | 1 + deps/crypto/trezor-crypto/pallas.c | 468 ++++++++++++++++-- deps/crypto/trezor-crypto/pallas.h | 57 ++- deps/crypto/trezor-crypto/pallas_ct.c | 2 + deps/crypto/trezor-crypto/pallas_sinsemilla.c | 9 +- deps/crypto/trezor-crypto/redpallas.c | 16 +- lib/firmware/zcash.c | 21 +- tools/check_pallas_api_boundary.py | 107 ++++ 8 files changed, 588 insertions(+), 93 deletions(-) create mode 100644 tools/check_pallas_api_boundary.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d6a733035..c4bdb9109 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -210,6 +210,7 @@ jobs: - name: Enforce RC18 security invariants run: | + python3 tools/check_pallas_api_boundary.py if git grep -n -E \ 'uses:[[:space:]]+[^#[:space:]]+@(v[0-9]+|main|master)([[:space:]#]|$)' \ -- .github/workflows; then diff --git a/deps/crypto/trezor-crypto/pallas.c b/deps/crypto/trezor-crypto/pallas.c index 20cd3f145..1363b9240 100644 --- a/deps/crypto/trezor-crypto/pallas.c +++ b/deps/crypto/trezor-crypto/pallas.c @@ -9,8 +9,8 @@ * IMPORTANT: The trezor-crypto bignum library assumes primes in the range * [2^256 - 2^224, 2^256]. The Pallas prime (~2^254) falls outside this range, * so bn_multiply/bn_inverse/bn_fast_mod produce incorrect results. - * pallas_ct.c implements fixed-width Montgomery field arithmetic and the - * fixed-schedule projective path used for secret scalar multiplication. + * This file implements custom field arithmetic using Barrett reduction + * to correctly handle the Pallas prime. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the "Software"), @@ -37,9 +37,14 @@ #include "blake2b.h" #include "memzero.h" -#include "pallas_ct.h" +/* bn_multiply_long is defined in bignum.c (non-static) */ +extern void bn_multiply_long(const bignum256 *k, const bignum256 *x, + uint32_t res[2 * 9]); + +#define BN_LIMBS 9 #define BN_BITS_PER_LIMB 29 +#define BN_LIMB_MASK ((1u << BN_BITS_PER_LIMB) - 1) /* ==================================================================== * Constants @@ -61,6 +66,22 @@ const curve_point pallas_G = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}}}; +/* + * Barrett reduction constant for the Pallas prime: + * mu_p = floor(2^510 / p) + */ +static const bignum256 mu_p = { + /*.val =*/{0x1ffffffc, 0x1a59e25f, 0x1306e466, 0x0b381fb5, 0x1ffff76e, + 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x00ffffff}}; + +/* + * Barrett reduction constant for the Pallas order: + * mu_q = floor(2^510 / q) + */ +static const bignum256 mu_q = { + /*.val =*/{0x1ffffffc, 0x17229bdf, 0x0b572273, 0x0b381fb3, 0x1ffff76e, + 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x00ffffff}}; + /* * Full ecdsa_curve struct (kept for compatibility, but point_multiply * from ecdsa.c should NOT be used with Pallas - use pallas_scalar_mult_G). @@ -91,6 +112,117 @@ const ecdsa_curve pallas = { #endif }; +/* ==================================================================== + * Barrett Reduction for ~254-bit primes + * + * Given an 18-limb product (up to ~510 bits), reduce mod prime. + * Uses Barrett: q_hat = floor(floor(x / 2^254) * mu / 2^256) + * r = x - q_hat * prime + * while r >= prime: r -= prime + * ==================================================================== */ + +_Static_assert(BN_LIMBS == 9, + "Pallas Barrett helpers require nine 29-bit limbs"); + +/* + * Shift an 18-limb number right by 254 bits. + * 254 = 8*29 + 22, so we skip 8 limbs and shift remaining by 22 bits. + */ +static void shift_right_254(const uint32_t in[18], bignum256 *out) { + for (int i = 0; i < BN_LIMBS; i++) { + uint32_t lo = in[i + 8] >> 22; + uint32_t hi = in[i + 9] << 7; + out->val[i] = (lo | hi) & BN_LIMB_MASK; + } +} + +/* + * Shift an 18-limb number right by 256 bits. + * 256 = 8*29 + 24, so we skip 8 limbs and shift remaining by 24 bits. + */ +static void shift_right_256(const uint32_t in[18], bignum256 *out) { + for (int i = 0; i < BN_LIMBS; i++) { + uint32_t lo = in[i + 8] >> 24; + uint32_t hi = in[i + 9] << 5; + out->val[i] = (lo | hi) & BN_LIMB_MASK; + } +} + +/* + * Compare two bignum256 values (both must be normalized). + * Returns 1 if a >= b, 0 otherwise. + */ +static int bn_gte(const bignum256 *a, const bignum256 *b) { + for (int i = BN_LIMBS - 1; i >= 0; i--) { + if (a->val[i] > b->val[i]) return 1; + if (a->val[i] < b->val[i]) return 0; + } + return 1; /* equal */ +} + +/* + * Subtract b from a, storing result in res. Assumes a >= b. + * All operands must be normalized. + */ +static void bn_sub(const bignum256 *a, const bignum256 *b, bignum256 *res) { + int32_t borrow = 0; + for (int i = 0; i < BN_LIMBS; i++) { + int32_t diff = (int32_t)a->val[i] - (int32_t)b->val[i] + borrow; + if (diff < 0) { + diff += (1 << BN_BITS_PER_LIMB); + borrow = -1; + } else { + borrow = 0; + } + res->val[i] = (uint32_t)diff; + } +} + +/* + * Barrett reduction: reduce an 18-limb product mod a ~254-bit prime. + * + * prime: the modulus (~254-255 bits) + * mu: precomputed floor(2^510 / prime) (~256 bits) + * res[18]: input product (up to ~510 bits) + * out: output, reduced to [0, prime) + */ +static void pallas_barrett_reduce(const uint32_t res[18], + const bignum256 *prime, + const bignum256 *mu, bignum256 *out) { + /* Step 1: q_hat = floor(floor(x / 2^254) * mu / 2^256) */ + bignum256 x_shifted; + shift_right_254(res, &x_shifted); + bn_normalize(&x_shifted); + + uint32_t qmu[18] = {0}; + bn_multiply_long(&x_shifted, mu, qmu); + + bignum256 q_hat; + shift_right_256(qmu, &q_hat); + bn_normalize(&q_hat); + + /* Step 2: r = x - q_hat * prime (low 9 limbs only) */ + uint32_t qp[18] = {0}; + bn_multiply_long(&q_hat, prime, qp); + + /* Compute r = x - q*p using 9 low limbs. + * The true result fits in ~256 bits (< 3*prime). */ + int64_t borrow = 0; + for (int i = 0; i < BN_LIMBS; i++) { + int64_t diff = (int64_t)res[i] - (int64_t)qp[i] + borrow; + out->val[i] = (uint32_t)(diff & BN_LIMB_MASK); + borrow = diff >> BN_BITS_PER_LIMB; + } + bn_normalize(out); + + /* Step 3: while r >= prime, r -= prime (at most 3 times) */ + for (int i = 0; i < 3; i++) { + if (bn_gte(out, prime)) { + bn_sub(out, prime, out); + } + } +} + /* ==================================================================== * Pallas Field Arithmetic * ==================================================================== */ @@ -98,62 +230,132 @@ const ecdsa_curve pallas = { /* * Field multiplication: x = k * x mod pallas_prime */ -void pallas_mul_mod_p(bignum256* x, const bignum256* k) { - pallas_ct_mul_mod_p(x, k); +void pallas_mul_mod_p(bignum256 *x, const bignum256 *k) { + uint32_t res[18] = {0}; + bn_multiply_long(k, x, res); + pallas_barrett_reduce(res, &pallas_prime, &mu_p, x); } /* * Scalar multiplication: x = k * x mod pallas_order */ -void pallas_mul_mod_q(bignum256* x, const bignum256* k) { - pallas_ct_mul_mod_q(x, k); +void pallas_mul_mod_q(bignum256 *x, const bignum256 *k) { + uint32_t res[18] = {0}; + bn_multiply_long(k, x, res); + pallas_barrett_reduce(res, &pallas_order, &mu_q, x); } /* * Field addition: x = (a + b) mod pallas_prime */ -void pallas_add_mod_p(const bignum256* a, const bignum256* b, bignum256* res) { - pallas_ct_add_mod_p(a, b, res); +void pallas_add_mod_p(const bignum256 *a, const bignum256 *b, + bignum256 *res) { + uint32_t carry = 0; + for (int i = 0; i < BN_LIMBS; i++) { + carry += a->val[i] + b->val[i]; + res->val[i] = carry & BN_LIMB_MASK; + carry >>= BN_BITS_PER_LIMB; + } + bn_normalize(res); + if (bn_gte(res, &pallas_prime)) { + bn_sub(res, &pallas_prime, res); + } } /* * Field subtraction: res = (a - b) mod pallas_prime */ -void pallas_sub_mod_p(const bignum256* a, const bignum256* b, bignum256* res) { - pallas_ct_sub_mod_p(a, b, res); +void pallas_sub_mod_p(const bignum256 *a, const bignum256 *b, + bignum256 *res) { + if (bn_gte(a, b)) { + bn_sub(a, b, res); + } else { + /* a < b: res = a + prime - b = prime - (b - a) */ + bignum256 tmp; + bn_sub(b, a, &tmp); + bn_sub(&pallas_prime, &tmp, res); + } } /* * Field inversion: x = x^(-1) mod pallas_prime * Uses Fermat's little theorem: x^(-1) = x^(p-2) mod p */ -void pallas_inv_mod_p(bignum256* x) { pallas_ct_inv_mod_p(x); } +void pallas_inv_mod_p(bignum256 *x) { + /* Compute e = p - 2 with proper borrow (since p.val[0] = 1 < 2) */ + bignum256 e; + bn_copy(&pallas_prime, &e); + /* val[0] = 1, so 1 - 2 requires borrow from val[1] */ + e.val[0] = e.val[0] + (1u << BN_BITS_PER_LIMB) - 2; /* 1 + 2^29 - 2 = 0x1FFFFFFF */ + e.val[1] -= 1; /* borrow */ + + /* Square-and-multiply: result = x^e mod p */ + bignum256 result; + bn_one(&result); + + bignum256 base; + bn_copy(x, &base); + + /* Process each bit of e from LSB to MSB */ + for (int bit = 0; bit < 255; bit++) { + int limb_idx = bit / BN_BITS_PER_LIMB; + int bit_idx = bit % BN_BITS_PER_LIMB; + + if ((e.val[limb_idx] >> bit_idx) & 1) { + pallas_mul_mod_p(&result, &base); + } + /* Square the base */ + bignum256 tmp; + bn_copy(&base, &tmp); + pallas_mul_mod_p(&base, &tmp); + } + + bn_copy(&result, x); + memzero(&result, sizeof(result)); + memzero(&base, sizeof(base)); +} /* * Simple modular reduction: x = x mod pallas_prime - * The input is a canonical 256-bit value represented as a bignum256. + * For values already < 2^261 (bignum256 range). */ -void pallas_mod_p(bignum256* x) { pallas_ct_mod_p(x); } +void pallas_mod_p(bignum256 *x) { + bn_normalize(x); + while (bn_gte(x, &pallas_prime)) { + bn_sub(x, &pallas_prime, x); + } +} /* * Simple modular reduction: x = x mod pallas_order - * The input is a canonical 256-bit value represented as a bignum256. + * For values already < 2^261 (bignum256 range). */ -void pallas_mod_q(bignum256* x) { pallas_ct_mod_q(x); } +void pallas_mod_q(bignum256 *x) { + bn_normalize(x); + while (bn_gte(x, &pallas_order)) { + bn_sub(x, &pallas_order, x); + } +} /* * Scalar addition: a = (a + b) mod pallas_order */ -void pallas_add_mod_q(bignum256* a, const bignum256* b) { - pallas_ct_add_mod_q(a, b); +void pallas_add_mod_q(bignum256 *a, const bignum256 *b) { + uint32_t carry = 0; + for (int i = 0; i < BN_LIMBS; i++) { + carry += a->val[i] + b->val[i]; + a->val[i] = carry & BN_LIMB_MASK; + carry >>= BN_BITS_PER_LIMB; + } + pallas_mod_q(a); } /* * Modular exponentiation: result = base^exp mod pallas_prime * Uses square-and-multiply (LSB to MSB). */ -static void pallas_pow_mod_p(const bignum256* base, const bignum256* exp, - bignum256* result) { +static void pallas_pow_mod_p(const bignum256 *base, const bignum256 *exp, + bignum256 *result) { bn_zero(result); result->val[0] = 1; @@ -181,7 +383,7 @@ static void pallas_pow_mod_p(const bignum256* base, const bignum256* exp, * * Returns 0 on success (n modified to sqrt), -1 if n is not a QR. */ -int pallas_sqrt_mod_p(bignum256* n) { +int pallas_sqrt_mod_p(bignum256 *n) { if (bn_is_zero(n)) return 0; /* p - 1 */ @@ -204,8 +406,7 @@ int pallas_sqrt_mod_p(bignum256* n) { bignum256 half_pm1; bn_copy(&pm1, &half_pm1); for (i = 0; i < 8; i++) { - half_pm1.val[i] = - (half_pm1.val[i] >> 1) | ((half_pm1.val[i + 1] & 0x1) << 28); + half_pm1.val[i] = (half_pm1.val[i] >> 1) | ((half_pm1.val[i + 1] & 0x1) << 28); } half_pm1.val[8] >>= 1; @@ -222,22 +423,22 @@ int pallas_sqrt_mod_p(bignum256* n) { /* Tonelli-Shanks initialization */ int M = 32; bignum256 c; - pallas_pow_mod_p(&z, &Q, &c); /* c = z^Q mod p */ + pallas_pow_mod_p(&z, &Q, &c); /* c = z^Q mod p */ bignum256 t; - pallas_pow_mod_p(n, &Q, &t); /* t = n^Q mod p */ + pallas_pow_mod_p(n, &Q, &t); /* t = n^Q mod p */ /* (Q+1)/2 */ bignum256 Q_half; bn_copy(&Q, &Q_half); - Q_half.val[0]++; /* Q is odd, so Q+1 is even */ + Q_half.val[0]++; /* Q is odd, so Q+1 is even */ for (i = 0; i < 8; i++) { Q_half.val[i] = (Q_half.val[i] >> 1) | ((Q_half.val[i + 1] & 0x1) << 28); } Q_half.val[8] >>= 1; bignum256 R; - pallas_pow_mod_p(n, &Q_half, &R); /* R = n^((Q+1)/2) mod p */ + pallas_pow_mod_p(n, &Q_half, &R); /* R = n^((Q+1)/2) mod p */ bignum256 one; bn_zero(&one); @@ -262,13 +463,13 @@ int pallas_sqrt_mod_p(bignum256* n) { for (ii = 1; ii < M; ii++) { bignum256 sq; bn_copy(&tmp, &sq); - pallas_mul_mod_p(&tmp, &sq); /* tmp = tmp^2 */ + pallas_mul_mod_p(&tmp, &sq); /* tmp = tmp^2 */ bn_normalize(&tmp); if (bn_is_equal(&tmp, &one)) break; } if (ii >= M) { - return -1; /* n is not a quadratic residue */ + return -1; /* n is not a quadratic residue */ } /* b = c^(2^(M-ii-1)) */ @@ -277,7 +478,7 @@ int pallas_sqrt_mod_p(bignum256* n) { for (int j = 0; j < M - ii - 1; j++) { bignum256 sq; bn_copy(&b, &sq); - pallas_mul_mod_p(&b, &sq); /* b = b^2 */ + pallas_mul_mod_p(&b, &sq); /* b = b^2 */ } /* Update M, c, t, R */ @@ -288,14 +489,14 @@ int pallas_sqrt_mod_p(bignum256* n) { { bignum256 sq; bn_copy(&c, &sq); - pallas_mul_mod_p(&c, &sq); /* c = c^2 = b^2 */ + pallas_mul_mod_p(&c, &sq); /* c = c^2 = b^2 */ } /* t = t * c (where c = b^2) */ - pallas_mul_mod_p(&t, &c); /* t = c * t = b^2 * t */ + pallas_mul_mod_p(&t, &c); /* t = c * t = b^2 * t */ /* R = R * b */ - pallas_mul_mod_p(&R, &b); /* R = b * R */ + pallas_mul_mod_p(&R, &b); /* R = b * R */ } } @@ -303,35 +504,203 @@ int pallas_sqrt_mod_p(bignum256* n) { * Pallas Point Operations (affine coordinates) * ==================================================================== */ -static int pallas_point_is_infinity(const curve_point* p) { +static int pallas_point_is_infinity(const curve_point *p) { return bn_is_zero(&p->x) && bn_is_zero(&p->y); } -/* Point addition uses the constant-time projective implementation. */ -void pallas_point_add(const curve_point* p, const curve_point* q, - curve_point* res) { - pallas_ct_point_add(p, q, res); +static void pallas_point_set_infinity(curve_point *p) { + bn_zero(&p->x); + bn_zero(&p->y); +} + +/* + * Point doubling: res = 2*P on Pallas curve (y^2 = x^3 + 5, a=0) + * Formula: lambda = 3*x^2 / (2*y) + * xr = lambda^2 - 2*x + * yr = lambda*(x - xr) - y + */ +static void pallas_point_dbl(const curve_point *p, curve_point *res) { + if (pallas_point_is_infinity(p) || bn_is_zero(&p->y)) { + pallas_point_set_infinity(res); + return; + } + + bignum256 lambda, xr, yr, tmp, tmp2; + + /* lambda = 3*x^2 / (2*y) mod p */ + /* Numerator: 3*x^2 */ + bn_copy(&p->x, &tmp); + pallas_mul_mod_p(&tmp, &p->x); /* tmp = x^2 */ + bn_copy(&tmp, &tmp2); + pallas_add_mod_p(&tmp, &tmp2, &lambda); /* lambda = 2*x^2 */ + pallas_add_mod_p(&lambda, &tmp2, &lambda); /* lambda = 3*x^2 */ + + /* Denominator: 2*y */ + pallas_add_mod_p(&p->y, &p->y, &tmp); /* tmp = 2*y */ + + /* Invert denominator */ + pallas_inv_mod_p(&tmp); /* tmp = 1/(2*y) */ + + /* lambda = 3*x^2 * (1/(2*y)) */ + pallas_mul_mod_p(&lambda, &tmp); + + /* xr = lambda^2 - 2*x */ + bn_copy(&lambda, &xr); + pallas_mul_mod_p(&xr, &lambda); /* xr = lambda^2 */ + pallas_add_mod_p(&p->x, &p->x, &tmp); /* tmp = 2*x */ + pallas_sub_mod_p(&xr, &tmp, &xr); /* xr = lambda^2 - 2*x */ + + /* yr = lambda*(x - xr) - y */ + pallas_sub_mod_p(&p->x, &xr, &yr); /* yr = x - xr */ + pallas_mul_mod_p(&yr, &lambda); /* yr = lambda*(x - xr) */ + pallas_sub_mod_p(&yr, &p->y, &yr); /* yr = lambda*(x-xr) - y */ + + bn_copy(&xr, &res->x); + bn_copy(&yr, &res->y); +} + +/* + * Point addition: res = P + Q on Pallas curve + */ +void pallas_point_add(const curve_point *p, const curve_point *q, + curve_point *res) { + if (pallas_point_is_infinity(p)) { + *res = *q; + return; + } + if (pallas_point_is_infinity(q)) { + *res = *p; + return; + } + + /* Check if P == Q (use doubling) */ + bignum256 px_norm, qx_norm, py_norm, qy_norm; + bn_copy(&p->x, &px_norm); + bn_copy(&q->x, &qx_norm); + bn_copy(&p->y, &py_norm); + bn_copy(&q->y, &qy_norm); + bn_normalize(&px_norm); + bn_normalize(&qx_norm); + bn_normalize(&py_norm); + bn_normalize(&qy_norm); + + int x_equal = 1; + for (int i = 0; i < BN_LIMBS; i++) { + if (px_norm.val[i] != qx_norm.val[i]) { x_equal = 0; break; } + } + if (x_equal) { + int y_equal = 1; + for (int i = 0; i < BN_LIMBS; i++) { + if (py_norm.val[i] != qy_norm.val[i]) { y_equal = 0; break; } + } + if (y_equal) { + pallas_point_dbl(p, res); + return; + } + /* P.x == Q.x but P.y != Q.y → P + Q = O (point at infinity) */ + pallas_point_set_infinity(res); + return; + } + + bignum256 lambda, xr, yr, tmp; + + /* lambda = (Q.y - P.y) / (Q.x - P.x) mod p */ + pallas_sub_mod_p(&q->y, &p->y, &lambda); /* num = Q.y - P.y */ + pallas_sub_mod_p(&q->x, &p->x, &tmp); /* den = Q.x - P.x */ + pallas_inv_mod_p(&tmp); /* den = 1/(Q.x - P.x) */ + pallas_mul_mod_p(&lambda, &tmp); /* lambda = num/den */ + + /* xr = lambda^2 - P.x - Q.x */ + bn_copy(&lambda, &xr); + pallas_mul_mod_p(&xr, &lambda); /* xr = lambda^2 */ + pallas_sub_mod_p(&xr, &p->x, &xr); /* xr -= P.x */ + pallas_sub_mod_p(&xr, &q->x, &xr); /* xr -= Q.x */ + + /* yr = lambda*(P.x - xr) - P.y */ + pallas_sub_mod_p(&p->x, &xr, &yr); /* yr = P.x - xr */ + pallas_mul_mod_p(&yr, &lambda); /* yr *= lambda */ + pallas_sub_mod_p(&yr, &p->y, &yr); /* yr -= P.y */ + + bn_copy(&xr, &res->x); + bn_copy(&yr, &res->y); +} + +/* ==================================================================== + * Scalar Multiplication (double-and-add, left-to-right) + * ==================================================================== */ + +/* + * Compute res = k * P on Pallas. + * Uses the double-and-add algorithm. + * k must be in [1, order-1]. + */ +static void pallas_scalar_mult_impl(const bignum256 *k, const curve_point *p, + curve_point *res) { + /* Find the highest set bit */ + int highest_bit = -1; + for (int i = BN_LIMBS - 1; i >= 0; i--) { + if (k->val[i] != 0) { + uint32_t v = k->val[i]; + int bit = BN_BITS_PER_LIMB - 1; + while (bit >= 0 && !((v >> bit) & 1)) bit--; + highest_bit = i * BN_BITS_PER_LIMB + bit; + break; + } + } + + if (highest_bit < 0) { + /* k == 0 */ + pallas_point_set_infinity(res); + return; + } + + /* Initialize res = P (for the highest bit) */ + *res = *p; + + /* Process remaining bits from second-highest down to 0 */ + for (int bit = highest_bit - 1; bit >= 0; bit--) { + /* Double */ + curve_point tmp; + pallas_point_dbl(res, &tmp); + *res = tmp; + + /* Add if bit is set */ + int limb_idx = bit / BN_BITS_PER_LIMB; + int bit_idx = bit % BN_BITS_PER_LIMB; + if ((k->val[limb_idx] >> bit_idx) & 1) { + pallas_point_add(res, p, &tmp); + *res = tmp; + } + } } /* ==================================================================== * Public API * ==================================================================== */ -void pallas_scalar_mult_G(const bignum256* k, curve_point* res) { - pallas_ct_point_mult(k, &pallas_G, res); +void pallas_scalar_mult_G(const bignum256 *k, curve_point *res) { + if (bn_is_zero(k)) { + pallas_point_set_infinity(res); + return; + } + pallas_scalar_mult_impl(k, &pallas_G, res); } -void pallas_point_mult(const bignum256* k, const curve_point* p, - curve_point* res) { - pallas_ct_point_mult(k, p, res); +void pallas_point_mult(const bignum256 *k, const curve_point *p, + curve_point *res) { + if (bn_is_zero(k)) { + pallas_point_set_infinity(res); + return; + } + pallas_scalar_mult_impl(k, p, res); } -int pallas_point_is_identity(const curve_point* p) { +int pallas_point_is_identity(const curve_point *p) { if (!p) return 1; return pallas_point_is_infinity(p); } -void pallas_point_encode(const curve_point* p, uint8_t out[32]) { +void pallas_point_encode(const curve_point *p, uint8_t out[32]) { if (!p || !out) return; memset(out, 0, 32); @@ -346,9 +715,9 @@ void pallas_point_encode(const curve_point* p, uint8_t out[32]) { memzero(&x, sizeof(x)); } -int pallas_expand_message_xmd_blake2b(const uint8_t* msg, size_t msg_len, - const uint8_t* dst, size_t dst_len, - uint8_t* out, size_t out_len) { +int pallas_expand_message_xmd_blake2b(const uint8_t *msg, size_t msg_len, + const uint8_t *dst, size_t dst_len, + uint8_t *out, size_t out_len) { enum { B_IN_BYTES = 64, R_IN_BYTES = 128, @@ -413,8 +782,7 @@ int pallas_expand_message_xmd_blake2b(const uint8_t* msg, size_t msg_len, } ctr = (uint8_t)i; - if (blake2b_InitPersonal(&ctx, B_IN_BYTES, personal, sizeof(personal)) != - 0) { + if (blake2b_InitPersonal(&ctx, B_IN_BYTES, personal, sizeof(personal)) != 0) { memzero(&ctx, sizeof(ctx)); return -1; } diff --git a/deps/crypto/trezor-crypto/pallas.h b/deps/crypto/trezor-crypto/pallas.h index 9fc0cbe2f..a88510d62 100644 --- a/deps/crypto/trezor-crypto/pallas.h +++ b/deps/crypto/trezor-crypto/pallas.h @@ -50,58 +50,63 @@ extern const bignum256 pallas_order; extern const curve_point pallas_G; /* expand_message_xmd using BLAKE2b-512, per RFC 9380 §5.3.1. */ -int pallas_expand_message_xmd_blake2b(const uint8_t* msg, size_t msg_len, - const uint8_t* dst, size_t dst_len, - uint8_t* out, size_t out_len); +int pallas_expand_message_xmd_blake2b(const uint8_t *msg, size_t msg_len, + const uint8_t *dst, size_t dst_len, + uint8_t *out, size_t out_len); -/* --- Field arithmetic mod p (fixed-width Montgomery arithmetic) --- */ +/* --- Variable-time public-data arithmetic (Barrett reduction) --- + * + * These compatibility APIs are used by public Orchard group-hash and + * Sinsemilla note-commitment verification. They are not safe for private + * scalars or private field elements; secret-bearing callers must use the + * fixed-schedule pallas_ct.h API instead. */ /* x = k * x mod p */ -void pallas_mul_mod_p(bignum256* x, const bignum256* k); +void pallas_mul_mod_p(bignum256 *x, const bignum256 *k); -/* x = x mod p */ -void pallas_mod_p(bignum256* x); +/* x = x mod p (simple reduction for values < 2^261) */ +void pallas_mod_p(bignum256 *x); /* x = x^(-1) mod p (Fermat's little theorem) */ -void pallas_inv_mod_p(bignum256* x); +void pallas_inv_mod_p(bignum256 *x); /* res = (a + b) mod p */ -void pallas_add_mod_p(const bignum256* a, const bignum256* b, bignum256* res); +void pallas_add_mod_p(const bignum256 *a, const bignum256 *b, bignum256 *res); /* res = (a - b) mod p */ -void pallas_sub_mod_p(const bignum256* a, const bignum256* b, bignum256* res); +void pallas_sub_mod_p(const bignum256 *a, const bignum256 *b, bignum256 *res); /* n = sqrt(n) mod p (Tonelli-Shanks). Returns 0 on success, -1 if no sqrt. */ -int pallas_sqrt_mod_p(bignum256* n); +int pallas_sqrt_mod_p(bignum256 *n); -/* --- Scalar arithmetic mod q (fixed-width Montgomery arithmetic) --- */ +/* --- Variable-time public-data scalar arithmetic mod q --- */ /* x = k * x mod q */ -void pallas_mul_mod_q(bignum256* x, const bignum256* k); +void pallas_mul_mod_q(bignum256 *x, const bignum256 *k); -/* x = x mod q */ -void pallas_mod_q(bignum256* x); +/* x = x mod q (simple reduction for values < 2^261) */ +void pallas_mod_q(bignum256 *x); /* a = (a + b) mod q */ -void pallas_add_mod_q(bignum256* a, const bignum256* b); +void pallas_add_mod_q(bignum256 *a, const bignum256 *b); -/* --- Point operations on Pallas curve --- */ +/* --- Variable-time public-data point operations on Pallas curve --- */ -/* res = k * G, using a fixed 255-round branchless projective path */ -void pallas_scalar_mult_G(const bignum256* k, curve_point* res); +/* res = k * G */ +void pallas_scalar_mult_G(const bignum256 *k, curve_point *res); -/* res = k * P, using a fixed 255-round branchless projective path */ -void pallas_point_mult(const bignum256* k, const curve_point* p, - curve_point* res); +/* res = k * P */ +void pallas_point_mult(const bignum256 *k, const curve_point *p, + curve_point *res); /* res = P + Q */ -void pallas_point_add(const curve_point* p, const curve_point* q, - curve_point* res); +void pallas_point_add(const curve_point *p, const curve_point *q, + curve_point *res); /* Returns nonzero if P is the point at infinity in this implementation. */ -int pallas_point_is_identity(const curve_point* p); +int pallas_point_is_identity(const curve_point *p); /* Serialize Pallas point as LE x-coordinate with y parity in bit 255. */ -void pallas_point_encode(const curve_point* p, uint8_t out[32]); +void pallas_point_encode(const curve_point *p, uint8_t out[32]); #endif diff --git a/deps/crypto/trezor-crypto/pallas_ct.c b/deps/crypto/trezor-crypto/pallas_ct.c index 306c433e1..61ae77bff 100644 --- a/deps/crypto/trezor-crypto/pallas_ct.c +++ b/deps/crypto/trezor-crypto/pallas_ct.c @@ -183,6 +183,8 @@ static uint32_t ct_half_limb(const ct_fe* value, size_t index) { * UINT32_MAX, so the compiler can use the fixed-latency 32-bit MUL/MLA path. * Both Pallas moduli have low half-limb 1, hence -m^-1 mod 2^16 = 0xffff. * All carry propagation loops have public, fixed bounds. + * Requires a < 2^256 and b < mod. The only unreduced input is paired with a + * reduced Montgomery constant, so one final conditional subtraction suffices. */ static void ct_fe_mul_mod(ct_fe* out, const ct_fe* a, const ct_fe* b, const ct_modulus* mod) { diff --git a/deps/crypto/trezor-crypto/pallas_sinsemilla.c b/deps/crypto/trezor-crypto/pallas_sinsemilla.c index 7120c33bb..97e8a7e0f 100644 --- a/deps/crypto/trezor-crypto/pallas_sinsemilla.c +++ b/deps/crypto/trezor-crypto/pallas_sinsemilla.c @@ -20,6 +20,7 @@ #include "bignum.h" #include "memzero.h" #include "pallas.h" +#include "pallas_ct.h" #include "pallas_swu.h" static const uint8_t COMMIT_IVK_Q_X[32] = { @@ -214,8 +215,12 @@ int pallas_sinsemilla_commit(const curve_point *q, const curve_point *r, return -1; } - pallas_point_mult(&blind_scalar, r, &blind_point); - pallas_point_add(&hash_point, &blind_point, &commit); + /* The blind is host-supplied for transaction note verification, but is the + * device-secret rivk during IVK derivation. Keep this narrow part of the + * commitment on the fixed-schedule path; only the repeated public + * Sinsemilla hash additions use the compatibility implementation. */ + pallas_ct_point_mult(&blind_scalar, r, &blind_point); + pallas_ct_point_add(&hash_point, &blind_point, &commit); *out = commit; memzero(&blind_scalar, sizeof(blind_scalar)); diff --git a/deps/crypto/trezor-crypto/redpallas.c b/deps/crypto/trezor-crypto/redpallas.c index 277b42307..37237a1a9 100644 --- a/deps/crypto/trezor-crypto/redpallas.c +++ b/deps/crypto/trezor-crypto/redpallas.c @@ -140,7 +140,10 @@ static void pallas_scalar_mult_spendauth(const bignum256 *k, curve_point *res) { pallas_point_deserialize(pallas_spendauth_G_bytes, &spendauth_G_cache); spendauth_G_initialized = 1; } - pallas_point_mult(k, &spendauth_G_cache, res); + /* k is an authorization scalar or nonce on signing/derivation paths. Keep + * it on the fixed-schedule projective implementation; pallas_point_mult() + * is the variable-time public-data API used by Sinsemilla verification. */ + pallas_ct_point_mult(k, &spendauth_G_cache, res); } /* @@ -239,7 +242,7 @@ int redpallas_sign_digest(const uint8_t *ask, const uint8_t *alpha, /* rsk = (ask + alpha) mod order */ bn_copy(&ask_scalar, &rsk); - pallas_add_mod_q(&rsk, &alpha_scalar); + pallas_ct_add_mod_q(&rsk, &alpha_scalar); /* rk = [rsk]G_spendauth - randomized verification key */ pallas_scalar_mult_spendauth(&rsk, &rk_point); @@ -249,7 +252,7 @@ int redpallas_sign_digest(const uint8_t *ask, const uint8_t *alpha, uint8_t rbuf[32]; random_buffer(rbuf, 32); bn_read_le(rbuf, &r); - pallas_mod_q(&r); + pallas_ct_mod_q(&r); /* Ensure r is not zero without branching on the secret nonce. */ pallas_ct_scalar_replace_zero_with_one(&r); @@ -262,9 +265,9 @@ int redpallas_sign_digest(const uint8_t *ask, const uint8_t *alpha, redpallas_hash_challenge(R_bytes, rk_bytes, sighash, &c); /* S = r + c * rsk (mod order) */ - pallas_mul_mod_q(&c, &rsk); /* c = c * rsk mod order */ + pallas_ct_mul_mod_q(&c, &rsk); /* c = c * rsk mod order */ bn_copy(&r, &s); - pallas_add_mod_q(&s, &c); /* s = r + c*rsk mod order */ + pallas_ct_add_mod_q(&s, &c); /* s = r + c*rsk mod order */ /* Output: R (32 bytes LE) || S (32 bytes LE) */ memcpy(sig_out, R_bytes, 32); @@ -275,6 +278,7 @@ int redpallas_sign_digest(const uint8_t *ask, const uint8_t *alpha, memzero(&alpha_scalar, sizeof(alpha_scalar)); memzero(&rsk, sizeof(rsk)); memzero(&r, sizeof(r)); + memzero(&c, sizeof(c)); memzero(&s, sizeof(s)); memzero(rbuf, sizeof(rbuf)); @@ -337,7 +341,7 @@ int redpallas_derive_rk(const uint8_t *ask, const uint8_t *alpha, /* rsk = (ask + alpha) mod order */ bn_copy(&ask_scalar, &rsk); - pallas_add_mod_q(&rsk, &alpha_scalar); + pallas_ct_add_mod_q(&rsk, &alpha_scalar); /* rk = [rsk]G_spendauth */ pallas_scalar_mult_spendauth(&rsk, &rk_point); diff --git a/lib/firmware/zcash.c b/lib/firmware/zcash.c index c84ef1e3b..c3e5adfdd 100644 --- a/lib/firmware/zcash.c +++ b/lib/firmware/zcash.c @@ -28,6 +28,7 @@ #include "trezor/crypto/hasher.h" #include "trezor/crypto/memzero.h" #include "trezor/crypto/pallas.h" +#include "trezor/crypto/pallas_ct.h" #include "trezor/crypto/pallas_sinsemilla.h" #include "trezor/crypto/pallas_swu.h" #include "trezor/crypto/redpallas.h" @@ -115,19 +116,19 @@ static void to_scalar(const uint8_t input[64], uint8_t output[32]) { bignum256 lo, hi, t256, result; bn_read_le(input, &lo); - pallas_mod_q(&lo); + pallas_ct_mod_q(&lo); bn_read_le(input + 32, &hi); - pallas_mod_q(&hi); + pallas_ct_mod_q(&hi); bn_read_le(two_256_mod_q, &t256); /* result = hi * (2^256 mod q) mod q */ bn_copy(&hi, &result); - pallas_mul_mod_q(&result, &t256); + pallas_ct_mul_mod_q(&result, &t256); /* result = result + lo mod q */ - pallas_add_mod_q(&result, &lo); + pallas_ct_add_mod_q(&result, &lo); bn_write_le(&result, output); @@ -147,20 +148,20 @@ static void to_base(const uint8_t input[64], uint8_t output[32]) { bignum256 lo, hi, t256, result; bn_read_le(input, &lo); - pallas_mod_p(&lo); + pallas_ct_mod_p(&lo); bn_read_le(input + 32, &hi); - pallas_mod_p(&hi); + pallas_ct_mod_p(&hi); bn_read_le(two_256_mod_p, &t256); /* result = hi * (2^256 mod p) mod p */ bn_copy(&hi, &result); - pallas_mul_mod_p(&result, &t256); + pallas_ct_mul_mod_p(&result, &t256); /* result = result + lo mod p */ bignum256 sum; - pallas_add_mod_p(&result, &lo, &sum); + pallas_ct_add_mod_p(&result, &lo, &sum); bn_copy(&sum, &result); memzero(&sum, sizeof(sum)); @@ -362,7 +363,9 @@ bool zcash_orchard_derive_transmission_key(const uint8_t ivk[32], } curve_point pkd; - pallas_point_mult(&ivk_scalar, &gd, &pkd); + /* ivk is private viewing-key material. Do not use the variable-time + * public-data multiplier that Sinsemilla note verification relies on. */ + pallas_ct_point_mult(&ivk_scalar, &gd, &pkd); if (pallas_point_is_identity(&pkd)) { memzero(&ivk_scalar, sizeof(ivk_scalar)); memzero(&gd, sizeof(gd)); diff --git a/tools/check_pallas_api_boundary.py b/tools/check_pallas_api_boundary.py new file mode 100644 index 000000000..4876e22a0 --- /dev/null +++ b/tools/check_pallas_api_boundary.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python3 +"""Enforce the RC18 split between public and secret Pallas operations.""" + +import re +import sys +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] + + +def source(path): + return (ROOT / path).read_text(encoding="utf-8") + + +def function_body(text, name): + match = re.search(r"\b" + re.escape(name) + r"\s*\([^;]*?\)\s*\{", text, re.S) + if not match: + raise AssertionError("function not found: " + name) + start = match.end() - 1 + depth = 0 + for index in range(start, len(text)): + if text[index] == "{": + depth += 1 + elif text[index] == "}": + depth -= 1 + if depth == 0: + return text[start + 1:index] + raise AssertionError("unterminated function: " + name) + + +def code_only(text): + return re.sub(r"/\*.*?\*/|//[^\n]*", "", text, flags=re.S) + + +def require(body, token, where): + if token not in body: + raise AssertionError("{} must call {}".format(where, token)) + + +def forbid(body, token, where): + if token in body: + raise AssertionError("{} must not call {}".format(where, token)) + + +def main(): + pallas = source("deps/crypto/trezor-crypto/pallas.c") + sinsemilla = source("deps/crypto/trezor-crypto/pallas_sinsemilla.c") + redpallas = source("deps/crypto/trezor-crypto/redpallas.c") + zcash = source("lib/firmware/zcash.c") + + # Public transaction data needs the fast compatibility implementation. + forbid(pallas, '"pallas_ct.h"', "pallas.c public compatibility path") + hash_to_point = code_only(function_body(sinsemilla, + "pallas_sinsemilla_hash_to_point")) + require(hash_to_point, "sinsemilla_incomplete_add", + "Sinsemilla public hash path") + forbid(hash_to_point, "pallas_ct_", "Sinsemilla public hash path") + incomplete_add = code_only(function_body(sinsemilla, + "sinsemilla_incomplete_add")) + require(incomplete_add, "pallas_point_add", "Sinsemilla public hash add") + forbid(incomplete_add, "pallas_ct_", "Sinsemilla public hash add") + + # The commitment blind is rivk on IVK derivation paths, so its one scalar + # multiplication and the final add remain fixed-schedule. This does not + # put the repeated transaction commitment hash additions on the slow path. + commit = code_only(function_body(sinsemilla, "pallas_sinsemilla_commit")) + require(commit, "pallas_ct_point_mult", "Sinsemilla blinding") + require(commit, "pallas_ct_point_add", "Sinsemilla blinding") + forbid(commit, "pallas_point_mult(", "Sinsemilla blinding") + forbid(commit, "pallas_point_add(", "Sinsemilla blinding") + + # Authorization scalars, nonces, and randomized keys must never fall back + # to the variable-time public-data API. + spendauth = code_only(function_body(redpallas, "pallas_scalar_mult_spendauth")) + require(spendauth, "pallas_ct_point_mult", "RedPallas scalar multiplication") + forbid(spendauth, "pallas_point_mult(", "RedPallas scalar multiplication") + + sign = code_only(function_body(redpallas, "redpallas_sign_digest")) + for token in ("pallas_ct_add_mod_q", "pallas_ct_mod_q", + "pallas_ct_mul_mod_q", "pallas_ct_scalar_replace_zero_with_one"): + require(sign, token, "redpallas_sign_digest") + for token in ("pallas_add_mod_q(", "pallas_mod_q(", "pallas_mul_mod_q("): + forbid(sign, token, "redpallas_sign_digest") + + derive_rk = code_only(function_body(redpallas, "redpallas_derive_rk")) + require(derive_rk, "pallas_ct_add_mod_q", "redpallas_derive_rk") + + # ZIP-32 key reduction and transmission-key derivation also process + # device-secret viewing/spending material. + for name in ("to_scalar", "to_base"): + body = code_only(function_body(zcash, name)) + require(body, "pallas_ct_", name) + transmission = code_only(function_body(zcash, "zcash_orchard_derive_transmission_key")) + require(transmission, "pallas_ct_point_mult", "Orchard transmission-key derivation") + forbid(transmission, "pallas_point_mult(", "Orchard transmission-key derivation") + + print("Pallas API boundary: public Sinsemilla fast path and secret CT path verified") + return 0 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except AssertionError as error: + print("Pallas API boundary violation: {}".format(error), file=sys.stderr) + sys.exit(1) From b6e6e5ff3c2503fec828c82fbbae31b02722db8c Mon Sep 17 00:00:00 2001 From: highlander Date: Sun, 26 Jul 2026 00:13:30 -0300 Subject: [PATCH 11/22] fix(zcash): stream signing progress and cut public work --- deps/crypto/trezor-crypto/pallas_ct.c | 37 ++++ deps/crypto/trezor-crypto/pallas_ct.h | 9 + deps/crypto/trezor-crypto/pallas_sinsemilla.c | 136 +++++++----- deps/crypto/trezor-crypto/pallas_sinsemilla.h | 28 ++- deps/crypto/trezor-crypto/redpallas.c | 195 +++++++++++++----- deps/crypto/trezor-crypto/redpallas.h | 39 +++- include/keepkey/firmware/zcash.h | 2 + lib/firmware/fsm_msg_zcash.h | 58 ++++-- lib/firmware/zcash.c | 4 + tools/check_pallas_api_boundary.py | 48 ++++- tools/check_pallas_ct_disassembly.py | 66 +++++- unittests/crypto/pallas_ct.cpp | 31 +++ unittests/firmware/zcash.cpp | 59 ++++++ 13 files changed, 562 insertions(+), 150 deletions(-) diff --git a/deps/crypto/trezor-crypto/pallas_ct.c b/deps/crypto/trezor-crypto/pallas_ct.c index 61ae77bff..4d252abdd 100644 --- a/deps/crypto/trezor-crypto/pallas_ct.c +++ b/deps/crypto/trezor-crypto/pallas_ct.c @@ -470,6 +470,43 @@ void pallas_ct_point_mult(const bignum256* k, const curve_point* p, memzero(&acc, sizeof(acc)); } +void pallas_ct_point_mult_progress(const bignum256* k, const curve_point* p, + curve_point* res, + pallas_ct_progress_callback progress, + void* progress_context) { + ct_fe scalar_mont; + ct_fe scalar; + ct_point base; + ct_point acc; + static const ct_fe raw_one = {{1, 0, 0, 0, 0, 0, 0, 0}}; + + /* This is deliberately the same fixed schedule as pallas_ct_point_mult(). + * The callback runs once after every round and receives only public loop + * counters, so OLED refreshes cannot disclose scalar bits. */ + ct_fe_from_bn(&scalar_mont, k, &CT_Q); + ct_fe_mul_mod(&scalar, &scalar_mont, &raw_one, &CT_Q); + ct_point_from_affine(&base, p); + ct_point_identity(&acc); + + for (int bit = 254; bit >= 0; bit--) { + ct_point doubled; + ct_point added; + const uint32_t scalar_bit = + (scalar.v[(unsigned)bit / 32] >> ((unsigned)bit % 32)) & 1u; + CT_COUNT(scalar_round); + ct_point_double(&doubled, &acc); + ct_point_add_internal(&added, &doubled, &base); + ct_point_select(&acc, &doubled, &added, scalar_bit); + progress((uint32_t)(255 - bit), 255, progress_context); + } + + ct_point_to_affine(res, &acc); + memzero(&scalar_mont, sizeof(scalar_mont)); + memzero(&scalar, sizeof(scalar)); + memzero(&base, sizeof(base)); + memzero(&acc, sizeof(acc)); +} + void pallas_ct_point_add(const curve_point* p, const curve_point* q, curve_point* res) { ct_point lhs; diff --git a/deps/crypto/trezor-crypto/pallas_ct.h b/deps/crypto/trezor-crypto/pallas_ct.h index f685676fc..6b9de542b 100644 --- a/deps/crypto/trezor-crypto/pallas_ct.h +++ b/deps/crypto/trezor-crypto/pallas_ct.h @@ -13,6 +13,11 @@ #include "bignum.h" #include "ecdsa.h" +/* Progress is reported from the fixed 255-round scalar schedule. Both values + * are public loop counters; callbacks must not inspect scalar data. */ +typedef void (*pallas_ct_progress_callback)(uint32_t completed, uint32_t total, + void* context); + void pallas_ct_mul_mod_p(bignum256* x, const bignum256* k); void pallas_ct_add_mod_p(const bignum256* a, const bignum256* b, bignum256* res); @@ -30,6 +35,10 @@ void pallas_ct_point_add(const curve_point* p, const curve_point* q, curve_point* res); void pallas_ct_point_mult(const bignum256* k, const curve_point* p, curve_point* res); +void pallas_ct_point_mult_progress(const bignum256* k, const curve_point* p, + curve_point* res, + pallas_ct_progress_callback progress, + void* progress_context); #ifdef PALLAS_CT_TESTING typedef struct { diff --git a/deps/crypto/trezor-crypto/pallas_sinsemilla.c b/deps/crypto/trezor-crypto/pallas_sinsemilla.c index 97e8a7e0f..eff4fc35e 100644 --- a/deps/crypto/trezor-crypto/pallas_sinsemilla.c +++ b/deps/crypto/trezor-crypto/pallas_sinsemilla.c @@ -24,56 +24,52 @@ #include "pallas_swu.h" static const uint8_t COMMIT_IVK_Q_X[32] = { - 0xf2, 0x82, 0x0f, 0x79, 0x92, 0x2f, 0xcb, 0x6b, - 0x32, 0xa2, 0x28, 0x51, 0x24, 0xcc, 0x1b, 0x42, - 0xfa, 0x41, 0xa2, 0x5a, 0xb8, 0x81, 0xcc, 0x7d, - 0x11, 0xc8, 0xa9, 0x4a, 0xf1, 0x0c, 0xbc, 0x05, + 0xf2, 0x82, 0x0f, 0x79, 0x92, 0x2f, 0xcb, 0x6b, 0x32, 0xa2, 0x28, + 0x51, 0x24, 0xcc, 0x1b, 0x42, 0xfa, 0x41, 0xa2, 0x5a, 0xb8, 0x81, + 0xcc, 0x7d, 0x11, 0xc8, 0xa9, 0x4a, 0xf1, 0x0c, 0xbc, 0x05, }; static const uint8_t COMMIT_IVK_Q_Y[32] = { - 0xbe, 0xde, 0xad, 0xcf, 0xce, 0xe5, 0x5a, 0xbe, - 0xf1, 0xa5, 0x6d, 0xc9, 0x1d, 0x35, 0xc4, 0x46, - 0x4b, 0x05, 0xde, 0x20, 0x46, 0x07, 0x59, 0xef, - 0xe6, 0xbe, 0x1a, 0xd4, 0xf6, 0x4c, 0x01, 0x1b, + 0xbe, 0xde, 0xad, 0xcf, 0xce, 0xe5, 0x5a, 0xbe, 0xf1, 0xa5, 0x6d, + 0xc9, 0x1d, 0x35, 0xc4, 0x46, 0x4b, 0x05, 0xde, 0x20, 0x46, 0x07, + 0x59, 0xef, 0xe6, 0xbe, 0x1a, 0xd4, 0xf6, 0x4c, 0x01, 0x1b, }; static const uint8_t COMMIT_IVK_R_X[32] = { - 0x18, 0xa1, 0xf8, 0x5f, 0x6e, 0x48, 0x23, 0x98, - 0xc7, 0xed, 0x1a, 0xd3, 0xe2, 0x7f, 0x95, 0x02, - 0x48, 0x89, 0x80, 0x40, 0x0a, 0x29, 0x34, 0x16, - 0x4e, 0x13, 0x70, 0x50, 0xcd, 0x2c, 0xa2, 0x25, + 0x18, 0xa1, 0xf8, 0x5f, 0x6e, 0x48, 0x23, 0x98, 0xc7, 0xed, 0x1a, + 0xd3, 0xe2, 0x7f, 0x95, 0x02, 0x48, 0x89, 0x80, 0x40, 0x0a, 0x29, + 0x34, 0x16, 0x4e, 0x13, 0x70, 0x50, 0xcd, 0x2c, 0xa2, 0x25, }; static const uint8_t COMMIT_IVK_R_Y[32] = { - 0xa9, 0xdd, 0x7f, 0xe3, 0xb3, 0x93, 0xe7, 0x3f, - 0xc7, 0xa6, 0x58, 0x1b, 0xfb, 0x42, 0x44, 0x6b, - 0x94, 0x57, 0x4b, 0x28, 0xc4, 0x90, 0xc8, 0xc2, - 0xeb, 0xfa, 0xa2, 0x66, 0x99, 0xd2, 0xcf, 0x29, + 0xa9, 0xdd, 0x7f, 0xe3, 0xb3, 0x93, 0xe7, 0x3f, 0xc7, 0xa6, 0x58, + 0x1b, 0xfb, 0x42, 0x44, 0x6b, 0x94, 0x57, 0x4b, 0x28, 0xc4, 0x90, + 0xc8, 0xc2, 0xeb, 0xfa, 0xa2, 0x66, 0x99, 0xd2, 0xcf, 0x29, }; static void point_from_xy_le(const uint8_t x[32], const uint8_t y[32], - curve_point *out) { + curve_point* out) { bn_read_le(x, &out->x); bn_read_le(y, &out->y); bn_normalize(&out->x); bn_normalize(&out->y); } -static int read_base_field(const uint8_t in[32], bignum256 *out) { +static int read_base_field(const uint8_t in[32], bignum256* out) { if (!in || !out) return -1; bn_read_le(in, out); bn_normalize(out); return bn_is_less(out, &pallas_prime) ? 0 : -1; } -static int read_scalar_field(const uint8_t in[32], bignum256 *out) { +static int read_scalar_field(const uint8_t in[32], bignum256* out) { if (!in || !out) return -1; bn_read_le(in, out); bn_normalize(out); return bn_is_less(out, &pallas_order) ? 0 : -1; } -static int points_same_x(const curve_point *a, const curve_point *b) { +static int points_same_x(const curve_point* a, const curve_point* b) { bignum256 ax, bx; bn_copy(&a->x, &ax); bn_copy(&b->x, &bx); @@ -85,8 +81,8 @@ static int points_same_x(const curve_point *a, const curve_point *b) { return same; } -static int sinsemilla_incomplete_add(const curve_point *a, const curve_point *b, - curve_point *out) { +static int sinsemilla_incomplete_add(const curve_point* a, const curve_point* b, + curve_point* out) { if (!a || !b || !out) return -1; if (pallas_point_is_identity(a) || pallas_point_is_identity(b)) return -1; if (points_same_x(a, b)) return -1; @@ -95,11 +91,11 @@ static int sinsemilla_incomplete_add(const curve_point *a, const curve_point *b, return 0; } -static int bit_from_msg(const uint8_t *msg, size_t bit) { +static int bit_from_msg(const uint8_t* msg, size_t bit) { return (msg[bit / 8] >> (bit % 8)) & 1; } -static uint32_t sinsemilla_word(const uint8_t *msg, size_t msg_bits, +static uint32_t sinsemilla_word(const uint8_t* msg, size_t msg_bits, size_t word_idx) { uint32_t word = 0; for (size_t i = 0; i < PALLAS_SINSEMILLA_K; i++) { @@ -111,7 +107,7 @@ static uint32_t sinsemilla_word(const uint8_t *msg, size_t msg_bits, return word; } -static int sinsemilla_s_generator(uint32_t word, curve_point *out) { +static int sinsemilla_s_generator(uint32_t word, curve_point* out) { static const char domain[] = "z.cash:SinsemillaS"; uint8_t word_le[4] = { (uint8_t)(word & 0xff), @@ -124,7 +120,7 @@ static int sinsemilla_s_generator(uint32_t word, curve_point *out) { return ret; } -static void set_msg_bit(uint8_t *msg, size_t bit) { +static void set_msg_bit(uint8_t* msg, size_t bit) { msg[bit / 8] |= (uint8_t)(1u << (bit % 8)); } @@ -141,8 +137,8 @@ static void pack_commit_ivk_msg(const uint8_t ak[32], const uint8_t nk[32], } } -int pallas_sinsemilla_hash_to_point(const curve_point *q, const uint8_t *msg, - size_t msg_bits, curve_point *out) { +int pallas_sinsemilla_hash_to_point(const curve_point* q, const uint8_t* msg, + size_t msg_bits, curve_point* out) { if (!q || (!msg && msg_bits != 0) || !out) return -1; if (msg_bits > PALLAS_SINSEMILLA_MAX_BITS) return -1; if (pallas_point_is_identity(q)) return -1; @@ -179,7 +175,7 @@ int pallas_sinsemilla_hash_to_point(const curve_point *q, const uint8_t *msg, return 0; } -int pallas_sinsemilla_hash(const curve_point *q, const uint8_t *msg, +int pallas_sinsemilla_hash(const curve_point* q, const uint8_t* msg, size_t msg_bits, uint8_t hash_out[32]) { if (!hash_out) return -1; @@ -197,28 +193,65 @@ int pallas_sinsemilla_hash(const curve_point *q, const uint8_t *msg, return 0; } -int pallas_sinsemilla_commit(const curve_point *q, const curve_point *r, - const uint8_t *msg, size_t msg_bits, - const uint8_t blind[32], curve_point *out) { - if (!r || !blind || !out) return -1; +static int pallas_sinsemilla_commit_prepare(const curve_point* q, + const curve_point* r, + const uint8_t* msg, size_t msg_bits, + const uint8_t blind[32], + bignum256* blind_scalar, + curve_point* hash_point) { + if (!r || !blind || !blind_scalar || !hash_point) return -1; if (pallas_point_is_identity(r)) return -1; + if (read_scalar_field(blind, blind_scalar) != 0) { + memzero(blind_scalar, sizeof(*blind_scalar)); + return -1; + } + + if (pallas_sinsemilla_hash_to_point(q, msg, msg_bits, hash_point) != 0) { + memzero(blind_scalar, sizeof(*blind_scalar)); + return -1; + } + return 0; +} + +int pallas_sinsemilla_commit(const curve_point* q, const curve_point* r, + const uint8_t* msg, size_t msg_bits, + const uint8_t blind[32], curve_point* out) { + if (!out) return -1; + bignum256 blind_scalar; - if (read_scalar_field(blind, &blind_scalar) != 0) { - memzero(&blind_scalar, sizeof(blind_scalar)); + curve_point hash_point, blind_point, commit; + if (pallas_sinsemilla_commit_prepare(q, r, msg, msg_bits, blind, + &blind_scalar, &hash_point) != 0) { return -1; } + /* This generic API is used to verify transaction note commitments. Its + * rcm is derived from host-supplied rseed/rho and is public PCZT data. */ + pallas_point_mult(&blind_scalar, r, &blind_point); + pallas_point_add(&hash_point, &blind_point, &commit); + *out = commit; + + memzero(&blind_scalar, sizeof(blind_scalar)); + memzero(&hash_point, sizeof(hash_point)); + memzero(&blind_point, sizeof(blind_point)); + memzero(&commit, sizeof(commit)); + return 0; +} + +static int pallas_sinsemilla_commit_secret_blind( + const curve_point* q, const curve_point* r, const uint8_t* msg, + size_t msg_bits, const uint8_t blind[32], curve_point* out) { + if (!out) return -1; + + bignum256 blind_scalar; curve_point hash_point, blind_point, commit; - if (pallas_sinsemilla_hash_to_point(q, msg, msg_bits, &hash_point) != 0) { - memzero(&blind_scalar, sizeof(blind_scalar)); + if (pallas_sinsemilla_commit_prepare(q, r, msg, msg_bits, blind, + &blind_scalar, &hash_point) != 0) { return -1; } - /* The blind is host-supplied for transaction note verification, but is the - * device-secret rivk during IVK derivation. Keep this narrow part of the - * commitment on the fixed-schedule path; only the repeated public - * Sinsemilla hash additions use the compatibility implementation. */ + /* rivk is device-secret during IVK derivation. */ pallas_ct_point_mult(&blind_scalar, r, &blind_point); pallas_ct_point_add(&hash_point, &blind_point, &commit); *out = commit; @@ -230,10 +263,9 @@ int pallas_sinsemilla_commit(const curve_point *q, const curve_point *r, return 0; } -int pallas_sinsemilla_short_commit(const curve_point *q, const curve_point *r, - const uint8_t *msg, size_t msg_bits, - const uint8_t blind[32], - uint8_t out[32]) { +int pallas_sinsemilla_short_commit(const curve_point* q, const curve_point* r, + const uint8_t* msg, size_t msg_bits, + const uint8_t blind[32], uint8_t out[32]) { if (!out) return -1; curve_point commit; @@ -251,8 +283,7 @@ int pallas_sinsemilla_short_commit(const curve_point *q, const curve_point *r, } int pallas_sinsemilla_commit_ivk(const uint8_t ak[32], const uint8_t nk[32], - const uint8_t rivk[32], - uint8_t ivk_out[32]) { + const uint8_t rivk[32], uint8_t ivk_out[32]) { if (!ak || !nk || !rivk || !ivk_out) return -1; bignum256 ak_field, nk_field; @@ -268,12 +299,21 @@ int pallas_sinsemilla_commit_ivk(const uint8_t ak[32], const uint8_t nk[32], pack_commit_ivk_msg(ak, nk, msg); point_from_xy_le(COMMIT_IVK_Q_X, COMMIT_IVK_Q_Y, &q); point_from_xy_le(COMMIT_IVK_R_X, COMMIT_IVK_R_Y, &r); - int ret = pallas_sinsemilla_short_commit(&q, &r, msg, 510, rivk, ivk_out); + curve_point commit; + int ret = + pallas_sinsemilla_commit_secret_blind(&q, &r, msg, 510, rivk, &commit); + if (ret == 0) { + bignum256 x; + bn_copy(&commit.x, &x); + bn_write_le(&x, ivk_out); + memzero(&x, sizeof(x)); + } memzero(&ak_field, sizeof(ak_field)); memzero(&nk_field, sizeof(nk_field)); memzero(msg, sizeof(msg)); memzero(&q, sizeof(q)); memzero(&r, sizeof(r)); + memzero(&commit, sizeof(commit)); return ret; } diff --git a/deps/crypto/trezor-crypto/pallas_sinsemilla.h b/deps/crypto/trezor-crypto/pallas_sinsemilla.h index 325f45884..8076c6cb4 100644 --- a/deps/crypto/trezor-crypto/pallas_sinsemilla.h +++ b/deps/crypto/trezor-crypto/pallas_sinsemilla.h @@ -14,8 +14,7 @@ #define PALLAS_SINSEMILLA_K 10 #define PALLAS_SINSEMILLA_C 253 -#define PALLAS_SINSEMILLA_MAX_BITS \ - (PALLAS_SINSEMILLA_K * PALLAS_SINSEMILLA_C) +#define PALLAS_SINSEMILLA_MAX_BITS (PALLAS_SINSEMILLA_K * PALLAS_SINSEMILLA_C) /* * Compute SinsemillaHashToPoint(Q, msg). @@ -23,33 +22,33 @@ * msg is a packed little-endian bit string: bit i is read from * msg[i / 8] >> (i % 8). msg_bits must be <= PALLAS_SINSEMILLA_MAX_BITS. */ -int pallas_sinsemilla_hash_to_point(const curve_point *q, const uint8_t *msg, - size_t msg_bits, curve_point *out); +int pallas_sinsemilla_hash_to_point(const curve_point* q, const uint8_t* msg, + size_t msg_bits, curve_point* out); /* * Compute SinsemillaHash(Q, msg), returning the little-endian Pallas base-field * x-coordinate extracted from SinsemillaHashToPoint. */ -int pallas_sinsemilla_hash(const curve_point *q, const uint8_t *msg, +int pallas_sinsemilla_hash(const curve_point* q, const uint8_t* msg, size_t msg_bits, uint8_t hash_out[32]); /* * Compute SinsemillaCommit(Q, R, msg, r). * - * blind is a canonical Pallas scalar-field encoding. + * blind is a canonical Pallas scalar-field encoding and must be public + * transaction data. Secret rivk commitments use the dedicated IVK API below. */ -int pallas_sinsemilla_commit(const curve_point *q, const curve_point *r, - const uint8_t *msg, size_t msg_bits, - const uint8_t blind[32], curve_point *out); +int pallas_sinsemilla_commit(const curve_point* q, const curve_point* r, + const uint8_t* msg, size_t msg_bits, + const uint8_t blind[32], curve_point* out); /* * Compute SinsemillaShortCommit(Q, R, msg, r), returning the little-endian * Pallas base-field x-coordinate extracted from SinsemillaCommit. */ -int pallas_sinsemilla_short_commit(const curve_point *q, const curve_point *r, - const uint8_t *msg, size_t msg_bits, - const uint8_t blind[32], - uint8_t out[32]); +int pallas_sinsemilla_short_commit(const curve_point* q, const curve_point* r, + const uint8_t* msg, size_t msg_bits, + const uint8_t blind[32], uint8_t out[32]); /* * Compute Commit^ivk.Output = SinsemillaShortCommit( @@ -60,7 +59,6 @@ int pallas_sinsemilla_short_commit(const curve_point *q, const curve_point *r, * base-field output; callers must reject zero where required by Orchard IVKs. */ int pallas_sinsemilla_commit_ivk(const uint8_t ak[32], const uint8_t nk[32], - const uint8_t rivk[32], - uint8_t ivk_out[32]); + const uint8_t rivk[32], uint8_t ivk_out[32]); #endif diff --git a/deps/crypto/trezor-crypto/redpallas.c b/deps/crypto/trezor-crypto/redpallas.c index 37237a1a9..6faf166ad 100644 --- a/deps/crypto/trezor-crypto/redpallas.c +++ b/deps/crypto/trezor-crypto/redpallas.c @@ -50,10 +50,9 @@ * Source: reddsa-0.5.1 ORCHARD_SPENDAUTHSIG_BASEPOINT_BYTES constant. */ static const uint8_t pallas_spendauth_G_bytes[32] = { - 0x63, 0xc9, 0x75, 0xb8, 0x84, 0x72, 0x1a, 0x8d, - 0x0c, 0xa1, 0x70, 0x7b, 0xe3, 0x0c, 0x7f, 0x0c, - 0x5f, 0x44, 0x5f, 0x3e, 0x7c, 0x18, 0x8d, 0x3b, - 0x06, 0xd6, 0xf1, 0x28, 0xb3, 0x23, 0x55, 0xb7, + 0x63, 0xc9, 0x75, 0xb8, 0x84, 0x72, 0x1a, 0x8d, 0x0c, 0xa1, 0x70, + 0x7b, 0xe3, 0x0c, 0x7f, 0x0c, 0x5f, 0x44, 0x5f, 0x3e, 0x7c, 0x18, + 0x8d, 0x3b, 0x06, 0xd6, 0xf1, 0x28, 0xb3, 0x23, 0x55, 0xb7, }; /* Cached SpendAuth basepoint (lazy-initialized from compressed bytes) */ @@ -68,7 +67,7 @@ static int spendauth_G_initialized = 0; * sign(y) = y is odd (bit 0 of y) */ -static void pallas_point_serialize(const curve_point *p, uint8_t out[32]) { +static void pallas_point_serialize(const curve_point* p, uint8_t out[32]) { bignum256 x_copy; bn_copy(&p->x, &x_copy); bn_write_le(&x_copy, out); @@ -77,7 +76,7 @@ static void pallas_point_serialize(const curve_point *p, uint8_t out[32]) { } } -static int pallas_point_deserialize(const uint8_t in[32], curve_point *p) { +static int pallas_point_deserialize(const uint8_t in[32], curve_point* p) { uint8_t buf[32]; memcpy(buf, in, 32); /* Extract sign bit */ @@ -95,29 +94,29 @@ static int pallas_point_deserialize(const uint8_t in[32], curve_point *p) { /* Compute y^2 = x^3 + 5 mod p using custom Pallas arithmetic */ bignum256 y2; bn_copy(&p->x, &y2); - pallas_mul_mod_p(&y2, &p->x); /* y2 = x^2 */ - pallas_mul_mod_p(&y2, &p->x); /* y2 = x^3 */ + pallas_mul_mod_p(&y2, &p->x); /* y2 = x^2 */ + pallas_mul_mod_p(&y2, &p->x); /* y2 = x^3 */ bignum256 b; bn_zero(&b); b.val[0] = 5; - pallas_add_mod_p(&y2, &b, &y2); /* y2 = x^3 + 5 mod p */ + pallas_add_mod_p(&y2, &b, &y2); /* y2 = x^3 + 5 mod p */ /* Compute y = sqrt(y2) mod p using Tonelli-Shanks */ bn_copy(&y2, &p->y); if (pallas_sqrt_mod_p(&p->y) != 0) { - return -1; /* Not a valid point (y2 is not a QR) */ + return -1; /* Not a valid point (y2 is not a QR) */ } /* Verify sqrt is correct: check y^2 == y2 */ bignum256 check; bn_copy(&p->y, &check); - pallas_mul_mod_p(&check, &p->y); /* check = y^2 */ + pallas_mul_mod_p(&check, &p->y); /* check = y^2 */ /* Normalize both for comparison */ bn_normalize(&check); bn_normalize(&y2); if (!bn_is_equal(&check, &y2)) { - return -1; /* Not a valid point */ + return -1; /* Not a valid point */ } /* Fix sign of y */ @@ -135,7 +134,7 @@ static int pallas_point_deserialize(const uint8_t in[32], curve_point *p) { * * res = k * G_spendauth */ -static void pallas_scalar_mult_spendauth(const bignum256 *k, curve_point *res) { +static void pallas_scalar_mult_spendauth(const bignum256* k, curve_point* res) { if (!spendauth_G_initialized) { pallas_point_deserialize(pallas_spendauth_G_bytes, &spendauth_G_cache); spendauth_G_initialized = 1; @@ -146,11 +145,22 @@ static void pallas_scalar_mult_spendauth(const bignum256 *k, curve_point *res) { pallas_ct_point_mult(k, &spendauth_G_cache, res); } +static void pallas_scalar_mult_spendauth_public(const bignum256* k, + curve_point* res) { + if (!spendauth_G_initialized) { + pallas_point_deserialize(pallas_spendauth_G_bytes, &spendauth_G_cache); + spendauth_G_initialized = 1; + } + /* alpha is transmitted by the host and committed by the Orchard action. + * This path must never be used with ask, rsk, a nonce, or another secret. */ + pallas_point_mult(k, &spendauth_G_cache, res); +} + /* * Public API: Scalar multiplication by SpendAuth basepoint. * For use by FVK export (ak = [ask]*G_spendauth). */ -void redpallas_scalar_mult_spendauth_G(const bignum256 *k, curve_point *res) { +void redpallas_scalar_mult_spendauth_G(const bignum256* k, curve_point* res) { pallas_scalar_mult_spendauth(k, res); } @@ -159,17 +169,17 @@ void redpallas_scalar_mult_spendauth_G(const bignum256 *k, curve_point *res) { * * q = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001 * 2^256 mod q = 2^254 - 3*(q - 2^254) - * = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF992C350BE34205675B2B3E9CFFFFFFFD + * = + * 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF992C350BE34205675B2B3E9CFFFFFFFD * * Stored as 32 bytes little-endian. * Source: pasta_curves Montgomery radix R for the Pallas scalar field (Fq). * Verified: R + 3*q == 2^256. */ static const uint8_t two_256_mod_q[32] = { - 0xfd, 0xff, 0xff, 0xff, 0x9c, 0x3e, 0x2b, 0x5b, - 0x67, 0x05, 0x42, 0xe3, 0x0b, 0x35, 0x2c, 0x99, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, + 0xfd, 0xff, 0xff, 0xff, 0x9c, 0x3e, 0x2b, 0x5b, 0x67, 0x05, 0x42, + 0xe3, 0x0b, 0x35, 0x2c, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, }; /* @@ -184,7 +194,7 @@ static const uint8_t two_256_mod_q[32] = { * because the orchard crate verifies against from_uniform_bytes — the * values differ whenever hi != 0, which is ~100% of the time. */ -static void pallas_from_uniform_bytes(const uint8_t input[64], bignum256 *out) { +static void pallas_from_uniform_bytes(const uint8_t input[64], bignum256* out) { bignum256 lo, hi, t256; bn_read_le(input, &lo); @@ -213,8 +223,7 @@ static void pallas_from_uniform_bytes(const uint8_t input[64], bignum256 *out) { */ static void redpallas_hash_challenge(const uint8_t R_bytes[32], const uint8_t rk_bytes[32], - const uint8_t sighash[32], - bignum256 *c) { + const uint8_t sighash[32], bignum256* c) { uint8_t hash_out[64]; BLAKE2B_CTX ctx; @@ -230,23 +239,27 @@ static void redpallas_hash_challenge(const uint8_t R_bytes[32], memzero(hash_out, sizeof(hash_out)); } -int redpallas_sign_digest(const uint8_t *ask, const uint8_t *alpha, - const uint8_t *sighash, uint8_t *sig_out) { - bignum256 ask_scalar, alpha_scalar, rsk, r, c, s; - curve_point R_point, rk_point; - uint8_t R_bytes[32], rk_bytes[32]; - - /* Read scalars (little-endian, as used by Zcash) */ - bn_read_le(ask, &ask_scalar); - bn_read_le(alpha, &alpha_scalar); - - /* rsk = (ask + alpha) mod order */ - bn_copy(&ask_scalar, &rsk); - pallas_ct_add_mod_q(&rsk, &alpha_scalar); +typedef struct { + redpallas_progress_callback callback; + void* context; +} redpallas_progress_bridge; + +static void redpallas_nonce_progress(uint32_t completed, uint32_t total, + void* context) { + redpallas_progress_bridge* bridge = (redpallas_progress_bridge*)context; + /* Public-rk validation is the first 10%; the fixed 255-round nonce + * multiplication is the remaining 90%. */ + bridge->callback(100 + (900 * completed) / total, 1000, bridge->context); +} - /* rk = [rsk]G_spendauth - randomized verification key */ - pallas_scalar_mult_spendauth(&rsk, &rk_point); - pallas_point_serialize(&rk_point, rk_bytes); +static int redpallas_sign_with_rsk(const bignum256* rsk, + const uint8_t rk_bytes[32], + const uint8_t* sighash, uint8_t* sig_out, + redpallas_progress_callback progress, + void* progress_context) { + bignum256 r, c, s; + curve_point R_point; + uint8_t R_bytes[32]; /* Generate random nonce r */ uint8_t rbuf[32]; @@ -258,35 +271,121 @@ int redpallas_sign_digest(const uint8_t *ask, const uint8_t *alpha, pallas_ct_scalar_replace_zero_with_one(&r); /* R = [r]G_spendauth - nonce commitment */ - pallas_scalar_mult_spendauth(&r, &R_point); + if (progress) { + redpallas_progress_bridge bridge = {progress, progress_context}; + pallas_ct_point_mult_progress(&r, &spendauth_G_cache, &R_point, + redpallas_nonce_progress, &bridge); + } else { + pallas_scalar_mult_spendauth(&r, &R_point); + } pallas_point_serialize(&R_point, R_bytes); /* c = H("Zcash_RedPallasH", R || rk || sighash) mod order */ redpallas_hash_challenge(R_bytes, rk_bytes, sighash, &c); /* S = r + c * rsk (mod order) */ - pallas_ct_mul_mod_q(&c, &rsk); /* c = c * rsk mod order */ + pallas_ct_mul_mod_q(&c, rsk); /* c = c * rsk mod order */ bn_copy(&r, &s); - pallas_ct_add_mod_q(&s, &c); /* s = r + c*rsk mod order */ + pallas_ct_add_mod_q(&s, &c); /* s = r + c*rsk mod order */ /* Output: R (32 bytes LE) || S (32 bytes LE) */ memcpy(sig_out, R_bytes, 32); bn_write_le(&s, sig_out + 32); /* Clean up sensitive data */ - memzero(&ask_scalar, sizeof(ask_scalar)); - memzero(&alpha_scalar, sizeof(alpha_scalar)); - memzero(&rsk, sizeof(rsk)); memzero(&r, sizeof(r)); memzero(&c, sizeof(c)); memzero(&s, sizeof(s)); + memzero(&R_point, sizeof(R_point)); + memzero(R_bytes, sizeof(R_bytes)); memzero(rbuf, sizeof(rbuf)); return 0; } -int redpallas_verify_digest(const uint8_t *rk, const uint8_t *sighash, - const uint8_t *sig) { +int redpallas_derive_rk_from_ak(const uint8_t* ak, const uint8_t* alpha, + uint8_t* rk_out) { + if (!ak || !alpha || !rk_out) return -1; + + curve_point ak_point, alpha_point, rk_point; + bignum256 alpha_scalar; + if (pallas_point_deserialize(ak, &ak_point) != 0) { + return -1; + } + + bn_read_le(alpha, &alpha_scalar); + pallas_mod_q(&alpha_scalar); + pallas_scalar_mult_spendauth_public(&alpha_scalar, &alpha_point); + pallas_point_add(&ak_point, &alpha_point, &rk_point); + pallas_point_serialize(&rk_point, rk_out); + + memzero(&alpha_scalar, sizeof(alpha_scalar)); + memzero(&ak_point, sizeof(ak_point)); + memzero(&alpha_point, sizeof(alpha_point)); + memzero(&rk_point, sizeof(rk_point)); + return 0; +} + +int redpallas_sign_digest_with_ak(const uint8_t* ask, const uint8_t* ak, + const uint8_t* alpha, + const uint8_t* expected_rk, + const uint8_t* sighash, uint8_t* sig_out, + redpallas_progress_callback progress, + void* progress_context) { + if (!ask || !ak || !alpha || !expected_rk || !sighash || !sig_out) return -1; + + bignum256 ask_scalar, alpha_scalar, rsk; + uint8_t rk_bytes[32]; + if (progress) progress(0, 1000, progress_context); + + if (redpallas_derive_rk_from_ak(ak, alpha, rk_bytes) != 0 || + memcmp(rk_bytes, expected_rk, sizeof(rk_bytes)) != 0) { + memzero(rk_bytes, sizeof(rk_bytes)); + return -1; + } + if (progress) progress(100, 1000, progress_context); + + bn_read_le(ask, &ask_scalar); + bn_read_le(alpha, &alpha_scalar); + bn_copy(&ask_scalar, &rsk); + pallas_ct_add_mod_q(&rsk, &alpha_scalar); + + int result = redpallas_sign_with_rsk(&rsk, rk_bytes, sighash, sig_out, + progress, progress_context); + memzero(&ask_scalar, sizeof(ask_scalar)); + memzero(&alpha_scalar, sizeof(alpha_scalar)); + memzero(&rsk, sizeof(rsk)); + memzero(rk_bytes, sizeof(rk_bytes)); + return result; +} + +int redpallas_sign_digest(const uint8_t* ask, const uint8_t* alpha, + const uint8_t* sighash, uint8_t* sig_out) { + bignum256 ask_scalar, alpha_scalar, rsk; + curve_point rk_point; + uint8_t rk_bytes[32]; + + bn_read_le(ask, &ask_scalar); + bn_read_le(alpha, &alpha_scalar); + bn_copy(&ask_scalar, &rsk); + pallas_ct_add_mod_q(&rsk, &alpha_scalar); + + /* Compatibility API: without a cached ak, derive rk from secret rsk. */ + pallas_scalar_mult_spendauth(&rsk, &rk_point); + pallas_point_serialize(&rk_point, rk_bytes); + int result = + redpallas_sign_with_rsk(&rsk, rk_bytes, sighash, sig_out, NULL, NULL); + + memzero(&ask_scalar, sizeof(ask_scalar)); + memzero(&alpha_scalar, sizeof(alpha_scalar)); + memzero(&rsk, sizeof(rsk)); + memzero(&rk_point, sizeof(rk_point)); + memzero(rk_bytes, sizeof(rk_bytes)); + return result; +} + +int redpallas_verify_digest(const uint8_t* rk, const uint8_t* sighash, + const uint8_t* sig) { bignum256 c, s; curve_point R_point, rk_point, lhs, rhs, cR; @@ -331,8 +430,8 @@ int redpallas_verify_digest(const uint8_t *rk, const uint8_t *sighash, return 0; } -int redpallas_derive_rk(const uint8_t *ask, const uint8_t *alpha, - uint8_t *rk_out) { +int redpallas_derive_rk(const uint8_t* ask, const uint8_t* alpha, + uint8_t* rk_out) { bignum256 ask_scalar, alpha_scalar, rsk; curve_point rk_point; diff --git a/deps/crypto/trezor-crypto/redpallas.h b/deps/crypto/trezor-crypto/redpallas.h index a16e7a3eb..061deca3c 100644 --- a/deps/crypto/trezor-crypto/redpallas.h +++ b/deps/crypto/trezor-crypto/redpallas.h @@ -30,6 +30,9 @@ #include "bignum.h" #include "ecdsa.h" +typedef void (*redpallas_progress_callback)(uint32_t completed, uint32_t total, + void* context); + /** * RedPallas spend authorization signature. * @@ -48,8 +51,27 @@ * @param sig_out 64-byte output: R (32 bytes) || S (32 bytes), little-endian * @return 0 on success, non-zero on error */ -int redpallas_sign_digest(const uint8_t *ask, const uint8_t *alpha, - const uint8_t *sighash, uint8_t *sig_out); +int redpallas_sign_digest(const uint8_t* ask, const uint8_t* alpha, + const uint8_t* sighash, uint8_t* sig_out); + +/** + * Sign using the cached public ak and verify the host-provided rk first. + * + * rk = ak + [alpha]G is derived entirely from public data, avoiding a second + * secret-scalar multiplication during each signature. The nonce commitment + * remains on the fixed-schedule implementation. Progress reports fixed public + * work units in the range 0..1000. + */ +int redpallas_sign_digest_with_ak(const uint8_t* ask, const uint8_t* ak, + const uint8_t* alpha, + const uint8_t* expected_rk, + const uint8_t* sighash, uint8_t* sig_out, + redpallas_progress_callback progress, + void* progress_context); + +/** Derive rk = ak + [alpha]G from public Orchard transaction data. */ +int redpallas_derive_rk_from_ak(const uint8_t* ak, const uint8_t* alpha, + uint8_t* rk_out); /** * Verify a RedPallas signature. @@ -59,8 +81,8 @@ int redpallas_sign_digest(const uint8_t *ask, const uint8_t *alpha, * @param sig 64-byte signature: R (32 bytes) || S (32 bytes) * @return 0 if signature is valid, non-zero otherwise */ -int redpallas_verify_digest(const uint8_t *rk, const uint8_t *sighash, - const uint8_t *sig); +int redpallas_verify_digest(const uint8_t* rk, const uint8_t* sighash, + const uint8_t* sig); /** * Derive randomized verification key: rk = [(ask + alpha) mod order] * G @@ -70,16 +92,17 @@ int redpallas_verify_digest(const uint8_t *rk, const uint8_t *sighash, * @param rk_out 32-byte output: compressed point (little-endian x-coordinate) * @return 0 on success */ -int redpallas_derive_rk(const uint8_t *ask, const uint8_t *alpha, - uint8_t *rk_out); +int redpallas_derive_rk(const uint8_t* ask, const uint8_t* alpha, + uint8_t* rk_out); /** * Scalar multiplication by the Orchard SpendAuth basepoint. - * Computes res = k * G_spendauth where G_spendauth = GroupHash^P("z.cash:Orchard", "G"). + * Computes res = k * G_spendauth where G_spendauth = + * GroupHash^P("z.cash:Orchard", "G"). * * @param k Scalar to multiply (bignum256) * @param res Output point */ -void redpallas_scalar_mult_spendauth_G(const bignum256 *k, curve_point *res); +void redpallas_scalar_mult_spendauth_G(const bignum256* k, curve_point* res); #endif diff --git a/include/keepkey/firmware/zcash.h b/include/keepkey/firmware/zcash.h index 79b27c391..3bd31916d 100644 --- a/include/keepkey/firmware/zcash.h +++ b/include/keepkey/firmware/zcash.h @@ -34,6 +34,8 @@ typedef struct { // cppcheck-suppress unusedStructMember uint8_t ask[32]; /* Spend authorizing key (scalar) */ // cppcheck-suppress unusedStructMember + uint8_t ak[32]; /* Public spend validating key (compressed, even y) */ + // cppcheck-suppress unusedStructMember uint8_t nk[32]; /* Nullifier deriving key */ // cppcheck-suppress unusedStructMember uint8_t rivk[32]; /* Commitment randomness key */ diff --git a/lib/firmware/fsm_msg_zcash.h b/lib/firmware/fsm_msg_zcash.h index cd40a8022..a78555176 100644 --- a/lib/firmware/fsm_msg_zcash.h +++ b/lib/firmware/fsm_msg_zcash.h @@ -324,6 +324,27 @@ static bool zcash_verify_and_confirm_fee(void) { return true; } +typedef struct { + uint32_t base; + uint32_t span; + uint32_t last; +} ZcashRedPallasProgress; + +static void zcash_redpallas_progress(uint32_t completed, uint32_t total, + void* context) { + ZcashRedPallasProgress* progress = (ZcashRedPallasProgress*)context; + if (!progress || total == 0) return; + + /* completed/total is the fixed public scalar-loop schedule, never a value + * derived from ask or the nonce. Update only when the visible permil changes + * to avoid redundant OLED transfers while preserving a smooth bar. */ + uint32_t permil = progress->base + (progress->span * completed) / total; + if (permil != progress->last) { + progress->last = permil; + layoutProgress(_("Signing Zcash"), (int)permil); + } +} + static void zcash_send_action_ack(uint32_t next_index) { ZcashPCZTActionAck* resp_ack = (ZcashPCZTActionAck*)msg_resp; memset(resp_ack, 0, sizeof(ZcashPCZTActionAck)); @@ -819,25 +840,10 @@ void fsm_msgZcashGetOrchardFVK(const ZcashGetOrchardFVK* msg) { return; } - /* Compute ak = [ask]G_spendauth on Pallas curve (SpendAuth basepoint) */ - bignum256 ask_scalar; - bn_read_le(keys.ask, &ask_scalar); - curve_point ak_point; - redpallas_scalar_mult_spendauth_G(&ask_scalar, &ak_point); - - /* Serialize ak as Pallas point (LE x-coord, sign bit in high byte) */ - uint8_t ak_bytes[32]; - bignum256 x_copy; - bn_copy(&ak_point.x, &x_copy); - bn_write_le(&x_copy, ak_bytes); - if (bn_is_odd(&ak_point.y)) { - ak_bytes[31] |= 0x80; - } - /* Build response */ resp->has_ak = true; resp->ak.size = 32; - memcpy(resp->ak.bytes, ak_bytes, 32); + memcpy(resp->ak.bytes, keys.ak, 32); resp->has_nk = true; resp->nk.size = 32; @@ -858,7 +864,6 @@ void fsm_msgZcashGetOrchardFVK(const ZcashGetOrchardFVK* msg) { } /* Clean up sensitive data */ - memzero(&ask_scalar, sizeof(ask_scalar)); memzero(&keys, sizeof(keys)); msg_write(MessageType_MessageType_ZcashOrchardFVK, resp); @@ -1048,10 +1053,21 @@ void fsm_msgZcashPCZTAction(const ZcashPCZTAction* msg) { const uint8_t* sighash = zcash_signing.sighash; - /* Sign this action with RedPallas: - * sig = RedPallas.sign(ask, alpha, sighash) */ - if (redpallas_sign_digest(zcash_signing.keys.ask, msg->alpha.bytes, sighash, - zcash_signing.signatures[msg->index]) != 0) { + /* Sign this action with RedPallas. Derive rk from cached public ak + public + * alpha and require it to match the PCZT before using it in the challenge. + * This removes one secret-scalar multiplication per action; the secret nonce + * multiplication remains fixed-schedule and reports its public loop progress + * directly so the OLED advances during CPU-bound signing. */ + const uint32_t action_base = + (zcash_signing.current_action * 1000) / zcash_signing.n_actions; + const uint32_t action_target = + ((zcash_signing.current_action + 1) * 1000) / zcash_signing.n_actions; + ZcashRedPallasProgress signing_progress = { + action_base, action_target - action_base, action_base}; + if (redpallas_sign_digest_with_ak( + zcash_signing.keys.ask, zcash_signing.keys.ak, msg->alpha.bytes, + msg->rk.bytes, sighash, zcash_signing.signatures[msg->index], + zcash_redpallas_progress, &signing_progress) != 0) { fsm_sendFailure(FailureType_Failure_Other, _("RedPallas signing failed")); zcash_signing_abort(); layoutHome(); diff --git a/lib/firmware/zcash.c b/lib/firmware/zcash.c index c3e5adfdd..034ddac0b 100644 --- a/lib/firmware/zcash.c +++ b/lib/firmware/zcash.c @@ -641,6 +641,10 @@ bool zcash_derive_orchard_keys(const uint8_t* seed, uint32_t seed_len, memzero(&ak_test, sizeof(ak_test)); memzero(&ak_x, sizeof(ak_x)); } + /* Cache the public key produced by the normalization multiplication. This + * avoids repeating the same expensive secret-scalar operation for FVK + * export and lets signing derive rk from public ak + public alpha. */ + memcpy(keys->ak, ak_bytes, sizeof(keys->ak)); /* nk = ToBase(PRF^expand(sk, [0x07])) */ uint8_t t_nk = 0x07; diff --git a/tools/check_pallas_api_boundary.py b/tools/check_pallas_api_boundary.py index 4876e22a0..fd0789ece 100644 --- a/tools/check_pallas_api_boundary.py +++ b/tools/check_pallas_api_boundary.py @@ -61,27 +61,57 @@ def main(): require(incomplete_add, "pallas_point_add", "Sinsemilla public hash add") forbid(incomplete_add, "pallas_ct_", "Sinsemilla public hash add") - # The commitment blind is rivk on IVK derivation paths, so its one scalar - # multiplication and the final add remain fixed-schedule. This does not - # put the repeated transaction commitment hash additions on the slow path. + # Transaction note rcm is host-known; use the fast public path. The IVK's + # device-secret rivk has a separate helper that remains fixed-schedule. commit = code_only(function_body(sinsemilla, "pallas_sinsemilla_commit")) - require(commit, "pallas_ct_point_mult", "Sinsemilla blinding") - require(commit, "pallas_ct_point_add", "Sinsemilla blinding") - forbid(commit, "pallas_point_mult(", "Sinsemilla blinding") - forbid(commit, "pallas_point_add(", "Sinsemilla blinding") + require(commit, "pallas_point_mult", "public Sinsemilla blinding") + require(commit, "pallas_point_add", "public Sinsemilla blinding") + forbid(commit, "pallas_ct_", "public Sinsemilla blinding") + secret_commit = code_only(function_body( + sinsemilla, "pallas_sinsemilla_commit_secret_blind")) + require(secret_commit, "pallas_ct_point_mult", "secret IVK blinding") + require(secret_commit, "pallas_ct_point_add", "secret IVK blinding") + forbid(secret_commit, "pallas_point_mult(", "secret IVK blinding") + forbid(secret_commit, "pallas_point_add(", "secret IVK blinding") + commit_ivk = code_only(function_body(sinsemilla, + "pallas_sinsemilla_commit_ivk")) + require(commit_ivk, "pallas_sinsemilla_commit_secret_blind", + "IVK commitment") + forbid(commit_ivk, "pallas_sinsemilla_short_commit", "IVK commitment") # Authorization scalars, nonces, and randomized keys must never fall back # to the variable-time public-data API. spendauth = code_only(function_body(redpallas, "pallas_scalar_mult_spendauth")) require(spendauth, "pallas_ct_point_mult", "RedPallas scalar multiplication") forbid(spendauth, "pallas_point_mult(", "RedPallas scalar multiplication") + public_spendauth = code_only(function_body( + redpallas, "pallas_scalar_mult_spendauth_public")) + require(public_spendauth, "pallas_point_mult", + "public alpha scalar multiplication") + forbid(public_spendauth, "pallas_ct_", + "public alpha scalar multiplication") sign = code_only(function_body(redpallas, "redpallas_sign_digest")) + require(sign, "pallas_ct_add_mod_q", "redpallas_sign_digest") + for token in ("pallas_add_mod_q(", "pallas_mod_q(", "pallas_mul_mod_q("): + forbid(sign, token, "redpallas_sign_digest") + + sign_core = code_only(function_body(redpallas, + "redpallas_sign_with_rsk")) for token in ("pallas_ct_add_mod_q", "pallas_ct_mod_q", "pallas_ct_mul_mod_q", "pallas_ct_scalar_replace_zero_with_one"): - require(sign, token, "redpallas_sign_digest") + require(sign_core, token, "RedPallas signing core") for token in ("pallas_add_mod_q(", "pallas_mod_q(", "pallas_mul_mod_q("): - forbid(sign, token, "redpallas_sign_digest") + forbid(sign_core, token, "RedPallas signing core") + + optimized_sign = code_only(function_body( + redpallas, "redpallas_sign_digest_with_ak")) + require(optimized_sign, "redpallas_derive_rk_from_ak", + "optimized RedPallas signing") + require(optimized_sign, "pallas_ct_add_mod_q", + "optimized RedPallas signing") + forbid(optimized_sign, "pallas_scalar_mult_spendauth_public", + "optimized RedPallas signing") derive_rk = code_only(function_body(redpallas, "redpallas_derive_rk")) require(derive_rk, "pallas_ct_add_mod_q", "redpallas_derive_rk") diff --git a/tools/check_pallas_ct_disassembly.py b/tools/check_pallas_ct_disassembly.py index f8308c526..fa95a5ee1 100644 --- a/tools/check_pallas_ct_disassembly.py +++ b/tools/check_pallas_ct_disassembly.py @@ -125,6 +125,69 @@ def verify_full(disassembly): if outside_loop: raise ValueError(f"fixed-round calls moved outside scalar loop: {outside_loop}") + progress_symbol = "pallas_ct_point_mult_progress" + progress_instructions = symbol_instructions(disassembly, progress_symbol) + if progress_instructions is None: + raise ValueError(f"missing required ARM symbol: {progress_symbol}") + progress_branches = [] + for index, instruction in enumerate(progress_instructions): + address, instruction_mnemonic, operands = instruction + if instruction_mnemonic not in CONDITIONAL_BRANCHES: + continue + next_instruction = ( + progress_instructions[index + 1] + if index + 1 < len(progress_instructions) + else None + ) + if ( + next_instruction is not None + and next_instruction[1] == "bl" + and "<__stack_chk_fail>" in next_instruction[2] + ): + continue + progress_branches.append( + (address, instruction_mnemonic, branch_target(operands)) + ) + if len(progress_branches) != 1: + raise ValueError( + f"{progress_symbol} must have one fixed loop branch; found " + f"{progress_branches}" + ) + progress_branch_address, _, progress_target = progress_branches[0] + if progress_target is None or progress_target >= progress_branch_address: + raise ValueError( + f"{progress_symbol} loop branch is not backward: " + f"{progress_branches[0]}" + ) + progress_required_calls = { + "ct_point_double": None, + "ct_point_add_internal": None, + "ct_point_select": None, + } + for address, instruction_mnemonic, operands in progress_instructions: + if instruction_mnemonic != "bl": + continue + for required in progress_required_calls: + if f"<{required}>" in operands: + progress_required_calls[required] = address + progress_missing = [ + name for name, address in progress_required_calls.items() if address is None + ] + if progress_missing: + raise ValueError( + f"{progress_symbol} is missing fixed-round calls: {progress_missing}" + ) + progress_outside_loop = [ + name + for name, address in progress_required_calls.items() + if not progress_target <= address < progress_branch_address + ] + if progress_outside_loop: + raise ValueError( + f"{progress_symbol} fixed-round calls moved outside scalar loop: " + f"{progress_outside_loop}" + ) + # Secret-dependent selects are written as masks. On the pinned ARM build, # every remaining conditional branch in this module must therefore be a # backward, fixed-bound loop (apart from stack-canary failure branches). @@ -190,7 +253,8 @@ def verify_full(disassembly): print( "Pallas ARM disassembly gate: PASS " - f"(one backward {mnemonic} loop; double/add/select all inside; " + f"(regular + progress multipliers each have one backward {mnemonic} " + "loop; double/add/select all inside; " "only fixed backward loops; no secret IT; no long multiply/divide)" ) diff --git a/unittests/crypto/pallas_ct.cpp b/unittests/crypto/pallas_ct.cpp index 9c94eb250..e738c6a9b 100644 --- a/unittests/crypto/pallas_ct.cpp +++ b/unittests/crypto/pallas_ct.cpp @@ -78,6 +78,21 @@ pallas_ct_counts MultiplyAndCount(const bignum256& scalar, return counts; } +struct ProgressCapture { + uint32_t calls = 0; + uint32_t last_completed = 0; + uint32_t last_total = 0; + bool monotonic = true; +}; + +void CaptureProgress(uint32_t completed, uint32_t total, void* context) { + auto* capture = static_cast(context); + if (completed <= capture->last_completed) capture->monotonic = false; + capture->calls++; + capture->last_completed = completed; + capture->last_total = total; +} + TEST(PallasConstantTime, ScalarScheduleDoesNotDependOnSecretBits) { const bignum256 zero = {{0}}; const bignum256 one = ScalarWithBit(0); @@ -104,6 +119,22 @@ TEST(PallasConstantTime, ScalarScheduleDoesNotDependOnSecretBits) { } } +TEST(PallasConstantTime, ProgressVariantMatchesAndReportsEveryFixedRound) { + const bignum256 scalar = DenseScalar(); + curve_point expected, actual; + pallas_ct_point_mult(&scalar, &kPallasGenerator, &expected); + + ProgressCapture progress; + pallas_ct_point_mult_progress(&scalar, &kPallasGenerator, &actual, + CaptureProgress, &progress); + + EXPECT_TRUE(PointsEqual(expected, actual)); + EXPECT_TRUE(progress.monotonic); + EXPECT_EQ(255u, progress.calls); + EXPECT_EQ(255u, progress.last_completed); + EXPECT_EQ(255u, progress.last_total); +} + TEST(PallasConstantTime, ZeroAndOneScalarResultsAreCanonical) { const bignum256 zero = {{0}}; const bignum256 one = ScalarWithBit(0); diff --git a/unittests/firmware/zcash.cpp b/unittests/firmware/zcash.cpp index 2d8f43e7f..7894f162e 100644 --- a/unittests/firmware/zcash.cpp +++ b/unittests/firmware/zcash.cpp @@ -490,6 +490,9 @@ TEST(Zcash, DeriveOrchardKeys_ReferenceVector_Account0) { EXPECT_TRUE(memcmp(keys.nk, EXPECTED_NK_ALL_0, 32) == 0) << "nk mismatch for all-mnemonic account 0"; + EXPECT_TRUE(memcmp(keys.ak, EXPECTED_AK_ALL_0, 32) == 0) + << "cached ak mismatch for all-mnemonic account 0"; + /* rivk must match reference */ EXPECT_TRUE(memcmp(keys.rivk, EXPECTED_RIVK_ALL_0, 32) == 0) << "rivk mismatch for all-mnemonic account 0"; @@ -570,6 +573,7 @@ TEST(Zcash, DeriveOrchardKeys_Deterministic) { EXPECT_TRUE(memcmp(keys1.sk, keys2.sk, 32) == 0); EXPECT_TRUE(memcmp(keys1.ask, keys2.ask, 32) == 0); + EXPECT_TRUE(memcmp(keys1.ak, keys2.ak, 32) == 0); EXPECT_TRUE(memcmp(keys1.nk, keys2.nk, 32) == 0); EXPECT_TRUE(memcmp(keys1.rivk, keys2.rivk, 32) == 0); EXPECT_TRUE(memcmp(keys1.dk, keys2.dk, 32) == 0); @@ -1505,6 +1509,61 @@ TEST(Zcash, ComputeShieldedSighash_KnownVector) { /* ── RedPallas Signing Smoke Test ────────────────────────────────── */ +struct RedPallasProgressCapture { + uint32_t calls = 0; + uint32_t last = 0; + uint32_t total = 0; + bool monotonic = true; +}; + +static void capture_redpallas_progress(uint32_t completed, uint32_t total, + void* context) { + auto* capture = static_cast(context); + if (capture->calls > 0 && completed < capture->last) { + capture->monotonic = false; + } + capture->calls++; + capture->last = completed; + capture->total = total; +} + +TEST(Zcash, RedPallasPublicRkPathMatchesAndReportsFixedProgress) { + ZcashOrchardKeys keys; + ASSERT_TRUE(zcash_derive_orchard_keys(SEED_ALL, 64, 0, &keys)); + + uint8_t alpha[32]; + memset(alpha, 0x01, sizeof(alpha)); + alpha[31] = 0; + uint8_t sighash[32]; + memset(sighash, 0xA5, sizeof(sighash)); + + uint8_t public_rk[32], secret_reference_rk[32]; + ASSERT_EQ(redpallas_derive_rk_from_ak(keys.ak, alpha, public_rk), 0); + ASSERT_EQ(redpallas_derive_rk(keys.ask, alpha, secret_reference_rk), 0); + EXPECT_EQ(memcmp(public_rk, secret_reference_rk, sizeof(public_rk)), 0); + + RedPallasProgressCapture progress; + uint8_t signature[64]; + ASSERT_EQ(redpallas_sign_digest_with_ak( + keys.ask, keys.ak, alpha, public_rk, sighash, signature, + capture_redpallas_progress, &progress), + 0); + EXPECT_TRUE(progress.monotonic); + EXPECT_EQ(257u, progress.calls); + EXPECT_EQ(1000u, progress.last); + EXPECT_EQ(1000u, progress.total); + EXPECT_EQ(redpallas_verify_digest(public_rk, sighash, signature), 0); + + uint8_t wrong_rk[32]; + memcpy(wrong_rk, public_rk, sizeof(wrong_rk)); + wrong_rk[0] ^= 1; + EXPECT_NE(redpallas_sign_digest_with_ak(keys.ask, keys.ak, alpha, wrong_rk, + sighash, signature, nullptr, nullptr), + 0); + + memzero(&keys, sizeof(keys)); +} + TEST(Zcash, RedPallasSign_ProducesVerifiableSignature) { ZcashOrchardKeys keys; ASSERT_TRUE(zcash_derive_orchard_keys(SEED_ALL, 64, 0, &keys)); From b3dbf42f82ea6517fd1a3fc93f8e24094ed323bf Mon Sep 17 00:00:00 2001 From: highlander Date: Sun, 26 Jul 2026 01:11:28 -0300 Subject: [PATCH 12/22] fix(zcash): skip dummy spends and unblock signing --- deps/crypto/trezor-crypto/redpallas.c | 56 ++++++++++++++++++------ deps/crypto/trezor-crypto/redpallas.h | 15 +++++++ lib/firmware/fsm_msg_zcash.h | 62 +++++++++++++++------------ tools/check_pallas_api_boundary.py | 24 +++++++++++ unittests/firmware/zcash.cpp | 35 +++++++++++++++ 5 files changed, 153 insertions(+), 39 deletions(-) diff --git a/deps/crypto/trezor-crypto/redpallas.c b/deps/crypto/trezor-crypto/redpallas.c index 6faf166ad..6f9b58f25 100644 --- a/deps/crypto/trezor-crypto/redpallas.c +++ b/deps/crypto/trezor-crypto/redpallas.c @@ -242,21 +242,21 @@ static void redpallas_hash_challenge(const uint8_t R_bytes[32], typedef struct { redpallas_progress_callback callback; void* context; + uint32_t base; + uint32_t span; } redpallas_progress_bridge; static void redpallas_nonce_progress(uint32_t completed, uint32_t total, void* context) { redpallas_progress_bridge* bridge = (redpallas_progress_bridge*)context; - /* Public-rk validation is the first 10%; the fixed 255-round nonce - * multiplication is the remaining 90%. */ - bridge->callback(100 + (900 * completed) / total, 1000, bridge->context); + bridge->callback(bridge->base + (bridge->span * completed) / total, 1000, + bridge->context); } -static int redpallas_sign_with_rsk(const bignum256* rsk, - const uint8_t rk_bytes[32], - const uint8_t* sighash, uint8_t* sig_out, - redpallas_progress_callback progress, - void* progress_context) { +static int redpallas_sign_with_rsk( + const bignum256* rsk, const uint8_t rk_bytes[32], const uint8_t* sighash, + uint8_t* sig_out, redpallas_progress_callback progress, + void* progress_context, uint32_t progress_base, uint32_t progress_span) { bignum256 r, c, s; curve_point R_point; uint8_t R_bytes[32]; @@ -272,7 +272,8 @@ static int redpallas_sign_with_rsk(const bignum256* rsk, /* R = [r]G_spendauth - nonce commitment */ if (progress) { - redpallas_progress_bridge bridge = {progress, progress_context}; + redpallas_progress_bridge bridge = {progress, progress_context, + progress_base, progress_span}; pallas_ct_point_mult_progress(&r, &spendauth_G_cache, &R_point, redpallas_nonce_progress, &bridge); } else { @@ -303,6 +304,37 @@ static int redpallas_sign_with_rsk(const bignum256* rsk, return 0; } +int redpallas_sign_digest_for_rk(const uint8_t* ask, const uint8_t* alpha, + const uint8_t* rk, const uint8_t* sighash, + uint8_t* sig_out, + redpallas_progress_callback progress, + void* progress_context) { + if (!ask || !alpha || !rk || !sighash || !sig_out) return -1; + + if (!spendauth_G_initialized) { + if (pallas_point_deserialize(pallas_spendauth_G_bytes, + &spendauth_G_cache) != 0) { + return -1; + } + spendauth_G_initialized = 1; + } + + bignum256 ask_scalar, alpha_scalar, rsk; + if (progress) progress(0, 1000, progress_context); + + bn_read_le(ask, &ask_scalar); + bn_read_le(alpha, &alpha_scalar); + bn_copy(&ask_scalar, &rsk); + pallas_ct_add_mod_q(&rsk, &alpha_scalar); + + const int result = redpallas_sign_with_rsk( + &rsk, rk, sighash, sig_out, progress, progress_context, 0, 1000); + memzero(&ask_scalar, sizeof(ask_scalar)); + memzero(&alpha_scalar, sizeof(alpha_scalar)); + memzero(&rsk, sizeof(rsk)); + return result; +} + int redpallas_derive_rk_from_ak(const uint8_t* ak, const uint8_t* alpha, uint8_t* rk_out) { if (!ak || !alpha || !rk_out) return -1; @@ -351,7 +383,7 @@ int redpallas_sign_digest_with_ak(const uint8_t* ask, const uint8_t* ak, pallas_ct_add_mod_q(&rsk, &alpha_scalar); int result = redpallas_sign_with_rsk(&rsk, rk_bytes, sighash, sig_out, - progress, progress_context); + progress, progress_context, 100, 900); memzero(&ask_scalar, sizeof(ask_scalar)); memzero(&alpha_scalar, sizeof(alpha_scalar)); memzero(&rsk, sizeof(rsk)); @@ -373,8 +405,8 @@ int redpallas_sign_digest(const uint8_t* ask, const uint8_t* alpha, /* Compatibility API: without a cached ak, derive rk from secret rsk. */ pallas_scalar_mult_spendauth(&rsk, &rk_point); pallas_point_serialize(&rk_point, rk_bytes); - int result = - redpallas_sign_with_rsk(&rsk, rk_bytes, sighash, sig_out, NULL, NULL); + int result = redpallas_sign_with_rsk(&rsk, rk_bytes, sighash, sig_out, NULL, + NULL, 0, 1000); memzero(&ask_scalar, sizeof(ask_scalar)); memzero(&alpha_scalar, sizeof(alpha_scalar)); diff --git a/deps/crypto/trezor-crypto/redpallas.h b/deps/crypto/trezor-crypto/redpallas.h index 061deca3c..c5950da88 100644 --- a/deps/crypto/trezor-crypto/redpallas.h +++ b/deps/crypto/trezor-crypto/redpallas.h @@ -54,6 +54,21 @@ typedef void (*redpallas_progress_callback)(uint32_t completed, uint32_t total, int redpallas_sign_digest(const uint8_t* ask, const uint8_t* alpha, const uint8_t* sighash, uint8_t* sig_out); +/** + * Sign a PCZT spend using its transaction-bound randomized verification key. + * + * The caller must independently bind rk to the transaction digest. If rk does + * not correspond to ask + alpha, the resulting signature cannot verify. This + * avoids a redundant fixed-base multiplication on the constrained device and + * leaves only the fixed-schedule secret nonce multiplication in the hot path. + * Progress reports public work units in the range 0..1000. + */ +int redpallas_sign_digest_for_rk(const uint8_t* ask, const uint8_t* alpha, + const uint8_t* rk, const uint8_t* sighash, + uint8_t* sig_out, + redpallas_progress_callback progress, + void* progress_context); + /** * Sign using the cached public ak and verify the host-provided rk first. * diff --git a/lib/firmware/fsm_msg_zcash.h b/lib/firmware/fsm_msg_zcash.h index a78555176..8056e93e6 100644 --- a/lib/firmware/fsm_msg_zcash.h +++ b/lib/firmware/fsm_msg_zcash.h @@ -87,8 +87,11 @@ static struct { uint8_t orchard_flags; int64_t orchard_value_balance; uint8_t orchard_anchor[32]; - /* Signatures buffer: one 64-byte sig per action */ + /* Compact signatures buffer: one 64-byte sig per real Orchard spend. + * Dummy spends are signed by the PCZT finalizer and must not be signed with + * the device's Orchard key. */ uint8_t signatures[ZCASH_MAX_ACTIONS][64]; + uint32_t signature_count; /* Phase 3: transparent shielding state */ bool has_expected_transparent_digest; uint8_t expected_transparent_digest[32]; @@ -1005,11 +1008,12 @@ void fsm_msgZcashPCZTAction(const ZcashPCZTAction* msg) { } const bool has_orchard_action_data = - zcash_signing.verify_orchard_digest && msg->has_nullifier && - msg->nullifier.size == 32 && msg->has_cmx && msg->cmx.size == 32 && - msg->has_epk && msg->epk.size == 32 && msg->has_enc_compact && - msg->enc_compact.size == 52 && msg->has_enc_memo && - msg->enc_memo.size == 512 && msg->has_enc_noncompact && + zcash_signing.verify_orchard_digest && msg->has_is_spend && + msg->has_nullifier && msg->nullifier.size == 32 && msg->has_cmx && + msg->cmx.size == 32 && msg->has_epk && msg->epk.size == 32 && + msg->has_enc_compact && msg->enc_compact.size == 52 && + msg->has_enc_memo && msg->enc_memo.size == 512 && + msg->has_enc_noncompact && /* 580-byte enc_ciphertext = compact(52) + memo(512) + noncompact(16); * pin the exact size like every sibling field so a host serializer bug * fails fast per-action instead of as an end-of-flow digest mismatch. */ @@ -1053,25 +1057,29 @@ void fsm_msgZcashPCZTAction(const ZcashPCZTAction* msg) { const uint8_t* sighash = zcash_signing.sighash; - /* Sign this action with RedPallas. Derive rk from cached public ak + public - * alpha and require it to match the PCZT before using it in the challenge. - * This removes one secret-scalar multiplication per action; the secret nonce - * multiplication remains fixed-schedule and reports its public loop progress - * directly so the OLED advances during CPU-bound signing. */ - const uint32_t action_base = - (zcash_signing.current_action * 1000) / zcash_signing.n_actions; - const uint32_t action_target = - ((zcash_signing.current_action + 1) * 1000) / zcash_signing.n_actions; - ZcashRedPallasProgress signing_progress = { - action_base, action_target - action_base, action_base}; - if (redpallas_sign_digest_with_ak( - zcash_signing.keys.ask, zcash_signing.keys.ak, msg->alpha.bytes, - msg->rk.bytes, sighash, zcash_signing.signatures[msg->index], - zcash_redpallas_progress, &signing_progress) != 0) { - fsm_sendFailure(FailureType_Failure_Other, _("RedPallas signing failed")); - zcash_signing_abort(); - layoutHome(); - return; + /* Orchard actions always contain a spend and an output, but the spend can be + * a dummy. finalize_io() has already signed dummy spends with their ephemeral + * key; replacing that signature with one from the device key is invalid and + * can never satisfy the action's rk. Stream and verify every action above, + * but return compact signatures only for real spends, in action order. */ + if (msg->is_spend) { + const uint32_t action_base = + (zcash_signing.current_action * 1000) / zcash_signing.n_actions; + const uint32_t action_target = + ((zcash_signing.current_action + 1) * 1000) / zcash_signing.n_actions; + ZcashRedPallasProgress signing_progress = { + action_base, action_target - action_base, action_base}; + if (redpallas_sign_digest_for_rk( + zcash_signing.keys.ask, msg->alpha.bytes, msg->rk.bytes, sighash, + zcash_signing.signatures[zcash_signing.signature_count], + zcash_redpallas_progress, &signing_progress) != 0) { + fsm_sendFailure(FailureType_Failure_Other, + _("Orchard spend authorization failed")); + zcash_signing_abort(); + layoutHome(); + return; + } + zcash_signing.signature_count++; } zcash_signing.current_action++; @@ -1139,8 +1147,8 @@ void fsm_msgZcashPCZTAction(const ZcashPCZTAction* msg) { ZcashSignedPCZT* resp_signed = (ZcashSignedPCZT*)msg_resp; memset(resp_signed, 0, sizeof(ZcashSignedPCZT)); - resp_signed->signatures_count = zcash_signing.n_actions; - for (uint32_t i = 0; i < zcash_signing.n_actions; i++) { + resp_signed->signatures_count = zcash_signing.signature_count; + for (uint32_t i = 0; i < zcash_signing.signature_count; i++) { resp_signed->signatures[i].size = 64; memcpy(resp_signed->signatures[i].bytes, zcash_signing.signatures[i], 64); } diff --git a/tools/check_pallas_api_boundary.py b/tools/check_pallas_api_boundary.py index fd0789ece..08a37f846 100644 --- a/tools/check_pallas_api_boundary.py +++ b/tools/check_pallas_api_boundary.py @@ -48,6 +48,7 @@ def main(): sinsemilla = source("deps/crypto/trezor-crypto/pallas_sinsemilla.c") redpallas = source("deps/crypto/trezor-crypto/redpallas.c") zcash = source("lib/firmware/zcash.c") + zcash_fsm = source("lib/firmware/fsm_msg_zcash.h") # Public transaction data needs the fast compatibility implementation. forbid(pallas, '"pallas_ct.h"', "pallas.c public compatibility path") @@ -113,6 +114,29 @@ def main(): forbid(optimized_sign, "pallas_scalar_mult_spendauth_public", "optimized RedPallas signing") + pczt_sign = code_only(function_body( + redpallas, "redpallas_sign_digest_for_rk")) + require(pczt_sign, "pallas_ct_add_mod_q", "PCZT RedPallas signing") + require(pczt_sign, "redpallas_sign_with_rsk", "PCZT RedPallas signing") + forbid(pczt_sign, "pallas_point_mult(", "PCZT RedPallas signing") + forbid(pczt_sign, "pallas_scalar_mult_spendauth_public", + "PCZT RedPallas signing") + action_handler = code_only(function_body(zcash_fsm, + "fsm_msgZcashPCZTAction")) + require(action_handler, "msg->has_is_spend", "PCZT action handler") + require(action_handler, "if (msg->is_spend)", "PCZT action handler") + require(action_handler, "redpallas_sign_digest_for_rk", + "PCZT action handler") + require(action_handler, "signatures[zcash_signing.signature_count]", + "compact PCZT signature collection") + require(action_handler, "zcash_signing.signature_count++", + "compact PCZT signature collection") + require(action_handler, + "resp_signed->signatures_count = zcash_signing.signature_count", + "compact PCZT signature response") + forbid(action_handler, "redpallas_sign_digest_with_ak", + "PCZT action handler") + derive_rk = code_only(function_body(redpallas, "redpallas_derive_rk")) require(derive_rk, "pallas_ct_add_mod_q", "redpallas_derive_rk") diff --git a/unittests/firmware/zcash.cpp b/unittests/firmware/zcash.cpp index 7894f162e..1677aa2c9 100644 --- a/unittests/firmware/zcash.cpp +++ b/unittests/firmware/zcash.cpp @@ -1564,6 +1564,41 @@ TEST(Zcash, RedPallasPublicRkPathMatchesAndReportsFixedProgress) { memzero(&keys, sizeof(keys)); } +TEST(Zcash, RedPallasPcztPathUsesBoundRkAndReportsFixedProgress) { + ZcashOrchardKeys keys; + ASSERT_TRUE(zcash_derive_orchard_keys(SEED_ALL, 64, 0, &keys)); + + uint8_t alpha[32]; + memset(alpha, 0x31, sizeof(alpha)); + alpha[31] = 0; + uint8_t sighash[32]; + memset(sighash, 0x5A, sizeof(sighash)); + uint8_t rk[32]; + ASSERT_EQ(redpallas_derive_rk(keys.ask, alpha, rk), 0); + + RedPallasProgressCapture progress; + uint8_t signature[64]; + ASSERT_EQ( + redpallas_sign_digest_for_rk(keys.ask, alpha, rk, sighash, signature, + capture_redpallas_progress, &progress), + 0); + EXPECT_TRUE(progress.monotonic); + EXPECT_EQ(256u, progress.calls); + EXPECT_EQ(1000u, progress.last); + EXPECT_EQ(1000u, progress.total); + EXPECT_EQ(redpallas_verify_digest(rk, sighash, signature), 0); + + uint8_t wrong_rk[32]; + memcpy(wrong_rk, rk, sizeof(wrong_rk)); + wrong_rk[0] ^= 1; + ASSERT_EQ(redpallas_sign_digest_for_rk(keys.ask, alpha, wrong_rk, sighash, + signature, nullptr, nullptr), + 0); + EXPECT_NE(redpallas_verify_digest(rk, sighash, signature), 0); + + memzero(&keys, sizeof(keys)); +} + TEST(Zcash, RedPallasSign_ProducesVerifiableSignature) { ZcashOrchardKeys keys; ASSERT_TRUE(zcash_derive_orchard_keys(SEED_ALL, 64, 0, &keys)); From d4a94532dc2d496dac4efa095d467fa3a87dd0c9 Mon Sep 17 00:00:00 2001 From: highlander Date: Sun, 26 Jul 2026 01:58:58 -0300 Subject: [PATCH 13/22] fix(zcash): report Orchard key derivation progress --- deps/crypto/trezor-crypto/redpallas.c | 15 +++++++++++++++ deps/crypto/trezor-crypto/redpallas.h | 10 ++++++++++ include/keepkey/firmware/zcash.h | 13 +++++++++++++ lib/firmware/storage.c | 13 +++++++++++-- lib/firmware/zcash.c | 15 ++++++++++++--- tools/check_pallas_api_boundary.py | 19 +++++++++++++++++++ unittests/firmware/zcash.cpp | 15 +++++++++++++++ 7 files changed, 95 insertions(+), 5 deletions(-) diff --git a/deps/crypto/trezor-crypto/redpallas.c b/deps/crypto/trezor-crypto/redpallas.c index 6f9b58f25..432f85e5a 100644 --- a/deps/crypto/trezor-crypto/redpallas.c +++ b/deps/crypto/trezor-crypto/redpallas.c @@ -164,6 +164,21 @@ void redpallas_scalar_mult_spendauth_G(const bignum256* k, curve_point* res) { pallas_scalar_mult_spendauth(k, res); } +void redpallas_scalar_mult_spendauth_G_progress( + const bignum256* k, curve_point* res, redpallas_progress_callback progress, + void* progress_context) { + if (!spendauth_G_initialized) { + pallas_point_deserialize(pallas_spendauth_G_bytes, &spendauth_G_cache); + spendauth_G_initialized = 1; + } + if (progress) { + pallas_ct_point_mult_progress(k, &spendauth_G_cache, res, progress, + progress_context); + } else { + pallas_ct_point_mult(k, &spendauth_G_cache, res); + } +} + /* * Constant: 2^256 mod q (Pallas scalar field order). * diff --git a/deps/crypto/trezor-crypto/redpallas.h b/deps/crypto/trezor-crypto/redpallas.h index c5950da88..0ce8b8e3b 100644 --- a/deps/crypto/trezor-crypto/redpallas.h +++ b/deps/crypto/trezor-crypto/redpallas.h @@ -120,4 +120,14 @@ int redpallas_derive_rk(const uint8_t* ask, const uint8_t* alpha, */ void redpallas_scalar_mult_spendauth_G(const bignum256* k, curve_point* res); +/** + * Progress-reporting form of redpallas_scalar_mult_spendauth_G(). + * + * The callback receives only the fixed public loop counter; it is independent + * of scalar bits and therefore safe to use while deriving ak from secret ask. + */ +void redpallas_scalar_mult_spendauth_G_progress( + const bignum256* k, curve_point* res, redpallas_progress_callback progress, + void* progress_context); + #endif diff --git a/include/keepkey/firmware/zcash.h b/include/keepkey/firmware/zcash.h index 3bd31916d..b1d84af4e 100644 --- a/include/keepkey/firmware/zcash.h +++ b/include/keepkey/firmware/zcash.h @@ -43,6 +43,9 @@ typedef struct { uint8_t dk[32]; /* Diversifier key */ } ZcashOrchardKeys; +typedef void (*ZcashOrchardProgressCallback)(uint32_t completed, uint32_t total, + void* context); + typedef struct { bool has_header_digest; size_t header_digest_size; @@ -119,6 +122,16 @@ bool zcash_pczt_signing_request_is_clear( bool zcash_derive_orchard_keys(const uint8_t* seed, uint32_t seed_len, uint32_t account, ZcashOrchardKeys* keys); +/** + * Progress-reporting Orchard key derivation for interactive device flows. + * Progress is driven by the fixed public scalar-multiplication schedule and + * does not depend on the derived secret key. + */ +bool zcash_derive_orchard_keys_with_progress( + const uint8_t* seed, uint32_t seed_len, uint32_t account, + ZcashOrchardKeys* keys, ZcashOrchardProgressCallback progress, + void* progress_context); + /** * Compute the ZIP 244 shielded sighash for Orchard spend authorization. * diff --git a/lib/firmware/storage.c b/lib/firmware/storage.c index 546b51aef..9fd7e2162 100644 --- a/lib/firmware/storage.c +++ b/lib/firmware/storage.c @@ -2019,13 +2019,22 @@ const uint8_t* storage_getSeed(const ConfigFlash* cfg, bool usePassphrase) { */ #if ZCASH_PRIVACY +static void storage_zcash_orchard_progress(uint32_t completed, uint32_t total, + void* context) { + (void)context; + if (total == 0) return; + animating_progress_handler(_("Deriving Zcash"), + (int)((completed * 1000u) / total)); +} + bool storage_zcashOrchardKeys(uint32_t account, bool usePassphrase, ZcashOrchardKeys* keys_out) { if (!keys_out) return false; const uint8_t* seed = storage_getSeed(&shadow_config, usePassphrase); if (!seed) return false; - animating_progress_handler(_("Deriving Zcash"), 250); - return zcash_derive_orchard_keys(seed, 64, account, keys_out); + animating_progress_handler(_("Deriving Zcash"), 0); + return zcash_derive_orchard_keys_with_progress( + seed, 64, account, keys_out, storage_zcash_orchard_progress, NULL); } bool storage_zcashSeedFingerprint(bool usePassphrase, diff --git a/lib/firmware/zcash.c b/lib/firmware/zcash.c index 034ddac0b..1416c5cc5 100644 --- a/lib/firmware/zcash.c +++ b/lib/firmware/zcash.c @@ -557,8 +557,10 @@ bool zcash_orchard_compute_cmx( return ok; } -bool zcash_derive_orchard_keys(const uint8_t* seed, uint32_t seed_len, - uint32_t account, ZcashOrchardKeys* keys) { +bool zcash_derive_orchard_keys_with_progress( + const uint8_t* seed, uint32_t seed_len, uint32_t account, + ZcashOrchardKeys* keys, ZcashOrchardProgressCallback progress, + void* progress_context) { uint8_t I[64]; uint8_t sk[32], chain_code[32]; @@ -624,7 +626,8 @@ bool zcash_derive_orchard_keys(const uint8_t* seed, uint32_t seed_len, bignum256 ask_test; bn_read_le(keys->ask, &ask_test); curve_point ak_test; - redpallas_scalar_mult_spendauth_G(&ask_test, &ak_test); + redpallas_scalar_mult_spendauth_G_progress(&ask_test, &ak_test, progress, + progress_context); bignum256 ak_x; bn_copy(&ak_test.x, &ak_x); bn_write_le(&ak_x, ak_bytes); @@ -678,6 +681,12 @@ bool zcash_derive_orchard_keys(const uint8_t* seed, uint32_t seed_len, return true; } +bool zcash_derive_orchard_keys(const uint8_t* seed, uint32_t seed_len, + uint32_t account, ZcashOrchardKeys* keys) { + return zcash_derive_orchard_keys_with_progress(seed, seed_len, account, keys, + NULL, NULL); +} + bool zcash_compute_shielded_sighash(const uint8_t header_digest[32], const uint8_t transparent_digest[32], const uint8_t sapling_digest[32], diff --git a/tools/check_pallas_api_boundary.py b/tools/check_pallas_api_boundary.py index 08a37f846..660c24ae8 100644 --- a/tools/check_pallas_api_boundary.py +++ b/tools/check_pallas_api_boundary.py @@ -49,6 +49,7 @@ def main(): redpallas = source("deps/crypto/trezor-crypto/redpallas.c") zcash = source("lib/firmware/zcash.c") zcash_fsm = source("lib/firmware/fsm_msg_zcash.h") + storage = source("lib/firmware/storage.c") # Public transaction data needs the fast compatibility implementation. forbid(pallas, '"pallas_ct.h"', "pallas.c public compatibility path") @@ -85,6 +86,12 @@ def main(): spendauth = code_only(function_body(redpallas, "pallas_scalar_mult_spendauth")) require(spendauth, "pallas_ct_point_mult", "RedPallas scalar multiplication") forbid(spendauth, "pallas_point_mult(", "RedPallas scalar multiplication") + spendauth_progress = code_only(function_body( + redpallas, "redpallas_scalar_mult_spendauth_G_progress")) + require(spendauth_progress, "pallas_ct_point_mult_progress", + "progress-reporting RedPallas scalar multiplication") + forbid(spendauth_progress, "pallas_point_mult(", + "progress-reporting RedPallas scalar multiplication") public_spendauth = code_only(function_body( redpallas, "pallas_scalar_mult_spendauth_public")) require(public_spendauth, "pallas_point_mult", @@ -145,6 +152,18 @@ def main(): for name in ("to_scalar", "to_base"): body = code_only(function_body(zcash, name)) require(body, "pallas_ct_", name) + key_derivation = code_only(function_body( + zcash, "zcash_derive_orchard_keys_with_progress")) + require(key_derivation, "redpallas_scalar_mult_spendauth_G_progress", + "Orchard key derivation") + forbid(key_derivation, "redpallas_scalar_mult_spendauth_G(", + "Orchard key derivation") + stored_key_derivation = code_only(function_body( + storage, "storage_zcashOrchardKeys")) + require(stored_key_derivation, "zcash_derive_orchard_keys_with_progress", + "interactive Orchard key derivation") + forbid(stored_key_derivation, "zcash_derive_orchard_keys(", + "interactive Orchard key derivation") transmission = code_only(function_body(zcash, "zcash_orchard_derive_transmission_key")) require(transmission, "pallas_ct_point_mult", "Orchard transmission-key derivation") forbid(transmission, "pallas_point_mult(", "Orchard transmission-key derivation") diff --git a/unittests/firmware/zcash.cpp b/unittests/firmware/zcash.cpp index 1677aa2c9..9f70a68cd 100644 --- a/unittests/firmware/zcash.cpp +++ b/unittests/firmware/zcash.cpp @@ -1527,6 +1527,21 @@ static void capture_redpallas_progress(uint32_t completed, uint32_t total, capture->total = total; } +TEST(Zcash, OrchardKeyDerivationReportsFixedProgress) { + ZcashOrchardKeys keys; + RedPallasProgressCapture progress; + + ASSERT_TRUE(zcash_derive_orchard_keys_with_progress( + SEED_ALL, 64, 0, &keys, capture_redpallas_progress, &progress)); + EXPECT_TRUE(progress.monotonic); + EXPECT_EQ(255u, progress.calls); + EXPECT_EQ(255u, progress.last); + EXPECT_EQ(255u, progress.total); + EXPECT_EQ(0, memcmp(keys.ak, EXPECTED_AK_ALL_0, sizeof(keys.ak))); + + memzero(&keys, sizeof(keys)); +} + TEST(Zcash, RedPallasPublicRkPathMatchesAndReportsFixedProgress) { ZcashOrchardKeys keys; ASSERT_TRUE(zcash_derive_orchard_keys(SEED_ALL, 64, 0, &keys)); From 94ffc1a5653346a5a24b8e1e6856cc9a1c9cec58 Mon Sep 17 00:00:00 2001 From: highlander Date: Sun, 26 Jul 2026 13:23:12 -0300 Subject: [PATCH 14/22] fix(zcash): report action verification progress --- deps/crypto/trezor-crypto/pallas_sinsemilla.c | 68 ++++++++++++++----- deps/crypto/trezor-crypto/pallas_sinsemilla.h | 21 ++++++ include/keepkey/firmware/zcash.h | 9 +++ lib/firmware/fsm_msg_zcash.h | 61 ++++++++++------- lib/firmware/zcash.c | 15 +++- tools/check_pallas_api_boundary.py | 20 +++++- unittests/firmware/zcash.cpp | 29 +++++++- 7 files changed, 173 insertions(+), 50 deletions(-) diff --git a/deps/crypto/trezor-crypto/pallas_sinsemilla.c b/deps/crypto/trezor-crypto/pallas_sinsemilla.c index eff4fc35e..0ae8fffa5 100644 --- a/deps/crypto/trezor-crypto/pallas_sinsemilla.c +++ b/deps/crypto/trezor-crypto/pallas_sinsemilla.c @@ -137,8 +137,9 @@ static void pack_commit_ivk_msg(const uint8_t ak[32], const uint8_t nk[32], } } -int pallas_sinsemilla_hash_to_point(const curve_point* q, const uint8_t* msg, - size_t msg_bits, curve_point* out) { +int pallas_sinsemilla_hash_to_point_progress( + const curve_point* q, const uint8_t* msg, size_t msg_bits, curve_point* out, + PallasSinsemillaProgressCallback progress, void* progress_context) { if (!q || (!msg && msg_bits != 0) || !out) return -1; if (msg_bits > PALLAS_SINSEMILLA_MAX_BITS) return -1; if (pallas_point_is_identity(q)) return -1; @@ -168,6 +169,10 @@ int pallas_sinsemilla_hash_to_point(const curve_point* q, const uint8_t* msg, memzero(&s, sizeof(s)); memzero(&old_acc, sizeof(old_acc)); memzero(&tmp, sizeof(tmp)); + + if (progress) { + progress((uint32_t)(i + 1), (uint32_t)word_count, progress_context); + } } *out = acc; @@ -175,6 +180,12 @@ int pallas_sinsemilla_hash_to_point(const curve_point* q, const uint8_t* msg, return 0; } +int pallas_sinsemilla_hash_to_point(const curve_point* q, const uint8_t* msg, + size_t msg_bits, curve_point* out) { + return pallas_sinsemilla_hash_to_point_progress(q, msg, msg_bits, out, NULL, + NULL); +} + int pallas_sinsemilla_hash(const curve_point* q, const uint8_t* msg, size_t msg_bits, uint8_t hash_out[32]) { if (!hash_out) return -1; @@ -193,12 +204,11 @@ int pallas_sinsemilla_hash(const curve_point* q, const uint8_t* msg, return 0; } -static int pallas_sinsemilla_commit_prepare(const curve_point* q, - const curve_point* r, - const uint8_t* msg, size_t msg_bits, - const uint8_t blind[32], - bignum256* blind_scalar, - curve_point* hash_point) { +static int pallas_sinsemilla_commit_prepare( + const curve_point* q, const curve_point* r, const uint8_t* msg, + size_t msg_bits, const uint8_t blind[32], bignum256* blind_scalar, + curve_point* hash_point, PallasSinsemillaProgressCallback progress, + void* progress_context) { if (!r || !blind || !blind_scalar || !hash_point) return -1; if (pallas_point_is_identity(r)) return -1; @@ -207,22 +217,27 @@ static int pallas_sinsemilla_commit_prepare(const curve_point* q, return -1; } - if (pallas_sinsemilla_hash_to_point(q, msg, msg_bits, hash_point) != 0) { + if (pallas_sinsemilla_hash_to_point_progress( + q, msg, msg_bits, hash_point, progress, progress_context) != 0) { memzero(blind_scalar, sizeof(*blind_scalar)); return -1; } return 0; } -int pallas_sinsemilla_commit(const curve_point* q, const curve_point* r, - const uint8_t* msg, size_t msg_bits, - const uint8_t blind[32], curve_point* out) { +int pallas_sinsemilla_commit_progress(const curve_point* q, + const curve_point* r, const uint8_t* msg, + size_t msg_bits, const uint8_t blind[32], + curve_point* out, + PallasSinsemillaProgressCallback progress, + void* progress_context) { if (!out) return -1; bignum256 blind_scalar; curve_point hash_point, blind_point, commit; if (pallas_sinsemilla_commit_prepare(q, r, msg, msg_bits, blind, - &blind_scalar, &hash_point) != 0) { + &blind_scalar, &hash_point, progress, + progress_context) != 0) { return -1; } @@ -239,6 +254,13 @@ int pallas_sinsemilla_commit(const curve_point* q, const curve_point* r, return 0; } +int pallas_sinsemilla_commit(const curve_point* q, const curve_point* r, + const uint8_t* msg, size_t msg_bits, + const uint8_t blind[32], curve_point* out) { + return pallas_sinsemilla_commit_progress(q, r, msg, msg_bits, blind, out, + NULL, NULL); +} + static int pallas_sinsemilla_commit_secret_blind( const curve_point* q, const curve_point* r, const uint8_t* msg, size_t msg_bits, const uint8_t blind[32], curve_point* out) { @@ -247,7 +269,8 @@ static int pallas_sinsemilla_commit_secret_blind( bignum256 blind_scalar; curve_point hash_point, blind_point, commit; if (pallas_sinsemilla_commit_prepare(q, r, msg, msg_bits, blind, - &blind_scalar, &hash_point) != 0) { + &blind_scalar, &hash_point, NULL, + NULL) != 0) { return -1; } @@ -263,13 +286,15 @@ static int pallas_sinsemilla_commit_secret_blind( return 0; } -int pallas_sinsemilla_short_commit(const curve_point* q, const curve_point* r, - const uint8_t* msg, size_t msg_bits, - const uint8_t blind[32], uint8_t out[32]) { +int pallas_sinsemilla_short_commit_progress( + const curve_point* q, const curve_point* r, const uint8_t* msg, + size_t msg_bits, const uint8_t blind[32], uint8_t out[32], + PallasSinsemillaProgressCallback progress, void* progress_context) { if (!out) return -1; curve_point commit; - if (pallas_sinsemilla_commit(q, r, msg, msg_bits, blind, &commit) != 0) { + if (pallas_sinsemilla_commit_progress(q, r, msg, msg_bits, blind, &commit, + progress, progress_context) != 0) { return -1; } @@ -282,6 +307,13 @@ int pallas_sinsemilla_short_commit(const curve_point* q, const curve_point* r, return 0; } +int pallas_sinsemilla_short_commit(const curve_point* q, const curve_point* r, + const uint8_t* msg, size_t msg_bits, + const uint8_t blind[32], uint8_t out[32]) { + return pallas_sinsemilla_short_commit_progress(q, r, msg, msg_bits, blind, + out, NULL, NULL); +} + int pallas_sinsemilla_commit_ivk(const uint8_t ak[32], const uint8_t nk[32], const uint8_t rivk[32], uint8_t ivk_out[32]) { if (!ak || !nk || !rivk || !ivk_out) return -1; diff --git a/deps/crypto/trezor-crypto/pallas_sinsemilla.h b/deps/crypto/trezor-crypto/pallas_sinsemilla.h index 8076c6cb4..4548a837b 100644 --- a/deps/crypto/trezor-crypto/pallas_sinsemilla.h +++ b/deps/crypto/trezor-crypto/pallas_sinsemilla.h @@ -16,6 +16,10 @@ #define PALLAS_SINSEMILLA_C 253 #define PALLAS_SINSEMILLA_MAX_BITS (PALLAS_SINSEMILLA_K * PALLAS_SINSEMILLA_C) +/* Progress depends only on the public message length and loop index. */ +typedef void (*PallasSinsemillaProgressCallback)(uint32_t completed, + uint32_t total, void* context); + /* * Compute SinsemillaHashToPoint(Q, msg). * @@ -25,6 +29,11 @@ int pallas_sinsemilla_hash_to_point(const curve_point* q, const uint8_t* msg, size_t msg_bits, curve_point* out); +/* Progress-reporting form for interactive verification of public PCZT data. */ +int pallas_sinsemilla_hash_to_point_progress( + const curve_point* q, const uint8_t* msg, size_t msg_bits, curve_point* out, + PallasSinsemillaProgressCallback progress, void* progress_context); + /* * Compute SinsemillaHash(Q, msg), returning the little-endian Pallas base-field * x-coordinate extracted from SinsemillaHashToPoint. @@ -42,6 +51,13 @@ int pallas_sinsemilla_commit(const curve_point* q, const curve_point* r, const uint8_t* msg, size_t msg_bits, const uint8_t blind[32], curve_point* out); +int pallas_sinsemilla_commit_progress(const curve_point* q, + const curve_point* r, const uint8_t* msg, + size_t msg_bits, const uint8_t blind[32], + curve_point* out, + PallasSinsemillaProgressCallback progress, + void* progress_context); + /* * Compute SinsemillaShortCommit(Q, R, msg, r), returning the little-endian * Pallas base-field x-coordinate extracted from SinsemillaCommit. @@ -50,6 +66,11 @@ int pallas_sinsemilla_short_commit(const curve_point* q, const curve_point* r, const uint8_t* msg, size_t msg_bits, const uint8_t blind[32], uint8_t out[32]); +int pallas_sinsemilla_short_commit_progress( + const curve_point* q, const curve_point* r, const uint8_t* msg, + size_t msg_bits, const uint8_t blind[32], uint8_t out[32], + PallasSinsemillaProgressCallback progress, void* progress_context); + /* * Compute Commit^ivk.Output = SinsemillaShortCommit( * "z.cash:Orchard-CommitIvk", I2LEBSP_255(ak) || I2LEBSP_255(nk), rivk) diff --git a/include/keepkey/firmware/zcash.h b/include/keepkey/firmware/zcash.h index b1d84af4e..26d6a7501 100644 --- a/include/keepkey/firmware/zcash.h +++ b/include/keepkey/firmware/zcash.h @@ -218,6 +218,15 @@ bool zcash_orchard_compute_cmx( const uint8_t receiver[ZCASH_ORCHARD_RAW_RECEIVER_SIZE], uint64_t value, const uint8_t rho[32], const uint8_t rseed[32], uint8_t cmx_out[32]); +/** + * Progress-reporting note-commitment verification for interactive PCZT flows. + * The callback exposes only the public Sinsemilla word index and count. + */ +bool zcash_orchard_compute_cmx_with_progress( + const uint8_t receiver[ZCASH_ORCHARD_RAW_RECEIVER_SIZE], uint64_t value, + const uint8_t rho[32], const uint8_t rseed[32], uint8_t cmx_out[32], + ZcashOrchardProgressCallback progress, void* progress_context); + /** * Derive an Orchard diversifier from a diversifier key and 88-bit index. * diff --git a/lib/firmware/fsm_msg_zcash.h b/lib/firmware/fsm_msg_zcash.h index 8056e93e6..c1bfec87f 100644 --- a/lib/firmware/fsm_msg_zcash.h +++ b/lib/firmware/fsm_msg_zcash.h @@ -225,7 +225,8 @@ static bool zcash_check_seed_fingerprint(bool has_expected, } static bool zcash_verify_and_confirm_orchard_output( - const ZcashPCZTAction* msg) { + const ZcashPCZTAction* msg, ZcashOrchardProgressCallback progress, + void* progress_context) { if (!msg->has_value || !msg->has_recipient || msg->recipient.size != ZCASH_ORCHARD_RAW_RECEIVER_SIZE || !msg->has_rseed || msg->rseed.size != 32) { @@ -235,9 +236,9 @@ static bool zcash_verify_and_confirm_orchard_output( } uint8_t computed_cmx[32]; - if (!zcash_orchard_compute_cmx(msg->recipient.bytes, msg->value, - msg->nullifier.bytes, msg->rseed.bytes, - computed_cmx) || + if (!zcash_orchard_compute_cmx_with_progress( + msg->recipient.bytes, msg->value, msg->nullifier.bytes, + msg->rseed.bytes, computed_cmx, progress, progress_context) || memcmp(computed_cmx, msg->cmx.bytes, 32) != 0) { memzero(computed_cmx, sizeof(computed_cmx)); fsm_sendFailure(FailureType_Failure_Other, @@ -331,16 +332,18 @@ typedef struct { uint32_t base; uint32_t span; uint32_t last; -} ZcashRedPallasProgress; +} ZcashActionProgress; -static void zcash_redpallas_progress(uint32_t completed, uint32_t total, - void* context) { - ZcashRedPallasProgress* progress = (ZcashRedPallasProgress*)context; +static void zcash_action_progress(uint32_t completed, uint32_t total, + void* context) { + ZcashActionProgress* progress = (ZcashActionProgress*)context; if (!progress || total == 0) return; - /* completed/total is the fixed public scalar-loop schedule, never a value - * derived from ask or the nonce. Update only when the visible permil changes - * to avoid redundant OLED transfers while preserving a smooth bar. */ + /* completed/total is a public loop schedule: either the fixed scalar round + * count or the fixed-size PCZT note-commitment word count. It never depends + * on ask, the nonce, or a secret message bit. Update only when the visible + * permil changes to avoid redundant OLED transfers while preserving a smooth + * bar. */ uint32_t permil = progress->base + (progress->span * completed) / total; if (permil != progress->last) { progress->last = permil; @@ -1029,17 +1032,30 @@ void fsm_msgZcashPCZTAction(const ZcashPCZTAction* msg) { return; } - if (!zcash_verify_and_confirm_orchard_output(msg)) { + const uint32_t action_base = + (zcash_signing.current_action * 1000) / zcash_signing.n_actions; + const uint32_t action_target = + ((zcash_signing.current_action + 1) * 1000) / zcash_signing.n_actions; + const uint32_t action_span = action_target - action_base; + const uint32_t verification_target = + msg->is_spend ? action_base + action_span / 3 : action_target; + ZcashActionProgress verification_progress = { + action_base, verification_target - action_base, action_base}; + + /* The 1086-bit Orchard note commitment takes 109 public Sinsemilla rounds. + * Draw their real progress instead of freezing the prior trickle at 0%. */ + layoutProgress(_("Signing Zcash"), action_base); + if (!zcash_verify_and_confirm_orchard_output(msg, zcash_action_progress, + &verification_progress)) { zcash_signing_abort(); layoutHome(); return; } - /* The user just approved — switch to the signing screen NOW. RedPallas - * signing below is many seconds of pure device-side math, and without - * this draw the dismissed dialog would sit on screen the whole time. */ - layoutProgress(_("Signing Zcash"), (zcash_signing.current_action * 1000) / - zcash_signing.n_actions); + /* The user just approved — restore the progress screen at the verified + * milestone. Real spends continue through RedPallas below; dummy spends + * complete without an authorization signature. */ + layoutProgress(_("Signing Zcash"), verification_target); /* Phase 2b: feed action data into incremental BLAKE2b contexts */ blake2b_Update(&zcash_signing.compact_ctx, msg->nullifier.bytes, 32); @@ -1063,16 +1079,13 @@ void fsm_msgZcashPCZTAction(const ZcashPCZTAction* msg) { * can never satisfy the action's rk. Stream and verify every action above, * but return compact signatures only for real spends, in action order. */ if (msg->is_spend) { - const uint32_t action_base = - (zcash_signing.current_action * 1000) / zcash_signing.n_actions; - const uint32_t action_target = - ((zcash_signing.current_action + 1) * 1000) / zcash_signing.n_actions; - ZcashRedPallasProgress signing_progress = { - action_base, action_target - action_base, action_base}; + ZcashActionProgress signing_progress = {verification_target, + action_target - verification_target, + verification_target}; if (redpallas_sign_digest_for_rk( zcash_signing.keys.ask, msg->alpha.bytes, msg->rk.bytes, sighash, zcash_signing.signatures[zcash_signing.signature_count], - zcash_redpallas_progress, &signing_progress) != 0) { + zcash_action_progress, &signing_progress) != 0) { fsm_sendFailure(FailureType_Failure_Other, _("Orchard spend authorization failed")); zcash_signing_abort(); diff --git a/lib/firmware/zcash.c b/lib/firmware/zcash.c index 1416c5cc5..17124ca7c 100644 --- a/lib/firmware/zcash.c +++ b/lib/firmware/zcash.c @@ -513,9 +513,10 @@ static bool zcash_pack_orchard_note_commit_msg(const uint8_t receiver[43], return true; } -bool zcash_orchard_compute_cmx( +bool zcash_orchard_compute_cmx_with_progress( const uint8_t receiver[ZCASH_ORCHARD_RAW_RECEIVER_SIZE], uint64_t value, - const uint8_t rho[32], const uint8_t rseed[32], uint8_t cmx_out[32]) { + const uint8_t rho[32], const uint8_t rseed[32], uint8_t cmx_out[32], + ZcashOrchardProgressCallback progress, void* progress_context) { if (!receiver || !rho || !rseed || !cmx_out) return false; uint8_t msg[136]; @@ -541,7 +542,8 @@ bool zcash_orchard_compute_cmx( (const uint8_t*)"z.cash:Orchard-NoteCommit-M", strlen("z.cash:Orchard-NoteCommit-M"), &q) == 0 && pallas_group_hash("z.cash:Orchard-NoteCommit-r", NULL, 0, &r) == 0 && - pallas_sinsemilla_short_commit(&q, &r, msg, 1086, rcm, cmx_out) == 0; + pallas_sinsemilla_short_commit_progress(&q, &r, msg, 1086, rcm, cmx_out, + progress, progress_context) == 0; if (!ok) { memzero(cmx_out, 32); @@ -557,6 +559,13 @@ bool zcash_orchard_compute_cmx( return ok; } +bool zcash_orchard_compute_cmx( + const uint8_t receiver[ZCASH_ORCHARD_RAW_RECEIVER_SIZE], uint64_t value, + const uint8_t rho[32], const uint8_t rseed[32], uint8_t cmx_out[32]) { + return zcash_orchard_compute_cmx_with_progress(receiver, value, rho, rseed, + cmx_out, NULL, NULL); +} + bool zcash_derive_orchard_keys_with_progress( const uint8_t* seed, uint32_t seed_len, uint32_t account, ZcashOrchardKeys* keys, ZcashOrchardProgressCallback progress, diff --git a/tools/check_pallas_api_boundary.py b/tools/check_pallas_api_boundary.py index 660c24ae8..9e56a371a 100644 --- a/tools/check_pallas_api_boundary.py +++ b/tools/check_pallas_api_boundary.py @@ -53,11 +53,12 @@ def main(): # Public transaction data needs the fast compatibility implementation. forbid(pallas, '"pallas_ct.h"', "pallas.c public compatibility path") - hash_to_point = code_only(function_body(sinsemilla, - "pallas_sinsemilla_hash_to_point")) + hash_to_point = code_only(function_body( + sinsemilla, "pallas_sinsemilla_hash_to_point_progress")) require(hash_to_point, "sinsemilla_incomplete_add", "Sinsemilla public hash path") forbid(hash_to_point, "pallas_ct_", "Sinsemilla public hash path") + require(hash_to_point, "progress(", "Sinsemilla public hash progress") incomplete_add = code_only(function_body(sinsemilla, "sinsemilla_incomplete_add")) require(incomplete_add, "pallas_point_add", "Sinsemilla public hash add") @@ -65,10 +66,13 @@ def main(): # Transaction note rcm is host-known; use the fast public path. The IVK's # device-secret rivk has a separate helper that remains fixed-schedule. - commit = code_only(function_body(sinsemilla, "pallas_sinsemilla_commit")) + commit = code_only(function_body( + sinsemilla, "pallas_sinsemilla_commit_progress")) require(commit, "pallas_point_mult", "public Sinsemilla blinding") require(commit, "pallas_point_add", "public Sinsemilla blinding") forbid(commit, "pallas_ct_", "public Sinsemilla blinding") + require(commit, "pallas_sinsemilla_commit_prepare", + "public Sinsemilla progress propagation") secret_commit = code_only(function_body( sinsemilla, "pallas_sinsemilla_commit_secret_blind")) require(secret_commit, "pallas_ct_point_mult", "secret IVK blinding") @@ -143,6 +147,16 @@ def main(): "compact PCZT signature response") forbid(action_handler, "redpallas_sign_digest_with_ak", "PCZT action handler") + output_verification = code_only(function_body( + zcash_fsm, "zcash_verify_and_confirm_orchard_output")) + require(output_verification, "zcash_orchard_compute_cmx_with_progress", + "interactive Orchard note verification") + forbid(output_verification, "zcash_orchard_compute_cmx(", + "interactive Orchard note verification") + note_commitment = code_only(function_body( + zcash, "zcash_orchard_compute_cmx_with_progress")) + require(note_commitment, "pallas_sinsemilla_short_commit_progress", + "Orchard note verification progress") derive_rk = code_only(function_body(redpallas, "redpallas_derive_rk")) require(derive_rk, "pallas_ct_add_mod_q", "redpallas_derive_rk") diff --git a/unittests/firmware/zcash.cpp b/unittests/firmware/zcash.cpp index 9f70a68cd..f536554c4 100644 --- a/unittests/firmware/zcash.cpp +++ b/unittests/firmware/zcash.cpp @@ -924,7 +924,25 @@ TEST(Zcash, OrchardUnifiedAddress_RejectsInvalidInputs) { memzero(&keys, sizeof(keys)); } -TEST(Zcash, OrchardNoteCommitment_KnownVector) { +struct OrchardNoteProgressCapture { + uint32_t calls = 0; + uint32_t last = 0; + uint32_t total = 0; + bool monotonic = true; +}; + +static void capture_orchard_note_progress(uint32_t completed, uint32_t total, + void* context) { + auto* capture = static_cast(context); + if (capture->calls > 0 && completed < capture->last) { + capture->monotonic = false; + } + capture->calls++; + capture->last = completed; + capture->total = total; +} + +TEST(Zcash, OrchardNoteCommitment_KnownVectorAndProgress) { const uint8_t recipient[ZCASH_ORCHARD_RAW_RECEIVER_SIZE] = { 0x3c, 0x15, 0x0e, 0x60, 0x98, 0xb8, 0x61, 0x71, 0x6c, 0xc7, 0xf6, 0x28, 0x35, 0xf6, 0x9f, 0xeb, 0x30, 0x21, 0x93, 0xc9, 0x26, 0x60, @@ -945,8 +963,15 @@ TEST(Zcash, OrchardNoteCommitment_KnownVector) { 0xfa, 0x16, 0x21, 0xd5, 0xfb, 0x98, 0x9e, 0x1d, 0xeb, 0x36}; uint8_t cmx[32]; - ASSERT_TRUE(zcash_orchard_compute_cmx(recipient, value, rho, rseed, cmx)); + OrchardNoteProgressCapture progress; + ASSERT_TRUE(zcash_orchard_compute_cmx_with_progress( + recipient, value, rho, rseed, cmx, capture_orchard_note_progress, + &progress)); EXPECT_TRUE(memcmp(cmx, expected_cmx, sizeof(cmx)) == 0); + EXPECT_TRUE(progress.monotonic); + EXPECT_EQ(109u, progress.calls); + EXPECT_EQ(109u, progress.last); + EXPECT_EQ(109u, progress.total); uint8_t tampered[ZCASH_ORCHARD_RAW_RECEIVER_SIZE]; memcpy(tampered, recipient, sizeof(tampered)); From 37c42e5c1fe42440f69c49af1b04f4355abb52ae Mon Sep 17 00:00:00 2001 From: highlander Date: Sun, 26 Jul 2026 14:52:08 -0300 Subject: [PATCH 15/22] chore(rc18): repin reviewed dependency heads --- deps/device-protocol | 2 +- deps/python-keepkey | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/deps/device-protocol b/deps/device-protocol index e31cddfe7..6d0ae670e 160000 --- a/deps/device-protocol +++ b/deps/device-protocol @@ -1 +1 @@ -Subproject commit e31cddfe7f5c72c983d06a889ac7db649b9811df +Subproject commit 6d0ae670e287a75338244fe82c4bef33a920a2ee diff --git a/deps/python-keepkey b/deps/python-keepkey index 9ce1aeb48..951913fc9 160000 --- a/deps/python-keepkey +++ b/deps/python-keepkey @@ -1 +1 @@ -Subproject commit 9ce1aeb480333176b3ed098066f51b22fd40a9d7 +Subproject commit 951913fc9123fdbaca0cd3551a286991d3f4aa65 From 50b3f85d0b6ff73da508bbf09122dec5cc2752d2 Mon Sep 17 00:00:00 2001 From: highlander Date: Sun, 26 Jul 2026 14:57:05 -0300 Subject: [PATCH 16/22] chore(rc18): align nested protocol pin --- deps/python-keepkey | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/python-keepkey b/deps/python-keepkey index 951913fc9..a578e19e9 160000 --- a/deps/python-keepkey +++ b/deps/python-keepkey @@ -1 +1 @@ -Subproject commit 951913fc9123fdbaca0cd3551a286991d3f4aa65 +Subproject commit a578e19e920ffeac90bc7d8acd80e6e05e642f08 From 9d28cb3fde9dd2f1ec532368221bd3337bc1dcf1 Mon Sep 17 00:00:00 2001 From: highlander Date: Sun, 26 Jul 2026 15:25:53 -0300 Subject: [PATCH 17/22] chore(rc18): repin Python integration fix --- deps/python-keepkey | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/python-keepkey b/deps/python-keepkey index a578e19e9..737361d6e 160000 --- a/deps/python-keepkey +++ b/deps/python-keepkey @@ -1 +1 @@ -Subproject commit a578e19e920ffeac90bc7d8acd80e6e05e642f08 +Subproject commit 737361d6eec884216c86a7d98ad9e898999193d4 From 5c5a6b9cfa2cfd5dcb772577ba01710ffd49fb93 Mon Sep 17 00:00:00 2001 From: highlander Date: Sun, 26 Jul 2026 16:38:28 -0300 Subject: [PATCH 18/22] build(crypto): restore reviewed trezor-firmware fork --- .github/workflows/ci.yml | 24 +- .github/workflows/release.yml | 2 + .gitleaks.toml | 10 +- .gitmodules | 3 + CMakeLists.txt | 4 +- deps/crypto/CMakeLists.txt | 139 +- deps/crypto/trezor-crypto/.gitignore | 9 - deps/crypto/trezor-crypto/AUTHORS | 2 - deps/crypto/trezor-crypto/CONTRIBUTORS | 16 - deps/crypto/trezor-crypto/KEEPKEY_VENDOR.md | 65 - deps/crypto/trezor-crypto/LICENSE | 22 - deps/crypto/trezor-crypto/Makefile | 144 - deps/crypto/trezor-crypto/README.md | 45 - .../trezor-crypto/SECURITY_BACKPORTS.md | 81 - deps/crypto/trezor-crypto/address.c | 91 - deps/crypto/trezor-crypto/address.h | 40 - deps/crypto/trezor-crypto/aes/aes.h | 226 - deps/crypto/trezor-crypto/aes/aes_modes.c | 957 -- deps/crypto/trezor-crypto/aes/aescrypt.c | 307 - deps/crypto/trezor-crypto/aes/aeskey.c | 560 - deps/crypto/trezor-crypto/aes/aesopt.h | 789 -- deps/crypto/trezor-crypto/aes/aestab.c | 417 - deps/crypto/trezor-crypto/aes/aestab.h | 173 - deps/crypto/trezor-crypto/aes/aestst.c | 182 - deps/crypto/trezor-crypto/aes/aestst.h | 85 - deps/crypto/trezor-crypto/base32.c | 241 - deps/crypto/trezor-crypto/base32.h | 44 - deps/crypto/trezor-crypto/base58.c | 274 - deps/crypto/trezor-crypto/base58.h | 53 - deps/crypto/trezor-crypto/bignum.c | 1833 ---- deps/crypto/trezor-crypto/bignum.h | 166 - deps/crypto/trezor-crypto/bip32.c | 1045 -- deps/crypto/trezor-crypto/bip32.h | 157 - deps/crypto/trezor-crypto/bip39.c | 323 - deps/crypto/trezor-crypto/bip39.h | 62 - deps/crypto/trezor-crypto/bip39_english.c | 4125 ------- deps/crypto/trezor-crypto/bip39_english.h | 24 - deps/crypto/trezor-crypto/blake256.c | 234 - deps/crypto/trezor-crypto/blake256.h | 53 - deps/crypto/trezor-crypto/blake2_common.h | 25 - deps/crypto/trezor-crypto/blake2b.c | 324 - deps/crypto/trezor-crypto/blake2b.h | 41 - deps/crypto/trezor-crypto/blake2s.c | 318 - deps/crypto/trezor-crypto/blake2s.h | 41 - deps/crypto/trezor-crypto/cash_addr.c | 193 - deps/crypto/trezor-crypto/cash_addr.h | 80 - .../chacha20poly1305/chacha20poly1305.c | 60 - .../chacha20poly1305/chacha20poly1305.h | 19 - .../chacha20poly1305/chacha_merged.c | 252 - .../chacha20poly1305/ecrypt-config.h | 316 - .../chacha20poly1305/ecrypt-machine.h | 49 - .../chacha20poly1305/ecrypt-portable.h | 275 - .../chacha20poly1305/ecrypt-sync.h | 290 - .../chacha20poly1305/ecrypt-types.h | 53 - .../chacha20poly1305/poly1305-donna-32.h | 218 - .../chacha20poly1305/poly1305-donna.c | 179 - .../chacha20poly1305/poly1305-donna.h | 19 - .../trezor-crypto/chacha20poly1305/rfc7539.c | 48 - .../trezor-crypto/chacha20poly1305/rfc7539.h | 10 - deps/crypto/trezor-crypto/chacha_drbg.c | 126 - deps/crypto/trezor-crypto/chacha_drbg.h | 54 - deps/crypto/trezor-crypto/check_mem.h | 30 - deps/crypto/trezor-crypto/curves.c | 39 - deps/crypto/trezor-crypto/curves.h | 44 - deps/crypto/trezor-crypto/ecdsa.c | 1265 --- deps/crypto/trezor-crypto/ecdsa.h | 128 - .../trezor-crypto/ed25519-donna/README.md | 183 - .../ed25519-donna/curve25519-donna-32bit.c | 681 -- .../ed25519-donna/curve25519-donna-32bit.h | 79 - .../ed25519-donna/curve25519-donna-helpers.c | 66 - .../ed25519-donna/curve25519-donna-helpers.h | 22 - .../curve25519-donna-scalarmult-base.c | 67 - .../curve25519-donna-scalarmult-base.h | 8 - .../ed25519-donna/ed25519-blake2b.c | 8 - .../ed25519-donna/ed25519-blake2b.h | 21 - .../ed25519-donna-32bit-tables.c | 63 - .../ed25519-donna-32bit-tables.h | 17 - .../ed25519-donna-basepoint-table.c | 261 - .../ed25519-donna-basepoint-table.h | 2 - .../ed25519-donna/ed25519-donna-impl-base.c | 751 -- .../ed25519-donna/ed25519-donna-impl-base.h | 104 - .../ed25519-donna/ed25519-donna-portable.h | 24 - .../ed25519-donna/ed25519-donna.h | 52 - .../ed25519-hash-custom-blake2b.h | 23 - .../ed25519-hash-custom-keccak.h | 23 - .../ed25519-donna/ed25519-hash-custom-sha3.h | 23 - .../ed25519-donna/ed25519-hash-custom.h | 23 - .../ed25519-donna/ed25519-keccak.c | 8 - .../ed25519-donna/ed25519-keccak.h | 21 - .../ed25519-donna/ed25519-sha3.c | 8 - .../ed25519-donna/ed25519-sha3.h | 21 - .../trezor-crypto/ed25519-donna/ed25519.c | 377 - .../trezor-crypto/ed25519-donna/ed25519.h | 49 - .../ed25519-donna/modm-donna-32bit.c | 517 - .../ed25519-donna/modm-donna-32bit.h | 80 - deps/crypto/trezor-crypto/fuzzer/README.md | 67 - deps/crypto/trezor-crypto/fuzzer/fuzzer.c | 416 - deps/crypto/trezor-crypto/groestl.c | 787 -- deps/crypto/trezor-crypto/groestl.h | 95 - deps/crypto/trezor-crypto/groestl_internal.h | 509 - deps/crypto/trezor-crypto/gui/.gitignore | 4 - deps/crypto/trezor-crypto/gui/gui.pro | 34 - deps/crypto/trezor-crypto/gui/main.cpp | 10 - deps/crypto/trezor-crypto/gui/mainwindow.cpp | 78 - deps/crypto/trezor-crypto/gui/mainwindow.h | 27 - deps/crypto/trezor-crypto/gui/mainwindow.ui | 161 - deps/crypto/trezor-crypto/hasher.c | 156 - deps/crypto/trezor-crypto/hasher.h | 86 - deps/crypto/trezor-crypto/hmac.c | 176 - deps/crypto/trezor-crypto/hmac.h | 60 - deps/crypto/trezor-crypto/hmac_drbg.c | 130 - deps/crypto/trezor-crypto/hmac_drbg.h | 43 - deps/crypto/trezor-crypto/memzero.c | 75 - deps/crypto/trezor-crypto/memzero.h | 8 - deps/crypto/trezor-crypto/monero/base58.c | 247 - deps/crypto/trezor-crypto/monero/base58.h | 43 - deps/crypto/trezor-crypto/monero/int-util.h | 77 - deps/crypto/trezor-crypto/monero/monero.h | 21 - .../crypto/trezor-crypto/monero/range_proof.c | 115 - .../crypto/trezor-crypto/monero/range_proof.h | 31 - deps/crypto/trezor-crypto/monero/serialize.c | 53 - deps/crypto/trezor-crypto/monero/serialize.h | 15 - deps/crypto/trezor-crypto/monero/xmr.c | 143 - deps/crypto/trezor-crypto/monero/xmr.h | 76 - deps/crypto/trezor-crypto/nano.c | 155 - deps/crypto/trezor-crypto/nano.h | 52 - deps/crypto/trezor-crypto/nem.c | 507 - deps/crypto/trezor-crypto/nem.h | 156 - deps/crypto/trezor-crypto/nist256p1.c | 69 - deps/crypto/trezor-crypto/nist256p1.h | 35 - deps/crypto/trezor-crypto/nist256p1.table | 1664 --- deps/crypto/trezor-crypto/options.h | 99 - deps/crypto/trezor-crypto/pallas.c | 809 -- deps/crypto/trezor-crypto/pallas.h | 112 - deps/crypto/trezor-crypto/pallas_ct.c | 601 -- deps/crypto/trezor-crypto/pallas_ct.h | 58 - deps/crypto/trezor-crypto/pallas_sinsemilla.c | 351 - deps/crypto/trezor-crypto/pallas_sinsemilla.h | 85 - .../trezor-crypto/pallas_sinsemilla_table.inc | 1026 -- deps/crypto/trezor-crypto/pallas_swu.c | 712 -- deps/crypto/trezor-crypto/pallas_swu.h | 41 - deps/crypto/trezor-crypto/pbkdf2.c | 179 - deps/crypto/trezor-crypto/pbkdf2.h | 66 - deps/crypto/trezor-crypto/rand.c | 81 - deps/crypto/trezor-crypto/rand.h | 37 - deps/crypto/trezor-crypto/rc4.c | 56 - deps/crypto/trezor-crypto/rc4.h | 37 - deps/crypto/trezor-crypto/redpallas.c | 501 - deps/crypto/trezor-crypto/redpallas.h | 133 - deps/crypto/trezor-crypto/rfc6979.c | 62 - deps/crypto/trezor-crypto/rfc6979.h | 41 - deps/crypto/trezor-crypto/ripemd160.c | 343 - deps/crypto/trezor-crypto/ripemd160.h | 22 - deps/crypto/trezor-crypto/schnorr.c | 215 - deps/crypto/trezor-crypto/schnorr.h | 36 - deps/crypto/trezor-crypto/script.c | 66 - deps/crypto/trezor-crypto/script.h | 31 - deps/crypto/trezor-crypto/secp256k1.c | 94 - deps/crypto/trezor-crypto/secp256k1.h | 38 - deps/crypto/trezor-crypto/secp256k1.table | 1664 --- deps/crypto/trezor-crypto/segwit_addr.c | 209 - deps/crypto/trezor-crypto/segwit_addr.h | 116 - deps/crypto/trezor-crypto/setup.py | 39 - deps/crypto/trezor-crypto/sha2.c | 1283 --- deps/crypto/trezor-crypto/sha2.h | 116 - deps/crypto/trezor-crypto/sha3.c | 399 - deps/crypto/trezor-crypto/sha3.h | 89 - deps/crypto/trezor-crypto/shamir.c | 335 - deps/crypto/trezor-crypto/shamir.h | 70 - deps/crypto/trezor-crypto/slip39.c | 151 - deps/crypto/trezor-crypto/slip39.h | 39 - deps/crypto/trezor-crypto/slip39_wordlist.h | 1246 --- .../crypto/trezor-crypto/tests/test_bignum.py | 1032 -- deps/crypto/trezor-crypto/tests/test_check.c | 9514 ----------------- .../trezor-crypto/tests/test_check_cardano.h | 468 - .../trezor-crypto/tests/test_check_cashaddr.h | 68 - .../trezor-crypto/tests/test_check_monero.h | 1180 -- .../trezor-crypto/tests/test_check_nano.h | 111 - .../trezor-crypto/tests/test_check_segwit.h | 149 - .../crypto/trezor-crypto/tests/test_curves.py | 353 - .../crypto/trezor-crypto/tests/test_openssl.c | 143 - .../trezor-crypto/tests/test_pallas_ct.c | 119 - deps/crypto/trezor-crypto/tests/test_speed.c | 233 - .../trezor-crypto/tests/test_wycheproof.py | 721 -- deps/crypto/trezor-crypto/tools/.gitignore | 3 - deps/crypto/trezor-crypto/tools/README.md | 54 - .../trezor-crypto/tools/bip39bruteforce.c | 100 - deps/crypto/trezor-crypto/tools/mktable.c | 69 - .../trezor-crypto/tools/nem_test_vectors.erb | 18 - .../trezor-crypto/tools/nem_test_vectors.rb | 126 - deps/crypto/trezor-crypto/tools/xpubaddrgen.c | 48 - deps/crypto/trezor-crypto/zcash_zip316.c | 271 - deps/crypto/trezor-crypto/zcash_zip316.h | 37 - deps/crypto/trezor-firmware | 1 + fuzzer/firmware/CMakeLists.txt | 2 +- include/trezor/crypto | 2 +- lib/board/CMakeLists.txt | 2 +- lib/emulator/CMakeLists.txt | 2 +- lib/firmware/CMakeLists.txt | 2 +- tools/blupdater/CMakeLists.txt | 2 +- tools/bootloader/CMakeLists.txt | 2 +- tools/bootstrap/CMakeLists.txt | 2 +- tools/check_pallas_api_boundary.py | 6 +- tools/display_test/CMakeLists.txt | 2 +- tools/emulator/CMakeLists.txt | 2 +- tools/firmware/CMakeLists.txt | 2 +- unittests/board/CMakeLists.txt | 2 +- unittests/crypto/CMakeLists.txt | 12 +- unittests/firmware/CMakeLists.txt | 2 +- 209 files changed, 123 insertions(+), 53913 deletions(-) delete mode 100644 deps/crypto/trezor-crypto/.gitignore delete mode 100644 deps/crypto/trezor-crypto/AUTHORS delete mode 100644 deps/crypto/trezor-crypto/CONTRIBUTORS delete mode 100644 deps/crypto/trezor-crypto/KEEPKEY_VENDOR.md delete mode 100644 deps/crypto/trezor-crypto/LICENSE delete mode 100644 deps/crypto/trezor-crypto/Makefile delete mode 100644 deps/crypto/trezor-crypto/README.md delete mode 100644 deps/crypto/trezor-crypto/SECURITY_BACKPORTS.md delete mode 100644 deps/crypto/trezor-crypto/address.c delete mode 100644 deps/crypto/trezor-crypto/address.h delete mode 100644 deps/crypto/trezor-crypto/aes/aes.h delete mode 100644 deps/crypto/trezor-crypto/aes/aes_modes.c delete mode 100644 deps/crypto/trezor-crypto/aes/aescrypt.c delete mode 100644 deps/crypto/trezor-crypto/aes/aeskey.c delete mode 100644 deps/crypto/trezor-crypto/aes/aesopt.h delete mode 100644 deps/crypto/trezor-crypto/aes/aestab.c delete mode 100644 deps/crypto/trezor-crypto/aes/aestab.h delete mode 100644 deps/crypto/trezor-crypto/aes/aestst.c delete mode 100644 deps/crypto/trezor-crypto/aes/aestst.h delete mode 100644 deps/crypto/trezor-crypto/base32.c delete mode 100644 deps/crypto/trezor-crypto/base32.h delete mode 100644 deps/crypto/trezor-crypto/base58.c delete mode 100644 deps/crypto/trezor-crypto/base58.h delete mode 100644 deps/crypto/trezor-crypto/bignum.c delete mode 100644 deps/crypto/trezor-crypto/bignum.h delete mode 100644 deps/crypto/trezor-crypto/bip32.c delete mode 100644 deps/crypto/trezor-crypto/bip32.h delete mode 100644 deps/crypto/trezor-crypto/bip39.c delete mode 100644 deps/crypto/trezor-crypto/bip39.h delete mode 100644 deps/crypto/trezor-crypto/bip39_english.c delete mode 100644 deps/crypto/trezor-crypto/bip39_english.h delete mode 100644 deps/crypto/trezor-crypto/blake256.c delete mode 100644 deps/crypto/trezor-crypto/blake256.h delete mode 100644 deps/crypto/trezor-crypto/blake2_common.h delete mode 100644 deps/crypto/trezor-crypto/blake2b.c delete mode 100644 deps/crypto/trezor-crypto/blake2b.h delete mode 100644 deps/crypto/trezor-crypto/blake2s.c delete mode 100644 deps/crypto/trezor-crypto/blake2s.h delete mode 100644 deps/crypto/trezor-crypto/cash_addr.c delete mode 100644 deps/crypto/trezor-crypto/cash_addr.h delete mode 100644 deps/crypto/trezor-crypto/chacha20poly1305/chacha20poly1305.c delete mode 100644 deps/crypto/trezor-crypto/chacha20poly1305/chacha20poly1305.h delete mode 100644 deps/crypto/trezor-crypto/chacha20poly1305/chacha_merged.c delete mode 100644 deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-config.h delete mode 100644 deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-machine.h delete mode 100644 deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-portable.h delete mode 100644 deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-sync.h delete mode 100644 deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-types.h delete mode 100644 deps/crypto/trezor-crypto/chacha20poly1305/poly1305-donna-32.h delete mode 100644 deps/crypto/trezor-crypto/chacha20poly1305/poly1305-donna.c delete mode 100644 deps/crypto/trezor-crypto/chacha20poly1305/poly1305-donna.h delete mode 100644 deps/crypto/trezor-crypto/chacha20poly1305/rfc7539.c delete mode 100644 deps/crypto/trezor-crypto/chacha20poly1305/rfc7539.h delete mode 100644 deps/crypto/trezor-crypto/chacha_drbg.c delete mode 100644 deps/crypto/trezor-crypto/chacha_drbg.h delete mode 100644 deps/crypto/trezor-crypto/check_mem.h delete mode 100644 deps/crypto/trezor-crypto/curves.c delete mode 100644 deps/crypto/trezor-crypto/curves.h delete mode 100644 deps/crypto/trezor-crypto/ecdsa.c delete mode 100644 deps/crypto/trezor-crypto/ecdsa.h delete mode 100644 deps/crypto/trezor-crypto/ed25519-donna/README.md delete mode 100644 deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-32bit.c delete mode 100644 deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-32bit.h delete mode 100644 deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-helpers.c delete mode 100644 deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-helpers.h delete mode 100644 deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-scalarmult-base.c delete mode 100644 deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-scalarmult-base.h delete mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-blake2b.c delete mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-blake2b.h delete mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-32bit-tables.c delete mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-32bit-tables.h delete mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-basepoint-table.c delete mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-basepoint-table.h delete mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-impl-base.c delete mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-impl-base.h delete mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-portable.h delete mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna.h delete mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom-blake2b.h delete mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom-keccak.h delete mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom-sha3.h delete mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom.h delete mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-keccak.c delete mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-keccak.h delete mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-sha3.c delete mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519-sha3.h delete mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519.c delete mode 100644 deps/crypto/trezor-crypto/ed25519-donna/ed25519.h delete mode 100644 deps/crypto/trezor-crypto/ed25519-donna/modm-donna-32bit.c delete mode 100644 deps/crypto/trezor-crypto/ed25519-donna/modm-donna-32bit.h delete mode 100644 deps/crypto/trezor-crypto/fuzzer/README.md delete mode 100644 deps/crypto/trezor-crypto/fuzzer/fuzzer.c delete mode 100644 deps/crypto/trezor-crypto/groestl.c delete mode 100644 deps/crypto/trezor-crypto/groestl.h delete mode 100644 deps/crypto/trezor-crypto/groestl_internal.h delete mode 100644 deps/crypto/trezor-crypto/gui/.gitignore delete mode 100644 deps/crypto/trezor-crypto/gui/gui.pro delete mode 100644 deps/crypto/trezor-crypto/gui/main.cpp delete mode 100644 deps/crypto/trezor-crypto/gui/mainwindow.cpp delete mode 100644 deps/crypto/trezor-crypto/gui/mainwindow.h delete mode 100644 deps/crypto/trezor-crypto/gui/mainwindow.ui delete mode 100644 deps/crypto/trezor-crypto/hasher.c delete mode 100644 deps/crypto/trezor-crypto/hasher.h delete mode 100644 deps/crypto/trezor-crypto/hmac.c delete mode 100644 deps/crypto/trezor-crypto/hmac.h delete mode 100644 deps/crypto/trezor-crypto/hmac_drbg.c delete mode 100644 deps/crypto/trezor-crypto/hmac_drbg.h delete mode 100644 deps/crypto/trezor-crypto/memzero.c delete mode 100644 deps/crypto/trezor-crypto/memzero.h delete mode 100644 deps/crypto/trezor-crypto/monero/base58.c delete mode 100644 deps/crypto/trezor-crypto/monero/base58.h delete mode 100644 deps/crypto/trezor-crypto/monero/int-util.h delete mode 100644 deps/crypto/trezor-crypto/monero/monero.h delete mode 100644 deps/crypto/trezor-crypto/monero/range_proof.c delete mode 100644 deps/crypto/trezor-crypto/monero/range_proof.h delete mode 100644 deps/crypto/trezor-crypto/monero/serialize.c delete mode 100644 deps/crypto/trezor-crypto/monero/serialize.h delete mode 100644 deps/crypto/trezor-crypto/monero/xmr.c delete mode 100644 deps/crypto/trezor-crypto/monero/xmr.h delete mode 100644 deps/crypto/trezor-crypto/nano.c delete mode 100644 deps/crypto/trezor-crypto/nano.h delete mode 100644 deps/crypto/trezor-crypto/nem.c delete mode 100644 deps/crypto/trezor-crypto/nem.h delete mode 100644 deps/crypto/trezor-crypto/nist256p1.c delete mode 100644 deps/crypto/trezor-crypto/nist256p1.h delete mode 100644 deps/crypto/trezor-crypto/nist256p1.table delete mode 100644 deps/crypto/trezor-crypto/options.h delete mode 100644 deps/crypto/trezor-crypto/pallas.c delete mode 100644 deps/crypto/trezor-crypto/pallas.h delete mode 100644 deps/crypto/trezor-crypto/pallas_ct.c delete mode 100644 deps/crypto/trezor-crypto/pallas_ct.h delete mode 100644 deps/crypto/trezor-crypto/pallas_sinsemilla.c delete mode 100644 deps/crypto/trezor-crypto/pallas_sinsemilla.h delete mode 100644 deps/crypto/trezor-crypto/pallas_sinsemilla_table.inc delete mode 100644 deps/crypto/trezor-crypto/pallas_swu.c delete mode 100644 deps/crypto/trezor-crypto/pallas_swu.h delete mode 100644 deps/crypto/trezor-crypto/pbkdf2.c delete mode 100644 deps/crypto/trezor-crypto/pbkdf2.h delete mode 100644 deps/crypto/trezor-crypto/rand.c delete mode 100644 deps/crypto/trezor-crypto/rand.h delete mode 100644 deps/crypto/trezor-crypto/rc4.c delete mode 100644 deps/crypto/trezor-crypto/rc4.h delete mode 100644 deps/crypto/trezor-crypto/redpallas.c delete mode 100644 deps/crypto/trezor-crypto/redpallas.h delete mode 100644 deps/crypto/trezor-crypto/rfc6979.c delete mode 100644 deps/crypto/trezor-crypto/rfc6979.h delete mode 100644 deps/crypto/trezor-crypto/ripemd160.c delete mode 100644 deps/crypto/trezor-crypto/ripemd160.h delete mode 100644 deps/crypto/trezor-crypto/schnorr.c delete mode 100644 deps/crypto/trezor-crypto/schnorr.h delete mode 100644 deps/crypto/trezor-crypto/script.c delete mode 100644 deps/crypto/trezor-crypto/script.h delete mode 100644 deps/crypto/trezor-crypto/secp256k1.c delete mode 100644 deps/crypto/trezor-crypto/secp256k1.h delete mode 100644 deps/crypto/trezor-crypto/secp256k1.table delete mode 100644 deps/crypto/trezor-crypto/segwit_addr.c delete mode 100644 deps/crypto/trezor-crypto/segwit_addr.h delete mode 100755 deps/crypto/trezor-crypto/setup.py delete mode 100644 deps/crypto/trezor-crypto/sha2.c delete mode 100644 deps/crypto/trezor-crypto/sha2.h delete mode 100644 deps/crypto/trezor-crypto/sha3.c delete mode 100644 deps/crypto/trezor-crypto/sha3.h delete mode 100644 deps/crypto/trezor-crypto/shamir.c delete mode 100644 deps/crypto/trezor-crypto/shamir.h delete mode 100644 deps/crypto/trezor-crypto/slip39.c delete mode 100644 deps/crypto/trezor-crypto/slip39.h delete mode 100644 deps/crypto/trezor-crypto/slip39_wordlist.h delete mode 100755 deps/crypto/trezor-crypto/tests/test_bignum.py delete mode 100644 deps/crypto/trezor-crypto/tests/test_check.c delete mode 100644 deps/crypto/trezor-crypto/tests/test_check_cardano.h delete mode 100644 deps/crypto/trezor-crypto/tests/test_check_cashaddr.h delete mode 100644 deps/crypto/trezor-crypto/tests/test_check_monero.h delete mode 100644 deps/crypto/trezor-crypto/tests/test_check_nano.h delete mode 100644 deps/crypto/trezor-crypto/tests/test_check_segwit.h delete mode 100755 deps/crypto/trezor-crypto/tests/test_curves.py delete mode 100644 deps/crypto/trezor-crypto/tests/test_openssl.c delete mode 100644 deps/crypto/trezor-crypto/tests/test_pallas_ct.c delete mode 100644 deps/crypto/trezor-crypto/tests/test_speed.c delete mode 100755 deps/crypto/trezor-crypto/tests/test_wycheproof.py delete mode 100644 deps/crypto/trezor-crypto/tools/.gitignore delete mode 100644 deps/crypto/trezor-crypto/tools/README.md delete mode 100644 deps/crypto/trezor-crypto/tools/bip39bruteforce.c delete mode 100644 deps/crypto/trezor-crypto/tools/mktable.c delete mode 100644 deps/crypto/trezor-crypto/tools/nem_test_vectors.erb delete mode 100755 deps/crypto/trezor-crypto/tools/nem_test_vectors.rb delete mode 100644 deps/crypto/trezor-crypto/tools/xpubaddrgen.c delete mode 100644 deps/crypto/trezor-crypto/zcash_zip316.c delete mode 100644 deps/crypto/trezor-crypto/zcash_zip316.h create mode 160000 deps/crypto/trezor-firmware diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c4bdb9109..2e8fb9a37 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,7 +5,7 @@ # Stage 1: GATE (seconds, no Docker) # ├─ lint-format clang-format diff check # ├─ static-analysis cppcheck static analysis -# ├─ crypto-tests vendored trezor-crypto vectors + ASan/UBSan +# ├─ crypto-tests pinned fork crypto vectors + ASan/UBSan # ├─ secret-scan gitleaks credential detection # └─ check-submodules verify all deps present # @@ -109,6 +109,9 @@ jobs: ref: ${{ github.event.pull_request.head.sha || github.sha }} submodules: false + - name: Init crypto submodule + run: git submodule update --init deps/crypto/trezor-firmware + - name: Install cppcheck run: sudo apt-get update && sudo apt-get install -y cppcheck @@ -123,7 +126,7 @@ jobs: --inline-suppr \ --suppressions-list=.cppcheck-suppressions \ -I include \ - -I deps/crypto/trezor-crypto \ + -I deps/crypto/trezor-firmware/crypto \ -I deps/device-protocol \ -DSTM32F2=1 \ -DUSE_ETHEREUM=1 \ @@ -187,10 +190,14 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha || github.sha }} + - name: Init crypto submodule + run: git submodule update --init deps/crypto/trezor-firmware + - name: Verify submodules are declared run: | echo "Checking required submodule declarations..." REQUIRED=( + "deps/crypto/trezor-firmware" "deps/device-protocol" "deps/python-keepkey" "deps/googletest" @@ -249,11 +256,14 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha || github.sha }} + - name: Init crypto submodule + run: git submodule update --init deps/crypto/trezor-firmware + - name: Install crypto test dependencies run: sudo apt-get update && sudo apt-get install -y check libssl-dev pkg-config valgrind - name: Run optimized crypto suite - working-directory: deps/crypto/trezor-crypto + working-directory: deps/crypto/trezor-firmware/crypto run: | make clean make VALGRIND=0 tests/test_check tests/test_pallas_ct @@ -261,7 +271,7 @@ jobs: ./tests/test_pallas_ct - name: Verify Pallas secret flow with Valgrind - working-directory: deps/crypto/trezor-crypto + working-directory: deps/crypto/trezor-firmware/crypto run: | make clean make VALGRIND=1 OPTFLAGS='-O2 -g' tests/test_pallas_ct @@ -269,7 +279,7 @@ jobs: ./tests/test_pallas_ct - name: Run crypto suite with ASan and UBSan - working-directory: deps/crypto/trezor-crypto + working-directory: deps/crypto/trezor-firmware/crypto run: | make clean make CC='gcc -fsanitize=address,undefined' VALGRIND=0 \ @@ -313,6 +323,7 @@ jobs: - name: Init submodules run: | + git submodule update --init deps/crypto/trezor-firmware git submodule update --init deps/device-protocol git submodule update --init --recursive deps/python-keepkey git submodule update --init deps/googletest @@ -380,6 +391,7 @@ jobs: - name: Init submodules run: | + git submodule update --init deps/crypto/trezor-firmware git submodule update --init deps/device-protocol git submodule update --init --recursive deps/python-keepkey git submodule update --init deps/googletest @@ -536,6 +548,7 @@ jobs: - name: Init submodules run: | + git submodule update --init deps/crypto/trezor-firmware git submodule update --init deps/device-protocol git submodule update --init --recursive deps/python-keepkey git submodule update --init deps/googletest @@ -640,6 +653,7 @@ jobs: - name: Init submodules run: | + git submodule update --init deps/crypto/trezor-firmware git submodule update --init deps/device-protocol git submodule update --init --recursive deps/python-keepkey git submodule update --init deps/qrenc/QR-Code-generator diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bc70241cd..eb08d05f9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -96,6 +96,7 @@ jobs: - name: Init required submodules run: | + git submodule update --init deps/crypto/trezor-firmware git submodule update --init deps/device-protocol git submodule update --init --recursive deps/python-keepkey git submodule update --init deps/googletest @@ -217,6 +218,7 @@ jobs: - name: Init required submodules run: | + git submodule update --init deps/crypto/trezor-firmware git submodule update --init deps/device-protocol git submodule update --init --recursive deps/python-keepkey git submodule update --init deps/googletest diff --git a/.gitleaks.toml b/.gitleaks.toml index a8ac90a02..25ede9cca 100644 --- a/.gitleaks.toml +++ b/.gitleaks.toml @@ -4,20 +4,20 @@ title = "KeepKey firmware Gitleaks configuration" useDefault = true [[allowlists]] -description = "Published AES test vectors in vendored trezor-crypto" +description = "Published AES test vectors in the pinned trezor-crypto fork" targetRules = ["generic-api-key"] condition = "AND" regexTarget = "line" -paths = ['''^deps/crypto/trezor-crypto/aes/aestst\.c$'''] +paths = ['''^deps/crypto/trezor-firmware/crypto/aes/aestst\.c$'''] regexes = ['''(?i)^[[:space:]]*//[[:space:]]*key[[:space:]]*=[[:space:]]*[0-9a-f]+[[:space:]]*$'''] [[allowlists]] -description = "Ed25519 C type names in vendored trezor-crypto" +description = "Ed25519 C type names in the pinned trezor-crypto fork" targetRules = ["generic-api-key"] condition = "AND" regexTarget = "line" paths = [ - '''^deps/crypto/trezor-crypto/ed25519-donna/ed25519-(blake2b|keccak|sha3)\.h$''', - '''^deps/crypto/trezor-crypto/ed25519-donna/ed25519\.[ch]$''', + '''^deps/crypto/trezor-firmware/crypto/ed25519-donna/ed25519-(blake2b|keccak|sha3)\.h$''', + '''^deps/crypto/trezor-firmware/crypto/ed25519-donna/ed25519\.[ch]$''', ] regexes = ['''ed25519.*secret_key.*signature'''] diff --git a/.gitmodules b/.gitmodules index 873868109..b8d6fe804 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,6 +2,9 @@ path = deps/device-protocol url = https://github.com/keepkey/device-protocol.git branch = up/release-protocol +[submodule "deps/trezor-firmware"] +path = deps/crypto/trezor-firmware +url = https://github.com/keepkey/trezor-firmware.git [submodule "googletest"] path = deps/googletest url = https://github.com/google/googletest.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 58b964696..542b6027d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,10 +70,10 @@ if(NOT EXISTS ${CMAKE_SOURCE_DIR}/deps/googletest/CMakeLists.txt) "googletest missing. Need to 'git submodule update --init --recursive") endif() -if(NOT EXISTS ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-crypto/Makefile) +if(NOT EXISTS ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-firmware/crypto/Makefile) message( FATAL_ERROR - " vendored trezor-crypto missing from deps/crypto/trezor-crypto" + "trezor-crypto fork missing. Run 'git submodule update --init deps/crypto/trezor-firmware'" ) endif() diff --git a/deps/crypto/CMakeLists.txt b/deps/crypto/CMakeLists.txt index 7b238328f..758a019fd 100644 --- a/deps/crypto/CMakeLists.txt +++ b/deps/crypto/CMakeLists.txt @@ -1,87 +1,86 @@ set(sources - trezor-crypto/bip39.c - trezor-crypto/bip39_english.c - trezor-crypto/hmac.c - trezor-crypto/hmac_drbg.c - trezor-crypto/sha2.c - trezor-crypto/base32.c - trezor-crypto/hasher.c - #trezor-crypto/tools/bip39bruteforce.c - #trezor-crypto/tools/mktable.c - #trezor-crypto/tools/xpubaddrgen.c - trezor-crypto/rand.c - trezor-crypto/rc4.c - trezor-crypto/blake256.c - trezor-crypto/cash_addr.c - trezor-crypto/curves.c - trezor-crypto/rfc6979.c - trezor-crypto/ed25519-donna/curve25519-donna-scalarmult-base.c - trezor-crypto/ed25519-donna/ed25519-donna-32bit-tables.c - trezor-crypto/ed25519-donna/ed25519.c - trezor-crypto/ed25519-donna/curve25519-donna-helpers.c - trezor-crypto/ed25519-donna/ed25519-blake2b.c - trezor-crypto/ed25519-donna/ed25519-keccak.c - trezor-crypto/ed25519-donna/ed25519-sha3.c - trezor-crypto/ed25519-donna/ed25519-donna-basepoint-table.c - trezor-crypto/ed25519-donna/modm-donna-32bit.c - trezor-crypto/ed25519-donna/curve25519-donna-32bit.c - trezor-crypto/ed25519-donna/ed25519-donna-impl-base.c - trezor-crypto/nem.c - trezor-crypto/nano.c - #trezor-crypto/tests/test_check.c - #trezor-crypto/tests/test_openssl.c - #trezor-crypto/tests/test_speed.c - trezor-crypto/secp256k1.c - trezor-crypto/bignum.c - trezor-crypto/segwit_addr.c - trezor-crypto/ripemd160.c - trezor-crypto/groestl.c - trezor-crypto/nist256p1.c - #trezor-crypto/monero/serialize.c - #trezor-crypto/monero/range_proof.c - #trezor-crypto/monero/xmr.c - #trezor-crypto/monero/base58.c - trezor-crypto/memzero.c - trezor-crypto/blake2b.c - trezor-crypto/script.c - trezor-crypto/bip32.c - trezor-crypto/address.c - trezor-crypto/blake2s.c - trezor-crypto/sha3.c - trezor-crypto/base58.c - trezor-crypto/ecdsa.c - trezor-crypto/pbkdf2.c - trezor-crypto/aes/aeskey.c - trezor-crypto/aes/aescrypt.c - trezor-crypto/aes/aes_modes.c - #trezor-crypto/aes/aestst.c - trezor-crypto/aes/aestab.c) + trezor-firmware/crypto/bip39.c + trezor-firmware/crypto/bip39_english.c + trezor-firmware/crypto/hmac.c + trezor-firmware/crypto/hmac_drbg.c + trezor-firmware/crypto/sha2.c + trezor-firmware/crypto/base32.c + trezor-firmware/crypto/hasher.c + #trezor-firmware/crypto/tools/bip39bruteforce.c + #trezor-firmware/crypto/tools/mktable.c + #trezor-firmware/crypto/tools/xpubaddrgen.c + trezor-firmware/crypto/rand.c + trezor-firmware/crypto/rc4.c + trezor-firmware/crypto/blake256.c + trezor-firmware/crypto/cash_addr.c + trezor-firmware/crypto/curves.c + trezor-firmware/crypto/rfc6979.c + trezor-firmware/crypto/ed25519-donna/curve25519-donna-scalarmult-base.c + trezor-firmware/crypto/ed25519-donna/ed25519-donna-32bit-tables.c + trezor-firmware/crypto/ed25519-donna/ed25519.c + trezor-firmware/crypto/ed25519-donna/curve25519-donna-helpers.c + trezor-firmware/crypto/ed25519-donna/ed25519-blake2b.c + trezor-firmware/crypto/ed25519-donna/ed25519-keccak.c + trezor-firmware/crypto/ed25519-donna/ed25519-sha3.c + trezor-firmware/crypto/ed25519-donna/ed25519-donna-basepoint-table.c + trezor-firmware/crypto/ed25519-donna/modm-donna-32bit.c + trezor-firmware/crypto/ed25519-donna/curve25519-donna-32bit.c + trezor-firmware/crypto/ed25519-donna/ed25519-donna-impl-base.c + trezor-firmware/crypto/nem.c + trezor-firmware/crypto/nano.c + #trezor-firmware/crypto/tests/test_check.c + #trezor-firmware/crypto/tests/test_openssl.c + #trezor-firmware/crypto/tests/test_speed.c + trezor-firmware/crypto/secp256k1.c + trezor-firmware/crypto/bignum.c + trezor-firmware/crypto/segwit_addr.c + trezor-firmware/crypto/ripemd160.c + trezor-firmware/crypto/groestl.c + trezor-firmware/crypto/nist256p1.c + #trezor-firmware/crypto/monero/serialize.c + #trezor-firmware/crypto/monero/range_proof.c + #trezor-firmware/crypto/monero/xmr.c + #trezor-firmware/crypto/monero/base58.c + trezor-firmware/crypto/memzero.c + trezor-firmware/crypto/blake2b.c + trezor-firmware/crypto/script.c + trezor-firmware/crypto/bip32.c + trezor-firmware/crypto/address.c + trezor-firmware/crypto/blake2s.c + trezor-firmware/crypto/sha3.c + trezor-firmware/crypto/base58.c + trezor-firmware/crypto/ecdsa.c + trezor-firmware/crypto/pbkdf2.c + trezor-firmware/crypto/aes/aeskey.c + trezor-firmware/crypto/aes/aescrypt.c + trezor-firmware/crypto/aes/aes_modes.c + #trezor-firmware/crypto/aes/aestst.c + trezor-firmware/crypto/aes/aestab.c) # Pallas/Orchard curve arithmetic (~2.4k LOC) -- only the Zcash shielded engine # uses it. Excluded from the default and bitcoin-only images. if(${KK_ZCASH_PRIVACY}) list(APPEND sources - trezor-crypto/pallas.c - trezor-crypto/pallas_ct.c - trezor-crypto/pallas_sinsemilla.c - trezor-crypto/pallas_swu.c - trezor-crypto/redpallas.c - trezor-crypto/zcash_zip316.c) + trezor-firmware/crypto/pallas.c + trezor-firmware/crypto/pallas_ct.c + trezor-firmware/crypto/pallas_sinsemilla.c + trezor-firmware/crypto/pallas_swu.c + trezor-firmware/crypto/redpallas.c + trezor-firmware/crypto/zcash_zip316.c) endif() # Clang 5.0 in the docker image (kktech/firmware:v7) is missing # , which breaks these. Until they're needed, we'll just elide # them. - #trezor-crypto/chacha20poly1305/chacha_merged.c - #trezor-crypto/chacha20poly1305/rfc7539.c - #trezor-crypto/chacha20poly1305/poly1305-donna.c - #trezor-crypto/chacha20poly1305/chacha20poly1305.c + #trezor-firmware/crypto/chacha20poly1305/chacha_merged.c + #trezor-firmware/crypto/chacha20poly1305/rfc7539.c + #trezor-firmware/crypto/chacha20poly1305/poly1305-donna.c + #trezor-firmware/crypto/chacha20poly1305/chacha20poly1305.c include_directories( - ${CMAKE_CURRENT_SOURCE_DIR}/trezor-crypto - ${CMAKE_CURRENT_SOURCE_DIR}/trezor-crypto/ - ${CMAKE_CURRENT_SOURCE_DIR}/trezor-crypto/ed25519-donna + ${CMAKE_CURRENT_SOURCE_DIR}/trezor-firmware/crypto + ${CMAKE_CURRENT_SOURCE_DIR}/trezor-firmware/crypto/ed25519-donna ${OPENSSL_INCLUDE_DIR}) diff --git a/deps/crypto/trezor-crypto/.gitignore b/deps/crypto/trezor-crypto/.gitignore deleted file mode 100644 index 5037519b3..000000000 --- a/deps/crypto/trezor-crypto/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -*.d -*.exe -*.o -*.os -tests/aestst -tests/libtrezor-crypto.so -tests/test_check -tests/test_openssl -tests/test_speed diff --git a/deps/crypto/trezor-crypto/AUTHORS b/deps/crypto/trezor-crypto/AUTHORS deleted file mode 100644 index 51c9bdab0..000000000 --- a/deps/crypto/trezor-crypto/AUTHORS +++ /dev/null @@ -1,2 +0,0 @@ -Tomas Dzetkulic -Pavol Rusnak diff --git a/deps/crypto/trezor-crypto/CONTRIBUTORS b/deps/crypto/trezor-crypto/CONTRIBUTORS deleted file mode 100644 index 300b9788d..000000000 --- a/deps/crypto/trezor-crypto/CONTRIBUTORS +++ /dev/null @@ -1,16 +0,0 @@ -Tomas Dzetkulic -Pavol Rusnak -Jochen Hoenicke -Dustin Laurence -Ondrej Mikle -Roman Zeyde -Alex Beregszaszi -netanelkl -Jan Pochyla -Ondrej Mikle -Josh Billings -Adam Mackler -Oleg Andreev -mog -John Dvorak -Christian Reitter diff --git a/deps/crypto/trezor-crypto/KEEPKEY_VENDOR.md b/deps/crypto/trezor-crypto/KEEPKEY_VENDOR.md deleted file mode 100644 index f863e94f7..000000000 --- a/deps/crypto/trezor-crypto/KEEPKEY_VENDOR.md +++ /dev/null @@ -1,65 +0,0 @@ -# KeepKey vendored trezor-crypto - -This directory is a direct, in-tree firmware dependency. It replaces the -`deps/crypto/trezor-firmware` submodule so that a KeepKey release no longer -depends on an unrelated Trezor monorepo fork. - -## Provenance - -- Previous RC18 crypto pin: `keepkey/trezor-firmware@0837875b9f5ce29f5d29f2a8ad3798787bd25b61` -- Vendoring baseline: `keepkey/trezor-firmware@56f404e452bc7738cd3b3e14454dfecb25c083bf` -- Upstream audit reference: `trezor/trezor-firmware@90e07df6c8b85ff3dc41f502de9dfff21493671b` -- Audit date: 2026-07-25 -- License: MIT; see `LICENSE` - -The vendoring baseline contains the KeepKey AES-small-tables and -Orchard/Pallas work. The source in this directory additionally contains the -security backports and KeepKey adaptations recorded in -`SECURITY_BACKPORTS.md`. - -The complete `crypto/` subtree is retained, including its tests. No Trezor -Core, Legacy firmware, Python client, storage implementation, CI, or other -monorepo component is vendored. - -## Updating - -Do not merge the current Trezor monorepo into this directory for version -optics. Audit crypto changes explicitly: - -1. Fetch `https://github.com/trezor/trezor-firmware.git`. -2. Review `git log --no-merges ..upstream/main -- crypto`. -3. Classify each correctness or security change for the KeepKey build and - document the decision in `SECURITY_BACKPORTS.md`. -4. Apply applicable changes to an isolated crypto worktree, preserving - upstream commit IDs in commit messages. -5. Run the standalone optimized and sanitizer suites below. -6. Replace this directory from the tested worktree and run both full firmware - variants before opening a PR. - -The upstream monorepo had diverged by 7,996 commits and 5,494 files at this -audit point. A mechanical merge was possible but was not treated as a -security review. - -## Standalone verification - -On macOS with Homebrew `check` installed: - -```sh -make clean -make VALGRIND=0 \ - OPTFLAGS='-O3 -g -I/opt/homebrew/include -Wno-error=unterminated-string-initialization' \ - tests/test_check -./tests/test_check -``` - -ASan and UBSan: - -```sh -make clean -make CC='clang -fsanitize=address,undefined' VALGRIND=0 \ - OPTFLAGS='-O1 -g -fno-omit-frame-pointer -I/opt/homebrew/include -Wno-error=unterminated-string-initialization -Wno-error=deprecated-declarations' \ - tests/test_check -ASAN_OPTIONS=halt_on_error=1 UBSAN_OPTIONS=halt_on_error=1 ./tests/test_check -``` - -The vendoring audit passed 158 checks in both configurations. diff --git a/deps/crypto/trezor-crypto/LICENSE b/deps/crypto/trezor-crypto/LICENSE deleted file mode 100644 index 1ea1df703..000000000 --- a/deps/crypto/trezor-crypto/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2013 Tomas Dzetkulic -Copyright (c) 2013 Pavol Rusnak - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/deps/crypto/trezor-crypto/Makefile b/deps/crypto/trezor-crypto/Makefile deleted file mode 100644 index 4cef4f4c1..000000000 --- a/deps/crypto/trezor-crypto/Makefile +++ /dev/null @@ -1,144 +0,0 @@ -ifeq ($(FUZZER),1) -CC ?= clang -LD ?= $(CC) - -SANFLAGS += -fsanitize=fuzzer - -CFLAGS += $(SANFLAGS) -LDFLAGS += $(SANFLAGS) -endif - -CC ?= gcc - -OPTFLAGS ?= -O3 -g - -CFLAGS += $(OPTFLAGS) \ - -std=gnu99 \ - -W \ - -Wall \ - -Wextra \ - -Wimplicit-function-declaration \ - -Wredundant-decls \ - -Wstrict-prototypes \ - -Wundef \ - -Wshadow \ - -Wpointer-arith \ - -Wformat \ - -Wreturn-type \ - -Wsign-compare \ - -Wmultichar \ - -Wformat-nonliteral \ - -Winit-self \ - -Wuninitialized \ - -Wformat-security \ - -Wno-missing-braces \ - -Werror - -VALGRIND ?= 1 - -CFLAGS += -I. -CFLAGS += -DVALGRIND=$(VALGRIND) -CFLAGS += -DUSE_ETHEREUM=1 -CFLAGS += -DUSE_GRAPHENE=1 -CFLAGS += -DUSE_KECCAK=1 -CFLAGS += -DUSE_MONERO=1 -CFLAGS += -DUSE_NEM=1 -CFLAGS += -DUSE_CARDANO=1 -CFLAGS += -DUSE_NANO=1 -CFLAGS += $(shell pkg-config --cflags openssl) - -# disable certain optimizations and features when small footprint is required -ifdef SMALL -CFLAGS += -DUSE_PRECOMPUTED_CP=0 -endif - -SRCS = bignum.c ecdsa.c curves.c secp256k1.c nist256p1.c rand.c hmac.c bip32.c bip39.c bip39_english.c pbkdf2.c base58.c base32.c -SRCS += address.c -SRCS += script.c -SRCS += ripemd160.c -SRCS += sha2.c -SRCS += sha3.c -SRCS += hasher.c -SRCS += aes/aescrypt.c aes/aeskey.c aes/aestab.c aes/aes_modes.c -SRCS += ed25519-donna/curve25519-donna-32bit.c ed25519-donna/curve25519-donna-helpers.c ed25519-donna/modm-donna-32bit.c -SRCS += ed25519-donna/ed25519-donna-basepoint-table.c ed25519-donna/ed25519-donna-32bit-tables.c ed25519-donna/ed25519-donna-impl-base.c -SRCS += ed25519-donna/ed25519.c ed25519-donna/curve25519-donna-scalarmult-base.c ed25519-donna/ed25519-sha3.c ed25519-donna/ed25519-keccak.c -SRCS += ed25519-donna/ed25519-blake2b.c -SRCS += monero/base58.c -SRCS += monero/serialize.c -SRCS += monero/xmr.c -SRCS += monero/range_proof.c -SRCS += blake256.c -SRCS += blake2b.c blake2s.c -SRCS += chacha_drbg.c -SRCS += groestl.c -SRCS += chacha20poly1305/chacha20poly1305.c chacha20poly1305/chacha_merged.c chacha20poly1305/poly1305-donna.c chacha20poly1305/rfc7539.c -SRCS += rc4.c -SRCS += nem.c -SRCS += nano.c -SRCS += segwit_addr.c cash_addr.c -SRCS += zcash_zip316.c -SRCS += memzero.c -SRCS += shamir.c -SRCS += hmac_drbg.c -SRCS += rfc6979.c -SRCS += slip39.c -SRCS += schnorr.c - -OBJS = $(SRCS:.c=.o) - -TESTLIBS = $(shell pkg-config --libs check) -lpthread -lm -TESTSSLLIBS = $(shell pkg-config --libs openssl) - -all: tools tests - -%.o: %.c %.h options.h - $(CC) $(CFLAGS) -o $@ -c $< - -tests: tests/test_check tests/test_openssl tests/test_speed tests/libtrezor-crypto.so tests/aestst - -tests/aestst: aes/aestst.o aes/aescrypt.o aes/aeskey.o aes/aestab.o - $(CC) $^ -o $@ - -tests/test_check.o: tests/test_check_cardano.h tests/test_check_nano.h tests/test_check_monero.h tests/test_check_cashaddr.h tests/test_check_segwit.h - -tests/test_check: tests/test_check.o $(OBJS) - $(CC) tests/test_check.o $(OBJS) $(TESTLIBS) -o tests/test_check - -# Standalone Pallas secret-flow harness. It deliberately has no dependency on -# Check/OpenSSL so CI can run it under ASan/UBSan and Valgrind's constant-time -# taint check without building the rest of the test suite. -tests/test_pallas_ct: tests/test_pallas_ct.c pallas_ct.c pallas_ct.h memzero.c options.h - $(CC) $(CFLAGS) tests/test_pallas_ct.c pallas_ct.c memzero.c -o tests/test_pallas_ct - -tests/test_speed: tests/test_speed.o $(OBJS) - $(CC) tests/test_speed.o $(OBJS) -o tests/test_speed - -tests/test_openssl: tests/test_openssl.o $(OBJS) - $(CC) tests/test_openssl.o $(OBJS) $(TESTSSLLIBS) -o tests/test_openssl - -tests/libtrezor-crypto.so: $(SRCS) - $(CC) $(CFLAGS) -DAES_128 -DAES_192 -fPIC -shared $(SRCS) -o tests/libtrezor-crypto.so - -tools: tools/xpubaddrgen tools/mktable tools/bip39bruteforce - -tools/xpubaddrgen: tools/xpubaddrgen.o $(OBJS) - $(CC) tools/xpubaddrgen.o $(OBJS) -o tools/xpubaddrgen - -tools/mktable: tools/mktable.o $(OBJS) - $(CC) tools/mktable.o $(OBJS) -o tools/mktable - -tools/bip39bruteforce: tools/bip39bruteforce.o $(OBJS) - $(CC) tools/bip39bruteforce.o $(OBJS) -o tools/bip39bruteforce - -fuzzer: fuzzer/fuzzer.o $(OBJS) - $(CC) $(CFLAGS) fuzzer/fuzzer.o $(OBJS) -o fuzzer/fuzzer - -clean: - rm -f *.o aes/*.o chacha20poly1305/*.o ed25519-donna/*.o monero/*.o - rm -f tests/*.o tests/test_check tests/test_pallas_ct tests/test_speed tests/test_openssl tests/libtrezor-crypto.so tests/aestst - rm -f tools/*.o tools/xpubaddrgen tools/mktable tools/bip39bruteforce - rm -f fuzzer/*.o fuzzer/fuzzer - -clean-fuzzer: clean - rm -f crash-* fuzz-*.log slow-unit-* timeout-* diff --git a/deps/crypto/trezor-crypto/README.md b/deps/crypto/trezor-crypto/README.md deleted file mode 100644 index 50d9198a1..000000000 --- a/deps/crypto/trezor-crypto/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# trezor-crypto - -[![Build Status](https://travis-ci.org/trezor/trezor-crypto.svg?branch=master)](https://travis-ci.org/trezor/trezor-crypto) [![gitter](https://badges.gitter.im/trezor/community.svg)](https://gitter.im/trezor/community) - -Heavily optimized cryptography algorithms for embedded devices. - -These include: -- AES/Rijndael encryption/decryption -- Big Number (256 bit) Arithmetics -- BIP32 Hierarchical Deterministic Wallets -- BIP39 Mnemonic code -- ECDSA signing/verifying (supports secp256k1 and nist256p1 curves, - uses RFC6979 for deterministic signatures) -- ECDSA public key derivation -- Schnorr (BCH variant) signing/verifying -- Base32 (RFC4648 and custom alphabets) -- Base58 address representation -- Ed25519 signing/verifying (also SHA3 and Keccak variants) -- ECDH using secp256k1, nist256p1 and Curve25519 -- HMAC-SHA256 and HMAC-SHA512 -- PBKDF2 -- RIPEMD-160 -- SHA1 -- SHA2-256/SHA2-512 -- SHA3/Keccak -- BLAKE2s/BLAKE2b -- Chacha20-Poly1305 -- unit tests (using Check - check.sf.net; in test_check.c) -- tests against OpenSSL (in test_openssl.c) -- integrated Wycheproof tests - -Distibuted under MIT License. - -## Some parts of the library come from external sources: - -- AES: https://github.com/BrianGladman/aes -- Base58: https://github.com/luke-jr/libbase58 -- BLAKE2s/BLAKE2b: https://github.com/BLAKE2/BLAKE2 -- RIPEMD-160: https://github.com/ARMmbed/mbedtls -- SHA1/SHA2: http://www.aarongifford.com/computers/sha.html -- SHA3: https://github.com/rhash/RHash -- Curve25519: https://github.com/agl/curve25519-donna -- Ed25519: https://github.com/floodyberry/ed25519-donna -- Chacha20: https://github.com/wg/c20p1305 -- Poly1305: https://github.com/floodyberry/poly1305-donna diff --git a/deps/crypto/trezor-crypto/SECURITY_BACKPORTS.md b/deps/crypto/trezor-crypto/SECURITY_BACKPORTS.md deleted file mode 100644 index 47844c487..000000000 --- a/deps/crypto/trezor-crypto/SECURITY_BACKPORTS.md +++ /dev/null @@ -1,81 +0,0 @@ -# RC18 crypto security triage - -This file records the security-relevant delta applied after baseline -`56f404e452bc7738cd3b3e14454dfecb25c083bf`. - -## Applied upstream changes - -| Upstream commit | KeepKey disposition | -| --- | --- | -| `15bb085509263a2586b914363b095e1e62255816` | Propagate invalid public-child derivation failures. | -| `5d03110a4287d2cdb0820d07d04e71a79d445014` | Handle invalid ECDSA private-key and zero-digest edge cases. | -| `34621a6b6d340a42e917cad346ec527c94066712` | Tighten private-key validity checks. | -| `307d166383614a8fa6ebee90ee10c469dfa697d1` | Clean Ed25519 stack intermediates. | -| `f96e737ef540665ff8df0e5d46a3ad0e2d7f67f9` | Remove alignment-dependent SHA3 undefined behavior. | -| `4882648dad1e29b635568abe52251285fb56bdb1` | Reject a recovered ECDSA point at infinity. | -| `8baf1ca79f107da2c25348df7f429e2f147dd939` | Prevent an out-of-bounds read in `ecdsa_sig_to_der`. | -| `10bc747dc6dae3620dce73df37a55009bbfc87ed` | Correct Ed25519 argument types. | -| `4827969cc8411f38d4b10916658d2aa665ca555d` | Harden SHA function declarations. | -| `d1d3558d02732979c00c96c5e7b91e6560149e61` | Correct constant-time assertions and casts. | -| `d6fdadf6730727c26d0644d84faaa562cf75f4d3` | Remove zero-length Groestl/SHA3 undefined behavior. | -| `f4d0dd9807ec3d50483dd589455235569a1a63c6` | Initialize Ed25519 locals; adapted for KeepKey Cardano APIs. | -| `8e8f1afa8566cd5c7f89e4154163e6b9f6c9bee4` | Enforce strict DER signature decoding. | -| `1e53a84cfc22405d2a67295954cbb33ca0c336ca` | Zero-initialize AES stack contexts. | -| `3b49e5400db4c92490a259c363f257617cb017ff` | Remove secret-dependent Ed25519 memory access. | -| `ecc38f267f91dffdb8afaaea8d5e5853be72df21` | Use constant-time Ed25519 conditional moves. | -| `2ce1e6ba7dbe5bbaeeb336fff0a038e59cb40ef8` | Add BIP32/BIP39 cache clearing APIs. | -| `477cbb365a29c23df766fd8f128cc5b73ed04bb6` | Wipe HDNode deserialization scratch data. | -| `09e55d8c9cb255eaa0463a8aa58f5dca1ed17644` | Clean NEM AES contexts. | -| `26914ff4962812695a2abf49f06e268606a7a7e2` | Prevent fixed-size BIP32 cache-path overflow. | -| `ea542943fced278c3563f068c2aa63dda0d1705e` | Reject BIP32 depth overflow. | -| `865ca5f0a9534ca64f41a1d508983029b55c9b7b` | Correct SLIP-10/25519 fingerprints. | -| `3da9c6bbb9910ce7f8fc29f9c5da758dbb50cb9c` | Reject public CKD for 25519 curves. | -| `bddd38b47d920559e50aa50c82eab62a8f6510ca` | Wipe ECDSA signing intermediates. | -| `9b1c06205c41811abe7de81d9e50abd22613f0b3` | Make BIP39 word processing constant-time. | -| `13e6c4f55d3a54678d140ecd9b06205d5115881d` | Bound CashAddr HRP and output writes. | -| `ea5886026fac93f2a7544f425fa0480d6e896220` | Pass the curve into RFC6979 initialization. | -| `53d522a1fd6f391fe48de8accecae308e9754f09` | Reduce RFC6979 digests modulo the curve order. | -| `fa5e7feda66f2b64d8d2976f9110456a1f86989b` | Remove CoSi nonce bias. | -| `48db49fa67eb4b51a30dff394e27cbea6803dbf1` | Wipe CoSi secrets on early returns. | -| `892f3e348dacb6c7b9880bc697234a78aaf6d80a` | Remove caller-supplied Ed25519 public keys from signing APIs. | - -## KeepKey-specific corrections - -- Preserve the existing `mnemonic_find_word` API while using a fixed-size, - constant-time word lookup and wiping checksum intermediates. -- Reject an invalid/null-curve node in `hdnode_private_ckd_cached`; the legacy - implementation incorrectly returned success. -- Deserialize into a fresh output `HDNode` without first requiring that - uninitialized output to be valid, and reject an unknown curve safely. -- Calculate 25519 fingerprints without mutating a cached public key. -- Apply the hardened Ed25519 signing API to the KeepKey Nano/Blake2b variant - and all firmware call sites. -- Clear BIP32 and BIP39 global caches on session clear and storage reset. - -## Reviewed but not applied - -- `a5f7c19` insecure platform-independent LCG: not active in production. - KeepKey defines `RAND_PLATFORM_INDEPENDENT=0` and supplies hardware - `random32`; host tests use their own platform source. -- `b1bee00` BIP39 word-boundary read: the KeepKey word list already carried a - sentinel, and the constant-time BIP39 rewrite above supersedes this path. -- `dfb7295` migration of crypto globals to stack: deferred because the legacy - embedded target has strict stack limits. Existing static secret - intermediates are explicitly wiped, and the new cache-clear APIs are called - at the firmware session boundary. -- Broad feature, architecture, generated-file, Rust/Python/Core, and toolchain - changes outside the compiled KeepKey crypto surface were not backported. - -## Regression coverage - -The standalone suite includes focused tests for: - -- zero-valued DER signature components; -- recovered point-at-infinity rejection; -- BIP32 cache paths deeper than `BIP32_CACHE_MAXDEPTH`; -- private and public BIP32 depth overflow; -- RFC6979 digest reduction/deterministic signatures; -- the hardened Ed25519, Cardano, and CoSi APIs; -- the complete pre-existing crypto vector suite. - -Result: 158/158 checks pass under the optimized build and under ASan+UBSan. diff --git a/deps/crypto/trezor-crypto/address.c b/deps/crypto/trezor-crypto/address.c deleted file mode 100644 index 8f3aa9734..000000000 --- a/deps/crypto/trezor-crypto/address.c +++ /dev/null @@ -1,91 +0,0 @@ -/** - * Copyright (c) 2016 Daira Hopwood - * Copyright (c) 2016 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "address.h" -#include "bignum.h" - -size_t address_prefix_bytes_len(uint32_t address_type) { - if (address_type <= 0xFF) return 1; - if (address_type <= 0xFFFF) return 2; - if (address_type <= 0xFFFFFF) return 3; - return 4; -} - -void address_write_prefix_bytes(uint32_t address_type, uint8_t *out) { - if (address_type > 0xFFFFFF) *(out++) = address_type >> 24; - if (address_type > 0xFFFF) *(out++) = (address_type >> 16) & 0xFF; - if (address_type > 0xFF) *(out++) = (address_type >> 8) & 0xFF; - *(out++) = address_type & 0xFF; -} - -bool address_check_prefix(const uint8_t *addr, uint32_t address_type) { - if (address_type <= 0xFF) { - return address_type == (uint32_t)(addr[0]); - } - if (address_type <= 0xFFFF) { - return address_type == (((uint32_t)addr[0] << 8) | ((uint32_t)addr[1])); - } - if (address_type <= 0xFFFFFF) { - return address_type == (((uint32_t)addr[0] << 16) | - ((uint32_t)addr[1] << 8) | ((uint32_t)addr[2])); - } - return address_type == - (((uint32_t)addr[0] << 24) | ((uint32_t)addr[1] << 16) | - ((uint32_t)addr[2] << 8) | ((uint32_t)addr[3])); -} - -#if USE_ETHEREUM -#include "sha3.h" - -void ethereum_address_checksum(const uint8_t *addr, char *address, bool rskip60, - uint32_t chain_id) { - const char *hex = "0123456789abcdef"; - for (int i = 0; i < 20; i++) { - address[i * 2] = hex[(addr[i] >> 4) & 0xF]; - address[i * 2 + 1] = hex[addr[i] & 0xF]; - } - address[40] = 0; - - SHA3_CTX ctx = {0}; - uint8_t hash[32] = {0}; - keccak_256_Init(&ctx); - if (rskip60) { - char prefix[16] = {0}; - int prefix_size = bn_format_uint64(chain_id, NULL, "0x", 0, 0, false, - prefix, sizeof(prefix)); - keccak_Update(&ctx, (const uint8_t *)prefix, prefix_size); - } - keccak_Update(&ctx, (const uint8_t *)address, 40); - keccak_Final(&ctx, hash); - - for (int i = 0; i < 20; i++) { - if (hash[i] & 0x80 && address[i * 2] >= 'a' && address[i * 2] <= 'f') { - address[i * 2] -= 0x20; - } - if (hash[i] & 0x08 && address[i * 2 + 1] >= 'a' && - address[i * 2 + 1] <= 'f') { - address[i * 2 + 1] -= 0x20; - } - } -} -#endif diff --git a/deps/crypto/trezor-crypto/address.h b/deps/crypto/trezor-crypto/address.h deleted file mode 100644 index 8147f2c35..000000000 --- a/deps/crypto/trezor-crypto/address.h +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (c) 2016 Daira Hopwood - * Copyright (c) 2016 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __ADDRESS_H__ -#define __ADDRESS_H__ - -#include -#include -#include -#include "options.h" - -size_t address_prefix_bytes_len(uint32_t address_type); -void address_write_prefix_bytes(uint32_t address_type, uint8_t *out); -bool address_check_prefix(const uint8_t *addr, uint32_t address_type); -#if USE_ETHEREUM -void ethereum_address_checksum(const uint8_t *addr, char *address, bool rskip60, - uint32_t chain_id); -#endif - -#endif diff --git a/deps/crypto/trezor-crypto/aes/aes.h b/deps/crypto/trezor-crypto/aes/aes.h deleted file mode 100644 index 878943b57..000000000 --- a/deps/crypto/trezor-crypto/aes/aes.h +++ /dev/null @@ -1,226 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. - -The redistribution and use of this software (with or without changes) -is allowed without the payment of fees or royalties provided that: - - source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation. - -This software is provided 'as is' with no explicit or implied warranties -in respect of its operation, including, but not limited to, correctness -and fitness for purpose. ---------------------------------------------------------------------------- -Issue Date: 02/08/2018 - - This file contains the definitions required to use AES in C. See aesopt.h - for optimisation details. -*/ - -#ifndef _AES_H -#define _AES_H - -#include -#include - -#define VOID_RETURN void -#define INT_RETURN int -#define ALIGN_OFFSET(x,n) (((intptr_t)(x)) & ((n) - 1)) -#define ALIGN_FLOOR(x,n) ((uint8_t*)(x) - ( ((intptr_t)(x)) & ((n) - 1))) -#define ALIGN_CEIL(x,n) ((uint8_t*)(x) + (-((intptr_t)(x)) & ((n) - 1))) - -#if defined(__cplusplus) -extern "C" -{ -#endif - -// #define AES_128 /* if a fast 128 bit key scheduler is needed */ -// #define AES_192 /* if a fast 192 bit key scheduler is needed */ -#define AES_256 /* if a fast 256 bit key scheduler is needed */ -// #define AES_VAR /* if variable key size scheduler is needed */ -#if 1 -# define AES_MODES /* if support is needed for modes in the C code */ -#endif /* (these will use AES_NI if it is present) */ -#if 0 /* add this to make direct calls to the AES_NI */ -# /* implemented CBC and CTR modes available */ -# define ADD_AESNI_MODE_CALLS -#endif - -/* The following must also be set in assembler files if being used */ - -#define AES_ENCRYPT /* if support for encryption is needed */ -#define AES_DECRYPT /* if support for decryption is needed */ - -#define AES_BLOCK_SIZE_P2 4 /* AES block size as a power of 2 */ -#define AES_BLOCK_SIZE (1 << AES_BLOCK_SIZE_P2) /* AES block size */ -#define N_COLS 4 /* the number of columns in the state */ - -/* The key schedule length is 11, 13 or 15 16-byte blocks for 128, */ -/* 192 or 256-bit keys respectively. That is 176, 208 or 240 bytes */ -/* or 44, 52 or 60 32-bit words. */ - -#if defined( AES_VAR ) || defined( AES_256 ) -#define KS_LENGTH 60 -#elif defined( AES_192 ) -#define KS_LENGTH 52 -#else -#define KS_LENGTH 44 -#endif - -#define AES_RETURN INT_RETURN - -/* the character array 'inf' in the following structures is used */ -/* to hold AES context information. This AES code uses cx->inf.b[0] */ -/* to hold the number of rounds multiplied by 16. The other three */ -/* elements can be used by code that implements additional modes */ - -typedef union -{ uint32_t l; - uint8_t b[4]; -} aes_inf; - -#ifdef _MSC_VER -# pragma warning( disable : 4324 ) -#endif - -#if defined(_MSC_VER) && defined(_WIN64) -#define ALIGNED_(x) __declspec(align(x)) -#elif defined(__GNUC__) && defined(__x86_64__) -#define ALIGNED_(x) __attribute__ ((aligned(x))) -#else -#define ALIGNED_(x) -#endif - -typedef struct ALIGNED_(16) -{ uint32_t ks[KS_LENGTH]; - aes_inf inf; -} aes_encrypt_ctx; - -typedef struct ALIGNED_(16) -{ uint32_t ks[KS_LENGTH]; - aes_inf inf; -} aes_decrypt_ctx; - -#ifdef _MSC_VER -# pragma warning( default : 4324 ) -#endif - -/* This routine must be called before first use if non-static */ -/* tables are being used */ - -AES_RETURN aes_init(void); - -/* Key lengths in the range 16 <= key_len <= 32 are given in bytes, */ -/* those in the range 128 <= key_len <= 256 are given in bits */ - -#if defined( AES_ENCRYPT ) - -#if defined( AES_128 ) || defined( AES_VAR) -AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]); -#endif - -#if defined( AES_192 ) || defined( AES_VAR) -AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]); -#endif - -#if defined( AES_256 ) || defined( AES_VAR) -AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]); -#endif - -#if defined( AES_VAR ) -AES_RETURN aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1]); -#endif - -AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1]); - -#endif - -#if defined( AES_DECRYPT ) - -#if defined( AES_128 ) || defined( AES_VAR) -AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]); -#endif - -#if defined( AES_192 ) || defined( AES_VAR) -AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]); -#endif - -#if defined( AES_256 ) || defined( AES_VAR) -AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]); -#endif - -#if defined( AES_VAR ) -AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1]); -#endif - -AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1]); - -#endif - -#if defined( AES_MODES ) - -/* Multiple calls to the following subroutines for multiple block */ -/* ECB, CBC, CFB, OFB and CTR mode encryption can be used to handle */ -/* long messages incrementally provided that the context AND the iv */ -/* are preserved between all such calls. For the ECB and CBC modes */ -/* each individual call within a series of incremental calls must */ -/* process only full blocks (i.e. len must be a multiple of 16) but */ -/* the CFB, OFB and CTR mode calls can handle multiple incremental */ -/* calls of any length. Each mode is reset when a new AES key is */ -/* set but ECB needs no reset and CBC can be reset without setting */ -/* a new key by setting a new IV value. To reset CFB, OFB and CTR */ -/* without setting the key, aes_mode_reset() must be called and the */ -/* IV must be set. NOTE: All these calls update the IV on exit so */ -/* this has to be reset if a new operation with the same IV as the */ -/* previous one is required (or decryption follows encryption with */ -/* the same IV array). */ - -AES_RETURN aes_test_alignment_detection(unsigned int n); - -AES_RETURN aes_ecb_encrypt(const unsigned char *ibuf, unsigned char *obuf, - int len, const aes_encrypt_ctx cx[1]); - -AES_RETURN aes_ecb_decrypt(const unsigned char *ibuf, unsigned char *obuf, - int len, const aes_decrypt_ctx cx[1]); - -AES_RETURN aes_cbc_encrypt(const unsigned char *ibuf, unsigned char *obuf, - int len, unsigned char *iv, const aes_encrypt_ctx cx[1]); - -AES_RETURN aes_cbc_decrypt(const unsigned char *ibuf, unsigned char *obuf, - int len, unsigned char *iv, const aes_decrypt_ctx cx[1]); - -AES_RETURN aes_mode_reset(aes_encrypt_ctx cx[1]); - -AES_RETURN aes_cfb_encrypt(const unsigned char *ibuf, unsigned char *obuf, - int len, unsigned char *iv, aes_encrypt_ctx cx[1]); - -AES_RETURN aes_cfb_decrypt(const unsigned char *ibuf, unsigned char *obuf, - int len, unsigned char *iv, aes_encrypt_ctx cx[1]); - -#define aes_ofb_encrypt aes_ofb_crypt -#define aes_ofb_decrypt aes_ofb_crypt - -AES_RETURN aes_ofb_crypt(const unsigned char *ibuf, unsigned char *obuf, - int len, unsigned char *iv, aes_encrypt_ctx cx[1]); - -typedef void cbuf_inc(unsigned char *cbuf); - -#define aes_ctr_encrypt aes_ctr_crypt -#define aes_ctr_decrypt aes_ctr_crypt - -AES_RETURN aes_ctr_crypt(const unsigned char *ibuf, unsigned char *obuf, - int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx cx[1]); - -void aes_ctr_cbuf_inc(unsigned char *cbuf); - -#endif - -#if defined(__cplusplus) -} -#endif - -#endif diff --git a/deps/crypto/trezor-crypto/aes/aes_modes.c b/deps/crypto/trezor-crypto/aes/aes_modes.c deleted file mode 100644 index b89283d0f..000000000 --- a/deps/crypto/trezor-crypto/aes/aes_modes.c +++ /dev/null @@ -1,957 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. - -The redistribution and use of this software (with or without changes) -is allowed without the payment of fees or royalties provided that: - - source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation. - -This software is provided 'as is' with no explicit or implied warranties -in respect of its operation, including, but not limited to, correctness -and fitness for purpose. ---------------------------------------------------------------------------- -Issue Date: 20/12/2007 - - These subroutines implement multiple block AES modes for ECB, CBC, CFB, - OFB and CTR encryption, The code provides support for the VIA Advanced - Cryptography Engine (ACE). - - NOTE: In the following subroutines, the AES contexts (ctx) must be - 16 byte aligned if VIA ACE is being used -*/ - -#include -#include -#include - -#include "aesopt.h" - -#if defined( AES_MODES ) -#if defined(__cplusplus) -extern "C" -{ -#endif - -#if defined( _MSC_VER ) && ( _MSC_VER > 800 ) -#pragma intrinsic(memcpy) -#endif - -#define BFR_BLOCKS 8 - -/* These values are used to detect long word alignment in order to */ -/* speed up some buffer operations. This facility may not work on */ -/* some machines so this define can be commented out if necessary */ - -#define FAST_BUFFER_OPERATIONS - -#define lp32(x) ((uint32_t*)(x)) - -#if defined( USE_VIA_ACE_IF_PRESENT ) - -#include "aes_via_ace.h" - -#pragma pack(16) - -aligned_array(unsigned long, enc_gen_table, 12, 16) = NEH_ENC_GEN_DATA; -aligned_array(unsigned long, enc_load_table, 12, 16) = NEH_ENC_LOAD_DATA; -aligned_array(unsigned long, enc_hybrid_table, 12, 16) = NEH_ENC_HYBRID_DATA; -aligned_array(unsigned long, dec_gen_table, 12, 16) = NEH_DEC_GEN_DATA; -aligned_array(unsigned long, dec_load_table, 12, 16) = NEH_DEC_LOAD_DATA; -aligned_array(unsigned long, dec_hybrid_table, 12, 16) = NEH_DEC_HYBRID_DATA; - -/* NOTE: These control word macros must only be used after */ -/* a key has been set up because they depend on key size */ -/* See the VIA ACE documentation for key type information */ -/* and aes_via_ace.h for non-default NEH_KEY_TYPE values */ - -#ifndef NEH_KEY_TYPE -# define NEH_KEY_TYPE NEH_HYBRID -#endif - -#if NEH_KEY_TYPE == NEH_LOAD -#define kd_adr(c) ((uint8_t*)(c)->ks) -#elif NEH_KEY_TYPE == NEH_GENERATE -#define kd_adr(c) ((uint8_t*)(c)->ks + (c)->inf.b[0]) -#elif NEH_KEY_TYPE == NEH_HYBRID -#define kd_adr(c) ((uint8_t*)(c)->ks + ((c)->inf.b[0] == 160 ? 160 : 0)) -#else -#error no key type defined for VIA ACE -#endif - -#else - -#define aligned_array(type, name, no, stride) type name[no] -#define aligned_auto(type, name, no, stride) type name[no] - -#endif - -#if defined( _MSC_VER ) && _MSC_VER > 1200 - -#define via_cwd(cwd, ty, dir, len) \ - unsigned long* cwd = (dir##_##ty##_table + ((len - 128) >> 4)) - -#else - -#define via_cwd(cwd, ty, dir, len) \ - aligned_auto(unsigned long, cwd, 4, 16); \ - cwd[1] = cwd[2] = cwd[3] = 0; \ - cwd[0] = neh_##dir##_##ty##_key(len) - -#endif - -/* test the code for detecting and setting pointer alignment */ - -AES_RETURN aes_test_alignment_detection(unsigned int n) /* 4 <= n <= 16 */ -{ uint8_t p[16] = {0}; - uint32_t i = 0, count_eq = 0, count_neq = 0; - - if(n < 4 || n > 16) - return EXIT_FAILURE; - - for(i = 0; i < n; ++i) - { - uint8_t *qf = ALIGN_FLOOR(p + i, n), - *qh = ALIGN_CEIL(p + i, n); - - if(qh == qf) - ++count_eq; - else if(qh == qf + n) - ++count_neq; - else - return EXIT_FAILURE; - } - return (count_eq != 1 || count_neq != n - 1 ? EXIT_FAILURE : EXIT_SUCCESS); -} - -AES_RETURN aes_mode_reset(aes_encrypt_ctx ctx[1]) -{ - ctx->inf.b[2] = 0; - return EXIT_SUCCESS; -} - -AES_RETURN aes_ecb_encrypt(const unsigned char *ibuf, unsigned char *obuf, - int len, const aes_encrypt_ctx ctx[1]) -{ int nb = len >> AES_BLOCK_SIZE_P2; - - if(len & (AES_BLOCK_SIZE - 1)) - return EXIT_FAILURE; - -#if defined( USE_VIA_ACE_IF_PRESENT ) - - if(ctx->inf.b[1] == 0xff) - { uint8_t *ksp = (uint8_t*)(ctx->ks); - via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); - - if(ALIGN_OFFSET( ctx, 16 )) - return EXIT_FAILURE; - - if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 )) - { - via_ecb_op5(ksp, cwd, ibuf, obuf, nb); - } - else - { aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); - uint8_t *ip = NULL, *op = NULL; - - while(nb) - { - int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); - - ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); - op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); - - if(ip != ibuf) - memcpy(buf, ibuf, m * AES_BLOCK_SIZE); - - via_ecb_op5(ksp, cwd, ip, op, m); - - if(op != obuf) - memcpy(obuf, buf, m * AES_BLOCK_SIZE); - - ibuf += m * AES_BLOCK_SIZE; - obuf += m * AES_BLOCK_SIZE; - nb -= m; - } - } - - return EXIT_SUCCESS; - } - -#endif - -#if !defined( ASSUME_VIA_ACE_PRESENT ) - while(nb--) - { - if(aes_encrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - ibuf += AES_BLOCK_SIZE; - obuf += AES_BLOCK_SIZE; - } -#endif - return EXIT_SUCCESS; -} - -AES_RETURN aes_ecb_decrypt(const unsigned char *ibuf, unsigned char *obuf, - int len, const aes_decrypt_ctx ctx[1]) -{ int nb = len >> AES_BLOCK_SIZE_P2; - - if(len & (AES_BLOCK_SIZE - 1)) - return EXIT_FAILURE; - -#if defined( USE_VIA_ACE_IF_PRESENT ) - - if(ctx->inf.b[1] == 0xff) - { uint8_t *ksp = kd_adr(ctx); - via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192); - - if(ALIGN_OFFSET( ctx, 16 )) - return EXIT_FAILURE; - - if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 )) - { - via_ecb_op5(ksp, cwd, ibuf, obuf, nb); - } - else - { aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); - uint8_t *ip = NULL, *op = NULL; - - while(nb) - { - int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); - - ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); - op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); - - if(ip != ibuf) - memcpy(buf, ibuf, m * AES_BLOCK_SIZE); - - via_ecb_op5(ksp, cwd, ip, op, m); - - if(op != obuf) - memcpy(obuf, buf, m * AES_BLOCK_SIZE); - - ibuf += m * AES_BLOCK_SIZE; - obuf += m * AES_BLOCK_SIZE; - nb -= m; - } - } - - return EXIT_SUCCESS; - } - -#endif - -#if !defined( ASSUME_VIA_ACE_PRESENT ) - while(nb--) - { - if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - ibuf += AES_BLOCK_SIZE; - obuf += AES_BLOCK_SIZE; - } -#endif - return EXIT_SUCCESS; -} - -AES_RETURN aes_cbc_encrypt(const unsigned char *ibuf, unsigned char *obuf, - int len, unsigned char *iv, const aes_encrypt_ctx ctx[1]) -{ int nb = len >> AES_BLOCK_SIZE_P2; - - if(len & (AES_BLOCK_SIZE - 1)) - return EXIT_FAILURE; - -#if defined( USE_VIA_ACE_IF_PRESENT ) - - if(ctx->inf.b[1] == 0xff) - { uint8_t *ksp = (uint8_t*)(ctx->ks), *ivp = iv; - aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16); - via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); - - if(ALIGN_OFFSET( ctx, 16 )) - return EXIT_FAILURE; - - if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */ - { - ivp = liv; - memcpy(liv, iv, AES_BLOCK_SIZE); - } - - if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ) && !ALIGN_OFFSET( iv, 16 )) - { - via_cbc_op7(ksp, cwd, ibuf, obuf, nb, ivp, ivp); - } - else - { aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); - uint8_t *ip = NULL, *op = NULL; - - while(nb) - { - int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); - - ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); - op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); - - if(ip != ibuf) - memcpy(buf, ibuf, m * AES_BLOCK_SIZE); - - via_cbc_op7(ksp, cwd, ip, op, m, ivp, ivp); - - if(op != obuf) - memcpy(obuf, buf, m * AES_BLOCK_SIZE); - - ibuf += m * AES_BLOCK_SIZE; - obuf += m * AES_BLOCK_SIZE; - nb -= m; - } - } - - if(iv != ivp) - memcpy(iv, ivp, AES_BLOCK_SIZE); - - return EXIT_SUCCESS; - } - -#endif - -#if !defined( ASSUME_VIA_ACE_PRESENT ) -# ifdef FAST_BUFFER_OPERATIONS - if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( iv, 4 )) - while(nb--) - { - lp32(iv)[0] ^= lp32(ibuf)[0]; - lp32(iv)[1] ^= lp32(ibuf)[1]; - lp32(iv)[2] ^= lp32(ibuf)[2]; - lp32(iv)[3] ^= lp32(ibuf)[3]; - if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - memcpy(obuf, iv, AES_BLOCK_SIZE); - ibuf += AES_BLOCK_SIZE; - obuf += AES_BLOCK_SIZE; - } - else -# endif - while(nb--) - { - iv[ 0] ^= ibuf[ 0]; iv[ 1] ^= ibuf[ 1]; - iv[ 2] ^= ibuf[ 2]; iv[ 3] ^= ibuf[ 3]; - iv[ 4] ^= ibuf[ 4]; iv[ 5] ^= ibuf[ 5]; - iv[ 6] ^= ibuf[ 6]; iv[ 7] ^= ibuf[ 7]; - iv[ 8] ^= ibuf[ 8]; iv[ 9] ^= ibuf[ 9]; - iv[10] ^= ibuf[10]; iv[11] ^= ibuf[11]; - iv[12] ^= ibuf[12]; iv[13] ^= ibuf[13]; - iv[14] ^= ibuf[14]; iv[15] ^= ibuf[15]; - if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - memcpy(obuf, iv, AES_BLOCK_SIZE); - ibuf += AES_BLOCK_SIZE; - obuf += AES_BLOCK_SIZE; - } -#endif - return EXIT_SUCCESS; -} - -AES_RETURN aes_cbc_decrypt(const unsigned char *ibuf, unsigned char *obuf, - int len, unsigned char *iv, const aes_decrypt_ctx ctx[1]) -{ unsigned char tmp[AES_BLOCK_SIZE] = {0}; - int nb = len >> AES_BLOCK_SIZE_P2; - - if(len & (AES_BLOCK_SIZE - 1)) - return EXIT_FAILURE; - -#if defined( USE_VIA_ACE_IF_PRESENT ) - - if(ctx->inf.b[1] == 0xff) - { uint8_t *ksp = kd_adr(ctx), *ivp = iv; - aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16); - via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192); - - if(ALIGN_OFFSET( ctx, 16 )) - return EXIT_FAILURE; - - if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */ - { - ivp = liv; - memcpy(liv, iv, AES_BLOCK_SIZE); - } - - if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ) && !ALIGN_OFFSET( iv, 16 )) - { - via_cbc_op6(ksp, cwd, ibuf, obuf, nb, ivp); - } - else - { aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); - uint8_t *ip = NULL, *op = NULL; - - while(nb) - { - int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); - - ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); - op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); - - if(ip != ibuf) - memcpy(buf, ibuf, m * AES_BLOCK_SIZE); - - via_cbc_op6(ksp, cwd, ip, op, m, ivp); - - if(op != obuf) - memcpy(obuf, buf, m * AES_BLOCK_SIZE); - - ibuf += m * AES_BLOCK_SIZE; - obuf += m * AES_BLOCK_SIZE; - nb -= m; - } - } - - if(iv != ivp) - memcpy(iv, ivp, AES_BLOCK_SIZE); - - return EXIT_SUCCESS; - } -#endif - -#if !defined( ASSUME_VIA_ACE_PRESENT ) -# ifdef FAST_BUFFER_OPERATIONS - if(!ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 )) - while(nb--) - { - memcpy(tmp, ibuf, AES_BLOCK_SIZE); - if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - lp32(obuf)[0] ^= lp32(iv)[0]; - lp32(obuf)[1] ^= lp32(iv)[1]; - lp32(obuf)[2] ^= lp32(iv)[2]; - lp32(obuf)[3] ^= lp32(iv)[3]; - memcpy(iv, tmp, AES_BLOCK_SIZE); - ibuf += AES_BLOCK_SIZE; - obuf += AES_BLOCK_SIZE; - } - else -# endif - while(nb--) - { - memcpy(tmp, ibuf, AES_BLOCK_SIZE); - if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - obuf[ 0] ^= iv[ 0]; obuf[ 1] ^= iv[ 1]; - obuf[ 2] ^= iv[ 2]; obuf[ 3] ^= iv[ 3]; - obuf[ 4] ^= iv[ 4]; obuf[ 5] ^= iv[ 5]; - obuf[ 6] ^= iv[ 6]; obuf[ 7] ^= iv[ 7]; - obuf[ 8] ^= iv[ 8]; obuf[ 9] ^= iv[ 9]; - obuf[10] ^= iv[10]; obuf[11] ^= iv[11]; - obuf[12] ^= iv[12]; obuf[13] ^= iv[13]; - obuf[14] ^= iv[14]; obuf[15] ^= iv[15]; - memcpy(iv, tmp, AES_BLOCK_SIZE); - ibuf += AES_BLOCK_SIZE; - obuf += AES_BLOCK_SIZE; - } -#endif - return EXIT_SUCCESS; -} - -AES_RETURN aes_cfb_encrypt(const unsigned char *ibuf, unsigned char *obuf, - int len, unsigned char *iv, aes_encrypt_ctx ctx[1]) -{ int cnt = 0, b_pos = (int)ctx->inf.b[2], nb = 0; - - if(b_pos) /* complete any partial block */ - { - while(b_pos < AES_BLOCK_SIZE && cnt < len) - { - *obuf++ = (iv[b_pos++] ^= *ibuf++); - cnt++; - } - - b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); - } - - if((nb = (len - cnt) >> AES_BLOCK_SIZE_P2) != 0) /* process whole blocks */ - { -#if defined( USE_VIA_ACE_IF_PRESENT ) - - if(ctx->inf.b[1] == 0xff) - { int m = 0; - uint8_t *ksp = (uint8_t*)(ctx->ks), *ivp = iv; - aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16); - via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); - - if(ALIGN_OFFSET( ctx, 16 )) - return EXIT_FAILURE; - - if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */ - { - ivp = liv; - memcpy(liv, iv, AES_BLOCK_SIZE); - } - - if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 )) - { - via_cfb_op7(ksp, cwd, ibuf, obuf, nb, ivp, ivp); - ibuf += nb * AES_BLOCK_SIZE; - obuf += nb * AES_BLOCK_SIZE; - cnt += nb * AES_BLOCK_SIZE; - } - else /* input, output or both are unaligned */ - { aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); - uint8_t *ip = NULL, *op = NULL; - - while(nb) - { - m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m; - - ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); - op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); - - if(ip != ibuf) - memcpy(buf, ibuf, m * AES_BLOCK_SIZE); - - via_cfb_op7(ksp, cwd, ip, op, m, ivp, ivp); - - if(op != obuf) - memcpy(obuf, buf, m * AES_BLOCK_SIZE); - - ibuf += m * AES_BLOCK_SIZE; - obuf += m * AES_BLOCK_SIZE; - cnt += m * AES_BLOCK_SIZE; - } - } - - if(ivp != iv) - memcpy(iv, ivp, AES_BLOCK_SIZE); - } -#else -# ifdef FAST_BUFFER_OPERATIONS - if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 )) - while(cnt + AES_BLOCK_SIZE <= len) - { - assert(b_pos == 0); - if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - lp32(obuf)[0] = lp32(iv)[0] ^= lp32(ibuf)[0]; - lp32(obuf)[1] = lp32(iv)[1] ^= lp32(ibuf)[1]; - lp32(obuf)[2] = lp32(iv)[2] ^= lp32(ibuf)[2]; - lp32(obuf)[3] = lp32(iv)[3] ^= lp32(ibuf)[3]; - ibuf += AES_BLOCK_SIZE; - obuf += AES_BLOCK_SIZE; - cnt += AES_BLOCK_SIZE; - } - else -# endif - while(cnt + AES_BLOCK_SIZE <= len) - { - assert(b_pos == 0); - if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - obuf[ 0] = iv[ 0] ^= ibuf[ 0]; obuf[ 1] = iv[ 1] ^= ibuf[ 1]; - obuf[ 2] = iv[ 2] ^= ibuf[ 2]; obuf[ 3] = iv[ 3] ^= ibuf[ 3]; - obuf[ 4] = iv[ 4] ^= ibuf[ 4]; obuf[ 5] = iv[ 5] ^= ibuf[ 5]; - obuf[ 6] = iv[ 6] ^= ibuf[ 6]; obuf[ 7] = iv[ 7] ^= ibuf[ 7]; - obuf[ 8] = iv[ 8] ^= ibuf[ 8]; obuf[ 9] = iv[ 9] ^= ibuf[ 9]; - obuf[10] = iv[10] ^= ibuf[10]; obuf[11] = iv[11] ^= ibuf[11]; - obuf[12] = iv[12] ^= ibuf[12]; obuf[13] = iv[13] ^= ibuf[13]; - obuf[14] = iv[14] ^= ibuf[14]; obuf[15] = iv[15] ^= ibuf[15]; - ibuf += AES_BLOCK_SIZE; - obuf += AES_BLOCK_SIZE; - cnt += AES_BLOCK_SIZE; - } -#endif - } - - while(cnt < len) - { - if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - - while(cnt < len && b_pos < AES_BLOCK_SIZE) - { - *obuf++ = (iv[b_pos++] ^= *ibuf++); - cnt++; - } - - b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); - } - - ctx->inf.b[2] = (uint8_t)b_pos; - return EXIT_SUCCESS; -} - -AES_RETURN aes_cfb_decrypt(const unsigned char *ibuf, unsigned char *obuf, - int len, unsigned char *iv, aes_encrypt_ctx ctx[1]) -{ int cnt = 0, b_pos = (int)ctx->inf.b[2], nb = 0; - - if(b_pos) /* complete any partial block */ - { uint8_t t = 0; - - while(b_pos < AES_BLOCK_SIZE && cnt < len) - { - t = *ibuf++; - *obuf++ = t ^ iv[b_pos]; - iv[b_pos++] = t; - cnt++; - } - - b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); - } - - if((nb = (len - cnt) >> AES_BLOCK_SIZE_P2) != 0) /* process whole blocks */ - { -#if defined( USE_VIA_ACE_IF_PRESENT ) - - if(ctx->inf.b[1] == 0xff) - { int m = 0; - uint8_t *ksp = (uint8_t*)(ctx->ks), *ivp = iv; - aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16); - via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192); - - if(ALIGN_OFFSET( ctx, 16 )) - return EXIT_FAILURE; - - if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */ - { - ivp = liv; - memcpy(liv, iv, AES_BLOCK_SIZE); - } - - if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 )) - { - via_cfb_op6(ksp, cwd, ibuf, obuf, nb, ivp); - ibuf += nb * AES_BLOCK_SIZE; - obuf += nb * AES_BLOCK_SIZE; - cnt += nb * AES_BLOCK_SIZE; - } - else /* input, output or both are unaligned */ - { aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); - uint8_t *ip = NULL, *op = NULL; - - while(nb) - { - m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m; - - ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); - op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); - - if(ip != ibuf) /* input buffer is not aligned */ - memcpy(buf, ibuf, m * AES_BLOCK_SIZE); - - via_cfb_op6(ksp, cwd, ip, op, m, ivp); - - if(op != obuf) /* output buffer is not aligned */ - memcpy(obuf, buf, m * AES_BLOCK_SIZE); - - ibuf += m * AES_BLOCK_SIZE; - obuf += m * AES_BLOCK_SIZE; - cnt += m * AES_BLOCK_SIZE; - } - } - - if(ivp != iv) - memcpy(iv, ivp, AES_BLOCK_SIZE); - } -#else -# ifdef FAST_BUFFER_OPERATIONS - if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) &&!ALIGN_OFFSET( iv, 4 )) - while(cnt + AES_BLOCK_SIZE <= len) - { uint32_t t = 0; - - assert(b_pos == 0); - if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - t = lp32(ibuf)[0], lp32(obuf)[0] = t ^ lp32(iv)[0], lp32(iv)[0] = t; - t = lp32(ibuf)[1], lp32(obuf)[1] = t ^ lp32(iv)[1], lp32(iv)[1] = t; - t = lp32(ibuf)[2], lp32(obuf)[2] = t ^ lp32(iv)[2], lp32(iv)[2] = t; - t = lp32(ibuf)[3], lp32(obuf)[3] = t ^ lp32(iv)[3], lp32(iv)[3] = t; - ibuf += AES_BLOCK_SIZE; - obuf += AES_BLOCK_SIZE; - cnt += AES_BLOCK_SIZE; - } - else -# endif - while(cnt + AES_BLOCK_SIZE <= len) - { uint8_t t = 0; - - assert(b_pos == 0); - if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - t = ibuf[ 0], obuf[ 0] = t ^ iv[ 0], iv[ 0] = t; - t = ibuf[ 1], obuf[ 1] = t ^ iv[ 1], iv[ 1] = t; - t = ibuf[ 2], obuf[ 2] = t ^ iv[ 2], iv[ 2] = t; - t = ibuf[ 3], obuf[ 3] = t ^ iv[ 3], iv[ 3] = t; - t = ibuf[ 4], obuf[ 4] = t ^ iv[ 4], iv[ 4] = t; - t = ibuf[ 5], obuf[ 5] = t ^ iv[ 5], iv[ 5] = t; - t = ibuf[ 6], obuf[ 6] = t ^ iv[ 6], iv[ 6] = t; - t = ibuf[ 7], obuf[ 7] = t ^ iv[ 7], iv[ 7] = t; - t = ibuf[ 8], obuf[ 8] = t ^ iv[ 8], iv[ 8] = t; - t = ibuf[ 9], obuf[ 9] = t ^ iv[ 9], iv[ 9] = t; - t = ibuf[10], obuf[10] = t ^ iv[10], iv[10] = t; - t = ibuf[11], obuf[11] = t ^ iv[11], iv[11] = t; - t = ibuf[12], obuf[12] = t ^ iv[12], iv[12] = t; - t = ibuf[13], obuf[13] = t ^ iv[13], iv[13] = t; - t = ibuf[14], obuf[14] = t ^ iv[14], iv[14] = t; - t = ibuf[15], obuf[15] = t ^ iv[15], iv[15] = t; - ibuf += AES_BLOCK_SIZE; - obuf += AES_BLOCK_SIZE; - cnt += AES_BLOCK_SIZE; - } -#endif - } - - while(cnt < len) - { uint8_t t = 0; - - if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - - while(cnt < len && b_pos < AES_BLOCK_SIZE) - { - t = *ibuf++; - *obuf++ = t ^ iv[b_pos]; - iv[b_pos++] = t; - cnt++; - } - - b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); - } - - ctx->inf.b[2] = (uint8_t)b_pos; - return EXIT_SUCCESS; -} - -AES_RETURN aes_ofb_crypt(const unsigned char *ibuf, unsigned char *obuf, - int len, unsigned char *iv, aes_encrypt_ctx ctx[1]) -{ int cnt = 0, b_pos = (int)ctx->inf.b[2], nb = 0; - - if(b_pos) /* complete any partial block */ - { - while(b_pos < AES_BLOCK_SIZE && cnt < len) - { - *obuf++ = iv[b_pos++] ^ *ibuf++; - cnt++; - } - - b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); - } - - if((nb = (len - cnt) >> AES_BLOCK_SIZE_P2) != 0) /* process whole blocks */ - { -#if defined( USE_VIA_ACE_IF_PRESENT ) - - if(ctx->inf.b[1] == 0xff) - { int m = 0; - uint8_t *ksp = (uint8_t*)(ctx->ks), *ivp = iv; - aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16); - via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); - - if(ALIGN_OFFSET( ctx, 16 )) - return EXIT_FAILURE; - - if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */ - { - ivp = liv; - memcpy(liv, iv, AES_BLOCK_SIZE); - } - - if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 )) - { - via_ofb_op6(ksp, cwd, ibuf, obuf, nb, ivp); - ibuf += nb * AES_BLOCK_SIZE; - obuf += nb * AES_BLOCK_SIZE; - cnt += nb * AES_BLOCK_SIZE; - } - else /* input, output or both are unaligned */ - { aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); - uint8_t *ip = NULL, *op = NULL; - - while(nb) - { - m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m; - - ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); - op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); - - if(ip != ibuf) - memcpy(buf, ibuf, m * AES_BLOCK_SIZE); - - via_ofb_op6(ksp, cwd, ip, op, m, ivp); - - if(op != obuf) - memcpy(obuf, buf, m * AES_BLOCK_SIZE); - - ibuf += m * AES_BLOCK_SIZE; - obuf += m * AES_BLOCK_SIZE; - cnt += m * AES_BLOCK_SIZE; - } - } - - if(ivp != iv) - memcpy(iv, ivp, AES_BLOCK_SIZE); - } -#else -# ifdef FAST_BUFFER_OPERATIONS - if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 )) - while(cnt + AES_BLOCK_SIZE <= len) - { - assert(b_pos == 0); - if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - lp32(obuf)[0] = lp32(iv)[0] ^ lp32(ibuf)[0]; - lp32(obuf)[1] = lp32(iv)[1] ^ lp32(ibuf)[1]; - lp32(obuf)[2] = lp32(iv)[2] ^ lp32(ibuf)[2]; - lp32(obuf)[3] = lp32(iv)[3] ^ lp32(ibuf)[3]; - ibuf += AES_BLOCK_SIZE; - obuf += AES_BLOCK_SIZE; - cnt += AES_BLOCK_SIZE; - } - else -# endif - while(cnt + AES_BLOCK_SIZE <= len) - { - assert(b_pos == 0); - if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - obuf[ 0] = iv[ 0] ^ ibuf[ 0]; obuf[ 1] = iv[ 1] ^ ibuf[ 1]; - obuf[ 2] = iv[ 2] ^ ibuf[ 2]; obuf[ 3] = iv[ 3] ^ ibuf[ 3]; - obuf[ 4] = iv[ 4] ^ ibuf[ 4]; obuf[ 5] = iv[ 5] ^ ibuf[ 5]; - obuf[ 6] = iv[ 6] ^ ibuf[ 6]; obuf[ 7] = iv[ 7] ^ ibuf[ 7]; - obuf[ 8] = iv[ 8] ^ ibuf[ 8]; obuf[ 9] = iv[ 9] ^ ibuf[ 9]; - obuf[10] = iv[10] ^ ibuf[10]; obuf[11] = iv[11] ^ ibuf[11]; - obuf[12] = iv[12] ^ ibuf[12]; obuf[13] = iv[13] ^ ibuf[13]; - obuf[14] = iv[14] ^ ibuf[14]; obuf[15] = iv[15] ^ ibuf[15]; - ibuf += AES_BLOCK_SIZE; - obuf += AES_BLOCK_SIZE; - cnt += AES_BLOCK_SIZE; - } -#endif - } - - while(cnt < len) - { - if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - - while(cnt < len && b_pos < AES_BLOCK_SIZE) - { - *obuf++ = iv[b_pos++] ^ *ibuf++; - cnt++; - } - - b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); - } - - ctx->inf.b[2] = (uint8_t)b_pos; - return EXIT_SUCCESS; -} - -#define BFR_LENGTH (BFR_BLOCKS * AES_BLOCK_SIZE) - -AES_RETURN aes_ctr_crypt(const unsigned char *ibuf, unsigned char *obuf, - int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx ctx[1]) -{ unsigned char *ip = NULL; - int i = 0, blen = 0, b_pos = (int)(ctx->inf.b[2]); - -#if defined( USE_VIA_ACE_IF_PRESENT ) - aligned_auto(uint8_t, buf, BFR_LENGTH, 16); - if(ctx->inf.b[1] == 0xff && ALIGN_OFFSET( ctx, 16 )) - return EXIT_FAILURE; -#else - uint8_t buf[BFR_LENGTH] = {0}; -#endif - - if(b_pos) - { - memcpy(buf, cbuf, AES_BLOCK_SIZE); - if(aes_ecb_encrypt(buf, buf, AES_BLOCK_SIZE, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - - while(b_pos < AES_BLOCK_SIZE && len) - { - *obuf++ = *ibuf++ ^ buf[b_pos++]; - --len; - } - - if(len) - ctr_inc(cbuf), b_pos = 0; - } - - while(len) - { - blen = (len > BFR_LENGTH ? BFR_LENGTH : len), len -= blen; - - for(i = 0, ip = buf; i < (blen >> AES_BLOCK_SIZE_P2); ++i) - { - memcpy(ip, cbuf, AES_BLOCK_SIZE); - ctr_inc(cbuf); - ip += AES_BLOCK_SIZE; - } - - if(blen & (AES_BLOCK_SIZE - 1)) - memcpy(ip, cbuf, AES_BLOCK_SIZE), i++; - -#if defined( USE_VIA_ACE_IF_PRESENT ) - if(ctx->inf.b[1] == 0xff) - { - via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); - via_ecb_op5((ctx->ks), cwd, buf, buf, i); - } - else -#endif - if(aes_ecb_encrypt(buf, buf, i * AES_BLOCK_SIZE, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - - i = 0; ip = buf; -# ifdef FAST_BUFFER_OPERATIONS - if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( ip, 4 )) - while(i + AES_BLOCK_SIZE <= blen) - { - lp32(obuf)[0] = lp32(ibuf)[0] ^ lp32(ip)[0]; - lp32(obuf)[1] = lp32(ibuf)[1] ^ lp32(ip)[1]; - lp32(obuf)[2] = lp32(ibuf)[2] ^ lp32(ip)[2]; - lp32(obuf)[3] = lp32(ibuf)[3] ^ lp32(ip)[3]; - i += AES_BLOCK_SIZE; - ip += AES_BLOCK_SIZE; - ibuf += AES_BLOCK_SIZE; - obuf += AES_BLOCK_SIZE; - } - else -#endif - while(i + AES_BLOCK_SIZE <= blen) - { - obuf[ 0] = ibuf[ 0] ^ ip[ 0]; obuf[ 1] = ibuf[ 1] ^ ip[ 1]; - obuf[ 2] = ibuf[ 2] ^ ip[ 2]; obuf[ 3] = ibuf[ 3] ^ ip[ 3]; - obuf[ 4] = ibuf[ 4] ^ ip[ 4]; obuf[ 5] = ibuf[ 5] ^ ip[ 5]; - obuf[ 6] = ibuf[ 6] ^ ip[ 6]; obuf[ 7] = ibuf[ 7] ^ ip[ 7]; - obuf[ 8] = ibuf[ 8] ^ ip[ 8]; obuf[ 9] = ibuf[ 9] ^ ip[ 9]; - obuf[10] = ibuf[10] ^ ip[10]; obuf[11] = ibuf[11] ^ ip[11]; - obuf[12] = ibuf[12] ^ ip[12]; obuf[13] = ibuf[13] ^ ip[13]; - obuf[14] = ibuf[14] ^ ip[14]; obuf[15] = ibuf[15] ^ ip[15]; - i += AES_BLOCK_SIZE; - ip += AES_BLOCK_SIZE; - ibuf += AES_BLOCK_SIZE; - obuf += AES_BLOCK_SIZE; - } - - while(i++ < blen) - *obuf++ = *ibuf++ ^ ip[b_pos++]; - } - - ctx->inf.b[2] = (uint8_t)b_pos; - return EXIT_SUCCESS; -} - -void aes_ctr_cbuf_inc(unsigned char *cbuf) -{ - int i = AES_BLOCK_SIZE - 1; - while (i >= 0) { - cbuf[i]++; - if (cbuf[i]) return; // if there was no overflow - i--; - } -} - -#if defined(__cplusplus) -} -#endif -#endif diff --git a/deps/crypto/trezor-crypto/aes/aescrypt.c b/deps/crypto/trezor-crypto/aes/aescrypt.c deleted file mode 100644 index 4d0fcdefe..000000000 --- a/deps/crypto/trezor-crypto/aes/aescrypt.c +++ /dev/null @@ -1,307 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. - -The redistribution and use of this software (with or without changes) -is allowed without the payment of fees or royalties provided that: - - source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation. - -This software is provided 'as is' with no explicit or implied warranties -in respect of its operation, including, but not limited to, correctness -and fitness for purpose. ---------------------------------------------------------------------------- -Issue Date: 20/12/2007 -*/ - -#include "aesopt.h" -#include "aestab.h" - -#if defined( USE_INTEL_AES_IF_PRESENT ) -# include "aes_ni.h" -#else -/* map names here to provide the external API ('name' -> 'aes_name') */ -# define aes_xi(x) aes_ ## x -#endif - -#if defined(__cplusplus) -extern "C" -{ -#endif - -#define si(y,x,k,c) (s(y,c) = word_in(x, c) ^ (k)[c]) -#define so(y,x,c) word_out(y, c, s(x,c)) - -#if defined(ARRAYS) -#define locals(y,x) x[4] = {0}, y[4] = {0} -#else -#define locals(y,x) x##0=0,x##1=0,x##2=0,x##3=0,y##0=0,y##1=0,y##2=0,y##3=0 -#endif - -#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \ - s(y,2) = s(x,2); s(y,3) = s(x,3); -#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3) -#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3) -#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3) - -#if ( FUNCS_IN_C & ENCRYPTION_IN_C ) - -/* Visual C++ .Net v7.1 provides the fastest encryption code when using - Pentium optimiation with small code but this is poor for decryption - so we need to control this with the following VC++ pragmas -*/ - -#if defined( _MSC_VER ) && !defined( _WIN64 ) && !defined( __clang__ ) -#pragma optimize( "s", on ) -#endif - -/* Given the column (c) of the output state variable, the following - macros give the input state variables which are needed in its - computation for each row (r) of the state. All the alternative - macros give the same end values but expand into different ways - of calculating these values. In particular the complex macro - used for dynamically variable block sizes is designed to expand - to a compile time constant whenever possible but will expand to - conditional clauses on some branches (I am grateful to Frank - Yellin for this construction) -*/ - -#define fwd_var(x,r,c)\ - ( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\ - : r == 1 ? ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))\ - : r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\ - : ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2))) - -#if defined(FT4_SET) -#undef dec_fmvars -#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,n),fwd_var,rf1,c)) -#elif defined(FT1_SET) -#undef dec_fmvars -#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(f,n),fwd_var,rf1,c)) -#else -#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ fwd_mcol(no_table(x,t_use(s,box),fwd_var,rf1,c))) -#endif - -#if defined(FL4_SET) -#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,l),fwd_var,rf1,c)) -#elif defined(FL1_SET) -#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(f,l),fwd_var,rf1,c)) -#else -#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ no_table(x,t_use(s,box),fwd_var,rf1,c)) -#endif - -AES_RETURN aes_xi(encrypt)(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1]) -{ uint32_t locals(b0, b1); - const uint32_t *kp = NULL; -#if defined( dec_fmvars ) - dec_fmvars; /* declare variables for fwd_mcol() if needed */ -#endif - - if(cx->inf.b[0] != 10 * AES_BLOCK_SIZE && cx->inf.b[0] != 12 * AES_BLOCK_SIZE && cx->inf.b[0] != 14 * AES_BLOCK_SIZE) - return EXIT_FAILURE; - - kp = cx->ks; - state_in(b0, in, kp); - -#if (ENC_UNROLL == FULL) - - switch(cx->inf.b[0]) - { - case 14 * AES_BLOCK_SIZE: - round(fwd_rnd, b1, b0, kp + 1 * N_COLS); - round(fwd_rnd, b0, b1, kp + 2 * N_COLS); - kp += 2 * N_COLS; - //-fallthrough - case 12 * AES_BLOCK_SIZE: - round(fwd_rnd, b1, b0, kp + 1 * N_COLS); - round(fwd_rnd, b0, b1, kp + 2 * N_COLS); - kp += 2 * N_COLS; - //-fallthrough - case 10 * AES_BLOCK_SIZE: - round(fwd_rnd, b1, b0, kp + 1 * N_COLS); - round(fwd_rnd, b0, b1, kp + 2 * N_COLS); - round(fwd_rnd, b1, b0, kp + 3 * N_COLS); - round(fwd_rnd, b0, b1, kp + 4 * N_COLS); - round(fwd_rnd, b1, b0, kp + 5 * N_COLS); - round(fwd_rnd, b0, b1, kp + 6 * N_COLS); - round(fwd_rnd, b1, b0, kp + 7 * N_COLS); - round(fwd_rnd, b0, b1, kp + 8 * N_COLS); - round(fwd_rnd, b1, b0, kp + 9 * N_COLS); - round(fwd_lrnd, b0, b1, kp +10 * N_COLS); - //-fallthrough - } - -#else - -#if (ENC_UNROLL == PARTIAL) - { uint32_t rnd = 0; - for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd) - { - kp += N_COLS; - round(fwd_rnd, b1, b0, kp); - kp += N_COLS; - round(fwd_rnd, b0, b1, kp); - } - kp += N_COLS; - round(fwd_rnd, b1, b0, kp); -#else - { uint32_t rnd = 0; - for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd) - { - kp += N_COLS; - round(fwd_rnd, b1, b0, kp); - l_copy(b0, b1); - } -#endif - kp += N_COLS; - round(fwd_lrnd, b0, b1, kp); - } -#endif - - state_out(out, b0); - return EXIT_SUCCESS; -} - -#endif - -#if ( FUNCS_IN_C & DECRYPTION_IN_C) - -/* Visual C++ .Net v7.1 provides the fastest encryption code when using - Pentium optimiation with small code but this is poor for decryption - so we need to control this with the following VC++ pragmas -*/ - -#if defined( _MSC_VER ) && !defined( _WIN64 ) && !defined( __clang__ ) -#pragma optimize( "t", on ) -#endif - -/* Given the column (c) of the output state variable, the following - macros give the input state variables which are needed in its - computation for each row (r) of the state. All the alternative - macros give the same end values but expand into different ways - of calculating these values. In particular the complex macro - used for dynamically variable block sizes is designed to expand - to a compile time constant whenever possible but will expand to - conditional clauses on some branches (I am grateful to Frank - Yellin for this construction) -*/ - -#define inv_var(x,r,c)\ - ( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\ - : r == 1 ? ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2))\ - : r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\ - : ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))) - -#if defined(IT4_SET) -#undef dec_imvars -#define inv_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,n),inv_var,rf1,c)) -#elif defined(IT1_SET) -#undef dec_imvars -#define inv_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(i,n),inv_var,rf1,c)) -#else -#define inv_rnd(y,x,k,c) (s(y,c) = inv_mcol((k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c))) -#endif - -#if defined(IL4_SET) -#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,l),inv_var,rf1,c)) -#elif defined(IL1_SET) -#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(i,l),inv_var,rf1,c)) -#else -#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c)) -#endif - -/* This code can work with the decryption key schedule in the */ -/* order that is used for encrytpion (where the 1st decryption */ -/* round key is at the high end ot the schedule) or with a key */ -/* schedule that has been reversed to put the 1st decryption */ -/* round key at the low end of the schedule in memory (when */ -/* AES_REV_DKS is defined) */ - -#ifdef AES_REV_DKS -#define key_ofs 0 -#define rnd_key(n) (kp + n * N_COLS) -#else -#define key_ofs 1 -#define rnd_key(n) (kp - n * N_COLS) -#endif - -AES_RETURN aes_xi(decrypt)(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1]) -{ uint32_t locals(b0, b1); -#if defined( dec_imvars ) - dec_imvars; /* declare variables for inv_mcol() if needed */ -#endif - const uint32_t *kp = NULL; - - if(cx->inf.b[0] != 10 * AES_BLOCK_SIZE && cx->inf.b[0] != 12 * AES_BLOCK_SIZE && cx->inf.b[0] != 14 * AES_BLOCK_SIZE) - return EXIT_FAILURE; - - kp = cx->ks + (key_ofs ? (cx->inf.b[0] >> 2) : 0); - state_in(b0, in, kp); - -#if (DEC_UNROLL == FULL) - - kp = cx->ks + (key_ofs ? 0 : (cx->inf.b[0] >> 2)); - switch(cx->inf.b[0]) - { - case 14 * AES_BLOCK_SIZE: - round(inv_rnd, b1, b0, rnd_key(-13)); - round(inv_rnd, b0, b1, rnd_key(-12)); - //-fallthrough - case 12 * AES_BLOCK_SIZE: - round(inv_rnd, b1, b0, rnd_key(-11)); - round(inv_rnd, b0, b1, rnd_key(-10)); - //-fallthrough - case 10 * AES_BLOCK_SIZE: - round(inv_rnd, b1, b0, rnd_key(-9)); - round(inv_rnd, b0, b1, rnd_key(-8)); - round(inv_rnd, b1, b0, rnd_key(-7)); - round(inv_rnd, b0, b1, rnd_key(-6)); - round(inv_rnd, b1, b0, rnd_key(-5)); - round(inv_rnd, b0, b1, rnd_key(-4)); - round(inv_rnd, b1, b0, rnd_key(-3)); - round(inv_rnd, b0, b1, rnd_key(-2)); - round(inv_rnd, b1, b0, rnd_key(-1)); - round(inv_lrnd, b0, b1, rnd_key( 0)); - //-fallthrough - } - -#else - -#if (DEC_UNROLL == PARTIAL) - { uint32_t rnd = 0; - for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd) - { - kp = rnd_key(1); - round(inv_rnd, b1, b0, kp); - kp = rnd_key(1); - round(inv_rnd, b0, b1, kp); - } - kp = rnd_key(1); - round(inv_rnd, b1, b0, kp); -#else - { uint32_t rnd = 0; - for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd) - { - kp = rnd_key(1); - round(inv_rnd, b1, b0, kp); - l_copy(b0, b1); - } -#endif - kp = rnd_key(1); - round(inv_lrnd, b0, b1, kp); - } -#endif - - state_out(out, b0); - return EXIT_SUCCESS; -} - -#endif - -#if defined(__cplusplus) -} -#endif diff --git a/deps/crypto/trezor-crypto/aes/aeskey.c b/deps/crypto/trezor-crypto/aes/aeskey.c deleted file mode 100644 index f675d6968..000000000 --- a/deps/crypto/trezor-crypto/aes/aeskey.c +++ /dev/null @@ -1,560 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. - -The redistribution and use of this software (with or without changes) -is allowed without the payment of fees or royalties provided that: - - source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation. - -This software is provided 'as is' with no explicit or implied warranties -in respect of its operation, including, but not limited to, correctness -and fitness for purpose. ---------------------------------------------------------------------------- -Issue Date: 20/12/2007 -*/ - -#include "aesopt.h" -#include "aestab.h" - -#if defined( USE_INTEL_AES_IF_PRESENT ) -# include "aes_ni.h" -#else -/* map names here to provide the external API ('name' -> 'aes_name') */ -# define aes_xi(x) aes_ ## x -#endif - -#ifdef USE_VIA_ACE_IF_PRESENT -# include "aes_via_ace.h" -#endif - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/* Initialise the key schedule from the user supplied key. The key - length can be specified in bytes, with legal values of 16, 24 - and 32, or in bits, with legal values of 128, 192 and 256. These - values correspond with Nk values of 4, 6 and 8 respectively. - - The following macros implement a single cycle in the key - schedule generation process. The number of cycles needed - for each cx->n_col and nk value is: - - nk = 4 5 6 7 8 - ------------------------------ - cx->n_col = 4 10 9 8 7 7 - cx->n_col = 5 14 11 10 9 9 - cx->n_col = 6 19 15 12 11 11 - cx->n_col = 7 21 19 16 13 14 - cx->n_col = 8 29 23 19 17 14 -*/ - -#if defined( REDUCE_CODE_SIZE ) -# define ls_box ls_sub - uint32_t ls_sub(const uint32_t t, const uint32_t n); -# define inv_mcol im_sub - uint32_t im_sub(const uint32_t x); -# ifdef ENC_KS_UNROLL -# undef ENC_KS_UNROLL -# endif -# ifdef DEC_KS_UNROLL -# undef DEC_KS_UNROLL -# endif -#endif - -#if (FUNCS_IN_C & ENC_KEYING_IN_C) - -#if defined(AES_128) || defined( AES_VAR ) - -#define ke4(k,i) \ -{ k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; \ - k[4*(i)+5] = ss[1] ^= ss[0]; \ - k[4*(i)+6] = ss[2] ^= ss[1]; \ - k[4*(i)+7] = ss[3] ^= ss[2]; \ -} - -AES_RETURN aes_xi(encrypt_key128)(const unsigned char *key, aes_encrypt_ctx cx[1]) -{ uint32_t ss[4] = {0}; - - cx->ks[0] = ss[0] = word_in(key, 0); - cx->ks[1] = ss[1] = word_in(key, 1); - cx->ks[2] = ss[2] = word_in(key, 2); - cx->ks[3] = ss[3] = word_in(key, 3); - -#ifdef ENC_KS_UNROLL - ke4(cx->ks, 0); ke4(cx->ks, 1); - ke4(cx->ks, 2); ke4(cx->ks, 3); - ke4(cx->ks, 4); ke4(cx->ks, 5); - ke4(cx->ks, 6); ke4(cx->ks, 7); - ke4(cx->ks, 8); -#else - { uint32_t i = 0; - for(i = 0; i < 9; ++i) - ke4(cx->ks, i); - } -#endif - ke4(cx->ks, 9); - cx->inf.l = 0; - cx->inf.b[0] = 10 * AES_BLOCK_SIZE; - -#ifdef USE_VIA_ACE_IF_PRESENT - if(VIA_ACE_AVAILABLE) - cx->inf.b[1] = 0xff; -#endif - return EXIT_SUCCESS; -} - -#endif - -#if defined(AES_192) || defined( AES_VAR ) - -#define kef6(k,i) \ -{ k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; \ - k[6*(i)+ 7] = ss[1] ^= ss[0]; \ - k[6*(i)+ 8] = ss[2] ^= ss[1]; \ - k[6*(i)+ 9] = ss[3] ^= ss[2]; \ -} - -#define ke6(k,i) \ -{ kef6(k,i); \ - k[6*(i)+10] = ss[4] ^= ss[3]; \ - k[6*(i)+11] = ss[5] ^= ss[4]; \ -} - -AES_RETURN aes_xi(encrypt_key192)(const unsigned char *key, aes_encrypt_ctx cx[1]) -{ uint32_t ss[6] = {0}; - - cx->ks[0] = ss[0] = word_in(key, 0); - cx->ks[1] = ss[1] = word_in(key, 1); - cx->ks[2] = ss[2] = word_in(key, 2); - cx->ks[3] = ss[3] = word_in(key, 3); - cx->ks[4] = ss[4] = word_in(key, 4); - cx->ks[5] = ss[5] = word_in(key, 5); - -#ifdef ENC_KS_UNROLL - ke6(cx->ks, 0); ke6(cx->ks, 1); - ke6(cx->ks, 2); ke6(cx->ks, 3); - ke6(cx->ks, 4); ke6(cx->ks, 5); - ke6(cx->ks, 6); -#else - { uint32_t i = 0; - for(i = 0; i < 7; ++i) - ke6(cx->ks, i); - } -#endif - kef6(cx->ks, 7); - cx->inf.l = 0; - cx->inf.b[0] = 12 * AES_BLOCK_SIZE; - -#ifdef USE_VIA_ACE_IF_PRESENT - if(VIA_ACE_AVAILABLE) - cx->inf.b[1] = 0xff; -#endif - return EXIT_SUCCESS; -} - -#endif - -#if defined(AES_256) || defined( AES_VAR ) - -#define kef8(k,i) \ -{ k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; \ - k[8*(i)+ 9] = ss[1] ^= ss[0]; \ - k[8*(i)+10] = ss[2] ^= ss[1]; \ - k[8*(i)+11] = ss[3] ^= ss[2]; \ -} - -#define ke8(k,i) \ -{ kef8(k,i); \ - k[8*(i)+12] = ss[4] ^= ls_box(ss[3],0); \ - k[8*(i)+13] = ss[5] ^= ss[4]; \ - k[8*(i)+14] = ss[6] ^= ss[5]; \ - k[8*(i)+15] = ss[7] ^= ss[6]; \ -} - -AES_RETURN aes_xi(encrypt_key256)(const unsigned char *key, aes_encrypt_ctx cx[1]) -{ uint32_t ss[8] = {0}; - - cx->ks[0] = ss[0] = word_in(key, 0); - cx->ks[1] = ss[1] = word_in(key, 1); - cx->ks[2] = ss[2] = word_in(key, 2); - cx->ks[3] = ss[3] = word_in(key, 3); - cx->ks[4] = ss[4] = word_in(key, 4); - cx->ks[5] = ss[5] = word_in(key, 5); - cx->ks[6] = ss[6] = word_in(key, 6); - cx->ks[7] = ss[7] = word_in(key, 7); - -#ifdef ENC_KS_UNROLL - ke8(cx->ks, 0); ke8(cx->ks, 1); - ke8(cx->ks, 2); ke8(cx->ks, 3); - ke8(cx->ks, 4); ke8(cx->ks, 5); -#else - { uint32_t i = 0; - for(i = 0; i < 6; ++i) - ke8(cx->ks, i); - } -#endif - kef8(cx->ks, 6); - cx->inf.l = 0; - cx->inf.b[0] = 14 * AES_BLOCK_SIZE; - -#ifdef USE_VIA_ACE_IF_PRESENT - if(VIA_ACE_AVAILABLE) - cx->inf.b[1] = 0xff; -#endif - return EXIT_SUCCESS; -} - -#endif - -#endif - -#if (FUNCS_IN_C & DEC_KEYING_IN_C) - -/* this is used to store the decryption round keys */ -/* in forward or reverse order */ - -#ifdef AES_REV_DKS -#define v(n,i) ((n) - (i) + 2 * ((i) & 3)) -#else -#define v(n,i) (i) -#endif - -#if DEC_ROUND == NO_TABLES -#define ff(x) (x) -#else -#define ff(x) inv_mcol(x) -#if defined( dec_imvars ) -#define d_vars dec_imvars -#endif -#endif - -#if defined(AES_128) || defined( AES_VAR ) - -#define k4e(k,i) \ -{ k[v(40,(4*(i))+4)] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; \ - k[v(40,(4*(i))+5)] = ss[1] ^= ss[0]; \ - k[v(40,(4*(i))+6)] = ss[2] ^= ss[1]; \ - k[v(40,(4*(i))+7)] = ss[3] ^= ss[2]; \ -} - -#if 1 - -#define kdf4(k,i) \ -{ ss[0] = ss[0] ^ ss[2] ^ ss[1] ^ ss[3]; \ - ss[1] = ss[1] ^ ss[3]; \ - ss[2] = ss[2] ^ ss[3]; \ - ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; \ - ss[i % 4] ^= ss[4]; \ - ss[4] ^= k[v(40,(4*(i)))]; k[v(40,(4*(i))+4)] = ff(ss[4]); \ - ss[4] ^= k[v(40,(4*(i))+1)]; k[v(40,(4*(i))+5)] = ff(ss[4]); \ - ss[4] ^= k[v(40,(4*(i))+2)]; k[v(40,(4*(i))+6)] = ff(ss[4]); \ - ss[4] ^= k[v(40,(4*(i))+3)]; k[v(40,(4*(i))+7)] = ff(ss[4]); \ -} - -#define kd4(k,i) \ -{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; \ - ss[i % 4] ^= ss[4]; ss[4] = ff(ss[4]); \ - k[v(40,(4*(i))+4)] = ss[4] ^= k[v(40,(4*(i)))]; \ - k[v(40,(4*(i))+5)] = ss[4] ^= k[v(40,(4*(i))+1)]; \ - k[v(40,(4*(i))+6)] = ss[4] ^= k[v(40,(4*(i))+2)]; \ - k[v(40,(4*(i))+7)] = ss[4] ^= k[v(40,(4*(i))+3)]; \ -} - -#define kdl4(k,i) \ -{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; ss[i % 4] ^= ss[4]; \ - k[v(40,(4*(i))+4)] = (ss[0] ^= ss[1]) ^ ss[2] ^ ss[3]; \ - k[v(40,(4*(i))+5)] = ss[1] ^ ss[3]; \ - k[v(40,(4*(i))+6)] = ss[0]; \ - k[v(40,(4*(i))+7)] = ss[1]; \ -} - -#else - -#define kdf4(k,i) \ -{ ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[v(40,(4*(i))+ 4)] = ff(ss[0]); \ - ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ff(ss[1]); \ - ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ff(ss[2]); \ - ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ff(ss[3]); \ -} - -#define kd4(k,i) \ -{ ss[4] = ls_box(ss[3],3) ^ t_use(r,c)[i]; \ - ss[0] ^= ss[4]; ss[4] = ff(ss[4]); k[v(40,(4*(i))+ 4)] = ss[4] ^= k[v(40,(4*(i)))]; \ - ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ss[4] ^= k[v(40,(4*(i))+ 1)]; \ - ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ss[4] ^= k[v(40,(4*(i))+ 2)]; \ - ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ss[4] ^= k[v(40,(4*(i))+ 3)]; \ -} - -#define kdl4(k,i) \ -{ ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[v(40,(4*(i))+ 4)] = ss[0]; \ - ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ss[1]; \ - ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ss[2]; \ - ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ss[3]; \ -} - -#endif - -AES_RETURN aes_xi(decrypt_key128)(const unsigned char *key, aes_decrypt_ctx cx[1]) -{ uint32_t ss[5] = {0}; -#if defined( d_vars ) - d_vars; -#endif - - cx->ks[v(40,(0))] = ss[0] = word_in(key, 0); - cx->ks[v(40,(1))] = ss[1] = word_in(key, 1); - cx->ks[v(40,(2))] = ss[2] = word_in(key, 2); - cx->ks[v(40,(3))] = ss[3] = word_in(key, 3); - -#ifdef DEC_KS_UNROLL - kdf4(cx->ks, 0); kd4(cx->ks, 1); - kd4(cx->ks, 2); kd4(cx->ks, 3); - kd4(cx->ks, 4); kd4(cx->ks, 5); - kd4(cx->ks, 6); kd4(cx->ks, 7); - kd4(cx->ks, 8); kdl4(cx->ks, 9); -#else - { uint32_t i = 0; - for(i = 0; i < 10; ++i) - k4e(cx->ks, i); -#if !(DEC_ROUND == NO_TABLES) - for(i = N_COLS; i < 10 * N_COLS; ++i) - cx->ks[i] = inv_mcol(cx->ks[i]); -#endif - } -#endif - cx->inf.l = 0; - cx->inf.b[0] = 10 * AES_BLOCK_SIZE; - -#ifdef USE_VIA_ACE_IF_PRESENT - if(VIA_ACE_AVAILABLE) - cx->inf.b[1] = 0xff; -#endif - return EXIT_SUCCESS; -} - -#endif - -#if defined(AES_192) || defined( AES_VAR ) - -#define k6ef(k,i) \ -{ k[v(48,(6*(i))+ 6)] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; \ - k[v(48,(6*(i))+ 7)] = ss[1] ^= ss[0]; \ - k[v(48,(6*(i))+ 8)] = ss[2] ^= ss[1]; \ - k[v(48,(6*(i))+ 9)] = ss[3] ^= ss[2]; \ -} - -#define k6e(k,i) \ -{ k6ef(k,i); \ - k[v(48,(6*(i))+10)] = ss[4] ^= ss[3]; \ - k[v(48,(6*(i))+11)] = ss[5] ^= ss[4]; \ -} - -#define kdf6(k,i) \ -{ ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[v(48,(6*(i))+ 6)] = ff(ss[0]); \ - ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ff(ss[1]); \ - ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ff(ss[2]); \ - ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ff(ss[3]); \ - ss[4] ^= ss[3]; k[v(48,(6*(i))+10)] = ff(ss[4]); \ - ss[5] ^= ss[4]; k[v(48,(6*(i))+11)] = ff(ss[5]); \ -} - -#define kd6(k,i) \ -{ ss[6] = ls_box(ss[5],3) ^ t_use(r,c)[i]; \ - ss[0] ^= ss[6]; ss[6] = ff(ss[6]); k[v(48,(6*(i))+ 6)] = ss[6] ^= k[v(48,(6*(i)))]; \ - ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ss[6] ^= k[v(48,(6*(i))+ 1)]; \ - ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ss[6] ^= k[v(48,(6*(i))+ 2)]; \ - ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ss[6] ^= k[v(48,(6*(i))+ 3)]; \ - ss[4] ^= ss[3]; k[v(48,(6*(i))+10)] = ss[6] ^= k[v(48,(6*(i))+ 4)]; \ - ss[5] ^= ss[4]; k[v(48,(6*(i))+11)] = ss[6] ^= k[v(48,(6*(i))+ 5)]; \ -} - -#define kdl6(k,i) \ -{ ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[v(48,(6*(i))+ 6)] = ss[0]; \ - ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ss[1]; \ - ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ss[2]; \ - ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ss[3]; \ -} - -AES_RETURN aes_xi(decrypt_key192)(const unsigned char *key, aes_decrypt_ctx cx[1]) -{ uint32_t ss[7] = {0}; -#if defined( d_vars ) - d_vars; -#endif - - cx->ks[v(48,(0))] = ss[0] = word_in(key, 0); - cx->ks[v(48,(1))] = ss[1] = word_in(key, 1); - cx->ks[v(48,(2))] = ss[2] = word_in(key, 2); - cx->ks[v(48,(3))] = ss[3] = word_in(key, 3); - -#ifdef DEC_KS_UNROLL - ss[4] = word_in(key, 4); - ss[5] = word_in(key, 5); - cx->ks[v(48,(4))] = ff(ss[4]); - cx->ks[v(48,(5))] = ff(ss[5]); - kdf6(cx->ks, 0); kd6(cx->ks, 1); - kd6(cx->ks, 2); kd6(cx->ks, 3); - kd6(cx->ks, 4); kd6(cx->ks, 5); - kd6(cx->ks, 6); kdl6(cx->ks, 7); -#else - cx->ks[v(48,(4))] = ss[4] = word_in(key, 4); - cx->ks[v(48,(5))] = ss[5] = word_in(key, 5); - { uint32_t i = 0; - - for(i = 0; i < 7; ++i) - k6e(cx->ks, i); - k6ef(cx->ks, 7); -#if !(DEC_ROUND == NO_TABLES) - for(i = N_COLS; i < 12 * N_COLS; ++i) - cx->ks[i] = inv_mcol(cx->ks[i]); -#endif - } -#endif - cx->inf.l = 0; - cx->inf.b[0] = 12 * AES_BLOCK_SIZE; - -#ifdef USE_VIA_ACE_IF_PRESENT - if(VIA_ACE_AVAILABLE) - cx->inf.b[1] = 0xff; -#endif - return EXIT_SUCCESS; -} - -#endif - -#if defined(AES_256) || defined( AES_VAR ) - -#define k8ef(k,i) \ -{ k[v(56,(8*(i))+ 8)] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; \ - k[v(56,(8*(i))+ 9)] = ss[1] ^= ss[0]; \ - k[v(56,(8*(i))+10)] = ss[2] ^= ss[1]; \ - k[v(56,(8*(i))+11)] = ss[3] ^= ss[2]; \ -} - -#define k8e(k,i) \ -{ k8ef(k,i); \ - k[v(56,(8*(i))+12)] = ss[4] ^= ls_box(ss[3],0); \ - k[v(56,(8*(i))+13)] = ss[5] ^= ss[4]; \ - k[v(56,(8*(i))+14)] = ss[6] ^= ss[5]; \ - k[v(56,(8*(i))+15)] = ss[7] ^= ss[6]; \ -} - -#define kdf8(k,i) \ -{ ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[v(56,(8*(i))+ 8)] = ff(ss[0]); \ - ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ff(ss[1]); \ - ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ff(ss[2]); \ - ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ff(ss[3]); \ - ss[4] ^= ls_box(ss[3],0); k[v(56,(8*(i))+12)] = ff(ss[4]); \ - ss[5] ^= ss[4]; k[v(56,(8*(i))+13)] = ff(ss[5]); \ - ss[6] ^= ss[5]; k[v(56,(8*(i))+14)] = ff(ss[6]); \ - ss[7] ^= ss[6]; k[v(56,(8*(i))+15)] = ff(ss[7]); \ -} - -#define kd8(k,i) \ -{ ss[8] = ls_box(ss[7],3) ^ t_use(r,c)[i]; \ - ss[0] ^= ss[8]; ss[8] = ff(ss[8]); k[v(56,(8*(i))+ 8)] = ss[8] ^= k[v(56,(8*(i)))]; \ - ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ss[8] ^= k[v(56,(8*(i))+ 1)]; \ - ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ss[8] ^= k[v(56,(8*(i))+ 2)]; \ - ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[8] ^= k[v(56,(8*(i))+ 3)]; \ - ss[8] = ls_box(ss[3],0); \ - ss[4] ^= ss[8]; ss[8] = ff(ss[8]); k[v(56,(8*(i))+12)] = ss[8] ^= k[v(56,(8*(i))+ 4)]; \ - ss[5] ^= ss[4]; k[v(56,(8*(i))+13)] = ss[8] ^= k[v(56,(8*(i))+ 5)]; \ - ss[6] ^= ss[5]; k[v(56,(8*(i))+14)] = ss[8] ^= k[v(56,(8*(i))+ 6)]; \ - ss[7] ^= ss[6]; k[v(56,(8*(i))+15)] = ss[8] ^= k[v(56,(8*(i))+ 7)]; \ -} - -#define kdl8(k,i) \ -{ ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[v(56,(8*(i))+ 8)] = ss[0]; \ - ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ss[1]; \ - ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ss[2]; \ - ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[3]; \ -} - -AES_RETURN aes_xi(decrypt_key256)(const unsigned char *key, aes_decrypt_ctx cx[1]) -{ uint32_t ss[9] = {0}; -#if defined( d_vars ) - d_vars; -#endif - - cx->ks[v(56,(0))] = ss[0] = word_in(key, 0); - cx->ks[v(56,(1))] = ss[1] = word_in(key, 1); - cx->ks[v(56,(2))] = ss[2] = word_in(key, 2); - cx->ks[v(56,(3))] = ss[3] = word_in(key, 3); - -#ifdef DEC_KS_UNROLL - ss[4] = word_in(key, 4); - ss[5] = word_in(key, 5); - ss[6] = word_in(key, 6); - ss[7] = word_in(key, 7); - cx->ks[v(56,(4))] = ff(ss[4]); - cx->ks[v(56,(5))] = ff(ss[5]); - cx->ks[v(56,(6))] = ff(ss[6]); - cx->ks[v(56,(7))] = ff(ss[7]); - kdf8(cx->ks, 0); kd8(cx->ks, 1); - kd8(cx->ks, 2); kd8(cx->ks, 3); - kd8(cx->ks, 4); kd8(cx->ks, 5); - kdl8(cx->ks, 6); -#else - cx->ks[v(56,(4))] = ss[4] = word_in(key, 4); - cx->ks[v(56,(5))] = ss[5] = word_in(key, 5); - cx->ks[v(56,(6))] = ss[6] = word_in(key, 6); - cx->ks[v(56,(7))] = ss[7] = word_in(key, 7); - { uint32_t i = 0; - - for(i = 0; i < 6; ++i) - k8e(cx->ks, i); - k8ef(cx->ks, 6); -#if !(DEC_ROUND == NO_TABLES) - for(i = N_COLS; i < 14 * N_COLS; ++i) - cx->ks[i] = inv_mcol(cx->ks[i]); -#endif - } -#endif - cx->inf.l = 0; - cx->inf.b[0] = 14 * AES_BLOCK_SIZE; - -#ifdef USE_VIA_ACE_IF_PRESENT - if(VIA_ACE_AVAILABLE) - cx->inf.b[1] = 0xff; -#endif - return EXIT_SUCCESS; -} - -#endif - -#endif - -#if defined( AES_VAR ) - -AES_RETURN aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1]) -{ - switch(key_len) - { - case 16: case 128: return aes_encrypt_key128(key, cx); - case 24: case 192: return aes_encrypt_key192(key, cx); - case 32: case 256: return aes_encrypt_key256(key, cx); - default: return EXIT_FAILURE; - } -} - -AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1]) -{ - switch(key_len) - { - case 16: case 128: return aes_decrypt_key128(key, cx); - case 24: case 192: return aes_decrypt_key192(key, cx); - case 32: case 256: return aes_decrypt_key256(key, cx); - default: return EXIT_FAILURE; - } -} - -#endif - -#if defined(__cplusplus) -} -#endif diff --git a/deps/crypto/trezor-crypto/aes/aesopt.h b/deps/crypto/trezor-crypto/aes/aesopt.h deleted file mode 100644 index d8dca1b3b..000000000 --- a/deps/crypto/trezor-crypto/aes/aesopt.h +++ /dev/null @@ -1,789 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. - -The redistribution and use of this software (with or without changes) -is allowed without the payment of fees or royalties provided that: - - source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation. - -This software is provided 'as is' with no explicit or implied warranties -in respect of its operation, including, but not limited to, correctness -and fitness for purpose. ---------------------------------------------------------------------------- -Issue Date: 20/12/2007 - - This file contains the compilation options for AES (Rijndael) and code - that is common across encryption, key scheduling and table generation. - - OPERATION - - These source code files implement the AES algorithm Rijndael designed by - Joan Daemen and Vincent Rijmen. This version is designed for the standard - block size of 16 bytes and for key sizes of 128, 192 and 256 bits (16, 24 - and 32 bytes). - - This version is designed for flexibility and speed using operations on - 32-bit words rather than operations on bytes. It can be compiled with - either big or little endian internal byte order but is faster when the - native byte order for the processor is used. - - THE CIPHER INTERFACE - - The cipher interface is implemented as an array of bytes in which lower - AES bit sequence indexes map to higher numeric significance within bytes. - - uint8_t (an unsigned 8-bit type) - uint32_t (an unsigned 32-bit type) - struct aes_encrypt_ctx (structure for the cipher encryption context) - struct aes_decrypt_ctx (structure for the cipher decryption context) - AES_RETURN the function return type - - C subroutine calls: - - AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]); - AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]); - AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]); - AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, - const aes_encrypt_ctx cx[1]); - - AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]); - AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]); - AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]); - AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, - const aes_decrypt_ctx cx[1]); - - IMPORTANT NOTE: If you are using this C interface with dynamic tables make sure that - you call aes_init() before AES is used so that the tables are initialised. - - C++ aes class subroutines: - - Class AESencrypt for encryption - - Constructors: - AESencrypt(void) - AESencrypt(const unsigned char *key) - 128 bit key - Members: - AES_RETURN key128(const unsigned char *key) - AES_RETURN key192(const unsigned char *key) - AES_RETURN key256(const unsigned char *key) - AES_RETURN encrypt(const unsigned char *in, unsigned char *out) const - - Class AESdecrypt for encryption - Constructors: - AESdecrypt(void) - AESdecrypt(const unsigned char *key) - 128 bit key - Members: - AES_RETURN key128(const unsigned char *key) - AES_RETURN key192(const unsigned char *key) - AES_RETURN key256(const unsigned char *key) - AES_RETURN decrypt(const unsigned char *in, unsigned char *out) const -*/ - -#if !defined( _AESOPT_H ) -#define _AESOPT_H - -#if defined( __cplusplus ) -#include "aescpp.h" -#else -#include "aes.h" -#endif - -/* PLATFORM SPECIFIC INCLUDES */ - -#define IS_BIG_ENDIAN 4321 -#define IS_LITTLE_ENDIAN 1234 -#define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN - -/* CONFIGURATION - THE USE OF DEFINES - - Later in this section there are a number of defines that control the - operation of the code. In each section, the purpose of each define is - explained so that the relevant form can be included or excluded by - setting either 1's or 0's respectively on the branches of the related - #if clauses. The following local defines should not be changed. -*/ - -#define ENCRYPTION_IN_C 1 -#define DECRYPTION_IN_C 2 -#define ENC_KEYING_IN_C 4 -#define DEC_KEYING_IN_C 8 - -#define NO_TABLES 0 -#define ONE_TABLE 1 -#define FOUR_TABLES 4 -#define NONE 0 -#define PARTIAL 1 -#define FULL 2 - -/* --- START OF USER CONFIGURED OPTIONS --- */ - -/* 1. BYTE ORDER WITHIN 32 BIT WORDS - - The fundamental data processing units in Rijndael are 8-bit bytes. The - input, output and key input are all enumerated arrays of bytes in which - bytes are numbered starting at zero and increasing to one less than the - number of bytes in the array in question. This enumeration is only used - for naming bytes and does not imply any adjacency or order relationship - from one byte to another. When these inputs and outputs are considered - as bit sequences, bits 8*n to 8*n+7 of the bit sequence are mapped to - byte[n] with bit 8n+i in the sequence mapped to bit 7-i within the byte. - In this implementation bits are numbered from 0 to 7 starting at the - numerically least significant end of each byte (bit n represents 2^n). - - However, Rijndael can be implemented more efficiently using 32-bit - words by packing bytes into words so that bytes 4*n to 4*n+3 are placed - into word[n]. While in principle these bytes can be assembled into words - in any positions, this implementation only supports the two formats in - which bytes in adjacent positions within words also have adjacent byte - numbers. This order is called big-endian if the lowest numbered bytes - in words have the highest numeric significance and little-endian if the - opposite applies. - - This code can work in either order irrespective of the order used by the - machine on which it runs. Normally the internal byte order will be set - to the order of the processor on which the code is to be run but this - define can be used to reverse this in special situations - - WARNING: Assembler code versions rely on PLATFORM_BYTE_ORDER being set. - This define will hence be redefined later (in section 4) if necessary -*/ - -#if 1 -# define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER -#elif 0 -# define ALGORITHM_BYTE_ORDER IS_LITTLE_ENDIAN -#elif 0 -# define ALGORITHM_BYTE_ORDER IS_BIG_ENDIAN -#else -# error The algorithm byte order is not defined -#endif - -/* 2. Intel AES AND VIA ACE SUPPORT */ - -#if defined( __GNUC__ ) && defined( __i386__ ) && !defined(__BEOS__) \ - || defined( _WIN32 ) && defined( _M_IX86 ) && !(defined( _WIN64 ) \ - || defined( _WIN32_WCE ) || defined( _MSC_VER ) && ( _MSC_VER <= 800 )) -# define VIA_ACE_POSSIBLE -#endif - -/* AESNI is supported by all Windows x64 compilers, but for Linux/GCC - we have to test for SSE 2, SSE 3, and AES to before enabling it; */ -#if !defined( INTEL_AES_POSSIBLE ) -# if defined( _WIN64 ) && defined( _MSC_VER ) \ - || defined( __GNUC__ ) && defined( __x86_64__ ) && \ - defined( __SSE2__ ) && defined( __SSE3__ ) && \ - defined( __AES__ ) -# define INTEL_AES_POSSIBLE -# endif -#endif - -/* Define this option if support for the Intel AESNI is required - If USE_INTEL_AES_IF_PRESENT is defined then AESNI will be used - if it is detected (both present and enabled). - - AESNI uses a decryption key schedule with the first decryption - round key at the high end of the key scedule with the following - round keys at lower positions in memory. So AES_REV_DKS must NOT - be defined when AESNI will be used. Although it is unlikely that - assembler code will be used with an AESNI build, if it is then - AES_REV_DKS must NOT be defined when the assembler files are - built (the definition of USE_INTEL_AES_IF_PRESENT in the assembler - code files must match that here if they are used). -*/ - -#if 0 && defined( INTEL_AES_POSSIBLE ) && !defined( USE_INTEL_AES_IF_PRESENT ) -# define USE_INTEL_AES_IF_PRESENT -#endif - -/* Define this option if support for the VIA ACE is required. This uses - inline assembler instructions and is only implemented for the Microsoft, - Intel and GCC compilers. If VIA ACE is known to be present, then defining - ASSUME_VIA_ACE_PRESENT will remove the ordinary encryption/decryption - code. If USE_VIA_ACE_IF_PRESENT is defined then VIA ACE will be used if - it is detected (both present and enabled) but the normal AES code will - also be present. - - When VIA ACE is to be used, all AES encryption contexts MUST be 16 byte - aligned; other input/output buffers do not need to be 16 byte aligned - but there are very large performance gains if this can be arranged. - VIA ACE also requires the decryption key schedule to be in reverse - order (which later checks below ensure). - - AES_REV_DKS must be set for assembler code used with a VIA ACE build -*/ - -#if 0 && defined( VIA_ACE_POSSIBLE ) && !defined( USE_VIA_ACE_IF_PRESENT ) -# define USE_VIA_ACE_IF_PRESENT -#endif - -#if 0 && defined( VIA_ACE_POSSIBLE ) && !defined( ASSUME_VIA_ACE_PRESENT ) -# define ASSUME_VIA_ACE_PRESENT -# endif - -/* 3. ASSEMBLER SUPPORT - - This define (which can be on the command line) enables the use of the - assembler code routines for encryption, decryption and key scheduling - as follows: - - ASM_X86_V1C uses the assembler (aes_x86_v1.asm) with large tables for - encryption and decryption and but with key scheduling in C - ASM_X86_V2 uses assembler (aes_x86_v2.asm) with compressed tables for - encryption, decryption and key scheduling - ASM_X86_V2C uses assembler (aes_x86_v2.asm) with compressed tables for - encryption and decryption and but with key scheduling in C - ASM_AMD64_C uses assembler (aes_amd64.asm) with compressed tables for - encryption and decryption and but with key scheduling in C - - Change one 'if 0' below to 'if 1' to select the version or define - as a compilation option. -*/ - -#if 0 && !defined( ASM_X86_V1C ) -# define ASM_X86_V1C -#elif 0 && !defined( ASM_X86_V2 ) -# define ASM_X86_V2 -#elif 0 && !defined( ASM_X86_V2C ) -# define ASM_X86_V2C -#elif 0 && !defined( ASM_AMD64_C ) -# define ASM_AMD64_C -#endif - -#if defined( __i386 ) || defined( _M_IX86 ) -# define A32_ -#elif defined( __x86_64__ ) || defined( _M_X64 ) -# define A64_ -#endif - -#if (defined ( ASM_X86_V1C ) || defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )) \ - && !defined( A32_ ) || defined( ASM_AMD64_C ) && !defined( A64_ ) -# error Assembler code is only available for x86 and AMD64 systems -#endif - -/* 4. FAST INPUT/OUTPUT OPERATIONS. - - On some machines it is possible to improve speed by transferring the - bytes in the input and output arrays to and from the internal 32-bit - variables by addressing these arrays as if they are arrays of 32-bit - words. On some machines this will always be possible but there may - be a large performance penalty if the byte arrays are not aligned on - the normal word boundaries. On other machines this technique will - lead to memory access errors when such 32-bit word accesses are not - properly aligned. The option SAFE_IO avoids such problems but will - often be slower on those machines that support misaligned access - (especially so if care is taken to align the input and output byte - arrays on 32-bit word boundaries). If SAFE_IO is not defined it is - assumed that access to byte arrays as if they are arrays of 32-bit - words will not cause problems when such accesses are misaligned. -*/ -#if 1 && !defined( _MSC_VER ) -# define SAFE_IO -#endif - -/* 5. LOOP UNROLLING - - The code for encryption and decrytpion cycles through a number of rounds - that can be implemented either in a loop or by expanding the code into a - long sequence of instructions, the latter producing a larger program but - one that will often be much faster. The latter is called loop unrolling. - There are also potential speed advantages in expanding two iterations in - a loop with half the number of iterations, which is called partial loop - unrolling. The following options allow partial or full loop unrolling - to be set independently for encryption and decryption -*/ -#if 1 -# define ENC_UNROLL FULL -#elif 0 -# define ENC_UNROLL PARTIAL -#else -# define ENC_UNROLL NONE -#endif - -#if 1 -# define DEC_UNROLL FULL -#elif 0 -# define DEC_UNROLL PARTIAL -#else -# define DEC_UNROLL NONE -#endif - -#if 1 -# define ENC_KS_UNROLL -#endif - -#if 1 -# define DEC_KS_UNROLL -#endif - -/* 6. FAST FINITE FIELD OPERATIONS - - If this section is included, tables are used to provide faster finite - field arithmetic (this has no effect if STATIC_TABLES is defined). -*/ -#if 1 -# define FF_TABLES -#endif - -/* 7. INTERNAL STATE VARIABLE FORMAT - - The internal state of Rijndael is stored in a number of local 32-bit - word varaibles which can be defined either as an array or as individual - names variables. Include this section if you want to store these local - varaibles in arrays. Otherwise individual local variables will be used. -*/ -#if 1 -# define ARRAYS -#endif - -/* 8. FIXED OR DYNAMIC TABLES - - When this section is included the tables used by the code are compiled - statically into the binary file. Otherwise the subroutine aes_init() - must be called to compute them before the code is first used. -*/ -#if 1 && !(defined( _MSC_VER ) && ( _MSC_VER <= 800 )) -# define STATIC_TABLES -#endif - -/* 9. MASKING OR CASTING FROM LONGER VALUES TO BYTES - - In some systems it is better to mask longer values to extract bytes - rather than using a cast. This option allows this choice. -*/ -#if 0 -# define to_byte(x) ((uint8_t)(x)) -#else -# define to_byte(x) ((x) & 0xff) -#endif - -/* 10. TABLE ALIGNMENT - - On some sytsems speed will be improved by aligning the AES large lookup - tables on particular boundaries. This define should be set to a power of - two giving the desired alignment. It can be left undefined if alignment - is not needed. This option is specific to the Microsft VC++ compiler - - it seems to sometimes cause trouble for the VC++ version 6 compiler. -*/ - -#if 1 && defined( _MSC_VER ) && ( _MSC_VER >= 1300 ) -# define TABLE_ALIGN 32 -#endif - -/* 11. REDUCE CODE AND TABLE SIZE - - This replaces some expanded macros with function calls if AES_ASM_V2 or - AES_ASM_V2C are defined -*/ - -#if 1 && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )) -# define REDUCE_CODE_SIZE -#endif - -/* 12. TABLE OPTIONS - - This cipher proceeds by repeating in a number of cycles known as 'rounds' - which are implemented by a round function which can optionally be speeded - up using tables. The basic tables are each 256 32-bit words, with either - one or four tables being required for each round function depending on - how much speed is required. The encryption and decryption round functions - are different and the last encryption and decrytpion round functions are - different again making four different round functions in all. - - This means that: - 1. Normal encryption and decryption rounds can each use either 0, 1 - or 4 tables and table spaces of 0, 1024 or 4096 bytes each. - 2. The last encryption and decryption rounds can also use either 0, 1 - or 4 tables and table spaces of 0, 1024 or 4096 bytes each. - - Include or exclude the appropriate definitions below to set the number - of tables used by this implementation. - - Defining AES_SMALL_TABLES selects ONE_TABLE for every round function, - shrinking the five lookup tables from 4096 to 1024 bytes each (15,360 - bytes of flash reclaimed) at a modest cycle cost per round. Intended - for ROM-constrained firmware variants; the default remains FOUR_TABLES. -*/ - -#if defined( AES_SMALL_TABLES ) /* set tables for the normal encryption round */ -# define ENC_ROUND ONE_TABLE -#elif 1 -# define ENC_ROUND FOUR_TABLES -#else -# define ENC_ROUND NO_TABLES -#endif - -#if defined( AES_SMALL_TABLES ) /* set tables for the last encryption round */ -# define LAST_ENC_ROUND ONE_TABLE -#elif 1 -# define LAST_ENC_ROUND FOUR_TABLES -#else -# define LAST_ENC_ROUND NO_TABLES -#endif - -#if defined( AES_SMALL_TABLES ) /* set tables for the normal decryption round */ -# define DEC_ROUND ONE_TABLE -#elif 1 -# define DEC_ROUND FOUR_TABLES -#else -# define DEC_ROUND NO_TABLES -#endif - -#if defined( AES_SMALL_TABLES ) /* set tables for the last decryption round */ -# define LAST_DEC_ROUND ONE_TABLE -#elif 1 -# define LAST_DEC_ROUND FOUR_TABLES -#else -# define LAST_DEC_ROUND NO_TABLES -#endif - -/* The decryption key schedule can be speeded up with tables in the same - way that the round functions can. Include or exclude the following - defines to set this requirement. -*/ -#if defined( AES_SMALL_TABLES ) -# define KEY_SCHED ONE_TABLE -#elif 1 -# define KEY_SCHED FOUR_TABLES -#else -# define KEY_SCHED NO_TABLES -#endif - -/* ---- END OF USER CONFIGURED OPTIONS ---- */ - -/* VIA ACE support is only available for VC++ and GCC */ - -#if !defined( _MSC_VER ) && !defined( __GNUC__ ) -# if defined( ASSUME_VIA_ACE_PRESENT ) -# undef ASSUME_VIA_ACE_PRESENT -# endif -# if defined( USE_VIA_ACE_IF_PRESENT ) -# undef USE_VIA_ACE_IF_PRESENT -# endif -#endif - -#if defined( ASSUME_VIA_ACE_PRESENT ) && !defined( USE_VIA_ACE_IF_PRESENT ) -# define USE_VIA_ACE_IF_PRESENT -#endif - -/* define to reverse decryption key schedule */ -#if 1 || defined( USE_VIA_ACE_IF_PRESENT ) && !defined ( AES_REV_DKS ) -# define AES_REV_DKS -#endif - -/* Intel AESNI uses a decryption key schedule in the encryption order */ -#if defined( USE_INTEL_AES_IF_PRESENT ) && defined ( AES_REV_DKS ) -# undef AES_REV_DKS -#endif - -/* Assembler support requires the use of platform byte order */ - -#if ( defined( ASM_X86_V1C ) || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) ) \ - && (ALGORITHM_BYTE_ORDER != PLATFORM_BYTE_ORDER) -# undef ALGORITHM_BYTE_ORDER -# define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER -#endif - -/* In this implementation the columns of the state array are each held in - 32-bit words. The state array can be held in various ways: in an array - of words, in a number of individual word variables or in a number of - processor registers. The following define maps a variable name x and - a column number c to the way the state array variable is to be held. - The first define below maps the state into an array x[c] whereas the - second form maps the state into a number of individual variables x0, - x1, etc. Another form could map individual state colums to machine - register names. -*/ - -#if defined( ARRAYS ) -# define s(x,c) x[c] -#else -# define s(x,c) x##c -#endif - -/* This implementation provides subroutines for encryption, decryption - and for setting the three key lengths (separately) for encryption - and decryption. Since not all functions are needed, masks are set - up here to determine which will be implemented in C -*/ - -#if !defined( AES_ENCRYPT ) -# define EFUNCS_IN_C 0 -#elif defined( ASSUME_VIA_ACE_PRESENT ) || defined( ASM_X86_V1C ) \ - || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) -# define EFUNCS_IN_C ENC_KEYING_IN_C -#elif !defined( ASM_X86_V2 ) -# define EFUNCS_IN_C ( ENCRYPTION_IN_C | ENC_KEYING_IN_C ) -#else -# define EFUNCS_IN_C 0 -#endif - -#if !defined( AES_DECRYPT ) -# define DFUNCS_IN_C 0 -#elif defined( ASSUME_VIA_ACE_PRESENT ) || defined( ASM_X86_V1C ) \ - || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) -# define DFUNCS_IN_C DEC_KEYING_IN_C -#elif !defined( ASM_X86_V2 ) -# define DFUNCS_IN_C ( DECRYPTION_IN_C | DEC_KEYING_IN_C ) -#else -# define DFUNCS_IN_C 0 -#endif - -#define FUNCS_IN_C ( EFUNCS_IN_C | DFUNCS_IN_C ) - -/* END OF CONFIGURATION OPTIONS */ - -#define RC_LENGTH (5 * (AES_BLOCK_SIZE / 4 - 2)) - -/* Disable or report errors on some combinations of options */ - -#if ENC_ROUND == NO_TABLES && LAST_ENC_ROUND != NO_TABLES -# undef LAST_ENC_ROUND -# define LAST_ENC_ROUND NO_TABLES -#elif ENC_ROUND == ONE_TABLE && LAST_ENC_ROUND == FOUR_TABLES -# undef LAST_ENC_ROUND -# define LAST_ENC_ROUND ONE_TABLE -#endif - -#if ENC_ROUND == NO_TABLES && ENC_UNROLL != NONE -# undef ENC_UNROLL -# define ENC_UNROLL NONE -#endif - -#if DEC_ROUND == NO_TABLES && LAST_DEC_ROUND != NO_TABLES -# undef LAST_DEC_ROUND -# define LAST_DEC_ROUND NO_TABLES -#elif DEC_ROUND == ONE_TABLE && LAST_DEC_ROUND == FOUR_TABLES -# undef LAST_DEC_ROUND -# define LAST_DEC_ROUND ONE_TABLE -#endif - -#if DEC_ROUND == NO_TABLES && DEC_UNROLL != NONE -# undef DEC_UNROLL -# define DEC_UNROLL NONE -#endif - -#if defined( bswap32 ) -# define aes_sw32 bswap32 -#elif defined( bswap_32 ) -# define aes_sw32 bswap_32 -#else -# define brot(x,n) (((uint32_t)(x) << n) | ((uint32_t)(x) >> (32 - n))) -# define aes_sw32(x) ((brot((x),8) & 0x00ff00ff) | (brot((x),24) & 0xff00ff00)) -#endif - -/* upr(x,n): rotates bytes within words by n positions, moving bytes to - higher index positions with wrap around into low positions - ups(x,n): moves bytes by n positions to higher index positions in - words but without wrap around - bval(x,n): extracts a byte from a word - - WARNING: The definitions given here are intended only for use with - unsigned variables and with shift counts that are compile - time constants -*/ - -#if ( ALGORITHM_BYTE_ORDER == IS_LITTLE_ENDIAN ) -# define upr(x,n) (((uint32_t)(x) << (8 * (n))) | ((uint32_t)(x) >> (32 - 8 * (n)))) -# define ups(x,n) ((uint32_t) (x) << (8 * (n))) -# define bval(x,n) to_byte((x) >> (8 * (n))) -# define bytes2word(b0, b1, b2, b3) \ - (((uint32_t)(b3) << 24) | ((uint32_t)(b2) << 16) | ((uint32_t)(b1) << 8) | (b0)) -#endif - -#if ( ALGORITHM_BYTE_ORDER == IS_BIG_ENDIAN ) -# define upr(x,n) (((uint32_t)(x) >> (8 * (n))) | ((uint32_t)(x) << (32 - 8 * (n)))) -# define ups(x,n) ((uint32_t) (x) >> (8 * (n))) -# define bval(x,n) to_byte((x) >> (24 - 8 * (n))) -# define bytes2word(b0, b1, b2, b3) \ - (((uint32_t)(b0) << 24) | ((uint32_t)(b1) << 16) | ((uint32_t)(b2) << 8) | (b3)) -#endif - -#if defined( SAFE_IO ) -# define word_in(x,c) bytes2word(((const uint8_t*)(x)+4*c)[0], ((const uint8_t*)(x)+4*c)[1], \ - ((const uint8_t*)(x)+4*c)[2], ((const uint8_t*)(x)+4*c)[3]) -# define word_out(x,c,v) { ((uint8_t*)(x)+4*c)[0] = bval(v,0); ((uint8_t*)(x)+4*c)[1] = bval(v,1); \ - ((uint8_t*)(x)+4*c)[2] = bval(v,2); ((uint8_t*)(x)+4*c)[3] = bval(v,3); } -#elif ( ALGORITHM_BYTE_ORDER == PLATFORM_BYTE_ORDER ) -# define word_in(x,c) (*((uint32_t*)(x)+(c))) -# define word_out(x,c,v) (*((uint32_t*)(x)+(c)) = (v)) -#else -# define word_in(x,c) aes_sw32(*((uint32_t*)(x)+(c))) -# define word_out(x,c,v) (*((uint32_t*)(x)+(c)) = aes_sw32(v)) -#endif - -/* the finite field modular polynomial and elements */ - -#define WPOLY 0x011b -#define BPOLY 0x1b - -/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */ - -#define gf_c1 0x80808080 -#define gf_c2 0x7f7f7f7f -#define gf_mulx(x) ((((x) & gf_c2) << 1) ^ ((((x) & gf_c1) >> 7) * BPOLY)) - -/* The following defines provide alternative definitions of gf_mulx that might - give improved performance if a fast 32-bit multiply is not available. Note - that a temporary variable u needs to be defined where gf_mulx is used. - -#define gf_mulx(x) (u = (x) & gf_c1, u |= (u >> 1), ((x) & gf_c2) << 1) ^ ((u >> 3) | (u >> 6)) -#define gf_c4 (0x01010101 * BPOLY) -#define gf_mulx(x) (u = (x) & gf_c1, ((x) & gf_c2) << 1) ^ ((u - (u >> 7)) & gf_c4) -*/ - -/* Work out which tables are needed for the different options */ - -#if defined( ASM_X86_V1C ) -# if defined( ENC_ROUND ) -# undef ENC_ROUND -# endif -# define ENC_ROUND FOUR_TABLES -# if defined( LAST_ENC_ROUND ) -# undef LAST_ENC_ROUND -# endif -# define LAST_ENC_ROUND FOUR_TABLES -# if defined( DEC_ROUND ) -# undef DEC_ROUND -# endif -# define DEC_ROUND FOUR_TABLES -# if defined( LAST_DEC_ROUND ) -# undef LAST_DEC_ROUND -# endif -# define LAST_DEC_ROUND FOUR_TABLES -# if defined( KEY_SCHED ) -# undef KEY_SCHED -# define KEY_SCHED FOUR_TABLES -# endif -#endif - -#if ( FUNCS_IN_C & ENCRYPTION_IN_C ) || defined( ASM_X86_V1C ) -# if ENC_ROUND == ONE_TABLE -# define FT1_SET -# elif ENC_ROUND == FOUR_TABLES -# define FT4_SET -# else -# define SBX_SET -# endif -# if LAST_ENC_ROUND == ONE_TABLE -# define FL1_SET -# elif LAST_ENC_ROUND == FOUR_TABLES -# define FL4_SET -# elif !defined( SBX_SET ) -# define SBX_SET -# endif -#endif - -#if ( FUNCS_IN_C & DECRYPTION_IN_C ) || defined( ASM_X86_V1C ) -# if DEC_ROUND == ONE_TABLE -# define IT1_SET -# elif DEC_ROUND == FOUR_TABLES -# define IT4_SET -# else -# define ISB_SET -# endif -# if LAST_DEC_ROUND == ONE_TABLE -# define IL1_SET -# elif LAST_DEC_ROUND == FOUR_TABLES -# define IL4_SET -# elif !defined(ISB_SET) -# define ISB_SET -# endif -#endif - -#if !(defined( REDUCE_CODE_SIZE ) && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C ))) -# if ((FUNCS_IN_C & ENC_KEYING_IN_C) || (FUNCS_IN_C & DEC_KEYING_IN_C)) -# if KEY_SCHED == ONE_TABLE -# if !defined( FL1_SET ) && !defined( FL4_SET ) -# define LS1_SET -# endif -# elif KEY_SCHED == FOUR_TABLES -# if !defined( FL4_SET ) -# define LS4_SET -# endif -# elif !defined( SBX_SET ) -# define SBX_SET -# endif -# endif -# if (FUNCS_IN_C & DEC_KEYING_IN_C) -# if KEY_SCHED == ONE_TABLE -# define IM1_SET -# elif KEY_SCHED == FOUR_TABLES -# define IM4_SET -# elif !defined( SBX_SET ) -# define SBX_SET -# endif -# endif -#endif - -/* generic definitions of Rijndael macros that use tables */ - -#define no_table(x,box,vf,rf,c) bytes2word( \ - box[bval(vf(x,0,c),rf(0,c))], \ - box[bval(vf(x,1,c),rf(1,c))], \ - box[bval(vf(x,2,c),rf(2,c))], \ - box[bval(vf(x,3,c),rf(3,c))]) - -#define one_table(x,op,tab,vf,rf,c) \ - ( tab[bval(vf(x,0,c),rf(0,c))] \ - ^ op(tab[bval(vf(x,1,c),rf(1,c))],1) \ - ^ op(tab[bval(vf(x,2,c),rf(2,c))],2) \ - ^ op(tab[bval(vf(x,3,c),rf(3,c))],3)) - -#define four_tables(x,tab,vf,rf,c) \ - ( tab[0][bval(vf(x,0,c),rf(0,c))] \ - ^ tab[1][bval(vf(x,1,c),rf(1,c))] \ - ^ tab[2][bval(vf(x,2,c),rf(2,c))] \ - ^ tab[3][bval(vf(x,3,c),rf(3,c))]) - -#define vf1(x,r,c) (x) -#define rf1(r,c) (r) -#define rf2(r,c) ((8+r-c)&3) - -/* perform forward and inverse column mix operation on four bytes in long word x in */ -/* parallel. NOTE: x must be a simple variable, NOT an expression in these macros. */ - -#if !(defined( REDUCE_CODE_SIZE ) && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C ))) - -#if defined( FM4_SET ) /* not currently used */ -# define fwd_mcol(x) four_tables(x,t_use(f,m),vf1,rf1,0) -#elif defined( FM1_SET ) /* not currently used */ -# define fwd_mcol(x) one_table(x,upr,t_use(f,m),vf1,rf1,0) -#else -# define dec_fmvars uint32_t g2 -# define fwd_mcol(x) (g2 = gf_mulx(x), g2 ^ upr((x) ^ g2, 3) ^ upr((x), 2) ^ upr((x), 1)) -#endif - -#if defined( IM4_SET ) -# define inv_mcol(x) four_tables(x,t_use(i,m),vf1,rf1,0) -#elif defined( IM1_SET ) -# define inv_mcol(x) one_table(x,upr,t_use(i,m),vf1,rf1,0) -#else -# define dec_imvars uint32_t g2, g4, g9 -# define inv_mcol(x) (g2 = gf_mulx(x), g4 = gf_mulx(g2), g9 = (x) ^ gf_mulx(g4), g4 ^= g9, \ - (x) ^ g2 ^ g4 ^ upr(g2 ^ g9, 3) ^ upr(g4, 2) ^ upr(g9, 1)) -#endif - -#if defined( FL4_SET ) -# define ls_box(x,c) four_tables(x,t_use(f,l),vf1,rf2,c) -#elif defined( LS4_SET ) -# define ls_box(x,c) four_tables(x,t_use(l,s),vf1,rf2,c) -#elif defined( FL1_SET ) -# define ls_box(x,c) one_table(x,upr,t_use(f,l),vf1,rf2,c) -#elif defined( LS1_SET ) -# define ls_box(x,c) one_table(x,upr,t_use(l,s),vf1,rf2,c) -#else -# define ls_box(x,c) no_table(x,t_use(s,box),vf1,rf2,c) -#endif - -#endif - -#if defined( ASM_X86_V1C ) && defined( AES_DECRYPT ) && !defined( ISB_SET ) -# define ISB_SET -#endif - -#endif diff --git a/deps/crypto/trezor-crypto/aes/aestab.c b/deps/crypto/trezor-crypto/aes/aestab.c deleted file mode 100644 index 5e5dc1deb..000000000 --- a/deps/crypto/trezor-crypto/aes/aestab.c +++ /dev/null @@ -1,417 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. - -The redistribution and use of this software (with or without changes) -is allowed without the payment of fees or royalties provided that: - - source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation. - -This software is provided 'as is' with no explicit or implied warranties -in respect of its operation, including, but not limited to, correctness -and fitness for purpose. ---------------------------------------------------------------------------- -Issue Date: 20/12/2007 -*/ - -#define DO_TABLES - -#include "aes.h" -#include "aesopt.h" - -#if defined(STATIC_TABLES) - -#define sb_data(w) {\ - w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\ - w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\ - w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\ - w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\ - w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\ - w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\ - w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\ - w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\ - w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\ - w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\ - w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\ - w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\ - w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\ - w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\ - w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\ - w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\ - w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\ - w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\ - w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\ - w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\ - w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\ - w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\ - w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\ - w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\ - w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\ - w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\ - w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\ - w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\ - w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\ - w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\ - w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\ - w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) } - -#define isb_data(w) {\ - w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38),\ - w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb),\ - w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87),\ - w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), w(0xde), w(0xe9), w(0xcb),\ - w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d),\ - w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e),\ - w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2),\ - w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25),\ - w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16),\ - w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92),\ - w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda),\ - w(0x5e), w(0x15), w(0x46), w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84),\ - w(0x90), w(0xd8), w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a),\ - w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06),\ - w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02),\ - w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), w(0x6b),\ - w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea),\ - w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73),\ - w(0x96), w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85),\ - w(0xe2), w(0xf9), w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e),\ - w(0x47), w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89),\ - w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b),\ - w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), w(0x20),\ - w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), w(0x5a), w(0xf4),\ - w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), w(0x31),\ - w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f),\ - w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d),\ - w(0x2d), w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef),\ - w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0),\ - w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61),\ - w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), w(0xd6), w(0x26),\ - w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), w(0x21), w(0x0c), w(0x7d) } - -#define mm_data(w) {\ - w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07),\ - w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f),\ - w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), w(0x16), w(0x17),\ - w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), w(0x1d), w(0x1e), w(0x1f),\ - w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), w(0x25), w(0x26), w(0x27),\ - w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f),\ - w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37),\ - w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f),\ - w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47),\ - w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f),\ - w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57),\ - w(0x58), w(0x59), w(0x5a), w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f),\ - w(0x60), w(0x61), w(0x62), w(0x63), w(0x64), w(0x65), w(0x66), w(0x67),\ - w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f),\ - w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77),\ - w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), w(0x7f),\ - w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87),\ - w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f),\ - w(0x90), w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97),\ - w(0x98), w(0x99), w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f),\ - w(0xa0), w(0xa1), w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7),\ - w(0xa8), w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf),\ - w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), w(0xb7),\ - w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), w(0xbe), w(0xbf),\ - w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), w(0xc7),\ - w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf),\ - w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7),\ - w(0xd8), w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf),\ - w(0xe0), w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7),\ - w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef),\ - w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), w(0xf6), w(0xf7),\ - w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), w(0xfd), w(0xfe), w(0xff) } - -#define rc_data(w) {\ - w(0x01), w(0x02), w(0x04), w(0x08), w(0x10),w(0x20), w(0x40), w(0x80),\ - w(0x1b), w(0x36) } - -#define h0(x) (x) - -#define w0(p) bytes2word(p, 0, 0, 0) -#define w1(p) bytes2word(0, p, 0, 0) -#define w2(p) bytes2word(0, 0, p, 0) -#define w3(p) bytes2word(0, 0, 0, p) - -#define u0(p) bytes2word(f2(p), p, p, f3(p)) -#define u1(p) bytes2word(f3(p), f2(p), p, p) -#define u2(p) bytes2word(p, f3(p), f2(p), p) -#define u3(p) bytes2word(p, p, f3(p), f2(p)) - -#define v0(p) bytes2word(fe(p), f9(p), fd(p), fb(p)) -#define v1(p) bytes2word(fb(p), fe(p), f9(p), fd(p)) -#define v2(p) bytes2word(fd(p), fb(p), fe(p), f9(p)) -#define v3(p) bytes2word(f9(p), fd(p), fb(p), fe(p)) - -#endif - -#if defined(STATIC_TABLES) || !defined(FF_TABLES) - -#define f2(x) ((x<<1) ^ (((x>>7) & 1) * WPOLY)) -#define f4(x) ((x<<2) ^ (((x>>6) & 1) * WPOLY) ^ (((x>>6) & 2) * WPOLY)) -#define f8(x) ((x<<3) ^ (((x>>5) & 1) * WPOLY) ^ (((x>>5) & 2) * WPOLY) \ - ^ (((x>>5) & 4) * WPOLY)) -#define f3(x) (f2(x) ^ x) -#define f9(x) (f8(x) ^ x) -#define fb(x) (f8(x) ^ f2(x) ^ x) -#define fd(x) (f8(x) ^ f4(x) ^ x) -#define fe(x) (f8(x) ^ f4(x) ^ f2(x)) - -#else - -#define f2(x) ((x) ? pow[log[x] + 0x19] : 0) -#define f3(x) ((x) ? pow[log[x] + 0x01] : 0) -#define f9(x) ((x) ? pow[log[x] + 0xc7] : 0) -#define fb(x) ((x) ? pow[log[x] + 0x68] : 0) -#define fd(x) ((x) ? pow[log[x] + 0xee] : 0) -#define fe(x) ((x) ? pow[log[x] + 0xdf] : 0) - -#endif - -#include "aestab.h" - -#if defined(__cplusplus) -extern "C" -{ -#endif - -#if defined(STATIC_TABLES) - -/* implemented in case of wrong call for fixed tables */ - -AES_RETURN aes_init(void) -{ - return EXIT_SUCCESS; -} - -#else /* Generate the tables for the dynamic table option */ - -#if defined(FF_TABLES) - -#define gf_inv(x) ((x) ? pow[ 255 - log[x]] : 0) - -#else - -/* It will generally be sensible to use tables to compute finite - field multiplies and inverses but where memory is scarse this - code might sometimes be better. But it only has effect during - initialisation so its pretty unimportant in overall terms. -*/ - -/* return 2 ^ (n - 1) where n is the bit number of the highest bit - set in x with x in the range 1 < x < 0x00000200. This form is - used so that locals within fi can be bytes rather than words -*/ - -static uint8_t hibit(const uint32_t x) -{ uint8_t r = (uint8_t)((x >> 1) | (x >> 2)); - - r |= (r >> 2); - r |= (r >> 4); - return (r + 1) >> 1; -} - -/* return the inverse of the finite field element x */ - -static uint8_t gf_inv(const uint8_t x) -{ uint8_t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0; - - if(x < 2) - return x; - - for( ; ; ) - { - if(n1) - while(n2 >= n1) /* divide polynomial p2 by p1 */ - { - n2 /= n1; /* shift smaller polynomial left */ - p2 ^= (p1 * n2) & 0xff; /* and remove from larger one */ - v2 ^= v1 * n2; /* shift accumulated value and */ - n2 = hibit(p2); /* add into result */ - } - else - return v1; - - if(n2) /* repeat with values swapped */ - while(n1 >= n2) - { - n1 /= n2; - p1 ^= p2 * n1; - v1 ^= v2 * n1; - n1 = hibit(p1); - } - else - return v2; - } -} - -#endif - -/* The forward and inverse affine transformations used in the S-box */ -uint8_t fwd_affine(const uint8_t x) -{ uint32_t w = x; - w ^= (w << 1) ^ (w << 2) ^ (w << 3) ^ (w << 4); - return 0x63 ^ ((w ^ (w >> 8)) & 0xff); -} - -uint8_t inv_affine(const uint8_t x) -{ uint32_t w = x; - w = (w << 1) ^ (w << 3) ^ (w << 6); - return 0x05 ^ ((w ^ (w >> 8)) & 0xff); -} - -static int init = 0; - -AES_RETURN aes_init(void) -{ uint32_t i = 0, w = 0; - -#if defined(FF_TABLES) - - uint8_t pow[512] = {0}, log[256] = {0}; - - if(init) - return EXIT_SUCCESS; - /* log and power tables for GF(2^8) finite field with - WPOLY as modular polynomial - the simplest primitive - root is 0x03, used here to generate the tables - */ - - i = 0; w = 1; - do - { - pow[i] = (uint8_t)w; - pow[i + 255] = (uint8_t)w; - log[w] = (uint8_t)i++; - w ^= (w << 1) ^ (w & 0x80 ? WPOLY : 0); - } - while (w != 1); - -#else - if(init) - return EXIT_SUCCESS; -#endif - - for(i = 0, w = 1; i < RC_LENGTH; ++i) - { - t_set(r,c)[i] = bytes2word(w, 0, 0, 0); - w = f2(w); - } - - for(i = 0; i < 256; ++i) - { uint8_t b = 0; - - b = fwd_affine(gf_inv((uint8_t)i)); - w = bytes2word(f2(b), b, b, f3(b)); - -#if defined( SBX_SET ) - t_set(s,box)[i] = b; -#endif - -#if defined( FT1_SET ) /* tables for a normal encryption round */ - t_set(f,n)[i] = w; -#endif -#if defined( FT4_SET ) - t_set(f,n)[0][i] = w; - t_set(f,n)[1][i] = upr(w,1); - t_set(f,n)[2][i] = upr(w,2); - t_set(f,n)[3][i] = upr(w,3); -#endif - w = bytes2word(b, 0, 0, 0); - -#if defined( FL1_SET ) /* tables for last encryption round (may also */ - t_set(f,l)[i] = w; /* be used in the key schedule) */ -#endif -#if defined( FL4_SET ) - t_set(f,l)[0][i] = w; - t_set(f,l)[1][i] = upr(w,1); - t_set(f,l)[2][i] = upr(w,2); - t_set(f,l)[3][i] = upr(w,3); -#endif - -#if defined( LS1_SET ) /* table for key schedule if t_set(f,l) above is*/ - t_set(l,s)[i] = w; /* not of the required form */ -#endif -#if defined( LS4_SET ) - t_set(l,s)[0][i] = w; - t_set(l,s)[1][i] = upr(w,1); - t_set(l,s)[2][i] = upr(w,2); - t_set(l,s)[3][i] = upr(w,3); -#endif - - b = gf_inv(inv_affine((uint8_t)i)); - w = bytes2word(fe(b), f9(b), fd(b), fb(b)); - -#if defined( IM1_SET ) /* tables for the inverse mix column operation */ - t_set(i,m)[b] = w; -#endif -#if defined( IM4_SET ) - t_set(i,m)[0][b] = w; - t_set(i,m)[1][b] = upr(w,1); - t_set(i,m)[2][b] = upr(w,2); - t_set(i,m)[3][b] = upr(w,3); -#endif - -#if defined( ISB_SET ) - t_set(i,box)[i] = b; -#endif -#if defined( IT1_SET ) /* tables for a normal decryption round */ - t_set(i,n)[i] = w; -#endif -#if defined( IT4_SET ) - t_set(i,n)[0][i] = w; - t_set(i,n)[1][i] = upr(w,1); - t_set(i,n)[2][i] = upr(w,2); - t_set(i,n)[3][i] = upr(w,3); -#endif - w = bytes2word(b, 0, 0, 0); -#if defined( IL1_SET ) /* tables for last decryption round */ - t_set(i,l)[i] = w; -#endif -#if defined( IL4_SET ) - t_set(i,l)[0][i] = w; - t_set(i,l)[1][i] = upr(w,1); - t_set(i,l)[2][i] = upr(w,2); - t_set(i,l)[3][i] = upr(w,3); -#endif - } - init = 1; - return EXIT_SUCCESS; -} - -/* - Automatic code initialisation (suggested by by Henrik S. Gaßmann) - based on code provided by Joe Lowe and placed in the public domain at: - http://stackoverflow.com/questions/1113409/attribute-constructor-equivalent-in-vc -*/ - -#ifdef _MSC_VER - -#pragma section(".CRT$XCU", read) - -__declspec(allocate(".CRT$XCU")) void (__cdecl *aes_startup)(void) = aes_init; - -#elif defined(__GNUC__) - -static void aes_startup(void) __attribute__((constructor)); - -static void aes_startup(void) -{ - aes_init(); -} - -#else - -#pragma message( "dynamic tables must be initialised manually on your system" ) - -#endif - -#endif - -#if defined(__cplusplus) -} -#endif diff --git a/deps/crypto/trezor-crypto/aes/aestab.h b/deps/crypto/trezor-crypto/aes/aestab.h deleted file mode 100644 index 8fe32d180..000000000 --- a/deps/crypto/trezor-crypto/aes/aestab.h +++ /dev/null @@ -1,173 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. - -The redistribution and use of this software (with or without changes) -is allowed without the payment of fees or royalties provided that: - - source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation. - -This software is provided 'as is' with no explicit or implied warranties -in respect of its operation, including, but not limited to, correctness -and fitness for purpose. ---------------------------------------------------------------------------- -Issue Date: 20/12/2007 - - This file contains the code for declaring the tables needed to implement - AES. The file aesopt.h is assumed to be included before this header file. - If there are no global variables, the definitions here can be used to put - the AES tables in a structure so that a pointer can then be added to the - AES context to pass them to the AES routines that need them. If this - facility is used, the calling program has to ensure that this pointer is - managed appropriately. In particular, the value of the t_dec(in,it) item - in the table structure must be set to zero in order to ensure that the - tables are initialised. In practice the three code sequences in aeskey.c - that control the calls to aes_init() and the aes_init() routine itself will - have to be changed for a specific implementation. If global variables are - available it will generally be preferable to use them with the precomputed - STATIC_TABLES option that uses static global tables. - - The following defines can be used to control the way the tables - are defined, initialised and used in embedded environments that - require special features for these purposes - - the 't_dec' construction is used to declare fixed table arrays - the 't_set' construction is used to set fixed table values - the 't_use' construction is used to access fixed table values - - 256 byte tables: - - t_xxx(s,box) => forward S box - t_xxx(i,box) => inverse S box - - 256 32-bit word OR 4 x 256 32-bit word tables: - - t_xxx(f,n) => forward normal round - t_xxx(f,l) => forward last round - t_xxx(i,n) => inverse normal round - t_xxx(i,l) => inverse last round - t_xxx(l,s) => key schedule table - t_xxx(i,m) => key schedule table - - Other variables and tables: - - t_xxx(r,c) => the rcon table -*/ - -#if !defined( _AESTAB_H ) -#define _AESTAB_H - -#if defined(__cplusplus) -extern "C" { -#endif - -#define t_dec(m,n) t_##m##n -#define t_set(m,n) t_##m##n -#define t_use(m,n) t_##m##n - -#if defined(STATIC_TABLES) -# if !defined( __GNUC__ ) && (defined( __MSDOS__ ) || defined( __WIN16__ )) -/* make tables far data to avoid using too much DGROUP space (PG) */ -# define CONST const far -# else -# define CONST const -# endif -#else -# define CONST -#endif - -#if defined(DO_TABLES) -# define EXTERN -#else -# define EXTERN extern -#endif - -#if defined(_MSC_VER) && defined(TABLE_ALIGN) -#define ALIGN __declspec(align(TABLE_ALIGN)) -#else -#define ALIGN -#endif - -#if defined( __WATCOMC__ ) && ( __WATCOMC__ >= 1100 ) -# define XP_DIR __cdecl -#else -# define XP_DIR -#endif - -#if defined(DO_TABLES) && defined(STATIC_TABLES) -#define d_1(t,n,b,e) EXTERN ALIGN CONST XP_DIR t n[256] = b(e) -#define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256] = { b(e), b(f), b(g), b(h) } -EXTERN ALIGN CONST uint32_t t_dec(r,c)[RC_LENGTH] = rc_data(w0); -#else -#define d_1(t,n,b,e) EXTERN ALIGN CONST XP_DIR t n[256] -#define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256] -EXTERN ALIGN CONST uint32_t t_dec(r,c)[RC_LENGTH]; -#endif - -#if defined( SBX_SET ) - d_1(uint8_t, t_dec(s,box), sb_data, h0); -#endif -#if defined( ISB_SET ) - d_1(uint8_t, t_dec(i,box), isb_data, h0); -#endif - -#if defined( FT1_SET ) - d_1(uint32_t, t_dec(f,n), sb_data, u0); -#endif -#if defined( FT4_SET ) - d_4(uint32_t, t_dec(f,n), sb_data, u0, u1, u2, u3); -#endif - -#if defined( FL1_SET ) - d_1(uint32_t, t_dec(f,l), sb_data, w0); -#endif -#if defined( FL4_SET ) - d_4(uint32_t, t_dec(f,l), sb_data, w0, w1, w2, w3); -#endif - -#if defined( IT1_SET ) - d_1(uint32_t, t_dec(i,n), isb_data, v0); -#endif -#if defined( IT4_SET ) - d_4(uint32_t, t_dec(i,n), isb_data, v0, v1, v2, v3); -#endif - -#if defined( IL1_SET ) - d_1(uint32_t, t_dec(i,l), isb_data, w0); -#endif -#if defined( IL4_SET ) - d_4(uint32_t, t_dec(i,l), isb_data, w0, w1, w2, w3); -#endif - -#if defined( LS1_SET ) -#if defined( FL1_SET ) -#undef LS1_SET -#else - d_1(uint32_t, t_dec(l,s), sb_data, w0); -#endif -#endif - -#if defined( LS4_SET ) -#if defined( FL4_SET ) -#undef LS4_SET -#else - d_4(uint32_t, t_dec(l,s), sb_data, w0, w1, w2, w3); -#endif -#endif - -#if defined( IM1_SET ) - d_1(uint32_t, t_dec(i,m), mm_data, v0); -#endif -#if defined( IM4_SET ) - d_4(uint32_t, t_dec(i,m), mm_data, v0, v1, v2, v3); -#endif - -#if defined(__cplusplus) -} -#endif - -#endif diff --git a/deps/crypto/trezor-crypto/aes/aestst.c b/deps/crypto/trezor-crypto/aes/aestst.c deleted file mode 100644 index 90a8714a9..000000000 --- a/deps/crypto/trezor-crypto/aes/aestst.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - --------------------------------------------------------------------------- - Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved. - - LICENSE TERMS - - The redistribution and use of this software (with or without changes) - is allowed without the payment of fees or royalties provided that: - - 1. source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - 2. binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation; - - 3. the name of the copyright holder is not used to endorse products - built using this software without specific written permission. - - DISCLAIMER - - This software is provided 'as is' with no explicit or implied warranties - in respect of its properties, including, but not limited to, correctness - and/or fitness for purpose. - --------------------------------------------------------------------------- - Issue Date: 20/12/2007 -*/ - -// Correct Output (for variable block size - AES_BLOCK_SIZE undefined): - -// lengths: block = 16 bytes, key = 16 bytes -// key = 2b7e151628aed2a6abf7158809cf4f3c -// input = 3243f6a8885a308d313198a2e0370734 -// encrypt = 3925841d02dc09fbdc118597196a0b32 -// decrypt = 3243f6a8885a308d313198a2e0370734 - -// lengths: block = 16 bytes, key = 24 bytes -// key = 2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da5 -// input = 3243f6a8885a308d313198a2e0370734 -// encrypt = f9fb29aefc384a250340d833b87ebc00 -// decrypt = 3243f6a8885a308d313198a2e0370734 - -// lengths: block = 16 bytes, key = 32 bytes -// key = 2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d9045190cfe -// input = 3243f6a8885a308d313198a2e0370734 -// encrypt = 1a6e6c2c662e7da6501ffb62bc9e93f3 -// decrypt = 3243f6a8885a308d313198a2e0370734 - -#include -#include - -#include "aes.h" -#include "aestst.h" - -void out_state(long s0, long s1, long s2, long s3) -{ - printf("\n%08lx%08lx%08lx%08lx", s0, s1, s2, s3); -} - -void oblk(char m[], unsigned char v[], unsigned long n) -{ unsigned long i; - - printf("\n%s", m); - - for(i = 0; i < n; ++i) - printf("%02x", v[i]); -} - -void message(const char *s) { printf("%s", s); } - -unsigned char pih[32] = // hex digits of pi -{ - 0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, - 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34, - 0x4a, 0x40, 0x93, 0x82, 0x22, 0x99, 0xf3, 0x1d, - 0x00, 0x82, 0xef, 0xa9, 0x8e, 0xc4, 0xe6, 0xc8 -}; - -unsigned char exh[32] = // hex digits of e -{ - 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, - 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c, - 0x76, 0x2e, 0x71, 0x60, 0xf3, 0x8b, 0x4d, 0xa5, - 0x6a, 0x78, 0x4d, 0x90, 0x45, 0x19, 0x0c, 0xfe -}; - -unsigned char res[3][32] = -{ - { 0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, - 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32 - }, - { 0xf9, 0xfb, 0x29, 0xae, 0xfc, 0x38, 0x4a, 0x25, - 0x03, 0x40, 0xd8, 0x33, 0xb8, 0x7e, 0xbc, 0x00 - }, - { 0x1a, 0x6e, 0x6c, 0x2c, 0x66, 0x2e, 0x7d, 0xa6, - 0x50, 0x1f, 0xfb, 0x62, 0xbc, 0x9e, 0x93, 0xf3 - } -}; - -void cycles(volatile uint64_t *rtn) -{ -#if defined( _MSCVER ) - __asm // read the Pentium Time Stamp Counter - { cpuid - rdtsc - mov ecx,rtn - mov [ecx],eax - mov [ecx+4],edx - cpuid - } -#elif defined( __GNUC__ ) -#if defined(__aarch64__) - __asm__ __volatile__("mrs %0, cntvct_el0": "=r" (*rtn)); -#else - __asm__ __volatile__("rdtsc": "=A" (*rtn)); -#endif -#endif -} - -int main(void) -{ unsigned char out[32], ret[32], err = 0; - f_ectx alge[1]; - f_dctx algd[1]; - - aes_init(); - - message("\nRun tests for the AES algorithm"); - - memset(&alge, 0, sizeof(aes_encrypt_ctx)); - memset(&algd, 0, sizeof(aes_decrypt_ctx)); - -#if defined( AES_128 ) - memset(out, 0xcc, 16); memset(ret, 0xcc, 16); - printf("\n\n// lengths: block = 16, bytes, key = 16 bytes"); - f_enc_key128(alge, exh); - oblk("// key = ", exh, 16); - oblk("// input = ", pih, 16); - do_enc(alge, pih, out, 1); - oblk("// encrypt = ", out, 16); - if(memcmp(out, res[0], 16)) { message (" error"); err += 1; } - f_dec_key128(algd, exh); - do_dec(algd, out, ret, 1); - oblk("// decrypt = ", ret, 16); - if(memcmp(ret, pih, 16)) { message (" error"); err += 2; } -#endif - -#if defined( AES_192 ) - memset(out, 0xcc, 16); memset(ret, 0xcc, 16); - printf("\n\n// lengths: block = 16, bytes, key = 24 bytes"); - f_enc_key192(alge, exh); - oblk("// key = ", exh, 24); - oblk("// input = ", pih, 16); - do_enc(alge, pih, out, 1); - oblk("// encrypt = ", out, 16); - if(memcmp(out, res[1], 16)) { message (" error"); err += 4; } - f_dec_key192(algd, exh); - do_dec(algd, out, ret, 1); - oblk("// decrypt = ", ret, 16); - if(memcmp(ret, pih, 16)) { message (" error"); err += 8; } -#endif - -#if defined( AES_256 ) - memset(out, 0xcc, 16); memset(ret, 0xcc, 16); - printf("\n\n// lengths: block = 16, bytes, key = 32 bytes"); - f_enc_key256(alge, exh); - oblk("// key = ", exh, 32); - oblk("// input = ", pih, 16); - do_enc(alge, pih, out, 1); - oblk("// encrypt = ", out, 16); - if(memcmp(out, res[2], 16)) { message (" error"); err += 16; } - f_dec_key256(algd, exh); - do_dec(algd, out, ret, 1); - oblk("// decrypt = ", ret, 16); - if(memcmp(ret, pih, 16)) { message (" error"); err += 32; } -#endif - - if(!err) - message("\n\nThese values are all correct\n\n"); - else - message("\n\nSome values are in error\n\n"); - - return 0; -} diff --git a/deps/crypto/trezor-crypto/aes/aestst.h b/deps/crypto/trezor-crypto/aes/aestst.h deleted file mode 100644 index 3c5461c3c..000000000 --- a/deps/crypto/trezor-crypto/aes/aestst.h +++ /dev/null @@ -1,85 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. - -The redistribution and use of this software (with or without changes) -is allowed without the payment of fees or royalties provided that: - - source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation. - -This software is provided 'as is' with no explicit or implied warranties -in respect of its operation, including, but not limited to, correctness -and fitness for purpose. ---------------------------------------------------------------------------- -Issue Date: 20/12/2007 -*/ - -// The following definitions are required for testing only, They are not needed -// for AES (Rijndael) implementation. They are used to allow C, C++ and DLL -// data access and subroutine calls to be expressed in the same form in the -// testing code. - -#ifndef AESTST_H -#define AESTST_H - -#define f_info(x) (x)->inf.b[2] -#define f_ectx aes_encrypt_ctx -#define f_enc_key128(a,b) aes_encrypt_key128((b),(a)) -#define f_enc_key192(a,b) aes_encrypt_key192((b),(a)) -#define f_enc_key256(a,b) aes_encrypt_key256((b),(a)) -#define f_enc_key(a,b,c) aes_encrypt_key((b),(c),(a)) -#define f_enc_blk(a,b,c) aes_encrypt((b),(c),(a)) - -#define f_dctx aes_decrypt_ctx -#define f_dec_key128(a,b) aes_decrypt_key128((b),(a)) -#define f_dec_key192(a,b) aes_decrypt_key192((b),(a)) -#define f_dec_key256(a,b) aes_decrypt_key256((b),(a)) -#define f_dec_key(a,b,c) aes_decrypt_key((b),(c),(a)) -#define f_dec_blk(a,b,c) aes_decrypt((b),(c),(a)) - -#define f_talign(a,b) aes_test_alignment_detection(b) -#define f_mode_reset(a) aes_mode_reset(a) -#define f_ecb_enc(a,b,c,d) aes_ecb_encrypt((b),(c),(d),(a)) -#define f_ecb_dec(a,b,c,d) aes_ecb_decrypt((b),(c),(d),(a)) -#define f_cbc_enc(a,b,c,d,e) aes_cbc_encrypt((b),(c),(d),(e),(a)) -#define f_cbc_dec(a,b,c,d,e) aes_cbc_decrypt((b),(c),(d),(e),(a)) -#define f_cfb_enc(a,b,c,d,e) aes_cfb_encrypt((b),(c),(d),(e),(a)) -#define f_cfb_dec(a,b,c,d,e) aes_cfb_decrypt((b),(c),(d),(e),(a)) -#define f_ofb_cry(a,b,c,d,e) aes_ofb_crypt((b),(c),(d),(e),(a)) -#define f_ctr_cry(a,b,c,d,e,f) aes_ctr_crypt((b),(c),(d),(e),(f),(a)) - -#define ek_name128 "aes_encrypt_key128" -#define ek_name192 "aes_encrypt_key192" -#define ek_name256 "aes_encrypt_key256" -#define ek_name "aes_encrypt_key" -#define eb_name "aes_encrypt" - -#define dk_name128 "aes_decrypt_key128" -#define dk_name192 "aes_decrypt_key192" -#define dk_name256 "aes_decrypt_key256" -#define dk_name "aes_decrypt_key" -#define db_name "aes_decrypt" - -#define eres_name "aes_mode_reset" -#define ecbe_name "aes_ecb_encrypt" -#define ecbd_name "aes_ecb_decrypt" -#define cbce_name "aes_cbc_encrypt" -#define cbcd_name "aes_cbc_decrypt" -#define cfbe_name "aes_cfb_encrypt" -#define cfbd_name "aes_cfb_decrypt" -#define ofb_name "aes_ofb_crypt" -#define ctr_name "aes_ctr_crypt" - -#ifndef AES_N_BLOCK -#define do_enc(a,b,c,d) f_enc_blk(a, b, c) -#define do_dec(a,b,c,d) f_dec_blk(a, b, c) -#else -#define do_enc(a,b,c,d) f_ecb_enc(a, b, c, 1) -#define do_dec(a,b,c,d) f_ecb_dec(a, b, c, 1) -#endif - -#endif diff --git a/deps/crypto/trezor-crypto/base32.c b/deps/crypto/trezor-crypto/base32.c deleted file mode 100644 index ef9b76bec..000000000 --- a/deps/crypto/trezor-crypto/base32.c +++ /dev/null @@ -1,241 +0,0 @@ -/** - * Copyright (c) 2017 Saleem Rashid - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, E1PRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "base32.h" - -#include - -const char *BASE32_ALPHABET_RFC4648 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ23456789"; - -static inline void base32_5to8(const uint8_t *in, uint8_t length, uint8_t *out); -static inline bool base32_8to5(const uint8_t *in, uint8_t length, uint8_t *out, - const char *alphabet); -static inline void base32_8to5_raw(const uint8_t *in, uint8_t length, - uint8_t *out); - -static inline int base32_encode_character(uint8_t decoded, - const char *alphabet); -static inline int base32_decode_character(char encoded, const char *alphabet); - -char *base32_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen, - const char *alphabet) { - size_t length = base32_encoded_length(inlen); - if (outlen <= length) { - return NULL; - } - - base32_encode_unsafe(in, inlen, (uint8_t *)out); - - for (size_t i = 0; i < length; i++) { - int ret = base32_encode_character(out[i], alphabet); - - if (ret == -1) { - return false; - } else { - out[i] = ret; - } - } - - out[length] = '\0'; - return &out[length]; -} - -uint8_t *base32_decode(const char *in, size_t inlen, uint8_t *out, - size_t outlen, const char *alphabet) { - size_t length = base32_decoded_length(inlen); - if (outlen < length) { - return NULL; - } - - if (!base32_decode_unsafe((uint8_t *)in, inlen, (uint8_t *)out, alphabet)) { - return NULL; - } - - return &out[length]; -} - -void base32_encode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out) { - uint8_t remainder = inlen % 5; - size_t limit = inlen - remainder; - - size_t i = 0, j = 0; - for (i = 0, j = 0; i < limit; i += 5, j += 8) { - base32_5to8(&in[i], 5, &out[j]); - } - - if (remainder) base32_5to8(&in[i], remainder, &out[j]); -} - -bool base32_decode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out, - const char *alphabet) { - uint8_t remainder = inlen % 8; - size_t limit = inlen - remainder; - - size_t i = 0, j = 0; - for (i = 0, j = 0; i < limit; i += 8, j += 5) { - if (!base32_8to5(&in[i], 8, &out[j], alphabet)) { - return false; - } - } - - if (remainder && !base32_8to5(&in[i], remainder, &out[j], alphabet)) { - return false; - } - - return true; -} - -size_t base32_encoded_length(size_t inlen) { - uint8_t remainder = inlen % 5; - - return (inlen / 5) * 8 + (remainder * 8 + 4) / 5; -} - -size_t base32_decoded_length(size_t inlen) { - uint8_t remainder = inlen % 8; - - return (inlen / 8) * 5 + (remainder * 5) / 8; -} - -void base32_5to8(const uint8_t *in, uint8_t length, uint8_t *out) { - if (length >= 1) { - out[0] = (in[0] >> 3); - out[1] = (in[0] & 7) << 2; - } - - if (length >= 2) { - out[1] |= (in[1] >> 6); - out[2] = (in[1] >> 1) & 31; - out[3] = (in[1] & 1) << 4; - } - - if (length >= 3) { - out[3] |= (in[2] >> 4); - out[4] = (in[2] & 15) << 1; - } - - if (length >= 4) { - out[4] |= (in[3] >> 7); - out[5] = (in[3] >> 2) & 31; - out[6] = (in[3] & 3) << 3; - } - - if (length >= 5) { - out[6] |= (in[4] >> 5); - out[7] = (in[4] & 31); - } -} - -bool base32_8to5(const uint8_t *in, uint8_t length, uint8_t *out, - const char *alphabet) { - if (length == 1 || length == 3 || length == 6 || length > 8) { - return false; - } - - if (alphabet) { - uint8_t decoded[length]; - memset(decoded, 0, sizeof(decoded)); - - for (size_t i = 0; i < length; i++) { - int ret = base32_decode_character(in[i], alphabet); - - if (ret == -1) { - return false; - } else { - decoded[i] = ret; - } - } - - base32_8to5_raw(decoded, length, out); - } else { - base32_8to5_raw(in, length, out); - } - - return true; -} - -void base32_8to5_raw(const uint8_t *in, uint8_t length, uint8_t *out) { - if (length >= 2) { - out[0] = (in[0] << 3); - out[0] |= (in[1] >> 2); - } - - if (length >= 4) { - out[1] = (in[1] & 3) << 6; - out[1] |= (in[2] << 1); - out[1] |= (in[3] >> 4); - } - - if (length >= 5) { - out[2] = (in[3] & 15) << 4; - out[2] |= (in[4] >> 1); - } - - if (length >= 7) { - out[3] = (in[4] & 1) << 7; - out[3] |= (in[5] << 2); - out[3] |= (in[6] >> 3); - } - - if (length >= 8) { - out[4] = (in[6] & 7) << 5; - out[4] |= (in[7] & 31); - } -} - -int base32_encode_character(uint8_t decoded, const char *alphabet) { - if (decoded >> 5) { - return -1; - } - - if (alphabet == BASE32_ALPHABET_RFC4648) { - if (decoded < 26) { - return 'A' + decoded; - } else { - return '2' - 26 + decoded; - } - } - - return alphabet[decoded]; -} - -int base32_decode_character(char encoded, const char *alphabet) { - if (alphabet == BASE32_ALPHABET_RFC4648) { - if (encoded >= 'A' && encoded <= 'Z') { - return encoded - 'A'; - } else if (encoded >= 'a' && encoded <= 'z') { - return encoded - 'a'; - } else if (encoded >= '2' && encoded <= '7') { - return encoded - '2' + 26; - } else { - return -1; - } - } - - const char *occurrence = strchr(alphabet, encoded); - - if (occurrence) { - return occurrence - alphabet; - } else { - return -1; - } -} diff --git a/deps/crypto/trezor-crypto/base32.h b/deps/crypto/trezor-crypto/base32.h deleted file mode 100644 index 8b5cc8513..000000000 --- a/deps/crypto/trezor-crypto/base32.h +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Copyright (c) 2017 Saleem Rashid - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __BASE32_H__ -#define __BASE32_H__ - -#include -#include -#include - -extern const char *BASE32_ALPHABET_RFC4648; - -char *base32_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen, - const char *alphabet); -void base32_encode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out); - -uint8_t *base32_decode(const char *in, size_t inlen, uint8_t *out, - size_t outlen, const char *alphabet); -bool base32_decode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out, - const char *alphabet); - -size_t base32_encoded_length(size_t inlen); -size_t base32_decoded_length(size_t inlen); - -#endif diff --git a/deps/crypto/trezor-crypto/base58.c b/deps/crypto/trezor-crypto/base58.c deleted file mode 100644 index faa763501..000000000 --- a/deps/crypto/trezor-crypto/base58.c +++ /dev/null @@ -1,274 +0,0 @@ -/** - * Copyright (c) 2012-2014 Luke Dashjr - * Copyright (c) 2013-2014 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "base58.h" -#include -#include -#include "memzero.h" -#include "ripemd160.h" -#include "sha2.h" - -const char b58digits_ordered[] = - "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; -const int8_t b58digits_map[] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, - 8, -1, -1, -1, -1, -1, -1, -1, 9, 10, 11, 12, 13, 14, 15, 16, -1, 17, 18, - 19, 20, 21, -1, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, - -1, -1, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, -1, 44, 45, 46, 47, 48, - 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, -1, -1, -1, -}; - -typedef uint64_t b58_maxint_t; -typedef uint32_t b58_almostmaxint_t; -#define b58_almostmaxint_bits (sizeof(b58_almostmaxint_t) * 8) -static const b58_almostmaxint_t b58_almostmaxint_mask = - ((((b58_maxint_t)1) << b58_almostmaxint_bits) - 1); - -// Decodes a null-terminated Base58 string `b58` to binary and writes the result -// at the end of the buffer `bin` of size `*binszp`. On success `*binszp` is set -// to the number of valid bytes at the end of the buffer. -bool b58tobin(void *bin, size_t *binszp, const char *b58) { - size_t binsz = *binszp; - - if (binsz == 0) { - return false; - } - - const unsigned char *b58u = (const unsigned char *)b58; - unsigned char *binu = bin; - size_t outisz = - (binsz + sizeof(b58_almostmaxint_t) - 1) / sizeof(b58_almostmaxint_t); - b58_almostmaxint_t outi[outisz]; - b58_maxint_t t = 0; - b58_almostmaxint_t c = 0; - size_t i = 0, j = 0; - uint8_t bytesleft = binsz % sizeof(b58_almostmaxint_t); - b58_almostmaxint_t zeromask = - bytesleft ? (b58_almostmaxint_mask << (bytesleft * 8)) : 0; - unsigned zerocount = 0; - - size_t b58sz = strlen(b58); - - memzero(outi, sizeof(outi)); - - // Leading zeros, just count - for (i = 0; i < b58sz && b58u[i] == '1'; ++i) ++zerocount; - - for (; i < b58sz; ++i) { - if (b58u[i] & 0x80) - // High-bit set on invalid digit - return false; - if (b58digits_map[b58u[i]] == -1) - // Invalid base58 digit - return false; - c = (unsigned)b58digits_map[b58u[i]]; - for (j = outisz; j--;) { - t = ((b58_maxint_t)outi[j]) * 58 + c; - c = t >> b58_almostmaxint_bits; - outi[j] = t & b58_almostmaxint_mask; - } - if (c) - // Output number too big (carry to the next int32) - return false; - if (outi[0] & zeromask) - // Output number too big (last int32 filled too far) - return false; - } - - j = 0; - if (bytesleft) { - for (i = bytesleft; i > 0; --i) { - *(binu++) = (outi[0] >> (8 * (i - 1))) & 0xff; - } - ++j; - } - - for (; j < outisz; ++j) { - for (i = sizeof(*outi); i > 0; --i) { - *(binu++) = (outi[j] >> (8 * (i - 1))) & 0xff; - } - } - - // locate the most significant byte - binu = bin; - for (i = 0; i < binsz; ++i) { - if (binu[i]) break; - } - - // prepend the correct number of null-bytes - if (zerocount > i) { - /* result too large */ - return false; - } - *binszp = binsz - i + zerocount; - - return true; -} - -int b58check(const void *bin, size_t binsz, HasherType hasher_type, - const char *base58str) { - unsigned char buf[32] = {0}; - const uint8_t *binc = bin; - unsigned i = 0; - if (binsz < 4) return -4; - hasher_Raw(hasher_type, bin, binsz - 4, buf); - if (memcmp(&binc[binsz - 4], buf, 4)) return -1; - - // Check number of zeros is correct AFTER verifying checksum (to avoid - // possibility of accessing base58str beyond the end) - for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i) { - } // Just finding the end of zeros, nothing to do in loop - if (binc[i] == '\0' || base58str[i] == '1') return -3; - - return binc[0]; -} - -bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz) { - const uint8_t *bin = data; - int carry = 0; - size_t i = 0, j = 0, high = 0, zcount = 0; - size_t size = 0; - - while (zcount < binsz && !bin[zcount]) ++zcount; - - size = (binsz - zcount) * 138 / 100 + 1; - uint8_t buf[size]; - memzero(buf, size); - - for (i = zcount, high = size - 1; i < binsz; ++i, high = j) { - for (carry = bin[i], j = size - 1; (j > high) || carry; --j) { - carry += 256 * buf[j]; - buf[j] = carry % 58; - carry /= 58; - if (!j) { - // Otherwise j wraps to maxint which is > high - break; - } - } - } - - for (j = 0; j < size && !buf[j]; ++j) - ; - - if (*b58sz <= zcount + size - j) { - *b58sz = zcount + size - j + 1; - return false; - } - - if (zcount) memset(b58, '1', zcount); - for (i = zcount; j < size; ++i, ++j) b58[i] = b58digits_ordered[buf[j]]; - b58[i] = '\0'; - *b58sz = i + 1; - - return true; -} - -int base58_encode_check(const uint8_t *data, int datalen, - HasherType hasher_type, char *str, int strsize) { - if (datalen > 128) { - return 0; - } - uint8_t buf[datalen + 32]; - memset(buf, 0, sizeof(buf)); - uint8_t *hash = buf + datalen; - memcpy(buf, data, datalen); - hasher_Raw(hasher_type, data, datalen, hash); - size_t res = strsize; - bool success = b58enc(str, &res, buf, datalen + 4); - memzero(buf, sizeof(buf)); - return success ? res : 0; -} - -int base58_decode_check(const char *str, HasherType hasher_type, uint8_t *data, - int datalen) { - if (datalen > 128) { - return 0; - } - uint8_t d[datalen + 4]; - memset(d, 0, sizeof(d)); - size_t res = datalen + 4; - if (b58tobin(d, &res, str) != true) { - return 0; - } - uint8_t *nd = d + datalen + 4 - res; - if (b58check(nd, res, hasher_type, str) < 0) { - return 0; - } - memcpy(data, nd, res - 4); - return res - 4; -} - -#if USE_GRAPHENE -int b58gphcheck(const void *bin, size_t binsz, const char *base58str) { - unsigned char buf[32] = {0}; - const uint8_t *binc = bin; - unsigned i = 0; - if (binsz < 4) return -4; - ripemd160(bin, binsz - 4, buf); // No double SHA256, but a single RIPEMD160 - if (memcmp(&binc[binsz - 4], buf, 4)) return -1; - - // Check number of zeros is correct AFTER verifying checksum (to avoid - // possibility of accessing base58str beyond the end) - for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i) { - } // Just finding the end of zeros, nothing to do in loop - if (binc[i] == '\0' || base58str[i] == '1') return -3; - - return binc[0]; -} - -int base58gph_encode_check(const uint8_t *data, int datalen, char *str, - int strsize) { - if (datalen > 128) { - return 0; - } - uint8_t buf[datalen + 32]; - memset(buf, 0, sizeof(buf)); - uint8_t *hash = buf + datalen; - memcpy(buf, data, datalen); - ripemd160(data, datalen, hash); // No double SHA256, but a single RIPEMD160 - size_t res = strsize; - bool success = b58enc(str, &res, buf, datalen + 4); - memzero(buf, sizeof(buf)); - return success ? res : 0; -} - -int base58gph_decode_check(const char *str, uint8_t *data, int datalen) { - if (datalen > 128) { - return 0; - } - uint8_t d[datalen + 4]; - memset(d, 0, sizeof(d)); - size_t res = datalen + 4; - if (b58tobin(d, &res, str) != true) { - return 0; - } - uint8_t *nd = d + datalen + 4 - res; - if (b58gphcheck(nd, res, str) < 0) { - return 0; - } - memcpy(data, nd, res - 4); - return res - 4; -} -#endif diff --git a/deps/crypto/trezor-crypto/base58.h b/deps/crypto/trezor-crypto/base58.h deleted file mode 100644 index 97cb54e60..000000000 --- a/deps/crypto/trezor-crypto/base58.h +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Copyright (c) 2013-2014 Tomas Dzetkulic - * Copyright (c) 2013-2014 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __BASE58_H__ -#define __BASE58_H__ - -#include -#include -#include "hasher.h" -#include "options.h" - -extern const char b58digits_ordered[]; -extern const int8_t b58digits_map[]; - -int base58_encode_check(const uint8_t *data, int len, HasherType hasher_type, - char *str, int strsize); -int base58_decode_check(const char *str, HasherType hasher_type, uint8_t *data, - int datalen); - -// Private -bool b58tobin(void *bin, size_t *binszp, const char *b58); -int b58check(const void *bin, size_t binsz, HasherType hasher_type, - const char *base58str); -bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz); - -#if USE_GRAPHENE -int base58gph_encode_check(const uint8_t *data, int datalen, char *str, - int strsize); -int base58gph_decode_check(const char *str, uint8_t *data, int datalen); -int b58gphcheck(const void *bin, size_t binsz, const char *base58str); -#endif - -#endif diff --git a/deps/crypto/trezor-crypto/bignum.c b/deps/crypto/trezor-crypto/bignum.c deleted file mode 100644 index e2bb9a129..000000000 --- a/deps/crypto/trezor-crypto/bignum.c +++ /dev/null @@ -1,1833 +0,0 @@ -/** - * Copyright (c) 2013-2014 Tomas Dzetkulic - * Copyright (c) 2013-2014 Pavol Rusnak - * Copyright (c) 2015 Jochen Hoenicke - * Copyright (c) 2016 Alex Beregszaszi - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "bignum.h" - -#include -#include -#include -#include - -#include "memzero.h" -#include "script.h" - -/* - This library implements 256-bit numbers arithmetic. - - An unsigned 256-bit number is represented by a bignum256 structure, that is an - array of nine 32-bit values called limbs. Limbs are digits of the number in - the base 2**29 representation in the little endian order. This means that - bignum256 x; - represents the value - sum([x[i] * 2**(29*i) for i in range(9)). - - A limb of a bignum256 is *normalized* iff it's less than 2**29. - A bignum256 is *normalized* iff every its limb is normalized. - A number is *fully reduced modulo p* iff it is less than p. - A number is *partly reduced modulo p* iff is is less than 2*p. - The number p is usually a prime number such that 2^256 - 2^224 <= p <= 2^256. - - All functions except bn_fast_mod expect that all their bignum256 inputs are - normalized. (The function bn_fast_mod allows the input number to have the - most significant limb unnormalized). All bignum256 outputs of all functions - are guaranteed to be normalized. - - A number can be partly reduced with bn_fast_mod, a partly reduced number can - be fully reduced with bn_mod. - - A function has *constant control flow with regard to its argument* iff the - order in which instructions of the function are executed doesn't depend on the - value of the argument. - A function has *constant memory access flow with regard to its argument* iff - the memory addresses that are acessed and the order in which they are accessed - don't depend on the value of the argument. - A function *has contant control (memory access) flow* iff it has constant - control (memory access) flow with regard to all its arguments. - - The following function has contant control flow with regard to its arugment - n, however is doesn't have constant memory access flow with regard to it: - void (int n, int *a) } - a[0] = 0; - a[n] = 0; // memory address reveals the value of n - } - - Unless stated otherwise all functions are supposed to have both constant - control flow and constant memory access flow. - */ - -#define BN_MAX_DECIMAL_DIGITS \ - 79 // floor(log(2**(LIMBS * BITS_PER_LIMB), 10)) + 1 - -// out_number = (bignum256) in_number -// Assumes in_number is a raw bigendian 256-bit number -// Guarantees out_number is normalized -void bn_read_be(const uint8_t *in_number, bignum256 *out_number) { - uint32_t temp = 0; - - for (int i = 0; i < BN_LIMBS - 1; i++) { - uint32_t limb = read_be(in_number + (BN_LIMBS - 2 - i) * 4); - - temp |= limb << (BN_EXTRA_BITS * i); - out_number->val[i] = temp & BN_LIMB_MASK; - - temp = limb >> (32 - BN_EXTRA_BITS * (i + 1)); - } - - out_number->val[BN_LIMBS - 1] = temp; -} - -// out_number = (256BE) in_number -// Assumes in_number < 2**256 -// Guarantess out_number is a raw bigendian 256-bit number -void bn_write_be(const bignum256 *in_number, uint8_t *out_number) { - uint32_t temp = in_number->val[BN_LIMBS - 1]; - for (int i = BN_LIMBS - 2; i >= 0; i--) { - uint32_t limb = in_number->val[i]; - - temp = (temp << (BN_BITS_PER_LIMB - BN_EXTRA_BITS * i)) | - (limb >> (BN_EXTRA_BITS * i)); - write_be(out_number + (BN_LIMBS - 2 - i) * 4, temp); - - temp = limb; - } -} - -// out_number = (bignum256) in_number -// Assumes in_number is a raw little endian 256-bit number -// Guarantees out_number is normalized -void bn_read_le(const uint8_t *in_number, bignum256 *out_number) { - uint32_t temp = 0; - for (int i = 0; i < BN_LIMBS - 1; i++) { - uint32_t limb = read_le(in_number + i * 4); - - temp |= limb << (BN_EXTRA_BITS * i); - out_number->val[i] = temp & BN_LIMB_MASK; - temp = limb >> (32 - BN_EXTRA_BITS * (i + 1)); - } - - out_number->val[BN_LIMBS - 1] = temp; -} - -// out_number = (256LE) in_number -// Assumes in_number < 2**256 -// Guarantess out_number is a raw little endian 256-bit number -void bn_write_le(const bignum256 *in_number, uint8_t *out_number) { - uint32_t temp = in_number->val[BN_LIMBS - 1]; - - for (int i = BN_LIMBS - 2; i >= 0; i--) { - uint32_t limb = in_number->val[i]; - temp = (temp << (BN_BITS_PER_LIMB - BN_EXTRA_BITS * i)) | - (limb >> (BN_EXTRA_BITS * i)); - write_le(out_number + i * 4, temp); - temp = limb; - } -} - -// out_number = (bignum256) in_number -// Guarantees out_number is normalized -void bn_read_uint32(uint32_t in_number, bignum256 *out_number) { - out_number->val[0] = in_number & BN_LIMB_MASK; - out_number->val[1] = in_number >> BN_BITS_PER_LIMB; - for (uint32_t i = 2; i < BN_LIMBS; i++) out_number->val[i] = 0; -} - -// out_number = (bignum256) in_number -// Guarantees out_number is normalized -void bn_read_uint64(uint64_t in_number, bignum256 *out_number) { - out_number->val[0] = in_number & BN_LIMB_MASK; - out_number->val[1] = (in_number >>= BN_BITS_PER_LIMB) & BN_LIMB_MASK; - out_number->val[2] = in_number >> BN_BITS_PER_LIMB; - for (uint32_t i = 3; i < BN_LIMBS; i++) out_number->val[i] = 0; -} - -// Returns the bitsize of x -// Assumes x is normalized -// The function doesn't have neither constant control flow nor constant memory -// access flow -int bn_bitcount(const bignum256 *x) { - for (int i = BN_LIMBS - 1; i >= 0; i--) { - uint32_t limb = x->val[i]; - if (limb != 0) { - // __builtin_clz returns the number of leading zero bits starting at the - // most significant bit position - return i * BN_BITS_PER_LIMB + (32 - __builtin_clz(limb)); - } - } - return 0; -} - -// Returns the number of decimal digits of x; if x is 0, returns 1 -// Assumes x is normalized -// The function doesn't have neither constant control flow nor constant memory -// access flow -unsigned int bn_digitcount(const bignum256 *x) { - bignum256 val = {0}; - bn_copy(x, &val); - - unsigned int digits = 1; - for (unsigned int i = 0; i < BN_MAX_DECIMAL_DIGITS; i += 3) { - uint32_t limb = 0; - - bn_divmod1000(&val, &limb); - - if (limb >= 100) { - digits = i + 3; - } else if (limb >= 10) { - digits = i + 2; - } else if (limb >= 1) { - digits = i + 1; - } - } - - memzero(&val, sizeof(val)); - - return digits; -} - -// x = 0 -// Guarantees x is normalized -void bn_zero(bignum256 *x) { - for (int i = 0; i < BN_LIMBS; i++) { - x->val[i] = 0; - } -} - -// x = 1 -// Guarantees x is normalized -void bn_one(bignum256 *x) { - x->val[0] = 1; - for (int i = 1; i < BN_LIMBS; i++) { - x->val[i] = 0; - } -} - -// Returns x == 0 -// Assumes x is normalized -int bn_is_zero(const bignum256 *x) { - uint32_t result = 0; - for (int i = 0; i < BN_LIMBS; i++) { - result |= x->val[i]; - } - return !result; -} - -// Returns x == 1 -// Assumes x is normalized -int bn_is_one(const bignum256 *x) { - uint32_t result = x->val[0] ^ 1; - for (int i = 1; i < BN_LIMBS; i++) { - result |= x->val[i]; - } - return !result; -} - -// Returns x < y -// Assumes x, y are normalized -int bn_is_less(const bignum256 *x, const bignum256 *y) { - uint32_t res1 = 0; - uint32_t res2 = 0; - for (int i = BN_LIMBS - 1; i >= 0; i--) { - res1 = (res1 << 1) | (x->val[i] < y->val[i]); - res2 = (res2 << 1) | (x->val[i] > y->val[i]); - } - return res1 > res2; -} - -// Returns x == y -// Assumes x, y are normalized -int bn_is_equal(const bignum256 *x, const bignum256 *y) { - uint32_t result = 0; - for (int i = 0; i < BN_LIMBS; i++) { - result |= x->val[i] ^ y->val[i]; - } - return !result; -} - -// res = cond if truecase else falsecase -// Assumes cond is either 0 or 1 -// Works properly even if &res == &truecase or &res == &falsecase or -// &truecase == &falsecase or &res == &truecase == &falsecase -void bn_cmov(bignum256 *res, volatile uint32_t cond, const bignum256 *truecase, - const bignum256 *falsecase) { - // Intentional use of bitwise OR operator to ensure constant-time - assert((int)(cond == 1) | (int)(cond == 0)); - - uint32_t tmask = -cond; // tmask = 0xFFFFFFFF if cond else 0x00000000 - uint32_t fmask = ~tmask; // fmask = 0x00000000 if cond else 0xFFFFFFFF - - for (int i = 0; i < BN_LIMBS; i++) { - res->val[i] = (truecase->val[i] & tmask) | (falsecase->val[i] & fmask); - } -} - -// x = -x % prime if cond else x, -// Explicitly x = (3 * prime - x if x > prime else 2 * prime - x) if cond else -// else (x if x > prime else x + prime) -// Assumes x is normalized and partly reduced -// Assumes cond is either 1 or 0 -// Guarantees x is normalized -// Assumes prime is normalized and -// 0 < prime < 2**260 == 2**(BITS_PER_LIMB * LIMBS - 1) -void bn_cnegate(volatile uint32_t cond, bignum256 *x, const bignum256 *prime) { - // Intentional use of bitwise OR operator to ensure constant time - assert((int)(cond == 1) | (int)(cond == 0)); - - uint32_t tmask = -cond; // tmask = 0xFFFFFFFF if cond else 0x00000000 - uint32_t fmask = ~tmask; // fmask = 0x00000000 if cond else 0xFFFFFFFF - - bn_mod(x, prime); - // x < prime - - uint32_t acc1 = 1; - uint32_t acc2 = 0; - - for (int i = 0; i < BN_LIMBS; i++) { - acc1 += (BN_BASE - 1) + 2 * prime->val[i] - x->val[i]; - // acc1 neither overflows 32 bits nor underflows 0 - // Proof: - // acc1 + (BASE - 1) + 2 * prime[i] - x[i] - // >= (BASE - 1) - x >= (2**BITS_PER_LIMB - 1) - (2**BITS_PER_LIMB - 1) - // == 0 - // acc1 + (BASE - 1) + 2 * prime[i] - x[i] - // <= acc1 + (BASE - 1) + 2 * prime[i] - // <= (2**(32 - BITS_PER_LIMB) - 1) + 2 * (2**BITS_PER_LIMB - 1) + - // (2**BITS_PER_LIMB - 1) - // == 7 + 3 * 2**29 < 2**32 - - acc2 += prime->val[i] + x->val[i]; - // acc2 doesn't overflow 32 bits - // Proof: - // acc2 + prime[i] + x[i] - // <= 2**(32 - BITS_PER_LIMB) - 1 + 2 * (2**BITS_PER_LIMB - 1) - // == 2**(32 - BITS_PER_LIMB) + 2**(BITS_PER_LIMB + 1) - 2 - // == 2**30 + 5 < 2**32 - - // x = acc1 & LIMB_MASK if cond else acc2 & LIMB_MASK - x->val[i] = ((acc1 & tmask) | (acc2 & fmask)) & BN_LIMB_MASK; - - acc1 >>= BN_BITS_PER_LIMB; - // acc1 <= 7 == 2**(32 - BITS_PER_LIMB) - 1 - // acc1 == 2**(BITS_PER_LIMB * (i + 1)) + 2 * prime[:i + 1] - x[:i + 1] - // >> BITS_PER_LIMB * (i + 1) - - acc2 >>= BN_BITS_PER_LIMB; - // acc2 <= 7 == 2**(32 - BITS_PER_LIMB) - 1 - // acc2 == prime[:i + 1] + x[:i + 1] >> BITS_PER_LIMB * (i + 1) - } - - // assert(acc1 == 1); // assert prime <= 2**260 - // assert(acc2 == 0); - - // clang-format off - // acc1 == 1 - // Proof: - // acc1 == 2**(BITS_PER_LIMB * LIMBS) + 2 * prime[:LIMBS] - x[:LIMBS] >> BITS_PER_LIMB * LIMBS - // == 2**(BITS_PER_LIMB * LIMBS) + 2 * prime - x >> BITS_PER_LIMB * LIMBS - // <= 2**(BITS_PER_LIMB * LIMBS) + 2 * prime >> BITS_PER_LIMB * LIMBS - // <= 2**(BITS_PER_LIMB * LIMBS) + 2 * (2**(BITS_PER_LIMB * LIMBS - 1) - 1) >> BITS_PER_LIMB * LIMBS - // <= 2**(BITS_PER_LIMB * LIMBS) + 2**(BITS_PER_LIMB * LIMBS) - 2 >> BITS_PER_LIMB * LIMBS - // == 1 - - // acc1 == 2**(BITS_PER_LIMB * LIMBS) + 2 * prime[:LIMBS] - x[:LIMBS] >> BITS_PER_LIMB * LIMBS - // == 2**(BITS_PER_LIMB * LIMBS) + 2 * prime - x >> BITS_PER_LIMB * LIMBS - // >= 2**(BITS_PER_LIMB * LIMBS) + 0 >> BITS_PER_LIMB * LIMBS - // == 1 - - // acc2 == 0 - // Proof: - // acc2 == prime[:LIMBS] + x[:LIMBS] >> BITS_PER_LIMB * LIMBS - // == prime + x >> BITS_PER_LIMB * LIMBS - // <= 2 * prime - 1 >> BITS_PER_LIMB * LIMBS - // <= 2 * (2**(BITS_PER_LIMB * LIMBS - 1) - 1) - 1 >> 261 - // == 2**(BITS_PER_LIMB * LIMBS) - 3 >> BITS_PER_LIMB * LIMBS - // == 0 - // clang-format on -} - -// x <<= 1 -// Assumes x is normalized, x < 2**260 == 2**(LIMBS*BITS_PER_LIMB - 1) -// Guarantees x is normalized -void bn_lshift(bignum256 *x) { - for (int i = BN_LIMBS - 1; i > 0; i--) { - x->val[i] = ((x->val[i] << 1) & BN_LIMB_MASK) | - (x->val[i - 1] >> (BN_BITS_PER_LIMB - 1)); - } - x->val[0] = (x->val[0] << 1) & BN_LIMB_MASK; -} - -// x >>= 1, i.e. x = floor(x/2) -// Assumes x is normalized -// Guarantees x is normalized -// If x is partly reduced (fully reduced) modulo prime, -// guarantess x will be partly reduced (fully reduced) modulo prime -void bn_rshift(bignum256 *x) { - for (int i = 0; i < BN_LIMBS - 1; i++) { - x->val[i] = - (x->val[i] >> 1) | ((x->val[i + 1] & 1) << (BN_BITS_PER_LIMB - 1)); - } - x->val[BN_LIMBS - 1] >>= 1; -} - -// Sets i-th least significant bit (counting from zero) -// Assumes x is normalized and 0 <= i < 261 == LIMBS*BITS_PER_LIMB -// Guarantees x is normalized -// The function has constant control flow but not constant memory access flow -// with regard to i -void bn_setbit(bignum256 *x, uint16_t i) { - assert(i < BN_LIMBS * BN_BITS_PER_LIMB); - x->val[i / BN_BITS_PER_LIMB] |= (1u << (i % BN_BITS_PER_LIMB)); -} - -// clears i-th least significant bit (counting from zero) -// Assumes x is normalized and 0 <= i < 261 == LIMBS*BITS_PER_LIMB -// Guarantees x is normalized -// The function has constant control flow but not constant memory access flow -// with regard to i -void bn_clearbit(bignum256 *x, uint16_t i) { - assert(i < BN_LIMBS * BN_BITS_PER_LIMB); - x->val[i / BN_BITS_PER_LIMB] &= ~(1u << (i % BN_BITS_PER_LIMB)); -} - -// returns i-th least significant bit (counting from zero) -// Assumes x is normalized and 0 <= i < 261 == LIMBS*BITS_PER_LIMB -// The function has constant control flow but not constant memory access flow -// with regard to i -uint32_t bn_testbit(const bignum256 *x, uint16_t i) { - assert(i < BN_LIMBS * BN_BITS_PER_LIMB); - return (x->val[i / BN_BITS_PER_LIMB] >> (i % BN_BITS_PER_LIMB)) & 1; -} - -// res = x ^ y -// Assumes x, y are normalized -// Guarantees res is normalized -// Works properly even if &res == &x or &res == &y or &res == &x == &y -void bn_xor(bignum256 *res, const bignum256 *x, const bignum256 *y) { - for (int i = 0; i < BN_LIMBS; i++) { - res->val[i] = x->val[i] ^ y->val[i]; - } -} - -// x = x / 2 % prime -// Explicitly x = x / 2 if is_even(x) else (x + prime) / 2 -// Assumes x is normalized, x + prime < 261 == LIMBS * BITS_PER_LIMB -// Guarantees x is normalized -// If x is partly reduced (fully reduced) modulo prime, -// guarantess x will be partly reduced (fully reduced) modulo prime -// Assumes prime is an odd number and normalized -void bn_mult_half(bignum256 *x, const bignum256 *prime) { - // x = x / 2 if is_even(x) else (x + prime) / 2 - - uint32_t x_is_odd_mask = - -(x->val[0] & 1); // x_is_odd_mask = 0xFFFFFFFF if is_odd(x) else 0 - - uint32_t acc = (x->val[0] + (prime->val[0] & x_is_odd_mask)) >> 1; - // acc < 2**BITS_PER_LIMB - // Proof: - // acc == x[0] + prime[0] & x_is_odd_mask >> 1 - // <= (2**(BITS_PER_LIMB) - 1) + (2**(BITS_PER_LIMB) - 1) >> 1 - // == 2**(BITS_PER_LIMB + 1) - 2 >> 1 - // < 2**(BITS_PER_LIMB) - - for (int i = 0; i < BN_LIMBS - 1; i++) { - uint32_t temp = (x->val[i + 1] + (prime->val[i + 1] & x_is_odd_mask)); - // temp < 2**(BITS_PER_LIMB + 1) - // Proof: - // temp == x[i + 1] + val[i + 1] & x_is_odd_mask - // <= (2**(BITS_PER_LIMB) - 1) + (2**(BITS_PER_LIMB) - 1) - // < 2**(BITS_PER_LIMB + 1) - - acc += (temp & 1) << (BN_BITS_PER_LIMB - 1); - // acc doesn't overflow 32 bits - // Proof: - // acc + (temp & 1 << BITS_PER_LIMB - 1) - // <= 2**(BITS_PER_LIMB + 1) + 2**(BITS_PER_LIMB - 1) - // <= 2**30 + 2**28 < 2**32 - - x->val[i] = acc & BN_LIMB_MASK; - acc >>= BN_BITS_PER_LIMB; - acc += temp >> 1; - // acc < 2**(BITS_PER_LIMB + 1) - // Proof: - // acc + (temp >> 1) - // <= (2**(32 - BITS_PER_LIMB) - 1) + (2**(BITS_PER_LIMB + 1) - 1 >> 1) - // == 7 + 2**(BITS_PER_LIMB) - 1 < 2**(BITS_PER_LIMB + 1) - - // acc == x[:i+2]+(prime[:i+2] & x_is_odd_mask) >> BITS_PER_LIMB * (i+1) - } - x->val[BN_LIMBS - 1] = acc; - - // assert(acc >> BITS_PER_LIMB == 0); - // acc >> BITS_PER_LIMB == 0 - // Proof: - // acc - // == x[:LIMBS] + (prime[:LIMBS] & x_is_odd_mask) >> BITS_PER_LIMB*LIMBS - // == x + (prime & x_is_odd_mask) >> BITS_PER_LIMB * LIMBS - // <= x + prime >> BITS_PER_LIMB * LIMBS - // <= 2**(BITS_PER_LIMB * LIMBS) - 1 >> BITS_PER_LIMB * LIMBS - // == 0 -} - -// x = x * k % prime -// Assumes x is normalized, 0 <= k <= 8 = 2**(32 - BITS_PER_LIMB) -// Assumes prime is normalized and 2^256 - 2^224 <= prime <= 2^256 -// Guarantees x is normalized and partly reduced modulo prime -void bn_mult_k(bignum256 *x, uint8_t k, const bignum256 *prime) { - assert(k <= 8); - - for (int i = 0; i < BN_LIMBS; i++) { - x->val[i] = k * x->val[i]; - // x[i] doesn't overflow 32 bits - // k * x[i] <= 2**(32 - BITS_PER_LIMB) * (2**BITS_PER_LIMB - 1) - // < 2**(32 - BITS_PER_LIMB) * 2**BITS_PER_LIMB == 2**32 - } - - bn_fast_mod(x, prime); -} - -// Reduces partly reduced x modulo prime -// Explicitly x = x if x < prime else x - prime -// Assumes x is partly reduced modulo prime -// Guarantees x is fully reduced modulo prime -// Assumes prime is nonzero and normalized -void bn_mod(bignum256 *x, const bignum256 *prime) { - uint32_t x_less_prime = bn_is_less(x, prime); - - bignum256 temp = {0}; - bn_subtract(x, prime, &temp); - bn_cmov(x, x_less_prime, x, &temp); - - memzero(&temp, sizeof(temp)); -} - -// Auxiliary function for bn_multiply -// res = k * x -// Assumes k and x are normalized -// Guarantees res is normalized 18 digit little endian number in base 2**29 -void bn_multiply_long(const bignum256 *k, const bignum256 *x, - uint32_t res[2 * BN_LIMBS]) { - // Uses long multiplication in base 2**29, see - // https://en.wikipedia.org/wiki/Multiplication_algorithm#Long_multiplication - - uint64_t acc = 0; - - // compute lower half - for (int i = 0; i < BN_LIMBS; i++) { - for (int j = 0; j <= i; j++) { - acc += k->val[j] * (uint64_t)x->val[i - j]; - // acc doesn't overflow 64 bits - // Proof: - // acc <= acc + sum([k[j] * x[i-j] for j in range(i)]) - // <= (2**(64 - BITS_PER_LIMB) - 1) + - // LIMBS * (2**BITS_PER_LIMB - 1) * (2**BITS_PER_LIMB - 1) - // == (2**35 - 1) + 9 * (2**29 - 1) * (2**29 - 1) - // <= 2**35 + 9 * 2**58 < 2**64 - } - - res[i] = acc & BN_LIMB_MASK; - acc >>= BN_BITS_PER_LIMB; - // acc <= 2**35 - 1 == 2**(64 - BITS_PER_LIMB) - 1 - } - - // compute upper half - for (int i = BN_LIMBS; i < 2 * BN_LIMBS - 1; i++) { - for (int j = i - BN_LIMBS + 1; j < BN_LIMBS; j++) { - acc += k->val[j] * (uint64_t)x->val[i - j]; - // acc doesn't overflow 64 bits - // Proof: - // acc <= acc + sum([k[j] * x[i-j] for j in range(i)]) - // <= (2**(64 - BITS_PER_LIMB) - 1) - // LIMBS * (2**BITS_PER_LIMB - 1) * (2**BITS_PER_LIMB - 1) - // == (2**35 - 1) + 9 * (2**29 - 1) * (2**29 - 1) - // <= 2**35 + 9 * 2**58 < 2**64 - } - - res[i] = acc & (BN_BASE - 1); - acc >>= BN_BITS_PER_LIMB; - // acc < 2**35 == 2**(64 - BITS_PER_LIMB) - } - - res[2 * BN_LIMBS - 1] = acc; -} - -// Auxiliary function for bn_multiply -// Assumes 0 <= d <= 8 == LIMBS - 1 -// Assumes res is normalized and res < 2**(256 + 29*d + 31) -// Guarantess res in normalized and res < 2 * prime * 2**(29*d) -// Assumes prime is normalized, 2**256 - 2**224 <= prime <= 2**256 -void bn_multiply_reduce_step(uint32_t res[2 * BN_LIMBS], const bignum256 *prime, - uint32_t d) { - // clang-format off - // Computes res = res - (res // 2**(256 + BITS_PER_LIMB * d)) * prime * 2**(BITS_PER_LIMB * d) - - // res - (res // 2**(256 + BITS_PER_LIMB * d)) * prime * 2**(BITS_PER_LIMB * d) < 2 * prime * 2**(BITS_PER_LIMB * d) - // Proof: - // res - res // (2**(256 + BITS_PER_LIMB * d)) * 2**(BITS_PER_LIMB * d) * prime - // == res - res // (2**(256 + BITS_PER_LIMB * d)) * 2**(BITS_PER_LIMB * d) * (2**256 - (2**256 - prime)) - // == res - res // (2**(256 + BITS_PER_LIMB * d)) * 2**(BITS_PER_LIMB * d) * 2**256 + res // (2**(256 + BITS_PER_LIMB * d)) * 2**(BITS_PER_LIMB * d) * (2**256 - prime) - // == (res % 2**(256 + BITS_PER_LIMB * d)) + res // (2**256 + BITS_PER_LIMB * d) * 2**(BITS_PER_LIMB * d) * (2**256 - prime) - // <= (2**(256 + 29*d + 31) % 2**(256 + 29*d)) + (2**(256 + 29*d + 31) - 1) / (2**256 + 29*d) * 2**(29*d) * (2**256 - prime) - // <= 2**(256 + 29*d) + 2**(256 + 29*d + 31) / (2**256 + 29*d) * 2**(29*d) * (2**256 - prime) - // == 2**(256 + 29*d) + 2**31 * 2**(29*d) * (2**256 - prime) - // == 2**(29*d) * (2**256 + 2**31 * (2*256 - prime)) - // <= 2**(29*d) * (2**256 + 2**31 * 2*224) - // <= 2**(29*d) * (2**256 + 2**255) - // <= 2**(29*d) * 2 * (2**256 - 2**224) - // <= 2 * prime * 2**(29*d) - // clang-format on - - uint32_t coef = - (res[d + BN_LIMBS - 1] >> (256 - (BN_LIMBS - 1) * BN_BITS_PER_LIMB)) + - (res[d + BN_LIMBS] << ((BN_LIMBS * BN_BITS_PER_LIMB) - 256)); - - // coef == res // 2**(256 + BITS_PER_LIMB * d) - - // coef < 2**31 - // Proof: - // coef == res // 2**(256 + BITS_PER_LIMB * d) - // < 2**(256 + 29 * d + 31) // 2**(256 + 29 * d) - // == 2**31 - - const int shift = 31; - uint64_t acc = 1ull << shift; - - for (int i = 0; i < BN_LIMBS; i++) { - acc += (((uint64_t)(BN_BASE - 1)) << shift) + res[d + i] - - prime->val[i] * (uint64_t)coef; - // acc neither overflow 64 bits nor underflow zero - // Proof: - // acc + ((BASE - 1) << shift) + res[d + i] - prime[i] * coef - // >= ((BASE - 1) << shift) - prime[i] * coef - // == 2**shift * (2**BITS_PER_LIMB - 1) - (2**BITS_PER_LIMB - 1) * - // (2**31 - 1) - // == (2**shift - 2**31 + 1) * (2**BITS_PER_LIMB - 1) - // == (2**31 - 2**31 + 1) * (2**29 - 1) - // == 2**29 - 1 > 0 - // acc + ((BASE - 1) << shift) + res[d + i] - prime[i] * coef - // <= acc + ((BASE - 1) << shift) + res[d+i] - // <= (2**(64 - BITS_PER_LIMB) - 1) + 2**shift * (2**BITS_PER_LIMB - 1) - // + (2*BITS_PER_LIMB - 1) - // == (2**(64 - BITS_PER_LIMB) - 1) + (2**shift + 1) * - // (2**BITS_PER_LIMB - 1) - // == (2**35 - 1) + (2**31 + 1) * (2**29 - 1) - // <= 2**35 + 2**60 + 2**29 < 2**64 - - res[d + i] = acc & BN_LIMB_MASK; - acc >>= BN_BITS_PER_LIMB; - // acc <= 2**(64 - BITS_PER_LIMB) - 1 == 2**35 - 1 - - // acc == (1 << BITS_PER_LIMB * (i + 1) + shift) + res[d : d + i + 1] - // - coef * prime[:i + 1] >> BITS_PER_LIMB * (i + 1) - } - - // acc += (((uint64_t)(BASE - 1)) << shift) + res[d + LIMBS]; - // acc >>= BITS_PER_LIMB; - // assert(acc <= 1ul << shift); - - // clang-format off - // acc == 1 << shift - // Proof: - // acc - // == (1 << BITS_PER_LIMB * (LIMBS + 1) + shift) + res[d : d + LIMBS + 1] - coef * prime[:LIMBS] >> BITS_PER_LIMB * (LIMBS + 1) - // == (1 << BITS_PER_LIMB * (LIMBS + 1) + shift) + res[d : d + LIMBS + 1] - coef * prime >> BITS_PER_LIMB * (LIMBS + 1) - - // == (1 << BITS_PER_LIMB * (LIMBS + 1) + shift) + (res[d : d + LIMBS + 1] - coef * prime) >> BITS_PER_LIMB * (LIMBS + 1) - // <= (1 << BITS_PER_LIMB * (LIMBS + 1) + shift) + (res[:d] + BASE**d * res[d : d + LIMBS + 1] - BASE**d * coef * prime)//BASE**d >> BITS_PER_LIMB * (LIMBS + 1) - // <= (1 << BITS_PER_LIMB * (LIMBS + 1) + shift) + (res - BASE**d * coef * prime) // BASE**d >> BITS_PER_LIMB * (LIMBS + 1) - // == (1 << BITS_PER_LIMB * (LIMBS + 1) + shift) + (2 * prime * BASE**d) // BASE**d >> BITS_PER_LIMB * (LIMBS + 1) - // <= (1 << 321) + 2 * 2**256 >> 290 - // == 1 << 31 == 1 << shift - - // == (1 << BITS_PER_LIMB * (LIMBS + 1) + shift) + res[d : d + LIMBS + 1] - coef * prime[:LIMBS + 1] >> BITS_PER_LIMB * (LIMBS + 1) - // >= (1 << BITS_PER_LIMB * (LIMBS + 1) + shift) + 0 >> BITS_PER_LIMB * (LIMBS + 1) - // == 1 << shift - // clang-format on - - res[d + BN_LIMBS] = 0; -} - -// Auxiliary function for bn_multiply -// Partly reduces res and stores both in x and res -// Assumes res in normalized and res < 2**519 -// Guarantees x is normalized and partly reduced modulo prime -// Assumes prime is normalized, 2**256 - 2**224 <= prime <= 2**256 -void bn_multiply_reduce(bignum256 *x, uint32_t res[2 * BN_LIMBS], - const bignum256 *prime) { - for (int i = BN_LIMBS - 1; i >= 0; i--) { - // res < 2**(256 + 29*i + 31) - // Proof: - // if i == LIMBS - 1: - // res < 2**519 - // == 2**(256 + 29 * 8 + 31) - // == 2**(256 + 29 * (LIMBS - 1) + 31) - // else: - // res < 2 * prime * 2**(29 * (i + 1)) - // <= 2**256 * 2**(29*i + 29) < 2**(256 + 29*i + 31) - bn_multiply_reduce_step(res, prime, i); - } - - for (int i = 0; i < BN_LIMBS; i++) { - x->val[i] = res[i]; - } -} - -// x = k * x % prime -// Assumes k, x are normalized, k * x < 2**519 -// Guarantees x is normalized and partly reduced modulo prime -// Assumes prime is normalized, 2**256 - 2**224 <= prime <= 2**256 -void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime) { - uint32_t res[2 * BN_LIMBS] = {0}; - - bn_multiply_long(k, x, res); - bn_multiply_reduce(x, res, prime); - - memzero(res, sizeof(res)); -} - -// Partly reduces x modulo prime -// Assumes limbs of x except the last (the most significant) one are normalized -// Assumes prime is normalized and 2^256 - 2^224 <= prime <= 2^256 -// Guarantees x is normalized and partly reduced modulo prime -void bn_fast_mod(bignum256 *x, const bignum256 *prime) { - // Computes x = x - (x // 2**256) * prime - - // x < 2**((LIMBS - 1) * BITS_PER_LIMB + 32) == 2**264 - - // x - (x // 2**256) * prime < 2 * prime - // Proof: - // x - (x // 2**256) * prime - // == x - (x // 2**256) * (2**256 - (2**256 - prime)) - // == x - ((x // 2**256) * 2**256) + (x // 2**256) * (2**256 - prime) - // == (x % prime) + (x // 2**256) * (2**256 - prime) - // <= prime - 1 + (2**264 // 2**256) * (2**256 - prime) - // <= 2**256 + 2**8 * 2**224 == 2**256 + 2**232 - // < 2 * (2**256 - 2**224) - // <= 2 * prime - - // x - (x // 2**256 - 1) * prime < 2 * prime - // Proof: - // x - (x // 2**256) * prime + prime - // == x - (x // 2**256) * (2**256 - (2**256 - prime)) + prime - // == x - ((x//2**256) * 2**256) + (x//2**256) * (2**256 - prime) + prime - // == (x % prime) + (x // 2**256) * (2**256 - prime) + prime - // <= 2 * prime - 1 + (2**264 // 2**256) * (2**256 - prime) - // <= 2 * prime + 2**8 * 2**224 == 2**256 + 2**232 + 2**256 - 2**224 - // < 2 * (2**256 - 2**224) - // <= 2 * prime - - uint32_t coef = - x->val[BN_LIMBS - 1] >> (256 - ((BN_LIMBS - 1) * BN_BITS_PER_LIMB)); - - // clang-format off - // coef == x // 2**256 - // 0 <= coef < 2**((LIMBS - 1) * BITS_PER_LIMB + 32 - 256) == 256 - // Proof: - //* Let x[[a : b] be the number consisting of a-th to (b-1)-th bit of the number x. - // x[LIMBS - 1] >> (256 - ((LIMBS - 1) * BITS_PER_LIMB)) - // == x[[(LIMBS - 1) * BITS_PER_LIMB : (LIMBS - 1) * BITS_PER_LIMB + 32]] >> (256 - ((LIMBS - 1) * BITS_PER_LIMB)) - // == x[[256 - ((LIMBS - 1) * BITS_PER_LIMB) + (LIMBS - 1) * BITS_PER_LIMB : (LIMBS - 1) * BITS_PER_LIMB + 32]] - // == x[[256 : (LIMBS - 1) * BITS_PER_LIMB + 32]] - // == x[[256 : 264]] == x // 2**256 - // clang-format on - - const int shift = 8; - uint64_t acc = 1ull << shift; - - for (int i = 0; i < BN_LIMBS; i++) { - acc += (((uint64_t)(BN_BASE - 1)) << shift) + x->val[i] - - prime->val[i] * (uint64_t)coef; - // acc neither overflows 64 bits nor underflows 0 - // Proof: - // acc + (BASE - 1 << shift) + x[i] - prime[i] * coef - // >= (BASE - 1 << shift) - prime[i] * coef - // >= 2**shift * (2**BITS_PER_LIMB - 1) - (2**BITS_PER_LIMB - 1) * 255 - // == (2**shift - 255) * (2**BITS_PER_LIMB - 1) - // == (2**8 - 255) * (2**29 - 1) == 2**29 - 1 >= 0 - // acc + (BASE - 1 << shift) + x[i] - prime[i] * coef - // <= acc + ((BASE - 1) << shift) + x[i] - // <= (2**(64 - BITS_PER_LIMB) - 1) + 2**shift * (2**BITS_PER_LIMB - 1) - // + (2**32 - 1) - // == (2**35 - 1) + 2**8 * (2**29 - 1) + 2**32 - // < 2**35 + 2**37 + 2**32 < 2**64 - - x->val[i] = acc & BN_LIMB_MASK; - acc >>= BN_BITS_PER_LIMB; - // acc <= 2**(64 - BITS_PER_LIMB) - 1 == 2**35 - 1 - - // acc == (1 << BITS_PER_LIMB * (i + 1) + shift) + x[:i + 1] - // - coef * prime[:i + 1] >> BITS_PER_LIMB * (i + 1) - } - - // assert(acc == 1 << shift); - - // clang-format off - // acc == 1 << shift - // Proof: - // acc - // == (1 << BITS_PER_LIMB * LIMBS + shift) + x[:LIMBS] - coef * prime[:LIMBS] >> BITS_PER_LIMB * LIMBS - // == (1 << BITS_PER_LIMB * LIMBS + shift) + (x - coef * prime) >> BITS_PER_LIMB * LIMBS - // <= (1 << BITS_PER_LIMB * LIMBS + shift) + (2 * prime) >> BITS_PER_LIMB * LIMBS - // <= (1 << BITS_PER_LIMB * LIMBS + shift) + 2 * 2**256 >> BITS_PER_LIMB * LIMBS - // <= 2**269 + 2**257 >> 2**261 - // <= 1 << 8 == 1 << shift - - // acc - // == (1 << BITS_PER_LIMB * LIMBS + shift) + x[:LIMBS] - coef * prime[:LIMBS] >> BITS_PER_LIMB * LIMBS - // >= (1 << BITS_PER_LIMB * LIMBS + shift) + 0 >> BITS_PER_LIMB * LIMBS - // == (1 << BITS_PER_LIMB * LIMBS + shift) + 0 >> BITS_PER_LIMB * LIMBS - // <= 1 << 8 == 1 << shift - // clang-format on -} - -// res = x**e % prime -// Assumes both x and e are normalized, x < 2**259 -// Guarantees res is normalized and partly reduced modulo prime -// Works properly even if &x == &res -// Assumes prime is normalized, 2**256 - 2**224 <= prime <= 2**256 -// The function doesn't have neither constant control flow nor constant memory -// access flow with regard to e -void bn_power_mod(const bignum256 *x, const bignum256 *e, - const bignum256 *prime, bignum256 *res) { - // Uses iterative right-to-left exponentiation by squaring, see - // https://en.wikipedia.org/wiki/Modular_exponentiation#Right-to-left_binary_method - - bignum256 acc = {0}; - bn_copy(x, &acc); - - bn_one(res); - for (int i = 0; i < BN_LIMBS; i++) { - uint32_t limb = e->val[i]; - - for (int j = 0; j < BN_BITS_PER_LIMB; j++) { - // Break if the following bits of the last limb are zero - if (i == BN_LIMBS - 1 && limb == 0) break; - - if (limb & 1) - // acc * res < 2**519 - // Proof: - // acc * res <= max(2**259 - 1, 2 * prime) * (2 * prime) - // == max(2**259 - 1, 2**257) * 2**257 < 2**259 * 2**257 - // == 2**516 < 2**519 - bn_multiply(&acc, res, prime); - - limb >>= 1; - // acc * acc < 2**519 - // Proof: - // acc * acc <= max(2**259 - 1, 2 * prime)**2 - // <= (2**259)**2 == 2**518 < 2**519 - bn_multiply(&acc, &acc, prime); - } - // acc == x**(e[:i + 1]) % prime - } - - memzero(&acc, sizeof(acc)); -} - -// x = sqrt(x) % prime -// Explicitly x = x**((prime+1)/4) % prime -// The other root is -sqrt(x) -// Assumes x is normalized, x < 2**259 and quadratic residuum mod prime -// Assumes prime is a prime number, prime % 4 == 3, it is normalized and -// 2**256 - 2**224 <= prime <= 2**256 -// Guarantees x is normalized and fully reduced modulo prime -// The function doesn't have neither constant control flow nor constant memory -// access flow with regard to prime -void bn_sqrt(bignum256 *x, const bignum256 *prime) { - // Uses the Lagrange formula for the primes of the special form, see - // http://en.wikipedia.org/wiki/Quadratic_residue#Prime_or_prime_power_modulus - // If prime % 4 == 3, then sqrt(x) % prime == x**((prime+1)//4) % prime - - assert(prime->val[BN_LIMBS - 1] % 4 == 3); - - // e = (prime + 1) // 4 - bignum256 e = {0}; - bn_copy(prime, &e); - bn_addi(&e, 1); - bn_rshift(&e); - bn_rshift(&e); - - bn_power_mod(x, &e, prime, x); - bn_mod(x, prime); - - memzero(&e, sizeof(e)); -} - -// a = 1/a % 2**n -// Assumes a is odd, 1 <= n <= 32 -// The function doesn't have neither constant control flow nor constant memory -// access flow with regard to n -uint32_t inverse_mod_power_two(uint32_t a, uint32_t n) { - // Uses "Explicit Quadratic Modular inverse modulo 2" from section 3.3 of "On - // Newton-Raphson iteration for multiplicative inverses modulo prime powers" - // by Jean-Guillaume Dumas, see - // https://arxiv.org/pdf/1209.6626.pdf - - // 1/a % 2**n - // = (2-a) * product([1 + (a-1)**(2**i) for i in range(1, floor(log2(n)))]) - - uint32_t acc = 2 - a; - uint32_t f = a - 1; - - // mask = (1 << n) - 1 - uint32_t mask = n == 32 ? 0xFFFFFFFF : (1u << n) - 1; - - for (uint32_t i = 1; i < n; i <<= 1) { - f = (f * f) & mask; - acc = (acc * (1 + f)) & mask; - } - - return acc; -} - -// x = (x / 2**BITS_PER_LIMB) % prime -// Assumes both x and prime are normalized -// Assumes prime is an odd number and normalized -// Guarantees x is normalized -// If x is partly reduced (fully reduced) modulo prime, -// guarantess x will be partly reduced (fully reduced) modulo prime -void bn_divide_base(bignum256 *x, const bignum256 *prime) { - // Uses an explicit formula for the modular inverse of power of two - // (x / 2**n) % prime == (x + ((-x / prime) % 2**n) * prime) // 2**n - // Proof: - // (x + ((-x / prime) % 2**n) * prime) % 2**n - // == (x - x / prime * prime) % 2**n - // == 0 - // (x + ((-1 / prime) % 2**n) * prime) % prime - // == x - // if x < prime: - // (x + ((-x / prime) % 2**n) * prime) // 2**n - // <= ((prime - 1) + (2**n - 1) * prime) / 2**n - // == (2**n * prime - 1) / 2**n == prime - 1 / 2**n < prime - // if x < 2 * prime: - // (x + ((-x / prime) % 2**n) * prime) // 2**n - // <= ((2 * prime - 1) + (2**n - 1) * prime) / 2**n - // == (2**n * prime + prime - 1) / 2**n - // == prime + (prime - 1) / 2**n < 2 * prime - - // m = (-x / prime) % 2**BITS_PER_LIMB - uint32_t m = (x->val[0] * (BN_BASE - inverse_mod_power_two( - prime->val[0], BN_BITS_PER_LIMB))) & - BN_LIMB_MASK; - // m < 2**BITS_PER_LIMB - - uint64_t acc = x->val[0] + (uint64_t)m * prime->val[0]; - acc >>= BN_BITS_PER_LIMB; - - for (int i = 1; i < BN_LIMBS; i++) { - acc = acc + x->val[i] + (uint64_t)m * prime->val[i]; - // acc does not overflow 64 bits - // acc == acc + x + m * prime - // <= 2**(64 - BITS_PER_LIMB) + 2**(BITS_PER_LIMB) - // 2**(BITS_PER_LIMB) * 2**(BITS_PER_LIMB) - // <= 2**(2 * BITS_PER_LIMB) + 2**(64 - BITS_PER_LIMB) + - // 2**(BITS_PER_LIMB) - // <= 2**58 + 2**35 + 2**29 < 2**64 - - x->val[i - 1] = acc & BN_LIMB_MASK; - acc >>= BN_BITS_PER_LIMB; - // acc < 2**35 == 2**(64 - BITS_PER_LIMB) - - // acc == x[:i + 1] + m * prime[:i + 1] >> BITS_PER_LIMB * (i + 1) - } - - x->val[BN_LIMBS - 1] = acc; - - assert(acc >> BN_BITS_PER_LIMB == 0); - - // clang-format off - // acc >> BITS_PER_LIMB == 0 - // Proof: - // acc >> BITS_PER_LIMB - // == (x[:LIMB] + m * prime[:LIMB] >> BITS_PER_LIMB * LIMBS) >> BITS_PER_LIMB * (LIMBS + 1) - // == x + m * prime >> BITS_PER_LIMB * (LIMBS + 1) - // <= (2**(BITS_PER_LIMB * LIMBS) - 1) + (2**BITS_PER_LIMB - 1) * (2**(BITS_PER_LIMB * LIMBS) - 1) >> BITS_PER_LIMB * (LIMBS + 1) - // == 2**(BITS_PER_LIMB * LIMBS) - 1 + 2**(BITS_PER_LIMB * (LIMBS + 1)) - 2**(BITS_PER_LIMB * LIMBS) - 2**BITS_PER_LIMB + 1 >> BITS_PER_LIMB * (LIMBS + 1) - // == 2**(BITS_PER_LIMB * (LIMBS + 1)) - 2**BITS_PER_LIMB >> BITS_PER_LIMB * (LIMBS + 1) - // == 0 - // clang-format on -} - -#if !USE_INVERSE_FAST -// x = 1/x % prime if x != 0 else 0 -// Assumes x is normalized -// Assumes prime is a prime number -// Guarantees x is normalized and fully reduced modulo prime -// Assumes prime is normalized, 2**256 - 2**224 <= prime <= 2**256 -// The function doesn't have neither constant control flow nor constant memory -// access flow with regard to prime -static void bn_inverse_slow(bignum256 *x, const bignum256 *prime) { - // Uses formula 1/x % prime == x**(prime - 2) % prime - // See https://en.wikipedia.org/wiki/Fermat%27s_little_theorem - - bn_fast_mod(x, prime); - - // e = prime - 2 - bignum256 e = {0}; - bn_read_uint32(2, &e); - bn_subtract(prime, &e, &e); - - bn_power_mod(x, &e, prime, x); - bn_mod(x, prime); - - memzero(&e, sizeof(e)); -} -#endif - -#if false -// x = 1/x % prime if x != 0 else 0 -// Assumes x is is_normalized -// Assumes GCD(x, prime) = 1 -// Guarantees x is normalized and fully reduced modulo prime -// Assumes prime is odd, normalized, 2**256 - 2**224 <= prime <= 2**256 -// The function doesn't have neither constant control flow nor constant memory -// access flow with regard to prime and x -static void bn_inverse_fast(bignum256 *x, const bignum256 *prime) { - // "The Almost Montgomery Inverse" from the section 3 of "Constant Time - // Modular Inversion" by Joppe W. Bos - // See http://www.joppebos.com/files/CTInversion.pdf - - /* - u = prime - v = x & prime - s = 1 - r = 0 - - k = 0 - while v != 1: - k += 1 - if is_even(u): - u = u // 2 - s = 2 * s - elif is_even(v): - v = v // 2 - r = 2 * r - elif v < u: - u = (u - v) // 2 - r = r + s - s = 2 * s - else: - v = (v - u) // 2 - s = r + s - r = 2 * r - - s = (s / 2**k) % prime - return s - */ - - if (bn_is_zero(x)) return; - - bn_fast_mod(x, prime); - bn_mod(x, prime); - - bignum256 u = {0}, v = {0}, r = {0}, s = {0}; - bn_copy(prime, &u); - bn_copy(x, &v); - bn_one(&s); - bn_zero(&r); - - int k = 0; - while (!bn_is_one(&v)) { - if ((u.val[0] & 1) == 0) { - bn_rshift(&u); - bn_lshift(&s); - } else if ((v.val[0] & 1) == 0) { - bn_rshift(&v); - bn_lshift(&r); - } else if (bn_is_less(&v, &u)) { - bn_subtract(&u, &v, &u); - bn_rshift(&u); - bn_add(&r, &s); - bn_lshift(&s); - } else { - bn_subtract(&v, &u, &v); - bn_rshift(&v); - bn_add(&s, &r); - bn_lshift(&r); - } - k += 1; - assert(!bn_is_zero(&v)); // assert GCD(x, prime) == 1 - } - - // s = s / 2**(k // BITS_PER_LIMB * BITS_PER_LIMB) - for (int i = 0; i < k / BITS_PER_LIMB; i++) { - bn_divide_base(&s, prime); - } - - // s = s / 2**(k % BITS_PER_LIMB) - for (int i = 0; i < k % BN_BITS_PER_LIMB; i++) { - bn_mult_half(&s, prime); - } - - bn_copy(&s, x); - - memzero(&u, sizeof(u)); - memzero(&v, sizeof(v)); - memzero(&r, sizeof(r)); - memzero(&s, sizeof(s)); -} -#endif - -#if USE_INVERSE_FAST -// x = 1/x % prime if x != 0 else 0 -// Assumes x is is_normalized -// Assumes GCD(x, prime) = 1 -// Guarantees x is normalized and fully reduced modulo prime -// Assumes prime is odd, normalized, 2**256 - 2**224 <= prime <= 2**256 -// The function has constant control flow but not constant memory access flow -// with regard to prime and x -static void bn_inverse_fast(bignum256 *x, const bignum256 *prime) { - // Custom constant time version of "The Almost Montgomery Inverse" from the - // section 3 of "Constant Time Modular Inversion" by Joppe W. Bos - // See http://www.joppebos.com/files/CTInversion.pdf - - /* - u = prime - v = x % prime - s = 1 - r = 0 - - k = 0 - while v != 1: - k += 1 - if is_even(u): # b1 - u = u // 2 - s = 2 * s - elif is_even(v): # b2 - v = v // 2 - r = 2 * r - elif v < u: # b3 - u = (u - v) // 2 - r = r + s - s = 2 * s - else: # b4 - v = (v - u) // 2 - s = r + s - r = 2 * r - - s = (s / 2**k) % prime - return s - */ - - bn_fast_mod(x, prime); - bn_mod(x, prime); - - bignum256 u = {0}, v = {0}, r = {0}, s = {0}; - bn_copy(prime, &u); - bn_copy(x, &v); - bn_one(&s); - bn_zero(&r); - - bignum256 zero = {0}; - bn_zero(&zero); - - int k = 0; - - int finished = 0, u_even = 0, v_even = 0, v_less_u = 0, b1 = 0, b2 = 0, - b3 = 0, b4 = 0; - finished = 0; - - for (int i = 0; i < 2 * BN_LIMBS * BN_BITS_PER_LIMB; i++) { - finished = finished | -bn_is_one(&v); - u_even = -bn_is_even(&u); - v_even = -bn_is_even(&v); - v_less_u = -bn_is_less(&v, &u); - - b1 = ~finished & u_even; - b2 = ~finished & ~b1 & v_even; - b3 = ~finished & ~b1 & ~b2 & v_less_u; - b4 = ~finished & ~b1 & ~b2 & ~b3; - -// The ternary operator for pointers with constant control flow -// BN_INVERSE_FAST_TERNARY(c, t, f) = t if c else f -// Very nasty hack, sorry for that -#define BN_INVERSE_FAST_TERNARY(c, t, f) \ - ((void *)(((c) & (uintptr_t)(t)) | (~(c) & (uintptr_t)(f)))) - - bn_subtract(BN_INVERSE_FAST_TERNARY(b3, &u, &v), - BN_INVERSE_FAST_TERNARY( - b3 | b4, BN_INVERSE_FAST_TERNARY(b3, &v, &u), &zero), - BN_INVERSE_FAST_TERNARY(b3, &u, &v)); - - bn_add(BN_INVERSE_FAST_TERNARY(b3, &r, &s), - BN_INVERSE_FAST_TERNARY(b3 | b4, BN_INVERSE_FAST_TERNARY(b3, &s, &r), - &zero)); - bn_rshift(BN_INVERSE_FAST_TERNARY(b1 | b3, &u, &v)); - bn_lshift(BN_INVERSE_FAST_TERNARY(b1 | b3, &s, &r)); - - k = k - ~finished; - } - - // s = s / 2**(k // BITS_PER_LIMB * BITS_PER_LIMB) - for (int i = 0; i < 2 * BN_LIMBS; i++) { - // s = s / 2**BITS_PER_LIMB % prime if i < k // BITS_PER_LIMB else s - bn_copy(&s, &r); - bn_divide_base(&r, prime); - bn_cmov(&s, i < k / BN_BITS_PER_LIMB, &r, &s); - } - - // s = s / 2**(k % BITS_PER_LIMB) - for (int i = 0; i < BN_BITS_PER_LIMB; i++) { - // s = s / 2 % prime if i < k % BITS_PER_LIMB else s - bn_copy(&s, &r); - bn_mult_half(&r, prime); - bn_cmov(&s, i < k % BN_BITS_PER_LIMB, &r, &s); - } - - bn_cmov(x, bn_is_zero(x), x, &s); - - memzero(&u, sizeof(u)); - memzero(&v, sizeof(v)); - memzero(&r, sizeof(s)); - memzero(&s, sizeof(s)); -} -#endif - -#if false -// x = 1/x % prime if x != 0 else 0 -// Assumes x is is_normalized -// Assumes GCD(x, prime) = 1 -// Guarantees x is normalized and fully reduced modulo prime -// Assumes prime is odd, normalized, 2**256 - 2**224 <= prime <= 2**256 -static void bn_inverse_fast(bignum256 *x, const bignum256 *prime) { - // Custom constant time version of "The Almost Montgomery Inverse" from the - // section 3 of "Constant Time Modular Inversion" by Joppe W. Bos - // See http://www.joppebos.com/files/CTInversion.pdf - - /* - u = prime - v = x % prime - s = 1 - r = 0 - - k = 0 - while v != 1: - k += 1 - if is_even(u): # b1 - u = u // 2 - s = 2 * s - elif is_even(v): # b2 - v = v // 2 - r = 2 * r - elif v < u: # b3 - u = (u - v) // 2 - r = r + s - s = 2 * s - else: # b4 - v = (v - u) // 2 - s = r + s - r = 2 * r - - s = (s / 2**k) % prime - return s - */ - - bn_fast_mod(x, prime); - bn_mod(x, prime); - - bignum256 u = {0}, v = {0}, r = {0}, s = {0}; - bn_copy(prime, &u); - bn_copy(x, &v); - bn_one(&s); - bn_zero(&r); - - bignum256 zero = {0}; - bn_zero(&zero); - - int k = 0; - - uint32_t finished = 0, u_even = 0, v_even = 0, v_less_u = 0, b1 = 0, b2 = 0, - b3 = 0, b4 = 0; - finished = 0; - - bignum256 u_half = {0}, v_half = {0}, u_minus_v_half = {0}, v_minus_u_half = {0}, r_plus_s = {0}, r_twice = {0}, s_twice = {0}; - for (int i = 0; i < 2 * BN_LIMBS * BN_BITS_PER_LIMB; i++) { - finished = finished | bn_is_one(&v); - u_even = bn_is_even(&u); - v_even = bn_is_even(&v); - v_less_u = bn_is_less(&v, &u); - - b1 = (finished ^ 1) & u_even; - b2 = (finished ^ 1) & (b1 ^ 1) & v_even; - b3 = (finished ^ 1) & (b1 ^ 1) & (b2 ^ 1) & v_less_u; - b4 = (finished ^ 1) & (b1 ^ 1) & (b2 ^ 1) & (b3 ^ 1); - - // u_half = u // 2 - bn_copy(&u, &u_half); - bn_rshift(&u_half); - - // v_half = v // 2 - bn_copy(&v, &v_half); - bn_rshift(&v_half); - - // u_minus_v_half = (u - v) // 2 - bn_subtract(&u, &v, &u_minus_v_half); - bn_rshift(&u_minus_v_half); - - // v_minus_u_half = (v - u) // 2 - bn_subtract(&v, &u, &v_minus_u_half); - bn_rshift(&v_minus_u_half); - - // r_plus_s = r + s - bn_copy(&r, &r_plus_s); - bn_add(&r_plus_s, &s); - - // r_twice = 2 * r - bn_copy(&r, &r_twice); - bn_lshift(&r_twice); - - // s_twice = 2 * s - bn_copy(&s, &s_twice); - bn_lshift(&s_twice); - - bn_cmov(&u, b1, &u_half, &u); - bn_cmov(&u, b3, &u_minus_v_half, &u); - - bn_cmov(&v, b2, &v_half, &v); - bn_cmov(&v, b4, &v_minus_u_half, &v); - - bn_cmov(&r, b2 | b4, &r_twice, &r); - bn_cmov(&r, b3, &r_plus_s, &r); - - bn_cmov(&s, b1 | b3, &s_twice, &s); - bn_cmov(&s, b4, &r_plus_s, &s); - - k = k + (finished ^ 1); - } - - // s = s / 2**(k // BITS_PER_LIMB * BITS_PER_LIMB) - for (int i = 0; i < 2 * BN_LIMBS; i++) { - // s = s / 2**BITS_PER_LIMB % prime if i < k // BITS_PER_LIMB else s - bn_copy(&s, &r); - bn_divide_base(&r, prime); - bn_cmov(&s, i < k / BITS_PER_LIMB, &r, &s); - } - - // s = s / 2**(k % BITS_PER_LIMB) - for (int i = 0; i < BN_BITS_PER_LIMB; i++) { - // s = s / 2 % prime if i < k % BITS_PER_LIMB else s - bn_copy(&s, &r); - bn_mult_half(&r, prime); - bn_cmov(&s, i < k % BN_BITS_PER_LIMB, &r, &s); - } - - bn_cmov(x, bn_is_zero(x), x, &s); - - memzero(&u, sizeof(u)); - memzero(&v, sizeof(v)); - memzero(&r, sizeof(r)); - memzero(&s, sizeof(s)); - memzero(&u_half, sizeof(u_half)); - memzero(&v_half, sizeof(v_half)); - memzero(&u_minus_v_half, sizeof(u_minus_v_half)); - memzero(&v_minus_u_half, sizeof(v_minus_u_half)); - memzero(&r_twice, sizeof(r_twice)); - memzero(&s_twice, sizeof(s_twice)); - memzero(&r_plus_s, sizeof(r_plus_s)); -} -#endif - -// Normalizes x -// Assumes x < 2**261 == 2**(LIMBS * BITS_PER_LIMB) -// Guarantees x is normalized -void bn_normalize(bignum256 *x) { - uint32_t acc = 0; - - for (int i = 0; i < BN_LIMBS; i++) { - acc += x->val[i]; - // acc doesn't overflow 32 bits - // Proof: - // acc + x[i] - // <= (2**(32 - BITS_PER_LIMB) - 1) + (2**BITS_PER_LIMB - 1) - // == 7 + 2**29 - 1 < 2**32 - - x->val[i] = acc & BN_LIMB_MASK; - acc >>= (BN_BITS_PER_LIMB); - // acc <= 7 == 2**(32 - BITS_PER_LIMB) - 1 - } -} - -// x = x + y -// Assumes x, y are normalized, x + y < 2**(LIMBS*BITS_PER_LIMB) == 2**261 -// Guarantees x is normalized -// Works properly even if &x == &y -void bn_add(bignum256 *x, const bignum256 *y) { - uint32_t acc = 0; - for (int i = 0; i < BN_LIMBS; i++) { - acc += x->val[i] + y->val[i]; - // acc doesn't overflow 32 bits - // Proof: - // acc + x[i] + y[i] - // <= (2**(32 - BITS_PER_LIMB) - 1) + 2 * (2**BITS_PER_LIMB - 1) - // == (2**(32 - BITS_PER_LIMB) - 1) + 2**(BITS_PER_LIMB + 1) - 2 - // == 7 + 2**30 - 2 < 2**32 - - x->val[i] = acc & BN_LIMB_MASK; - acc >>= BN_BITS_PER_LIMB; - // acc <= 7 == 2**(32 - BITS_PER_LIMB) - 1 - - // acc == x[:i + 1] + y[:i + 1] >> BITS_PER_LIMB * (i + 1) - } - - // assert(acc == 0); // assert x + y < 2**261 - // acc == 0 - // Proof: - // acc == x[:LIMBS] + y[:LIMBS] >> LIMBS * BITS_PER_LIMB - // == x + y >> LIMBS * BITS_PER_LIMB - // <= 2**(LIMBS * BITS_PER_LIMB) - 1 >> LIMBS * BITS_PER_LIMB == 0 -} - -// x = x + y % prime -// Assumes x, y are normalized -// Guarantees x is normalized and partly reduced modulo prime -// Assumes prime is normalized and 2^256 - 2^224 <= prime <= 2^256 -void bn_addmod(bignum256 *x, const bignum256 *y, const bignum256 *prime) { - for (int i = 0; i < BN_LIMBS; i++) { - x->val[i] += y->val[i]; - // x[i] doesn't overflow 32 bits - // Proof: - // x[i] + y[i] - // <= 2 * (2**BITS_PER_LIMB - 1) - // == 2**30 - 2 < 2**32 - } - - bn_fast_mod(x, prime); -} - -// x = x + y -// Assumes x is normalized -// Assumes y <= 2**32 - 2**29 == 2**32 - 2**BITS_PER_LIMB and -// x + y < 2**261 == 2**(LIMBS * BITS_PER_LIMB) -// Guarantees x is normalized -void bn_addi(bignum256 *x, uint32_t y) { - // assert(y <= 3758096384); // assert y <= 2**32 - 2**29 - uint32_t acc = y; - - for (int i = 0; i < BN_LIMBS; i++) { - acc += x->val[i]; - // acc doesn't overflow 32 bits - // Proof: - // if i == 0: - // acc + x[i] == y + x[0] - // <= (2**32 - 2**BITS_PER_LIMB) + (2**BITS_PER_LIMB - 1) - // == 2**32 - 1 < 2**32 - // else: - // acc + x[i] - // <= (2**(32 - BITS_PER_LIMB) - 1) + (2**BITS_PER_LIMB - 1) - // == 7 + 2**29 - 1 < 2**32 - - x->val[i] = acc & BN_LIMB_MASK; - acc >>= (BN_BITS_PER_LIMB); - // acc <= 7 == 2**(32 - BITS_PER_LIMB) - 1 - - // acc == x[:i + 1] + y >> BITS_PER_LIMB * (i + 1) - } - - // assert(acc == 0); // assert x + y < 2**261 - // acc == 0 - // Proof: - // acc == x[:LIMBS] + y << LIMBS * BITS_PER_LIMB - // == x + y << LIMBS * BITS_PER_LIMB - // <= 2**(LIMBS + BITS_PER_LIMB) - 1 << LIMBS * BITS_PER_LIMB - // == 0 -} - -// x = x - y % prime -// Explicitly x = x + prime - y -// Assumes x, y are normalized -// Assumes y < prime[0], x + prime - y < 2**261 == 2**(LIMBS * BITS_PER_LIMB) -// Guarantees x is normalized -// If x is fully reduced modulo prime, -// guarantess x will be partly reduced modulo prime -// Assumes prime is nonzero and normalized -void bn_subi(bignum256 *x, uint32_t y, const bignum256 *prime) { - assert(y < prime->val[0]); - - // x = x + prime - y - - uint32_t acc = -y; - for (int i = 0; i < BN_LIMBS; i++) { - acc += x->val[i] + prime->val[i]; - // acc neither overflows 32 bits nor underflows 0 - // Proof: - // acc + x[i] + prime[i] - // <= (2**(32 - BITS_PER_LIMB) - 1) + 2 * (2**BITS_PER_LIMB - 1) - // <= 7 + 2**30 - 2 < 2**32 - // acc + x[i] + prime[i] - // >= -y + prime[0] >= 0 - - x->val[i] = acc & BN_LIMB_MASK; - acc >>= BN_BITS_PER_LIMB; - // acc <= 7 == 2**(32 - BITS_PER_LIMB) - 1 - - // acc == x[:i + 1] + prime[:i + 1] - y >> BITS_PER_LIMB * (i + 1) - } - - // assert(acc == 0); // assert x + prime - y < 2**261 - // acc == 0 - // Proof: - // acc == x[:LIMBS] + prime[:LIMBS] - y >> BITS_PER_LIMB * LIMBS - // == x + prime - y >> BITS_PER_LIMB * LIMBS - // <= 2**(LIMBS * BITS_PER_LIMB) - 1 >> BITS_PER_LIMB * LIMBS == 0 -} - -// res = x - y % prime -// Explicitly res = x + (2 * prime - y) -// Assumes x, y are normalized, y is partly reduced -// Assumes x + 2 * prime - y < 2**261 == 2**(BITS_PER_LIMB * LIMBS) -// Guarantees res is normalized -// Assumes prime is nonzero and normalized -void bn_subtractmod(const bignum256 *x, const bignum256 *y, bignum256 *res, - const bignum256 *prime) { - // res = x + (2 * prime - y) - - uint32_t acc = 1; - - for (int i = 0; i < BN_LIMBS; i++) { - acc += (BN_BASE - 1) + x->val[i] + 2 * prime->val[i] - y->val[i]; - // acc neither overflows 32 bits nor underflows 0 - // Proof: - // acc + (BASE - 1) + x[i] + 2 * prime[i] - y[i] - // >= (BASE - 1) - y[i] - // == (2**BITS_PER_LIMB - 1) - (2**BITS_PER_LIMB - 1) == 0 - // acc + (BASE - 1) + x[i] + 2 * prime[i] - y[i] - // <= acc + (BASE - 1) + x[i] + 2 * prime[i] - // <= (2**(32 - BITS_PER_LIMB) - 1) + (2**BITS_PER_LIMB - 1) + - // (2**BITS_PER_LIMB - 1) + 2 * (2**BITS_PER_LIMB - 1) - // <= (2**(32 - BITS_PER_LIMB) - 1) + 4 * (2**BITS_PER_LIMB - 1) - // == 7 + 4 * 2**29 - 4 == 2**31 + 3 < 2**32 - - res->val[i] = acc & (BN_BASE - 1); - acc >>= BN_BITS_PER_LIMB; - // acc <= 7 == 2**(32 - BITS_PER_LIMB) - 1 - - // acc == 2**(BITS_PER_LIMB * (i + 1)) + x[:i+1] - y[:i+1] + 2*prime[:i+1] - // >> BITS_PER_LIMB * (i+1) - } - - // assert(acc == 1); // assert x + 2 * prime - y < 2**261 - - // clang-format off - // acc == 1 - // Proof: - // acc == 2**(BITS_PER_LIMB * LIMBS) + x[:LIMBS] - y[:LIMBS] + 2 * prime[:LIMBS] >> BITS_PER_LIMB * LIMBS - // == 2**(BITS_PER_LIMB * LIMBS) + x - y + 2 * prime >> BITS_PER_LIMB * LIMBS - // == 2**(BITS_PER_LIMB * LIMBS) + x + (2 * prime - y) >> BITS_PER_LIMB * LIMBS - // <= 2**(BITS_PER_LIMB * LIMBS) + 2**(BITS_PER_LIMB * LIMBS) - 1 >> BITS_PER_LIMB * LIMBS - // <= 2 * 2**(BITS_PER_LIMB * LIMBS) - 1 >> BITS_PER_LIMB * LIMBS - // == 1 - - // acc == 2**(BITS_PER_LIMB * LIMBS) + x[:LIMBS] - y[:LIMBS] + 2 * prime[:LIMBS] >> BITS_PER_LIMB * LIMBS - // == 2**(BITS_PER_LIMB * LIMBS) + x - y + 2 * prime >> BITS_PER_LIMB * LIMBS - // == 2**(BITS_PER_LIMB * LIMBS) + x + (2 * prime - y) >> BITS_PER_LIMB * LIMBS - // >= 2**(BITS_PER_LIMB * LIMBS) + 0 + 1 >> BITS_PER_LIMB * LIMBS - // == 1 - // clang-format on -} - -// res = x - y -// Assumes x, y are normalized and x >= y -// Guarantees res is normalized -// Works properly even if &x == &y or &x == &res or &y == &res or -// &x == &y == &res -void bn_subtract(const bignum256 *x, const bignum256 *y, bignum256 *res) { - uint32_t acc = 1; - for (int i = 0; i < BN_LIMBS; i++) { - acc += (BN_BASE - 1) + x->val[i] - y->val[i]; - // acc neither overflows 32 bits nor underflows 0 - // Proof: - // acc + (BASE - 1) + x[i] - y[i] - // >= (BASE - 1) - y == (2**BITS_PER_LIMB - 1) - (2**BITS_PER_LIMB - 1) - // == 0 - // acc + (BASE - 1) + x[i] - y[i] - // <= acc + (BASE - 1) + x[i] - // <= (2**(32 - BITS_PER_LIMB) - 1) + (2**BITS_PER_LIMB - 1) + - // (2**BITS_PER_LIMB - 1) - // == 7 + 2 * 2**29 < 2 **32 - - res->val[i] = acc & BN_LIMB_MASK; - acc >>= BN_BITS_PER_LIMB; - // acc <= 7 == 2**(32 - BITS_PER_LIMB) - 1 - - // acc == 2**(BITS_PER_LIMB * (i + 1)) + x[:i + 1] - y[:i + 1] - // >> BITS_PER_LIMB * (i + 1) - } - - // assert(acc == 1); // assert x >= y - - // clang-format off - // acc == 1 - // Proof: - // acc == 2**(BITS_PER_LIMB * LIMBS) + x[:LIMBS] - y[:LIMBS] >> BITS_PER_LIMB * LIMBS - // == 2**(BITS_PER_LIMB * LIMBS) + x - y >> BITS_PER_LIMB * LIMBS - // == 2**(BITS_PER_LIMB * LIMBS) + x >> BITS_PER_LIMB * LIMBS - // <= 2**(BITS_PER_LIMB * LIMBS) + 2**(BITS_PER_LIMB * LIMBS) - 1 >> BITS_PER_LIMB * LIMBS - // <= 2 * 2**(BITS_PER_LIMB * LIMBS) - 1 >> BITS_PER_LIMB * LIMBS - // == 1 - - // acc == 2**(BITS_PER_LIMB * LIMBS) + x[:LIMBS] - y[:LIMBS] >> BITS_PER_LIMB * LIMBS - // == 2**(BITS_PER_LIMB * LIMBS) + x - y >> BITS_PER_LIMB * LIMBS - // >= 2**(BITS_PER_LIMB * LIMBS) >> BITS_PER_LIMB * LIMBS - // == 1 -} - -// q = x // d, r = x % d -// Assumes x is normalized, 1 <= d <= 61304 -// Guarantees q is normalized -void bn_long_division(bignum256 *x, uint32_t d, bignum256 *q, uint32_t *r) { - assert(1 <= d && d < 61304); - - uint32_t acc = 0; - - *r = x->val[BN_LIMBS - 1] % d; - q->val[BN_LIMBS - 1] = x->val[BN_LIMBS - 1] / d; - - for (int i = BN_LIMBS - 2; i >= 0; i--) { - acc = *r * (BN_BASE % d) + x->val[i]; - // acc doesn't overflow 32 bits - // Proof: - // r * (BASE % d) + x[i] - // <= (d - 1) * (d - 1) + (2**BITS_PER_LIMB - 1) - // == d**2 - 2*d + 2**BITS_PER_LIMB - // == 61304**2 - 2 * 61304 + 2**29 - // == 3758057808 + 2**29 < 2**32 - - q->val[i] = *r * (BN_BASE / d) + (acc / d); - // q[i] doesn't overflow 32 bits - // Proof: - // r * (BASE // d) + (acc // d) - // <= (d - 1) * (2**BITS_PER_LIMB / d) + - // ((d**2 - 2*d + 2**BITS_PER_LIMB) / d) - // <= (d - 1) * (2**BITS_PER_LIMB / d) + (d - 2 + 2**BITS_PER_LIMB / d) - // == (d - 1 + 1) * (2**BITS_PER_LIMB / d) + d - 2 - // == 2**BITS_PER_LIMB + d - 2 <= 2**29 + 61304 < 2**32 - - // q[i] == (r * BASE + x[i]) // d - // Proof: - // q[i] == r * (BASE // d) + (acc // d) - // == r * (BASE // d) + (r * (BASE % d) + x[i]) // d - // == (r * d * (BASE // d) + r * (BASE % d) + x[i]) // d - // == (r * (d * (BASE // d) + (BASE % d)) + x[i]) // d - // == (r * BASE + x[i]) // d - - // q[i] < 2**BITS_PER_LIMB - // Proof: - // q[i] == (r * BASE + x[i]) // d - // <= ((d - 1) * 2**BITS_PER_LIMB + (2**BITS_PER_LIMB - 1)) / d - // == (d * 2**BITS_PER_LIMB - 1) / d == 2**BITS_PER_LIMB - 1 / d - // < 2**BITS_PER_LIMB - - *r = acc % d; - // r == (r * BASE + x[i]) % d - // Proof: - // r == acc % d == (r * (BASE % d) + x[i]) % d - // == (r * BASE + x[i]) % d - - // x[:i] == q[:i] * d + r - } -} - -// x = x // 58, r = x % 58 -// Assumes x is normalized -// Guarantees x is normalized -void bn_divmod58(bignum256 *x, uint32_t *r) { bn_long_division(x, 58, x, r); } - -// x = x // 1000, r = x % 1000 -// Assumes x is normalized -// Guarantees x is normalized -void bn_divmod1000(bignum256 *x, uint32_t *r) { - bn_long_division(x, 1000, x, r); -} - -// x = x // 10, r = x % 10 -// Assumes x is normalized -// Guarantees x is normalized -void bn_divmod10(bignum256 *x, uint32_t *r) { bn_long_division(x, 10, x, r); } - -// Formats amount -// Assumes amount is normalized -// Assumes prefix and suffix are null-terminated strings -// Assumes output is an array of length output_length -// The function doesn't have neither constant control flow nor constant memory -// access flow with regard to any its argument -size_t bn_format(const bignum256 *amount, const char *prefix, const char *suffix, unsigned int decimals, int exponent, bool trailing, char *output, size_t output_length) { - -/* - Python prototype of the function: - - def format(amount, prefix, suffix, decimals, exponent, trailing): - if exponent >= 0: - amount *= 10 ** exponent - else: - amount //= 10 ** (-exponent) - - d = pow(10, decimals) - - if decimals: - output = "%d.%0*d" % (amount // d, decimals, amount % d) - if not trailing: - output = output.rstrip("0").rstrip(".") - else: - output = "%d" % (amount // d) - - return prefix + output + suffix -*/ - -// Auxiliary macro for bn_format -// If enough space adds one character to output starting from the end -#define BN_FORMAT_ADD_OUTPUT_CHAR(c) \ - { \ - --position; \ - if (output <= position && position < output + output_length) { \ - *position = (c); \ - } else { \ - memset(output, '\0', output_length); \ - return 0; \ - } \ - } - - bignum256 temp = {0}; - bn_copy(amount, &temp); - uint32_t digit = 0; - - char *position = output + output_length; - - // Add string ending character - BN_FORMAT_ADD_OUTPUT_CHAR('\0'); - - // Add suffix - size_t suffix_length = suffix ? strlen(suffix) : 0; - for (int i = suffix_length - 1; i >= 0; --i) - BN_FORMAT_ADD_OUTPUT_CHAR(suffix[i]) - - // amount //= 10**exponent - for (; exponent < 0; ++exponent) { - // if temp == 0, there is no need to divide it by 10 anymore - if (bn_is_zero(&temp)) { - exponent = 0; - break; - } - bn_divmod10(&temp, &digit); - } - - // exponent >= 0 && decimals >= 0 - - bool fractional_part = false; // is fractional-part of amount present - - { // Add fractional-part digits of amount - // Add trailing zeroes - unsigned int trailing_zeros = decimals < (unsigned int) exponent ? decimals : (unsigned int) exponent; - // When casting a negative int to unsigned int, UINT_MAX is added to the int before - // Since exponent >= 0, the value remains unchanged - decimals -= trailing_zeros; - exponent -= trailing_zeros; - - if (trailing && trailing_zeros) { - fractional_part = true; - for (; trailing_zeros > 0; --trailing_zeros) - BN_FORMAT_ADD_OUTPUT_CHAR('0') - } - - // exponent == 0 || decimals == 0 - - // Add significant digits and leading zeroes - for (; decimals > 0; --decimals) { - bn_divmod10(&temp, &digit); - - if (fractional_part || digit || trailing) { - fractional_part = true; - BN_FORMAT_ADD_OUTPUT_CHAR('0' + digit) - } - else if (bn_is_zero(&temp)) { - // We break since the remaining digits are zeroes and fractional_part == trailing == false - decimals = 0; - break; - } - } - // decimals == 0 - } - - if (fractional_part) { - BN_FORMAT_ADD_OUTPUT_CHAR('.') - } - - { // Add integer-part digits of amount - // Add trailing zeroes - if (!bn_is_zero(&temp)) { - for (; exponent > 0; --exponent) { - BN_FORMAT_ADD_OUTPUT_CHAR('0') - } - } - // decimals == 0 && exponent == 0 - - // Add significant digits - do { - bn_divmod10(&temp, &digit); - BN_FORMAT_ADD_OUTPUT_CHAR('0' + digit) - } while (!bn_is_zero(&temp)); - } - - // Add prefix - size_t prefix_length = prefix ? strlen(prefix) : 0; - for (int i = prefix_length - 1; i >= 0; --i) - BN_FORMAT_ADD_OUTPUT_CHAR(prefix[i]) - - // Move formatted amount to the start of output - int length = output - position + output_length; - memmove(output, position, length); - return length - 1; -} - -#if USE_BN_PRINT -// Prints x in hexadecimal -// Assumes x is normalized and x < 2**256 -void bn_print(const bignum256 *x) { - printf("%06x", x->val[8]); - printf("%08x", ((x->val[7] << 3) | (x->val[6] >> 26))); - printf("%07x", ((x->val[6] << 2) | (x->val[5] >> 27)) & 0x0FFFFFFF); - printf("%07x", ((x->val[5] << 1) | (x->val[4] >> 28)) & 0x0FFFFFFF); - printf("%07x", x->val[4] & 0x0FFFFFFF); - printf("%08x", ((x->val[3] << 3) | (x->val[2] >> 26))); - printf("%07x", ((x->val[2] << 2) | (x->val[1] >> 27)) & 0x0FFFFFFF); - printf("%07x", ((x->val[1] << 1) | (x->val[0] >> 28)) & 0x0FFFFFFF); - printf("%07x", x->val[0] & 0x0FFFFFFF); -} - -// Prints comma separated list of limbs of x -void bn_print_raw(const bignum256 *x) { - for (int i = 0; i < BN_LIMBS - 1; i++) { - printf("0x%08x, ", x->val[i]); - } - printf("0x%08x", x->val[BN_LIMBS - 1]); -} -#endif - -#if USE_INVERSE_FAST -void bn_inverse(bignum256 *x, const bignum256 *prime) { - bn_inverse_fast(x, prime); -} -#else -void bn_inverse(bignum256 *x, const bignum256 *prime) { - bn_inverse_slow(x, prime); -} -#endif diff --git a/deps/crypto/trezor-crypto/bignum.h b/deps/crypto/trezor-crypto/bignum.h deleted file mode 100644 index fcae2f773..000000000 --- a/deps/crypto/trezor-crypto/bignum.h +++ /dev/null @@ -1,166 +0,0 @@ -/** - * Copyright (c) 2013-2014 Tomas Dzetkulic - * Copyright (c) 2013-2014 Pavol Rusnak - * Copyright (c) 2016 Alex Beregszaszi - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __BIGNUM_H__ -#define __BIGNUM_H__ - -#include -#include -#include - -#include "options.h" - -#define BN_LIMBS 9 -#define BN_BITS_PER_LIMB 29 -#define BN_BASE (1u << BN_BITS_PER_LIMB) -#define BN_LIMB_MASK ((1u << BN_BITS_PER_LIMB) - 1) -#define BN_EXTRA_BITS (32 - BN_BITS_PER_LIMB) -#define BN_BITS_LAST_LIMB (256 - (BN_LIMBS - 1) * BN_BITS_PER_LIMB) - -// Represents the number sum([val[i] * 2**(29*i) for i in range(9)) -typedef struct { - uint32_t val[BN_LIMBS]; -} bignum256; - -static inline uint32_t read_be(const uint8_t *data) { - return (((uint32_t)data[0]) << 24) | (((uint32_t)data[1]) << 16) | - (((uint32_t)data[2]) << 8) | (((uint32_t)data[3])); -} - -static inline void write_be(uint8_t *data, uint32_t x) { - data[0] = x >> 24; - data[1] = x >> 16; - data[2] = x >> 8; - data[3] = x; -} - -static inline uint32_t read_le(const uint8_t *data) { - return (((uint32_t)data[3]) << 24) | (((uint32_t)data[2]) << 16) | - (((uint32_t)data[1]) << 8) | (((uint32_t)data[0])); -} - -static inline void write_le(uint8_t *data, uint32_t x) { - data[3] = x >> 24; - data[2] = x >> 16; - data[1] = x >> 8; - data[0] = x; -} - -void bn_read_be(const uint8_t *in_number, bignum256 *out_number); -void bn_write_be(const bignum256 *in_number, uint8_t *out_number); -void bn_read_le(const uint8_t *in_number, bignum256 *out_number); -void bn_write_le(const bignum256 *in_number, uint8_t *out_number); -void bn_read_uint32(uint32_t in_number, bignum256 *out_number); -void bn_read_uint64(uint64_t in_number, bignum256 *out_number); -int bn_bitcount(const bignum256 *x); -unsigned int bn_digitcount(const bignum256 *x); -void bn_zero(bignum256 *x); -void bn_one(bignum256 *x); -int bn_is_zero(const bignum256 *x); -int bn_is_one(const bignum256 *x); -int bn_is_less(const bignum256 *x, const bignum256 *y); -int bn_is_equal(const bignum256 *x, const bignum256 *y); -void bn_cmov(bignum256 *res, volatile uint32_t cond, const bignum256 *truecase, - const bignum256 *falsecase); -void bn_cnegate(volatile uint32_t cond, bignum256 *x, const bignum256 *prime); -void bn_lshift(bignum256 *x); -void bn_rshift(bignum256 *x); -void bn_setbit(bignum256 *x, uint16_t i); -void bn_clearbit(bignum256 *x, uint16_t i); -uint32_t bn_testbit(const bignum256 *x, uint16_t i); -void bn_xor(bignum256 *res, const bignum256 *x, const bignum256 *y); -void bn_mult_half(bignum256 *x, const bignum256 *prime); -void bn_mult_k(bignum256 *x, uint8_t k, const bignum256 *prime); -void bn_mod(bignum256 *x, const bignum256 *prime); -void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime); -void bn_fast_mod(bignum256 *x, const bignum256 *prime); -void bn_power_mod(const bignum256 *x, const bignum256 *e, - const bignum256 *prime, bignum256 *res); -void bn_sqrt(bignum256 *x, const bignum256 *prime); -uint32_t inverse_mod_power_two(uint32_t a, uint32_t n); -void bn_divide_base(bignum256 *x, const bignum256 *prime); -void bn_normalize(bignum256 *x); -void bn_add(bignum256 *x, const bignum256 *y); -void bn_addmod(bignum256 *x, const bignum256 *y, const bignum256 *prime); -void bn_addi(bignum256 *x, uint32_t y); -void bn_subi(bignum256 *x, uint32_t y, const bignum256 *prime); -void bn_subtractmod(const bignum256 *x, const bignum256 *y, bignum256 *res, - const bignum256 *prime); -void bn_subtract(const bignum256 *x, const bignum256 *y, bignum256 *res); -void bn_long_division(bignum256 *x, uint32_t d, bignum256 *q, uint32_t *r); -void bn_divmod58(bignum256 *x, uint32_t *r); -void bn_divmod1000(bignum256 *x, uint32_t *r); -void bn_inverse(bignum256 *x, const bignum256 *prime); -size_t bn_format(const bignum256 *amount, const char *prefix, - const char *suffix, unsigned int decimals, int exponent, - bool trailing, char *output, size_t output_length); - -// Returns (uint32_t) in_number -// Assumes in_number < 2**32 -// Assumes in_number is normalized -static inline uint32_t bn_write_uint32(const bignum256 *in_number) { - return in_number->val[0] | (in_number->val[1] << BN_BITS_PER_LIMB); -} - -// Returns (uint64_t) in_number -// Assumes in_number < 2**64 -// Assumes in_number is normalized -static inline uint64_t bn_write_uint64(const bignum256 *in_number) { - uint64_t acc; - acc = in_number->val[2]; - acc <<= BN_BITS_PER_LIMB; - acc |= in_number->val[1]; - acc <<= BN_BITS_PER_LIMB; - acc |= in_number->val[0]; - return acc; -} - -// y = x -static inline void bn_copy(const bignum256 *x, bignum256 *y) { *y = *x; } - -// Returns x % 2 == 0 -static inline int bn_is_even(const bignum256 *x) { - return (x->val[0] & 1) == 0; -} - -// Returns x % 2 == 0 -static inline int bn_is_odd(const bignum256 *x) { return (x->val[0] & 1) == 1; } - -static inline size_t bn_format_uint64(uint64_t amount, const char *prefix, - const char *suffix, unsigned int decimals, - int exponent, bool trailing, char *output, - size_t output_length) { - bignum256 bn_amount; - bn_read_uint64(amount, &bn_amount); - - return bn_format(&bn_amount, prefix, suffix, decimals, exponent, trailing, - output, output_length); -} - -#if USE_BN_PRINT -void bn_print(const bignum256 *x); -void bn_print_raw(const bignum256 *x); -#endif - -#endif diff --git a/deps/crypto/trezor-crypto/bip32.c b/deps/crypto/trezor-crypto/bip32.c deleted file mode 100644 index 66f8fd9e6..000000000 --- a/deps/crypto/trezor-crypto/bip32.c +++ /dev/null @@ -1,1045 +0,0 @@ -/** - * Copyright (c) 2013-2016 Tomas Dzetkulic - * Copyright (c) 2013-2016 Pavol Rusnak - * Copyright (c) 2015-2016 Jochen Hoenicke - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include - -#include "aes/aes.h" -#include "address.h" -#include "bignum.h" -#include "hmac.h" -#include "ecdsa.h" -#include "bip32.h" -#include "sha2.h" -#include "sha3.h" -#include "base58.h" -#include "curves.h" -#include "secp256k1.h" -#include "nist256p1.h" -#include "ed25519-donna/ed25519.h" -#if USE_NANO -#include "ed25519-donna/ed25519-blake2b.h" -#endif -#include "ed25519-donna/ed25519-sha3.h" -#if USE_KECCAK -#include "ed25519-donna/ed25519-keccak.h" -#endif -#if USE_NEM -#include "nem.h" -#endif -#if USE_CARDANO -#include "pbkdf2.h" -#endif -#include "memzero.h" - -#define CARDANO_MAX_NODE_DEPTH 1048576 - -const curve_info ed25519_info = { - .bip32_name = "ed25519 seed", - .params = NULL, - .hasher_base58 = HASHER_SHA2D, - .hasher_sign = HASHER_SHA2D, - .hasher_pubkey = HASHER_SHA2_RIPEMD, - .hasher_script = HASHER_SHA2, -}; - -const curve_info ed25519_cardano_info = { - .bip32_name = "ed25519 cardano seed", - .params = NULL, - .hasher_base58 = HASHER_SHA2D, - .hasher_sign = HASHER_SHA2D, - .hasher_pubkey = HASHER_SHA2_RIPEMD, - .hasher_script = HASHER_SHA2, -}; - -#if USE_NANO -const curve_info ed25519_blake2b_nano_info = { - .bip32_name = "ed25519 seed", - .params = NULL, - .hasher_base58 = HASHER_SHA2D, - .hasher_sign = HASHER_SHA2D, - .hasher_pubkey = HASHER_SHA2_RIPEMD, - .hasher_script = HASHER_SHA2, -}; -#endif - -const curve_info ed25519_sha3_info = { - .bip32_name = "ed25519-sha3 seed", - .params = NULL, - .hasher_base58 = HASHER_SHA2D, - .hasher_sign = HASHER_SHA2D, - .hasher_pubkey = HASHER_SHA2_RIPEMD, - .hasher_script = HASHER_SHA2, -}; - -#if USE_KECCAK -const curve_info ed25519_keccak_info = { - .bip32_name = "ed25519-keccak seed", - .params = NULL, - .hasher_base58 = HASHER_SHA2D, - .hasher_sign = HASHER_SHA2D, - .hasher_pubkey = HASHER_SHA2_RIPEMD, - .hasher_script = HASHER_SHA2, -}; -#endif - -const curve_info curve25519_info = { - .bip32_name = "curve25519 seed", - .params = NULL, - .hasher_base58 = HASHER_SHA2D, - .hasher_sign = HASHER_SHA2D, - .hasher_pubkey = HASHER_SHA2_RIPEMD, - .hasher_script = HASHER_SHA2, -}; - -bool hdnode_is_valid(const HDNode* node) { - return node && node->curve; -} - -int hdnode_from_xpub(uint32_t depth, uint32_t child_num, - const uint8_t *chain_code, const uint8_t *public_key, - const char *curve, HDNode *out) { - const curve_info *info = get_curve_by_name(curve); - if (info == 0) { - return 0; - } - if (public_key[0] != 0x02 && public_key[0] != 0x03) { // invalid pubkey - return 0; - } - out->curve = info; - out->depth = depth; - out->child_num = child_num; - memcpy(out->chain_code, chain_code, 32); - memzero(out->private_key, 32); - memzero(out->private_key_extension, 32); - memcpy(out->public_key, public_key, 33); - return 1; -} - -int hdnode_from_xprv(uint32_t depth, uint32_t child_num, - const uint8_t *chain_code, const uint8_t *private_key, - const char *curve, HDNode *out) { - bool failed = false; - const curve_info *info = get_curve_by_name(curve); - if (info == 0) { - failed = true; - } else if (info->params) { - bignum256 a = {0}; - bn_read_be(private_key, &a); - if (bn_is_zero(&a)) { // == 0 - failed = true; - } else { - if (!bn_is_less(&a, &info->params->order)) { // >= order - failed = true; - } - } - memzero(&a, sizeof(a)); - } - - if (failed) { - return 0; - } - - out->curve = info; - out->depth = depth; - out->child_num = child_num; - memcpy(out->chain_code, chain_code, 32); - memcpy(out->private_key, private_key, 32); - memzero(out->public_key, sizeof(out->public_key)); - memzero(out->private_key_extension, sizeof(out->private_key_extension)); - return 1; -} - -int hdnode_from_seed(const uint8_t *seed, int seed_len, const char *curve, - HDNode *out) { - static CONFIDENTIAL uint8_t I[32 + 32]; - memzero(out, sizeof(HDNode)); - out->depth = 0; - out->child_num = 0; - out->curve = get_curve_by_name(curve); - if (out->curve == 0) { - return 0; - } - static CONFIDENTIAL HMAC_SHA512_CTX ctx; - hmac_sha512_Init(&ctx, (const uint8_t *)out->curve->bip32_name, - strlen(out->curve->bip32_name)); - hmac_sha512_Update(&ctx, seed, seed_len); - hmac_sha512_Final(&ctx, I); - - if (out->curve->params) { - bignum256 a = {0}; - while (true) { - bn_read_be(I, &a); - if (!bn_is_zero(&a) // != 0 - && bn_is_less(&a, &out->curve->params->order)) { // < order - break; - } - hmac_sha512_Init(&ctx, (const uint8_t *)out->curve->bip32_name, - strlen(out->curve->bip32_name)); - hmac_sha512_Update(&ctx, I, sizeof(I)); - hmac_sha512_Final(&ctx, I); - } - memzero(&a, sizeof(a)); - } - memcpy(out->private_key, I, 32); - memcpy(out->chain_code, I + 32, 32); - memzero(out->public_key, sizeof(out->public_key)); - memzero(I, sizeof(I)); - return 1; -} - -uint32_t hdnode_fingerprint(HDNode *node) { - if (!hdnode_is_valid(node)) return 0; - - uint8_t digest[32] = {0}; - uint8_t public_key[33] = {0}; - uint32_t fingerprint = 0; - - hdnode_fill_public_key(node); - memcpy(public_key, node->public_key, sizeof(public_key)); - if (public_key[0] == 0x01) { - // SLIP-10 fingerprints Ed25519 and Curve25519 keys with a 0x00 prefix. - public_key[0] = 0x00; - } - hasher_Raw(node->curve->hasher_pubkey, public_key, sizeof(public_key), - digest); - fingerprint = ((uint32_t)digest[0] << 24) + (digest[1] << 16) + - (digest[2] << 8) + digest[3]; - memzero(public_key, sizeof(public_key)); - memzero(digest, sizeof(digest)); - return fingerprint; -} - -int hdnode_private_ckd(HDNode *inout, uint32_t i) { - if (!hdnode_is_valid(inout)) return 0; - if (inout->depth == UINT32_MAX) return 0; - - static CONFIDENTIAL uint8_t data[1 + 32 + 4]; - static CONFIDENTIAL uint8_t I[32 + 32]; - static CONFIDENTIAL bignum256 a, b; - - if (i & 0x80000000) { // private derivation - data[0] = 0; - memcpy(data + 1, inout->private_key, 32); - } else { // public derivation - if (!inout->curve->params) { - return 0; - } - hdnode_fill_public_key(inout); - memcpy(data, inout->public_key, 33); - } - write_be(data + 33, i); - - bn_read_be(inout->private_key, &a); - - static CONFIDENTIAL HMAC_SHA512_CTX ctx; - hmac_sha512_Init(&ctx, inout->chain_code, 32); - hmac_sha512_Update(&ctx, data, sizeof(data)); - hmac_sha512_Final(&ctx, I); - - if (inout->curve->params) { - while (true) { - bool failed = false; - bn_read_be(I, &b); - if (!bn_is_less(&b, &inout->curve->params->order)) { // >= order - failed = true; - } else { - bn_add(&b, &a); - bn_mod(&b, &inout->curve->params->order); - if (bn_is_zero(&b)) { - failed = true; - } - } - - if (!failed) { - bn_write_be(&b, inout->private_key); - break; - } - - data[0] = 1; - memcpy(data + 1, I + 32, 32); - hmac_sha512_Init(&ctx, inout->chain_code, 32); - hmac_sha512_Update(&ctx, data, sizeof(data)); - hmac_sha512_Final(&ctx, I); - } - } else { - memcpy(inout->private_key, I, 32); - } - - memcpy(inout->chain_code, I + 32, 32); - inout->depth++; - inout->child_num = i; - memzero(inout->public_key, sizeof(inout->public_key)); - - // making sure to wipe our memory - memzero(&a, sizeof(a)); - memzero(&b, sizeof(b)); - memzero(I, sizeof(I)); - memzero(data, sizeof(data)); - return 1; -} - -#if USE_CARDANO -static void scalar_multiply8(const uint8_t *src, int bytes, uint8_t *dst) { - uint8_t prev_acc = 0; - for (int i = 0; i < bytes; i++) { - dst[i] = (src[i] << 3) + (prev_acc & 0x7); - prev_acc = src[i] >> 5; - } - dst[bytes] = src[bytes - 1] >> 5; -} - -static void scalar_add_256bits(const uint8_t *src1, const uint8_t *src2, - uint8_t *dst) { - uint16_t r = 0; - for (int i = 0; i < 32; i++) { - r = r + (uint16_t)src1[i] + (uint16_t)src2[i]; - dst[i] = r & 0xff; - r >>= 8; - } -} - -int hdnode_private_ckd_cardano(HDNode *inout, uint32_t index) { - if (!hdnode_is_valid(inout)) return 0; - - if (inout->depth >= CARDANO_MAX_NODE_DEPTH) { - return 0; - } - - // checks for hardened/non-hardened derivation, keysize 32 means we are - // dealing with public key and thus non-h, keysize 64 is for private key - int keysize = 32; - if (index & 0x80000000) { - keysize = 64; - } - - static CONFIDENTIAL uint8_t data[1 + 64 + 4]; - static CONFIDENTIAL uint8_t z[32 + 32]; - static CONFIDENTIAL uint8_t priv_key[64]; - static CONFIDENTIAL uint8_t res_key[64]; - - write_le(data + keysize + 1, index); - - memcpy(priv_key, inout->private_key, 32); - memcpy(priv_key + 32, inout->private_key_extension, 32); - - if (keysize == 64) { // private derivation - data[0] = 0; - memcpy(data + 1, inout->private_key, 32); - memcpy(data + 1 + 32, inout->private_key_extension, 32); - } else { // public derivation - hdnode_fill_public_key(inout); - data[0] = 2; - memcpy(data + 1, inout->public_key + 1, 32); - } - - static CONFIDENTIAL HMAC_SHA512_CTX ctx; - hmac_sha512_Init(&ctx, inout->chain_code, 32); - hmac_sha512_Update(&ctx, data, 1 + keysize + 4); - hmac_sha512_Final(&ctx, z); - - static CONFIDENTIAL uint8_t zl8[32]; - memzero(zl8, 32); - - /* get 8 * Zl */ - scalar_multiply8(z, 28, zl8); - /* Kl = 8*Zl + parent(K)l */ - scalar_add_256bits(zl8, priv_key, res_key); - - /* Kr = Zr + parent(K)r */ - scalar_add_256bits(z + 32, priv_key + 32, res_key + 32); - - memcpy(inout->private_key, res_key, 32); - memcpy(inout->private_key_extension, res_key + 32, 32); - - if (keysize == 64) { - data[0] = 1; - } else { - data[0] = 3; - } - hmac_sha512_Init(&ctx, inout->chain_code, 32); - hmac_sha512_Update(&ctx, data, 1 + keysize + 4); - hmac_sha512_Final(&ctx, z); - - memcpy(inout->chain_code, z + 32, 32); - inout->depth++; - inout->child_num = index; - memzero(inout->public_key, sizeof(inout->public_key)); - - // making sure to wipe our memory - memzero(z, sizeof(z)); - memzero(data, sizeof(data)); - memzero(priv_key, sizeof(priv_key)); - memzero(res_key, sizeof(res_key)); - return 1; -} - -static int hdnode_from_secret_cardano(const uint8_t *k, - const uint8_t *chain_code, HDNode *out) { - memzero(out, sizeof(HDNode)); - out->depth = 0; - out->child_num = 0; - out->curve = &ed25519_cardano_info; - memcpy(out->private_key, k, 32); - memcpy(out->private_key_extension, k + 32, 32); - memcpy(out->chain_code, chain_code, 32); - - out->private_key[0] &= 0xf8; - out->private_key[31] &= 0x1f; - out->private_key[31] |= 0x40; - - out->public_key[0] = 0; - hdnode_fill_public_key(out); - - return 1; -} - -// Derives the root Cardano HDNode from a master secret, aka seed, as defined in -// SLIP-0023. -int hdnode_from_seed_cardano(const uint8_t *seed, int seed_len, HDNode *out) { - static CONFIDENTIAL uint8_t I[SHA512_DIGEST_LENGTH]; - static CONFIDENTIAL uint8_t k[SHA512_DIGEST_LENGTH]; - static CONFIDENTIAL HMAC_SHA512_CTX ctx; - - hmac_sha512_Init(&ctx, (const uint8_t *)ED25519_CARDANO_NAME, - strlen(ED25519_CARDANO_NAME)); - hmac_sha512_Update(&ctx, seed, seed_len); - hmac_sha512_Final(&ctx, I); - - sha512_Raw(I, 32, k); - - int ret = hdnode_from_secret_cardano(k, I + 32, out); - - memzero(I, sizeof(I)); - memzero(k, sizeof(k)); - memzero(&ctx, sizeof(ctx)); - return ret; -} - -// Derives the root Cardano HDNode from a passphrase and the entropy encoded in -// a BIP-0039 mnemonic using the Icarus derivation scheme, aka V2 derivation -// scheme. -int hdnode_from_entropy_cardano_icarus(const uint8_t *pass, int pass_len, - const uint8_t *entropy, int entropy_len, - HDNode *out) { - static CONFIDENTIAL uint8_t secret[96]; - pbkdf2_hmac_sha512(pass, pass_len, entropy, entropy_len, 4096, secret, 96); - - int ret = hdnode_from_secret_cardano(secret, secret + 64, out); - memzero(secret, sizeof(secret)); - return ret; -} -#endif - -int hdnode_public_ckd_cp(const ecdsa_curve *curve, const curve_point *parent, - const uint8_t *parent_chain_code, uint32_t i, - curve_point *child, uint8_t *child_chain_code) { - uint8_t data[(1 + 32) + 4] = {0}; - uint8_t I[32 + 32] = {0}; - bignum256 c = {0}; - - if (i & 0x80000000) { // private derivation - return 0; - } - - data[0] = 0x02 | (parent->y.val[0] & 0x01); - bn_write_be(&parent->x, data + 1); - write_be(data + 33, i); - - while (true) { - hmac_sha512(parent_chain_code, 32, data, sizeof(data), I); - bn_read_be(I, &c); - if (bn_is_less(&c, &curve->order)) { // < order - scalar_multiply(curve, &c, child); // b = c * G - point_add(curve, parent, child); // b = a + b - if (!point_is_infinity(child)) { - if (child_chain_code) { - memcpy(child_chain_code, I + 32, 32); - } - - // Wipe all stack data. - memzero(data, sizeof(data)); - memzero(I, sizeof(I)); - memzero(&c, sizeof(c)); - return 1; - } - } - - data[0] = 1; - memcpy(data + 1, I + 32, 32); - } -} - -int hdnode_public_ckd(HDNode *inout, uint32_t i) { - if (!hdnode_is_valid(inout)) return 0; - if (inout->depth == UINT32_MAX) return 0; - if (!inout->curve->params) { - // SLIP-10 does not define public child derivation for 25519 curves. - return 0; - } - - curve_point parent = {0}, child = {0}; - - if (!ecdsa_read_pubkey(inout->curve->params, inout->public_key, &parent)) { - return 0; - } - if (!hdnode_public_ckd_cp(inout->curve->params, &parent, inout->chain_code, i, - &child, inout->chain_code)) { - return 0; - } - memzero(inout->private_key, 32); - inout->depth++; - inout->child_num = i; - inout->public_key[0] = 0x02 | (child.y.val[0] & 0x01); - bn_write_be(&child.x, inout->public_key + 1); - - // Wipe all stack data. - memzero(&parent, sizeof(parent)); - memzero(&child, sizeof(child)); - - return 1; -} - -void hdnode_public_ckd_address_optimized(const curve_point *pub, - const uint8_t *chain_code, uint32_t i, - uint32_t version, - HasherType hasher_pubkey, - HasherType hasher_base58, char *addr, - int addrsize, int addrformat) { - uint8_t child_pubkey[33] = {0}; - curve_point b = {0}; - - hdnode_public_ckd_cp(&secp256k1, pub, chain_code, i, &b, NULL); - child_pubkey[0] = 0x02 | (b.y.val[0] & 0x01); - bn_write_be(&b.x, child_pubkey + 1); - - switch (addrformat) { - case 1: // Segwit-in-P2SH - ecdsa_get_address_segwit_p2sh(child_pubkey, version, hasher_pubkey, - hasher_base58, addr, addrsize); - break; - default: // normal address - ecdsa_get_address(child_pubkey, version, hasher_pubkey, hasher_base58, - addr, addrsize); - break; - } -} - -#if USE_BIP32_CACHE -static bool private_ckd_cache_root_set = false; -static CONFIDENTIAL HDNode private_ckd_cache_root; -static int private_ckd_cache_index = 0; - -static CONFIDENTIAL struct { - bool set; - size_t depth; - uint32_t i[BIP32_CACHE_MAXDEPTH]; - HDNode node; -} private_ckd_cache[BIP32_CACHE_SIZE]; - -void bip32_cache_clear(void) { - private_ckd_cache_root_set = false; - private_ckd_cache_index = 0; - memzero(&private_ckd_cache_root, sizeof(private_ckd_cache_root)); - memzero(private_ckd_cache, sizeof(private_ckd_cache)); -} - -int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count, - uint32_t *fingerprint) { - if (!hdnode_is_valid(inout)) return 0; - - if (i_count == 0) { - // no way how to compute parent fingerprint - return 1; - } - if (i_count == 1 || i_count - 1 > BIP32_CACHE_MAXDEPTH) { - // when parent is uncacheable just derive the node and return - for (size_t k = 0; k < i_count - 1; k++) { - if (hdnode_private_ckd(inout, i[k]) == 0) return 0; - } - if (fingerprint) { - *fingerprint = hdnode_fingerprint(inout); - } - if (hdnode_private_ckd(inout, i[i_count - 1]) == 0) return 0; - return 1; - } - - bool found = false; - // if root is not set or not the same - if (!private_ckd_cache_root_set || - memcmp(&private_ckd_cache_root, inout, sizeof(HDNode)) != 0) { - // clear the cache - private_ckd_cache_index = 0; - memzero(private_ckd_cache, sizeof(private_ckd_cache)); - // setup new root - memcpy(&private_ckd_cache_root, inout, sizeof(HDNode)); - private_ckd_cache_root_set = true; - } else { - // try to find parent - int j = 0; - for (j = 0; j < BIP32_CACHE_SIZE; j++) { - if (private_ckd_cache[j].set && - private_ckd_cache[j].depth == i_count - 1 && - memcmp(private_ckd_cache[j].i, i, (i_count - 1) * sizeof(uint32_t)) == - 0 && - private_ckd_cache[j].node.curve == inout->curve) { - memcpy(inout, &(private_ckd_cache[j].node), sizeof(HDNode)); - found = true; - break; - } - } - } - - // else derive parent - if (!found) { - size_t k = 0; - for (k = 0; k < i_count - 1; k++) { - if (hdnode_private_ckd(inout, i[k]) == 0) return 0; - } - // and save it - memzero(&(private_ckd_cache[private_ckd_cache_index]), - sizeof(private_ckd_cache[private_ckd_cache_index])); - private_ckd_cache[private_ckd_cache_index].set = true; - private_ckd_cache[private_ckd_cache_index].depth = i_count - 1; - memcpy(private_ckd_cache[private_ckd_cache_index].i, i, - (i_count - 1) * sizeof(uint32_t)); - memcpy(&(private_ckd_cache[private_ckd_cache_index].node), inout, - sizeof(HDNode)); - private_ckd_cache_index = (private_ckd_cache_index + 1) % BIP32_CACHE_SIZE; - } - - if (fingerprint) { - *fingerprint = hdnode_fingerprint(inout); - } - if (hdnode_private_ckd(inout, i[i_count - 1]) == 0) return 0; - - return 1; -} -#endif - -void hdnode_get_address_raw(HDNode *node, uint32_t version, uint8_t *addr_raw) { - if (!hdnode_is_valid(node)) return; - - hdnode_fill_public_key(node); - ecdsa_get_address_raw(node->public_key, version, node->curve->hasher_pubkey, - addr_raw); -} - -void hdnode_get_address(HDNode *node, uint32_t version, char *addr, - int addrsize) { - if (!hdnode_is_valid(node)) return; - - hdnode_fill_public_key(node); - ecdsa_get_address(node->public_key, version, node->curve->hasher_pubkey, - node->curve->hasher_base58, addr, addrsize); -} - -void hdnode_fill_public_key(HDNode *node) { - if (!hdnode_is_valid(node)) return; - - if (node->public_key[0] != 0) return; - -#if USE_BIP32_25519_CURVES - if (node->curve->params) { - ecdsa_get_public_key33(node->curve->params, node->private_key, - node->public_key); - } else { - node->public_key[0] = 1; - if (node->curve == &ed25519_info) { - ed25519_publickey(node->private_key, node->public_key + 1); -#if USE_NANO - } else if (node->curve == &ed25519_blake2b_nano_info) { - ed25519_publickey_blake2b(node->private_key, node->public_key + 1); -#endif - } else if (node->curve == &ed25519_sha3_info) { - ed25519_publickey_sha3(node->private_key, node->public_key + 1); -#if USE_KECCAK - } else if (node->curve == &ed25519_keccak_info) { - ed25519_publickey_keccak(node->private_key, node->public_key + 1); -#endif - } else if (node->curve == &curve25519_info) { - curve25519_scalarmult_basepoint(node->public_key + 1, node->private_key); -#if USE_CARDANO - } else if (node->curve == &ed25519_cardano_info) { - ed25519_publickey_ext(node->private_key, node->private_key_extension, - node->public_key + 1); -#endif - } - } -#else - - ecdsa_get_public_key33(node->curve->params, node->private_key, - node->public_key); -#endif -} - -#if USE_ETHEREUM -int hdnode_get_ethereum_pubkeyhash(const HDNode *node, uint8_t *pubkeyhash) { - if (!hdnode_is_valid(node)) return 0; - - uint8_t buf[65] = {0}; - SHA3_CTX ctx = {0}; - - /* get uncompressed public key */ - ecdsa_get_public_key65(node->curve->params, node->private_key, buf); - - /* compute sha3 of x and y coordinate without 04 prefix */ - sha3_256_Init(&ctx); - sha3_Update(&ctx, buf + 1, 64); - keccak_Final(&ctx, buf); - - /* result are the least significant 160 bits */ - memcpy(pubkeyhash, buf + 12, 20); - - return 1; -} -#endif - -#if USE_NEM -int hdnode_get_nem_address(HDNode *node, uint8_t version, char *address) { - if (!hdnode_is_valid(node)) return 0; - - if (node->curve != &ed25519_keccak_info) { - return 0; - } - - hdnode_fill_public_key(node); - return nem_get_address(&node->public_key[1], version, address); -} - -int hdnode_get_nem_shared_key(const HDNode *node, - const ed25519_public_key peer_public_key, - const uint8_t *salt, ed25519_public_key mul, - uint8_t *shared_key) { - if (!hdnode_is_valid(node)) return 0; - - if (node->curve != &ed25519_keccak_info) { - return 0; - } - - // sizeof(ed25519_public_key) == SHA3_256_DIGEST_LENGTH - if (mul == NULL) mul = shared_key; - - if (ed25519_scalarmult_keccak(mul, node->private_key, peer_public_key)) { - return 0; - } - - for (size_t i = 0; i < 32; i++) { - shared_key[i] = mul[i] ^ salt[i]; - } - - keccak_256(shared_key, 32, shared_key); - return 1; -} - -int hdnode_nem_encrypt(const HDNode *node, const ed25519_public_key public_key, - const uint8_t *iv_immut, const uint8_t *salt, - const uint8_t *payload, size_t size, uint8_t *buffer) { - if (!hdnode_is_valid(node)) return 0; - - uint8_t last_block[AES_BLOCK_SIZE] = {0}; - uint8_t remainder = size % AES_BLOCK_SIZE; - - // Round down to last whole block - size -= remainder; - // Copy old last block - memcpy(last_block, &payload[size], remainder); - // Pad new last block with number of missing bytes - memset(&last_block[remainder], AES_BLOCK_SIZE - remainder, - AES_BLOCK_SIZE - remainder); - - // the IV gets mutated, so we make a copy not to touch the original - uint8_t iv[AES_BLOCK_SIZE] = {0}; - memcpy(iv, iv_immut, AES_BLOCK_SIZE); - - uint8_t shared_key[SHA3_256_DIGEST_LENGTH] = {0}; - if (!hdnode_get_nem_shared_key(node, public_key, salt, NULL, shared_key)) { - return 0; - } - - aes_encrypt_ctx ctx = {0}; - - int succ = 0; - int ret = aes_encrypt_key256(shared_key, &ctx); - memzero(shared_key, sizeof(shared_key)); - - if (ret != EXIT_SUCCESS) { - goto cleanup; - } - - if (aes_cbc_encrypt(payload, buffer, size, iv, &ctx) != EXIT_SUCCESS) { - goto cleanup; - } - - if (aes_cbc_encrypt(last_block, &buffer[size], sizeof(last_block), iv, - &ctx) != EXIT_SUCCESS) { - goto cleanup; - } - - succ = 1; -cleanup: - memzero(&ctx, sizeof(ctx)); - return succ; -} - -int hdnode_nem_decrypt(const HDNode *node, const ed25519_public_key public_key, - uint8_t *iv, const uint8_t *salt, const uint8_t *payload, - size_t size, uint8_t *buffer) { - if (!hdnode_is_valid(node)) return 0; - - uint8_t shared_key[SHA3_256_DIGEST_LENGTH] = {0}; - - if (!hdnode_get_nem_shared_key(node, public_key, salt, NULL, shared_key)) { - return 0; - } - - aes_decrypt_ctx ctx = {0}; - - int succ = 0; - int ret = aes_decrypt_key256(shared_key, &ctx); - memzero(shared_key, sizeof(shared_key)); - - if (ret != EXIT_SUCCESS) { - goto cleanup; - } - - if (aes_cbc_decrypt(payload, buffer, size, iv, &ctx) != EXIT_SUCCESS) { - goto cleanup; - } - - succ = 1; -cleanup: - memzero(&ctx, sizeof(ctx)); - return succ; -} -#endif - -// msg is a data to be signed -// msg_len is the message length -int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, - HasherType hasher_sign, uint8_t *sig, uint8_t *pby, - int (*is_canonical)(uint8_t by, uint8_t sig[64])) { - if (!hdnode_is_valid(node)) return 1; - - if (node->curve->params) { - return ecdsa_sign(node->curve->params, hasher_sign, node->private_key, msg, - msg_len, sig, pby, is_canonical); - } else if (node->curve == &curve25519_info) { - return 1; // signatures are not supported - } else { - if (node->curve == &ed25519_info) { - ed25519_sign(msg, msg_len, node->private_key, sig); -#if USE_NANO - } else if (node->curve == &ed25519_blake2b_nano_info) { - ed25519_sign_blake2b(msg, msg_len, node->private_key, sig); -#endif - } else if (node->curve == &ed25519_sha3_info) { - ed25519_sign_sha3(msg, msg_len, node->private_key, sig); -#if USE_KECCAK - } else if (node->curve == &ed25519_keccak_info) { - ed25519_sign_keccak(msg, msg_len, node->private_key, sig); -#endif - } else { - return 1; // unknown or unsupported curve - } - return 0; - } -} - -int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, - uint8_t *pby, - int (*is_canonical)(uint8_t by, uint8_t sig[64])) { - if (!hdnode_is_valid(node)) return 1; - - if (node->curve->params) { - return ecdsa_sign_digest(node->curve->params, node->private_key, digest, - sig, pby, is_canonical); - } else if (node->curve == &curve25519_info) { - return 1; // signatures are not supported - } else { - return hdnode_sign(node, digest, 32, 0, sig, pby, is_canonical); - } -} - -int hdnode_get_shared_key(const HDNode *node, const uint8_t *peer_public_key, - uint8_t *session_key, int *result_size) { - if (!hdnode_is_valid(node)) return 1; - - // Use elliptic curve Diffie-Helman to compute shared session key - if (node->curve->params) { - if (ecdh_multiply(node->curve->params, node->private_key, peer_public_key, - session_key) != 0) { - return 1; - } - *result_size = 65; - return 0; - } else if (node->curve == &curve25519_info) { - session_key[0] = 0x04; - if (peer_public_key[0] != 0x40) { - return 1; // Curve25519 public key should start with 0x40 byte. - } - curve25519_scalarmult(session_key + 1, node->private_key, - peer_public_key + 1); - *result_size = 33; - return 0; - } else { - *result_size = 0; - return 1; // ECDH is not supported - } -} - -static int hdnode_serialize(const HDNode *node, uint32_t fingerprint, - uint32_t version, bool use_private, char *str, - int strsize) { - if (!hdnode_is_valid(node)) return 0; - - uint8_t node_data[78] = {0}; - write_be(node_data, version); - node_data[4] = node->depth; - write_be(node_data + 5, fingerprint); - write_be(node_data + 9, node->child_num); - memcpy(node_data + 13, node->chain_code, 32); - if (use_private) { - node_data[45] = 0; - memcpy(node_data + 46, node->private_key, 32); - } else { - memcpy(node_data + 45, node->public_key, 33); - } - int ret = base58_encode_check(node_data, sizeof(node_data), - node->curve->hasher_base58, str, strsize); - memzero(node_data, sizeof(node_data)); - return ret; -} - -int hdnode_serialize_public(const HDNode *node, uint32_t fingerprint, - uint32_t version, char *str, int strsize) { - return hdnode_serialize(node, fingerprint, version, false, str, strsize); -} - -int hdnode_serialize_private(const HDNode *node, uint32_t fingerprint, - uint32_t version, char *str, int strsize) { - return hdnode_serialize(node, fingerprint, version, true, str, strsize); -} - -// check for validity of curve point in case of public data not performed -static int hdnode_deserialize(const char *str, uint32_t version, - bool use_private, const char *curve, HDNode *node, - uint32_t *fingerprint) { - int ret = 0; - uint8_t node_data[78] = {0}; - memzero(node, sizeof(HDNode)); - node->curve = get_curve_by_name(curve); - if (!node->curve) { - ret = -1; - goto cleanup; - } - if (base58_decode_check(str, node->curve->hasher_base58, node_data, - sizeof(node_data)) != sizeof(node_data)) { - ret = -1; - goto cleanup; - } - uint32_t ver = read_be(node_data); - if (ver != version) { - ret = -3; // invalid version - goto cleanup; - } - if (use_private) { - // invalid data - if (node_data[45]) { - ret = -2; - goto cleanup; - } - memcpy(node->private_key, node_data + 46, 32); - memzero(node->public_key, sizeof(node->public_key)); - } else { - memzero(node->private_key, sizeof(node->private_key)); - memcpy(node->public_key, node_data + 45, 33); - } - node->depth = node_data[4]; - if (fingerprint) { - *fingerprint = read_be(node_data + 5); - } - node->child_num = read_be(node_data + 9); - memcpy(node->chain_code, node_data + 13, 32); - -cleanup: - memzero(node_data, sizeof(node_data)); - return ret; -} - -int hdnode_deserialize_public(const char *str, uint32_t version, - const char *curve, HDNode *node, - uint32_t *fingerprint) { - return hdnode_deserialize(str, version, false, curve, node, fingerprint); -} - -int hdnode_deserialize_private(const char *str, uint32_t version, - const char *curve, HDNode *node, - uint32_t *fingerprint) { - return hdnode_deserialize(str, version, true, curve, node, fingerprint); -} - -const curve_info *get_curve_by_name(const char *curve_name) { - if (curve_name == 0) { - return 0; - } - if (strcmp(curve_name, SECP256K1_NAME) == 0) { - return &secp256k1_info; - } - if (strcmp(curve_name, SECP256K1_DECRED_NAME) == 0) { - return &secp256k1_decred_info; - } - if (strcmp(curve_name, SECP256K1_GROESTL_NAME) == 0) { - return &secp256k1_groestl_info; - } - if (strcmp(curve_name, SECP256K1_SMART_NAME) == 0) { - return &secp256k1_smart_info; - } - if (strcmp(curve_name, NIST256P1_NAME) == 0) { - return &nist256p1_info; - } - if (strcmp(curve_name, ED25519_NAME) == 0) { - return &ed25519_info; - } - if (strcmp(curve_name, ED25519_CARDANO_NAME) == 0) { - return &ed25519_cardano_info; - } -#if USE_NANO - if (strcmp(curve_name, ED25519_BLAKE2B_NANO_NAME) == 0) { - return &ed25519_blake2b_nano_info; - } -#endif - if (strcmp(curve_name, ED25519_SHA3_NAME) == 0) { - return &ed25519_sha3_info; - } -#if USE_KECCAK - if (strcmp(curve_name, ED25519_KECCAK_NAME) == 0) { - return &ed25519_keccak_info; - } -#endif - if (strcmp(curve_name, CURVE25519_NAME) == 0) { - return &curve25519_info; - } - return 0; -} diff --git a/deps/crypto/trezor-crypto/bip32.h b/deps/crypto/trezor-crypto/bip32.h deleted file mode 100644 index 06d6f8001..000000000 --- a/deps/crypto/trezor-crypto/bip32.h +++ /dev/null @@ -1,157 +0,0 @@ -/** - * Copyright (c) 2013-2014 Tomas Dzetkulic - * Copyright (c) 2013-2014 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __BIP32_H__ -#define __BIP32_H__ - -#include -#include -#include -#include "ecdsa.h" -#include "ed25519-donna/ed25519.h" -#include "options.h" - -// Maximum length of a Base58Check-encoded extended public or private key. -#define XPUB_MAXLEN 112 - -// Maximum length of a Base58Check-encoded address. -#define ADDRESS_MAXLEN 39 - -typedef struct { - const char *bip32_name; // string for generating BIP32 xprv from seed - const ecdsa_curve *params; // ecdsa curve parameters, null for ed25519 - - HasherType hasher_base58; - HasherType hasher_sign; - HasherType hasher_pubkey; - HasherType hasher_script; -} curve_info; - -typedef struct { - uint32_t depth; - uint32_t child_num; - uint8_t chain_code[32]; - - uint8_t private_key[32]; - uint8_t private_key_extension[32]; - - uint8_t public_key[33]; - const curve_info *curve; -} HDNode; - -int hdnode_from_xpub(uint32_t depth, uint32_t child_num, - const uint8_t *chain_code, const uint8_t *public_key, - const char *curve, HDNode *out); - -int hdnode_from_xprv(uint32_t depth, uint32_t child_num, - const uint8_t *chain_code, const uint8_t *private_key, - const char *curve, HDNode *out); - -int hdnode_from_seed(const uint8_t *seed, int seed_len, const char *curve, - HDNode *out); - -#define hdnode_private_ckd_prime(X, I) \ - hdnode_private_ckd((X), ((I) | 0x80000000)) - -int hdnode_private_ckd(HDNode *inout, uint32_t i); - -#if USE_CARDANO -int hdnode_private_ckd_cardano(HDNode *inout, uint32_t i); -int hdnode_from_seed_cardano(const uint8_t *seed, int seed_len, HDNode *out); -int hdnode_from_entropy_cardano_icarus(const uint8_t *pass, int pass_len, - const uint8_t *seed, int seed_len, - HDNode *out); -#endif - -int hdnode_public_ckd_cp(const ecdsa_curve *curve, const curve_point *parent, - const uint8_t *parent_chain_code, uint32_t i, - curve_point *child, uint8_t *child_chain_code); - -int hdnode_public_ckd(HDNode *inout, uint32_t i); - -void hdnode_public_ckd_address_optimized(const curve_point *pub, - const uint8_t *chain_code, uint32_t i, - uint32_t version, - HasherType hasher_pubkey, - HasherType hasher_base58, char *addr, - int addrsize, int addrformat); - -#if USE_BIP32_CACHE -void bip32_cache_clear(void); -int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count, - uint32_t *fingerprint); -#endif - -uint32_t hdnode_fingerprint(HDNode *node); - -void hdnode_fill_public_key(HDNode *node); - -#if USE_ETHEREUM -int hdnode_get_ethereum_pubkeyhash(const HDNode *node, uint8_t *pubkeyhash); -#endif - -#if USE_NEM -int hdnode_get_nem_address(HDNode *node, uint8_t version, char *address); -int hdnode_get_nem_shared_key(const HDNode *node, - const ed25519_public_key peer_public_key, - const uint8_t *salt, ed25519_public_key mul, - uint8_t *shared_key); -int hdnode_nem_encrypt(const HDNode *node, const ed25519_public_key public_key, - const uint8_t *iv, const uint8_t *salt, - const uint8_t *payload, size_t size, uint8_t *buffer); -int hdnode_nem_decrypt(const HDNode *node, const ed25519_public_key public_key, - uint8_t *iv, const uint8_t *salt, const uint8_t *payload, - size_t size, uint8_t *buffer); -#endif - -int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, - HasherType hasher_sign, uint8_t *sig, uint8_t *pby, - int (*is_canonical)(uint8_t by, uint8_t sig[64])); -int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, - uint8_t *pby, - int (*is_canonical)(uint8_t by, uint8_t sig[64])); - -int hdnode_get_shared_key(const HDNode *node, const uint8_t *peer_public_key, - uint8_t *session_key, int *result_size); - -int hdnode_serialize_public(const HDNode *node, uint32_t fingerprint, - uint32_t version, char *str, int strsize); - -int hdnode_serialize_private(const HDNode *node, uint32_t fingerprint, - uint32_t version, char *str, int strsize); - -int hdnode_deserialize_public(const char *str, uint32_t version, - const char *curve, HDNode *node, - uint32_t *fingerprint); - -int hdnode_deserialize_private(const char *str, uint32_t version, - const char *curve, HDNode *node, - uint32_t *fingerprint); - -void hdnode_get_address_raw(HDNode *node, uint32_t version, uint8_t *addr_raw); -void hdnode_get_address(HDNode *node, uint32_t version, char *addr, - int addrsize); - -const curve_info *get_curve_by_name(const char *curve_name); - -#endif diff --git a/deps/crypto/trezor-crypto/bip39.c b/deps/crypto/trezor-crypto/bip39.c deleted file mode 100644 index 44074e1fa..000000000 --- a/deps/crypto/trezor-crypto/bip39.c +++ /dev/null @@ -1,323 +0,0 @@ -/** - * Copyright (c) 2013-2014 Tomas Dzetkulic - * Copyright (c) 2013-2014 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include - -#include "bip39.h" -#include "bip39_english.h" -#include "hmac.h" -#include "memzero.h" -#include "options.h" -#include "pbkdf2.h" -#include "rand.h" -#include "sha2.h" - -#if USE_BIP39_CACHE - -static int bip39_cache_index = 0; - -static CONFIDENTIAL struct { - bool set; - char mnemonic[256]; - char passphrase[64]; - uint8_t seed[512 / 8]; -} bip39_cache[BIP39_CACHE_SIZE]; - -void bip39_cache_clear(void) { - memzero(bip39_cache, sizeof(bip39_cache)); - bip39_cache_index = 0; -} - -#endif - -const char *mnemonic_generate(int strength) { - if (strength % 32 || strength < 128 || strength > 256) { - return 0; - } - uint8_t data[32] = {0}; - random_buffer(data, 32); - const char *r = mnemonic_from_data(data, strength / 8); - memzero(data, sizeof(data)); - return r; -} - -static CONFIDENTIAL char mnemo[24 * 10]; - -const char *mnemonic_from_data(const uint8_t *data, int len) { - if (len % 4 || len < 16 || len > 32) { - return 0; - } - - uint8_t bits[32 + 1] = {0}; - - sha256_Raw(data, len, bits); - // checksum - bits[len] = bits[0]; - // data - memcpy(bits, data, len); - - int mlen = len * 3 / 4; - - int i = 0, j = 0, idx = 0; - char *p = mnemo; - for (i = 0; i < mlen; i++) { - idx = 0; - for (j = 0; j < 11; j++) { - idx <<= 1; - idx += (bits[(i * 11 + j) / 8] & (1 << (7 - ((i * 11 + j) % 8)))) > 0; - } - strcpy(p, wordlist[idx]); - p += strlen(wordlist[idx]); - *p = (i < mlen - 1) ? ' ' : 0; - p++; - } - memzero(bits, sizeof(bits)); - - return mnemo; -} - -void mnemonic_clear(void) { memzero(mnemo, sizeof(mnemo)); } - -typedef struct { - int index; - size_t length; -} found_word; - -static bool constant_time_memeq(const void *s1, const void *s2, size_t n) { - const unsigned char *p1 = s1; - const unsigned char *p2 = s2; - unsigned int diff = 0; - for (size_t i = 0; i < n; i++) { - diff |= p1[i] ^ p2[i]; - } - return diff == 0; -} - -static found_word mnemonic_find_word_constant_time(const char *word) { - int result_index = -1; - size_t result_length = 0; - - for (int i = 0; i < BIP39_WORDS; i++) { - const char *dict_word = wordlist[i]; - size_t dict_word_len = strlen(dict_word); - bool is_match = - constant_time_memeq(word, dict_word, dict_word_len + 1); - int match_mask = -((int)is_match); - result_index = (match_mask & i) | (~match_mask & result_index); - result_length = - ((size_t)match_mask & dict_word_len) | - ((size_t)~match_mask & result_length); - } - - return (found_word){.index = result_index, .length = result_length}; -} - -int mnemonic_to_bits(const char *mnemonic_orig, uint8_t *bits) { - if (!mnemonic_orig || !bits) { - return 0; - } - - char mnemonic[BIP39_MAX_MNEMONIC_LEN + BIP39_MAX_WORD_LEN + 1] = {0}; - uint8_t result[32 + 1] = {0}; - int result_bits = 0; - - size_t mnemonic_len = strlen(mnemonic_orig); - if (mnemonic_len > BIP39_MAX_MNEMONIC_LEN) { - goto cleanup; - } - - uint32_t word_count = 0; - for (size_t i = 0; i < mnemonic_len; i++) { - bool is_space = mnemonic_orig[i] == ' '; - int space_mask = -((int)is_space) & ' '; - mnemonic[i] = mnemonic_orig[i] ^ space_mask; - word_count += is_space; - } - word_count++; - - if (word_count < 12 || word_count > 24 || (word_count % 3)) { - goto cleanup; - } - - uint32_t bit_count = 0; - size_t word_offset = 0; - while (word_offset < mnemonic_len) { - found_word found = - mnemonic_find_word_constant_time(&mnemonic[word_offset]); - word_offset += found.length + 1; - if (found.index < 0) { - goto cleanup; - } - - for (uint32_t bit_in_index = 0; bit_in_index < BIP39_BITS_PER_WORD; - bit_in_index++) { - uint32_t secret_bit = - ((uint32_t)found.index >> - (BIP39_BITS_PER_WORD - 1 - bit_in_index)) & - 1; - uint32_t mask = 0U - secret_bit; - result[bit_count / 8] |= - (uint8_t)((1U << (7 - (bit_count % 8))) & mask); - bit_count++; - } - } - - if (bit_count != word_count * BIP39_BITS_PER_WORD) { - goto cleanup; - } - - memcpy(bits, result, sizeof(result)); - result_bits = (int)bit_count; - -cleanup: - memzero(result, sizeof(result)); - memzero(mnemonic, sizeof(mnemonic)); - return result_bits; -} - -int mnemonic_check(const char *mnemonic) { - uint8_t bits[32 + 1] = {0}; - int mnemonic_bits_len = mnemonic_to_bits(mnemonic, bits); - int result = 0; - if (mnemonic_bits_len != (12 * BIP39_BITS_PER_WORD) && - mnemonic_bits_len != (18 * BIP39_BITS_PER_WORD) && - mnemonic_bits_len != (24 * BIP39_BITS_PER_WORD)) { - goto cleanup; - } - int words = mnemonic_bits_len / BIP39_BITS_PER_WORD; - - uint8_t checksum = bits[words * 4 / 3]; - sha256_Raw(bits, words * 4 / 3, bits); - if (words == 12) { - result = (bits[0] & 0xF0) == (checksum & 0xF0); - } else if (words == 18) { - result = (bits[0] & 0xFC) == (checksum & 0xFC); - } else if (words == 24) { - result = bits[0] == checksum; - } - -cleanup: - memzero(bits, sizeof(bits)); - return result; -} - -int mnemonic_find_word(const char *word) { - if (!word) { - return -1; - } - - char word_buffer[BIP39_MAX_WORD_LEN + 1] = {0}; - size_t word_len = strnlen(word, sizeof(word_buffer)); - if (word_len > BIP39_MAX_WORD_LEN) { - return -1; - } - memcpy(word_buffer, word, word_len); - found_word found = mnemonic_find_word_constant_time(word_buffer); - memzero(word_buffer, sizeof(word_buffer)); - return found.index; -} - -// passphrase must be at most 256 characters otherwise it would be truncated -void mnemonic_to_seed(const char *mnemonic, const char *passphrase, - uint8_t seed[512 / 8], - void (*progress_callback)(uint32_t current, - uint32_t total)) { - int mnemoniclen = strlen(mnemonic); - int passphraselen = strnlen(passphrase, 256); -#if USE_BIP39_CACHE - // check cache - if (mnemoniclen < 256 && passphraselen < 64) { - for (int i = 0; i < BIP39_CACHE_SIZE; i++) { - if (!bip39_cache[i].set) continue; - if (strcmp(bip39_cache[i].mnemonic, mnemonic) != 0) continue; - if (strcmp(bip39_cache[i].passphrase, passphrase) != 0) continue; - // found the correct entry - memcpy(seed, bip39_cache[i].seed, 512 / 8); - return; - } - } -#endif - uint8_t salt[8 + 256] = {0}; - memcpy(salt, "mnemonic", 8); - memcpy(salt + 8, passphrase, passphraselen); - static CONFIDENTIAL PBKDF2_HMAC_SHA512_CTX pctx; - pbkdf2_hmac_sha512_Init(&pctx, (const uint8_t *)mnemonic, mnemoniclen, salt, - passphraselen + 8, 1); - if (progress_callback) { - progress_callback(0, BIP39_PBKDF2_ROUNDS); - } - for (int i = 0; i < 16; i++) { - pbkdf2_hmac_sha512_Update(&pctx, BIP39_PBKDF2_ROUNDS / 16); - if (progress_callback) { - progress_callback((i + 1) * BIP39_PBKDF2_ROUNDS / 16, - BIP39_PBKDF2_ROUNDS); - } - } - pbkdf2_hmac_sha512_Final(&pctx, seed); - memzero(salt, sizeof(salt)); -#if USE_BIP39_CACHE - // store to cache - if (mnemoniclen < 256 && passphraselen < 64) { - bip39_cache[bip39_cache_index].set = true; - strcpy(bip39_cache[bip39_cache_index].mnemonic, mnemonic); - strcpy(bip39_cache[bip39_cache_index].passphrase, passphrase); - memcpy(bip39_cache[bip39_cache_index].seed, seed, 512 / 8); - bip39_cache_index = (bip39_cache_index + 1) % BIP39_CACHE_SIZE; - } -#endif -} - -const char *mnemonic_complete_word(const char *prefix, int len) { - // we need to perform linear search, - // because we want to return the first match - for (const char *const *w = wordlist; *w != 0; w++) { - if (strncmp(*w, prefix, len) == 0) { - return *w; - } - } - return NULL; -} - -const char *mnemonic_get_word(int index) { - if (index >= 0 && index < BIP39_WORDS) { - return wordlist[index]; - } else { - return NULL; - } -} - -uint32_t mnemonic_word_completion_mask(const char *prefix, int len) { - if (len <= 0) { - return 0x3ffffff; // all letters (bits 1-26 set) - } - uint32_t res = 0; - for (const char *const *w = wordlist; *w != 0; w++) { - const char *word = *w; - if (strncmp(word, prefix, len) == 0 && word[len] >= 'a' && - word[len] <= 'z') { - res |= 1 << (word[len] - 'a'); - } - } - return res; -} diff --git a/deps/crypto/trezor-crypto/bip39.h b/deps/crypto/trezor-crypto/bip39.h deleted file mode 100644 index ab1e57fad..000000000 --- a/deps/crypto/trezor-crypto/bip39.h +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Copyright (c) 2013-2014 Tomas Dzetkulic - * Copyright (c) 2013-2014 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __BIP39_H__ -#define __BIP39_H__ - -#include -#include -#include - -#include "options.h" - -#define BIP39_WORDS 2048 -#define BIP39_PBKDF2_ROUNDS 2048 -#define BIP39_MAX_WORD_LEN 8 -#define BIP39_MAX_MNEMONIC_LEN (24 * BIP39_MAX_WORD_LEN + 23) -#define BIP39_BITS_PER_WORD 11 - -#if USE_BIP39_CACHE -void bip39_cache_clear(void); -#endif - -const char *mnemonic_generate(int strength); // strength in bits -const char *mnemonic_from_data(const uint8_t *data, int len); -void mnemonic_clear(void); - -int mnemonic_check(const char *mnemonic); - -int mnemonic_to_bits(const char *mnemonic, uint8_t *bits); - -// passphrase must be at most 256 characters otherwise it would be truncated -void mnemonic_to_seed(const char *mnemonic, const char *passphrase, - uint8_t seed[512 / 8], - void (*progress_callback)(uint32_t current, - uint32_t total)); - -int mnemonic_find_word(const char *word); -const char *mnemonic_complete_word(const char *prefix, int len); -const char *mnemonic_get_word(int index); -uint32_t mnemonic_word_completion_mask(const char *prefix, int len); - -#endif diff --git a/deps/crypto/trezor-crypto/bip39_english.c b/deps/crypto/trezor-crypto/bip39_english.c deleted file mode 100644 index 82b404699..000000000 --- a/deps/crypto/trezor-crypto/bip39_english.c +++ /dev/null @@ -1,4125 +0,0 @@ -/** - * Copyright (c) 2013-2014 Tomas Dzetkulic - * Copyright (c) 2013-2014 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -const char * const wordlist[2048 + 1] = { -#ifndef BIP39_WORDLIST_PADDED -"abandon", -"ability", -"able", -"about", -"above", -"absent", -"absorb", -"abstract", -"absurd", -"abuse", -"access", -"accident", -"account", -"accuse", -"achieve", -"acid", -"acoustic", -"acquire", -"across", -"act", -"action", -"actor", -"actress", -"actual", -"adapt", -"add", -"addict", -"address", -"adjust", -"admit", -"adult", -"advance", -"advice", -"aerobic", -"affair", -"afford", -"afraid", -"again", -"age", -"agent", -"agree", -"ahead", -"aim", -"air", -"airport", -"aisle", -"alarm", -"album", -"alcohol", -"alert", -"alien", -"all", -"alley", -"allow", -"almost", -"alone", -"alpha", -"already", -"also", -"alter", -"always", -"amateur", -"amazing", -"among", -"amount", -"amused", -"analyst", -"anchor", -"ancient", -"anger", -"angle", -"angry", -"animal", -"ankle", -"announce", -"annual", -"another", -"answer", -"antenna", -"antique", -"anxiety", -"any", -"apart", -"apology", -"appear", -"apple", -"approve", -"april", -"arch", -"arctic", -"area", -"arena", -"argue", -"arm", -"armed", -"armor", -"army", -"around", -"arrange", -"arrest", -"arrive", -"arrow", -"art", -"artefact", -"artist", -"artwork", -"ask", -"aspect", -"assault", -"asset", -"assist", -"assume", -"asthma", -"athlete", -"atom", -"attack", -"attend", -"attitude", -"attract", -"auction", -"audit", -"august", -"aunt", -"author", -"auto", -"autumn", -"average", -"avocado", -"avoid", -"awake", -"aware", -"away", -"awesome", -"awful", -"awkward", -"axis", -"baby", -"bachelor", -"bacon", -"badge", -"bag", -"balance", -"balcony", -"ball", -"bamboo", -"banana", -"banner", -"bar", -"barely", -"bargain", -"barrel", -"base", -"basic", -"basket", -"battle", -"beach", -"bean", -"beauty", -"because", -"become", -"beef", -"before", -"begin", -"behave", -"behind", -"believe", -"below", -"belt", -"bench", -"benefit", -"best", -"betray", -"better", -"between", -"beyond", -"bicycle", -"bid", -"bike", -"bind", -"biology", -"bird", -"birth", -"bitter", -"black", -"blade", -"blame", -"blanket", -"blast", -"bleak", -"bless", -"blind", -"blood", -"blossom", -"blouse", -"blue", -"blur", -"blush", -"board", -"boat", -"body", -"boil", -"bomb", -"bone", -"bonus", -"book", -"boost", -"border", -"boring", -"borrow", -"boss", -"bottom", -"bounce", -"box", -"boy", -"bracket", -"brain", -"brand", -"brass", -"brave", -"bread", -"breeze", -"brick", -"bridge", -"brief", -"bright", -"bring", -"brisk", -"broccoli", -"broken", -"bronze", -"broom", -"brother", -"brown", -"brush", -"bubble", -"buddy", -"budget", -"buffalo", -"build", -"bulb", -"bulk", -"bullet", -"bundle", -"bunker", -"burden", -"burger", -"burst", -"bus", -"business", -"busy", -"butter", -"buyer", -"buzz", -"cabbage", -"cabin", -"cable", -"cactus", -"cage", -"cake", -"call", -"calm", -"camera", -"camp", -"can", -"canal", -"cancel", -"candy", -"cannon", -"canoe", -"canvas", -"canyon", -"capable", -"capital", -"captain", -"car", -"carbon", -"card", -"cargo", -"carpet", -"carry", -"cart", -"case", -"cash", -"casino", -"castle", -"casual", -"cat", -"catalog", -"catch", -"category", -"cattle", -"caught", -"cause", -"caution", -"cave", -"ceiling", -"celery", -"cement", -"census", -"century", -"cereal", -"certain", -"chair", -"chalk", -"champion", -"change", -"chaos", -"chapter", -"charge", -"chase", -"chat", -"cheap", -"check", -"cheese", -"chef", -"cherry", -"chest", -"chicken", -"chief", -"child", -"chimney", -"choice", -"choose", -"chronic", -"chuckle", -"chunk", -"churn", -"cigar", -"cinnamon", -"circle", -"citizen", -"city", -"civil", -"claim", -"clap", -"clarify", -"claw", -"clay", -"clean", -"clerk", -"clever", -"click", -"client", -"cliff", -"climb", -"clinic", -"clip", -"clock", -"clog", -"close", -"cloth", -"cloud", -"clown", -"club", -"clump", -"cluster", -"clutch", -"coach", -"coast", -"coconut", -"code", -"coffee", -"coil", -"coin", -"collect", -"color", -"column", -"combine", -"come", -"comfort", -"comic", -"common", -"company", -"concert", -"conduct", -"confirm", -"congress", -"connect", -"consider", -"control", -"convince", -"cook", -"cool", -"copper", -"copy", -"coral", -"core", -"corn", -"correct", -"cost", -"cotton", -"couch", -"country", -"couple", -"course", -"cousin", -"cover", -"coyote", -"crack", -"cradle", -"craft", -"cram", -"crane", -"crash", -"crater", -"crawl", -"crazy", -"cream", -"credit", -"creek", -"crew", -"cricket", -"crime", -"crisp", -"critic", -"crop", -"cross", -"crouch", -"crowd", -"crucial", -"cruel", -"cruise", -"crumble", -"crunch", -"crush", -"cry", -"crystal", -"cube", -"culture", -"cup", -"cupboard", -"curious", -"current", -"curtain", -"curve", -"cushion", -"custom", -"cute", -"cycle", -"dad", -"damage", -"damp", -"dance", -"danger", -"daring", -"dash", -"daughter", -"dawn", -"day", -"deal", -"debate", -"debris", -"decade", -"december", -"decide", -"decline", -"decorate", -"decrease", -"deer", -"defense", -"define", -"defy", -"degree", -"delay", -"deliver", -"demand", -"demise", -"denial", -"dentist", -"deny", -"depart", -"depend", -"deposit", -"depth", -"deputy", -"derive", -"describe", -"desert", -"design", -"desk", -"despair", -"destroy", -"detail", -"detect", -"develop", -"device", -"devote", -"diagram", -"dial", -"diamond", -"diary", -"dice", -"diesel", -"diet", -"differ", -"digital", -"dignity", -"dilemma", -"dinner", -"dinosaur", -"direct", -"dirt", -"disagree", -"discover", -"disease", -"dish", -"dismiss", -"disorder", -"display", -"distance", -"divert", -"divide", -"divorce", -"dizzy", -"doctor", -"document", -"dog", -"doll", -"dolphin", -"domain", -"donate", -"donkey", -"donor", -"door", -"dose", -"double", -"dove", -"draft", -"dragon", -"drama", -"drastic", -"draw", -"dream", -"dress", -"drift", -"drill", -"drink", -"drip", -"drive", -"drop", -"drum", -"dry", -"duck", -"dumb", -"dune", -"during", -"dust", -"dutch", -"duty", -"dwarf", -"dynamic", -"eager", -"eagle", -"early", -"earn", -"earth", -"easily", -"east", -"easy", -"echo", -"ecology", -"economy", -"edge", -"edit", -"educate", -"effort", -"egg", -"eight", -"either", -"elbow", -"elder", -"electric", -"elegant", -"element", -"elephant", -"elevator", -"elite", -"else", -"embark", -"embody", -"embrace", -"emerge", -"emotion", -"employ", -"empower", -"empty", -"enable", -"enact", -"end", -"endless", -"endorse", -"enemy", -"energy", -"enforce", -"engage", -"engine", -"enhance", -"enjoy", -"enlist", -"enough", -"enrich", -"enroll", -"ensure", -"enter", -"entire", -"entry", -"envelope", -"episode", -"equal", -"equip", -"era", -"erase", -"erode", -"erosion", -"error", -"erupt", -"escape", -"essay", -"essence", -"estate", -"eternal", -"ethics", -"evidence", -"evil", -"evoke", -"evolve", -"exact", -"example", -"excess", -"exchange", -"excite", -"exclude", -"excuse", -"execute", -"exercise", -"exhaust", -"exhibit", -"exile", -"exist", -"exit", -"exotic", -"expand", -"expect", -"expire", -"explain", -"expose", -"express", -"extend", -"extra", -"eye", -"eyebrow", -"fabric", -"face", -"faculty", -"fade", -"faint", -"faith", -"fall", -"false", -"fame", -"family", -"famous", -"fan", -"fancy", -"fantasy", -"farm", -"fashion", -"fat", -"fatal", -"father", -"fatigue", -"fault", -"favorite", -"feature", -"february", -"federal", -"fee", -"feed", -"feel", -"female", -"fence", -"festival", -"fetch", -"fever", -"few", -"fiber", -"fiction", -"field", -"figure", -"file", -"film", -"filter", -"final", -"find", -"fine", -"finger", -"finish", -"fire", -"firm", -"first", -"fiscal", -"fish", -"fit", -"fitness", -"fix", -"flag", -"flame", -"flash", -"flat", -"flavor", -"flee", -"flight", -"flip", -"float", -"flock", -"floor", -"flower", -"fluid", -"flush", -"fly", -"foam", -"focus", -"fog", -"foil", -"fold", -"follow", -"food", -"foot", -"force", -"forest", -"forget", -"fork", -"fortune", -"forum", -"forward", -"fossil", -"foster", -"found", -"fox", -"fragile", -"frame", -"frequent", -"fresh", -"friend", -"fringe", -"frog", -"front", -"frost", -"frown", -"frozen", -"fruit", -"fuel", -"fun", -"funny", -"furnace", -"fury", -"future", -"gadget", -"gain", -"galaxy", -"gallery", -"game", -"gap", -"garage", -"garbage", -"garden", -"garlic", -"garment", -"gas", -"gasp", -"gate", -"gather", -"gauge", -"gaze", -"general", -"genius", -"genre", -"gentle", -"genuine", -"gesture", -"ghost", -"giant", -"gift", -"giggle", -"ginger", -"giraffe", -"girl", -"give", -"glad", -"glance", -"glare", -"glass", -"glide", -"glimpse", -"globe", -"gloom", -"glory", -"glove", -"glow", -"glue", -"goat", -"goddess", -"gold", -"good", -"goose", -"gorilla", -"gospel", -"gossip", -"govern", -"gown", -"grab", -"grace", -"grain", -"grant", -"grape", -"grass", -"gravity", -"great", -"green", -"grid", -"grief", -"grit", -"grocery", -"group", -"grow", -"grunt", -"guard", -"guess", -"guide", -"guilt", -"guitar", -"gun", -"gym", -"habit", -"hair", -"half", -"hammer", -"hamster", -"hand", -"happy", -"harbor", -"hard", -"harsh", -"harvest", -"hat", -"have", -"hawk", -"hazard", -"head", -"health", -"heart", -"heavy", -"hedgehog", -"height", -"hello", -"helmet", -"help", -"hen", -"hero", -"hidden", -"high", -"hill", -"hint", -"hip", -"hire", -"history", -"hobby", -"hockey", -"hold", -"hole", -"holiday", -"hollow", -"home", -"honey", -"hood", -"hope", -"horn", -"horror", -"horse", -"hospital", -"host", -"hotel", -"hour", -"hover", -"hub", -"huge", -"human", -"humble", -"humor", -"hundred", -"hungry", -"hunt", -"hurdle", -"hurry", -"hurt", -"husband", -"hybrid", -"ice", -"icon", -"idea", -"identify", -"idle", -"ignore", -"ill", -"illegal", -"illness", -"image", -"imitate", -"immense", -"immune", -"impact", -"impose", -"improve", -"impulse", -"inch", -"include", -"income", -"increase", -"index", -"indicate", -"indoor", -"industry", -"infant", -"inflict", -"inform", -"inhale", -"inherit", -"initial", -"inject", -"injury", -"inmate", -"inner", -"innocent", -"input", -"inquiry", -"insane", -"insect", -"inside", -"inspire", -"install", -"intact", -"interest", -"into", -"invest", -"invite", -"involve", -"iron", -"island", -"isolate", -"issue", -"item", -"ivory", -"jacket", -"jaguar", -"jar", -"jazz", -"jealous", -"jeans", -"jelly", -"jewel", -"job", -"join", -"joke", -"journey", -"joy", -"judge", -"juice", -"jump", -"jungle", -"junior", -"junk", -"just", -"kangaroo", -"keen", -"keep", -"ketchup", -"key", -"kick", -"kid", -"kidney", -"kind", -"kingdom", -"kiss", -"kit", -"kitchen", -"kite", -"kitten", -"kiwi", -"knee", -"knife", -"knock", -"know", -"lab", -"label", -"labor", -"ladder", -"lady", -"lake", -"lamp", -"language", -"laptop", -"large", -"later", -"latin", -"laugh", -"laundry", -"lava", -"law", -"lawn", -"lawsuit", -"layer", -"lazy", -"leader", -"leaf", -"learn", -"leave", -"lecture", -"left", -"leg", -"legal", -"legend", -"leisure", -"lemon", -"lend", -"length", -"lens", -"leopard", -"lesson", -"letter", -"level", -"liar", -"liberty", -"library", -"license", -"life", -"lift", -"light", -"like", -"limb", -"limit", -"link", -"lion", -"liquid", -"list", -"little", -"live", -"lizard", -"load", -"loan", -"lobster", -"local", -"lock", -"logic", -"lonely", -"long", -"loop", -"lottery", -"loud", -"lounge", -"love", -"loyal", -"lucky", -"luggage", -"lumber", -"lunar", -"lunch", -"luxury", -"lyrics", -"machine", -"mad", -"magic", -"magnet", -"maid", -"mail", -"main", -"major", -"make", -"mammal", -"man", -"manage", -"mandate", -"mango", -"mansion", -"manual", -"maple", -"marble", -"march", -"margin", -"marine", -"market", -"marriage", -"mask", -"mass", -"master", -"match", -"material", -"math", -"matrix", -"matter", -"maximum", -"maze", -"meadow", -"mean", -"measure", -"meat", -"mechanic", -"medal", -"media", -"melody", -"melt", -"member", -"memory", -"mention", -"menu", -"mercy", -"merge", -"merit", -"merry", -"mesh", -"message", -"metal", -"method", -"middle", -"midnight", -"milk", -"million", -"mimic", -"mind", -"minimum", -"minor", -"minute", -"miracle", -"mirror", -"misery", -"miss", -"mistake", -"mix", -"mixed", -"mixture", -"mobile", -"model", -"modify", -"mom", -"moment", -"monitor", -"monkey", -"monster", -"month", -"moon", -"moral", -"more", -"morning", -"mosquito", -"mother", -"motion", -"motor", -"mountain", -"mouse", -"move", -"movie", -"much", -"muffin", -"mule", -"multiply", -"muscle", -"museum", -"mushroom", -"music", -"must", -"mutual", -"myself", -"mystery", -"myth", -"naive", -"name", -"napkin", -"narrow", -"nasty", -"nation", -"nature", -"near", -"neck", -"need", -"negative", -"neglect", -"neither", -"nephew", -"nerve", -"nest", -"net", -"network", -"neutral", -"never", -"news", -"next", -"nice", -"night", -"noble", -"noise", -"nominee", -"noodle", -"normal", -"north", -"nose", -"notable", -"note", -"nothing", -"notice", -"novel", -"now", -"nuclear", -"number", -"nurse", -"nut", -"oak", -"obey", -"object", -"oblige", -"obscure", -"observe", -"obtain", -"obvious", -"occur", -"ocean", -"october", -"odor", -"off", -"offer", -"office", -"often", -"oil", -"okay", -"old", -"olive", -"olympic", -"omit", -"once", -"one", -"onion", -"online", -"only", -"open", -"opera", -"opinion", -"oppose", -"option", -"orange", -"orbit", -"orchard", -"order", -"ordinary", -"organ", -"orient", -"original", -"orphan", -"ostrich", -"other", -"outdoor", -"outer", -"output", -"outside", -"oval", -"oven", -"over", -"own", -"owner", -"oxygen", -"oyster", -"ozone", -"pact", -"paddle", -"page", -"pair", -"palace", -"palm", -"panda", -"panel", -"panic", -"panther", -"paper", -"parade", -"parent", -"park", -"parrot", -"party", -"pass", -"patch", -"path", -"patient", -"patrol", -"pattern", -"pause", -"pave", -"payment", -"peace", -"peanut", -"pear", -"peasant", -"pelican", -"pen", -"penalty", -"pencil", -"people", -"pepper", -"perfect", -"permit", -"person", -"pet", -"phone", -"photo", -"phrase", -"physical", -"piano", -"picnic", -"picture", -"piece", -"pig", -"pigeon", -"pill", -"pilot", -"pink", -"pioneer", -"pipe", -"pistol", -"pitch", -"pizza", -"place", -"planet", -"plastic", -"plate", -"play", -"please", -"pledge", -"pluck", -"plug", -"plunge", -"poem", -"poet", -"point", -"polar", -"pole", -"police", -"pond", -"pony", -"pool", -"popular", -"portion", -"position", -"possible", -"post", -"potato", -"pottery", -"poverty", -"powder", -"power", -"practice", -"praise", -"predict", -"prefer", -"prepare", -"present", -"pretty", -"prevent", -"price", -"pride", -"primary", -"print", -"priority", -"prison", -"private", -"prize", -"problem", -"process", -"produce", -"profit", -"program", -"project", -"promote", -"proof", -"property", -"prosper", -"protect", -"proud", -"provide", -"public", -"pudding", -"pull", -"pulp", -"pulse", -"pumpkin", -"punch", -"pupil", -"puppy", -"purchase", -"purity", -"purpose", -"purse", -"push", -"put", -"puzzle", -"pyramid", -"quality", -"quantum", -"quarter", -"question", -"quick", -"quit", -"quiz", -"quote", -"rabbit", -"raccoon", -"race", -"rack", -"radar", -"radio", -"rail", -"rain", -"raise", -"rally", -"ramp", -"ranch", -"random", -"range", -"rapid", -"rare", -"rate", -"rather", -"raven", -"raw", -"razor", -"ready", -"real", -"reason", -"rebel", -"rebuild", -"recall", -"receive", -"recipe", -"record", -"recycle", -"reduce", -"reflect", -"reform", -"refuse", -"region", -"regret", -"regular", -"reject", -"relax", -"release", -"relief", -"rely", -"remain", -"remember", -"remind", -"remove", -"render", -"renew", -"rent", -"reopen", -"repair", -"repeat", -"replace", -"report", -"require", -"rescue", -"resemble", -"resist", -"resource", -"response", -"result", -"retire", -"retreat", -"return", -"reunion", -"reveal", -"review", -"reward", -"rhythm", -"rib", -"ribbon", -"rice", -"rich", -"ride", -"ridge", -"rifle", -"right", -"rigid", -"ring", -"riot", -"ripple", -"risk", -"ritual", -"rival", -"river", -"road", -"roast", -"robot", -"robust", -"rocket", -"romance", -"roof", -"rookie", -"room", -"rose", -"rotate", -"rough", -"round", -"route", -"royal", -"rubber", -"rude", -"rug", -"rule", -"run", -"runway", -"rural", -"sad", -"saddle", -"sadness", -"safe", -"sail", -"salad", -"salmon", -"salon", -"salt", -"salute", -"same", -"sample", -"sand", -"satisfy", -"satoshi", -"sauce", -"sausage", -"save", -"say", -"scale", -"scan", -"scare", -"scatter", -"scene", -"scheme", -"school", -"science", -"scissors", -"scorpion", -"scout", -"scrap", -"screen", -"script", -"scrub", -"sea", -"search", -"season", -"seat", -"second", -"secret", -"section", -"security", -"seed", -"seek", -"segment", -"select", -"sell", -"seminar", -"senior", -"sense", -"sentence", -"series", -"service", -"session", -"settle", -"setup", -"seven", -"shadow", -"shaft", -"shallow", -"share", -"shed", -"shell", -"sheriff", -"shield", -"shift", -"shine", -"ship", -"shiver", -"shock", -"shoe", -"shoot", -"shop", -"short", -"shoulder", -"shove", -"shrimp", -"shrug", -"shuffle", -"shy", -"sibling", -"sick", -"side", -"siege", -"sight", -"sign", -"silent", -"silk", -"silly", -"silver", -"similar", -"simple", -"since", -"sing", -"siren", -"sister", -"situate", -"six", -"size", -"skate", -"sketch", -"ski", -"skill", -"skin", -"skirt", -"skull", -"slab", -"slam", -"sleep", -"slender", -"slice", -"slide", -"slight", -"slim", -"slogan", -"slot", -"slow", -"slush", -"small", -"smart", -"smile", -"smoke", -"smooth", -"snack", -"snake", -"snap", -"sniff", -"snow", -"soap", -"soccer", -"social", -"sock", -"soda", -"soft", -"solar", -"soldier", -"solid", -"solution", -"solve", -"someone", -"song", -"soon", -"sorry", -"sort", -"soul", -"sound", -"soup", -"source", -"south", -"space", -"spare", -"spatial", -"spawn", -"speak", -"special", -"speed", -"spell", -"spend", -"sphere", -"spice", -"spider", -"spike", -"spin", -"spirit", -"split", -"spoil", -"sponsor", -"spoon", -"sport", -"spot", -"spray", -"spread", -"spring", -"spy", -"square", -"squeeze", -"squirrel", -"stable", -"stadium", -"staff", -"stage", -"stairs", -"stamp", -"stand", -"start", -"state", -"stay", -"steak", -"steel", -"stem", -"step", -"stereo", -"stick", -"still", -"sting", -"stock", -"stomach", -"stone", -"stool", -"story", -"stove", -"strategy", -"street", -"strike", -"strong", -"struggle", -"student", -"stuff", -"stumble", -"style", -"subject", -"submit", -"subway", -"success", -"such", -"sudden", -"suffer", -"sugar", -"suggest", -"suit", -"summer", -"sun", -"sunny", -"sunset", -"super", -"supply", -"supreme", -"sure", -"surface", -"surge", -"surprise", -"surround", -"survey", -"suspect", -"sustain", -"swallow", -"swamp", -"swap", -"swarm", -"swear", -"sweet", -"swift", -"swim", -"swing", -"switch", -"sword", -"symbol", -"symptom", -"syrup", -"system", -"table", -"tackle", -"tag", -"tail", -"talent", -"talk", -"tank", -"tape", -"target", -"task", -"taste", -"tattoo", -"taxi", -"teach", -"team", -"tell", -"ten", -"tenant", -"tennis", -"tent", -"term", -"test", -"text", -"thank", -"that", -"theme", -"then", -"theory", -"there", -"they", -"thing", -"this", -"thought", -"three", -"thrive", -"throw", -"thumb", -"thunder", -"ticket", -"tide", -"tiger", -"tilt", -"timber", -"time", -"tiny", -"tip", -"tired", -"tissue", -"title", -"toast", -"tobacco", -"today", -"toddler", -"toe", -"together", -"toilet", -"token", -"tomato", -"tomorrow", -"tone", -"tongue", -"tonight", -"tool", -"tooth", -"top", -"topic", -"topple", -"torch", -"tornado", -"tortoise", -"toss", -"total", -"tourist", -"toward", -"tower", -"town", -"toy", -"track", -"trade", -"traffic", -"tragic", -"train", -"transfer", -"trap", -"trash", -"travel", -"tray", -"treat", -"tree", -"trend", -"trial", -"tribe", -"trick", -"trigger", -"trim", -"trip", -"trophy", -"trouble", -"truck", -"true", -"truly", -"trumpet", -"trust", -"truth", -"try", -"tube", -"tuition", -"tumble", -"tuna", -"tunnel", -"turkey", -"turn", -"turtle", -"twelve", -"twenty", -"twice", -"twin", -"twist", -"two", -"type", -"typical", -"ugly", -"umbrella", -"unable", -"unaware", -"uncle", -"uncover", -"under", -"undo", -"unfair", -"unfold", -"unhappy", -"uniform", -"unique", -"unit", -"universe", -"unknown", -"unlock", -"until", -"unusual", -"unveil", -"update", -"upgrade", -"uphold", -"upon", -"upper", -"upset", -"urban", -"urge", -"usage", -"use", -"used", -"useful", -"useless", -"usual", -"utility", -"vacant", -"vacuum", -"vague", -"valid", -"valley", -"valve", -"van", -"vanish", -"vapor", -"various", -"vast", -"vault", -"vehicle", -"velvet", -"vendor", -"venture", -"venue", -"verb", -"verify", -"version", -"very", -"vessel", -"veteran", -"viable", -"vibrant", -"vicious", -"victory", -"video", -"view", -"village", -"vintage", -"violin", -"virtual", -"virus", -"visa", -"visit", -"visual", -"vital", -"vivid", -"vocal", -"voice", -"void", -"volcano", -"volume", -"vote", -"voyage", -"wage", -"wagon", -"wait", -"walk", -"wall", -"walnut", -"want", -"warfare", -"warm", -"warrior", -"wash", -"wasp", -"waste", -"water", -"wave", -"way", -"wealth", -"weapon", -"wear", -"weasel", -"weather", -"web", -"wedding", -"weekend", -"weird", -"welcome", -"west", -"wet", -"whale", -"what", -"wheat", -"wheel", -"when", -"where", -"whip", -"whisper", -"wide", -"width", -"wife", -"wild", -"will", -"win", -"window", -"wine", -"wing", -"wink", -"winner", -"winter", -"wire", -"wisdom", -"wise", -"wish", -"witness", -"wolf", -"woman", -"wonder", -"wood", -"wool", -"word", -"work", -"world", -"worry", -"worth", -"wrap", -"wreck", -"wrestle", -"wrist", -"write", -"wrong", -"yard", -"year", -"yellow", -"you", -"young", -"youth", -"zebra", -"zero", -"zone", -"zoo", -#else -"abandon\0", -"ability\0", -"able\0\0\0\0", -"about\0\0\0", -"above\0\0\0", -"absent\0\0", -"absorb\0\0", -"abstract", -"absurd\0\0", -"abuse\0\0\0", -"access\0\0", -"accident", -"account\0", -"accuse\0\0", -"achieve\0", -"acid\0\0\0\0", -"acoustic", -"acquire\0", -"across\0\0", -"act\0\0\0\0\0", -"action\0\0", -"actor\0\0\0", -"actress\0", -"actual\0\0", -"adapt\0\0\0", -"add\0\0\0\0\0", -"addict\0\0", -"address\0", -"adjust\0\0", -"admit\0\0\0", -"adult\0\0\0", -"advance\0", -"advice\0\0", -"aerobic\0", -"affair\0\0", -"afford\0\0", -"afraid\0\0", -"again\0\0\0", -"age\0\0\0\0\0", -"agent\0\0\0", -"agree\0\0\0", -"ahead\0\0\0", -"aim\0\0\0\0\0", -"air\0\0\0\0\0", -"airport\0", -"aisle\0\0\0", -"alarm\0\0\0", -"album\0\0\0", -"alcohol\0", -"alert\0\0\0", -"alien\0\0\0", -"all\0\0\0\0\0", -"alley\0\0\0", -"allow\0\0\0", -"almost\0\0", -"alone\0\0\0", -"alpha\0\0\0", -"already\0", -"also\0\0\0\0", -"alter\0\0\0", -"always\0\0", -"amateur\0", -"amazing\0", -"among\0\0\0", -"amount\0\0", -"amused\0\0", -"analyst\0", -"anchor\0\0", -"ancient\0", -"anger\0\0\0", -"angle\0\0\0", -"angry\0\0\0", -"animal\0\0", -"ankle\0\0\0", -"announce", -"annual\0\0", -"another\0", -"answer\0\0", -"antenna\0", -"antique\0", -"anxiety\0", -"any\0\0\0\0\0", -"apart\0\0\0", -"apology\0", -"appear\0\0", -"apple\0\0\0", -"approve\0", -"april\0\0\0", -"arch\0\0\0\0", -"arctic\0\0", -"area\0\0\0\0", -"arena\0\0\0", -"argue\0\0\0", -"arm\0\0\0\0\0", -"armed\0\0\0", -"armor\0\0\0", -"army\0\0\0\0", -"around\0\0", -"arrange\0", -"arrest\0\0", -"arrive\0\0", -"arrow\0\0\0", -"art\0\0\0\0\0", -"artefact", -"artist\0\0", -"artwork\0", -"ask\0\0\0\0\0", -"aspect\0\0", -"assault\0", -"asset\0\0\0", -"assist\0\0", -"assume\0\0", -"asthma\0\0", -"athlete\0", -"atom\0\0\0\0", -"attack\0\0", -"attend\0\0", -"attitude", -"attract\0", -"auction\0", -"audit\0\0\0", -"august\0\0", -"aunt\0\0\0\0", -"author\0\0", -"auto\0\0\0\0", -"autumn\0\0", -"average\0", -"avocado\0", -"avoid\0\0\0", -"awake\0\0\0", -"aware\0\0\0", -"away\0\0\0\0", -"awesome\0", -"awful\0\0\0", -"awkward\0", -"axis\0\0\0\0", -"baby\0\0\0\0", -"bachelor", -"bacon\0\0\0", -"badge\0\0\0", -"bag\0\0\0\0\0", -"balance\0", -"balcony\0", -"ball\0\0\0\0", -"bamboo\0\0", -"banana\0\0", -"banner\0\0", -"bar\0\0\0\0\0", -"barely\0\0", -"bargain\0", -"barrel\0\0", -"base\0\0\0\0", -"basic\0\0\0", -"basket\0\0", -"battle\0\0", -"beach\0\0\0", -"bean\0\0\0\0", -"beauty\0\0", -"because\0", -"become\0\0", -"beef\0\0\0\0", -"before\0\0", -"begin\0\0\0", -"behave\0\0", -"behind\0\0", -"believe\0", -"below\0\0\0", -"belt\0\0\0\0", -"bench\0\0\0", -"benefit\0", -"best\0\0\0\0", -"betray\0\0", -"better\0\0", -"between\0", -"beyond\0\0", -"bicycle\0", -"bid\0\0\0\0\0", -"bike\0\0\0\0", -"bind\0\0\0\0", -"biology\0", -"bird\0\0\0\0", -"birth\0\0\0", -"bitter\0\0", -"black\0\0\0", -"blade\0\0\0", -"blame\0\0\0", -"blanket\0", -"blast\0\0\0", -"bleak\0\0\0", -"bless\0\0\0", -"blind\0\0\0", -"blood\0\0\0", -"blossom\0", -"blouse\0\0", -"blue\0\0\0\0", -"blur\0\0\0\0", -"blush\0\0\0", -"board\0\0\0", -"boat\0\0\0\0", -"body\0\0\0\0", -"boil\0\0\0\0", -"bomb\0\0\0\0", -"bone\0\0\0\0", -"bonus\0\0\0", -"book\0\0\0\0", -"boost\0\0\0", -"border\0\0", -"boring\0\0", -"borrow\0\0", -"boss\0\0\0\0", -"bottom\0\0", -"bounce\0\0", -"box\0\0\0\0\0", -"boy\0\0\0\0\0", -"bracket\0", -"brain\0\0\0", -"brand\0\0\0", -"brass\0\0\0", -"brave\0\0\0", -"bread\0\0\0", -"breeze\0\0", -"brick\0\0\0", -"bridge\0\0", -"brief\0\0\0", -"bright\0\0", -"bring\0\0\0", -"brisk\0\0\0", -"broccoli", -"broken\0\0", -"bronze\0\0", -"broom\0\0\0", -"brother\0", -"brown\0\0\0", -"brush\0\0\0", -"bubble\0\0", -"buddy\0\0\0", -"budget\0\0", -"buffalo\0", -"build\0\0\0", -"bulb\0\0\0\0", -"bulk\0\0\0\0", -"bullet\0\0", -"bundle\0\0", -"bunker\0\0", -"burden\0\0", -"burger\0\0", -"burst\0\0\0", -"bus\0\0\0\0\0", -"business", -"busy\0\0\0\0", -"butter\0\0", -"buyer\0\0\0", -"buzz\0\0\0\0", -"cabbage\0", -"cabin\0\0\0", -"cable\0\0\0", -"cactus\0\0", -"cage\0\0\0\0", -"cake\0\0\0\0", -"call\0\0\0\0", -"calm\0\0\0\0", -"camera\0\0", -"camp\0\0\0\0", -"can\0\0\0\0\0", -"canal\0\0\0", -"cancel\0\0", -"candy\0\0\0", -"cannon\0\0", -"canoe\0\0\0", -"canvas\0\0", -"canyon\0\0", -"capable\0", -"capital\0", -"captain\0", -"car\0\0\0\0\0", -"carbon\0\0", -"card\0\0\0\0", -"cargo\0\0\0", -"carpet\0\0", -"carry\0\0\0", -"cart\0\0\0\0", -"case\0\0\0\0", -"cash\0\0\0\0", -"casino\0\0", -"castle\0\0", -"casual\0\0", -"cat\0\0\0\0\0", -"catalog\0", -"catch\0\0\0", -"category", -"cattle\0\0", -"caught\0\0", -"cause\0\0\0", -"caution\0", -"cave\0\0\0\0", -"ceiling\0", -"celery\0\0", -"cement\0\0", -"census\0\0", -"century\0", -"cereal\0\0", -"certain\0", -"chair\0\0\0", -"chalk\0\0\0", -"champion", -"change\0\0", -"chaos\0\0\0", -"chapter\0", -"charge\0\0", -"chase\0\0\0", -"chat\0\0\0\0", -"cheap\0\0\0", -"check\0\0\0", -"cheese\0\0", -"chef\0\0\0\0", -"cherry\0\0", -"chest\0\0\0", -"chicken\0", -"chief\0\0\0", -"child\0\0\0", -"chimney\0", -"choice\0\0", -"choose\0\0", -"chronic\0", -"chuckle\0", -"chunk\0\0\0", -"churn\0\0\0", -"cigar\0\0\0", -"cinnamon", -"circle\0\0", -"citizen\0", -"city\0\0\0\0", -"civil\0\0\0", -"claim\0\0\0", -"clap\0\0\0\0", -"clarify\0", -"claw\0\0\0\0", -"clay\0\0\0\0", -"clean\0\0\0", -"clerk\0\0\0", -"clever\0\0", -"click\0\0\0", -"client\0\0", -"cliff\0\0\0", -"climb\0\0\0", -"clinic\0\0", -"clip\0\0\0\0", -"clock\0\0\0", -"clog\0\0\0\0", -"close\0\0\0", -"cloth\0\0\0", -"cloud\0\0\0", -"clown\0\0\0", -"club\0\0\0\0", -"clump\0\0\0", -"cluster\0", -"clutch\0\0", -"coach\0\0\0", -"coast\0\0\0", -"coconut\0", -"code\0\0\0\0", -"coffee\0\0", -"coil\0\0\0\0", -"coin\0\0\0\0", -"collect\0", -"color\0\0\0", -"column\0\0", -"combine\0", -"come\0\0\0\0", -"comfort\0", -"comic\0\0\0", -"common\0\0", -"company\0", -"concert\0", -"conduct\0", -"confirm\0", -"congress", -"connect\0", -"consider", -"control\0", -"convince", -"cook\0\0\0\0", -"cool\0\0\0\0", -"copper\0\0", -"copy\0\0\0\0", -"coral\0\0\0", -"core\0\0\0\0", -"corn\0\0\0\0", -"correct\0", -"cost\0\0\0\0", -"cotton\0\0", -"couch\0\0\0", -"country\0", -"couple\0\0", -"course\0\0", -"cousin\0\0", -"cover\0\0\0", -"coyote\0\0", -"crack\0\0\0", -"cradle\0\0", -"craft\0\0\0", -"cram\0\0\0\0", -"crane\0\0\0", -"crash\0\0\0", -"crater\0\0", -"crawl\0\0\0", -"crazy\0\0\0", -"cream\0\0\0", -"credit\0\0", -"creek\0\0\0", -"crew\0\0\0\0", -"cricket\0", -"crime\0\0\0", -"crisp\0\0\0", -"critic\0\0", -"crop\0\0\0\0", -"cross\0\0\0", -"crouch\0\0", -"crowd\0\0\0", -"crucial\0", -"cruel\0\0\0", -"cruise\0\0", -"crumble\0", -"crunch\0\0", -"crush\0\0\0", -"cry\0\0\0\0\0", -"crystal\0", -"cube\0\0\0\0", -"culture\0", -"cup\0\0\0\0\0", -"cupboard", -"curious\0", -"current\0", -"curtain\0", -"curve\0\0\0", -"cushion\0", -"custom\0\0", -"cute\0\0\0\0", -"cycle\0\0\0", -"dad\0\0\0\0\0", -"damage\0\0", -"damp\0\0\0\0", -"dance\0\0\0", -"danger\0\0", -"daring\0\0", -"dash\0\0\0\0", -"daughter", -"dawn\0\0\0\0", -"day\0\0\0\0\0", -"deal\0\0\0\0", -"debate\0\0", -"debris\0\0", -"decade\0\0", -"december", -"decide\0\0", -"decline\0", -"decorate", -"decrease", -"deer\0\0\0\0", -"defense\0", -"define\0\0", -"defy\0\0\0\0", -"degree\0\0", -"delay\0\0\0", -"deliver\0", -"demand\0\0", -"demise\0\0", -"denial\0\0", -"dentist\0", -"deny\0\0\0\0", -"depart\0\0", -"depend\0\0", -"deposit\0", -"depth\0\0\0", -"deputy\0\0", -"derive\0\0", -"describe", -"desert\0\0", -"design\0\0", -"desk\0\0\0\0", -"despair\0", -"destroy\0", -"detail\0\0", -"detect\0\0", -"develop\0", -"device\0\0", -"devote\0\0", -"diagram\0", -"dial\0\0\0\0", -"diamond\0", -"diary\0\0\0", -"dice\0\0\0\0", -"diesel\0\0", -"diet\0\0\0\0", -"differ\0\0", -"digital\0", -"dignity\0", -"dilemma\0", -"dinner\0\0", -"dinosaur", -"direct\0\0", -"dirt\0\0\0\0", -"disagree", -"discover", -"disease\0", -"dish\0\0\0\0", -"dismiss\0", -"disorder", -"display\0", -"distance", -"divert\0\0", -"divide\0\0", -"divorce\0", -"dizzy\0\0\0", -"doctor\0\0", -"document", -"dog\0\0\0\0\0", -"doll\0\0\0\0", -"dolphin\0", -"domain\0\0", -"donate\0\0", -"donkey\0\0", -"donor\0\0\0", -"door\0\0\0\0", -"dose\0\0\0\0", -"double\0\0", -"dove\0\0\0\0", -"draft\0\0\0", -"dragon\0\0", -"drama\0\0\0", -"drastic\0", -"draw\0\0\0\0", -"dream\0\0\0", -"dress\0\0\0", -"drift\0\0\0", -"drill\0\0\0", -"drink\0\0\0", -"drip\0\0\0\0", -"drive\0\0\0", -"drop\0\0\0\0", -"drum\0\0\0\0", -"dry\0\0\0\0\0", -"duck\0\0\0\0", -"dumb\0\0\0\0", -"dune\0\0\0\0", -"during\0\0", -"dust\0\0\0\0", -"dutch\0\0\0", -"duty\0\0\0\0", -"dwarf\0\0\0", -"dynamic\0", -"eager\0\0\0", -"eagle\0\0\0", -"early\0\0\0", -"earn\0\0\0\0", -"earth\0\0\0", -"easily\0\0", -"east\0\0\0\0", -"easy\0\0\0\0", -"echo\0\0\0\0", -"ecology\0", -"economy\0", -"edge\0\0\0\0", -"edit\0\0\0\0", -"educate\0", -"effort\0\0", -"egg\0\0\0\0\0", -"eight\0\0\0", -"either\0\0", -"elbow\0\0\0", -"elder\0\0\0", -"electric", -"elegant\0", -"element\0", -"elephant", -"elevator", -"elite\0\0\0", -"else\0\0\0\0", -"embark\0\0", -"embody\0\0", -"embrace\0", -"emerge\0\0", -"emotion\0", -"employ\0\0", -"empower\0", -"empty\0\0\0", -"enable\0\0", -"enact\0\0\0", -"end\0\0\0\0\0", -"endless\0", -"endorse\0", -"enemy\0\0\0", -"energy\0\0", -"enforce\0", -"engage\0\0", -"engine\0\0", -"enhance\0", -"enjoy\0\0\0", -"enlist\0\0", -"enough\0\0", -"enrich\0\0", -"enroll\0\0", -"ensure\0\0", -"enter\0\0\0", -"entire\0\0", -"entry\0\0\0", -"envelope", -"episode\0", -"equal\0\0\0", -"equip\0\0\0", -"era\0\0\0\0\0", -"erase\0\0\0", -"erode\0\0\0", -"erosion\0", -"error\0\0\0", -"erupt\0\0\0", -"escape\0\0", -"essay\0\0\0", -"essence\0", -"estate\0\0", -"eternal\0", -"ethics\0\0", -"evidence", -"evil\0\0\0\0", -"evoke\0\0\0", -"evolve\0\0", -"exact\0\0\0", -"example\0", -"excess\0\0", -"exchange", -"excite\0\0", -"exclude\0", -"excuse\0\0", -"execute\0", -"exercise", -"exhaust\0", -"exhibit\0", -"exile\0\0\0", -"exist\0\0\0", -"exit\0\0\0\0", -"exotic\0\0", -"expand\0\0", -"expect\0\0", -"expire\0\0", -"explain\0", -"expose\0\0", -"express\0", -"extend\0\0", -"extra\0\0\0", -"eye\0\0\0\0\0", -"eyebrow\0", -"fabric\0\0", -"face\0\0\0\0", -"faculty\0", -"fade\0\0\0\0", -"faint\0\0\0", -"faith\0\0\0", -"fall\0\0\0\0", -"false\0\0\0", -"fame\0\0\0\0", -"family\0\0", -"famous\0\0", -"fan\0\0\0\0\0", -"fancy\0\0\0", -"fantasy\0", -"farm\0\0\0\0", -"fashion\0", -"fat\0\0\0\0\0", -"fatal\0\0\0", -"father\0\0", -"fatigue\0", -"fault\0\0\0", -"favorite", -"feature\0", -"february", -"federal\0", -"fee\0\0\0\0\0", -"feed\0\0\0\0", -"feel\0\0\0\0", -"female\0\0", -"fence\0\0\0", -"festival", -"fetch\0\0\0", -"fever\0\0\0", -"few\0\0\0\0\0", -"fiber\0\0\0", -"fiction\0", -"field\0\0\0", -"figure\0\0", -"file\0\0\0\0", -"film\0\0\0\0", -"filter\0\0", -"final\0\0\0", -"find\0\0\0\0", -"fine\0\0\0\0", -"finger\0\0", -"finish\0\0", -"fire\0\0\0\0", -"firm\0\0\0\0", -"first\0\0\0", -"fiscal\0\0", -"fish\0\0\0\0", -"fit\0\0\0\0\0", -"fitness\0", -"fix\0\0\0\0\0", -"flag\0\0\0\0", -"flame\0\0\0", -"flash\0\0\0", -"flat\0\0\0\0", -"flavor\0\0", -"flee\0\0\0\0", -"flight\0\0", -"flip\0\0\0\0", -"float\0\0\0", -"flock\0\0\0", -"floor\0\0\0", -"flower\0\0", -"fluid\0\0\0", -"flush\0\0\0", -"fly\0\0\0\0\0", -"foam\0\0\0\0", -"focus\0\0\0", -"fog\0\0\0\0\0", -"foil\0\0\0\0", -"fold\0\0\0\0", -"follow\0\0", -"food\0\0\0\0", -"foot\0\0\0\0", -"force\0\0\0", -"forest\0\0", -"forget\0\0", -"fork\0\0\0\0", -"fortune\0", -"forum\0\0\0", -"forward\0", -"fossil\0\0", -"foster\0\0", -"found\0\0\0", -"fox\0\0\0\0\0", -"fragile\0", -"frame\0\0\0", -"frequent", -"fresh\0\0\0", -"friend\0\0", -"fringe\0\0", -"frog\0\0\0\0", -"front\0\0\0", -"frost\0\0\0", -"frown\0\0\0", -"frozen\0\0", -"fruit\0\0\0", -"fuel\0\0\0\0", -"fun\0\0\0\0\0", -"funny\0\0\0", -"furnace\0", -"fury\0\0\0\0", -"future\0\0", -"gadget\0\0", -"gain\0\0\0\0", -"galaxy\0\0", -"gallery\0", -"game\0\0\0\0", -"gap\0\0\0\0\0", -"garage\0\0", -"garbage\0", -"garden\0\0", -"garlic\0\0", -"garment\0", -"gas\0\0\0\0\0", -"gasp\0\0\0\0", -"gate\0\0\0\0", -"gather\0\0", -"gauge\0\0\0", -"gaze\0\0\0\0", -"general\0", -"genius\0\0", -"genre\0\0\0", -"gentle\0\0", -"genuine\0", -"gesture\0", -"ghost\0\0\0", -"giant\0\0\0", -"gift\0\0\0\0", -"giggle\0\0", -"ginger\0\0", -"giraffe\0", -"girl\0\0\0\0", -"give\0\0\0\0", -"glad\0\0\0\0", -"glance\0\0", -"glare\0\0\0", -"glass\0\0\0", -"glide\0\0\0", -"glimpse\0", -"globe\0\0\0", -"gloom\0\0\0", -"glory\0\0\0", -"glove\0\0\0", -"glow\0\0\0\0", -"glue\0\0\0\0", -"goat\0\0\0\0", -"goddess\0", -"gold\0\0\0\0", -"good\0\0\0\0", -"goose\0\0\0", -"gorilla\0", -"gospel\0\0", -"gossip\0\0", -"govern\0\0", -"gown\0\0\0\0", -"grab\0\0\0\0", -"grace\0\0\0", -"grain\0\0\0", -"grant\0\0\0", -"grape\0\0\0", -"grass\0\0\0", -"gravity\0", -"great\0\0\0", -"green\0\0\0", -"grid\0\0\0\0", -"grief\0\0\0", -"grit\0\0\0\0", -"grocery\0", -"group\0\0\0", -"grow\0\0\0\0", -"grunt\0\0\0", -"guard\0\0\0", -"guess\0\0\0", -"guide\0\0\0", -"guilt\0\0\0", -"guitar\0\0", -"gun\0\0\0\0\0", -"gym\0\0\0\0\0", -"habit\0\0\0", -"hair\0\0\0\0", -"half\0\0\0\0", -"hammer\0\0", -"hamster\0", -"hand\0\0\0\0", -"happy\0\0\0", -"harbor\0\0", -"hard\0\0\0\0", -"harsh\0\0\0", -"harvest\0", -"hat\0\0\0\0\0", -"have\0\0\0\0", -"hawk\0\0\0\0", -"hazard\0\0", -"head\0\0\0\0", -"health\0\0", -"heart\0\0\0", -"heavy\0\0\0", -"hedgehog", -"height\0\0", -"hello\0\0\0", -"helmet\0\0", -"help\0\0\0\0", -"hen\0\0\0\0\0", -"hero\0\0\0\0", -"hidden\0\0", -"high\0\0\0\0", -"hill\0\0\0\0", -"hint\0\0\0\0", -"hip\0\0\0\0\0", -"hire\0\0\0\0", -"history\0", -"hobby\0\0\0", -"hockey\0\0", -"hold\0\0\0\0", -"hole\0\0\0\0", -"holiday\0", -"hollow\0\0", -"home\0\0\0\0", -"honey\0\0\0", -"hood\0\0\0\0", -"hope\0\0\0\0", -"horn\0\0\0\0", -"horror\0\0", -"horse\0\0\0", -"hospital", -"host\0\0\0\0", -"hotel\0\0\0", -"hour\0\0\0\0", -"hover\0\0\0", -"hub\0\0\0\0\0", -"huge\0\0\0\0", -"human\0\0\0", -"humble\0\0", -"humor\0\0\0", -"hundred\0", -"hungry\0\0", -"hunt\0\0\0\0", -"hurdle\0\0", -"hurry\0\0\0", -"hurt\0\0\0\0", -"husband\0", -"hybrid\0\0", -"ice\0\0\0\0\0", -"icon\0\0\0\0", -"idea\0\0\0\0", -"identify", -"idle\0\0\0\0", -"ignore\0\0", -"ill\0\0\0\0\0", -"illegal\0", -"illness\0", -"image\0\0\0", -"imitate\0", -"immense\0", -"immune\0\0", -"impact\0\0", -"impose\0\0", -"improve\0", -"impulse\0", -"inch\0\0\0\0", -"include\0", -"income\0\0", -"increase", -"index\0\0\0", -"indicate", -"indoor\0\0", -"industry", -"infant\0\0", -"inflict\0", -"inform\0\0", -"inhale\0\0", -"inherit\0", -"initial\0", -"inject\0\0", -"injury\0\0", -"inmate\0\0", -"inner\0\0\0", -"innocent", -"input\0\0\0", -"inquiry\0", -"insane\0\0", -"insect\0\0", -"inside\0\0", -"inspire\0", -"install\0", -"intact\0\0", -"interest", -"into\0\0\0\0", -"invest\0\0", -"invite\0\0", -"involve\0", -"iron\0\0\0\0", -"island\0\0", -"isolate\0", -"issue\0\0\0", -"item\0\0\0\0", -"ivory\0\0\0", -"jacket\0\0", -"jaguar\0\0", -"jar\0\0\0\0\0", -"jazz\0\0\0\0", -"jealous\0", -"jeans\0\0\0", -"jelly\0\0\0", -"jewel\0\0\0", -"job\0\0\0\0\0", -"join\0\0\0\0", -"joke\0\0\0\0", -"journey\0", -"joy\0\0\0\0\0", -"judge\0\0\0", -"juice\0\0\0", -"jump\0\0\0\0", -"jungle\0\0", -"junior\0\0", -"junk\0\0\0\0", -"just\0\0\0\0", -"kangaroo", -"keen\0\0\0\0", -"keep\0\0\0\0", -"ketchup\0", -"key\0\0\0\0\0", -"kick\0\0\0\0", -"kid\0\0\0\0\0", -"kidney\0\0", -"kind\0\0\0\0", -"kingdom\0", -"kiss\0\0\0\0", -"kit\0\0\0\0\0", -"kitchen\0", -"kite\0\0\0\0", -"kitten\0\0", -"kiwi\0\0\0\0", -"knee\0\0\0\0", -"knife\0\0\0", -"knock\0\0\0", -"know\0\0\0\0", -"lab\0\0\0\0\0", -"label\0\0\0", -"labor\0\0\0", -"ladder\0\0", -"lady\0\0\0\0", -"lake\0\0\0\0", -"lamp\0\0\0\0", -"language", -"laptop\0\0", -"large\0\0\0", -"later\0\0\0", -"latin\0\0\0", -"laugh\0\0\0", -"laundry\0", -"lava\0\0\0\0", -"law\0\0\0\0\0", -"lawn\0\0\0\0", -"lawsuit\0", -"layer\0\0\0", -"lazy\0\0\0\0", -"leader\0\0", -"leaf\0\0\0\0", -"learn\0\0\0", -"leave\0\0\0", -"lecture\0", -"left\0\0\0\0", -"leg\0\0\0\0\0", -"legal\0\0\0", -"legend\0\0", -"leisure\0", -"lemon\0\0\0", -"lend\0\0\0\0", -"length\0\0", -"lens\0\0\0\0", -"leopard\0", -"lesson\0\0", -"letter\0\0", -"level\0\0\0", -"liar\0\0\0\0", -"liberty\0", -"library\0", -"license\0", -"life\0\0\0\0", -"lift\0\0\0\0", -"light\0\0\0", -"like\0\0\0\0", -"limb\0\0\0\0", -"limit\0\0\0", -"link\0\0\0\0", -"lion\0\0\0\0", -"liquid\0\0", -"list\0\0\0\0", -"little\0\0", -"live\0\0\0\0", -"lizard\0\0", -"load\0\0\0\0", -"loan\0\0\0\0", -"lobster\0", -"local\0\0\0", -"lock\0\0\0\0", -"logic\0\0\0", -"lonely\0\0", -"long\0\0\0\0", -"loop\0\0\0\0", -"lottery\0", -"loud\0\0\0\0", -"lounge\0\0", -"love\0\0\0\0", -"loyal\0\0\0", -"lucky\0\0\0", -"luggage\0", -"lumber\0\0", -"lunar\0\0\0", -"lunch\0\0\0", -"luxury\0\0", -"lyrics\0\0", -"machine\0", -"mad\0\0\0\0\0", -"magic\0\0\0", -"magnet\0\0", -"maid\0\0\0\0", -"mail\0\0\0\0", -"main\0\0\0\0", -"major\0\0\0", -"make\0\0\0\0", -"mammal\0\0", -"man\0\0\0\0\0", -"manage\0\0", -"mandate\0", -"mango\0\0\0", -"mansion\0", -"manual\0\0", -"maple\0\0\0", -"marble\0\0", -"march\0\0\0", -"margin\0\0", -"marine\0\0", -"market\0\0", -"marriage", -"mask\0\0\0\0", -"mass\0\0\0\0", -"master\0\0", -"match\0\0\0", -"material", -"math\0\0\0\0", -"matrix\0\0", -"matter\0\0", -"maximum\0", -"maze\0\0\0\0", -"meadow\0\0", -"mean\0\0\0\0", -"measure\0", -"meat\0\0\0\0", -"mechanic", -"medal\0\0\0", -"media\0\0\0", -"melody\0\0", -"melt\0\0\0\0", -"member\0\0", -"memory\0\0", -"mention\0", -"menu\0\0\0\0", -"mercy\0\0\0", -"merge\0\0\0", -"merit\0\0\0", -"merry\0\0\0", -"mesh\0\0\0\0", -"message\0", -"metal\0\0\0", -"method\0\0", -"middle\0\0", -"midnight", -"milk\0\0\0\0", -"million\0", -"mimic\0\0\0", -"mind\0\0\0\0", -"minimum\0", -"minor\0\0\0", -"minute\0\0", -"miracle\0", -"mirror\0\0", -"misery\0\0", -"miss\0\0\0\0", -"mistake\0", -"mix\0\0\0\0\0", -"mixed\0\0\0", -"mixture\0", -"mobile\0\0", -"model\0\0\0", -"modify\0\0", -"mom\0\0\0\0\0", -"moment\0\0", -"monitor\0", -"monkey\0\0", -"monster\0", -"month\0\0\0", -"moon\0\0\0\0", -"moral\0\0\0", -"more\0\0\0\0", -"morning\0", -"mosquito", -"mother\0\0", -"motion\0\0", -"motor\0\0\0", -"mountain", -"mouse\0\0\0", -"move\0\0\0\0", -"movie\0\0\0", -"much\0\0\0\0", -"muffin\0\0", -"mule\0\0\0\0", -"multiply", -"muscle\0\0", -"museum\0\0", -"mushroom", -"music\0\0\0", -"must\0\0\0\0", -"mutual\0\0", -"myself\0\0", -"mystery\0", -"myth\0\0\0\0", -"naive\0\0\0", -"name\0\0\0\0", -"napkin\0\0", -"narrow\0\0", -"nasty\0\0\0", -"nation\0\0", -"nature\0\0", -"near\0\0\0\0", -"neck\0\0\0\0", -"need\0\0\0\0", -"negative", -"neglect\0", -"neither\0", -"nephew\0\0", -"nerve\0\0\0", -"nest\0\0\0\0", -"net\0\0\0\0\0", -"network\0", -"neutral\0", -"never\0\0\0", -"news\0\0\0\0", -"next\0\0\0\0", -"nice\0\0\0\0", -"night\0\0\0", -"noble\0\0\0", -"noise\0\0\0", -"nominee\0", -"noodle\0\0", -"normal\0\0", -"north\0\0\0", -"nose\0\0\0\0", -"notable\0", -"note\0\0\0\0", -"nothing\0", -"notice\0\0", -"novel\0\0\0", -"now\0\0\0\0\0", -"nuclear\0", -"number\0\0", -"nurse\0\0\0", -"nut\0\0\0\0\0", -"oak\0\0\0\0\0", -"obey\0\0\0\0", -"object\0\0", -"oblige\0\0", -"obscure\0", -"observe\0", -"obtain\0\0", -"obvious\0", -"occur\0\0\0", -"ocean\0\0\0", -"october\0", -"odor\0\0\0\0", -"off\0\0\0\0\0", -"offer\0\0\0", -"office\0\0", -"often\0\0\0", -"oil\0\0\0\0\0", -"okay\0\0\0\0", -"old\0\0\0\0\0", -"olive\0\0\0", -"olympic\0", -"omit\0\0\0\0", -"once\0\0\0\0", -"one\0\0\0\0\0", -"onion\0\0\0", -"online\0\0", -"only\0\0\0\0", -"open\0\0\0\0", -"opera\0\0\0", -"opinion\0", -"oppose\0\0", -"option\0\0", -"orange\0\0", -"orbit\0\0\0", -"orchard\0", -"order\0\0\0", -"ordinary", -"organ\0\0\0", -"orient\0\0", -"original", -"orphan\0\0", -"ostrich\0", -"other\0\0\0", -"outdoor\0", -"outer\0\0\0", -"output\0\0", -"outside\0", -"oval\0\0\0\0", -"oven\0\0\0\0", -"over\0\0\0\0", -"own\0\0\0\0\0", -"owner\0\0\0", -"oxygen\0\0", -"oyster\0\0", -"ozone\0\0\0", -"pact\0\0\0\0", -"paddle\0\0", -"page\0\0\0\0", -"pair\0\0\0\0", -"palace\0\0", -"palm\0\0\0\0", -"panda\0\0\0", -"panel\0\0\0", -"panic\0\0\0", -"panther\0", -"paper\0\0\0", -"parade\0\0", -"parent\0\0", -"park\0\0\0\0", -"parrot\0\0", -"party\0\0\0", -"pass\0\0\0\0", -"patch\0\0\0", -"path\0\0\0\0", -"patient\0", -"patrol\0\0", -"pattern\0", -"pause\0\0\0", -"pave\0\0\0\0", -"payment\0", -"peace\0\0\0", -"peanut\0\0", -"pear\0\0\0\0", -"peasant\0", -"pelican\0", -"pen\0\0\0\0\0", -"penalty\0", -"pencil\0\0", -"people\0\0", -"pepper\0\0", -"perfect\0", -"permit\0\0", -"person\0\0", -"pet\0\0\0\0\0", -"phone\0\0\0", -"photo\0\0\0", -"phrase\0\0", -"physical", -"piano\0\0\0", -"picnic\0\0", -"picture\0", -"piece\0\0\0", -"pig\0\0\0\0\0", -"pigeon\0\0", -"pill\0\0\0\0", -"pilot\0\0\0", -"pink\0\0\0\0", -"pioneer\0", -"pipe\0\0\0\0", -"pistol\0\0", -"pitch\0\0\0", -"pizza\0\0\0", -"place\0\0\0", -"planet\0\0", -"plastic\0", -"plate\0\0\0", -"play\0\0\0\0", -"please\0\0", -"pledge\0\0", -"pluck\0\0\0", -"plug\0\0\0\0", -"plunge\0\0", -"poem\0\0\0\0", -"poet\0\0\0\0", -"point\0\0\0", -"polar\0\0\0", -"pole\0\0\0\0", -"police\0\0", -"pond\0\0\0\0", -"pony\0\0\0\0", -"pool\0\0\0\0", -"popular\0", -"portion\0", -"position", -"possible", -"post\0\0\0\0", -"potato\0\0", -"pottery\0", -"poverty\0", -"powder\0\0", -"power\0\0\0", -"practice", -"praise\0\0", -"predict\0", -"prefer\0\0", -"prepare\0", -"present\0", -"pretty\0\0", -"prevent\0", -"price\0\0\0", -"pride\0\0\0", -"primary\0", -"print\0\0\0", -"priority", -"prison\0\0", -"private\0", -"prize\0\0\0", -"problem\0", -"process\0", -"produce\0", -"profit\0\0", -"program\0", -"project\0", -"promote\0", -"proof\0\0\0", -"property", -"prosper\0", -"protect\0", -"proud\0\0\0", -"provide\0", -"public\0\0", -"pudding\0", -"pull\0\0\0\0", -"pulp\0\0\0\0", -"pulse\0\0\0", -"pumpkin\0", -"punch\0\0\0", -"pupil\0\0\0", -"puppy\0\0\0", -"purchase", -"purity\0\0", -"purpose\0", -"purse\0\0\0", -"push\0\0\0\0", -"put\0\0\0\0\0", -"puzzle\0\0", -"pyramid\0", -"quality\0", -"quantum\0", -"quarter\0", -"question", -"quick\0\0\0", -"quit\0\0\0\0", -"quiz\0\0\0\0", -"quote\0\0\0", -"rabbit\0\0", -"raccoon\0", -"race\0\0\0\0", -"rack\0\0\0\0", -"radar\0\0\0", -"radio\0\0\0", -"rail\0\0\0\0", -"rain\0\0\0\0", -"raise\0\0\0", -"rally\0\0\0", -"ramp\0\0\0\0", -"ranch\0\0\0", -"random\0\0", -"range\0\0\0", -"rapid\0\0\0", -"rare\0\0\0\0", -"rate\0\0\0\0", -"rather\0\0", -"raven\0\0\0", -"raw\0\0\0\0\0", -"razor\0\0\0", -"ready\0\0\0", -"real\0\0\0\0", -"reason\0\0", -"rebel\0\0\0", -"rebuild\0", -"recall\0\0", -"receive\0", -"recipe\0\0", -"record\0\0", -"recycle\0", -"reduce\0\0", -"reflect\0", -"reform\0\0", -"refuse\0\0", -"region\0\0", -"regret\0\0", -"regular\0", -"reject\0\0", -"relax\0\0\0", -"release\0", -"relief\0\0", -"rely\0\0\0\0", -"remain\0\0", -"remember", -"remind\0\0", -"remove\0\0", -"render\0\0", -"renew\0\0\0", -"rent\0\0\0\0", -"reopen\0\0", -"repair\0\0", -"repeat\0\0", -"replace\0", -"report\0\0", -"require\0", -"rescue\0\0", -"resemble", -"resist\0\0", -"resource", -"response", -"result\0\0", -"retire\0\0", -"retreat\0", -"return\0\0", -"reunion\0", -"reveal\0\0", -"review\0\0", -"reward\0\0", -"rhythm\0\0", -"rib\0\0\0\0\0", -"ribbon\0\0", -"rice\0\0\0\0", -"rich\0\0\0\0", -"ride\0\0\0\0", -"ridge\0\0\0", -"rifle\0\0\0", -"right\0\0\0", -"rigid\0\0\0", -"ring\0\0\0\0", -"riot\0\0\0\0", -"ripple\0\0", -"risk\0\0\0\0", -"ritual\0\0", -"rival\0\0\0", -"river\0\0\0", -"road\0\0\0\0", -"roast\0\0\0", -"robot\0\0\0", -"robust\0\0", -"rocket\0\0", -"romance\0", -"roof\0\0\0\0", -"rookie\0\0", -"room\0\0\0\0", -"rose\0\0\0\0", -"rotate\0\0", -"rough\0\0\0", -"round\0\0\0", -"route\0\0\0", -"royal\0\0\0", -"rubber\0\0", -"rude\0\0\0\0", -"rug\0\0\0\0\0", -"rule\0\0\0\0", -"run\0\0\0\0\0", -"runway\0\0", -"rural\0\0\0", -"sad\0\0\0\0\0", -"saddle\0\0", -"sadness\0", -"safe\0\0\0\0", -"sail\0\0\0\0", -"salad\0\0\0", -"salmon\0\0", -"salon\0\0\0", -"salt\0\0\0\0", -"salute\0\0", -"same\0\0\0\0", -"sample\0\0", -"sand\0\0\0\0", -"satisfy\0", -"satoshi\0", -"sauce\0\0\0", -"sausage\0", -"save\0\0\0\0", -"say\0\0\0\0\0", -"scale\0\0\0", -"scan\0\0\0\0", -"scare\0\0\0", -"scatter\0", -"scene\0\0\0", -"scheme\0\0", -"school\0\0", -"science\0", -"scissors", -"scorpion", -"scout\0\0\0", -"scrap\0\0\0", -"screen\0\0", -"script\0\0", -"scrub\0\0\0", -"sea\0\0\0\0\0", -"search\0\0", -"season\0\0", -"seat\0\0\0\0", -"second\0\0", -"secret\0\0", -"section\0", -"security", -"seed\0\0\0\0", -"seek\0\0\0\0", -"segment\0", -"select\0\0", -"sell\0\0\0\0", -"seminar\0", -"senior\0\0", -"sense\0\0\0", -"sentence", -"series\0\0", -"service\0", -"session\0", -"settle\0\0", -"setup\0\0\0", -"seven\0\0\0", -"shadow\0\0", -"shaft\0\0\0", -"shallow\0", -"share\0\0\0", -"shed\0\0\0\0", -"shell\0\0\0", -"sheriff\0", -"shield\0\0", -"shift\0\0\0", -"shine\0\0\0", -"ship\0\0\0\0", -"shiver\0\0", -"shock\0\0\0", -"shoe\0\0\0\0", -"shoot\0\0\0", -"shop\0\0\0\0", -"short\0\0\0", -"shoulder", -"shove\0\0\0", -"shrimp\0\0", -"shrug\0\0\0", -"shuffle\0", -"shy\0\0\0\0\0", -"sibling\0", -"sick\0\0\0\0", -"side\0\0\0\0", -"siege\0\0\0", -"sight\0\0\0", -"sign\0\0\0\0", -"silent\0\0", -"silk\0\0\0\0", -"silly\0\0\0", -"silver\0\0", -"similar\0", -"simple\0\0", -"since\0\0\0", -"sing\0\0\0\0", -"siren\0\0\0", -"sister\0\0", -"situate\0", -"six\0\0\0\0\0", -"size\0\0\0\0", -"skate\0\0\0", -"sketch\0\0", -"ski\0\0\0\0\0", -"skill\0\0\0", -"skin\0\0\0\0", -"skirt\0\0\0", -"skull\0\0\0", -"slab\0\0\0\0", -"slam\0\0\0\0", -"sleep\0\0\0", -"slender\0", -"slice\0\0\0", -"slide\0\0\0", -"slight\0\0", -"slim\0\0\0\0", -"slogan\0\0", -"slot\0\0\0\0", -"slow\0\0\0\0", -"slush\0\0\0", -"small\0\0\0", -"smart\0\0\0", -"smile\0\0\0", -"smoke\0\0\0", -"smooth\0\0", -"snack\0\0\0", -"snake\0\0\0", -"snap\0\0\0\0", -"sniff\0\0\0", -"snow\0\0\0\0", -"soap\0\0\0\0", -"soccer\0\0", -"social\0\0", -"sock\0\0\0\0", -"soda\0\0\0\0", -"soft\0\0\0\0", -"solar\0\0\0", -"soldier\0", -"solid\0\0\0", -"solution", -"solve\0\0\0", -"someone\0", -"song\0\0\0\0", -"soon\0\0\0\0", -"sorry\0\0\0", -"sort\0\0\0\0", -"soul\0\0\0\0", -"sound\0\0\0", -"soup\0\0\0\0", -"source\0\0", -"south\0\0\0", -"space\0\0\0", -"spare\0\0\0", -"spatial\0", -"spawn\0\0\0", -"speak\0\0\0", -"special\0", -"speed\0\0\0", -"spell\0\0\0", -"spend\0\0\0", -"sphere\0\0", -"spice\0\0\0", -"spider\0\0", -"spike\0\0\0", -"spin\0\0\0\0", -"spirit\0\0", -"split\0\0\0", -"spoil\0\0\0", -"sponsor\0", -"spoon\0\0\0", -"sport\0\0\0", -"spot\0\0\0\0", -"spray\0\0\0", -"spread\0\0", -"spring\0\0", -"spy\0\0\0\0\0", -"square\0\0", -"squeeze\0", -"squirrel", -"stable\0\0", -"stadium\0", -"staff\0\0\0", -"stage\0\0\0", -"stairs\0\0", -"stamp\0\0\0", -"stand\0\0\0", -"start\0\0\0", -"state\0\0\0", -"stay\0\0\0\0", -"steak\0\0\0", -"steel\0\0\0", -"stem\0\0\0\0", -"step\0\0\0\0", -"stereo\0\0", -"stick\0\0\0", -"still\0\0\0", -"sting\0\0\0", -"stock\0\0\0", -"stomach\0", -"stone\0\0\0", -"stool\0\0\0", -"story\0\0\0", -"stove\0\0\0", -"strategy", -"street\0\0", -"strike\0\0", -"strong\0\0", -"struggle", -"student\0", -"stuff\0\0\0", -"stumble\0", -"style\0\0\0", -"subject\0", -"submit\0\0", -"subway\0\0", -"success\0", -"such\0\0\0\0", -"sudden\0\0", -"suffer\0\0", -"sugar\0\0\0", -"suggest\0", -"suit\0\0\0\0", -"summer\0\0", -"sun\0\0\0\0\0", -"sunny\0\0\0", -"sunset\0\0", -"super\0\0\0", -"supply\0\0", -"supreme\0", -"sure\0\0\0\0", -"surface\0", -"surge\0\0\0", -"surprise", -"surround", -"survey\0\0", -"suspect\0", -"sustain\0", -"swallow\0", -"swamp\0\0\0", -"swap\0\0\0\0", -"swarm\0\0\0", -"swear\0\0\0", -"sweet\0\0\0", -"swift\0\0\0", -"swim\0\0\0\0", -"swing\0\0\0", -"switch\0\0", -"sword\0\0\0", -"symbol\0\0", -"symptom\0", -"syrup\0\0\0", -"system\0\0", -"table\0\0\0", -"tackle\0\0", -"tag\0\0\0\0\0", -"tail\0\0\0\0", -"talent\0\0", -"talk\0\0\0\0", -"tank\0\0\0\0", -"tape\0\0\0\0", -"target\0\0", -"task\0\0\0\0", -"taste\0\0\0", -"tattoo\0\0", -"taxi\0\0\0\0", -"teach\0\0\0", -"team\0\0\0\0", -"tell\0\0\0\0", -"ten\0\0\0\0\0", -"tenant\0\0", -"tennis\0\0", -"tent\0\0\0\0", -"term\0\0\0\0", -"test\0\0\0\0", -"text\0\0\0\0", -"thank\0\0\0", -"that\0\0\0\0", -"theme\0\0\0", -"then\0\0\0\0", -"theory\0\0", -"there\0\0\0", -"they\0\0\0\0", -"thing\0\0\0", -"this\0\0\0\0", -"thought\0", -"three\0\0\0", -"thrive\0\0", -"throw\0\0\0", -"thumb\0\0\0", -"thunder\0", -"ticket\0\0", -"tide\0\0\0\0", -"tiger\0\0\0", -"tilt\0\0\0\0", -"timber\0\0", -"time\0\0\0\0", -"tiny\0\0\0\0", -"tip\0\0\0\0\0", -"tired\0\0\0", -"tissue\0\0", -"title\0\0\0", -"toast\0\0\0", -"tobacco\0", -"today\0\0\0", -"toddler\0", -"toe\0\0\0\0\0", -"together", -"toilet\0\0", -"token\0\0\0", -"tomato\0\0", -"tomorrow", -"tone\0\0\0\0", -"tongue\0\0", -"tonight\0", -"tool\0\0\0\0", -"tooth\0\0\0", -"top\0\0\0\0\0", -"topic\0\0\0", -"topple\0\0", -"torch\0\0\0", -"tornado\0", -"tortoise", -"toss\0\0\0\0", -"total\0\0\0", -"tourist\0", -"toward\0\0", -"tower\0\0\0", -"town\0\0\0\0", -"toy\0\0\0\0\0", -"track\0\0\0", -"trade\0\0\0", -"traffic\0", -"tragic\0\0", -"train\0\0\0", -"transfer", -"trap\0\0\0\0", -"trash\0\0\0", -"travel\0\0", -"tray\0\0\0\0", -"treat\0\0\0", -"tree\0\0\0\0", -"trend\0\0\0", -"trial\0\0\0", -"tribe\0\0\0", -"trick\0\0\0", -"trigger\0", -"trim\0\0\0\0", -"trip\0\0\0\0", -"trophy\0\0", -"trouble\0", -"truck\0\0\0", -"true\0\0\0\0", -"truly\0\0\0", -"trumpet\0", -"trust\0\0\0", -"truth\0\0\0", -"try\0\0\0\0\0", -"tube\0\0\0\0", -"tuition\0", -"tumble\0\0", -"tuna\0\0\0\0", -"tunnel\0\0", -"turkey\0\0", -"turn\0\0\0\0", -"turtle\0\0", -"twelve\0\0", -"twenty\0\0", -"twice\0\0\0", -"twin\0\0\0\0", -"twist\0\0\0", -"two\0\0\0\0\0", -"type\0\0\0\0", -"typical\0", -"ugly\0\0\0\0", -"umbrella", -"unable\0\0", -"unaware\0", -"uncle\0\0\0", -"uncover\0", -"under\0\0\0", -"undo\0\0\0\0", -"unfair\0\0", -"unfold\0\0", -"unhappy\0", -"uniform\0", -"unique\0\0", -"unit\0\0\0\0", -"universe", -"unknown\0", -"unlock\0\0", -"until\0\0\0", -"unusual\0", -"unveil\0\0", -"update\0\0", -"upgrade\0", -"uphold\0\0", -"upon\0\0\0\0", -"upper\0\0\0", -"upset\0\0\0", -"urban\0\0\0", -"urge\0\0\0\0", -"usage\0\0\0", -"use\0\0\0\0\0", -"used\0\0\0\0", -"useful\0\0", -"useless\0", -"usual\0\0\0", -"utility\0", -"vacant\0\0", -"vacuum\0\0", -"vague\0\0\0", -"valid\0\0\0", -"valley\0\0", -"valve\0\0\0", -"van\0\0\0\0\0", -"vanish\0\0", -"vapor\0\0\0", -"various\0", -"vast\0\0\0\0", -"vault\0\0\0", -"vehicle\0", -"velvet\0\0", -"vendor\0\0", -"venture\0", -"venue\0\0\0", -"verb\0\0\0\0", -"verify\0\0", -"version\0", -"very\0\0\0\0", -"vessel\0\0", -"veteran\0", -"viable\0\0", -"vibrant\0", -"vicious\0", -"victory\0", -"video\0\0\0", -"view\0\0\0\0", -"village\0", -"vintage\0", -"violin\0\0", -"virtual\0", -"virus\0\0\0", -"visa\0\0\0\0", -"visit\0\0\0", -"visual\0\0", -"vital\0\0\0", -"vivid\0\0\0", -"vocal\0\0\0", -"voice\0\0\0", -"void\0\0\0\0", -"volcano\0", -"volume\0\0", -"vote\0\0\0\0", -"voyage\0\0", -"wage\0\0\0\0", -"wagon\0\0\0", -"wait\0\0\0\0", -"walk\0\0\0\0", -"wall\0\0\0\0", -"walnut\0\0", -"want\0\0\0\0", -"warfare\0", -"warm\0\0\0\0", -"warrior\0", -"wash\0\0\0\0", -"wasp\0\0\0\0", -"waste\0\0\0", -"water\0\0\0", -"wave\0\0\0\0", -"way\0\0\0\0\0", -"wealth\0\0", -"weapon\0\0", -"wear\0\0\0\0", -"weasel\0\0", -"weather\0", -"web\0\0\0\0\0", -"wedding\0", -"weekend\0", -"weird\0\0\0", -"welcome\0", -"west\0\0\0\0", -"wet\0\0\0\0\0", -"whale\0\0\0", -"what\0\0\0\0", -"wheat\0\0\0", -"wheel\0\0\0", -"when\0\0\0\0", -"where\0\0\0", -"whip\0\0\0\0", -"whisper\0", -"wide\0\0\0\0", -"width\0\0\0", -"wife\0\0\0\0", -"wild\0\0\0\0", -"will\0\0\0\0", -"win\0\0\0\0\0", -"window\0\0", -"wine\0\0\0\0", -"wing\0\0\0\0", -"wink\0\0\0\0", -"winner\0\0", -"winter\0\0", -"wire\0\0\0\0", -"wisdom\0\0", -"wise\0\0\0\0", -"wish\0\0\0\0", -"witness\0", -"wolf\0\0\0\0", -"woman\0\0\0", -"wonder\0\0", -"wood\0\0\0\0", -"wool\0\0\0\0", -"word\0\0\0\0", -"work\0\0\0\0", -"world\0\0\0", -"worry\0\0\0", -"worth\0\0\0", -"wrap\0\0\0\0", -"wreck\0\0\0", -"wrestle\0", -"wrist\0\0\0", -"write\0\0\0", -"wrong\0\0\0", -"yard\0\0\0\0", -"year\0\0\0\0", -"yellow\0\0", -"you\0\0\0\0\0", -"young\0\0\0", -"youth\0\0\0", -"zebra\0\0\0", -"zero\0\0\0\0", -"zone\0\0\0\0", -"zoo\0\0\0\0\0", -#endif -0, -}; diff --git a/deps/crypto/trezor-crypto/bip39_english.h b/deps/crypto/trezor-crypto/bip39_english.h deleted file mode 100644 index 69dc38f59..000000000 --- a/deps/crypto/trezor-crypto/bip39_english.h +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright (c) 2013-2014 Tomas Dzetkulic - * Copyright (c) 2013-2014 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -extern const char * const wordlist[2048 + 1]; diff --git a/deps/crypto/trezor-crypto/blake256.c b/deps/crypto/trezor-crypto/blake256.c deleted file mode 100644 index a7cb843c1..000000000 --- a/deps/crypto/trezor-crypto/blake256.c +++ /dev/null @@ -1,234 +0,0 @@ -/* - BLAKE reference C implementation - - Copyright (c) 2012 Jean-Philippe Aumasson - - To the extent possible under law, the author(s) have dedicated all copyright - and related and neighboring rights to this software to the public domain - worldwide. This software is distributed without any warranty. - - You should have received a copy of the CC0 Public Domain Dedication along with - this software. If not, see . - */ -#include "blake256.h" - -#include - -#define U8TO32_BIG(p) \ - (((uint32_t)((p)[0]) << 24) | ((uint32_t)((p)[1]) << 16) | \ - ((uint32_t)((p)[2]) << 8) | ((uint32_t)((p)[3]) )) - -#define U32TO8_BIG(p, v) \ - (p)[0] = (uint8_t)((v) >> 24); (p)[1] = (uint8_t)((v) >> 16); \ - (p)[2] = (uint8_t)((v) >> 8); (p)[3] = (uint8_t)((v) ); - -static const uint8_t sigma[][16] = -{ - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, - {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, - {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, - { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, - { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, - { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 }, - {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 }, - {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 }, - { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 }, - {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 }, - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, - {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, - {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, - { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, - { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, - { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } -}; - -static const uint32_t u256[16] = -{ - 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, - 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, - 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, - 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917 -}; - -static const uint8_t padding[129] = -{ - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -static void blake256_compress( BLAKE256_CTX *S, const uint8_t *block ) -{ - uint32_t v[16] = {0}, m[16] = {0}, i = 0; -#define ROT(x,n) (((x)<<(32-n))|( (x)>>(n))) -#define G(a,b,c,d,e) \ - v[a] += (m[sigma[i][e]] ^ u256[sigma[i][e+1]]) + v[b]; \ - v[d] = ROT( v[d] ^ v[a],16); \ - v[c] += v[d]; \ - v[b] = ROT( v[b] ^ v[c],12); \ - v[a] += (m[sigma[i][e+1]] ^ u256[sigma[i][e]])+v[b]; \ - v[d] = ROT( v[d] ^ v[a], 8); \ - v[c] += v[d]; \ - v[b] = ROT( v[b] ^ v[c], 7); - - for( i = 0; i < 16; ++i ) m[i] = U8TO32_BIG( block + i * 4 ); - - for( i = 0; i < 8; ++i ) v[i] = S->h[i]; - - v[ 8] = S->s[0] ^ u256[0]; - v[ 9] = S->s[1] ^ u256[1]; - v[10] = S->s[2] ^ u256[2]; - v[11] = S->s[3] ^ u256[3]; - v[12] = u256[4]; - v[13] = u256[5]; - v[14] = u256[6]; - v[15] = u256[7]; - - /* don't xor t when the block is only padding */ - if ( !S->nullt ) - { - v[12] ^= S->t[0]; - v[13] ^= S->t[0]; - v[14] ^= S->t[1]; - v[15] ^= S->t[1]; - } - - for( i = 0; i < 14; ++i ) - { - /* column step */ - G( 0, 4, 8, 12, 0 ); - G( 1, 5, 9, 13, 2 ); - G( 2, 6, 10, 14, 4 ); - G( 3, 7, 11, 15, 6 ); - /* diagonal step */ - G( 0, 5, 10, 15, 8 ); - G( 1, 6, 11, 12, 10 ); - G( 2, 7, 8, 13, 12 ); - G( 3, 4, 9, 14, 14 ); - } - - for( i = 0; i < 16; ++i ) S->h[i % 8] ^= v[i]; - - for( i = 0; i < 8 ; ++i ) S->h[i] ^= S->s[i % 4]; -} - - -void blake256_Init( BLAKE256_CTX *S ) -{ - S->h[0] = 0x6a09e667; - S->h[1] = 0xbb67ae85; - S->h[2] = 0x3c6ef372; - S->h[3] = 0xa54ff53a; - S->h[4] = 0x510e527f; - S->h[5] = 0x9b05688c; - S->h[6] = 0x1f83d9ab; - S->h[7] = 0x5be0cd19; - S->t[0] = S->t[1] = S->buflen = S->nullt = 0; - S->s[0] = S->s[1] = S->s[2] = S->s[3] = 0; -} - - -void blake256_Update( BLAKE256_CTX *S, const uint8_t *in, size_t inlen ) -{ - size_t left = S->buflen; - size_t fill = 64 - left; - - /* data left and data received fill a block */ - if( left && ( inlen >= fill ) ) - { - memcpy( ( void * ) ( S->buf + left ), ( void * ) in, fill ); - S->t[0] += 512; - - if ( S->t[0] == 0 ) S->t[1]++; - - blake256_compress( S, S->buf ); - in += fill; - inlen -= fill; - left = 0; - } - - /* compress blocks of data received */ - while( inlen >= 64 ) - { - S->t[0] += 512; - - if ( S->t[0] == 0 ) S->t[1]++; - - blake256_compress( S, in ); - in += 64; - inlen -= 64; - } - - /* store any data left */ - if( inlen > 0 ) - { - memcpy( ( void * ) ( S->buf + left ), \ - ( void * ) in, ( size_t ) inlen ); - } - S->buflen = left + inlen; -} - - -void blake256_Final( BLAKE256_CTX *S, uint8_t *out ) -{ - uint8_t msglen[8] = {0}, zo = 0x01, oo = 0x81; - uint32_t lo = S->t[0] + ( S->buflen << 3 ), hi = S->t[1]; - - /* support for hashing more than 2^32 bits */ - if ( lo < ( S->buflen << 3 ) ) hi++; - - U32TO8_BIG( msglen + 0, hi ); - U32TO8_BIG( msglen + 4, lo ); - - if ( S->buflen == 55 ) /* one padding byte */ - { - S->t[0] -= 8; - blake256_Update( S, &oo, 1 ); - } - else - { - if ( S->buflen < 55 ) /* enough space to fill the block */ - { - if ( !S->buflen ) S->nullt = 1; - - S->t[0] -= 440 - ( S->buflen << 3 ); - blake256_Update( S, padding, 55 - S->buflen ); - } - else /* need 2 compressions */ - { - S->t[0] -= 512 - ( S->buflen << 3 ); - blake256_Update( S, padding, 64 - S->buflen ); - S->t[0] -= 440; - blake256_Update( S, padding + 1, 55 ); - S->nullt = 1; - } - - blake256_Update( S, &zo, 1 ); - S->t[0] -= 8; - } - - S->t[0] -= 64; - blake256_Update( S, msglen, 8 ); - U32TO8_BIG( out + 0, S->h[0] ); - U32TO8_BIG( out + 4, S->h[1] ); - U32TO8_BIG( out + 8, S->h[2] ); - U32TO8_BIG( out + 12, S->h[3] ); - U32TO8_BIG( out + 16, S->h[4] ); - U32TO8_BIG( out + 20, S->h[5] ); - U32TO8_BIG( out + 24, S->h[6] ); - U32TO8_BIG( out + 28, S->h[7] ); -} - - -void blake256( const uint8_t *in, size_t inlen, uint8_t *out ) -{ - BLAKE256_CTX S = {0}; - blake256_Init( &S ); - blake256_Update( &S, in, inlen ); - blake256_Final( &S, out ); -} diff --git a/deps/crypto/trezor-crypto/blake256.h b/deps/crypto/trezor-crypto/blake256.h deleted file mode 100644 index 2c68ae2ef..000000000 --- a/deps/crypto/trezor-crypto/blake256.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2014-2017, The Monero Project -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are -// permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of -// conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list -// of conditions and the following disclaimer in the documentation and/or other -// materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be -// used to endorse or promote products derived from this software without specific -// prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers - -#ifndef __BLAKE256_H__ -#define __BLAKE256_H__ - -#include -#include - -#define BLAKE256_DIGEST_LENGTH 32 -#define BLAKE256_BLOCK_LENGTH 64 - -typedef struct { - uint32_t h[8], s[4], t[2]; - size_t buflen; - uint8_t nullt; - uint8_t buf[64]; -} BLAKE256_CTX; - -void blake256_Init(BLAKE256_CTX *); -void blake256_Update(BLAKE256_CTX *, const uint8_t *, size_t); -void blake256_Final(BLAKE256_CTX *, uint8_t *); - -void blake256(const uint8_t *, size_t, uint8_t *); - -#endif /* __BLAKE256_H__ */ diff --git a/deps/crypto/trezor-crypto/blake2_common.h b/deps/crypto/trezor-crypto/blake2_common.h deleted file mode 100644 index 0a7a3ad91..000000000 --- a/deps/crypto/trezor-crypto/blake2_common.h +++ /dev/null @@ -1,25 +0,0 @@ -static inline uint32_t load32(const void *src) { - uint32_t w; - memcpy(&w, src, sizeof w); - return w; -} - -static inline uint64_t load64(const void *src) { - uint64_t w; - memcpy(&w, src, sizeof w); - return w; -} - -static inline void store16(void *dst, uint16_t w) { memcpy(dst, &w, sizeof w); } - -static inline void store32(void *dst, uint32_t w) { memcpy(dst, &w, sizeof w); } - -static inline void store64(void *dst, uint64_t w) { memcpy(dst, &w, sizeof w); } - -static inline uint32_t rotr32(const uint32_t w, const unsigned c) { - return (w >> c) | (w << (32 - c)); -} - -static inline uint64_t rotr64(const uint64_t w, const unsigned c) { - return (w >> c) | (w << (64 - c)); -} diff --git a/deps/crypto/trezor-crypto/blake2b.c b/deps/crypto/trezor-crypto/blake2b.c deleted file mode 100644 index f0832c359..000000000 --- a/deps/crypto/trezor-crypto/blake2b.c +++ /dev/null @@ -1,324 +0,0 @@ -/* - BLAKE2 reference source code package - reference C implementations - - Copyright 2012, Samuel Neves . You may use this under the - terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at - your option. The terms of these licenses can be found at: - - - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 - - OpenSSL license : https://www.openssl.org/source/license.html - - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 - - More information about the BLAKE2 hash function can be found at - https://blake2.net. -*/ - -#include - -#include "blake2b.h" -#include "blake2_common.h" -#include "memzero.h" - -typedef struct blake2b_param__ -{ - uint8_t digest_length; /* 1 */ - uint8_t key_length; /* 2 */ - uint8_t fanout; /* 3 */ - uint8_t depth; /* 4 */ - uint32_t leaf_length; /* 8 */ - uint32_t node_offset; /* 12 */ - uint32_t xof_length; /* 16 */ - uint8_t node_depth; /* 17 */ - uint8_t inner_length; /* 18 */ - uint8_t reserved[14]; /* 32 */ - uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */ - uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */ -} __attribute__((packed)) blake2b_param; - -static const uint64_t blake2b_IV[8] = -{ - 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, - 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, - 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, - 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL -}; - -static const uint8_t blake2b_sigma[12][16] = -{ - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , - { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , - { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , - { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , - { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , - { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , - { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , - { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , - { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , - { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , - { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } -}; - - -static void blake2b_set_lastnode( blake2b_state *S ) -{ - S->f[1] = (uint64_t)-1; -} - -/* Some helper functions, not necessarily useful */ -static int blake2b_is_lastblock( const blake2b_state *S ) -{ - return S->f[0] != 0; -} - -static void blake2b_set_lastblock( blake2b_state *S ) -{ - if( S->last_node ) blake2b_set_lastnode( S ); - - S->f[0] = (uint64_t)-1; -} - -static void blake2b_increment_counter( blake2b_state *S, const uint64_t inc ) -{ - S->t[0] += inc; - S->t[1] += ( S->t[0] < inc ); -} - -static void blake2b_init0( blake2b_state *S ) -{ - size_t i = 0; - memzero( S, sizeof( blake2b_state ) ); - - for( i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i]; -} - -/* init xors IV with input parameter block */ -int blake2b_init_param( blake2b_state *S, const blake2b_param *P ) -{ - const uint8_t *p = ( const uint8_t * )( P ); - size_t i = 0; - - blake2b_init0( S ); - - /* IV XOR ParamBlock */ - for( i = 0; i < 8; ++i ) - S->h[i] ^= load64( p + sizeof( S->h[i] ) * i ); - - S->outlen = P->digest_length; - return 0; -} - - -/* Sequential blake2b initialization */ -int blake2b_Init( blake2b_state *S, size_t outlen ) -{ - blake2b_param P[1] = {0}; - - if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1; - - P->digest_length = (uint8_t)outlen; - P->key_length = 0; - P->fanout = 1; - P->depth = 1; - store32( &P->leaf_length, 0 ); - store32( &P->node_offset, 0 ); - store32( &P->xof_length, 0 ); - P->node_depth = 0; - P->inner_length = 0; - memzero( P->reserved, sizeof( P->reserved ) ); - memzero( P->salt, sizeof( P->salt ) ); - memzero( P->personal, sizeof( P->personal ) ); - return blake2b_init_param( S, P ); -} - -int blake2b_InitPersonal( blake2b_state *S, size_t outlen, const void *personal, size_t personal_len) -{ - blake2b_param P[1] = {0}; - - if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1; - if ( ( !personal ) || ( personal_len != BLAKE2B_PERSONALBYTES ) ) return -1; - - P->digest_length = (uint8_t)outlen; - P->key_length = 0; - P->fanout = 1; - P->depth = 1; - store32( &P->leaf_length, 0 ); - store32( &P->node_offset, 0 ); - store32( &P->xof_length, 0 ); - P->node_depth = 0; - P->inner_length = 0; - memzero( P->reserved, sizeof( P->reserved ) ); - memzero( P->salt, sizeof( P->salt ) ); - memcpy( P->personal, personal, BLAKE2B_PERSONALBYTES ); - return blake2b_init_param( S, P ); -} - -int blake2b_InitKey( blake2b_state *S, size_t outlen, const void *key, size_t keylen ) -{ - blake2b_param P[1] = {0}; - - if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1; - - if ( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1; - - P->digest_length = (uint8_t)outlen; - P->key_length = (uint8_t)keylen; - P->fanout = 1; - P->depth = 1; - store32( &P->leaf_length, 0 ); - store32( &P->node_offset, 0 ); - store32( &P->xof_length, 0 ); - P->node_depth = 0; - P->inner_length = 0; - memzero( P->reserved, sizeof( P->reserved ) ); - memzero( P->salt, sizeof( P->salt ) ); - memzero( P->personal, sizeof( P->personal ) ); - - if( blake2b_init_param( S, P ) < 0 ) return -1; - - { - uint8_t block[BLAKE2B_BLOCKBYTES] = {0}; - memzero( block, BLAKE2B_BLOCKBYTES ); - memcpy( block, key, keylen ); - blake2b_Update( S, block, BLAKE2B_BLOCKBYTES ); - memzero( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */ - } - return 0; -} - -#define G(r,i,a,b,c,d) \ - do { \ - a = a + b + m[blake2b_sigma[r][2*i+0]]; \ - d = rotr64(d ^ a, 32); \ - c = c + d; \ - b = rotr64(b ^ c, 24); \ - a = a + b + m[blake2b_sigma[r][2*i+1]]; \ - d = rotr64(d ^ a, 16); \ - c = c + d; \ - b = rotr64(b ^ c, 63); \ - } while(0) - -#define ROUND(r) \ - do { \ - G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ - G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ - G(r,2,v[ 2],v[ 6],v[10],v[14]); \ - G(r,3,v[ 3],v[ 7],v[11],v[15]); \ - G(r,4,v[ 0],v[ 5],v[10],v[15]); \ - G(r,5,v[ 1],v[ 6],v[11],v[12]); \ - G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ - G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \ - } while(0) - -static void blake2b_compress( blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES] ) -{ - uint64_t m[16] = {0}; - uint64_t v[16] = {0}; - size_t i = 0; - - for( i = 0; i < 16; ++i ) { - m[i] = load64( block + i * sizeof( m[i] ) ); - } - - for( i = 0; i < 8; ++i ) { - v[i] = S->h[i]; - } - - v[ 8] = blake2b_IV[0]; - v[ 9] = blake2b_IV[1]; - v[10] = blake2b_IV[2]; - v[11] = blake2b_IV[3]; - v[12] = blake2b_IV[4] ^ S->t[0]; - v[13] = blake2b_IV[5] ^ S->t[1]; - v[14] = blake2b_IV[6] ^ S->f[0]; - v[15] = blake2b_IV[7] ^ S->f[1]; - - ROUND( 0 ); - ROUND( 1 ); - ROUND( 2 ); - ROUND( 3 ); - ROUND( 4 ); - ROUND( 5 ); - ROUND( 6 ); - ROUND( 7 ); - ROUND( 8 ); - ROUND( 9 ); - ROUND( 10 ); - ROUND( 11 ); - - for( i = 0; i < 8; ++i ) { - S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; - } -} - -#undef G -#undef ROUND - -int blake2b_Update( blake2b_state *S, const void *pin, size_t inlen ) -{ - const unsigned char * in = (const unsigned char *)pin; - if( inlen > 0 ) - { - size_t left = S->buflen; - size_t fill = BLAKE2B_BLOCKBYTES - left; - if( inlen > fill ) - { - S->buflen = 0; - memcpy( S->buf + left, in, fill ); /* Fill buffer */ - blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES ); - blake2b_compress( S, S->buf ); /* Compress */ - in += fill; inlen -= fill; - while(inlen > BLAKE2B_BLOCKBYTES) { - blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); - blake2b_compress( S, in ); - in += BLAKE2B_BLOCKBYTES; - inlen -= BLAKE2B_BLOCKBYTES; - } - } - memcpy( S->buf + S->buflen, in, inlen ); - S->buflen += inlen; - } - return 0; -} - -int blake2b_Final( blake2b_state *S, void *out, size_t outlen ) -{ - uint8_t buffer[BLAKE2B_OUTBYTES] = {0}; - size_t i = 0; - - if( out == NULL || outlen < S->outlen ) - return -1; - - if( blake2b_is_lastblock( S ) ) - return -1; - - blake2b_increment_counter( S, S->buflen ); - blake2b_set_lastblock( S ); - memzero( S->buf + S->buflen, BLAKE2B_BLOCKBYTES - S->buflen ); /* Padding */ - blake2b_compress( S, S->buf ); - - for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */ - store64( buffer + sizeof( S->h[i] ) * i, S->h[i] ); - - memcpy( out, buffer, S->outlen ); - memzero(buffer, sizeof(buffer)); - return 0; -} - -int blake2b(const uint8_t *msg, uint32_t msg_len, void *out, size_t outlen) -{ - BLAKE2B_CTX ctx; - if (0 != blake2b_Init(&ctx, outlen)) return -1; - if (0 != blake2b_Update(&ctx, msg, msg_len)) return -1; - if (0 != blake2b_Final(&ctx, out, outlen)) return -1; - return 0; -} - -int blake2b_Key(const uint8_t *msg, uint32_t msg_len, const void *key, size_t keylen, void *out, size_t outlen) -{ - BLAKE2B_CTX ctx; - if (0 != blake2b_InitKey(&ctx, outlen, key, keylen)) return -1; - if (0 != blake2b_Update(&ctx, msg, msg_len)) return -1; - if (0 != blake2b_Final(&ctx, out, outlen)) return -1; - return 0; -} diff --git a/deps/crypto/trezor-crypto/blake2b.h b/deps/crypto/trezor-crypto/blake2b.h deleted file mode 100644 index 1a43e92d1..000000000 --- a/deps/crypto/trezor-crypto/blake2b.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef __BLAKE2B_H__ -#define __BLAKE2B_H__ - -#include -#include - -enum blake2b_constant -{ - BLAKE2B_BLOCKBYTES = 128, - BLAKE2B_OUTBYTES = 64, - BLAKE2B_KEYBYTES = 64, - BLAKE2B_SALTBYTES = 16, - BLAKE2B_PERSONALBYTES = 16 -}; - -typedef struct __blake2b_state -{ - uint64_t h[8]; - uint64_t t[2]; - uint64_t f[2]; - uint8_t buf[BLAKE2B_BLOCKBYTES]; - size_t buflen; - size_t outlen; - uint8_t last_node; -} blake2b_state; - -#define BLAKE2B_CTX blake2b_state -#define BLAKE2B_BLOCK_LENGTH BLAKE2B_BLOCKBYTES -#define BLAKE2B_DIGEST_LENGTH BLAKE2B_OUTBYTES -#define BLAKE2B_KEY_LENGTH BLAKE2B_KEYBYTES - -int blake2b_Init(blake2b_state *S, size_t outlen); -int blake2b_InitKey(blake2b_state *S, size_t outlen, const void *key, size_t keylen); -int blake2b_InitPersonal(blake2b_state *S, size_t outlen, const void *personal, size_t personal_len); -int blake2b_Update(blake2b_state *S, const void *pin, size_t inlen); -int blake2b_Final(blake2b_state *S, void *out, size_t outlen); - -int blake2b(const uint8_t *msg, uint32_t msg_len, void *out, size_t outlen); -int blake2b_Key(const uint8_t *msg, uint32_t msg_len, const void *key, size_t keylen, void *out, size_t outlen); - -#endif diff --git a/deps/crypto/trezor-crypto/blake2s.c b/deps/crypto/trezor-crypto/blake2s.c deleted file mode 100644 index 2c060a637..000000000 --- a/deps/crypto/trezor-crypto/blake2s.c +++ /dev/null @@ -1,318 +0,0 @@ -/* - BLAKE2 reference source code package - reference C implementations - - Copyright 2012, Samuel Neves . You may use this under the - terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at - your option. The terms of these licenses can be found at: - - - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 - - OpenSSL license : https://www.openssl.org/source/license.html - - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 - - More information about the BLAKE2 hash function can be found at - https://blake2.net. -*/ - -#include - -#include "blake2s.h" -#include "blake2_common.h" -#include "memzero.h" - -typedef struct blake2s_param__ -{ - uint8_t digest_length; /* 1 */ - uint8_t key_length; /* 2 */ - uint8_t fanout; /* 3 */ - uint8_t depth; /* 4 */ - uint32_t leaf_length; /* 8 */ - uint32_t node_offset; /* 12 */ - uint16_t xof_length; /* 14 */ - uint8_t node_depth; /* 15 */ - uint8_t inner_length; /* 16 */ - /* uint8_t reserved[0]; */ - uint8_t salt[BLAKE2S_SALTBYTES]; /* 24 */ - uint8_t personal[BLAKE2S_PERSONALBYTES]; /* 32 */ -} __attribute__((packed)) blake2s_param; - -static const uint32_t blake2s_IV[8] = -{ - 0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL, - 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL -}; - -static const uint8_t blake2s_sigma[10][16] = -{ - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , - { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , - { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , - { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , - { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , - { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , - { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , - { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , - { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , - { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , -}; - -static void blake2s_set_lastnode( blake2s_state *S ) -{ - S->f[1] = (uint32_t)-1; -} - -/* Some helper functions, not necessarily useful */ -static int blake2s_is_lastblock( const blake2s_state *S ) -{ - return S->f[0] != 0; -} - -static void blake2s_set_lastblock( blake2s_state *S ) -{ - if( S->last_node ) blake2s_set_lastnode( S ); - - S->f[0] = (uint32_t)-1; -} - -static void blake2s_increment_counter( blake2s_state *S, const uint32_t inc ) -{ - S->t[0] += inc; - S->t[1] += ( S->t[0] < inc ); -} - -static void blake2s_init0( blake2s_state *S ) -{ - size_t i = 0; - memzero( S, sizeof( blake2s_state ) ); - - for( i = 0; i < 8; ++i ) S->h[i] = blake2s_IV[i]; -} - -/* init2 xors IV with input parameter block */ -int blake2s_init_param( blake2s_state *S, const blake2s_param *P ) -{ - const unsigned char *p = ( const unsigned char * )( P ); - size_t i = 0; - - blake2s_init0( S ); - - /* IV XOR ParamBlock */ - for( i = 0; i < 8; ++i ) - S->h[i] ^= load32( &p[i * 4] ); - - S->outlen = P->digest_length; - return 0; -} - - -/* Sequential blake2s initialization */ -int blake2s_Init( blake2s_state *S, size_t outlen ) -{ - blake2s_param P[1] = {0}; - - if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1; - - P->digest_length = (uint8_t)outlen; - P->key_length = 0; - P->fanout = 1; - P->depth = 1; - store32( &P->leaf_length, 0 ); - store32( &P->node_offset, 0 ); - store16( &P->xof_length, 0 ); - P->node_depth = 0; - P->inner_length = 0; - /* memzero(P->reserved, sizeof(P->reserved) ); */ - memzero( P->salt, sizeof( P->salt ) ); - memzero( P->personal, sizeof( P->personal ) ); - return blake2s_init_param( S, P ); -} - -int blake2s_InitPersonal( blake2s_state *S, size_t outlen, const void *personal, size_t personal_len) -{ - blake2s_param P[1] = {0}; - - if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1; - if ( ( !personal ) || ( personal_len != BLAKE2S_PERSONALBYTES ) ) return -1; - - P->digest_length = (uint8_t)outlen; - P->key_length = 0; - P->fanout = 1; - P->depth = 1; - store32( &P->leaf_length, 0 ); - store32( &P->node_offset, 0 ); - store16( &P->xof_length, 0 ); - P->node_depth = 0; - P->inner_length = 0; - /* memzero(P->reserved, sizeof(P->reserved) ); */ - memzero( P->salt, sizeof( P->salt ) ); - memcpy( P->personal, personal, BLAKE2S_PERSONALBYTES ); - return blake2s_init_param( S, P ); -} - - -int blake2s_InitKey( blake2s_state *S, size_t outlen, const void *key, size_t keylen ) -{ - blake2s_param P[1] = {0}; - - if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1; - - if ( !key || !keylen || keylen > BLAKE2S_KEYBYTES ) return -1; - - P->digest_length = (uint8_t)outlen; - P->key_length = (uint8_t)keylen; - P->fanout = 1; - P->depth = 1; - store32( &P->leaf_length, 0 ); - store32( &P->node_offset, 0 ); - store16( &P->xof_length, 0 ); - P->node_depth = 0; - P->inner_length = 0; - /* memzero(P->reserved, sizeof(P->reserved) ); */ - memzero( P->salt, sizeof( P->salt ) ); - memzero( P->personal, sizeof( P->personal ) ); - - if( blake2s_init_param( S, P ) < 0 ) return -1; - - { - uint8_t block[BLAKE2S_BLOCKBYTES] = {0}; - memzero( block, BLAKE2S_BLOCKBYTES ); - memcpy( block, key, keylen ); - blake2s_Update( S, block, BLAKE2S_BLOCKBYTES ); - memzero( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */ - } - return 0; -} - -#define G(r,i,a,b,c,d) \ - do { \ - a = a + b + m[blake2s_sigma[r][2*i+0]]; \ - d = rotr32(d ^ a, 16); \ - c = c + d; \ - b = rotr32(b ^ c, 12); \ - a = a + b + m[blake2s_sigma[r][2*i+1]]; \ - d = rotr32(d ^ a, 8); \ - c = c + d; \ - b = rotr32(b ^ c, 7); \ - } while(0) - -#define ROUND(r) \ - do { \ - G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ - G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ - G(r,2,v[ 2],v[ 6],v[10],v[14]); \ - G(r,3,v[ 3],v[ 7],v[11],v[15]); \ - G(r,4,v[ 0],v[ 5],v[10],v[15]); \ - G(r,5,v[ 1],v[ 6],v[11],v[12]); \ - G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ - G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \ - } while(0) - -static void blake2s_compress( blake2s_state *S, const uint8_t in[BLAKE2S_BLOCKBYTES] ) -{ - uint32_t m[16] = {0}; - uint32_t v[16] = {0}; - size_t i = 0; - - for( i = 0; i < 16; ++i ) { - m[i] = load32( in + i * sizeof( m[i] ) ); - } - - for( i = 0; i < 8; ++i ) { - v[i] = S->h[i]; - } - - v[ 8] = blake2s_IV[0]; - v[ 9] = blake2s_IV[1]; - v[10] = blake2s_IV[2]; - v[11] = blake2s_IV[3]; - v[12] = S->t[0] ^ blake2s_IV[4]; - v[13] = S->t[1] ^ blake2s_IV[5]; - v[14] = S->f[0] ^ blake2s_IV[6]; - v[15] = S->f[1] ^ blake2s_IV[7]; - - ROUND( 0 ); - ROUND( 1 ); - ROUND( 2 ); - ROUND( 3 ); - ROUND( 4 ); - ROUND( 5 ); - ROUND( 6 ); - ROUND( 7 ); - ROUND( 8 ); - ROUND( 9 ); - - for( i = 0; i < 8; ++i ) { - S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; - } -} - -#undef G -#undef ROUND - -int blake2s_Update( blake2s_state *S, const void *pin, size_t inlen ) -{ - const unsigned char * in = (const unsigned char *)pin; - if( inlen > 0 ) - { - size_t left = S->buflen; - size_t fill = BLAKE2S_BLOCKBYTES - left; - if( inlen > fill ) - { - S->buflen = 0; - memcpy( S->buf + left, in, fill ); /* Fill buffer */ - blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES ); - blake2s_compress( S, S->buf ); /* Compress */ - in += fill; inlen -= fill; - while(inlen > BLAKE2S_BLOCKBYTES) { - blake2s_increment_counter(S, BLAKE2S_BLOCKBYTES); - blake2s_compress( S, in ); - in += BLAKE2S_BLOCKBYTES; - inlen -= BLAKE2S_BLOCKBYTES; - } - } - memcpy( S->buf + S->buflen, in, inlen ); - S->buflen += inlen; - } - return 0; -} - -int blake2s_Final( blake2s_state *S, void *out, size_t outlen ) -{ - uint8_t buffer[BLAKE2S_OUTBYTES] = {0}; - size_t i = 0; - - if( out == NULL || outlen < S->outlen ) - return -1; - - if( blake2s_is_lastblock( S ) ) - return -1; - - blake2s_increment_counter( S, ( uint32_t )S->buflen ); - blake2s_set_lastblock( S ); - memzero( S->buf + S->buflen, BLAKE2S_BLOCKBYTES - S->buflen ); /* Padding */ - blake2s_compress( S, S->buf ); - - for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */ - store32( buffer + sizeof( S->h[i] ) * i, S->h[i] ); - - memcpy( out, buffer, outlen ); - memzero(buffer, sizeof(buffer)); - return 0; -} - -int blake2s(const uint8_t *msg, uint32_t msg_len, void *out, size_t outlen) -{ - BLAKE2S_CTX ctx; - if (0 != blake2s_Init(&ctx, outlen)) return -1; - if (0 != blake2s_Update(&ctx, msg, msg_len)) return -1; - if (0 != blake2s_Final(&ctx, out, outlen)) return -1; - return 0; -} - -int blake2s_Key(const uint8_t *msg, uint32_t msg_len, const void *key, size_t keylen, void *out, size_t outlen) -{ - BLAKE2S_CTX ctx; - if (0 != blake2s_InitKey(&ctx, outlen, key, keylen)) return -1; - if (0 != blake2s_Update(&ctx, msg, msg_len)) return -1; - if (0 != blake2s_Final(&ctx, out, outlen)) return -1; - return 0; -} diff --git a/deps/crypto/trezor-crypto/blake2s.h b/deps/crypto/trezor-crypto/blake2s.h deleted file mode 100644 index 57991bc91..000000000 --- a/deps/crypto/trezor-crypto/blake2s.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef __BLAKE2S_H__ -#define __BLAKE2S_H__ - -#include -#include - -enum blake2s_constant -{ - BLAKE2S_BLOCKBYTES = 64, - BLAKE2S_OUTBYTES = 32, - BLAKE2S_KEYBYTES = 32, - BLAKE2S_SALTBYTES = 8, - BLAKE2S_PERSONALBYTES = 8 -}; - -typedef struct __blake2s_state -{ - uint32_t h[8]; - uint32_t t[2]; - uint32_t f[2]; - uint8_t buf[BLAKE2S_BLOCKBYTES]; - uint32_t buflen; - uint8_t outlen; - uint8_t last_node; -} blake2s_state; - -#define BLAKE2S_CTX blake2s_state -#define BLAKE2S_BLOCK_LENGTH BLAKE2S_BLOCKBYTES -#define BLAKE2S_DIGEST_LENGTH BLAKE2S_OUTBYTES -#define BLAKE2S_KEY_LENGTH BLAKE2S_KEYBYTES - -int blake2s_Init(blake2s_state *S, size_t outlen); -int blake2s_InitKey(blake2s_state *S, size_t outlen, const void *key, size_t keylen); -int blake2s_InitPersonal(blake2s_state *S, size_t outlen, const void *personal, size_t personal_len); -int blake2s_Update(blake2s_state *S, const void *pin, size_t inlen); -int blake2s_Final(blake2s_state *S, void *out, size_t outlen); - -int blake2s(const uint8_t *msg, uint32_t msg_len, void *out, size_t outlen); -int blake2s_Key(const uint8_t *msg, uint32_t msg_len, const void *key, size_t keylen, void *out, size_t outlen); - -#endif diff --git a/deps/crypto/trezor-crypto/cash_addr.c b/deps/crypto/trezor-crypto/cash_addr.c deleted file mode 100644 index 1057e7ef6..000000000 --- a/deps/crypto/trezor-crypto/cash_addr.c +++ /dev/null @@ -1,193 +0,0 @@ -/* Copyright (c) 2017 Jochen Hoenicke - * based on code Copyright (c) 2017 Peter Wuille - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include -#include -#include - -#include "cash_addr.h" - -#define MAX_CASHADDR_LEN 129 -#define MAX_BASE32_SIZE 104 -#define MAX_PROG_SIZE 65 -#define MAX_HRP_LEN 20 -#define CHECKSUM_SIZE 8 - -uint64_t cashaddr_polymod_step(uint64_t pre) { - uint8_t b = pre >> 35; - return ((pre & 0x7FFFFFFFFULL) << 5) ^ (-((b >> 0) & 1) & 0x98f2bc8e61ULL) ^ - (-((b >> 1) & 1) & 0x79b76d99e2ULL) ^ - (-((b >> 2) & 1) & 0xf33e5fb3c4ULL) ^ - (-((b >> 3) & 1) & 0xae2eabe2a8ULL) ^ - (-((b >> 4) & 1) & 0x1e4f43e470ULL); -} - -static const char* charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; - -static const int8_t charset_rev[128] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 15, -1, 10, 17, 21, 20, 26, 30, 7, - 5, -1, -1, -1, -1, -1, -1, -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, - 31, 27, 19, -1, 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, - -1, -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, 1, 0, - 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1}; - -int cash_encode(char* output, const char* hrp, const uint8_t* data, - size_t data_size) { - uint64_t chk = 1; - size_t i = 0; - while (hrp[i] != 0) { - int ch = hrp[i]; - if (ch < 33 || ch > 126) { - return 0; - } - *(output++) = ch; - chk = cashaddr_polymod_step(chk) ^ (ch & 0x1f); - ++i; - if (i > MAX_HRP_LEN) { - return 0; - } - } - if (i + 1 + data_size + CHECKSUM_SIZE > MAX_CASHADDR_LEN) { - return 0; - } - chk = cashaddr_polymod_step(chk); - *(output++) = ':'; - for (i = 0; i < data_size; ++i) { - if (*data >> 5) return 0; - chk = cashaddr_polymod_step(chk) ^ (*data); - *(output++) = charset[*(data++)]; - } - for (i = 0; i < CHECKSUM_SIZE; ++i) { - chk = cashaddr_polymod_step(chk); - } - chk ^= 1; - for (i = 0; i < CHECKSUM_SIZE; ++i) { - *(output++) = charset[(chk >> ((CHECKSUM_SIZE - 1 - i) * 5)) & 0x1f]; - } - *output = 0; - return 1; -} - -int cash_decode(char* hrp, uint8_t* data, size_t* data_size, - const char* input) { - uint64_t chk = 1; - size_t i = 0; - size_t input_len = strlen(input); - size_t hrp_len = 0; - int have_lower = 0, have_upper = 0; - if (input_len < CHECKSUM_SIZE || input_len > MAX_CASHADDR_LEN) { - return 0; - } - *data_size = 0; - while (*data_size < input_len && input[(input_len - 1) - *data_size] != ':') { - ++(*data_size); - } - hrp_len = input_len - (1 + *data_size); - if (1 + *data_size >= input_len || hrp_len > MAX_HRP_LEN || - *data_size < CHECKSUM_SIZE || - *data_size > CHECKSUM_SIZE + MAX_BASE32_SIZE) { - return 0; - } - // subtract checksum - *(data_size) -= CHECKSUM_SIZE; - for (i = 0; i < hrp_len; ++i) { - int ch = input[i]; - if (ch < 33 || ch > 126) { - return 0; - } - if (ch >= 'a' && ch <= 'z') { - have_lower = 1; - } else if (ch >= 'A' && ch <= 'Z') { - have_upper = 1; - ch = (ch - 'A') + 'a'; - } - hrp[i] = ch; - chk = cashaddr_polymod_step(chk) ^ (ch & 0x1f); - } - hrp[i] = 0; - chk = cashaddr_polymod_step(chk); - ++i; - while (i < input_len) { - int v = (input[i] & 0x80) ? -1 : charset_rev[(int)input[i]]; - if (input[i] >= 'a' && input[i] <= 'z') have_lower = 1; - if (input[i] >= 'A' && input[i] <= 'Z') have_upper = 1; - if (v == -1) { - return 0; - } - chk = cashaddr_polymod_step(chk) ^ v; - if (i + CHECKSUM_SIZE < input_len) { - data[i - (1 + hrp_len)] = v; - } - ++i; - } - if (have_lower && have_upper) { - return 0; - } - return chk == 1; -} - -static int convert_bits(uint8_t* out, size_t* outlen, int outbits, - const uint8_t* in, size_t inlen, int inbits, int pad) { - uint32_t val = 0; - int bits = 0; - uint32_t maxv = (((uint32_t)1) << outbits) - 1; - while (inlen--) { - val = (val << inbits) | *(in++); - bits += inbits; - while (bits >= outbits) { - bits -= outbits; - out[(*outlen)++] = (val >> bits) & maxv; - } - } - if (pad) { - if (bits) { - out[(*outlen)++] = (val << (outbits - bits)) & maxv; - } - } else if (((val << (outbits - bits)) & maxv) || bits >= inbits) { - return 0; - } - return 1; -} - -int cash_addr_encode(char* output, const char* hrp, const uint8_t* prog, - size_t prog_size) { - uint8_t base32[MAX_BASE32_SIZE] = {0}; - size_t base32size = 0; - if (prog_size < 2 || prog_size > MAX_PROG_SIZE) return 0; - convert_bits(base32, &base32size, 5, prog, prog_size, 8, 1); - return cash_encode(output, hrp, base32, base32size); -} - -int cash_addr_decode(uint8_t* prog, size_t* prog_size, const char* hrp, - const char* addr) { - uint8_t data[MAX_BASE32_SIZE] = {0}; - char hrp_actual[MAX_HRP_LEN + 1] = {0}; - size_t data_size = 0; - if (!cash_decode(hrp_actual, data, &data_size, addr)) return 0; - if (data_size == 0 || data_size > MAX_BASE32_SIZE) return 0; - if (strncmp(hrp, hrp_actual, MAX_HRP_LEN + 1) != 0) return 0; - *prog_size = 0; - if (!convert_bits(prog, prog_size, 8, data, data_size, 5, 0)) return 0; - if (*prog_size < 2 || *prog_size > MAX_PROG_SIZE) return 0; - return 1; -} diff --git a/deps/crypto/trezor-crypto/cash_addr.h b/deps/crypto/trezor-crypto/cash_addr.h deleted file mode 100644 index 5f27edb85..000000000 --- a/deps/crypto/trezor-crypto/cash_addr.h +++ /dev/null @@ -1,80 +0,0 @@ -/* Copyright (c) 2017 Jochen Hoenicke, Pieter Wuille - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef _CASH_ADDR_H_ -#define _CASH_ADDR_H_ 1 - -#include - -/** Encode a Cashaddr address - * - * Out: output: Pointer to a buffer of size min(114 + strlen(hrp), 130) - * that will be updated to contain the null-terminated - * address. - * In: hrp: Pointer to the null-terminated human readable part to use - * (chain/network specific). - * prog: Data bytes for the hash (between 21 and 65 bytes). - * prog_size: Number of data bytes in prog. - * Returns 1 if successful. - */ -int cash_addr_encode(char *output, const char *hrp, const uint8_t *prog, - size_t prog_size); - -/** Decode a CashAddr address - * - * Out: prog: Pointer to a buffer of size 65 that will be updated to - * contain the witness program bytes. - * prog_size: Pointer to a size_t that will be updated to contain the - * length of bytes in prog. - * In: hrp: Pointer to the null-terminated human readable part that is - * expected (chain/network specific). - * addr: Pointer to the null-terminated address. - * Returns 1 if successful. - */ -int cash_addr_decode(uint8_t *prog, size_t *prog_size, const char *hrp, - const char *addr); - -/** Encode a Cash string - * - * Out: output: Pointer to a buffer of size strlen(hrp) + data_size + 10 that - * will be updated to contain the null-terminated Cash string. - * In: hrp: Pointer to the null-terminated human readable part. - * data: Pointer to an array of 5-bit values. - * data_size: Length of the data array. - * Returns 1 if successful. - */ -int cash_encode(char *output, const char *hrp, const uint8_t *data, - size_t data_size); - -/** Decode a Cash string - * - * Out: hrp: Pointer to a buffer of size strlen(input) - 6. Will be - * updated to contain the null-terminated human readable part. - * data: Pointer to a buffer of size strlen(input) - 8 that will - * hold the encoded 5-bit data values. - * data_size: Pointer to a size_t that will be updated to be the number - * of entries in data. - * In: input: Pointer to a null-terminated Cash string. - * Returns 1 if succesful. - */ -int cash_decode(char *hrp, uint8_t *data, size_t *data_size, const char *input); - -#endif diff --git a/deps/crypto/trezor-crypto/chacha20poly1305/chacha20poly1305.c b/deps/crypto/trezor-crypto/chacha20poly1305/chacha20poly1305.c deleted file mode 100644 index 4012dd056..000000000 --- a/deps/crypto/trezor-crypto/chacha20poly1305/chacha20poly1305.c +++ /dev/null @@ -1,60 +0,0 @@ -// Implementations of the XChaCha20 + Poly1305 and ChaCha20 + Poly1305 -// AEAD constructions with a goal of simplicity and correctness rather -// than performance. - -#include "chacha20poly1305.h" -#include "ecrypt-portable.h" - -void hchacha20(ECRYPT_ctx *x,u8 *c); - -// Initialize the XChaCha20 + Poly1305 context for encryption or decryption -// using a 32 byte key and 24 byte nonce. The key and the first 16 bytes of -// the nonce are used as input to HChaCha20 to derive the Chacha20 key. -void xchacha20poly1305_init(chacha20poly1305_ctx *ctx, const uint8_t key[32], const uint8_t nonce[24]) { - unsigned char subkey[32] = {0}; - unsigned char block0[64] = {0}; - ECRYPT_ctx tmp = {0}; - - // Generate the Chacha20 key by applying HChaCha20 to the - // original key and the first 16 bytes of the nonce. - ECRYPT_keysetup(&tmp, key, 256, 16); - tmp.input[12] = U8TO32_LITTLE(nonce + 0); - tmp.input[13] = U8TO32_LITTLE(nonce + 4); - tmp.input[14] = U8TO32_LITTLE(nonce + 8); - tmp.input[15] = U8TO32_LITTLE(nonce + 12); - hchacha20(&tmp, subkey); - - // Initialize Chacha20 with the newly generated key and - // the last 8 bytes of the nonce. - ECRYPT_keysetup(&ctx->chacha20, subkey, 256, 16); - ECRYPT_ivsetup(&ctx->chacha20, nonce+16); - - // Encrypt 64 bytes of zeros and use the first 32 bytes - // as the Poly1305 key. - ECRYPT_encrypt_bytes(&ctx->chacha20, block0, block0, 64); - poly1305_init(&ctx->poly1305, block0); -} - -// Encrypt n bytes of plaintext where n must be evenly divisible by the -// Chacha20 blocksize of 64, except for the final n bytes of plaintext. -void chacha20poly1305_encrypt(chacha20poly1305_ctx *ctx, const uint8_t *in, uint8_t *out, size_t n) { - ECRYPT_encrypt_bytes(&ctx->chacha20, in, out, n); - poly1305_update(&ctx->poly1305, out, n); -} - -// Decrypt n bytes of ciphertext where n must be evenly divisible by the -// Chacha20 blocksize of 64, except for the final n bytes of ciphertext. -void chacha20poly1305_decrypt(chacha20poly1305_ctx *ctx, const uint8_t *in, uint8_t *out, size_t n) { - poly1305_update(&ctx->poly1305, in, n); - ECRYPT_encrypt_bytes(&ctx->chacha20, in, out, n); -} - -// Include authenticated data in the Poly1305 MAC. -void chacha20poly1305_auth(chacha20poly1305_ctx *ctx, const uint8_t *in, size_t n) { - poly1305_update(&ctx->poly1305, in, n); -} - -// Compute NaCl secretbox-style Poly1305 MAC. -void chacha20poly1305_finish(chacha20poly1305_ctx *ctx, uint8_t mac[16]) { - poly1305_finish(&ctx->poly1305, mac); -} diff --git a/deps/crypto/trezor-crypto/chacha20poly1305/chacha20poly1305.h b/deps/crypto/trezor-crypto/chacha20poly1305/chacha20poly1305.h deleted file mode 100644 index 1f501f12e..000000000 --- a/deps/crypto/trezor-crypto/chacha20poly1305/chacha20poly1305.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef CHACHA20POLY1305_H -#define CHACHA20POLY1305_H - -#include -#include "ecrypt-sync.h" -#include "poly1305-donna.h" - -typedef struct { - ECRYPT_ctx chacha20; - poly1305_context poly1305; -} chacha20poly1305_ctx; - -void xchacha20poly1305_init(chacha20poly1305_ctx *ctx, const uint8_t key[32], const uint8_t nonce[24]); -void chacha20poly1305_encrypt(chacha20poly1305_ctx *ctx, const uint8_t *in, uint8_t *out, size_t n); -void chacha20poly1305_decrypt(chacha20poly1305_ctx *ctx, const uint8_t *in, uint8_t *out, size_t n); -void chacha20poly1305_auth(chacha20poly1305_ctx *ctx, const uint8_t *in, size_t n); -void chacha20poly1305_finish(chacha20poly1305_ctx *ctx, uint8_t mac[16]); - -#endif // CHACHA20POLY1305_H diff --git a/deps/crypto/trezor-crypto/chacha20poly1305/chacha_merged.c b/deps/crypto/trezor-crypto/chacha20poly1305/chacha_merged.c deleted file mode 100644 index f5c37fa8a..000000000 --- a/deps/crypto/trezor-crypto/chacha20poly1305/chacha_merged.c +++ /dev/null @@ -1,252 +0,0 @@ -/* -chacha-merged.c version 20080118 -D. J. Bernstein -Public domain. -*/ - -#include "ecrypt-sync.h" -#include "ecrypt-portable.h" - -#define ROTATE(v,c) (ROTL32(v,c)) -#define XOR(v,w) ((v) ^ (w)) -#define PLUS(v,w) (U32V((v) + (w))) -#define PLUSONE(v) (PLUS((v),1)) - -#define QUARTERROUND(a,b,c,d) \ - a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ - c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ - a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ - c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); - -void ECRYPT_init(void) -{ - return; -} - -static const char sigma[16] = "expand 32-byte k"; -static const char tau[16] = "expand 16-byte k"; - -void ECRYPT_keysetup(ECRYPT_ctx *x,const u8 *k,u32 kbits,u32 ivbits) -{ - (void)ivbits; - const char *constants = (const char *)0; - - x->input[4] = U8TO32_LITTLE(k + 0); - x->input[5] = U8TO32_LITTLE(k + 4); - x->input[6] = U8TO32_LITTLE(k + 8); - x->input[7] = U8TO32_LITTLE(k + 12); - if (kbits == 256) { /* recommended */ - k += 16; - constants = sigma; - } else { /* kbits == 128 */ - constants = tau; - } - x->input[8] = U8TO32_LITTLE(k + 0); - x->input[9] = U8TO32_LITTLE(k + 4); - x->input[10] = U8TO32_LITTLE(k + 8); - x->input[11] = U8TO32_LITTLE(k + 12); - x->input[0] = U8TO32_LITTLE(constants + 0); - x->input[1] = U8TO32_LITTLE(constants + 4); - x->input[2] = U8TO32_LITTLE(constants + 8); - x->input[3] = U8TO32_LITTLE(constants + 12); -} - -void ECRYPT_ivsetup(ECRYPT_ctx *x,const u8 *iv) -{ - x->input[12] = 0; - x->input[13] = 0; - x->input[14] = U8TO32_LITTLE(iv + 0); - x->input[15] = U8TO32_LITTLE(iv + 4); -} - -void ECRYPT_ctrsetup(ECRYPT_ctx *x,const u8 *ctr) -{ - x->input[12] = U8TO32_LITTLE(ctr + 0); - x->input[13] = U8TO32_LITTLE(ctr + 4); -} - -void ECRYPT_encrypt_bytes(ECRYPT_ctx *x,const u8 *m,u8 *c,u32 bytes) -{ - u32 x0 = 0, x1 = 0, x2 = 0, x3 = 0, x4 = 0, x5 = 0, x6 = 0, x7 = 0, x8 = 0, x9 = 0, x10 = 0, x11 = 0, x12 = 0, x13 = 0, x14 = 0, x15 = 0; - u32 j0 = 0, j1 = 0, j2 = 0, j3 = 0, j4 = 0, j5 = 0, j6 = 0, j7 = 0, j8 = 0, j9 = 0, j10 = 0, j11 = 0, j12 = 0, j13 = 0, j14 = 0, j15 = 0; - u8 *ctarget = 0; - u8 tmp[64] = {0}; - int i = 0; - - if (!bytes) return; - - j0 = x->input[0]; - j1 = x->input[1]; - j2 = x->input[2]; - j3 = x->input[3]; - j4 = x->input[4]; - j5 = x->input[5]; - j6 = x->input[6]; - j7 = x->input[7]; - j8 = x->input[8]; - j9 = x->input[9]; - j10 = x->input[10]; - j11 = x->input[11]; - j12 = x->input[12]; - j13 = x->input[13]; - j14 = x->input[14]; - j15 = x->input[15]; - - for (;;) { - if (bytes < 64) { - for (i = 0;i < (int)bytes;++i) tmp[i] = m[i]; - m = tmp; - ctarget = c; - c = tmp; - } - x0 = j0; - x1 = j1; - x2 = j2; - x3 = j3; - x4 = j4; - x5 = j5; - x6 = j6; - x7 = j7; - x8 = j8; - x9 = j9; - x10 = j10; - x11 = j11; - x12 = j12; - x13 = j13; - x14 = j14; - x15 = j15; - for (i = 20;i > 0;i -= 2) { - QUARTERROUND( x0, x4, x8,x12) - QUARTERROUND( x1, x5, x9,x13) - QUARTERROUND( x2, x6,x10,x14) - QUARTERROUND( x3, x7,x11,x15) - QUARTERROUND( x0, x5,x10,x15) - QUARTERROUND( x1, x6,x11,x12) - QUARTERROUND( x2, x7, x8,x13) - QUARTERROUND( x3, x4, x9,x14) - } - x0 = PLUS(x0,j0); - x1 = PLUS(x1,j1); - x2 = PLUS(x2,j2); - x3 = PLUS(x3,j3); - x4 = PLUS(x4,j4); - x5 = PLUS(x5,j5); - x6 = PLUS(x6,j6); - x7 = PLUS(x7,j7); - x8 = PLUS(x8,j8); - x9 = PLUS(x9,j9); - x10 = PLUS(x10,j10); - x11 = PLUS(x11,j11); - x12 = PLUS(x12,j12); - x13 = PLUS(x13,j13); - x14 = PLUS(x14,j14); - x15 = PLUS(x15,j15); - - x0 = XOR(x0,U8TO32_LITTLE(m + 0)); - x1 = XOR(x1,U8TO32_LITTLE(m + 4)); - x2 = XOR(x2,U8TO32_LITTLE(m + 8)); - x3 = XOR(x3,U8TO32_LITTLE(m + 12)); - x4 = XOR(x4,U8TO32_LITTLE(m + 16)); - x5 = XOR(x5,U8TO32_LITTLE(m + 20)); - x6 = XOR(x6,U8TO32_LITTLE(m + 24)); - x7 = XOR(x7,U8TO32_LITTLE(m + 28)); - x8 = XOR(x8,U8TO32_LITTLE(m + 32)); - x9 = XOR(x9,U8TO32_LITTLE(m + 36)); - x10 = XOR(x10,U8TO32_LITTLE(m + 40)); - x11 = XOR(x11,U8TO32_LITTLE(m + 44)); - x12 = XOR(x12,U8TO32_LITTLE(m + 48)); - x13 = XOR(x13,U8TO32_LITTLE(m + 52)); - x14 = XOR(x14,U8TO32_LITTLE(m + 56)); - x15 = XOR(x15,U8TO32_LITTLE(m + 60)); - - j12 = PLUSONE(j12); - if (!j12) { - j13 = PLUSONE(j13); - /* stopping at 2^70 bytes per nonce is user's responsibility */ - } - - U32TO8_LITTLE(c + 0,x0); - U32TO8_LITTLE(c + 4,x1); - U32TO8_LITTLE(c + 8,x2); - U32TO8_LITTLE(c + 12,x3); - U32TO8_LITTLE(c + 16,x4); - U32TO8_LITTLE(c + 20,x5); - U32TO8_LITTLE(c + 24,x6); - U32TO8_LITTLE(c + 28,x7); - U32TO8_LITTLE(c + 32,x8); - U32TO8_LITTLE(c + 36,x9); - U32TO8_LITTLE(c + 40,x10); - U32TO8_LITTLE(c + 44,x11); - U32TO8_LITTLE(c + 48,x12); - U32TO8_LITTLE(c + 52,x13); - U32TO8_LITTLE(c + 56,x14); - U32TO8_LITTLE(c + 60,x15); - - if (bytes <= 64) { - if (bytes < 64) { - for (i = 0;i < (int)bytes;++i) ctarget[i] = c[i]; - } - x->input[12] = j12; - x->input[13] = j13; - return; - } - bytes -= 64; - c += 64; - m += 64; - } -} - -void ECRYPT_decrypt_bytes(ECRYPT_ctx *x,const u8 *c,u8 *m,u32 bytes) -{ - ECRYPT_encrypt_bytes(x,c,m,bytes); -} - -void ECRYPT_keystream_bytes(ECRYPT_ctx *x,u8 *stream,u32 bytes) -{ - u32 i = 0; - for (i = 0;i < bytes;++i) stream[i] = 0; - ECRYPT_encrypt_bytes(x,stream,stream,bytes); -} - -void hchacha20(ECRYPT_ctx *x,u8 *c) -{ - u32 x0 = 0, x1 = 0, x2 = 0, x3 = 0, x4 = 0, x5 = 0, x6 = 0, x7 = 0, x8 = 0, x9 = 0, x10 = 0, x11 = 0, x12 = 0, x13 = 0, x14 = 0, x15 = 0; - int i = 0; - - x0 = x->input[0]; - x1 = x->input[1]; - x2 = x->input[2]; - x3 = x->input[3]; - x4 = x->input[4]; - x5 = x->input[5]; - x6 = x->input[6]; - x7 = x->input[7]; - x8 = x->input[8]; - x9 = x->input[9]; - x10 = x->input[10]; - x11 = x->input[11]; - x12 = x->input[12]; - x13 = x->input[13]; - x14 = x->input[14]; - x15 = x->input[15]; - - for (i = 20;i > 0;i -= 2) { - QUARTERROUND( x0, x4, x8,x12) - QUARTERROUND( x1, x5, x9,x13) - QUARTERROUND( x2, x6,x10,x14) - QUARTERROUND( x3, x7,x11,x15) - QUARTERROUND( x0, x5,x10,x15) - QUARTERROUND( x1, x6,x11,x12) - QUARTERROUND( x2, x7, x8,x13) - QUARTERROUND( x3, x4, x9,x14) - } - - U32TO8_LITTLE(c + 0,x0); - U32TO8_LITTLE(c + 4,x1); - U32TO8_LITTLE(c + 8,x2); - U32TO8_LITTLE(c + 12,x3); - U32TO8_LITTLE(c + 16,x12); - U32TO8_LITTLE(c + 20,x13); - U32TO8_LITTLE(c + 24,x14); - U32TO8_LITTLE(c + 28,x15); -} diff --git a/deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-config.h b/deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-config.h deleted file mode 100644 index 0749df730..000000000 --- a/deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-config.h +++ /dev/null @@ -1,316 +0,0 @@ -/* ecrypt-config.h */ - -/* *** Normally, it should not be necessary to edit this file. *** */ - -#ifndef ECRYPT_CONFIG -#define ECRYPT_CONFIG - -/* ------------------------------------------------------------------------- */ - -/* Guess the endianness of the target architecture. */ - -/* - * The LITTLE endian machines: - */ -#if defined(__ultrix) /* Older MIPS */ -#define ECRYPT_LITTLE_ENDIAN -#elif defined(__alpha) /* Alpha */ -#define ECRYPT_LITTLE_ENDIAN -#elif defined(i386) /* x86 (gcc) */ -#define ECRYPT_LITTLE_ENDIAN -#elif defined(__i386) /* x86 (gcc) */ -#define ECRYPT_LITTLE_ENDIAN -#elif defined(__x86_64) /* x86_64 (gcc) */ -#define ECRYPT_LITTLE_ENDIAN -#elif defined(_M_IX86) /* x86 (MSC, Borland) */ -#define ECRYPT_LITTLE_ENDIAN -#elif defined(_MSC_VER) /* x86 (surely MSC) */ -#define ECRYPT_LITTLE_ENDIAN -#elif defined(__INTEL_COMPILER) /* x86 (surely Intel compiler icl.exe) */ -#define ECRYPT_LITTLE_ENDIAN - -/* - * The BIG endian machines: - */ -#elif defined(__sparc) /* Newer Sparc's */ -#define ECRYPT_BIG_ENDIAN -#elif defined(__powerpc__) /* PowerPC */ -#define ECRYPT_BIG_ENDIAN -#elif defined(__ppc__) /* PowerPC */ -#define ECRYPT_BIG_ENDIAN -#elif defined(__hppa) /* HP-PA */ -#define ECRYPT_BIG_ENDIAN - -/* - * Finally machines with UNKNOWN endianness: - */ -#elif defined (_AIX) /* RS6000 */ -#define ECRYPT_UNKNOWN -#elif defined(__aux) /* 68K */ -#define ECRYPT_UNKNOWN -#elif defined(__dgux) /* 88K (but P6 in latest boxes) */ -#define ECRYPT_UNKNOWN -#elif defined(__sgi) /* Newer MIPS */ -#define ECRYPT_UNKNOWN -#else /* Any other processor */ -#define ECRYPT_UNKNOWN -#endif - -/* ------------------------------------------------------------------------- */ - -/* - * Find minimal-width types to store 8-bit, 16-bit, 32-bit, and 64-bit - * integers. - * - * Note: to enable 64-bit types on 32-bit compilers, it might be - * necessary to switch from ISO C90 mode to ISO C99 mode (e.g., gcc - * -std=c99), or to allow compiler-specific extensions. - */ - -#include - -/* --- check char --- */ - -#if (UCHAR_MAX / 0xFU > 0xFU) -#ifndef I8T -#define I8T char -#define U8C(v) (v##U) - -#if (UCHAR_MAX == 0xFFU) -#define ECRYPT_I8T_IS_BYTE -#endif - -#endif - -#if (UCHAR_MAX / 0xFFU > 0xFFU) -#ifndef I16T -#define I16T char -#define U16C(v) (v##U) -#endif - -#if (UCHAR_MAX / 0xFFFFU > 0xFFFFU) -#ifndef I32T -#define I32T char -#define U32C(v) (v##U) -#endif - -#if (UCHAR_MAX / 0xFFFFFFFFU > 0xFFFFFFFFU) -#ifndef I64T -#define I64T char -#define U64C(v) (v##U) -#define ECRYPT_NATIVE64 -#endif - -#endif -#endif -#endif -#endif - -/* --- check short --- */ - -#if (USHRT_MAX / 0xFU > 0xFU) -#ifndef I8T -#define I8T short -#define U8C(v) (v##U) - -#if (USHRT_MAX == 0xFFU) -#define ECRYPT_I8T_IS_BYTE -#endif - -#endif - -#if (USHRT_MAX / 0xFFU > 0xFFU) -#ifndef I16T -#define I16T short -#define U16C(v) (v##U) -#endif - -#if (USHRT_MAX / 0xFFFFU > 0xFFFFU) -#ifndef I32T -#define I32T short -#define U32C(v) (v##U) -#endif - -#if (USHRT_MAX / 0xFFFFFFFFU > 0xFFFFFFFFU) -#ifndef I64T -#define I64T short -#define U64C(v) (v##U) -#define ECRYPT_NATIVE64 -#endif - -#endif -#endif -#endif -#endif - -/* --- check int --- */ - -#if (UINT_MAX / 0xFU > 0xFU) -#ifndef I8T -#define I8T int -#define U8C(v) (v##U) - -#if (ULONG_MAX == 0xFFU) -#define ECRYPT_I8T_IS_BYTE -#endif - -#endif - -#if (UINT_MAX / 0xFFU > 0xFFU) -#ifndef I16T -#define I16T int -#define U16C(v) (v##U) -#endif - -#if (UINT_MAX / 0xFFFFU > 0xFFFFU) -#ifndef I32T -#define I32T int -#define U32C(v) (v##U) -#endif - -#if (UINT_MAX / 0xFFFFFFFFU > 0xFFFFFFFFU) -#ifndef I64T -#define I64T int -#define U64C(v) (v##U) -#define ECRYPT_NATIVE64 -#endif - -#endif -#endif -#endif -#endif - -/* --- check long --- */ - -#if (ULONG_MAX / 0xFUL > 0xFUL) -#ifndef I8T -#define I8T long -#define U8C(v) (v##UL) - -#if (ULONG_MAX == 0xFFUL) -#define ECRYPT_I8T_IS_BYTE -#endif - -#endif - -#if (ULONG_MAX / 0xFFUL > 0xFFUL) -#ifndef I16T -#define I16T long -#define U16C(v) (v##UL) -#endif - -#if (ULONG_MAX / 0xFFFFUL > 0xFFFFUL) -#ifndef I32T -#define I32T long -#define U32C(v) (v##UL) -#endif - -#if (ULONG_MAX / 0xFFFFFFFFUL > 0xFFFFFFFFUL) -#ifndef I64T -#define I64T long -#define U64C(v) (v##UL) -#define ECRYPT_NATIVE64 -#endif - -#endif -#endif -#endif -#endif - -/* --- check long long --- */ - -#ifdef ULLONG_MAX - -#if (ULLONG_MAX / 0xFULL > 0xFULL) -#ifndef I8T -#define I8T long long -#define U8C(v) (v##ULL) - -#if (ULLONG_MAX == 0xFFULL) -#define ECRYPT_I8T_IS_BYTE -#endif - -#endif - -#if (ULLONG_MAX / 0xFFULL > 0xFFULL) -#ifndef I16T -#define I16T long long -#define U16C(v) (v##ULL) -#endif - -#if (ULLONG_MAX / 0xFFFFULL > 0xFFFFULL) -#ifndef I32T -#define I32T long long -#define U32C(v) (v##ULL) -#endif - -#if (ULLONG_MAX / 0xFFFFFFFFULL > 0xFFFFFFFFULL) -#ifndef I64T -#define I64T long long -#define U64C(v) (v##ULL) -#endif - -#endif -#endif -#endif -#endif - -#endif - -/* --- check __int64 --- */ - -#if !defined(__STDC__) && defined(_UI64_MAX) - -#ifndef I64T -#define I64T __int64 -#define U64C(v) (v##ui64) -#endif - -#endif - -/* --- if platform doesn't announce anything, use most common choices --- */ - -#ifndef I8T -#define I8T char -#define U8C(v) (v##U) -#endif -#ifndef I16T -#define I16T short -#define U16C(v) (v##U) -#endif -#ifndef I32T -#define I32T int -#define U32C(v) (v##U) -#endif -#ifndef I64T -#define I64T long long -#define U64C(v) (v##ULL) -#endif - -/* ------------------------------------------------------------------------- */ - -/* find the largest type on this platform (used for alignment) */ - -#if defined(__SSE__) || (defined(_MSC_VER) && (_MSC_VER >= 1300)) - -#include -#define MAXT __m128 - -#elif defined(__MMX__) - -#include -#define MAXT __m64 - -#elif defined(__ALTIVEC__) - -#define MAXT __vector int - -#else - -#define MAXT long - -#endif - -/* ------------------------------------------------------------------------- */ - -#endif diff --git a/deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-machine.h b/deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-machine.h deleted file mode 100644 index d006bedec..000000000 --- a/deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-machine.h +++ /dev/null @@ -1,49 +0,0 @@ -/* ecrypt-machine.h */ - -/* - * This file is included by 'ecrypt-portable.h'. It allows to override - * the default macros for specific platforms. Please carefully check - * the machine code generated by your compiler (with optimisations - * turned on) before deciding to edit this file. - */ - -/* ------------------------------------------------------------------------- */ - -#if (defined(ECRYPT_DEFAULT_ROT) && !defined(ECRYPT_MACHINE_ROT)) - -#define ECRYPT_MACHINE_ROT - -#if (defined(WIN32) && defined(_MSC_VER)) - -#undef ROTL32 -#undef ROTR32 -#undef ROTL64 -#undef ROTR64 - -#include - -#pragma intrinsic(_lrotl) /* compile rotations "inline" */ -#pragma intrinsic(_lrotr) - -#define ROTL32(v, n) _lrotl(v, n) -#define ROTR32(v, n) _lrotr(v, n) -#define ROTL64(v, n) _rotl64(v, n) -#define ROTR64(v, n) _rotr64(v, n) - -#endif - -#endif - -/* ------------------------------------------------------------------------- */ - -#if (defined(ECRYPT_DEFAULT_SWAP) && !defined(ECRYPT_MACHINE_SWAP)) - -#define ECRYPT_MACHINE_SWAP - -/* - * If you want to overwrite the default swap macros, put it here. And so on. - */ - -#endif - -/* ------------------------------------------------------------------------- */ diff --git a/deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-portable.h b/deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-portable.h deleted file mode 100644 index e5276d846..000000000 --- a/deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-portable.h +++ /dev/null @@ -1,275 +0,0 @@ -/* ecrypt-portable.h */ - -/* - * WARNING: the conversions defined below are implemented as macros, - * and should be used carefully. They should NOT be used with - * parameters which perform some action. E.g., the following two lines - * are not equivalent: - * - * 1) ++x; y = ROTL32(x, n); - * 2) y = ROTL32(++x, n); - */ - -/* - * *** Please do not edit this file. *** - * - * The default macros can be overridden for specific architectures by - * editing 'ecrypt-machine.h'. - */ - -#ifndef ECRYPT_PORTABLE -#define ECRYPT_PORTABLE - -#include "ecrypt-config.h" -#include "ecrypt-types.h" - -/* ------------------------------------------------------------------------- */ - -/* - * The following macros are used to obtain exact-width results. - */ - -#define U8V(v) ((u8)(v) & U8C(0xFF)) -#define U16V(v) ((u16)(v) & U16C(0xFFFF)) -#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) -#define U64V(v) ((u64)(v) & U64C(0xFFFFFFFFFFFFFFFF)) - -/* ------------------------------------------------------------------------- */ - -/* - * The following macros return words with their bits rotated over n - * positions to the left/right. - */ - -#define ECRYPT_DEFAULT_ROT - -#define ROTL8(v, n) \ - (U8V((v) << (n)) | ((v) >> (8 - (n)))) - -#define ROTL16(v, n) \ - (U16V((v) << (n)) | ((v) >> (16 - (n)))) - -#define ROTL32(v, n) \ - (U32V((v) << (n)) | ((v) >> (32 - (n)))) - -#define ROTL64(v, n) \ - (U64V((v) << (n)) | ((v) >> (64 - (n)))) - -#define ROTR8(v, n) ROTL8(v, 8 - (n)) -#define ROTR16(v, n) ROTL16(v, 16 - (n)) -#define ROTR32(v, n) ROTL32(v, 32 - (n)) -#define ROTR64(v, n) ROTL64(v, 64 - (n)) - -#include "ecrypt-machine.h" - -/* ------------------------------------------------------------------------- */ - -/* - * The following macros return a word with bytes in reverse order. - */ - -#define ECRYPT_DEFAULT_SWAP - -#define SWAP16(v) \ - ROTL16(v, 8) - -#define SWAP32(v) \ - ((ROTL32(v, 8) & U32C(0x00FF00FF)) | \ - (ROTL32(v, 24) & U32C(0xFF00FF00))) - -#ifdef ECRYPT_NATIVE64 -#define SWAP64(v) \ - ((ROTL64(v, 8) & U64C(0x000000FF000000FF)) | \ - (ROTL64(v, 24) & U64C(0x0000FF000000FF00)) | \ - (ROTL64(v, 40) & U64C(0x00FF000000FF0000)) | \ - (ROTL64(v, 56) & U64C(0xFF000000FF000000))) -#else -#define SWAP64(v) \ - (((u64)SWAP32(U32V(v)) << 32) | (u64)SWAP32(U32V(v >> 32))) -#endif - -#include "ecrypt-machine.h" - -#define ECRYPT_DEFAULT_WTOW - -#ifdef ECRYPT_LITTLE_ENDIAN -#define U16TO16_LITTLE(v) (v) -#define U32TO32_LITTLE(v) (v) -#define U64TO64_LITTLE(v) (v) - -#define U16TO16_BIG(v) SWAP16(v) -#define U32TO32_BIG(v) SWAP32(v) -#define U64TO64_BIG(v) SWAP64(v) -#endif - -#ifdef ECRYPT_BIG_ENDIAN -#define U16TO16_LITTLE(v) SWAP16(v) -#define U32TO32_LITTLE(v) SWAP32(v) -#define U64TO64_LITTLE(v) SWAP64(v) - -#define U16TO16_BIG(v) (v) -#define U32TO32_BIG(v) (v) -#define U64TO64_BIG(v) (v) -#endif - -#include "ecrypt-machine.h" - -/* - * The following macros load words from an array of bytes with - * different types of endianness, and vice versa. - */ - -#define ECRYPT_DEFAULT_BTOW - -#if (!defined(ECRYPT_UNKNOWN) && defined(ECRYPT_I8T_IS_BYTE)) - -#define U8TO16_LITTLE(p) U16TO16_LITTLE(((u16*)(p))[0]) -#define U8TO32_LITTLE(p) U32TO32_LITTLE(((u32*)(p))[0]) -#define U8TO64_LITTLE(p) U64TO64_LITTLE(((u64*)(p))[0]) - -#define U8TO16_BIG(p) U16TO16_BIG(((u16*)(p))[0]) -#define U8TO32_BIG(p) U32TO32_BIG(((u32*)(p))[0]) -#define U8TO64_BIG(p) U64TO64_BIG(((u64*)(p))[0]) - -#define U16TO8_LITTLE(p, v) (((u16*)(p))[0] = U16TO16_LITTLE(v)) -#define U32TO8_LITTLE(p, v) (((u32*)(p))[0] = U32TO32_LITTLE(v)) -#define U64TO8_LITTLE(p, v) (((u64*)(p))[0] = U64TO64_LITTLE(v)) - -#define U16TO8_BIG(p, v) (((u16*)(p))[0] = U16TO16_BIG(v)) -#define U32TO8_BIG(p, v) (((u32*)(p))[0] = U32TO32_BIG(v)) -#define U64TO8_BIG(p, v) (((u64*)(p))[0] = U64TO64_BIG(v)) - -#else - -#define U8TO16_LITTLE(p) \ - (((u16)((p)[0]) ) | \ - ((u16)((p)[1]) << 8)) - -#define U8TO32_LITTLE(p) \ - (((u32)((p)[0]) ) | \ - ((u32)((p)[1]) << 8) | \ - ((u32)((p)[2]) << 16) | \ - ((u32)((p)[3]) << 24)) - -#ifdef ECRYPT_NATIVE64 -#define U8TO64_LITTLE(p) \ - (((u64)((p)[0]) ) | \ - ((u64)((p)[1]) << 8) | \ - ((u64)((p)[2]) << 16) | \ - ((u64)((p)[3]) << 24) | \ - ((u64)((p)[4]) << 32) | \ - ((u64)((p)[5]) << 40) | \ - ((u64)((p)[6]) << 48) | \ - ((u64)((p)[7]) << 56)) -#else -#define U8TO64_LITTLE(p) \ - ((u64)U8TO32_LITTLE(p) | ((u64)U8TO32_LITTLE((p) + 4) << 32)) -#endif - -#define U8TO16_BIG(p) \ - (((u16)((p)[0]) << 8) | \ - ((u16)((p)[1]) )) - -#define U8TO32_BIG(p) \ - (((u32)((p)[0]) << 24) | \ - ((u32)((p)[1]) << 16) | \ - ((u32)((p)[2]) << 8) | \ - ((u32)((p)[3]) )) - -#ifdef ECRYPT_NATIVE64 -#define U8TO64_BIG(p) \ - (((u64)((p)[0]) << 56) | \ - ((u64)((p)[1]) << 48) | \ - ((u64)((p)[2]) << 40) | \ - ((u64)((p)[3]) << 32) | \ - ((u64)((p)[4]) << 24) | \ - ((u64)((p)[5]) << 16) | \ - ((u64)((p)[6]) << 8) | \ - ((u64)((p)[7]) )) -#else -#define U8TO64_BIG(p) \ - (((u64)U8TO32_BIG(p) << 32) | (u64)U8TO32_BIG((p) + 4)) -#endif - -#define U16TO8_LITTLE(p, v) \ - do { \ - (p)[0] = U8V((v) ); \ - (p)[1] = U8V((v) >> 8); \ - } while (0) - -#define U32TO8_LITTLE(p, v) \ - do { \ - (p)[0] = U8V((v) ); \ - (p)[1] = U8V((v) >> 8); \ - (p)[2] = U8V((v) >> 16); \ - (p)[3] = U8V((v) >> 24); \ - } while (0) - -#ifdef ECRYPT_NATIVE64 -#define U64TO8_LITTLE(p, v) \ - do { \ - (p)[0] = U8V((v) ); \ - (p)[1] = U8V((v) >> 8); \ - (p)[2] = U8V((v) >> 16); \ - (p)[3] = U8V((v) >> 24); \ - (p)[4] = U8V((v) >> 32); \ - (p)[5] = U8V((v) >> 40); \ - (p)[6] = U8V((v) >> 48); \ - (p)[7] = U8V((v) >> 56); \ - } while (0) -#else -#define U64TO8_LITTLE(p, v) \ - do { \ - U32TO8_LITTLE((p), U32V((v) )); \ - U32TO8_LITTLE((p) + 4, U32V((v) >> 32)); \ - } while (0) -#endif - -#define U16TO8_BIG(p, v) \ - do { \ - (p)[0] = U8V((v) ); \ - (p)[1] = U8V((v) >> 8); \ - } while (0) - -#define U32TO8_BIG(p, v) \ - do { \ - (p)[0] = U8V((v) >> 24); \ - (p)[1] = U8V((v) >> 16); \ - (p)[2] = U8V((v) >> 8); \ - (p)[3] = U8V((v) ); \ - } while (0) - -#ifdef ECRYPT_NATIVE64 -#define U64TO8_BIG(p, v) \ - do { \ - (p)[0] = U8V((v) >> 56); \ - (p)[1] = U8V((v) >> 48); \ - (p)[2] = U8V((v) >> 40); \ - (p)[3] = U8V((v) >> 32); \ - (p)[4] = U8V((v) >> 24); \ - (p)[5] = U8V((v) >> 16); \ - (p)[6] = U8V((v) >> 8); \ - (p)[7] = U8V((v) ); \ - } while (0) -#else -#define U64TO8_BIG(p, v) \ - do { \ - U32TO8_BIG((p), U32V((v) >> 32)); \ - U32TO8_BIG((p) + 4, U32V((v) )); \ - } while (0) -#endif - -#endif - -#include "ecrypt-machine.h" - -/* ------------------------------------------------------------------------- */ - -#define AT_LEAST_ONE(n) (((n) < 1) ? 1 : (n)) - -#define ALIGN(t, v, n) \ - union { t b[n]; MAXT l[AT_LEAST_ONE(n * sizeof(t) / sizeof(MAXT))]; } v - -/* ------------------------------------------------------------------------- */ - -#endif diff --git a/deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-sync.h b/deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-sync.h deleted file mode 100644 index efce9dde2..000000000 --- a/deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-sync.h +++ /dev/null @@ -1,290 +0,0 @@ -#define ECRYPT_VARIANT 1 -#define ECRYPT_API -/* ecrypt-sync.h */ - -/* - * Header file for synchronous stream ciphers without authentication - * mechanism. - * - * *** Please only edit parts marked with "[edit]". *** - */ - -#ifndef ECRYPT_SYNC -#define ECRYPT_SYNC - -#include "ecrypt-types.h" - -/* ------------------------------------------------------------------------- */ - -/* Cipher parameters */ - -/* - * The name of your cipher. - */ -#define ECRYPT_NAME "ChaCha20" -#define ECRYPT_PROFILE "_____" - -/* - * Specify which key and IV sizes are supported by your cipher. A user - * should be able to enumerate the supported sizes by running the - * following code: - * - * for (i = 0; ECRYPT_KEYSIZE(i) <= ECRYPT_MAXKEYSIZE; ++i) - * { - * keysize = ECRYPT_KEYSIZE(i); - * - * ... - * } - * - * All sizes are in bits. - */ - -#define ECRYPT_MAXKEYSIZE 256 /* [edit] */ -#define ECRYPT_KEYSIZE(i) (128 + (i)*128) /* [edit] */ - -#define ECRYPT_MAXIVSIZE 64 /* [edit] */ -#define ECRYPT_IVSIZE(i) (64 + (i)*64) /* [edit] */ - -/* ------------------------------------------------------------------------- */ - -/* Data structures */ - -/* - * ECRYPT_ctx is the structure containing the representation of the - * internal state of your cipher. - */ - -typedef struct -{ - u32 input[16]; /* could be compressed */ - /* - * [edit] - * - * Put here all state variable needed during the encryption process. - */ -} ECRYPT_ctx; - -/* ------------------------------------------------------------------------- */ - -/* Mandatory functions */ - -/* - * Key and message independent initialization. This function will be - * called once when the program starts (e.g., to build expanded S-box - * tables). - */ -void ECRYPT_init(void); - -/* - * Key setup. It is the user's responsibility to select the values of - * keysize and ivsize from the set of supported values specified - * above. - */ -void ECRYPT_keysetup( - ECRYPT_ctx* ctx, - const u8* key, - u32 keysize, /* Key size in bits. */ - u32 ivsize); /* IV size in bits. */ - -/* - * IV setup. After having called ECRYPT_keysetup(), the user is - * allowed to call ECRYPT_ivsetup() different times in order to - * encrypt/decrypt different messages with the same key but different - * IV's. ECRYPT_ivsetup() also sets block counter to zero. - */ -void ECRYPT_ivsetup( - ECRYPT_ctx* ctx, - const u8* iv); - -/* - * Block counter setup. It is used only for special purposes, - * since block counter is usually initialized with ECRYPT_ivsetup. - * ECRYPT_ctrsetup has to be called after ECRYPT_ivsetup. - */ -void ECRYPT_ctrsetup( - ECRYPT_ctx* ctx, - const u8* ctr); - -/* - * Encryption/decryption of arbitrary length messages. - * - * For efficiency reasons, the API provides two types of - * encrypt/decrypt functions. The ECRYPT_encrypt_bytes() function - * (declared here) encrypts byte strings of arbitrary length, while - * the ECRYPT_encrypt_blocks() function (defined later) only accepts - * lengths which are multiples of ECRYPT_BLOCKLENGTH. - * - * The user is allowed to make multiple calls to - * ECRYPT_encrypt_blocks() to incrementally encrypt a long message, - * but he is NOT allowed to make additional encryption calls once he - * has called ECRYPT_encrypt_bytes() (unless he starts a new message - * of course). For example, this sequence of calls is acceptable: - * - * ECRYPT_keysetup(); - * - * ECRYPT_ivsetup(); - * ECRYPT_encrypt_blocks(); - * ECRYPT_encrypt_blocks(); - * ECRYPT_encrypt_bytes(); - * - * ECRYPT_ivsetup(); - * ECRYPT_encrypt_blocks(); - * ECRYPT_encrypt_blocks(); - * - * ECRYPT_ivsetup(); - * ECRYPT_encrypt_bytes(); - * - * The following sequence is not: - * - * ECRYPT_keysetup(); - * ECRYPT_ivsetup(); - * ECRYPT_encrypt_blocks(); - * ECRYPT_encrypt_bytes(); - * ECRYPT_encrypt_blocks(); - */ - -void ECRYPT_encrypt_bytes( - ECRYPT_ctx* ctx, - const u8* plaintext, - u8* ciphertext, - u32 msglen); /* Message length in bytes. */ - -void ECRYPT_decrypt_bytes( - ECRYPT_ctx* ctx, - const u8* ciphertext, - u8* plaintext, - u32 msglen); /* Message length in bytes. */ - -/* ------------------------------------------------------------------------- */ - -/* Optional features */ - -/* - * For testing purposes it can sometimes be useful to have a function - * which immediately generates keystream without having to provide it - * with a zero plaintext. If your cipher cannot provide this function - * (e.g., because it is not strictly a synchronous cipher), please - * reset the ECRYPT_GENERATES_KEYSTREAM flag. - */ - -#define ECRYPT_GENERATES_KEYSTREAM -#ifdef ECRYPT_GENERATES_KEYSTREAM - -void ECRYPT_keystream_bytes( - ECRYPT_ctx* ctx, - u8* keystream, - u32 length); /* Length of keystream in bytes. */ - -#endif - -/* ------------------------------------------------------------------------- */ - -/* Optional optimizations */ - -/* - * By default, the functions in this section are implemented using - * calls to functions declared above. However, you might want to - * implement them differently for performance reasons. - */ - -/* - * All-in-one encryption/decryption of (short) packets. - * - * The default definitions of these functions can be found in - * "ecrypt-sync.c". If you want to implement them differently, please - * undef the ECRYPT_USES_DEFAULT_ALL_IN_ONE flag. - */ -#define ECRYPT_USES_DEFAULT_ALL_IN_ONE /* [edit] */ - -void ECRYPT_encrypt_packet( - ECRYPT_ctx* ctx, - const u8* iv, - const u8* plaintext, - u8* ciphertext, - u32 msglen); - -void ECRYPT_decrypt_packet( - ECRYPT_ctx* ctx, - const u8* iv, - const u8* ciphertext, - u8* plaintext, - u32 msglen); - -/* - * Encryption/decryption of blocks. - * - * By default, these functions are defined as macros. If you want to - * provide a different implementation, please undef the - * ECRYPT_USES_DEFAULT_BLOCK_MACROS flag and implement the functions - * declared below. - */ - -#define ECRYPT_BLOCKLENGTH 64 /* [edit] */ - -#define ECRYPT_USES_DEFAULT_BLOCK_MACROS /* [edit] */ -#ifdef ECRYPT_USES_DEFAULT_BLOCK_MACROS - -#define ECRYPT_encrypt_blocks(ctx, plaintext, ciphertext, blocks) \ - ECRYPT_encrypt_bytes(ctx, plaintext, ciphertext, \ - (blocks) * ECRYPT_BLOCKLENGTH) - -#define ECRYPT_decrypt_blocks(ctx, ciphertext, plaintext, blocks) \ - ECRYPT_decrypt_bytes(ctx, ciphertext, plaintext, \ - (blocks) * ECRYPT_BLOCKLENGTH) - -#ifdef ECRYPT_GENERATES_KEYSTREAM - -#define ECRYPT_keystream_blocks(ctx, keystream, blocks) \ - ECRYPT_keystream_bytes(ctx, keystream, \ - (blocks) * ECRYPT_BLOCKLENGTH) - -#endif - -#else - -void ECRYPT_encrypt_blocks( - ECRYPT_ctx* ctx, - const u8* plaintext, - u8* ciphertext, - u32 blocks); /* Message length in blocks. */ - -void ECRYPT_decrypt_blocks( - ECRYPT_ctx* ctx, - const u8* ciphertext, - u8* plaintext, - u32 blocks); /* Message length in blocks. */ - -#ifdef ECRYPT_GENERATES_KEYSTREAM - -void ECRYPT_keystream_blocks( - ECRYPT_ctx* ctx, - const u8* keystream, - u32 blocks); /* Keystream length in blocks. */ - -#endif - -#endif - -/* - * If your cipher can be implemented in different ways, you can use - * the ECRYPT_VARIANT parameter to allow the user to choose between - * them at compile time (e.g., gcc -DECRYPT_VARIANT=3 ...). Please - * only use this possibility if you really think it could make a - * significant difference and keep the number of variants - * (ECRYPT_MAXVARIANT) as small as possible (definitely not more than - * 10). Note also that all variants should have exactly the same - * external interface (i.e., the same ECRYPT_BLOCKLENGTH, etc.). - */ -#define ECRYPT_MAXVARIANT 1 /* [edit] */ - -#ifndef ECRYPT_VARIANT -#define ECRYPT_VARIANT 1 -#endif - -#if (ECRYPT_VARIANT > ECRYPT_MAXVARIANT) -#error this variant does not exist -#endif - -/* ------------------------------------------------------------------------- */ - -#endif diff --git a/deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-types.h b/deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-types.h deleted file mode 100644 index e608e220a..000000000 --- a/deps/crypto/trezor-crypto/chacha20poly1305/ecrypt-types.h +++ /dev/null @@ -1,53 +0,0 @@ -/* ecrypt-types.h */ - -/* - * *** Please do not edit this file. *** - * - * The default macros can be overridden for specific architectures by - * editing 'ecrypt-machine.h'. - */ - -#ifndef ECRYPT_TYPES -#define ECRYPT_TYPES - -#include "ecrypt-config.h" - -/* ------------------------------------------------------------------------- */ - -/* - * The following types are defined (if available): - * - * u8: unsigned integer type, at least 8 bits - * u16: unsigned integer type, at least 16 bits - * u32: unsigned integer type, at least 32 bits - * u64: unsigned integer type, at least 64 bits - * - * s8, s16, s32, s64 -> signed counterparts of u8, u16, u32, u64 - * - * The selection of minimum-width integer types is taken care of by - * 'ecrypt-config.h'. Note: to enable 64-bit types on 32-bit - * compilers, it might be necessary to switch from ISO C90 mode to ISO - * C99 mode (e.g., gcc -std=c99). - */ - -#ifdef I8T -typedef signed I8T s8; -typedef unsigned I8T u8; -#endif - -#ifdef I16T -typedef signed I16T s16; -typedef unsigned I16T u16; -#endif - -#ifdef I32T -typedef signed I32T s32; -typedef unsigned I32T u32; -#endif - -#ifdef I64T -typedef signed I64T s64; -typedef unsigned I64T u64; -#endif - -#endif diff --git a/deps/crypto/trezor-crypto/chacha20poly1305/poly1305-donna-32.h b/deps/crypto/trezor-crypto/chacha20poly1305/poly1305-donna-32.h deleted file mode 100644 index eab8acdbf..000000000 --- a/deps/crypto/trezor-crypto/chacha20poly1305/poly1305-donna-32.h +++ /dev/null @@ -1,218 +0,0 @@ -/* - poly1305 implementation using 32 bit * 32 bit = 64 bit multiplication and 64 bit addition -*/ - -#if defined(_MSC_VER) - #define POLY1305_NOINLINE __declspec(noinline) -#elif defined(__GNUC__) - #define POLY1305_NOINLINE __attribute__((noinline)) -#else - #define POLY1305_NOINLINE -#endif - -#define poly1305_block_size 16 - -/* 17 + sizeof(size_t) + 14*sizeof(unsigned long) */ -typedef struct poly1305_state_internal_t { - unsigned long r[5]; - unsigned long h[5]; - unsigned long pad[4]; - size_t leftover; - unsigned char buffer[poly1305_block_size]; - unsigned char final; -} poly1305_state_internal_t; - -/* interpret four 8 bit unsigned integers as a 32 bit unsigned integer in little endian */ -static unsigned long -U8TO32(const unsigned char *p) { - return - (((unsigned long)(p[0] & 0xff) ) | - ((unsigned long)(p[1] & 0xff) << 8) | - ((unsigned long)(p[2] & 0xff) << 16) | - ((unsigned long)(p[3] & 0xff) << 24)); -} - -/* store a 32 bit unsigned integer as four 8 bit unsigned integers in little endian */ -static void -U32TO8(unsigned char *p, unsigned long v) { - p[0] = (v ) & 0xff; - p[1] = (v >> 8) & 0xff; - p[2] = (v >> 16) & 0xff; - p[3] = (v >> 24) & 0xff; -} - -void -poly1305_init(poly1305_context *ctx, const unsigned char key[32]) { - poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; - - /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ - st->r[0] = (U8TO32(&key[ 0]) ) & 0x3ffffff; - st->r[1] = (U8TO32(&key[ 3]) >> 2) & 0x3ffff03; - st->r[2] = (U8TO32(&key[ 6]) >> 4) & 0x3ffc0ff; - st->r[3] = (U8TO32(&key[ 9]) >> 6) & 0x3f03fff; - st->r[4] = (U8TO32(&key[12]) >> 8) & 0x00fffff; - - /* h = 0 */ - st->h[0] = 0; - st->h[1] = 0; - st->h[2] = 0; - st->h[3] = 0; - st->h[4] = 0; - - /* save pad for later */ - st->pad[0] = U8TO32(&key[16]); - st->pad[1] = U8TO32(&key[20]); - st->pad[2] = U8TO32(&key[24]); - st->pad[3] = U8TO32(&key[28]); - - st->leftover = 0; - st->final = 0; -} - -static void -poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t bytes) { - const unsigned long hibit = (st->final) ? 0 : (1UL << 24); /* 1 << 128 */ - unsigned long r0,r1,r2,r3,r4; - unsigned long s1,s2,s3,s4; - unsigned long h0,h1,h2,h3,h4; - unsigned long long d0,d1,d2,d3,d4; - unsigned long c; - - r0 = st->r[0]; - r1 = st->r[1]; - r2 = st->r[2]; - r3 = st->r[3]; - r4 = st->r[4]; - - s1 = r1 * 5; - s2 = r2 * 5; - s3 = r3 * 5; - s4 = r4 * 5; - - h0 = st->h[0]; - h1 = st->h[1]; - h2 = st->h[2]; - h3 = st->h[3]; - h4 = st->h[4]; - - while (bytes >= poly1305_block_size) { - /* h += m[i] */ - h0 += (U8TO32(m+ 0) ) & 0x3ffffff; - h1 += (U8TO32(m+ 3) >> 2) & 0x3ffffff; - h2 += (U8TO32(m+ 6) >> 4) & 0x3ffffff; - h3 += (U8TO32(m+ 9) >> 6) & 0x3ffffff; - h4 += (U8TO32(m+12) >> 8) | hibit; - - /* h *= r */ - d0 = ((unsigned long long)h0 * r0) + ((unsigned long long)h1 * s4) + ((unsigned long long)h2 * s3) + ((unsigned long long)h3 * s2) + ((unsigned long long)h4 * s1); - d1 = ((unsigned long long)h0 * r1) + ((unsigned long long)h1 * r0) + ((unsigned long long)h2 * s4) + ((unsigned long long)h3 * s3) + ((unsigned long long)h4 * s2); - d2 = ((unsigned long long)h0 * r2) + ((unsigned long long)h1 * r1) + ((unsigned long long)h2 * r0) + ((unsigned long long)h3 * s4) + ((unsigned long long)h4 * s3); - d3 = ((unsigned long long)h0 * r3) + ((unsigned long long)h1 * r2) + ((unsigned long long)h2 * r1) + ((unsigned long long)h3 * r0) + ((unsigned long long)h4 * s4); - d4 = ((unsigned long long)h0 * r4) + ((unsigned long long)h1 * r3) + ((unsigned long long)h2 * r2) + ((unsigned long long)h3 * r1) + ((unsigned long long)h4 * r0); - - /* (partial) h %= p */ - c = (unsigned long)(d0 >> 26); h0 = (unsigned long)d0 & 0x3ffffff; - d1 += c; c = (unsigned long)(d1 >> 26); h1 = (unsigned long)d1 & 0x3ffffff; - d2 += c; c = (unsigned long)(d2 >> 26); h2 = (unsigned long)d2 & 0x3ffffff; - d3 += c; c = (unsigned long)(d3 >> 26); h3 = (unsigned long)d3 & 0x3ffffff; - d4 += c; c = (unsigned long)(d4 >> 26); h4 = (unsigned long)d4 & 0x3ffffff; - h0 += c * 5; c = (h0 >> 26); h0 = h0 & 0x3ffffff; - h1 += c; - - m += poly1305_block_size; - bytes -= poly1305_block_size; - } - - st->h[0] = h0; - st->h[1] = h1; - st->h[2] = h2; - st->h[3] = h3; - st->h[4] = h4; -} - -POLY1305_NOINLINE void -poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) { - poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; - unsigned long h0,h1,h2,h3,h4,c; - unsigned long g0,g1,g2,g3,g4; - unsigned long long f; - unsigned long mask; - - /* process the remaining block */ - if (st->leftover) { - size_t i = st->leftover; - st->buffer[i++] = 1; - for (; i < poly1305_block_size; i++) - st->buffer[i] = 0; - st->final = 1; - poly1305_blocks(st, st->buffer, poly1305_block_size); - } - - /* fully carry h */ - h0 = st->h[0]; - h1 = st->h[1]; - h2 = st->h[2]; - h3 = st->h[3]; - h4 = st->h[4]; - - c = h1 >> 26; h1 = h1 & 0x3ffffff; - h2 += c; c = h2 >> 26; h2 = h2 & 0x3ffffff; - h3 += c; c = h3 >> 26; h3 = h3 & 0x3ffffff; - h4 += c; c = h4 >> 26; h4 = h4 & 0x3ffffff; - h0 += c * 5; c = h0 >> 26; h0 = h0 & 0x3ffffff; - h1 += c; - - /* compute h + -p */ - g0 = h0 + 5; c = g0 >> 26; g0 &= 0x3ffffff; - g1 = h1 + c; c = g1 >> 26; g1 &= 0x3ffffff; - g2 = h2 + c; c = g2 >> 26; g2 &= 0x3ffffff; - g3 = h3 + c; c = g3 >> 26; g3 &= 0x3ffffff; - g4 = h4 + c - (1UL << 26); - - /* select h if h < p, or h + -p if h >= p */ - mask = (g4 >> ((sizeof(unsigned long) * 8) - 1)) - 1; - g0 &= mask; - g1 &= mask; - g2 &= mask; - g3 &= mask; - g4 &= mask; - mask = ~mask; - h0 = (h0 & mask) | g0; - h1 = (h1 & mask) | g1; - h2 = (h2 & mask) | g2; - h3 = (h3 & mask) | g3; - h4 = (h4 & mask) | g4; - - /* h = h % (2^128) */ - h0 = ((h0 ) | (h1 << 26)) & 0xffffffff; - h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff; - h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff; - h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff; - - /* mac = (h + pad) % (2^128) */ - f = (unsigned long long)h0 + st->pad[0] ; h0 = (unsigned long)f; - f = (unsigned long long)h1 + st->pad[1] + (f >> 32); h1 = (unsigned long)f; - f = (unsigned long long)h2 + st->pad[2] + (f >> 32); h2 = (unsigned long)f; - f = (unsigned long long)h3 + st->pad[3] + (f >> 32); h3 = (unsigned long)f; - - U32TO8(mac + 0, h0); - U32TO8(mac + 4, h1); - U32TO8(mac + 8, h2); - U32TO8(mac + 12, h3); - - /* zero out the state */ - st->h[0] = 0; - st->h[1] = 0; - st->h[2] = 0; - st->h[3] = 0; - st->h[4] = 0; - st->r[0] = 0; - st->r[1] = 0; - st->r[2] = 0; - st->r[3] = 0; - st->r[4] = 0; - st->pad[0] = 0; - st->pad[1] = 0; - st->pad[2] = 0; - st->pad[3] = 0; -} diff --git a/deps/crypto/trezor-crypto/chacha20poly1305/poly1305-donna.c b/deps/crypto/trezor-crypto/chacha20poly1305/poly1305-donna.c deleted file mode 100644 index bb6e7a3ec..000000000 --- a/deps/crypto/trezor-crypto/chacha20poly1305/poly1305-donna.c +++ /dev/null @@ -1,179 +0,0 @@ -#include "poly1305-donna.h" -#include "poly1305-donna-32.h" - -void -poly1305_update(poly1305_context *ctx, const unsigned char *m, size_t bytes) { - poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; - size_t i = 0; - - /* handle leftover */ - if (st->leftover) { - size_t want = (poly1305_block_size - st->leftover); - if (want > bytes) - want = bytes; - for (i = 0; i < want; i++) - st->buffer[st->leftover + i] = m[i]; - bytes -= want; - m += want; - st->leftover += want; - if (st->leftover < poly1305_block_size) - return; - poly1305_blocks(st, st->buffer, poly1305_block_size); - st->leftover = 0; - } - - /* process full blocks */ - if (bytes >= poly1305_block_size) { - size_t want = (bytes & ~(poly1305_block_size - 1)); - poly1305_blocks(st, m, want); - m += want; - bytes -= want; - } - - /* store leftover */ - if (bytes) { - for (i = 0; i < bytes; i++) - st->buffer[st->leftover + i] = m[i]; - st->leftover += bytes; - } -} - -void -poly1305_auth(unsigned char mac[16], const unsigned char *m, size_t bytes, const unsigned char key[32]) { - poly1305_context ctx = {0}; - poly1305_init(&ctx, key); - poly1305_update(&ctx, m, bytes); - poly1305_finish(&ctx, mac); -} - -int -poly1305_verify(const unsigned char mac1[16], const unsigned char mac2[16]) { - size_t i = 0; - unsigned int dif = 0; - for (i = 0; i < 16; i++) - dif |= (mac1[i] ^ mac2[i]); - dif = (dif - 1) >> ((sizeof(unsigned int) * 8) - 1); - return (dif & 1); -} - - -/* test a few basic operations */ -int -poly1305_power_on_self_test(void) { - /* example from nacl */ - static const unsigned char nacl_key[32] = { - 0xee,0xa6,0xa7,0x25,0x1c,0x1e,0x72,0x91, - 0x6d,0x11,0xc2,0xcb,0x21,0x4d,0x3c,0x25, - 0x25,0x39,0x12,0x1d,0x8e,0x23,0x4e,0x65, - 0x2d,0x65,0x1f,0xa4,0xc8,0xcf,0xf8,0x80, - }; - - static const unsigned char nacl_msg[131] = { - 0x8e,0x99,0x3b,0x9f,0x48,0x68,0x12,0x73, - 0xc2,0x96,0x50,0xba,0x32,0xfc,0x76,0xce, - 0x48,0x33,0x2e,0xa7,0x16,0x4d,0x96,0xa4, - 0x47,0x6f,0xb8,0xc5,0x31,0xa1,0x18,0x6a, - 0xc0,0xdf,0xc1,0x7c,0x98,0xdc,0xe8,0x7b, - 0x4d,0xa7,0xf0,0x11,0xec,0x48,0xc9,0x72, - 0x71,0xd2,0xc2,0x0f,0x9b,0x92,0x8f,0xe2, - 0x27,0x0d,0x6f,0xb8,0x63,0xd5,0x17,0x38, - 0xb4,0x8e,0xee,0xe3,0x14,0xa7,0xcc,0x8a, - 0xb9,0x32,0x16,0x45,0x48,0xe5,0x26,0xae, - 0x90,0x22,0x43,0x68,0x51,0x7a,0xcf,0xea, - 0xbd,0x6b,0xb3,0x73,0x2b,0xc0,0xe9,0xda, - 0x99,0x83,0x2b,0x61,0xca,0x01,0xb6,0xde, - 0x56,0x24,0x4a,0x9e,0x88,0xd5,0xf9,0xb3, - 0x79,0x73,0xf6,0x22,0xa4,0x3d,0x14,0xa6, - 0x59,0x9b,0x1f,0x65,0x4c,0xb4,0x5a,0x74, - 0xe3,0x55,0xa5 - }; - - static const unsigned char nacl_mac[16] = { - 0xf3,0xff,0xc7,0x70,0x3f,0x94,0x00,0xe5, - 0x2a,0x7d,0xfb,0x4b,0x3d,0x33,0x05,0xd9 - }; - - /* generates a final value of (2^130 - 2) == 3 */ - static const unsigned char wrap_key[32] = { - 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - }; - - static const unsigned char wrap_msg[16] = { - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff - }; - - static const unsigned char wrap_mac[16] = { - 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - }; - - /* - mac of the macs of messages of length 0 to 256, where the key and messages - have all their values set to the length - */ - static const unsigned char total_key[32] = { - 0x01,0x02,0x03,0x04,0x05,0x06,0x07, - 0xff,0xfe,0xfd,0xfc,0xfb,0xfa,0xf9, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff - }; - - static const unsigned char total_mac[16] = { - 0x64,0xaf,0xe2,0xe8,0xd6,0xad,0x7b,0xbd, - 0xd2,0x87,0xf9,0x7c,0x44,0x62,0x3d,0x39 - }; - - poly1305_context ctx = {0}; - poly1305_context total_ctx = {0}; - unsigned char all_key[32] = {0}; - unsigned char all_msg[256] = {0}; - unsigned char mac[16] = {0}; - size_t i = 0, j = 0; - int result = 1; - - for (i = 0; i < sizeof(mac); i++) - mac[i] = 0; - poly1305_auth(mac, nacl_msg, sizeof(nacl_msg), nacl_key); - result &= poly1305_verify(nacl_mac, mac); - - for (i = 0; i < sizeof(mac); i++) - mac[i] = 0; - poly1305_init(&ctx, nacl_key); - poly1305_update(&ctx, nacl_msg + 0, 32); - poly1305_update(&ctx, nacl_msg + 32, 64); - poly1305_update(&ctx, nacl_msg + 96, 16); - poly1305_update(&ctx, nacl_msg + 112, 8); - poly1305_update(&ctx, nacl_msg + 120, 4); - poly1305_update(&ctx, nacl_msg + 124, 2); - poly1305_update(&ctx, nacl_msg + 126, 1); - poly1305_update(&ctx, nacl_msg + 127, 1); - poly1305_update(&ctx, nacl_msg + 128, 1); - poly1305_update(&ctx, nacl_msg + 129, 1); - poly1305_update(&ctx, nacl_msg + 130, 1); - poly1305_finish(&ctx, mac); - result &= poly1305_verify(nacl_mac, mac); - - for (i = 0; i < sizeof(mac); i++) - mac[i] = 0; - poly1305_auth(mac, wrap_msg, sizeof(wrap_msg), wrap_key); - result &= poly1305_verify(wrap_mac, mac); - - poly1305_init(&total_ctx, total_key); - for (i = 0; i < 256; i++) { - /* set key and message to 'i,i,i..' */ - for (j = 0; j < sizeof(all_key); j++) - all_key[j] = i; - for (j = 0; j < i; j++) - all_msg[j] = i; - poly1305_auth(mac, all_msg, i, all_key); - poly1305_update(&total_ctx, mac, 16); - } - poly1305_finish(&total_ctx, mac); - result &= poly1305_verify(total_mac, mac); - - return result; -} diff --git a/deps/crypto/trezor-crypto/chacha20poly1305/poly1305-donna.h b/deps/crypto/trezor-crypto/chacha20poly1305/poly1305-donna.h deleted file mode 100644 index 39b7a8f5e..000000000 --- a/deps/crypto/trezor-crypto/chacha20poly1305/poly1305-donna.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef POLY1305_DONNA_H -#define POLY1305_DONNA_H - -#include - -typedef struct poly1305_context { - size_t aligner; - unsigned char opaque[136]; -} poly1305_context; - -void poly1305_init(poly1305_context *ctx, const unsigned char key[32]); -void poly1305_update(poly1305_context *ctx, const unsigned char *m, size_t bytes); -void poly1305_finish(poly1305_context *ctx, unsigned char mac[16]); -void poly1305_auth(unsigned char mac[16], const unsigned char *m, size_t bytes, const unsigned char key[32]); - -int poly1305_verify(const unsigned char mac1[16], const unsigned char mac2[16]); -int poly1305_power_on_self_test(void); - -#endif /* POLY1305_DONNA_H */ diff --git a/deps/crypto/trezor-crypto/chacha20poly1305/rfc7539.c b/deps/crypto/trezor-crypto/chacha20poly1305/rfc7539.c deleted file mode 100644 index 94e5f0b23..000000000 --- a/deps/crypto/trezor-crypto/chacha20poly1305/rfc7539.c +++ /dev/null @@ -1,48 +0,0 @@ -// Implementation of the ChaCha20 + Poly1305 AEAD construction -// as described in RFC 7539. - -#include -#include "rfc7539.h" -#include "ecrypt-portable.h" - -// Initialize the ChaCha20 + Poly1305 context for encryption or decryption -// using a 32 byte key and 12 byte nonce as in the RFC 7539 style. -void rfc7539_init(chacha20poly1305_ctx *ctx, const uint8_t key[32], const uint8_t nonce[12]) { - unsigned char block0[64] = {0}; - - ECRYPT_keysetup(&ctx->chacha20, key, 256, 16); - ctx->chacha20.input[12] = 0; - ctx->chacha20.input[13] = U8TO32_LITTLE(nonce + 0); - ctx->chacha20.input[14] = U8TO32_LITTLE(nonce + 4); - ctx->chacha20.input[15] = U8TO32_LITTLE(nonce + 8); - - // Encrypt 64 bytes of zeros and use the first 32 bytes - // as the Poly1305 key. - ECRYPT_encrypt_bytes(&ctx->chacha20, block0, block0, 64); - poly1305_init(&ctx->poly1305, block0); -} - -// Include authenticated data in the Poly1305 MAC using the RFC 7539 -// style with 16 byte padding. This must only be called once and prior -// to encryption or decryption. -void rfc7539_auth(chacha20poly1305_ctx *ctx, const uint8_t *in, size_t n) { - uint8_t padding[16] = {0}; - poly1305_update(&ctx->poly1305, in, n); - if (n % 16 != 0) - poly1305_update(&ctx->poly1305, padding, 16 - n%16); -} - -// Compute RFC 7539-style Poly1305 MAC. -void rfc7539_finish(chacha20poly1305_ctx *ctx, int64_t alen, int64_t plen, uint8_t mac[16]) { - uint8_t padding[16] = {0}; - uint8_t lengths[16] = {0}; - - memcpy(lengths, &alen, sizeof(int64_t)); - memcpy(lengths + 8, &plen, sizeof(int64_t)); - - if (plen % 16 != 0) - poly1305_update(&ctx->poly1305, padding, 16 - plen%16); - poly1305_update(&ctx->poly1305, lengths, 16); - - poly1305_finish(&ctx->poly1305, mac); -} diff --git a/deps/crypto/trezor-crypto/chacha20poly1305/rfc7539.h b/deps/crypto/trezor-crypto/chacha20poly1305/rfc7539.h deleted file mode 100644 index 75e3d1d7e..000000000 --- a/deps/crypto/trezor-crypto/chacha20poly1305/rfc7539.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef RFC7539_H -#define RFC7539_H - -#include "chacha20poly1305.h" - -void rfc7539_init(chacha20poly1305_ctx *ctx, const uint8_t key[32], const uint8_t nonce[12]); -void rfc7539_auth(chacha20poly1305_ctx *ctx, const uint8_t *in, size_t n); -void rfc7539_finish(chacha20poly1305_ctx *ctx, int64_t alen, int64_t plen, uint8_t mac[16]); - -#endif // RFC7539_H diff --git a/deps/crypto/trezor-crypto/chacha_drbg.c b/deps/crypto/trezor-crypto/chacha_drbg.c deleted file mode 100644 index 663b1a355..000000000 --- a/deps/crypto/trezor-crypto/chacha_drbg.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - * This file is part of the Trezor project, https://trezor.io/ - * - * Copyright (c) SatoshiLabs - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "chacha_drbg.h" - -#include -#include -#include - -#include "chacha20poly1305/ecrypt-portable.h" -#include "memzero.h" -#include "sha2.h" - -#define CHACHA_DRBG_KEY_LENGTH 32 -#define CHACHA_DRBG_COUNTER_LENGTH 8 -#define CHACHA_DRBG_IV_LENGTH 8 -#define CHACHA_DRBG_SEED_LENGTH \ - (CHACHA_DRBG_KEY_LENGTH + CHACHA_DRBG_COUNTER_LENGTH + CHACHA_DRBG_IV_LENGTH) - -#define MAX(a, b) (a) > (b) ? (a) : (b) - -static void derivation_function(const uint8_t *input1, size_t input1_length, - const uint8_t *input2, size_t input2_length, - uint8_t *output, size_t output_length) { - // Implementation of Hash_df from NIST SP 800-90A - uint32_t block_count = (output_length - 1) / SHA256_DIGEST_LENGTH + 1; - size_t partial_block_length = output_length % SHA256_DIGEST_LENGTH; - assert(block_count <= 255); - - uint32_t output_length_bits = output_length * 8; -#if BYTE_ORDER == LITTLE_ENDIAN - REVERSE32(output_length_bits, output_length_bits); -#endif - - SHA256_CTX ctx = {0}; - - for (uint8_t counter = 1; counter <= block_count; counter++) { - sha256_Init(&ctx); - sha256_Update(&ctx, &counter, sizeof(counter)); - sha256_Update(&ctx, (uint8_t *)&output_length_bits, - sizeof(output_length_bits)); - sha256_Update(&ctx, input1, input1_length); - sha256_Update(&ctx, input2, input2_length); - - if (counter != block_count || partial_block_length == 0) { - sha256_Final(&ctx, output); - output += SHA256_DIGEST_LENGTH; - } else { // last block is partial - uint8_t digest[SHA256_DIGEST_LENGTH] = {0}; - sha256_Final(&ctx, digest); - memcpy(output, digest, partial_block_length); - memzero(digest, sizeof(digest)); - } - } - - memzero(&ctx, sizeof(ctx)); -} - -void chacha_drbg_init(CHACHA_DRBG_CTX *ctx, const uint8_t *entropy, - size_t entropy_length, const uint8_t *nonce, - size_t nonce_length) { - uint8_t buffer[MAX(CHACHA_DRBG_KEY_LENGTH, CHACHA_DRBG_IV_LENGTH)] = {0}; - ECRYPT_keysetup(&ctx->chacha_ctx, buffer, CHACHA_DRBG_KEY_LENGTH * 8, - CHACHA_DRBG_IV_LENGTH * 8); - ECRYPT_ivsetup(&ctx->chacha_ctx, buffer); - - chacha_drbg_reseed(ctx, entropy, entropy_length, nonce, nonce_length); -} - -static void chacha_drbg_update(CHACHA_DRBG_CTX *ctx, - const uint8_t data[CHACHA_DRBG_SEED_LENGTH]) { - uint8_t seed[CHACHA_DRBG_SEED_LENGTH] = {0}; - - if (data) - ECRYPT_encrypt_bytes(&ctx->chacha_ctx, data, seed, CHACHA_DRBG_SEED_LENGTH); - else - ECRYPT_keystream_bytes(&ctx->chacha_ctx, seed, CHACHA_DRBG_SEED_LENGTH); - - ECRYPT_keysetup(&ctx->chacha_ctx, seed, CHACHA_DRBG_KEY_LENGTH * 8, - CHACHA_DRBG_IV_LENGTH * 8); - - ECRYPT_ivsetup(&ctx->chacha_ctx, - seed + CHACHA_DRBG_KEY_LENGTH + CHACHA_DRBG_COUNTER_LENGTH); - - ECRYPT_ctrsetup(&ctx->chacha_ctx, seed + CHACHA_DRBG_KEY_LENGTH); - - memzero(seed, sizeof(seed)); -} - -void chacha_drbg_generate(CHACHA_DRBG_CTX *ctx, uint8_t *output, - size_t output_length) { - assert(output_length < 65536); - assert(ctx->reseed_counter + 1 != 0); - - ECRYPT_keystream_bytes(&ctx->chacha_ctx, output, output_length); - chacha_drbg_update(ctx, NULL); - ctx->reseed_counter++; -} - -void chacha_drbg_reseed(CHACHA_DRBG_CTX *ctx, const uint8_t *entropy, - size_t entropy_length, const uint8_t *additional_input, - size_t additional_input_length) { - uint8_t seed[CHACHA_DRBG_SEED_LENGTH] = {0}; - derivation_function(entropy, entropy_length, additional_input, - additional_input_length, seed, sizeof(seed)); - chacha_drbg_update(ctx, seed); - memzero(seed, sizeof(seed)); - - ctx->reseed_counter = 1; -} diff --git a/deps/crypto/trezor-crypto/chacha_drbg.h b/deps/crypto/trezor-crypto/chacha_drbg.h deleted file mode 100644 index 83e2d0b42..000000000 --- a/deps/crypto/trezor-crypto/chacha_drbg.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * This file is part of the Trezor project, https://trezor.io/ - * - * Copyright (c) SatoshiLabs - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef __CHACHA_DRBG__ -#define __CHACHA_DRBG__ - -#include "chacha20poly1305/chacha20poly1305.h" -#include "sha2.h" - -// A very fast deterministic random bit generator based on CTR_DRBG in NIST SP -// 800-90A. Chacha is used instead of a block cipher in the counter mode, SHA256 -// is used as a derivation function. The highest supported security strength is -// at least 256 bits. Reseeding is left up to caller. - -// Length of inputs of chacha_drbg_init (entropy and nonce) or -// chacha_drbg_reseed (entropy and additional_input) that fill exactly -// block_count blocks of hash function in derivation_function. There is no need -// the input to have this length, it's just an optimalization. -#define CHACHA_DRBG_OPTIMAL_RESEED_LENGTH(block_count) \ - ((block_count)*SHA256_BLOCK_LENGTH - 1 - 4 - 9) -// 1 = sizeof(counter), 4 = sizeof(output_length) in -// derivation_function, 9 is length of SHA256 padding of message -// aligned to bytes - -typedef struct _CHACHA_DRBG_CTX { - ECRYPT_ctx chacha_ctx; - uint32_t reseed_counter; -} CHACHA_DRBG_CTX; - -void chacha_drbg_init(CHACHA_DRBG_CTX *ctx, const uint8_t *entropy, - size_t entropy_length, const uint8_t *nonce, - size_t nonce_length); -void chacha_drbg_generate(CHACHA_DRBG_CTX *ctx, uint8_t *output, - size_t output_length); -void chacha_drbg_reseed(CHACHA_DRBG_CTX *ctx, const uint8_t *entropy, - size_t entropy_length, const uint8_t *additional_input, - size_t additional_input_length); -#endif // __CHACHA_DRBG__ diff --git a/deps/crypto/trezor-crypto/check_mem.h b/deps/crypto/trezor-crypto/check_mem.h deleted file mode 100644 index be8a43cd6..000000000 --- a/deps/crypto/trezor-crypto/check_mem.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef CHECK_MEM_H -#define CHECK_MEM_H - -#if CHECK_MAJOR_VERSION == 0 && CHECK_MINOR_VERSION < 11 - -#define _ck_assert_mem(X, Y, L, OP) do { \ - const char* _ck_x = (const char*)(void*)(X); \ - const char* _ck_y = (const char*)(void*)(Y); \ - size_t _ck_l = (L); \ - char _ck_x_str[129]; \ - char _ck_y_str[129]; \ - static char _ck_hexdigits[] = "0123456789abcdef"; \ - size_t _ck_i; \ - for (_ck_i = 0; _ck_i < ((_ck_l > 64) ? 64 : _ck_l); _ck_i++) { \ - _ck_x_str[_ck_i * 2 ] = _ck_hexdigits[(_ck_x[_ck_i] >> 4) & 0xF]; \ - _ck_y_str[_ck_i * 2 ] = _ck_hexdigits[(_ck_y[_ck_i] >> 4) & 0xF]; \ - _ck_x_str[_ck_i * 2 + 1] = _ck_hexdigits[_ck_x[_ck_i] & 0xF]; \ - _ck_y_str[_ck_i * 2 + 1] = _ck_hexdigits[_ck_y[_ck_i] & 0xF]; \ - } \ - _ck_x_str[_ck_i * 2] = 0; \ - _ck_y_str[_ck_i * 2] = 0; \ - ck_assert_msg(0 OP memcmp(_ck_y, _ck_x, _ck_l), \ - "Assertion '"#X#OP#Y"' failed: "#X"==\"%s\", "#Y"==\"%s\"", _ck_x_str, _ck_y_str); \ -} while (0) -#define ck_assert_mem_eq(X, Y, L) _ck_assert_mem(X, Y, L, ==) -#define ck_assert_mem_ne(X, Y, L) _ck_assert_mem(X, Y, L, !=) - -#endif - -#endif diff --git a/deps/crypto/trezor-crypto/curves.c b/deps/crypto/trezor-crypto/curves.c deleted file mode 100644 index 64cb0dffd..000000000 --- a/deps/crypto/trezor-crypto/curves.c +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (c) 2016 Jochen Hoenicke - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "curves.h" - -const char SECP256K1_NAME[] = "secp256k1"; -const char SECP256K1_DECRED_NAME[] = "secp256k1-decred"; -const char SECP256K1_GROESTL_NAME[] = "secp256k1-groestl"; -const char SECP256K1_SMART_NAME[] = "secp256k1-smart"; -const char NIST256P1_NAME[] = "nist256p1"; -const char ED25519_NAME[] = "ed25519"; -const char ED25519_CARDANO_NAME[] = "ed25519 cardano seed"; -#if USE_NANO -const char ED25519_BLAKE2B_NANO_NAME[] = "ed25519-blake2b-nano"; -#endif -const char ED25519_SHA3_NAME[] = "ed25519-sha3"; -#if USE_KECCAK -const char ED25519_KECCAK_NAME[] = "ed25519-keccak"; -#endif -const char CURVE25519_NAME[] = "curve25519"; diff --git a/deps/crypto/trezor-crypto/curves.h b/deps/crypto/trezor-crypto/curves.h deleted file mode 100644 index e6e2c4045..000000000 --- a/deps/crypto/trezor-crypto/curves.h +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Copyright (c) 2016 Jochen Hoenicke - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __CURVES_H__ -#define __CURVES_H__ - -#include "options.h" - -extern const char SECP256K1_NAME[]; -extern const char SECP256K1_DECRED_NAME[]; -extern const char SECP256K1_GROESTL_NAME[]; -extern const char SECP256K1_SMART_NAME[]; -extern const char NIST256P1_NAME[]; -extern const char ED25519_NAME[]; -extern const char ED25519_CARDANO_NAME[]; -#if USE_NANO -extern const char ED25519_BLAKE2B_NANO_NAME[]; -#endif -extern const char ED25519_SHA3_NAME[]; -#if USE_KECCAK -extern const char ED25519_KECCAK_NAME[]; -#endif -extern const char CURVE25519_NAME[]; - -#endif diff --git a/deps/crypto/trezor-crypto/ecdsa.c b/deps/crypto/trezor-crypto/ecdsa.c deleted file mode 100644 index 0349719f2..000000000 --- a/deps/crypto/trezor-crypto/ecdsa.c +++ /dev/null @@ -1,1265 +0,0 @@ -/** - * Copyright (c) 2013-2014 Tomas Dzetkulic - * Copyright (c) 2013-2014 Pavol Rusnak - * Copyright (c) 2015 Jochen Hoenicke - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include -#include - -#include "address.h" -#include "base58.h" -#include "bignum.h" -#include "ecdsa.h" -#include "hmac.h" -#include "memzero.h" -#include "rand.h" -#include "rfc6979.h" -#include "secp256k1.h" - -// Set cp2 = cp1 -void point_copy(const curve_point *cp1, curve_point *cp2) { *cp2 = *cp1; } - -// cp2 = cp1 + cp2 -void point_add(const ecdsa_curve *curve, const curve_point *cp1, - curve_point *cp2) { - bignum256 lambda = {0}, inv = {0}, xr = {0}, yr = {0}; - - if (point_is_infinity(cp1)) { - return; - } - if (point_is_infinity(cp2)) { - point_copy(cp1, cp2); - return; - } - if (point_is_equal(cp1, cp2)) { - point_double(curve, cp2); - return; - } - if (point_is_negative_of(cp1, cp2)) { - point_set_infinity(cp2); - return; - } - - // lambda = (y2 - y1) / (x2 - x1) - bn_subtractmod(&(cp2->x), &(cp1->x), &inv, &curve->prime); - bn_inverse(&inv, &curve->prime); - bn_subtractmod(&(cp2->y), &(cp1->y), &lambda, &curve->prime); - bn_multiply(&inv, &lambda, &curve->prime); - - // xr = lambda^2 - x1 - x2 - xr = lambda; - bn_multiply(&xr, &xr, &curve->prime); - yr = cp1->x; - bn_addmod(&yr, &(cp2->x), &curve->prime); - bn_subtractmod(&xr, &yr, &xr, &curve->prime); - bn_fast_mod(&xr, &curve->prime); - bn_mod(&xr, &curve->prime); - - // yr = lambda (x1 - xr) - y1 - bn_subtractmod(&(cp1->x), &xr, &yr, &curve->prime); - bn_multiply(&lambda, &yr, &curve->prime); - bn_subtractmod(&yr, &(cp1->y), &yr, &curve->prime); - bn_fast_mod(&yr, &curve->prime); - bn_mod(&yr, &curve->prime); - - cp2->x = xr; - cp2->y = yr; -} - -// cp = cp + cp -void point_double(const ecdsa_curve *curve, curve_point *cp) { - bignum256 lambda = {0}, xr = {0}, yr = {0}; - - if (point_is_infinity(cp)) { - return; - } - if (bn_is_zero(&(cp->y))) { - point_set_infinity(cp); - return; - } - - // lambda = (3 x^2 + a) / (2 y) - lambda = cp->y; - bn_mult_k(&lambda, 2, &curve->prime); - bn_fast_mod(&lambda, &curve->prime); - bn_mod(&lambda, &curve->prime); - bn_inverse(&lambda, &curve->prime); - - xr = cp->x; - bn_multiply(&xr, &xr, &curve->prime); - bn_mult_k(&xr, 3, &curve->prime); - bn_subi(&xr, -curve->a, &curve->prime); - bn_multiply(&xr, &lambda, &curve->prime); - - // xr = lambda^2 - 2*x - xr = lambda; - bn_multiply(&xr, &xr, &curve->prime); - yr = cp->x; - bn_lshift(&yr); - bn_subtractmod(&xr, &yr, &xr, &curve->prime); - bn_fast_mod(&xr, &curve->prime); - bn_mod(&xr, &curve->prime); - - // yr = lambda (x - xr) - y - bn_subtractmod(&(cp->x), &xr, &yr, &curve->prime); - bn_multiply(&lambda, &yr, &curve->prime); - bn_subtractmod(&yr, &(cp->y), &yr, &curve->prime); - bn_fast_mod(&yr, &curve->prime); - bn_mod(&yr, &curve->prime); - - cp->x = xr; - cp->y = yr; -} - -// set point to internal representation of point at infinity -void point_set_infinity(curve_point *p) { - bn_zero(&(p->x)); - bn_zero(&(p->y)); -} - -// return true iff p represent point at infinity -// both coords are zero in internal representation -int point_is_infinity(const curve_point *p) { - return bn_is_zero(&(p->x)) && bn_is_zero(&(p->y)); -} - -// return true iff both points are equal -int point_is_equal(const curve_point *p, const curve_point *q) { - return bn_is_equal(&(p->x), &(q->x)) && bn_is_equal(&(p->y), &(q->y)); -} - -// returns true iff p == -q -// expects p and q be valid points on curve other than point at infinity -int point_is_negative_of(const curve_point *p, const curve_point *q) { - // if P == (x, y), then -P would be (x, -y) on this curve - if (!bn_is_equal(&(p->x), &(q->x))) { - return 0; - } - - // we shouldn't hit this for a valid point - if (bn_is_zero(&(p->y))) { - return 0; - } - - return !bn_is_equal(&(p->y), &(q->y)); -} - -typedef struct jacobian_curve_point { - bignum256 x, y, z; -} jacobian_curve_point; - -// generate random K for signing/side-channel noise -static void generate_k_random(bignum256 *k, const bignum256 *prime) { - do { - int i = 0; - for (i = 0; i < 8; i++) { - k->val[i] = random32() & ((1u << BN_BITS_PER_LIMB) - 1); - } - k->val[8] = random32() & ((1u << BN_BITS_LAST_LIMB) - 1); - // check that k is in range and not zero. - } while (bn_is_zero(k) || !bn_is_less(k, prime)); -} - -void curve_to_jacobian(const curve_point *p, jacobian_curve_point *jp, - const bignum256 *prime) { - // randomize z coordinate - generate_k_random(&jp->z, prime); - - jp->x = jp->z; - bn_multiply(&jp->z, &jp->x, prime); - // x = z^2 - jp->y = jp->x; - bn_multiply(&jp->z, &jp->y, prime); - // y = z^3 - - bn_multiply(&p->x, &jp->x, prime); - bn_multiply(&p->y, &jp->y, prime); -} - -void jacobian_to_curve(const jacobian_curve_point *jp, curve_point *p, - const bignum256 *prime) { - p->y = jp->z; - bn_inverse(&p->y, prime); - // p->y = z^-1 - p->x = p->y; - bn_multiply(&p->x, &p->x, prime); - // p->x = z^-2 - bn_multiply(&p->x, &p->y, prime); - // p->y = z^-3 - bn_multiply(&jp->x, &p->x, prime); - // p->x = jp->x * z^-2 - bn_multiply(&jp->y, &p->y, prime); - // p->y = jp->y * z^-3 - bn_mod(&p->x, prime); - bn_mod(&p->y, prime); -} - -void point_jacobian_add(const curve_point *p1, jacobian_curve_point *p2, - const ecdsa_curve *curve) { - bignum256 r = {0}, h = {0}, r2 = {0}; - bignum256 hcby = {0}, hsqx = {0}; - bignum256 xz = {0}, yz = {0}, az = {0}; - int is_doubling = 0; - const bignum256 *prime = &curve->prime; - int a = curve->a; - - assert(-3 <= a && a <= 0); - - /* First we bring p1 to the same denominator: - * x1' := x1 * z2^2 - * y1' := y1 * z2^3 - */ - /* - * lambda = ((y1' - y2)/z2^3) / ((x1' - x2)/z2^2) - * = (y1' - y2) / (x1' - x2) z2 - * x3/z3^2 = lambda^2 - (x1' + x2)/z2^2 - * y3/z3^3 = 1/2 lambda * (2x3/z3^2 - (x1' + x2)/z2^2) + (y1'+y2)/z2^3 - * - * For the special case x1=x2, y1=y2 (doubling) we have - * lambda = 3/2 ((x2/z2^2)^2 + a) / (y2/z2^3) - * = 3/2 (x2^2 + a*z2^4) / y2*z2) - * - * to get rid of fraction we write lambda as - * lambda = r / (h*z2) - * with r = is_doubling ? 3/2 x2^2 + az2^4 : (y1 - y2) - * h = is_doubling ? y1+y2 : (x1 - x2) - * - * With z3 = h*z2 (the denominator of lambda) - * we get x3 = lambda^2*z3^2 - (x1' + x2)/z2^2*z3^2 - * = r^2 - h^2 * (x1' + x2) - * and y3 = 1/2 r * (2x3 - h^2*(x1' + x2)) + h^3*(y1' + y2) - */ - - /* h = x1 - x2 - * r = y1 - y2 - * x3 = r^2 - h^3 - 2*h^2*x2 - * y3 = r*(h^2*x2 - x3) - h^3*y2 - * z3 = h*z2 - */ - - xz = p2->z; - bn_multiply(&xz, &xz, prime); // xz = z2^2 - yz = p2->z; - bn_multiply(&xz, &yz, prime); // yz = z2^3 - - if (a != 0) { - az = xz; - bn_multiply(&az, &az, prime); // az = z2^4 - bn_mult_k(&az, -a, prime); // az = -az2^4 - } - - bn_multiply(&p1->x, &xz, prime); // xz = x1' = x1*z2^2; - h = xz; - bn_subtractmod(&h, &p2->x, &h, prime); - bn_fast_mod(&h, prime); - // h = x1' - x2; - - bn_add(&xz, &p2->x); - // xz = x1' + x2 - - // check for h == 0 % prime. Note that h never normalizes to - // zero, since h = x1' + 2*prime - x2 > 0 and a positive - // multiple of prime is always normalized to prime by - // bn_fast_mod. - is_doubling = bn_is_equal(&h, prime); - - bn_multiply(&p1->y, &yz, prime); // yz = y1' = y1*z2^3; - bn_subtractmod(&yz, &p2->y, &r, prime); - // r = y1' - y2; - - bn_add(&yz, &p2->y); - // yz = y1' + y2 - - r2 = p2->x; - bn_multiply(&r2, &r2, prime); - bn_mult_k(&r2, 3, prime); - - if (a != 0) { - // subtract -a z2^4, i.e, add a z2^4 - bn_subtractmod(&r2, &az, &r2, prime); - } - bn_cmov(&r, is_doubling, &r2, &r); - bn_cmov(&h, is_doubling, &yz, &h); - - // hsqx = h^2 - hsqx = h; - bn_multiply(&hsqx, &hsqx, prime); - - // hcby = h^3 - hcby = h; - bn_multiply(&hsqx, &hcby, prime); - - // hsqx = h^2 * (x1 + x2) - bn_multiply(&xz, &hsqx, prime); - - // hcby = h^3 * (y1 + y2) - bn_multiply(&yz, &hcby, prime); - - // z3 = h*z2 - bn_multiply(&h, &p2->z, prime); - - // x3 = r^2 - h^2 (x1 + x2) - p2->x = r; - bn_multiply(&p2->x, &p2->x, prime); - bn_subtractmod(&p2->x, &hsqx, &p2->x, prime); - bn_fast_mod(&p2->x, prime); - - // y3 = 1/2 (r*(h^2 (x1 + x2) - 2x3) - h^3 (y1 + y2)) - bn_subtractmod(&hsqx, &p2->x, &p2->y, prime); - bn_subtractmod(&p2->y, &p2->x, &p2->y, prime); - bn_multiply(&r, &p2->y, prime); - bn_subtractmod(&p2->y, &hcby, &p2->y, prime); - bn_mult_half(&p2->y, prime); - bn_fast_mod(&p2->y, prime); -} - -void point_jacobian_double(jacobian_curve_point *p, const ecdsa_curve *curve) { - bignum256 az4 = {0}, m = {0}, msq = {0}, ysq = {0}, xysq = {0}; - const bignum256 *prime = &curve->prime; - - assert(-3 <= curve->a && curve->a <= 0); - /* usual algorithm: - * - * lambda = (3((x/z^2)^2 + a) / 2y/z^3) = (3x^2 + az^4)/2yz - * x3/z3^2 = lambda^2 - 2x/z^2 - * y3/z3^3 = lambda * (x/z^2 - x3/z3^2) - y/z^3 - * - * to get rid of fraction we set - * m = (3 x^2 + az^4) / 2 - * Hence, - * lambda = m / yz = m / z3 - * - * With z3 = yz (the denominator of lambda) - * we get x3 = lambda^2*z3^2 - 2*x/z^2*z3^2 - * = m^2 - 2*xy^2 - * and y3 = (lambda * (x/z^2 - x3/z3^2) - y/z^3) * z3^3 - * = m * (xy^2 - x3) - y^4 - */ - - /* m = (3*x^2 + a z^4) / 2 - * x3 = m^2 - 2*xy^2 - * y3 = m*(xy^2 - x3) - 8y^4 - * z3 = y*z - */ - - m = p->x; - bn_multiply(&m, &m, prime); - bn_mult_k(&m, 3, prime); - - az4 = p->z; - bn_multiply(&az4, &az4, prime); - bn_multiply(&az4, &az4, prime); - bn_mult_k(&az4, -curve->a, prime); - bn_subtractmod(&m, &az4, &m, prime); - bn_mult_half(&m, prime); - - // msq = m^2 - msq = m; - bn_multiply(&msq, &msq, prime); - // ysq = y^2 - ysq = p->y; - bn_multiply(&ysq, &ysq, prime); - // xysq = xy^2 - xysq = p->x; - bn_multiply(&ysq, &xysq, prime); - - // z3 = yz - bn_multiply(&p->y, &p->z, prime); - - // x3 = m^2 - 2*xy^2 - p->x = xysq; - bn_lshift(&p->x); - bn_fast_mod(&p->x, prime); - bn_subtractmod(&msq, &p->x, &p->x, prime); - bn_fast_mod(&p->x, prime); - - // y3 = m*(xy^2 - x3) - y^4 - bn_subtractmod(&xysq, &p->x, &p->y, prime); - bn_multiply(&m, &p->y, prime); - bn_multiply(&ysq, &ysq, prime); - bn_subtractmod(&p->y, &ysq, &p->y, prime); - bn_fast_mod(&p->y, prime); -} - -// res = k * p -// returns 0 on success -int point_multiply(const ecdsa_curve *curve, const bignum256 *k, - const curve_point *p, curve_point *res) { - // this algorithm is loosely based on - // Katsuyuki Okeya and Tsuyoshi Takagi, The Width-w NAF Method Provides - // Small Memory and Fast Elliptic Scalar Multiplications Secure against - // Side Channel Attacks. - if (!bn_is_less(k, &curve->order)) { - return 1; - } - - int i = 0, j = 0; - static CONFIDENTIAL bignum256 a; - uint32_t *aptr = NULL; - uint32_t abits = 0; - int ashift = 0; - uint32_t is_even = (k->val[0] & 1) - 1; - uint32_t bits = {0}, sign = {0}, nsign = {0}; - static CONFIDENTIAL jacobian_curve_point jres; - curve_point pmult[8] = {0}; - const bignum256 *prime = &curve->prime; - - // is_even = 0xffffffff if k is even, 0 otherwise. - - // add 2^256. - // make number odd: subtract curve->order if even - uint32_t tmp = 1; - uint32_t is_non_zero = 0; - for (j = 0; j < 8; j++) { - is_non_zero |= k->val[j]; - tmp += (BN_BASE - 1) + k->val[j] - (curve->order.val[j] & is_even); - a.val[j] = tmp & (BN_BASE - 1); - tmp >>= BN_BITS_PER_LIMB; - } - is_non_zero |= k->val[j]; - a.val[j] = tmp + 0xffffff + k->val[j] - (curve->order.val[j] & is_even); - assert((a.val[0] & 1) != 0); - - // special case 0*p: just return zero. We don't care about constant time. - if (!is_non_zero) { - point_set_infinity(res); - return 1; - } - - // Now a = k + 2^256 (mod curve->order) and a is odd. - // - // The idea is to bring the new a into the form. - // sum_{i=0..64} a[i] 16^i, where |a[i]| < 16 and a[i] is odd. - // a[0] is odd, since a is odd. If a[i] would be even, we can - // add 1 to it and subtract 16 from a[i-1]. Afterwards, - // a[64] = 1, which is the 2^256 that we added before. - // - // Since k = a - 2^256 (mod curve->order), we can compute - // k*p = sum_{i=0..63} a[i] 16^i * p - // - // We compute |a[i]| * p in advance for all possible - // values of |a[i]| * p. pmult[i] = (2*i+1) * p - // We compute p, 3*p, ..., 15*p and store it in the table pmult. - // store p^2 temporarily in pmult[7] - pmult[7] = *p; - point_double(curve, &pmult[7]); - // compute 3*p, etc by repeatedly adding p^2. - pmult[0] = *p; - for (i = 1; i < 8; i++) { - pmult[i] = pmult[7]; - point_add(curve, &pmult[i - 1], &pmult[i]); - } - - // now compute res = sum_{i=0..63} a[i] * 16^i * p step by step, - // starting with i = 63. - // initialize jres = |a[63]| * p. - // Note that a[i] = a>>(4*i) & 0xf if (a&0x10) != 0 - // and - (16 - (a>>(4*i) & 0xf)) otherwise. We can compute this as - // ((a ^ (((a >> 4) & 1) - 1)) & 0xf) >> 1 - // since a is odd. - aptr = &a.val[8]; - abits = *aptr; - ashift = 256 - (BN_BITS_PER_LIMB * 8) - 4; - bits = abits >> ashift; - sign = (bits >> 4) - 1; - bits ^= sign; - bits &= 15; - curve_to_jacobian(&pmult[bits >> 1], &jres, prime); - for (i = 62; i >= 0; i--) { - // sign = sign(a[i+1]) (0xffffffff for negative, 0 for positive) - // invariant jres = (-1)^sign sum_{j=i+1..63} (a[j] * 16^{j-i-1} * p) - // abits >> (ashift - 4) = lowbits(a >> (i*4)) - - point_jacobian_double(&jres, curve); - point_jacobian_double(&jres, curve); - point_jacobian_double(&jres, curve); - point_jacobian_double(&jres, curve); - - // get lowest 5 bits of a >> (i*4). - ashift -= 4; - if (ashift < 0) { - // the condition only depends on the iteration number and - // leaks no private information to a side-channel. - bits = abits << (-ashift); - abits = *(--aptr); - ashift += BN_BITS_PER_LIMB; - bits |= abits >> ashift; - } else { - bits = abits >> ashift; - } - bits &= 31; - nsign = (bits >> 4) - 1; - bits ^= nsign; - bits &= 15; - - // negate last result to make signs of this round and the - // last round equal. - bn_cnegate((sign ^ nsign) & 1, &jres.z, prime); - - // add odd factor - point_jacobian_add(&pmult[bits >> 1], &jres, curve); - sign = nsign; - } - bn_cnegate(sign & 1, &jres.z, prime); - jacobian_to_curve(&jres, res, prime); - memzero(&a, sizeof(a)); - memzero(&jres, sizeof(jres)); - - return 0; -} - -#if USE_PRECOMPUTED_CP - -// res = k * G -// k must be a normalized number with 0 <= k < curve->order -// returns 0 on success -int scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, - curve_point *res) { - if (!bn_is_less(k, &curve->order)) { - return 1; - } - - int i = {0}, j = {0}; - static CONFIDENTIAL bignum256 a; - uint32_t is_even = (k->val[0] & 1) - 1; - uint32_t lowbits = 0; - static CONFIDENTIAL jacobian_curve_point jres; - const bignum256 *prime = &curve->prime; - - // is_even = 0xffffffff if k is even, 0 otherwise. - - // add 2^256. - // make number odd: subtract curve->order if even - uint32_t tmp = 1; - uint32_t is_non_zero = 0; - for (j = 0; j < 8; j++) { - is_non_zero |= k->val[j]; - tmp += (BN_BASE - 1) + k->val[j] - (curve->order.val[j] & is_even); - a.val[j] = tmp & (BN_BASE - 1); - tmp >>= BN_BITS_PER_LIMB; - } - is_non_zero |= k->val[j]; - a.val[j] = tmp + 0xffffff + k->val[j] - (curve->order.val[j] & is_even); - assert((a.val[0] & 1) != 0); - - // special case 0*G: just return zero. We don't care about constant time. - if (!is_non_zero) { - point_set_infinity(res); - return 0; - } - - // Now a = k + 2^256 (mod curve->order) and a is odd. - // - // The idea is to bring the new a into the form. - // sum_{i=0..64} a[i] 16^i, where |a[i]| < 16 and a[i] is odd. - // a[0] is odd, since a is odd. If a[i] would be even, we can - // add 1 to it and subtract 16 from a[i-1]. Afterwards, - // a[64] = 1, which is the 2^256 that we added before. - // - // Since k = a - 2^256 (mod curve->order), we can compute - // k*G = sum_{i=0..63} a[i] 16^i * G - // - // We have a big table curve->cp that stores all possible - // values of |a[i]| 16^i * G. - // curve->cp[i][j] = (2*j+1) * 16^i * G - - // now compute res = sum_{i=0..63} a[i] * 16^i * G step by step. - // initial res = |a[0]| * G. Note that a[0] = a & 0xf if (a&0x10) != 0 - // and - (16 - (a & 0xf)) otherwise. We can compute this as - // ((a ^ (((a >> 4) & 1) - 1)) & 0xf) >> 1 - // since a is odd. - lowbits = a.val[0] & ((1 << 5) - 1); - lowbits ^= (lowbits >> 4) - 1; - lowbits &= 15; - curve_to_jacobian(&curve->cp[0][lowbits >> 1], &jres, prime); - for (i = 1; i < 64; i++) { - // invariant res = sign(a[i-1]) sum_{j=0..i-1} (a[j] * 16^j * G) - - // shift a by 4 places. - for (j = 0; j < 8; j++) { - a.val[j] = - (a.val[j] >> 4) | ((a.val[j + 1] & 0xf) << (BN_BITS_PER_LIMB - 4)); - } - a.val[j] >>= 4; - // a = old(a)>>(4*i) - // a is even iff sign(a[i-1]) = -1 - - lowbits = a.val[0] & ((1 << 5) - 1); - lowbits ^= (lowbits >> 4) - 1; - lowbits &= 15; - // negate last result to make signs of this round and the - // last round equal. - bn_cnegate(~lowbits & 1, &jres.y, prime); - - // add odd factor - point_jacobian_add(&curve->cp[i][lowbits >> 1], &jres, curve); - } - bn_cnegate(~(a.val[0] >> 4) & 1, &jres.y, prime); - jacobian_to_curve(&jres, res, prime); - memzero(&a, sizeof(a)); - memzero(&jres, sizeof(jres)); - - return 0; -} - -#else - -int scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, - curve_point *res) { - return point_multiply(curve, k, &curve->G, res); -} - -#endif - -int ecdh_multiply(const ecdsa_curve *curve, const uint8_t *priv_key, - const uint8_t *pub_key, uint8_t *session_key) { - curve_point point = {0}; - if (!ecdsa_read_pubkey(curve, pub_key, &point)) { - return 1; - } - - bignum256 k = {0}; - bn_read_be(priv_key, &k); - if (bn_is_zero(&k) || !bn_is_less(&k, &curve->order)) { - // Invalid private key. - memzero(&k, sizeof(k)); - return 2; - } - - point_multiply(curve, &k, &point, &point); - memzero(&k, sizeof(k)); - - session_key[0] = 0x04; - bn_write_be(&point.x, session_key + 1); - bn_write_be(&point.y, session_key + 33); - memzero(&point, sizeof(point)); - - return 0; -} - -// msg is a data to be signed -// msg_len is the message length -int ecdsa_sign(const ecdsa_curve *curve, HasherType hasher_sign, - const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, - uint8_t *sig, uint8_t *pby, - int (*is_canonical)(uint8_t by, uint8_t sig[64])) { - uint8_t hash[32] = {0}; - hasher_Raw(hasher_sign, msg, msg_len, hash); - int res = ecdsa_sign_digest(curve, priv_key, hash, sig, pby, is_canonical); - memzero(hash, sizeof(hash)); - return res; -} - -// uses secp256k1 curve -// priv_key is a 32 byte big endian stored number -// sig is 64 bytes long array for the signature -// digest is 32 bytes of digest -// is_canonical is an optional function that checks if the signature -// conforms to additional coin-specific rules. -int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, - const uint8_t *digest, uint8_t *sig, uint8_t *pby, - int (*is_canonical)(uint8_t by, uint8_t sig[64])) { - int ret = -1; - int i = 0; - curve_point R = {0}; - bignum256 k = {0}, z = {0}, randk = {0}, s = {0}; - uint8_t by; // signature recovery byte - -#if USE_RFC6979 - rfc6979_state rng = {0}; - init_rfc6979(priv_key, digest, curve, &rng); -#endif - - bn_read_be(digest, &z); - if (bn_is_zero(&z)) { - // The probability of the digest being all-zero by chance is infinitesimal, - // so this is most likely an indication of a bug. Furthermore, the signature - // has no value, because in this case it can be easily forged for any public - // key, see ecdsa_verify_digest(). - ret = 1; - goto cleanup; - } - - for (i = 0; i < 10000; i++) { -#if USE_RFC6979 - // generate K deterministically - generate_k_rfc6979(&k, &rng); - // if k is too big or too small, we don't like it - if (bn_is_zero(&k) || !bn_is_less(&k, &curve->order)) { - continue; - } -#else - // generate random number k - generate_k_random(&k, &curve->order); -#endif - - // compute k*G - scalar_multiply(curve, &k, &R); - by = R.y.val[0] & 1; - // r = (rx mod n) - if (!bn_is_less(&R.x, &curve->order)) { - bn_subtract(&R.x, &curve->order, &R.x); - by |= 2; - } - // if r is zero, we retry - if (bn_is_zero(&R.x)) { - continue; - } - - bn_read_be(priv_key, &s); - if (bn_is_zero(&s) || !bn_is_less(&s, &curve->order)) { - // Invalid private key. - ret = 2; - goto cleanup; - } - - // randomize operations to counter side-channel attacks - generate_k_random(&randk, &curve->order); - bn_multiply(&randk, &k, &curve->order); // k*rand - bn_inverse(&k, &curve->order); // (k*rand)^-1 - bn_multiply(&R.x, &s, &curve->order); // R.x*priv - bn_add(&s, &z); // R.x*priv + z - bn_multiply(&k, &s, &curve->order); // (k*rand)^-1 (R.x*priv + z) - bn_multiply(&randk, &s, &curve->order); // k^-1 (R.x*priv + z) - bn_mod(&s, &curve->order); - // if s is zero, we retry - if (bn_is_zero(&s)) { - continue; - } - - // if S > order/2 => S = -S - if (bn_is_less(&curve->order_half, &s)) { - bn_subtract(&curve->order, &s, &s); - by ^= 1; - } - // we are done, R.x and s is the result signature - bn_write_be(&R.x, sig); - bn_write_be(&s, sig + 32); - - // check if the signature is acceptable or retry - if (is_canonical && !is_canonical(by, sig)) { - continue; - } - - if (pby) { - *pby = by; - } - ret = 0; - goto cleanup; - } - - // Too many retries without a valid signature - // -> fail with an error -cleanup: - memzero(&R, sizeof(R)); - memzero(&k, sizeof(k)); - memzero(&randk, sizeof(randk)); - memzero(&z, sizeof(z)); - memzero(&s, sizeof(s)); -#if USE_RFC6979 - memzero(&rng, sizeof(rng)); -#endif - return ret; -} - -// returns 0 on success -int ecdsa_get_public_key33(const ecdsa_curve *curve, const uint8_t *priv_key, - uint8_t *pub_key) { - curve_point R = {0}; - bignum256 k = {0}; - - bn_read_be(priv_key, &k); - if (bn_is_zero(&k) || !bn_is_less(&k, &curve->order)) { - // Invalid private key. - memzero(&k, sizeof(k)); - memzero(pub_key, 33); - return -1; - } - - // compute k*G - if (scalar_multiply(curve, &k, &R) != 0) { - memzero(&k, sizeof(k)); - return 1; - } - pub_key[0] = 0x02 | (R.y.val[0] & 0x01); - bn_write_be(&R.x, pub_key + 1); - memzero(&R, sizeof(R)); - memzero(&k, sizeof(k)); - return 0; -} - -// returns 0 on success -int ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key, - uint8_t *pub_key) { - curve_point R = {0}; - bignum256 k = {0}; - - bn_read_be(priv_key, &k); - if (bn_is_zero(&k) || !bn_is_less(&k, &curve->order)) { - // Invalid private key. - memzero(&k, sizeof(k)); - memzero(pub_key, 65); - return -1; - } - - // compute k*G - if (scalar_multiply(curve, &k, &R) != 0) { - memzero(&k, sizeof(k)); - return 1; - } - pub_key[0] = 0x04; - bn_write_be(&R.x, pub_key + 1); - bn_write_be(&R.y, pub_key + 33); - memzero(&R, sizeof(R)); - memzero(&k, sizeof(k)); - return 0; -} - -int ecdsa_uncompress_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, - uint8_t *uncompressed) { - curve_point pub = {0}; - - if (!ecdsa_read_pubkey(curve, pub_key, &pub)) { - return 0; - } - - uncompressed[0] = 4; - bn_write_be(&pub.x, uncompressed + 1); - bn_write_be(&pub.y, uncompressed + 33); - - return 1; -} - -void ecdsa_get_pubkeyhash(const uint8_t *pub_key, HasherType hasher_pubkey, - uint8_t *pubkeyhash) { - uint8_t h[HASHER_DIGEST_LENGTH] = {0}; - if (pub_key[0] == 0x04) { // uncompressed format - hasher_Raw(hasher_pubkey, pub_key, 65, h); - } else if (pub_key[0] == 0x00) { // point at infinity - hasher_Raw(hasher_pubkey, pub_key, 1, h); - } else { // expecting compressed format - hasher_Raw(hasher_pubkey, pub_key, 33, h); - } - memcpy(pubkeyhash, h, 20); - memzero(h, sizeof(h)); -} - -void ecdsa_get_address_raw(const uint8_t *pub_key, uint32_t version, - HasherType hasher_pubkey, uint8_t *addr_raw) { - size_t prefix_len = address_prefix_bytes_len(version); - address_write_prefix_bytes(version, addr_raw); - ecdsa_get_pubkeyhash(pub_key, hasher_pubkey, addr_raw + prefix_len); -} - -void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, - HasherType hasher_pubkey, HasherType hasher_base58, - char *addr, int addrsize) { - uint8_t raw[MAX_ADDR_RAW_SIZE] = {0}; - size_t prefix_len = address_prefix_bytes_len(version); - ecdsa_get_address_raw(pub_key, version, hasher_pubkey, raw); - base58_encode_check(raw, 20 + prefix_len, hasher_base58, addr, addrsize); - // not as important to clear this one, but we might as well - memzero(raw, sizeof(raw)); -} - -void ecdsa_get_address_segwit_p2sh_raw(const uint8_t *pub_key, uint32_t version, - HasherType hasher_pubkey, - uint8_t *addr_raw) { - uint8_t buf[32 + 2] = {0}; - buf[0] = 0; // version byte - buf[1] = 20; // push 20 bytes - ecdsa_get_pubkeyhash(pub_key, hasher_pubkey, buf + 2); - size_t prefix_len = address_prefix_bytes_len(version); - address_write_prefix_bytes(version, addr_raw); - hasher_Raw(hasher_pubkey, buf, 22, addr_raw + prefix_len); -} - -void ecdsa_get_address_segwit_p2sh(const uint8_t *pub_key, uint32_t version, - HasherType hasher_pubkey, - HasherType hasher_base58, char *addr, - int addrsize) { - uint8_t raw[MAX_ADDR_RAW_SIZE] = {0}; - size_t prefix_len = address_prefix_bytes_len(version); - ecdsa_get_address_segwit_p2sh_raw(pub_key, version, hasher_pubkey, raw); - base58_encode_check(raw, prefix_len + 20, hasher_base58, addr, addrsize); - memzero(raw, sizeof(raw)); -} - -void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, - HasherType hasher_base58, char *wif, int wifsize) { - uint8_t wif_raw[MAX_WIF_RAW_SIZE] = {0}; - size_t prefix_len = address_prefix_bytes_len(version); - address_write_prefix_bytes(version, wif_raw); - memcpy(wif_raw + prefix_len, priv_key, 32); - wif_raw[prefix_len + 32] = 0x01; - base58_encode_check(wif_raw, prefix_len + 32 + 1, hasher_base58, wif, - wifsize); - // private keys running around our stack can cause trouble - memzero(wif_raw, sizeof(wif_raw)); -} - -int ecdsa_address_decode(const char *addr, uint32_t version, - HasherType hasher_base58, uint8_t *out) { - if (!addr) return 0; - int prefix_len = address_prefix_bytes_len(version); - return base58_decode_check(addr, hasher_base58, out, 20 + prefix_len) == - 20 + prefix_len && - address_check_prefix(out, version); -} - -void compress_coords(const curve_point *cp, uint8_t *compressed) { - compressed[0] = bn_is_odd(&cp->y) ? 0x03 : 0x02; - bn_write_be(&cp->x, compressed + 1); -} - -void uncompress_coords(const ecdsa_curve *curve, uint8_t odd, - const bignum256 *x, bignum256 *y) { - // y^2 = x^3 + a*x + b - memcpy(y, x, sizeof(bignum256)); // y is x - bn_multiply(x, y, &curve->prime); // y is x^2 - bn_subi(y, -curve->a, &curve->prime); // y is x^2 + a - bn_multiply(x, y, &curve->prime); // y is x^3 + ax - bn_add(y, &curve->b); // y is x^3 + ax + b - bn_sqrt(y, &curve->prime); // y = sqrt(y) - if ((odd & 0x01) != (y->val[0] & 1)) { - bn_subtract(&curve->prime, y, y); // y = -y - } -} - -int ecdsa_read_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, - curve_point *pub) { - if (!curve) { - curve = &secp256k1; - } - if (pub_key[0] == 0x04) { - bn_read_be(pub_key + 1, &(pub->x)); - bn_read_be(pub_key + 33, &(pub->y)); - return ecdsa_validate_pubkey(curve, pub); - } - if (pub_key[0] == 0x02 || pub_key[0] == 0x03) { // compute missing y coords - bn_read_be(pub_key + 1, &(pub->x)); - uncompress_coords(curve, pub_key[0], &(pub->x), &(pub->y)); - return ecdsa_validate_pubkey(curve, pub); - } - // error - return 0; -} - -// Verifies that: -// - pub is not the point at infinity. -// - pub->x and pub->y are in range [0,p-1]. -// - pub is on the curve. -// We assume that all curves using this code have cofactor 1, so there is no -// need to verify that pub is a scalar multiple of G. -int ecdsa_validate_pubkey(const ecdsa_curve *curve, const curve_point *pub) { - bignum256 y_2 = {0}, x3_ax_b = {0}; - - if (point_is_infinity(pub)) { - return 0; - } - - if (!bn_is_less(&(pub->x), &curve->prime) || - !bn_is_less(&(pub->y), &curve->prime)) { - return 0; - } - - memcpy(&y_2, &(pub->y), sizeof(bignum256)); - memcpy(&x3_ax_b, &(pub->x), sizeof(bignum256)); - - // y^2 - bn_multiply(&(pub->y), &y_2, &curve->prime); - bn_mod(&y_2, &curve->prime); - - // x^3 + ax + b - bn_multiply(&(pub->x), &x3_ax_b, &curve->prime); // x^2 - bn_subi(&x3_ax_b, -curve->a, &curve->prime); // x^2 + a - bn_multiply(&(pub->x), &x3_ax_b, &curve->prime); // x^3 + ax - bn_addmod(&x3_ax_b, &curve->b, &curve->prime); // x^3 + ax + b - bn_mod(&x3_ax_b, &curve->prime); - - if (!bn_is_equal(&x3_ax_b, &y_2)) { - return 0; - } - - return 1; -} - -// uses secp256k1 curve -// pub_key - 65 bytes uncompressed key -// signature - 64 bytes signature -// msg is a data that was signed -// msg_len is the message length - -int ecdsa_verify(const ecdsa_curve *curve, HasherType hasher_sign, - const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, - uint32_t msg_len) { - uint8_t hash[32] = {0}; - hasher_Raw(hasher_sign, msg, msg_len, hash); - int res = ecdsa_verify_digest(curve, pub_key, sig, hash); - memzero(hash, sizeof(hash)); - return res; -} - -// Compute public key from signature and recovery id. -// returns 0 if the key is successfully recovered -int ecdsa_recover_pub_from_sig(const ecdsa_curve *curve, uint8_t *pub_key, - const uint8_t *sig, const uint8_t *digest, - int recid) { - bignum256 r = {0}, s = {0}, e = {0}; - curve_point cp = {0}, cp2 = {0}; - - // read r and s - bn_read_be(sig, &r); - bn_read_be(sig + 32, &s); - if (!bn_is_less(&r, &curve->order) || bn_is_zero(&r)) { - return 1; - } - if (!bn_is_less(&s, &curve->order) || bn_is_zero(&s)) { - return 1; - } - // cp = R = k * G (k is secret nonce when signing) - memcpy(&cp.x, &r, sizeof(bignum256)); - if (recid & 2) { - bn_add(&cp.x, &curve->order); - if (!bn_is_less(&cp.x, &curve->prime)) { - return 1; - } - } - // compute y from x - uncompress_coords(curve, recid & 1, &cp.x, &cp.y); - if (!ecdsa_validate_pubkey(curve, &cp)) { - return 1; - } - // e = -digest - bn_read_be(digest, &e); - bn_mod(&e, &curve->order); - bn_subtract(&curve->order, &e, &e); - // r = r^-1 - bn_inverse(&r, &curve->order); - // e = -digest * r^-1 - bn_multiply(&r, &e, &curve->order); - bn_mod(&e, &curve->order); - // s = s * r^-1 - bn_multiply(&r, &s, &curve->order); - bn_mod(&s, &curve->order); - // cp = s * r^-1 * k * G - point_multiply(curve, &s, &cp, &cp); - // cp2 = -digest * r^-1 * G - scalar_multiply(curve, &e, &cp2); - // cp = (s * r^-1 * k - digest * r^-1) * G = Pub - point_add(curve, &cp2, &cp); - // The point at infinity is not considered to be a valid public key. - if (point_is_infinity(&cp)) { - return 1; - } - pub_key[0] = 0x04; - bn_write_be(&cp.x, pub_key + 1); - bn_write_be(&cp.y, pub_key + 33); - return 0; -} - -// returns 0 if verification succeeded -int ecdsa_verify_digest(const ecdsa_curve *curve, const uint8_t *pub_key, - const uint8_t *sig, const uint8_t *digest) { - curve_point pub = {0}, res = {0}; - bignum256 r = {0}, s = {0}, z = {0}; - int result = 0; - - if (!ecdsa_read_pubkey(curve, pub_key, &pub)) { - result = 1; - } - - if (result == 0) { - bn_read_be(sig, &r); - bn_read_be(sig + 32, &s); - bn_read_be(digest, &z); - if (bn_is_zero(&r) || bn_is_zero(&s) || (!bn_is_less(&r, &curve->order)) || - (!bn_is_less(&s, &curve->order))) { - result = 2; - } - if (bn_is_zero(&z)) { - // The digest was all-zero. The probability of this happening by chance is - // infinitesimal, but it could be induced by a fault injection. In this - // case the signature (r,s) can be forged by taking r := (t * Q).x mod n - // and s := r * t^-1 mod n for any t in [1, n-1]. We fail verification, - // because there is no guarantee that the signature was created by the - // owner of the private key. - result = 3; - } - } - - if (result == 0) { - bn_inverse(&s, &curve->order); // s = s^-1 - bn_multiply(&s, &z, &curve->order); // z = z * s [u1 = z * s^-1 mod n] - bn_mod(&z, &curve->order); - } - - if (result == 0) { - bn_multiply(&r, &s, &curve->order); // s = r * s [u2 = r * s^-1 mod n] - bn_mod(&s, &curve->order); - scalar_multiply(curve, &z, &res); // res = z * G [= u1 * G] - point_multiply(curve, &s, &pub, &pub); // pub = s * pub [= u2 * Q] - point_add(curve, &pub, &res); // res = pub + res [R = u1 * G + u2 * Q] - if (point_is_infinity(&res)) { - // R == Infinity - result = 4; - } - } - - if (result == 0) { - bn_mod(&(res.x), &curve->order); - if (!bn_is_equal(&res.x, &r)) { - // R.x != r - // signature does not match - result = 5; - } - } - - memzero(&pub, sizeof(pub)); - memzero(&res, sizeof(res)); - memzero(&r, sizeof(r)); - memzero(&s, sizeof(s)); - memzero(&z, sizeof(z)); - - // all OK - return result; -} - -int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der) { - int i = 0; - uint8_t *p = der, *len = NULL, *len1 = NULL, *len2 = NULL; - *p = 0x30; - p++; // sequence - *p = 0x00; - len = p; - p++; // len(sequence) - - *p = 0x02; - p++; // integer - *p = 0x00; - len1 = p; - p++; // len(integer) - - // process R - i = 0; - while (i < 31 && sig[i] == 0) { - i++; - } // skip leading zeroes - if (sig[i] >= 0x80) { // put zero in output if MSB set - *p = 0x00; - p++; - *len1 = *len1 + 1; - } - while (i < 32) { // copy bytes to output - *p = sig[i]; - p++; - *len1 = *len1 + 1; - i++; - } - - *p = 0x02; - p++; // integer - *p = 0x00; - len2 = p; - p++; // len(integer) - - // process S - i = 32; - while (i < 63 && sig[i] == 0) { - i++; - } // skip leading zeroes - if (sig[i] >= 0x80) { // put zero in output if MSB set - *p = 0x00; - p++; - *len2 = *len2 + 1; - } - while (i < 64) { // copy bytes to output - *p = sig[i]; - p++; - *len2 = *len2 + 1; - i++; - } - - *len = *len1 + *len2 + 4; - return *len + 2; -} - -// Parse a DER-encoded signature. We check whether the encoded integers satisfy -// DER requirements regarding leading zeros. -int ecdsa_sig_from_der(const uint8_t *der, size_t der_len, uint8_t sig[64]) { - memzero(sig, 64); - - // Check sequence header. - if (der_len < 2 || der_len > 72 || der[0] != 0x30 || der[1] != der_len - 2) { - return 1; - } - - // Read two DER-encoded integers. - size_t pos = 2; - for (int i = 0; i < 2; ++i) { - // Check integer header. - if (der_len < pos + 2 || der[pos] != 0x02) { - return 1; - } - - // Locate the integer. - size_t int_len = der[pos + 1]; - pos += 2; - if (pos + int_len > der_len) { - return 1; - } - - // Positive integers must not start with an octet that has bit 8 set to 1. - if (int_len == 0 || der[pos] > 0x7f) { - return 1; - } - - // Skip a possible leading null octet. - if (int_len > 1 && der[pos] == 0x00) { - int_len--; - pos++; - - // Check that integer uses the shortest possible encoding. - if (der[pos] < 0x80) { - return 1; - } - } - - // Copy the integer to the output, making sure it fits. - if (int_len > 32) { - return 1; - } - memcpy(sig + 32 * (i + 1) - int_len, der + pos, int_len); - - // Move on to the next one. - pos += int_len; - } - - // Check that there are no trailing elements in the sequence. - if (pos != der_len) { - return 1; - } - - return 0; -} diff --git a/deps/crypto/trezor-crypto/ecdsa.h b/deps/crypto/trezor-crypto/ecdsa.h deleted file mode 100644 index 7b951d236..000000000 --- a/deps/crypto/trezor-crypto/ecdsa.h +++ /dev/null @@ -1,128 +0,0 @@ -/** - * Copyright (c) 2013-2014 Tomas Dzetkulic - * Copyright (c) 2013-2014 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __ECDSA_H__ -#define __ECDSA_H__ - -#include -#include "bignum.h" -#include "hasher.h" -#include "options.h" - -// curve point x and y -typedef struct { - bignum256 x, y; -} curve_point; - -typedef struct { - bignum256 prime; // prime order of the finite field - curve_point G; // initial curve point - bignum256 order; // order of G - bignum256 order_half; // order of G divided by 2 - int a; // coefficient 'a' of the elliptic curve - bignum256 b; // coefficient 'b' of the elliptic curve - -#if USE_PRECOMPUTED_CP - const curve_point cp[64][8]; -#endif - -} ecdsa_curve; - -// 4 byte prefix + 40 byte data (segwit) -// 1 byte prefix + 64 byte data (cashaddr) -#define MAX_ADDR_RAW_SIZE 65 -// bottle neck is cashaddr -// segwit is at most 90 characters plus NUL separator -// cashaddr: human readable prefix + 1 separator + 104 data + 8 checksum + 1 NUL -// we choose 130 as maximum (including NUL character) -#define MAX_ADDR_SIZE 130 -// 4 byte prefix + 32 byte privkey + 1 byte compressed marker -#define MAX_WIF_RAW_SIZE (4 + 32 + 1) -// (4 + 32 + 1 + 4 [checksum]) * 8 / log2(58) plus NUL. -#define MAX_WIF_SIZE (57) - -void point_copy(const curve_point *cp1, curve_point *cp2); -void point_add(const ecdsa_curve *curve, const curve_point *cp1, - curve_point *cp2); -void point_double(const ecdsa_curve *curve, curve_point *cp); -int point_multiply(const ecdsa_curve *curve, const bignum256 *k, - const curve_point *p, curve_point *res); -void point_set_infinity(curve_point *p); -int point_is_infinity(const curve_point *p); -int point_is_equal(const curve_point *p, const curve_point *q); -int point_is_negative_of(const curve_point *p, const curve_point *q); -int scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, - curve_point *res); -int ecdh_multiply(const ecdsa_curve *curve, const uint8_t *priv_key, - const uint8_t *pub_key, uint8_t *session_key); -void compress_coords(const curve_point *cp, uint8_t *compressed); -void uncompress_coords(const ecdsa_curve *curve, uint8_t odd, - const bignum256 *x, bignum256 *y); -int ecdsa_uncompress_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, - uint8_t *uncompressed); - -int ecdsa_sign(const ecdsa_curve *curve, HasherType hasher_sign, - const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, - uint8_t *sig, uint8_t *pby, - int (*is_canonical)(uint8_t by, uint8_t sig[64])); -int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, - const uint8_t *digest, uint8_t *sig, uint8_t *pby, - int (*is_canonical)(uint8_t by, uint8_t sig[64])); -int ecdsa_get_public_key33(const ecdsa_curve *curve, const uint8_t *priv_key, - uint8_t *pub_key); -int ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key, - uint8_t *pub_key); -void ecdsa_get_pubkeyhash(const uint8_t *pub_key, HasherType hasher_pubkey, - uint8_t *pubkeyhash); -void ecdsa_get_address_raw(const uint8_t *pub_key, uint32_t version, - HasherType hasher_pubkey, uint8_t *addr_raw); -void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, - HasherType hasher_pubkey, HasherType hasher_base58, - char *addr, int addrsize); -void ecdsa_get_address_segwit_p2sh_raw(const uint8_t *pub_key, uint32_t version, - HasherType hasher_pubkey, - uint8_t *addr_raw); -void ecdsa_get_address_segwit_p2sh(const uint8_t *pub_key, uint32_t version, - HasherType hasher_pubkey, - HasherType hasher_base58, char *addr, - int addrsize); -void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, - HasherType hasher_base58, char *wif, int wifsize); - -int ecdsa_address_decode(const char *addr, uint32_t version, - HasherType hasher_base58, uint8_t *out); -int ecdsa_read_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, - curve_point *pub); -int ecdsa_validate_pubkey(const ecdsa_curve *curve, const curve_point *pub); -int ecdsa_verify(const ecdsa_curve *curve, HasherType hasher_sign, - const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, - uint32_t msg_len); -int ecdsa_verify_digest(const ecdsa_curve *curve, const uint8_t *pub_key, - const uint8_t *sig, const uint8_t *digest); -int ecdsa_recover_pub_from_sig(const ecdsa_curve *curve, uint8_t *pub_key, - const uint8_t *sig, const uint8_t *digest, - int recid); -int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der); -int ecdsa_sig_from_der(const uint8_t *der, size_t der_len, uint8_t sig[64]); - -#endif diff --git a/deps/crypto/trezor-crypto/ed25519-donna/README.md b/deps/crypto/trezor-crypto/ed25519-donna/README.md deleted file mode 100644 index 73eadf8db..000000000 --- a/deps/crypto/trezor-crypto/ed25519-donna/README.md +++ /dev/null @@ -1,183 +0,0 @@ -[ed25519](https://ed25519.cr.yp.to) is an -[Elliptic Curve Digital Signature Algortithm](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm), -developed by [Dan Bernstein](https://cr.yp.to/djb.html), -[Niels Duif](https://www.nielsduif.nl), -[Tanja Lange](https://hyperelliptic.org/tanja), -[Peter Schwabe](https://cryptojedi.org/peter), -and [Bo-Yin Yang](https://www.iis.sinica.edu.tw/pages/byyang). - -This project provides performant, portable 32-bit & 64-bit implementations. All implementations are -of course constant time in regard to secret data. - -#### Performance - -SSE2 code and benches have not been updated yet. I will do those next. - -Compilers versions are gcc 4.6.3, icc 13.1.1, clang 3.4-1~exp1. - -Batch verification time (in parentheses) is the average time per 1 verification in a batch of 64 signatures. Counts are in thousands of cycles. - -Note that SSE2 performance may be less impressive on AMD & older CPUs with slower SSE ops! - -Visual Studio performance for `ge25519_scalarmult_base_niels` will lag behind a bit until optimized assembler versions of `ge25519_scalarmult_base_choose_niels` -are made. - -##### E5200 @ 2.5ghz, march=core2 - - - - - - - - - - - -
ImplementationSigngcciccclangVerifygcciccclang
ed25519-donna 64bit 100k110k137k327k (144k) 342k (163k) 422k (194k)
amd64-64-24k 102k 355k (158k)
ed25519-donna-sse2 64bit108k111k116k353k (155k) 345k (154k) 360k (161k)
amd64-51-32k 116k 380k (175k)
ed25519-donna-sse2 32bit147k147k156k380k (178k) 381k (173k) 430k (192k)
ed25519-donna 32bit 597k335k380k1693k (720k)1052k (453k)1141k (493k)
- -##### E3-1270 @ 3.4ghz, march=corei7-avx - - - - - - - - - - - -
ImplementationSigngcciccclangVerifygcciccclang
amd64-64-24k 68k 225k (104k)
ed25519-donna 64bit 71k 75k 90k226k (105k) 226k (112k) 277k (125k)
amd64-51-32k 72k 218k (107k)
ed25519-donna-sse2 64bit 79k 82k 92k252k (122k) 259k (124k) 282k (131k)
ed25519-donna-sse2 32bit 94k 95k103k296k (146k) 294k (137k) 306k (147k)
ed25519-donna 32bit 525k299k316k1502k (645k)959k (418k) 954k (416k)
- -#### Compilation - -No configuration is needed **if you are compiling against OpenSSL**. - -##### Hash Options - -If you are not compiling aginst OpenSSL, you will need a hash function. - -To use a simple/**slow** implementation of SHA-512, use `-DED25519_REFHASH` when compiling `ed25519.c`. -This should never be used except to verify the code works when OpenSSL is not available. - -To use a custom hash function, use `-DED25519_CUSTOMHASH` when compiling `ed25519.c` and put your -custom hash implementation in ed25519-hash-custom.h. The hash must have a 512bit digest and implement - - struct ed25519_hash_context; - - void ed25519_hash_init(ed25519_hash_context *ctx); - void ed25519_hash_update(ed25519_hash_context *ctx, const uint8_t *in, size_t inlen); - void ed25519_hash_final(ed25519_hash_context *ctx, uint8_t *hash); - void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen); - -##### Random Options - -If you are not compiling aginst OpenSSL, you will need a random function for batch verification. - -To use a custom random function, use `-DED25519_CUSTOMRANDOM` when compiling `ed25519.c` and put your -custom hash implementation in ed25519-randombytes-custom.h. The random function must implement: - - void ED25519_FN(ed25519_randombytes_unsafe) (void *p, size_t len); - -Use `-DED25519_TEST` when compiling `ed25519.c` to use a deterministically seeded, non-thread safe CSPRNG -variant of Bob Jenkins [ISAAC](https://en.wikipedia.org/wiki/ISAAC_%28cipher%29) - -##### Minor options - -Use `-DED25519_INLINE_ASM` to disable the use of custom assembler routines and instead rely on portable C. - -Use `-DED25519_FORCE_32BIT` to force the use of 32 bit routines even when compiling for 64 bit. - -##### 32-bit - - gcc ed25519.c -m32 -O3 -c - -##### 64-bit - - gcc ed25519.c -m64 -O3 -c - -##### SSE2 - - gcc ed25519.c -m32 -O3 -c -DED25519_SSE2 -msse2 - gcc ed25519.c -m64 -O3 -c -DED25519_SSE2 - -clang and icc are also supported - - -#### Usage - -To use the code, link against `ed25519.o -mbits` and: - - #include "ed25519.h" - -Add `-lssl -lcrypto` when using OpenSSL (Some systems don't need -lcrypto? It might be trial and error). - -To generate a private key, simply generate 32 bytes from a secure -cryptographic source: - - ed25519_secret_key sk; - randombytes(sk, sizeof(ed25519_secret_key)); - -To generate a public key: - - ed25519_public_key pk; - ed25519_publickey(sk, pk); - -To sign a message: - - ed25519_signature sig; - ed25519_sign(message, message_len, sk, pk, signature); - -To verify a signature: - - int valid = ed25519_sign_open(message, message_len, pk, signature) == 0; - -To batch verify signatures: - - const unsigned char *mp[num] = {message1, message2..} - size_t ml[num] = {message_len1, message_len2..} - const unsigned char *pkp[num] = {pk1, pk2..} - const unsigned char *sigp[num] = {signature1, signature2..} - int valid[num] - - /* valid[i] will be set to 1 if the individual signature was valid, 0 otherwise */ - int all_valid = ed25519_sign_open_batch(mp, ml, pkp, sigp, num, valid) == 0; - -**Note**: Batch verification uses `ed25519_randombytes_unsafe`, implemented in -`ed25519-randombytes.h`, to generate random scalars for the verification code. -The default implementation now uses OpenSSLs `RAND_bytes`. - -Unlike the [SUPERCOP](https://bench.cr.yp.to/supercop.html) version, signatures are -not appended to messages, and there is no need for padding in front of messages. -Additionally, the secret key does not contain a copy of the public key, so it is -32 bytes instead of 64 bytes, and the public key must be provided to the signing -function. - -##### Curve25519 - -Curve25519 public keys can be generated thanks to -[Adam Langley](https://www.imperialviolet.org/2013/05/10/fastercurve25519.html) -leveraging Ed25519's precomputed basepoint scalar multiplication. - - curved25519_key sk, pk; - randombytes(sk, sizeof(curved25519_key)); - curved25519_scalarmult_basepoint(pk, sk); - -Note the name is curved25519, a combination of curve and ed25519, to prevent -name clashes. Performance is slightly faster than short message ed25519 -signing due to both using the same code for the scalar multiply. - -#### Testing - -Fuzzing against reference implemenations is now available. See [fuzz/README](fuzz/README.md). - -Building `ed25519.c` with `-DED25519_TEST` and linking with `test.c` will run basic sanity tests -and benchmark each function. `test-batch.c` has been incorporated in to `test.c`. - -`test-internals.c` is standalone and built the same way as `ed25519.c`. It tests the math primitives -with extreme values to ensure they function correctly. SSE2 is now supported. - -#### Papers - -[Available on the Ed25519 website](https://ed25519.cr.yp.to/papers.html) diff --git a/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-32bit.c b/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-32bit.c deleted file mode 100644 index 5a09710be..000000000 --- a/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-32bit.c +++ /dev/null @@ -1,681 +0,0 @@ -/* - Public domain by Andrew M. - See: https://github.com/floodyberry/curve25519-donna - - 32 bit integer curve25519 implementation -*/ - -#include "ed25519-donna.h" - -static const uint32_t reduce_mask_25 = (1 << 25) - 1; -static const uint32_t reduce_mask_26 = (1 << 26) - 1; - -/* out = in */ -void curve25519_copy(bignum25519 out, const bignum25519 in) { - out[0] = in[0]; - out[1] = in[1]; - out[2] = in[2]; - out[3] = in[3]; - out[4] = in[4]; - out[5] = in[5]; - out[6] = in[6]; - out[7] = in[7]; - out[8] = in[8]; - out[9] = in[9]; -} - -/* out = a + b */ -void curve25519_add(bignum25519 out, const bignum25519 a, const bignum25519 b) { - out[0] = a[0] + b[0]; - out[1] = a[1] + b[1]; - out[2] = a[2] + b[2]; - out[3] = a[3] + b[3]; - out[4] = a[4] + b[4]; - out[5] = a[5] + b[5]; - out[6] = a[6] + b[6]; - out[7] = a[7] + b[7]; - out[8] = a[8] + b[8]; - out[9] = a[9] + b[9]; -} - -void curve25519_add_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) { - uint32_t c = 0; - out[0] = a[0] + b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; - out[1] = a[1] + b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; - out[2] = a[2] + b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; - out[3] = a[3] + b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; - out[4] = a[4] + b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; - out[5] = a[5] + b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; - out[6] = a[6] + b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; - out[7] = a[7] + b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; - out[8] = a[8] + b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; - out[9] = a[9] + b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; - out[0] += 19 * c; -} - -void curve25519_add_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) { - uint32_t c = 0; - out[0] = a[0] + b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; - out[1] = a[1] + b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; - out[2] = a[2] + b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; - out[3] = a[3] + b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; - out[4] = a[4] + b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; - out[5] = a[5] + b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; - out[6] = a[6] + b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; - out[7] = a[7] + b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; - out[8] = a[8] + b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; - out[9] = a[9] + b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; - out[0] += 19 * c; -} - -/* multiples of p */ -static const uint32_t twoP0 = 0x07ffffda; -static const uint32_t twoP13579 = 0x03fffffe; -static const uint32_t twoP2468 = 0x07fffffe; -static const uint32_t fourP0 = 0x0fffffb4; -static const uint32_t fourP13579 = 0x07fffffc; -static const uint32_t fourP2468 = 0x0ffffffc; - -/* out = a - b */ -void curve25519_sub(bignum25519 out, const bignum25519 a, const bignum25519 b) { - uint32_t c = 0; - out[0] = twoP0 + a[0] - b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; - out[1] = twoP13579 + a[1] - b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; - out[2] = twoP2468 + a[2] - b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; - out[3] = twoP13579 + a[3] - b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; - out[4] = twoP2468 + a[4] - b[4] + c; - out[5] = twoP13579 + a[5] - b[5] ; - out[6] = twoP2468 + a[6] - b[6] ; - out[7] = twoP13579 + a[7] - b[7] ; - out[8] = twoP2468 + a[8] - b[8] ; - out[9] = twoP13579 + a[9] - b[9] ; -} - -/* out = in * scalar */ -void curve25519_scalar_product(bignum25519 out, const bignum25519 in, const uint32_t scalar) { - uint64_t a = 0; - uint32_t c = 0; - a = mul32x32_64(in[0], scalar); out[0] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); - a = mul32x32_64(in[1], scalar) + c; out[1] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); - a = mul32x32_64(in[2], scalar) + c; out[2] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); - a = mul32x32_64(in[3], scalar) + c; out[3] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); - a = mul32x32_64(in[4], scalar) + c; out[4] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); - a = mul32x32_64(in[5], scalar) + c; out[5] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); - a = mul32x32_64(in[6], scalar) + c; out[6] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); - a = mul32x32_64(in[7], scalar) + c; out[7] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); - a = mul32x32_64(in[8], scalar) + c; out[8] = (uint32_t)a & reduce_mask_26; c = (uint32_t)(a >> 26); - a = mul32x32_64(in[9], scalar) + c; out[9] = (uint32_t)a & reduce_mask_25; c = (uint32_t)(a >> 25); - out[0] += c * 19; -} - -/* out = a - b, where a is the result of a basic op (add,sub) */ -void curve25519_sub_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) { - uint32_t c = 0; - out[0] = fourP0 + a[0] - b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; - out[1] = fourP13579 + a[1] - b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; - out[2] = fourP2468 + a[2] - b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; - out[3] = fourP13579 + a[3] - b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; - out[4] = fourP2468 + a[4] - b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; - out[5] = fourP13579 + a[5] - b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; - out[6] = fourP2468 + a[6] - b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; - out[7] = fourP13579 + a[7] - b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; - out[8] = fourP2468 + a[8] - b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; - out[9] = fourP13579 + a[9] - b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; - out[0] += 19 * c; -} - -void curve25519_sub_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) { - uint32_t c = 0; - out[0] = fourP0 + a[0] - b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; - out[1] = fourP13579 + a[1] - b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; - out[2] = fourP2468 + a[2] - b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; - out[3] = fourP13579 + a[3] - b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; - out[4] = fourP2468 + a[4] - b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; - out[5] = fourP13579 + a[5] - b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; - out[6] = fourP2468 + a[6] - b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; - out[7] = fourP13579 + a[7] - b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; - out[8] = fourP2468 + a[8] - b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; - out[9] = fourP13579 + a[9] - b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; - out[0] += 19 * c; -} - -/* out = -a */ -void curve25519_neg(bignum25519 out, const bignum25519 a) { - uint32_t c = 0; - out[0] = twoP0 - a[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; - out[1] = twoP13579 - a[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; - out[2] = twoP2468 - a[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; - out[3] = twoP13579 - a[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; - out[4] = twoP2468 - a[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; - out[5] = twoP13579 - a[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; - out[6] = twoP2468 - a[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; - out[7] = twoP13579 - a[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; - out[8] = twoP2468 - a[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; - out[9] = twoP13579 - a[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; - out[0] += 19 * c; -} - -/* out = a * b */ -#define curve25519_mul_noinline curve25519_mul -void curve25519_mul(bignum25519 out, const bignum25519 a, const bignum25519 b) { - uint32_t r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0, r6 = 0, r7 = 0, r8 = 0, r9 = 0; - uint32_t s0 = 0, s1 = 0, s2 = 0, s3 = 0, s4 = 0, s5 = 0, s6 = 0, s7 = 0, s8 = 0, s9 = 0; - uint64_t m0 = 0, m1 = 0, m2 = 0, m3 = 0, m4 = 0, m5 = 0, m6 = 0, m7 = 0, m8 = 0, m9 = 0, c = 0; - uint32_t p = 0; - - r0 = b[0]; - r1 = b[1]; - r2 = b[2]; - r3 = b[3]; - r4 = b[4]; - r5 = b[5]; - r6 = b[6]; - r7 = b[7]; - r8 = b[8]; - r9 = b[9]; - - s0 = a[0]; - s1 = a[1]; - s2 = a[2]; - s3 = a[3]; - s4 = a[4]; - s5 = a[5]; - s6 = a[6]; - s7 = a[7]; - s8 = a[8]; - s9 = a[9]; - - m1 = mul32x32_64(r0, s1) + mul32x32_64(r1, s0); - m3 = mul32x32_64(r0, s3) + mul32x32_64(r1, s2) + mul32x32_64(r2, s1) + mul32x32_64(r3, s0); - m5 = mul32x32_64(r0, s5) + mul32x32_64(r1, s4) + mul32x32_64(r2, s3) + mul32x32_64(r3, s2) + mul32x32_64(r4, s1) + mul32x32_64(r5, s0); - m7 = mul32x32_64(r0, s7) + mul32x32_64(r1, s6) + mul32x32_64(r2, s5) + mul32x32_64(r3, s4) + mul32x32_64(r4, s3) + mul32x32_64(r5, s2) + mul32x32_64(r6, s1) + mul32x32_64(r7, s0); - m9 = mul32x32_64(r0, s9) + mul32x32_64(r1, s8) + mul32x32_64(r2, s7) + mul32x32_64(r3, s6) + mul32x32_64(r4, s5) + mul32x32_64(r5, s4) + mul32x32_64(r6, s3) + mul32x32_64(r7, s2) + mul32x32_64(r8, s1) + mul32x32_64(r9, s0); - - r1 *= 2; - r3 *= 2; - r5 *= 2; - r7 *= 2; - - m0 = mul32x32_64(r0, s0); - m2 = mul32x32_64(r0, s2) + mul32x32_64(r1, s1) + mul32x32_64(r2, s0); - m4 = mul32x32_64(r0, s4) + mul32x32_64(r1, s3) + mul32x32_64(r2, s2) + mul32x32_64(r3, s1) + mul32x32_64(r4, s0); - m6 = mul32x32_64(r0, s6) + mul32x32_64(r1, s5) + mul32x32_64(r2, s4) + mul32x32_64(r3, s3) + mul32x32_64(r4, s2) + mul32x32_64(r5, s1) + mul32x32_64(r6, s0); - m8 = mul32x32_64(r0, s8) + mul32x32_64(r1, s7) + mul32x32_64(r2, s6) + mul32x32_64(r3, s5) + mul32x32_64(r4, s4) + mul32x32_64(r5, s3) + mul32x32_64(r6, s2) + mul32x32_64(r7, s1) + mul32x32_64(r8, s0); - - r1 *= 19; - r2 *= 19; - r3 = (r3 / 2) * 19; - r4 *= 19; - r5 = (r5 / 2) * 19; - r6 *= 19; - r7 = (r7 / 2) * 19; - r8 *= 19; - r9 *= 19; - - m1 += (mul32x32_64(r9, s2) + mul32x32_64(r8, s3) + mul32x32_64(r7, s4) + mul32x32_64(r6, s5) + mul32x32_64(r5, s6) + mul32x32_64(r4, s7) + mul32x32_64(r3, s8) + mul32x32_64(r2, s9)); - m3 += (mul32x32_64(r9, s4) + mul32x32_64(r8, s5) + mul32x32_64(r7, s6) + mul32x32_64(r6, s7) + mul32x32_64(r5, s8) + mul32x32_64(r4, s9)); - m5 += (mul32x32_64(r9, s6) + mul32x32_64(r8, s7) + mul32x32_64(r7, s8) + mul32x32_64(r6, s9)); - m7 += (mul32x32_64(r9, s8) + mul32x32_64(r8, s9)); - - r3 *= 2; - r5 *= 2; - r7 *= 2; - r9 *= 2; - - m0 += (mul32x32_64(r9, s1) + mul32x32_64(r8, s2) + mul32x32_64(r7, s3) + mul32x32_64(r6, s4) + mul32x32_64(r5, s5) + mul32x32_64(r4, s6) + mul32x32_64(r3, s7) + mul32x32_64(r2, s8) + mul32x32_64(r1, s9)); - m2 += (mul32x32_64(r9, s3) + mul32x32_64(r8, s4) + mul32x32_64(r7, s5) + mul32x32_64(r6, s6) + mul32x32_64(r5, s7) + mul32x32_64(r4, s8) + mul32x32_64(r3, s9)); - m4 += (mul32x32_64(r9, s5) + mul32x32_64(r8, s6) + mul32x32_64(r7, s7) + mul32x32_64(r6, s8) + mul32x32_64(r5, s9)); - m6 += (mul32x32_64(r9, s7) + mul32x32_64(r8, s8) + mul32x32_64(r7, s9)); - m8 += (mul32x32_64(r9, s9)); - - r0 = (uint32_t)m0 & reduce_mask_26; c = (m0 >> 26); - m1 += c; r1 = (uint32_t)m1 & reduce_mask_25; c = (m1 >> 25); - m2 += c; r2 = (uint32_t)m2 & reduce_mask_26; c = (m2 >> 26); - m3 += c; r3 = (uint32_t)m3 & reduce_mask_25; c = (m3 >> 25); - m4 += c; r4 = (uint32_t)m4 & reduce_mask_26; c = (m4 >> 26); - m5 += c; r5 = (uint32_t)m5 & reduce_mask_25; c = (m5 >> 25); - m6 += c; r6 = (uint32_t)m6 & reduce_mask_26; c = (m6 >> 26); - m7 += c; r7 = (uint32_t)m7 & reduce_mask_25; c = (m7 >> 25); - m8 += c; r8 = (uint32_t)m8 & reduce_mask_26; c = (m8 >> 26); - m9 += c; r9 = (uint32_t)m9 & reduce_mask_25; p = (uint32_t)(m9 >> 25); - m0 = r0 + mul32x32_64(p,19); r0 = (uint32_t)m0 & reduce_mask_26; p = (uint32_t)(m0 >> 26); - r1 += p; - - out[0] = r0; - out[1] = r1; - out[2] = r2; - out[3] = r3; - out[4] = r4; - out[5] = r5; - out[6] = r6; - out[7] = r7; - out[8] = r8; - out[9] = r9; -} - -/* out = in * in */ -void curve25519_square(bignum25519 out, const bignum25519 in) { - uint32_t r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0, r6 = 0, r7 = 0, r8 = 0, r9 = 0; - uint32_t d6 = 0, d7 = 0, d8 = 0, d9 = 0; - uint64_t m0 = 0, m1 = 0, m2 = 0, m3 = 0, m4 = 0, m5 = 0, m6 = 0, m7 = 0, m8 = 0, m9 = 0, c = 0; - uint32_t p = 0; - - r0 = in[0]; - r1 = in[1]; - r2 = in[2]; - r3 = in[3]; - r4 = in[4]; - r5 = in[5]; - r6 = in[6]; - r7 = in[7]; - r8 = in[8]; - r9 = in[9]; - - m0 = mul32x32_64(r0, r0); - r0 *= 2; - m1 = mul32x32_64(r0, r1); - m2 = mul32x32_64(r0, r2) + mul32x32_64(r1, r1 * 2); - r1 *= 2; - m3 = mul32x32_64(r0, r3) + mul32x32_64(r1, r2 ); - m4 = mul32x32_64(r0, r4) + mul32x32_64(r1, r3 * 2) + mul32x32_64(r2, r2); - r2 *= 2; - m5 = mul32x32_64(r0, r5) + mul32x32_64(r1, r4 ) + mul32x32_64(r2, r3); - m6 = mul32x32_64(r0, r6) + mul32x32_64(r1, r5 * 2) + mul32x32_64(r2, r4) + mul32x32_64(r3, r3 * 2); - r3 *= 2; - m7 = mul32x32_64(r0, r7) + mul32x32_64(r1, r6 ) + mul32x32_64(r2, r5) + mul32x32_64(r3, r4 ); - m8 = mul32x32_64(r0, r8) + mul32x32_64(r1, r7 * 2) + mul32x32_64(r2, r6) + mul32x32_64(r3, r5 * 2) + mul32x32_64(r4, r4 ); - m9 = mul32x32_64(r0, r9) + mul32x32_64(r1, r8 ) + mul32x32_64(r2, r7) + mul32x32_64(r3, r6 ) + mul32x32_64(r4, r5 * 2); - - d6 = r6 * 19; - d7 = r7 * 2 * 19; - d8 = r8 * 19; - d9 = r9 * 2 * 19; - - m0 += (mul32x32_64(d9, r1 ) + mul32x32_64(d8, r2 ) + mul32x32_64(d7, r3 ) + mul32x32_64(d6, r4 * 2) + mul32x32_64(r5, r5 * 2 * 19)); - m1 += (mul32x32_64(d9, r2 / 2) + mul32x32_64(d8, r3 ) + mul32x32_64(d7, r4 ) + mul32x32_64(d6, r5 * 2)); - m2 += (mul32x32_64(d9, r3 ) + mul32x32_64(d8, r4 * 2) + mul32x32_64(d7, r5 * 2) + mul32x32_64(d6, r6 )); - m3 += (mul32x32_64(d9, r4 ) + mul32x32_64(d8, r5 * 2) + mul32x32_64(d7, r6 )); - m4 += (mul32x32_64(d9, r5 * 2) + mul32x32_64(d8, r6 * 2) + mul32x32_64(d7, r7 )); - m5 += (mul32x32_64(d9, r6 ) + mul32x32_64(d8, r7 * 2)); - m6 += (mul32x32_64(d9, r7 * 2) + mul32x32_64(d8, r8 )); - m7 += (mul32x32_64(d9, r8 )); - m8 += (mul32x32_64(d9, r9 )); - - r0 = (uint32_t)m0 & reduce_mask_26; c = (m0 >> 26); - m1 += c; r1 = (uint32_t)m1 & reduce_mask_25; c = (m1 >> 25); - m2 += c; r2 = (uint32_t)m2 & reduce_mask_26; c = (m2 >> 26); - m3 += c; r3 = (uint32_t)m3 & reduce_mask_25; c = (m3 >> 25); - m4 += c; r4 = (uint32_t)m4 & reduce_mask_26; c = (m4 >> 26); - m5 += c; r5 = (uint32_t)m5 & reduce_mask_25; c = (m5 >> 25); - m6 += c; r6 = (uint32_t)m6 & reduce_mask_26; c = (m6 >> 26); - m7 += c; r7 = (uint32_t)m7 & reduce_mask_25; c = (m7 >> 25); - m8 += c; r8 = (uint32_t)m8 & reduce_mask_26; c = (m8 >> 26); - m9 += c; r9 = (uint32_t)m9 & reduce_mask_25; p = (uint32_t)(m9 >> 25); - m0 = r0 + mul32x32_64(p,19); r0 = (uint32_t)m0 & reduce_mask_26; p = (uint32_t)(m0 >> 26); - r1 += p; - - out[0] = r0; - out[1] = r1; - out[2] = r2; - out[3] = r3; - out[4] = r4; - out[5] = r5; - out[6] = r6; - out[7] = r7; - out[8] = r8; - out[9] = r9; -} - -/* out = in ^ (2 * count) */ -void curve25519_square_times(bignum25519 out, const bignum25519 in, int count) { - uint32_t r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0, r6 = 0, r7 = 0, r8 = 0, r9 = 0; - uint32_t d6 = 0, d7 = 0, d8 = 0, d9 = 0; - uint64_t m0 = 0, m1 = 0, m2 = 0, m3 = 0, m4 = 0, m5 = 0, m6 = 0, m7 = 0, m8 = 0, m9 = 0, c = 0; - uint32_t p = 0; - - r0 = in[0]; - r1 = in[1]; - r2 = in[2]; - r3 = in[3]; - r4 = in[4]; - r5 = in[5]; - r6 = in[6]; - r7 = in[7]; - r8 = in[8]; - r9 = in[9]; - - do { - m0 = mul32x32_64(r0, r0); - r0 *= 2; - m1 = mul32x32_64(r0, r1); - m2 = mul32x32_64(r0, r2) + mul32x32_64(r1, r1 * 2); - r1 *= 2; - m3 = mul32x32_64(r0, r3) + mul32x32_64(r1, r2 ); - m4 = mul32x32_64(r0, r4) + mul32x32_64(r1, r3 * 2) + mul32x32_64(r2, r2); - r2 *= 2; - m5 = mul32x32_64(r0, r5) + mul32x32_64(r1, r4 ) + mul32x32_64(r2, r3); - m6 = mul32x32_64(r0, r6) + mul32x32_64(r1, r5 * 2) + mul32x32_64(r2, r4) + mul32x32_64(r3, r3 * 2); - r3 *= 2; - m7 = mul32x32_64(r0, r7) + mul32x32_64(r1, r6 ) + mul32x32_64(r2, r5) + mul32x32_64(r3, r4 ); - m8 = mul32x32_64(r0, r8) + mul32x32_64(r1, r7 * 2) + mul32x32_64(r2, r6) + mul32x32_64(r3, r5 * 2) + mul32x32_64(r4, r4 ); - m9 = mul32x32_64(r0, r9) + mul32x32_64(r1, r8 ) + mul32x32_64(r2, r7) + mul32x32_64(r3, r6 ) + mul32x32_64(r4, r5 * 2); - - d6 = r6 * 19; - d7 = r7 * 2 * 19; - d8 = r8 * 19; - d9 = r9 * 2 * 19; - - m0 += (mul32x32_64(d9, r1 ) + mul32x32_64(d8, r2 ) + mul32x32_64(d7, r3 ) + mul32x32_64(d6, r4 * 2) + mul32x32_64(r5, r5 * 2 * 19)); - m1 += (mul32x32_64(d9, r2 / 2) + mul32x32_64(d8, r3 ) + mul32x32_64(d7, r4 ) + mul32x32_64(d6, r5 * 2)); - m2 += (mul32x32_64(d9, r3 ) + mul32x32_64(d8, r4 * 2) + mul32x32_64(d7, r5 * 2) + mul32x32_64(d6, r6 )); - m3 += (mul32x32_64(d9, r4 ) + mul32x32_64(d8, r5 * 2) + mul32x32_64(d7, r6 )); - m4 += (mul32x32_64(d9, r5 * 2) + mul32x32_64(d8, r6 * 2) + mul32x32_64(d7, r7 )); - m5 += (mul32x32_64(d9, r6 ) + mul32x32_64(d8, r7 * 2)); - m6 += (mul32x32_64(d9, r7 * 2) + mul32x32_64(d8, r8 )); - m7 += (mul32x32_64(d9, r8 )); - m8 += (mul32x32_64(d9, r9 )); - - r0 = (uint32_t)m0 & reduce_mask_26; c = (m0 >> 26); - m1 += c; r1 = (uint32_t)m1 & reduce_mask_25; c = (m1 >> 25); - m2 += c; r2 = (uint32_t)m2 & reduce_mask_26; c = (m2 >> 26); - m3 += c; r3 = (uint32_t)m3 & reduce_mask_25; c = (m3 >> 25); - m4 += c; r4 = (uint32_t)m4 & reduce_mask_26; c = (m4 >> 26); - m5 += c; r5 = (uint32_t)m5 & reduce_mask_25; c = (m5 >> 25); - m6 += c; r6 = (uint32_t)m6 & reduce_mask_26; c = (m6 >> 26); - m7 += c; r7 = (uint32_t)m7 & reduce_mask_25; c = (m7 >> 25); - m8 += c; r8 = (uint32_t)m8 & reduce_mask_26; c = (m8 >> 26); - m9 += c; r9 = (uint32_t)m9 & reduce_mask_25; p = (uint32_t)(m9 >> 25); - m0 = r0 + mul32x32_64(p,19); r0 = (uint32_t)m0 & reduce_mask_26; p = (uint32_t)(m0 >> 26); - r1 += p; - } while (--count); - - out[0] = r0; - out[1] = r1; - out[2] = r2; - out[3] = r3; - out[4] = r4; - out[5] = r5; - out[6] = r6; - out[7] = r7; - out[8] = r8; - out[9] = r9; -} - -/* Take a little-endian, 32-byte number and expand it into polynomial form */ -void curve25519_expand(bignum25519 out, const unsigned char in[32]) { - uint32_t x0 = 0, x1 = 0, x2 = 0, x3 = 0, x4 = 0, x5 = 0, x6 = 0, x7 = 0; - #define F(s) \ - ((((uint32_t)in[s + 0]) ) | \ - (((uint32_t)in[s + 1]) << 8) | \ - (((uint32_t)in[s + 2]) << 16) | \ - (((uint32_t)in[s + 3]) << 24)) - x0 = F(0); - x1 = F(4); - x2 = F(8); - x3 = F(12); - x4 = F(16); - x5 = F(20); - x6 = F(24); - x7 = F(28); - #undef F - - out[0] = ( x0 ) & reduce_mask_26; - out[1] = ((((uint64_t)x1 << 32) | x0) >> 26) & reduce_mask_25; - out[2] = ((((uint64_t)x2 << 32) | x1) >> 19) & reduce_mask_26; - out[3] = ((((uint64_t)x3 << 32) | x2) >> 13) & reduce_mask_25; - out[4] = (( x3) >> 6) & reduce_mask_26; - out[5] = ( x4 ) & reduce_mask_25; - out[6] = ((((uint64_t)x5 << 32) | x4) >> 25) & reduce_mask_26; - out[7] = ((((uint64_t)x6 << 32) | x5) >> 19) & reduce_mask_25; - out[8] = ((((uint64_t)x7 << 32) | x6) >> 12) & reduce_mask_26; - out[9] = (( x7) >> 6) & reduce_mask_25; /* ignore the top bit */ -} - -/* Take a fully reduced polynomial form number and contract it into a - * little-endian, 32-byte array - */ -void curve25519_contract(unsigned char out[32], const bignum25519 in) { - bignum25519 f = {0}; - curve25519_copy(f, in); - - #define carry_pass() \ - f[1] += f[0] >> 26; f[0] &= reduce_mask_26; \ - f[2] += f[1] >> 25; f[1] &= reduce_mask_25; \ - f[3] += f[2] >> 26; f[2] &= reduce_mask_26; \ - f[4] += f[3] >> 25; f[3] &= reduce_mask_25; \ - f[5] += f[4] >> 26; f[4] &= reduce_mask_26; \ - f[6] += f[5] >> 25; f[5] &= reduce_mask_25; \ - f[7] += f[6] >> 26; f[6] &= reduce_mask_26; \ - f[8] += f[7] >> 25; f[7] &= reduce_mask_25; \ - f[9] += f[8] >> 26; f[8] &= reduce_mask_26; - - #define carry_pass_full() \ - carry_pass() \ - f[0] += 19 * (f[9] >> 25); f[9] &= reduce_mask_25; - - #define carry_pass_final() \ - carry_pass() \ - f[9] &= reduce_mask_25; - - carry_pass_full() - carry_pass_full() - - /* now t is between 0 and 2^255-1, properly carried. */ - /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ - f[0] += 19; - carry_pass_full() - - /* now between 19 and 2^255-1 in both cases, and offset by 19. */ - f[0] += (reduce_mask_26 + 1) - 19; - f[1] += (reduce_mask_25 + 1) - 1; - f[2] += (reduce_mask_26 + 1) - 1; - f[3] += (reduce_mask_25 + 1) - 1; - f[4] += (reduce_mask_26 + 1) - 1; - f[5] += (reduce_mask_25 + 1) - 1; - f[6] += (reduce_mask_26 + 1) - 1; - f[7] += (reduce_mask_25 + 1) - 1; - f[8] += (reduce_mask_26 + 1) - 1; - f[9] += (reduce_mask_25 + 1) - 1; - - /* now between 2^255 and 2^256-20, and offset by 2^255. */ - carry_pass_final() - - #undef carry_pass - #undef carry_full - #undef carry_final - - f[1] <<= 2; - f[2] <<= 3; - f[3] <<= 5; - f[4] <<= 6; - f[6] <<= 1; - f[7] <<= 3; - f[8] <<= 4; - f[9] <<= 6; - - #define F(i, s) \ - out[s+0] |= (unsigned char )(f[i] & 0xff); \ - out[s+1] = (unsigned char )((f[i] >> 8) & 0xff); \ - out[s+2] = (unsigned char )((f[i] >> 16) & 0xff); \ - out[s+3] = (unsigned char )((f[i] >> 24) & 0xff); - - out[0] = 0; - out[16] = 0; - F(0,0); - F(1,3); - F(2,6); - F(3,9); - F(4,12); - F(5,16); - F(6,19); - F(7,22); - F(8,25); - F(9,28); - #undef F -} - -/* if (iswap) swap(a, b) */ -void curve25519_swap_conditional(bignum25519 a, bignum25519 b, uint32_t iswap) { - const uint32_t swap = (uint32_t)(-(int32_t)iswap); - uint32_t x0 = 0, x1 = 0, x2 = 0, x3 = 0, x4 = 0, x5 = 0, x6 = 0, x7 = 0, x8 = 0, x9 = 0; - - x0 = swap & (a[0] ^ b[0]); a[0] ^= x0; b[0] ^= x0; - x1 = swap & (a[1] ^ b[1]); a[1] ^= x1; b[1] ^= x1; - x2 = swap & (a[2] ^ b[2]); a[2] ^= x2; b[2] ^= x2; - x3 = swap & (a[3] ^ b[3]); a[3] ^= x3; b[3] ^= x3; - x4 = swap & (a[4] ^ b[4]); a[4] ^= x4; b[4] ^= x4; - x5 = swap & (a[5] ^ b[5]); a[5] ^= x5; b[5] ^= x5; - x6 = swap & (a[6] ^ b[6]); a[6] ^= x6; b[6] ^= x6; - x7 = swap & (a[7] ^ b[7]); a[7] ^= x7; b[7] ^= x7; - x8 = swap & (a[8] ^ b[8]); a[8] ^= x8; b[8] ^= x8; - x9 = swap & (a[9] ^ b[9]); a[9] ^= x9; b[9] ^= x9; -} - -void curve25519_set(bignum25519 r, uint32_t x){ - r[0] = x & reduce_mask_26; x >>= 26; - r[1] = x & reduce_mask_25; - r[2] = 0; - r[3] = 0; - r[4] = 0; - r[5] = 0; - r[6] = 0; - r[7] = 0; - r[8] = 0; - r[9] = 0; -} - -void curve25519_set_d(bignum25519 r){ - curve25519_copy(r, ge25519_ecd); -} - -void curve25519_set_2d(bignum25519 r){ - curve25519_copy(r, ge25519_ec2d); -} - -void curve25519_set_sqrtneg1(bignum25519 r){ - curve25519_copy(r, ge25519_sqrtneg1); -} - -int curve25519_isnegative(const bignum25519 f) { - unsigned char s[32] = {0}; - curve25519_contract(s, f); - return s[0] & 1; -} - -int curve25519_isnonzero(const bignum25519 f) { - unsigned char s[32] = {0}; - curve25519_contract(s, f); - return ((((int) (s[0] | s[1] | s[2] | s[3] | s[4] | s[5] | s[6] | s[7] | s[8] | - s[9] | s[10] | s[11] | s[12] | s[13] | s[14] | s[15] | s[16] | s[17] | - s[18] | s[19] | s[20] | s[21] | s[22] | s[23] | s[24] | s[25] | s[26] | - s[27] | s[28] | s[29] | s[30] | s[31]) - 1) >> 8) + 1) & 0x1; -} - -void curve25519_reduce(bignum25519 out, const bignum25519 in) { - uint32_t c = 0; - out[0] = in[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; - out[1] = in[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; - out[2] = in[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; - out[3] = in[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; - out[4] = in[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; - out[5] = in[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; - out[6] = in[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; - out[7] = in[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; - out[8] = in[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; - out[9] = in[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; - out[0] += 19 * c; -} - -void curve25519_divpowm1(bignum25519 r, const bignum25519 u, const bignum25519 v) { - bignum25519 v3={0}, uv7={0}, t0={0}, t1={0}, t2={0}; - int i = 0; - - curve25519_square(v3, v); - curve25519_mul(v3, v3, v); /* v3 = v^3 */ - curve25519_square(uv7, v3); - curve25519_mul(uv7, uv7, v); - curve25519_mul(uv7, uv7, u); /* uv7 = uv^7 */ - - /*fe_pow22523(uv7, uv7);*/ - /* From fe_pow22523.c */ - - curve25519_square(t0, uv7); - curve25519_square(t1, t0); - curve25519_square(t1, t1); - curve25519_mul(t1, uv7, t1); - curve25519_mul(t0, t0, t1); - curve25519_square(t0, t0); - curve25519_mul(t0, t1, t0); - curve25519_square(t1, t0); - for (i = 0; i < 4; ++i) { - curve25519_square(t1, t1); - } - curve25519_mul(t0, t1, t0); - curve25519_square(t1, t0); - for (i = 0; i < 9; ++i) { - curve25519_square(t1, t1); - } - curve25519_mul(t1, t1, t0); - curve25519_square(t2, t1); - for (i = 0; i < 19; ++i) { - curve25519_square(t2, t2); - } - curve25519_mul(t1, t2, t1); - for (i = 0; i < 10; ++i) { - curve25519_square(t1, t1); - } - curve25519_mul(t0, t1, t0); - curve25519_square(t1, t0); - for (i = 0; i < 49; ++i) { - curve25519_square(t1, t1); - } - curve25519_mul(t1, t1, t0); - curve25519_square(t2, t1); - for (i = 0; i < 99; ++i) { - curve25519_square(t2, t2); - } - curve25519_mul(t1, t2, t1); - for (i = 0; i < 50; ++i) { - curve25519_square(t1, t1); - } - curve25519_mul(t0, t1, t0); - curve25519_square(t0, t0); - curve25519_square(t0, t0); - curve25519_mul(t0, t0, uv7); - - /* End fe_pow22523.c */ - /* t0 = (uv^7)^((q-5)/8) */ - curve25519_mul(t0, t0, v3); - curve25519_mul(r, t0, u); /* u^(m+1)v^(-(m+1)) */ -} - -void curve25519_expand_reduce(bignum25519 out, const unsigned char in[32]) { - uint32_t x0 = 0, x1 = 0, x2 = 0, x3 = 0, x4 = 0, x5 = 0, x6 = 0, x7 = 0; -#define F(s) \ - ((((uint32_t)in[s + 0]) ) | \ - (((uint32_t)in[s + 1]) << 8) | \ - (((uint32_t)in[s + 2]) << 16) | \ - (((uint32_t)in[s + 3]) << 24)) - x0 = F(0); - x1 = F(4); - x2 = F(8); - x3 = F(12); - x4 = F(16); - x5 = F(20); - x6 = F(24); - x7 = F(28); -#undef F - - out[0] = ( x0 ) & reduce_mask_26; - out[1] = ((((uint64_t)x1 << 32) | x0) >> 26) & reduce_mask_25; - out[2] = ((((uint64_t)x2 << 32) | x1) >> 19) & reduce_mask_26; - out[3] = ((((uint64_t)x3 << 32) | x2) >> 13) & reduce_mask_25; - out[4] = (( x3) >> 6) & reduce_mask_26; - out[5] = ( x4 ) & reduce_mask_25; - out[6] = ((((uint64_t)x5 << 32) | x4) >> 25) & reduce_mask_26; - out[7] = ((((uint64_t)x6 << 32) | x5) >> 19) & reduce_mask_25; - out[8] = ((((uint64_t)x7 << 32) | x6) >> 12) & reduce_mask_26; - out[9] = (( x7) >> 6); // & reduce_mask_25; /* ignore the top bit */ - out[0] += 19 * (out[9] >> 25); - out[9] &= reduce_mask_25; -} diff --git a/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-32bit.h b/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-32bit.h deleted file mode 100644 index 87bea94f9..000000000 --- a/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-32bit.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - Public domain by Andrew M. - See: https://github.com/floodyberry/curve25519-donna - - 32 bit integer curve25519 implementation -*/ - -typedef uint32_t bignum25519[10]; - -/* out = in */ -void curve25519_copy(bignum25519 out, const bignum25519 in); - -/* out = a + b */ -void curve25519_add(bignum25519 out, const bignum25519 a, const bignum25519 b); - -void curve25519_add_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b); - -void curve25519_add_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b); - -/* out = a - b */ -void curve25519_sub(bignum25519 out, const bignum25519 a, const bignum25519 b); - -/* out = in * scalar */ -void curve25519_scalar_product(bignum25519 out, const bignum25519 in, const uint32_t scalar); - -/* out = a - b, where a is the result of a basic op (add,sub) */ -void curve25519_sub_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b); - -void curve25519_sub_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b); - -/* out = -a */ -void curve25519_neg(bignum25519 out, const bignum25519 a); - -/* out = a * b */ -#define curve25519_mul_noinline curve25519_mul -void curve25519_mul(bignum25519 out, const bignum25519 a, const bignum25519 b); - -/* out = in * in */ -void curve25519_square(bignum25519 out, const bignum25519 in); - -/* out = in ^ (2 * count) */ -void curve25519_square_times(bignum25519 out, const bignum25519 in, int count); - -/* Take a little-endian, 32-byte number and expand it into polynomial form */ -void curve25519_expand(bignum25519 out, const unsigned char in[32]); - -/* Take a fully reduced polynomial form number and contract it into a - * little-endian, 32-byte array - */ -void curve25519_contract(unsigned char out[32], const bignum25519 in); - -/* if (iswap) swap(a, b) */ -void curve25519_swap_conditional(bignum25519 a, bignum25519 b, uint32_t iswap); - -/* uint32_t to Zmod(2^255-19) */ -void curve25519_set(bignum25519 r, uint32_t x); - -/* set d */ -void curve25519_set_d(bignum25519 r); - -/* set 2d */ -void curve25519_set_2d(bignum25519 r); - -/* set sqrt(-1) */ -void curve25519_set_sqrtneg1(bignum25519 r); - -/* constant time Zmod(2^255-19) negative test */ -int curve25519_isnegative(const bignum25519 f); - -/* constant time Zmod(2^255-19) non-zero test */ -int curve25519_isnonzero(const bignum25519 f); - -/* reduce Zmod(2^255-19) */ -void curve25519_reduce(bignum25519 r, const bignum25519 in); - -void curve25519_divpowm1(bignum25519 r, const bignum25519 u, const bignum25519 v); - -/* Zmod(2^255-19) from byte array to bignum25519 expansion with modular reduction */ -void curve25519_expand_reduce(bignum25519 out, const unsigned char in[32]); diff --git a/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-helpers.c b/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-helpers.c deleted file mode 100644 index b18500aab..000000000 --- a/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-helpers.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - Public domain by Andrew M. - See: https://github.com/floodyberry/curve25519-donna - - Curve25519 implementation agnostic helpers -*/ - -#include "ed25519-donna.h" - -/* - * In: b = 2^5 - 2^0 - * Out: b = 2^250 - 2^0 - */ -void curve25519_pow_two5mtwo0_two250mtwo0(bignum25519 b) { - bignum25519 ALIGN(16) t0 = {0}, c = {0}; - - /* 2^5 - 2^0 */ /* b */ - /* 2^10 - 2^5 */ curve25519_square_times(t0, b, 5); - /* 2^10 - 2^0 */ curve25519_mul_noinline(b, t0, b); - /* 2^20 - 2^10 */ curve25519_square_times(t0, b, 10); - /* 2^20 - 2^0 */ curve25519_mul_noinline(c, t0, b); - /* 2^40 - 2^20 */ curve25519_square_times(t0, c, 20); - /* 2^40 - 2^0 */ curve25519_mul_noinline(t0, t0, c); - /* 2^50 - 2^10 */ curve25519_square_times(t0, t0, 10); - /* 2^50 - 2^0 */ curve25519_mul_noinline(b, t0, b); - /* 2^100 - 2^50 */ curve25519_square_times(t0, b, 50); - /* 2^100 - 2^0 */ curve25519_mul_noinline(c, t0, b); - /* 2^200 - 2^100 */ curve25519_square_times(t0, c, 100); - /* 2^200 - 2^0 */ curve25519_mul_noinline(t0, t0, c); - /* 2^250 - 2^50 */ curve25519_square_times(t0, t0, 50); - /* 2^250 - 2^0 */ curve25519_mul_noinline(b, t0, b); -} - -/* - * z^(p - 2) = z(2^255 - 21) - */ -void curve25519_recip(bignum25519 out, const bignum25519 z) { - bignum25519 ALIGN(16) a = {0}, t0 = {0}, b = {0}; - - /* 2 */ curve25519_square_times(a, z, 1); /* a = 2 */ - /* 8 */ curve25519_square_times(t0, a, 2); - /* 9 */ curve25519_mul_noinline(b, t0, z); /* b = 9 */ - /* 11 */ curve25519_mul_noinline(a, b, a); /* a = 11 */ - /* 22 */ curve25519_square_times(t0, a, 1); - /* 2^5 - 2^0 = 31 */ curve25519_mul_noinline(b, t0, b); - /* 2^250 - 2^0 */ curve25519_pow_two5mtwo0_two250mtwo0(b); - /* 2^255 - 2^5 */ curve25519_square_times(b, b, 5); - /* 2^255 - 21 */ curve25519_mul_noinline(out, b, a); -} - -/* - * z^((p-5)/8) = z^(2^252 - 3) - */ -void curve25519_pow_two252m3(bignum25519 two252m3, const bignum25519 z) { - bignum25519 ALIGN(16) b,c,t0; - - /* 2 */ curve25519_square_times(c, z, 1); /* c = 2 */ - /* 8 */ curve25519_square_times(t0, c, 2); /* t0 = 8 */ - /* 9 */ curve25519_mul_noinline(b, t0, z); /* b = 9 */ - /* 11 */ curve25519_mul_noinline(c, b, c); /* c = 11 */ - /* 22 */ curve25519_square_times(t0, c, 1); - /* 2^5 - 2^0 = 31 */ curve25519_mul_noinline(b, t0, b); - /* 2^250 - 2^0 */ curve25519_pow_two5mtwo0_two250mtwo0(b); - /* 2^252 - 2^2 */ curve25519_square_times(b, b, 2); - /* 2^252 - 3 */ curve25519_mul_noinline(two252m3, b, z); -} diff --git a/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-helpers.h b/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-helpers.h deleted file mode 100644 index 62fde9099..000000000 --- a/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-helpers.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - Public domain by Andrew M. - See: https://github.com/floodyberry/curve25519-donna - - Curve25519 implementation agnostic helpers -*/ - -/* - * In: b = 2^5 - 2^0 - * Out: b = 2^250 - 2^0 - */ -void curve25519_pow_two5mtwo0_two250mtwo0(bignum25519 b); - -/* - * z^(p - 2) = z(2^255 - 21) - */ -void curve25519_recip(bignum25519 out, const bignum25519 z); - -/* - * z^((p-5)/8) = z^(2^252 - 3) - */ -void curve25519_pow_two252m3(bignum25519 two252m3, const bignum25519 z); diff --git a/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-scalarmult-base.c b/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-scalarmult-base.c deleted file mode 100644 index 85a5d14b3..000000000 --- a/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-scalarmult-base.c +++ /dev/null @@ -1,67 +0,0 @@ -#include "ed25519-donna.h" -#include "ed25519.h" - -/* Calculates nQ where Q is the x-coordinate of a point on the curve - * - * mypublic: the packed little endian x coordinate of the resulting curve point - * n: a little endian, 32-byte number - * basepoint: a packed little endian point of the curve - */ - -void curve25519_scalarmult_donna(curve25519_key mypublic, const curve25519_key n, const curve25519_key basepoint) { - bignum25519 nqpqx = {1}, nqpqz = {0}, nqz = {1}, nqx = {0}; - bignum25519 q = {0}, qx = {0}, qpqx = {0}, qqx = {0}, zzz = {0}, zmone = {0}; - size_t bit = 0, lastbit = 0; - int32_t i = 0; - - curve25519_expand(q, basepoint); - curve25519_copy(nqx, q); - - /* bit 255 is always 0, and bit 254 is always 1, so skip bit 255 and - start pre-swapped on bit 254 */ - lastbit = 1; - - /* we are doing bits 254..3 in the loop, but are swapping in bits 253..2 */ - for (i = 253; i >= 2; i--) { - curve25519_add(qx, nqx, nqz); - curve25519_sub(nqz, nqx, nqz); - curve25519_add(qpqx, nqpqx, nqpqz); - curve25519_sub(nqpqz, nqpqx, nqpqz); - curve25519_mul(nqpqx, qpqx, nqz); - curve25519_mul(nqpqz, qx, nqpqz); - curve25519_add(qqx, nqpqx, nqpqz); - curve25519_sub(nqpqz, nqpqx, nqpqz); - curve25519_square(nqpqz, nqpqz); - curve25519_square(nqpqx, qqx); - curve25519_mul(nqpqz, nqpqz, q); - curve25519_square(qx, qx); - curve25519_square(nqz, nqz); - curve25519_mul(nqx, qx, nqz); - curve25519_sub(nqz, qx, nqz); - curve25519_scalar_product(zzz, nqz, 121665); - curve25519_add(zzz, zzz, qx); - curve25519_mul(nqz, nqz, zzz); - - bit = (n[i/8] >> (i & 7)) & 1; - curve25519_swap_conditional(nqx, nqpqx, bit ^ lastbit); - curve25519_swap_conditional(nqz, nqpqz, bit ^ lastbit); - lastbit = bit; - } - - /* the final 3 bits are always zero, so we only need to double */ - for (i = 0; i < 3; i++) { - curve25519_add(qx, nqx, nqz); - curve25519_sub(nqz, nqx, nqz); - curve25519_square(qx, qx); - curve25519_square(nqz, nqz); - curve25519_mul(nqx, qx, nqz); - curve25519_sub(nqz, qx, nqz); - curve25519_scalar_product(zzz, nqz, 121665); - curve25519_add(zzz, zzz, qx); - curve25519_mul(nqz, nqz, zzz); - } - - curve25519_recip(zmone, nqz); - curve25519_mul(nqz, nqx, zmone); - curve25519_contract(mypublic, nqz); -} diff --git a/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-scalarmult-base.h b/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-scalarmult-base.h deleted file mode 100644 index 9f3d79895..000000000 --- a/deps/crypto/trezor-crypto/ed25519-donna/curve25519-donna-scalarmult-base.h +++ /dev/null @@ -1,8 +0,0 @@ -/* Calculates nQ where Q is the x-coordinate of a point on the curve - * - * mypublic: the packed little endian x coordinate of the resulting curve point - * n: a little endian, 32-byte number - * basepoint: a packed little endian point of the curve - */ - -void curve25519_scalarmult_donna(curve25519_key mypublic, const curve25519_key n, const curve25519_key basepoint); diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-blake2b.c b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-blake2b.c deleted file mode 100644 index 3223c5543..000000000 --- a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-blake2b.c +++ /dev/null @@ -1,8 +0,0 @@ -#include - -#include "ed25519-blake2b.h" -#include "ed25519-hash-custom-blake2b.h" - -#define ED25519_SUFFIX _blake2b - -#include "ed25519.c" diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-blake2b.h b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-blake2b.h deleted file mode 100644 index 95dc31e80..000000000 --- a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-blake2b.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef ED25519_BLAKE2B_H -#define ED25519_BLAKE2B_H - -#include "ed25519.h" - -#if defined(__cplusplus) -extern "C" { -#endif - -void ed25519_publickey_blake2b(const ed25519_secret_key sk, ed25519_public_key pk); - -int ed25519_sign_open_blake2b(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS); -void ed25519_sign_blake2b(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, ed25519_signature RS); - -int ed25519_scalarmult_blake2b(ed25519_public_key res, const ed25519_secret_key sk, const ed25519_public_key pk); - -#if defined(__cplusplus) -} -#endif - -#endif // ED25519_BLAKE2B_H diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-32bit-tables.c b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-32bit-tables.c deleted file mode 100644 index fd2236b05..000000000 --- a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-32bit-tables.c +++ /dev/null @@ -1,63 +0,0 @@ -#include "ed25519-donna.h" - -const ge25519 ALIGN(16) ge25519_basepoint = { - {0x0325d51a,0x018b5823,0x00f6592a,0x0104a92d,0x01a4b31d,0x01d6dc5c,0x027118fe,0x007fd814,0x013cd6e5,0x0085a4db}, - {0x02666658,0x01999999,0x00cccccc,0x01333333,0x01999999,0x00666666,0x03333333,0x00cccccc,0x02666666,0x01999999}, - {0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000}, - {0x01b7dda3,0x01a2ace9,0x025eadbb,0x0003ba8a,0x0083c27e,0x00abe37d,0x01274732,0x00ccacdd,0x00fd78b7,0x019e1d7c} -}; - -/* - d -*/ - -const bignum25519 ALIGN(16) ge25519_ecd = { - 0x035978a3,0x00d37284,0x03156ebd,0x006a0a0e,0x0001c029,0x0179e898,0x03a03cbb,0x01ce7198,0x02e2b6ff,0x01480db3 -}; - -const bignum25519 ALIGN(16) ge25519_ec2d = { - 0x02b2f159,0x01a6e509,0x022add7a,0x00d4141d,0x00038052,0x00f3d130,0x03407977,0x019ce331,0x01c56dff,0x00901b67 -}; - -/* - sqrt(-1) -*/ - -const bignum25519 ALIGN(16) ge25519_sqrtneg1 = { - 0x020ea0b0,0x0186c9d2,0x008f189d,0x0035697f,0x00bd0c60,0x01fbd7a7,0x02804c9e,0x01e16569,0x0004fc1d,0x00ae0c92 -}; - -const ge25519_niels ALIGN(16) ge25519_niels_sliding_multiples[32] = { - {{0x0340913e,0x000e4175,0x03d673a2,0x002e8a05,0x03f4e67c,0x008f8a09,0x00c21a34,0x004cf4b8,0x01298f81,0x0113f4be},{0x018c3b85,0x0124f1bd,0x01c325f7,0x0037dc60,0x033e4cb7,0x003d42c2,0x01a44c32,0x014ca4e1,0x03a33d4b,0x001f3e74},{0x037aaa68,0x00448161,0x0093d579,0x011e6556,0x009b67a0,0x0143598c,0x01bee5ee,0x00b50b43,0x0289f0c6,0x01bc45ed}}, - {{0x00fcd265,0x0047fa29,0x034faacc,0x01ef2e0d,0x00ef4d4f,0x014bd6bd,0x00f98d10,0x014c5026,0x007555bd,0x00aae456},{0x00ee9730,0x016c2a13,0x017155e4,0x01874432,0x00096a10,0x01016732,0x01a8014f,0x011e9823,0x01b9a80f,0x01e85938},{0x01d0d889,0x01a4cfc3,0x034c4295,0x0110e1ae,0x0162508c,0x00f2db4c,0x0072a2c6,0x0098da2e,0x02f12b9b,0x0168a09a}}, - {{0x0047d6ba,0x0060b0e9,0x0136eff2,0x008a5939,0x03540053,0x0064a087,0x02788e5c,0x00be7c67,0x033eb1b5,0x005529f9},{0x00a5bb33,0x00af1102,0x01a05442,0x001e3af7,0x02354123,0x00bfec44,0x01f5862d,0x00dd7ba3,0x03146e20,0x00a51733},{0x012a8285,0x00f6fc60,0x023f9797,0x003e85ee,0x009c3820,0x01bda72d,0x01b3858d,0x00d35683,0x0296b3bb,0x010eaaf9}}, - {{0x023221b1,0x01cb26aa,0x0074f74d,0x0099ddd1,0x01b28085,0x00192c3a,0x013b27c9,0x00fc13bd,0x01d2e531,0x0075bb75},{0x004ea3bf,0x00973425,0x001a4d63,0x01d59cee,0x01d1c0d4,0x00542e49,0x01294114,0x004fce36,0x029283c9,0x01186fa9},{0x01b8b3a2,0x00db7200,0x00935e30,0x003829f5,0x02cc0d7d,0x0077adf3,0x0220dd2c,0x0014ea53,0x01c6a0f9,0x01ea7eec}}, - {{0x039d8064,0x01885f80,0x00337e6d,0x01b7a902,0x02628206,0x015eb044,0x01e30473,0x0191f2d9,0x011fadc9,0x01270169},{0x02a8632f,0x0199e2a9,0x00d8b365,0x017a8de2,0x02994279,0x0086f5b5,0x0119e4e3,0x01eb39d6,0x0338add7,0x00d2e7b4},{0x0045af1b,0x013a2fe4,0x0245e0d6,0x014538ce,0x038bfe0f,0x01d4cf16,0x037e14c9,0x0160d55e,0x0021b008,0x01cf05c8}}, - {{0x01864348,0x01d6c092,0x0070262b,0x014bb844,0x00fb5acd,0x008deb95,0x003aaab5,0x00eff474,0x00029d5c,0x0062ad66},{0x02802ade,0x01c02122,0x01c4e5f7,0x00781181,0x039767fb,0x01703406,0x0342388b,0x01f5e227,0x022546d8,0x0109d6ab},{0x016089e9,0x00cb317f,0x00949b05,0x01099417,0x000c7ad2,0x011a8622,0x0088ccda,0x01290886,0x022b53df,0x00f71954}}, - {{0x027fbf93,0x01c04ecc,0x01ed6a0d,0x004cdbbb,0x02bbf3af,0x00ad5968,0x01591955,0x0094f3a2,0x02d17602,0x00099e20},{0x02007f6d,0x003088a8,0x03db77ee,0x00d5ade6,0x02fe12ce,0x0107ba07,0x0107097d,0x00482a6f,0x02ec346f,0x008d3f5f},{0x032ea378,0x0028465c,0x028e2a6c,0x018efc6e,0x0090df9a,0x01a7e533,0x039bfc48,0x010c745d,0x03daa097,0x0125ee9b}}, - {{0x028ccf0b,0x00f36191,0x021ac081,0x012154c8,0x034e0a6e,0x01b25192,0x00180403,0x01d7eea1,0x00218d05,0x010ed735},{0x03cfeaa0,0x01b300c4,0x008da499,0x0068c4e1,0x0219230a,0x01f2d4d0,0x02defd60,0x00e565b7,0x017f12de,0x018788a4},{0x03d0b516,0x009d8be6,0x03ddcbb3,0x0071b9fe,0x03ace2bd,0x01d64270,0x032d3ec9,0x01084065,0x0210ae4d,0x01447584}}, - {{0x0020de87,0x00e19211,0x01b68102,0x00b5ac97,0x022873c0,0x01942d25,0x01271394,0x0102073f,0x02fe2482,0x01c69ff9},{0x010e9d81,0x019dbbe5,0x0089f258,0x006e06b8,0x02951883,0x018f1248,0x019b3237,0x00bc7553,0x024ddb85,0x01b4c964},{0x01c8c854,0x0060ae29,0x01406d8e,0x01cff2f9,0x00cff451,0x01778d0c,0x03ac8c41,0x01552e59,0x036559ee,0x011d1b12}}, - {{0x00741147,0x0151b219,0x01092690,0x00e877e6,0x01f4d6bb,0x0072a332,0x01cd3b03,0x00dadff2,0x0097db5e,0x0086598d},{0x01c69a2b,0x01decf1b,0x02c2fa6e,0x013b7c4f,0x037beac8,0x013a16b5,0x028e7bda,0x01f6e8ac,0x01e34fe9,0x01726947},{0x01f10e67,0x003c73de,0x022b7ea2,0x010f32c2,0x03ff776a,0x00142277,0x01d38b88,0x00776138,0x03c60822,0x01201140}}, - {{0x0236d175,0x0008748e,0x03c6476d,0x013f4cdc,0x02eed02a,0x00838a47,0x032e7210,0x018bcbb3,0x00858de4,0x01dc7826},{0x00a37fc7,0x0127b40b,0x01957884,0x011d30ad,0x02816683,0x016e0e23,0x00b76be4,0x012db115,0x02516506,0x0154ce62},{0x00451edf,0x00bd749e,0x03997342,0x01cc2c4c,0x00eb6975,0x01a59508,0x03a516cf,0x00c228ef,0x0168ff5a,0x01697b47}}, - {{0x00527359,0x01783156,0x03afd75c,0x00ce56dc,0x00e4b970,0x001cabe9,0x029e0f6d,0x0188850c,0x0135fefd,0x00066d80},{0x02150e83,0x01448abf,0x02bb0232,0x012bf259,0x033c8268,0x00711e20,0x03fc148f,0x005e0e70,0x017d8bf9,0x0112b2e2},{0x02134b83,0x001a0517,0x0182c3cc,0x00792182,0x0313d799,0x001a3ed7,0x0344547e,0x01f24a0d,0x03de6ad2,0x00543127}}, - {{0x00dca868,0x00618f27,0x015a1709,0x00ddc38a,0x0320fd13,0x0036168d,0x0371ab06,0x01783fc7,0x0391e05f,0x01e29b5d},{0x01471138,0x00fca542,0x00ca31cf,0x01ca7bad,0x0175bfbc,0x01a708ad,0x03bce212,0x01244215,0x0075bb99,0x01acad68},{0x03a0b976,0x01dc12d1,0x011aab17,0x00aba0ba,0x029806cd,0x0142f590,0x018fd8ea,0x01a01545,0x03c4ad55,0x01c971ff}}, - {{0x00d098c0,0x000afdc7,0x006cd230,0x01276af3,0x03f905b2,0x0102994c,0x002eb8a4,0x015cfbeb,0x025f855f,0x01335518},{0x01cf99b2,0x0099c574,0x01a69c88,0x00881510,0x01cd4b54,0x0112109f,0x008abdc5,0x0074647a,0x0277cb1f,0x01e53324},{0x02ac5053,0x01b109b0,0x024b095e,0x016997b3,0x02f26bb6,0x00311021,0x00197885,0x01d0a55a,0x03b6fcc8,0x01c020d5}}, - {{0x02584a34,0x00e7eee0,0x03257a03,0x011e95a3,0x011ead91,0x00536202,0x00b1ce24,0x008516c6,0x03669d6d,0x004ea4a8},{0x00773f01,0x0019c9ce,0x019f6171,0x01d4afde,0x02e33323,0x01ad29b6,0x02ead1dc,0x01ed51a5,0x01851ad0,0x001bbdfa},{0x00577de5,0x00ddc730,0x038b9952,0x00f281ae,0x01d50390,0x0002e071,0x000780ec,0x010d448d,0x01f8a2af,0x00f0a5b7}}, - {{0x031f2541,0x00d34bae,0x0323ff9d,0x003a056d,0x02e25443,0x00a1ad05,0x00d1bee8,0x002f7f8e,0x03007477,0x002a24b1},{0x0114a713,0x01457e76,0x032255d5,0x01cc647f,0x02a4bdef,0x0153d730,0x00118bcf,0x00f755ff,0x013490c7,0x01ea674e},{0x02bda3e8,0x00bb490d,0x00f291ea,0x000abf40,0x01dea321,0x002f9ce0,0x00b2b193,0x00fa54b5,0x0128302f,0x00a19d8b}}, - {{0x022ef5bd,0x01638af3,0x038c6f8a,0x01a33a3d,0x039261b2,0x01bb89b8,0x010bcf9d,0x00cf42a9,0x023d6f17,0x01da1bca},{0x00e35b25,0x000d824f,0x0152e9cf,0x00ed935d,0x020b8460,0x01c7b83f,0x00c969e5,0x01a74198,0x0046a9d9,0x00cbc768},{0x01597c6a,0x0144a99b,0x00a57551,0x0018269c,0x023c464c,0x0009b022,0x00ee39e1,0x0114c7f2,0x038a9ad2,0x01584c17}}, - {{0x03b0c0d5,0x00b30a39,0x038a6ce4,0x01ded83a,0x01c277a6,0x01010a61,0x0346d3eb,0x018d995e,0x02f2c57c,0x000c286b},{0x0092aed1,0x0125e37b,0x027ca201,0x001a6b6b,0x03290f55,0x0047ba48,0x018d916c,0x01a59062,0x013e35d4,0x0002abb1},{0x003ad2aa,0x007ddcc0,0x00c10f76,0x0001590b,0x002cfca6,0x000ed23e,0x00ee4329,0x00900f04,0x01c24065,0x0082fa70}}, - {{0x02025e60,0x003912b8,0x0327041c,0x017e5ee5,0x02c0ecec,0x015a0d1c,0x02b1ce7c,0x0062220b,0x0145067e,0x01a5d931},{0x009673a6,0x00e1f609,0x00927c2a,0x016faa37,0x01650ef0,0x016f63b5,0x03cd40e1,0x003bc38f,0x0361f0ac,0x01d42acc},{0x02f81037,0x008ca0e8,0x017e23d1,0x011debfe,0x01bcbb68,0x002e2563,0x03e8add6,0x000816e5,0x03fb7075,0x0153e5ac}}, - {{0x02b11ecd,0x016bf185,0x008f22ef,0x00e7d2bb,0x0225d92e,0x00ece785,0x00508873,0x017e16f5,0x01fbe85d,0x01e39a0e},{0x01669279,0x017c810a,0x024941f5,0x0023ebeb,0x00eb7688,0x005760f1,0x02ca4146,0x0073cde7,0x0052bb75,0x00f5ffa7},{0x03b8856b,0x00cb7dcd,0x02f14e06,0x001820d0,0x01d74175,0x00e59e22,0x03fba550,0x00484641,0x03350088,0x01c3c9a3}}, - {{0x00dcf355,0x0104481c,0x0022e464,0x01f73fe7,0x00e03325,0x0152b698,0x02ef769a,0x00973663,0x00039b8c,0x0101395b},{0x01805f47,0x019160ec,0x03832cd0,0x008b06eb,0x03d4d717,0x004cb006,0x03a75b8f,0x013b3d30,0x01cfad88,0x01f034d1},{0x0078338a,0x01c7d2e3,0x02bc2b23,0x018b3f05,0x0280d9aa,0x005f3d44,0x0220a95a,0x00eeeb97,0x0362aaec,0x00835d51}}, - {{0x01b9f543,0x013fac4d,0x02ad93ae,0x018ef464,0x0212cdf7,0x01138ba9,0x011583ab,0x019c3d26,0x028790b4,0x00e2e2b6},{0x033bb758,0x01f0dbf1,0x03734bd1,0x0129b1e5,0x02b3950e,0x003bc922,0x01a53ec8,0x018c5532,0x006f3cee,0x00ae3c79},{0x0351f95d,0x0012a737,0x03d596b8,0x017658fe,0x00ace54a,0x008b66da,0x0036c599,0x012a63a2,0x032ceba1,0x00126bac}}, - {{0x03dcfe7e,0x019f4f18,0x01c81aee,0x0044bc2b,0x00827165,0x014f7c13,0x03b430f0,0x00bf96cc,0x020c8d62,0x01471997},{0x01fc7931,0x001f42dd,0x00ba754a,0x005bd339,0x003fbe49,0x016b3930,0x012a159c,0x009f83b0,0x03530f67,0x01e57b85},{0x02ecbd81,0x0096c294,0x01fce4a9,0x017701a5,0x0175047d,0x00ee4a31,0x012686e5,0x008efcd4,0x0349dc54,0x01b3466f}}, - {{0x02179ca3,0x01d86414,0x03f0afd0,0x00305964,0x015c7428,0x0099711e,0x015d5442,0x00c71014,0x01b40b2e,0x01d483cf},{0x01afc386,0x01984859,0x036203ff,0x0045c6a8,0x0020a8aa,0x00990baa,0x03313f10,0x007ceede,0x027429e4,0x017806ce},{0x039357a1,0x0142f8f4,0x0294a7b6,0x00eaccf4,0x0259edb3,0x01311e6e,0x004d326f,0x0130c346,0x01ccef3c,0x01c424b2}}, - {{0x0364918c,0x00148fc0,0x01638a7b,0x01a1fd5b,0x028ad013,0x0081e5a4,0x01a54f33,0x0174e101,0x003d0257,0x003a856c},{0x00051dcf,0x00f62b1d,0x0143d0ad,0x0042adbd,0x000fda90,0x01743ceb,0x0173e5e4,0x017bc749,0x03b7137a,0x0105ce96},{0x00f9218a,0x015b8c7c,0x00e102f8,0x0158d7e2,0x0169a5b8,0x00b2f176,0x018b347a,0x014cfef2,0x0214a4e3,0x017f1595}}, - {{0x006d7ae5,0x0195c371,0x0391e26d,0x0062a7c6,0x003f42ab,0x010dad86,0x024f8198,0x01542b2a,0x0014c454,0x0189c471},{0x0390988e,0x00b8799d,0x02e44912,0x0078e2e6,0x00075654,0x01923eed,0x0040cd72,0x00a37c76,0x0009d466,0x00c8531d},{0x02651770,0x00609d01,0x0286c265,0x0134513c,0x00ee9281,0x005d223c,0x035c760c,0x00679b36,0x0073ecb8,0x016faa50}}, - {{0x02c89be4,0x016fc244,0x02f38c83,0x018beb72,0x02b3ce2c,0x0097b065,0x034f017b,0x01dd957f,0x00148f61,0x00eab357},{0x0343d2f8,0x003398fc,0x011e368e,0x00782a1f,0x00019eea,0x00117b6f,0x0128d0d1,0x01a5e6bb,0x01944f1b,0x012b41e1},{0x03318301,0x018ecd30,0x0104d0b1,0x0038398b,0x03726701,0x019da88c,0x002d9769,0x00a7a681,0x031d9028,0x00ebfc32}}, - {{0x0220405e,0x0171face,0x02d930f8,0x017f6d6a,0x023b8c47,0x0129d5f9,0x02972456,0x00a3a524,0x006f4cd2,0x004439fa},{0x00c53505,0x0190c2fd,0x00507244,0x009930f9,0x01a39270,0x01d327c6,0x0399bc47,0x01cfe13d,0x0332bd99,0x00b33e7d},{0x0203f5e4,0x003627b5,0x00018af8,0x01478581,0x004a2218,0x002e3bb7,0x039384d0,0x0146ea62,0x020b9693,0x0017155f}}, - {{0x03c97e6f,0x00738c47,0x03b5db1f,0x01808fcf,0x01e8fc98,0x01ed25dd,0x01bf5045,0x00eb5c2b,0x0178fe98,0x01b85530},{0x01c20eb0,0x01aeec22,0x030b9eee,0x01b7d07e,0x0187e16f,0x014421fb,0x009fa731,0x0040b6d7,0x00841861,0x00a27fbc},{0x02d69abf,0x0058cdbf,0x0129f9ec,0x013c19ae,0x026c5b93,0x013a7fe7,0x004bb2ba,0x0063226f,0x002a95ca,0x01abefd9}}, - {{0x02f5d2c1,0x00378318,0x03734fb5,0x01258073,0x0263f0f6,0x01ad70e0,0x01b56d06,0x01188fbd,0x011b9503,0x0036d2e1},{0x0113a8cc,0x01541c3e,0x02ac2bbc,0x01d95867,0x01f47459,0x00ead489,0x00ab5b48,0x01db3b45,0x00edb801,0x004b024f},{0x00b8190f,0x011fe4c2,0x00621f82,0x010508d7,0x001a5a76,0x00c7d7fd,0x03aab96d,0x019cd9dc,0x019c6635,0x00ceaa1e}}, - {{0x01085cf2,0x01fd47af,0x03e3f5e1,0x004b3e99,0x01e3d46a,0x0060033c,0x015ff0a8,0x0150cdd8,0x029e8e21,0x008cf1bc},{0x00156cb1,0x003d623f,0x01a4f069,0x00d8d053,0x01b68aea,0x01ca5ab6,0x0316ae43,0x0134dc44,0x001c8d58,0x0084b343},{0x0318c781,0x0135441f,0x03a51a5e,0x019293f4,0x0048bb37,0x013d3341,0x0143151e,0x019c74e1,0x00911914,0x0076ddde}}, - {{0x006bc26f,0x00d48e5f,0x00227bbe,0x00629ea8,0x01ea5f8b,0x0179a330,0x027a1d5f,0x01bf8f8e,0x02d26e2a,0x00c6b65e},{0x01701ab6,0x0051da77,0x01b4b667,0x00a0ce7c,0x038ae37b,0x012ac852,0x03a0b0fe,0x0097c2bb,0x00a017d2,0x01eb8b2a},{0x0120b962,0x0005fb42,0x0353b6fd,0x0061f8ce,0x007a1463,0x01560a64,0x00e0a792,0x01907c92,0x013a6622,0x007b47f1}} -}; diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-32bit-tables.h b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-32bit-tables.h deleted file mode 100644 index f76a832cf..000000000 --- a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-32bit-tables.h +++ /dev/null @@ -1,17 +0,0 @@ -extern const ge25519 ALIGN(16) ge25519_basepoint; - -/* - d -*/ - -extern const bignum25519 ALIGN(16) ge25519_ecd; - -extern const bignum25519 ALIGN(16) ge25519_ec2d; - -/* - sqrt(-1) -*/ - -extern const bignum25519 ALIGN(16) ge25519_sqrtneg1; - -extern const ge25519_niels ALIGN(16) ge25519_niels_sliding_multiples[32]; diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-basepoint-table.c b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-basepoint-table.c deleted file mode 100644 index cd5d18728..000000000 --- a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-basepoint-table.c +++ /dev/null @@ -1,261 +0,0 @@ -#include "ed25519-donna.h" - -/* multiples of the base point in packed {ysubx, xaddy, t2d} form */ -const uint8_t ALIGN(16) ge25519_niels_base_multiples[256][96] = { - {0x3e,0x91,0x40,0xd7,0x05,0x39,0x10,0x9d,0xb3,0xbe,0x40,0xd1,0x05,0x9f,0x39,0xfd,0x09,0x8a,0x8f,0x68,0x34,0x84,0xc1,0xa5,0x67,0x12,0xf8,0x98,0x92,0x2f,0xfd,0x44,0x85,0x3b,0x8c,0xf5,0xc6,0x93,0xbc,0x2f,0x19,0x0e,0x8c,0xfb,0xc6,0x2d,0x93,0xcf,0xc2,0x42,0x3d,0x64,0x98,0x48,0x0b,0x27,0x65,0xba,0xd4,0x33,0x3a,0x9d,0xcf,0x07,0x59,0xbb,0x6f,0x4b,0x67,0x15,0xbd,0xdb,0xea,0xa5,0xa2,0xee,0x00,0x3f,0xe1,0x41,0xfa,0xc6,0x57,0xc9,0x1c,0x9d,0xd4,0xcd,0xca,0xec,0x16,0xaf,0x1f,0xbe,0x0e,0x4f}, - {0xa8,0xd5,0xb4,0x42,0x60,0xa5,0x99,0x8a,0xf6,0xac,0x60,0x4e,0x0c,0x81,0x2b,0x8f,0xaa,0x37,0x6e,0xb1,0x6b,0x23,0x9e,0xe0,0x55,0x25,0xc9,0x69,0xa6,0x95,0xb5,0x6b,0xd7,0x71,0x3c,0x93,0xfc,0xe7,0x24,0x92,0xb5,0xf5,0x0f,0x7a,0x96,0x9d,0x46,0x9f,0x02,0x07,0xd6,0xe1,0x65,0x9a,0xa6,0x5a,0x2e,0x2e,0x7d,0xa8,0x3f,0x06,0x0c,0x59,0x02,0x68,0xd3,0xda,0xaa,0x7e,0x34,0x6e,0x05,0x48,0xee,0x83,0x93,0x59,0xf3,0xba,0x26,0x68,0x07,0xe6,0x10,0xbe,0xca,0x3b,0xb8,0xd1,0x5e,0x16,0x0a,0x4f,0x31,0x49}, - {0x65,0xd2,0xfc,0xa4,0xe8,0x1f,0x61,0x56,0x7d,0xba,0xc1,0xe5,0xfd,0x53,0xd3,0x3b,0xbd,0xd6,0x4b,0x21,0x1a,0xf3,0x31,0x81,0x62,0xda,0x5b,0x55,0x87,0x15,0xb9,0x2a,0x30,0x97,0xee,0x4c,0xa8,0xb0,0x25,0xaf,0x8a,0x4b,0x86,0xe8,0x30,0x84,0x5a,0x02,0x32,0x67,0x01,0x9f,0x02,0x50,0x1b,0xc1,0xf4,0xf8,0x80,0x9a,0x1b,0x4e,0x16,0x7a,0x34,0x48,0x67,0xf1,0xf4,0x11,0xf2,0x9b,0x95,0xf8,0x2d,0xf6,0x17,0x6b,0x4e,0xb8,0x4e,0x2a,0x72,0x5b,0x07,0x6f,0xde,0xd7,0x21,0x2a,0xbb,0x63,0xb9,0x04,0x9a,0x54}, - {0xbf,0x18,0x68,0x05,0x0a,0x05,0xfe,0x95,0xa9,0xfa,0x60,0x56,0x71,0x89,0x7e,0x32,0x73,0x50,0xa0,0x06,0xcd,0xe3,0xe8,0xc3,0x9a,0xa4,0x45,0x74,0x4c,0x3f,0x93,0x27,0x9f,0x09,0xfc,0x8e,0xb9,0x51,0x73,0x28,0x38,0x25,0xfd,0x7d,0xf4,0xc6,0x65,0x67,0x65,0x92,0x0a,0xfb,0x3d,0x8d,0x34,0xca,0x27,0x87,0xe5,0x21,0x03,0x91,0x0e,0x68,0xb0,0x26,0x14,0xe5,0xec,0x45,0x1e,0xbf,0x94,0x0f,0xba,0x6d,0x3d,0xc6,0x2b,0xe3,0xc0,0x52,0xf8,0x8c,0xd5,0x74,0x29,0xe4,0x18,0x4c,0xe6,0xb0,0xb1,0x79,0xf0,0x44}, - {0xba,0xd6,0x47,0xa4,0xc3,0x82,0x91,0x7f,0xb7,0x29,0x27,0x4b,0xd1,0x14,0x00,0xd5,0x87,0xa0,0x64,0xb8,0x1c,0xf1,0x3c,0xe3,0xf3,0x55,0x1b,0xeb,0x73,0x7e,0x4a,0x15,0x33,0xbb,0xa5,0x08,0x44,0xbc,0x12,0xa2,0x02,0xed,0x5e,0xc7,0xc3,0x48,0x50,0x8d,0x44,0xec,0xbf,0x5a,0x0c,0xeb,0x1b,0xdd,0xeb,0x06,0xe2,0x46,0xf1,0xcc,0x45,0x29,0xb3,0x03,0xd0,0xe7,0x79,0xa1,0x32,0xc8,0x7e,0x4d,0x12,0x00,0x0a,0x9d,0x72,0x5f,0xf3,0x8f,0x6d,0x0e,0xa1,0xd4,0xc1,0x62,0x98,0x7a,0xb2,0x38,0x59,0xac,0xb8,0x68}, - {0xa4,0x8c,0x7d,0x7b,0xb6,0x06,0x98,0x49,0x39,0x27,0xd2,0x27,0x84,0xe2,0x5b,0x57,0xb9,0x53,0x45,0x20,0xe7,0x5c,0x08,0xbb,0x84,0x78,0x41,0xae,0x41,0x4c,0xb6,0x38,0x31,0x71,0x15,0x77,0xeb,0xee,0x0c,0x3a,0x88,0xaf,0xc8,0x00,0x89,0x15,0x27,0x9b,0x36,0xa7,0x59,0xda,0x68,0xb6,0x65,0x80,0xbd,0x38,0xcc,0xa2,0xb6,0x7b,0xe5,0x51,0xa4,0xe3,0x9d,0x68,0x91,0xad,0x9d,0x8f,0x37,0x91,0xfb,0xf8,0x28,0x24,0x5f,0x17,0x88,0xb9,0xcf,0x9f,0x32,0xb5,0x0a,0x05,0x9f,0xc0,0x54,0x13,0xa2,0xdf,0x65,0x78}, - {0xb1,0x21,0x32,0xaa,0x9a,0x2c,0x6f,0xba,0xa7,0x23,0xba,0x3b,0x53,0x21,0xa0,0x6c,0x3a,0x2c,0x19,0x92,0x4f,0x76,0xea,0x9d,0xe0,0x17,0x53,0x2e,0x5d,0xdd,0x6e,0x1d,0xbf,0xa3,0x4e,0x94,0xd0,0x5c,0x1a,0x6b,0xd2,0xc0,0x9d,0xb3,0x3a,0x35,0x70,0x74,0x49,0x2e,0x54,0x28,0x82,0x52,0xb2,0x71,0x7e,0x92,0x3c,0x28,0x69,0xea,0x1b,0x46,0x36,0xda,0x0f,0xab,0xac,0x8a,0x7a,0x21,0xc8,0x49,0x35,0x3d,0x54,0xc6,0x28,0xa5,0x68,0x75,0xab,0x13,0x8b,0x5b,0xd0,0x37,0x37,0xbc,0x2c,0x3a,0x62,0xef,0x3c,0x23}, - {0xd9,0x34,0x92,0xf3,0xed,0x5d,0xa7,0xe2,0xf9,0x58,0xb5,0xe1,0x80,0x76,0x3d,0x96,0xfb,0x23,0x3c,0x6e,0xac,0x41,0x27,0x2c,0xc3,0x01,0x0e,0x32,0xa1,0x24,0x90,0x3a,0x8f,0x3e,0xdd,0x04,0x66,0x59,0xb7,0x59,0x2c,0x70,0x88,0xe2,0x77,0x03,0xb3,0x6c,0x23,0xc3,0xd9,0x5e,0x66,0x9c,0x33,0xb1,0x2f,0xe5,0xbc,0x61,0x60,0xe7,0x15,0x09,0x7e,0xa3,0x34,0xa8,0x35,0xe8,0x7d,0xdf,0xea,0x57,0x98,0x68,0xda,0x9c,0xe1,0x8b,0x26,0xb3,0x67,0x71,0x36,0x85,0x11,0x2c,0xc2,0xd5,0xef,0xdb,0xd9,0xb3,0x9e,0x58}, - {0x5e,0x51,0xaa,0x49,0x54,0x63,0x5b,0xed,0x3a,0x82,0xc6,0x0b,0x9f,0xc4,0x65,0xa8,0xc4,0xd1,0x42,0x5b,0xe9,0x1f,0x0c,0x85,0xb9,0x15,0xd3,0x03,0x6f,0x6d,0xd7,0x30,0x1d,0x9c,0x2f,0x63,0x0e,0xdd,0xcc,0x2e,0x15,0x31,0x89,0x76,0x96,0xb6,0xd0,0x51,0x58,0x7a,0x63,0xa8,0x6b,0xb7,0xdf,0x52,0x39,0xef,0x0e,0xa0,0x49,0x7d,0xd3,0x6d,0xc7,0xe4,0x06,0x21,0x17,0x44,0x44,0x6c,0x69,0x7f,0x8d,0x92,0x80,0xd6,0x53,0xfb,0x26,0x3f,0x4d,0x69,0xa4,0x9e,0x73,0xb4,0xb0,0x4b,0x86,0x2e,0x11,0x97,0xc6,0x10}, - {0xde,0x5f,0xbe,0x7d,0x27,0xc4,0x93,0x64,0xa2,0x7e,0xad,0x19,0xad,0x4f,0x5d,0x26,0x90,0x45,0x30,0x46,0xc8,0xdf,0x00,0x0e,0x09,0xfe,0x66,0xed,0xab,0x1c,0xe6,0x25,0x05,0xc8,0x58,0x83,0xa0,0x2a,0xa6,0x0c,0x47,0x42,0x20,0x7a,0xe3,0x4a,0x3d,0x6a,0xdc,0xed,0x11,0x3b,0xa6,0xd3,0x64,0x74,0xef,0x06,0x08,0x55,0xaf,0x9b,0xbf,0x03,0x04,0x66,0x58,0xcc,0x28,0xe1,0x13,0x3f,0x7e,0x74,0x59,0xb4,0xec,0x73,0x58,0x6f,0xf5,0x68,0x12,0xcc,0xed,0x3d,0xb6,0xa0,0x2c,0xe2,0x86,0x45,0x63,0x78,0x6d,0x56}, - {0x34,0x08,0xc1,0x9c,0x9f,0xa4,0x37,0x16,0x51,0xc4,0x9b,0xa8,0xd5,0x56,0x8e,0xbc,0xdb,0xd2,0x7f,0x7f,0x0f,0xec,0xb5,0x1c,0xd9,0x35,0xcc,0x5e,0xca,0x5b,0x97,0x33,0xd0,0x2f,0x5a,0xc6,0x85,0x42,0x05,0xa1,0xc3,0x67,0x16,0xf3,0x2a,0x11,0x64,0x6c,0x58,0xee,0x1a,0x73,0x40,0xe2,0x0a,0x68,0x2a,0xb2,0x93,0x47,0xf3,0xa5,0xfb,0x14,0xd4,0xf7,0x85,0x69,0x16,0x46,0xd7,0x3c,0x57,0x00,0xc8,0xc9,0x84,0x5e,0x3e,0x59,0x1e,0x13,0x61,0x7b,0xb6,0xf2,0xc3,0x2f,0x6c,0x52,0xfc,0x83,0xea,0x9c,0x82,0x14}, - {0xc2,0x95,0xdd,0x97,0x84,0x7b,0x43,0xff,0xa7,0xb5,0x4e,0xaa,0x30,0x4e,0x74,0x6c,0x8b,0xe8,0x85,0x3c,0x61,0x5d,0x0c,0x9e,0x73,0x81,0x75,0x5f,0x1e,0xc7,0xd9,0x2f,0xb8,0xec,0x71,0x4e,0x2f,0x0b,0xe7,0x21,0xe3,0x77,0xa4,0x40,0xb9,0xdd,0x56,0xe6,0x80,0x4f,0x1d,0xce,0xce,0x56,0x65,0xbf,0x7e,0x7b,0x5d,0x53,0xc4,0x3b,0xfc,0x05,0xdd,0xde,0xaf,0x52,0xae,0xb3,0xb8,0x24,0xcf,0x30,0x3b,0xed,0x8c,0x63,0x95,0x34,0x95,0x81,0xbe,0xa9,0x83,0xbc,0xa4,0x33,0x04,0x1f,0x65,0x5c,0x47,0x67,0x37,0x37}, - {0xd9,0xad,0xd1,0x40,0xfd,0x99,0xba,0x2f,0x27,0xd0,0xf4,0x96,0x6f,0x16,0x07,0xb3,0xae,0x3b,0xf0,0x15,0x52,0xf0,0x63,0x43,0x99,0xf9,0x18,0x3b,0x6c,0xa5,0xbe,0x1f,0x90,0x65,0x24,0x14,0xcb,0x95,0x40,0x63,0x35,0x55,0xc1,0x16,0x40,0x14,0x12,0xef,0x60,0xbc,0x10,0x89,0x0c,0x14,0x38,0x9e,0x8c,0x7c,0x90,0x30,0x57,0x90,0xf5,0x6b,0x8a,0x5b,0x41,0xe1,0xf1,0x78,0xa7,0x0f,0x7e,0xa7,0xc3,0xba,0xf7,0x9f,0x40,0x06,0x50,0x9a,0xa2,0x9a,0xb8,0xd7,0x52,0x6f,0x56,0x5a,0x63,0x7a,0xf6,0x1c,0x52,0x02}, - {0x94,0x52,0x9d,0x0a,0x0b,0xee,0x3f,0x51,0x66,0x5a,0xdf,0x0f,0x5c,0xe7,0x98,0x8f,0xce,0x07,0xe1,0xbf,0x88,0x86,0x61,0xd4,0xed,0x2c,0x38,0x71,0x7e,0x0a,0xa0,0x3f,0xe4,0x5e,0x2f,0x77,0x20,0x67,0x14,0xb1,0xce,0x9a,0x07,0x96,0xb1,0x94,0xf8,0xe8,0x4a,0x82,0xac,0x00,0x4d,0x22,0xf8,0x4a,0xc4,0x6c,0xcd,0xf7,0xd9,0x53,0x17,0x00,0x34,0xdb,0x3d,0x96,0x2d,0x23,0x69,0x3c,0x58,0x38,0x97,0xb4,0xda,0x87,0xde,0x1d,0x85,0xf2,0x91,0xa0,0xf9,0xd1,0xd7,0xaa,0xb6,0xed,0x48,0xa0,0x2f,0xfe,0xb5,0x12}, - {0x4d,0xe3,0xfc,0x96,0xc4,0xfb,0xf0,0x71,0xed,0x5b,0xf3,0xad,0x6b,0x82,0xb9,0x73,0x61,0xc5,0x28,0xff,0x61,0x72,0x04,0xd2,0x6f,0x20,0xb1,0x6f,0xf9,0x76,0x9b,0x74,0x92,0x1e,0x6f,0xad,0x26,0x7c,0x2b,0xdf,0x13,0x89,0x4b,0x50,0x23,0xd3,0x66,0x4b,0xc3,0x8b,0x1c,0x75,0xc0,0x9d,0x40,0x8c,0xb8,0xc7,0x96,0x07,0xc2,0x93,0x7e,0x6f,0x05,0xae,0xa6,0xae,0x04,0xf6,0x5a,0x1f,0x99,0x9c,0xe4,0xbe,0xf1,0x51,0x23,0xc1,0x66,0x6b,0xff,0xee,0xb5,0x08,0xa8,0x61,0x51,0x21,0xe0,0x01,0x0f,0xc1,0xce,0x0f}, - {0x44,0x1e,0xfe,0x49,0xa6,0x58,0x4d,0x64,0x7e,0x77,0xad,0x31,0xa2,0xae,0xfc,0x21,0xd2,0xd0,0x7f,0x88,0x5a,0x1c,0x44,0x02,0xf3,0x11,0xc5,0x83,0x71,0xaa,0x01,0x49,0x45,0x4e,0x24,0xc4,0x9d,0xd2,0xf2,0x3d,0x0a,0xde,0xd8,0x93,0x74,0x0e,0x02,0x2b,0x4d,0x21,0x0c,0x82,0x7e,0x06,0xc8,0x6c,0x0a,0xb9,0xea,0x6f,0x16,0x79,0x37,0x41,0xf0,0xf8,0x1a,0x8c,0x54,0xb7,0xb1,0x08,0xb4,0x99,0x62,0x24,0x7c,0x7a,0x0f,0xce,0x39,0xd9,0x06,0x1e,0xf9,0xb0,0x60,0xf7,0x13,0x12,0x6d,0x72,0x7b,0x88,0xbb,0x41}, - {0xbe,0x46,0x43,0x74,0x44,0x7d,0xe8,0x40,0x25,0x2b,0xb5,0x15,0xd4,0xda,0x48,0x1d,0x3e,0x60,0x3b,0xa1,0x18,0x8a,0x3a,0x7c,0xf7,0xbd,0xcd,0x2f,0xc1,0x28,0xb7,0x4e,0xae,0x91,0x66,0x7c,0x59,0x4c,0x23,0x7e,0xc8,0xb4,0x85,0x0a,0x3d,0x9d,0x88,0x64,0xe7,0xfa,0x4a,0x35,0x0c,0xc9,0xe2,0xda,0x1d,0x9e,0x6a,0x0c,0x07,0x1e,0x87,0x0a,0x89,0x89,0xbc,0x4b,0x99,0xb5,0x01,0x33,0x60,0x42,0xdd,0x5b,0x3a,0xae,0x6b,0x73,0x3c,0x9e,0xd5,0x19,0xe2,0xad,0x61,0x0d,0x64,0xd4,0x85,0x26,0x0f,0x30,0xe7,0x3e}, - {0xb7,0xd6,0x7d,0x9e,0xe4,0x55,0xd2,0xf5,0xac,0x1e,0x0b,0x61,0x5c,0x11,0x16,0x80,0xca,0x87,0xe1,0x92,0x5d,0x97,0x99,0x3c,0xc2,0x25,0x91,0x97,0x62,0x57,0x81,0x13,0x18,0x75,0x1e,0x84,0x47,0x79,0xfa,0x43,0xd7,0x46,0x9c,0x63,0x59,0xfa,0xc6,0xe5,0x74,0x2b,0x05,0xe3,0x1d,0x5e,0x06,0xa1,0x30,0x90,0xb8,0xcf,0xa2,0xc6,0x47,0x7d,0xe0,0xd6,0xf0,0x8e,0x14,0xd0,0xda,0x3f,0x3c,0x6f,0x54,0x91,0x9a,0x74,0x3e,0x9d,0x57,0x81,0xbb,0x26,0x10,0x62,0xec,0x71,0x80,0xec,0xc9,0x34,0x8d,0xf5,0x8c,0x14}, - {0x27,0xf0,0x34,0x79,0xf6,0x92,0xa4,0x46,0xa9,0x0a,0x84,0xf6,0xbe,0x84,0x99,0x46,0x54,0x18,0x61,0x89,0x2a,0xbc,0xa1,0x5c,0xd4,0xbb,0x5d,0xbd,0x1e,0xfa,0xf2,0x3f,0x6d,0x75,0xe4,0x9a,0x7d,0x2f,0x57,0xe2,0x7f,0x48,0xf3,0x88,0xbb,0x45,0xc3,0x56,0x8d,0xa8,0x60,0x69,0x6d,0x0b,0xd1,0x9f,0xb9,0xa1,0xae,0x4e,0xad,0xeb,0x8f,0x27,0x66,0x39,0x93,0x8c,0x1f,0x68,0xaa,0xb1,0x98,0x0c,0x29,0x20,0x9c,0x94,0x21,0x8c,0x52,0x3c,0x9d,0x21,0x91,0x52,0x11,0x39,0x7b,0x67,0x9c,0xfe,0x02,0xdd,0x04,0x41}, - {0x2a,0x42,0x24,0x11,0x5e,0xbf,0xb2,0x72,0xb5,0x3a,0xa3,0x98,0x33,0x0c,0xfa,0xa1,0x66,0xb6,0x52,0xfa,0x01,0x61,0xcb,0x94,0xd5,0x53,0xaf,0xaf,0x00,0x3b,0x86,0x2c,0xb8,0x6a,0x09,0xdb,0x06,0x4e,0x21,0x81,0x35,0x4f,0xe4,0x0c,0xc9,0xb6,0xa8,0x21,0xf5,0x2a,0x9e,0x40,0x2a,0xc1,0x24,0x65,0x81,0xa4,0xfc,0x8e,0xa4,0xb5,0x65,0x01,0x76,0x6a,0x84,0xa0,0x74,0xa4,0x90,0xf1,0xc0,0x7c,0x2f,0xcd,0x84,0xf9,0xef,0x12,0x8f,0x2b,0xaa,0x58,0x06,0x29,0x5e,0x69,0xb8,0xc8,0xfe,0xbf,0xd9,0x67,0x1b,0x59}, - {0xfa,0x9b,0xb4,0x80,0x1c,0x0d,0x2f,0x31,0x8a,0xec,0xf3,0xab,0x5e,0x51,0x79,0x59,0x88,0x1c,0xf0,0x9e,0xc0,0x33,0x70,0x72,0xcb,0x7b,0x8f,0xca,0xc7,0x2e,0xe0,0x3d,0x5d,0xb5,0x18,0x9f,0x71,0xb3,0xb9,0x99,0x1e,0x64,0x8c,0xa1,0xfa,0xe5,0x65,0xe4,0xed,0x05,0x9f,0xc2,0x36,0x11,0x08,0x61,0x8b,0x12,0x30,0x70,0x86,0x4f,0x9b,0x48,0xef,0x92,0xeb,0x3a,0x2d,0x10,0x32,0xd2,0x61,0xa8,0x16,0x61,0xb4,0x53,0x62,0xe1,0x24,0xaa,0x0b,0x19,0xe7,0xab,0x7e,0x3d,0xbf,0xbe,0x6c,0x49,0xba,0xfb,0xf5,0x49}, - {0xd4,0xcf,0x5b,0x8a,0x10,0x9a,0x94,0x30,0xeb,0x73,0x64,0xbc,0x70,0xdd,0x40,0xdc,0x1c,0x0d,0x7c,0x30,0xc1,0x94,0xc2,0x92,0x74,0x6e,0xfa,0xcb,0x6d,0xa8,0x04,0x56,0x2e,0x57,0x9c,0x1e,0x8c,0x62,0x5d,0x15,0x41,0x47,0x88,0xc5,0xac,0x86,0x4d,0x8a,0xeb,0x63,0x57,0x51,0xf6,0x52,0xa3,0x91,0x5b,0x51,0x67,0x88,0xc2,0xa6,0xa1,0x06,0xb6,0x64,0x17,0x7c,0xd4,0xd1,0x88,0x72,0x51,0x8b,0x41,0xe0,0x40,0x11,0x54,0x72,0xd1,0xf6,0xac,0x18,0x60,0x1a,0x03,0x9f,0xc6,0x42,0x27,0xfe,0x89,0x9e,0x98,0x20}, - {0x7f,0xcc,0x2d,0x3a,0xfd,0x77,0x97,0x49,0x92,0xd8,0x4f,0xa5,0x2c,0x7c,0x85,0x32,0xa0,0xe3,0x07,0xd2,0x64,0xd8,0x79,0xa2,0x29,0x7e,0xa6,0x0c,0x1d,0xed,0x03,0x04,0x2e,0xec,0xea,0x85,0x8b,0x27,0x74,0x16,0xdf,0x2b,0xcb,0x7a,0x07,0xdc,0x21,0x56,0x5a,0xf4,0xcb,0x61,0x16,0x4c,0x0a,0x64,0xd3,0x95,0x05,0xf7,0x50,0x99,0x0b,0x73,0x52,0xc5,0x4e,0x87,0x35,0x2d,0x4b,0xc9,0x8d,0x6f,0x24,0x98,0xcf,0xc8,0xe6,0xc5,0xce,0x35,0xc0,0x16,0xfa,0x46,0xcb,0xf7,0xcc,0x3d,0x30,0x08,0x43,0x45,0xd7,0x5b}, - {0xc2,0x4c,0xb2,0x28,0x95,0xd1,0x9a,0x7f,0x81,0xc1,0x35,0x63,0x65,0x54,0x6b,0x7f,0x36,0x72,0xc0,0x4f,0x6e,0xb6,0xb8,0x66,0x83,0xad,0x80,0x73,0x00,0x78,0x3a,0x13,0x2a,0x79,0xe7,0x15,0x21,0x93,0xc4,0x85,0xc9,0xdd,0xcd,0xbd,0xa2,0x89,0x4c,0xc6,0x62,0xd7,0xa3,0xad,0xa8,0x3d,0x1e,0x9d,0x2c,0xf8,0x67,0x30,0x12,0xdb,0xb7,0x5b,0xbe,0x62,0xca,0xc6,0x67,0xf4,0x61,0x09,0xee,0x52,0x19,0x21,0xd6,0x21,0xec,0x04,0x70,0x47,0xd5,0x9b,0x77,0x60,0x23,0x18,0xd2,0xe0,0xf0,0x58,0x6d,0xca,0x0d,0x74}, - {0x4e,0xce,0xcf,0x52,0x07,0xee,0x48,0xdf,0xb7,0x08,0xec,0x06,0xf3,0xfa,0xff,0xc3,0xc4,0x59,0x54,0xb9,0x2a,0x0b,0x71,0x05,0x8d,0xa3,0x3e,0x96,0xfa,0x25,0x1d,0x16,0x3c,0x43,0x78,0x04,0x57,0x8c,0x1a,0x23,0x9d,0x43,0x81,0xc2,0x0e,0x27,0xb5,0xb7,0x9f,0x07,0xd9,0xe3,0xea,0x99,0xaa,0xdb,0xd9,0x03,0x2b,0x6c,0x25,0xf5,0x03,0x2c,0x7d,0xa4,0x53,0x7b,0x75,0x18,0x0f,0x79,0x79,0x58,0x0c,0xcf,0x30,0x01,0x7b,0x30,0xf9,0xf7,0x7e,0x25,0x77,0x3d,0x90,0x31,0xaf,0xbb,0x96,0xbd,0xbd,0x68,0x94,0x69}, - {0xcf,0xfe,0xda,0xf4,0x46,0x2f,0x1f,0xbd,0xf7,0xd6,0x7f,0xa4,0x14,0x01,0xef,0x7c,0x7f,0xb3,0x47,0x4a,0xda,0xfd,0x1f,0xd3,0x85,0x57,0x90,0x73,0xa4,0x19,0x52,0x52,0x48,0x19,0xa9,0x6a,0xe6,0x3d,0xdd,0xd8,0xcc,0xd2,0xc0,0x2f,0xc2,0x64,0x50,0x48,0x2f,0xea,0xfd,0x34,0x66,0x24,0x48,0x9b,0x3a,0x2e,0x4a,0x6c,0x4e,0x1c,0x3e,0x29,0xe1,0x12,0x51,0x92,0x4b,0x13,0x6e,0x37,0xa0,0x5d,0xa1,0xdc,0xb5,0x78,0x37,0x70,0x11,0x31,0x1c,0x46,0xaf,0x89,0x45,0xb0,0x23,0x28,0x03,0x7f,0x44,0x5c,0x60,0x5b}, - {0x89,0x7c,0xc4,0x20,0x59,0x80,0x65,0xb9,0xcc,0x8f,0x3b,0x92,0x0c,0x10,0xf0,0xe7,0x77,0xef,0xe2,0x02,0x65,0x25,0x01,0x00,0xee,0xb3,0xae,0xa8,0xce,0x6d,0xa7,0x24,0x4c,0xf0,0xe7,0xf0,0xc6,0xfe,0xe9,0x3b,0x62,0x49,0xe3,0x75,0x9e,0x57,0x6a,0x86,0x1a,0xe6,0x1d,0x1e,0x16,0xef,0x42,0x55,0xd5,0xbd,0x5a,0xcc,0xf4,0xfe,0x12,0x2f,0x40,0xc7,0xc0,0xdf,0xb2,0x22,0x45,0x0a,0x07,0xa4,0xc9,0x40,0x7f,0x6e,0xd0,0x10,0x68,0xf6,0xcf,0x78,0x41,0x14,0xcf,0xc6,0x90,0x37,0xa4,0x18,0x25,0x7b,0x60,0x5e}, - {0x18,0x18,0xdf,0x6c,0x8f,0x1d,0xb3,0x58,0xa2,0x58,0x62,0xc3,0x4f,0xa7,0xcf,0x35,0x6e,0x1d,0xe6,0x66,0x4f,0xff,0xb3,0xe1,0xf7,0xd5,0xcd,0x6c,0xab,0xac,0x67,0x50,0x14,0xcf,0x96,0xa5,0x1c,0x43,0x2c,0xa0,0x00,0xe4,0xd3,0xae,0x40,0x2d,0xc4,0xe3,0xdb,0x26,0x0f,0x2e,0x80,0x26,0x45,0xd2,0x68,0x70,0x45,0x9e,0x13,0x33,0x1f,0x20,0x51,0x9d,0x03,0x08,0x6b,0x7f,0x52,0xfd,0x06,0x00,0x7c,0x01,0x64,0x49,0xb1,0x18,0xa8,0xa4,0x25,0x2e,0xb0,0x0e,0x22,0xd5,0x75,0x03,0x46,0x62,0x88,0xba,0x7c,0x39}, - {0xb2,0x59,0x59,0xf0,0x93,0x30,0xc1,0x30,0x76,0x79,0xa9,0xe9,0x8d,0xa1,0x3a,0xe2,0x26,0x5e,0x1d,0x72,0x91,0xd4,0x2f,0x22,0x3a,0x6c,0x6e,0x76,0x20,0xd3,0x39,0x23,0xe7,0x79,0x13,0xc8,0xfb,0xc3,0x15,0x78,0xf1,0x2a,0xe1,0xdd,0x20,0x94,0x61,0xa6,0xd5,0xfd,0xa8,0x85,0xf8,0xc0,0xa9,0xff,0x52,0xc2,0xe1,0xc1,0x22,0x40,0x1b,0x77,0xa7,0x2f,0x3a,0x51,0x86,0xd9,0x7d,0xd8,0x08,0xcf,0xd4,0xf9,0x71,0x9b,0xac,0xf5,0xb3,0x83,0xa2,0x1e,0x1b,0xc3,0x6b,0xd0,0x76,0x1a,0x97,0x19,0x92,0x18,0x1a,0x33}, - {0xc6,0x80,0x4f,0xfb,0x45,0x6f,0x16,0xf5,0xcf,0x75,0xc7,0x61,0xde,0xc7,0x36,0x9c,0x1c,0xd9,0x41,0x90,0x1b,0xe8,0xd4,0xe3,0x21,0xfe,0xbd,0x83,0x6b,0x7c,0x16,0x31,0xaf,0x72,0x75,0x9d,0x3a,0x2f,0x51,0x26,0x9e,0x4a,0x07,0x68,0x88,0xe2,0xcb,0x5b,0xc4,0xf7,0x80,0x11,0xc1,0xc1,0xed,0x84,0x7b,0xa6,0x49,0xf6,0x9f,0x61,0xc9,0x1a,0x68,0x10,0x4b,0x52,0x42,0x38,0x2b,0xf2,0x87,0xe9,0x9c,0xee,0x3b,0x34,0x68,0x50,0xc8,0x50,0x62,0x4a,0x84,0x71,0x9d,0xfc,0x11,0xb1,0x08,0x1f,0x34,0x36,0x24,0x61}, - {0x8d,0x89,0x4e,0x87,0xdb,0x41,0x9d,0xd9,0x20,0xdc,0x07,0x6c,0xf1,0xa5,0xfe,0x09,0xbc,0x9b,0x0f,0xd0,0x67,0x2c,0x3d,0x79,0x40,0xff,0x5e,0x9e,0x30,0xe2,0xeb,0x46,0x38,0x26,0x2d,0x1a,0xe3,0x49,0x63,0x8b,0x35,0xfd,0xd3,0x9b,0x00,0xb7,0xdf,0x9d,0xa4,0x6b,0xa0,0xa3,0xb8,0xf1,0x8b,0x7f,0x45,0x04,0xd9,0x78,0x31,0xaa,0x22,0x15,0x38,0x49,0x61,0x69,0x53,0x2f,0x38,0x2c,0x10,0x6d,0x2d,0xb7,0x9a,0x40,0xfe,0xda,0x27,0xf2,0x46,0xb6,0x91,0x33,0xc8,0xe8,0x6c,0x30,0x24,0x05,0xf5,0x70,0xfe,0x45}, - {0x8c,0x0b,0x0c,0x96,0xa6,0x75,0x48,0xda,0x20,0x2f,0x0e,0xef,0x76,0xd0,0x68,0x5b,0xd4,0x8f,0x0b,0x3d,0xcf,0x51,0xfb,0x07,0xd4,0x92,0xe3,0xa0,0x23,0x16,0x8d,0x42,0x91,0x14,0x95,0xc8,0x20,0x49,0xf2,0x62,0xa2,0x0c,0x63,0x3f,0xc8,0x07,0xf0,0x05,0xb8,0xd4,0xc9,0xf5,0xd2,0x45,0xbb,0x6f,0x45,0x22,0x7a,0xb5,0x6d,0x9f,0x61,0x16,0xfd,0x08,0xa3,0x01,0x44,0x4a,0x4f,0x08,0xac,0xca,0xa5,0x76,0xc3,0x19,0x22,0xa8,0x7d,0xbc,0xd1,0x43,0x46,0xde,0xb8,0xde,0xc6,0x38,0xbd,0x60,0x2d,0x59,0x81,0x1d}, - {0x5f,0xac,0x0d,0xa6,0x56,0x87,0x36,0x61,0x57,0xdc,0xab,0xeb,0x6a,0x2f,0xe0,0x17,0x7d,0x0f,0xce,0x4c,0x2d,0x3f,0x19,0x7f,0xf0,0xdc,0xec,0x89,0x77,0x4a,0x23,0x20,0xe8,0xc5,0x85,0x7b,0x9f,0xb6,0x65,0x87,0xb2,0xba,0x68,0xd1,0x8b,0x67,0xf0,0x6f,0x9b,0x0f,0x33,0x1d,0x7c,0xe7,0x70,0x3a,0x7c,0x8e,0xaf,0xb0,0x51,0x6d,0x5f,0x3a,0x52,0xb2,0x78,0x71,0xb6,0x0d,0xd2,0x76,0x60,0xd1,0x1e,0xd5,0xf9,0x34,0x1c,0x07,0x70,0x11,0xe4,0xb3,0x20,0x4a,0x2a,0xf6,0x66,0xe3,0xff,0x3c,0x35,0x82,0xd6,0x7c}, - {0xb6,0xfa,0x87,0xd8,0x5b,0xa4,0xe1,0x0b,0x6e,0x3b,0x40,0xba,0x32,0x6a,0x84,0x2a,0x00,0x60,0x6e,0xe9,0x12,0x10,0x92,0xd9,0x43,0x09,0xdc,0x3b,0x86,0xc8,0x38,0x28,0xf3,0xf4,0xac,0x68,0x60,0xcd,0x65,0xa6,0xd3,0xe3,0xd7,0x3c,0x18,0x2d,0xd9,0x42,0xd9,0x25,0x60,0x33,0x9d,0x38,0x59,0x57,0xff,0xd8,0x2c,0x2b,0x3b,0x25,0xf0,0x3e,0x30,0x50,0x46,0x4a,0xcf,0xb0,0x6b,0xd1,0xab,0x77,0xc5,0x15,0x41,0x6b,0x49,0xfa,0x9d,0x41,0xab,0xf4,0x8a,0xae,0xcf,0x82,0x12,0x28,0xa8,0x06,0xa6,0xb8,0xdc,0x21}, - {0xc8,0x9f,0x9d,0x8c,0x46,0x04,0x60,0x5c,0xcb,0xa3,0x2a,0xd4,0x6e,0x09,0x40,0x25,0x9c,0x2f,0xee,0x12,0x4c,0x4d,0x5b,0x12,0xab,0x1d,0xa3,0x94,0x81,0xd0,0xc3,0x0b,0xba,0x31,0x77,0xbe,0xfa,0x00,0x8d,0x9a,0x89,0x18,0x9e,0x62,0x7e,0x60,0x03,0x82,0x7f,0xd9,0xf3,0x43,0x37,0x02,0xcc,0xb2,0x8b,0x67,0x6f,0x6c,0xbf,0x0d,0x84,0x5d,0x8b,0xe1,0x9f,0x30,0x0d,0x38,0x6e,0x70,0xc7,0x65,0xe1,0xb9,0xa6,0x2d,0xb0,0x6e,0xab,0x20,0xae,0x7d,0x99,0xba,0xbb,0x57,0xdd,0x96,0xc1,0x2a,0x23,0x76,0x42,0x3a}, - {0xfa,0x84,0x70,0x8a,0x2c,0x43,0x42,0x4b,0x45,0xe5,0xb9,0xdf,0xe3,0x19,0x8a,0x89,0x5d,0xe4,0x58,0x9c,0x21,0x00,0x9f,0xbe,0xd1,0xeb,0x6d,0xa1,0xce,0x77,0xf1,0x1f,0xcb,0x7e,0x44,0xdb,0x72,0xc1,0xf8,0x3b,0xbd,0x2d,0x28,0xc6,0x1f,0xc4,0xcf,0x5f,0xfe,0x15,0xaa,0x75,0xc0,0xff,0xac,0x80,0xf9,0xa9,0xe1,0x24,0xe8,0xc9,0x70,0x07,0xfd,0xb5,0xb5,0x45,0x9a,0xd9,0x61,0xcf,0x24,0x79,0x3a,0x1b,0xe9,0x84,0x09,0x86,0x89,0x3e,0x3e,0x30,0x19,0x09,0x30,0xe7,0x1e,0x0b,0x50,0x41,0xfd,0x64,0xf2,0x39}, - {0x9c,0xe2,0xe7,0xdb,0x17,0x34,0xad,0xa7,0x9c,0x13,0x9c,0x2b,0x6a,0x37,0x94,0xbd,0xa9,0x7b,0x59,0x93,0x8e,0x1b,0xe9,0xa0,0x40,0x98,0x88,0x68,0x34,0xd7,0x12,0x17,0xe1,0x7b,0x09,0xfe,0xab,0x4a,0x9b,0xd1,0x29,0x19,0xe0,0xdf,0xe1,0xfc,0x6d,0xa4,0xff,0xf1,0xa6,0x2c,0x94,0x08,0xc9,0xc3,0x4e,0xf1,0x35,0x2c,0x27,0x21,0xc6,0x65,0xdd,0x93,0x31,0xce,0xf8,0x89,0x2b,0xe7,0xbb,0xc0,0x25,0xa1,0x56,0x33,0x10,0x4d,0x83,0xfe,0x1c,0x2e,0x3d,0xa9,0x19,0x04,0x72,0xe2,0x9c,0xb1,0x0a,0x80,0xf9,0x22}, - {0xcb,0xf8,0x9e,0x3e,0x8a,0x36,0x5a,0x60,0x15,0x47,0x50,0xa5,0x22,0xc0,0xe9,0xe3,0x8f,0x24,0x24,0x5f,0xb0,0x48,0x3d,0x55,0xe5,0x26,0x76,0x64,0xcd,0x16,0xf4,0x13,0xac,0xfd,0x6e,0x9a,0xdd,0x9f,0x02,0x42,0x41,0x49,0xa5,0x34,0xbe,0xce,0x12,0xb9,0x7b,0xf3,0xbd,0x87,0xb9,0x64,0x0f,0x64,0xb4,0xca,0x98,0x85,0xd3,0xa4,0x71,0x41,0x8c,0x4c,0xc9,0x99,0xaa,0x58,0x27,0xfa,0x07,0xb8,0x00,0xb0,0x6f,0x6f,0x00,0x23,0x92,0x53,0xda,0xad,0xdd,0x91,0xd2,0xfb,0xab,0xd1,0x4b,0x57,0xfa,0x14,0x82,0x50}, - {0x4b,0xfe,0xd6,0x3e,0x15,0x69,0x02,0xc2,0xc4,0x77,0x1d,0x51,0x39,0x67,0x5a,0xa6,0x94,0xaf,0x14,0x2c,0x46,0x26,0xde,0xcb,0x4b,0xa7,0xab,0x6f,0xec,0x60,0xf9,0x22,0xd6,0x03,0xd0,0x53,0xbb,0x15,0x1a,0x46,0x65,0xc9,0xf3,0xbc,0x88,0x28,0x10,0xb2,0x5a,0x3a,0x68,0x6c,0x75,0x76,0xc5,0x27,0x47,0xb4,0x6c,0xc8,0xa4,0x58,0x77,0x3a,0x76,0x50,0xae,0x93,0xf6,0x11,0x81,0x54,0xa6,0x54,0xfd,0x1d,0xdf,0x21,0xae,0x1d,0x65,0x5e,0x11,0xf3,0x90,0x8c,0x24,0x12,0x94,0xf4,0xe7,0x8d,0x5f,0xd1,0x9f,0x5d}, - {0x7f,0x72,0x63,0x6d,0xd3,0x08,0x14,0x03,0x33,0xb5,0xc7,0xd7,0xef,0x9a,0x37,0x6a,0x4b,0xe2,0xae,0xcc,0xc5,0x8f,0xe1,0xa9,0xd3,0xbe,0x8f,0x4f,0x91,0x35,0x2f,0x33,0x1e,0x52,0xd7,0xee,0x2a,0x4d,0x24,0x3f,0x15,0x96,0x2e,0x43,0x28,0x90,0x3a,0x8e,0xd4,0x16,0x9c,0x2e,0x77,0xba,0x64,0xe1,0xd8,0x98,0xeb,0x47,0xfa,0x87,0xc1,0x3b,0x0c,0xc2,0x86,0xea,0x15,0x01,0x47,0x6d,0x25,0xd1,0x46,0x6c,0xcb,0xb7,0x8a,0x99,0x88,0x01,0x66,0x3a,0xb5,0x32,0x78,0xd7,0x03,0xba,0x6f,0x90,0xce,0x81,0x0d,0x45}, - {0x75,0x52,0x20,0xa6,0xa1,0xb6,0x7b,0x6e,0x83,0x8e,0x3c,0x41,0xd7,0x21,0x4f,0xaa,0xb2,0x5c,0x8f,0xe8,0x55,0xd1,0x56,0x6f,0xe1,0x5b,0x34,0xa6,0x4b,0x5d,0xe2,0x2d,0x3f,0x74,0xae,0x1c,0x96,0xd8,0x74,0xd0,0xed,0x63,0x1c,0xee,0xf5,0x18,0x6d,0xf8,0x29,0xed,0xf4,0xe7,0x5b,0xc5,0xbd,0x97,0x08,0xb1,0x3a,0x66,0x79,0xd2,0xba,0x4c,0xcd,0x1f,0xd7,0xa0,0x24,0x90,0xd1,0x80,0xf8,0x8a,0x28,0xfb,0x0a,0xc2,0x25,0xc5,0x19,0x64,0x3a,0x5f,0x4b,0x97,0xa3,0xb1,0x33,0x72,0x00,0xe2,0xef,0xbc,0x7f,0x7d}, - {0x01,0x28,0x6b,0x26,0x6a,0x1e,0xef,0xfa,0x16,0x9f,0x73,0xd5,0xc4,0x68,0x6c,0x86,0x2c,0x76,0x03,0x1b,0xbc,0x2f,0x8a,0xf6,0x8d,0x5a,0xb7,0x87,0x5e,0x43,0x75,0x59,0x94,0x90,0xc2,0xf3,0xc5,0x5d,0x7c,0xcd,0xab,0x05,0x91,0x2a,0x9a,0xa2,0x81,0xc7,0x58,0x30,0x1c,0x42,0x36,0x1d,0xc6,0x80,0xd7,0xd4,0xd8,0xdc,0x96,0xd1,0x9c,0x4f,0x68,0x37,0x7b,0x6a,0xd8,0x97,0x92,0x19,0x63,0x7a,0xd1,0x1a,0x24,0x58,0xd0,0xd0,0x17,0x0c,0x1c,0x5c,0xad,0x9c,0x02,0xba,0x07,0x03,0x7a,0x38,0x84,0xd0,0xcd,0x7c}, - {0x17,0x04,0x26,0x6d,0x2c,0x42,0xa6,0xdc,0xbd,0x40,0x82,0x94,0x50,0x3d,0x15,0xae,0x77,0xc6,0x68,0xfb,0xb4,0xc1,0xc0,0xa9,0x53,0xcf,0xd0,0x61,0xed,0xd0,0x8b,0x42,0x93,0xcc,0x60,0x67,0x18,0x84,0x0c,0x9b,0x99,0x2a,0xb3,0x1a,0x7a,0x00,0xae,0xcd,0x18,0xda,0x0b,0x62,0x86,0xec,0x8d,0xa8,0x44,0xca,0x90,0x81,0x84,0xca,0x93,0x35,0xa7,0x9a,0x84,0x5e,0x9a,0x18,0x13,0x92,0xcd,0xfa,0xd8,0x65,0x35,0xc3,0xd8,0xd4,0xd1,0xbb,0xfd,0x53,0x5b,0x54,0x52,0x8c,0xe6,0x63,0x2d,0xda,0x08,0x83,0x39,0x27}, - {0x13,0xd4,0x5e,0x43,0x28,0x8d,0xc3,0x42,0xc9,0xcc,0x78,0x32,0x60,0xf3,0x50,0xbd,0xef,0x03,0xda,0x79,0x1a,0xab,0x07,0xbb,0x55,0x33,0x8c,0xbe,0xae,0x97,0x95,0x26,0x53,0x24,0x70,0x0a,0x4c,0x0e,0xa1,0xb9,0xde,0x1b,0x7d,0xd5,0x66,0x58,0xa2,0x0f,0xf7,0xda,0x27,0xcd,0xb5,0xd9,0xb9,0xff,0xfd,0x33,0x2c,0x49,0x45,0x29,0x2c,0x57,0xbe,0x30,0xcd,0xd6,0x45,0xc7,0x7f,0xc7,0xfb,0xae,0xba,0xe3,0xd3,0xe8,0xdf,0xe4,0x0c,0xda,0x5d,0xaa,0x30,0x88,0x2c,0xa2,0x80,0xca,0x5b,0xc0,0x98,0x54,0x98,0x7f}, - {0x17,0xe1,0x0b,0x9f,0x88,0xce,0x49,0x38,0x88,0xa2,0x54,0x7b,0x1b,0xad,0x05,0x80,0x1c,0x92,0xfc,0x23,0x9f,0xc3,0xa3,0x3d,0x04,0xf3,0x31,0x0a,0x47,0xec,0xc2,0x76,0x63,0x63,0xbf,0x0f,0x52,0x15,0x56,0xd3,0xa6,0xfb,0x4d,0xcf,0x45,0x5a,0x04,0x08,0xc2,0xa0,0x3f,0x87,0xbc,0x4f,0xc2,0xee,0xe7,0x12,0x9b,0xd6,0x3c,0x65,0xf2,0x30,0x85,0x0c,0xc1,0xaa,0x38,0xc9,0x08,0x8a,0xcb,0x6b,0x27,0xdb,0x60,0x9b,0x17,0x46,0x70,0xac,0x6f,0x0e,0x1e,0xc0,0x20,0xa9,0xda,0x73,0x64,0x59,0xf1,0x73,0x12,0x2f}, - {0x11,0x1e,0xe0,0x8a,0x7c,0xfc,0x39,0x47,0x9f,0xab,0x6a,0x4a,0x90,0x74,0x52,0xfd,0x2e,0x8f,0x72,0x87,0x82,0x8a,0xd9,0x41,0xf2,0x69,0x5b,0xd8,0x2a,0x57,0x9e,0x5d,0xc0,0x0b,0xa7,0x55,0xd7,0x8b,0x48,0x30,0xe7,0x42,0xd4,0xf1,0xa4,0xb5,0xd6,0x06,0x62,0x61,0x59,0xbc,0x9e,0xa6,0xd1,0xea,0x84,0xf7,0xc5,0xed,0x97,0x19,0xac,0x38,0x3b,0xb1,0x51,0xa7,0x17,0xb5,0x66,0x06,0x8c,0x85,0x9b,0x7e,0x86,0x06,0x7d,0x74,0x49,0xde,0x4d,0x45,0x11,0xc0,0xac,0xac,0x9c,0xe6,0xe9,0xbf,0x9c,0xcd,0xdf,0x22}, - {0xd9,0x0c,0x0d,0xc3,0xe0,0xd2,0xdb,0x8d,0x33,0x43,0xbb,0xac,0x5f,0x66,0x8e,0xad,0x1f,0x96,0x2a,0x32,0x8c,0x25,0x6b,0x8f,0xc7,0xc1,0x48,0x54,0xc0,0x16,0x29,0x6b,0xa1,0xe0,0x3b,0x10,0xb4,0x59,0xec,0x56,0x69,0xf9,0x59,0xd2,0xec,0xba,0xe3,0x2e,0x32,0xcd,0xf5,0x13,0x94,0xb2,0x7c,0x79,0x72,0xe4,0xcd,0x24,0x78,0x87,0xe9,0x0f,0x3b,0x91,0xba,0x0a,0xd1,0x34,0xdb,0x7e,0x0e,0xac,0x6d,0x2e,0x82,0xcd,0xa3,0x4e,0x15,0xf8,0x78,0x65,0xff,0x3d,0x08,0x66,0x17,0x0a,0xf0,0x7f,0x30,0x3f,0x30,0x4c}, - {0x85,0x8c,0xb2,0x17,0xd6,0x3b,0x0a,0xd3,0xea,0x3b,0x77,0x39,0xb7,0x77,0xd3,0xc5,0xbf,0x5c,0x6a,0x1e,0x8c,0xe7,0xc6,0xc6,0xc4,0xb7,0x2a,0x8b,0xf7,0xb8,0x61,0x0d,0x00,0x45,0xd9,0x0d,0x58,0x03,0xfc,0x29,0x93,0xec,0xbb,0x6f,0xa4,0x7a,0xd2,0xec,0xf8,0xa7,0xe2,0xc2,0x5f,0x15,0x0a,0x13,0xd5,0xa1,0x06,0xb7,0x1a,0x15,0x6b,0x41,0xb0,0x36,0xc1,0xe9,0xef,0xd7,0xa8,0x56,0x20,0x4b,0xe4,0x58,0xcd,0xe5,0x07,0xbd,0xab,0xe0,0x57,0x1b,0xda,0x2f,0xe6,0xaf,0xd2,0xe8,0x77,0x42,0xf7,0x2a,0x1a,0x19}, - {0x31,0x14,0x3c,0xc5,0x4b,0xf7,0x16,0xce,0xde,0xed,0x72,0x20,0xce,0x25,0x97,0x2b,0xe7,0x3e,0xb2,0xb5,0x6f,0xc3,0xb9,0xb8,0x08,0xc9,0x5c,0x0b,0x45,0x0e,0x2e,0x7e,0xfb,0x0e,0x46,0x4f,0x43,0x2b,0xe6,0x9f,0xd6,0x07,0x36,0xa6,0xd4,0x03,0xd3,0xde,0x24,0xda,0xa0,0xb7,0x0e,0x21,0x52,0xf0,0x93,0x5b,0x54,0x00,0xbe,0x7d,0x7e,0x23,0x30,0xb4,0x01,0x67,0xed,0x75,0x35,0x01,0x10,0xfd,0x0b,0x9f,0xe6,0x94,0x10,0x23,0x22,0x7f,0xe4,0x83,0x15,0x0f,0x32,0x75,0xe3,0x55,0x11,0xb1,0x99,0xa6,0xaf,0x71}, - {0x1d,0xb6,0x53,0x39,0x9b,0x6f,0xce,0x65,0xe6,0x41,0xa1,0xaf,0xea,0x39,0x58,0xc6,0xfe,0x59,0xf7,0xa9,0xfd,0x5f,0x43,0x0f,0x8e,0xc2,0xb1,0xc2,0xe9,0x42,0x11,0x02,0xd6,0x50,0x3b,0x47,0x1c,0x3c,0x42,0xea,0x10,0xef,0x38,0x3b,0x1f,0x7a,0xe8,0x51,0x95,0xbe,0xc9,0xb2,0x5f,0xbf,0x84,0x9b,0x1c,0x9a,0xf8,0x78,0xbc,0x1f,0x73,0x00,0x80,0x18,0xf8,0x48,0x18,0xc7,0x30,0xe4,0x19,0xc1,0xce,0x5e,0x22,0x0c,0x96,0xbf,0xe3,0x15,0xba,0x6b,0x83,0xe0,0xda,0xb6,0x08,0x58,0xe1,0x47,0x33,0x6f,0x4d,0x4c}, - {0xc9,0x1f,0x7d,0xc1,0xcf,0xec,0xf7,0x18,0x14,0x3c,0x40,0x51,0xa6,0xf5,0x75,0x6c,0xdf,0x0c,0xee,0xf7,0x2b,0x71,0xde,0xdb,0x22,0x7a,0xe4,0xa7,0xaa,0xdd,0x3f,0x19,0x70,0x19,0x8f,0x98,0xfc,0xdd,0x0c,0x2f,0x1b,0xf5,0xb9,0xb0,0x27,0x62,0x91,0x6b,0xbe,0x76,0x91,0x77,0xc4,0xb6,0xc7,0x6e,0xa8,0x9f,0x8f,0xa8,0x00,0x95,0xbf,0x38,0x6f,0x87,0xe8,0x37,0x3c,0xc9,0xd2,0x1f,0x2c,0x46,0xd1,0x18,0x5a,0x1e,0xf6,0xa2,0x76,0x12,0x24,0x39,0x82,0xf5,0x80,0x50,0x69,0x49,0x0d,0xbf,0x9e,0xb9,0x6f,0x6a}, - {0xeb,0x55,0x08,0x56,0xbb,0xc1,0x46,0x6a,0x9d,0xf0,0x93,0xf8,0x38,0xbb,0x16,0x24,0xc1,0xac,0x71,0x8f,0x37,0x11,0x1d,0xd7,0xea,0x96,0x18,0xa3,0x14,0x69,0xf7,0x75,0xc6,0x23,0xe4,0xb6,0xb5,0x22,0xb1,0xee,0x8e,0xff,0x86,0xf2,0x10,0x70,0x9d,0x93,0x8c,0x5d,0xcf,0x1d,0x83,0x2a,0xa9,0x90,0x10,0xeb,0xc5,0x42,0x9f,0xda,0x6f,0x13,0xd1,0xbd,0x05,0xa3,0xb1,0xdf,0x4c,0xf9,0x08,0x2c,0xf8,0x9f,0x9d,0x4b,0x36,0x0f,0x8a,0x58,0xbb,0xc3,0xa5,0xd8,0x87,0x2a,0xba,0xdc,0xe8,0x0b,0x51,0x83,0x21,0x02}, - {0x14,0x2d,0xad,0x5e,0x38,0x66,0xf7,0x4a,0x30,0x58,0x7c,0xca,0x80,0xd8,0x8e,0xa0,0x3d,0x1e,0x21,0x10,0xe6,0xa6,0x13,0x0d,0x03,0x6c,0x80,0x7b,0xe1,0x1c,0x07,0x6a,0x7f,0x7a,0x30,0x43,0x01,0x71,0x5a,0x9d,0x5f,0xa4,0x7d,0xc4,0x9e,0xde,0x63,0xb0,0xd3,0x7a,0x92,0xbe,0x52,0xfe,0xbb,0x22,0x6c,0x42,0x40,0xfd,0x41,0xc4,0x87,0x13,0xf8,0x8a,0x97,0x87,0xd1,0xc3,0xd3,0xb5,0x13,0x44,0x0e,0x7f,0x3d,0x5a,0x2b,0x72,0xa0,0x7c,0x47,0xbb,0x48,0x48,0x7b,0x0d,0x92,0xdc,0x1e,0xaf,0x6a,0xb2,0x71,0x31}, - {0xa8,0x4c,0x56,0x97,0x90,0x31,0x2f,0xa9,0x19,0xe1,0x75,0x22,0x4c,0xb8,0x7b,0xff,0x50,0x51,0x87,0xa4,0x37,0xfe,0x55,0x4f,0x5a,0x83,0xf0,0x3c,0x87,0xd4,0x1f,0x22,0xd1,0x47,0x8a,0xb2,0xd8,0xb7,0x0d,0xa6,0xf1,0xa4,0x70,0x17,0xd6,0x14,0xbf,0xa6,0x58,0xbd,0xdd,0x53,0x93,0xf8,0xa1,0xd4,0xe9,0x43,0x42,0x34,0x63,0x4a,0x51,0x6c,0x41,0x63,0x15,0x3a,0x4f,0x20,0x22,0x23,0x2d,0x03,0x0a,0xba,0xe9,0xe0,0x73,0xfb,0x0e,0x03,0x0f,0x41,0x4c,0xdd,0xe0,0xfc,0xaa,0x4a,0x92,0xfb,0x96,0xa5,0xda,0x48}, - {0xc7,0x9c,0xa5,0x5c,0x66,0x8e,0xca,0x6e,0xa0,0xac,0x38,0x2e,0x4b,0x25,0x47,0xa8,0xce,0x17,0x1e,0xd2,0x08,0xc7,0xaf,0x31,0xf7,0x4a,0xd8,0xca,0xfc,0xd6,0x6d,0x67,0x93,0x97,0x4c,0xc8,0x5d,0x1d,0xf6,0x14,0x06,0x82,0x41,0xef,0xe3,0xf9,0x41,0x99,0xac,0x77,0x62,0x34,0x8f,0xb8,0xf5,0xcd,0xa9,0x79,0x8a,0x0e,0xfa,0x37,0xc8,0x58,0x58,0x90,0xfc,0x96,0x85,0x68,0xf9,0x0c,0x1b,0xa0,0x56,0x7b,0xf3,0xbb,0xdc,0x1d,0x6a,0xd6,0x35,0x49,0x7d,0xe7,0xc2,0xdc,0x0a,0x7f,0xa5,0xc6,0xf2,0x73,0x4f,0x1c}, - {0xbb,0xa0,0x5f,0x30,0xbd,0x4f,0x7a,0x0e,0xad,0x63,0xc6,0x54,0xe0,0x4c,0x9d,0x82,0x48,0x38,0xe3,0x2f,0x83,0xc3,0x21,0xf4,0x42,0x4c,0xf6,0x1b,0x0d,0xc8,0x5a,0x79,0x84,0x34,0x7c,0xfc,0x6e,0x70,0x6e,0xb3,0x61,0xcf,0xc1,0xc3,0xb4,0xc9,0xdf,0x73,0xe5,0xc7,0x1c,0x78,0xc9,0x79,0x1d,0xeb,0x5c,0x67,0xaf,0x7d,0xdb,0x9a,0x45,0x70,0xb3,0x2b,0xb4,0x91,0x49,0xdb,0x91,0x1b,0xca,0xdc,0x02,0x4b,0x23,0x96,0x26,0x57,0xdc,0x78,0x8c,0x1f,0xe5,0x9e,0xdf,0x9f,0xd3,0x1f,0xe2,0x8c,0x84,0x62,0xe1,0x5f}, - {0x1a,0x96,0x94,0xe1,0x4f,0x21,0x59,0x4e,0x4f,0xcd,0x71,0x0d,0xc7,0x7d,0xbe,0x49,0x2d,0xf2,0x50,0x3b,0xd2,0xcf,0x00,0x93,0x32,0x72,0x91,0xfc,0x46,0xd4,0x89,0x47,0x08,0xb2,0x7c,0x5d,0x2d,0x85,0x79,0x28,0xe7,0xf2,0x7d,0x68,0x70,0xdd,0xde,0xb8,0x91,0x78,0x68,0x21,0xab,0xff,0x0b,0xdc,0x35,0xaa,0x7d,0x67,0x43,0xc0,0x44,0x2b,0x8e,0xb7,0x4e,0x07,0xab,0x87,0x1c,0x1a,0x67,0xf4,0xda,0x99,0x8e,0xd1,0xc6,0xfa,0x67,0x90,0x4f,0x48,0xcd,0xbb,0xac,0x3e,0xe4,0xa4,0xb9,0x2b,0xef,0x2e,0xc5,0x60}, - {0xf1,0x8b,0xfd,0x3b,0xbc,0x89,0x5d,0x0b,0x1a,0x55,0xf3,0xc9,0x37,0x92,0x6b,0xb0,0xf5,0x28,0x30,0xd5,0xb0,0x16,0x4c,0x0e,0xab,0xca,0xcf,0x2c,0x31,0x9c,0xbc,0x10,0x11,0x6d,0xae,0x7c,0xc2,0xc5,0x2b,0x70,0xab,0x8c,0xa4,0x54,0x9b,0x69,0xc7,0x44,0xb2,0x2e,0x49,0xba,0x56,0x40,0xbc,0xef,0x6d,0x67,0xb6,0xd9,0x48,0x72,0xd7,0x70,0x5b,0xa0,0xc2,0x3e,0x4b,0xe8,0x8a,0xaa,0xe0,0x81,0x17,0xed,0xf4,0x9e,0x69,0x98,0xd1,0x85,0x8e,0x70,0xe4,0x13,0x45,0x79,0x13,0xf4,0x76,0xa9,0xd3,0x5b,0x75,0x63}, - {0x53,0x08,0xd1,0x2a,0x3e,0xa0,0x5f,0xb5,0x69,0x35,0xe6,0x9e,0x90,0x75,0x6f,0x35,0x90,0xb8,0x69,0xbe,0xfd,0xf1,0xf9,0x9f,0x84,0x6f,0xc1,0x8b,0xc4,0xc1,0x8c,0x0d,0xb7,0xac,0xf1,0x97,0x18,0x10,0xc7,0x3d,0xd8,0xbb,0x65,0xc1,0x5e,0x7d,0xda,0x5d,0x0f,0x02,0xa1,0x0f,0x9c,0x5b,0x8e,0x50,0x56,0x2a,0xc5,0x37,0x17,0x75,0x63,0x27,0xa9,0x19,0xb4,0x6e,0xd3,0x02,0x94,0x02,0xa5,0x60,0xb4,0x77,0x7e,0x4e,0xb4,0xf0,0x56,0x49,0x3c,0xd4,0x30,0x62,0xa8,0xcf,0xe7,0x66,0xd1,0x7a,0x8a,0xdd,0xc2,0x70}, - {0x0e,0xec,0x6f,0x9f,0x50,0x94,0x61,0x65,0x8d,0x51,0xc6,0x46,0xa9,0x7e,0x2e,0xee,0x5c,0x9b,0xe0,0x67,0xf3,0xc1,0x33,0x97,0x95,0x84,0x94,0x63,0x63,0xac,0x0f,0x2e,0x13,0x7e,0xed,0xb8,0x7d,0x96,0xd4,0x91,0x7a,0x81,0x76,0xd7,0x0a,0x2f,0x25,0x74,0x64,0x25,0x85,0x0d,0xe0,0x82,0x09,0xe4,0xe5,0x3c,0xa5,0x16,0x38,0x61,0xb8,0x32,0x64,0xcd,0x48,0xe4,0xbe,0xf7,0xe7,0x79,0xd0,0x86,0x78,0x08,0x67,0x3a,0xc8,0x6a,0x2e,0xdb,0xe4,0xa0,0xd9,0xd4,0x9f,0xf8,0x41,0x4f,0x5a,0x73,0x5c,0x21,0x79,0x41}, - {0x2a,0xed,0xdc,0xd7,0xe7,0x94,0x70,0x8c,0x70,0x9c,0xd3,0x47,0xc3,0x8a,0xfb,0x97,0x02,0xd9,0x06,0xa9,0x33,0xe0,0x3b,0xe1,0x76,0x9d,0xd9,0x0c,0xa3,0x44,0x03,0x70,0x34,0xcd,0x6b,0x28,0xb9,0x33,0xae,0xe4,0xdc,0xd6,0x9d,0x55,0xb6,0x7e,0xef,0xb7,0x1f,0x8e,0xd3,0xb3,0x1f,0x14,0x8b,0x27,0x86,0xc2,0x41,0x22,0x66,0x85,0xfa,0x31,0xf4,0x22,0x36,0x2e,0x42,0x6c,0x82,0xaf,0x2d,0x50,0x33,0x98,0x87,0x29,0x20,0xc1,0x23,0x91,0x38,0x2b,0xe1,0xb7,0xc1,0x9b,0x89,0x24,0x95,0xa9,0x12,0x23,0xbb,0x24}, - {0xc3,0x67,0xde,0x32,0x17,0xed,0xa8,0xb1,0x48,0x49,0x1b,0x46,0x18,0x94,0xb4,0x3c,0xd2,0xbc,0xcf,0x76,0x43,0x43,0xbd,0x8e,0x08,0x80,0x18,0x1e,0x87,0x3e,0xee,0x0f,0x6b,0x5c,0xf8,0xf5,0x2a,0x0c,0xf8,0x41,0x94,0x67,0xfa,0x04,0xc3,0x84,0x72,0x68,0xad,0x1b,0xba,0xa3,0x99,0xdf,0x45,0x89,0x16,0x5d,0xeb,0xff,0xf9,0x2a,0x1d,0x0d,0xdf,0x1e,0x62,0x32,0xa1,0x8a,0xda,0xa9,0x79,0x65,0x22,0x59,0xa1,0x22,0xb8,0x30,0x93,0xc1,0x9a,0xa7,0x7b,0x19,0x04,0x40,0x76,0x1d,0x53,0x18,0x97,0xd7,0xac,0x16}, - {0x3d,0x1d,0x9b,0x2d,0xaf,0x72,0xdf,0x72,0x5a,0x24,0x32,0xa4,0x36,0x2a,0x46,0x63,0x37,0x96,0xb3,0x16,0x79,0xa0,0xce,0x3e,0x09,0x23,0x30,0xb9,0xf6,0x0e,0x3e,0x12,0xad,0xb6,0x87,0x78,0xc5,0xc6,0x59,0xc9,0xba,0xfe,0x90,0x5f,0xad,0x9e,0xe1,0x94,0x04,0xf5,0x42,0xa3,0x62,0x4e,0xe2,0x16,0x00,0x17,0x16,0x18,0x4b,0xd3,0x4e,0x16,0x9a,0xe6,0x2f,0x19,0x4c,0xd9,0x7e,0x48,0x13,0x15,0x91,0x3a,0xea,0x2c,0xae,0x61,0x27,0xde,0xa4,0xb9,0xd3,0xf6,0x7b,0x87,0xeb,0xf3,0x73,0x10,0xc6,0x0f,0xda,0x78}, - {0x6a,0xc6,0x2b,0xe5,0x28,0x5d,0xf1,0x5b,0x8e,0x1a,0xf0,0x70,0x18,0xe3,0x47,0x2c,0xdd,0x8b,0xc2,0x06,0xbc,0xaf,0x19,0x24,0x3a,0x17,0x6b,0x25,0xeb,0xde,0x25,0x2d,0x94,0x3a,0x0c,0x68,0xf1,0x80,0x9f,0xa2,0xe6,0xe7,0xe9,0x1a,0x15,0x7e,0xf7,0x71,0x73,0x79,0x01,0x48,0x58,0xf1,0x00,0x11,0xdd,0x8d,0xb3,0x16,0xb3,0xa4,0x4a,0x05,0xb8,0x7c,0x26,0x19,0x8d,0x46,0xc8,0xdf,0xaf,0x4d,0xe5,0x66,0x9c,0x78,0x28,0x0b,0x17,0xec,0x6e,0x66,0x2a,0x1d,0xeb,0x2a,0x60,0xa7,0x7d,0xab,0xa6,0x10,0x46,0x13}, - {0xfe,0xb0,0xf6,0x8d,0xc7,0x8e,0x13,0x51,0x1b,0xf5,0x75,0xe5,0x89,0xda,0x97,0x53,0xb9,0xf1,0x7a,0x71,0x1d,0x7a,0x20,0x09,0x50,0xd6,0x20,0x2b,0xba,0xfd,0x02,0x21,0x15,0xf5,0xd1,0x77,0xe7,0x65,0x2a,0xcd,0xf1,0x60,0xaa,0x8f,0x87,0x91,0x89,0x54,0xe5,0x06,0xbc,0xda,0xbc,0x3b,0xb7,0xb1,0xfb,0xc9,0x7c,0xa9,0xcb,0x78,0x48,0x65,0xa1,0xe6,0x5c,0x05,0x05,0xe4,0x9e,0x96,0x29,0xad,0x51,0x12,0x68,0xa7,0xbc,0x36,0x15,0xa4,0x7d,0xaa,0x17,0xf5,0x1a,0x3a,0xba,0xb2,0xec,0x29,0xdb,0x25,0xd7,0x0a}, - {0x57,0x24,0x4e,0x83,0xb1,0x67,0x42,0xdc,0xc5,0x1b,0xce,0x70,0xb5,0x44,0x75,0xb6,0xd7,0x5e,0xd1,0xf7,0x0b,0x7a,0xf0,0x1a,0x50,0x36,0xa0,0x71,0xfb,0xcf,0xef,0x4a,0x85,0x6f,0x05,0x9b,0x0c,0xbc,0xc7,0xfe,0xd7,0xff,0xf5,0xe7,0x68,0x52,0x7d,0x53,0xfa,0xae,0x12,0x43,0x62,0xc6,0xaf,0x77,0xd9,0x9f,0x39,0x02,0x53,0x5f,0x67,0x4f,0x1e,0x17,0x15,0x04,0x36,0x36,0x2d,0xc3,0x3b,0x48,0x98,0x89,0x11,0xef,0x2b,0xcd,0x10,0x51,0x94,0xd0,0xad,0x6e,0x0a,0x87,0x61,0x65,0xa8,0xa2,0x72,0xbb,0xcc,0x0b}, - {0xc8,0xa9,0xb1,0xea,0x2f,0x96,0x5e,0x18,0xcd,0x7d,0x14,0x65,0x35,0xe6,0xe7,0x86,0xf2,0x6d,0x5b,0xbb,0x31,0xe0,0x92,0xb0,0x3e,0xb7,0xd6,0x59,0xab,0xf0,0x24,0x40,0x96,0x12,0xfe,0x50,0x4c,0x5e,0x6d,0x18,0x7e,0x9f,0xe8,0xfe,0x82,0x7b,0x39,0xe0,0xb0,0x31,0x70,0x50,0xc5,0xf6,0xc7,0x3b,0xc2,0x37,0x8f,0x10,0x69,0xfd,0x78,0x66,0xc2,0x63,0x68,0x63,0x31,0xfa,0x86,0x15,0xf2,0x33,0x2d,0x57,0x48,0x8c,0xf6,0x07,0xfc,0xae,0x9e,0x78,0x9f,0xcc,0x73,0x4f,0x01,0x47,0xad,0x8e,0x10,0xe2,0x42,0x2d}, - {0x9b,0xd2,0xdf,0x94,0x15,0x13,0xf5,0x97,0x6a,0x4c,0x3f,0x31,0x5d,0x98,0x55,0x61,0x10,0x50,0x45,0x08,0x07,0x3f,0xa1,0xeb,0x22,0xd3,0xd2,0xb8,0x08,0x26,0x6b,0x67,0x93,0x75,0x53,0x0f,0x0d,0x7b,0x71,0x21,0x4c,0x06,0x1e,0x13,0x0b,0x69,0x4e,0x91,0x9f,0xe0,0x2a,0x75,0xae,0x87,0xb6,0x1b,0x6e,0x3c,0x42,0x9b,0xa7,0xf3,0x0b,0x42,0x47,0x2b,0x5b,0x1c,0x65,0xba,0x38,0x81,0x80,0x1b,0x1b,0x31,0xec,0xb6,0x71,0x86,0xb0,0x35,0x31,0xbc,0xb1,0x0c,0xff,0x7b,0xe0,0xf1,0x0c,0x9c,0xfa,0x2f,0x5d,0x74}, - {0xbd,0xc8,0xc9,0x2b,0x1e,0x5a,0x52,0xbf,0x81,0x9d,0x47,0x26,0x08,0x26,0x5b,0xea,0xdb,0x55,0x01,0xdf,0x0e,0xc7,0x11,0xd5,0xd0,0xf5,0x0c,0x96,0xeb,0x3c,0xe2,0x1a,0x6a,0x4e,0xd3,0x21,0x57,0xdf,0x36,0x60,0xd0,0xb3,0x7b,0x99,0x27,0x88,0xdb,0xb1,0xfa,0x6a,0x75,0xc8,0xc3,0x09,0xc2,0xd3,0x39,0xc8,0x1d,0x4c,0xe5,0x5b,0xe1,0x06,0x4a,0x99,0x32,0x19,0x87,0x5d,0x72,0x5b,0xb0,0xda,0xb1,0xce,0xb5,0x1c,0x35,0x32,0x05,0xca,0xb7,0xda,0x49,0x15,0xc4,0x7d,0xf7,0xc1,0x8e,0x27,0x61,0xd8,0xde,0x58}, - {0x5c,0xc5,0x66,0xf2,0x93,0x37,0x17,0xd8,0x49,0x4e,0x45,0xcc,0xc5,0x76,0xc9,0xc8,0xa8,0xc3,0x26,0xbc,0xf8,0x82,0xe3,0x5c,0xf9,0xf6,0x85,0x54,0xe8,0x9d,0xf3,0x2f,0xa8,0xc9,0xc2,0xb6,0xa8,0x5b,0xfb,0x2d,0x8c,0x59,0x2c,0xf5,0x8e,0xef,0xee,0x48,0x73,0x15,0x2d,0xf1,0x07,0x91,0x80,0x33,0xd8,0x5b,0x1d,0x53,0x6b,0x69,0xba,0x08,0x7a,0xc5,0xef,0xc3,0xee,0x3e,0xed,0x77,0x11,0x48,0xff,0xd4,0x17,0x55,0xe0,0x04,0xcb,0x71,0xa6,0xf1,0x3f,0x7a,0x3d,0xea,0x54,0xfe,0x7c,0x94,0xb4,0x33,0x06,0x12}, - {0x42,0x00,0x61,0x91,0x78,0x98,0x94,0x0b,0xe8,0xfa,0xeb,0xec,0x3c,0xb1,0xe7,0x4e,0xc0,0xa4,0xf0,0x94,0x95,0x73,0xbe,0x70,0x85,0x91,0xd5,0xb4,0x99,0x0a,0xd3,0x35,0x0a,0x10,0x12,0x49,0x47,0x31,0xbd,0x82,0x06,0xbe,0x6f,0x7e,0x6d,0x7b,0x23,0xde,0xc6,0x79,0xea,0x11,0x19,0x76,0x1e,0xe1,0xde,0x3b,0x39,0xcb,0xe3,0x3b,0x43,0x07,0xf4,0x97,0xe9,0x5c,0xc0,0x44,0x79,0xff,0xa3,0x51,0x5c,0xb0,0xe4,0x3d,0x5d,0x57,0x7c,0x84,0x76,0x5a,0xfd,0x81,0x33,0x58,0x9f,0xda,0xf6,0x7a,0xde,0x3e,0x87,0x2d}, - {0x09,0x34,0x37,0x43,0x64,0x31,0x7a,0x15,0xd9,0x81,0xaa,0xf4,0xee,0xb7,0xb8,0xfa,0x06,0x48,0xa6,0xf5,0xe6,0xfe,0x93,0xb0,0xb6,0xa7,0x7f,0x70,0x54,0x36,0x77,0x2e,0x81,0xf9,0x5d,0x4e,0xe1,0x02,0x62,0xaa,0xf5,0xe1,0x15,0x50,0x17,0x59,0x0d,0xa2,0x6c,0x1d,0xe2,0xba,0xd3,0x75,0xa2,0x18,0x53,0x02,0x60,0x01,0x8a,0x61,0x43,0x05,0xc1,0x23,0x4c,0x97,0xf4,0xbd,0xea,0x0d,0x93,0x46,0xce,0x9d,0x25,0x0a,0x6f,0xaa,0x2c,0xba,0x9a,0xa2,0xb8,0x2c,0x20,0x04,0x0d,0x96,0x07,0x2d,0x36,0x43,0x14,0x4b}, - {0x7a,0x1f,0x6e,0xb6,0xc7,0xb7,0xc4,0xcc,0x7e,0x2f,0x0c,0xf5,0x25,0x7e,0x15,0x44,0x1c,0xaf,0x3e,0x71,0xfc,0x6d,0xf0,0x3e,0xf7,0x63,0xda,0x52,0x67,0x44,0x2f,0x58,0xcb,0x9c,0x52,0x1c,0xe9,0x54,0x7c,0x96,0xfb,0x35,0xc6,0x64,0x92,0x26,0xf6,0x30,0x65,0x19,0x12,0x78,0xf4,0xaf,0x47,0x27,0x5c,0x6f,0xf6,0xea,0x18,0x84,0x03,0x17,0xe4,0x4c,0x32,0x20,0xd3,0x7b,0x31,0xc6,0xc4,0x8b,0x48,0xa4,0xe8,0x42,0x10,0xa8,0x64,0x13,0x5a,0x4e,0x8b,0xf1,0x1e,0xb2,0xc9,0x8d,0xa2,0xcd,0x4b,0x1c,0x2a,0x0c}, - {0x47,0x04,0x1f,0x6f,0xd0,0xc7,0x4d,0xd2,0x59,0xc0,0x87,0xdb,0x3e,0x9e,0x26,0xb2,0x8f,0xd2,0xb2,0xfb,0x72,0x02,0x5b,0xd1,0x77,0x48,0xf6,0xc6,0xd1,0x8b,0x55,0x7c,0x45,0x69,0xbd,0x69,0x48,0x81,0xc4,0xed,0x22,0x8d,0x1c,0xbe,0x7d,0x90,0x6d,0x0d,0xab,0xc5,0x5c,0xd5,0x12,0xd2,0x3b,0xc6,0x83,0xdc,0x14,0xa3,0x30,0x9b,0x6a,0x5a,0x3d,0x46,0x96,0xd3,0x24,0x15,0xec,0xd0,0xf0,0x24,0x5a,0xc3,0x8a,0x62,0xbb,0x12,0xa4,0x5f,0xbc,0x1c,0x79,0x3a,0x0c,0xa5,0xc3,0xaf,0xfb,0x0a,0xca,0xa5,0x04,0x04}, - {0xd6,0x43,0xa7,0x0a,0x07,0x40,0x1f,0x8c,0xe8,0x5e,0x26,0x5b,0xcb,0xd0,0xba,0xcc,0xde,0xd2,0x8f,0x66,0x6b,0x04,0x4b,0x57,0x33,0x96,0xdd,0xca,0xfd,0x5b,0x39,0x46,0xd1,0x6f,0x41,0x2a,0x1b,0x9e,0xbc,0x62,0x8b,0x59,0x50,0xe3,0x28,0xf7,0xc6,0xb5,0x67,0x69,0x5d,0x3d,0xd8,0x3f,0x34,0x04,0x98,0xee,0xf8,0xe7,0x16,0x75,0x52,0x39,0x9c,0x9a,0x5d,0x1a,0x2d,0xdb,0x7f,0x11,0x2a,0x5c,0x00,0xd1,0xbc,0x45,0x77,0x9c,0xea,0x6f,0xd5,0x54,0xf1,0xbe,0xd4,0xef,0x16,0xd0,0x22,0xe8,0x29,0x9a,0x57,0x76}, - {0x17,0x2a,0xc0,0x49,0x7e,0x8e,0xb6,0x45,0x7f,0xa3,0xa9,0xbc,0xa2,0x51,0xcd,0x23,0x1b,0x4c,0x22,0xec,0x11,0x5f,0xd6,0x3e,0xb1,0xbd,0x05,0x9e,0xdc,0x84,0xa3,0x43,0xf2,0x34,0xb4,0x52,0x13,0xb5,0x3c,0x33,0xe1,0x80,0xde,0x93,0x49,0x28,0x32,0xd8,0xce,0x35,0x0d,0x75,0x87,0x28,0x51,0xb5,0xc1,0x77,0x27,0x2a,0xbb,0x14,0xc5,0x02,0x45,0xb6,0xf1,0x8b,0xda,0xd5,0x4b,0x68,0x53,0x4b,0xb5,0xf6,0x7e,0xd3,0x8b,0xfb,0x53,0xd2,0xb0,0xa9,0xd7,0x16,0x39,0x31,0x59,0x80,0x54,0x61,0x09,0x92,0x60,0x11}, - {0xaa,0xcf,0xda,0x29,0x69,0x16,0x4d,0xb4,0x8f,0x59,0x13,0x84,0x4c,0x9f,0x52,0xda,0x59,0x55,0x3d,0x45,0xca,0x63,0xef,0xe9,0x0b,0x8e,0x69,0xc5,0x5b,0x12,0x1e,0x35,0xcd,0x4d,0x9b,0x36,0x16,0x56,0x38,0x7a,0x63,0x35,0x5c,0x65,0xa7,0x2c,0xc0,0x75,0x21,0x80,0xf1,0xd4,0xf9,0x1b,0xc2,0x7d,0x42,0xe0,0xe6,0x91,0x74,0x7d,0x63,0x2f,0xbe,0x7b,0xf6,0x1a,0x46,0x9b,0xb4,0xd4,0x61,0x89,0xab,0xc8,0x7a,0x03,0x03,0xd6,0xfb,0x99,0xa6,0xf9,0x9f,0xe1,0xde,0x71,0x9a,0x2a,0xce,0xe7,0x06,0x2d,0x18,0x7f}, - {0xec,0x68,0x01,0xab,0x64,0x8e,0x7c,0x7a,0x43,0xc5,0xed,0x15,0x55,0x4a,0x5a,0xcb,0xda,0x0e,0xcd,0x47,0xd3,0x19,0x55,0x09,0xb0,0x93,0x3e,0x34,0x8c,0xac,0xd4,0x67,0x22,0x75,0x21,0x8e,0x72,0x4b,0x45,0x09,0xd8,0xb8,0x84,0xd4,0xf4,0xe8,0x58,0xaa,0x3c,0x90,0x46,0x7f,0x4d,0x25,0x58,0xd3,0x17,0x52,0x1c,0x24,0x43,0xc0,0xac,0x44,0x77,0x57,0x7a,0x4f,0xbb,0x6b,0x7d,0x1c,0xe1,0x13,0x83,0x91,0xd4,0xfe,0x35,0x8b,0x84,0x46,0x6b,0xc9,0xc6,0xa1,0xdc,0x4a,0xbd,0x71,0xad,0x12,0x83,0x1c,0x6d,0x55}, - {0x82,0x39,0x8d,0x0c,0xe3,0x40,0xef,0x17,0x34,0xfa,0xa3,0x15,0x3e,0x07,0xf7,0x31,0x6e,0x64,0x73,0x07,0xcb,0xf3,0x21,0x4f,0xff,0x4e,0x82,0x1d,0x6d,0x6c,0x6c,0x74,0x21,0xe8,0x1b,0xb1,0x56,0x67,0xf0,0x81,0xdd,0xf3,0xa3,0x10,0x23,0xf8,0xaf,0x0f,0x5d,0x46,0x99,0x6a,0x55,0xd0,0xb2,0xf8,0x05,0x7f,0x8c,0xcc,0x38,0xbe,0x7a,0x09,0xa4,0x2d,0xa5,0x7e,0x87,0xc9,0x49,0x0c,0x43,0x1d,0xdc,0x9b,0x55,0x69,0x43,0x4c,0xd2,0xeb,0xcc,0xf7,0x09,0x38,0x2c,0x02,0xbd,0x84,0xee,0x4b,0xa3,0x14,0x7e,0x57}, - {0x0a,0x3b,0xa7,0x61,0xac,0x68,0xe2,0xf0,0xf5,0xa5,0x91,0x37,0x10,0xfa,0xfa,0xf2,0xe9,0x00,0x6d,0x6b,0x82,0x3e,0xe1,0xc1,0x42,0x8f,0xd7,0x6f,0xe9,0x7e,0xfa,0x60,0x2b,0xd7,0x4d,0xbd,0xbe,0xce,0xfe,0x94,0x11,0x22,0x0f,0x06,0xda,0x4f,0x6a,0xf4,0xff,0xd1,0xc8,0xc0,0x77,0x59,0x4a,0x12,0x95,0x92,0x00,0xfb,0xb8,0x04,0x53,0x70,0xc6,0x6e,0x29,0x4d,0x35,0x1d,0x3d,0xb6,0xd8,0x31,0xad,0x5f,0x3e,0x05,0xc3,0xf3,0xec,0x42,0xbd,0xb4,0x8c,0x95,0x0b,0x67,0xfd,0x53,0x63,0xa1,0x0c,0x8e,0x39,0x21}, - {0xf3,0x33,0x2b,0x38,0x8a,0x05,0xf5,0x89,0xb4,0xc0,0x48,0xad,0x0b,0xba,0xe2,0x5a,0x6e,0xb3,0x3d,0xa5,0x03,0xb5,0x93,0x8f,0xe6,0x32,0xa2,0x95,0x9d,0xed,0xa3,0x5a,0x01,0x56,0xb7,0xb4,0xf9,0xaa,0x98,0x27,0x72,0xad,0x8d,0x5c,0x13,0x72,0xac,0x5e,0x23,0xa0,0xb7,0x61,0x61,0xaa,0xce,0xd2,0x4e,0x7d,0x8f,0xe9,0x84,0xb2,0xbf,0x1b,0x61,0x65,0xd9,0xc7,0xe9,0x77,0x67,0x65,0x36,0x80,0xc7,0x72,0x54,0x12,0x2b,0xcb,0xee,0x6e,0x50,0xd9,0x99,0x32,0x05,0x65,0xcc,0x57,0x89,0x5e,0x4e,0xe1,0x07,0x4a}, - {0x99,0xf9,0x0d,0x98,0xcb,0x12,0xe4,0x4e,0x71,0xc7,0x6e,0x3c,0x6f,0xd7,0x15,0xa3,0xfd,0x77,0x5c,0x92,0xde,0xed,0xa5,0xbb,0x02,0x34,0x31,0x1d,0x39,0xac,0x0b,0x3f,0x9b,0xa4,0x77,0xc4,0xcd,0x58,0x0b,0x24,0x17,0xf0,0x47,0x64,0xde,0xda,0x38,0xfd,0xad,0x6a,0xc8,0xa7,0x32,0x8d,0x92,0x19,0x81,0xa0,0xaf,0x84,0xed,0x7a,0xaf,0x50,0xe5,0x5b,0xf6,0x15,0x01,0xde,0x4f,0x6e,0xb2,0x09,0x61,0x21,0x21,0x26,0x98,0x29,0xd9,0xd6,0xad,0x0b,0x81,0x05,0x02,0x78,0x06,0xd0,0xeb,0xba,0x16,0xa3,0x21,0x19}, - {0xfc,0x70,0xb8,0xdf,0x7e,0x2f,0x42,0x89,0xbd,0xb3,0x76,0x4f,0xeb,0x6b,0x29,0x2c,0xf7,0x4d,0xc2,0x36,0xd4,0xf1,0x38,0x07,0xb0,0xae,0x73,0xe2,0x41,0xdf,0x58,0x64,0x8b,0xc1,0xf3,0xd9,0x9a,0xad,0x5a,0xd7,0x9c,0xc1,0xb1,0x60,0xef,0x0e,0x6a,0x56,0xd9,0x0e,0x5c,0x25,0xac,0x0b,0x9a,0x3e,0xf5,0xc7,0x62,0xa0,0xec,0x9d,0x04,0x7b,0x83,0x44,0x44,0x35,0x7a,0xe3,0xcb,0xdc,0x93,0xbe,0xed,0x0f,0x33,0x79,0x88,0x75,0x87,0xdd,0xc5,0x12,0xc3,0x04,0x60,0x78,0x64,0x0e,0x95,0xc2,0xcb,0xdc,0x93,0x60}, - {0x6d,0x70,0xe0,0x85,0x85,0x9a,0xf3,0x1f,0x33,0x39,0xe7,0xb3,0xd8,0xa5,0xd0,0x36,0x3b,0x45,0x8f,0x71,0xe1,0xf2,0xb9,0x43,0x7c,0xa9,0x27,0x48,0x08,0xea,0xd1,0x57,0x4b,0x03,0x84,0x60,0xbe,0xee,0xde,0x6b,0x54,0xb8,0x0f,0x78,0xb6,0xc2,0x99,0x31,0x95,0x06,0x2d,0xb6,0xab,0x76,0x33,0x97,0x90,0x7d,0x64,0x8b,0xc9,0x80,0x31,0x6e,0x71,0xb0,0x28,0xa1,0xe7,0xb6,0x7a,0xee,0xaa,0x8b,0xa8,0x93,0x6d,0x59,0xc1,0xa4,0x30,0x61,0x21,0xb2,0x82,0xde,0xb4,0xf7,0x18,0xbd,0x97,0xdd,0x9d,0x99,0x3e,0x36}, - {0xc4,0x1f,0xee,0x35,0xc1,0x43,0xa8,0x96,0xcf,0xc8,0xe4,0x08,0x55,0xb3,0x6e,0x97,0x30,0xd3,0x8c,0xb5,0x01,0x68,0x2f,0xb4,0x2b,0x05,0x3a,0x69,0x78,0x9b,0xee,0x48,0xc6,0xae,0x4b,0xe2,0xdc,0x48,0x18,0x2f,0x60,0xaf,0xbc,0xba,0x55,0x72,0x9b,0x76,0x31,0xe9,0xef,0x3c,0x6e,0x3c,0xcb,0x90,0x55,0xb3,0xf9,0xc6,0x9b,0x97,0x1f,0x23,0xc6,0xf3,0x2a,0xcc,0x4b,0xde,0x31,0x5c,0x1f,0x8d,0x20,0xfe,0x30,0xb0,0x4b,0xb0,0x66,0xb4,0x4f,0xc1,0x09,0x70,0x8d,0xb7,0x13,0x24,0x79,0x08,0x9b,0xfa,0x9b,0x07}, - {0xf4,0x0d,0x30,0xda,0x51,0x3a,0x90,0xe3,0xb0,0x5a,0xa9,0x3d,0x23,0x64,0x39,0x84,0x80,0x64,0x35,0x0b,0x2d,0xf1,0x3c,0xed,0x94,0x71,0x81,0x84,0xf6,0x77,0x8c,0x03,0x45,0x42,0xd5,0xa2,0x80,0xed,0xc9,0xf3,0x52,0x39,0xf6,0x77,0x78,0x8b,0xa0,0x0a,0x75,0x54,0x08,0xd1,0x63,0xac,0x6d,0xd7,0x6b,0x63,0x70,0x94,0x15,0xfb,0xf4,0x1e,0xec,0x7b,0x16,0x5b,0xe6,0x5e,0x4e,0x85,0xc2,0xcd,0xd0,0x96,0x42,0x0a,0x59,0x59,0x99,0x21,0x10,0x98,0x34,0xdf,0xb2,0x72,0x56,0xff,0x0b,0x4a,0x2a,0xe9,0x5e,0x57}, - {0xcf,0x2f,0x18,0x8a,0x90,0x80,0xc0,0xd4,0xbd,0x9d,0x48,0x99,0xc2,0x70,0xe1,0x30,0xde,0x33,0xf7,0x52,0x57,0xbd,0xba,0x05,0x00,0xfd,0xd3,0x2c,0x11,0xe7,0xd4,0x43,0x01,0xd8,0xa4,0x0a,0x45,0xbc,0x46,0x5d,0xd8,0xb9,0x33,0xa5,0x27,0x12,0xaf,0xc3,0xc2,0x06,0x89,0x2b,0x26,0x3b,0x9e,0x38,0x1b,0x58,0x2f,0x38,0x7e,0x1e,0x0a,0x20,0xc5,0x3a,0xf9,0xea,0x67,0xb9,0x8d,0x51,0xc0,0x52,0x66,0x05,0x9b,0x98,0xbc,0x71,0xf5,0x97,0x71,0x56,0xd9,0x85,0x2b,0xfe,0x38,0x4e,0x1e,0x65,0x52,0xca,0x0e,0x05}, - {0x9c,0x0c,0x3f,0x45,0xde,0x1a,0x43,0xc3,0x9b,0x3b,0x70,0xff,0x5e,0x04,0xf5,0xe9,0x3d,0x7b,0x84,0xed,0xc9,0x7a,0xd9,0xfc,0xc6,0xf4,0x58,0x1c,0xc2,0xe6,0x0e,0x4b,0xea,0x68,0xe6,0x60,0x76,0x39,0xac,0x97,0x97,0xb4,0x3a,0x15,0xfe,0xbb,0x19,0x9b,0x9f,0xa7,0xec,0x34,0xb5,0x79,0xb1,0x4c,0x57,0xae,0x31,0xa1,0x9f,0xc0,0x51,0x61,0x96,0x5d,0xf0,0xfd,0x0d,0x5c,0xf5,0x3a,0x7a,0xee,0xb4,0x2a,0xe0,0x2e,0x26,0xdd,0x09,0x17,0x17,0x12,0x87,0xbb,0xb2,0x11,0x0b,0x03,0x0f,0x80,0xfa,0x24,0xef,0x1f}, - {0x96,0x31,0xa7,0x1a,0xfb,0x53,0xd6,0x37,0x18,0x64,0xd7,0x3f,0x30,0x95,0x94,0x0f,0xb2,0x17,0x3a,0xfb,0x09,0x0b,0x20,0xad,0x3e,0x61,0xc8,0x2f,0x29,0x49,0x4d,0x54,0x86,0x6b,0x97,0x30,0xf5,0xaf,0xd2,0x22,0x04,0x46,0xd2,0xc2,0x06,0xb8,0x90,0x8d,0xe5,0xba,0xe5,0x4d,0x6c,0x89,0xa1,0xdc,0x17,0x0c,0x34,0xc8,0xe6,0x5f,0x00,0x28,0x88,0x86,0x52,0x34,0x9f,0xba,0xef,0x6a,0xa1,0x7d,0x10,0x25,0x94,0xff,0x1b,0x5c,0x36,0x4b,0xd9,0x66,0xcd,0xbb,0x5b,0xf7,0xfa,0x6d,0x31,0x0f,0x93,0x72,0xe4,0x72}, - {0x4f,0x08,0x81,0x97,0x8c,0x20,0x95,0x26,0xe1,0x0e,0x45,0x23,0x0b,0x2a,0x50,0xb1,0x02,0xde,0xef,0x03,0xa6,0xae,0x9d,0xfd,0x4c,0xa3,0x33,0x27,0x8c,0x2e,0x9d,0x5a,0x27,0x76,0x2a,0xd3,0x35,0xf6,0xf3,0x07,0xf0,0x66,0x65,0x5f,0x86,0x4d,0xaa,0x7a,0x50,0x44,0xd0,0x28,0x97,0xe7,0x85,0x3c,0x38,0x64,0xe0,0x0f,0x00,0x7f,0xee,0x1f,0xe5,0xf7,0xdb,0x03,0xda,0x05,0x53,0x76,0xbd,0xcd,0x34,0x14,0x49,0xf2,0xda,0xa4,0xec,0x88,0x4a,0xd2,0xcd,0xd5,0x4a,0x7b,0x43,0x05,0x04,0xee,0x51,0x40,0xf9,0x00}, - {0xb2,0x30,0xd3,0xc3,0x23,0x6b,0x35,0x8d,0x06,0x1b,0x47,0xb0,0x9b,0x8b,0x1c,0xf2,0x3c,0xb8,0x42,0x6e,0x6c,0x31,0x6c,0xb3,0x0d,0xb1,0xea,0x8b,0x7e,0x9c,0xd7,0x07,0x53,0x97,0xaf,0x07,0xbb,0x93,0xef,0xd7,0xa7,0x66,0xb7,0x3d,0xcf,0xd0,0x3e,0x58,0xc5,0x1e,0x0b,0x6e,0xbf,0x98,0x69,0xce,0x52,0x04,0xd4,0x5d,0xd2,0xff,0xb7,0x47,0x12,0xdd,0x08,0xbc,0x9c,0xfb,0xfb,0x87,0x9b,0xc2,0xee,0xe1,0x3a,0x6b,0x06,0x8a,0xbf,0xc1,0x1f,0xdb,0x2b,0x24,0x57,0x0d,0xb6,0x4b,0xa6,0x5e,0xa3,0x20,0x35,0x1c}, - {0x4a,0xa3,0xcb,0xbc,0xa6,0x53,0xd2,0x80,0x9b,0x21,0x38,0x38,0xa1,0xc3,0x61,0x3e,0x96,0xe3,0x82,0x98,0x01,0xb6,0xc3,0x90,0x6f,0xe6,0x0e,0x5d,0x77,0x05,0x3d,0x1c,0x59,0xc0,0x6b,0x21,0x40,0x6f,0xa8,0xcd,0x7e,0xd8,0xbc,0x12,0x1d,0x23,0xbb,0x1f,0x90,0x09,0xc7,0x17,0x9e,0x6a,0x95,0xb4,0x55,0x2e,0xd1,0x66,0x3b,0x0c,0x75,0x38,0x1a,0xe5,0x22,0x94,0x40,0xf1,0x2e,0x69,0x71,0xf6,0x5d,0x2b,0x3c,0xc7,0xc0,0xcb,0x29,0xe0,0x4c,0x74,0xe7,0x4f,0x01,0x21,0x7c,0x48,0x30,0xd3,0xc7,0xe2,0x21,0x06}, - {0x8d,0x83,0x59,0x82,0xcc,0x60,0x98,0xaf,0xdc,0x9a,0x9f,0xc6,0xc1,0x48,0xea,0x90,0x30,0x1e,0x58,0x65,0x37,0x48,0x26,0x65,0xbc,0xa5,0xd3,0x7b,0x09,0xd6,0x07,0x00,0xf3,0xf0,0xdb,0xb0,0x96,0x17,0xae,0xb7,0x96,0xe1,0x7c,0xe1,0xb9,0xaf,0xdf,0x54,0xb4,0xa3,0xaa,0xe9,0x71,0x30,0x92,0x25,0x9d,0x2e,0x00,0xa1,0x9c,0x58,0x8e,0x5d,0x4b,0xa9,0x42,0x08,0x95,0x1d,0xbf,0xc0,0x3e,0x2e,0x8f,0x58,0x63,0xc3,0xd3,0xb2,0xef,0xe2,0x51,0xbb,0x38,0x14,0x96,0x0a,0x86,0xbf,0x1c,0x3c,0x78,0xd7,0x83,0x15}, - {0xe1,0x7a,0xa2,0x5d,0xef,0xa2,0xee,0xec,0x74,0x01,0x67,0x55,0x14,0x3a,0x7c,0x59,0x7a,0x16,0x09,0x66,0x12,0x2a,0xa6,0xc9,0x70,0x8f,0xed,0x81,0x2e,0x5f,0x2a,0x25,0xc7,0x28,0x9d,0xcc,0x04,0x47,0x03,0x90,0x8f,0xc5,0x2c,0xf7,0x9e,0x67,0x1b,0x1d,0x26,0x87,0x5b,0xbe,0x5f,0x2b,0xe1,0x16,0x0a,0x58,0xc5,0x83,0x4e,0x06,0x58,0x49,0x0d,0xe8,0x66,0x50,0x26,0x94,0x28,0x0d,0x6b,0x8c,0x7c,0x30,0x85,0xf7,0xc3,0xfc,0xfd,0x12,0x11,0x0c,0x78,0xda,0x53,0x1b,0x88,0xb3,0x43,0xd8,0x0b,0x17,0x9c,0x07}, - {0xff,0x6f,0xfa,0x64,0xe4,0xec,0x06,0x05,0x23,0xe5,0x05,0x62,0x1e,0x43,0xe3,0xbe,0x42,0xea,0xb8,0x51,0x24,0x42,0x79,0x35,0x00,0xfb,0xc9,0x4a,0xe3,0x05,0xec,0x6d,0x56,0xd0,0xd5,0xc0,0x50,0xcd,0xd6,0xcd,0x3b,0x57,0x03,0xbb,0x6d,0x68,0xf7,0x9a,0x48,0xef,0xc3,0xf3,0x3f,0x72,0xa6,0x3c,0xcc,0x8a,0x7b,0x31,0xd7,0xc0,0x68,0x67,0xb3,0xc1,0x55,0xf1,0xe5,0x25,0xb6,0x94,0x91,0x7b,0x7b,0x99,0xa7,0xf3,0x7b,0x41,0x00,0x26,0x6b,0x6d,0xdc,0xbd,0x2c,0xc2,0xf4,0x52,0xcd,0xdd,0x14,0x5e,0x44,0x51}, - {0x51,0x49,0x14,0x3b,0x4b,0x2b,0x50,0x57,0xb3,0xbc,0x4b,0x44,0x6b,0xff,0x67,0x8e,0xdb,0x85,0x63,0x16,0x27,0x69,0xbd,0xb8,0xc8,0x95,0x92,0xe3,0x31,0x6f,0x18,0x13,0x55,0xa4,0xbe,0x2b,0xab,0x47,0x31,0x89,0x29,0x91,0x07,0x92,0x4f,0xa2,0x53,0x8c,0xa7,0xf7,0x30,0xbe,0x48,0xf9,0x49,0x4b,0x3d,0xd4,0x4f,0x6e,0x08,0x90,0xe9,0x12,0x2e,0xbb,0xdf,0x7f,0xb3,0x96,0x0c,0xf1,0xf9,0xea,0x1c,0x12,0x5e,0x93,0x9a,0x9f,0x3f,0x98,0x5b,0x3a,0xc4,0x36,0x11,0xdf,0xaf,0x99,0x3e,0x5d,0xf0,0xe3,0xb2,0x77}, - {0xde,0xc4,0x2e,0x9c,0xc5,0xa9,0x6f,0x29,0xcb,0xf3,0x84,0x4f,0xbf,0x61,0x8b,0xbc,0x08,0xf9,0xa8,0x17,0xd9,0x06,0x77,0x1c,0x5d,0x25,0xd3,0x7a,0xfc,0x95,0xb7,0x63,0xa4,0xb0,0xdd,0x12,0x9c,0x63,0x98,0xd5,0x6b,0x86,0x24,0xc0,0x30,0x9f,0xd1,0xa5,0x60,0xe4,0xfc,0x58,0x03,0x2f,0x7c,0xd1,0x8a,0x5e,0x09,0x2e,0x15,0x95,0xa1,0x07,0xc8,0x5f,0x9e,0x38,0x02,0x8f,0x36,0xa8,0x3b,0xe4,0x8d,0xcf,0x02,0x3b,0x43,0x90,0x43,0x26,0x41,0xc5,0x5d,0xfd,0xa1,0xaf,0x37,0x01,0x2f,0x03,0x3d,0xe8,0x8f,0x3e}, - {0x94,0xa2,0x70,0x05,0xb9,0x15,0x8b,0x2f,0x49,0x45,0x08,0x67,0x70,0x42,0xf2,0x94,0x84,0xfd,0xbb,0x61,0xe1,0x5a,0x1c,0xde,0x07,0x40,0xac,0x7f,0x79,0x3b,0xba,0x75,0x3c,0xd1,0xef,0xe8,0x8d,0x4c,0x70,0x08,0x31,0x37,0xe0,0x33,0x8e,0x1a,0xc5,0xdf,0xe3,0xcd,0x60,0x12,0xa5,0x5d,0x9d,0xa5,0x86,0x8c,0x25,0xa6,0x99,0x08,0xd6,0x22,0x96,0xd1,0xcd,0x70,0xc0,0xdb,0x39,0x62,0x9a,0x8a,0x7d,0x6c,0x8b,0x8a,0xfe,0x60,0x60,0x12,0x40,0xeb,0xbc,0x47,0x88,0xb3,0x5e,0x9e,0x77,0x87,0x7b,0xd0,0x04,0x09}, - {0x9c,0x91,0xba,0xdd,0xd4,0x1f,0xce,0xb4,0xaa,0x8d,0x4c,0xc7,0x3e,0xdb,0x31,0xcf,0x51,0xcc,0x86,0xad,0x63,0xcc,0x63,0x2c,0x07,0xde,0x1d,0xbc,0x3f,0x14,0xe2,0x43,0xb9,0x40,0xf9,0x48,0x66,0x2d,0x32,0xf4,0x39,0x0c,0x2d,0xbd,0x0c,0x2f,0x95,0x06,0x31,0xf9,0x81,0xa0,0xad,0x97,0x76,0x16,0x6c,0x2a,0xf7,0xba,0xce,0xaa,0x40,0x62,0xa0,0x95,0xa2,0x5b,0x9c,0x74,0x34,0xf8,0x5a,0xd2,0x37,0xca,0x5b,0x7c,0x94,0xd6,0x6a,0x31,0xc9,0xe7,0xa7,0x3b,0xf1,0x66,0xac,0x0c,0xb4,0x8d,0x23,0xaf,0xbd,0x56}, - {0xeb,0x33,0x35,0xf5,0xe3,0xb9,0x2a,0x36,0x40,0x3d,0xb9,0x6e,0xd5,0x68,0x85,0x33,0x72,0x55,0x5a,0x1d,0x52,0x14,0x0e,0x9e,0x18,0x13,0x74,0x83,0x6d,0xa8,0x24,0x1d,0xb2,0x3b,0x9d,0xc1,0x6c,0xd3,0x10,0x13,0xb9,0x86,0x23,0x62,0xb7,0x6b,0x2a,0x06,0x5c,0x4f,0xa1,0xd7,0x91,0x85,0x9b,0x7c,0x54,0x57,0x1e,0x7e,0x50,0x31,0xaa,0x03,0x1f,0xce,0xd4,0xff,0x48,0x76,0xec,0xf4,0x1c,0x8c,0xac,0x54,0xf0,0xea,0x45,0xe0,0x7c,0x35,0x09,0x1d,0x82,0x25,0xd2,0x88,0x59,0x48,0xeb,0x9a,0xdc,0x61,0xb2,0x43}, - {0xbb,0x79,0xbb,0x88,0x19,0x1e,0x5b,0xe5,0x9d,0x35,0x7a,0xc1,0x7d,0xd0,0x9e,0xa0,0x33,0xea,0x3d,0x60,0xe2,0x2e,0x2c,0xb0,0xc2,0x6b,0x27,0x5b,0xcf,0x55,0x60,0x32,0x64,0x13,0x95,0x6c,0x8b,0x3d,0x51,0x19,0x7b,0xf4,0x0b,0x00,0x26,0x71,0xfe,0x94,0x67,0x95,0x4f,0xd5,0xdd,0x10,0x8d,0x02,0x64,0x09,0x94,0x42,0xe2,0xd5,0xb4,0x02,0xf2,0x8d,0xd1,0x28,0xcb,0x55,0xa1,0xb4,0x08,0xe5,0x6c,0x18,0x46,0x46,0xcc,0xea,0x89,0x43,0x82,0x6c,0x93,0xf4,0x9c,0xc4,0x10,0x34,0x5d,0xae,0x09,0xc8,0xa6,0x27}, - {0x88,0xb1,0x0d,0x1f,0xcd,0xeb,0xa6,0x8b,0xe8,0x5b,0x5a,0x67,0x3a,0xd7,0xd3,0x37,0x5a,0x58,0xf5,0x15,0xa3,0xdf,0x2e,0xf2,0x7e,0xa1,0x60,0xff,0x74,0x71,0xb6,0x2c,0x54,0x69,0x3d,0xc4,0x0a,0x27,0x2c,0xcd,0xb2,0xca,0x66,0x6a,0x57,0x3e,0x4a,0xdd,0x6c,0x03,0xd7,0x69,0x24,0x59,0xfa,0x79,0x99,0x25,0x8c,0x3d,0x60,0x03,0x15,0x22,0xd0,0xe1,0x0b,0x39,0xf9,0xcd,0xee,0x59,0xf1,0xe3,0x8c,0x72,0x44,0x20,0x42,0xa9,0xf4,0xf0,0x94,0x7a,0x66,0x1c,0x89,0x82,0x36,0xf4,0x90,0x38,0xb7,0xf4,0x1d,0x7b}, - {0x24,0xa2,0xb2,0xb3,0xe0,0xf2,0x92,0xe4,0x60,0x11,0x55,0x2b,0x06,0x9e,0x6c,0x7c,0x0e,0x7b,0x7f,0x0d,0xe2,0x8f,0xeb,0x15,0x92,0x59,0xfc,0x58,0x26,0xef,0xfc,0x61,0x8c,0xf5,0xf8,0x07,0x18,0x22,0x2e,0x5f,0xd4,0x09,0x94,0xd4,0x9f,0x5c,0x55,0xe3,0x30,0xa6,0xb6,0x1f,0x8d,0xa8,0xaa,0xb2,0x3d,0xe0,0x52,0xd3,0x45,0x82,0x69,0x68,0x7a,0x18,0x18,0x2a,0x85,0x5d,0xb1,0xdb,0xd7,0xac,0xdd,0x86,0xd3,0xaa,0xe4,0xf3,0x82,0xc4,0xf6,0x0f,0x81,0xe2,0xba,0x44,0xcf,0x01,0xaf,0x3d,0x47,0x4c,0xcf,0x46}, - {0xf9,0xe5,0xc4,0x9e,0xed,0x25,0x65,0x42,0x03,0x33,0x90,0x16,0x01,0xda,0x5e,0x0e,0xdc,0xca,0xe5,0xcb,0xf2,0xa7,0xb1,0x72,0x40,0x5f,0xeb,0x14,0xcd,0x7b,0x38,0x29,0x40,0x81,0x49,0xf1,0xa7,0x6e,0x3c,0x21,0x54,0x48,0x2b,0x39,0xf8,0x7e,0x1e,0x7c,0xba,0xce,0x29,0x56,0x8c,0xc3,0x88,0x24,0xbb,0xc5,0x8c,0x0d,0xe5,0xaa,0x65,0x10,0x57,0x0d,0x20,0xdf,0x25,0x45,0x2c,0x1c,0x4a,0x67,0xca,0xbf,0xd6,0x2d,0x3b,0x5c,0x30,0x40,0x83,0xe1,0xb1,0xe7,0x07,0x0a,0x16,0xe7,0x1c,0x4f,0xe6,0x98,0xa1,0x69}, - {0xbc,0x78,0x1a,0xd9,0xe0,0xb2,0x62,0x90,0x67,0x96,0x50,0xc8,0x9c,0x88,0xc9,0x47,0xb8,0x70,0x50,0x40,0x66,0x4a,0xf5,0x9d,0xbf,0xa1,0x93,0x24,0xa9,0xe6,0x69,0x73,0xed,0xca,0xc5,0xdc,0x34,0x44,0x01,0xe1,0x33,0xfb,0x84,0x3c,0x96,0x5d,0xed,0x47,0xe7,0xa0,0x86,0xed,0x76,0x95,0x01,0x70,0xe4,0xf9,0x67,0xd2,0x7b,0x69,0xb2,0x25,0x64,0x68,0x98,0x13,0xfb,0x3f,0x67,0x9d,0xb8,0xc7,0x5d,0x41,0xd9,0xfb,0xa5,0x3c,0x5e,0x3b,0x27,0xdf,0x3b,0xcc,0x4e,0xe0,0xd2,0x4c,0x4e,0xb5,0x3d,0x68,0x20,0x14}, - {0x97,0xd1,0x9d,0x24,0x1e,0xbd,0x78,0xb4,0x02,0xc1,0x58,0x5e,0x00,0x35,0x0c,0x62,0x5c,0xac,0xba,0xcc,0x2f,0xd3,0x02,0xfb,0x2d,0xa7,0x08,0xf5,0xeb,0x3b,0xb6,0x60,0xd0,0x5a,0xcc,0xc1,0x6f,0xbb,0xee,0x34,0x8b,0xac,0x46,0x96,0xe9,0x0c,0x1b,0x6a,0x53,0xde,0x6b,0xa6,0x49,0xda,0xb0,0xd3,0xc1,0x81,0xd0,0x61,0x41,0x3b,0xe8,0x31,0x4f,0x2b,0x06,0x9e,0x12,0xc7,0xe8,0x97,0xd8,0x0a,0x32,0x29,0x4f,0x8f,0xe4,0x49,0x3f,0x68,0x18,0x6f,0x4b,0xe1,0xec,0x5b,0x17,0x03,0x55,0x2d,0xb6,0x1e,0xcf,0x55}, - {0x58,0x3d,0xc2,0x65,0x10,0x10,0x79,0x58,0x9c,0x81,0x94,0x50,0x6d,0x08,0x9d,0x8b,0xa7,0x5f,0xc5,0x12,0xa9,0x2f,0x40,0xe2,0xd4,0x91,0x08,0x57,0x64,0x65,0x9a,0x66,0x52,0x8c,0xf5,0x7d,0xe3,0xb5,0x76,0x30,0x36,0xcc,0x99,0xe7,0xdd,0xb9,0x3a,0xd7,0x20,0xee,0x13,0x49,0xe3,0x1c,0x83,0xbd,0x33,0x01,0xba,0x62,0xaa,0xfb,0x56,0x1a,0xec,0xc9,0x9d,0x5c,0x50,0x6b,0x3e,0x94,0x1a,0x37,0x7c,0xa7,0xbb,0x57,0x25,0x30,0x51,0x76,0x34,0x41,0x56,0xae,0x73,0x98,0x5c,0x8a,0xc5,0x99,0x67,0x83,0xc4,0x13}, - {0xb9,0xe1,0xb3,0x5a,0x46,0x5d,0x3a,0x42,0x61,0x3f,0xf1,0xc7,0x87,0xc1,0x13,0xfc,0xb6,0xb9,0xb5,0xec,0x64,0x36,0xf8,0x19,0x07,0xb6,0x37,0xa6,0x93,0x0c,0xf8,0x66,0x80,0xd0,0x8b,0x5d,0x6a,0xfb,0xdc,0xc4,0x42,0x48,0x1a,0x57,0xec,0xc4,0xeb,0xde,0x65,0x53,0xe5,0xb8,0x83,0xe8,0xb2,0xd4,0x27,0xb8,0xe5,0xc8,0x7d,0xc8,0xbd,0x50,0x11,0xe1,0xdf,0x6e,0x83,0x37,0x6d,0x60,0xd9,0xab,0x11,0xf0,0x15,0x3e,0x35,0x32,0x96,0x3b,0xb7,0x25,0xc3,0x3a,0xb0,0x64,0xae,0xd5,0x5f,0x72,0x44,0x64,0xd5,0x1d}, - {0x7d,0x12,0x62,0x33,0xf8,0x7f,0xa4,0x8f,0x15,0x7c,0xcd,0x71,0xc4,0x6a,0x9f,0xbc,0x8b,0x0c,0x22,0x49,0x43,0x45,0x71,0x6e,0x2e,0x73,0x9f,0x21,0x12,0x59,0x64,0x0e,0x9a,0xc8,0xba,0x08,0x00,0xe6,0x97,0xc2,0xe0,0xc3,0xe1,0xea,0x11,0xea,0x4c,0x7d,0x7c,0x97,0xe7,0x9f,0xe1,0x8b,0xe3,0xf3,0xcd,0x05,0xa3,0x63,0x0f,0x45,0x3a,0x3a,0x27,0x46,0x39,0xd8,0x31,0x2f,0x8f,0x07,0x10,0xa5,0x94,0xde,0x83,0x31,0x9d,0x38,0x80,0x6f,0x99,0x17,0x6d,0x6c,0xe3,0xd1,0x7b,0xa8,0xa9,0x93,0x93,0x8d,0x8c,0x31}, - {0x19,0xfe,0xff,0x2a,0x03,0x5d,0x74,0xf2,0x66,0xdb,0x24,0x7f,0x49,0x3c,0x9f,0x0c,0xef,0x98,0x85,0xba,0xe3,0xd3,0x98,0xbc,0x14,0x53,0x1d,0x9a,0x67,0x7c,0x4c,0x22,0x98,0xd3,0x1d,0xab,0x29,0x9e,0x66,0x5d,0x3b,0x9e,0x2d,0x34,0x58,0x16,0x92,0xfc,0xcd,0x73,0x59,0xf3,0xfd,0x1d,0x85,0x55,0xf6,0x0a,0x95,0x25,0xc3,0x41,0x9a,0x50,0xe9,0x25,0xf9,0xa6,0xdc,0x6e,0xc0,0xbd,0x33,0x1f,0x1b,0x64,0xf4,0xf3,0x3e,0x79,0x89,0x3e,0x83,0x9d,0x80,0x12,0xec,0x82,0x89,0x13,0xa1,0x28,0x23,0xf0,0xbf,0x05}, - {0x0b,0xe0,0xca,0x23,0x70,0x13,0x32,0x36,0x59,0xcf,0xac,0xd1,0x0a,0xcf,0x4a,0x54,0x88,0x1c,0x1a,0xd2,0x49,0x10,0x74,0x96,0xa7,0x44,0x2a,0xfa,0xc3,0x8c,0x0b,0x78,0xe4,0x12,0xc5,0x0d,0xdd,0xa0,0x81,0x68,0xfe,0xfa,0xa5,0x44,0xc8,0x0d,0xe7,0x4f,0x40,0x52,0x4a,0x8f,0x6b,0x8e,0x74,0x1f,0xea,0xa3,0x01,0xee,0xcd,0x77,0x62,0x57,0x5f,0x30,0x4f,0x23,0xbc,0x8a,0xf3,0x1e,0x08,0xde,0x05,0x14,0xbd,0x7f,0x57,0x9a,0x0d,0x2a,0xe6,0x34,0x14,0xa5,0x82,0x5e,0xa1,0xb7,0x71,0x62,0x72,0x18,0xf4,0x5f}, - {0x9d,0xdb,0x89,0x17,0x0c,0x08,0x8e,0x39,0xf5,0x78,0xe7,0xf3,0x25,0x20,0x60,0xa7,0x5d,0x03,0xbd,0x06,0x4c,0x89,0x98,0xfa,0xbe,0x66,0xa9,0x25,0xdc,0x03,0x6a,0x10,0x40,0x95,0xb6,0x13,0xe8,0x47,0xdb,0xe5,0xe1,0x10,0x26,0x43,0x3b,0x2a,0x5d,0xf3,0x76,0x12,0x78,0x38,0xe9,0x26,0x1f,0xac,0x69,0xcb,0xa0,0xa0,0x8c,0xdb,0xd4,0x29,0xd0,0x53,0x33,0x33,0xaf,0x0a,0xad,0xd9,0xe5,0x09,0xd3,0xac,0xa5,0x9d,0x66,0x38,0xf0,0xf7,0x88,0xc8,0x8a,0x65,0x57,0x3c,0xfa,0xbe,0x2c,0x05,0x51,0x8a,0xb3,0x4a}, - {0x93,0xd5,0x68,0x67,0x25,0x2b,0x7c,0xda,0x13,0xca,0x22,0x44,0x57,0xc0,0xc1,0x98,0x1d,0xce,0x0a,0xca,0xd5,0x0b,0xa8,0xf1,0x90,0xa6,0x88,0xc0,0xad,0xd1,0xcd,0x29,0x9c,0xc0,0xdd,0x5f,0xef,0xd1,0xcf,0xd6,0xce,0x5d,0x57,0xf7,0xfd,0x3e,0x2b,0xe8,0xc2,0x34,0x16,0x20,0x5d,0x6b,0xd5,0x25,0x9b,0x2b,0xed,0x04,0xbb,0xc6,0x41,0x30,0x48,0xe1,0x56,0xd9,0xf9,0xf2,0xf2,0x0f,0x2e,0x6b,0x35,0x9f,0x75,0x97,0xe7,0xad,0x5c,0x02,0x6c,0x5f,0xbb,0x98,0x46,0x1a,0x7b,0x9a,0x04,0x14,0x68,0xbd,0x4b,0x10}, - {0x67,0xed,0xf1,0x68,0x31,0xfd,0xf0,0x51,0xc2,0x3b,0x6f,0xd8,0xcd,0x1d,0x81,0x2c,0xde,0xf2,0xd2,0x04,0x43,0x5c,0xdc,0x44,0x49,0x71,0x2a,0x09,0x57,0xcc,0xe8,0x5b,0x63,0xf1,0x7f,0xd6,0x5f,0x9a,0x5d,0xa9,0x81,0x56,0xc7,0x4c,0x9d,0xe6,0x2b,0xe9,0x57,0xf2,0x20,0xde,0x4c,0x02,0xf8,0xb7,0xf5,0x2d,0x07,0xfb,0x20,0x2a,0x4f,0x20,0x79,0xb0,0xeb,0x30,0x3d,0x3b,0x14,0xc8,0x30,0x2e,0x65,0xbd,0x5a,0x15,0x89,0x75,0x31,0x5c,0x6d,0x8f,0x31,0x3c,0x3c,0x65,0x1f,0x16,0x79,0xc2,0x17,0xfb,0x70,0x25}, - {0x75,0x15,0xb6,0x2c,0x7f,0x36,0xfa,0x3e,0x6c,0x02,0xd6,0x1c,0x76,0x6f,0xf9,0xf5,0x62,0x25,0xb5,0x65,0x2a,0x14,0xc7,0xe8,0xcd,0x0a,0x03,0x53,0xea,0x65,0xcb,0x3d,0x5a,0x24,0xb8,0x0b,0x55,0xa9,0x2e,0x19,0xd1,0x50,0x90,0x8f,0xa8,0xfb,0xe6,0xc8,0x35,0xc9,0xa4,0x88,0x2d,0xea,0x86,0x79,0x68,0x86,0x01,0xde,0x91,0x5f,0x1c,0x24,0xaa,0x6c,0xde,0x40,0x29,0x17,0xd8,0x28,0x3a,0x73,0xd9,0x22,0xf0,0x2c,0xbf,0x8f,0xd1,0x01,0x5b,0x23,0xdd,0xfc,0xd7,0x16,0xe5,0xf0,0xcd,0x5f,0xdd,0x0e,0x42,0x08}, - {0x4a,0xfa,0x62,0x83,0xab,0x20,0xff,0xcd,0x6e,0x3e,0x1a,0xe2,0xd4,0x18,0xe1,0x57,0x2b,0xe6,0x39,0xfc,0x17,0x96,0x17,0xe3,0xfd,0x69,0x17,0xbc,0xef,0x53,0x9a,0x0d,0xce,0x10,0xf4,0x04,0x4e,0xc3,0x58,0x03,0x85,0x06,0x6e,0x27,0x5a,0x5b,0x13,0xb6,0x21,0x15,0xb9,0xeb,0xc7,0x70,0x96,0x5d,0x9c,0x88,0xdb,0x21,0xf3,0x54,0xd6,0x04,0xd5,0xb5,0xbd,0xdd,0x16,0xc1,0x7d,0x5e,0x2d,0xdd,0xa5,0x8d,0xb6,0xde,0x54,0x29,0x92,0xa2,0x34,0x33,0x17,0x08,0xb6,0x1c,0xd7,0x1a,0x99,0x18,0x26,0x4f,0x7a,0x4a}, - {0x95,0x5f,0xb1,0x5f,0x02,0x18,0xa7,0xf4,0x8f,0x1b,0x5c,0x6b,0x34,0x5f,0xf6,0x3d,0x12,0x11,0xe0,0x00,0x85,0xf0,0xfc,0xcd,0x48,0x18,0xd3,0xdd,0x4c,0x0c,0xb5,0x11,0x4b,0x2a,0x37,0xaf,0x91,0xb2,0xc3,0x24,0xf2,0x47,0x81,0x71,0x70,0x82,0xda,0x93,0xf2,0x9e,0x89,0x86,0x64,0x85,0x84,0xdd,0x33,0xee,0xe0,0x23,0x42,0x31,0x96,0x4a,0xd6,0xff,0xa4,0x08,0x44,0x27,0xe8,0xa6,0xd9,0x76,0x15,0x9c,0x7e,0x17,0x8e,0x73,0xf2,0xb3,0x02,0x3d,0xb6,0x48,0x33,0x77,0x51,0xcc,0x6b,0xce,0x4d,0xce,0x4b,0x4f}, - {0x84,0x25,0x24,0xe2,0x5a,0xce,0x1f,0xa7,0x9e,0x8a,0xf5,0x92,0x56,0x72,0xea,0x26,0xf4,0x3c,0xea,0x1c,0xd7,0x09,0x1a,0xd2,0xe6,0x01,0x1c,0xb7,0x14,0xdd,0xfc,0x73,0x6f,0x0b,0x9d,0xc4,0x6e,0x61,0xe2,0x30,0x17,0x23,0xec,0xca,0x8f,0x71,0x56,0xe4,0xa6,0x4f,0x6b,0xf2,0x9b,0x40,0xeb,0x48,0x37,0x5f,0x59,0x61,0xe5,0xce,0x42,0x30,0x41,0xac,0x9b,0x44,0x79,0x70,0x7e,0x42,0x0a,0x31,0xe2,0xbc,0x6d,0xe3,0x5a,0x85,0x7c,0x1a,0x84,0x5f,0x21,0x76,0xae,0x4c,0xd6,0xe1,0x9c,0x9a,0x0c,0x74,0x9e,0x38}, - {0xce,0xb9,0xdc,0x34,0xae,0xb3,0xfc,0x64,0xad,0xd0,0x48,0xe3,0x23,0x03,0x50,0x97,0x1b,0x38,0xc6,0x62,0x7d,0xf0,0xb3,0x45,0x88,0x67,0x5a,0x46,0x79,0x53,0x54,0x61,0x28,0xac,0x0e,0x57,0xf6,0x78,0xbd,0xc9,0xe1,0x9c,0x91,0x27,0x32,0x0b,0x5b,0xe5,0xed,0x91,0x9b,0xa1,0xab,0x3e,0xfc,0x65,0x90,0x36,0x26,0xd6,0xe5,0x25,0xc4,0x25,0x6e,0xde,0xd7,0xf1,0xa6,0x06,0x3e,0x3f,0x08,0x23,0x06,0x8e,0x27,0x76,0xf9,0x3e,0x77,0x6c,0x8a,0x4e,0x26,0xf6,0x14,0x8c,0x59,0x47,0x48,0x15,0x89,0xa0,0x39,0x65}, - {0x73,0xf7,0xd2,0xc3,0x74,0x1f,0xd2,0xe9,0x45,0x68,0xc4,0x25,0x41,0x54,0x50,0xc1,0x33,0x9e,0xb9,0xf9,0xe8,0x5c,0x4e,0x62,0x6c,0x18,0xcd,0xc5,0xaa,0xe4,0xc5,0x11,0x19,0x4a,0xbb,0x14,0xd4,0xdb,0xc4,0xdd,0x8e,0x4f,0x42,0x98,0x3c,0xbc,0xb2,0x19,0x69,0x71,0xca,0x36,0xd7,0x9f,0xa8,0x48,0x90,0xbd,0x19,0xf0,0x0e,0x32,0x65,0x0f,0xc6,0xe0,0xfd,0xca,0xb1,0xd1,0x86,0xd4,0x81,0x51,0x3b,0x16,0xe3,0xe6,0x3f,0x4f,0x9a,0x93,0xf2,0xfa,0x0d,0xaf,0xa8,0x59,0x2a,0x07,0x33,0xec,0xbd,0xc7,0xab,0x4c}, - {0x2e,0x0a,0x9c,0x08,0x24,0x96,0x9e,0x23,0x38,0x47,0xfe,0x3a,0xc0,0xc4,0x48,0xc7,0x2a,0xa1,0x4f,0x76,0x2a,0xed,0xdb,0x17,0x82,0x85,0x1c,0x32,0xf0,0x93,0x9b,0x63,0x89,0xd2,0x78,0x3f,0x8f,0x78,0x8f,0xc0,0x9f,0x4d,0x40,0xa1,0x2c,0xa7,0x30,0xfe,0x9d,0xcc,0x65,0xcf,0xfc,0x8b,0x77,0xf2,0x21,0x20,0xcb,0x5a,0x16,0x98,0xe4,0x7e,0xc3,0xa1,0x11,0x91,0xe3,0x08,0xd5,0x7b,0x89,0x74,0x90,0x80,0xd4,0x90,0x2b,0x2b,0x19,0xfd,0x72,0xae,0xc2,0xae,0xd2,0xe7,0xa6,0x02,0xb6,0x85,0x3c,0x49,0xdf,0x0e}, - {0x68,0x5a,0x9b,0x59,0x58,0x81,0xcc,0xae,0x0e,0xe2,0xad,0xeb,0x0f,0x4f,0x57,0xea,0x07,0x7f,0xb6,0x22,0x74,0x1d,0xe4,0x4f,0xb4,0x4f,0x9d,0x01,0xe3,0x92,0x3b,0x40,0x13,0x41,0x76,0x84,0xd2,0xc4,0x67,0x67,0x35,0xf8,0xf5,0xf7,0x3f,0x40,0x90,0xa0,0xde,0xbe,0xe6,0xca,0xfa,0xcf,0x8f,0x1c,0x69,0xa3,0xdf,0xd1,0x54,0x0c,0xc0,0x04,0xf8,0x5c,0x46,0x8b,0x81,0x2f,0xc2,0x4d,0xf8,0xef,0x80,0x14,0x5a,0xf3,0xa0,0x71,0x57,0xd6,0xc7,0x04,0xad,0xbf,0xe8,0xae,0xf4,0x76,0x61,0xb2,0x2a,0xb1,0x5b,0x35}, - {0xf4,0xbb,0x93,0x74,0xcc,0x64,0x1e,0xa7,0xc3,0xb0,0xa3,0xec,0xd9,0x84,0xbd,0xe5,0x85,0xe7,0x05,0xfa,0x0c,0xc5,0x6b,0x0a,0x12,0xc3,0x2e,0x18,0x32,0x81,0x9b,0x0f,0x18,0x73,0x8c,0x5a,0xc7,0xda,0x01,0xa3,0x11,0xaa,0xce,0xb3,0x9d,0x03,0x90,0xed,0x2d,0x3f,0xae,0x3b,0xbf,0x7c,0x07,0x6f,0x8e,0xad,0x52,0xe0,0xf8,0xea,0x18,0x75,0x32,0x6c,0x7f,0x1b,0xc4,0x59,0x88,0xa4,0x98,0x32,0x38,0xf4,0xbc,0x60,0x2d,0x0f,0xd9,0xd1,0xb1,0xc9,0x29,0xa9,0x15,0x18,0xc4,0x55,0x17,0xbb,0x1b,0x87,0xc3,0x47}, - {0x48,0x4f,0xec,0x71,0x97,0x53,0x44,0x51,0x6e,0x5d,0x8c,0xc9,0x7d,0xb1,0x05,0xf8,0x6b,0xc6,0xc3,0x47,0x1a,0xc1,0x62,0xf7,0xdc,0x99,0x46,0x76,0x85,0x9b,0xb8,0x00,0xb0,0x66,0x50,0xc8,0x50,0x5d,0xe6,0xfb,0xb0,0x99,0xa2,0xb3,0xb0,0xc4,0xec,0x62,0xe0,0xe8,0x1a,0x44,0xea,0x54,0x37,0xe5,0x5f,0x8d,0xd4,0xe8,0x2c,0xa0,0xfe,0x08,0xd0,0xea,0xde,0x68,0x76,0xdd,0x4d,0x82,0x23,0x5d,0x68,0x4b,0x20,0x45,0x64,0xc8,0x65,0xd6,0x89,0x5d,0xcd,0xcf,0x14,0xb5,0x37,0xd5,0x75,0x4f,0xa7,0x29,0x38,0x47}, - {0x18,0xc4,0x79,0x46,0x75,0xda,0xd2,0x82,0xf0,0x8d,0x61,0xb2,0xd8,0xd7,0x3b,0xe6,0x0a,0xeb,0x47,0xac,0x24,0xef,0x5e,0x35,0xb4,0xc6,0x33,0x48,0x4c,0x68,0x78,0x20,0xc9,0x02,0x39,0xad,0x3a,0x53,0xd9,0x23,0x8f,0x58,0x03,0xef,0xce,0xdd,0xc2,0x64,0xb4,0x2f,0xe1,0xcf,0x90,0x73,0x25,0x15,0x90,0xd3,0xe4,0x44,0x4d,0x8b,0x66,0x6c,0x0c,0x82,0x78,0x7a,0x21,0xcf,0x48,0x3b,0x97,0x3e,0x27,0x81,0xb2,0x0a,0x6a,0xf7,0x7b,0xed,0x8e,0x8c,0xa7,0x65,0x6c,0xa9,0x3f,0x43,0x8a,0x4f,0x05,0xa6,0x11,0x74}, - {0x6d,0xc8,0x9d,0xb9,0x32,0x9d,0x65,0x4d,0x15,0xf1,0x3a,0x60,0x75,0xdc,0x4c,0x04,0x88,0xe4,0xc2,0xdc,0x2c,0x71,0x4c,0xb3,0xff,0x34,0x81,0xfb,0x74,0x65,0x13,0x7c,0xb4,0x75,0xb1,0x18,0x3d,0xe5,0x9a,0x57,0x02,0xa1,0x92,0xf3,0x59,0x31,0x71,0x68,0xf5,0x35,0xef,0x1e,0xba,0xec,0x55,0x84,0x8f,0x39,0x8c,0x45,0x72,0xa8,0xc9,0x1e,0x9b,0x50,0xa2,0x00,0xd4,0xa4,0xe6,0xb8,0xb4,0x82,0xc8,0x0b,0x02,0xd7,0x81,0x9b,0x61,0x75,0x95,0xf1,0x9b,0xcc,0xe7,0x57,0x60,0x64,0xcd,0xc7,0xa5,0x88,0xdd,0x3a}, - {0xf2,0xdc,0x35,0xb6,0x70,0x57,0x89,0xab,0xbc,0x1f,0x6c,0xf6,0x6c,0xef,0xdf,0x02,0x87,0xd1,0xb6,0xbe,0x68,0x02,0x53,0x85,0x74,0x9e,0x87,0xcc,0xfc,0x29,0x99,0x24,0x46,0x30,0x39,0x59,0xd4,0x98,0xc2,0x85,0xec,0x59,0xf6,0x5f,0x98,0x35,0x7e,0x8f,0x3a,0x6e,0xf6,0xf2,0x2a,0xa2,0x2c,0x1d,0x20,0xa7,0x06,0xa4,0x31,0x11,0xba,0x61,0x29,0x90,0x95,0x16,0xf1,0xa0,0xd0,0xa3,0x89,0xbd,0x7e,0xba,0x6c,0x6b,0x3b,0x02,0x07,0x33,0x78,0x26,0x3e,0x5a,0xf1,0x7b,0xe7,0xec,0xd8,0xbb,0x0c,0x31,0x20,0x56}, - {0x43,0xd6,0x34,0x49,0x43,0x93,0x89,0x52,0xf5,0x22,0x12,0xa5,0x06,0xf8,0xdb,0xb9,0x22,0x1c,0xf4,0xc3,0x8f,0x87,0x6d,0x8f,0x30,0x97,0x9d,0x4d,0x2a,0x6a,0x67,0x37,0xd6,0x85,0xe2,0x77,0xf4,0xb5,0x46,0x66,0x93,0x61,0x8f,0x6c,0x67,0xff,0xe8,0x40,0xdd,0x94,0xb5,0xab,0x11,0x73,0xec,0xa6,0x4d,0xec,0x8c,0x65,0xf3,0x46,0xc8,0x7e,0xc7,0x2e,0xa2,0x1d,0x3f,0x8f,0x5e,0x9b,0x13,0xcd,0x01,0x6c,0x77,0x1d,0x0f,0x13,0xb8,0x9f,0x98,0xa2,0xcf,0x8f,0x4c,0x21,0xd5,0x9d,0x9b,0x39,0x23,0xf7,0xaa,0x6d}, - {0x47,0xbe,0x3d,0xeb,0x62,0x75,0x3a,0x5f,0xb8,0xa0,0xbd,0x8e,0x54,0x38,0xea,0xf7,0x99,0x72,0x74,0x45,0x31,0xe5,0xc3,0x00,0x51,0xd5,0x27,0x16,0xe7,0xe9,0x04,0x13,0xa2,0x8e,0xad,0xac,0xbf,0x04,0x3b,0x58,0x84,0xe8,0x8b,0x14,0xe8,0x43,0xb7,0x29,0xdb,0xc5,0x10,0x08,0x3b,0x58,0x1e,0x2b,0xaa,0xbb,0xb3,0x8e,0xe5,0x49,0x54,0x2b,0xfe,0x9c,0xdc,0x6a,0xd2,0x14,0x98,0x78,0x0b,0xdd,0x48,0x8b,0x3f,0xab,0x1b,0x3c,0x0a,0xc6,0x79,0xf9,0xff,0xe1,0x0f,0xda,0x93,0xd6,0x2d,0x7c,0x2d,0xde,0x68,0x44}, - {0x9e,0x46,0x19,0x94,0x5e,0x35,0xbb,0x51,0x54,0xc7,0xdd,0x23,0x4c,0xdc,0xe6,0x33,0x62,0x99,0x7f,0x44,0xd6,0xb6,0xa5,0x93,0x63,0xbd,0x44,0xfb,0x6f,0x7c,0xce,0x6c,0xce,0x07,0x63,0xf8,0xc6,0xd8,0x9a,0x4b,0x28,0x0c,0x5d,0x43,0x31,0x35,0x11,0x21,0x2c,0x77,0x7a,0x65,0xc5,0x66,0xa8,0xd4,0x52,0x73,0x24,0x63,0x7e,0x42,0xa6,0x5d,0xca,0x22,0xac,0xde,0x88,0xc6,0x94,0x1a,0xf8,0x1f,0xae,0xbb,0xf7,0x6e,0x06,0xb9,0x0f,0x58,0x59,0x8d,0x38,0x8c,0xad,0x88,0xa8,0x2c,0x9f,0xe7,0xbf,0x9a,0xf2,0x58}, - {0x68,0x3e,0xe7,0x8d,0xab,0xcf,0x0e,0xe9,0xa5,0x76,0x7e,0x37,0x9f,0x6f,0x03,0x54,0x82,0x59,0x01,0xbe,0x0b,0x5b,0x49,0xf0,0x36,0x1e,0xf4,0xa7,0xc4,0x29,0x76,0x57,0xf6,0xcd,0x0e,0x71,0xbf,0x64,0x5a,0x4b,0x3c,0x29,0x2c,0x46,0x38,0xe5,0x4c,0xb1,0xb9,0x3a,0x0b,0xd5,0x56,0xd0,0x43,0x36,0x70,0x48,0x5b,0x18,0x24,0x37,0xf9,0x6a,0x88,0xa8,0xc6,0x09,0x45,0x02,0x20,0x32,0x73,0x89,0x55,0x4b,0x13,0x36,0xe0,0xd2,0x9f,0x28,0x33,0x3c,0x23,0x36,0xe2,0x83,0x8f,0xc1,0xae,0x0c,0xbb,0x25,0x1f,0x70}, - {0xed,0x6c,0x61,0xe4,0xf8,0xb0,0xa8,0xc3,0x7d,0xa8,0x25,0x9e,0x0e,0x66,0x00,0xf7,0x9c,0xa5,0xbc,0xf4,0x1f,0x06,0xe3,0x61,0xe9,0x0b,0xc4,0xbd,0xbf,0x92,0x0c,0x2e,0x13,0xc1,0xbe,0x7c,0xd9,0xf6,0x18,0x9d,0xe4,0xdb,0xbf,0x74,0xe6,0x06,0x4a,0x84,0xd6,0x60,0x4e,0xac,0x22,0xb5,0xf5,0x20,0x51,0x5e,0x95,0x50,0xc0,0x5b,0x0a,0x72,0x35,0x5a,0x80,0x9b,0x43,0x09,0x3f,0x0c,0xfc,0xab,0x42,0x62,0x37,0x8b,0x4e,0xe8,0x46,0x93,0x22,0x5c,0xf3,0x17,0x14,0x69,0xec,0xf0,0x4e,0x14,0xbb,0x9c,0x9b,0x0e}, - {0xad,0x20,0x57,0xfb,0x8f,0xd4,0xba,0xfb,0x0e,0x0d,0xf9,0xdb,0x6b,0x91,0x81,0xee,0xbf,0x43,0x55,0x63,0x52,0x31,0x81,0xd4,0xd8,0x7b,0x33,0x3f,0xeb,0x04,0x11,0x22,0xee,0xbe,0xb1,0x5d,0xd5,0x9b,0xee,0x8d,0xb9,0x3f,0x72,0x0a,0x37,0xab,0xc3,0xc9,0x91,0xd7,0x68,0x1c,0xbf,0xf1,0xa8,0x44,0xde,0x3c,0xfd,0x1c,0x19,0x44,0x6d,0x36,0x14,0x8c,0xbc,0xf2,0x43,0x17,0x3c,0x9e,0x3b,0x6c,0x85,0xb5,0xfc,0x26,0xda,0x2e,0x97,0xfb,0xa7,0x68,0x0e,0x2f,0xb8,0xcc,0x44,0x32,0x59,0xbc,0xe6,0xa4,0x67,0x41}, - {0x00,0x27,0xf6,0x76,0x28,0x9d,0x3b,0x64,0xeb,0x68,0x76,0x0e,0x40,0x9d,0x1d,0x5d,0x84,0x06,0xfc,0x21,0x03,0x43,0x4b,0x1b,0x6a,0x24,0x55,0x22,0x7e,0xbb,0x38,0x79,0xee,0x8f,0xce,0xf8,0x65,0x26,0xbe,0xc2,0x2c,0xd6,0x80,0xe8,0x14,0xff,0x67,0xe9,0xee,0x4e,0x36,0x2f,0x7e,0x6e,0x2e,0xf1,0xf6,0xd2,0x7e,0xcb,0x70,0x33,0xb3,0x34,0xcc,0xd6,0x81,0x86,0xee,0x91,0xc5,0xcd,0x53,0xa7,0x85,0xed,0x9c,0x10,0x02,0xce,0x83,0x88,0x80,0x58,0xc1,0x85,0x74,0xed,0xe4,0x65,0xfe,0x2d,0x6e,0xfc,0x76,0x11}, - {0x9b,0x61,0x9c,0x5b,0xd0,0x6c,0xaf,0xb4,0x80,0x84,0xa5,0xb2,0xf4,0xc9,0xdf,0x2d,0xc4,0x4d,0xe9,0xeb,0x02,0xa5,0x4f,0x3d,0x34,0x5f,0x7d,0x67,0x4c,0x3a,0xfc,0x08,0xb8,0x0e,0x77,0x49,0x89,0xe2,0x90,0xdb,0xa3,0x40,0xf4,0xac,0x2a,0xcc,0xfb,0x98,0x9b,0x87,0xd7,0xde,0xfe,0x4f,0x35,0x21,0xb6,0x06,0x69,0xf2,0x54,0x3e,0x6a,0x1f,0xea,0x34,0x07,0xd3,0x99,0xc1,0xa4,0x60,0xd6,0x5c,0x16,0x31,0xb6,0x85,0xc0,0x40,0x95,0x82,0x59,0xf7,0x23,0x3e,0x33,0xe2,0xd1,0x00,0xb9,0x16,0x01,0xad,0x2f,0x4f}, - {0x54,0x4e,0xae,0x94,0x41,0xb2,0xbe,0x44,0x6c,0xef,0x57,0x18,0x51,0x1c,0x54,0x5f,0x98,0x04,0x8d,0x36,0x2d,0x6b,0x1e,0xa6,0xab,0xf7,0x2e,0x97,0xa4,0x84,0x54,0x44,0x38,0xb6,0x3b,0xb7,0x1d,0xd9,0x2c,0x96,0x08,0x9c,0x12,0xfc,0xaa,0x77,0x05,0xe6,0x89,0x16,0xb6,0xf3,0x39,0x9b,0x61,0x6f,0x81,0xee,0x44,0x29,0x5f,0x99,0x51,0x34,0x7c,0x7d,0xea,0x9f,0xd0,0xfc,0x52,0x91,0xf6,0x5c,0x93,0xb0,0x94,0x6c,0x81,0x4a,0x40,0x5c,0x28,0x47,0xaa,0x9a,0x8e,0x25,0xb7,0x93,0x28,0x04,0xa6,0x9c,0xb8,0x10}, - {0x9c,0x28,0x18,0x97,0x49,0x47,0x59,0x3d,0x26,0x3f,0x53,0x24,0xc5,0xf8,0xeb,0x12,0x15,0xef,0xc3,0x14,0xcb,0xbf,0x62,0x02,0x8e,0x51,0xb7,0x77,0xd5,0x78,0xb8,0x20,0x6e,0xf0,0x45,0x5a,0xbe,0x41,0x39,0x75,0x65,0x5f,0x9c,0x6d,0xed,0xae,0x7c,0xd0,0xb6,0x51,0xff,0x72,0x9c,0x6b,0x77,0x11,0xa9,0x4d,0x0d,0xef,0xd9,0xd1,0xd2,0x17,0x6a,0x3e,0x3f,0x07,0x18,0xaf,0xf2,0x27,0x69,0x10,0x52,0xd7,0x19,0xe5,0x3f,0xfd,0x22,0x00,0xa6,0x3c,0x2c,0xb7,0xe3,0x22,0xa7,0xc6,0x65,0xcc,0x63,0x4f,0x21,0x72}, - {0x93,0xa6,0x07,0x53,0x40,0x7f,0xe3,0xb4,0x95,0x67,0x33,0x2f,0xd7,0x14,0xa7,0xab,0x99,0x10,0x76,0x73,0xa7,0xd0,0xfb,0xd6,0xc9,0xcb,0x71,0x81,0xc5,0x48,0xdf,0x5f,0xc9,0x29,0x3b,0xf4,0xb9,0xb7,0x9d,0x1d,0x75,0x8f,0x51,0x4f,0x4a,0x82,0x05,0xd6,0xc4,0x9d,0x2f,0x31,0xbd,0x72,0xc0,0xf2,0xb0,0x45,0x15,0x5a,0x85,0xac,0x24,0x1f,0xaa,0x05,0x95,0x8e,0x32,0x08,0xd6,0x24,0xee,0x20,0x14,0x0c,0xd1,0xc1,0x48,0x47,0xa2,0x25,0xfb,0x06,0x5c,0xe4,0xff,0xc7,0xe6,0x95,0xe3,0x2a,0x9e,0x73,0xba,0x00}, - {0xd6,0x90,0x87,0x5c,0xde,0x98,0x2e,0x59,0xdf,0xa2,0xc2,0x45,0xd3,0xb7,0xbf,0xe5,0x22,0x99,0xb4,0xf9,0x60,0x3b,0x5a,0x11,0xf3,0x78,0xad,0x67,0x3e,0x3a,0x28,0x03,0x26,0xbb,0x88,0xea,0xf5,0x26,0x44,0xae,0xfb,0x3b,0x97,0x84,0xd9,0x79,0x06,0x36,0x50,0x4e,0x69,0x26,0x0c,0x03,0x9f,0x5c,0x26,0xd2,0x18,0xd5,0xe7,0x7d,0x29,0x72,0x39,0xb9,0x0c,0xbe,0xc7,0x1d,0x24,0x48,0x80,0x30,0x63,0x8b,0x4d,0x9b,0xf1,0x32,0x08,0x93,0x28,0x02,0x0d,0xc9,0xdf,0xd3,0x45,0x19,0x27,0x46,0x68,0x29,0xe1,0x05}, - {0x5a,0x49,0x9c,0x2d,0xb3,0xee,0x82,0xba,0x7c,0xb9,0x2b,0xf1,0xfc,0xc8,0xef,0xce,0xe0,0xd1,0xb5,0x93,0xae,0xab,0x2d,0xb0,0x9b,0x8d,0x69,0x13,0x9c,0x0c,0xc0,0x39,0x50,0x45,0x2c,0x24,0xc8,0xbb,0xbf,0xad,0xd9,0x81,0x30,0xd0,0xec,0x0c,0xc8,0xbc,0x92,0xdf,0xc8,0xf5,0xa6,0x66,0x35,0x84,0x4c,0xce,0x58,0x82,0xd3,0x25,0xcf,0x78,0x68,0x9d,0x48,0x31,0x8e,0x6b,0xae,0x15,0x87,0xf0,0x2b,0x9c,0xab,0x1c,0x85,0xaa,0x05,0xfa,0x4e,0xf0,0x97,0x5a,0xa7,0xc9,0x32,0xf8,0x3f,0x6b,0x07,0x52,0x6b,0x00}, - {0x1c,0x78,0x95,0x9d,0xe1,0xcf,0xe0,0x29,0xe2,0x10,0x63,0x96,0x18,0xdf,0x81,0xb6,0x39,0x6b,0x51,0x70,0xd3,0x39,0xdf,0x57,0x22,0x61,0xc7,0x3b,0x44,0xe3,0x57,0x4d,0x2d,0x08,0xce,0xb9,0x16,0x7e,0xcb,0xf5,0x29,0xbc,0x7a,0x41,0x4c,0xf1,0x07,0x34,0xab,0xa7,0xf4,0x2b,0xce,0x6b,0xb3,0xd4,0xce,0x75,0x9f,0x1a,0x56,0xe9,0xe2,0x7d,0xcb,0x5e,0xa5,0xb6,0xf4,0xd4,0x70,0xde,0x99,0xdb,0x85,0x5d,0x7f,0x52,0x01,0x48,0x81,0x9a,0xee,0xd3,0x40,0xc4,0xc9,0xdb,0xed,0x29,0x60,0x1a,0xaf,0x90,0x2a,0x6b}, - {0x97,0x1e,0xe6,0x9a,0xfc,0xf4,0x23,0x69,0xd1,0x5f,0x3f,0xe0,0x1d,0x28,0x35,0x57,0x2d,0xd1,0xed,0xe6,0x43,0xae,0x64,0xa7,0x4a,0x3e,0x2d,0xd1,0xe9,0xf4,0xd8,0x5f,0x0a,0xd8,0xb2,0x5b,0x24,0xf3,0xeb,0x77,0x9b,0x07,0xb9,0x2f,0x47,0x1b,0x30,0xd8,0x33,0x73,0xee,0x4c,0xf2,0xe6,0x47,0xc6,0x09,0x21,0x6c,0x27,0xc8,0x12,0x58,0x46,0xd9,0x62,0x10,0x2a,0xb2,0xbe,0x43,0x4d,0x16,0xdc,0x31,0x38,0x75,0xfb,0x65,0x70,0xd7,0x68,0x29,0xde,0x7b,0x4a,0x0d,0x18,0x90,0x67,0xb1,0x1c,0x2b,0x2c,0xb3,0x05}, - {0xfd,0xa8,0x4d,0xd2,0xcc,0x5e,0xc0,0xc8,0x83,0xef,0xdf,0x05,0xac,0x1a,0xcf,0xa1,0x61,0xcd,0xf9,0x7d,0xf2,0xef,0xbe,0xdb,0x99,0x1e,0x47,0x7b,0xa3,0x56,0x55,0x3b,0x95,0x81,0xd5,0x7a,0x2c,0xa4,0xfc,0xf7,0xcc,0xf3,0x33,0x43,0x6e,0x28,0x14,0x32,0x9d,0x97,0x0b,0x34,0x0d,0x9d,0xc2,0xb6,0xe1,0x07,0x73,0x56,0x48,0x1a,0x77,0x31,0x82,0xd4,0x4d,0xe1,0x24,0xc5,0xb0,0x32,0xb6,0xa4,0x2b,0x1a,0x54,0x51,0xb3,0xed,0xf3,0x5a,0x2b,0x28,0x48,0x60,0xd1,0xa3,0xeb,0x36,0x73,0x7a,0xd2,0x79,0xc0,0x4f}, - {0x7f,0x2f,0xbf,0x89,0xb0,0x38,0xc9,0x51,0xa7,0xe9,0xdf,0x02,0x65,0xbd,0x97,0x24,0x53,0xe4,0x80,0x78,0x9c,0xc0,0xff,0xff,0x92,0x8e,0xf9,0xca,0xce,0x67,0x45,0x12,0x0d,0xc5,0x86,0x0c,0x44,0x8b,0x34,0xdc,0x51,0xe6,0x94,0xcc,0xc9,0xcb,0x37,0x13,0xb9,0x3c,0x3e,0x64,0x4d,0xf7,0x22,0x64,0x08,0xcd,0xe3,0xba,0xc2,0x70,0x11,0x24,0xb4,0x73,0xc4,0x0a,0x86,0xab,0xf9,0x3f,0x35,0xe4,0x13,0x01,0xee,0x1d,0x91,0xf0,0xaf,0xc4,0xc6,0xeb,0x60,0x50,0xe7,0x4a,0x0d,0x00,0x87,0x6c,0x96,0x12,0x86,0x3f}, - {0xde,0x0d,0x2a,0x78,0xc9,0x0c,0x9a,0x55,0x85,0x83,0x71,0xea,0xb2,0xcd,0x1d,0x55,0x8c,0x23,0xef,0x31,0x5b,0x86,0x62,0x7f,0x3d,0x61,0x73,0x79,0x76,0xa7,0x4a,0x50,0x13,0x8d,0x04,0x36,0xfa,0xfc,0x18,0x9c,0xdd,0x9d,0x89,0x73,0xb3,0x9d,0x15,0x29,0xaa,0xd0,0x92,0x9f,0x0b,0x35,0x9f,0xdc,0xd4,0x19,0x8a,0x87,0xee,0x7e,0xf5,0x26,0xb1,0xef,0x87,0x56,0xd5,0x2c,0xab,0x0c,0x7b,0xf1,0x7a,0x24,0x62,0xd1,0x80,0x51,0x67,0x24,0x5a,0x4f,0x34,0x5a,0xc1,0x85,0x69,0x30,0xba,0x9d,0x3d,0x94,0x41,0x40}, - {0x96,0xcc,0xeb,0x43,0xba,0xee,0xc0,0xc3,0xaf,0x9c,0xea,0x26,0x9c,0x9c,0x74,0x8d,0xc6,0xcc,0x77,0x1c,0xee,0x95,0xfa,0xd9,0x0f,0x34,0x84,0x76,0xd9,0xa1,0x20,0x14,0xdd,0xaa,0x6c,0xa2,0x43,0x77,0x21,0x4b,0xce,0xb7,0x8a,0x64,0x24,0xb4,0xa6,0x47,0xe3,0xc9,0xfb,0x03,0x7a,0x4f,0x1d,0xcb,0x19,0xd0,0x00,0x98,0x42,0x31,0xd9,0x12,0x4f,0x59,0x37,0xd3,0x99,0x77,0xc6,0x00,0x7b,0xa4,0x3a,0xb2,0x40,0x51,0x3c,0x5e,0x95,0xf3,0x5f,0xe3,0x54,0x28,0x18,0x44,0x12,0xa0,0x59,0x43,0x31,0x92,0x4f,0x1b}, - {0x51,0x09,0x15,0x89,0x9d,0x10,0x5c,0x3e,0x6a,0x69,0xe9,0x2d,0x91,0xfa,0xce,0x39,0x20,0x30,0x5f,0x97,0x3f,0xe4,0xea,0x20,0xae,0x2d,0x13,0x7f,0x2a,0x57,0x9b,0x23,0xb1,0x66,0x98,0xa4,0x30,0x30,0xcf,0x33,0x59,0x48,0x5f,0x21,0xd2,0x73,0x1f,0x25,0xf6,0xf4,0xde,0x51,0x40,0xaa,0x82,0xab,0xf6,0x23,0x9a,0x6f,0xd5,0x91,0xf1,0x5f,0x68,0x90,0x2d,0xac,0x33,0xd4,0x9e,0x81,0x23,0x85,0xc9,0x5f,0x79,0xab,0x83,0x28,0x3d,0xeb,0x93,0x55,0x80,0x72,0x45,0xef,0xcb,0x36,0x8f,0x75,0x6a,0x52,0x0c,0x02}, - {0xbc,0xdb,0xd8,0x9e,0xf8,0x34,0x98,0x77,0x6c,0xa4,0x7c,0xdc,0xf9,0xaa,0xf2,0xc8,0x74,0xb0,0xe1,0xa3,0xdc,0x4c,0x52,0xa9,0x77,0x38,0x31,0x15,0x46,0xcc,0xaa,0x02,0x89,0xcc,0x42,0xf0,0x59,0xef,0x31,0xe9,0xb6,0x4b,0x12,0x8e,0x9d,0x9c,0x58,0x2c,0x97,0x59,0xc7,0xae,0x8a,0xe1,0xc8,0xad,0x0c,0xc5,0x02,0x56,0x0a,0xfe,0x2c,0x45,0xdf,0x77,0x78,0x64,0xa0,0xf7,0xa0,0x86,0x9f,0x7c,0x60,0x0e,0x27,0x64,0xc4,0xbb,0xc9,0x11,0xfb,0xf1,0x25,0xea,0x17,0xab,0x7b,0x87,0x4b,0x30,0x7b,0x7d,0xfb,0x4c}, - {0xfe,0x75,0x9b,0xb8,0x6c,0x3d,0xb4,0x72,0x80,0xdc,0x6a,0x9c,0xd9,0x94,0xc6,0x54,0x9f,0x4c,0xe3,0x3e,0x37,0xaa,0xc3,0xb8,0x64,0x53,0x07,0x39,0x2b,0x62,0xb4,0x14,0x12,0xef,0x89,0x97,0xc2,0x99,0x86,0xe2,0x0d,0x19,0x57,0xdf,0x71,0xcd,0x6e,0x2b,0xd0,0x70,0xc9,0xec,0x57,0xc8,0x43,0xc3,0xc5,0x3a,0x4d,0x43,0xbc,0x4c,0x1d,0x5b,0x26,0x9f,0x0a,0xcc,0x15,0x26,0xfb,0xb6,0xe5,0xcc,0x8d,0xb8,0x2b,0x0e,0x4f,0x3a,0x05,0xa7,0x69,0x33,0x8b,0x49,0x01,0x13,0xd1,0x2d,0x59,0x58,0x12,0xf7,0x98,0x2f}, - {0x56,0x9e,0x0f,0xb5,0x4c,0xa7,0x94,0x0c,0x20,0x13,0x8e,0x8e,0xa9,0xf4,0x1f,0x5b,0x67,0x0f,0x30,0x82,0x21,0xcc,0x2a,0x9a,0xf9,0xaa,0x06,0xd8,0x49,0xe2,0x6a,0x3a,0x01,0xa7,0x54,0x4f,0x44,0xae,0x12,0x2e,0xde,0xd7,0xcb,0xa9,0xf0,0x3e,0xfe,0xfc,0xe0,0x5d,0x83,0x75,0x0d,0x89,0xbf,0xce,0x54,0x45,0x61,0xe7,0xe9,0x62,0x80,0x1d,0x5a,0x7c,0x90,0xa9,0x85,0xda,0x7a,0x65,0x62,0x0f,0xb9,0x91,0xb5,0xa8,0x0e,0x1a,0xe9,0xb4,0x34,0xdf,0xfb,0x1d,0x0e,0x8d,0xf3,0x5f,0xf2,0xae,0xe8,0x8c,0x8b,0x29}, - {0xb2,0x0c,0xf7,0xef,0x53,0x79,0x92,0x2a,0x76,0x70,0x15,0x79,0x2a,0xc9,0x89,0x4b,0x6a,0xcf,0xa7,0x30,0x7a,0x45,0x18,0x94,0x85,0xe4,0x5c,0x4d,0x40,0xa8,0xb8,0x34,0xde,0x65,0x21,0x0a,0xea,0x72,0x7a,0x83,0xf6,0x79,0xcf,0x0b,0xb4,0x07,0xab,0x3f,0x70,0xae,0x38,0x77,0xc7,0x36,0x16,0x52,0xdc,0xd7,0xa7,0x03,0x18,0x27,0xa6,0x6b,0x35,0x33,0x69,0x83,0xb5,0xec,0x6e,0xc2,0xfd,0xfe,0xb5,0x63,0xdf,0x13,0xa8,0xd5,0x73,0x25,0xb2,0xa4,0x9a,0xaa,0x93,0xa2,0x6a,0x1c,0x5e,0x46,0xdd,0x2b,0xd6,0x71}, - {0x80,0xdf,0x78,0xd3,0x28,0xcc,0x33,0x65,0xb4,0xa4,0x0f,0x0a,0x79,0x43,0xdb,0xf6,0x5a,0xda,0x01,0xf7,0xf9,0x5f,0x64,0xe3,0xa4,0x2b,0x17,0xf3,0x17,0xf3,0xd5,0x74,0xf5,0x5e,0xf7,0xb1,0xda,0xb5,0x2d,0xcd,0xf5,0x65,0xb0,0x16,0xcf,0x95,0x7f,0xd7,0x85,0xf0,0x49,0x3f,0xea,0x1f,0x57,0x14,0x3d,0x2b,0x2b,0x26,0x21,0x36,0x33,0x1c,0x81,0xca,0xd9,0x67,0x54,0xe5,0x6f,0xa8,0x37,0x8c,0x29,0x2b,0x75,0x7c,0x8b,0x39,0x3b,0x62,0xac,0xe3,0x92,0x08,0x6d,0xda,0x8c,0xd9,0xe9,0x47,0x45,0xcc,0xeb,0x4a}, - {0xc9,0x01,0x6d,0x27,0x1b,0x07,0xf0,0x12,0x70,0x8c,0xc4,0x86,0xc5,0xba,0xb8,0xe7,0xa9,0xfb,0xd6,0x71,0x9b,0x12,0x08,0x53,0x92,0xb7,0x3d,0x5a,0xf9,0xfb,0x88,0x5d,0x10,0xb6,0x54,0x73,0x9e,0x8d,0x40,0x0b,0x6e,0x5b,0xa8,0x5b,0x53,0x32,0x6b,0x80,0x07,0xa2,0x58,0x4a,0x03,0x3a,0xe6,0xdb,0x2c,0xdf,0xa1,0xc9,0xdd,0xd9,0x3b,0x17,0xdf,0x72,0x58,0xfe,0x1e,0x0f,0x50,0x2b,0xc1,0x18,0x39,0xd4,0x2e,0x58,0xd6,0x58,0xe0,0x3a,0x67,0xc9,0x8e,0x27,0xed,0xe6,0x19,0xa3,0x9e,0xb1,0x13,0xcd,0xe1,0x06}, - {0x23,0x6f,0x16,0x6f,0x51,0xad,0xd0,0x40,0xbe,0x6a,0xab,0x1f,0x93,0x32,0x8e,0x11,0x8e,0x08,0x4d,0xa0,0x14,0x5e,0xe3,0x3f,0x66,0x62,0xe1,0x26,0x35,0x60,0x80,0x30,0x53,0x03,0x5b,0x9e,0x62,0xaf,0x2b,0x47,0x47,0x04,0x8d,0x27,0x90,0x0b,0xaa,0x3b,0x27,0xbf,0x43,0x96,0x46,0x5f,0x78,0x0c,0x13,0x7b,0x83,0x8d,0x1a,0x6a,0x3a,0x7f,0x0b,0x80,0x3d,0x5d,0x39,0x44,0xe6,0xf7,0xf6,0xed,0x01,0xc9,0x55,0xd5,0xa8,0x95,0x39,0x63,0x2c,0x59,0x30,0x78,0xcd,0x68,0x7e,0x30,0x51,0x2e,0xed,0xfd,0xd0,0x30}, - {0xb3,0x33,0x12,0xf2,0x1a,0x4d,0x59,0xe0,0x9c,0x4d,0xcc,0xf0,0x8e,0xe7,0xdb,0x1b,0x77,0x9a,0x49,0x8f,0x7f,0x18,0x65,0x69,0x68,0x98,0x09,0x2c,0x20,0x14,0x92,0x0a,0x50,0x47,0xb8,0x68,0x1e,0x97,0xb4,0x9c,0xcf,0xbb,0x64,0x66,0x29,0x72,0x95,0xa0,0x2b,0x41,0xfa,0x72,0x26,0xe7,0x8d,0x5c,0xd9,0x89,0xc5,0x51,0x43,0x08,0x15,0x46,0x2e,0xa0,0xb9,0xae,0xc0,0x19,0x90,0xbc,0xae,0x4c,0x03,0x16,0x0d,0x11,0xc7,0x55,0xec,0x32,0x99,0x65,0x01,0xf5,0x6d,0x0e,0xfe,0x5d,0xca,0x95,0x28,0x0d,0xca,0x3b}, - {0xa4,0x62,0x5d,0x3c,0xbc,0x31,0xf0,0x40,0x60,0x7a,0xf0,0xcf,0x3e,0x8b,0xfc,0x19,0x45,0xb5,0x0f,0x13,0xa2,0x3d,0x18,0x98,0xcd,0x13,0x8f,0xae,0xdd,0xde,0x31,0x56,0xbf,0x01,0xcc,0x9e,0xb6,0x8e,0x68,0x9c,0x6f,0x89,0x44,0xa6,0xad,0x83,0xbc,0xf0,0xe2,0x9f,0x7a,0x5f,0x5f,0x95,0x2d,0xca,0x41,0x82,0xf2,0x8d,0x03,0xb4,0xa8,0x4e,0x02,0xd2,0xca,0xf1,0x0a,0x46,0xed,0x2a,0x83,0xee,0x8c,0xa4,0x05,0x53,0x30,0x46,0x5f,0x1a,0xf1,0x49,0x45,0x77,0x21,0x91,0x63,0xa4,0x2c,0x54,0x30,0x09,0xce,0x24}, - {0x06,0xc1,0x06,0xfd,0xf5,0x90,0xe8,0x1f,0xf2,0x10,0x88,0x5d,0x35,0x68,0xc4,0xb5,0x3e,0xaf,0x8c,0x6e,0xfe,0x08,0x78,0x82,0x4b,0xd7,0x06,0x8a,0xc2,0xe3,0xd4,0x41,0x85,0x0b,0xf3,0xfd,0x55,0xa1,0xcf,0x3f,0xa4,0x2e,0x37,0x36,0x8e,0x16,0xf7,0xd2,0x44,0xf8,0x92,0x64,0xde,0x64,0xe0,0xb2,0x80,0x42,0x4f,0x32,0xa7,0x28,0x99,0x54,0x2e,0x1a,0xee,0x63,0xa7,0x32,0x6e,0xf2,0xea,0xfd,0x5f,0xd2,0xb7,0xe4,0x91,0xae,0x69,0x4d,0x7f,0xd1,0x3b,0xd3,0x3b,0xbc,0x6a,0xff,0xdc,0xc0,0xde,0x66,0x1b,0x49}, - {0xa7,0x32,0xea,0xc7,0x3d,0xb1,0xf5,0x98,0x98,0xdb,0x16,0x7e,0xcc,0xf8,0xd5,0xe3,0x47,0xd9,0xf8,0xcb,0x52,0xbf,0x0a,0xac,0xac,0xe4,0x5e,0xc8,0xd0,0x38,0xf3,0x08,0xa1,0x64,0xda,0xd0,0x8e,0x4a,0xf0,0x75,0x4b,0x28,0xe2,0x67,0xaf,0x2c,0x22,0xed,0xa4,0x7b,0x7b,0x1f,0x79,0xa3,0x34,0x82,0x67,0x8b,0x01,0xb7,0xb0,0xb8,0xf6,0x4c,0xbd,0x73,0x1a,0x99,0x21,0xa8,0x83,0xc3,0x7a,0x0c,0x32,0xdf,0x01,0xbc,0x27,0xab,0x63,0x70,0x77,0x84,0x1b,0x33,0x3d,0xc1,0x99,0x8a,0x07,0xeb,0x82,0x4a,0x0d,0x53}, - {0x25,0x48,0xf9,0xe1,0x30,0x36,0x4c,0x00,0x5a,0x53,0xab,0x8c,0x26,0x78,0x2d,0x7e,0x8b,0xff,0x84,0xcc,0x23,0x23,0x48,0xc7,0xb9,0x70,0x17,0x10,0x3f,0x75,0xea,0x65,0x9e,0xbf,0x9a,0x6c,0x45,0x73,0x69,0x6d,0x80,0xa8,0x00,0x49,0xfc,0xb2,0x7f,0x25,0x50,0xb8,0xcf,0xc8,0x12,0xf4,0xac,0x2b,0x5b,0xbd,0xbf,0x0c,0xe0,0xe7,0xb3,0x0d,0x63,0x63,0x09,0xe2,0x3e,0xfc,0x66,0x3d,0x6b,0xcb,0xb5,0x61,0x7f,0x2c,0xd6,0x81,0x1a,0x3b,0x44,0x13,0x42,0x04,0xbe,0x0f,0xdb,0xa1,0xe1,0x21,0x19,0xec,0xa4,0x02}, - {0xa2,0xb8,0x24,0x3b,0x9a,0x25,0xe6,0x5c,0xb8,0xa0,0xaf,0x45,0xcc,0x7a,0x57,0xb8,0x37,0x70,0xa0,0x8b,0xe8,0xe6,0xcb,0xcc,0xbf,0x09,0x78,0x12,0x51,0x3c,0x14,0x3d,0x5f,0x79,0xcf,0xf1,0x62,0x61,0xc8,0xf5,0xf2,0x57,0xee,0x26,0x19,0x86,0x8c,0x11,0x78,0x35,0x06,0x1c,0x85,0x24,0x21,0x17,0xcf,0x7f,0x06,0xec,0x5d,0x2b,0xd1,0x36,0x57,0x45,0x15,0x79,0x91,0x27,0x6d,0x12,0x0a,0x3a,0x78,0xfc,0x5c,0x8f,0xe4,0xd5,0xac,0x9b,0x17,0xdf,0xe8,0xb6,0xbd,0x36,0x59,0x28,0xa8,0x5b,0x88,0x17,0xf5,0x2e}, - {0xdc,0xae,0x58,0x8c,0x4e,0x97,0x37,0x46,0xa4,0x41,0xf0,0xab,0xfb,0x22,0xef,0xb9,0x8a,0x71,0x80,0xe9,0x56,0xd9,0x85,0xe1,0xa6,0xa8,0x43,0xb1,0xfa,0x78,0x1b,0x2f,0x51,0x2f,0x5b,0x30,0xfb,0xbf,0xee,0x96,0xb8,0x96,0x95,0x88,0xad,0x38,0xf9,0xd3,0x25,0xdd,0xd5,0x46,0xc7,0x2d,0xf5,0xf0,0x95,0x00,0x3a,0xbb,0x90,0x82,0x96,0x57,0x01,0xe1,0x20,0x0a,0x43,0xb8,0x1a,0xf7,0x47,0xec,0xf0,0x24,0x8d,0x65,0x93,0xf3,0xd1,0xee,0xe2,0x6e,0xa8,0x09,0x75,0xcf,0xe1,0xa3,0x2a,0xdc,0x35,0x3e,0xc4,0x7d}, - {0xc3,0xd9,0x7d,0x88,0x65,0x66,0x96,0x85,0x55,0x53,0xb0,0x4b,0x31,0x9b,0x0f,0xc9,0xb1,0x79,0x20,0xef,0xf8,0x8d,0xe0,0xc6,0x2f,0xc1,0x8c,0x75,0x16,0x20,0xf7,0x7e,0x18,0x97,0x3e,0x27,0x5c,0x2a,0x78,0x5a,0x94,0xfd,0x4e,0x5e,0x99,0xc6,0x76,0x35,0x3e,0x7d,0x23,0x1f,0x05,0xd8,0x2e,0x0f,0x99,0x0a,0xd5,0x82,0x1d,0xb8,0x4f,0x04,0xd9,0xe3,0x07,0xa9,0xc5,0x18,0xdf,0xc1,0x59,0x63,0x4c,0xce,0x1d,0x37,0xb3,0x57,0x49,0xbb,0x01,0xb2,0x34,0x45,0x70,0xca,0x2e,0xdd,0x30,0x9c,0x3f,0x82,0x79,0x7f}, - {0xe8,0x13,0xb5,0xa3,0x39,0xd2,0x34,0x83,0xd8,0xa8,0x1f,0xb9,0xd4,0x70,0x36,0xc1,0x33,0xbd,0x90,0xf5,0x36,0x41,0xb5,0x12,0xb4,0xd9,0x84,0xd7,0x73,0x03,0x4e,0x0a,0xba,0x87,0xf5,0x68,0xf0,0x1f,0x9c,0x6a,0xde,0xc8,0x50,0x00,0x4e,0x89,0x27,0x08,0xe7,0x5b,0xed,0x7d,0x55,0x99,0xbf,0x3c,0xf0,0xd6,0x06,0x1c,0x43,0xb0,0xa9,0x64,0x19,0x29,0x7d,0x5b,0xa1,0xd6,0xb3,0x2e,0x35,0x82,0x3a,0xd5,0xa0,0xf6,0xb4,0xb0,0x47,0x5d,0xa4,0x89,0x43,0xce,0x56,0x71,0x6c,0x34,0x18,0xce,0x0a,0x7d,0x1a,0x07}, - {0x0b,0xba,0x87,0xc8,0xaa,0x2d,0x07,0xd3,0xee,0x62,0xa5,0xbf,0x05,0x29,0x26,0x01,0x8b,0x76,0xef,0xc0,0x02,0x30,0x54,0xcf,0x9c,0x7e,0xea,0x46,0x71,0xcc,0x3b,0x2c,0x31,0x44,0xe1,0x20,0x52,0x35,0x0c,0xcc,0x41,0x51,0xb1,0x09,0x07,0x95,0x65,0x0d,0x36,0x5f,0x9d,0x20,0x1b,0x62,0xf5,0x9a,0xd3,0x55,0x77,0x61,0xf7,0xbc,0x69,0x7c,0x5f,0x29,0xe8,0x04,0xeb,0xd7,0xf0,0x07,0x7d,0xf3,0x50,0x2f,0x25,0x18,0xdb,0x10,0xd7,0x98,0x17,0x17,0xa3,0xa9,0x51,0xe9,0x1d,0xa5,0xac,0x22,0x73,0x9a,0x5a,0x6f}, - {0xc5,0xc6,0x41,0x2f,0x0c,0x00,0xa1,0x8b,0x9b,0xfb,0xfe,0x0c,0xc1,0x79,0x9f,0xc4,0x9f,0x1c,0xc5,0x3c,0x70,0x47,0xfa,0x4e,0xca,0xaf,0x47,0xe1,0xa2,0x21,0x4e,0x49,0xbe,0x44,0xd9,0xa3,0xeb,0xd4,0x29,0xe7,0x9e,0xaf,0x78,0x80,0x40,0x09,0x9e,0x8d,0x03,0x9c,0x86,0x47,0x7a,0x56,0x25,0x45,0x24,0x3b,0x8d,0xee,0x80,0x96,0xab,0x02,0x9a,0x0d,0xe5,0xdd,0x85,0x8a,0xa4,0xef,0x49,0xa2,0xb9,0x0f,0x4e,0x22,0x9a,0x21,0xd9,0xf6,0x1e,0xd9,0x1d,0x1f,0x09,0xfa,0x34,0xbb,0x46,0xea,0xcb,0x76,0x5d,0x6b}, - {0x94,0xd9,0x0c,0xec,0x6c,0x55,0x57,0x88,0xba,0x1d,0xd0,0x5c,0x6f,0xdc,0x72,0x64,0x77,0xb4,0x42,0x8f,0x14,0x69,0x01,0xaf,0x54,0x73,0x27,0x85,0xf6,0x33,0xe3,0x0a,0x22,0x25,0x78,0x1e,0x17,0x41,0xf9,0xe0,0xd3,0x36,0x69,0x03,0x74,0xae,0xe6,0xf1,0x46,0xc7,0xfc,0xd0,0xa2,0x3e,0x8b,0x40,0x3e,0x31,0xdd,0x03,0x9c,0x86,0xfb,0x16,0x62,0x09,0xb6,0x33,0x97,0x19,0x8e,0x28,0x33,0xe1,0xab,0xd8,0xb4,0x72,0xfc,0x24,0x3e,0xd0,0x91,0x09,0xed,0xf7,0x11,0x48,0x75,0xd0,0x70,0x8f,0x8b,0xe3,0x81,0x3f}, - {0xfe,0xaf,0xd9,0x7e,0xcc,0x0f,0x91,0x7f,0x4b,0x87,0x65,0x24,0xa1,0xb8,0x5c,0x54,0x04,0x47,0x0c,0x4b,0xd2,0x7e,0x39,0xa8,0x93,0x09,0xf5,0x04,0xc1,0x0f,0x51,0x50,0x24,0xc8,0x17,0x5f,0x35,0x7f,0xdb,0x0a,0xa4,0x99,0x42,0xd7,0xc3,0x23,0xb9,0x74,0xf7,0xea,0xf8,0xcb,0x8b,0x3e,0x7c,0xd5,0x3d,0xdc,0xde,0x4c,0xd3,0xe2,0xd3,0x0a,0x9d,0x24,0x6e,0x33,0xc5,0x0f,0x0c,0x6f,0xd9,0xcf,0x31,0xc3,0x19,0xde,0x5e,0x74,0x1c,0xfe,0xee,0x09,0x00,0xfd,0xd6,0xf2,0xbe,0x1e,0xfa,0xf0,0x8b,0x15,0x7c,0x12}, - {0xa2,0x79,0x98,0x2e,0x42,0x7c,0x19,0xf6,0x47,0x36,0xca,0x52,0xd4,0xdd,0x4a,0xa4,0xcb,0xac,0x4e,0x4b,0xc1,0x3f,0x41,0x9b,0x68,0x4f,0xef,0x07,0x7d,0xf8,0x4e,0x35,0x74,0xb9,0x51,0xae,0xc4,0x8f,0xa2,0xde,0x96,0xfe,0x4d,0x74,0xd3,0x73,0x99,0x1d,0xa8,0x48,0x38,0x87,0x0b,0x68,0x40,0x62,0x95,0xdf,0x67,0xd1,0x79,0x24,0xd8,0x4e,0x75,0xd9,0xc5,0x60,0x22,0xb5,0xe3,0xfe,0xb8,0xb0,0x41,0xeb,0xfc,0x2e,0x35,0x50,0x3c,0x65,0xf6,0xa9,0x30,0xac,0x08,0x88,0x6d,0x23,0x39,0x05,0xd2,0x92,0x2d,0x30}, - {0x3d,0x28,0xa4,0xbc,0xa2,0xc1,0x13,0x78,0xd9,0x3d,0x86,0xa1,0x91,0xf0,0x62,0xed,0x86,0xfa,0x68,0xc2,0xb8,0xbc,0xc7,0xae,0x4c,0xae,0x1c,0x6f,0xb7,0xd3,0xe5,0x10,0x77,0xf1,0xe0,0xe4,0xb6,0x6f,0xbc,0x2d,0x93,0x6a,0xbd,0xa4,0x29,0xbf,0xe1,0x04,0xe8,0xf6,0x7a,0x78,0xd4,0x66,0x19,0x5e,0x60,0xd0,0x26,0xb4,0x5e,0x5f,0xdc,0x0e,0x67,0x8e,0xda,0x53,0xd6,0xbf,0x53,0x54,0x41,0xf6,0xa9,0x24,0xec,0x1e,0xdc,0xe9,0x23,0x8a,0x57,0x03,0x3b,0x26,0x87,0xbf,0x72,0xba,0x1c,0x36,0x51,0x6c,0xb4,0x45}, - {0xa1,0x7f,0x4f,0x31,0xbf,0x2a,0x40,0xa9,0x50,0xf4,0x8c,0x8e,0xdc,0xf1,0x57,0xe2,0x84,0xbe,0xa8,0x23,0x4b,0xd5,0xbb,0x1d,0x3b,0x71,0xcb,0x6d,0xa3,0xbf,0x77,0x21,0xe4,0xe3,0x7f,0x8a,0xdd,0x4d,0x9d,0xce,0x30,0x0e,0x62,0x76,0x56,0x64,0x13,0xab,0x58,0x99,0x0e,0xb3,0x7b,0x4f,0x59,0x4b,0xdf,0x29,0x12,0x32,0xef,0x0a,0x1c,0x5c,0x8f,0xdb,0x79,0xfa,0xbc,0x1b,0x08,0x37,0xb3,0x59,0x5f,0xc2,0x1e,0x81,0x48,0x60,0x87,0x24,0x83,0x9c,0x65,0x76,0x7a,0x08,0xbb,0xb5,0x8a,0x7d,0x38,0x19,0xe6,0x4a}, - {0x2e,0xa3,0x44,0x53,0xaa,0xf6,0xdb,0x8d,0x78,0x40,0x1b,0xb4,0xb4,0xea,0x88,0x7d,0x60,0x0d,0x13,0x4a,0x97,0xeb,0xb0,0x5e,0x03,0x3e,0xbf,0x17,0x1b,0xd9,0x00,0x1a,0x83,0xfb,0x5b,0x98,0x44,0x7e,0x11,0x61,0x36,0x31,0x96,0x71,0x2a,0x46,0xe0,0xfc,0x4b,0x90,0x25,0xd4,0x48,0x34,0xac,0x83,0x64,0x3d,0xa4,0x5b,0xbe,0x5a,0x68,0x75,0xb2,0xf2,0x61,0xeb,0x33,0x09,0x96,0x6e,0x52,0x49,0xff,0xc9,0xa8,0x0f,0x3d,0x54,0x69,0x65,0xf6,0x7a,0x10,0x75,0x72,0xdf,0xaa,0xe6,0xb0,0x23,0xb6,0x29,0x55,0x13}, - {0x18,0xd5,0xd1,0xad,0xd7,0xdb,0xf0,0x18,0x11,0x1f,0xc1,0xcf,0x88,0x78,0x9f,0x97,0x9b,0x75,0x14,0x71,0xf0,0xe1,0x32,0x87,0x01,0x3a,0xca,0x65,0x1a,0xb8,0xb5,0x79,0xfe,0x83,0x2e,0xe2,0xbc,0x16,0xc7,0xf5,0xc1,0x85,0x09,0xe8,0x19,0xeb,0x2b,0xb4,0xae,0x4a,0x25,0x14,0x37,0xa6,0x9d,0xec,0x13,0xa6,0x90,0x15,0x05,0xea,0x72,0x59,0x11,0x78,0x8f,0xdc,0x20,0xac,0xd4,0x0f,0xa8,0x4f,0x4d,0xac,0x94,0xd2,0x9a,0x9a,0x34,0x04,0x36,0xb3,0x64,0x2d,0x1b,0xc0,0xdb,0x3b,0x5f,0x90,0x95,0x9c,0x7e,0x4f}, - {0x2e,0x30,0x81,0x57,0xbc,0x4b,0x67,0x62,0x0f,0xdc,0xad,0x89,0x39,0x0f,0x52,0xd8,0xc6,0xd9,0xfb,0x53,0xae,0x99,0x29,0x8c,0x4c,0x8e,0x63,0x2e,0xd9,0x3a,0x99,0x31,0xfe,0x99,0x52,0x35,0x3d,0x44,0xc8,0x71,0xd7,0xea,0xeb,0xdb,0x1c,0x3b,0xcd,0x8b,0x66,0x94,0xa4,0xf1,0x9e,0x49,0x92,0x80,0xc8,0xad,0x44,0xa1,0xc4,0xee,0x42,0x19,0x92,0x49,0x23,0xae,0x19,0x53,0xac,0x7d,0x92,0x3e,0xea,0x0c,0x91,0x3d,0x1b,0x2c,0x22,0x11,0x3c,0x25,0x94,0xe4,0x3c,0x55,0x75,0xca,0xf9,0x4e,0x31,0x65,0x0a,0x2a}, - {0xc2,0x27,0xf9,0xf7,0x7f,0x93,0xb7,0x2d,0x35,0xa6,0xd0,0x17,0x06,0x1f,0x74,0xdb,0x76,0xaf,0x55,0x11,0xa2,0xf3,0x82,0x59,0xed,0x2d,0x7c,0x64,0x18,0xe2,0xf6,0x4c,0x3a,0x79,0x1c,0x3c,0xcd,0x1a,0x36,0xcf,0x3b,0xbc,0x35,0x5a,0xac,0xbc,0x9e,0x2f,0xab,0xa6,0xcd,0xa8,0xe9,0x60,0xe8,0x60,0x13,0x1a,0xea,0x6d,0x9b,0xc3,0x5d,0x05,0xb6,0x5b,0x8d,0xc2,0x7c,0x22,0x19,0xb1,0xab,0xff,0x4d,0x77,0xbc,0x4e,0xe2,0x07,0x89,0x2c,0xa3,0xe4,0xce,0x78,0x3c,0xa8,0xb6,0x24,0xaa,0x10,0x77,0x30,0x1a,0x12}, - {0x97,0x4a,0x03,0x9f,0x5e,0x5d,0xdb,0xe4,0x2d,0xbc,0x34,0x30,0x09,0xfc,0x53,0xe1,0xb1,0xd3,0x51,0x95,0x91,0x46,0x05,0x46,0x2d,0xe5,0x40,0x7a,0x6c,0xc7,0x3f,0x33,0xc9,0x83,0x74,0xc7,0x3e,0x71,0x59,0xd6,0xaf,0x96,0x2b,0xb8,0x77,0xe0,0xbf,0x88,0xd3,0xbc,0x97,0x10,0x23,0x28,0x9e,0x28,0x9b,0x3a,0xed,0x6c,0x4a,0xb9,0x7b,0x52,0x2e,0x48,0x5b,0x99,0x2a,0x99,0x3d,0x56,0x01,0x38,0x38,0x6e,0x7c,0xd0,0x05,0x34,0xe5,0xd8,0x64,0x2f,0xde,0x35,0x50,0x48,0xf7,0xa9,0xa7,0x20,0x9b,0x06,0x89,0x6b}, - {0x0d,0x22,0x70,0x62,0x41,0xa0,0x2a,0x81,0x4e,0x5b,0x24,0xf9,0xfa,0x89,0x5a,0x99,0x05,0xef,0x72,0x50,0xce,0xc4,0xad,0xff,0x73,0xeb,0x73,0xaa,0x03,0x21,0xbc,0x23,0x77,0xdb,0xc7,0xb5,0x8c,0xfa,0x82,0x40,0x55,0xc1,0x34,0xc7,0xf8,0x86,0x86,0x06,0x7e,0xa5,0xe7,0xf6,0xd9,0xc8,0xe6,0x29,0xcf,0x9b,0x63,0xa7,0x08,0xd3,0x73,0x04,0x05,0x9e,0x58,0x03,0x26,0x79,0xee,0xca,0x92,0xc4,0xdc,0x46,0x12,0x42,0x4b,0x2b,0x4f,0xa9,0x01,0xe6,0x74,0xef,0xa1,0x02,0x1a,0x34,0x04,0xde,0xbf,0x73,0x2f,0x10}, - {0xc6,0x45,0x57,0x7f,0xab,0xb9,0x18,0xeb,0x90,0xc6,0x87,0x57,0xee,0x8a,0x3a,0x02,0xa9,0xaf,0xf7,0x2d,0xda,0x12,0x27,0xb7,0x3d,0x01,0x5c,0xea,0x25,0x7d,0x59,0x36,0x9a,0x1c,0x51,0xb5,0xe0,0xda,0xb4,0xa2,0x06,0xff,0xff,0x2b,0x29,0x60,0xc8,0x7a,0x34,0x42,0x50,0xf5,0x5d,0x37,0x1f,0x98,0x2d,0xa1,0x4e,0xda,0x25,0xd7,0x6b,0x3f,0xac,0x58,0x60,0x10,0x7b,0x8d,0x4d,0x73,0x5f,0x90,0xc6,0x6f,0x9e,0x57,0x40,0xd9,0x2d,0x93,0x02,0x92,0xf9,0xf8,0x66,0x64,0xd0,0xd6,0x60,0xda,0x19,0xcc,0x7e,0x7b}, - {0x0d,0x69,0x5c,0x69,0x3c,0x37,0xc2,0x78,0x6e,0x90,0x42,0x06,0x66,0x2e,0x25,0xdd,0xd2,0x2b,0xe1,0x4a,0x44,0x44,0x1d,0x95,0x56,0x39,0x74,0x01,0x76,0xad,0x35,0x42,0x9b,0xfa,0x7c,0xa7,0x51,0x4a,0xae,0x6d,0x50,0x86,0xa3,0xe7,0x54,0x36,0x26,0x82,0xdb,0x82,0x2d,0x8f,0xcd,0xff,0xbb,0x09,0xba,0xca,0xf5,0x1b,0x66,0xdc,0xbe,0x03,0xf5,0x75,0x89,0x07,0x0d,0xcb,0x58,0x62,0x98,0xf2,0x89,0x91,0x54,0x42,0x29,0x49,0xe4,0x6e,0xe3,0xe2,0x23,0xb4,0xca,0xa0,0xa1,0x66,0xf0,0xcd,0xb0,0xe2,0x7c,0x0e}, - {0xa3,0x85,0x8c,0xc4,0x3a,0x64,0x94,0xc4,0xad,0x39,0x61,0x3c,0xf4,0x1d,0x36,0xfd,0x48,0x4d,0xe9,0x3a,0xdd,0x17,0xdb,0x09,0x4a,0x67,0xb4,0x8f,0x5d,0x0a,0x6e,0x66,0xf9,0x70,0x4b,0xd9,0xdf,0xfe,0xa6,0xfe,0x2d,0xba,0xfc,0xc1,0x51,0xc0,0x30,0xf1,0x89,0xab,0x2f,0x7f,0x7e,0xd4,0x82,0x48,0xb5,0xee,0xec,0x8a,0x13,0x56,0x52,0x61,0x0d,0xcb,0x70,0x48,0x4e,0xf6,0xbb,0x2a,0x6b,0x8b,0x45,0xaa,0xf0,0xbc,0x65,0xcd,0x5d,0x98,0xe8,0x75,0xba,0x4e,0xbe,0x9a,0xe4,0xde,0x14,0xd5,0x10,0xc8,0x0b,0x7f}, - {0x6f,0x13,0xf4,0x26,0xa4,0x6b,0x00,0xb9,0x35,0x30,0xe0,0x57,0x9e,0x36,0x67,0x8d,0x28,0x3c,0x46,0x4f,0xd9,0xdf,0xc8,0xcb,0xf5,0xdb,0xee,0xf8,0xbc,0x8d,0x1f,0x0d,0xa0,0x13,0x72,0x73,0xad,0x9d,0xac,0x83,0x98,0x2e,0xf7,0x2e,0xba,0xf8,0xf6,0x9f,0x57,0x69,0xec,0x43,0xdd,0x2e,0x1e,0x31,0x75,0xab,0xc5,0xde,0x7d,0x90,0x3a,0x1d,0xdc,0x81,0xd0,0x3e,0x31,0x93,0x16,0xba,0x80,0x34,0x1b,0x85,0xad,0x9f,0x32,0x29,0xcb,0x21,0x03,0x03,0x3c,0x01,0x28,0x01,0xe3,0xfd,0x1b,0xa3,0x44,0x1b,0x01,0x00}, - {0x0c,0x6c,0xc6,0x3f,0x6c,0xa0,0xdf,0x3f,0xd2,0x0d,0xd6,0x4d,0x8e,0xe3,0x40,0x5d,0x71,0x4d,0x8e,0x26,0x38,0x8b,0xe3,0x7a,0xe1,0x57,0x83,0x6e,0x91,0x8d,0xc4,0x3a,0x5c,0xa7,0x0a,0x6a,0x69,0x1f,0x56,0x16,0x6a,0xbd,0x52,0x58,0x5c,0x72,0xbf,0xc1,0xad,0x66,0x79,0x9a,0x7f,0xdd,0xa8,0x11,0x26,0x10,0x85,0xd2,0xa2,0x88,0xd9,0x63,0x2e,0x23,0xbd,0xaf,0x53,0x07,0x12,0x00,0x83,0xf6,0xd8,0xfd,0xb8,0xce,0x2b,0xe9,0x91,0x2b,0xe7,0x84,0xb3,0x69,0x16,0xf8,0x66,0xa0,0x68,0x23,0x2b,0xd5,0xfa,0x33}, - {0x16,0x1e,0xe4,0xc5,0xc6,0x49,0x06,0x54,0x35,0x77,0x3f,0x33,0x30,0x64,0xf8,0x0a,0x46,0xe7,0x05,0xf3,0xd2,0xfc,0xac,0xb2,0xa7,0xdc,0x56,0xa2,0x29,0xf4,0xc0,0x16,0xe8,0xcf,0x22,0xc4,0xd0,0xc8,0x2c,0x8d,0xcb,0x3a,0xa1,0x05,0x7b,0x4f,0x2b,0x07,0x6f,0xa5,0xf6,0xec,0xe6,0xb6,0xfe,0xa3,0xe2,0x71,0x0a,0xb9,0xcc,0x55,0xc3,0x3c,0x31,0x91,0x3e,0x90,0x43,0x94,0xb6,0xe9,0xce,0x37,0x56,0x7a,0xcb,0x94,0xa4,0xb8,0x44,0x92,0xba,0xba,0xa4,0xd1,0x7c,0xc8,0x68,0x75,0xae,0x6b,0x42,0xaf,0x1e,0x63}, - {0x9f,0xfe,0x66,0xda,0x10,0x04,0xe9,0xb3,0xa6,0xe5,0x16,0x6c,0x52,0x4b,0xdd,0x85,0x83,0xbf,0xf9,0x1e,0x61,0x97,0x3d,0xbc,0xb5,0x19,0xa9,0x1e,0x8b,0x64,0x99,0x55,0xe8,0x0d,0x70,0xa3,0xb9,0x75,0xd9,0x47,0x52,0x05,0xf8,0xe2,0xfb,0xc5,0x80,0x72,0xe1,0x5d,0xe4,0x32,0x27,0x8f,0x65,0x53,0xb5,0x80,0x5f,0x66,0x7f,0x2c,0x1f,0x43,0x19,0x7b,0x8f,0x85,0x44,0x63,0x02,0xd6,0x4a,0x51,0xea,0xa1,0x2f,0x35,0xab,0x14,0xd7,0xa9,0x90,0x20,0x1a,0x44,0x00,0x89,0x26,0x3b,0x25,0x91,0x5f,0x71,0x04,0x7b}, - {0x43,0xae,0xf6,0xac,0x28,0xbd,0xed,0x83,0xb4,0x7a,0x5c,0x7d,0x8b,0x7c,0x35,0x86,0x44,0x2c,0xeb,0xb7,0x69,0x47,0x40,0xc0,0x3f,0x58,0xf6,0xc2,0xf5,0x7b,0xb3,0x59,0xc6,0xba,0xe6,0xc4,0x80,0xc2,0x76,0xb3,0x0b,0x9b,0x1d,0x6d,0xdd,0xd3,0x0e,0x97,0x44,0xf9,0x0b,0x45,0x58,0x95,0x9a,0xb0,0x23,0xe2,0xcd,0x57,0xfa,0xac,0xd0,0x48,0x71,0xe6,0xab,0x7d,0xe4,0x26,0x0f,0xb6,0x37,0x3a,0x2f,0x62,0x97,0xa1,0xd1,0xf1,0x94,0x03,0x96,0xe9,0x7e,0xce,0x08,0x42,0xdb,0x3b,0x6d,0x33,0x91,0x41,0x23,0x16}, - {0xf6,0x7f,0x26,0xf6,0xde,0x99,0xe4,0xb9,0x43,0x08,0x2c,0x74,0x7b,0xca,0x72,0x77,0xb1,0xf2,0xa4,0xe9,0x3f,0x15,0xa0,0x23,0x06,0x50,0xd0,0xd5,0xec,0xdf,0xdf,0x2c,0x40,0x86,0xf3,0x1f,0xd6,0x9c,0x49,0xdd,0xa0,0x25,0x36,0x06,0xc3,0x9b,0xcd,0x29,0xc3,0x3d,0xd7,0x3d,0x02,0xd8,0xe2,0x51,0x31,0x92,0x3b,0x20,0x7a,0x70,0x25,0x4a,0x6a,0xed,0xf6,0x53,0x8a,0x66,0xb7,0x2a,0xa1,0x70,0xd1,0x1d,0x58,0x42,0x42,0x30,0x61,0x01,0xe2,0x3a,0x4c,0x14,0x00,0x40,0xfc,0x49,0x8e,0x24,0x6d,0x89,0x21,0x57}, - {0xae,0x1b,0x18,0xfd,0x17,0x55,0x6e,0x0b,0xb4,0x63,0xb9,0x2b,0x9f,0x62,0x22,0x90,0x25,0x46,0x06,0x32,0xe9,0xbc,0x09,0x55,0xda,0x13,0x3c,0xf6,0x74,0xdd,0x8e,0x57,0x4e,0xda,0xd0,0xa1,0x91,0x50,0x5d,0x28,0x08,0x3e,0xfe,0xb5,0xa7,0x6f,0xaa,0x4b,0xb3,0x93,0x93,0xe1,0x7c,0x17,0xe5,0x63,0xfd,0x30,0xb0,0xc4,0xaf,0x35,0xc9,0x03,0x3d,0x0c,0x2b,0x49,0xc6,0x76,0x72,0x99,0xfc,0x05,0xe2,0xdf,0xc4,0xc2,0xcc,0x47,0x3c,0x3a,0x62,0xdd,0x84,0x9b,0xd2,0xdc,0xa2,0xc7,0x88,0x02,0x59,0xab,0xc2,0x3e}, - {0xb9,0x7b,0xd8,0xe4,0x7b,0xd2,0xa0,0xa1,0xed,0x1a,0x39,0x61,0xeb,0x4d,0x8b,0xa9,0x83,0x9b,0xcb,0x73,0xd0,0xdd,0xa0,0x99,0xce,0xca,0x0f,0x20,0x5a,0xc2,0xd5,0x2d,0xcb,0xd1,0x32,0xae,0x09,0x3a,0x21,0xa7,0xd5,0xc2,0xf5,0x40,0xdf,0x87,0x2b,0x0f,0x29,0xab,0x1e,0xe8,0xc6,0xa4,0xae,0x0b,0x5e,0xac,0xdb,0x6a,0x6c,0xf6,0x1b,0x0e,0x7e,0x88,0x2c,0x79,0xe9,0xd5,0xab,0xe2,0x5d,0x6d,0x92,0xcb,0x18,0x00,0x02,0x1a,0x1e,0x5f,0xae,0xba,0xcd,0x69,0xba,0xbf,0x5f,0x8f,0xe8,0x5a,0xb3,0x48,0x05,0x73}, - {0xee,0xb8,0xa8,0xcb,0xa3,0x51,0x35,0xc4,0x16,0x5f,0x11,0xb2,0x1d,0x6f,0xa2,0x65,0x50,0x38,0x8c,0xab,0x52,0x4f,0x0f,0x76,0xca,0xb8,0x1d,0x41,0x3b,0x44,0x43,0x30,0x34,0xe3,0xd6,0xa1,0x4b,0x09,0x5b,0x80,0x19,0x3f,0x35,0x09,0x77,0xf1,0x3e,0xbf,0x2b,0x70,0x22,0x06,0xcb,0x06,0x3f,0x42,0xdd,0x45,0x78,0xd8,0x77,0x22,0x5a,0x58,0x62,0x89,0xd4,0x33,0x82,0x5f,0x8a,0xa1,0x7f,0x25,0x78,0xec,0xb5,0xc4,0x98,0x66,0xff,0x41,0x3e,0x37,0xa5,0x6f,0x8e,0xa7,0x1f,0x98,0xef,0x50,0x89,0x27,0x56,0x76}, - {0xc0,0xc8,0x1f,0xd5,0x59,0xcf,0xc3,0x38,0xf2,0xb6,0x06,0x05,0xfd,0xd2,0xed,0x9b,0x8f,0x0e,0x57,0xab,0x9f,0x10,0xbf,0x26,0xa6,0x46,0xb8,0xc1,0xa8,0x60,0x41,0x3f,0x9d,0xcf,0x86,0xea,0xa3,0x73,0x70,0xe1,0xdc,0x5f,0x15,0x07,0xb7,0xfb,0x8c,0x3a,0x8e,0x8a,0x83,0x31,0xfc,0xe7,0x53,0x48,0x16,0xf6,0x13,0xb6,0x84,0xf4,0xbb,0x28,0x7c,0x6c,0x13,0x6f,0x5c,0x2f,0x61,0xf2,0xbe,0x11,0xdd,0xf6,0x07,0xd1,0xea,0xaf,0x33,0x6f,0xde,0x13,0xd2,0x9a,0x7e,0x52,0x5d,0xf7,0x88,0x81,0x35,0xcb,0x79,0x1e}, - {0xf1,0xe3,0xf7,0xee,0xc3,0x36,0x34,0x01,0xf8,0x10,0x9e,0xfe,0x7f,0x6a,0x8b,0x82,0xfc,0xde,0xf9,0xbc,0xe5,0x08,0xf9,0x7f,0x31,0x38,0x3b,0x3a,0x1b,0x95,0xd7,0x65,0x81,0x81,0xe0,0xf5,0xd8,0x53,0xe9,0x77,0xd9,0xde,0x9d,0x29,0x44,0x0c,0xa5,0x84,0xe5,0x25,0x45,0x86,0x0c,0x2d,0x6c,0xdc,0xf4,0xf2,0xd1,0x39,0x2d,0xb5,0x8a,0x47,0x59,0xd1,0x52,0x92,0xd3,0xa4,0xa6,0x66,0x07,0xc8,0x1a,0x87,0xbc,0xe1,0xdd,0xe5,0x6f,0xc9,0xc1,0xa6,0x40,0x6b,0x2c,0xb8,0x14,0x22,0x21,0x1a,0x41,0x7a,0xd8,0x16}, - {0x15,0x62,0x06,0x42,0x5a,0x7e,0xbd,0xb3,0xc1,0x24,0x5a,0x0c,0xcd,0xe3,0x9b,0x87,0xb7,0x94,0xf9,0xd6,0xb1,0x5d,0xc0,0x57,0xa6,0x8c,0xf3,0x65,0x81,0x7c,0xf8,0x28,0x83,0x05,0x4e,0xd5,0xe2,0xd5,0xa4,0xfb,0xfa,0x99,0xbd,0x2e,0xd7,0xaf,0x1f,0xe2,0x8f,0x77,0xe9,0x6e,0x73,0xc2,0x7a,0x49,0xde,0x6d,0x5a,0x7a,0x57,0x0b,0x99,0x1f,0xd6,0xf7,0xe8,0x1b,0xad,0x4e,0x34,0xa3,0x8f,0x79,0xea,0xac,0xeb,0x50,0x1e,0x7d,0x52,0xe0,0x0d,0x52,0x9e,0x56,0xc6,0x77,0x3e,0x6d,0x4d,0x53,0xe1,0x2f,0x88,0x45}, - {0xd6,0x83,0x79,0x75,0x5d,0x34,0x69,0x66,0xa6,0x11,0xaa,0x17,0x11,0xed,0xb6,0x62,0x8f,0x12,0x5e,0x98,0x57,0x18,0xdd,0x7d,0xdd,0xf6,0x26,0xf6,0xb8,0xe5,0x8f,0x68,0xe4,0x6f,0x3c,0x94,0x29,0x99,0xac,0xd8,0xa2,0x92,0x83,0xa3,0x61,0xf1,0xf9,0xb5,0xf3,0x9a,0xc8,0xbe,0x13,0xdb,0x99,0x26,0x74,0xf0,0x05,0xe4,0x3c,0x84,0xcf,0x7d,0xc0,0x32,0x47,0x4a,0x48,0xd6,0x90,0x6c,0x99,0x32,0x56,0xca,0xfd,0x43,0x21,0xd5,0xe1,0xc6,0x5d,0x91,0xc3,0x28,0xbe,0xb3,0x1b,0x19,0x27,0x73,0x7e,0x68,0x39,0x67}, - {0xa6,0x75,0x56,0x38,0x14,0x20,0x78,0xef,0xe8,0xa9,0xfd,0xaa,0x30,0x9f,0x64,0xa2,0xcb,0xa8,0xdf,0x5c,0x50,0xeb,0xd1,0x4c,0xb3,0xc0,0x4d,0x1d,0xba,0x5a,0x11,0x46,0xc0,0x1a,0x0c,0xc8,0x9d,0xcc,0x6d,0xa6,0x36,0xa4,0x38,0x1b,0xf4,0x5c,0xa0,0x97,0xc6,0xd7,0xdb,0x95,0xbe,0xf3,0xeb,0xa7,0xab,0x7d,0x7e,0x8d,0xf6,0xb8,0xa0,0x7d,0x76,0xda,0xb5,0xc3,0x53,0x19,0x0f,0xd4,0x9b,0x9e,0x11,0x21,0x73,0x6f,0xac,0x1d,0x60,0x59,0xb2,0xfe,0x21,0x60,0xcc,0x03,0x4b,0x4b,0x67,0x83,0x7e,0x88,0x5f,0x5a}, - {0x11,0x3d,0xa1,0x70,0xcf,0x01,0x63,0x8f,0xc4,0xd0,0x0d,0x35,0x15,0xb8,0xce,0xcf,0x7e,0xa4,0xbc,0xa4,0xd4,0x97,0x02,0xf7,0x34,0x14,0x4d,0xe4,0x56,0xb6,0x69,0x36,0xb9,0x43,0xa6,0xa0,0xd3,0x28,0x96,0x9e,0x64,0x20,0xc3,0xe6,0x00,0xcb,0xc3,0xb5,0x32,0xec,0x2d,0x7c,0x89,0x02,0x53,0x9b,0x0c,0xc7,0xd1,0xd5,0xe2,0x7a,0xe3,0x43,0x33,0xe1,0xa6,0xed,0x06,0x3f,0x7e,0x38,0xc0,0x3a,0xa1,0x99,0x51,0x1d,0x30,0x67,0x11,0x38,0x26,0x36,0xf8,0xd8,0x5a,0xbd,0xbe,0xe9,0xd5,0x4f,0xcd,0xe6,0x21,0x6a}, - {0x5f,0xe6,0x46,0x30,0x0a,0x17,0xc6,0xf1,0x24,0x35,0xd2,0x00,0x2a,0x2a,0x71,0x58,0x55,0xb7,0x82,0x8c,0x3c,0xbd,0xdb,0x69,0x57,0xff,0x95,0xa1,0xf1,0xf9,0x6b,0x58,0xe3,0xb2,0x99,0x66,0x12,0x29,0x41,0xef,0x01,0x13,0x8d,0x70,0x47,0x08,0xd3,0x71,0xbd,0xb0,0x82,0x11,0xd0,0x32,0x54,0x32,0x36,0x8b,0x1e,0x00,0x07,0x1b,0x37,0x45,0x0b,0x79,0xf8,0x5e,0x8d,0x08,0xdb,0xa6,0xe5,0x37,0x09,0x61,0xdc,0xf0,0x78,0x52,0xb8,0x6e,0xa1,0x61,0xd2,0x49,0x03,0xac,0x79,0x21,0xe5,0x90,0x37,0xb0,0xaf,0x0e}, - {0x2f,0x04,0x48,0x37,0xc1,0x55,0x05,0x96,0x11,0xaa,0x0b,0x82,0xe6,0x41,0x9a,0x21,0x0c,0x6d,0x48,0x73,0x38,0xf7,0x81,0x1c,0x61,0xc6,0x02,0x5a,0x67,0xcc,0x9a,0x30,0x1d,0xae,0x75,0x0f,0x5e,0x80,0x40,0x51,0x30,0xcc,0x62,0x26,0xe3,0xfb,0x02,0xec,0x6d,0x39,0x92,0xea,0x1e,0xdf,0xeb,0x2c,0xb3,0x5b,0x43,0xc5,0x44,0x33,0xae,0x44,0xee,0x43,0xa5,0xbb,0xb9,0x89,0xf2,0x9c,0x42,0x71,0xc9,0x5a,0x9d,0x0e,0x76,0xf3,0xaa,0x60,0x93,0x4f,0xc6,0xe5,0x82,0x1d,0x8f,0x67,0x94,0x7f,0x1b,0x22,0xd5,0x62}, - {0x6d,0x93,0xd0,0x18,0x9c,0x29,0x4c,0x52,0x0c,0x1a,0x0c,0x8a,0x6c,0xb5,0x6b,0xc8,0x31,0x86,0x4a,0xdb,0x2e,0x05,0x75,0xa3,0x62,0x45,0x75,0xbc,0xe4,0xfd,0x0e,0x5c,0x3c,0x7a,0xf7,0x3a,0x26,0xd4,0x85,0x75,0x4d,0x14,0xe9,0xfe,0x11,0x7b,0xae,0xdf,0x3d,0x19,0xf7,0x59,0x80,0x70,0x06,0xa5,0x37,0x20,0x92,0x83,0x53,0x9a,0xf2,0x14,0xf5,0xd7,0xb2,0x25,0xdc,0x7e,0x71,0xdf,0x40,0x30,0xb5,0x99,0xdb,0x70,0xf9,0x21,0x62,0x4c,0xed,0xc3,0xb7,0x34,0x92,0xda,0x3e,0x09,0xee,0x7b,0x5c,0x36,0x72,0x5e}, - {0x7f,0x21,0x71,0x45,0x07,0xfc,0x5b,0x57,0x5b,0xd9,0x94,0x06,0x5d,0x67,0x79,0x37,0x33,0x1e,0x19,0xf4,0xbb,0x37,0x0a,0x9a,0xbc,0xea,0xb4,0x47,0x4c,0x10,0xf1,0x77,0x3e,0xb3,0x08,0x2f,0x06,0x39,0x93,0x7d,0xbe,0x32,0x9f,0xdf,0xe5,0x59,0x96,0x5b,0xfd,0xbd,0x9e,0x1f,0xad,0x3d,0xff,0xac,0xb7,0x49,0x73,0xcb,0x55,0x05,0xb2,0x70,0x4c,0x2c,0x11,0x55,0xc5,0x13,0x51,0xbe,0xcd,0x1f,0x88,0x9a,0x3a,0x42,0x88,0x66,0x47,0x3b,0x50,0x5e,0x85,0x77,0x66,0x44,0x4a,0x40,0x06,0x4a,0x8f,0x39,0x34,0x0e}, - {0xe8,0xbd,0xce,0x3e,0xd9,0x22,0x7d,0xb6,0x07,0x2f,0x82,0x27,0x41,0xe8,0xb3,0x09,0x8d,0x6d,0x5b,0xb0,0x1f,0xa6,0x3f,0x74,0x72,0x23,0x36,0x8a,0x36,0x05,0x54,0x5e,0x28,0x19,0x4b,0x3e,0x09,0x0b,0x93,0x18,0x40,0xf6,0xf3,0x73,0x0e,0xe1,0xe3,0x7d,0x6f,0x5d,0x39,0x73,0xda,0x17,0x32,0xf4,0x3e,0x9c,0x37,0xca,0xd6,0xde,0x8a,0x6f,0x9a,0xb2,0xb7,0xfd,0x3d,0x12,0x40,0xe3,0x91,0xb2,0x1a,0xa2,0xe1,0x97,0x7b,0x48,0x9e,0x94,0xe6,0xfd,0x02,0x7d,0x96,0xf9,0x97,0xde,0xd3,0xc8,0x2e,0xe7,0x0d,0x78}, - {0xbc,0xe7,0x9a,0x08,0x45,0x85,0xe2,0x0a,0x06,0x4d,0x7f,0x1c,0xcf,0xde,0x8d,0x38,0xb8,0x11,0x48,0x0a,0x51,0x15,0xac,0x38,0xe4,0x8c,0x92,0x71,0xf6,0x8b,0xb2,0x0e,0x72,0x27,0xf4,0x00,0xf3,0xea,0x1f,0x67,0xaa,0x41,0x8c,0x2a,0x2a,0xeb,0x72,0x8f,0x92,0x32,0x37,0x97,0xd7,0x7f,0xa1,0x29,0xa6,0x87,0xb5,0x32,0xad,0xc6,0xef,0x1d,0xa7,0x95,0x51,0xef,0x1a,0xbe,0x5b,0xaf,0xed,0x15,0x7b,0x91,0x77,0x12,0x8c,0x14,0x2e,0xda,0xe5,0x7a,0xfb,0xf7,0x91,0x29,0x67,0x28,0xdd,0xf8,0x1b,0x20,0x7d,0x46}, - {0xad,0x4f,0xef,0x74,0x9a,0x91,0xfe,0x95,0xa2,0x08,0xa3,0xf6,0xec,0x7b,0x82,0x3a,0x01,0x7b,0xa4,0x09,0xd3,0x01,0x4e,0x96,0x97,0xc7,0xa3,0x5b,0x4f,0x3c,0xc4,0x71,0xa9,0xe7,0x7a,0x56,0xbd,0xf4,0x1e,0xbc,0xbd,0x98,0x44,0xd6,0xb2,0x4c,0x62,0x3f,0xc8,0x4e,0x1f,0x2c,0xd2,0x64,0x10,0xe4,0x01,0x40,0x38,0xba,0xa5,0xc5,0xf9,0x2e,0xcd,0x74,0x9e,0xfa,0xf6,0x6d,0xfd,0xb6,0x7a,0x26,0xaf,0xe4,0xbc,0x78,0x82,0xf1,0x0e,0x99,0xef,0xf1,0xd0,0xb3,0x55,0x82,0x93,0xf2,0xc5,0x90,0xa3,0x8c,0x75,0x5a}, - {0x95,0x24,0x46,0xd9,0x10,0x27,0xb7,0xa2,0x03,0x50,0x7d,0xd5,0xd2,0xc6,0xa8,0x3a,0xca,0x87,0xb4,0xa0,0xbf,0x00,0xd4,0xe3,0xec,0x72,0xeb,0xb3,0x44,0xe2,0xba,0x2d,0x94,0xdc,0x61,0x1d,0x8b,0x91,0xe0,0x8c,0x66,0x30,0x81,0x9a,0x46,0x36,0xed,0x8d,0xd3,0xaa,0xe8,0xaf,0x29,0xa8,0xe6,0xd4,0x3f,0xd4,0x39,0xf6,0x27,0x80,0x73,0x0a,0xcc,0xe1,0xff,0x57,0x2f,0x4a,0x0f,0x98,0x43,0x98,0x83,0xe1,0x0d,0x0d,0x67,0x00,0xfd,0x15,0xfb,0x49,0x4a,0x3f,0x5c,0x10,0x9c,0xa6,0x26,0x51,0x63,0xca,0x98,0x26}, - {0x78,0xba,0xb0,0x32,0x88,0x31,0x65,0xe7,0x8b,0xff,0x5c,0x92,0xf7,0x31,0x18,0x38,0xcc,0x1f,0x29,0xa0,0x91,0x1b,0xa8,0x08,0x07,0xeb,0xca,0x49,0xcc,0x3d,0xb4,0x1f,0x0e,0xd9,0x3d,0x5e,0x2f,0x70,0x3d,0x2e,0x86,0x53,0xd2,0xe4,0x18,0x09,0x3f,0x9e,0x6a,0xa9,0x4d,0x02,0xf6,0x3e,0x77,0x5e,0x32,0x33,0xfa,0x4a,0x0c,0x4b,0x00,0x3c,0x2b,0xb8,0xf4,0x06,0xac,0x46,0xa9,0x9a,0xf3,0xc4,0x06,0xa8,0xa5,0x84,0xa2,0x1c,0x87,0x47,0xcd,0xc6,0x5f,0x26,0xd3,0x3e,0x17,0xd2,0x1f,0xcd,0x01,0xfd,0x43,0x6b}, - {0x44,0xc5,0x97,0x46,0x4b,0x5d,0xa7,0xc7,0xbf,0xff,0x0f,0xdf,0x48,0xf8,0xfd,0x15,0x5a,0x78,0x46,0xaa,0xeb,0xb9,0x68,0x28,0x14,0xf7,0x52,0x5b,0x10,0xd7,0x68,0x5a,0xf3,0x0e,0x76,0x3e,0x58,0x42,0xc7,0xb5,0x90,0xb9,0x0a,0xee,0xb9,0x52,0xdc,0x75,0x3f,0x92,0x2b,0x07,0xc2,0x27,0x14,0xbf,0xf0,0xd9,0xf0,0x6f,0x2d,0x0b,0x42,0x73,0x06,0x1e,0x85,0x9e,0xcb,0xf6,0x2c,0xaf,0xc4,0x38,0x22,0xc6,0x13,0x39,0x59,0x8f,0x73,0xf3,0xfb,0x99,0x96,0xb8,0x8a,0xda,0x9e,0xbc,0x34,0xea,0x2f,0x63,0xb5,0x3d}, - {0xd8,0xd9,0x5d,0xf7,0x2b,0xee,0x6e,0xf4,0xa5,0x59,0x67,0x39,0xf6,0xb1,0x17,0x0d,0x73,0x72,0x9e,0x49,0x31,0xd1,0xf2,0x1b,0x13,0x5f,0xd7,0x49,0xdf,0x1a,0x32,0x04,0xd5,0x25,0x98,0x82,0xb1,0x90,0x49,0x2e,0x91,0x89,0x9a,0x3e,0x87,0xeb,0xea,0xed,0xf8,0x4a,0x70,0x4c,0x39,0x3d,0xf0,0xee,0x0e,0x2b,0xdf,0x95,0xa4,0x7e,0x19,0x59,0xae,0x5a,0xe5,0xe4,0x19,0x60,0xe1,0x04,0xe9,0x92,0x2f,0x7e,0x7a,0x43,0x7b,0xe7,0xa4,0x9a,0x15,0x6f,0xc1,0x2d,0xce,0xc7,0xc0,0x0c,0xd7,0xf4,0xc1,0xfd,0xea,0x45}, - {0x2b,0xd7,0x45,0x80,0x85,0x01,0x84,0x69,0x51,0x06,0x2f,0xcf,0xa2,0xfa,0x22,0x4c,0xc6,0x2d,0x22,0x6b,0x65,0x36,0x1a,0x94,0xde,0xda,0x62,0x03,0xc8,0xeb,0x5e,0x5a,0xed,0xb1,0xcc,0xcf,0x24,0x46,0x0e,0xb6,0x95,0x03,0x5c,0xbd,0x92,0xc2,0xdb,0x59,0xc9,0x81,0x04,0xdc,0x1d,0x9d,0xa0,0x31,0x40,0xd9,0x56,0x5d,0xea,0xce,0x73,0x3f,0xc6,0x8d,0x4e,0x0a,0xd1,0xbf,0xa7,0xb7,0x39,0xb3,0xc9,0x44,0x7e,0x00,0x57,0xbe,0xfa,0xae,0x57,0x15,0x7f,0x20,0xc1,0x60,0xdb,0x18,0x62,0x26,0x91,0x88,0x05,0x26}, - {0x04,0xff,0x60,0x83,0xa6,0x04,0xf7,0x59,0xf4,0xe6,0x61,0x76,0xde,0x3f,0xd9,0xc3,0x51,0x35,0x87,0x12,0x73,0x2a,0x1b,0x83,0x57,0x5d,0x61,0x4e,0x2e,0x0c,0xad,0x54,0x42,0xe5,0x76,0xc6,0x3c,0x8e,0x81,0x4c,0xad,0xcc,0xce,0x03,0x93,0x2c,0x42,0x5e,0x08,0x9f,0x12,0xb4,0xca,0xcc,0x07,0xec,0xb8,0x43,0x44,0xb2,0x10,0xfa,0xed,0x0d,0x2a,0x52,0x2b,0xb8,0xd5,0x67,0x3b,0xee,0xeb,0xc1,0xa5,0x9f,0x46,0x63,0xf1,0x36,0xd3,0x9f,0xc1,0x6e,0xf2,0xd2,0xb4,0xa5,0x08,0x94,0x7a,0xa7,0xba,0xb2,0xec,0x62}, - {0x3d,0x2b,0x15,0x61,0x52,0x79,0xed,0xe5,0xd1,0xd7,0xdd,0x0e,0x7d,0x35,0x62,0x49,0x71,0x4c,0x6b,0xb9,0xd0,0xc8,0x82,0x74,0xbe,0xd8,0x66,0xa9,0x19,0xf9,0x59,0x2e,0x74,0x28,0xb6,0xaf,0x36,0x28,0x07,0x92,0xa5,0x04,0xe1,0x79,0x85,0x5e,0xcd,0x5f,0x4a,0xa1,0x30,0xc6,0xad,0x01,0xad,0x5a,0x98,0x3f,0x66,0x75,0x50,0x3d,0x91,0x61,0xda,0x31,0x32,0x1a,0x36,0x2d,0xc6,0x0d,0x70,0x02,0x20,0x94,0x32,0x58,0x47,0xfa,0xce,0x94,0x95,0x3f,0x51,0x01,0xd8,0x02,0x5c,0x5d,0xc0,0x31,0xa1,0xc2,0xdb,0x3d}, - {0x4b,0xc5,0x5e,0xce,0xf9,0x0f,0xdc,0x9a,0x0d,0x13,0x2f,0x8c,0x6b,0x2a,0x9c,0x03,0x15,0x95,0xf8,0xf0,0xc7,0x07,0x80,0x02,0x6b,0xb3,0x04,0xac,0x14,0x83,0x96,0x78,0x14,0xbb,0x96,0x27,0xa2,0x57,0xaa,0xf3,0x21,0xda,0x07,0x9b,0xb7,0xba,0x3a,0x88,0x1c,0x39,0xa0,0x31,0x18,0xe2,0x4b,0xe5,0xf9,0x05,0x32,0xd8,0x38,0xfb,0xe7,0x5e,0x8e,0x6a,0x44,0x41,0xcb,0xfd,0x8d,0x53,0xf9,0x37,0x49,0x43,0xa9,0xfd,0xac,0xa5,0x78,0x8c,0x3c,0x26,0x8d,0x90,0xaf,0x46,0x09,0x0d,0xca,0x9b,0x3c,0x63,0xd0,0x61}, - {0x66,0x25,0xdb,0xff,0x35,0x49,0x74,0x63,0xbb,0x68,0x0b,0x78,0x89,0x6b,0xbd,0xc5,0x03,0xec,0x3e,0x55,0x80,0x32,0x1b,0x6f,0xf5,0xd7,0xae,0x47,0xd8,0x5f,0x96,0x6e,0xdf,0x73,0xfc,0xf8,0xbc,0x28,0xa3,0xad,0xfc,0x37,0xf0,0xa6,0x5d,0x69,0x84,0xee,0x09,0xa9,0xc2,0x38,0xdb,0xb4,0x7f,0x63,0xdc,0x7b,0x06,0xf8,0x2d,0xac,0x23,0x5b,0x7b,0x52,0x80,0xee,0x53,0xb9,0xd2,0x9a,0x8d,0x6d,0xde,0xfa,0xaa,0x19,0x8f,0xe8,0xcf,0x82,0x0e,0x15,0x04,0x17,0x71,0x0e,0xdc,0xde,0x95,0xdd,0xb9,0xbb,0xb9,0x79}, - {0xc2,0x26,0x31,0x6a,0x40,0x55,0xb3,0xeb,0x93,0xc3,0xc8,0x68,0xa8,0x83,0x63,0xd2,0x82,0x7a,0xb9,0xe5,0x29,0x64,0x0c,0x6c,0x47,0x21,0xfd,0xc9,0x58,0xf1,0x65,0x50,0x74,0x73,0x9f,0x8e,0xae,0x7d,0x99,0xd1,0x16,0x08,0xbb,0xcf,0xf8,0xa2,0x32,0xa0,0x0a,0x5f,0x44,0x6d,0x12,0xba,0x6c,0xcd,0x34,0xb8,0xcc,0x0a,0x46,0x11,0xa8,0x1b,0x54,0x99,0x42,0x0c,0xfb,0x69,0x81,0x70,0x67,0xcf,0x6e,0xd7,0xac,0x00,0x46,0xe1,0xba,0x45,0xe6,0x70,0x8a,0xb9,0xaa,0x2e,0xf2,0xfa,0xa4,0x58,0x9e,0xf3,0x81,0x39}, - {0x93,0x0a,0x23,0x59,0x75,0x8a,0xfb,0x18,0x5d,0xf4,0xe6,0x60,0x69,0x8f,0x16,0x1d,0xb5,0x3c,0xa9,0x14,0x45,0xa9,0x85,0x3a,0xfd,0xd0,0xac,0x05,0x37,0x08,0xdc,0x38,0xde,0x6f,0xe6,0x6d,0xa5,0xdf,0x45,0xc8,0x3a,0x48,0x40,0x2c,0x00,0xa5,0x52,0xe1,0x32,0xf6,0xb4,0xc7,0x63,0xe1,0xd2,0xe9,0x65,0x1b,0xbc,0xdc,0x2e,0x45,0xf4,0x30,0x40,0x97,0x75,0xc5,0x82,0x27,0x6d,0x85,0xcc,0xbe,0x9c,0xf9,0x69,0x45,0x13,0xfa,0x71,0x4e,0xea,0xc0,0x73,0xfc,0x44,0x88,0x69,0x24,0x3f,0x59,0x1a,0x9a,0x2d,0x63}, - {0xa6,0xcb,0x07,0xb8,0x15,0x6b,0xbb,0xf6,0xd7,0xf0,0x54,0xbc,0xdf,0xc7,0x23,0x18,0x0b,0x67,0x29,0x6e,0x03,0x97,0x1d,0xbb,0x57,0x4a,0xed,0x47,0x88,0xf4,0x24,0x0b,0xa7,0x84,0x0c,0xed,0x11,0xfd,0x09,0xbf,0x3a,0x69,0x9f,0x0d,0x81,0x71,0xf0,0x63,0x79,0x87,0xcf,0x57,0x2d,0x8c,0x90,0x21,0xa2,0x4b,0xf6,0x8a,0xf2,0x7d,0x5a,0x3a,0xc7,0xea,0x1b,0x51,0xbe,0xd4,0xda,0xdc,0xf2,0xcc,0x26,0xed,0x75,0x80,0x53,0xa4,0x65,0x9a,0x5f,0x00,0x9f,0xff,0x9c,0xe1,0x63,0x1f,0x48,0x75,0x44,0xf7,0xfc,0x34}, - {0xca,0x67,0x97,0x78,0x4c,0xe0,0x97,0xc1,0x7d,0x46,0xd9,0x38,0xcb,0x4d,0x71,0xb8,0xa8,0x5f,0xf9,0x83,0x82,0x88,0xde,0x55,0xf7,0x63,0xfa,0x4d,0x16,0xdc,0x3b,0x3d,0x98,0xaa,0xcf,0x78,0xab,0x1d,0xbb,0xa5,0xf2,0x72,0x0b,0x19,0x67,0xa2,0xed,0x5c,0x8e,0x60,0x92,0x0a,0x11,0xc9,0x09,0x93,0xb0,0x74,0xb3,0x2f,0x04,0xa3,0x19,0x01,0x7d,0x17,0xc2,0xe8,0x9c,0xd8,0xa2,0x67,0xc1,0xd0,0x95,0x68,0xf6,0xa5,0x9d,0x66,0xb0,0xa2,0x82,0xb2,0xe5,0x98,0x65,0xf5,0x73,0x0a,0xe2,0xed,0xf1,0x88,0xc0,0x56}, - {0x17,0x6e,0xa8,0x10,0x11,0x3d,0x6d,0x33,0xfa,0xb2,0x75,0x0b,0x32,0x88,0xf3,0xd7,0x88,0x29,0x07,0x25,0x76,0x33,0x15,0xf9,0x87,0x8b,0x10,0x99,0x6b,0x4c,0x67,0x09,0x02,0x8f,0xf3,0x24,0xac,0x5f,0x1b,0x58,0xbd,0x0c,0xe3,0xba,0xfe,0xe9,0x0b,0xa9,0xf0,0x92,0xcf,0x8a,0x02,0x69,0x21,0x9a,0x8f,0x03,0x59,0x83,0xa4,0x7e,0x8b,0x03,0xf8,0x6f,0x31,0x99,0x21,0xf8,0x4e,0x9f,0x4f,0x8d,0xa7,0xea,0x82,0xd2,0x49,0x2f,0x74,0x31,0xef,0x5a,0xab,0xa5,0x71,0x09,0x65,0xeb,0x69,0x59,0x02,0x31,0x5e,0x6e}, - {0xfb,0x93,0xe5,0x87,0xf5,0x62,0x6c,0xb1,0x71,0x3e,0x5d,0xca,0xde,0xed,0x99,0x49,0x6d,0x3e,0xcc,0x14,0xe0,0xc1,0x91,0xb4,0xa8,0xdb,0xa8,0x89,0x47,0x11,0xf5,0x08,0x22,0x62,0x06,0x63,0x0e,0xfb,0x04,0x33,0x3f,0xba,0xac,0x87,0x89,0x06,0x35,0xfb,0xa3,0x61,0x10,0x8c,0x77,0x24,0x19,0xbd,0x20,0x86,0x83,0xd1,0x43,0xad,0x58,0x30,0xd0,0x63,0x76,0xe5,0xfd,0x0f,0x3c,0x32,0x10,0xa6,0x2e,0xa2,0x38,0xdf,0xc3,0x05,0x9a,0x4f,0x99,0xac,0xbd,0x8a,0xc7,0xbd,0x99,0xdc,0xe3,0xef,0xa4,0x9f,0x54,0x26}, - {0xd6,0xf9,0x6b,0x1e,0x46,0x5a,0x1d,0x74,0x81,0xa5,0x77,0x77,0xfc,0xb3,0x05,0x23,0xd9,0xd3,0x74,0x64,0xa2,0x74,0x55,0xd4,0xff,0xe0,0x01,0x64,0xdc,0xe1,0x26,0x19,0x6e,0x66,0x3f,0xaf,0x49,0x85,0x46,0xdb,0xa5,0x0e,0x4a,0xf1,0x04,0xcf,0x7f,0xd7,0x47,0x0c,0xba,0xa4,0xf7,0x3f,0xf2,0x3d,0x85,0x3c,0xce,0x32,0xe1,0xdf,0x10,0x3a,0xa0,0xce,0x17,0xea,0x8a,0x4e,0x7f,0xe0,0xfd,0xc1,0x1f,0x3a,0x46,0x15,0xd5,0x2f,0xf1,0xc0,0xf2,0x31,0xfd,0x22,0x53,0x17,0x15,0x5d,0x1e,0x86,0x1d,0xd0,0xa1,0x1f}, - {0x32,0x98,0x59,0x7d,0x94,0x55,0x80,0xcc,0x20,0x55,0xf1,0x37,0xda,0x56,0x46,0x1e,0x20,0x93,0x05,0x4e,0x74,0xf7,0xf6,0x99,0x33,0xcf,0x75,0x6a,0xbc,0x63,0x35,0x77,0xab,0x94,0xdf,0xd1,0x00,0xac,0xdc,0x38,0xe9,0x0d,0x08,0xd1,0xdd,0x2b,0x71,0x2e,0x62,0xe2,0xd5,0xfd,0x3e,0xe9,0x13,0x7f,0xe5,0x01,0x9a,0xee,0x18,0xed,0xfc,0x73,0xb3,0x9c,0x13,0x63,0x08,0xe9,0xb1,0x06,0xcd,0x3e,0xa0,0xc5,0x67,0xda,0x93,0xa4,0x32,0x89,0x63,0xad,0xc8,0xce,0x77,0x8d,0x44,0x4f,0x86,0x1b,0x70,0x6b,0x42,0x1f}, - {0x01,0x1c,0x91,0x41,0x4c,0x26,0xc9,0xef,0x25,0x2c,0xa2,0x17,0xb8,0xb7,0xa3,0xf1,0x47,0x14,0x0f,0xf3,0x6b,0xda,0x75,0x58,0x90,0xb0,0x31,0x1d,0x27,0xf5,0x1a,0x4e,0x52,0x25,0xa1,0x91,0xc8,0x35,0x7e,0xf1,0x76,0x9c,0x5e,0x57,0x53,0x81,0x6b,0xb7,0x3e,0x72,0x9b,0x0d,0x6f,0x40,0x83,0xfa,0x38,0xe4,0xa7,0x3f,0x1b,0xbb,0x76,0x0b,0x9b,0x93,0x92,0x7f,0xf9,0xc1,0xb8,0x08,0x6e,0xab,0x44,0xd4,0xcb,0x71,0x67,0xbe,0x17,0x80,0xbb,0x99,0x63,0x64,0xe5,0x22,0x55,0xa9,0x72,0xb7,0x1e,0xd6,0x6d,0x7b}, - {0x92,0x3d,0xf3,0x50,0xe8,0xc1,0xad,0xb7,0xcf,0xd5,0x8c,0x60,0x4f,0xfa,0x98,0x79,0xdb,0x5b,0xfc,0x8d,0xbd,0x2d,0x96,0xad,0x4f,0x2f,0x1d,0xaf,0xce,0x9b,0x3e,0x70,0xc7,0xd2,0x01,0xab,0xf9,0xab,0x30,0x57,0x18,0x3b,0x14,0x40,0xdc,0x76,0xfb,0x16,0x81,0xb2,0xcb,0xa0,0x65,0xbe,0x6c,0x86,0xfe,0x6a,0xff,0x9b,0x65,0x9b,0xfa,0x53,0x55,0x54,0x88,0x94,0xe9,0xc8,0x14,0x6c,0xe5,0xd4,0xae,0x65,0x66,0x5d,0x3a,0x84,0xf1,0x5a,0xd6,0xbc,0x3e,0xb7,0x1b,0x18,0x50,0x1f,0xc6,0xc4,0xe5,0x93,0x8d,0x39}, - {0xf3,0x48,0xe2,0x33,0x67,0xd1,0x4b,0x1c,0x5f,0x0a,0xbf,0x15,0x87,0x12,0x9e,0xbd,0x76,0x03,0x0b,0xa1,0xf0,0x8c,0x3f,0xd4,0x13,0x1b,0x19,0xdf,0x5d,0x9b,0xb0,0x53,0xf2,0xe3,0xe7,0xd2,0x60,0x7c,0x87,0xc3,0xb1,0x8b,0x82,0x30,0xa0,0xaa,0x34,0x3b,0x38,0xf1,0x9e,0x73,0xe7,0x26,0x3e,0x28,0x77,0x05,0xc3,0x02,0x90,0x9c,0x9c,0x69,0xcc,0xf1,0x46,0x59,0x23,0xa7,0x06,0xf3,0x7d,0xd9,0xe5,0xcc,0xb5,0x18,0x17,0x92,0x75,0xe9,0xb4,0x81,0x47,0xd2,0xcd,0x28,0x07,0xd9,0xcd,0x6f,0x0c,0xf3,0xca,0x51}, - {0x0a,0xe0,0x74,0x76,0x42,0xa7,0x0b,0xa6,0xf3,0x7b,0x7a,0xa1,0x70,0x85,0x0e,0x63,0xcc,0x24,0x33,0xcf,0x3d,0x56,0x58,0x37,0xaa,0xfd,0x83,0x23,0x29,0xaa,0x04,0x55,0xc7,0x54,0xac,0x18,0x9a,0xf9,0x7a,0x73,0x0f,0xb3,0x1c,0xc5,0xdc,0x78,0x33,0x90,0xc7,0x0c,0xe1,0x4c,0x33,0xbc,0x89,0x2b,0x9a,0xe9,0xf8,0x89,0xc1,0x29,0xae,0x12,0xcf,0x01,0x0d,0x1f,0xcb,0xc0,0x9e,0xa9,0xae,0xf7,0x34,0x3a,0xcc,0xef,0xd1,0x0d,0x22,0x4e,0x9c,0xd0,0x21,0x75,0xca,0x55,0xea,0xa5,0xeb,0x58,0xe9,0x4f,0xd1,0x5f}, - {0x2c,0xab,0x45,0x28,0xdf,0x2d,0xdc,0xb5,0x93,0xe9,0x7f,0x0a,0xb1,0x91,0x94,0x06,0x46,0xe3,0x02,0x40,0xd6,0xf3,0xaa,0x4d,0xd1,0x74,0x64,0x58,0x6e,0xf2,0x3f,0x09,0x8e,0xcb,0x93,0xbf,0x5e,0xfe,0x42,0x3c,0x5f,0x56,0xd4,0x36,0x51,0xa8,0xdf,0xbe,0xe8,0x20,0x42,0x88,0x9e,0x85,0xf0,0xe0,0x28,0xd1,0x25,0x07,0x96,0x3f,0xd7,0x7d,0x29,0x98,0x05,0x68,0xfe,0x24,0x0d,0xb1,0xe5,0x23,0xaf,0xdb,0x72,0x06,0x73,0x75,0x29,0xac,0x57,0xb4,0x3a,0x25,0x67,0x13,0xa4,0x70,0xb4,0x86,0xbc,0xbc,0x59,0x2f}, - {0x5f,0x13,0x17,0x99,0x42,0x7d,0x84,0x83,0xd7,0x03,0x7d,0x56,0x1f,0x91,0x1b,0xad,0xd1,0xaa,0x77,0xbe,0xd9,0x48,0x77,0x7e,0x4a,0xaf,0x51,0x2e,0x2e,0xb4,0x58,0x54,0x01,0xc3,0x91,0xb6,0x60,0xd5,0x41,0x70,0x1e,0xe7,0xd7,0xad,0x3f,0x1b,0x20,0x85,0x85,0x55,0x33,0x11,0x63,0xe1,0xc2,0x16,0xb1,0x28,0x08,0x01,0x3d,0x5e,0xa5,0x2a,0x4f,0x44,0x07,0x0c,0xe6,0x92,0x51,0xed,0x10,0x1d,0x42,0x74,0x2d,0x4e,0xc5,0x42,0x64,0xc8,0xb5,0xfd,0x82,0x4c,0x2b,0x35,0x64,0x86,0x76,0x8a,0x4a,0x00,0xe9,0x13}, - {0xdb,0xce,0x2f,0x83,0x45,0x88,0x9d,0x73,0x63,0xf8,0x6b,0xae,0xc9,0xd6,0x38,0xfa,0xf7,0xfe,0x4f,0xb7,0xca,0x0d,0xbc,0x32,0x5e,0xe4,0xbc,0x14,0x88,0x7e,0x93,0x73,0x7f,0x87,0x3b,0x19,0xc9,0x00,0x2e,0xbb,0x6b,0x50,0xdc,0xe0,0x90,0xa8,0xe3,0xec,0x9f,0x64,0xde,0x36,0xc0,0xb7,0xf3,0xec,0x1a,0x9e,0xde,0x98,0x08,0x04,0x46,0x5f,0x8d,0xf4,0x7b,0x29,0x16,0x71,0x03,0xb9,0x34,0x68,0xf0,0xd4,0x22,0x3b,0xd1,0xa9,0xc6,0xbd,0x96,0x46,0x57,0x15,0x97,0xe1,0x35,0xe8,0xd5,0x91,0xe8,0xa4,0xf8,0x2c}, - {0x67,0x0f,0x11,0x07,0x87,0xfd,0x93,0x6d,0x49,0xb5,0x38,0x7c,0xd3,0x09,0x4c,0xdd,0x86,0x6a,0x73,0xc2,0x4c,0x6a,0xb1,0x7c,0x09,0x2a,0x25,0x58,0x6e,0xbd,0x49,0x20,0xa2,0x6b,0xd0,0x17,0x7e,0x48,0xb5,0x2c,0x6b,0x19,0x50,0x39,0x1c,0x38,0xd2,0x24,0x30,0x8a,0x97,0x85,0x81,0x9c,0x65,0xd7,0xf6,0xa4,0xd6,0x91,0x28,0x7f,0x6f,0x7a,0x49,0xef,0x9a,0x6a,0x8d,0xfd,0x09,0x7d,0x0b,0xb9,0x3d,0x5b,0xbe,0x60,0xee,0xf0,0xd4,0xbf,0x9e,0x51,0x2c,0xb5,0x21,0x4c,0x1d,0x94,0x45,0xc5,0xdf,0xaa,0x11,0x60}, - {0x3c,0xf8,0x95,0xcf,0x6d,0x92,0x67,0x5f,0x71,0x90,0x28,0x71,0x61,0x85,0x7e,0x7c,0x5b,0x7a,0x8f,0x99,0xf3,0xe7,0xa1,0xd6,0xe0,0xf9,0x62,0x0b,0x1b,0xcc,0xc5,0x6f,0x90,0xf8,0xcb,0x02,0xc8,0xd0,0xde,0x63,0xaa,0x6a,0xff,0x0d,0xca,0x98,0xd0,0xfb,0x99,0xed,0xb6,0xb9,0xfd,0x0a,0x4d,0x62,0x1e,0x0b,0x34,0x79,0xb7,0x18,0xce,0x69,0xcb,0x79,0x98,0xb2,0x28,0x55,0xef,0xd1,0x92,0x90,0x7e,0xd4,0x3c,0xae,0x1a,0xdd,0x52,0x23,0x9f,0x18,0x42,0x04,0x7e,0x12,0xf1,0x01,0x71,0xe5,0x3a,0x6b,0x59,0x15}, - {0xa2,0x79,0x91,0x3f,0xd2,0x39,0x27,0x46,0xcf,0xdd,0xd6,0x97,0x31,0x12,0x83,0xff,0x8a,0x14,0xf2,0x53,0xb5,0xde,0x07,0x13,0xda,0x4d,0x5f,0x7b,0x68,0x37,0x22,0x0d,0xca,0x24,0x51,0x7e,0x16,0x31,0xff,0x09,0xdf,0x45,0xc7,0xd9,0x8b,0x15,0xe4,0x0b,0xe5,0x56,0xf5,0x7e,0x22,0x7d,0x2b,0x29,0x38,0xd1,0xb6,0xaf,0x41,0xe2,0xa4,0x3a,0xf5,0x05,0x33,0x2a,0xbf,0x38,0xc1,0x2c,0xc3,0x26,0xe9,0xa2,0x8f,0x3f,0x58,0x48,0xeb,0xd2,0x49,0x55,0xa2,0xb1,0x3a,0x08,0x6c,0xa3,0x87,0x46,0x6e,0xaa,0xfc,0x32}, - {0xf5,0x9a,0x7d,0xc5,0x8d,0x6e,0xc5,0x7b,0xf2,0xbd,0xf0,0x9d,0xed,0xd2,0x0b,0x3e,0xa3,0xe4,0xef,0x22,0xde,0x14,0xc0,0xaa,0x5c,0x6a,0xbd,0xfe,0xce,0xe9,0x27,0x46,0xdf,0xcc,0x87,0x27,0x73,0xa4,0x07,0x32,0xf8,0xe3,0x13,0xf2,0x08,0x19,0xe3,0x17,0x4e,0x96,0x0d,0xf6,0xd7,0xec,0xb2,0xd5,0xe9,0x0b,0x60,0xc2,0x36,0x63,0x6f,0x74,0x1c,0x97,0x6c,0xab,0x45,0xf3,0x4a,0x3f,0x1f,0x73,0x43,0x99,0x72,0xeb,0x88,0xe2,0x6d,0x18,0x44,0x03,0x8a,0x6a,0x59,0x33,0x93,0x62,0xd6,0x7e,0x00,0x17,0x49,0x7b}, - {0x64,0xb0,0x84,0xab,0x5c,0xfb,0x85,0x2d,0x14,0xbc,0xf3,0x89,0xd2,0x10,0x78,0x49,0x0c,0xce,0x15,0x7b,0x44,0xdc,0x6a,0x47,0x7b,0xfd,0x44,0xf8,0x76,0xa3,0x2b,0x12,0xdd,0xa2,0x53,0xdd,0x28,0x1b,0x34,0x54,0x3f,0xfc,0x42,0xdf,0x5b,0x90,0x17,0xaa,0xf4,0xf8,0xd2,0x4d,0xd9,0x92,0xf5,0x0f,0x7d,0xd3,0x8c,0xe0,0x0f,0x62,0x03,0x1d,0x54,0xe5,0xb4,0xa2,0xcd,0x32,0x02,0xc2,0x7f,0x18,0x5d,0x11,0x42,0xfd,0xd0,0x9e,0xd9,0x79,0xd4,0x7d,0xbe,0xb4,0xab,0x2e,0x4c,0xec,0x68,0x2b,0xf5,0x0b,0xc7,0x02}, - {0xbb,0x2f,0x0b,0x5d,0x4b,0xec,0x87,0xa2,0xca,0x82,0x48,0x07,0x90,0x57,0x5c,0x41,0x5c,0x81,0xd0,0xc1,0x1e,0xa6,0x44,0xe0,0xe0,0xf5,0x9e,0x40,0x0a,0x4f,0x33,0x26,0xe1,0x72,0x8d,0x45,0xbf,0x32,0xe5,0xac,0xb5,0x3c,0xb7,0x7c,0xe0,0x68,0xe7,0x5b,0xe7,0xbd,0x8b,0xee,0x94,0x7d,0xcf,0x56,0x03,0x3a,0xb4,0xfe,0xe3,0x97,0x06,0x6b,0xc0,0xa3,0x62,0xdf,0x4a,0xf0,0xc8,0xb6,0x5d,0xa4,0x6d,0x07,0xef,0x00,0xf0,0x3e,0xa9,0xd2,0xf0,0x49,0x58,0xb9,0x9c,0x9c,0xae,0x2f,0x1b,0x44,0x43,0x7f,0xc3,0x1c}, - {0x4f,0x32,0xc7,0x5c,0x5a,0x56,0x8f,0x50,0x22,0xa9,0x06,0xe5,0xc0,0xc4,0x61,0xd0,0x19,0xac,0x45,0x5c,0xdb,0xab,0x18,0xfb,0x4a,0x31,0x80,0x03,0xc1,0x09,0x68,0x6c,0xb9,0xae,0xce,0xc9,0xf1,0x56,0x66,0xd7,0x6a,0x65,0xe5,0x18,0xf8,0x15,0x5b,0x1c,0x34,0x23,0x4c,0x84,0x32,0x28,0xe7,0x26,0x38,0x68,0x19,0x2f,0x77,0x6f,0x34,0x3a,0xc8,0x6a,0xda,0xe2,0x12,0x51,0xd5,0xd2,0xed,0x51,0xe8,0xb1,0x31,0x03,0xbd,0xe9,0x62,0x72,0xc6,0x8e,0xdd,0x46,0x07,0x96,0xd0,0xc5,0xf7,0x6e,0x9f,0x1b,0x91,0x05}, - {0xbb,0x0e,0xdf,0xf5,0x83,0x99,0x33,0xc1,0xac,0x4c,0x2c,0x51,0x8f,0x75,0xf3,0xc0,0xe1,0x98,0xb3,0x0b,0x0a,0x13,0xf1,0x2c,0x62,0x0c,0x27,0xaa,0xf9,0xec,0x3c,0x6b,0xef,0xea,0x2e,0x51,0xf3,0xac,0x49,0x53,0x49,0xcb,0xc1,0x1c,0xd3,0x41,0xc1,0x20,0x8d,0x68,0x9a,0xa9,0x07,0x0c,0x18,0x24,0x17,0x2d,0x4b,0xc6,0xd1,0xf9,0x5e,0x55,0x08,0xbd,0x73,0x3b,0xba,0x70,0xa7,0x36,0x0c,0xbf,0xaf,0xa3,0x08,0xef,0x4a,0x62,0xf2,0x46,0x09,0xb4,0x98,0xff,0x37,0x57,0x9d,0x74,0x81,0x33,0xe1,0x4d,0x5f,0x67}, - {0xfc,0x82,0x17,0x6b,0x03,0x52,0x2c,0x0e,0xb4,0x83,0xad,0x6c,0x81,0x6c,0x81,0x64,0x3e,0x07,0x64,0x69,0xd9,0xbd,0xdc,0xd0,0x20,0xc5,0x64,0x01,0xf7,0x9d,0xd9,0x13,0x1d,0xb3,0xda,0x3b,0xd9,0xf6,0x2f,0xa1,0xfe,0x2d,0x65,0x9d,0x0f,0xd8,0x25,0x07,0x87,0x94,0xbe,0x9a,0xf3,0x4f,0x9c,0x01,0x43,0x3c,0xcd,0x82,0xb8,0x50,0xf4,0x60,0xca,0xc0,0xe5,0x21,0xc3,0x5e,0x4b,0x01,0xa2,0xbf,0x19,0xd7,0xc9,0x69,0xcb,0x4f,0xa0,0x23,0x00,0x75,0x18,0x1c,0x5f,0x4e,0x80,0xac,0xed,0x55,0x9e,0xde,0x06,0x1c}, - {0xe2,0xc4,0x3e,0xa3,0xd6,0x7a,0x0f,0x99,0x8e,0xe0,0x2e,0xbe,0x38,0xf9,0x08,0x66,0x15,0x45,0x28,0x63,0xc5,0x43,0xa1,0x9c,0x0d,0xb6,0x2d,0xec,0x1f,0x8a,0xf3,0x4c,0xaa,0x69,0x6d,0xff,0x40,0x2b,0xd5,0xff,0xbb,0x49,0x40,0xdc,0x18,0x0b,0x53,0x34,0x97,0x98,0x4d,0xa3,0x2f,0x5c,0x4a,0x5e,0x2d,0xba,0x32,0x7d,0x8e,0x6f,0x09,0x78,0xe7,0x5c,0xfa,0x0d,0x65,0xaa,0xaa,0xa0,0x8c,0x47,0xb5,0x48,0x2a,0x9e,0xc4,0xf9,0x5b,0x72,0x03,0x70,0x7d,0xcc,0x09,0x4f,0xbe,0x1a,0x09,0x26,0x3a,0xad,0x3c,0x37}, - {0x7c,0xf5,0xc9,0x82,0x4d,0x63,0x94,0xb2,0x36,0x45,0x93,0x24,0xe1,0xfd,0xcb,0x1f,0x5a,0xdb,0x8c,0x41,0xb3,0x4d,0x9c,0x9e,0xfc,0x19,0x44,0x45,0xd9,0xf3,0x40,0x00,0xad,0xbb,0xdd,0x89,0xfb,0xa8,0xbe,0xf1,0xcb,0xae,0xae,0x61,0xbc,0x2c,0xcb,0x3b,0x9d,0x8d,0x9b,0x1f,0xbb,0xa7,0x58,0x8f,0x86,0xa6,0x12,0x51,0xda,0x7e,0x54,0x21,0xd3,0x86,0x59,0xfd,0x39,0xe9,0xfd,0xde,0x0c,0x38,0x0a,0x51,0x89,0x2c,0x27,0xf4,0xb9,0x19,0x31,0xbb,0x07,0xa4,0x2b,0xb7,0xf4,0x4d,0x25,0x4a,0x33,0x0a,0x55,0x63}, - {0x37,0xcf,0x69,0xb5,0xed,0xd6,0x07,0x65,0xe1,0x2e,0xa5,0x0c,0xb0,0x29,0x84,0x17,0x5d,0xd6,0x6b,0xeb,0x90,0x00,0x7c,0xea,0x51,0x8f,0xf7,0xda,0xc7,0x62,0xea,0x3e,0x49,0x7b,0x54,0x72,0x45,0x58,0xba,0x9b,0xe0,0x08,0xc4,0xe2,0xfa,0xc6,0x05,0xf3,0x8d,0xf1,0x34,0xc7,0x69,0xfa,0xe8,0x60,0x7a,0x76,0x7d,0xaa,0xaf,0x2b,0xa9,0x39,0x4e,0x27,0x93,0xe6,0x13,0xc7,0x24,0x9d,0x75,0xd3,0xdb,0x68,0x77,0x85,0x63,0x5f,0x9a,0xb3,0x8a,0xeb,0x60,0x55,0x52,0x70,0xcd,0xc4,0xc9,0x65,0x06,0x6a,0x43,0x68}, - {0x27,0x3f,0x2f,0x20,0xe8,0x35,0x02,0xbc,0xb0,0x75,0xf9,0x64,0xe2,0x00,0x5c,0xc7,0x16,0x24,0x8c,0xa3,0xd5,0xe9,0xa4,0x91,0xf9,0x89,0xb7,0x8a,0xf6,0xe7,0xb6,0x17,0x7c,0x10,0x20,0xe8,0x17,0xd3,0x56,0x1e,0x65,0xe9,0x0a,0x84,0x44,0x68,0x26,0xc5,0x7a,0xfc,0x0f,0x32,0xc6,0xa1,0xe0,0xc1,0x72,0x14,0x61,0x91,0x9c,0x66,0x73,0x53,0x57,0x52,0x0e,0x9a,0xab,0x14,0x28,0x5d,0xfc,0xb3,0xca,0xc9,0x84,0x20,0x8f,0x90,0xca,0x1e,0x2d,0x5b,0x88,0xf5,0xca,0xaf,0x11,0x7d,0xf8,0x78,0xa6,0xb5,0xb4,0x1c}, - {0x6c,0xfc,0x4a,0x39,0x6b,0xc0,0x64,0xb6,0xb1,0x5f,0xda,0x98,0x24,0xde,0x88,0x0c,0x34,0xd8,0xca,0x4b,0x16,0x03,0x8d,0x4f,0xa2,0x34,0x74,0xde,0x78,0xca,0x0b,0x33,0xe7,0x07,0xa0,0xa2,0x62,0xaa,0x74,0x6b,0xb1,0xc7,0x71,0xf0,0xb0,0xe0,0x11,0xf3,0x23,0xe2,0x0b,0x00,0x38,0xe4,0x07,0x57,0xac,0x6e,0xef,0x82,0x2d,0xfd,0xc0,0x2d,0x4e,0x74,0x19,0x11,0x84,0xff,0x2e,0x98,0x24,0x47,0x07,0x2b,0x96,0x5e,0x69,0xf9,0xfb,0x53,0xc9,0xbf,0x4f,0xc1,0x8a,0xc5,0xf5,0x1c,0x9f,0x36,0x1b,0xbe,0x31,0x3c}, - {0xee,0x8a,0x94,0x08,0x4d,0x86,0xf4,0xb0,0x6f,0x1c,0xba,0x91,0xee,0x19,0xdc,0x07,0x58,0xa1,0xac,0xa6,0xae,0xcd,0x75,0x79,0xbb,0xd4,0x62,0x42,0x13,0x61,0x0b,0x33,0x72,0x42,0xcb,0xf9,0x93,0xbc,0x68,0xc1,0x98,0xdb,0xce,0xc7,0x1f,0x71,0xb8,0xae,0x7a,0x8d,0xac,0x34,0xaa,0x52,0x0e,0x7f,0xbb,0x55,0x7d,0x7e,0x09,0xc1,0xce,0x41,0x8a,0x80,0x6d,0xa2,0xd7,0x19,0x96,0xf7,0x6d,0x15,0x9e,0x1d,0x9e,0xd4,0x1f,0xbb,0x27,0xdf,0xa1,0xdb,0x6c,0xc3,0xd7,0x73,0x7d,0x77,0x28,0x1f,0xd9,0x4c,0xb4,0x26}, - {0x75,0x74,0x38,0x8f,0x47,0x48,0xf0,0x51,0x3c,0xcb,0xbe,0x9c,0xf4,0xbc,0x5d,0xb2,0x55,0x20,0x9f,0xd9,0x44,0x12,0xab,0x9a,0xd6,0xa5,0x10,0x1c,0x6c,0x9e,0x70,0x2c,0x83,0x03,0x73,0x62,0x93,0xf2,0xb7,0xe1,0x2c,0x8a,0xca,0xeb,0xff,0x79,0x52,0x4b,0x14,0x13,0xd4,0xbf,0x8a,0x77,0xfc,0xda,0x0f,0x61,0x72,0x9c,0x14,0x10,0xeb,0x7d,0x7a,0xee,0x66,0x87,0x6a,0xaf,0x62,0xcb,0x0e,0xcd,0x53,0x55,0x04,0xec,0xcb,0x66,0xb5,0xe4,0x0b,0x0f,0x38,0x01,0x80,0x58,0xea,0xe2,0x2c,0xf6,0x9f,0x8e,0xe6,0x08}, - {0xad,0x30,0xc1,0x4b,0x0a,0x50,0xad,0x34,0x9c,0xd4,0x0b,0x3d,0x49,0xdb,0x38,0x8d,0xbe,0x89,0x0a,0x50,0x98,0x3d,0x5c,0xa2,0x09,0x3b,0xba,0xee,0x87,0x3f,0x1f,0x2f,0xf9,0xf2,0xb8,0x0a,0xd5,0x09,0x2d,0x2f,0xdf,0x23,0x59,0xc5,0x8d,0x21,0xb9,0xac,0xb9,0x6c,0x76,0x73,0x26,0x34,0x8f,0x4a,0xf5,0x19,0xf7,0x38,0xd7,0x3b,0xb1,0x4c,0x4a,0xb6,0x15,0xe5,0x75,0x8c,0x84,0xf7,0x38,0x90,0x4a,0xdb,0xba,0x01,0x95,0xa5,0x50,0x1b,0x75,0x3f,0x3f,0x31,0x0d,0xc2,0xe8,0x2e,0xae,0xc0,0x53,0xe3,0xa1,0x19}, - {0xc3,0x05,0xfa,0xba,0x60,0x75,0x1c,0x7d,0x61,0x5e,0xe5,0xc6,0xa0,0xa0,0xe1,0xb3,0x73,0x64,0xd6,0xc0,0x18,0x97,0x52,0xe3,0x86,0x34,0x0c,0xc2,0x11,0x6b,0x54,0x41,0xbd,0xbd,0x96,0xd5,0xcd,0x72,0x21,0xb4,0x40,0xfc,0xee,0x98,0x43,0x45,0xe0,0x93,0xb5,0x09,0x41,0xb4,0x47,0x53,0xb1,0x9f,0x34,0xae,0x66,0x02,0x99,0xd3,0x6b,0x73,0xb4,0xb3,0x34,0x93,0x50,0x2d,0x53,0x85,0x73,0x65,0x81,0x60,0x4b,0x11,0xfd,0x46,0x75,0x83,0x5c,0x42,0x30,0x5f,0x5f,0xcc,0x5c,0xab,0x7f,0xb8,0xa2,0x95,0x22,0x41}, - {0xe9,0xd6,0x7e,0xf5,0x88,0x9b,0xc9,0x19,0x25,0xc8,0xf8,0x6d,0x26,0xcb,0x93,0x53,0x73,0xd2,0x0a,0xb3,0x13,0x32,0xee,0x5c,0x34,0x2e,0x2d,0xb5,0xeb,0x53,0xe1,0x14,0xc6,0xea,0x93,0xe2,0x61,0x52,0x65,0x2e,0xdb,0xac,0x33,0x21,0x03,0x92,0x5a,0x84,0x6b,0x99,0x00,0x79,0xcb,0x75,0x09,0x46,0x80,0xdd,0x5a,0x19,0x8d,0xbb,0x60,0x07,0x8a,0x81,0xe6,0xcd,0x17,0x1a,0x3e,0x41,0x84,0xa0,0x69,0xed,0xa9,0x6d,0x15,0x57,0xb1,0xcc,0xca,0x46,0x8f,0x26,0xbf,0x2c,0xf2,0xc5,0x3a,0xc3,0x9b,0xbe,0x34,0x6b}, - {0xb2,0xc0,0x78,0x3a,0x64,0x2f,0xdf,0xf3,0x7c,0x02,0x2e,0xf2,0x1e,0x97,0x3e,0x4c,0xa3,0xb5,0xc1,0x49,0x5e,0x1c,0x7d,0xec,0x2d,0xdd,0x22,0x09,0x8f,0xc1,0x12,0x20,0xd3,0xf2,0x71,0x65,0x65,0x69,0xfc,0x11,0x7a,0x73,0x0e,0x53,0x45,0xe8,0xc9,0xc6,0x35,0x50,0xfe,0xd4,0xa2,0xe7,0x3a,0xe3,0x0b,0xd3,0x6d,0x2e,0xb6,0xc7,0xb9,0x01,0x29,0x9d,0xc8,0x5a,0xe5,0x55,0x0b,0x88,0x63,0xa7,0xa0,0x45,0x1f,0x24,0x83,0x14,0x1f,0x6c,0xe7,0xc2,0xdf,0xef,0x36,0x3d,0xe8,0xad,0x4b,0x4e,0x78,0x5b,0xaf,0x08}, - {0x33,0x25,0x1f,0x88,0xdc,0x99,0x34,0x28,0xb6,0x23,0x93,0x77,0xda,0x25,0x05,0x9d,0xf4,0x41,0x34,0x67,0xfb,0xdd,0x7a,0x89,0x8d,0x16,0x3a,0x16,0x71,0x9d,0xb7,0x32,0x4b,0x2c,0xcc,0x89,0xd2,0x14,0x73,0xe2,0x8d,0x17,0x87,0xa2,0x11,0xbd,0xe4,0x4b,0xce,0x64,0x33,0xfa,0xd6,0x28,0xd5,0x18,0x6e,0x82,0xd9,0xaf,0xd5,0xc1,0x23,0x64,0x6a,0xb3,0xfc,0xed,0xd9,0xf8,0x85,0xcc,0xf9,0xe5,0x46,0x37,0x8f,0xc2,0xbc,0x22,0xcd,0xd3,0xe5,0xf9,0x38,0xe3,0x9d,0xe4,0xcc,0x2d,0x3e,0xc1,0xfb,0x5e,0x0a,0x48}, - {0x71,0x20,0x62,0x01,0x0b,0xe7,0x51,0x0b,0xc5,0xaf,0x1d,0x8b,0xcf,0x05,0xb5,0x06,0xcd,0xab,0x5a,0xef,0x61,0xb0,0x6b,0x2c,0x31,0xbf,0xb7,0x0c,0x60,0x27,0xaa,0x47,0x1f,0x22,0xce,0x42,0xe4,0x4c,0x61,0xb6,0x28,0x39,0x05,0x4c,0xcc,0x9d,0x19,0x6e,0x03,0xbe,0x1c,0xdc,0xa4,0xb4,0x3f,0x66,0x06,0x8e,0x1c,0x69,0x47,0x1d,0xb3,0x24,0xc3,0xf8,0x15,0xc0,0xed,0x1e,0x54,0x2a,0x7c,0x3f,0x69,0x7c,0x7e,0xfe,0xa4,0x11,0xd6,0x78,0xa2,0x4e,0x13,0x66,0xaf,0xf0,0x94,0xa0,0xdd,0x14,0x5d,0x58,0x5b,0x54}, - {0x0f,0x3a,0xd4,0xa0,0x5e,0x27,0xbf,0x67,0xbe,0xee,0x9b,0x08,0x34,0x8e,0xe6,0xad,0x2e,0xe7,0x79,0xd4,0x4c,0x13,0x89,0x42,0x54,0x54,0xba,0x32,0xc3,0xf9,0x62,0x0f,0xe1,0x21,0xb3,0xe3,0xd0,0xe4,0x04,0x62,0x95,0x1e,0xff,0x28,0x7a,0x63,0xaa,0x3b,0x9e,0xbd,0x99,0x5b,0xfd,0xcf,0x0c,0x0b,0x71,0xd0,0xc8,0x64,0x3e,0xdc,0x22,0x4d,0x39,0x5f,0x3b,0xd6,0x89,0x65,0xb4,0xfc,0x61,0xcf,0xcb,0x57,0x3f,0x6a,0xae,0x5c,0x05,0xfa,0x3a,0x95,0xd2,0xc2,0xba,0xfe,0x36,0x14,0x37,0x36,0x1a,0xa0,0x0f,0x1c}, - {0xff,0x3d,0x94,0x22,0xb6,0x04,0xc6,0xd2,0xa0,0xb3,0xcf,0x44,0xce,0xbe,0x8c,0xbc,0x78,0x86,0x80,0x97,0xf3,0x4f,0x25,0x5d,0xbf,0xa6,0x1c,0x3b,0x4f,0x61,0xa3,0x0f,0x50,0x6a,0x93,0x8c,0x0e,0x2b,0x08,0x69,0xb6,0xc5,0xda,0xc1,0x35,0xa0,0xc9,0xf9,0x34,0xb6,0xdf,0xc4,0x54,0x3e,0xb7,0x6f,0x40,0xc1,0x2b,0x1d,0x9b,0x41,0x05,0x40,0xf0,0x82,0xbe,0xb9,0xbd,0xfe,0x03,0xa0,0x90,0xac,0x44,0x3a,0xaf,0xc1,0x89,0x20,0x8e,0xfa,0x54,0x19,0x91,0x9f,0x49,0xf8,0x42,0xab,0x40,0xef,0x8a,0x21,0xba,0x1f}, - {0x3e,0xf5,0xc8,0xfa,0x48,0x94,0x54,0xab,0x41,0x37,0xa6,0x7b,0x9a,0xe8,0xf6,0x81,0x01,0x5e,0x2b,0x6c,0x7d,0x6c,0xfd,0x74,0x42,0x6e,0xc8,0xa8,0xca,0x3a,0x2e,0x39,0x94,0x01,0x7b,0x3e,0x04,0x57,0x3e,0x4f,0x7f,0xaf,0xda,0x08,0xee,0x3e,0x1d,0xa8,0xf1,0xde,0xdc,0x99,0xab,0xc6,0x39,0xc8,0xd5,0x61,0x77,0xff,0x13,0x5d,0x53,0x6c,0xaf,0x35,0x8a,0x3e,0xe9,0x34,0xbd,0x4c,0x16,0xe8,0x87,0x58,0x44,0x81,0x07,0x2e,0xab,0xb0,0x9a,0xf2,0x76,0x9c,0x31,0x19,0x3b,0xc1,0x0a,0xd5,0xe4,0x7f,0xe1,0x25}, - {0x76,0xf6,0x04,0x1e,0xd7,0x9b,0x28,0x0a,0x95,0x0f,0x42,0xd6,0x52,0x1c,0x8e,0x20,0xab,0x1f,0x69,0x34,0xb0,0xd8,0x86,0x51,0x51,0xb3,0x9f,0x2a,0x44,0x51,0x57,0x25,0xa7,0x21,0xf1,0x76,0xf5,0x7f,0x5f,0x91,0xe3,0x87,0xcd,0x2f,0x27,0x32,0x4a,0xc3,0x26,0xe5,0x1b,0x4d,0xde,0x2f,0xba,0xcc,0x9b,0x89,0x69,0x89,0x8f,0x82,0xba,0x6b,0x01,0x39,0xfe,0x90,0x66,0xbc,0xd1,0xe2,0xd5,0x7a,0x99,0xa0,0x18,0x4a,0xb5,0x4c,0xd4,0x60,0x84,0xaf,0x14,0x69,0x1d,0x97,0xe4,0x7b,0x6b,0x7f,0x4f,0x50,0x9d,0x55}, - {0xd5,0x54,0xeb,0xb3,0x78,0x83,0x73,0xa7,0x7c,0x3c,0x55,0xa5,0x66,0xd3,0x69,0x1d,0xba,0x00,0x28,0xf9,0x62,0xcf,0x26,0x0a,0x17,0x32,0x7e,0x80,0xd5,0x12,0xab,0x01,0xfd,0x66,0xd2,0xf6,0xe7,0x91,0x48,0x9c,0x1b,0x78,0x07,0x03,0x9b,0xa1,0x44,0x07,0x3b,0xe2,0x61,0x60,0x1d,0x8f,0x38,0x88,0x0e,0xd5,0x4b,0x35,0xa3,0xa6,0x3e,0x12,0x96,0x2d,0xe3,0x41,0x90,0x18,0x8d,0x11,0x48,0x58,0x31,0xd8,0xc2,0xe3,0xed,0xb9,0xd9,0x45,0x32,0xd8,0x71,0x42,0xab,0x1e,0x54,0xa1,0x18,0xc9,0xe2,0x61,0x39,0x4a}, - {0xa0,0xbb,0xe6,0xf8,0xe0,0x3b,0xdc,0x71,0x0a,0xe3,0xff,0x7e,0x34,0xf8,0xce,0xd6,0x6a,0x47,0x3a,0xe1,0x5f,0x42,0x92,0xa9,0x63,0xb7,0x1d,0xfb,0xe3,0xbc,0xd6,0x2c,0x1e,0x3f,0x23,0xf3,0x44,0xd6,0x27,0x03,0x16,0xf0,0xfc,0x34,0x0e,0x26,0x9a,0x49,0x79,0xb9,0xda,0xf2,0x16,0xa7,0xb5,0x83,0x1f,0x11,0xd4,0x9b,0xad,0xee,0xac,0x68,0x10,0xc2,0xd7,0xf3,0x0e,0xc9,0xb4,0x38,0x0c,0x04,0xad,0xb7,0x24,0x6e,0x8e,0x30,0x23,0x3e,0xe7,0xb7,0xf1,0xd9,0x60,0x38,0x97,0xf5,0x08,0xb5,0xd5,0x60,0x57,0x59}, - {0x97,0x63,0xaa,0x04,0xe1,0xbf,0x29,0x61,0xcb,0xfc,0xa7,0xa4,0x08,0x00,0x96,0x8f,0x58,0x94,0x90,0x7d,0x89,0xc0,0x8b,0x3f,0xa9,0x91,0xb2,0xdc,0x3e,0xa4,0x9f,0x70,0x90,0x27,0x02,0xfd,0xeb,0xcb,0x2a,0x88,0x60,0x57,0x11,0xc4,0x05,0x33,0xaf,0x89,0xf4,0x73,0x34,0x7d,0xe3,0x92,0xf4,0x65,0x2b,0x5a,0x51,0x54,0xdf,0xc5,0xb2,0x2c,0xca,0x2a,0xfd,0x63,0x8c,0x5d,0x0a,0xeb,0xff,0x4e,0x69,0x2e,0x66,0xc1,0x2b,0xd2,0x3a,0xb0,0xcb,0xf8,0x6e,0xf3,0x23,0x27,0x1f,0x13,0xc8,0xf0,0xec,0x29,0xf0,0x70}, - {0x33,0x3e,0xed,0x2e,0xb3,0x07,0x13,0x46,0xe7,0x81,0x55,0xa4,0x33,0x2f,0x04,0xae,0x66,0x03,0x5f,0x19,0xd3,0x49,0x44,0xc9,0x58,0x48,0x31,0x6c,0x8a,0x5d,0x7d,0x0b,0xb9,0xb0,0x10,0x5e,0xaa,0xaf,0x6a,0x2a,0xa9,0x1a,0x04,0xef,0x70,0xa3,0xf0,0x78,0x1f,0xd6,0x3a,0xaa,0x77,0xfb,0x3e,0x77,0xe1,0xd9,0x4b,0xa7,0xa2,0xa5,0xec,0x44,0x43,0xd5,0x95,0x7b,0x32,0x48,0xd4,0x25,0x1d,0x0f,0x34,0xa3,0x00,0x83,0xd3,0x70,0x2b,0xc5,0xe1,0x60,0x1c,0x53,0x1c,0xde,0xe4,0xe9,0x7d,0x2c,0x51,0x24,0x22,0x27}, - {0x2e,0x34,0xc5,0x49,0xaf,0x92,0xbc,0x1a,0xd0,0xfa,0xe6,0xb2,0x11,0xd8,0xee,0xff,0x29,0x4e,0xc8,0xfc,0x8d,0x8c,0xa2,0xef,0x43,0xc5,0x4c,0xa4,0x18,0xdf,0xb5,0x11,0xfc,0x75,0xa9,0x42,0x8a,0xbb,0x7b,0xbf,0x58,0xa3,0xad,0x96,0x77,0x39,0x5c,0x8c,0x48,0xaa,0xed,0xcd,0x6f,0xc7,0x7f,0xe2,0xa6,0x20,0xbc,0xf6,0xd7,0x5f,0x73,0x19,0x66,0x42,0xc8,0x42,0xd0,0x90,0xab,0xe3,0x7e,0x54,0x19,0x7f,0x0f,0x8e,0x84,0xeb,0xb9,0x97,0xa4,0x65,0xd0,0xa1,0x03,0x25,0x5f,0x89,0xdf,0x91,0x11,0x91,0xef,0x0f} -}; diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-basepoint-table.h b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-basepoint-table.h deleted file mode 100644 index 9c0cdfc0c..000000000 --- a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-basepoint-table.h +++ /dev/null @@ -1,2 +0,0 @@ -/* multiples of the base point in packed {ysubx, xaddy, t2d} form */ -extern const uint8_t ALIGN(16) ge25519_niels_base_multiples[256][96]; diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-impl-base.c b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-impl-base.c deleted file mode 100644 index 889710bfc..000000000 --- a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-impl-base.c +++ /dev/null @@ -1,751 +0,0 @@ -#include -#include "ed25519-donna.h" -#include "memzero.h" - -/* sqrt(x) is such an integer y that 0 <= y <= p - 1, y % 2 = 0, and y^2 = x (mod p). */ -/* d = -121665 / 121666 */ -#if !defined(NDEBUG) -static const bignum25519 ALIGN(16) fe_d = { - 0x35978a3, 0x0d37284, 0x3156ebd, 0x06a0a0e, 0x001c029, 0x179e898, 0x3a03cbb, 0x1ce7198, 0x2e2b6ff, 0x1480db3}; /* d */ -#endif -static const bignum25519 ALIGN(16) fe_sqrtm1 = { - 0x20ea0b0, 0x186c9d2, 0x08f189d, 0x035697f, 0x0bd0c60, 0x1fbd7a7, 0x2804c9e, 0x1e16569, 0x004fc1d, 0x0ae0c92}; /* sqrt(-1) */ -//static const bignum25519 ALIGN(16) fe_d2 = { -// 0x2b2f159, 0x1a6e509, 0x22add7a, 0x0d4141d, 0x0038052, 0x0f3d130, 0x3407977, 0x19ce331, 0x1c56dff, 0x0901b67}; /* 2 * d */ - -/* A = 2 * (1 - d) / (1 + d) = 486662 */ -static const bignum25519 ALIGN(16) fe_ma2 = { - 0x33de3c9, 0x1fff236, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff}; /* -A^2 */ -static const bignum25519 ALIGN(16) fe_ma = { - 0x3f892e7, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff}; /* -A */ -static const bignum25519 ALIGN(16) fe_fffb1 = { - 0x1e3bdff, 0x025a2b3, 0x18e5bab, 0x0ba36ac, 0x0b9afed, 0x004e61c, 0x31d645f, 0x09d1bea, 0x102529e, 0x0063810}; /* sqrt(-2 * A * (A + 2)) */ -static const bignum25519 ALIGN(16) fe_fffb2 = { - 0x383650d, 0x066df27, 0x10405a4, 0x1cfdd48, 0x2b887f2, 0x1e9a041, 0x1d7241f, 0x0612dc5, 0x35fba5d, 0x0cbe787}; /* sqrt(2 * A * (A + 2)) */ -static const bignum25519 ALIGN(16) fe_fffb3 = { - 0x0cfd387, 0x1209e3a, 0x3bad4fc, 0x18ad34d, 0x2ff6c02, 0x0f25d12, 0x15cdfe0, 0x0e208ed, 0x32eb3df, 0x062d7bb}; /* sqrt(-sqrt(-1) * A * (A + 2)) */ -static const bignum25519 ALIGN(16) fe_fffb4 = { - 0x2b39186, 0x14640ed, 0x14930a7, 0x04509fa, 0x3b91bf0, 0x0f7432e, 0x07a443f, 0x17f24d8, 0x031067d, 0x0690fcc}; /* sqrt(sqrt(-1) * A * (A + 2)) */ - - -/* - Timing safe memory compare -*/ -int ed25519_verify(const unsigned char *x, const unsigned char *y, size_t len) { - size_t differentbits = 0; - while (len--) - differentbits |= (*x++ ^ *y++); - return (int) (1 & ((differentbits - 1) >> 8)); -} - -/* - conversions -*/ - -void ge25519_p1p1_to_partial(ge25519 *r, const ge25519_p1p1 *p) { - curve25519_mul(r->x, p->x, p->t); - curve25519_mul(r->y, p->y, p->z); - curve25519_mul(r->z, p->z, p->t); -} - -void ge25519_p1p1_to_full(ge25519 *r, const ge25519_p1p1 *p) { - curve25519_mul(r->x, p->x, p->t); - curve25519_mul(r->y, p->y, p->z); - curve25519_mul(r->z, p->z, p->t); - curve25519_mul(r->t, p->x, p->y); -} - -void ge25519_full_to_pniels(ge25519_pniels *p, const ge25519 *r) { - curve25519_sub(p->ysubx, r->y, r->x); - curve25519_add(p->xaddy, r->y, r->x); - curve25519_copy(p->z, r->z); - curve25519_mul(p->t2d, r->t, ge25519_ec2d); -} - -/* - adding & doubling -*/ - -void ge25519_double_p1p1(ge25519_p1p1 *r, const ge25519 *p) { - bignum25519 a = {0}, b = {0}, c = {0}; - - curve25519_square(a, p->x); - curve25519_square(b, p->y); - curve25519_square(c, p->z); - curve25519_add_reduce(c, c, c); - curve25519_add(r->x, p->x, p->y); - curve25519_square(r->x, r->x); - curve25519_add(r->y, b, a); - curve25519_sub(r->z, b, a); - curve25519_sub_after_basic(r->x, r->x, r->y); - curve25519_sub_after_basic(r->t, c, r->z); -} - -#ifndef ED25519_NO_PRECOMP -void ge25519_nielsadd2_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_niels *q, unsigned char signbit) { - const bignum25519 *qb = (const bignum25519 *)q; - bignum25519 *rb = (bignum25519 *)r; - bignum25519 a = {0}, b = {0}, c = {0}; - - curve25519_sub(a, p->y, p->x); - curve25519_add(b, p->y, p->x); - curve25519_mul(a, a, qb[signbit]); /* x for +, y for - */ - curve25519_mul(r->x, b, qb[signbit^1]); /* y for +, x for - */ - curve25519_add(r->y, r->x, a); - curve25519_sub(r->x, r->x, a); - curve25519_mul(c, p->t, q->t2d); - curve25519_add_reduce(r->t, p->z, p->z); - curve25519_copy(r->z, r->t); - curve25519_add(rb[2+signbit], rb[2+signbit], c); /* z for +, t for - */ - curve25519_sub(rb[2+(signbit^1)], rb[2+(signbit^1)], c); /* t for +, z for - */ -} -#endif - -void ge25519_pnielsadd_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_pniels *q, unsigned char signbit) { - bignum25519 q1, q2 = {0}; - bignum25519 a = {0}, b = {0}, c = {0}; - - curve25519_sub(a, p->y, p->x); - curve25519_add(b, p->y, p->x); - - // a = a * ysubx, r->x = b * xaddy for signbit = 0 - // a = a * xaddy, r->x = b * ysubx for signbit = 1 - curve25519_copy(q1, q->ysubx); - curve25519_copy(q2, q->xaddy); - curve25519_swap_conditional(q1, q2, signbit); - curve25519_mul(a, a, q1); - curve25519_mul(r->x, b, q2); - - curve25519_add(r->y, r->x, a); - curve25519_sub(r->x, r->x, a); - curve25519_mul(c, p->t, q->t2d); - curve25519_mul(r->t, p->z, q->z); - curve25519_add_reduce(r->t, r->t, r->t); - curve25519_copy(r->z, r->t); - - // r->z = r->z + c, r->t = r->t - c for signbit == 0 - // r->z = r->z - c, r->t = r->t + c for signbit == 1 - curve25519_swap_conditional(r->z, r->t, signbit); - curve25519_add(r->z, r->z, c); - curve25519_sub(r->t, r->t, c); - curve25519_swap_conditional(r->z, r->t, signbit); -} - -void ge25519_double_partial(ge25519 *r, const ge25519 *p) { - ge25519_p1p1 t = {0}; - ge25519_double_p1p1(&t, p); - ge25519_p1p1_to_partial(r, &t); -} - -void ge25519_double(ge25519 *r, const ge25519 *p) { - ge25519_p1p1 t = {0}; - ge25519_double_p1p1(&t, p); - ge25519_p1p1_to_full(r, &t); -} - -void ge25519_nielsadd2(ge25519 *r, const ge25519_niels *q) { - bignum25519 a = {0}, b = {0}, c = {0}, e = {0}, f = {0}, g = {0}, h = {0}; - - curve25519_sub(a, r->y, r->x); - curve25519_add(b, r->y, r->x); - curve25519_mul(a, a, q->ysubx); - curve25519_mul(e, b, q->xaddy); - curve25519_add(h, e, a); - curve25519_sub(e, e, a); - curve25519_mul(c, r->t, q->t2d); - curve25519_add(f, r->z, r->z); - curve25519_add_after_basic(g, f, c); - curve25519_sub_after_basic(f, f, c); - curve25519_mul(r->x, e, f); - curve25519_mul(r->y, h, g); - curve25519_mul(r->z, g, f); - curve25519_mul(r->t, e, h); -} - -void ge25519_pnielsadd(ge25519_pniels *r, const ge25519 *p, const ge25519_pniels *q) { - bignum25519 a = {0}, b = {0}, c = {0}, x = {0}, y = {0}, z = {0}, t = {0}; - - curve25519_sub(a, p->y, p->x); - curve25519_add(b, p->y, p->x); - curve25519_mul(a, a, q->ysubx); - curve25519_mul(x, b, q->xaddy); - curve25519_add(y, x, a); - curve25519_sub(x, x, a); - curve25519_mul(c, p->t, q->t2d); - curve25519_mul(t, p->z, q->z); - curve25519_add(t, t, t); - curve25519_add_after_basic(z, t, c); - curve25519_sub_after_basic(t, t, c); - curve25519_mul(r->xaddy, x, t); - curve25519_mul(r->ysubx, y, z); - curve25519_mul(r->z, z, t); - curve25519_mul(r->t2d, x, y); - curve25519_copy(y, r->ysubx); - curve25519_sub(r->ysubx, r->ysubx, r->xaddy); - curve25519_add(r->xaddy, r->xaddy, y); - curve25519_mul(r->t2d, r->t2d, ge25519_ec2d); -} - - -/* - pack & unpack -*/ - -void ge25519_pack(unsigned char r[32], const ge25519 *p) { - bignum25519 tx = {0}, ty = {0}, zi = {0}; - unsigned char parity[32] = {0}; - curve25519_recip(zi, p->z); - curve25519_mul(tx, p->x, zi); - curve25519_mul(ty, p->y, zi); - curve25519_contract(r, ty); - curve25519_contract(parity, tx); - r[31] ^= ((parity[0] & 1) << 7); -} - -int ge25519_unpack_negative_vartime(ge25519 *r, const unsigned char p[32]) { - const unsigned char zero[32] = {0}; - const bignum25519 one = {1}; - unsigned char parity = p[31] >> 7; - unsigned char check[32] = {0}; - bignum25519 t = {0}, root = {0}, num = {0}, den = {0}, d3 = {0}; - - curve25519_expand(r->y, p); - curve25519_copy(r->z, one); - curve25519_square(num, r->y); /* x = y^2 */ - curve25519_mul(den, num, ge25519_ecd); /* den = dy^2 */ - curve25519_sub_reduce(num, num, r->z); /* x = y^1 - 1 */ - curve25519_add(den, den, r->z); /* den = dy^2 + 1 */ - - /* Computation of sqrt(num/den) */ - /* 1.: computation of num^((p-5)/8)*den^((7p-35)/8) = (num*den^7)^((p-5)/8) */ - curve25519_square(t, den); - curve25519_mul(d3, t, den); - curve25519_square(r->x, d3); - curve25519_mul(r->x, r->x, den); - curve25519_mul(r->x, r->x, num); - curve25519_pow_two252m3(r->x, r->x); - - /* 2. computation of r->x = num * den^3 * (num*den^7)^((p-5)/8) */ - curve25519_mul(r->x, r->x, d3); - curve25519_mul(r->x, r->x, num); - - /* 3. Check if either of the roots works: */ - curve25519_square(t, r->x); - curve25519_mul(t, t, den); - curve25519_sub_reduce(root, t, num); - curve25519_contract(check, root); - if (!ed25519_verify(check, zero, 32)) { - curve25519_add_reduce(t, t, num); - curve25519_contract(check, t); - if (!ed25519_verify(check, zero, 32)) - return 0; - curve25519_mul(r->x, r->x, ge25519_sqrtneg1); - } - - curve25519_contract(check, r->x); - if ((check[0] & 1) == parity) { - curve25519_copy(t, r->x); - curve25519_neg(r->x, t); - } - curve25519_mul(r->t, r->x, r->y); - return 1; -} - -/* - scalarmults -*/ - -void ge25519_set_neutral(ge25519 *r) -{ - memzero(r, sizeof(ge25519)); - r->y[0] = 1; - r->z[0] = 1; -} - -#define S1_SWINDOWSIZE 5 -#define S1_TABLE_SIZE (1<<(S1_SWINDOWSIZE-2)) -#ifdef ED25519_NO_PRECOMP -#define S2_SWINDOWSIZE 5 -#else -#define S2_SWINDOWSIZE 7 -#endif -#define S2_TABLE_SIZE (1<<(S2_SWINDOWSIZE-2)) - -/* computes [s1]p1 + [s2]base */ -void ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256modm s1, const bignum256modm s2) { - signed char slide1[256] = {0}, slide2[256] = {0}; - ge25519_pniels pre1[S1_TABLE_SIZE] = {0}; -#ifdef ED25519_NO_PRECOMP - ge25519_pniels pre2[S2_TABLE_SIZE] = {0}; -#endif - ge25519 dp = {0}; - ge25519_p1p1 t = {0}; - int32_t i = 0; - - memzero(&t, sizeof(ge25519_p1p1)); - contract256_slidingwindow_modm(slide1, s1, S1_SWINDOWSIZE); - contract256_slidingwindow_modm(slide2, s2, S2_SWINDOWSIZE); - - ge25519_double(&dp, p1); - ge25519_full_to_pniels(pre1, p1); - for (i = 0; i < S1_TABLE_SIZE - 1; i++) - ge25519_pnielsadd(&pre1[i+1], &dp, &pre1[i]); - -#ifdef ED25519_NO_PRECOMP - ge25519_double(&dp, &ge25519_basepoint); - ge25519_full_to_pniels(pre2, &ge25519_basepoint); - for (i = 0; i < S2_TABLE_SIZE - 1; i++) - ge25519_pnielsadd(&pre2[i+1], &dp, &pre2[i]); -#endif - - ge25519_set_neutral(r); - - i = 255; - while ((i >= 0) && !(slide1[i] | slide2[i])) - i--; - - for (; i >= 0; i--) { - ge25519_double_p1p1(&t, r); - - if (slide1[i]) { - ge25519_p1p1_to_full(r, &t); - ge25519_pnielsadd_p1p1(&t, r, &pre1[abs(slide1[i]) / 2], (unsigned char)slide1[i] >> 7); - } - - if (slide2[i]) { - ge25519_p1p1_to_full(r, &t); -#ifdef ED25519_NO_PRECOMP - ge25519_pnielsadd_p1p1(&t, r, &pre2[abs(slide2[i]) / 2], (unsigned char)slide2[i] >> 7); -#else - ge25519_nielsadd2_p1p1(&t, r, &ge25519_niels_sliding_multiples[abs(slide2[i]) / 2], (unsigned char)slide2[i] >> 7); -#endif - } - - ge25519_p1p1_to_partial(r, &t); - } - curve25519_mul(r->t, t.x, t.y); - memzero(slide1, sizeof(slide1)); - memzero(slide2, sizeof(slide2)); -} - -/* computes [s1]p1 + [s2]p2 */ -#if USE_MONERO -void ge25519_double_scalarmult_vartime2(ge25519 *r, const ge25519 *p1, const bignum256modm s1, const ge25519 *p2, const bignum256modm s2) { - signed char slide1[256] = {0}, slide2[256] = {0}; - ge25519_pniels pre1[S1_TABLE_SIZE] = {0}; - ge25519_pniels pre2[S1_TABLE_SIZE] = {0}; - ge25519 dp = {0}; - ge25519_p1p1 t = {0}; - int32_t i = 0; - - memzero(&t, sizeof(ge25519_p1p1)); - contract256_slidingwindow_modm(slide1, s1, S1_SWINDOWSIZE); - contract256_slidingwindow_modm(slide2, s2, S1_SWINDOWSIZE); - - ge25519_double(&dp, p1); - ge25519_full_to_pniels(pre1, p1); - for (i = 0; i < S1_TABLE_SIZE - 1; i++) - ge25519_pnielsadd(&pre1[i+1], &dp, &pre1[i]); - - ge25519_double(&dp, p2); - ge25519_full_to_pniels(pre2, p2); - for (i = 0; i < S1_TABLE_SIZE - 1; i++) - ge25519_pnielsadd(&pre2[i+1], &dp, &pre2[i]); - - ge25519_set_neutral(r); - - i = 255; - while ((i >= 0) && !(slide1[i] | slide2[i])) - i--; - - for (; i >= 0; i--) { - ge25519_double_p1p1(&t, r); - - if (slide1[i]) { - ge25519_p1p1_to_full(r, &t); - ge25519_pnielsadd_p1p1(&t, r, &pre1[abs(slide1[i]) / 2], (unsigned char)slide1[i] >> 7); - } - - if (slide2[i]) { - ge25519_p1p1_to_full(r, &t); - ge25519_pnielsadd_p1p1(&t, r, &pre2[abs(slide2[i]) / 2], (unsigned char)slide2[i] >> 7); - } - - ge25519_p1p1_to_partial(r, &t); - } - curve25519_mul(r->t, t.x, t.y); - memzero(slide1, sizeof(slide1)); - memzero(slide2, sizeof(slide2)); -} -#endif - -/* - * The following conditional move stuff uses conditional moves. - * I will check on which compilers this works, and provide suitable - * workarounds for those where it doesn't. - * - * This works on gcc 4.x and above with -O3. Don't use -O2, this will - * cause the code to not generate conditional moves. Don't use any -march= - * with less than i686 on x86 - */ -static void ge25519_cmove_stride4(unsigned long * r, unsigned long * p, unsigned long * pos, unsigned long * n, int stride) { - unsigned long x0=r[0], x1=r[1], x2=r[2], x3=r[3], y0 = 0, y1 = 0, y2 = 0, y3 = 0; - for(; p= 0; i--) { - int k=abs(slide1[i]); - ge25519_double_partial(r, r); - ge25519_double_partial(r, r); - ge25519_double_partial(r, r); - ge25519_double_p1p1(&t, r); - ge25519_move_conditional_pniels_array(&pre, pre1, k, 9); - ge25519_p1p1_to_full(r, &t); - ge25519_pnielsadd_p1p1(&t, r, &pre, (unsigned char)slide1[i] >> 7); - ge25519_p1p1_to_partial(r, &t); - } - curve25519_mul(r->t, t.x, t.y); - memzero(slide1, sizeof(slide1)); -} - -void ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b) { - bignum25519 neg = {0}; - uint32_t sign = (uint32_t)((unsigned char)b >> 7); - uint32_t mask = ~(sign - 1); - uint32_t u = (b + mask) ^ mask; - - /* ysubx, xaddy, t2d in packed form. initialize to ysubx = 1, xaddy = 1, t2d = 0 */ - uint8_t packed[96] = {0}; - packed[0] = 1; - packed[32] = 1; - - ge25519_move_conditional_niels_array((ge25519_niels *)packed, &table[pos*8], u-1, 8); - - /* expand in to t */ - curve25519_expand(t->ysubx, packed + 0); - curve25519_expand(t->xaddy, packed + 32); - curve25519_expand(t->t2d , packed + 64); - - /* adjust for sign */ - curve25519_swap_conditional(t->ysubx, t->xaddy, sign); - curve25519_neg(neg, t->t2d); - curve25519_swap_conditional(t->t2d, neg, sign); -} - -/* computes [s]basepoint */ -void ge25519_scalarmult_base_niels(ge25519 *r, const uint8_t basepoint_table[256][96], const bignum256modm s) { - signed char b[64] = {0}; - uint32_t i = 0; - ge25519_niels t = {0}; - - contract256_window4_modm(b, s); - - ge25519_scalarmult_base_choose_niels(&t, basepoint_table, 0, b[1]); - curve25519_sub_reduce(r->x, t.xaddy, t.ysubx); - curve25519_add_reduce(r->y, t.xaddy, t.ysubx); - memzero(r->z, sizeof(bignum25519)); - curve25519_copy(r->t, t.t2d); - r->z[0] = 2; - for (i = 3; i < 64; i += 2) { - ge25519_scalarmult_base_choose_niels(&t, basepoint_table, i / 2, b[i]); - ge25519_nielsadd2(r, &t); - } - ge25519_double_partial(r, r); - ge25519_double_partial(r, r); - ge25519_double_partial(r, r); - ge25519_double(r, r); - ge25519_scalarmult_base_choose_niels(&t, basepoint_table, 0, b[0]); - curve25519_mul(t.t2d, t.t2d, ge25519_ecd); - ge25519_nielsadd2(r, &t); - for(i = 2; i < 64; i += 2) { - ge25519_scalarmult_base_choose_niels(&t, basepoint_table, i / 2, b[i]); - ge25519_nielsadd2(r, &t); - } -} - -int ge25519_check(const ge25519 *r){ - /* return (z % q != 0 and - x * y % q == z * t % q and - (y * y - x * x - z * z - ed25519.d * t * t) % q == 0) - */ - - bignum25519 z={0}, lhs={0}, rhs={0}, tmp={0}, res={0}; - curve25519_reduce(z, r->z); - - curve25519_mul(lhs, r->x, r->y); - curve25519_mul(rhs, r->z, r->t); - curve25519_sub_reduce(lhs, lhs, rhs); - - curve25519_square(res, r->y); - curve25519_square(tmp, r->x); - curve25519_sub_reduce(res, res, tmp); - curve25519_square(tmp, r->z); - curve25519_sub_reduce(res, res, tmp); - curve25519_square(tmp, r->t); - curve25519_mul(tmp, tmp, ge25519_ecd); - curve25519_sub_reduce(res, res, tmp); - - const int c1 = curve25519_isnonzero(z); - const int c2 = curve25519_isnonzero(lhs); - const int c3 = curve25519_isnonzero(res); - return c1 & (c2^0x1) & (c3^0x1); -} - -int ge25519_eq(const ge25519 *a, const ge25519 *b){ - int eq = 1; - bignum25519 t1={0}, t2={0}; - - eq &= ge25519_check(a); - eq &= ge25519_check(b); - - curve25519_mul(t1, a->x, b->z); - curve25519_mul(t2, b->x, a->z); - curve25519_sub_reduce(t1, t1, t2); - eq &= curve25519_isnonzero(t1) ^ 1; - - curve25519_mul(t1, a->y, b->z); - curve25519_mul(t2, b->y, a->z); - curve25519_sub_reduce(t1, t1, t2); - eq &= curve25519_isnonzero(t1) ^ 1; - - return eq; -} - -void ge25519_copy(ge25519 *dst, const ge25519 *src){ - curve25519_copy(dst->x, src->x); - curve25519_copy(dst->y, src->y); - curve25519_copy(dst->z, src->z); - curve25519_copy(dst->t, src->t); -} - -void ge25519_set_base(ge25519 *r){ - ge25519_copy(r, &ge25519_basepoint); -} - -void ge25519_mul8(ge25519 *r, const ge25519 *t) { - ge25519_double_partial(r, t); - ge25519_double_partial(r, r); - ge25519_double(r, r); -} - -void ge25519_neg_partial(ge25519 *r){ - curve25519_neg(r->x, r->x); -} - -void ge25519_neg_full(ge25519 *r){ - curve25519_neg(r->x, r->x); - curve25519_neg(r->t, r->t); -} - -void ge25519_reduce(ge25519 *r, const ge25519 *t){ - curve25519_reduce(r->x, t->x); - curve25519_reduce(r->y, t->y); - curve25519_reduce(r->z, t->z); - curve25519_reduce(r->t, t->t); -} - -void ge25519_norm(ge25519 *r, const ge25519 * t){ - bignum25519 zinv = {0}; - curve25519_recip(zinv, t->z); - curve25519_mul(r->x, t->x, zinv); - curve25519_mul(r->y, t->y, zinv); - curve25519_mul(r->t, r->x, r->y); - curve25519_set(r->z, 1); -} - -void ge25519_add(ge25519 *r, const ge25519 *p, const ge25519 *q, unsigned char signbit) { - ge25519_pniels P_ni = {0}; - ge25519_p1p1 P_11 = {0}; - - ge25519_full_to_pniels(&P_ni, q); - ge25519_pnielsadd_p1p1(&P_11, p, &P_ni, signbit); - ge25519_p1p1_to_full(r, &P_11); -} - -void ge25519_fromfe_frombytes_vartime(ge25519 *r, const unsigned char *s){ - bignum25519 u={0}, v={0}, w={0}, x={0}, y={0}, z={0}; - unsigned char sign = 0; - - curve25519_expand_reduce(u, s); - - curve25519_square(v, u); - curve25519_add_reduce(v, v, v); /* 2 * u^2 */ - curve25519_set(w, 1); - curve25519_add_reduce(w, v, w); /* w = 2 * u^2 + 1 */ - - curve25519_square(x, w); /* w^2 */ - curve25519_mul(y, fe_ma2, v); /* -2 * A^2 * u^2 */ - curve25519_add_reduce(x, x, y); /* x = w^2 - 2 * A^2 * u^2 */ - - curve25519_divpowm1(r->x, w, x); /* (w / x)^(m + 1) */ - curve25519_square(y, r->x); - curve25519_mul(x, y, x); - curve25519_sub_reduce(y, w, x); - curve25519_copy(z, fe_ma); - - if (curve25519_isnonzero(y)) { - curve25519_add_reduce(y, w, x); - if (curve25519_isnonzero(y)) { - goto negative; - } else { - curve25519_mul(r->x, r->x, fe_fffb1); - } - } else { - curve25519_mul(r->x, r->x, fe_fffb2); - } - curve25519_mul(r->x, r->x, u); /* u * sqrt(2 * A * (A + 2) * w / x) */ - curve25519_mul(z, z, v); /* -2 * A * u^2 */ - sign = 0; - goto setsign; -negative: - curve25519_mul(x, x, fe_sqrtm1); - curve25519_sub_reduce(y, w, x); - if (curve25519_isnonzero(y)) { - assert((curve25519_add_reduce(y, w, x), !curve25519_isnonzero(y))); - curve25519_mul(r->x, r->x, fe_fffb3); - } else { - curve25519_mul(r->x, r->x, fe_fffb4); - } - /* r->x = sqrt(A * (A + 2) * w / x) */ - /* z = -A */ - sign = 1; -setsign: - if (curve25519_isnegative(r->x) != sign) { - assert(curve25519_isnonzero(r->x)); - curve25519_neg(r->x, r->x); - } - curve25519_add_reduce(r->z, z, w); - curve25519_sub_reduce(r->y, z, w); - curve25519_mul(r->x, r->x, r->z); - - // Partial form, saving from T coord computation . - // Later is mul8 discarding T anyway. - // rt = ((rx * ry % q) * inv(rz)) % q - // curve25519_mul(x, r->x, r->y); - // curve25519_recip(z, r->z); - // curve25519_mul(r->t, x, z); - -#if !defined(NDEBUG) - { - bignum25519 check_x={0}, check_y={0}, check_iz={0}, check_v={0}; - curve25519_recip(check_iz, r->z); - curve25519_mul(check_x, r->x, check_iz); - curve25519_mul(check_y, r->y, check_iz); - curve25519_square(check_x, check_x); - curve25519_square(check_y, check_y); - curve25519_mul(check_v, check_x, check_y); - curve25519_mul(check_v, fe_d, check_v); - curve25519_add_reduce(check_v, check_v, check_x); - curve25519_sub_reduce(check_v, check_v, check_y); - curve25519_set(check_x, 1); - curve25519_add_reduce(check_v, check_v, check_x); - assert(!curve25519_isnonzero(check_v)); - } -#endif -} - -int ge25519_unpack_vartime(ge25519 *r, const unsigned char *s){ - int res = ge25519_unpack_negative_vartime(r, s); - ge25519_neg_full(r); - return res; -} - -void ge25519_scalarmult_base_wrapper(ge25519 *r, const bignum256modm s){ - ge25519_scalarmult_base_niels(r, ge25519_niels_base_multiples, s); -} diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-impl-base.h b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-impl-base.h deleted file mode 100644 index 342a6448a..000000000 --- a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-impl-base.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - Timing safe memory compare -*/ -int ed25519_verify(const unsigned char *x, const unsigned char *y, size_t len); - -/* - conversions -*/ - -void ge25519_p1p1_to_partial(ge25519 *r, const ge25519_p1p1 *p); - -void ge25519_p1p1_to_full(ge25519 *r, const ge25519_p1p1 *p); - -void ge25519_full_to_pniels(ge25519_pniels *p, const ge25519 *r); - -/* - adding & doubling -*/ - -void ge25519_double_p1p1(ge25519_p1p1 *r, const ge25519 *p); - -#ifndef ED25519_NO_PRECOMP -void ge25519_nielsadd2_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_niels *q, unsigned char signbit); -#endif - -/* computes [s1]p1 + [s2]p2 */ -#if USE_MONERO -void ge25519_double_scalarmult_vartime2(ge25519 *r, const ge25519 *p1, const bignum256modm s1, const ge25519 *p2, const bignum256modm s2); -#endif - -void ge25519_pnielsadd_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_pniels *q, unsigned char signbit); - -void ge25519_double_partial(ge25519 *r, const ge25519 *p); - -void ge25519_double(ge25519 *r, const ge25519 *p); - -void ge25519_nielsadd2(ge25519 *r, const ge25519_niels *q); - -void ge25519_pnielsadd(ge25519_pniels *r, const ge25519 *p, const ge25519_pniels *q); - - -/* - pack & unpack -*/ - -void ge25519_pack(unsigned char r[32], const ge25519 *p); - -int ge25519_unpack_negative_vartime(ge25519 *r, const unsigned char p[32]); - -/* - scalarmults -*/ - -void ge25519_set_neutral(ge25519 *r); - -/* computes [s1]p1 + [s2]base */ -void ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256modm s1, const bignum256modm s2); - -/* computes [s1]p1, constant time */ -void ge25519_scalarmult(ge25519 *r, const ge25519 *p1, const bignum256modm s1); - -void ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b); - -/* computes [s]basepoint */ -void ge25519_scalarmult_base_niels(ge25519 *r, const uint8_t basepoint_table[256][96], const bignum256modm s); - -/* check if r is on curve */ -int ge25519_check(const ge25519 *r); - -/* a == b */ -int ge25519_eq(const ge25519 *a, const ge25519 *b); - -/* copies one point to another */ -void ge25519_copy(ge25519 *dst, const ge25519 *src); - -/* sets B point to r */ -void ge25519_set_base(ge25519 *r); - -/* 8*P */ -void ge25519_mul8(ge25519 *r, const ge25519 *t); - -/* -P */ -void ge25519_neg_partial(ge25519 *r); - -/* -P */ -void ge25519_neg_full(ge25519 *r); - -/* reduce all coords */ -void ge25519_reduce(ge25519 *r, const ge25519 *t); - -/* normalizes coords. (x, y, 1, x*y) */ -void ge25519_norm(ge25519 *r, const ge25519 * t); - -/* Simple addition */ -void ge25519_add(ge25519 *r, const ge25519 *a, const ge25519 *b, unsigned char signbit); - -/* point from bytes, used in H_p() */ -void ge25519_fromfe_frombytes_vartime(ge25519 *r, const unsigned char *s); - -/* point from bytes */ -int ge25519_unpack_vartime(ge25519 *r, const unsigned char *s); - -/* aG, wrapper for niels base mult. */ -void ge25519_scalarmult_base_wrapper(ge25519 *r, const bignum256modm s); diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-portable.h b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-portable.h deleted file mode 100644 index ceeb55741..000000000 --- a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna-portable.h +++ /dev/null @@ -1,24 +0,0 @@ -#define mul32x32_64(a,b) (((uint64_t)(a))*(b)) - -#include -#include -#include - -#define DONNA_INLINE -#undef ALIGN -#define ALIGN(x) __attribute__((aligned(x))) - -static inline void U32TO8_LE(unsigned char *p, const uint32_t v) { - p[0] = (unsigned char)(v ); - p[1] = (unsigned char)(v >> 8); - p[2] = (unsigned char)(v >> 16); - p[3] = (unsigned char)(v >> 24); -} - -static inline uint32_t U8TO32_LE(const unsigned char *p) { - return - (((uint32_t)(p[0]) ) | - ((uint32_t)(p[1]) << 8) | - ((uint32_t)(p[2]) << 16) | - ((uint32_t)(p[3]) << 24)); -} diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna.h b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna.h deleted file mode 100644 index d3c340227..000000000 --- a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-donna.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - Public domain by Andrew M. - Modified from the amd64-51-30k implementation by - Daniel J. Bernstein - Niels Duif - Tanja Lange - Peter Schwabe - Bo-Yin Yang -*/ - -#ifndef ED25519_DONNA_H -#define ED25519_DONNA_H - -#include "ed25519-donna-portable.h" - -#include "curve25519-donna-32bit.h" - -#include "curve25519-donna-helpers.h" - -#include "modm-donna-32bit.h" - -typedef unsigned char hash_512bits[64]; - -/* - * Arithmetic on the twisted Edwards curve -x^2 + y^2 = 1 + dx^2y^2 - * with d = -(121665/121666) = 37095705934669439343138083508754565189542113879843219016388785533085940283555 - * Base point: (15112221349535400772501151409588531511454012693041857206046113283949847762202,46316835694926478169428394003475163141307993866256225615783033603165251855960); - */ - -typedef struct ge25519_t { - bignum25519 x, y, z, t; -} ge25519; - -typedef struct ge25519_p1p1_t { - bignum25519 x, y, z, t; -} ge25519_p1p1; - -typedef struct ge25519_niels_t { - bignum25519 ysubx, xaddy, t2d; -} ge25519_niels; - -typedef struct ge25519_pniels_t { - bignum25519 ysubx, xaddy, z, t2d; -} ge25519_pniels; - -#include "ed25519-donna-basepoint-table.h" - -#include "ed25519-donna-32bit-tables.h" - -#include "ed25519-donna-impl-base.h" - -#endif diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom-blake2b.h b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom-blake2b.h deleted file mode 100644 index 93b60c1d3..000000000 --- a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom-blake2b.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - a custom hash must have a 512bit digest and implement: - - struct ed25519_hash_context; - - void ed25519_hash_init(ed25519_hash_context *ctx); - void ed25519_hash_update(ed25519_hash_context *ctx, const uint8_t *in, size_t inlen); - void ed25519_hash_final(ed25519_hash_context *ctx, uint8_t *hash); - void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen); -*/ - -#ifndef ED25519_HASH_CUSTOM -#define ED25519_HASH_CUSTOM - -#include "blake2b.h" - -#define ed25519_hash_context BLAKE2B_CTX -#define ed25519_hash_init(ctx) blake2b_Init(ctx, 64) -#define ed25519_hash_update(ctx, in, inlen) blake2b_Update((ctx), (in), (inlen)) -#define ed25519_hash_final(ctx, hash) blake2b_Final((ctx), (hash), 64) -#define ed25519_hash(hash, in, inlen) blake2b((in), (inlen), (hash), 64) - -#endif // ED25519_HASH_CUSTOM diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom-keccak.h b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom-keccak.h deleted file mode 100644 index 4cfe148e5..000000000 --- a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom-keccak.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - a custom hash must have a 512bit digest and implement: - - struct ed25519_hash_context; - - void ed25519_hash_init(ed25519_hash_context *ctx); - void ed25519_hash_update(ed25519_hash_context *ctx, const uint8_t *in, size_t inlen); - void ed25519_hash_final(ed25519_hash_context *ctx, uint8_t *hash); - void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen); -*/ - -#ifndef ED25519_HASH_CUSTOM -#define ED25519_HASH_CUSTOM - -#include "sha3.h" - -#define ed25519_hash_context SHA3_CTX -#define ed25519_hash_init(ctx) keccak_512_Init(ctx) -#define ed25519_hash_update(ctx, in, inlen) keccak_Update((ctx), (in), (inlen)) -#define ed25519_hash_final(ctx, hash) keccak_Final((ctx), (hash)) -#define ed25519_hash(hash, in, inlen) keccak_512((in), (inlen), (hash)) - -#endif // ED25519_HASH_CUSTOM diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom-sha3.h b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom-sha3.h deleted file mode 100644 index 6d0bd8f23..000000000 --- a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom-sha3.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - a custom hash must have a 512bit digest and implement: - - struct ed25519_hash_context; - - void ed25519_hash_init(ed25519_hash_context *ctx); - void ed25519_hash_update(ed25519_hash_context *ctx, const uint8_t *in, size_t inlen); - void ed25519_hash_final(ed25519_hash_context *ctx, uint8_t *hash); - void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen); -*/ - -#ifndef ED25519_HASH_CUSTOM -#define ED25519_HASH_CUSTOM - -#include "sha3.h" - -#define ed25519_hash_context SHA3_CTX -#define ed25519_hash_init(ctx) sha3_512_Init(ctx) -#define ed25519_hash_update(ctx, in, inlen) sha3_Update((ctx), (in), (inlen)) -#define ed25519_hash_final(ctx, hash) sha3_Final((ctx), (hash)) -#define ed25519_hash(hash, in, inlen) sha3_512((in), (inlen), (hash)) - -#endif // ED25519_HASH_CUSTOM diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom.h b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom.h deleted file mode 100644 index 5d8236ee0..000000000 --- a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-hash-custom.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - a custom hash must have a 512bit digest and implement: - - struct ed25519_hash_context; - - void ed25519_hash_init(ed25519_hash_context *ctx); - void ed25519_hash_update(ed25519_hash_context *ctx, const uint8_t *in, size_t inlen); - void ed25519_hash_final(ed25519_hash_context *ctx, uint8_t *hash); - void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen); -*/ - -#ifndef ED25519_HASH_CUSTOM -#define ED25519_HASH_CUSTOM - -#include "sha2.h" - -#define ed25519_hash_context SHA512_CTX -#define ed25519_hash_init(ctx) sha512_Init(ctx) -#define ed25519_hash_update(ctx, in, inlen) sha512_Update((ctx), (in), (inlen)) -#define ed25519_hash_final(ctx, hash) sha512_Final((ctx), (hash)) -#define ed25519_hash(hash, in, inlen) sha512_Raw((in), (inlen), (hash)) - -#endif // ED25519_HASH_CUSTOM diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-keccak.c b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-keccak.c deleted file mode 100644 index b109360a7..000000000 --- a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-keccak.c +++ /dev/null @@ -1,8 +0,0 @@ -#include - -#include "ed25519-keccak.h" -#include "ed25519-hash-custom-keccak.h" - -#define ED25519_SUFFIX _keccak - -#include "ed25519.c" diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-keccak.h b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-keccak.h deleted file mode 100644 index d40ce7797..000000000 --- a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-keccak.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef ED25519_KECCAK_H -#define ED25519_KECCAK_H - -#include "ed25519.h" - -#if defined(__cplusplus) -extern "C" { -#endif - -void ed25519_publickey_keccak(const ed25519_secret_key sk, ed25519_public_key pk); - -int ed25519_sign_open_keccak(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS); -void ed25519_sign_keccak(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, ed25519_signature RS); - -int ed25519_scalarmult_keccak(ed25519_public_key res, const ed25519_secret_key sk, const ed25519_public_key pk); - -#if defined(__cplusplus) -} -#endif - -#endif // ED25519_KECCAK_H diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-sha3.c b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-sha3.c deleted file mode 100644 index 6a7687d0d..000000000 --- a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-sha3.c +++ /dev/null @@ -1,8 +0,0 @@ -#include - -#include "ed25519-sha3.h" -#include "ed25519-hash-custom-sha3.h" - -#define ED25519_SUFFIX _sha3 - -#include "ed25519.c" diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-sha3.h b/deps/crypto/trezor-crypto/ed25519-donna/ed25519-sha3.h deleted file mode 100644 index 51b764b03..000000000 --- a/deps/crypto/trezor-crypto/ed25519-donna/ed25519-sha3.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef ED25519_SHA3_H -#define ED25519_SHA3_H - -#include "ed25519.h" - -#if defined(__cplusplus) -extern "C" { -#endif - -void ed25519_publickey_sha3(const ed25519_secret_key sk, ed25519_public_key pk); - -int ed25519_sign_open_sha3(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS); -void ed25519_sign_sha3(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, ed25519_signature RS); - -int ed25519_scalarmult_sha3(ed25519_public_key res, const ed25519_secret_key sk, const ed25519_public_key pk); - -#if defined(__cplusplus) -} -#endif - -#endif // ED25519_SHA3_H diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519.c b/deps/crypto/trezor-crypto/ed25519-donna/ed25519.c deleted file mode 100644 index a90268c3c..000000000 --- a/deps/crypto/trezor-crypto/ed25519-donna/ed25519.c +++ /dev/null @@ -1,377 +0,0 @@ -/* - Public domain by Andrew M. - - Ed25519 reference implementation using Ed25519-donna -*/ - - -/* define ED25519_SUFFIX to have it appended to the end of each public function */ -#ifdef ED25519_SUFFIX -#define ED25519_FN3(fn,suffix) fn##suffix -#define ED25519_FN2(fn,suffix) ED25519_FN3(fn,suffix) -#define ED25519_FN(fn) ED25519_FN2(fn,ED25519_SUFFIX) -#else -#define ED25519_FN(fn) fn -#endif - -#include "ed25519-donna.h" -#include "ed25519.h" - -#include "ed25519-hash-custom.h" -#include "rand.h" -#include "memzero.h" - -/* - Generates a (extsk[0..31]) and aExt (extsk[32..63]) -*/ -DONNA_INLINE static void -ed25519_extsk(hash_512bits extsk, const ed25519_secret_key sk) { - ed25519_hash(extsk, sk, 32); - extsk[0] &= 248; - extsk[31] &= 127; - extsk[31] |= 64; -} - -static void -ed25519_hram(hash_512bits hram, const ed25519_public_key R, const ed25519_public_key pk, const unsigned char *m, size_t mlen) { - ed25519_hash_context ctx; - ed25519_hash_init(&ctx); - ed25519_hash_update(&ctx, R, 32); - ed25519_hash_update(&ctx, pk, 32); - ed25519_hash_update(&ctx, m, mlen); - ed25519_hash_final(&ctx, hram); -} - -void -ED25519_FN(ed25519_publickey) (const ed25519_secret_key sk, ed25519_public_key pk) { - bignum256modm a = {0}; - ge25519 ALIGN(16) A = {0}; - hash_512bits extsk = {0}; - - ed25519_extsk(extsk, sk); - expand256_modm(a, extsk, 32); - memzero(&extsk, sizeof(extsk)); - - /* A = aB */ - ge25519_scalarmult_base_niels(&A, ge25519_niels_base_multiples, a); - memzero(&a, sizeof(a)); - ge25519_pack(pk, &A); -} - -#if USE_CARDANO -void -ED25519_FN(ed25519_publickey_ext) (const ed25519_secret_key sk, const ed25519_secret_key skext, ed25519_public_key pk) { - bignum256modm a = {0}; - ge25519 ALIGN(16) A = {0}; - hash_512bits extsk = {0}; - - /* we don't stretch the key through hashing first since its already 64 bytes */ - - memcpy(extsk, sk, 32); - memcpy(extsk+32, skext, 32); - expand256_modm(a, extsk, 32); - memzero(&extsk, sizeof(extsk)); - ge25519_scalarmult_base_niels(&A, ge25519_niels_base_multiples, a); - memzero(&a, sizeof(a)); - ge25519_pack(pk, &A); -} -#endif - -void -ED25519_FN(ed25519_cosi_commit) (ed25519_secret_key nonce, ed25519_public_key commitment) { - bignum256modm r = {0}; - ge25519 ALIGN(16) R; - unsigned char extnonce[64] = {0}; - - /* r = random512 mod L */ - random_buffer(extnonce, sizeof(extnonce)); - expand256_modm(r, extnonce, sizeof(extnonce)); - memzero(&extnonce, sizeof(extnonce)); - contract256_modm(nonce, r); - - /* R = rB */ - ge25519_scalarmult_base_niels(&R, ge25519_niels_base_multiples, r); - memzero(&r, sizeof(r)); - ge25519_pack(commitment, &R); -} - -int -ED25519_FN(ed25519_cosi_sign) (const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_secret_key nonce, const ed25519_public_key R, const ed25519_public_key pk, ed25519_cosi_signature sig) { - bignum256modm r = {0}, S = {0}, a = {0}; - hash_512bits extsk = {0}, hram = {0}; - - ed25519_extsk(extsk, sk); - - /* r */ - expand_raw256_modm(r, nonce); - if (!is_reduced256_modm(r)) { - memzero(&extsk, sizeof(extsk)); - memzero(&r, sizeof(r)); - return -1; - } - - /* S = H(R,A,m).. */ - ed25519_hram(hram, R, pk, m, mlen); - expand256_modm(S, hram, 64); - - /* S = H(R,A,m)a */ - expand256_modm(a, extsk, 32); - memzero(&extsk, sizeof(extsk)); - mul256_modm(S, S, a); - memzero(&a, sizeof(a)); - - /* S = (r + H(R,A,m)a) */ - add256_modm(S, S, r); - memzero(&r, sizeof(r)); - - /* S = (r + H(R,A,m)a) mod L */ - contract256_modm(sig, S); - - return 0; -} - -void -ED25519_FN(ed25519_sign) (const unsigned char *m, size_t mlen, const ed25519_secret_key sk, ed25519_signature RS) { - ed25519_hash_context ctx; - bignum256modm r = {0}, S = {0}, a = {0}; - ge25519 ALIGN(16) R = {0}; - ge25519 ALIGN(16) A = {0}; - ed25519_public_key pk = {0}; - hash_512bits extsk = {0}, hashr = {0}, hram = {0}; - - ed25519_extsk(extsk, sk); - - - /* r = H(aExt[32..64], m) */ - ed25519_hash_init(&ctx); - ed25519_hash_update(&ctx, extsk + 32, 32); - ed25519_hash_update(&ctx, m, mlen); - ed25519_hash_final(&ctx, hashr); - expand256_modm(r, hashr, 64); - memzero(&hashr, sizeof(hashr)); - - /* R = rB */ - ge25519_scalarmult_base_niels(&R, ge25519_niels_base_multiples, r); - ge25519_pack(RS, &R); - - /* a = aExt[0..31] */ - expand256_modm(a, extsk, 32); - memzero(&extsk, sizeof(extsk)); - - /* A = aB */ - ge25519_scalarmult_base_niels(&A, ge25519_niels_base_multiples, a); - ge25519_pack(pk, &A); - - /* S = H(R,A,m).. */ - ed25519_hram(hram, RS, pk, m, mlen); - expand256_modm(S, hram, 64); - - /* S = H(R,A,m)a */ - mul256_modm(S, S, a); - memzero(&a, sizeof(a)); - - /* S = (r + H(R,A,m)a) */ - add256_modm(S, S, r); - memzero(&r, sizeof(r)); - - /* S = (r + H(R,A,m)a) mod L */ - contract256_modm(RS + 32, S); -} - -#if USE_CARDANO -void -ED25519_FN(ed25519_sign_ext) (const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_secret_key skext, ed25519_signature RS) { - ed25519_hash_context ctx; - bignum256modm r = {0}, S = {0}, a = {0}; - ge25519 ALIGN(16) R = {0}; - ge25519 ALIGN(16) A = {0}; - ed25519_public_key pk = {0}; - hash_512bits extsk = {0}, hashr = {0}, hram = {0}; - - /* we don't stretch the key through hashing first since its already 64 bytes */ - - memcpy(extsk, sk, 32); - memcpy(extsk+32, skext, 32); - - - /* r = H(aExt[32..64], m) */ - ed25519_hash_init(&ctx); - ed25519_hash_update(&ctx, extsk + 32, 32); - ed25519_hash_update(&ctx, m, mlen); - ed25519_hash_final(&ctx, hashr); - expand256_modm(r, hashr, 64); - memzero(&hashr, sizeof(hashr)); - - /* R = rB */ - ge25519_scalarmult_base_niels(&R, ge25519_niels_base_multiples, r); - ge25519_pack(RS, &R); - - /* a = aExt[0..31] */ - expand256_modm(a, extsk, 32); - memzero(&extsk, sizeof(extsk)); - - /* A = aB */ - ge25519_scalarmult_base_niels(&A, ge25519_niels_base_multiples, a); - ge25519_pack(pk, &A); - - /* S = H(R,A,m).. */ - ed25519_hram(hram, RS, pk, m, mlen); - expand256_modm(S, hram, 64); - - /* S = H(R,A,m)a */ - mul256_modm(S, S, a); - memzero(&a, sizeof(a)); - - /* S = (r + H(R,A,m)a) */ - add256_modm(S, S, r); - memzero(&r, sizeof(r)); - - /* S = (r + H(R,A,m)a) mod L */ - contract256_modm(RS + 32, S); -} -#endif - -int -ED25519_FN(ed25519_sign_open) (const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS) { - ge25519 ALIGN(16) R = {0}, A = {0}; - hash_512bits hash = {0}; - bignum256modm hram = {0}, S = {0}; - unsigned char checkR[32] = {0}; - - if ((RS[63] & 224) || !ge25519_unpack_negative_vartime(&A, pk)) - return -1; - - /* hram = H(R,A,m) */ - ed25519_hram(hash, RS, pk, m, mlen); - expand256_modm(hram, hash, 64); - - /* S */ - expand_raw256_modm(S, RS + 32); - if (!is_reduced256_modm(S)) - return -1; - - /* SB - H(R,A,m)A */ - ge25519_double_scalarmult_vartime(&R, &A, hram, S); - ge25519_pack(checkR, &R); - - /* check that R = SB - H(R,A,m)A */ - return ed25519_verify(RS, checkR, 32) ? 0 : -1; -} - -int -ED25519_FN(ed25519_scalarmult) (ed25519_public_key res, const ed25519_secret_key sk, const ed25519_public_key pk) { - bignum256modm a = {0}; - ge25519 ALIGN(16) A = {0}, P = {0}; - hash_512bits extsk = {0}; - - ed25519_extsk(extsk, sk); - expand256_modm(a, extsk, 32); - memzero(&extsk, sizeof(extsk)); - - if (!ge25519_unpack_negative_vartime(&P, pk)) { - return -1; - } - - ge25519_scalarmult(&A, &P, a); - memzero(&a, sizeof(a)); - curve25519_neg(A.x, A.x); - ge25519_pack(res, &A); - return 0; -} - - -#ifndef ED25519_SUFFIX - -#include "curve25519-donna-scalarmult-base.h" - -int -ed25519_cosi_combine_publickeys(ed25519_public_key res, CONST ed25519_public_key *pks, size_t n) { - size_t i = 0; - ge25519 P = {0}; - ge25519_pniels sump = {0}; - ge25519_p1p1 sump1 = {0}; - - if (n == 1) { - memcpy(res, pks, sizeof(ed25519_public_key)); - return 0; - } - if (!ge25519_unpack_negative_vartime(&P, pks[i++])) { - return -1; - } - ge25519_full_to_pniels(&sump, &P); - while (i < n - 1) { - if (!ge25519_unpack_negative_vartime(&P, pks[i++])) { - return -1; - } - ge25519_pnielsadd(&sump, &P, &sump); - } - if (!ge25519_unpack_negative_vartime(&P, pks[i++])) { - return -1; - } - ge25519_pnielsadd_p1p1(&sump1, &P, &sump, 0); - ge25519_p1p1_to_partial(&P, &sump1); - curve25519_neg(P.x, P.x); - ge25519_pack(res, &P); - return 0; -} - -void -ed25519_cosi_combine_signatures(ed25519_signature res, const ed25519_public_key R, CONST ed25519_cosi_signature *sigs, size_t n) { - bignum256modm s = {0}, t = {0}; - size_t i = 0; - - expand256_modm(s, sigs[i++], 32); - while (i < n) { - expand256_modm(t, sigs[i++], 32); - add256_modm(s, s, t); - } - memcpy(res, R, 32); - contract256_modm(res + 32, s); -} - -/* - Fast Curve25519 basepoint scalar multiplication -*/ -void -curve25519_scalarmult_basepoint(curve25519_key pk, const curve25519_key e) { - curve25519_key ec = {0}; - bignum256modm s = {0}; - bignum25519 ALIGN(16) yplusz = {0}, zminusy = {0}; - ge25519 ALIGN(16) p = {0}; - size_t i = 0; - - /* clamp */ - for (i = 0; i < 32; i++) ec[i] = e[i]; - ec[0] &= 248; - ec[31] &= 127; - ec[31] |= 64; - - expand_raw256_modm(s, ec); - memzero(&ec, sizeof(ec)); - - /* scalar * basepoint */ - ge25519_scalarmult_base_niels(&p, ge25519_niels_base_multiples, s); - memzero(&s, sizeof(s)); - - /* u = (y + z) / (z - y) */ - curve25519_add(yplusz, p.y, p.z); - curve25519_sub(zminusy, p.z, p.y); - curve25519_recip(zminusy, zminusy); - curve25519_mul(yplusz, yplusz, zminusy); - curve25519_contract(pk, yplusz); -} - -void -curve25519_scalarmult(curve25519_key mypublic, const curve25519_key secret, const curve25519_key basepoint) { - curve25519_key e = {0}; - size_t i = 0; - - for (i = 0;i < 32;++i) e[i] = secret[i]; - e[0] &= 0xf8; - e[31] &= 0x7f; - e[31] |= 0x40; - curve25519_scalarmult_donna(mypublic, e, basepoint); - memzero(&e, sizeof(e)); -} - -#endif // ED25519_SUFFIX diff --git a/deps/crypto/trezor-crypto/ed25519-donna/ed25519.h b/deps/crypto/trezor-crypto/ed25519-donna/ed25519.h deleted file mode 100644 index dbe0e35fb..000000000 --- a/deps/crypto/trezor-crypto/ed25519-donna/ed25519.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef ED25519_H -#define ED25519_H - -#include "../options.h" - -#if defined(__cplusplus) -extern "C" { -#endif - -typedef unsigned char ed25519_signature[64]; -typedef unsigned char ed25519_public_key[32]; -typedef unsigned char ed25519_secret_key[32]; - -typedef unsigned char curve25519_key[32]; - -typedef unsigned char ed25519_cosi_signature[32]; - -void ed25519_publickey(const ed25519_secret_key sk, ed25519_public_key pk); -#if USE_CARDANO -void ed25519_publickey_ext(const ed25519_secret_key sk, const ed25519_secret_key skext, ed25519_public_key pk); -#endif - -int ed25519_sign_open(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS); -void ed25519_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, ed25519_signature RS); -#if USE_CARDANO -void ed25519_sign_ext(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_secret_key skext, ed25519_signature RS); -#endif - -int ed25519_scalarmult(ed25519_public_key res, const ed25519_secret_key sk, const ed25519_public_key pk); - -void curve25519_scalarmult(curve25519_key mypublic, const curve25519_key secret, const curve25519_key basepoint); -void curve25519_scalarmult_basepoint(curve25519_key mypublic, const curve25519_key secret); - -#if !defined(__GNUC__) || __GNUC__ > 4 -#define CONST const -#else -#define CONST -#endif - -int ed25519_cosi_combine_publickeys(ed25519_public_key res, CONST ed25519_public_key *pks, size_t n); -void ed25519_cosi_combine_signatures(ed25519_signature res, const ed25519_public_key R, CONST ed25519_cosi_signature *sigs, size_t n); -void ed25519_cosi_commit(ed25519_secret_key nonce, ed25519_public_key commitment); -int ed25519_cosi_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key key, const ed25519_secret_key nonce, const ed25519_public_key R, const ed25519_public_key pk, ed25519_cosi_signature sig); - -#if defined(__cplusplus) -} -#endif - -#endif // ED25519_H diff --git a/deps/crypto/trezor-crypto/ed25519-donna/modm-donna-32bit.c b/deps/crypto/trezor-crypto/ed25519-donna/modm-donna-32bit.c deleted file mode 100644 index 4ff735f3f..000000000 --- a/deps/crypto/trezor-crypto/ed25519-donna/modm-donna-32bit.c +++ /dev/null @@ -1,517 +0,0 @@ -/* - Public domain by Andrew M. -*/ - -#include "ed25519-donna.h" - -/* - Arithmetic modulo the group order n = 2^252 + 27742317777372353535851937790883648493 = 7237005577332262213973186563042994240857116359379907606001950938285454250989 - - k = 32 - b = 1 << 8 = 256 - m = 2^252 + 27742317777372353535851937790883648493 = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed - mu = floor( b^(k*2) / m ) = 0xfffffffffffffffffffffffffffffffeb2106215d086329a7ed9ce5a30a2c131b -*/ - -static const bignum256modm modm_m = { - 0x1cf5d3ed, 0x20498c69, 0x2f79cd65, 0x37be77a8, - 0x00000014, 0x00000000, 0x00000000, 0x00000000, - 0x00001000 -}; - -static const bignum256modm modm_mu = { - 0x0a2c131b, 0x3673968c, 0x06329a7e, 0x01885742, - 0x3fffeb21, 0x3fffffff, 0x3fffffff, 0x3fffffff, - 0x000fffff -}; - -static bignum256modm_element_t -lt_modm(bignum256modm_element_t a, bignum256modm_element_t b) { - return (a - b) >> 31; -} - -/* see HAC, Alg. 14.42 Step 4 */ -void reduce256_modm(bignum256modm r) { - bignum256modm t = {0}; - bignum256modm_element_t b = 0, pb = 0, mask = 0; - - /* t = r - m */ - pb = 0; - pb += modm_m[0]; b = lt_modm(r[0], pb); t[0] = (r[0] - pb + (b << 30)); pb = b; - pb += modm_m[1]; b = lt_modm(r[1], pb); t[1] = (r[1] - pb + (b << 30)); pb = b; - pb += modm_m[2]; b = lt_modm(r[2], pb); t[2] = (r[2] - pb + (b << 30)); pb = b; - pb += modm_m[3]; b = lt_modm(r[3], pb); t[3] = (r[3] - pb + (b << 30)); pb = b; - pb += modm_m[4]; b = lt_modm(r[4], pb); t[4] = (r[4] - pb + (b << 30)); pb = b; - pb += modm_m[5]; b = lt_modm(r[5], pb); t[5] = (r[5] - pb + (b << 30)); pb = b; - pb += modm_m[6]; b = lt_modm(r[6], pb); t[6] = (r[6] - pb + (b << 30)); pb = b; - pb += modm_m[7]; b = lt_modm(r[7], pb); t[7] = (r[7] - pb + (b << 30)); pb = b; - pb += modm_m[8]; b = lt_modm(r[8], pb); t[8] = (r[8] - pb + (b << 16)); - - /* keep r if r was smaller than m */ - mask = b - 1; - r[0] ^= mask & (r[0] ^ t[0]); - r[1] ^= mask & (r[1] ^ t[1]); - r[2] ^= mask & (r[2] ^ t[2]); - r[3] ^= mask & (r[3] ^ t[3]); - r[4] ^= mask & (r[4] ^ t[4]); - r[5] ^= mask & (r[5] ^ t[5]); - r[6] ^= mask & (r[6] ^ t[6]); - r[7] ^= mask & (r[7] ^ t[7]); - r[8] ^= mask & (r[8] ^ t[8]); -} - -/* - Barrett reduction, see HAC, Alg. 14.42 - - Instead of passing in x, pre-process in to q1 and r1 for efficiency -*/ -void barrett_reduce256_modm(bignum256modm r, const bignum256modm q1, const bignum256modm r1) { - bignum256modm q3 = {0}, r2 = {0}; - uint64_t c = 0; - bignum256modm_element_t f = 0, b = 0, pb = 0; - - /* q1 = x >> 248 = 264 bits = 9 30 bit elements - q2 = mu * q1 - q3 = (q2 / 256(32+1)) = q2 / (2^8)^(32+1) = q2 >> 264 */ - c = mul32x32_64(modm_mu[0], q1[7]) + mul32x32_64(modm_mu[1], q1[6]) + mul32x32_64(modm_mu[2], q1[5]) + mul32x32_64(modm_mu[3], q1[4]) + mul32x32_64(modm_mu[4], q1[3]) + mul32x32_64(modm_mu[5], q1[2]) + mul32x32_64(modm_mu[6], q1[1]) + mul32x32_64(modm_mu[7], q1[0]); - c >>= 30; - c += mul32x32_64(modm_mu[0], q1[8]) + mul32x32_64(modm_mu[1], q1[7]) + mul32x32_64(modm_mu[2], q1[6]) + mul32x32_64(modm_mu[3], q1[5]) + mul32x32_64(modm_mu[4], q1[4]) + mul32x32_64(modm_mu[5], q1[3]) + mul32x32_64(modm_mu[6], q1[2]) + mul32x32_64(modm_mu[7], q1[1]) + mul32x32_64(modm_mu[8], q1[0]); - f = (bignum256modm_element_t)c; q3[0] = (f >> 24) & 0x3f; c >>= 30; - c += mul32x32_64(modm_mu[1], q1[8]) + mul32x32_64(modm_mu[2], q1[7]) + mul32x32_64(modm_mu[3], q1[6]) + mul32x32_64(modm_mu[4], q1[5]) + mul32x32_64(modm_mu[5], q1[4]) + mul32x32_64(modm_mu[6], q1[3]) + mul32x32_64(modm_mu[7], q1[2]) + mul32x32_64(modm_mu[8], q1[1]); - f = (bignum256modm_element_t)c; q3[0] |= (f << 6) & 0x3fffffff; q3[1] = (f >> 24) & 0x3f; c >>= 30; - c += mul32x32_64(modm_mu[2], q1[8]) + mul32x32_64(modm_mu[3], q1[7]) + mul32x32_64(modm_mu[4], q1[6]) + mul32x32_64(modm_mu[5], q1[5]) + mul32x32_64(modm_mu[6], q1[4]) + mul32x32_64(modm_mu[7], q1[3]) + mul32x32_64(modm_mu[8], q1[2]); - f = (bignum256modm_element_t)c; q3[1] |= (f << 6) & 0x3fffffff; q3[2] = (f >> 24) & 0x3f; c >>= 30; - c += mul32x32_64(modm_mu[3], q1[8]) + mul32x32_64(modm_mu[4], q1[7]) + mul32x32_64(modm_mu[5], q1[6]) + mul32x32_64(modm_mu[6], q1[5]) + mul32x32_64(modm_mu[7], q1[4]) + mul32x32_64(modm_mu[8], q1[3]); - f = (bignum256modm_element_t)c; q3[2] |= (f << 6) & 0x3fffffff; q3[3] = (f >> 24) & 0x3f; c >>= 30; - c += mul32x32_64(modm_mu[4], q1[8]) + mul32x32_64(modm_mu[5], q1[7]) + mul32x32_64(modm_mu[6], q1[6]) + mul32x32_64(modm_mu[7], q1[5]) + mul32x32_64(modm_mu[8], q1[4]); - f = (bignum256modm_element_t)c; q3[3] |= (f << 6) & 0x3fffffff; q3[4] = (f >> 24) & 0x3f; c >>= 30; - c += mul32x32_64(modm_mu[5], q1[8]) + mul32x32_64(modm_mu[6], q1[7]) + mul32x32_64(modm_mu[7], q1[6]) + mul32x32_64(modm_mu[8], q1[5]); - f = (bignum256modm_element_t)c; q3[4] |= (f << 6) & 0x3fffffff; q3[5] = (f >> 24) & 0x3f; c >>= 30; - c += mul32x32_64(modm_mu[6], q1[8]) + mul32x32_64(modm_mu[7], q1[7]) + mul32x32_64(modm_mu[8], q1[6]); - f = (bignum256modm_element_t)c; q3[5] |= (f << 6) & 0x3fffffff; q3[6] = (f >> 24) & 0x3f; c >>= 30; - c += mul32x32_64(modm_mu[7], q1[8]) + mul32x32_64(modm_mu[8], q1[7]); - f = (bignum256modm_element_t)c; q3[6] |= (f << 6) & 0x3fffffff; q3[7] = (f >> 24) & 0x3f; c >>= 30; - c += mul32x32_64(modm_mu[8], q1[8]); - f = (bignum256modm_element_t)c; q3[7] |= (f << 6) & 0x3fffffff; q3[8] = (bignum256modm_element_t)(c >> 24); - - /* r1 = (x mod 256^(32+1)) = x mod (2^8)(32+1) = x & ((1 << 264) - 1) - r2 = (q3 * m) mod (256^(32+1)) = (q3 * m) & ((1 << 264) - 1) */ - c = mul32x32_64(modm_m[0], q3[0]); - r2[0] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; - c += mul32x32_64(modm_m[0], q3[1]) + mul32x32_64(modm_m[1], q3[0]); - r2[1] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; - c += mul32x32_64(modm_m[0], q3[2]) + mul32x32_64(modm_m[1], q3[1]) + mul32x32_64(modm_m[2], q3[0]); - r2[2] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; - c += mul32x32_64(modm_m[0], q3[3]) + mul32x32_64(modm_m[1], q3[2]) + mul32x32_64(modm_m[2], q3[1]) + mul32x32_64(modm_m[3], q3[0]); - r2[3] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; - c += mul32x32_64(modm_m[0], q3[4]) + mul32x32_64(modm_m[1], q3[3]) + mul32x32_64(modm_m[2], q3[2]) + mul32x32_64(modm_m[3], q3[1]) + mul32x32_64(modm_m[4], q3[0]); - r2[4] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; - c += mul32x32_64(modm_m[0], q3[5]) + mul32x32_64(modm_m[1], q3[4]) + mul32x32_64(modm_m[2], q3[3]) + mul32x32_64(modm_m[3], q3[2]) + mul32x32_64(modm_m[4], q3[1]) + mul32x32_64(modm_m[5], q3[0]); - r2[5] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; - c += mul32x32_64(modm_m[0], q3[6]) + mul32x32_64(modm_m[1], q3[5]) + mul32x32_64(modm_m[2], q3[4]) + mul32x32_64(modm_m[3], q3[3]) + mul32x32_64(modm_m[4], q3[2]) + mul32x32_64(modm_m[5], q3[1]) + mul32x32_64(modm_m[6], q3[0]); - r2[6] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; - c += mul32x32_64(modm_m[0], q3[7]) + mul32x32_64(modm_m[1], q3[6]) + mul32x32_64(modm_m[2], q3[5]) + mul32x32_64(modm_m[3], q3[4]) + mul32x32_64(modm_m[4], q3[3]) + mul32x32_64(modm_m[5], q3[2]) + mul32x32_64(modm_m[6], q3[1]) + mul32x32_64(modm_m[7], q3[0]); - r2[7] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; - c += mul32x32_64(modm_m[0], q3[8]) + mul32x32_64(modm_m[1], q3[7]) + mul32x32_64(modm_m[2], q3[6]) + mul32x32_64(modm_m[3], q3[5]) + mul32x32_64(modm_m[4], q3[4]) + mul32x32_64(modm_m[5], q3[3]) + mul32x32_64(modm_m[6], q3[2]) + mul32x32_64(modm_m[7], q3[1]) + mul32x32_64(modm_m[8], q3[0]); - r2[8] = (bignum256modm_element_t)(c & 0xffffff); - - /* r = r1 - r2 - if (r < 0) r += (1 << 264) */ - pb = 0; - pb += r2[0]; b = lt_modm(r1[0], pb); r[0] = (r1[0] - pb + (b << 30)); pb = b; - pb += r2[1]; b = lt_modm(r1[1], pb); r[1] = (r1[1] - pb + (b << 30)); pb = b; - pb += r2[2]; b = lt_modm(r1[2], pb); r[2] = (r1[2] - pb + (b << 30)); pb = b; - pb += r2[3]; b = lt_modm(r1[3], pb); r[3] = (r1[3] - pb + (b << 30)); pb = b; - pb += r2[4]; b = lt_modm(r1[4], pb); r[4] = (r1[4] - pb + (b << 30)); pb = b; - pb += r2[5]; b = lt_modm(r1[5], pb); r[5] = (r1[5] - pb + (b << 30)); pb = b; - pb += r2[6]; b = lt_modm(r1[6], pb); r[6] = (r1[6] - pb + (b << 30)); pb = b; - pb += r2[7]; b = lt_modm(r1[7], pb); r[7] = (r1[7] - pb + (b << 30)); pb = b; - pb += r2[8]; b = lt_modm(r1[8], pb); r[8] = (r1[8] - pb + (b << 24)); - - reduce256_modm(r); - reduce256_modm(r); -} - -/* addition modulo m */ -void add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { - bignum256modm_element_t c = 0; - - c = x[0] + y[0]; r[0] = c & 0x3fffffff; c >>= 30; - c += x[1] + y[1]; r[1] = c & 0x3fffffff; c >>= 30; - c += x[2] + y[2]; r[2] = c & 0x3fffffff; c >>= 30; - c += x[3] + y[3]; r[3] = c & 0x3fffffff; c >>= 30; - c += x[4] + y[4]; r[4] = c & 0x3fffffff; c >>= 30; - c += x[5] + y[5]; r[5] = c & 0x3fffffff; c >>= 30; - c += x[6] + y[6]; r[6] = c & 0x3fffffff; c >>= 30; - c += x[7] + y[7]; r[7] = c & 0x3fffffff; c >>= 30; - c += x[8] + y[8]; r[8] = c; - - reduce256_modm(r); -} - -/* -x modulo m */ -void neg256_modm(bignum256modm r, const bignum256modm x) { - bignum256modm_element_t b = 0, pb = 0; - - /* r = m - x */ - pb = 0; - pb += x[0]; b = lt_modm(modm_m[0], pb); r[0] = (modm_m[0] - pb + (b << 30)); pb = b; - pb += x[1]; b = lt_modm(modm_m[1], pb); r[1] = (modm_m[1] - pb + (b << 30)); pb = b; - pb += x[2]; b = lt_modm(modm_m[2], pb); r[2] = (modm_m[2] - pb + (b << 30)); pb = b; - pb += x[3]; b = lt_modm(modm_m[3], pb); r[3] = (modm_m[3] - pb + (b << 30)); pb = b; - pb += x[4]; b = lt_modm(modm_m[4], pb); r[4] = (modm_m[4] - pb + (b << 30)); pb = b; - pb += x[5]; b = lt_modm(modm_m[5], pb); r[5] = (modm_m[5] - pb + (b << 30)); pb = b; - pb += x[6]; b = lt_modm(modm_m[6], pb); r[6] = (modm_m[6] - pb + (b << 30)); pb = b; - pb += x[7]; b = lt_modm(modm_m[7], pb); r[7] = (modm_m[7] - pb + (b << 30)); pb = b; - pb += x[8]; b = lt_modm(modm_m[8], pb); r[8] = (modm_m[8] - pb + (b << 16)); - - // if x==0, reduction is required - reduce256_modm(r); -} - -/* consts for subtraction, > p */ -/* Emilia Kasper trick, https://www.imperialviolet.org/2010/12/04/ecc.html */ -static const uint32_t twoP[] = { - 0x5cf5d3ed, 0x60498c68, 0x6f79cd64, 0x77be77a7, 0x40000013, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xfff}; - -/* subtraction x-y % m */ -void sub256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { - bignum256modm_element_t c = 0; - c = twoP[0] + x[0] - y[0]; r[0] = c & 0x3fffffff; c >>= 30; - c += twoP[1] + x[1] - y[1]; r[1] = c & 0x3fffffff; c >>= 30; - c += twoP[2] + x[2] - y[2]; r[2] = c & 0x3fffffff; c >>= 30; - c += twoP[3] + x[3] - y[3]; r[3] = c & 0x3fffffff; c >>= 30; - c += twoP[4] + x[4] - y[4]; r[4] = c & 0x3fffffff; c >>= 30; - c += twoP[5] + x[5] - y[5]; r[5] = c & 0x3fffffff; c >>= 30; - c += twoP[6] + x[6] - y[6]; r[6] = c & 0x3fffffff; c >>= 30; - c += twoP[7] + x[7] - y[7]; r[7] = c & 0x3fffffff; c >>= 30; - c += twoP[8] + x[8] - y[8]; r[8] = c; - reduce256_modm(r); -} - -/* multiplication modulo m */ -void mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { - bignum256modm r1 = {0}, q1 = {0}; - uint64_t c = 0; - bignum256modm_element_t f = 0; - - /* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1) - q1 = x >> 248 = 264 bits = 9 30 bit elements */ - c = mul32x32_64(x[0], y[0]); - f = (bignum256modm_element_t)c; r1[0] = (f & 0x3fffffff); c >>= 30; - c += mul32x32_64(x[0], y[1]) + mul32x32_64(x[1], y[0]); - f = (bignum256modm_element_t)c; r1[1] = (f & 0x3fffffff); c >>= 30; - c += mul32x32_64(x[0], y[2]) + mul32x32_64(x[1], y[1]) + mul32x32_64(x[2], y[0]); - f = (bignum256modm_element_t)c; r1[2] = (f & 0x3fffffff); c >>= 30; - c += mul32x32_64(x[0], y[3]) + mul32x32_64(x[1], y[2]) + mul32x32_64(x[2], y[1]) + mul32x32_64(x[3], y[0]); - f = (bignum256modm_element_t)c; r1[3] = (f & 0x3fffffff); c >>= 30; - c += mul32x32_64(x[0], y[4]) + mul32x32_64(x[1], y[3]) + mul32x32_64(x[2], y[2]) + mul32x32_64(x[3], y[1]) + mul32x32_64(x[4], y[0]); - f = (bignum256modm_element_t)c; r1[4] = (f & 0x3fffffff); c >>= 30; - c += mul32x32_64(x[0], y[5]) + mul32x32_64(x[1], y[4]) + mul32x32_64(x[2], y[3]) + mul32x32_64(x[3], y[2]) + mul32x32_64(x[4], y[1]) + mul32x32_64(x[5], y[0]); - f = (bignum256modm_element_t)c; r1[5] = (f & 0x3fffffff); c >>= 30; - c += mul32x32_64(x[0], y[6]) + mul32x32_64(x[1], y[5]) + mul32x32_64(x[2], y[4]) + mul32x32_64(x[3], y[3]) + mul32x32_64(x[4], y[2]) + mul32x32_64(x[5], y[1]) + mul32x32_64(x[6], y[0]); - f = (bignum256modm_element_t)c; r1[6] = (f & 0x3fffffff); c >>= 30; - c += mul32x32_64(x[0], y[7]) + mul32x32_64(x[1], y[6]) + mul32x32_64(x[2], y[5]) + mul32x32_64(x[3], y[4]) + mul32x32_64(x[4], y[3]) + mul32x32_64(x[5], y[2]) + mul32x32_64(x[6], y[1]) + mul32x32_64(x[7], y[0]); - f = (bignum256modm_element_t)c; r1[7] = (f & 0x3fffffff); c >>= 30; - c += mul32x32_64(x[0], y[8]) + mul32x32_64(x[1], y[7]) + mul32x32_64(x[2], y[6]) + mul32x32_64(x[3], y[5]) + mul32x32_64(x[4], y[4]) + mul32x32_64(x[5], y[3]) + mul32x32_64(x[6], y[2]) + mul32x32_64(x[7], y[1]) + mul32x32_64(x[8], y[0]); - f = (bignum256modm_element_t)c; r1[8] = (f & 0x00ffffff); q1[0] = (f >> 8) & 0x3fffff; c >>= 30; - c += mul32x32_64(x[1], y[8]) + mul32x32_64(x[2], y[7]) + mul32x32_64(x[3], y[6]) + mul32x32_64(x[4], y[5]) + mul32x32_64(x[5], y[4]) + mul32x32_64(x[6], y[3]) + mul32x32_64(x[7], y[2]) + mul32x32_64(x[8], y[1]); - f = (bignum256modm_element_t)c; q1[0] = (q1[0] | (f << 22)) & 0x3fffffff; q1[1] = (f >> 8) & 0x3fffff; c >>= 30; - c += mul32x32_64(x[2], y[8]) + mul32x32_64(x[3], y[7]) + mul32x32_64(x[4], y[6]) + mul32x32_64(x[5], y[5]) + mul32x32_64(x[6], y[4]) + mul32x32_64(x[7], y[3]) + mul32x32_64(x[8], y[2]); - f = (bignum256modm_element_t)c; q1[1] = (q1[1] | (f << 22)) & 0x3fffffff; q1[2] = (f >> 8) & 0x3fffff; c >>= 30; - c += mul32x32_64(x[3], y[8]) + mul32x32_64(x[4], y[7]) + mul32x32_64(x[5], y[6]) + mul32x32_64(x[6], y[5]) + mul32x32_64(x[7], y[4]) + mul32x32_64(x[8], y[3]); - f = (bignum256modm_element_t)c; q1[2] = (q1[2] | (f << 22)) & 0x3fffffff; q1[3] = (f >> 8) & 0x3fffff; c >>= 30; - c += mul32x32_64(x[4], y[8]) + mul32x32_64(x[5], y[7]) + mul32x32_64(x[6], y[6]) + mul32x32_64(x[7], y[5]) + mul32x32_64(x[8], y[4]); - f = (bignum256modm_element_t)c; q1[3] = (q1[3] | (f << 22)) & 0x3fffffff; q1[4] = (f >> 8) & 0x3fffff; c >>= 30; - c += mul32x32_64(x[5], y[8]) + mul32x32_64(x[6], y[7]) + mul32x32_64(x[7], y[6]) + mul32x32_64(x[8], y[5]); - f = (bignum256modm_element_t)c; q1[4] = (q1[4] | (f << 22)) & 0x3fffffff; q1[5] = (f >> 8) & 0x3fffff; c >>= 30; - c += mul32x32_64(x[6], y[8]) + mul32x32_64(x[7], y[7]) + mul32x32_64(x[8], y[6]); - f = (bignum256modm_element_t)c; q1[5] = (q1[5] | (f << 22)) & 0x3fffffff; q1[6] = (f >> 8) & 0x3fffff; c >>= 30; - c += mul32x32_64(x[7], y[8]) + mul32x32_64(x[8], y[7]); - f = (bignum256modm_element_t)c; q1[6] = (q1[6] | (f << 22)) & 0x3fffffff; q1[7] = (f >> 8) & 0x3fffff; c >>= 30; - c += mul32x32_64(x[8], y[8]); - f = (bignum256modm_element_t)c; q1[7] = (q1[7] | (f << 22)) & 0x3fffffff; q1[8] = (f >> 8) & 0x3fffff; - - barrett_reduce256_modm(r, q1, r1); -} - -void expand256_modm(bignum256modm out, const unsigned char *in, size_t len) { - unsigned char work[64] = {0}; - bignum256modm_element_t x[16] = {0}; - bignum256modm q1 = {0}; - - memcpy(work, in, len); - x[0] = U8TO32_LE(work + 0); - x[1] = U8TO32_LE(work + 4); - x[2] = U8TO32_LE(work + 8); - x[3] = U8TO32_LE(work + 12); - x[4] = U8TO32_LE(work + 16); - x[5] = U8TO32_LE(work + 20); - x[6] = U8TO32_LE(work + 24); - x[7] = U8TO32_LE(work + 28); - x[8] = U8TO32_LE(work + 32); - x[9] = U8TO32_LE(work + 36); - x[10] = U8TO32_LE(work + 40); - x[11] = U8TO32_LE(work + 44); - x[12] = U8TO32_LE(work + 48); - x[13] = U8TO32_LE(work + 52); - x[14] = U8TO32_LE(work + 56); - x[15] = U8TO32_LE(work + 60); - - /* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1) */ - out[0] = ( x[0]) & 0x3fffffff; - out[1] = ((x[ 0] >> 30) | (x[ 1] << 2)) & 0x3fffffff; - out[2] = ((x[ 1] >> 28) | (x[ 2] << 4)) & 0x3fffffff; - out[3] = ((x[ 2] >> 26) | (x[ 3] << 6)) & 0x3fffffff; - out[4] = ((x[ 3] >> 24) | (x[ 4] << 8)) & 0x3fffffff; - out[5] = ((x[ 4] >> 22) | (x[ 5] << 10)) & 0x3fffffff; - out[6] = ((x[ 5] >> 20) | (x[ 6] << 12)) & 0x3fffffff; - out[7] = ((x[ 6] >> 18) | (x[ 7] << 14)) & 0x3fffffff; - out[8] = ((x[ 7] >> 16) | (x[ 8] << 16)) & 0x00ffffff; - - /* 8*31 = 248 bits, no need to reduce */ - if (len < 32) - return; - - /* q1 = x >> 248 = 264 bits = 9 30 bit elements */ - q1[0] = ((x[ 7] >> 24) | (x[ 8] << 8)) & 0x3fffffff; - q1[1] = ((x[ 8] >> 22) | (x[ 9] << 10)) & 0x3fffffff; - q1[2] = ((x[ 9] >> 20) | (x[10] << 12)) & 0x3fffffff; - q1[3] = ((x[10] >> 18) | (x[11] << 14)) & 0x3fffffff; - q1[4] = ((x[11] >> 16) | (x[12] << 16)) & 0x3fffffff; - q1[5] = ((x[12] >> 14) | (x[13] << 18)) & 0x3fffffff; - q1[6] = ((x[13] >> 12) | (x[14] << 20)) & 0x3fffffff; - q1[7] = ((x[14] >> 10) | (x[15] << 22)) & 0x3fffffff; - q1[8] = ((x[15] >> 8) ); - - barrett_reduce256_modm(out, q1, out); -} - -void expand_raw256_modm(bignum256modm out, const unsigned char in[32]) { - bignum256modm_element_t x[8] = {0}; - - x[0] = U8TO32_LE(in + 0); - x[1] = U8TO32_LE(in + 4); - x[2] = U8TO32_LE(in + 8); - x[3] = U8TO32_LE(in + 12); - x[4] = U8TO32_LE(in + 16); - x[5] = U8TO32_LE(in + 20); - x[6] = U8TO32_LE(in + 24); - x[7] = U8TO32_LE(in + 28); - - out[0] = ( x[0]) & 0x3fffffff; - out[1] = ((x[ 0] >> 30) | (x[ 1] << 2)) & 0x3fffffff; - out[2] = ((x[ 1] >> 28) | (x[ 2] << 4)) & 0x3fffffff; - out[3] = ((x[ 2] >> 26) | (x[ 3] << 6)) & 0x3fffffff; - out[4] = ((x[ 3] >> 24) | (x[ 4] << 8)) & 0x3fffffff; - out[5] = ((x[ 4] >> 22) | (x[ 5] << 10)) & 0x3fffffff; - out[6] = ((x[ 5] >> 20) | (x[ 6] << 12)) & 0x3fffffff; - out[7] = ((x[ 6] >> 18) | (x[ 7] << 14)) & 0x3fffffff; - out[8] = ((x[ 7] >> 16) ) & 0x0000ffff; -} - -int is_reduced256_modm(const bignum256modm in) -{ - int i = 0; - uint32_t res1 = 0; - uint32_t res2 = 0; - for (i = 8; i >= 0; i--) { - res1 = (res1 << 1) | (in[i] < modm_m[i]); - res2 = (res2 << 1) | (in[i] > modm_m[i]); - } - return res1 > res2; -} - -void contract256_modm(unsigned char out[32], const bignum256modm in) { - U32TO8_LE(out + 0, (in[0] ) | (in[1] << 30)); - U32TO8_LE(out + 4, (in[1] >> 2) | (in[2] << 28)); - U32TO8_LE(out + 8, (in[2] >> 4) | (in[3] << 26)); - U32TO8_LE(out + 12, (in[3] >> 6) | (in[4] << 24)); - U32TO8_LE(out + 16, (in[4] >> 8) | (in[5] << 22)); - U32TO8_LE(out + 20, (in[5] >> 10) | (in[6] << 20)); - U32TO8_LE(out + 24, (in[6] >> 12) | (in[7] << 18)); - U32TO8_LE(out + 28, (in[7] >> 14) | (in[8] << 16)); -} - -void contract256_window4_modm(signed char r[64], const bignum256modm in) { - char carry = 0; - signed char *quads = r; - bignum256modm_element_t i = 0, j = 0, v = 0; - - for (i = 0; i < 8; i += 2) { - v = in[i]; - for (j = 0; j < 7; j++) { - *quads++ = (v & 15); - v >>= 4; - } - v |= (in[i+1] << 2); - for (j = 0; j < 8; j++) { - *quads++ = (v & 15); - v >>= 4; - } - } - v = in[8]; - *quads++ = (v & 15); v >>= 4; - *quads++ = (v & 15); v >>= 4; - *quads++ = (v & 15); v >>= 4; - *quads++ = (v & 15); v >>= 4; - - /* making it signed */ - carry = 0; - for(i = 0; i < 63; i++) { - r[i] += carry; - r[i+1] += (r[i] >> 4); - r[i] &= 15; - carry = (r[i] >> 3); - r[i] -= (carry << 4); - } - r[63] += carry; -} - -void contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int windowsize) { - int i = 0, j = 0, k = 0, b = 0; - int m = (1 << (windowsize - 1)) - 1, soplen = 256; - signed char *bits = r; - bignum256modm_element_t v = 0; - - /* first put the binary expansion into r */ - for (i = 0; i < 8; i++) { - v = s[i]; - for (j = 0; j < 30; j++, v >>= 1) - *bits++ = (v & 1); - } - v = s[8]; - for (j = 0; j < 16; j++, v >>= 1) - *bits++ = (v & 1); - - /* Making it sliding window */ - for (j = 0; j < soplen; j++) { - if (!r[j]) - continue; - - for (b = 1; (b < (soplen - j)) && (b <= 6); b++) { - if ((r[j] + (r[j + b] << b)) <= m) { - r[j] += r[j + b] << b; - r[j + b] = 0; - } else if ((r[j] - (r[j + b] << b)) >= -m) { - r[j] -= r[j + b] << b; - for (k = j + b; k < soplen; k++) { - if (!r[k]) { - r[k] = 1; - break; - } - r[k] = 0; - } - } else if (r[j + b]) { - break; - } - } - } -} - -void set256_modm(bignum256modm r, uint64_t v) { - r[0] = (bignum256modm_element_t) (v & 0x3fffffff); v >>= 30; - r[1] = (bignum256modm_element_t) (v & 0x3fffffff); v >>= 30; - r[2] = (bignum256modm_element_t) (v & 0x3fffffff); - r[3] = 0; - r[4] = 0; - r[5] = 0; - r[6] = 0; - r[7] = 0; - r[8] = 0; -} - -int get256_modm(uint64_t * v, const bignum256modm r){ - *v = 0; - int con1 = 0; - -#define NONZ(x) ((((((int64_t)(x)) - 1) >> 32) + 1) & 1) - bignum256modm_element_t c = 0; - c = r[0]; *v += (uint64_t)c & 0x3fffffff; c >>= 30; // 30 - c += r[1]; *v += ((uint64_t)c & 0x3fffffff) << 30; c >>= 30; // 60 - c += r[2]; *v += ((uint64_t)c & 0xf) << 60; con1 |= NONZ(c>>4); c >>= 30; // 64 bits - c += r[3]; con1 |= NONZ(c); c >>= 30; - c += r[4]; con1 |= NONZ(c); c >>= 30; - c += r[5]; con1 |= NONZ(c); c >>= 30; - c += r[6]; con1 |= NONZ(c); c >>= 30; - c += r[7]; con1 |= NONZ(c); c >>= 30; - c += r[8]; con1 |= NONZ(c); c >>= 30; - con1 |= NONZ(c); -#undef NONZ - - return con1 ^ 1; -} - -int eq256_modm(const bignum256modm x, const bignum256modm y){ - size_t differentbits = 0; - int len = bignum256modm_limb_size; - while (len--) { - differentbits |= (*x++ ^ *y++); - } - return (int) (1 & ((differentbits - 1) >> bignum256modm_bits_per_limb)); -} - -int cmp256_modm(const bignum256modm x, const bignum256modm y){ - int len = 2*bignum256modm_limb_size; - uint32_t a_gt = 0; - uint32_t b_gt = 0; - - // 16B chunks - while (len--) { - const uint32_t ln = (const uint32_t) len; - const uint32_t a = (x[ln>>1] >> 16*(ln & 1)) & 0xffff; - const uint32_t b = (y[ln>>1] >> 16*(ln & 1)) & 0xffff; - - const uint32_t limb_a_gt = ((b - a) >> 16) & 1; - const uint32_t limb_b_gt = ((a - b) >> 16) & 1; - a_gt |= limb_a_gt & ~b_gt; - b_gt |= limb_b_gt & ~a_gt; - } - - return a_gt - b_gt; -} - -int iszero256_modm(const bignum256modm x){ - size_t differentbits = 0; - int len = bignum256modm_limb_size; - while (len--) { - differentbits |= (*x++); - } - return (int) (1 & ((differentbits - 1) >> bignum256modm_bits_per_limb)); -} - -void copy256_modm(bignum256modm r, const bignum256modm x){ - r[0] = x[0]; - r[1] = x[1]; - r[2] = x[2]; - r[3] = x[3]; - r[4] = x[4]; - r[5] = x[5]; - r[6] = x[6]; - r[7] = x[7]; - r[8] = x[8]; -} - -int check256_modm(const bignum256modm x){ - int ok = 1; - bignum256modm t={0}, z={0}; - - ok &= iszero256_modm(x) ^ 1; - barrett_reduce256_modm(t, z, x); - ok &= eq256_modm(t, x); - return ok; -} - -void mulsub256_modm(bignum256modm r, const bignum256modm a, const bignum256modm b, const bignum256modm c){ - //(cc - aa * bb) % l - bignum256modm t={0}; - mul256_modm(t, a, b); - sub256_modm(r, c, t); -} - -void muladd256_modm(bignum256modm r, const bignum256modm a, const bignum256modm b, const bignum256modm c){ - //(cc + aa * bb) % l - bignum256modm t={0}; - mul256_modm(t, a, b); - add256_modm(r, c, t); -} diff --git a/deps/crypto/trezor-crypto/ed25519-donna/modm-donna-32bit.h b/deps/crypto/trezor-crypto/ed25519-donna/modm-donna-32bit.h deleted file mode 100644 index 98090f2fe..000000000 --- a/deps/crypto/trezor-crypto/ed25519-donna/modm-donna-32bit.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - Public domain by Andrew M. -*/ - - -/* - Arithmetic modulo the group order n = 2^252 + 27742317777372353535851937790883648493 = 7237005577332262213973186563042994240857116359379907606001950938285454250989 - - k = 32 - b = 1 << 8 = 256 - m = 2^252 + 27742317777372353535851937790883648493 = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed - mu = floor( b^(k*2) / m ) = 0xfffffffffffffffffffffffffffffffeb2106215d086329a7ed9ce5a30a2c131b -*/ - -#define bignum256modm_bits_per_limb 30 -#define bignum256modm_limb_size 9 - -typedef uint32_t bignum256modm_element_t; -typedef bignum256modm_element_t bignum256modm[9]; - -/* see HAC, Alg. 14.42 Step 4 */ -void reduce256_modm(bignum256modm r); - -/* - Barrett reduction, see HAC, Alg. 14.42 - - Instead of passing in x, pre-process in to q1 and r1 for efficiency -*/ -void barrett_reduce256_modm(bignum256modm r, const bignum256modm q1, const bignum256modm r1); - -/* addition modulo m */ -void add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y); - -/* -x modulo m */ -void neg256_modm(bignum256modm r, const bignum256modm x); - -/* subtraction x-y modulo m */ -void sub256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y); - -/* multiplication modulo m */ -void mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y); - -void expand256_modm(bignum256modm out, const unsigned char *in, size_t len); - -void expand_raw256_modm(bignum256modm out, const unsigned char in[32]); - -int is_reduced256_modm(const bignum256modm in); - -void contract256_modm(unsigned char out[32], const bignum256modm in); - -void contract256_window4_modm(signed char r[64], const bignum256modm in); - -void contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int windowsize); - -/* 64bit uint to scalar value */ -void set256_modm(bignum256modm r, uint64_t v); - -/* scalar value to 64bit uint */ -int get256_modm(uint64_t * v, const bignum256modm r); - -/* equality test on two reduced scalar values */ -int eq256_modm(const bignum256modm x, const bignum256modm y); - -/* comparison of two reduced scalar values */ -int cmp256_modm(const bignum256modm x, const bignum256modm y); - -/* scalar null check, has to be reduced */ -int iszero256_modm(const bignum256modm x); - -/* simple copy, no reduction */ -void copy256_modm(bignum256modm r, const bignum256modm x); - -/* check if nonzero && same after reduction */ -int check256_modm(const bignum256modm x); - -/* (cc - aa * bb) % l */ -void mulsub256_modm(bignum256modm r, const bignum256modm a, const bignum256modm b, const bignum256modm c); - -/* (cc + aa * bb) % l */ -void muladd256_modm(bignum256modm r, const bignum256modm a, const bignum256modm b, const bignum256modm c); diff --git a/deps/crypto/trezor-crypto/fuzzer/README.md b/deps/crypto/trezor-crypto/fuzzer/README.md deleted file mode 100644 index e1dbdeb20..000000000 --- a/deps/crypto/trezor-crypto/fuzzer/README.md +++ /dev/null @@ -1,67 +0,0 @@ -# trezor-crypto fuzzing -Selected functions can be fuzzed via specific libFuzzer harnesses for increased test coverage and issue detection. - -Note: the following commands are relative to the trezor-crypto main directory. - -## Build - -A modern C compiler with built-in libFuzzer support is required. The build process will use `clang` by default. -Set the `CC=` environment variable if you want to use a special compiler variant. - -```bash -make clean -FUZZER=1 make fuzzer -``` - -### Sanitizers -Recommended: ASAN / UBSAN / MSAN flags for error detection can be specified via the special `SANFLAGS`. - -Examples: - - * `SANFLAGS="-fsanitize=address,undefined"` - * `SANFLAGS="-fsanitize=memory"` - -### Optimizations - -Override `OPTFLAGS` to test the library at different optimization levels or simplify the debugging of detected issues. - -Example: - - * `OPTFLAGS="-O0 -ggdb3"` - -## Operation - -See the [libFuzzer documentation](https://llvm.org/docs/LibFuzzer.html#options) for valid options and usage. Detailed fuzzer usage and relevant considerations are out of scope of this document. - -**Warning**: fuzzing is resource-intensive and can have a negative impact on your system stability. - -Basic fuzzer call: -```bash -./fuzzer/fuzzer -``` - -Here is a more sophisticated multithreading example with a persistent input corpus and other optimizations: -```bash -mkdir fuzzer/fuzzer_corpus -./fuzzer/fuzzer -max_len=2048 -use_value_profile=1 -jobs=16 -timeout=1 -reload=5 -print_pcs=1 -print_funcs=42 fuzzer/fuzzer_corpus -``` - -Hint: for more permanent setups, consider invoking the fuzzer from outside of the source directory to avoid cluttering it with logfiles and crash inputs. - -## Automated fuzzer dictionary generation - -[Dictionaries](https://llvm.org/docs/LibFuzzer.html#dictionaries) are a useful mechanism to augment the capabilities of the fuzzer. Specify them via the `-dict=` flag. - -### Collect interesting strings from the unit tests -``` bash -grep -r -P -o -h "\"\w+\"" tests | sort | uniq > fuzzer_crypto_tests_strings_dictionary1.txt -``` - -## Evaluate source coverage - - 1. build the fuzzer binary with `CFLAGS="-fprofile-instr-generate -fcoverage-mapping"` - 1. run with suitable `-runs=` or `-max_total_time=` limits - 1. convert the recorded data `llvm-profdata merge -output=default.profdata -instr default.profraw` - 1. render the data `llvm-cov show fuzzer/fuzzer -instr-profile=default.profdata -format=html -output-dir=coverage-report` - 1. analyze report at `coverage-report/index.html` - 1. (optional) remove artifacts with `rm default.profraw default.profdata && rm -r coverage-report` diff --git a/deps/crypto/trezor-crypto/fuzzer/fuzzer.c b/deps/crypto/trezor-crypto/fuzzer/fuzzer.c deleted file mode 100644 index 3a1e7c1d9..000000000 --- a/deps/crypto/trezor-crypto/fuzzer/fuzzer.c +++ /dev/null @@ -1,416 +0,0 @@ -/** - * Copyright (c) 2020 Christian Reitter - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include -#include - -// necessary for the target functions -#include "bignum.h" -#include "ecdsa.h" -#include "hasher.h" -#include "rand.h" - -/* fuzzer input data handling */ -const uint8_t *fuzzer_ptr; -size_t fuzzer_length; - -const uint8_t *fuzzer_input(size_t len) { - if (fuzzer_length < len) { - fuzzer_length = 0; - return NULL; - } - const uint8_t *result = fuzzer_ptr; - fuzzer_length -= len; - fuzzer_ptr += len; - return result; -} - -/* fuzzer state handling */ -void fuzzer_reset_state(void) { - // reset the PRNGs to make individual fuzzer runs deterministic - srand(0); - random_reseed(0); -} - -/* individual fuzzer harness functions */ - -extern size_t bn_format(const bignum256 *amnt, const char *prefix, - const char *suffix, unsigned int decimals, int exponent, - bool trailing, char *out, size_t outlen); -int fuzz_bn_format() { - bignum256 target_bignum; - if (fuzzer_length < sizeof(target_bignum)) { - return 0; - } - - char buf[512]; - int r; - - // mutate the struct contents - memcpy(&target_bignum, fuzzer_ptr, sizeof(target_bignum)); - fuzzer_input(sizeof(target_bignum)); - - uint8_t prefixlen = 0; - if (fuzzer_length < 1) { - return 0; - } - memcpy(&prefixlen, fuzzer_input(1), 1); - char prefix[prefixlen]; - if (prefixlen > 0 && prefixlen <= 128 && prefixlen <= fuzzer_length) { - memcpy(&prefix, fuzzer_input(prefixlen), prefixlen); - // force null termination - prefix[prefixlen - 1] = 0; - } else { - return 0; - } - // TODO fuzzer idea: allow prefix=NULL - - uint8_t suffixlen = 0; - if (fuzzer_length < 1) { - return 0; - } - memcpy(&suffixlen, fuzzer_input(1), 1); - char suffix[suffixlen]; - if (suffixlen > 0 && suffixlen <= 128 && suffixlen <= fuzzer_length) { - memcpy(&suffix, fuzzer_input(suffixlen), suffixlen); - // force null termination - suffix[suffixlen - 1] = 0; - } else { - return 0; - } - // TODO fuzzer idea: allow suffix=NULL - uint32_t decimals = 0; - int32_t exponent = 0; - bool trailing = false; - - if (fuzzer_length >= 9) { - memcpy(&decimals, fuzzer_input(4), 4); - memcpy(&exponent, fuzzer_input(4), 4); - - trailing = (fuzzer_input(1)[0] & 1); - } else { - return 0; - } - - r = bn_format(&target_bignum, prefix, suffix, decimals, exponent, trailing, - buf, sizeof(buf)); - return 0; -} - -extern const char *BASE32_ALPHABET_RFC4648; -extern uint8_t *base32_decode(const char *in, size_t inlen, uint8_t *out, - size_t outlen, const char *alphabet); - -// arbitrarily chosen maximum size -#define BASE32_DECODE_MAX_INPUT_LEN 512 - -int fuzz_base32_decode() { - if (fuzzer_length < 2 || fuzzer_length > BASE32_DECODE_MAX_INPUT_LEN) { - return 0; - } - - char in_buffer[BASE32_DECODE_MAX_INPUT_LEN] = {0}; - uint8_t out_buffer[BASE32_DECODE_MAX_INPUT_LEN] = {0}; - size_t outlen = sizeof(out_buffer); - - // mutate in_buffer - size_t raw_inlen = fuzzer_length; - memcpy(&in_buffer, fuzzer_ptr, raw_inlen); - fuzzer_input(raw_inlen); - - // null-terminate input buffer to prevent issues with strlen() - in_buffer[BASE32_DECODE_MAX_INPUT_LEN - 1] = 0; - size_t inlen = strlen(in_buffer); - - base32_decode(in_buffer, inlen, out_buffer, outlen, BASE32_ALPHABET_RFC4648); - return 0; -} - -extern char *base32_encode(const uint8_t *in, size_t inlen, char *out, - size_t outlen, const char *alphabet); - -// arbitrarily chosen maximum size -#define BASE32_ENCODE_MAX_INPUT_LEN 512 - -int fuzz_base32_encode() { - if (fuzzer_length > BASE32_ENCODE_MAX_INPUT_LEN) { - return 0; - } - - uint8_t in_buffer[BASE32_ENCODE_MAX_INPUT_LEN] = {0}; - char out_buffer[BASE32_ENCODE_MAX_INPUT_LEN] = {0}; - size_t outlen = sizeof(out_buffer); - - // mutate in_buffer - size_t raw_inlen = fuzzer_length; - memcpy(&in_buffer, fuzzer_ptr, raw_inlen); - fuzzer_input(raw_inlen); - - base32_encode(in_buffer, raw_inlen, out_buffer, outlen, - BASE32_ALPHABET_RFC4648); - return 0; -} - -extern int base58_encode_check(const uint8_t *data, int datalen, - HasherType hasher_type, char *str, int strsize); - -// internal limit is 128, try some extra bytes -#define BASE58_ENCODE_MAX_INPUT_LEN 140 - -int fuzz_base58_encode_check() { - if (fuzzer_length > BASE58_ENCODE_MAX_INPUT_LEN) { - return 0; - } - - uint8_t in_buffer[BASE58_ENCODE_MAX_INPUT_LEN] = {0}; - char out_buffer[BASE58_ENCODE_MAX_INPUT_LEN] = {0}; - size_t outlen = sizeof(out_buffer); - - // mutate in_buffer - size_t raw_inlen = fuzzer_length; - memcpy(&in_buffer, fuzzer_ptr, raw_inlen); - fuzzer_input(raw_inlen); - - // run multiple hasher variants for the same input - base58_encode_check(in_buffer, raw_inlen, HASHER_SHA2D, out_buffer, outlen); - base58_encode_check(in_buffer, raw_inlen, HASHER_BLAKED, out_buffer, outlen); - base58_encode_check(in_buffer, raw_inlen, HASHER_GROESTLD_TRUNC, out_buffer, - outlen); - base58_encode_check(in_buffer, raw_inlen, HASHER_SHA3K, out_buffer, outlen); - return 0; -} - -extern int base58_decode_check(const char *str, HasherType hasher_type, - uint8_t *data, int datalen); - -// internal limit is 128, try some extra bytes -#define BASE58_DECODE_MAX_INPUT_LEN 140 - -int fuzz_base58_decode_check() { - if (fuzzer_length > BASE58_DECODE_MAX_INPUT_LEN) { - return 0; - } - - // with null terminator - uint8_t in_buffer[BASE58_DECODE_MAX_INPUT_LEN + 1] = {0}; - uint8_t out_buffer[BASE58_DECODE_MAX_INPUT_LEN] = {0}; - - // mutate in_buffer - size_t raw_inlen = fuzzer_length; - memcpy(&in_buffer, fuzzer_ptr, raw_inlen); - fuzzer_input(raw_inlen); - - // run multiple hasher variants for the same input - base58_decode_check((const char *)in_buffer, HASHER_SHA2D, out_buffer, - MAX_ADDR_RAW_SIZE); - base58_decode_check((const char *)in_buffer, HASHER_BLAKED, out_buffer, - MAX_ADDR_RAW_SIZE); - base58_decode_check((const char *)in_buffer, HASHER_GROESTLD_TRUNC, - out_buffer, MAX_ADDR_RAW_SIZE); - base58_decode_check((const char *)in_buffer, HASHER_SHA3K, out_buffer, - MAX_ADDR_RAW_SIZE); - return 0; -} - -extern int xmr_base58_addr_decode_check(const char *addr, size_t sz, - uint64_t *tag, void *data, - size_t datalen); - -// arbitrarily chosen maximum size -#define XMR_BASE58_ADDR_DECODE_MAX_INPUT_LEN 512 - -int fuzz_xmr_base58_addr_decode_check() { - if (fuzzer_length > XMR_BASE58_ADDR_DECODE_MAX_INPUT_LEN) { - return 0; - } - - char in_buffer[XMR_BASE58_ADDR_DECODE_MAX_INPUT_LEN] = {0}; - char out_buffer[XMR_BASE58_ADDR_DECODE_MAX_INPUT_LEN] = {0}; - size_t outlen = sizeof(out_buffer); - - // mutate in_buffer - size_t raw_inlen = fuzzer_length; - memcpy(&in_buffer, fuzzer_ptr, raw_inlen); - fuzzer_input(raw_inlen); - - uint64_t tag; - xmr_base58_addr_decode_check(in_buffer, raw_inlen, &tag, out_buffer, outlen); - return 0; -} - -extern int xmr_base58_addr_encode_check(uint64_t tag, const uint8_t *data, - size_t binsz, char *b58, size_t b58sz); - -// arbitrarily chosen maximum size -#define XMR_BASE58_ADDR_ENCODE_MAX_INPUT_LEN 512 - -int fuzz_xmr_base58_addr_encode_check() { - uint64_t tag_in; - size_t tag_size = sizeof(tag_in); - if (fuzzer_length < tag_size || - fuzzer_length > XMR_BASE58_ADDR_ENCODE_MAX_INPUT_LEN) { - return 0; - } - - uint8_t in_buffer[XMR_BASE58_ADDR_ENCODE_MAX_INPUT_LEN] = {0}; - char out_buffer[XMR_BASE58_ADDR_ENCODE_MAX_INPUT_LEN] = {0}; - size_t outlen = sizeof(out_buffer); - - // mutate tag_in - memcpy(&tag_in, fuzzer_ptr, tag_size); - fuzzer_input(tag_size); - - // mutate in_buffer - memcpy(&in_buffer, fuzzer_ptr, fuzzer_length); - size_t raw_inlen = fuzzer_length; - fuzzer_input(raw_inlen); - - xmr_base58_addr_encode_check(tag_in, in_buffer, raw_inlen, out_buffer, - outlen); - return 0; -} - -extern int xmr_size_varint(uint64_t num); -extern int xmr_write_varint(uint8_t *buff, size_t buff_size, uint64_t num); -extern int xmr_read_varint(uint8_t *buff, size_t buff_size, uint64_t *val); - -// arbitrarily chosen maximum size -#define XMR_SERIALIZE_VARINT_MAX_INPUT_LEN 128 - -int fuzz_xmr_serialize_varint() { - uint64_t varint_in; - size_t varint_in_size = sizeof(varint_in); - if (fuzzer_length < varint_in_size || - fuzzer_length > XMR_SERIALIZE_VARINT_MAX_INPUT_LEN) { - return 0; - } - - uint8_t in_buffer[XMR_SERIALIZE_VARINT_MAX_INPUT_LEN] = {0}; - uint8_t out_buffer[XMR_SERIALIZE_VARINT_MAX_INPUT_LEN] = {0}; - size_t outlen = sizeof(out_buffer); - uint64_t varint_out = 0; - - // mutate varint_in - memcpy(&varint_in, fuzzer_ptr, varint_in_size); - fuzzer_input(varint_in_size); - - // mutate in_buffer - memcpy(&in_buffer, fuzzer_ptr, fuzzer_length); - size_t raw_inlen = fuzzer_length; - fuzzer_input(raw_inlen); - - // call the actual xmr functions - xmr_size_varint(varint_in); - xmr_write_varint(out_buffer, outlen, varint_in); - xmr_read_varint(in_buffer, raw_inlen, &varint_out); - - return 0; -} - -extern bool nem_validate_address(const char *address, uint8_t network); - -// arbitrarily chosen maximum size -#define NEM_VALIDATE_ADDRESS_MAX_INPUT_LEN 128 - -int fuzz_nem_validate_address() { - if (fuzzer_length < (1 + 1) || - fuzzer_length > NEM_VALIDATE_ADDRESS_MAX_INPUT_LEN) { - return 0; - } - - char in_buffer[NEM_VALIDATE_ADDRESS_MAX_INPUT_LEN] = {0}; - - // TODO potential BUG: is it clearly specified that the address has to be null - // terminated? - in_buffer[NEM_VALIDATE_ADDRESS_MAX_INPUT_LEN - 1] = 0; - - uint8_t network = *fuzzer_ptr; - fuzzer_input(1); - - // mutate the buffer - memcpy(&in_buffer, fuzzer_ptr, fuzzer_length); - size_t raw_inlen = fuzzer_length; - fuzzer_input(raw_inlen); - - nem_validate_address(in_buffer, network); - - return 0; -} - -#define META_HEADER_SIZE 3 - -// main fuzzer entry -int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - // reject input that is too short - if (size < META_HEADER_SIZE) { - return 0; - } - - fuzzer_reset_state(); - - uint8_t decision = data[0]; - - // TODO use when necessary - // uint8_t subdecision = data[1]; - - // note: data[2] is reserved for future use - - // assign the fuzzer payload data for the target functions - fuzzer_ptr = data + META_HEADER_SIZE; - fuzzer_length = size - META_HEADER_SIZE; - - switch (decision) { - case 0: - fuzz_bn_format(); - break; - case 1: - fuzz_base32_decode(); - break; - case 2: - fuzz_base32_encode(); - break; - case 3: - fuzz_base58_encode_check(); - break; - case 4: - fuzz_base58_decode_check(); - break; - case 5: - fuzz_xmr_base58_addr_decode_check(); - break; - case 6: - fuzz_xmr_base58_addr_encode_check(); - break; - case 7: - fuzz_xmr_serialize_varint(); - break; - case 8: - fuzz_nem_validate_address(); - break; - default: - // do nothing - break; - } - return 0; -} diff --git a/deps/crypto/trezor-crypto/groestl.c b/deps/crypto/trezor-crypto/groestl.c deleted file mode 100644 index d913c76e0..000000000 --- a/deps/crypto/trezor-crypto/groestl.c +++ /dev/null @@ -1,787 +0,0 @@ -/* Groestl hash from https://github.com/Groestlcoin/vanitygen - * Trezor adaptation by Yura Pakhuchiy . */ -/* - * Groestl implementation. - * - * ==========================(LICENSE BEGIN)============================ - * - * Copyright (c) 2007-2010 Projet RNRT SAPHIR - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * ===========================(LICENSE END)============================= - * - * @author Thomas Pornin - */ - -#include -#include - -#include "groestl_internal.h" -#include "groestl.h" -#include "memzero.h" - - -#define C32e(x) ((SPH_C32(x) >> 24) \ - | ((SPH_C32(x) >> 8) & SPH_C32(0x0000FF00)) \ - | ((SPH_C32(x) << 8) & SPH_C32(0x00FF0000)) \ - | ((SPH_C32(x) << 24) & SPH_C32(0xFF000000))) -#define dec32e_aligned sph_dec32le_aligned -#define enc32e sph_enc32le -#define B32_0(x) ((x) & 0xFF) -#define B32_1(x) (((x) >> 8) & 0xFF) -#define B32_2(x) (((x) >> 16) & 0xFF) -#define B32_3(x) ((x) >> 24) - -#define R32u(u, d) SPH_T32(((u) << 16) | ((d) >> 16)) -#define R32d(u, d) SPH_T32(((u) >> 16) | ((d) << 16)) - -#define PC32up(j, r) ((sph_u32)((j) + (r))) -#define PC32dn(j, r) 0 -#define QC32up(j, r) SPH_C32(0xFFFFFFFF) -#define QC32dn(j, r) (((sph_u32)(r) << 24) ^ SPH_T32(~((sph_u32)(j) << 24))) - -#define C64e(x) ((SPH_C64(x) >> 56) \ - | ((SPH_C64(x) >> 40) & SPH_C64(0x000000000000FF00)) \ - | ((SPH_C64(x) >> 24) & SPH_C64(0x0000000000FF0000)) \ - | ((SPH_C64(x) >> 8) & SPH_C64(0x00000000FF000000)) \ - | ((SPH_C64(x) << 8) & SPH_C64(0x000000FF00000000)) \ - | ((SPH_C64(x) << 24) & SPH_C64(0x0000FF0000000000)) \ - | ((SPH_C64(x) << 40) & SPH_C64(0x00FF000000000000)) \ - | ((SPH_C64(x) << 56) & SPH_C64(0xFF00000000000000))) -#define dec64e_aligned sph_dec64le_aligned -#define enc64e sph_enc64le -#define B64_0(x) ((x) & 0xFF) -#define B64_1(x) (((x) >> 8) & 0xFF) -#define B64_2(x) (((x) >> 16) & 0xFF) -#define B64_3(x) (((x) >> 24) & 0xFF) -#define B64_4(x) (((x) >> 32) & 0xFF) -#define B64_5(x) (((x) >> 40) & 0xFF) -#define B64_6(x) (((x) >> 48) & 0xFF) -#define B64_7(x) ((x) >> 56) -#define R64 SPH_ROTL64 -#define PC64(j, r) ((sph_u64)((j) + (r))) -#define QC64(j, r) (((sph_u64)(r) << 56) ^ SPH_T64(~((sph_u64)(j) << 56))) - - -static const sph_u32 T0up[] = { - C32e(0xc632f4a5), C32e(0xf86f9784), C32e(0xee5eb099), C32e(0xf67a8c8d), - C32e(0xffe8170d), C32e(0xd60adcbd), C32e(0xde16c8b1), C32e(0x916dfc54), - C32e(0x6090f050), C32e(0x02070503), C32e(0xce2ee0a9), C32e(0x56d1877d), - C32e(0xe7cc2b19), C32e(0xb513a662), C32e(0x4d7c31e6), C32e(0xec59b59a), - C32e(0x8f40cf45), C32e(0x1fa3bc9d), C32e(0x8949c040), C32e(0xfa689287), - C32e(0xefd03f15), C32e(0xb29426eb), C32e(0x8ece40c9), C32e(0xfbe61d0b), - C32e(0x416e2fec), C32e(0xb31aa967), C32e(0x5f431cfd), C32e(0x456025ea), - C32e(0x23f9dabf), C32e(0x535102f7), C32e(0xe445a196), C32e(0x9b76ed5b), - C32e(0x75285dc2), C32e(0xe1c5241c), C32e(0x3dd4e9ae), C32e(0x4cf2be6a), - C32e(0x6c82ee5a), C32e(0x7ebdc341), C32e(0xf5f30602), C32e(0x8352d14f), - C32e(0x688ce45c), C32e(0x515607f4), C32e(0xd18d5c34), C32e(0xf9e11808), - C32e(0xe24cae93), C32e(0xab3e9573), C32e(0x6297f553), C32e(0x2a6b413f), - C32e(0x081c140c), C32e(0x9563f652), C32e(0x46e9af65), C32e(0x9d7fe25e), - C32e(0x30487828), C32e(0x37cff8a1), C32e(0x0a1b110f), C32e(0x2febc4b5), - C32e(0x0e151b09), C32e(0x247e5a36), C32e(0x1badb69b), C32e(0xdf98473d), - C32e(0xcda76a26), C32e(0x4ef5bb69), C32e(0x7f334ccd), C32e(0xea50ba9f), - C32e(0x123f2d1b), C32e(0x1da4b99e), C32e(0x58c49c74), C32e(0x3446722e), - C32e(0x3641772d), C32e(0xdc11cdb2), C32e(0xb49d29ee), C32e(0x5b4d16fb), - C32e(0xa4a501f6), C32e(0x76a1d74d), C32e(0xb714a361), C32e(0x7d3449ce), - C32e(0x52df8d7b), C32e(0xdd9f423e), C32e(0x5ecd9371), C32e(0x13b1a297), - C32e(0xa6a204f5), C32e(0xb901b868), C32e(0x00000000), C32e(0xc1b5742c), - C32e(0x40e0a060), C32e(0xe3c2211f), C32e(0x793a43c8), C32e(0xb69a2ced), - C32e(0xd40dd9be), C32e(0x8d47ca46), C32e(0x671770d9), C32e(0x72afdd4b), - C32e(0x94ed79de), C32e(0x98ff67d4), C32e(0xb09323e8), C32e(0x855bde4a), - C32e(0xbb06bd6b), C32e(0xc5bb7e2a), C32e(0x4f7b34e5), C32e(0xedd73a16), - C32e(0x86d254c5), C32e(0x9af862d7), C32e(0x6699ff55), C32e(0x11b6a794), - C32e(0x8ac04acf), C32e(0xe9d93010), C32e(0x040e0a06), C32e(0xfe669881), - C32e(0xa0ab0bf0), C32e(0x78b4cc44), C32e(0x25f0d5ba), C32e(0x4b753ee3), - C32e(0xa2ac0ef3), C32e(0x5d4419fe), C32e(0x80db5bc0), C32e(0x0580858a), - C32e(0x3fd3ecad), C32e(0x21fedfbc), C32e(0x70a8d848), C32e(0xf1fd0c04), - C32e(0x63197adf), C32e(0x772f58c1), C32e(0xaf309f75), C32e(0x42e7a563), - C32e(0x20705030), C32e(0xe5cb2e1a), C32e(0xfdef120e), C32e(0xbf08b76d), - C32e(0x8155d44c), C32e(0x18243c14), C32e(0x26795f35), C32e(0xc3b2712f), - C32e(0xbe8638e1), C32e(0x35c8fda2), C32e(0x88c74fcc), C32e(0x2e654b39), - C32e(0x936af957), C32e(0x55580df2), C32e(0xfc619d82), C32e(0x7ab3c947), - C32e(0xc827efac), C32e(0xba8832e7), C32e(0x324f7d2b), C32e(0xe642a495), - C32e(0xc03bfba0), C32e(0x19aab398), C32e(0x9ef668d1), C32e(0xa322817f), - C32e(0x44eeaa66), C32e(0x54d6827e), C32e(0x3bdde6ab), C32e(0x0b959e83), - C32e(0x8cc945ca), C32e(0xc7bc7b29), C32e(0x6b056ed3), C32e(0x286c443c), - C32e(0xa72c8b79), C32e(0xbc813de2), C32e(0x1631271d), C32e(0xad379a76), - C32e(0xdb964d3b), C32e(0x649efa56), C32e(0x74a6d24e), C32e(0x1436221e), - C32e(0x92e476db), C32e(0x0c121e0a), C32e(0x48fcb46c), C32e(0xb88f37e4), - C32e(0x9f78e75d), C32e(0xbd0fb26e), C32e(0x43692aef), C32e(0xc435f1a6), - C32e(0x39dae3a8), C32e(0x31c6f7a4), C32e(0xd38a5937), C32e(0xf274868b), - C32e(0xd5835632), C32e(0x8b4ec543), C32e(0x6e85eb59), C32e(0xda18c2b7), - C32e(0x018e8f8c), C32e(0xb11dac64), C32e(0x9cf16dd2), C32e(0x49723be0), - C32e(0xd81fc7b4), C32e(0xacb915fa), C32e(0xf3fa0907), C32e(0xcfa06f25), - C32e(0xca20eaaf), C32e(0xf47d898e), C32e(0x476720e9), C32e(0x10382818), - C32e(0x6f0b64d5), C32e(0xf0738388), C32e(0x4afbb16f), C32e(0x5cca9672), - C32e(0x38546c24), C32e(0x575f08f1), C32e(0x732152c7), C32e(0x9764f351), - C32e(0xcbae6523), C32e(0xa125847c), C32e(0xe857bf9c), C32e(0x3e5d6321), - C32e(0x96ea7cdd), C32e(0x611e7fdc), C32e(0x0d9c9186), C32e(0x0f9b9485), - C32e(0xe04bab90), C32e(0x7cbac642), C32e(0x712657c4), C32e(0xcc29e5aa), - C32e(0x90e373d8), C32e(0x06090f05), C32e(0xf7f40301), C32e(0x1c2a3612), - C32e(0xc23cfea3), C32e(0x6a8be15f), C32e(0xaebe10f9), C32e(0x69026bd0), - C32e(0x17bfa891), C32e(0x9971e858), C32e(0x3a536927), C32e(0x27f7d0b9), - C32e(0xd9914838), C32e(0xebde3513), C32e(0x2be5ceb3), C32e(0x22775533), - C32e(0xd204d6bb), C32e(0xa9399070), C32e(0x07878089), C32e(0x33c1f2a7), - C32e(0x2decc1b6), C32e(0x3c5a6622), C32e(0x15b8ad92), C32e(0xc9a96020), - C32e(0x875cdb49), C32e(0xaab01aff), C32e(0x50d88878), C32e(0xa52b8e7a), - C32e(0x03898a8f), C32e(0x594a13f8), C32e(0x09929b80), C32e(0x1a233917), - C32e(0x651075da), C32e(0xd7845331), C32e(0x84d551c6), C32e(0xd003d3b8), - C32e(0x82dc5ec3), C32e(0x29e2cbb0), C32e(0x5ac39977), C32e(0x1e2d3311), - C32e(0x7b3d46cb), C32e(0xa8b71ffc), C32e(0x6d0c61d6), C32e(0x2c624e3a) -}; - -static const sph_u32 T0dn[] = { - C32e(0xf497a5c6), C32e(0x97eb84f8), C32e(0xb0c799ee), C32e(0x8cf78df6), - C32e(0x17e50dff), C32e(0xdcb7bdd6), C32e(0xc8a7b1de), C32e(0xfc395491), - C32e(0xf0c05060), C32e(0x05040302), C32e(0xe087a9ce), C32e(0x87ac7d56), - C32e(0x2bd519e7), C32e(0xa67162b5), C32e(0x319ae64d), C32e(0xb5c39aec), - C32e(0xcf05458f), C32e(0xbc3e9d1f), C32e(0xc0094089), C32e(0x92ef87fa), - C32e(0x3fc515ef), C32e(0x267febb2), C32e(0x4007c98e), C32e(0x1ded0bfb), - C32e(0x2f82ec41), C32e(0xa97d67b3), C32e(0x1cbefd5f), C32e(0x258aea45), - C32e(0xda46bf23), C32e(0x02a6f753), C32e(0xa1d396e4), C32e(0xed2d5b9b), - C32e(0x5deac275), C32e(0x24d91ce1), C32e(0xe97aae3d), C32e(0xbe986a4c), - C32e(0xeed85a6c), C32e(0xc3fc417e), C32e(0x06f102f5), C32e(0xd11d4f83), - C32e(0xe4d05c68), C32e(0x07a2f451), C32e(0x5cb934d1), C32e(0x18e908f9), - C32e(0xaedf93e2), C32e(0x954d73ab), C32e(0xf5c45362), C32e(0x41543f2a), - C32e(0x14100c08), C32e(0xf6315295), C32e(0xaf8c6546), C32e(0xe2215e9d), - C32e(0x78602830), C32e(0xf86ea137), C32e(0x11140f0a), C32e(0xc45eb52f), - C32e(0x1b1c090e), C32e(0x5a483624), C32e(0xb6369b1b), C32e(0x47a53ddf), - C32e(0x6a8126cd), C32e(0xbb9c694e), C32e(0x4cfecd7f), C32e(0xbacf9fea), - C32e(0x2d241b12), C32e(0xb93a9e1d), C32e(0x9cb07458), C32e(0x72682e34), - C32e(0x776c2d36), C32e(0xcda3b2dc), C32e(0x2973eeb4), C32e(0x16b6fb5b), - C32e(0x0153f6a4), C32e(0xd7ec4d76), C32e(0xa37561b7), C32e(0x49face7d), - C32e(0x8da47b52), C32e(0x42a13edd), C32e(0x93bc715e), C32e(0xa2269713), - C32e(0x0457f5a6), C32e(0xb86968b9), C32e(0x00000000), C32e(0x74992cc1), - C32e(0xa0806040), C32e(0x21dd1fe3), C32e(0x43f2c879), C32e(0x2c77edb6), - C32e(0xd9b3bed4), C32e(0xca01468d), C32e(0x70ced967), C32e(0xdde44b72), - C32e(0x7933de94), C32e(0x672bd498), C32e(0x237be8b0), C32e(0xde114a85), - C32e(0xbd6d6bbb), C32e(0x7e912ac5), C32e(0x349ee54f), C32e(0x3ac116ed), - C32e(0x5417c586), C32e(0x622fd79a), C32e(0xffcc5566), C32e(0xa7229411), - C32e(0x4a0fcf8a), C32e(0x30c910e9), C32e(0x0a080604), C32e(0x98e781fe), - C32e(0x0b5bf0a0), C32e(0xccf04478), C32e(0xd54aba25), C32e(0x3e96e34b), - C32e(0x0e5ff3a2), C32e(0x19bafe5d), C32e(0x5b1bc080), C32e(0x850a8a05), - C32e(0xec7ead3f), C32e(0xdf42bc21), C32e(0xd8e04870), C32e(0x0cf904f1), - C32e(0x7ac6df63), C32e(0x58eec177), C32e(0x9f4575af), C32e(0xa5846342), - C32e(0x50403020), C32e(0x2ed11ae5), C32e(0x12e10efd), C32e(0xb7656dbf), - C32e(0xd4194c81), C32e(0x3c301418), C32e(0x5f4c3526), C32e(0x719d2fc3), - C32e(0x3867e1be), C32e(0xfd6aa235), C32e(0x4f0bcc88), C32e(0x4b5c392e), - C32e(0xf93d5793), C32e(0x0daaf255), C32e(0x9de382fc), C32e(0xc9f4477a), - C32e(0xef8bacc8), C32e(0x326fe7ba), C32e(0x7d642b32), C32e(0xa4d795e6), - C32e(0xfb9ba0c0), C32e(0xb3329819), C32e(0x6827d19e), C32e(0x815d7fa3), - C32e(0xaa886644), C32e(0x82a87e54), C32e(0xe676ab3b), C32e(0x9e16830b), - C32e(0x4503ca8c), C32e(0x7b9529c7), C32e(0x6ed6d36b), C32e(0x44503c28), - C32e(0x8b5579a7), C32e(0x3d63e2bc), C32e(0x272c1d16), C32e(0x9a4176ad), - C32e(0x4dad3bdb), C32e(0xfac85664), C32e(0xd2e84e74), C32e(0x22281e14), - C32e(0x763fdb92), C32e(0x1e180a0c), C32e(0xb4906c48), C32e(0x376be4b8), - C32e(0xe7255d9f), C32e(0xb2616ebd), C32e(0x2a86ef43), C32e(0xf193a6c4), - C32e(0xe372a839), C32e(0xf762a431), C32e(0x59bd37d3), C32e(0x86ff8bf2), - C32e(0x56b132d5), C32e(0xc50d438b), C32e(0xebdc596e), C32e(0xc2afb7da), - C32e(0x8f028c01), C32e(0xac7964b1), C32e(0x6d23d29c), C32e(0x3b92e049), - C32e(0xc7abb4d8), C32e(0x1543faac), C32e(0x09fd07f3), C32e(0x6f8525cf), - C32e(0xea8fafca), C32e(0x89f38ef4), C32e(0x208ee947), C32e(0x28201810), - C32e(0x64ded56f), C32e(0x83fb88f0), C32e(0xb1946f4a), C32e(0x96b8725c), - C32e(0x6c702438), C32e(0x08aef157), C32e(0x52e6c773), C32e(0xf3355197), - C32e(0x658d23cb), C32e(0x84597ca1), C32e(0xbfcb9ce8), C32e(0x637c213e), - C32e(0x7c37dd96), C32e(0x7fc2dc61), C32e(0x911a860d), C32e(0x941e850f), - C32e(0xabdb90e0), C32e(0xc6f8427c), C32e(0x57e2c471), C32e(0xe583aacc), - C32e(0x733bd890), C32e(0x0f0c0506), C32e(0x03f501f7), C32e(0x3638121c), - C32e(0xfe9fa3c2), C32e(0xe1d45f6a), C32e(0x1047f9ae), C32e(0x6bd2d069), - C32e(0xa82e9117), C32e(0xe8295899), C32e(0x6974273a), C32e(0xd04eb927), - C32e(0x48a938d9), C32e(0x35cd13eb), C32e(0xce56b32b), C32e(0x55443322), - C32e(0xd6bfbbd2), C32e(0x904970a9), C32e(0x800e8907), C32e(0xf266a733), - C32e(0xc15ab62d), C32e(0x6678223c), C32e(0xad2a9215), C32e(0x608920c9), - C32e(0xdb154987), C32e(0x1a4fffaa), C32e(0x88a07850), C32e(0x8e517aa5), - C32e(0x8a068f03), C32e(0x13b2f859), C32e(0x9b128009), C32e(0x3934171a), - C32e(0x75cada65), C32e(0x53b531d7), C32e(0x5113c684), C32e(0xd3bbb8d0), - C32e(0x5e1fc382), C32e(0xcb52b029), C32e(0x99b4775a), C32e(0x333c111e), - C32e(0x46f6cb7b), C32e(0x1f4bfca8), C32e(0x61dad66d), C32e(0x4e583a2c) -}; - -static const sph_u32 T1up[] = { - C32e(0xc6c632f4), C32e(0xf8f86f97), C32e(0xeeee5eb0), C32e(0xf6f67a8c), - C32e(0xffffe817), C32e(0xd6d60adc), C32e(0xdede16c8), C32e(0x91916dfc), - C32e(0x606090f0), C32e(0x02020705), C32e(0xcece2ee0), C32e(0x5656d187), - C32e(0xe7e7cc2b), C32e(0xb5b513a6), C32e(0x4d4d7c31), C32e(0xecec59b5), - C32e(0x8f8f40cf), C32e(0x1f1fa3bc), C32e(0x898949c0), C32e(0xfafa6892), - C32e(0xefefd03f), C32e(0xb2b29426), C32e(0x8e8ece40), C32e(0xfbfbe61d), - C32e(0x41416e2f), C32e(0xb3b31aa9), C32e(0x5f5f431c), C32e(0x45456025), - C32e(0x2323f9da), C32e(0x53535102), C32e(0xe4e445a1), C32e(0x9b9b76ed), - C32e(0x7575285d), C32e(0xe1e1c524), C32e(0x3d3dd4e9), C32e(0x4c4cf2be), - C32e(0x6c6c82ee), C32e(0x7e7ebdc3), C32e(0xf5f5f306), C32e(0x838352d1), - C32e(0x68688ce4), C32e(0x51515607), C32e(0xd1d18d5c), C32e(0xf9f9e118), - C32e(0xe2e24cae), C32e(0xabab3e95), C32e(0x626297f5), C32e(0x2a2a6b41), - C32e(0x08081c14), C32e(0x959563f6), C32e(0x4646e9af), C32e(0x9d9d7fe2), - C32e(0x30304878), C32e(0x3737cff8), C32e(0x0a0a1b11), C32e(0x2f2febc4), - C32e(0x0e0e151b), C32e(0x24247e5a), C32e(0x1b1badb6), C32e(0xdfdf9847), - C32e(0xcdcda76a), C32e(0x4e4ef5bb), C32e(0x7f7f334c), C32e(0xeaea50ba), - C32e(0x12123f2d), C32e(0x1d1da4b9), C32e(0x5858c49c), C32e(0x34344672), - C32e(0x36364177), C32e(0xdcdc11cd), C32e(0xb4b49d29), C32e(0x5b5b4d16), - C32e(0xa4a4a501), C32e(0x7676a1d7), C32e(0xb7b714a3), C32e(0x7d7d3449), - C32e(0x5252df8d), C32e(0xdddd9f42), C32e(0x5e5ecd93), C32e(0x1313b1a2), - C32e(0xa6a6a204), C32e(0xb9b901b8), C32e(0x00000000), C32e(0xc1c1b574), - C32e(0x4040e0a0), C32e(0xe3e3c221), C32e(0x79793a43), C32e(0xb6b69a2c), - C32e(0xd4d40dd9), C32e(0x8d8d47ca), C32e(0x67671770), C32e(0x7272afdd), - C32e(0x9494ed79), C32e(0x9898ff67), C32e(0xb0b09323), C32e(0x85855bde), - C32e(0xbbbb06bd), C32e(0xc5c5bb7e), C32e(0x4f4f7b34), C32e(0xededd73a), - C32e(0x8686d254), C32e(0x9a9af862), C32e(0x666699ff), C32e(0x1111b6a7), - C32e(0x8a8ac04a), C32e(0xe9e9d930), C32e(0x04040e0a), C32e(0xfefe6698), - C32e(0xa0a0ab0b), C32e(0x7878b4cc), C32e(0x2525f0d5), C32e(0x4b4b753e), - C32e(0xa2a2ac0e), C32e(0x5d5d4419), C32e(0x8080db5b), C32e(0x05058085), - C32e(0x3f3fd3ec), C32e(0x2121fedf), C32e(0x7070a8d8), C32e(0xf1f1fd0c), - C32e(0x6363197a), C32e(0x77772f58), C32e(0xafaf309f), C32e(0x4242e7a5), - C32e(0x20207050), C32e(0xe5e5cb2e), C32e(0xfdfdef12), C32e(0xbfbf08b7), - C32e(0x818155d4), C32e(0x1818243c), C32e(0x2626795f), C32e(0xc3c3b271), - C32e(0xbebe8638), C32e(0x3535c8fd), C32e(0x8888c74f), C32e(0x2e2e654b), - C32e(0x93936af9), C32e(0x5555580d), C32e(0xfcfc619d), C32e(0x7a7ab3c9), - C32e(0xc8c827ef), C32e(0xbaba8832), C32e(0x32324f7d), C32e(0xe6e642a4), - C32e(0xc0c03bfb), C32e(0x1919aab3), C32e(0x9e9ef668), C32e(0xa3a32281), - C32e(0x4444eeaa), C32e(0x5454d682), C32e(0x3b3bdde6), C32e(0x0b0b959e), - C32e(0x8c8cc945), C32e(0xc7c7bc7b), C32e(0x6b6b056e), C32e(0x28286c44), - C32e(0xa7a72c8b), C32e(0xbcbc813d), C32e(0x16163127), C32e(0xadad379a), - C32e(0xdbdb964d), C32e(0x64649efa), C32e(0x7474a6d2), C32e(0x14143622), - C32e(0x9292e476), C32e(0x0c0c121e), C32e(0x4848fcb4), C32e(0xb8b88f37), - C32e(0x9f9f78e7), C32e(0xbdbd0fb2), C32e(0x4343692a), C32e(0xc4c435f1), - C32e(0x3939dae3), C32e(0x3131c6f7), C32e(0xd3d38a59), C32e(0xf2f27486), - C32e(0xd5d58356), C32e(0x8b8b4ec5), C32e(0x6e6e85eb), C32e(0xdada18c2), - C32e(0x01018e8f), C32e(0xb1b11dac), C32e(0x9c9cf16d), C32e(0x4949723b), - C32e(0xd8d81fc7), C32e(0xacacb915), C32e(0xf3f3fa09), C32e(0xcfcfa06f), - C32e(0xcaca20ea), C32e(0xf4f47d89), C32e(0x47476720), C32e(0x10103828), - C32e(0x6f6f0b64), C32e(0xf0f07383), C32e(0x4a4afbb1), C32e(0x5c5cca96), - C32e(0x3838546c), C32e(0x57575f08), C32e(0x73732152), C32e(0x979764f3), - C32e(0xcbcbae65), C32e(0xa1a12584), C32e(0xe8e857bf), C32e(0x3e3e5d63), - C32e(0x9696ea7c), C32e(0x61611e7f), C32e(0x0d0d9c91), C32e(0x0f0f9b94), - C32e(0xe0e04bab), C32e(0x7c7cbac6), C32e(0x71712657), C32e(0xcccc29e5), - C32e(0x9090e373), C32e(0x0606090f), C32e(0xf7f7f403), C32e(0x1c1c2a36), - C32e(0xc2c23cfe), C32e(0x6a6a8be1), C32e(0xaeaebe10), C32e(0x6969026b), - C32e(0x1717bfa8), C32e(0x999971e8), C32e(0x3a3a5369), C32e(0x2727f7d0), - C32e(0xd9d99148), C32e(0xebebde35), C32e(0x2b2be5ce), C32e(0x22227755), - C32e(0xd2d204d6), C32e(0xa9a93990), C32e(0x07078780), C32e(0x3333c1f2), - C32e(0x2d2decc1), C32e(0x3c3c5a66), C32e(0x1515b8ad), C32e(0xc9c9a960), - C32e(0x87875cdb), C32e(0xaaaab01a), C32e(0x5050d888), C32e(0xa5a52b8e), - C32e(0x0303898a), C32e(0x59594a13), C32e(0x0909929b), C32e(0x1a1a2339), - C32e(0x65651075), C32e(0xd7d78453), C32e(0x8484d551), C32e(0xd0d003d3), - C32e(0x8282dc5e), C32e(0x2929e2cb), C32e(0x5a5ac399), C32e(0x1e1e2d33), - C32e(0x7b7b3d46), C32e(0xa8a8b71f), C32e(0x6d6d0c61), C32e(0x2c2c624e) -}; - -static const sph_u32 T1dn[] = { - C32e(0xa5f497a5), C32e(0x8497eb84), C32e(0x99b0c799), C32e(0x8d8cf78d), - C32e(0x0d17e50d), C32e(0xbddcb7bd), C32e(0xb1c8a7b1), C32e(0x54fc3954), - C32e(0x50f0c050), C32e(0x03050403), C32e(0xa9e087a9), C32e(0x7d87ac7d), - C32e(0x192bd519), C32e(0x62a67162), C32e(0xe6319ae6), C32e(0x9ab5c39a), - C32e(0x45cf0545), C32e(0x9dbc3e9d), C32e(0x40c00940), C32e(0x8792ef87), - C32e(0x153fc515), C32e(0xeb267feb), C32e(0xc94007c9), C32e(0x0b1ded0b), - C32e(0xec2f82ec), C32e(0x67a97d67), C32e(0xfd1cbefd), C32e(0xea258aea), - C32e(0xbfda46bf), C32e(0xf702a6f7), C32e(0x96a1d396), C32e(0x5bed2d5b), - C32e(0xc25deac2), C32e(0x1c24d91c), C32e(0xaee97aae), C32e(0x6abe986a), - C32e(0x5aeed85a), C32e(0x41c3fc41), C32e(0x0206f102), C32e(0x4fd11d4f), - C32e(0x5ce4d05c), C32e(0xf407a2f4), C32e(0x345cb934), C32e(0x0818e908), - C32e(0x93aedf93), C32e(0x73954d73), C32e(0x53f5c453), C32e(0x3f41543f), - C32e(0x0c14100c), C32e(0x52f63152), C32e(0x65af8c65), C32e(0x5ee2215e), - C32e(0x28786028), C32e(0xa1f86ea1), C32e(0x0f11140f), C32e(0xb5c45eb5), - C32e(0x091b1c09), C32e(0x365a4836), C32e(0x9bb6369b), C32e(0x3d47a53d), - C32e(0x266a8126), C32e(0x69bb9c69), C32e(0xcd4cfecd), C32e(0x9fbacf9f), - C32e(0x1b2d241b), C32e(0x9eb93a9e), C32e(0x749cb074), C32e(0x2e72682e), - C32e(0x2d776c2d), C32e(0xb2cda3b2), C32e(0xee2973ee), C32e(0xfb16b6fb), - C32e(0xf60153f6), C32e(0x4dd7ec4d), C32e(0x61a37561), C32e(0xce49face), - C32e(0x7b8da47b), C32e(0x3e42a13e), C32e(0x7193bc71), C32e(0x97a22697), - C32e(0xf50457f5), C32e(0x68b86968), C32e(0x00000000), C32e(0x2c74992c), - C32e(0x60a08060), C32e(0x1f21dd1f), C32e(0xc843f2c8), C32e(0xed2c77ed), - C32e(0xbed9b3be), C32e(0x46ca0146), C32e(0xd970ced9), C32e(0x4bdde44b), - C32e(0xde7933de), C32e(0xd4672bd4), C32e(0xe8237be8), C32e(0x4ade114a), - C32e(0x6bbd6d6b), C32e(0x2a7e912a), C32e(0xe5349ee5), C32e(0x163ac116), - C32e(0xc55417c5), C32e(0xd7622fd7), C32e(0x55ffcc55), C32e(0x94a72294), - C32e(0xcf4a0fcf), C32e(0x1030c910), C32e(0x060a0806), C32e(0x8198e781), - C32e(0xf00b5bf0), C32e(0x44ccf044), C32e(0xbad54aba), C32e(0xe33e96e3), - C32e(0xf30e5ff3), C32e(0xfe19bafe), C32e(0xc05b1bc0), C32e(0x8a850a8a), - C32e(0xadec7ead), C32e(0xbcdf42bc), C32e(0x48d8e048), C32e(0x040cf904), - C32e(0xdf7ac6df), C32e(0xc158eec1), C32e(0x759f4575), C32e(0x63a58463), - C32e(0x30504030), C32e(0x1a2ed11a), C32e(0x0e12e10e), C32e(0x6db7656d), - C32e(0x4cd4194c), C32e(0x143c3014), C32e(0x355f4c35), C32e(0x2f719d2f), - C32e(0xe13867e1), C32e(0xa2fd6aa2), C32e(0xcc4f0bcc), C32e(0x394b5c39), - C32e(0x57f93d57), C32e(0xf20daaf2), C32e(0x829de382), C32e(0x47c9f447), - C32e(0xacef8bac), C32e(0xe7326fe7), C32e(0x2b7d642b), C32e(0x95a4d795), - C32e(0xa0fb9ba0), C32e(0x98b33298), C32e(0xd16827d1), C32e(0x7f815d7f), - C32e(0x66aa8866), C32e(0x7e82a87e), C32e(0xabe676ab), C32e(0x839e1683), - C32e(0xca4503ca), C32e(0x297b9529), C32e(0xd36ed6d3), C32e(0x3c44503c), - C32e(0x798b5579), C32e(0xe23d63e2), C32e(0x1d272c1d), C32e(0x769a4176), - C32e(0x3b4dad3b), C32e(0x56fac856), C32e(0x4ed2e84e), C32e(0x1e22281e), - C32e(0xdb763fdb), C32e(0x0a1e180a), C32e(0x6cb4906c), C32e(0xe4376be4), - C32e(0x5de7255d), C32e(0x6eb2616e), C32e(0xef2a86ef), C32e(0xa6f193a6), - C32e(0xa8e372a8), C32e(0xa4f762a4), C32e(0x3759bd37), C32e(0x8b86ff8b), - C32e(0x3256b132), C32e(0x43c50d43), C32e(0x59ebdc59), C32e(0xb7c2afb7), - C32e(0x8c8f028c), C32e(0x64ac7964), C32e(0xd26d23d2), C32e(0xe03b92e0), - C32e(0xb4c7abb4), C32e(0xfa1543fa), C32e(0x0709fd07), C32e(0x256f8525), - C32e(0xafea8faf), C32e(0x8e89f38e), C32e(0xe9208ee9), C32e(0x18282018), - C32e(0xd564ded5), C32e(0x8883fb88), C32e(0x6fb1946f), C32e(0x7296b872), - C32e(0x246c7024), C32e(0xf108aef1), C32e(0xc752e6c7), C32e(0x51f33551), - C32e(0x23658d23), C32e(0x7c84597c), C32e(0x9cbfcb9c), C32e(0x21637c21), - C32e(0xdd7c37dd), C32e(0xdc7fc2dc), C32e(0x86911a86), C32e(0x85941e85), - C32e(0x90abdb90), C32e(0x42c6f842), C32e(0xc457e2c4), C32e(0xaae583aa), - C32e(0xd8733bd8), C32e(0x050f0c05), C32e(0x0103f501), C32e(0x12363812), - C32e(0xa3fe9fa3), C32e(0x5fe1d45f), C32e(0xf91047f9), C32e(0xd06bd2d0), - C32e(0x91a82e91), C32e(0x58e82958), C32e(0x27697427), C32e(0xb9d04eb9), - C32e(0x3848a938), C32e(0x1335cd13), C32e(0xb3ce56b3), C32e(0x33554433), - C32e(0xbbd6bfbb), C32e(0x70904970), C32e(0x89800e89), C32e(0xa7f266a7), - C32e(0xb6c15ab6), C32e(0x22667822), C32e(0x92ad2a92), C32e(0x20608920), - C32e(0x49db1549), C32e(0xff1a4fff), C32e(0x7888a078), C32e(0x7a8e517a), - C32e(0x8f8a068f), C32e(0xf813b2f8), C32e(0x809b1280), C32e(0x17393417), - C32e(0xda75cada), C32e(0x3153b531), C32e(0xc65113c6), C32e(0xb8d3bbb8), - C32e(0xc35e1fc3), C32e(0xb0cb52b0), C32e(0x7799b477), C32e(0x11333c11), - C32e(0xcb46f6cb), C32e(0xfc1f4bfc), C32e(0xd661dad6), C32e(0x3a4e583a) -}; - -#define DECL_STATE_SMALL \ - sph_u32 H[16] = {0}; - -#define READ_STATE_SMALL(sc) do { \ - memcpy(H, (sc)->state.narrow, sizeof H); \ - } while (0) - -#define WRITE_STATE_SMALL(sc) do { \ - memcpy((sc)->state.narrow, H, sizeof H); \ - } while (0) - -#define XCAT(x, y) XCAT_(x, y) -#define XCAT_(x, y) x ## y - -#define RSTT(d0, d1, a, b0, b1, b2, b3, b4, b5, b6, b7) do { \ - t[d0] = T0up[B32_0(a[b0])] \ - ^ T1up[B32_1(a[b1])] \ - ^ T2up[B32_2(a[b2])] \ - ^ T3up[B32_3(a[b3])] \ - ^ T0dn[B32_0(a[b4])] \ - ^ T1dn[B32_1(a[b5])] \ - ^ T2dn[B32_2(a[b6])] \ - ^ T3dn[B32_3(a[b7])]; \ - t[d1] = T0dn[B32_0(a[b0])] \ - ^ T1dn[B32_1(a[b1])] \ - ^ T2dn[B32_2(a[b2])] \ - ^ T3dn[B32_3(a[b3])] \ - ^ T0up[B32_0(a[b4])] \ - ^ T1up[B32_1(a[b5])] \ - ^ T2up[B32_2(a[b6])] \ - ^ T3up[B32_3(a[b7])]; \ - } while (0) - -#define ROUND_SMALL_P(a, r) do { \ - sph_u32 t[16]; \ - a[0x0] ^= PC32up(0x00, r); \ - a[0x1] ^= PC32dn(0x00, r); \ - a[0x2] ^= PC32up(0x10, r); \ - a[0x3] ^= PC32dn(0x10, r); \ - a[0x4] ^= PC32up(0x20, r); \ - a[0x5] ^= PC32dn(0x20, r); \ - a[0x6] ^= PC32up(0x30, r); \ - a[0x7] ^= PC32dn(0x30, r); \ - a[0x8] ^= PC32up(0x40, r); \ - a[0x9] ^= PC32dn(0x40, r); \ - a[0xA] ^= PC32up(0x50, r); \ - a[0xB] ^= PC32dn(0x50, r); \ - a[0xC] ^= PC32up(0x60, r); \ - a[0xD] ^= PC32dn(0x60, r); \ - a[0xE] ^= PC32up(0x70, r); \ - a[0xF] ^= PC32dn(0x70, r); \ - RSTT(0x0, 0x1, a, 0x0, 0x2, 0x4, 0x6, 0x9, 0xB, 0xD, 0xF); \ - RSTT(0x2, 0x3, a, 0x2, 0x4, 0x6, 0x8, 0xB, 0xD, 0xF, 0x1); \ - RSTT(0x4, 0x5, a, 0x4, 0x6, 0x8, 0xA, 0xD, 0xF, 0x1, 0x3); \ - RSTT(0x6, 0x7, a, 0x6, 0x8, 0xA, 0xC, 0xF, 0x1, 0x3, 0x5); \ - RSTT(0x8, 0x9, a, 0x8, 0xA, 0xC, 0xE, 0x1, 0x3, 0x5, 0x7); \ - RSTT(0xA, 0xB, a, 0xA, 0xC, 0xE, 0x0, 0x3, 0x5, 0x7, 0x9); \ - RSTT(0xC, 0xD, a, 0xC, 0xE, 0x0, 0x2, 0x5, 0x7, 0x9, 0xB); \ - RSTT(0xE, 0xF, a, 0xE, 0x0, 0x2, 0x4, 0x7, 0x9, 0xB, 0xD); \ - memcpy(a, t, sizeof t); \ - } while (0) - -#define ROUND_SMALL_Q(a, r) do { \ - sph_u32 t[16]; \ - a[0x0] ^= QC32up(0x00, r); \ - a[0x1] ^= QC32dn(0x00, r); \ - a[0x2] ^= QC32up(0x10, r); \ - a[0x3] ^= QC32dn(0x10, r); \ - a[0x4] ^= QC32up(0x20, r); \ - a[0x5] ^= QC32dn(0x20, r); \ - a[0x6] ^= QC32up(0x30, r); \ - a[0x7] ^= QC32dn(0x30, r); \ - a[0x8] ^= QC32up(0x40, r); \ - a[0x9] ^= QC32dn(0x40, r); \ - a[0xA] ^= QC32up(0x50, r); \ - a[0xB] ^= QC32dn(0x50, r); \ - a[0xC] ^= QC32up(0x60, r); \ - a[0xD] ^= QC32dn(0x60, r); \ - a[0xE] ^= QC32up(0x70, r); \ - a[0xF] ^= QC32dn(0x70, r); \ - RSTT(0x0, 0x1, a, 0x2, 0x6, 0xA, 0xE, 0x1, 0x5, 0x9, 0xD); \ - RSTT(0x2, 0x3, a, 0x4, 0x8, 0xC, 0x0, 0x3, 0x7, 0xB, 0xF); \ - RSTT(0x4, 0x5, a, 0x6, 0xA, 0xE, 0x2, 0x5, 0x9, 0xD, 0x1); \ - RSTT(0x6, 0x7, a, 0x8, 0xC, 0x0, 0x4, 0x7, 0xB, 0xF, 0x3); \ - RSTT(0x8, 0x9, a, 0xA, 0xE, 0x2, 0x6, 0x9, 0xD, 0x1, 0x5); \ - RSTT(0xA, 0xB, a, 0xC, 0x0, 0x4, 0x8, 0xB, 0xF, 0x3, 0x7); \ - RSTT(0xC, 0xD, a, 0xE, 0x2, 0x6, 0xA, 0xD, 0x1, 0x5, 0x9); \ - RSTT(0xE, 0xF, a, 0x0, 0x4, 0x8, 0xC, 0xF, 0x3, 0x7, 0xB); \ - memcpy(a, t, sizeof t); \ - } while (0) - -#define PERM_SMALL_P(a) do { \ - int r; \ - for (r = 0; r < 10; r ++) \ - ROUND_SMALL_P(a, r); \ - } while (0) - -#define PERM_SMALL_Q(a) do { \ - int r; \ - for (r = 0; r < 10; r ++) \ - ROUND_SMALL_Q(a, r); \ - } while (0) - - -#define COMPRESS_SMALL do { \ - sph_u32 g[16], m[16]; \ - size_t u; \ - for (u = 0; u < 16; u ++) { \ - m[u] = dec32e_aligned(buf + (u << 2)); \ - g[u] = m[u] ^ H[u]; \ - } \ - PERM_SMALL_P(g); \ - PERM_SMALL_Q(m); \ - for (u = 0; u < 16; u ++) \ - H[u] ^= g[u] ^ m[u]; \ - } while (0) - -#define FINAL_SMALL do { \ - sph_u32 x[16]; \ - size_t u; \ - memcpy(x, H, sizeof x); \ - PERM_SMALL_P(x); \ - for (u = 0; u < 16; u ++) \ - H[u] ^= x[u]; \ - } while (0) - -#define DECL_STATE_BIG \ - sph_u32 H[32] = {0}; - -#define READ_STATE_BIG(sc) do { \ - memcpy(H, (sc)->state.narrow, sizeof H); \ - } while (0) - -#define WRITE_STATE_BIG(sc) do { \ - memcpy((sc)->state.narrow, H, sizeof H); \ - } while (0) - - -#define RBTT(d0, d1, a, b0, b1, b2, b3, b4, b5, b6, b7) do { \ - sph_u32 fu2 = T0up[B32_2(a[b2])]; \ - sph_u32 fd2 = T0dn[B32_2(a[b2])]; \ - sph_u32 fu3 = T1up[B32_3(a[b3])]; \ - sph_u32 fd3 = T1dn[B32_3(a[b3])]; \ - sph_u32 fu6 = T0up[B32_2(a[b6])]; \ - sph_u32 fd6 = T0dn[B32_2(a[b6])]; \ - sph_u32 fu7 = T1up[B32_3(a[b7])]; \ - sph_u32 fd7 = T1dn[B32_3(a[b7])]; \ - t[d0] = T0up[B32_0(a[b0])] \ - ^ T1up[B32_1(a[b1])] \ - ^ R32u(fu2, fd2) \ - ^ R32u(fu3, fd3) \ - ^ T0dn[B32_0(a[b4])] \ - ^ T1dn[B32_1(a[b5])] \ - ^ R32d(fu6, fd6) \ - ^ R32d(fu7, fd7); \ - t[d1] = T0dn[B32_0(a[b0])] \ - ^ T1dn[B32_1(a[b1])] \ - ^ R32d(fu2, fd2) \ - ^ R32d(fu3, fd3) \ - ^ T0up[B32_0(a[b4])] \ - ^ T1up[B32_1(a[b5])] \ - ^ R32u(fu6, fd6) \ - ^ R32u(fu7, fd7); \ - } while (0) - - -#define ROUND_BIG_P(a, r) do { \ - sph_u32 t[32]; \ - size_t u; \ - a[0x00] ^= PC32up(0x00, r); \ - a[0x01] ^= PC32dn(0x00, r); \ - a[0x02] ^= PC32up(0x10, r); \ - a[0x03] ^= PC32dn(0x10, r); \ - a[0x04] ^= PC32up(0x20, r); \ - a[0x05] ^= PC32dn(0x20, r); \ - a[0x06] ^= PC32up(0x30, r); \ - a[0x07] ^= PC32dn(0x30, r); \ - a[0x08] ^= PC32up(0x40, r); \ - a[0x09] ^= PC32dn(0x40, r); \ - a[0x0A] ^= PC32up(0x50, r); \ - a[0x0B] ^= PC32dn(0x50, r); \ - a[0x0C] ^= PC32up(0x60, r); \ - a[0x0D] ^= PC32dn(0x60, r); \ - a[0x0E] ^= PC32up(0x70, r); \ - a[0x0F] ^= PC32dn(0x70, r); \ - a[0x10] ^= PC32up(0x80, r); \ - a[0x11] ^= PC32dn(0x80, r); \ - a[0x12] ^= PC32up(0x90, r); \ - a[0x13] ^= PC32dn(0x90, r); \ - a[0x14] ^= PC32up(0xA0, r); \ - a[0x15] ^= PC32dn(0xA0, r); \ - a[0x16] ^= PC32up(0xB0, r); \ - a[0x17] ^= PC32dn(0xB0, r); \ - a[0x18] ^= PC32up(0xC0, r); \ - a[0x19] ^= PC32dn(0xC0, r); \ - a[0x1A] ^= PC32up(0xD0, r); \ - a[0x1B] ^= PC32dn(0xD0, r); \ - a[0x1C] ^= PC32up(0xE0, r); \ - a[0x1D] ^= PC32dn(0xE0, r); \ - a[0x1E] ^= PC32up(0xF0, r); \ - a[0x1F] ^= PC32dn(0xF0, r); \ - for (u = 0; u < 32; u += 8) { \ - RBTT(u + 0x00, (u + 0x01) & 0x1F, a, \ - u + 0x00, (u + 0x02) & 0x1F, \ - (u + 0x04) & 0x1F, (u + 0x06) & 0x1F, \ - (u + 0x09) & 0x1F, (u + 0x0B) & 0x1F, \ - (u + 0x0D) & 0x1F, (u + 0x17) & 0x1F); \ - RBTT(u + 0x02, (u + 0x03) & 0x1F, a, \ - u + 0x02, (u + 0x04) & 0x1F, \ - (u + 0x06) & 0x1F, (u + 0x08) & 0x1F, \ - (u + 0x0B) & 0x1F, (u + 0x0D) & 0x1F, \ - (u + 0x0F) & 0x1F, (u + 0x19) & 0x1F); \ - RBTT(u + 0x04, (u + 0x05) & 0x1F, a, \ - u + 0x04, (u + 0x06) & 0x1F, \ - (u + 0x08) & 0x1F, (u + 0x0A) & 0x1F, \ - (u + 0x0D) & 0x1F, (u + 0x0F) & 0x1F, \ - (u + 0x11) & 0x1F, (u + 0x1B) & 0x1F); \ - RBTT(u + 0x06, (u + 0x07) & 0x1F, a, \ - u + 0x06, (u + 0x08) & 0x1F, \ - (u + 0x0A) & 0x1F, (u + 0x0C) & 0x1F, \ - (u + 0x0F) & 0x1F, (u + 0x11) & 0x1F, \ - (u + 0x13) & 0x1F, (u + 0x1D) & 0x1F); \ - } \ - memcpy(a, t, sizeof t); \ - } while (0) - -#define ROUND_BIG_Q(a, r) do { \ - sph_u32 t[32]; \ - size_t u; \ - a[0x00] ^= QC32up(0x00, r); \ - a[0x01] ^= QC32dn(0x00, r); \ - a[0x02] ^= QC32up(0x10, r); \ - a[0x03] ^= QC32dn(0x10, r); \ - a[0x04] ^= QC32up(0x20, r); \ - a[0x05] ^= QC32dn(0x20, r); \ - a[0x06] ^= QC32up(0x30, r); \ - a[0x07] ^= QC32dn(0x30, r); \ - a[0x08] ^= QC32up(0x40, r); \ - a[0x09] ^= QC32dn(0x40, r); \ - a[0x0A] ^= QC32up(0x50, r); \ - a[0x0B] ^= QC32dn(0x50, r); \ - a[0x0C] ^= QC32up(0x60, r); \ - a[0x0D] ^= QC32dn(0x60, r); \ - a[0x0E] ^= QC32up(0x70, r); \ - a[0x0F] ^= QC32dn(0x70, r); \ - a[0x10] ^= QC32up(0x80, r); \ - a[0x11] ^= QC32dn(0x80, r); \ - a[0x12] ^= QC32up(0x90, r); \ - a[0x13] ^= QC32dn(0x90, r); \ - a[0x14] ^= QC32up(0xA0, r); \ - a[0x15] ^= QC32dn(0xA0, r); \ - a[0x16] ^= QC32up(0xB0, r); \ - a[0x17] ^= QC32dn(0xB0, r); \ - a[0x18] ^= QC32up(0xC0, r); \ - a[0x19] ^= QC32dn(0xC0, r); \ - a[0x1A] ^= QC32up(0xD0, r); \ - a[0x1B] ^= QC32dn(0xD0, r); \ - a[0x1C] ^= QC32up(0xE0, r); \ - a[0x1D] ^= QC32dn(0xE0, r); \ - a[0x1E] ^= QC32up(0xF0, r); \ - a[0x1F] ^= QC32dn(0xF0, r); \ - for (u = 0; u < 32; u += 8) { \ - RBTT(u + 0x00, (u + 0x01) & 0x1F, a, \ - (u + 0x02) & 0x1F, (u + 0x06) & 0x1F, \ - (u + 0x0A) & 0x1F, (u + 0x16) & 0x1F, \ - (u + 0x01) & 0x1F, (u + 0x05) & 0x1F, \ - (u + 0x09) & 0x1F, (u + 0x0D) & 0x1F); \ - RBTT(u + 0x02, (u + 0x03) & 0x1F, a, \ - (u + 0x04) & 0x1F, (u + 0x08) & 0x1F, \ - (u + 0x0C) & 0x1F, (u + 0x18) & 0x1F, \ - (u + 0x03) & 0x1F, (u + 0x07) & 0x1F, \ - (u + 0x0B) & 0x1F, (u + 0x0F) & 0x1F); \ - RBTT(u + 0x04, (u + 0x05) & 0x1F, a, \ - (u + 0x06) & 0x1F, (u + 0x0A) & 0x1F, \ - (u + 0x0E) & 0x1F, (u + 0x1A) & 0x1F, \ - (u + 0x05) & 0x1F, (u + 0x09) & 0x1F, \ - (u + 0x0D) & 0x1F, (u + 0x11) & 0x1F); \ - RBTT(u + 0x06, (u + 0x07) & 0x1F, a, \ - (u + 0x08) & 0x1F, (u + 0x0C) & 0x1F, \ - (u + 0x10) & 0x1F, (u + 0x1C) & 0x1F, \ - (u + 0x07) & 0x1F, (u + 0x0B) & 0x1F, \ - (u + 0x0F) & 0x1F, (u + 0x13) & 0x1F); \ - } \ - memcpy(a, t, sizeof t); \ - } while (0) - - -#define PERM_BIG_P(a) do { \ - int r; \ - for (r = 0; r < 14; r ++) \ - ROUND_BIG_P(a, r); \ - } while (0) - -#define PERM_BIG_Q(a) do { \ - int r; \ - for (r = 0; r < 14; r ++) \ - ROUND_BIG_Q(a, r); \ - } while (0) - - -#define COMPRESS_BIG do { \ - sph_u32 g[32], m[32]; \ - size_t uu; \ - for (uu = 0; uu < 32; uu ++) { \ - m[uu] = dec32e_aligned(buf + (uu << 2)); \ - g[uu] = m[uu] ^ H[uu]; \ - } \ - PERM_BIG_P(g); \ - PERM_BIG_Q(m); \ - for (uu = 0; uu < 32; uu ++) \ - H[uu] ^= g[uu] ^ m[uu]; \ - } while (0) - -#define FINAL_BIG do { \ - sph_u32 x[32]; \ - size_t uu; \ - memcpy(x, H, sizeof x); \ - PERM_BIG_P(x); \ - for (uu = 0; uu < 32; uu ++) \ - H[uu] ^= x[uu]; \ - } while (0) - - -static void -groestl_big_init(sph_groestl_big_context *sc, unsigned out_size) -{ - size_t u = 0; - - sc->ptr = 0; - for (u = 0; u < 31; u ++) - sc->state.narrow[u] = 0; - sc->state.narrow[31] = ((sph_u32)(out_size & 0xFF) << 24) - | ((sph_u32)(out_size & 0xFF00) << 8); - sc->count = 0; -} - -static void -groestl_big_core(sph_groestl_big_context *sc, const void *data, size_t len) -{ - if (len == 0) { - return; - } - - unsigned char *buf = NULL; - size_t ptr = 0; - DECL_STATE_BIG - - buf = sc->buf; - ptr = sc->ptr; - if (len < (sizeof sc->buf) - ptr) { - memcpy(buf + ptr, data, len); - ptr += len; - sc->ptr = ptr; - return; - } - - READ_STATE_BIG(sc); - while (len > 0) { - size_t clen = 0; - - clen = (sizeof sc->buf) - ptr; - if (clen > len) - clen = len; - memcpy(buf + ptr, data, clen); - ptr += clen; - data = (const unsigned char *)data + clen; - len -= clen; - if (ptr == sizeof sc->buf) { - COMPRESS_BIG; - sc->count ++; - ptr = 0; - } - } - WRITE_STATE_BIG(sc); - sc->ptr = ptr; -} - -static void -groestl_big_close(sph_groestl_big_context *sc, - unsigned ub, unsigned n, void *dst, size_t out_len) -{ - unsigned char pad[136] = {0}; - size_t ptr = 0, pad_len = 0, u2 = 0; - sph_u64 count = 0; - unsigned z = 0; - DECL_STATE_BIG - - ptr = sc->ptr; - z = 0x80 >> n; - pad[0] = ((ub & -z) | z) & 0xFF; - if (ptr < 120) { - pad_len = 128 - ptr; - count = SPH_T64(sc->count + 1); - } else { - pad_len = 256 - ptr; - count = SPH_T64(sc->count + 2); - } - memzero(pad + 1, pad_len - 9); - sph_enc64be(pad + pad_len - 8, count); - groestl_big_core(sc, pad, pad_len); - READ_STATE_BIG(sc); - FINAL_BIG; - for (u2 = 0; u2 < 16; u2 ++) - enc32e(pad + (u2 << 2), H[u2 + 16]); - memcpy(dst, pad + 64 - out_len, out_len); - groestl_big_init(sc, (unsigned)out_len << 3); -} - -void -groestl512_Init(void *cc) -{ - groestl_big_init((sph_groestl_big_context *)cc, 512); -} - -void -groestl512_Update(void *cc, const void *data, size_t len) -{ - groestl_big_core((sph_groestl_big_context *)cc, data, len); -} - -void -groestl512_Final(void *cc, void *dst) -{ - groestl_big_close((sph_groestl_big_context *)cc, 0, 0, dst, 64); -} - -void -groestl512_DoubleTrunc(void *cc, void *dst) -{ - char buf[64] = {0}; - - groestl512_Final(cc, buf); - groestl512_Update(cc, buf, sizeof(buf)); - groestl512_Final(cc, buf); - memcpy(dst, buf, 32); -} diff --git a/deps/crypto/trezor-crypto/groestl.h b/deps/crypto/trezor-crypto/groestl.h deleted file mode 100644 index 7dd89d28a..000000000 --- a/deps/crypto/trezor-crypto/groestl.h +++ /dev/null @@ -1,95 +0,0 @@ -/* Groestl hash from https://github.com/Groestlcoin/vanitygen - * Trezor adaptation by Yura Pakhuchiy . */ -/** - * Groestl interface. This code implements Groestl with the recommended - * parameters for SHA-3, with outputs of 224, 256, 384 and 512 bits. - * - * ==========================(LICENSE BEGIN)============================ - * - * Copyright (c) 2007-2010 Projet RNRT SAPHIR - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * ===========================(LICENSE END)============================= - * - * @file sph_groestl.h - * @author Thomas Pornin - */ - -#ifndef GROESTL_H__ -#define GROESTL_H__ - -#include - -/** - * This structure is a context for Groestl-384 and Groestl-512 computations: - * it contains the intermediate values and some data from the last - * entered block. Once a Groestl computation has been performed, the - * context can be reused for another computation. - * - * The contents of this structure are private. A running Groestl - * computation can be cloned by copying the context (e.g. with a simple - * memcpy()). - */ -typedef struct { - unsigned char buf[128]; /* first field, for alignment */ - size_t ptr; - union { - uint64_t wide[16]; - uint32_t narrow[32]; - } state; - uint64_t count; -} sph_groestl_big_context; - -typedef sph_groestl_big_context GROESTL512_CTX; - -/** - * Initialize a Groestl-512 context. This process performs no memory allocation. - * - * @param cc the Groestl-512 context (pointer to a - * GROESTL512_CTX) - */ -void groestl512_Init(void *cc); - -/** - * Process some data bytes. It is acceptable that len is zero - * (in which case this function does nothing). - * - * @param cc the Groestl-512 context - * @param data the input data - * @param len the input data length (in bytes) - */ -void groestl512_Update(void *cc, const void *data, size_t len); - -/** - * Terminate the current Groestl-512 computation and output the result into - * the provided buffer. The destination buffer must be wide enough to - * accomodate the result (64 bytes). The context is automatically - * reinitialized. - * - * @param cc the Groestl-512 context - * @param dst the destination buffer - */ -void groestl512_Final(void *cc, void *dst); - -/* Calculate double Groestl-512 hash and truncate it to 256-bits. */ -void groestl512_DoubleTrunc(void *cc, void *dst); - -#endif diff --git a/deps/crypto/trezor-crypto/groestl_internal.h b/deps/crypto/trezor-crypto/groestl_internal.h deleted file mode 100644 index 3c675d8ea..000000000 --- a/deps/crypto/trezor-crypto/groestl_internal.h +++ /dev/null @@ -1,509 +0,0 @@ -/* Groestl hash from https://github.com/Groestlcoin/vanitygen - * Trezor adaptation by Yura Pakhuchiy . */ -/** - * Basic type definitions. - * - * This header file defines the generic integer types that will be used - * for the implementation of hash functions; it also contains helper - * functions which encode and decode multi-byte integer values, using - * either little-endian or big-endian conventions. - * - * This file contains a compile-time test on the size of a byte - * (the unsigned char C type). If bytes are not octets, - * i.e. if they do not have a size of exactly 8 bits, then compilation - * is aborted. Architectures where bytes are not octets are relatively - * rare, even in the embedded devices market. We forbid non-octet bytes - * because there is no clear convention on how octet streams are encoded - * on such systems. - * - * ==========================(LICENSE BEGIN)============================ - * - * Copyright (c) 2007-2010 Projet RNRT SAPHIR - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * ===========================(LICENSE END)============================= - * - * @file sph_types.h - * @author Thomas Pornin - */ - -#ifndef GROESTL_INTERNAL_H__ -#define GROESTL_INTERNAL_H__ - -#include - -/* - * All our I/O functions are defined over octet streams. We do not know - * how to handle input data if bytes are not octets. - */ -#if CHAR_BIT != 8 -#error This code requires 8-bit bytes -#endif - -#if defined __STDC__ && __STDC_VERSION__ >= 199901L - -#include - -typedef uint32_t sph_u32; -typedef int32_t sph_s32; -typedef uint64_t sph_u64; -typedef int64_t sph_s64; - -#define SPH_C32(x) ((sph_u32)(x)) -#define SPH_C64(x) ((sph_u64)(x)) - -#else -#error We need at least C99 compiler -#endif - -#define SPH_T32(x) ((x) & SPH_C32(0xFFFFFFFF)) -#define SPH_ROTL32(x, n) SPH_T32(((x) << (n)) | ((x) >> (32 - (n)))) -#define SPH_ROTR32(x, n) SPH_ROTL32(x, (32 - (n))) - -#define SPH_T64(x) ((x) & SPH_C64(0xFFFFFFFFFFFFFFFF)) -#define SPH_ROTL64(x, n) SPH_T64(((x) << (n)) | ((x) >> (64 - (n)))) -#define SPH_ROTR64(x, n) SPH_ROTL64(x, (64 - (n))) - -/* - * 32-bit x86, aka "i386 compatible". - */ -#if defined __i386__ || defined _M_IX86 - -#define SPH_DETECT_LITTLE_ENDIAN 1 -#define SPH_DETECT_BIG_ENDIAN 0 - -/* - * 64-bit x86, hereafter known as "amd64". - */ -#elif defined __x86_64 || defined _M_X64 - -#define SPH_DETECT_LITTLE_ENDIAN 1 -#define SPH_DETECT_BIG_ENDIAN 0 - -/* - * ARM, little-endian. - */ -#elif defined __arm__ && __ARMEL__ - -#define SPH_DETECT_LITTLE_ENDIAN 1 -#define SPH_DETECT_BIG_ENDIAN 0 - -/* - * ARM64, little-endian. - */ -#elif defined __aarch64__ - -#define SPH_DETECT_LITTLE_ENDIAN 1 -#define SPH_DETECT_BIG_ENDIAN 0 - -#endif - - -#if defined SPH_DETECT_LITTLE_ENDIAN && !defined SPH_LITTLE_ENDIAN -#define SPH_LITTLE_ENDIAN SPH_DETECT_LITTLE_ENDIAN -#endif -#if defined SPH_DETECT_BIG_ENDIAN && !defined SPH_BIG_ENDIAN -#define SPH_BIG_ENDIAN SPH_DETECT_BIG_ENDIAN -#endif - -static inline sph_u32 -sph_bswap32(sph_u32 x) -{ - x = SPH_T32((x << 16) | (x >> 16)); - x = ((x & SPH_C32(0xFF00FF00)) >> 8) - | ((x & SPH_C32(0x00FF00FF)) << 8); - return x; -} - -/** - * Byte-swap a 64-bit value. - * - * @param x the input value - * @return the byte-swapped value - */ -static inline sph_u64 -sph_bswap64(sph_u64 x) -{ - x = SPH_T64((x << 32) | (x >> 32)); - x = ((x & SPH_C64(0xFFFF0000FFFF0000)) >> 16) - | ((x & SPH_C64(0x0000FFFF0000FFFF)) << 16); - x = ((x & SPH_C64(0xFF00FF00FF00FF00)) >> 8) - | ((x & SPH_C64(0x00FF00FF00FF00FF)) << 8); - return x; -} - -static inline void -sph_enc16be(void *dst, unsigned val) -{ - ((unsigned char *)dst)[0] = (val >> 8); - ((unsigned char *)dst)[1] = val; -} - -static inline unsigned -sph_dec16be(const void *src) -{ - return ((unsigned)(((const unsigned char *)src)[0]) << 8) - | (unsigned)(((const unsigned char *)src)[1]); -} - -static inline void -sph_enc16le(void *dst, unsigned val) -{ - ((unsigned char *)dst)[0] = val; - ((unsigned char *)dst)[1] = val >> 8; -} - -static inline unsigned -sph_dec16le(const void *src) -{ - return (unsigned)(((const unsigned char *)src)[0]) - | ((unsigned)(((const unsigned char *)src)[1]) << 8); -} - -/** - * Encode a 32-bit value into the provided buffer (big endian convention). - * - * @param dst the destination buffer - * @param val the 32-bit value to encode - */ -static inline void -sph_enc32be(void *dst, sph_u32 val) -{ - ((unsigned char *)dst)[0] = (val >> 24); - ((unsigned char *)dst)[1] = (val >> 16); - ((unsigned char *)dst)[2] = (val >> 8); - ((unsigned char *)dst)[3] = val; -} - -/** - * Encode a 32-bit value into the provided buffer (big endian convention). - * The destination buffer must be properly aligned. - * - * @param dst the destination buffer (32-bit aligned) - * @param val the value to encode - */ -static inline void -sph_enc32be_aligned(void *dst, sph_u32 val) -{ -#if SPH_LITTLE_ENDIAN - *(sph_u32 *)dst = sph_bswap32(val); -#elif SPH_BIG_ENDIAN - *(sph_u32 *)dst = val; -#else - ((unsigned char *)dst)[0] = (val >> 24); - ((unsigned char *)dst)[1] = (val >> 16); - ((unsigned char *)dst)[2] = (val >> 8); - ((unsigned char *)dst)[3] = val; -#endif -} - -/** - * Decode a 32-bit value from the provided buffer (big endian convention). - * - * @param src the source buffer - * @return the decoded value - */ -static inline sph_u32 -sph_dec32be(const void *src) -{ - return ((sph_u32)(((const unsigned char *)src)[0]) << 24) - | ((sph_u32)(((const unsigned char *)src)[1]) << 16) - | ((sph_u32)(((const unsigned char *)src)[2]) << 8) - | (sph_u32)(((const unsigned char *)src)[3]); -} - -/** - * Decode a 32-bit value from the provided buffer (big endian convention). - * The source buffer must be properly aligned. - * - * @param src the source buffer (32-bit aligned) - * @return the decoded value - */ -static inline sph_u32 -sph_dec32be_aligned(const void *src) -{ -#if SPH_LITTLE_ENDIAN - return sph_bswap32(*(const sph_u32 *)src); -#elif SPH_BIG_ENDIAN - return *(const sph_u32 *)src; -#else - return ((sph_u32)(((const unsigned char *)src)[0]) << 24) - | ((sph_u32)(((const unsigned char *)src)[1]) << 16) - | ((sph_u32)(((const unsigned char *)src)[2]) << 8) - | (sph_u32)(((const unsigned char *)src)[3]); -#endif -} - -/** - * Encode a 32-bit value into the provided buffer (little endian convention). - * - * @param dst the destination buffer - * @param val the 32-bit value to encode - */ -static inline void -sph_enc32le(void *dst, sph_u32 val) -{ - ((unsigned char *)dst)[0] = val; - ((unsigned char *)dst)[1] = (val >> 8); - ((unsigned char *)dst)[2] = (val >> 16); - ((unsigned char *)dst)[3] = (val >> 24); -} - -/** - * Encode a 32-bit value into the provided buffer (little endian convention). - * The destination buffer must be properly aligned. - * - * @param dst the destination buffer (32-bit aligned) - * @param val the value to encode - */ -static inline void -sph_enc32le_aligned(void *dst, sph_u32 val) -{ -#if SPH_LITTLE_ENDIAN - *(sph_u32 *)dst = val; -#elif SPH_BIG_ENDIAN - *(sph_u32 *)dst = sph_bswap32(val); -#else - ((unsigned char *)dst)[0] = val; - ((unsigned char *)dst)[1] = (val >> 8); - ((unsigned char *)dst)[2] = (val >> 16); - ((unsigned char *)dst)[3] = (val >> 24); -#endif -} - -/** - * Decode a 32-bit value from the provided buffer (little endian convention). - * - * @param src the source buffer - * @return the decoded value - */ -static inline sph_u32 -sph_dec32le(const void *src) -{ - return (sph_u32)(((const unsigned char *)src)[0]) - | ((sph_u32)(((const unsigned char *)src)[1]) << 8) - | ((sph_u32)(((const unsigned char *)src)[2]) << 16) - | ((sph_u32)(((const unsigned char *)src)[3]) << 24); -} - -/** - * Decode a 32-bit value from the provided buffer (little endian convention). - * The source buffer must be properly aligned. - * - * @param src the source buffer (32-bit aligned) - * @return the decoded value - */ -static inline sph_u32 -sph_dec32le_aligned(const void *src) -{ -#if SPH_LITTLE_ENDIAN - return *(const sph_u32 *)src; -#elif SPH_BIG_ENDIAN - return sph_bswap32(*(const sph_u32 *)src); -#else - return (sph_u32)(((const unsigned char *)src)[0]) - | ((sph_u32)(((const unsigned char *)src)[1]) << 8) - | ((sph_u32)(((const unsigned char *)src)[2]) << 16) - | ((sph_u32)(((const unsigned char *)src)[3]) << 24); -#endif -} - -/** - * Encode a 64-bit value into the provided buffer (big endian convention). - * - * @param dst the destination buffer - * @param val the 64-bit value to encode - */ -static inline void -sph_enc64be(void *dst, sph_u64 val) -{ - ((unsigned char *)dst)[0] = (val >> 56); - ((unsigned char *)dst)[1] = (val >> 48); - ((unsigned char *)dst)[2] = (val >> 40); - ((unsigned char *)dst)[3] = (val >> 32); - ((unsigned char *)dst)[4] = (val >> 24); - ((unsigned char *)dst)[5] = (val >> 16); - ((unsigned char *)dst)[6] = (val >> 8); - ((unsigned char *)dst)[7] = val; -} - -/** - * Encode a 64-bit value into the provided buffer (big endian convention). - * The destination buffer must be properly aligned. - * - * @param dst the destination buffer (64-bit aligned) - * @param val the value to encode - */ -static inline void -sph_enc64be_aligned(void *dst, sph_u64 val) -{ -#if SPH_LITTLE_ENDIAN - *(sph_u64 *)dst = sph_bswap64(val); -#elif SPH_BIG_ENDIAN - *(sph_u64 *)dst = val; -#else - ((unsigned char *)dst)[0] = (val >> 56); - ((unsigned char *)dst)[1] = (val >> 48); - ((unsigned char *)dst)[2] = (val >> 40); - ((unsigned char *)dst)[3] = (val >> 32); - ((unsigned char *)dst)[4] = (val >> 24); - ((unsigned char *)dst)[5] = (val >> 16); - ((unsigned char *)dst)[6] = (val >> 8); - ((unsigned char *)dst)[7] = val; -#endif -} - -/** - * Decode a 64-bit value from the provided buffer (big endian convention). - * - * @param src the source buffer - * @return the decoded value - */ -static inline sph_u64 -sph_dec64be(const void *src) -{ - return ((sph_u64)(((const unsigned char *)src)[0]) << 56) - | ((sph_u64)(((const unsigned char *)src)[1]) << 48) - | ((sph_u64)(((const unsigned char *)src)[2]) << 40) - | ((sph_u64)(((const unsigned char *)src)[3]) << 32) - | ((sph_u64)(((const unsigned char *)src)[4]) << 24) - | ((sph_u64)(((const unsigned char *)src)[5]) << 16) - | ((sph_u64)(((const unsigned char *)src)[6]) << 8) - | (sph_u64)(((const unsigned char *)src)[7]); -} - -/** - * Decode a 64-bit value from the provided buffer (big endian convention). - * The source buffer must be properly aligned. - * - * @param src the source buffer (64-bit aligned) - * @return the decoded value - */ -static inline sph_u64 -sph_dec64be_aligned(const void *src) -{ -#if SPH_LITTLE_ENDIAN - return sph_bswap64(*(const sph_u64 *)src); -#elif SPH_BIG_ENDIAN - return *(const sph_u64 *)src; -#else - return ((sph_u64)(((const unsigned char *)src)[0]) << 56) - | ((sph_u64)(((const unsigned char *)src)[1]) << 48) - | ((sph_u64)(((const unsigned char *)src)[2]) << 40) - | ((sph_u64)(((const unsigned char *)src)[3]) << 32) - | ((sph_u64)(((const unsigned char *)src)[4]) << 24) - | ((sph_u64)(((const unsigned char *)src)[5]) << 16) - | ((sph_u64)(((const unsigned char *)src)[6]) << 8) - | (sph_u64)(((const unsigned char *)src)[7]); -#endif -} - -/** - * Encode a 64-bit value into the provided buffer (little endian convention). - * - * @param dst the destination buffer - * @param val the 64-bit value to encode - */ -static inline void -sph_enc64le(void *dst, sph_u64 val) -{ - ((unsigned char *)dst)[0] = val; - ((unsigned char *)dst)[1] = (val >> 8); - ((unsigned char *)dst)[2] = (val >> 16); - ((unsigned char *)dst)[3] = (val >> 24); - ((unsigned char *)dst)[4] = (val >> 32); - ((unsigned char *)dst)[5] = (val >> 40); - ((unsigned char *)dst)[6] = (val >> 48); - ((unsigned char *)dst)[7] = (val >> 56); -} - -/** - * Encode a 64-bit value into the provided buffer (little endian convention). - * The destination buffer must be properly aligned. - * - * @param dst the destination buffer (64-bit aligned) - * @param val the value to encode - */ -static inline void -sph_enc64le_aligned(void *dst, sph_u64 val) -{ -#if SPH_LITTLE_ENDIAN - *(sph_u64 *)dst = val; -#elif SPH_BIG_ENDIAN - *(sph_u64 *)dst = sph_bswap64(val); -#else - ((unsigned char *)dst)[0] = val; - ((unsigned char *)dst)[1] = (val >> 8); - ((unsigned char *)dst)[2] = (val >> 16); - ((unsigned char *)dst)[3] = (val >> 24); - ((unsigned char *)dst)[4] = (val >> 32); - ((unsigned char *)dst)[5] = (val >> 40); - ((unsigned char *)dst)[6] = (val >> 48); - ((unsigned char *)dst)[7] = (val >> 56); -#endif -} - -/** - * Decode a 64-bit value from the provided buffer (little endian convention). - * - * @param src the source buffer - * @return the decoded value - */ -static inline sph_u64 -sph_dec64le(const void *src) -{ - return (sph_u64)(((const unsigned char *)src)[0]) - | ((sph_u64)(((const unsigned char *)src)[1]) << 8) - | ((sph_u64)(((const unsigned char *)src)[2]) << 16) - | ((sph_u64)(((const unsigned char *)src)[3]) << 24) - | ((sph_u64)(((const unsigned char *)src)[4]) << 32) - | ((sph_u64)(((const unsigned char *)src)[5]) << 40) - | ((sph_u64)(((const unsigned char *)src)[6]) << 48) - | ((sph_u64)(((const unsigned char *)src)[7]) << 56); -} - -/** - * Decode a 64-bit value from the provided buffer (little endian convention). - * The source buffer must be properly aligned. - * - * @param src the source buffer (64-bit aligned) - * @return the decoded value - */ -static inline sph_u64 -sph_dec64le_aligned(const void *src) -{ -#if SPH_LITTLE_ENDIAN - return *(const sph_u64 *)src; -#elif SPH_BIG_ENDIAN - return sph_bswap64(*(const sph_u64 *)src); -#else - return (sph_u64)(((const unsigned char *)src)[0]) - | ((sph_u64)(((const unsigned char *)src)[1]) << 8) - | ((sph_u64)(((const unsigned char *)src)[2]) << 16) - | ((sph_u64)(((const unsigned char *)src)[3]) << 24) - | ((sph_u64)(((const unsigned char *)src)[4]) << 32) - | ((sph_u64)(((const unsigned char *)src)[5]) << 40) - | ((sph_u64)(((const unsigned char *)src)[6]) << 48) - | ((sph_u64)(((const unsigned char *)src)[7]) << 56); -#endif -} - -#endif diff --git a/deps/crypto/trezor-crypto/gui/.gitignore b/deps/crypto/trezor-crypto/gui/.gitignore deleted file mode 100644 index b44cbb243..000000000 --- a/deps/crypto/trezor-crypto/gui/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -gui.pro.user -moc_mainwindow.cpp -ui_mainwindow.h -Makefile diff --git a/deps/crypto/trezor-crypto/gui/gui.pro b/deps/crypto/trezor-crypto/gui/gui.pro deleted file mode 100644 index e4623bc4f..000000000 --- a/deps/crypto/trezor-crypto/gui/gui.pro +++ /dev/null @@ -1,34 +0,0 @@ -QT += core gui -greaterThan(QT_MAJOR_VERSION, 4): QT += widgets - -TARGET = gui -TEMPLATE = app - -SOURCES += ../address.c -SOURCES += ../bip32.c -SOURCES += ../bip39.c -SOURCES += ../sha2.c -SOURCES += ../pbkdf2.c -SOURCES += ../hmac.c -SOURCES += ../rand.c -SOURCES += ../bignum.c -SOURCES += ../ecdsa.c -SOURCES += ../rfc6979.c -SOURCES += ../hmac_drbg.c -SOURCES += ../ripemd160.c -SOURCES += ../base58.c -SOURCES += ../secp256k1.c -SOURCES += ../nist256p1.c -SOURCES += ../curves.c -SOURCES += ../ed25519-donna/ed25519.c -SOURCES += mainwindow.cpp -SOURCES += main.cpp - -HEADERS += mainwindow.h -HEADERS += ../bip32.h -HEADERS += ../bip39.h - -FORMS += mainwindow.ui - -INCLUDEPATH += .. -INCLUDEPATH += ../ed25519-donna diff --git a/deps/crypto/trezor-crypto/gui/main.cpp b/deps/crypto/trezor-crypto/gui/main.cpp deleted file mode 100644 index 115a22bf7..000000000 --- a/deps/crypto/trezor-crypto/gui/main.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "mainwindow.h" -#include - -int main(int argc, char *argv[]) -{ - QApplication a(argc, argv); - MainWindow w; - w.show(); - return a.exec(); -} diff --git a/deps/crypto/trezor-crypto/gui/mainwindow.cpp b/deps/crypto/trezor-crypto/gui/mainwindow.cpp deleted file mode 100644 index 1bc7ea5c9..000000000 --- a/deps/crypto/trezor-crypto/gui/mainwindow.cpp +++ /dev/null @@ -1,78 +0,0 @@ -#include -#include "mainwindow.h" -#include "ui_mainwindow.h" -extern "C" { -#include "../bip32.h" -#include "../bip39.h" -#include "../ecdsa.h" -#include "../curves.h" -} - -bool root_set = false; -HDNode root; - -MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) -{ - ui->setupUi(this); - for (int i = 0; i < 100; i++) { - ui->listAddress->insertRow(i); - ui->listChange->insertRow(i); - - } -} - -MainWindow::~MainWindow() -{ - delete ui; -} - -// abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about - -void MainWindow::on_buttonLoad_clicked() -{ - if (!mnemonic_check(ui->editMnemonic->text().toLocal8Bit().data())) { - QMessageBox::critical(this, "Error", "Text is not a valid BIP39 mnemonic.", QMessageBox::Ok); - return; - } - uint8_t seed[64]; - mnemonic_to_seed(ui->editMnemonic->text().toLocal8Bit().data(), ui->editPassphrase->text().toLocal8Bit().data(), seed, 0); - hdnode_from_seed(seed, 64, SECP256K1_NAME, &root); - root_set = true; - ui->spinAccount->setValue(1); - on_spinAccount_valueChanged(1); -} - -void MainWindow::on_spinAccount_valueChanged(int arg1) -{ - if (!root_set) return; - // constants for Bitcoin - const uint32_t version_public = 0x0488b21e; - const uint32_t version_private = 0x0488ade4; - const char addr_version = 0x00, wif_version = 0x80; - const size_t buflen = 128; - char buf[buflen + 1]; - HDNode node; - uint32_t fingerprint; - // external chain - for (int chain = 0; chain < 2; chain++) { - QTableWidget *list = chain == 0 ? ui->listAddress : ui->listChange; - node = root; - hdnode_private_ckd(&node, 44 | 0x80000000); - hdnode_private_ckd(&node, 0 | 0x80000000); // bitcoin - hdnode_private_ckd(&node, (arg1 - 1) | 0x80000000); - fingerprint = hdnode_fingerprint(&node); - hdnode_serialize_private(&node, fingerprint, version_private, buf, buflen); QString xprv = QString(buf); ui->lineXprv->setText(xprv); - hdnode_serialize_public(&node, fingerprint, version_public, buf, buflen); QString xpub = QString(buf); ui->lineXpub->setText(xpub); - hdnode_private_ckd(&node, chain); // external / internal - for (int i = 0; i < 100; i++) { - HDNode node2 = node; - hdnode_private_ckd(&node2, i); - hdnode_fill_public_key(&node2); - ecdsa_get_address(node2.public_key, addr_version, buf, buflen); QString address = QString(buf); - ecdsa_get_wif(node2.private_key, wif_version, buf, buflen); QString wif = QString(buf); - list->setItem(i, 0, new QTableWidgetItem(address)); - list->setItem(i, 1, new QTableWidgetItem(wif)); - list->setItem(i, 2, new QTableWidgetItem("0.0")); - } - } -} diff --git a/deps/crypto/trezor-crypto/gui/mainwindow.h b/deps/crypto/trezor-crypto/gui/mainwindow.h deleted file mode 100644 index 7275167da..000000000 --- a/deps/crypto/trezor-crypto/gui/mainwindow.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef MAINWINDOW_H -#define MAINWINDOW_H - -#include -#include - -namespace Ui { -class MainWindow; -} - -class MainWindow : public QMainWindow -{ - Q_OBJECT - -public: - explicit MainWindow(QWidget *parent = 0); - ~MainWindow(); - -private slots: - void on_buttonLoad_clicked(); - void on_spinAccount_valueChanged(int arg1); - -private: - Ui::MainWindow *ui; -}; - -#endif // MAINWINDOW_H diff --git a/deps/crypto/trezor-crypto/gui/mainwindow.ui b/deps/crypto/trezor-crypto/gui/mainwindow.ui deleted file mode 100644 index cbc302b3b..000000000 --- a/deps/crypto/trezor-crypto/gui/mainwindow.ui +++ /dev/null @@ -1,161 +0,0 @@ - - - MainWindow - - - - 0 - 0 - 1000 - 600 - - - - - DejaVu Sans Mono - 8 - - - - Trezor - - - - - - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - - 120 - 16777215 - - - - Load - - - - - - - - address - - - - - private key - - - - - balance - - - - - - - - - address - - - - - private key - - - - - balance - - - - - - - - Mnemonic: - - - - - - - Passphrase: - - - - - - - External Chain: - - - - - - - Internal Chain: - - - - - - - - 130 - 16777215 - - - - Account # - - - 1 - - - 2147483647 - - - - - - - - - - - - - - - editMnemonic - editPassphrase - buttonLoad - spinAccount - listAddress - listChange - - - - diff --git a/deps/crypto/trezor-crypto/hasher.c b/deps/crypto/trezor-crypto/hasher.c deleted file mode 100644 index 23a4c82c3..000000000 --- a/deps/crypto/trezor-crypto/hasher.c +++ /dev/null @@ -1,156 +0,0 @@ -/** - * Copyright (c) 2017 Saleem Rashid - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "hasher.h" -#include "ripemd160.h" - -void hasher_InitParam(Hasher *hasher, HasherType type, const void *param, - uint32_t param_size) { - hasher->type = type; - hasher->param = param; - hasher->param_size = param_size; - - switch (hasher->type) { - case HASHER_SHA2: - case HASHER_SHA2D: - case HASHER_SHA2_RIPEMD: - sha256_Init(&hasher->ctx.sha2); - break; - case HASHER_SHA3: -#if USE_KECCAK - case HASHER_SHA3K: -#endif - sha3_256_Init(&hasher->ctx.sha3); - break; - case HASHER_BLAKE: - case HASHER_BLAKED: - case HASHER_BLAKE_RIPEMD: - blake256_Init(&hasher->ctx.blake); - break; - case HASHER_GROESTLD_TRUNC: - groestl512_Init(&hasher->ctx.groestl); - break; - case HASHER_BLAKE2B: - blake2b_Init(&hasher->ctx.blake2b, 32); - break; - case HASHER_BLAKE2B_PERSONAL: - blake2b_InitPersonal(&hasher->ctx.blake2b, 32, hasher->param, - hasher->param_size); - break; - case HASHER_RIPEMD: - ripemd160_Init(&hasher->ctx.ripemd160); - break; - } -} - -void hasher_Init(Hasher *hasher, HasherType type) { - hasher_InitParam(hasher, type, NULL, 0); -} - -void hasher_Reset(Hasher *hasher) { - hasher_InitParam(hasher, hasher->type, hasher->param, hasher->param_size); -} - -void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length) { - switch (hasher->type) { - case HASHER_SHA2: - case HASHER_SHA2D: - case HASHER_SHA2_RIPEMD: - sha256_Update(&hasher->ctx.sha2, data, length); - break; - case HASHER_SHA3: -#if USE_KECCAK - case HASHER_SHA3K: -#endif - sha3_Update(&hasher->ctx.sha3, data, length); - break; - case HASHER_BLAKE: - case HASHER_BLAKED: - case HASHER_BLAKE_RIPEMD: - blake256_Update(&hasher->ctx.blake, data, length); - break; - case HASHER_GROESTLD_TRUNC: - groestl512_Update(&hasher->ctx.groestl, data, length); - break; - case HASHER_BLAKE2B: - case HASHER_BLAKE2B_PERSONAL: - blake2b_Update(&hasher->ctx.blake2b, data, length); - break; - case HASHER_RIPEMD: - ripemd160_Update(&hasher->ctx.ripemd160, data, length); - break; - } -} - -void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]) { - switch (hasher->type) { - case HASHER_SHA2: - sha256_Final(&hasher->ctx.sha2, hash); - break; - case HASHER_SHA2D: - sha256_Final(&hasher->ctx.sha2, hash); - hasher_Raw(HASHER_SHA2, hash, HASHER_DIGEST_LENGTH, hash); - break; - case HASHER_SHA2_RIPEMD: - sha256_Final(&hasher->ctx.sha2, hash); - ripemd160(hash, HASHER_DIGEST_LENGTH, hash); - break; - case HASHER_SHA3: - sha3_Final(&hasher->ctx.sha3, hash); - break; -#if USE_KECCAK - case HASHER_SHA3K: - keccak_Final(&hasher->ctx.sha3, hash); - break; -#endif - case HASHER_BLAKE: - blake256_Final(&hasher->ctx.blake, hash); - break; - case HASHER_BLAKED: - blake256_Final(&hasher->ctx.blake, hash); - hasher_Raw(HASHER_BLAKE, hash, HASHER_DIGEST_LENGTH, hash); - break; - case HASHER_BLAKE_RIPEMD: - blake256_Final(&hasher->ctx.blake, hash); - ripemd160(hash, HASHER_DIGEST_LENGTH, hash); - break; - case HASHER_GROESTLD_TRUNC: - groestl512_DoubleTrunc(&hasher->ctx.groestl, hash); - break; - case HASHER_BLAKE2B: - case HASHER_BLAKE2B_PERSONAL: - blake2b_Final(&hasher->ctx.blake2b, hash, 32); - break; - case HASHER_RIPEMD: - ripemd160_Final(&hasher->ctx.ripemd160, hash); - break; - } -} - -void hasher_Raw(HasherType type, const uint8_t *data, size_t length, - uint8_t hash[HASHER_DIGEST_LENGTH]) { - Hasher hasher = {0}; - - hasher_Init(&hasher, type); - hasher_Update(&hasher, data, length); - hasher_Final(&hasher, hash); -} diff --git a/deps/crypto/trezor-crypto/hasher.h b/deps/crypto/trezor-crypto/hasher.h deleted file mode 100644 index 4dd0f5457..000000000 --- a/deps/crypto/trezor-crypto/hasher.h +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright (c) 2017 Saleem Rashid - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __HASHER_H__ -#define __HASHER_H__ - -#include -#include - -#include "blake256.h" -#include "blake2b.h" -#include "ripemd160.h" -#include "groestl.h" -#include "sha2.h" -#include "sha3.h" - -#define HASHER_DIGEST_LENGTH 32 - -typedef enum { - HASHER_SHA2, - HASHER_SHA2D, - HASHER_SHA2_RIPEMD, - - HASHER_SHA3, -#if USE_KECCAK - HASHER_SHA3K, -#endif - - HASHER_BLAKE, - HASHER_BLAKED, - HASHER_BLAKE_RIPEMD, - - HASHER_GROESTLD_TRUNC, /* Double Groestl512 hasher truncated to 256 bits */ - - HASHER_BLAKE2B, - HASHER_BLAKE2B_PERSONAL, - - HASHER_RIPEMD, -} HasherType; - -typedef struct { - HasherType type; - - union { - SHA256_CTX sha2; // for HASHER_SHA2{,D} - SHA3_CTX sha3; // for HASHER_SHA3{,K} - BLAKE256_CTX blake; // for HASHER_BLAKE{,D} - GROESTL512_CTX groestl; // for HASHER_GROESTLD_TRUNC - BLAKE2B_CTX blake2b; // for HASHER_BLAKE2B{,_PERSONAL} - RIPEMD160_CTX ripemd160; // for HASHER_RIPEMD - } ctx; - - const void *param; - uint32_t param_size; -} Hasher; - -void hasher_InitParam(Hasher *hasher, HasherType type, const void *param, - uint32_t param_size); -void hasher_Init(Hasher *hasher, HasherType type); -void hasher_Reset(Hasher *hasher); -void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length); -void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]); - -void hasher_Raw(HasherType type, const uint8_t *data, size_t length, - uint8_t hash[HASHER_DIGEST_LENGTH]); - -#endif diff --git a/deps/crypto/trezor-crypto/hmac.c b/deps/crypto/trezor-crypto/hmac.c deleted file mode 100644 index 654f2d6e8..000000000 --- a/deps/crypto/trezor-crypto/hmac.c +++ /dev/null @@ -1,176 +0,0 @@ -/** - * Copyright (c) 2013-2014 Tomas Dzetkulic - * Copyright (c) 2013-2014 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include - -#include "hmac.h" -#include "memzero.h" -#include "options.h" - -void hmac_sha256_Init(HMAC_SHA256_CTX *hctx, const uint8_t *key, - const uint32_t keylen) { - static CONFIDENTIAL uint8_t i_key_pad[SHA256_BLOCK_LENGTH]; - memzero(i_key_pad, SHA256_BLOCK_LENGTH); - if (keylen > SHA256_BLOCK_LENGTH) { - sha256_Raw(key, keylen, i_key_pad); - } else { - memcpy(i_key_pad, key, keylen); - } - for (int i = 0; i < SHA256_BLOCK_LENGTH; i++) { - hctx->o_key_pad[i] = i_key_pad[i] ^ 0x5c; - i_key_pad[i] ^= 0x36; - } - sha256_Init(&(hctx->ctx)); - sha256_Update(&(hctx->ctx), i_key_pad, SHA256_BLOCK_LENGTH); - memzero(i_key_pad, sizeof(i_key_pad)); -} - -void hmac_sha256_Update(HMAC_SHA256_CTX *hctx, const uint8_t *msg, - const uint32_t msglen) { - sha256_Update(&(hctx->ctx), msg, msglen); -} - -void hmac_sha256_Final(HMAC_SHA256_CTX *hctx, uint8_t *hmac) { - sha256_Final(&(hctx->ctx), hmac); - sha256_Init(&(hctx->ctx)); - sha256_Update(&(hctx->ctx), hctx->o_key_pad, SHA256_BLOCK_LENGTH); - sha256_Update(&(hctx->ctx), hmac, SHA256_DIGEST_LENGTH); - sha256_Final(&(hctx->ctx), hmac); - memzero(hctx, sizeof(HMAC_SHA256_CTX)); -} - -void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, - const uint32_t msglen, uint8_t *hmac) { - static CONFIDENTIAL HMAC_SHA256_CTX hctx; - hmac_sha256_Init(&hctx, key, keylen); - hmac_sha256_Update(&hctx, msg, msglen); - hmac_sha256_Final(&hctx, hmac); -} - -void hmac_sha256_prepare(const uint8_t *key, const uint32_t keylen, - uint32_t *opad_digest, uint32_t *ipad_digest) { - static CONFIDENTIAL uint32_t key_pad[SHA256_BLOCK_LENGTH / sizeof(uint32_t)]; - - memzero(key_pad, sizeof(key_pad)); - if (keylen > SHA256_BLOCK_LENGTH) { - static CONFIDENTIAL SHA256_CTX context; - sha256_Init(&context); - sha256_Update(&context, key, keylen); - sha256_Final(&context, (uint8_t *)key_pad); - } else { - memcpy(key_pad, key, keylen); - } - - /* compute o_key_pad and its digest */ - for (int i = 0; i < SHA256_BLOCK_LENGTH / (int)sizeof(uint32_t); i++) { - uint32_t data = 0; -#if BYTE_ORDER == LITTLE_ENDIAN - REVERSE32(key_pad[i], data); -#else - data = key_pad[i]; -#endif - key_pad[i] = data ^ 0x5c5c5c5c; - } - sha256_Transform(sha256_initial_hash_value, key_pad, opad_digest); - - /* convert o_key_pad to i_key_pad and compute its digest */ - for (int i = 0; i < SHA256_BLOCK_LENGTH / (int)sizeof(uint32_t); i++) { - key_pad[i] = key_pad[i] ^ 0x5c5c5c5c ^ 0x36363636; - } - sha256_Transform(sha256_initial_hash_value, key_pad, ipad_digest); - memzero(key_pad, sizeof(key_pad)); -} - -void hmac_sha512_Init(HMAC_SHA512_CTX *hctx, const uint8_t *key, - const uint32_t keylen) { - static CONFIDENTIAL uint8_t i_key_pad[SHA512_BLOCK_LENGTH]; - memzero(i_key_pad, SHA512_BLOCK_LENGTH); - if (keylen > SHA512_BLOCK_LENGTH) { - sha512_Raw(key, keylen, i_key_pad); - } else { - memcpy(i_key_pad, key, keylen); - } - for (int i = 0; i < SHA512_BLOCK_LENGTH; i++) { - hctx->o_key_pad[i] = i_key_pad[i] ^ 0x5c; - i_key_pad[i] ^= 0x36; - } - sha512_Init(&(hctx->ctx)); - sha512_Update(&(hctx->ctx), i_key_pad, SHA512_BLOCK_LENGTH); - memzero(i_key_pad, sizeof(i_key_pad)); -} - -void hmac_sha512_Update(HMAC_SHA512_CTX *hctx, const uint8_t *msg, - const uint32_t msglen) { - sha512_Update(&(hctx->ctx), msg, msglen); -} - -void hmac_sha512_Final(HMAC_SHA512_CTX *hctx, uint8_t *hmac) { - sha512_Final(&(hctx->ctx), hmac); - sha512_Init(&(hctx->ctx)); - sha512_Update(&(hctx->ctx), hctx->o_key_pad, SHA512_BLOCK_LENGTH); - sha512_Update(&(hctx->ctx), hmac, SHA512_DIGEST_LENGTH); - sha512_Final(&(hctx->ctx), hmac); - memzero(hctx, sizeof(HMAC_SHA512_CTX)); -} - -void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, - const uint32_t msglen, uint8_t *hmac) { - HMAC_SHA512_CTX hctx = {0}; - hmac_sha512_Init(&hctx, key, keylen); - hmac_sha512_Update(&hctx, msg, msglen); - hmac_sha512_Final(&hctx, hmac); -} - -void hmac_sha512_prepare(const uint8_t *key, const uint32_t keylen, - uint64_t *opad_digest, uint64_t *ipad_digest) { - static CONFIDENTIAL uint64_t key_pad[SHA512_BLOCK_LENGTH / sizeof(uint64_t)]; - - memzero(key_pad, sizeof(key_pad)); - if (keylen > SHA512_BLOCK_LENGTH) { - static CONFIDENTIAL SHA512_CTX context; - sha512_Init(&context); - sha512_Update(&context, key, keylen); - sha512_Final(&context, (uint8_t *)key_pad); - } else { - memcpy(key_pad, key, keylen); - } - - /* compute o_key_pad and its digest */ - for (int i = 0; i < SHA512_BLOCK_LENGTH / (int)sizeof(uint64_t); i++) { - uint64_t data = 0; -#if BYTE_ORDER == LITTLE_ENDIAN - REVERSE64(key_pad[i], data); -#else - data = key_pad[i]; -#endif - key_pad[i] = data ^ 0x5c5c5c5c5c5c5c5c; - } - sha512_Transform(sha512_initial_hash_value, key_pad, opad_digest); - - /* convert o_key_pad to i_key_pad and compute its digest */ - for (int i = 0; i < SHA512_BLOCK_LENGTH / (int)sizeof(uint64_t); i++) { - key_pad[i] = key_pad[i] ^ 0x5c5c5c5c5c5c5c5c ^ 0x3636363636363636; - } - sha512_Transform(sha512_initial_hash_value, key_pad, ipad_digest); - memzero(key_pad, sizeof(key_pad)); -} diff --git a/deps/crypto/trezor-crypto/hmac.h b/deps/crypto/trezor-crypto/hmac.h deleted file mode 100644 index 3921a171e..000000000 --- a/deps/crypto/trezor-crypto/hmac.h +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright (c) 2013-2014 Tomas Dzetkulic - * Copyright (c) 2013-2014 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT HMAC_SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __HMAC_H__ -#define __HMAC_H__ - -#include -#include "sha2.h" - -typedef struct _HMAC_SHA256_CTX { - uint8_t o_key_pad[SHA256_BLOCK_LENGTH]; - SHA256_CTX ctx; -} HMAC_SHA256_CTX; - -typedef struct _HMAC_SHA512_CTX { - uint8_t o_key_pad[SHA512_BLOCK_LENGTH]; - SHA512_CTX ctx; -} HMAC_SHA512_CTX; - -void hmac_sha256_Init(HMAC_SHA256_CTX *hctx, const uint8_t *key, - const uint32_t keylen); -void hmac_sha256_Update(HMAC_SHA256_CTX *hctx, const uint8_t *msg, - const uint32_t msglen); -void hmac_sha256_Final(HMAC_SHA256_CTX *hctx, uint8_t *hmac); -void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, - const uint32_t msglen, uint8_t *hmac); -void hmac_sha256_prepare(const uint8_t *key, const uint32_t keylen, - uint32_t *opad_digest, uint32_t *ipad_digest); - -void hmac_sha512_Init(HMAC_SHA512_CTX *hctx, const uint8_t *key, - const uint32_t keylen); -void hmac_sha512_Update(HMAC_SHA512_CTX *hctx, const uint8_t *msg, - const uint32_t msglen); -void hmac_sha512_Final(HMAC_SHA512_CTX *hctx, uint8_t *hmac); -void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, - const uint32_t msglen, uint8_t *hmac); -void hmac_sha512_prepare(const uint8_t *key, const uint32_t keylen, - uint64_t *opad_digest, uint64_t *ipad_digest); - -#endif diff --git a/deps/crypto/trezor-crypto/hmac_drbg.c b/deps/crypto/trezor-crypto/hmac_drbg.c deleted file mode 100644 index 1ed1401b8..000000000 --- a/deps/crypto/trezor-crypto/hmac_drbg.c +++ /dev/null @@ -1,130 +0,0 @@ -/** - * Copyright (c) 2019 Andrew R. Kozlik - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "hmac_drbg.h" -#include -#include "memzero.h" -#include "sha2.h" - -static void update_k(HMAC_DRBG_CTX *ctx, uint8_t domain, const uint8_t *data1, - size_t len1, const uint8_t *data2, size_t len2) { - // Computes K = HMAC(K, V || domain || data1 || data 2). - - // First hash operation of HMAC. - uint32_t h[SHA256_BLOCK_LENGTH / sizeof(uint32_t)] = {0}; - if (len1 + len2 == 0) { - ctx->v[8] = 0x00800000; - ctx->v[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH + 1) * 8; - sha256_Transform(ctx->idig, ctx->v, h); - ctx->v[8] = 0x80000000; - ctx->v[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8; - } else { - SHA256_CTX sha_ctx = {0}; - memcpy(sha_ctx.state, ctx->idig, SHA256_DIGEST_LENGTH); - for (size_t i = 0; i < SHA256_DIGEST_LENGTH / sizeof(uint32_t); i++) { -#if BYTE_ORDER == LITTLE_ENDIAN - REVERSE32(ctx->v[i], sha_ctx.buffer[i]); -#else - sha_ctx.buffer[i] = ctx->v[i]; -#endif - } - ((uint8_t *)sha_ctx.buffer)[SHA256_DIGEST_LENGTH] = domain; - sha_ctx.bitcount = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH + 1) * 8; - sha256_Update(&sha_ctx, data1, len1); - sha256_Update(&sha_ctx, data2, len2); - sha256_Final(&sha_ctx, (uint8_t *)h); -#if BYTE_ORDER == LITTLE_ENDIAN - for (size_t i = 0; i < SHA256_DIGEST_LENGTH / sizeof(uint32_t); i++) - REVERSE32(h[i], h[i]); -#endif - } - - // Second hash operation of HMAC. - h[8] = 0x80000000; - h[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8; - sha256_Transform(ctx->odig, h, h); - - // Precompute the inner digest and outer digest of K. - h[8] = 0; - h[15] = 0; - for (size_t i = 0; i < SHA256_BLOCK_LENGTH / sizeof(uint32_t); i++) { - h[i] ^= 0x36363636; - } - sha256_Transform(sha256_initial_hash_value, h, ctx->idig); - - for (size_t i = 0; i < SHA256_BLOCK_LENGTH / sizeof(uint32_t); i++) { - h[i] = h[i] ^ 0x36363636 ^ 0x5c5c5c5c; - } - sha256_Transform(sha256_initial_hash_value, h, ctx->odig); - memzero(h, sizeof(h)); -} - -static void update_v(HMAC_DRBG_CTX *ctx) { - sha256_Transform(ctx->idig, ctx->v, ctx->v); - sha256_Transform(ctx->odig, ctx->v, ctx->v); -} - -void hmac_drbg_init(HMAC_DRBG_CTX *ctx, const uint8_t *entropy, - size_t entropy_len, const uint8_t *nonce, - size_t nonce_len) { - uint32_t h[SHA256_BLOCK_LENGTH / sizeof(uint32_t)] = {0}; - - // Precompute the inner digest and outer digest of K = 0x00 ... 0x00. - memset(h, 0x36, sizeof(h)); - sha256_Transform(sha256_initial_hash_value, h, ctx->idig); - memset(h, 0x5c, sizeof(h)); - sha256_Transform(sha256_initial_hash_value, h, ctx->odig); - - // Let V = 0x01 ... 0x01. - memset(ctx->v, 1, SHA256_DIGEST_LENGTH); - for (size_t i = 9; i < 15; i++) ctx->v[i] = 0; - ctx->v[8] = 0x80000000; - ctx->v[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8; - - hmac_drbg_reseed(ctx, entropy, entropy_len, nonce, nonce_len); - - memzero(h, sizeof(h)); -} - -void hmac_drbg_reseed(HMAC_DRBG_CTX *ctx, const uint8_t *entropy, size_t len, - const uint8_t *addin, size_t addin_len) { - update_k(ctx, 0, entropy, len, addin, addin_len); - update_v(ctx); - if (len == 0) return; - update_k(ctx, 1, entropy, len, addin, addin_len); - update_v(ctx); -} - -void hmac_drbg_generate(HMAC_DRBG_CTX *ctx, uint8_t *buf, size_t len) { - size_t i = 0; - while (i < len) { - update_v(ctx); - for (size_t j = 0; j < 8 && i < len; j++) { - uint32_t r = ctx->v[j]; - for (int k = 24; k >= 0 && i < len; k -= 8) { - buf[i++] = (r >> k) & 0xFF; - } - } - } - update_k(ctx, 0, NULL, 0, NULL, 0); - update_v(ctx); -} diff --git a/deps/crypto/trezor-crypto/hmac_drbg.h b/deps/crypto/trezor-crypto/hmac_drbg.h deleted file mode 100644 index 6a8f3978c..000000000 --- a/deps/crypto/trezor-crypto/hmac_drbg.h +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright (c) 2019 Andrew R. Kozlik - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __HMAC_DRBG_H__ -#define __HMAC_DRBG_H__ - -#include "sha2.h" -#include - -// HMAC based Deterministic Random Bit Generator with SHA-256 - -typedef struct _HMAC_DRBG_CTX { - uint32_t odig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; - uint32_t idig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; - uint32_t v[SHA256_BLOCK_LENGTH / sizeof(uint32_t)]; -} HMAC_DRBG_CTX; - -void hmac_drbg_init(HMAC_DRBG_CTX *ctx, const uint8_t *buf, size_t len, - const uint8_t *nonce, size_t nonce_len); -void hmac_drbg_reseed(HMAC_DRBG_CTX *ctx, const uint8_t *buf, size_t len, - const uint8_t *addin, size_t addin_len); -void hmac_drbg_generate(HMAC_DRBG_CTX *ctx, uint8_t *buf, size_t len); - -#endif diff --git a/deps/crypto/trezor-crypto/memzero.c b/deps/crypto/trezor-crypto/memzero.c deleted file mode 100644 index 1c5ea77a6..000000000 --- a/deps/crypto/trezor-crypto/memzero.c +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef __STDC_WANT_LIB_EXT1__ -#define __STDC_WANT_LIB_EXT1__ 1 // C11's bounds-checking interface. -#endif -#include - -#ifdef _WIN32 -#include -#endif - -#ifdef __unix__ -#include -#include -#endif - -// C11's bounds-checking interface. -#if defined(__STDC_LIB_EXT1__) -#define HAVE_MEMSET_S 1 -#endif - -// GNU C Library version 2.25 or later. -#if defined(__GLIBC__) && \ - (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25)) -#define HAVE_EXPLICIT_BZERO 1 -#endif - -// Newlib -#if defined(__NEWLIB__) -#define HAVE_EXPLICIT_BZERO 1 -#endif - -// FreeBSD version 11.0 or later. -#if defined(__FreeBSD__) && __FreeBSD_version >= 1100037 -#define HAVE_EXPLICIT_BZERO 1 -#endif - -// OpenBSD version 5.5 or later. -#if defined(__OpenBSD__) && OpenBSD >= 201405 -#define HAVE_EXPLICIT_BZERO 1 -#endif - -// NetBSD version 7.2 or later. -#if defined(__NetBSD__) && __NetBSD_Version__ >= 702000000 -#define HAVE_EXPLICIT_MEMSET 1 -#endif - -// Adapted from -// https://github.com/jedisct1/libsodium/blob/1647f0d53ae0e370378a9195477e3df0a792408f/src/libsodium/sodium/utils.c#L102-L130 - -void memzero(void *const pnt, const size_t len) { -#ifdef _WIN32 - SecureZeroMemory(pnt, len); -#elif defined(HAVE_MEMSET_S) - memset_s(pnt, (rsize_t)len, 0, (rsize_t)len); -#elif defined(HAVE_EXPLICIT_BZERO) - explicit_bzero(pnt, len); -#elif defined(HAVE_EXPLICIT_MEMSET) - explicit_memset(pnt, 0, len); -#else - volatile unsigned char *volatile pnt_ = (volatile unsigned char *volatile)pnt; - size_t i = (size_t)0U; - - while (i < len) { - pnt_[i++] = 0U; - } -#endif - - // explicitly mark the memory as overwritten for the Clang MemorySanitizer - // this is only included at compile time if MemorySanitizer is enabled and - // should not come with any downsides during regular builds -#if defined(__has_feature) -#if __has_feature(memory_sanitizer) - memset(pnt, 0, len); -#endif -#endif -} diff --git a/deps/crypto/trezor-crypto/memzero.h b/deps/crypto/trezor-crypto/memzero.h deleted file mode 100644 index 0a959fbc2..000000000 --- a/deps/crypto/trezor-crypto/memzero.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef __MEMZERO_H__ -#define __MEMZERO_H__ - -#include - -void memzero(void* const pnt, const size_t len); - -#endif diff --git a/deps/crypto/trezor-crypto/monero/base58.c b/deps/crypto/trezor-crypto/monero/base58.c deleted file mode 100644 index 6c49d1b24..000000000 --- a/deps/crypto/trezor-crypto/monero/base58.c +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright (c) 2014-2018, The Monero Project -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are -// permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of -// conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list -// of conditions and the following disclaimer in the documentation and/or other -// materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be -// used to endorse or promote products derived from this software without specific -// prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers - -#include -#include -#include -#include -#include "base58.h" -#include "int-util.h" -#include "sha2.h" -#include "../base58.h" - -const size_t alphabet_size = 58; // sizeof(b58digits_ordered) - 1; -const size_t encoded_block_sizes[] = {0, 2, 3, 5, 6, 7, 9, 10, 11}; -const size_t full_block_size = sizeof(encoded_block_sizes) / sizeof(encoded_block_sizes[0]) - 1; -const size_t full_encoded_block_size = 11; // encoded_block_sizes[full_block_size]; -const size_t addr_checksum_size = 4; -const int decoded_block_sizes[] = {0, -1, 1, 2, -1, 3, 4, 5, -1, 6, 7, 8}; -#define reverse_alphabet(letter) ((int8_t) b58digits_map[(int)letter]) - - -uint64_t uint_8be_to_64(const uint8_t* data, size_t size) -{ - assert(1 <= size && size <= sizeof(uint64_t)); - - uint64_t res = 0; - switch (9 - size) - { - case 1: res |= *data++; /* FALLTHRU */ - case 2: res <<= 8; res |= *data++; /* FALLTHRU */ - case 3: res <<= 8; res |= *data++; /* FALLTHRU */ - case 4: res <<= 8; res |= *data++; /* FALLTHRU */ - case 5: res <<= 8; res |= *data++; /* FALLTHRU */ - case 6: res <<= 8; res |= *data++; /* FALLTHRU */ - case 7: res <<= 8; res |= *data++; /* FALLTHRU */ - case 8: res <<= 8; res |= *data; break; - default: assert(false); - } - - return res; -} - -void uint_64_to_8be(uint64_t num, size_t size, uint8_t* data) -{ - assert(1 <= size && size <= sizeof(uint64_t)); - - uint64_t num_be = SWAP64(num); - memcpy(data, (uint8_t*)(&num_be) + sizeof(uint64_t) - size, size); -} - -void encode_block(const char* block, size_t size, char* res) -{ - assert(1 <= size && size <= full_block_size); - - uint64_t num = uint_8be_to_64((uint8_t*)(block), size); - int i = ((int)(encoded_block_sizes[size])) - 1; - while (0 <= i) - { - uint64_t remainder = num % alphabet_size; - num /= alphabet_size; - res[i] = b58digits_ordered[remainder]; - --i; - } -} - -bool decode_block(const char* block, size_t size, char* res) -{ - assert(1 <= size && size <= full_encoded_block_size); - - int res_size = decoded_block_sizes[size]; - if (res_size <= 0) - return false; // Invalid block size - - uint64_t res_num = 0; - uint64_t order = 1; - for (size_t i = size - 1; i < size; --i) - { - if (block[i] & 0x80) - return false; // Invalid symbol - int digit = reverse_alphabet(block[i]); - if (digit < 0) - return false; // Invalid symbol - - uint64_t product_hi = 0; - uint64_t tmp = res_num + mul128(order, (uint64_t) digit, &product_hi); - if (tmp < res_num || 0 != product_hi) - return false; // Overflow - - res_num = tmp; - order *= alphabet_size; // Never overflows, 58^10 < 2^64 - } - - if ((size_t)res_size < full_block_size && (UINT64_C(1) << (8 * res_size)) <= res_num) - return false; // Overflow - - uint_64_to_8be(res_num, res_size, (uint8_t*)(res)); - - return true; -} - - -bool xmr_base58_encode(char *b58, size_t *b58sz, const void *data, size_t binsz) -{ - if (binsz==0) - return true; - - const char * data_bin = data; - size_t full_block_count = binsz / full_block_size; - size_t last_block_size = binsz % full_block_size; - size_t res_size = full_block_count * full_encoded_block_size + encoded_block_sizes[last_block_size]; - - if (b58sz){ - if (res_size >= *b58sz){ - return false; - } - *b58sz = res_size; - } - - for (size_t i = 0; i < full_block_count; ++i) - { - encode_block(data_bin + i * full_block_size, full_block_size, b58 + i * full_encoded_block_size); - } - - if (0 < last_block_size) - { - encode_block(data_bin + full_block_count * full_block_size, last_block_size, b58 + full_block_count * full_encoded_block_size); - } - - return true; -} - -bool xmr_base58_decode(const char *b58, size_t b58sz, void *data, size_t *binsz) -{ - if (b58sz == 0) { - *binsz = 0; - return true; - } - - size_t full_block_count = b58sz / full_encoded_block_size; - size_t last_block_size = b58sz % full_encoded_block_size; - int last_block_decoded_size = decoded_block_sizes[last_block_size]; - if (last_block_decoded_size < 0) { - *binsz = 0; - return false; // Invalid enc length - } - - size_t data_size = full_block_count * full_block_size + last_block_decoded_size; - if (*binsz < data_size){ - *binsz = 0; - return false; - } - - char * data_bin = data; - for (size_t i = 0; i < full_block_count; ++i) - { - if (!decode_block(b58 + i * full_encoded_block_size, full_encoded_block_size, data_bin + i * full_block_size)) - return false; - } - - if (0 < last_block_size) - { - if (!decode_block(b58 + full_block_count * full_encoded_block_size, last_block_size, - data_bin + full_block_count * full_block_size)) - return false; - } - - return true; -} - -int xmr_base58_addr_encode_check(uint64_t tag, const uint8_t *data, size_t binsz, char *b58, size_t b58sz) -{ - if (binsz > 128 || tag > 127) { // tag varint - return false; - } - - size_t b58size = b58sz; - uint8_t buf[(binsz + 1) + HASHER_DIGEST_LENGTH]; - memset(buf, 0, sizeof(buf)); - uint8_t *hash = buf + binsz + 1; - buf[0] = (uint8_t) tag; - memcpy(buf + 1, data, binsz); - hasher_Raw(HASHER_SHA3K, buf, binsz + 1, hash); - - bool r = xmr_base58_encode(b58, &b58size, buf, binsz + 1 + addr_checksum_size); - return (int) (!r ? 0 : b58size); -} - -int xmr_base58_addr_decode_check(const char *addr, size_t sz, uint64_t *tag, void *data, size_t datalen) -{ - size_t buflen = 1 + 64 + addr_checksum_size; - uint8_t buf[buflen]; - memset(buf, 0, sizeof(buf)); - uint8_t hash[HASHER_DIGEST_LENGTH] = {0}; - - if (!xmr_base58_decode(addr, sz, buf, &buflen)){ - return 0; - } - - size_t res_size = buflen - addr_checksum_size - 1; - if (datalen < res_size){ - return 0; - } - - if (buflen <= addr_checksum_size+1) { - return 0; - } - - hasher_Raw(HASHER_SHA3K, buf, buflen - addr_checksum_size, hash); - if (memcmp(hash, buf + buflen - addr_checksum_size, addr_checksum_size) != 0){ - return 0; - } - - *tag = buf[0]; - if (*tag > 127){ - return false; // varint - } - - memcpy(data, buf+1, res_size); - return (int) res_size; -} diff --git a/deps/crypto/trezor-crypto/monero/base58.h b/deps/crypto/trezor-crypto/monero/base58.h deleted file mode 100644 index 5486d673a..000000000 --- a/deps/crypto/trezor-crypto/monero/base58.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2014-2018, The Monero Project -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are -// permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of -// conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list -// of conditions and the following disclaimer in the documentation and/or other -// materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be -// used to endorse or promote products derived from this software without specific -// prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers - -#ifndef __XMR_BASE58_H__ -#define __XMR_BASE58_H__ - -#include -#include "hasher.h" -#include "options.h" - -int xmr_base58_addr_encode_check(uint64_t tag, const uint8_t *data, size_t binsz, char *b58, size_t b58sz); -int xmr_base58_addr_decode_check(const char *addr, size_t sz, uint64_t *tag, void *data, size_t datalen); -bool xmr_base58_encode(char *b58, size_t *b58sz, const void *data, size_t binsz); -bool xmr_base58_decode(const char *b58, size_t b58sz, void *data, size_t *binsz); - -#endif diff --git a/deps/crypto/trezor-crypto/monero/int-util.h b/deps/crypto/trezor-crypto/monero/int-util.h deleted file mode 100644 index 9cba47a8b..000000000 --- a/deps/crypto/trezor-crypto/monero/int-util.h +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) 2014-2018, The Monero Project -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are -// permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of -// conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list -// of conditions and the following disclaimer in the documentation and/or other -// materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be -// used to endorse or promote products derived from this software without specific -// prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers - -#pragma once - -#include -#include - -static inline uint64_t hi_dword(uint64_t val) { - return val >> 32; -} - -static inline uint64_t lo_dword(uint64_t val) { - return val & 0xFFFFFFFF; -} - -static inline uint64_t mul128(uint64_t multiplier, uint64_t multiplicand, uint64_t* product_hi) { - // multiplier = ab = a * 2^32 + b - // multiplicand = cd = c * 2^32 + d - // ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d - uint64_t a = hi_dword(multiplier); - uint64_t b = lo_dword(multiplier); - uint64_t c = hi_dword(multiplicand); - uint64_t d = lo_dword(multiplicand); - - uint64_t ac = a * c; - uint64_t ad = a * d; - uint64_t bc = b * c; - uint64_t bd = b * d; - - uint64_t adbc = ad + bc; - uint64_t adbc_carry = adbc < ad ? 1 : 0; - - // multiplier * multiplicand = product_hi * 2^64 + product_lo - uint64_t product_lo = bd + (adbc << 32); - uint64_t product_lo_carry = product_lo < bd ? 1 : 0; - *product_hi = ac + (adbc >> 32) + (adbc_carry << 32) + product_lo_carry; - assert(ac <= *product_hi); - - return product_lo; -} - -#define SWAP64(x) ((((uint64_t) (x) & 0x00000000000000ff) << 56) | \ - (((uint64_t) (x) & 0x000000000000ff00) << 40) | \ - (((uint64_t) (x) & 0x0000000000ff0000) << 24) | \ - (((uint64_t) (x) & 0x00000000ff000000) << 8) | \ - (((uint64_t) (x) & 0x000000ff00000000) >> 8) | \ - (((uint64_t) (x) & 0x0000ff0000000000) >> 24) | \ - (((uint64_t) (x) & 0x00ff000000000000) >> 40) | \ - (((uint64_t) (x) & 0xff00000000000000) >> 56)) diff --git a/deps/crypto/trezor-crypto/monero/monero.h b/deps/crypto/trezor-crypto/monero/monero.h deleted file mode 100644 index ba436c3a3..000000000 --- a/deps/crypto/trezor-crypto/monero/monero.h +++ /dev/null @@ -1,21 +0,0 @@ -// -// Created by Dusan Klinec on 10/05/2018. -// - -#ifndef TREZOR_CRYPTO_MONERO_H -#define TREZOR_CRYPTO_MONERO_H - -#if !USE_MONERO -#error "Compile with -DUSE_MONERO=1" -#endif - -#if !USE_KECCAK -#error "Compile with -DUSE_KECCAK=1" -#endif - -#include "base58.h" -#include "range_proof.h" -#include "serialize.h" -#include "xmr.h" - -#endif // TREZOR_CRYPTO_MONERO_H diff --git a/deps/crypto/trezor-crypto/monero/range_proof.c b/deps/crypto/trezor-crypto/monero/range_proof.c deleted file mode 100644 index e3fd9b6a2..000000000 --- a/deps/crypto/trezor-crypto/monero/range_proof.c +++ /dev/null @@ -1,115 +0,0 @@ -// -// Created by Dusan Klinec on 10/05/2018. -// - -#include "range_proof.h" - -static void xmr_hash_ge25519_to_scalar(bignum256modm r, const ge25519 *p) { - unsigned char buff[32] = {0}; - ge25519_pack(buff, p); - xmr_hash_to_scalar(r, buff, sizeof(buff)); -} - -void xmr_gen_range_sig(xmr_range_sig_t *sig, ge25519 *C, bignum256modm mask, - xmr_amount amount, bignum256modm *last_mask) { - bignum256modm ai[64] = {0}; - bignum256modm alpha[64] = {0}; - xmr_gen_range_sig_ex(sig, C, mask, amount, last_mask, ai, alpha); -} - -void xmr_gen_range_sig_ex(xmr_range_sig_t *sig, ge25519 *C, bignum256modm mask, - xmr_amount amount, bignum256modm *last_mask, - bignum256modm ai[64], bignum256modm alpha[64]) { - const unsigned n = XMR_ATOMS; - bignum256modm a = {0}; - bignum256modm si = {0}; - bignum256modm c = {0}; - bignum256modm ee = {0}; - unsigned char buff[32] = {0}; - - Hasher kck = {0}; - xmr_hasher_init(&kck); - - ge25519 C_acc = {0}; - ge25519 C_h = {0}; - ge25519 C_tmp = {0}; - ge25519 L = {0}; - ge25519 Zero = {0}; - - ge25519_set_neutral(&Zero); - ge25519_set_neutral(&C_acc); - ge25519_set_xmr_h(&C_h); - set256_modm(a, 0); - -#define BB(i) ((amount >> (i)) & 1) - - // First pass, generates: ai, alpha, Ci, ee, s1 - for (unsigned ii = 0; ii < n; ++ii) { - xmr_random_scalar(ai[ii]); - if (last_mask != NULL && ii == n - 1) { - sub256_modm(ai[ii], *last_mask, a); - } - - add256_modm(a, a, ai[ii]); // creating the total mask since you have to - // pass this to receiver... - xmr_random_scalar(alpha[ii]); - - ge25519_scalarmult_base_niels(&L, ge25519_niels_base_multiples, alpha[ii]); - ge25519_scalarmult_base_niels(&C_tmp, ge25519_niels_base_multiples, ai[ii]); - - // C_tmp += &Zero if BB(ii) == 0 else &C_h - ge25519_add(&C_tmp, &C_tmp, BB(ii) == 0 ? &Zero : &C_h, 0); - ge25519_add(&C_acc, &C_acc, &C_tmp, 0); - - // Set Ci[ii] to sigs - ge25519_pack(sig->Ci[ii], &C_tmp); - - if (BB(ii) == 0) { - xmr_random_scalar(si); - xmr_hash_ge25519_to_scalar(c, &L); - - ge25519_add(&C_tmp, &C_tmp, &C_h, 1); // Ci[ii] -= c_h - xmr_add_keys2_vartime(&L, si, c, &C_tmp); - - // Set s1[ii] to sigs - contract256_modm(sig->asig.s1[ii], si); - } - - ge25519_pack(buff, &L); - xmr_hasher_update(&kck, buff, sizeof(buff)); - - ge25519_double(&C_h, &C_h); // c_H = crypto.scalarmult(c_H, 2) - } - - // Compute ee - xmr_hasher_final(&kck, buff); - expand256_modm(ee, buff, sizeof(buff)); - - ge25519_set_xmr_h(&C_h); - - // Second pass, s0, s1 - for (unsigned ii = 0; ii < n; ++ii) { - if (BB(ii) == 0) { - mulsub256_modm(si, ai[ii], ee, alpha[ii]); - contract256_modm(sig->asig.s0[ii], si); - - } else { - xmr_random_scalar(si); - contract256_modm(sig->asig.s0[ii], si); - - ge25519_unpack_vartime(&C_tmp, sig->Ci[ii]); - xmr_add_keys2_vartime(&L, si, ee, &C_tmp); - xmr_hash_ge25519_to_scalar(c, &L); - - mulsub256_modm(si, ai[ii], c, alpha[ii]); - contract256_modm(sig->asig.s1[ii], si); - } - - ge25519_double(&C_h, &C_h); // c_H = crypto.scalarmult(c_H, 2) - } - - ge25519_copy(C, &C_acc); - copy256_modm(mask, a); - contract256_modm(sig->asig.ee, ee); -#undef BB -} diff --git a/deps/crypto/trezor-crypto/monero/range_proof.h b/deps/crypto/trezor-crypto/monero/range_proof.h deleted file mode 100644 index f614ab04e..000000000 --- a/deps/crypto/trezor-crypto/monero/range_proof.h +++ /dev/null @@ -1,31 +0,0 @@ -// -// Created by Dusan Klinec on 10/05/2018. -// - -#ifndef TREZOR_CRYPTO_RANGE_PROOF_H -#define TREZOR_CRYPTO_RANGE_PROOF_H - -#include "xmr.h" -#define XMR_ATOMS 64 - -typedef uint64_t xmr_amount; -typedef xmr_key_t xmr_key64_t[64]; - -typedef struct xmr_boro_sig { - xmr_key64_t s0; - xmr_key64_t s1; - xmr_key_t ee; -} xmr_boro_sig_t; - -typedef struct range_sig { - xmr_boro_sig_t asig; - xmr_key64_t Ci; -} xmr_range_sig_t; - -void xmr_gen_range_sig(xmr_range_sig_t* sig, ge25519* C, bignum256modm mask, - xmr_amount amount, bignum256modm* last_mask); -void xmr_gen_range_sig_ex(xmr_range_sig_t* sig, ge25519* C, bignum256modm mask, - xmr_amount amount, bignum256modm* last_mask, - bignum256modm ai[64], bignum256modm alpha[64]); - -#endif // TREZOR_CRYPTO_RANGE_PROOF_H diff --git a/deps/crypto/trezor-crypto/monero/serialize.c b/deps/crypto/trezor-crypto/monero/serialize.c deleted file mode 100644 index 4d4cbd8bb..000000000 --- a/deps/crypto/trezor-crypto/monero/serialize.c +++ /dev/null @@ -1,53 +0,0 @@ -// -// Created by Dusan Klinec on 02/05/2018. -// - -#include "serialize.h" - -int xmr_size_varint(uint64_t num) { - int ctr = 1; - while (num >= 0x80) { - ++ctr; - num >>= 7; - } - return ctr; -} - -int xmr_write_varint(uint8_t *buff, size_t buff_size, uint64_t num) { - unsigned ctr = 0; - while (num >= 0x80 && ctr < buff_size) { - *buff = (uint8_t)(((num)&0x7f) | 0x80); - ++buff; - ++ctr; - num >>= 7; - } - - /* writes the last one to dest */ - if (ctr < buff_size) { - *buff = (uint8_t)num; - ++ctr; - } - return ctr <= buff_size ? (int)ctr : -1; -} - -int xmr_read_varint(uint8_t *buff, size_t buff_size, uint64_t *val) { - unsigned read = 0; - int finished_ok = 0; - *val = 0; - - for (int shift = 0; read < buff_size; shift += 7, ++read) { - uint8_t byte = buff[read]; - if ((byte == 0 && shift != 0) || (shift >= 63 && byte > 1)) { - return -1; - } - - *val |= (uint64_t)(byte & 0x7f) << shift; - - /* If there is no next */ - if ((byte & 0x80) == 0) { - finished_ok = 1; - break; - } - } - return finished_ok ? (int)read + 1 : -2; -} diff --git a/deps/crypto/trezor-crypto/monero/serialize.h b/deps/crypto/trezor-crypto/monero/serialize.h deleted file mode 100644 index 8d3499007..000000000 --- a/deps/crypto/trezor-crypto/monero/serialize.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// Created by Dusan Klinec on 02/05/2018. -// - -#ifndef TREZOR_XMR_SERIALIZE_H -#define TREZOR_XMR_SERIALIZE_H - -#include -#include - -int xmr_size_varint(uint64_t num); -int xmr_write_varint(uint8_t *buff, size_t buff_size, uint64_t num); -int xmr_read_varint(uint8_t *buff, size_t buff_size, uint64_t *val); - -#endif // TREZOR_XMR_SERIALIZE_H diff --git a/deps/crypto/trezor-crypto/monero/xmr.c b/deps/crypto/trezor-crypto/monero/xmr.c deleted file mode 100644 index a49e8a2ae..000000000 --- a/deps/crypto/trezor-crypto/monero/xmr.c +++ /dev/null @@ -1,143 +0,0 @@ -// -// Created by Dusan Klinec on 10/05/2018. -// - -#include "xmr.h" -#include "int-util.h" -#include "rand.h" -#include "serialize.h" - -const ge25519 ALIGN(16) xmr_h = { - {0x1861ec7, 0x1ceac77, 0x2f11626, 0x1f261d3, 0x346107c, 0x06d8c4a, - 0x254201d, 0x1675c09, 0x1301c3f, 0x0211d73}, - {0x326feb4, 0x12e30cc, 0x0cf54b4, 0x1117305, 0x318f5d5, 0x06cf754, - 0x2e578a1, 0x1daf058, 0x34430a1, 0x04410e9}, - {0x0fde4d2, 0x0774049, 0x22ca951, 0x05aec2b, 0x07a36a5, 0x1394f13, - 0x3c5385c, 0x1adb924, 0x2b6c581, 0x0a55fa4}, - {0x24517f7, 0x05ee936, 0x3acf5d9, 0x14b08aa, 0x3363738, 0x1051745, - 0x360601e, 0x0f3f2c9, 0x1ead2cd, 0x1d3e3df}}; - -void ge25519_set_xmr_h(ge25519 *r) { ge25519_copy(r, &xmr_h); } - -void xmr_random_scalar(bignum256modm m) { - unsigned char buff[32] = {0}; - random_buffer(buff, sizeof(buff)); - expand256_modm(m, buff, sizeof(buff)); -} - -void xmr_fast_hash(uint8_t *hash, const void *data, size_t length) { - hasher_Raw(HASHER_SHA3K, data, length, hash); -} - -void xmr_hasher_init(Hasher *hasher) { hasher_Init(hasher, HASHER_SHA3K); } - -void xmr_hasher_update(Hasher *hasher, const void *data, size_t length) { - hasher_Update(hasher, data, length); -} - -void xmr_hasher_final(Hasher *hasher, uint8_t *hash) { - hasher_Final(hasher, hash); -} - -void xmr_hasher_copy(Hasher *dst, const Hasher *src) { - memcpy(dst, src, sizeof(Hasher)); -} - -void xmr_hash_to_scalar(bignum256modm r, const void *data, size_t length) { - uint8_t hash[HASHER_DIGEST_LENGTH] = {0}; - hasher_Raw(HASHER_SHA3K, data, length, hash); - expand256_modm(r, hash, HASHER_DIGEST_LENGTH); -} - -void xmr_hash_to_ec(ge25519 *P, const void *data, size_t length) { - ge25519 point2 = {0}; - uint8_t hash[HASHER_DIGEST_LENGTH] = {0}; - hasher_Raw(HASHER_SHA3K, data, length, hash); - - ge25519_fromfe_frombytes_vartime(&point2, hash); - ge25519_mul8(P, &point2); -} - -void xmr_derivation_to_scalar(bignum256modm s, const ge25519 *p, - uint32_t output_index) { - uint8_t buff[32 + 8] = {0}; - ge25519_pack(buff, p); - int written = xmr_write_varint(buff + 32, 8, output_index); - xmr_hash_to_scalar(s, buff, 32u + written); -} - -void xmr_generate_key_derivation(ge25519 *r, const ge25519 *A, - const bignum256modm b) { - ge25519 bA = {0}; - ge25519_scalarmult(&bA, A, b); - ge25519_mul8(r, &bA); -} - -void xmr_derive_private_key(bignum256modm s, const ge25519 *deriv, uint32_t idx, - const bignum256modm base) { - xmr_derivation_to_scalar(s, deriv, idx); - add256_modm(s, s, base); -} - -void xmr_derive_public_key(ge25519 *r, const ge25519 *deriv, uint32_t idx, - const ge25519 *base) { - bignum256modm s = {0}; - ge25519 p2 = {0}; - - xmr_derivation_to_scalar(s, deriv, idx); - ge25519_scalarmult_base_niels(&p2, ge25519_niels_base_multiples, s); - ge25519_add(r, base, &p2, 0); -} - -void xmr_add_keys2(ge25519 *r, const bignum256modm a, const bignum256modm b, - const ge25519 *B) { - // aG + bB, G is basepoint - ge25519 aG = {0}, bB = {0}; - ge25519_scalarmult_base_niels(&aG, ge25519_niels_base_multiples, a); - ge25519_scalarmult(&bB, B, b); - ge25519_add(r, &aG, &bB, 0); -} - -void xmr_add_keys2_vartime(ge25519 *r, const bignum256modm a, - const bignum256modm b, const ge25519 *B) { - // aG + bB, G is basepoint - ge25519_double_scalarmult_vartime(r, B, b, a); -} - -void xmr_add_keys3(ge25519 *r, const bignum256modm a, const ge25519 *A, - const bignum256modm b, const ge25519 *B) { - // aA + bB - ge25519 aA = {0}, bB = {0}; - ge25519_scalarmult(&aA, A, a); - ge25519_scalarmult(&bB, B, b); - ge25519_add(r, &aA, &bB, 0); -} - -void xmr_add_keys3_vartime(ge25519 *r, const bignum256modm a, const ge25519 *A, - const bignum256modm b, const ge25519 *B) { - // aA + bB - ge25519_double_scalarmult_vartime2(r, A, a, B, b); -} - -void xmr_get_subaddress_secret_key(bignum256modm r, uint32_t major, - uint32_t minor, const bignum256modm m) { - const char prefix[] = "SubAddr"; - unsigned char buff[32] = {0}; - contract256_modm(buff, m); - - char data[sizeof(prefix) + sizeof(buff) + 2 * sizeof(uint32_t)] = {0}; - memcpy(data, prefix, sizeof(prefix)); - memcpy(data + sizeof(prefix), buff, sizeof(buff)); - memcpy(data + sizeof(prefix) + sizeof(buff), &major, sizeof(uint32_t)); - memcpy(data + sizeof(prefix) + sizeof(buff) + sizeof(uint32_t), &minor, - sizeof(uint32_t)); - - xmr_hash_to_scalar(r, data, sizeof(data)); -} - -void xmr_gen_c(ge25519 *r, const bignum256modm a, uint64_t amount) { - // C = aG + bH - bignum256modm b = {0}; - set256_modm(b, amount); - xmr_add_keys2(r, a, b, &xmr_h); -} diff --git a/deps/crypto/trezor-crypto/monero/xmr.h b/deps/crypto/trezor-crypto/monero/xmr.h deleted file mode 100644 index 4ef83a06b..000000000 --- a/deps/crypto/trezor-crypto/monero/xmr.h +++ /dev/null @@ -1,76 +0,0 @@ -// -// Created by Dusan Klinec on 10/05/2018. -// - -#ifndef TREZOR_CRYPTO_XMR_H -#define TREZOR_CRYPTO_XMR_H - -#include "ed25519-donna/ed25519-donna.h" -#include "hasher.h" - -extern const ge25519 ALIGN(16) xmr_h; - -typedef unsigned char xmr_key_t[32]; - -typedef struct xmr_ctkey { - xmr_key_t dest; - xmr_key_t mask; -} xmr_ctkey_t; - -/* sets H point to r */ -void ge25519_set_xmr_h(ge25519 *r); - -/* random scalar value */ -void xmr_random_scalar(bignum256modm m); - -/* cn_fast_hash */ -void xmr_fast_hash(uint8_t *hash, const void *data, size_t length); - -/* incremental hashing wrappers */ -void xmr_hasher_init(Hasher *hasher); -void xmr_hasher_update(Hasher *hasher, const void *data, size_t length); -void xmr_hasher_final(Hasher *hasher, uint8_t *hash); -void xmr_hasher_copy(Hasher *dst, const Hasher *src); - -/* H_s(buffer) */ -void xmr_hash_to_scalar(bignum256modm r, const void *data, size_t length); - -/* H_p(buffer) */ -void xmr_hash_to_ec(ge25519 *P, const void *data, size_t length); - -/* derivation to scalar value */ -void xmr_derivation_to_scalar(bignum256modm s, const ge25519 *p, - uint32_t output_index); - -/* derivation */ -void xmr_generate_key_derivation(ge25519 *r, const ge25519 *A, - const bignum256modm b); - -/* H_s(derivation || varint(output_index)) + base */ -void xmr_derive_private_key(bignum256modm s, const ge25519 *deriv, uint32_t idx, - const bignum256modm base); - -/* H_s(derivation || varint(output_index))G + base */ -void xmr_derive_public_key(ge25519 *r, const ge25519 *deriv, uint32_t idx, - const ge25519 *base); - -/* aG + bB, G is basepoint */ -void xmr_add_keys2(ge25519 *r, const bignum256modm a, const bignum256modm b, - const ge25519 *B); -void xmr_add_keys2_vartime(ge25519 *r, const bignum256modm a, - const bignum256modm b, const ge25519 *B); - -/* aA + bB */ -void xmr_add_keys3(ge25519 *r, const bignum256modm a, const ge25519 *A, - const bignum256modm b, const ge25519 *B); -void xmr_add_keys3_vartime(ge25519 *r, const bignum256modm a, const ge25519 *A, - const bignum256modm b, const ge25519 *B); - -/* subaddress secret */ -void xmr_get_subaddress_secret_key(bignum256modm r, uint32_t major, - uint32_t minor, const bignum256modm m); - -/* Generates Pedersen commitment C = aG + bH */ -void xmr_gen_c(ge25519 *r, const bignum256modm a, uint64_t amount); - -#endif // TREZOR_CRYPTO_XMR_H diff --git a/deps/crypto/trezor-crypto/nano.c b/deps/crypto/trezor-crypto/nano.c deleted file mode 100644 index ad73a20d7..000000000 --- a/deps/crypto/trezor-crypto/nano.c +++ /dev/null @@ -1,155 +0,0 @@ -/** - * Copyright (c) 2019 Mart Roosmaa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#if USE_NANO - -#include - -#include "nano.h" -#include "blake2b.h" -#include "base32.h" - -const char *BASE32_ALPHABET_NANO = "13456789abcdefghijkmnopqrstuwxyz"; - -#define NANO_ADDRESS_BASE_LENGTH 60 -#define NANO_CHECKSUM_LEN 5 - -typedef union { - uint8_t bytes[40]; - struct { - uint8_t padding[3]; - ed25519_public_key public_key; - uint8_t checksum[NANO_CHECKSUM_LEN]; - } data; -} nano_address_raw; - -typedef union { - char chars[65]; - struct { - char padding[4]; // 1111 - char address[NANO_ADDRESS_BASE_LENGTH]; - char terminator; // \0 - } data; -} nano_address_encoded; - -size_t nano_get_address( - const ed25519_public_key public_key, - const char *prefix, - const size_t prefix_len, - char *out, - size_t out_len -) { - if (out_len < prefix_len + NANO_ADDRESS_BASE_LENGTH + 1) { - return 0; - } - - // Construct raw address which is going to be base32 encoded - nano_address_raw raw; - memset(&raw, 0, sizeof(nano_address_raw)); - - uint8_t checksum[NANO_CHECKSUM_LEN]; - blake2b_state hash; - blake2b_Init(&hash, NANO_CHECKSUM_LEN); - blake2b_Update(&hash, public_key, sizeof(ed25519_public_key)); - blake2b_Final(&hash, checksum, NANO_CHECKSUM_LEN); - - for (int i = 0; i < NANO_CHECKSUM_LEN; i++) { - raw.data.checksum[NANO_CHECKSUM_LEN - (i + 1)] = checksum[i]; - } - memcpy(raw.data.public_key, public_key, sizeof(ed25519_public_key)); - - // Encode the address into a buffer and compose the final output - nano_address_encoded encoded; - memset(&encoded, 0, sizeof(nano_address_encoded)); - char *ret = base32_encode( - raw.bytes, sizeof(nano_address_raw), - encoded.chars, sizeof(encoded.chars), - BASE32_ALPHABET_NANO); - if (ret == NULL) { - return 0; - } - - size_t w = 0; - memcpy(&out[w], prefix, prefix_len); - w += prefix_len; - memcpy(&out[w], encoded.data.address, NANO_ADDRESS_BASE_LENGTH); - w += NANO_ADDRESS_BASE_LENGTH; - out[w] = 0; - w += 1; - return w; -} - -bool nano_validate_address( - const char *prefix, - const size_t prefix_len, - const char *address, - const size_t address_len, - ed25519_public_key out_public_key -) { - if (address_len != prefix_len + NANO_ADDRESS_BASE_LENGTH) { - return false; - } - - // Validate that the prefix matches - if (memcmp(address, prefix, prefix_len) != 0) { - return false; - } - - // Try to decode the address - nano_address_encoded encoded; - memcpy(encoded.data.padding, "1111", sizeof(encoded.data.padding)); - memcpy(encoded.data.address, &address[prefix_len], NANO_ADDRESS_BASE_LENGTH); - encoded.data.terminator = '\0'; - - nano_address_raw raw; - memset(&raw, 0, sizeof(nano_address_raw)); - uint8_t *ret = base32_decode( - encoded.chars, strlen(encoded.chars), - raw.bytes, sizeof(nano_address_raw), - BASE32_ALPHABET_NANO - ); - if (ret == NULL) { - return false; - } - - // Validate the checksum - uint8_t checksum[NANO_CHECKSUM_LEN]; - blake2b_state hash; - blake2b_Init(&hash, NANO_CHECKSUM_LEN); - blake2b_Update(&hash, raw.data.public_key, sizeof(ed25519_public_key)); - blake2b_Final(&hash, checksum, NANO_CHECKSUM_LEN); - - for (int i = 0; i < NANO_CHECKSUM_LEN; i++) { - if (raw.data.checksum[NANO_CHECKSUM_LEN - (i + 1)] != checksum[i]) { - return false; - } - } - - // Output the public key if the caller is interested in it - if (out_public_key != NULL) { - memcpy(out_public_key, raw.data.public_key, sizeof(ed25519_public_key)); - } - - return true; -} - -#endif \ No newline at end of file diff --git a/deps/crypto/trezor-crypto/nano.h b/deps/crypto/trezor-crypto/nano.h deleted file mode 100644 index e2c139b72..000000000 --- a/deps/crypto/trezor-crypto/nano.h +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Copyright (c) 2019 Mart Roosmaa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __NANO_H__ -#define __NANO_H__ - -#if USE_NANO - -#include -#include -#include - -#include "ed25519-donna/ed25519.h" - -extern const char *BASE32_ALPHABET_NANO; - -size_t nano_get_address( - const ed25519_public_key public_key, - const char *prefix, - const size_t prefix_len, - char *out, - size_t out_len); - -bool nano_validate_address( - const char *prefix, - const size_t prefix_len, - const char *address, - const size_t address_len, - ed25519_public_key out_public_key); - -#endif - -#endif \ No newline at end of file diff --git a/deps/crypto/trezor-crypto/nem.c b/deps/crypto/trezor-crypto/nem.c deleted file mode 100644 index dd77241ce..000000000 --- a/deps/crypto/trezor-crypto/nem.c +++ /dev/null @@ -1,507 +0,0 @@ -/** - * Copyright (c) 2017 Saleem Rashid - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, E1PRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "nem.h" - -#include - -#include "base32.h" -#include "ed25519-donna/ed25519-keccak.h" -#include "memzero.h" -#include "ripemd160.h" -#include "sha3.h" - -#define CAN_WRITE(NEEDED) ((ctx->offset + (NEEDED)) <= ctx->size) - -#define SERIALIZE_U32(DATA) \ - do { \ - if (!nem_write_u32(ctx, (DATA))) return false; \ - } while (0) -#define SERIALIZE_U64(DATA) \ - do { \ - if (!nem_write_u64(ctx, (DATA))) return false; \ - } while (0) -#define SERIALIZE_TAGGED(DATA, LENGTH) \ - do { \ - if (!nem_write_tagged(ctx, (DATA), (LENGTH))) return false; \ - } while (0) - -const char *nem_network_name(uint8_t network) { - switch (network) { - case NEM_NETWORK_MAINNET: - return "NEM Mainnet"; - case NEM_NETWORK_TESTNET: - return "NEM Testnet"; - case NEM_NETWORK_MIJIN: - return "Mijin"; - default: - return NULL; - } -} - -static inline bool nem_write_checked(nem_transaction_ctx *ctx, - const uint8_t *data, uint32_t length) { - if (!CAN_WRITE(length)) { - return false; - } - - memcpy(&ctx->buffer[ctx->offset], data, length); - ctx->offset += length; - return true; -} - -static inline bool nem_write_u32(nem_transaction_ctx *ctx, uint32_t data) { - if (!CAN_WRITE(4)) { - return false; - } - - ctx->buffer[ctx->offset++] = (data >> 0) & 0xff; - ctx->buffer[ctx->offset++] = (data >> 8) & 0xff; - ctx->buffer[ctx->offset++] = (data >> 16) & 0xff; - ctx->buffer[ctx->offset++] = (data >> 24) & 0xff; - - return true; -} - -static inline bool nem_write_u64(nem_transaction_ctx *ctx, uint64_t data) { - SERIALIZE_U32((data >> 0) & 0xffffffff); - SERIALIZE_U32((data >> 32) & 0xffffffff); - - return true; -} - -static inline bool nem_write_tagged(nem_transaction_ctx *ctx, - const uint8_t *data, uint32_t length) { - SERIALIZE_U32(length); - - return nem_write_checked(ctx, data, length); -} - -static inline bool nem_write_mosaic_str(nem_transaction_ctx *ctx, - const char *name, const char *value) { - uint32_t name_length = strlen(name); - uint32_t value_length = strlen(value); - - SERIALIZE_U32(sizeof(uint32_t) + name_length + sizeof(uint32_t) + - value_length); - SERIALIZE_TAGGED((const uint8_t *)name, name_length); - SERIALIZE_TAGGED((const uint8_t *)value, value_length); - - return true; -} - -static inline bool nem_write_mosaic_bool(nem_transaction_ctx *ctx, - const char *name, bool value) { - return nem_write_mosaic_str(ctx, name, value ? "true" : "false"); -} - -static inline bool nem_write_mosaic_u64(nem_transaction_ctx *ctx, - const char *name, uint64_t value) { - char buffer[21] = {0}; - - if (bn_format_uint64(value, NULL, NULL, 0, 0, false, buffer, - sizeof(buffer)) == 0) { - return false; - } - - return nem_write_mosaic_str(ctx, name, buffer); -} - -void nem_get_address_raw(const ed25519_public_key public_key, uint8_t version, - uint8_t *address) { - uint8_t hash[SHA3_256_DIGEST_LENGTH] = {0}; - - /* 1. Perform 256-bit Sha3 on the public key */ - keccak_256(public_key, sizeof(ed25519_public_key), hash); - - /* 2. Perform 160-bit Ripemd of hash resulting from step 1. */ - ripemd160(hash, SHA3_256_DIGEST_LENGTH, &address[1]); - - /* 3. Prepend version byte to Ripemd hash (either 0x68 or 0x98) */ - address[0] = version; - - /* 4. Perform 256-bit Sha3 on the result, take the first four bytes as a - * checksum */ - keccak_256(address, 1 + RIPEMD160_DIGEST_LENGTH, hash); - - /* 5. Concatenate output of step 3 and the checksum from step 4 */ - memcpy(&address[1 + RIPEMD160_DIGEST_LENGTH], hash, 4); - - memzero(hash, sizeof(hash)); -} - -bool nem_get_address(const ed25519_public_key public_key, uint8_t version, - char *address) { - uint8_t pubkeyhash[NEM_ADDRESS_SIZE_RAW] = {0}; - - nem_get_address_raw(public_key, version, pubkeyhash); - - char *ret = base32_encode(pubkeyhash, sizeof(pubkeyhash), address, - NEM_ADDRESS_SIZE + 1, BASE32_ALPHABET_RFC4648); - - memzero(pubkeyhash, sizeof(pubkeyhash)); - return (ret != NULL); -} - -bool nem_validate_address_raw(const uint8_t *address, uint8_t network) { - if (!nem_network_name(network) || address[0] != network) { - return false; - } - - uint8_t hash[SHA3_256_DIGEST_LENGTH] = {0}; - - keccak_256(address, 1 + RIPEMD160_DIGEST_LENGTH, hash); - bool valid = (memcmp(&address[1 + RIPEMD160_DIGEST_LENGTH], hash, 4) == 0); - - memzero(hash, sizeof(hash)); - return valid; -} - -bool nem_validate_address(const char *address, uint8_t network) { - uint8_t pubkeyhash[NEM_ADDRESS_SIZE_RAW] = {0}; - - if (strlen(address) != NEM_ADDRESS_SIZE) { - return false; - } - - uint8_t *ret = base32_decode(address, NEM_ADDRESS_SIZE, pubkeyhash, - sizeof(pubkeyhash), BASE32_ALPHABET_RFC4648); - bool valid = (ret != NULL) && nem_validate_address_raw(pubkeyhash, network); - - memzero(pubkeyhash, sizeof(pubkeyhash)); - return valid; -} - -void nem_transaction_start(nem_transaction_ctx *ctx, - const ed25519_public_key public_key, uint8_t *buffer, - size_t size) { - memcpy(ctx->public_key, public_key, sizeof(ctx->public_key)); - - ctx->buffer = buffer; - ctx->offset = 0; - ctx->size = size; -} - -size_t nem_transaction_end(nem_transaction_ctx *ctx, - const ed25519_secret_key private_key, - ed25519_signature signature) { - if (private_key != NULL && signature != NULL) { - ed25519_sign_keccak(ctx->buffer, ctx->offset, private_key, signature); - } - - return ctx->offset; -} - -bool nem_transaction_write_common(nem_transaction_ctx *ctx, uint32_t type, - uint32_t version, uint32_t timestamp, - const ed25519_public_key signer, uint64_t fee, - uint32_t deadline) { - SERIALIZE_U32(type); - SERIALIZE_U32(version); - SERIALIZE_U32(timestamp); - SERIALIZE_TAGGED(signer, sizeof(ed25519_public_key)); - SERIALIZE_U64(fee); - SERIALIZE_U32(deadline); - - return true; -} - -bool nem_transaction_create_transfer(nem_transaction_ctx *ctx, uint8_t network, - uint32_t timestamp, - const ed25519_public_key signer, - uint64_t fee, uint32_t deadline, - const char *recipient, uint64_t amount, - const uint8_t *payload, uint32_t length, - bool encrypted, uint32_t mosaics) { - if (!signer) { - signer = ctx->public_key; - } - - if (!payload) { - length = 0; - } - - bool ret = - nem_transaction_write_common(ctx, NEM_TRANSACTION_TYPE_TRANSFER, - (uint32_t)network << 24 | (mosaics ? 2 : 1), - timestamp, signer, fee, deadline); - if (!ret) return false; - - SERIALIZE_TAGGED((const uint8_t *)recipient, NEM_ADDRESS_SIZE); - SERIALIZE_U64(amount); - - if (length) { - SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint32_t) + length); - SERIALIZE_U32(encrypted ? 0x02 : 0x01); - SERIALIZE_TAGGED(payload, length); - } else { - SERIALIZE_U32(0); - } - - if (mosaics) { - SERIALIZE_U32(mosaics); - } - - return true; -} - -bool nem_transaction_write_mosaic(nem_transaction_ctx *ctx, - const char *namespace, const char *mosaic, - uint64_t quantity) { - size_t namespace_length = strlen(namespace); - size_t mosaic_length = strlen(mosaic); - size_t identifier_length = - sizeof(uint32_t) + namespace_length + sizeof(uint32_t) + mosaic_length; - - SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint64_t) + identifier_length); - SERIALIZE_U32(identifier_length); - SERIALIZE_TAGGED((const uint8_t *)namespace, namespace_length); - SERIALIZE_TAGGED((const uint8_t *)mosaic, mosaic_length); - SERIALIZE_U64(quantity); - - return true; -} - -bool nem_transaction_create_multisig(nem_transaction_ctx *ctx, uint8_t network, - uint32_t timestamp, - const ed25519_public_key signer, - uint64_t fee, uint32_t deadline, - const nem_transaction_ctx *inner) { - if (!signer) { - signer = ctx->public_key; - } - - bool ret = nem_transaction_write_common(ctx, NEM_TRANSACTION_TYPE_MULTISIG, - (uint32_t)network << 24 | 1, - timestamp, signer, fee, deadline); - if (!ret) return false; - - SERIALIZE_TAGGED(inner->buffer, inner->offset); - - return true; -} - -bool nem_transaction_create_multisig_signature( - nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, - const ed25519_public_key signer, uint64_t fee, uint32_t deadline, - const nem_transaction_ctx *inner) { - if (!signer) { - signer = ctx->public_key; - } - - bool ret = nem_transaction_write_common( - ctx, NEM_TRANSACTION_TYPE_MULTISIG_SIGNATURE, (uint32_t)network << 24 | 1, - timestamp, signer, fee, deadline); - if (!ret) return false; - - char address[NEM_ADDRESS_SIZE + 1] = {0}; - nem_get_address(inner->public_key, network, address); - - uint8_t hash[SHA3_256_DIGEST_LENGTH] = {0}; - keccak_256(inner->buffer, inner->offset, hash); - - SERIALIZE_U32(sizeof(uint32_t) + SHA3_256_DIGEST_LENGTH); - SERIALIZE_TAGGED(hash, SHA3_256_DIGEST_LENGTH); - SERIALIZE_TAGGED((const uint8_t *)address, NEM_ADDRESS_SIZE); - - return true; -} - -bool nem_transaction_create_provision_namespace( - nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, - const ed25519_public_key signer, uint64_t fee, uint32_t deadline, - const char *namespace, const char *parent, const char *rental_sink, - uint64_t rental_fee) { - if (!signer) { - signer = ctx->public_key; - } - - bool ret = nem_transaction_write_common( - ctx, NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE, - (uint32_t)network << 24 | 1, timestamp, signer, fee, deadline); - if (!ret) return false; - - if (parent) { - SERIALIZE_TAGGED((const uint8_t *)rental_sink, NEM_ADDRESS_SIZE); - SERIALIZE_U64(rental_fee); - SERIALIZE_TAGGED((const uint8_t *)namespace, strlen(namespace)); - SERIALIZE_TAGGED((const uint8_t *)parent, strlen(parent)); - } else { - SERIALIZE_TAGGED((const uint8_t *)rental_sink, NEM_ADDRESS_SIZE); - SERIALIZE_U64(rental_fee); - SERIALIZE_TAGGED((const uint8_t *)namespace, strlen(namespace)); - SERIALIZE_U32(0xffffffff); - } - - return true; -} - -bool nem_transaction_create_mosaic_creation( - nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, - const ed25519_public_key signer, uint64_t fee, uint32_t deadline, - const char *namespace, const char *mosaic, const char *description, - uint32_t divisibility, uint64_t supply, bool mutable_supply, - bool transferable, uint32_t levy_type, uint64_t levy_fee, - const char *levy_address, const char *levy_namespace, - const char *levy_mosaic, const char *creation_sink, uint64_t creation_fee) { - if (!signer) { - signer = ctx->public_key; - } - - bool ret = nem_transaction_write_common( - ctx, NEM_TRANSACTION_TYPE_MOSAIC_CREATION, (uint32_t)network << 24 | 1, - timestamp, signer, fee, deadline); - if (!ret) return false; - - size_t namespace_length = strlen(namespace); - size_t mosaic_length = strlen(mosaic); - size_t identifier_length = - sizeof(uint32_t) + namespace_length + sizeof(uint32_t) + mosaic_length; - - // This length will be rewritten later on - nem_transaction_ctx state = {0}; - memcpy(&state, ctx, sizeof(state)); - - SERIALIZE_U32(0); - SERIALIZE_TAGGED(signer, sizeof(ed25519_public_key)); - SERIALIZE_U32(identifier_length); - SERIALIZE_TAGGED((const uint8_t *)namespace, namespace_length); - SERIALIZE_TAGGED((const uint8_t *)mosaic, mosaic_length); - SERIALIZE_TAGGED((const uint8_t *)description, strlen(description)); - SERIALIZE_U32(4); // Number of properties - - if (!nem_write_mosaic_u64(ctx, "divisibility", divisibility)) return false; - if (!nem_write_mosaic_u64(ctx, "initialSupply", supply)) return false; - if (!nem_write_mosaic_bool(ctx, "supplyMutable", mutable_supply)) - return false; - if (!nem_write_mosaic_bool(ctx, "transferable", transferable)) return false; - - if (levy_type) { - size_t levy_namespace_length = strlen(levy_namespace); - size_t levy_mosaic_length = strlen(levy_mosaic); - size_t levy_identifier_length = sizeof(uint32_t) + levy_namespace_length + - sizeof(uint32_t) + levy_mosaic_length; - - SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint32_t) + NEM_ADDRESS_SIZE + - sizeof(uint32_t) + levy_identifier_length + sizeof(uint64_t)); - SERIALIZE_U32(levy_type); - SERIALIZE_TAGGED((const uint8_t *)levy_address, NEM_ADDRESS_SIZE); - SERIALIZE_U32(levy_identifier_length); - SERIALIZE_TAGGED((const uint8_t *)levy_namespace, levy_namespace_length); - SERIALIZE_TAGGED((const uint8_t *)levy_mosaic, levy_mosaic_length); - SERIALIZE_U64(levy_fee); - } else { - SERIALIZE_U32(0); - } - - // Rewrite length - nem_write_u32(&state, ctx->offset - state.offset - sizeof(uint32_t)); - - SERIALIZE_TAGGED((const uint8_t *)creation_sink, NEM_ADDRESS_SIZE); - SERIALIZE_U64(creation_fee); - - return true; -} - -bool nem_transaction_create_mosaic_supply_change( - nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, - const ed25519_public_key signer, uint64_t fee, uint32_t deadline, - const char *namespace, const char *mosaic, uint32_t type, uint64_t delta) { - if (!signer) { - signer = ctx->public_key; - } - - bool ret = nem_transaction_write_common( - ctx, NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE, - (uint32_t)network << 24 | 1, timestamp, signer, fee, deadline); - if (!ret) return false; - - size_t namespace_length = strlen(namespace); - size_t mosaic_length = strlen(mosaic); - size_t identifier_length = - sizeof(uint32_t) + namespace_length + sizeof(uint32_t) + mosaic_length; - - SERIALIZE_U32(identifier_length); - SERIALIZE_TAGGED((const uint8_t *)namespace, namespace_length); - SERIALIZE_TAGGED((const uint8_t *)mosaic, mosaic_length); - SERIALIZE_U32(type); - SERIALIZE_U64(delta); - - return true; -} - -bool nem_transaction_create_aggregate_modification( - nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, - const ed25519_public_key signer, uint64_t fee, uint32_t deadline, - uint32_t modifications, bool relative_change) { - if (!signer) { - signer = ctx->public_key; - } - - bool ret = nem_transaction_write_common( - ctx, NEM_TRANSACTION_TYPE_AGGREGATE_MODIFICATION, - (uint32_t)network << 24 | (relative_change ? 2 : 1), timestamp, signer, - fee, deadline); - if (!ret) return false; - - SERIALIZE_U32(modifications); - - return true; -} - -bool nem_transaction_write_cosignatory_modification( - nem_transaction_ctx *ctx, uint32_t type, - const ed25519_public_key cosignatory) { - SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint32_t) + - sizeof(ed25519_public_key)); - SERIALIZE_U32(type); - SERIALIZE_TAGGED(cosignatory, sizeof(ed25519_public_key)); - - return true; -} - -bool nem_transaction_write_minimum_cosignatories(nem_transaction_ctx *ctx, - int32_t relative_change) { - SERIALIZE_U32(sizeof(uint32_t)); - SERIALIZE_U32((uint32_t)relative_change); - - return true; -} - -bool nem_transaction_create_importance_transfer( - nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, - const ed25519_public_key signer, uint64_t fee, uint32_t deadline, - uint32_t mode, const ed25519_public_key remote) { - if (!signer) { - signer = ctx->public_key; - } - - bool ret = nem_transaction_write_common( - ctx, NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER, - (uint32_t)network << 24 | 1, timestamp, signer, fee, deadline); - if (!ret) return false; - - SERIALIZE_U32(mode); - SERIALIZE_TAGGED(remote, sizeof(ed25519_public_key)); - - return true; -} diff --git a/deps/crypto/trezor-crypto/nem.h b/deps/crypto/trezor-crypto/nem.h deleted file mode 100644 index fe68316fb..000000000 --- a/deps/crypto/trezor-crypto/nem.h +++ /dev/null @@ -1,156 +0,0 @@ -/** - * Copyright (c) 2017 Saleem Rashid - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __NEM_H__ -#define __NEM_H__ - -#include -#include -#include - -#include "bip32.h" -#include "ed25519-donna/ed25519.h" - -#define NEM_LEVY_PERCENTILE_DIVISOR 4 -#define NEM_MAX_DIVISIBILITY 6 -#define NEM_MAX_SUPPLY 9000000000 - -#define NEM_NETWORK_MAINNET 0x68 -#define NEM_NETWORK_TESTNET 0x98 -#define NEM_NETWORK_MIJIN 0x60 - -#define NEM_ADDRESS_SIZE 40 -#define NEM_ADDRESS_SIZE_RAW 25 - -#define NEM_TRANSACTION_TYPE_TRANSFER 0x0101 -#define NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER 0x0801 -#define NEM_TRANSACTION_TYPE_AGGREGATE_MODIFICATION 0x1001 -#define NEM_TRANSACTION_TYPE_MULTISIG_SIGNATURE 0x1002 -#define NEM_TRANSACTION_TYPE_MULTISIG 0x1004 -#define NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE 0x2001 -#define NEM_TRANSACTION_TYPE_MOSAIC_CREATION 0x4001 -#define NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE 0x4002 - -#define NEM_SALT_SIZE sizeof(ed25519_public_key) - -#define NEM_ENCRYPTED_SIZE(size) \ - (((size) + AES_BLOCK_SIZE) / AES_BLOCK_SIZE * AES_BLOCK_SIZE) -#define NEM_ENCRYPTED_PAYLOAD_SIZE(size) \ - (AES_BLOCK_SIZE + NEM_SALT_SIZE + NEM_ENCRYPTED_SIZE(size)) - -#define _NEM_PADDING_SIZE(buffer, size) ((buffer)[(size)-1]) -#define NEM_PADDING_SIZE(buffer, size) \ - (_NEM_PADDING_SIZE(buffer, size) > (size) ? (size) \ - : _NEM_PADDING_SIZE(buffer, size)) - -#define NEM_DECRYPTED_SIZE(buffer, size) ((size)-NEM_PADDING_SIZE(buffer, size)) - -typedef struct { - ed25519_public_key public_key; - uint8_t *buffer; - size_t offset; - size_t size; -} nem_transaction_ctx; - -const char *nem_network_name(uint8_t network); - -void nem_get_address_raw(const ed25519_public_key public_key, uint8_t version, - uint8_t *address); -bool nem_get_address(const ed25519_public_key public_key, uint8_t version, - char *address); - -bool nem_validate_address_raw(const uint8_t *address, uint8_t network); -bool nem_validate_address(const char *address, uint8_t network); - -void nem_transaction_start(nem_transaction_ctx *ctx, - const ed25519_public_key public_key, uint8_t *buffer, - size_t size); -size_t nem_transaction_end(nem_transaction_ctx *ctx, - const ed25519_secret_key private_key, - ed25519_signature signature); - -bool nem_transaction_write_common(nem_transaction_ctx *context, uint32_t type, - uint32_t version, uint32_t timestamp, - const ed25519_public_key signer, uint64_t fee, - uint32_t deadline); - -bool nem_transaction_create_transfer(nem_transaction_ctx *context, - uint8_t network, uint32_t timestamp, - const ed25519_public_key signer, - uint64_t fee, uint32_t deadline, - const char *recipient, uint64_t amount, - const uint8_t *payload, uint32_t length, - bool encrypted, uint32_t mosaics); - -bool nem_transaction_write_mosaic(nem_transaction_ctx *ctx, - const char *namespace, const char *mosaic, - uint64_t quantity); - -bool nem_transaction_create_multisig(nem_transaction_ctx *ctx, uint8_t network, - uint32_t timestamp, - const ed25519_public_key signer, - uint64_t fee, uint32_t deadline, - const nem_transaction_ctx *inner); - -bool nem_transaction_create_multisig_signature( - nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, - const ed25519_public_key signer, uint64_t fee, uint32_t deadline, - const nem_transaction_ctx *inner); - -bool nem_transaction_create_provision_namespace( - nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, - const ed25519_public_key signer, uint64_t fee, uint32_t deadline, - const char *namespace, const char *parent, const char *rental_sink, - uint64_t rental_fee); - -bool nem_transaction_create_mosaic_creation( - nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, - const ed25519_public_key signer, uint64_t fee, uint32_t deadline, - const char *namespace, const char *mosaic, const char *description, - uint32_t divisibility, uint64_t supply, bool mutable_supply, - bool transferable, uint32_t levy_type, uint64_t levy_fee, - const char *levy_address, const char *levy_namespace, - const char *levy_mosaic, const char *creation_sink, uint64_t creation_fee); - -bool nem_transaction_create_mosaic_supply_change( - nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, - const ed25519_public_key signer, uint64_t fee, uint32_t deadline, - const char *namespace, const char *mosaic, uint32_t type, uint64_t delta); - -bool nem_transaction_create_aggregate_modification( - nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, - const ed25519_public_key signer, uint64_t fee, uint32_t deadline, - uint32_t modifications, bool relative_change); - -bool nem_transaction_write_cosignatory_modification( - nem_transaction_ctx *ctx, uint32_t type, - const ed25519_public_key cosignatory); - -bool nem_transaction_write_minimum_cosignatories(nem_transaction_ctx *ctx, - int32_t relative_change); - -bool nem_transaction_create_importance_transfer( - nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp, - const ed25519_public_key signer, uint64_t fee, uint32_t deadline, - uint32_t mode, const ed25519_public_key remote); - -#endif diff --git a/deps/crypto/trezor-crypto/nist256p1.c b/deps/crypto/trezor-crypto/nist256p1.c deleted file mode 100644 index 1082d334c..000000000 --- a/deps/crypto/trezor-crypto/nist256p1.c +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Copyright (c) 2013-2014 Tomas Dzetkulic - * Copyright (c) 2013-2014 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "nist256p1.h" - -const ecdsa_curve nist256p1 = { - /* .prime */ {/*.val =*/{0x1fffffff, 0x1fffffff, 0x1fffffff, 0x000001ff, - 0x00000000, 0x00000000, 0x00040000, 0x1fe00000, - 0xffffff}}, - - /* G */ - {/*.x =*/{/*.val =*/{0x1898c296, 0x0509ca2e, 0x1acce83d, 0x06fb025b, - 0x040f2770, 0x1372b1d2, 0x091fe2f3, 0x1e5c2588, - 0x6b17d1}}, - /*.y =*/{/*.val =*/{0x17bf51f5, 0x1db20341, 0x0c57b3b2, 0x1c66aed6, - 0x19e162bc, 0x15a53e07, 0x1e6e3b9f, 0x1c5fc34f, - 0x4fe342}}}, - - /* order */ - {/*.val =*/{0x1c632551, 0x1dce5617, 0x05e7a13c, 0x0df55b4e, 0x1ffffbce, - 0x1fffffff, 0x0003ffff, 0x1fe00000, 0xffffff}}, - - /* order_half */ - {/*.val =*/{0x1e3192a8, 0x0ee72b0b, 0x02f3d09e, 0x06faada7, 0x1ffffde7, - 0x1fffffff, 0x0001ffff, 0x1ff00000, 0x7fffff}}, - - /* a */ -3, - - /* b */ - {/*.val =*/{0x07d2604b, 0x1e71e1f1, 0x14ec3d8e, 0x1a0d6198, 0x086bc651, - 0x1eaabb4c, 0x0f9ecfae, 0x1b154752, 0x005ac635}} - -#if USE_PRECOMPUTED_CP - , - /* cp */ - { -#include "nist256p1.table" - } -#endif -}; - -const curve_info nist256p1_info = { - .bip32_name = "Nist256p1 seed", - .params = &nist256p1, - .hasher_base58 = HASHER_SHA2D, - .hasher_sign = HASHER_SHA2D, - .hasher_pubkey = HASHER_SHA2_RIPEMD, - .hasher_script = HASHER_SHA2, -}; diff --git a/deps/crypto/trezor-crypto/nist256p1.h b/deps/crypto/trezor-crypto/nist256p1.h deleted file mode 100644 index 02d04025a..000000000 --- a/deps/crypto/trezor-crypto/nist256p1.h +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2013-2014 Tomas Dzetkulic - * Copyright (c) 2013-2014 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __NIST256P1_H__ -#define __NIST256P1_H__ - -#include - -#include "bip32.h" -#include "ecdsa.h" - -extern const ecdsa_curve nist256p1; -extern const curve_info nist256p1_info; - -#endif diff --git a/deps/crypto/trezor-crypto/nist256p1.table b/deps/crypto/trezor-crypto/nist256p1.table deleted file mode 100644 index 6be01b4d6..000000000 --- a/deps/crypto/trezor-crypto/nist256p1.table +++ /dev/null @@ -1,1664 +0,0 @@ - { - /* 1*16^0*G: */ - {{{0x1898c296, 0x0509ca2e, 0x1acce83d, 0x06fb025b, 0x040f2770, 0x1372b1d2, 0x091fe2f3, 0x1e5c2588, 0x6b17d1}}, - {{0x17bf51f5, 0x1db20341, 0x0c57b3b2, 0x1c66aed6, 0x19e162bc, 0x15a53e07, 0x1e6e3b9f, 0x1c5fc34f, 0x4fe342}}}, - /* 3*16^0*G: */ - {{{0x06e7fd6c, 0x1a0b30de, 0x0b6a617e, 0x0d6e43df, 0x1f165e6c, 0x17ca8ea5, 0x091323df, 0x1a34c661, 0x5ecbe4}}, - {{0x027d5032, 0x13cd893d, 0x13ee0f66, 0x15606c70, 0x0a2ecd82, 0x03670d32, 0x1df8dd2c, 0x0189331f, 0x873464}}}, - /* 5*16^0*G: */ - {{{0x03d033ed, 0x0aaa506e, 0x16f94908, 0x1905fa3e, 0x08fdfef8, 0x042b0433, 0x034b5e13, 0x0f4a2a28, 0x51590b}}, - {{0x1da16da4, 0x0e85da27, 0x16022234, 0x025e01a9, 0x079260d0, 0x1f9b5fc5, 0x09f62b86, 0x1512094e, 0xe0c17d}}}, - /* 7*16^0*G: */ - {{{0x1187b2a3, 0x00314381, 0x03fbd6cc, 0x13f17150, 0x1fb607ef, 0x18333e00, 0x0d1896ec, 0x0df417ef, 0x8e533b}}, - {{0x01f400b4, 0x0af0d436, 0x0106c871, 0x0e6c6796, 0x1900053c, 0x0fc1d37a, 0x00d9b41a, 0x17bc0663, 0x73eb1d}}}, - /* 9*16^0*G: */ - {{{0x10949ee0, 0x1cf4525c, 0x1b7e2cf5, 0x15971858, 0x1f8729e0, 0x1c6a8eb8, 0x0dc61e24, 0x16dfdbe1, 0xea68d7}}, - {{0x0dd048fa, 0x02d11252, 0x17a08ffa, 0x029fd549, 0x0a0c84d7, 0x054b2547, 0x139e1c05, 0x192e593f, 0x2a2744}}}, - /* 11*16^0*G: */ - {{{0x14bc21d1, 0x199c8e9b, 0x14122fd0, 0x085da04a, 0x01cda167, 0x1bced861, 0x116418e0, 0x16f10769, 0x3ed113}}, - {{0x082a3740, 0x17c777e7, 0x062276b8, 0x1a09b4bd, 0x0c68a090, 0x01d7d27a, 0x02889321, 0x13599899, 0x909920}}}, - /* 13*16^0*G: */ - {{{0x06072c01, 0x070aecea, 0x1ab562a6, 0x1c5096cb, 0x0e2fc792, 0x0ef96c2f, 0x05698601, 0x0f5c1589, 0x177c83}}, - {{0x0fc7bfd8, 0x021ddf17, 0x1ed37ce7, 0x1c298743, 0x14e7226e, 0x08d6da07, 0x15628902, 0x19a9d7d4, 0x63bb58}}}, - /* 15*16^0*G: */ - {{{0x059b9d5f, 0x1b34631f, 0x0e83bc58, 0x075f25bc, 0x08265ae0, 0x1bc4ccc4, 0x0b9eb7ec, 0x18d2e357, 0xf0454d}}, - {{0x0d034f36, 0x1f2ce6f0, 0x0d7e8fd1, 0x16439ceb, 0x043e62a3, 0x0a728fcb, 0x147d3996, 0x1c6b25c5, 0xb5b93e}}} - }, - { - /* 1*16^1*G: */ - {{{0x01277c6e, 0x0f5a3c3f, 0x1b280e29, 0x10725dfe, 0x0315fcd2, 0x0e314c1b, 0x06162e08, 0x02714d68, 0x76a94d}}, - {{0x0b8c5110, 0x14eeeb92, 0x11e2ea83, 0x1340081f, 0x08720859, 0x10daf08f, 0x1839b2c2, 0x0c2683e4, 0xa985fe}}}, - /* 3*16^1*G: */ - {{{0x1e4536ca, 0x1fdcee34, 0x0806986a, 0x1d252c14, 0x0cda11c2, 0x1a2df038, 0x07b23339, 0x01c924a7, 0x9482fb}}, - {{0x158cc1c8, 0x1d6c31df, 0x01efeec7, 0x1abc52ae, 0x14e63f63, 0x11c653a9, 0x1fe46975, 0x14e8be2a, 0x351d9c}}}, - /* 5*16^1*G: */ - {{{0x15ecff13, 0x0d8ed714, 0x1418cf12, 0x0c9439b7, 0x01eeb637, 0x0d28a984, 0x04656e0d, 0x182f5d26, 0xb2e1b7}}, - {{0x12187d44, 0x1dd24c4d, 0x17a8b9a8, 0x1435302f, 0x158c387d, 0x10d1556b, 0x0f33c8ce, 0x0262747d, 0xe6c044}}}, - /* 7*16^1*G: */ - {{{0x0ef87286, 0x05dd99a7, 0x08c2790e, 0x07d0fbf8, 0x0ee34070, 0x0bbee5e3, 0x0f0b2cd0, 0x05cfe36d, 0xb43346}}, - {{0x041496d9, 0x16023fb4, 0x0b3a92de, 0x1c4100d4, 0x12e6f9dc, 0x073960b4, 0x17f8e0fd, 0x0a4dda56, 0xa0da54}}}, - /* 9*16^1*G: */ - {{{0x19794381, 0x1cc35ad8, 0x0c31d806, 0x02b10ebd, 0x07b19189, 0x1482daab, 0x0933061b, 0x19c9a7b4, 0xa47420}}, - {{0x02769c52, 0x0b671d3f, 0x1dab1e1a, 0x0b811b73, 0x07afff3a, 0x1c9b0ccb, 0x1f839cf7, 0x1bef7c37, 0x2ebbff}}}, - /* 11*16^1*G: */ - {{{0x09a5185a, 0x03a23324, 0x179bcafb, 0x0e15913e, 0x1a3195b8, 0x0a009586, 0x05217fb3, 0x03373a12, 0x5ba7a}}, - {{0x01de3a4e, 0x0a1e4470, 0x016b8005, 0x0c441792, 0x1d48e760, 0x011f1271, 0x025b919e, 0x16bd0583, 0x30e0d2}}}, - /* 13*16^1*G: */ - {{{0x199b85fe, 0x151cc5af, 0x0e977f56, 0x1dfd355c, 0x1e0b79c0, 0x06c8c041, 0x0bf5a5e6, 0x193a1bfc, 0xb29f74}}, - {{0x0da604dc, 0x1d3214bb, 0x1d67a036, 0x1ec7a617, 0x1c6d92de, 0x18974b6b, 0x1e175741, 0x1874d852, 0xa3ce5b}}}, - /* 15*16^1*G: */ - {{{0x07e030ef, 0x1b3a2b74, 0x1543a589, 0x16560af9, 0x02b08576, 0x1f81f924, 0x13d41db2, 0x15517237, 0x99299b}}, - {{0x18d9aa9a, 0x0c735bee, 0x10021113, 0x0258933e, 0x0aa7957c, 0x0080d367, 0x1862fcce, 0x1a6667f1, 0x5cc2e3}}} - }, - { - /* 1*16^2*G: */ - {{{0x12d0441b, 0x0d971af8, 0x1a95930b, 0x1a16e21a, 0x1ed61190, 0x08a94301, 0x19661fff, 0x14760122, 0x34a2d4}}, - {{0x1e93b146, 0x01273c22, 0x1776076d, 0x0ecd73bd, 0x17fc0e7d, 0x1882373b, 0x0f08af29, 0x0d4a743c, 0xbeaaed}}}, - /* 3*16^2*G: */ - {{{0x1da08424, 0x0725719d, 0x1d912a77, 0x1f6f56e9, 0x123ed3ab, 0x02ffd4ae, 0x06a86d63, 0x00f5b86b, 0xa98b0a}}, - {{0x0831800c, 0x10943d07, 0x17d60b4d, 0x17d01741, 0x11320752, 0x0f46470e, 0x0d9b94c6, 0x08e44933, 0x4754c6}}}, - /* 5*16^2*G: */ - {{{0x083c2d6a, 0x096bf2f4, 0x0f4a6ced, 0x1f231b03, 0x0696dd22, 0x15bc642d, 0x0b17486d, 0x013911b5, 0xa034f0}}, - {{0x02c30e72, 0x019b7796, 0x099f9f3d, 0x0c06be2c, 0x0eb06be0, 0x1c2a2e76, 0x107ec336, 0x06d95133, 0xfe1b00}}}, - /* 7*16^2*G: */ - {{{0x08be8c78, 0x0b528ee9, 0x1e4f935c, 0x12d9f056, 0x0e9a14a0, 0x115a04b1, 0x100681db, 0x1fe633a8, 0xb52226}}, - {{0x11686903, 0x019b3e52, 0x0d63fcc8, 0x1eff91cb, 0x0851a819, 0x1b34bf49, 0x1503286c, 0x193ea73e, 0x701ee0}}}, - /* 9*16^2*G: */ - {{{0x0058b5a4, 0x0207f205, 0x0c65e6dc, 0x08c9f0f2, 0x04713de4, 0x07667e66, 0x16cf65a3, 0x0c30d1c0, 0xa3e388}}, - {{0x07113aef, 0x19836c87, 0x1c68a523, 0x1d08b76e, 0x1e68f3ce, 0x1359d74b, 0x04b0e123, 0x110fbe1a, 0xcfd457}}}, - /* 11*16^2*G: */ - {{{0x04a08314, 0x02faf648, 0x11f7fde8, 0x1c6db65b, 0x1197a82f, 0x055cd110, 0x14e4ccf3, 0x094263f4, 0x209954}}, - {{0x07573ccc, 0x1fc64e2f, 0x1f3fa5b9, 0x0dcb4e6d, 0x048dfd40, 0x1472e5c8, 0x0c6243ee, 0x1fa55467, 0xa5cf3d}}}, - /* 13*16^2*G: */ - {{{0x09078c18, 0x017fca57, 0x1b7a4a54, 0x018795dd, 0x1d39b99e, 0x1739556f, 0x11c0c23d, 0x0275981d, 0x751d65}}, - {{0x0ece0d67, 0x0c6b74ae, 0x1816b1e6, 0x12918397, 0x02a4ef00, 0x05d7b515, 0x056214d5, 0x1fb94948, 0xba9c3f}}}, - /* 15*16^2*G: */ - {{{0x1e86d900, 0x167e6ae4, 0x08f6d124, 0x1dc13a2f, 0x03b36405, 0x0184501d, 0x00445ed2, 0x044b88f0, 0x5be0f5}}, - {{0x158a5755, 0x066eb4df, 0x0cd3d6b1, 0x02e4a483, 0x1423df92, 0x11d273da, 0x108b4d1f, 0x1cdbfe58, 0x83d1d9}}} - }, - { - /* 1*16^3*G: */ - {{{0x0245573f, 0x03bf46d5, 0x1f42993c, 0x0cede5e9, 0x16bd2508, 0x04b39736, 0x193665de, 0x1a59e0d3, 0xe716ae}}, - {{0x069218d1, 0x02fe135a, 0x01f26cd4, 0x1a1be5f4, 0x1a851d13, 0x183343dc, 0x0aad644a, 0x1cd29f8e, 0x353663}}}, - /* 3*16^3*G: */ - {{{0x057008ac, 0x1cc3c983, 0x0a7b7edf, 0x1c3d9dc6, 0x1a22d19c, 0x0ac5260e, 0x13a19395, 0x11adea0f, 0xd2bf89}}, - {{0x127beb55, 0x088a9a53, 0x1fc1e620, 0x19c2156b, 0x10c56679, 0x0aed9fd4, 0x1ea8fe06, 0x196b4d6e, 0x69c0b1}}}, - /* 5*16^3*G: */ - {{{0x182f1580, 0x086be54b, 0x080fadff, 0x09bbdc48, 0x064f8b0e, 0x0b9c8f98, 0x19821fe9, 0x09dcb079, 0x4d8830}}, - {{0x1616edd7, 0x007d8b6a, 0x1ac78443, 0x19477ad1, 0x16518aaf, 0x00044c7e, 0x0db3a35a, 0x0e13560c, 0x28a94e}}}, - /* 7*16^3*G: */ - {{{0x00c38e11, 0x1c261ed7, 0x1b89ae97, 0x0c8437d4, 0x1af9e715, 0x1cc90172, 0x1bacc99c, 0x04f91f81, 0x17c727}}, - {{0x0e90decd, 0x0c1b35dd, 0x0336b8f3, 0x07328b4c, 0x1802e7e5, 0x17e67480, 0x0cf10180, 0x1e9fccc9, 0x95c5a4}}}, - /* 9*16^3*G: */ - {{{0x032f36ea, 0x0aafec57, 0x0d5070f6, 0x1e8d4e52, 0x0b8b3cd4, 0x18e7e426, 0x02a2118e, 0x15588e8a, 0x7e03fd}}, - {{0x0a68b8af, 0x16611fe4, 0x140275a2, 0x1d2f3498, 0x0af99419, 0x158b80c2, 0x03699a39, 0x1e240245, 0xdcf6d5}}}, - /* 11*16^3*G: */ - {{{0x1953baa9, 0x01f29536, 0x18637a35, 0x0b5d0c93, 0x0b214261, 0x1d60ee50, 0x1c1d858d, 0x0d096379, 0x8ce6da}}, - {{0x152689e5, 0x073ae147, 0x0a4d075e, 0x0730d76d, 0x1b56807f, 0x1de48030, 0x082f9a6c, 0x171f5262, 0x3d9f4f}}}, - /* 13*16^3*G: */ - {{{0x0f22a96a, 0x15c6c29d, 0x1aae3e52, 0x03753b38, 0x0e2b008b, 0x1aa4badd, 0x15288294, 0x06081b80, 0xb570e7}}, - {{0x085d1b00, 0x199fb30e, 0x15732732, 0x1376f4b0, 0x0cfbda7c, 0x1bb4dae0, 0x1dfc0a30, 0x0c71ee3c, 0xdcd8a2}}}, - /* 15*16^3*G: */ - {{{0x189a7509, 0x12075ca2, 0x1ea01527, 0x0e172c83, 0x1f20de12, 0x0d1f3ae3, 0x10ec1284, 0x04797572, 0x44d943}}, - {{0x00437234, 0x10515cdb, 0x137449b8, 0x07c3fbe2, 0x193586f9, 0x1de693bd, 0x1c280d08, 0x10010803, 0xb2c5b3}}} - }, - { - /* 1*16^4*G: */ - {{{0x0eade3c4, 0x1f4232e3, 0x014a8140, 0x156e9392, 0x186b4714, 0x1219a072, 0x04363971, 0x0de9d23d, 0xa01836}}, - {{0x0b26e8d0, 0x02e21013, 0x1853cdfd, 0x0e509c88, 0x18369d5f, 0x12bc1a4e, 0x0c59f1b3, 0x02e28221, 0xe2bbec}}}, - /* 3*16^4*G: */ - {{{0x19e0af06, 0x10e6f562, 0x1b65635b, 0x07314ac5, 0x1055c92f, 0x1dad36a2, 0x059142f4, 0x001711b1, 0x9cdf1f}}, - {{0x0216ade7, 0x0bd196db, 0x1f2951a3, 0x0a45b832, 0x194b0828, 0x05de6e46, 0x15993656, 0x1fda7e55, 0x916d25}}}, - /* 5*16^4*G: */ - {{{0x1305097e, 0x09b95c9c, 0x0ee94660, 0x0c2e1d08, 0x0448338d, 0x0d9682a0, 0x0fb6adac, 0x1aba34cc, 0x45bfd9}}, - {{0x108ddc04, 0x05d02c74, 0x14b05655, 0x173a677f, 0x0e908683, 0x0182a386, 0x14aeeb62, 0x0250ab5f, 0x9d1dc}}}, - /* 7*16^4*G: */ - {{{0x163bd6df, 0x098f8d05, 0x19abb0f3, 0x184785ba, 0x15e6fd1f, 0x0fce0144, 0x04ed9c7a, 0x02ac8ecd, 0xb599ad}}, - {{0x0efa09ac, 0x150e751c, 0x04d2d163, 0x0189ed22, 0x1c4166a4, 0x1b05c591, 0x0cc918dc, 0x1bd89f56, 0x6979d1}}}, - /* 9*16^4*G: */ - {{{0x07142d62, 0x1c309f99, 0x0ef09b6b, 0x14d46bf0, 0x054c11d9, 0x158913f4, 0x103a4998, 0x1e2ce655, 0xf4dca1}}, - {{0x1a618fc9, 0x04f66603, 0x134f5feb, 0x0f359dfb, 0x1c659bb9, 0x1c0dc8d5, 0x151b527c, 0x1cb69699, 0x551167}}}, - /* 11*16^4*G: */ - {{{0x015fae61, 0x1658ffa3, 0x0e57e087, 0x0b8fb89e, 0x0bb5a7f1, 0x1120738b, 0x0d9b6713, 0x141cdc13, 0xf07278}}, - {{0x096376f9, 0x1e865ba4, 0x0dfaaf3d, 0x0e0e2b70, 0x0f7d42c2, 0x10410c4c, 0x1a97df5e, 0x056294e3, 0x1a681b}}}, - /* 13*16^4*G: */ - {{{0x0466591f, 0x027020a9, 0x11a35a83, 0x0e5d51ff, 0x058ccbe1, 0x15a99dd4, 0x16c3c50e, 0x0af5e141, 0x1fc524}}, - {{0x196f8cdb, 0x077f7ab9, 0x1b1e0891, 0x11958465, 0x14e1629f, 0x1b7f2da1, 0x1047a7b1, 0x070113d7, 0x489c18}}}, - /* 15*16^4*G: */ - {{{0x122a8ebc, 0x12e85c61, 0x1e59c544, 0x039b6e31, 0x056d5a29, 0x05ad9865, 0x17d3f5fc, 0x16634918, 0xfa2501}}, - {{0x0a8a775b, 0x06c93dad, 0x0f20cc60, 0x11c11cd9, 0x1a8cbea5, 0x0f330d37, 0x0588ce14, 0x1629f0b1, 0x71c932}}} - }, - { - /* 1*16^5*G: */ - {{{0x1d96dff1, 0x1bee765b, 0x157f3fa3, 0x08638355, 0x198d530e, 0x105ab866, 0x153ffbda, 0x10a283fc, 0xec738}}, - {{0x1c7b552c, 0x16420d63, 0x1b5e2aa7, 0x04c99d0f, 0x052511d5, 0x0277ac03, 0x1d7646b3, 0x09d0f5d0, 0xd6224f}}}, - /* 3*16^5*G: */ - {{{0x088d58e9, 0x0e192558, 0x18c60e14, 0x14b838c9, 0x0a7b6e94, 0x12353e21, 0x0a1ba64a, 0x1fb8e0c9, 0x96dac3}}, - {{0x0ebebc5e, 0x01a49895, 0x01f9b8e0, 0x17d13729, 0x0c439685, 0x024a49c1, 0x06b615b3, 0x1e75a8d8, 0xcb1faf}}}, - /* 5*16^5*G: */ - {{{0x0db29f92, 0x0a956899, 0x11ecb162, 0x03a4e372, 0x18f811d2, 0x0e1bc575, 0x0c4a8417, 0x079d629e, 0xe297b2}}, - {{0x05e58ddb, 0x0794a645, 0x1b505058, 0x079d770b, 0x19149122, 0x0dd5dc66, 0x02d2d203, 0x041f196e, 0xe13725}}}, - /* 7*16^5*G: */ - {{{0x0ad88c33, 0x0ca1dbdc, 0x1d1af2bf, 0x15c729b2, 0x0da97d91, 0x1e490692, 0x12d9ac1a, 0x071f6572, 0x1cd223}}, - {{0x048fb1b2, 0x14753c21, 0x12879258, 0x1ca262bd, 0x0bc2713f, 0x1205589b, 0x02c25b21, 0x1f071569, 0xfc3acd}}}, - /* 9*16^5*G: */ - {{{0x1b26aa73, 0x09d644e1, 0x18e8383d, 0x0fc23618, 0x11ee0cdf, 0x16986ffd, 0x0eff2c72, 0x15b73d3f, 0xf462d7}}, - {{0x18479e73, 0x02f560bb, 0x140b3289, 0x11c14600, 0x13c7a49e, 0x1d253439, 0x0c50354e, 0x034f068a, 0x406a0d}}}, - /* 11*16^5*G: */ - {{{0x1cd015e3, 0x170f0155, 0x194089cf, 0x01d2b2fc, 0x15168af9, 0x1f59e544, 0x12bdd6f6, 0x04ba7ee1, 0xe0f689}}, - {{0x12157cce, 0x15126a16, 0x0a4daef6, 0x116a723c, 0x0c77c55b, 0x14b6393a, 0x0aa54d89, 0x0621c907, 0x8531e}}}, - /* 13*16^5*G: */ - {{{0x0bb76b12, 0x1362188a, 0x0649da47, 0x1cecee7c, 0x15a00ea8, 0x1598957b, 0x15ff0760, 0x182aa57e, 0x28e4ad}}, - {{0x0c4747bd, 0x1f229d3f, 0x058a3fd5, 0x014c1e2e, 0x0a3f703a, 0x1b2db5cf, 0x06cfd392, 0x09dfb340, 0x14d74c}}}, - /* 15*16^5*G: */ - {{{0x076ff697, 0x1fac00ff, 0x01d918a2, 0x16d10ca4, 0x097c6369, 0x16d5d9d0, 0x017b49c7, 0x04f29750, 0x85a0ba}}, - {{0x12142721, 0x04f6a6d2, 0x02962e4c, 0x12fff4f2, 0x1aa551de, 0x0869ee76, 0x0929551e, 0x0c3d587c, 0xadf32e}}} - }, - { - /* 1*16^6*G: */ - {{{0x0392d805, 0x192e2ee7, 0x1501750d, 0x1500d30e, 0x1449aa87, 0x06d57d51, 0x0f5e9295, 0x19e98d52, 0xf8f5dc}}, - {{0x0cda02fa, 0x1330ca8b, 0x0850ee80, 0x07b4c94a, 0x1327351f, 0x1f19b230, 0x0150e274, 0x19ecdac6, 0xe58176}}}, - /* 3*16^6*G: */ - {{{0x1fa046f7, 0x0ea598b3, 0x01cc2746, 0x021e7204, 0x02d45171, 0x05644a37, 0x0ea53821, 0x0950cb10, 0xe12c8e}}, - {{0x012646ad, 0x1d2ad145, 0x0c464d14, 0x1809c226, 0x126f6dd0, 0x1f6a9c98, 0x0bcd0cec, 0x0c21fb34, 0x7cec04}}}, - /* 5*16^6*G: */ - {{{0x02853c43, 0x0d893f46, 0x08b919ae, 0x0cd8af5c, 0x13236481, 0x1177f1e8, 0x0824f423, 0x0e82f2d2, 0x394bd4}}, - {{0x0064469d, 0x0bc14665, 0x03f3c32c, 0x1ece25b2, 0x00767d52, 0x1fe178eb, 0x1ae481f8, 0x0a42a3b8, 0x2b4d6d}}}, - /* 7*16^6*G: */ - {{{0x1c722e94, 0x016eb9cf, 0x0162587b, 0x102072da, 0x004334ed, 0x132b62ca, 0x0ba51171, 0x1be71bd0, 0xca8538}}, - {{0x1049a527, 0x105316f8, 0x02c9a90e, 0x12a75149, 0x19f12f20, 0x189350fd, 0x170c479c, 0x085d73c0, 0x3b27fc}}}, - /* 9*16^6*G: */ - {{{0x1cad6309, 0x18ba314e, 0x0e7fd221, 0x143f85e4, 0x07b3dd31, 0x1a312653, 0x0dd686ed, 0x0b3e46af, 0x663e1a}}, - {{0x09981f28, 0x19435d1c, 0x1ad4af54, 0x0fa88805, 0x0f918b90, 0x00c1e58e, 0x030f040b, 0x07700cd5, 0x292fb7}}}, - /* 11*16^6*G: */ - {{{0x02c23d03, 0x13ad9229, 0x11ffc924, 0x03609b1f, 0x1eeab3ba, 0x1611b83d, 0x19c25b0d, 0x1ce60c6c, 0xa2d9ef}}, - {{0x1085db74, 0x01726027, 0x0e77d144, 0x134fd2b0, 0x01b92ea0, 0x021b6388, 0x0e3c554c, 0x05199083, 0x1cc852}}}, - /* 13*16^6*G: */ - {{{0x07d4c6d1, 0x1aafcb38, 0x167ffec5, 0x059aa335, 0x135d0f66, 0x085a939f, 0x07bf82e4, 0x05691635, 0x5657e1}}, - {{0x0106bdec, 0x0181f94c, 0x14b05062, 0x1346b428, 0x06a0abff, 0x1c8799d7, 0x07e6b3ec, 0x1e971ba9, 0x72b5be}}}, - /* 15*16^6*G: */ - {{{0x1933564a, 0x032a6eaa, 0x18ebd13e, 0x1169f5db, 0x18d2b7a6, 0x16e333b6, 0x00042193, 0x02ba815c, 0x5b6862}}, - {{0x0204ef63, 0x1af822c4, 0x1e21a7ce, 0x15dc4510, 0x195de392, 0x062a68ce, 0x19154b4c, 0x0d39e744, 0x76b5ea}}} - }, - { - /* 1*16^7*G: */ - {{{0x0f922dbd, 0x025118bb, 0x064863e6, 0x0c622c3f, 0x171b91ca, 0x1556c726, 0x1cc4fe17, 0x17ffa9b5, 0x6d28b6}}, - {{0x00ef3cff, 0x055ff815, 0x1368a651, 0x09d3e170, 0x14a1c4c2, 0x10d30e65, 0x0be903ef, 0x00a283ba, 0xaf39d9}}}, - /* 3*16^7*G: */ - {{{0x1b168b64, 0x0c86ffcc, 0x01b2102d, 0x07a0558b, 0x0467ea15, 0x0482fe0a, 0x0f774f7c, 0x0f4ff7fc, 0x7cd315}}, - {{0x1abbb16b, 0x0b60695a, 0x180b8d61, 0x189b36e5, 0x1fafb13a, 0x073c5e6d, 0x1188815a, 0x0422e525, 0x9ca08d}}}, - /* 5*16^7*G: */ - {{{0x06ef29e8, 0x158e37d0, 0x166bb8ec, 0x18aa9613, 0x1356264d, 0x018ccea2, 0x03115ac9, 0x1b6be5bf, 0xed860b}}, - {{0x19b90f8f, 0x00d0e24d, 0x036a8cd4, 0x061eb85b, 0x17bb1e76, 0x1b59a020, 0x1ff5f1af, 0x086ebab4, 0xb837e7}}}, - /* 7*16^7*G: */ - {{{0x1636e617, 0x0fc8c59f, 0x1c73d667, 0x19a07783, 0x12c9d47d, 0x0e173f13, 0x090dcd78, 0x11fa3a42, 0x6868cc}}, - {{0x1cbb3d27, 0x046ee79f, 0x0e1335c7, 0x1c619148, 0x13f0a60f, 0x081c3c98, 0x079acf16, 0x14b7237f, 0xeed008}}}, - /* 9*16^7*G: */ - {{{0x113e2a34, 0x1ced1530, 0x0e8478b1, 0x1a5ccb9c, 0x1d318291, 0x1a4f8857, 0x1880b172, 0x0c1d591f, 0xec03b3}}, - {{0x184566d6, 0x01121f75, 0x084dade9, 0x102adccb, 0x122728aa, 0x0f108090, 0x010defbf, 0x1f6c140b, 0x86020f}}}, - /* 11*16^7*G: */ - {{{0x087c1b18, 0x1570672e, 0x12646897, 0x1c596a90, 0x056fa101, 0x01ad2c88, 0x04379a8c, 0x1473cf17, 0xa79464}}, - {{0x1b94809a, 0x15ac284b, 0x158a086f, 0x11bd38e2, 0x089f60d9, 0x0bc3cf4d, 0x03309269, 0x1c7ee50b, 0x1361f4}}}, - /* 13*16^7*G: */ - {{{0x1ed10d26, 0x0a714636, 0x19657d96, 0x157df053, 0x10ccc5a9, 0x0fdb4a79, 0x131e43a4, 0x101551f7, 0x544ef2}}, - {{0x16dafcc2, 0x1e127b93, 0x0b01ab8b, 0x1adf2edc, 0x170d3683, 0x0eff46c6, 0x0b3a75ac, 0x13b88b58, 0x95b91c}}}, - /* 15*16^7*G: */ - {{{0x17ad18e6, 0x04a3cfc5, 0x0f2b5789, 0x1a7cf31a, 0x0ff9b57a, 0x1e4235a5, 0x18853794, 0x110be698, 0xe2c26c}}, - {{0x0554cfad, 0x0d7f28d5, 0x0607792b, 0x0a2b94e3, 0x1ba113bc, 0x1337508b, 0x06214738, 0x0509e910, 0xb2121b}}} - }, - { - /* 1*16^8*G: */ - {{{0x185a5943, 0x12d4f110, 0x1977ed8e, 0x12326cb8, 0x071da1ab, 0x15991316, 0x1e248595, 0x0815e455, 0x7fe36b}}, - {{0x099ca101, 0x0868a963, 0x02bc84b5, 0x07ab0cf7, 0x0a6f174b, 0x1a0203ee, 0x18927c27, 0x0b04b6c6, 0xe697d4}}}, - /* 3*16^8*G: */ - {{{0x1f0922a8, 0x153c048e, 0x173e365d, 0x01d3a4a8, 0x18b808e9, 0x072b0117, 0x15ce0249, 0x080b69c5, 0x4b656a}}, - {{0x199a80bb, 0x0d6e562c, 0x0143da53, 0x0773c573, 0x0c4d6d47, 0x06612aec, 0x00e48341, 0x03a25cef, 0xee1ea3}}}, - /* 5*16^8*G: */ - {{{0x09d07e9e, 0x0827c443, 0x09830dad, 0x1cf943ed, 0x18e5ea09, 0x15f07d9e, 0x04f64f6c, 0x0dd7acbc, 0x9d7895}}, - {{0x03d8c8ee, 0x06eb0ad6, 0x0531ecbd, 0x0145b477, 0x010ce746, 0x144e0e99, 0x0335950a, 0x0dde91d5, 0xd5149e}}}, - /* 7*16^8*G: */ - {{{0x1dc4950f, 0x13ba8433, 0x0e5081d9, 0x03655b7a, 0x16316574, 0x1423726d, 0x1ea55c8d, 0x0e5c26a7, 0x4acb12}}, - {{0x03d8b4df, 0x16372223, 0x019ab159, 0x1c85016b, 0x1e29fdf9, 0x0c7b6638, 0x16b633ca, 0x01f6e879, 0x726cd2}}}, - /* 9*16^8*G: */ - {{{0x0d7e8cbd, 0x0063d3df, 0x01f605bd, 0x0cff15e0, 0x1464a2a6, 0x09aa8640, 0x1ed08d11, 0x17e34d62, 0x640c5e}}, - {{0x1ec5a5db, 0x171481e5, 0x1fe6c081, 0x0d3f6319, 0x0ab9eba0, 0x0375b80f, 0x14bcaba7, 0x1fb0539f, 0xd6ae88}}}, - /* 11*16^8*G: */ - {{{0x1e86bddc, 0x18502583, 0x1738f57d, 0x04d72f2e, 0x16b9bf1d, 0x116486ed, 0x0cc91455, 0x16368509, 0x8bba04}}, - {{0x09e349c4, 0x111e2d0f, 0x065b97d4, 0x19fbc9e8, 0x1437ac6a, 0x1c90b34c, 0x1afd966f, 0x18138411, 0xc34099}}}, - /* 13*16^8*G: */ - {{{0x0257f582, 0x0b873c02, 0x10e89634, 0x1213d5bd, 0x05fe41f9, 0x0a1fbe2d, 0x1f88429a, 0x089fd9a6, 0x8b0a57}}, - {{0x17372d4b, 0x00bff6f9, 0x0581d992, 0x168d74f6, 0x17d4656d, 0x0ad09bf1, 0x1ce598a8, 0x09d81ad8, 0x9e57a4}}}, - /* 15*16^8*G: */ - {{{0x185e797e, 0x18a24fcc, 0x0f0c5a0f, 0x1c449e5c, 0x078a6f06, 0x17a49ecb, 0x025c7e15, 0x12f84c8f, 0xa13ff}}, - {{0x139d666f, 0x193d5cfa, 0x0030e4a0, 0x1ede14eb, 0x1dc3ff27, 0x00c747d0, 0x0f5645f6, 0x09644b90, 0xeb1a96}}} - }, - { - /* 1*16^9*G: */ - {{{0x1dde3445, 0x17fa7f0f, 0x0ba9e05e, 0x1753bb45, 0x0519e76b, 0x0ff3ff93, 0x079a14dc, 0x0709ae0c, 0x6965b6}}, - {{0x18855113, 0x0621c4f0, 0x17e6765f, 0x19cc0a34, 0x12dbef47, 0x04b31c39, 0x1444c979, 0x1c738904, 0xd1bcda}}}, - /* 3*16^9*G: */ - {{{0x088acfc5, 0x0f207cb4, 0x1a25e27d, 0x1eb1366c, 0x11a71b1e, 0x1eedea04, 0x1f6809f9, 0x03bbceb8, 0xe1cbc5}}, - {{0x0249a225, 0x1e2ff6ad, 0x0fee948e, 0x065257dd, 0x1e23ce7d, 0x1b27fedc, 0x0bb6cc49, 0x12f9bcfb, 0xec6783}}}, - /* 5*16^9*G: */ - {{{0x0107ccc6, 0x0c7529ff, 0x0f208a1d, 0x112fc2a8, 0x100481d3, 0x0e9422d4, 0x0a85cc7a, 0x0f2e2271, 0x9c3f26}}, - {{0x1dea9152, 0x003ca669, 0x1e6c61a1, 0x11fa9d2b, 0x06eca51a, 0x1afa5f9f, 0x16722f8d, 0x036c96a3, 0xdaee0c}}}, - /* 7*16^9*G: */ - {{{0x15a449e7, 0x0e2f5a1c, 0x0f0af908, 0x054069ca, 0x0922b2fa, 0x160bd8a0, 0x15c9e5be, 0x0aef8d65, 0x5c30d9}}, - {{0x0e2677d0, 0x1875240d, 0x139e439d, 0x1c80a787, 0x192d0b75, 0x12fbcce2, 0x0e48592d, 0x16b611c3, 0x8025e3}}}, - /* 9*16^9*G: */ - {{{0x0b8ceb07, 0x12ac6014, 0x1b89c73e, 0x124a57ff, 0x0d995537, 0x11583f54, 0x1a0abf93, 0x046191d2, 0xaa3bbf}}, - {{0x1fd83984, 0x0d423174, 0x0cfe7ae6, 0x036578f5, 0x162ec3b7, 0x187f2648, 0x09a11372, 0x161383d8, 0xe6320c}}}, - /* 11*16^9*G: */ - {{{0x03bfd1f1, 0x00752aac, 0x1595ccb9, 0x0db86a2b, 0x001943a3, 0x07e4c8a0, 0x0605e798, 0x0a226668, 0xab4a32}}, - {{0x08e1c233, 0x089cb086, 0x07a633c8, 0x1b26484f, 0x1e057a57, 0x1de82097, 0x19a2d3ac, 0x17606d90, 0xea6c64}}}, - /* 13*16^9*G: */ - {{{0x0b1d6d3f, 0x02036bc0, 0x1baee242, 0x0ecd149d, 0x1a8105f3, 0x1fae6c52, 0x15dfdccd, 0x0b3bbdab, 0xdba9b2}}, - {{0x09cd8133, 0x01749414, 0x0af64f31, 0x1b3788a2, 0x1871448b, 0x0ca7a7f5, 0x0ded6b2a, 0x07eaea6b, 0xb3862d}}}, - /* 15*16^9*G: */ - {{{0x11fa2a6a, 0x1cd01c01, 0x0392c959, 0x183ab0b6, 0x1cdfe34f, 0x0ba158d1, 0x1d141eb7, 0x1885d304, 0x1998f4}}, - {{0x06415142, 0x03f6da5e, 0x1c962d58, 0x180470f6, 0x0a1e94c6, 0x1c0045bc, 0x08425c03, 0x0da3215f, 0x2ebb41}}} - }, - { - /* 1*16^10*G: */ - {{{0x0d9aefbd, 0x0c7e5362, 0x0e55dd49, 0x1c8f64e7, 0x043dc1ef, 0x0f86a0de, 0x15d8cb2a, 0x03918cd3, 0xfbc34}}, - {{0x13e71ca0, 0x09db754e, 0x02a7fc7b, 0x160d3c40, 0x1d3d3950, 0x058ea4ab, 0x18ff9005, 0x0c65e6c1, 0xbd8022}}}, - /* 3*16^10*G: */ - {{{0x09434837, 0x1cb6fff7, 0x08306ee1, 0x0628170c, 0x1b06dadb, 0x0e37fda7, 0x0bb6c4d0, 0x1578950f, 0xd76d18}}, - {{0x1b215b4c, 0x1d5027cd, 0x0df33093, 0x08b1ceeb, 0x1933290a, 0x010a7bd5, 0x19137839, 0x1465db2c, 0xf6bc4d}}}, - /* 5*16^10*G: */ - {{{0x1c07f222, 0x1744f90c, 0x183f9f40, 0x0438c758, 0x153d1c5e, 0x0e8d0f8b, 0x1d813d20, 0x0a0c2cff, 0xd5c0c6}}, - {{0x0c6ffd57, 0x177b48f0, 0x004ea1b8, 0x07ea34f1, 0x175b9baf, 0x063bfa4f, 0x02143378, 0x10c102f7, 0x15a30b}}}, - /* 7*16^10*G: */ - {{{0x0e93bfa6, 0x1238b512, 0x084d8a92, 0x1a52b413, 0x09fe0d39, 0x05d335a6, 0x18b39527, 0x09c948de, 0x734c36}}, - {{0x18d10774, 0x037d3ccc, 0x00a5f13f, 0x026c4112, 0x05f48eca, 0x00f1a906, 0x141277a6, 0x007554f3, 0x99515}}}, - /* 9*16^10*G: */ - {{{0x1fa194ae, 0x075a8bfa, 0x0152bb3c, 0x00523b34, 0x0b149064, 0x0ece954f, 0x0a24045d, 0x1b40f6cd, 0x79a3d9}}, - {{0x1fcf634b, 0x1e32f4e4, 0x1e6f1353, 0x084be65e, 0x103d86bd, 0x18dc2c57, 0x06cd2cd9, 0x194e4a96, 0x84e1db}}}, - /* 11*16^10*G: */ - {{{0x01e8b7fe, 0x16483001, 0x016c9a9a, 0x01c5c2ef, 0x098e05dd, 0x06556e7e, 0x160a28f9, 0x0129ab60, 0x3393fd}}, - {{0x023c6821, 0x00a12210, 0x06e52dc3, 0x0d661515, 0x0668d8e5, 0x1576ce2d, 0x1ae0babf, 0x17d90cf7, 0x130437}}}, - /* 13*16^10*G: */ - {{{0x01528cf6, 0x04abceab, 0x141a53a8, 0x004a15ec, 0x10a52e6a, 0x02c3772d, 0x1f85786d, 0x10c268c4, 0xa16b28}}, - {{0x1ce93f3b, 0x05c907cf, 0x132004e0, 0x07f79027, 0x150f4349, 0x16bcec08, 0x166644f3, 0x15d0a6f5, 0xf40598}}}, - /* 15*16^10*G: */ - {{{0x0c8db2e0, 0x0885335c, 0x035cd60d, 0x197b82be, 0x074f6473, 0x04d5d4ad, 0x1d32fdb2, 0x04031c68, 0xd317ce}}, - {{0x074bc9a9, 0x0d9a5159, 0x0e183ce9, 0x04e9a045, 0x19136caa, 0x01f471cb, 0x112e670b, 0x01521270, 0xd61a21}}} - }, - { - /* 1*16^11*G: */ - {{{0x03fe67b2, 0x1718cbd5, 0x0b8cce31, 0x117fce14, 0x123b234a, 0x15cdd4b9, 0x1772f199, 0x086ee790, 0x6608c2}}, - {{0x05b47a28, 0x091ff2e7, 0x1150c206, 0x162b3e81, 0x0e03fc22, 0x1206d3a3, 0x05a211bd, 0x17d8a438, 0xa1a916}}}, - /* 3*16^11*G: */ - {{{0x0bc73e02, 0x1f375569, 0x194c4b04, 0x0cc29dd6, 0x18631849, 0x0c08beab, 0x108c81aa, 0x1c54d8bb, 0xf0956a}}, - {{0x0611219d, 0x0967b4cc, 0x0ba515cb, 0x1a091b77, 0x19356672, 0x02c57941, 0x00f1db88, 0x0c02289c, 0x433fe6}}}, - /* 5*16^11*G: */ - {{{0x1c5fe45c, 0x0f116f28, 0x1f03d65f, 0x05035070, 0x1283488b, 0x124ebe7b, 0x183294bc, 0x1d479454, 0xdb98eb}}, - {{0x1ef45a22, 0x05380e21, 0x12038711, 0x06409f54, 0x12c8ce98, 0x094eec48, 0x168b7854, 0x016eb7b0, 0xe0c0f3}}}, - /* 7*16^11*G: */ - {{{0x02128eac, 0x1acf306f, 0x0bc732eb, 0x0eb1ab99, 0x051690c4, 0x159dbeb5, 0x17d086e9, 0x02c15bb4, 0xa73c0}}, - {{0x04f1180d, 0x02c948eb, 0x1576728e, 0x0eb3e2ee, 0x10a7c793, 0x1b6eca7a, 0x0e329572, 0x0ac089d0, 0x443fda}}}, - /* 9*16^11*G: */ - {{{0x03ccbc30, 0x12d4998b, 0x0d258631, 0x1fcba43a, 0x197249ed, 0x1bb33d04, 0x1c8dc3b4, 0x1868f969, 0x378720}}, - {{0x1315729e, 0x110193f8, 0x0d23e11a, 0x19f2aba2, 0x19b6d16b, 0x05605553, 0x0e324c46, 0x1739ee4a, 0x8f1bdd}}}, - /* 11*16^11*G: */ - {{{0x03bb1b6b, 0x12546f2a, 0x1f0afea9, 0x1fde65e8, 0x1a621575, 0x08c6082a, 0x09867660, 0x03b6f163, 0xfe8fd2}}, - {{0x10eaaf93, 0x1daecdd1, 0x0afe2265, 0x09bb9fe1, 0x113c00f1, 0x074afad6, 0x18dda78a, 0x15d864ad, 0x791e22}}}, - /* 13*16^11*G: */ - {{{0x144b7cea, 0x002acce5, 0x1b3e1f7a, 0x08d28122, 0x1dcca474, 0x00113c59, 0x18bba081, 0x1aaf3f6f, 0x2c331f}}, - {{0x15d1c9c2, 0x1e15a356, 0x0c2501df, 0x04a23fe2, 0x1d650619, 0x19ec61de, 0x19dbf3cf, 0x0399c0c3, 0x20567b}}}, - /* 15*16^11*G: */ - {{{0x0112278c, 0x1c94d9bc, 0x03668563, 0x02c93a15, 0x04b66dd0, 0x1a643fc2, 0x0c828d22, 0x0d88ca34, 0x509bc0}}, - {{0x0e178f66, 0x043ae4c4, 0x0d7e517b, 0x0bfd0dce, 0x164570f6, 0x1a78bdc7, 0x1bb05d83, 0x1856e448, 0xb4b168}}} - }, - { - /* 1*16^12*G: */ - {{{0x17e55104, 0x175d7c00, 0x03a71c70, 0x1506bf77, 0x1561cf73, 0x09e1a6c5, 0x1cdd8f7a, 0x0a44f6f0, 0xd8de76}}, - {{0x052e08cd, 0x10177c07, 0x1036c6ca, 0x0e7f9c32, 0x0f924c2f, 0x114568ee, 0x0b457131, 0x0cb7c27e, 0x2fd294}}}, - /* 3*16^12*G: */ - {{{0x0987bfd3, 0x09ce163f, 0x110a131a, 0x0a8e5fe9, 0x1d19187c, 0x1df57d6e, 0x18cd5477, 0x0df7aa31, 0xe3a578}}, - {{0x0cc23e7d, 0x1698db64, 0x0a38205f, 0x19e5d9b2, 0x0210ca3d, 0x1cffa56c, 0x039a11de, 0x012a6b08, 0xf74bad}}}, - /* 5*16^12*G: */ - {{{0x02d5056e, 0x13ca8e91, 0x11e81f2d, 0x196b4fc4, 0x05e480ed, 0x0ffe74b7, 0x03504549, 0x083d94a4, 0x42a970}}, - {{0x10f7db11, 0x020a6e45, 0x07f47f52, 0x1c907add, 0x03b26b64, 0x16e935ab, 0x1c19bb0d, 0x0cd9e010, 0xf2fc7f}}}, - /* 7*16^12*G: */ - {{{0x13dafd3b, 0x13a2fc8e, 0x12ce55b1, 0x1133e05b, 0x179d66fb, 0x16176b29, 0x1933f88c, 0x036384f2, 0xd6ca7}}, - {{0x1a6fe6e8, 0x156f8a10, 0x021dc6b5, 0x049157dd, 0x1de58a02, 0x0a501383, 0x04f67f92, 0x1671fbc5, 0xa85130}}}, - /* 9*16^12*G: */ - {{{0x11131f8b, 0x15fce3ff, 0x0883537d, 0x08d2c19f, 0x11fb4696, 0x116fce21, 0x0f65f530, 0x0f5b0cb4, 0x5edca}}, - {{0x1a6f779f, 0x167858cd, 0x1a275243, 0x04a00be1, 0x071be335, 0x0b8daf81, 0x1af00727, 0x03c91d10, 0x9e5888}}}, - /* 11*16^12*G: */ - {{{0x0b597e4d, 0x047cfa0f, 0x1f468c67, 0x09e64bce, 0x11c11497, 0x02d19dbb, 0x0290486d, 0x0ac178f4, 0x5a13c0}}, - {{0x041856e0, 0x1bf2434f, 0x04d9992b, 0x1d0f56b2, 0x173ce7bd, 0x0c507916, 0x1ffd47f4, 0x027121f2, 0xc9e73c}}}, - /* 13*16^12*G: */ - {{{0x0260faf0, 0x153c4b0a, 0x1a564d76, 0x17a68b2f, 0x1272ea2b, 0x070d3407, 0x19d50c51, 0x0ac02f6d, 0x96b256}}, - {{0x0366d412, 0x07212907, 0x1f53d6b0, 0x177f30e0, 0x199e1890, 0x072b99df, 0x12b002b6, 0x1400366f, 0xdcf8a6}}}, - /* 15*16^12*G: */ - {{{0x0ad13276, 0x04d0df25, 0x1010f1e9, 0x06a1d5d3, 0x171a3ca6, 0x15959c3b, 0x18909bc4, 0x0218839b, 0xb9719}}, - {{0x0a84dadb, 0x19c79a10, 0x1c3eb8ec, 0x1af25304, 0x0811f593, 0x122d9dfb, 0x1bef538b, 0x0dde00dd, 0xac2848}}} - }, - { - /* 1*16^13*G: */ - {{{0x071e5c83, 0x1535e490, 0x10a82fbb, 0x04fe330a, 0x0e5b18bd, 0x02db952c, 0x1cfc82a1, 0x082a04da, 0x54ccc9}}, - {{0x140916a1, 0x1e8477b8, 0x03b925b3, 0x1c1798bb, 0x0bf22929, 0x038aed69, 0x14c8ea3e, 0x08b68a28, 0x1c433f}}}, - /* 3*16^13*G: */ - {{{0x0f76167c, 0x02f1b115, 0x1d19ce53, 0x1e845988, 0x0d9f22f2, 0x163496e6, 0x1e54e708, 0x1b96e7df, 0x87582e}}, - {{0x0f4d7ff6, 0x037ddb0b, 0x065efa1b, 0x051e0cee, 0x036a8880, 0x0161e1b9, 0x09eff784, 0x06a15ac9, 0x75b94}}}, - /* 5*16^13*G: */ - {{{0x14de6611, 0x1391f743, 0x0087ec11, 0x0cae7297, 0x0f11e33f, 0x1b9b1ab3, 0x1b6c7096, 0x1943e4e6, 0x4a107a}}, - {{0x18a805fe, 0x1ac75f72, 0x084cab00, 0x1aa8f4b8, 0x0052e075, 0x12747b80, 0x1ce4d339, 0x0a200c7d, 0x809b26}}}, - /* 7*16^13*G: */ - {{{0x0dcfecb0, 0x05d27683, 0x0a3611bf, 0x07fa3a61, 0x149f6e98, 0x0706a4df, 0x1f259528, 0x166e555b, 0xfd402e}}, - {{0x0da08de8, 0x02c9f9ef, 0x19979e44, 0x1698497b, 0x1a86b1a4, 0x131c4dd5, 0x088ba698, 0x061bb4c7, 0xd6b340}}}, - /* 9*16^13*G: */ - {{{0x154659ed, 0x1a6eb07a, 0x17659b96, 0x1c7a4432, 0x1d0a07fa, 0x0703ff64, 0x145577ee, 0x08c8c30e, 0x467bb3}}, - {{0x0800cf83, 0x1903e859, 0x004f8026, 0x17821b9a, 0x02cd3701, 0x06ac36dc, 0x03a287cb, 0x1a0b552f, 0xd01eff}}}, - /* 11*16^13*G: */ - {{{0x1c97e515, 0x1324c256, 0x021697fb, 0x09ad8673, 0x0c7e5691, 0x0db1874f, 0x0391b21e, 0x11f19bb8, 0xcf66b9}}, - {{0x006c8a51, 0x0c10a754, 0x0400cea5, 0x00e8b1b3, 0x06a7b33f, 0x1a081a76, 0x04847096, 0x0f72088c, 0xa7071}}}, - /* 13*16^13*G: */ - {{{0x186154e5, 0x1d295080, 0x0be8374e, 0x0054cd35, 0x06770864, 0x04a9d6a4, 0x08d1d472, 0x18c1f7f5, 0x3d9252}}, - {{0x1603a8a2, 0x1fe49fb4, 0x1f75c1dd, 0x03f6faf8, 0x14cf3aea, 0x19a144b5, 0x15ff1124, 0x1b9a5f53, 0x3d0d01}}}, - /* 15*16^13*G: */ - {{{0x0a4a8daa, 0x1db1db15, 0x029728f4, 0x00c01de5, 0x0968ce51, 0x1ada47a5, 0x1a71d83a, 0x164d112e, 0x2bbe38}}, - {{0x1236e49b, 0x1043ba74, 0x1adb9f5f, 0x056749c7, 0x00850990, 0x1f7c8fcb, 0x0dbd78b3, 0x1ec01a76, 0xf85707}}} - }, - { - /* 1*16^14*G: */ - {{{0x02d32936, 0x187dbb89, 0x011fc070, 0x19a05c65, 0x17f38e40, 0x03e8a89e, 0x11f67db3, 0x0b2f0294, 0xc5440c}}, - {{0x07cabfd4, 0x1217d1ba, 0x19079766, 0x0da50c63, 0x0f4acd8a, 0x0f0e91f6, 0x1e9cbb70, 0x174707c3, 0xd27ee9}}}, - /* 3*16^14*G: */ - {{{0x1989a8e1, 0x0c280f63, 0x1b92f75f, 0x1b2de6e9, 0x0fe0a7c1, 0x1023cdce, 0x1e6dd403, 0x188b9bf4, 0x3e4d03}}, - {{0x041c240a, 0x03c89c42, 0x0f59d026, 0x1e31abe7, 0x0a719ffa, 0x0be56be5, 0x11d6ab04, 0x1a102b4c, 0x12f744}}}, - /* 5*16^14*G: */ - {{{0x19bb7902, 0x09cd4686, 0x0df1cfda, 0x04d8e50d, 0x05e9fd8c, 0x124f4a24, 0x00d66a68, 0x09367ac2, 0x1b684}}, - {{0x003ee653, 0x0bfa258f, 0x00d9a0b3, 0x164c08e3, 0x11581fce, 0x0c72e1b6, 0x10f82fc6, 0x143d26f3, 0xe59063}}}, - /* 7*16^14*G: */ - {{{0x0371d9fe, 0x14dab6a6, 0x0675aef0, 0x166ad833, 0x13a4cf04, 0x0ad3e1d5, 0x1288cd65, 0x16359993, 0x952c3c}}, - {{0x0189a13f, 0x1b673692, 0x0231d7b5, 0x08c9e230, 0x0e5d0664, 0x089b7b76, 0x1c1a9f7e, 0x08defac5, 0x59b985}}}, - /* 9*16^14*G: */ - {{{0x0bc2c885, 0x03ffe3b4, 0x19395f21, 0x03dceea4, 0x1cde5155, 0x002285cb, 0x1ab21626, 0x1c2b62cd, 0xdfcb4e}}, - {{0x1345d92e, 0x0ea53218, 0x0afa5d5d, 0x0e7128f7, 0x00f411c7, 0x1e136416, 0x0e854f13, 0x12aaa0c2, 0x536a23}}}, - /* 11*16^14*G: */ - {{{0x1510208e, 0x1c5c295f, 0x15e50e1c, 0x199c5b09, 0x097bbdb8, 0x179d023e, 0x00322a1e, 0x18137cca, 0x157966}}, - {{0x0d207357, 0x10777128, 0x1690f7f5, 0x1f8c8865, 0x0be07008, 0x1bdbddc6, 0x193aaf7f, 0x0b56e244, 0x40446d}}}, - /* 13*16^14*G: */ - {{{0x0b96fe13, 0x04fe65f4, 0x014baa07, 0x0495a769, 0x16e23e49, 0x147fc09f, 0x042b5b86, 0x078963d3, 0xc6b21e}}, - {{0x17bb1417, 0x0035cb57, 0x19b4b5a8, 0x0aa122f3, 0x128a2ff6, 0x1c0f1a75, 0x1523952d, 0x1b186669, 0x335bcd}}}, - /* 15*16^14*G: */ - {{{0x03936565, 0x1b2c0cd6, 0x1fe931f0, 0x0f66db2e, 0x122d997a, 0x054ea9ca, 0x05bc2d2f, 0x188f18e5, 0xa231e4}}, - {{0x15ec5f19, 0x172b5031, 0x1c5509a2, 0x0adc012d, 0x1cf942ba, 0x07634401, 0x1a470365, 0x117d8ff7, 0x80e0c9}}} - }, - { - /* 1*16^15*G: */ - {{{0x1066fd48, 0x1cfa0b95, 0x05c560ef, 0x0e203971, 0x0dca61c3, 0x0dcbd35d, 0x07141b1e, 0x0f4844fe, 0x241c56}}, - {{0x12857b08, 0x1be9633c, 0x08d9815f, 0x10e2715d, 0x003a48ea, 0x00be0219, 0x152e4d8e, 0x127a8605, 0x40a62d}}}, - /* 3*16^15*G: */ - {{{0x0df9591d, 0x10fbedc8, 0x0d320aa1, 0x18758485, 0x07218dce, 0x09e25599, 0x03a72e83, 0x07704d2f, 0xde2fd2}}, - {{0x0457ad84, 0x070cb9e8, 0x100da92d, 0x15143f11, 0x12ebbda9, 0x1bf6425c, 0x0fcc17b2, 0x02676c48, 0x400d71}}}, - /* 5*16^15*G: */ - {{{0x1562282c, 0x15412a57, 0x1ef0ddcb, 0x1e75f271, 0x11340f02, 0x04581270, 0x0f7664e5, 0x16060999, 0x8df889}}, - {{0x01d195cd, 0x12b55ecb, 0x1e6ec55c, 0x1ee0899d, 0x0f35e247, 0x0f318c45, 0x1bb5b1d0, 0x0ce640b9, 0x74525b}}}, - /* 7*16^15*G: */ - {{{0x0dddb2dd, 0x0ea944a8, 0x0b0369be, 0x10c99b98, 0x0f245078, 0x1c0678a9, 0x03e0007e, 0x119b3170, 0xa0fd75}}, - {{0x13ede6b2, 0x1eca7fc3, 0x10269f1f, 0x19d2df12, 0x08f311c8, 0x0fe989d8, 0x0357e1a4, 0x06b8266d, 0x53e5d8}}}, - /* 9*16^15*G: */ - {{{0x0f542e36, 0x0465d502, 0x0d0570b8, 0x05ff5f42, 0x135d84e2, 0x0933ca31, 0x03d9f796, 0x108e5a34, 0x3170c5}}, - {{0x163288b5, 0x1623ad77, 0x066f86f1, 0x1eead2b3, 0x1773d006, 0x0849ff5c, 0x1f88dd45, 0x025f874f, 0xb20836}}}, - /* 11*16^15*G: */ - {{{0x1c7548e9, 0x0cd91d2e, 0x04b5531e, 0x1b500e11, 0x03fe5d8d, 0x00b4a783, 0x180a76d2, 0x152145a7, 0x92fab0}}, - {{0x0917758f, 0x03896682, 0x0b421223, 0x01b8d1de, 0x079ffc8a, 0x18a70613, 0x1af3d0c5, 0x0d019648, 0x55e7b4}}}, - /* 13*16^15*G: */ - {{{0x1498f7f8, 0x06c0285c, 0x104588b8, 0x1ecfa64c, 0x08712c4d, 0x108d8c96, 0x145e742f, 0x17c3006a, 0x91b065}}, - {{0x1f23195b, 0x03a06cf1, 0x0258e78f, 0x18f684af, 0x1e264df2, 0x19a4800b, 0x1883fe7f, 0x0eff6ce2, 0x35b6f}}}, - /* 15*16^15*G: */ - {{{0x0060e322, 0x0ee5f712, 0x113452d4, 0x1b8e6f53, 0x0b9923ec, 0x034ba44d, 0x0cea70e4, 0x09995939, 0x8e4a1f}}, - {{0x104619d7, 0x110c1e6c, 0x13eff813, 0x01531b2a, 0x07bc4fb0, 0x0f692037, 0x1dd4bec1, 0x0bd6651a, 0x4936b7}}} - }, - { - /* 1*16^16*G: */ - {{{0x0e14db63, 0x073ae5a4, 0x1947dfa4, 0x1277555a, 0x025de294, 0x0c971937, 0x0a961249, 0x17850235, 0xfa822}}, - {{0x1f462ee7, 0x008922a2, 0x1fa0bd79, 0x034ca0a1, 0x1188b34b, 0x0a5e59ef, 0x0035bd2b, 0x1d1ebb75, 0xbff44a}}}, - /* 3*16^16*G: */ - {{{0x1db3cdec, 0x096229fb, 0x0a3afd5d, 0x1e742564, 0x04bc8dbe, 0x122f3df5, 0x1d739659, 0x0c9ff225, 0x85b2c0}}, - {{0x0a03f81f, 0x1a684102, 0x133e3823, 0x101669cc, 0x06d00dc9, 0x1d1697e6, 0x14d98f1f, 0x11e73a22, 0xf64b27}}}, - /* 5*16^16*G: */ - {{{0x0607b030, 0x0452d724, 0x01359cca, 0x15fec7cb, 0x0f29c24d, 0x1dd6760b, 0x119de147, 0x0ed88042, 0x110b03}}, - {{0x13617c3a, 0x01d50895, 0x0a61d27d, 0x1c2aadf6, 0x1c70c87b, 0x1c4fc230, 0x19cd31ba, 0x10a631dc, 0x84432b}}}, - /* 7*16^16*G: */ - {{{0x15a76f08, 0x076ec0e3, 0x0efb5395, 0x0be4a717, 0x0aaf8329, 0x1092158e, 0x075c53db, 0x0893ec8e, 0x18784e}}, - {{0x0b824993, 0x19cb02eb, 0x02894c82, 0x1ae94f4c, 0x1e671fc9, 0x147ed638, 0x0b9c5dde, 0x0fe943c3, 0x8d76ed}}}, - /* 9*16^16*G: */ - {{{0x1a6fad81, 0x14719e4f, 0x032c0fb3, 0x06cae918, 0x0037d9c3, 0x16ebb81d, 0x1ae6bbd5, 0x1c0fa0bc, 0x58a2f9}}, - {{0x1b109594, 0x00030af1, 0x0c02e095, 0x1765a65a, 0x1a6bd798, 0x017c38bf, 0x038306da, 0x18b58aac, 0x6ab64}}}, - /* 11*16^16*G: */ - {{{0x1eb52583, 0x191788fc, 0x03304ebe, 0x15339d82, 0x1676fea8, 0x16dd93c7, 0x0e8903b9, 0x1b99cfd7, 0x1ef020}}, - {{0x1a3f17ae, 0x0d93c0cb, 0x04b532d5, 0x0601f2e0, 0x095306ac, 0x1607a5cb, 0x12c025fd, 0x164b4f42, 0x594476}}}, - /* 13*16^16*G: */ - {{{0x10a1958f, 0x0e11f60f, 0x0d5990ed, 0x136a48df, 0x1a32c4f3, 0x0a267d5f, 0x084e5774, 0x0c783ad4, 0x4e4a81}}, - {{0x08636f8a, 0x01d9fa8a, 0x110f59a9, 0x0810bf65, 0x06fa8400, 0x051f714e, 0x03440cfd, 0x0b6f3d19, 0x2574a4}}}, - /* 15*16^16*G: */ - {{{0x04935db5, 0x013ad423, 0x1af6c3ba, 0x0f304c38, 0x0519e281, 0x1f076aca, 0x04138cc9, 0x02d5bac2, 0xf6966a}}, - {{0x1d166838, 0x11a41b60, 0x006fc04e, 0x08a74688, 0x0755e2d7, 0x172b961e, 0x16cb0697, 0x00f52063, 0xba0de3}}} - }, - { - /* 1*16^17*G: */ - {{{0x176a6987, 0x07a0982d, 0x1690ffda, 0x10356887, 0x01b3f2b4, 0x14c46bf7, 0x0551f771, 0x1af53313, 0x54bc18}}, - {{0x1b9aae49, 0x122be682, 0x1cec467f, 0x171da976, 0x1e2fd52e, 0x1c28dd39, 0x0bcdce46, 0x02423cdd, 0x4b2c8c}}}, - /* 3*16^17*G: */ - {{{0x1d1fd820, 0x05fa3faf, 0x1d9d400e, 0x0f0a8c90, 0x1271b788, 0x08113158, 0x14aaa18d, 0x1ed01838, 0xbafbbc}}, - {{0x1bf074f0, 0x176d6a90, 0x07f2b5ba, 0x18694246, 0x1c0fde81, 0x1fad644d, 0x1604b39e, 0x0f93b69b, 0x148799}}}, - /* 5*16^17*G: */ - {{{0x14299b7e, 0x08b84094, 0x01b8343a, 0x0f3e5a13, 0x020ec24e, 0x1dfe3ae1, 0x07f8a8f0, 0x1ee20671, 0x9b1938}}, - {{0x047b84de, 0x0bd942ba, 0x1ae08cb1, 0x1bd0a3f0, 0x03ec90ac, 0x14c70e55, 0x0a0cc503, 0x0dde2e20, 0xfb12aa}}}, - /* 7*16^17*G: */ - {{{0x110cc4c4, 0x0a083a06, 0x094f683f, 0x1a6b4589, 0x01b2cb71, 0x0fee033b, 0x1641f0e0, 0x10b9802e, 0xa67719}}, - {{0x1c976570, 0x1079d91b, 0x1fcc2530, 0x08aee74d, 0x19c3dbc7, 0x0b300f2e, 0x1663ca6f, 0x10beea1b, 0x855061}}}, - /* 9*16^17*G: */ - {{{0x14242a28, 0x0084016a, 0x0f29dc55, 0x1796424a, 0x14eca455, 0x17bc25bb, 0x1f0427a2, 0x0a6d61d5, 0x88b7ed}}, - {{0x194ed8ce, 0x1cb40f63, 0x00f8d1fe, 0x0cd4391f, 0x1bd934e3, 0x1cee9ac3, 0x11791fef, 0x040c48a6, 0x22b053}}}, - /* 11*16^17*G: */ - {{{0x1bc1a94c, 0x0b0a2764, 0x1c76be00, 0x0e3a567c, 0x08757516, 0x1958112f, 0x0f4814b5, 0x002550d6, 0x37114}}, - {{0x0fc2073c, 0x00605b67, 0x110920e3, 0x03186c55, 0x05335c85, 0x10d2a568, 0x0e43be30, 0x07aa3bae, 0x4d1d69}}}, - /* 13*16^17*G: */ - {{{0x077f88ba, 0x1de8f04c, 0x06fb4dbb, 0x100ef3dd, 0x02cc3509, 0x11974275, 0x04f8d2d6, 0x09913085, 0xcc9821}}, - {{0x07885278, 0x123177e4, 0x0d531382, 0x0c1cfdde, 0x163abeff, 0x053233be, 0x1ea44531, 0x1d1ca4b5, 0x4ebb4}}}, - /* 15*16^17*G: */ - {{{0x1d70187c, 0x0b98ca6f, 0x19031fc5, 0x1590c536, 0x15bf8751, 0x12f01487, 0x043e6053, 0x00534854, 0xad3ae}}, - {{0x1fc775a7, 0x0ffe7a59, 0x18a83d9f, 0x09f6102c, 0x1b33dd03, 0x0af82fd5, 0x1b8de171, 0x1a8eb108, 0x2af040}}} - }, - { - /* 1*16^18*G: */ - {{{0x10aae231, 0x0557d68b, 0x1e5adf18, 0x0970a4f3, 0x1756f519, 0x0411c933, 0x0fca17c9, 0x0d32ec3c, 0x1d35c9}}, - {{0x0cd6ac71, 0x033831d6, 0x0699bc56, 0x0b1548e5, 0x1f810edf, 0x055b1175, 0x008c7598, 0x16c5bec1, 0xc7226c}}}, - /* 3*16^18*G: */ - {{{0x0cfa3fac, 0x1069ff0c, 0x0ae064f3, 0x1b0d3f86, 0x1803023a, 0x1da2eb06, 0x0d338b3a, 0x08f4da44, 0xdf3d40}}, - {{0x0fc7d419, 0x03136c9c, 0x020a5d7d, 0x0c79c92d, 0x19dbfafd, 0x10f94e07, 0x036c92a8, 0x0a453fa8, 0x48fa6f}}}, - /* 5*16^18*G: */ - {{{0x1f1322d4, 0x16c92d70, 0x13372eeb, 0x14d28095, 0x1f822cb0, 0x16265188, 0x0513a879, 0x0d563f2c, 0xdbb2af}}, - {{0x0a8c5311, 0x12495a7a, 0x1f8e97ea, 0x1f92f0f6, 0x13f9d9a9, 0x068f6b21, 0x186a86d8, 0x1725e26a, 0xebae75}}}, - /* 7*16^18*G: */ - {{{0x01138f7b, 0x034d19e5, 0x1cba3cbc, 0x03927c5b, 0x15f0bc4c, 0x05133fcd, 0x1f532bea, 0x0b2fe4c3, 0x1dba7b}}, - {{0x039bf268, 0x0416c63d, 0x008cb037, 0x0dcd6f33, 0x007f5813, 0x08035dc0, 0x1f18eb86, 0x07cbbcfd, 0x6aaf7d}}}, - /* 9*16^18*G: */ - {{{0x179a70af, 0x0d43bb80, 0x1937ca23, 0x1a853536, 0x105c6ec9, 0x1416afa9, 0x0674c6ef, 0x0884c4d2, 0x348a2e}}, - {{0x07b66e82, 0x142430a4, 0x184f96b2, 0x0f858b6f, 0x10105b2a, 0x1de70011, 0x1a0231d1, 0x0f3eab47, 0xa1b9fa}}}, - /* 11*16^18*G: */ - {{{0x04d3a201, 0x1a3b6bb6, 0x06e7bbf1, 0x124d49fb, 0x0df5f36e, 0x07dfc98d, 0x1872a1a9, 0x0a333393, 0x3a4ec8}}, - {{0x08635f89, 0x0c2cb7bb, 0x0f3556f7, 0x063cb5ee, 0x14a8b27d, 0x1e08d23b, 0x0b79a780, 0x1f05ec4c, 0xc99a2e}}}, - /* 13*16^18*G: */ - {{{0x1c978567, 0x17d7397e, 0x1707e607, 0x1b4d1081, 0x1f60be15, 0x1aeb17f8, 0x115e13a4, 0x1b10669a, 0xb1ba52}}, - {{0x162dc291, 0x1fd24151, 0x1f35029d, 0x08d96175, 0x1b78fd9a, 0x1e7b89ed, 0x0e9df17d, 0x18f50d28, 0xa46bae}}}, - /* 15*16^18*G: */ - {{{0x12350da1, 0x11477528, 0x1d7c10f4, 0x0298ef82, 0x12c2f194, 0x1bdcb4b0, 0x0bf49c62, 0x07b1de55, 0xae6eb}}, - {{0x10a14bc3, 0x19f04f9b, 0x10f692f1, 0x08d1e1da, 0x189b566d, 0x1a7bfe20, 0x12b8b740, 0x13f6c00d, 0x99cdee}}} - }, - { - /* 1*16^19*G: */ - {{{0x150e4f5f, 0x0b957543, 0x19f83995, 0x0b95354a, 0x0f29acbf, 0x187bd501, 0x0bbce23f, 0x0b30896b, 0x55d9a9}}, - {{0x1ca97db0, 0x02c75bb5, 0x0b46c572, 0x10218c67, 0x0ec524c9, 0x0ba7de64, 0x080dd9b5, 0x1354bb5a, 0x69cb7f}}}, - /* 3*16^19*G: */ - {{{0x1eb142e9, 0x0354c43f, 0x01ff3ef0, 0x0dd60c8c, 0x0d480c17, 0x0341c7d7, 0x1845e536, 0x1d7c8de7, 0x4b0043}}, - {{0x02c68552, 0x0596296b, 0x04962201, 0x06521e74, 0x02d870f2, 0x04231b11, 0x106b6c5e, 0x047461b5, 0x173ccf}}}, - /* 5*16^19*G: */ - {{{0x17f1aa96, 0x16ea5738, 0x1fd9207d, 0x0f4bee69, 0x063c513d, 0x06e5db9a, 0x1f08c9ca, 0x0f3255ad, 0x79ead2}}, - {{0x0b0a3fb7, 0x05d38e72, 0x0ce556a0, 0x09ae2223, 0x16542de8, 0x01c9ab12, 0x0afc69b9, 0x19ff755b, 0xa95de9}}}, - /* 7*16^19*G: */ - {{{0x193a9ae6, 0x002e5397, 0x1dfe2b72, 0x01540b38, 0x1743f8ee, 0x0f1b18d6, 0x073ad49e, 0x0a1e49b4, 0x318e00}}, - {{0x1c447d79, 0x025ab4a6, 0x14ea3b86, 0x06dfb75d, 0x04bd0945, 0x1e528f28, 0x0a67d345, 0x022339d2, 0x2792ee}}}, - /* 9*16^19*G: */ - {{{0x1d30585a, 0x1bca2da6, 0x14052544, 0x1f143546, 0x0a4b495f, 0x197a4860, 0x10eee200, 0x0e3a5e3c, 0x6bbc54}}, - {{0x148b05f3, 0x17cbf779, 0x1e7ab65a, 0x00850205, 0x026be09f, 0x1158af91, 0x07c12a7b, 0x136182a5, 0x467b18}}}, - /* 11*16^19*G: */ - {{{0x00136275, 0x1127c046, 0x01dd4d49, 0x0f8002e7, 0x00d78a64, 0x0d487bbb, 0x144626d4, 0x18c2183f, 0x940148}}, - {{0x1997aa47, 0x0b1d088a, 0x13869097, 0x1675cac0, 0x1d6695d4, 0x06255a82, 0x13ddea89, 0x0be26cf4, 0x6967f9}}}, - /* 13*16^19*G: */ - {{{0x1f0fe850, 0x1d09ee9c, 0x0469ef70, 0x1a4617ca, 0x1f98e864, 0x164946d2, 0x127246d5, 0x124c0736, 0xc41833}}, - {{0x1d38666d, 0x1ac7a235, 0x0682bc04, 0x14fd93c0, 0x1d558065, 0x0aea1357, 0x1debae02, 0x19391a81, 0x3537fe}}}, - /* 15*16^19*G: */ - {{{0x14937fbe, 0x1f2209bb, 0x146e9bb3, 0x009bbbe0, 0x0f546c0b, 0x0000d7cb, 0x15c38305, 0x1ec4f8cf, 0x2baba3}}, - {{0x173a1df4, 0x1c872aba, 0x0b204424, 0x1b896321, 0x0abc9ec2, 0x1866c927, 0x0e235e0e, 0x0cb64411, 0x77e5c7}}} - }, - { - /* 1*16^20*G: */ - {{{0x0351964c, 0x069e96f2, 0x1504b075, 0x12486ede, 0x15c08346, 0x1e50c2ba, 0x11feb96a, 0x0b37c518, 0x6e29f9}}, - {{0x163fd88f, 0x0c4125ea, 0x02fed8c4, 0x0818a4f4, 0x0246def6, 0x163660c2, 0x0bd9414b, 0x13ea01e6, 0x34565d}}}, - /* 3*16^20*G: */ - {{{0x0c0e49cc, 0x1ca8081c, 0x1150034f, 0x065b50b7, 0x140ed412, 0x046f65db, 0x1dbb760a, 0x152f12e1, 0xd691d4}}, - {{0x100f4152, 0x085da60e, 0x1410fcb7, 0x17c3a055, 0x00c52ac5, 0x1edabb1f, 0x0e5fdfee, 0x10e96f1e, 0x7a79e7}}}, - /* 5*16^20*G: */ - {{{0x0b9b930a, 0x0c3b5cf9, 0x0c3d63cf, 0x026a548a, 0x1bc49deb, 0x1befbd3d, 0x1f177b96, 0x08d45c1a, 0x2a5d68}}, - {{0x1b2caeca, 0x17f9a2f9, 0x09c5a161, 0x16e686bc, 0x0ab58ea5, 0x181c81e2, 0x1db79733, 0x012d0ec8, 0xdc3d7c}}}, - /* 7*16^20*G: */ - {{{0x016959ef, 0x13ee5e94, 0x076d66be, 0x13a0ace8, 0x15df8767, 0x18a09713, 0x1498bc10, 0x0d471376, 0x876449}}, - {{0x00cd5010, 0x10188e5f, 0x1e78fc59, 0x0d5a82e5, 0x1961f285, 0x0093cb76, 0x1ff6782d, 0x1ac3a005, 0x599b69}}}, - /* 9*16^20*G: */ - {{{0x1aef0f84, 0x1ca04e71, 0x071d6e58, 0x16a0d50e, 0x1b8cab0b, 0x1fd60bd6, 0x06c4cf78, 0x1790248e, 0x94d393}}, - {{0x178ba7c1, 0x0d730dc9, 0x0b3c4aa1, 0x1e804ca1, 0x19a07dd3, 0x1e1c3591, 0x0fc87872, 0x169d696c, 0x5a826a}}}, - /* 11*16^20*G: */ - {{{0x0ffed1b7, 0x0a2abc27, 0x12a8ed3b, 0x17a24cac, 0x0bd2ee2d, 0x04b8169a, 0x18b745d4, 0x141113c9, 0x4a72b5}}, - {{0x1601dc5f, 0x0f94fec4, 0x1366116d, 0x0c971d8e, 0x0ea9685e, 0x1fe023e4, 0x038b230c, 0x1d4943a4, 0x3531e6}}}, - /* 13*16^20*G: */ - {{{0x10467317, 0x1021f92e, 0x16461a80, 0x03b883b1, 0x07900914, 0x13797d6f, 0x18569e19, 0x1f8b46e3, 0xd7f01c}}, - {{0x0f7d014e, 0x05cabeae, 0x1fef6257, 0x002e86d2, 0x1ef5728a, 0x10a0360a, 0x109bb1cd, 0x1b30ee4d, 0x888dbb}}}, - /* 15*16^20*G: */ - {{{0x1dea02c1, 0x1ebac853, 0x1d021f0e, 0x17736f8e, 0x11206e4f, 0x1fcec8f1, 0x1c6efa02, 0x173eef86, 0x7e50a0}}, - {{0x0d45c201, 0x1e4a36ff, 0x0386ca0c, 0x07269e2b, 0x19517742, 0x178eedc5, 0x0a7185b1, 0x0789c1fc, 0xc3405d}}} - }, - { - /* 1*16^21*G: */ - {{{0x0cb71280, 0x053ea088, 0x1158c44a, 0x0384b350, 0x1458ec14, 0x17783cb7, 0x1b67003c, 0x13d657fd, 0xff046a}}, - {{0x1ec33919, 0x161938fa, 0x0a121e9f, 0x16dcdd7a, 0x0fcc9012, 0x16edeea6, 0x085c2807, 0x159812a7, 0x432f55}}}, - /* 3*16^21*G: */ - {{{0x13ca3ce3, 0x193c1551, 0x1a9df897, 0x1630cb56, 0x0231fef2, 0x1e0fa989, 0x134c6a56, 0x0ba29a7b, 0xf717c4}}, - {{0x10ed88e9, 0x04a666da, 0x05db7c1a, 0x07c57bb8, 0x1ee55af5, 0x0a768556, 0x04b72a6d, 0x0ed1932a, 0x422c40}}}, - /* 5*16^21*G: */ - {{{0x1b28cd88, 0x1b42186a, 0x0a6f66b0, 0x1c12ea05, 0x1b32c738, 0x1ab13fc8, 0x0c830bfa, 0x169e66e1, 0x60e269}}, - {{0x0be2066c, 0x14dd4521, 0x1211ac38, 0x0ac2718d, 0x0df76024, 0x08c44b94, 0x02a58248, 0x0b4caf3e, 0xfe0017}}}, - /* 7*16^21*G: */ - {{{0x061cc594, 0x09d8c994, 0x1414dac5, 0x17ba2e09, 0x06855964, 0x1d02fe5a, 0x05242a96, 0x143cce73, 0x799297}}, - {{0x0f8d309e, 0x14888490, 0x0b1ba427, 0x150d5c17, 0x1e50127d, 0x088c3c4f, 0x06c3841a, 0x119aa479, 0x132ff1}}}, - /* 9*16^21*G: */ - {{{0x172d0aba, 0x04623d12, 0x1f86c5b7, 0x03215b8e, 0x1241dd8d, 0x0775aa80, 0x01c1e7b8, 0x09dfc850, 0x2d9be9}}, - {{0x11fa0876, 0x07b98fd9, 0x0dc439be, 0x038cf311, 0x1d91bbad, 0x1c9a5b0c, 0x0288a57b, 0x16bd3d13, 0xa9708d}}}, - /* 11*16^21*G: */ - {{{0x155e8732, 0x0603da41, 0x1b478c78, 0x0c5dbca0, 0x0c243cfa, 0x03298a49, 0x0859832f, 0x13d91048, 0x212703}}, - {{0x00cacc07, 0x0c91afa3, 0x15ef5a35, 0x07e7e775, 0x10a5cd69, 0x1cedddbf, 0x16a80652, 0x0de475c6, 0x85219c}}}, - /* 13*16^21*G: */ - {{{0x12083347, 0x0489a067, 0x0694c898, 0x15c7ccee, 0x0b42b9e1, 0x07ad5d01, 0x03ae5eb4, 0x09657b1c, 0xfab5b5}}, - {{0x1d38fd2f, 0x0664e6c1, 0x09a6bea7, 0x1c6f4c2d, 0x03eafc05, 0x15791305, 0x0540f21e, 0x02c30da8, 0x5758d1}}}, - /* 15*16^21*G: */ - {{{0x1f572554, 0x1b3930a7, 0x1d36adcf, 0x085c8e31, 0x0a56ff38, 0x0b3b85bf, 0x1f295e42, 0x0ae4f2e3, 0x685d27}}, - {{0x00979e03, 0x18d7b685, 0x1d33292d, 0x15545581, 0x0377cc58, 0x0e4020f0, 0x17f01b8e, 0x18441568, 0xa82f89}}} - }, - { - /* 1*16^22*G: */ - {{{0x05852e50, 0x1e859266, 0x15c33171, 0x18fcc79e, 0x07eff8b2, 0x1511a4f7, 0x016307e6, 0x1bffd576, 0xe486c7}}, - {{0x0ecf107d, 0x15d1e56d, 0x04baf619, 0x08c7ac67, 0x1e05a694, 0x052e4fa8, 0x04ba7ba2, 0x1daac0d4, 0x51fd75}}}, - /* 3*16^22*G: */ - {{{0x1c881907, 0x1355322a, 0x002c76b1, 0x190ce6b6, 0x00415142, 0x02e63357, 0x0df25904, 0x1771c5ff, 0x4acf44}}, - {{0x163cdafc, 0x0935a2b7, 0x1612c94a, 0x0a565ef9, 0x05457993, 0x142d6885, 0x01ecd510, 0x1fc1ffab, 0xad99a8}}}, - /* 5*16^22*G: */ - {{{0x1439383f, 0x15d7034b, 0x0068aaa0, 0x1f4ac56c, 0x14eec34f, 0x11496411, 0x192775ea, 0x10683114, 0x4ddf22}}, - {{0x03d52337, 0x197d40c1, 0x07e09a58, 0x0ba08a26, 0x00c6b3dd, 0x174be9c6, 0x00f5d2ae, 0x0f61b231, 0xe71c62}}}, - /* 7*16^22*G: */ - {{{0x1822b4f4, 0x16e440aa, 0x1977e3c9, 0x0a75f9f0, 0x1f39ba53, 0x14f03cbd, 0x1e784cd3, 0x0f226f30, 0x58b065}}, - {{0x0c60fbca, 0x103d4108, 0x13949659, 0x0940edf8, 0x0836c1ca, 0x12af8131, 0x10dc09f2, 0x14828b45, 0x55a98a}}}, - /* 9*16^22*G: */ - {{{0x14fe39b0, 0x195e8861, 0x0d37b452, 0x02e79ae9, 0x01f358a3, 0x020e119c, 0x14a5d8e9, 0x0b14c966, 0xa345e0}}, - {{0x0baf79dc, 0x184a405d, 0x0da77d4d, 0x18d4eb56, 0x1d949ce8, 0x02ad947c, 0x1c3e47c2, 0x14dab954, 0x7c6dd5}}}, - /* 11*16^22*G: */ - {{{0x126695fb, 0x1df03dcc, 0x0eb7b84f, 0x01773fc8, 0x0ccb6afd, 0x05c3a36b, 0x0b20806b, 0x10603214, 0x3a10bf}}, - {{0x04eb7e47, 0x0ae39595, 0x1514a21d, 0x1fd4d887, 0x065c5f28, 0x1c243445, 0x1c55d880, 0x167d8344, 0xb5d585}}}, - /* 13*16^22*G: */ - {{{0x1d2c8614, 0x00d474b3, 0x16116589, 0x012c14c0, 0x12876a7b, 0x1ad61848, 0x10cf2973, 0x1f592020, 0x12fbdd}}, - {{0x18b0b174, 0x03bde0ea, 0x067d257c, 0x04b04738, 0x0cfb54d4, 0x08a14669, 0x01a0cff6, 0x1a5204f0, 0xa5ff20}}}, - /* 15*16^22*G: */ - {{{0x0d9aeeaf, 0x1fbb2181, 0x16bf2194, 0x00f29940, 0x19a3005d, 0x11d0fd7c, 0x01ddee2b, 0x0b34572f, 0x8bece8}}, - {{0x05f9eb5e, 0x0d06d1e4, 0x02603dd5, 0x04071edf, 0x1c368bb2, 0x0885877f, 0x07f3eee2, 0x1898a0ca, 0x35f933}}} - }, - { - /* 1*16^23*G: */ - {{{0x0b519178, 0x05b5c761, 0x0f47f161, 0x17333148, 0x0ee0ab63, 0x067c5af1, 0x10c33f82, 0x0976bca0, 0xf41d7f}}, - {{0x0a6a3551, 0x1d0b32ee, 0x06787e69, 0x135986d2, 0x02347ab4, 0x16f1fd54, 0x035bc411, 0x17d7b35f, 0xe6a669}}}, - /* 3*16^23*G: */ - {{{0x1e3501d9, 0x138989f0, 0x187f22c6, 0x1059c376, 0x13e611be, 0x0b48eb16, 0x19fccccb, 0x0fdac5a9, 0xd65f82}}, - {{0x0b55759e, 0x1ca23637, 0x1cc2f86a, 0x02755aba, 0x187fc61c, 0x1e528b35, 0x03f94ded, 0x1f9e1352, 0xf24b60}}}, - /* 5*16^23*G: */ - {{{0x0f2ed84e, 0x1b17f120, 0x18ba84b2, 0x129be6bf, 0x0c0ade79, 0x045abc16, 0x10e17b9b, 0x16dbd60b, 0x55a9b5}}, - {{0x146495a3, 0x1cee2a82, 0x08363c15, 0x1f69ae25, 0x1f43ae8f, 0x068c876b, 0x06aca45d, 0x12d593e3, 0xc4f221}}}, - /* 7*16^23*G: */ - {{{0x075495a2, 0x1e967c38, 0x0f002ca6, 0x1c3d6c91, 0x08bc49fd, 0x0b05312a, 0x07687dfb, 0x0db8fb6e, 0x79de57}}, - {{0x0aec6fb8, 0x01646355, 0x04e9d1a0, 0x09ea12c9, 0x079c6831, 0x16d723ee, 0x0809e179, 0x01cd630d, 0x3b2d3d}}}, - /* 9*16^23*G: */ - {{{0x02d1e7bb, 0x17495664, 0x0465933b, 0x07ff206a, 0x1e55524c, 0x19b4acab, 0x12db8992, 0x0642c480, 0x8fe04e}}, - {{0x1a62e84f, 0x13acd686, 0x011aa336, 0x02c8c8de, 0x1b34e5b9, 0x0752bd46, 0x163f975b, 0x0a045ec6, 0x3987db}}}, - /* 11*16^23*G: */ - {{{0x09f7c360, 0x00d25763, 0x00217084, 0x19aaefc9, 0x024e24ef, 0x0531b469, 0x03c542a5, 0x012afdbf, 0x3af499}}, - {{0x087d7a7b, 0x1cee1553, 0x18225734, 0x0a9bac4e, 0x13c33485, 0x03241739, 0x04754c7e, 0x061a763b, 0xd17060}}}, - /* 13*16^23*G: */ - {{{0x170373be, 0x0d291d73, 0x18f4ed4e, 0x1a0c4424, 0x07c4e213, 0x0179ff11, 0x01db0696, 0x0b8c4790, 0x31a7e0}}, - {{0x090950a8, 0x16bc3c87, 0x08950c23, 0x105732a3, 0x1db1e8ce, 0x05571a11, 0x199c086c, 0x1e7f1a3b, 0xc23d2e}}}, - /* 15*16^23*G: */ - {{{0x0b923b45, 0x0130876e, 0x0f892f6d, 0x153f7fe2, 0x18458a33, 0x09a316ec, 0x08fb4554, 0x09026ada, 0x740a66}}, - {{0x11ecaa5f, 0x0609f1c2, 0x121202ea, 0x0f32720f, 0x006cfa89, 0x03c453ab, 0x08fcbd39, 0x1184b9aa, 0x7f6d04}}} - }, - { - /* 1*16^24*G: */ - {{{0x1512218e, 0x025549cb, 0x1280506a, 0x0a4360e9, 0x0e902e9a, 0x059d0c51, 0x1e995e20, 0x0cc254ce, 0x4a5b50}}, - {{0x0c4f3840, 0x1f56d3d2, 0x189b6742, 0x1b62a833, 0x07d40626, 0x027df0b1, 0x07c71098, 0x039d5811, 0xeb1346}}}, - /* 3*16^24*G: */ - {{{0x118473fd, 0x177a0712, 0x05cce454, 0x1204d78d, 0x0a9e3bbb, 0x155ccb94, 0x0e8214a4, 0x06466631, 0x106406}}, - {{0x185cf805, 0x1d30b173, 0x08740e6b, 0x1c321a18, 0x1883ccfb, 0x014f32c2, 0x0b63239e, 0x10477174, 0x9c6832}}}, - /* 5*16^24*G: */ - {{{0x053f30f3, 0x0b3f7643, 0x088e374d, 0x047da5db, 0x03f212b4, 0x0086aa04, 0x1efd7b69, 0x11fe0be4, 0x38c8ad}}, - {{0x0be9217b, 0x03073a4f, 0x1677cde8, 0x07f53052, 0x1641f658, 0x0b2a6ede, 0x045bce42, 0x0f0edb96, 0x83c261}}}, - /* 7*16^24*G: */ - {{{0x16ef1584, 0x01f3488d, 0x04832fd5, 0x1345471f, 0x1184277a, 0x1df1fe9a, 0x0c256163, 0x179d0c17, 0x6fcb8c}}, - {{0x1d3110f2, 0x1e4fbe10, 0x0290c970, 0x05edad25, 0x0459d599, 0x0411d618, 0x15db5530, 0x07b16e43, 0xa8f1a8}}}, - /* 9*16^24*G: */ - {{{0x062255ef, 0x07a89a02, 0x1901e33a, 0x0e3a68ce, 0x1b0ee50d, 0x0e486f22, 0x0af5cd45, 0x1727eedc, 0x7811d0}}, - {{0x1be3252e, 0x0c5f7cd8, 0x150dda29, 0x1da0a275, 0x05132f51, 0x174a00dc, 0x11e95300, 0x06e176b5, 0x99bb76}}}, - /* 11*16^24*G: */ - {{{0x153d2ea7, 0x1f088789, 0x1ea19424, 0x1a104747, 0x16f2a9ee, 0x194eafc0, 0x033831ed, 0x1289516a, 0xc3583d}}, - {{0x0b667bbd, 0x18c1f4f0, 0x17c710ca, 0x124b4ca2, 0x1cccdd6c, 0x113f7c4f, 0x043d6591, 0x1812723d, 0x53967a}}}, - /* 13*16^24*G: */ - {{{0x102e3099, 0x16ef8702, 0x01005963, 0x04274cc5, 0x0d00d53f, 0x180c5dbd, 0x1407ce83, 0x05079bdc, 0xd591cf}}, - {{0x055ac5af, 0x1de13b2a, 0x045bf58c, 0x05dff116, 0x1c5825cf, 0x19869a85, 0x1b913944, 0x19f88f1c, 0x87ebe5}}}, - /* 15*16^24*G: */ - {{{0x12a940a5, 0x1932b231, 0x0539ac4a, 0x06bd6b48, 0x1e8714a4, 0x00f0d27c, 0x17130049, 0x0c25e646, 0xa0aa0d}}, - {{0x0b950422, 0x1fc41534, 0x146fe4e4, 0x1239bb4f, 0x01f3e6c6, 0x067cd00c, 0x10a066cd, 0x174edeec, 0x22340e}}} - }, - { - /* 1*16^25*G: */ - {{{0x008e2df0, 0x1146c1b8, 0x0a397dd9, 0x0764ae86, 0x00f5032c, 0x14efc5df, 0x065404b0, 0x017bc557, 0x2eb391}}, - {{0x1274eaae, 0x08866276, 0x1d97d242, 0x01a241d9, 0x0999f954, 0x1e9a46d2, 0x0ce9df4d, 0x0466e8e9, 0x3f29c0}}}, - /* 3*16^25*G: */ - {{{0x082867f0, 0x1815c25b, 0x06428e6f, 0x084dc436, 0x100f0a21, 0x08b53c04, 0x1388aaaf, 0x111cc98f, 0xf6e9db}}, - {{0x0f1861ea, 0x1ad9d788, 0x1c2d88d1, 0x08374bf2, 0x0d5b1270, 0x1dbb7460, 0x0dd20764, 0x016f5a55, 0x53ca79}}}, - /* 5*16^25*G: */ - {{{0x120d6102, 0x16e821c7, 0x114e5026, 0x1aa6f146, 0x19a5ef06, 0x0adcdb0c, 0x1275e170, 0x070ec1c8, 0xfd1ddb}}, - {{0x0e003b7c, 0x1053248d, 0x144e60f6, 0x1c322422, 0x1b700163, 0x0f8fbc41, 0x0e2bb6a8, 0x0e720a0c, 0xcb54b8}}}, - /* 7*16^25*G: */ - {{{0x02c77cb7, 0x1fb9a0ee, 0x17056dbc, 0x1b281205, 0x0698fef6, 0x139f32f7, 0x00767f92, 0x1844b332, 0x61a273}}, - {{0x1ddb25ed, 0x0a308fc0, 0x0b87dd21, 0x0b5b34e1, 0x10cc9c5c, 0x10cfaf75, 0x0f4fd3a8, 0x0669a75a, 0x5bbacd}}}, - /* 9*16^25*G: */ - {{{0x177d8976, 0x0cc6ab71, 0x03ca4b6e, 0x0e7471c6, 0x104b55e1, 0x164c114e, 0x06d932c0, 0x0cbdeec0, 0xcd2e8e}}, - {{0x0867bc22, 0x0b4b7a0e, 0x10a30144, 0x1dbc1e6a, 0x0ff68f60, 0x074796a3, 0x0c7ff0c7, 0x06c46854, 0xf58ead}}}, - /* 11*16^25*G: */ - {{{0x0c67c998, 0x04d98361, 0x13c6e198, 0x160fd547, 0x04c259a9, 0x0f545218, 0x1bed0089, 0x13870447, 0x9bd61f}}, - {{0x08199514, 0x1a057ce1, 0x1092c630, 0x1b383d20, 0x050fa927, 0x104b4b4a, 0x1d71723c, 0x01322d8d, 0x77b204}}}, - /* 13*16^25*G: */ - {{{0x0aafa568, 0x122f0bdf, 0x07889d9a, 0x1af52ee0, 0x1a016b4c, 0x13d2088b, 0x1dd44ab8, 0x09ef2e0e, 0x7afaeb}}, - {{0x01c1f2df, 0x16a9d17c, 0x14e408cf, 0x1cd28653, 0x1365a972, 0x0a09a820, 0x09f62574, 0x03267f7a, 0xc6efe6}}}, - /* 15*16^25*G: */ - {{{0x0e59ddeb, 0x1f381f28, 0x07a62a2d, 0x1cc5395a, 0x10c3b483, 0x0a60a4b5, 0x0be41876, 0x044fc482, 0xd9a002}}, - {{0x0f0af5a4, 0x19c9ffc0, 0x17c63397, 0x05517956, 0x10581856, 0x07c521b3, 0x08b10f18, 0x1f276f40, 0x975eb2}}} - }, - { - /* 1*16^26*G: */ - {{{0x1ecca7e0, 0x19cd2f51, 0x10cccfb1, 0x05931ece, 0x19428a7d, 0x119a9126, 0x08303fbd, 0x078b8f25, 0x7ef2ee}}, - {{0x152ac094, 0x015916ea, 0x0f4f480c, 0x0428a1bf, 0x009db81b, 0x1fa8eaf3, 0x004693d9, 0x04e61598, 0xafb686}}}, - /* 3*16^26*G: */ - {{{0x033f0ffa, 0x179ac1ed, 0x001e905c, 0x09958c23, 0x1c641cae, 0x12bb64ec, 0x0b35d892, 0x04e2d10f, 0x370457}}, - {{0x00fa35ac, 0x1f69fe33, 0x02fcbf17, 0x147d6f55, 0x1ff4c57b, 0x1a5dc44a, 0x1d3e106e, 0x18c34e3c, 0x5c6408}}}, - /* 5*16^26*G: */ - {{{0x12603513, 0x037cc329, 0x1280254f, 0x0c9b8d02, 0x1b697f6c, 0x15216045, 0x0dc8b47a, 0x1ca8531b, 0xc2a979}}, - {{0x1c3505b9, 0x0baad961, 0x05451265, 0x0ccdbe90, 0x1ce7e8cc, 0x0040c9ad, 0x1721509e, 0x0943cdd6, 0xef9dd7}}}, - /* 7*16^26*G: */ - {{{0x19fdee3e, 0x1237fd8e, 0x0c0b8079, 0x1f2ee2d8, 0x1afb9681, 0x18ae6d8b, 0x07845cae, 0x0d563f8b, 0xc9f418}}, - {{0x0ced22e7, 0x0f33662e, 0x1637d3d4, 0x02a638f6, 0x1214344e, 0x18a15c41, 0x0d0437dc, 0x0fe79674, 0x9420a}}}, - /* 9*16^26*G: */ - {{{0x0814f217, 0x0659f33a, 0x15b3febc, 0x147ef70e, 0x1b6a4a9d, 0x00127c1d, 0x095ac228, 0x0b700900, 0x27dcf5}}, - {{0x0cf2ed4c, 0x064a5ac4, 0x07f0efc5, 0x1d1f5632, 0x02a380a4, 0x1d584a50, 0x17b82f22, 0x09ea91ab, 0xbe18f5}}}, - /* 11*16^26*G: */ - {{{0x1b9e310c, 0x0d1527ea, 0x133f529d, 0x19cb7370, 0x19187313, 0x125619ca, 0x092e7234, 0x00764add, 0x3b8b02}}, - {{0x0d19fc9b, 0x0a0b302d, 0x0cc160e6, 0x1f009705, 0x117a6a8f, 0x171bbe20, 0x056f585d, 0x09d6066c, 0x91117c}}}, - /* 13*16^26*G: */ - {{{0x07615b36, 0x18f0f15d, 0x1cf057e3, 0x1fe3d18f, 0x0c3372a4, 0x12037c8a, 0x00e84170, 0x118b7982, 0xa5e739}}, - {{0x09136d80, 0x0cc171ca, 0x0d84f013, 0x1f8326e1, 0x1f8c547f, 0x06f7950a, 0x1339190e, 0x11b92e9c, 0x1f3ff5}}}, - /* 15*16^26*G: */ - {{{0x0d3e10db, 0x1bd82197, 0x0e1c566e, 0x065c3591, 0x161fa477, 0x021ffa75, 0x0caf7b81, 0x06ab592a, 0xaad218}}, - {{0x0fa05fb3, 0x1a9ad5eb, 0x072e89d8, 0x064ee566, 0x18b4a720, 0x0f147eaf, 0x18ece9f7, 0x1dd75f05, 0x793b1e}}} - }, - { - /* 1*16^27*G: */ - {{{0x0c49e853, 0x180f8487, 0x1d781299, 0x16a6a532, 0x1a77aa9c, 0x12aa75af, 0x0bad5e00, 0x0c842c81, 0xe5141}}, - {{0x16405cb2, 0x1b71e89b, 0x127b8d8c, 0x10728321, 0x1030df56, 0x1a529d48, 0x11a49e3a, 0x1d4cb20a, 0xcf331c}}}, - /* 3*16^27*G: */ - {{{0x1dc6afad, 0x0511f8e0, 0x1e03d1b1, 0x07b2452b, 0x0c6771bd, 0x092fb260, 0x1c977a3b, 0x0cecb959, 0x977ba0}}, - {{0x1d7faa09, 0x0b166e28, 0x16868553, 0x0b42483b, 0x1d9992f7, 0x1d506840, 0x1e8a20cf, 0x0875db71, 0x1bc3bc}}}, - /* 5*16^27*G: */ - {{{0x1d81983b, 0x0fba2ebe, 0x03aade19, 0x041fa05f, 0x1facc102, 0x1b03b8ff, 0x0af930f2, 0x0c254247, 0x3bc328}}, - {{0x11a637b6, 0x0ccf9428, 0x0ee1236f, 0x0910b51f, 0x00a7f433, 0x182e5578, 0x0880942c, 0x0dbda191, 0xa6b582}}}, - /* 7*16^27*G: */ - {{{0x17c8537b, 0x0fbb60ff, 0x07e0185d, 0x19596e88, 0x16c21ca8, 0x17f0e57c, 0x12b146eb, 0x1d1d3d80, 0x67cba4}}, - {{0x185726da, 0x075a82b9, 0x100fdb87, 0x1e087da0, 0x1cc047bd, 0x030f97d8, 0x06128787, 0x1dbd4391, 0x5b65ed}}}, - /* 9*16^27*G: */ - {{{0x0b6a1226, 0x14114672, 0x15194e4d, 0x13d39156, 0x0f3922af, 0x1eb43234, 0x064c681c, 0x14daae93, 0xc5958e}}, - {{0x066961d4, 0x00803446, 0x08422e47, 0x0edb7d74, 0x1bd82968, 0x0cb8cea2, 0x175fb2f8, 0x105ee1ef, 0xa031a8}}}, - /* 11*16^27*G: */ - {{{0x13713a52, 0x06f1fc2d, 0x0f1505f9, 0x0eb718d0, 0x05fa025c, 0x0061e3a5, 0x129f07f3, 0x1f05c84b, 0x83f07b}}, - {{0x1fb0ffb6, 0x088939fc, 0x1ed174a8, 0x0b6ec1c3, 0x1d3cfcab, 0x0a648963, 0x0ee4125e, 0x02144b71, 0xf2ec4f}}}, - /* 13*16^27*G: */ - {{{0x01ba21b0, 0x16cd0489, 0x109954e6, 0x0bb1a401, 0x00076d85, 0x00343757, 0x0b539bda, 0x09f36b48, 0x938dba}}, - {{0x0d5b4325, 0x1a6ccaf2, 0x0ada5f0d, 0x0377dc7e, 0x0b90bcbf, 0x16dee89b, 0x1959ba6a, 0x15135eea, 0x48afc0}}}, - /* 15*16^27*G: */ - {{{0x1f2b24f1, 0x09f24d31, 0x19daf3ed, 0x1d8c9ebf, 0x09779cfa, 0x0d5679da, 0x079cea07, 0x16ed9406, 0x7efa89}}, - {{0x0f8e4b83, 0x12ee2ea5, 0x15291575, 0x15be758a, 0x0ab211db, 0x09117e0b, 0x1bfde33b, 0x1d8c3e95, 0xa99ff3}}} - }, - { - /* 1*16^28*G: */ - {{{0x02f2b734, 0x034cdfcf, 0x007499fc, 0x0776b6aa, 0x0445779c, 0x13c3788b, 0x066818d2, 0x0533dd99, 0x224a02}}, - {{0x11ec7fdf, 0x007ac2a4, 0x11ebf421, 0x0e096ce7, 0x17fff07b, 0x0456c38e, 0x0ad05268, 0x1a536da4, 0xfa41a8}}}, - /* 3*16^28*G: */ - {{{0x1d254033, 0x0f497a3a, 0x091c1eb2, 0x0d050185, 0x0f240783, 0x0fd3445b, 0x1167f36b, 0x1dc2a79d, 0xe63502}}, - {{0x08f05e3f, 0x1455444b, 0x1f3cd81f, 0x02b41897, 0x1ce482c9, 0x14078384, 0x1846b5d3, 0x0f63ec43, 0xa7c583}}}, - /* 5*16^28*G: */ - {{{0x01e08f33, 0x1cb04d7f, 0x060b328a, 0x1ac63b97, 0x000e2b1f, 0x02e299f8, 0x1a1c4aad, 0x184e5d72, 0x5648de}}, - {{0x0269f1c9, 0x1776cd62, 0x045e5449, 0x0577e5c0, 0x1a2693e7, 0x1ae326bb, 0x010fd1e3, 0x0e0e11ee, 0x95fddc}}}, - /* 7*16^28*G: */ - {{{0x1ab98c43, 0x1dc1005f, 0x0fa2a938, 0x14aeeafc, 0x08f03c5b, 0x17c765f6, 0x149a5454, 0x13e6701d, 0x1941c1}}, - {{0x02abe217, 0x1d1086d1, 0x17d58e63, 0x0c5a7b71, 0x18c53d8f, 0x0d95247d, 0x0adb8adb, 0x068b2bb6, 0x8e66b8}}}, - /* 9*16^28*G: */ - {{{0x02d8c2f4, 0x13386882, 0x07006279, 0x064373ef, 0x18a0bd73, 0x1def1b26, 0x0f59fe9c, 0x063a2169, 0xfc5864}}, - {{0x1cfd274a, 0x08c6447f, 0x10ce2d00, 0x05960bd7, 0x1b4ab29e, 0x013cf35e, 0x055928cf, 0x0a59d15b, 0x99fade}}}, - /* 11*16^28*G: */ - {{{0x11ff0f18, 0x1583bf8e, 0x12690b44, 0x0179ce0a, 0x0d6c207e, 0x1d67cd79, 0x077aa6fe, 0x14d6189e, 0xee993b}}, - {{0x050782ad, 0x009c3b65, 0x03cb2c60, 0x0b901bee, 0x1bcfeb43, 0x0eac6742, 0x0cb07db1, 0x1b28af1b, 0xd87fd4}}}, - /* 13*16^28*G: */ - {{{0x0fdde3fc, 0x03d3fbaa, 0x18a33279, 0x11113c0a, 0x131fbe5a, 0x0e20d297, 0x090a3683, 0x0f55d3fc, 0xba4951}}, - {{0x0fcb7d01, 0x1f7e9197, 0x0a4b2aa8, 0x1c3903c6, 0x1359adfd, 0x121bb009, 0x16542d3b, 0x1c39528a, 0xa88fb6}}}, - /* 15*16^28*G: */ - {{{0x1d14da68, 0x0449517b, 0x14805cde, 0x0983f09b, 0x012b54a6, 0x07c139bb, 0x06e9378b, 0x02e8455e, 0xd3398f}}, - {{0x15a90e3d, 0x183b18da, 0x10514e8f, 0x0f4f245a, 0x0b020afc, 0x0968f451, 0x1583adc9, 0x1a9a3fa7, 0xa34ad4}}} - }, - { - /* 1*16^29*G: */ - {{{0x1789b84d, 0x13032d6b, 0x010738ba, 0x1abdc9a2, 0x093fe167, 0x0888dab2, 0x0d3336d7, 0x028ae6e9, 0x4a89a6}}, - {{0x018e3ea8, 0x1cdbebf8, 0x1c46667b, 0x1c500c68, 0x077e6a72, 0x154bcff3, 0x1570230b, 0x10fda901, 0x45b04e}}}, - /* 3*16^29*G: */ - {{{0x02e14c34, 0x13b591ba, 0x0c9d64db, 0x18bd7c0e, 0x177c9834, 0x19873c09, 0x1e4a8aa6, 0x09150e1d, 0xcc9f96}}, - {{0x14be556b, 0x0490abd4, 0x031f8162, 0x122fe305, 0x089db299, 0x1319edf3, 0x05bd0c45, 0x0596bf19, 0x829bff}}}, - /* 5*16^29*G: */ - {{{0x15de4837, 0x1ef3642c, 0x1979d3a1, 0x050d905b, 0x18a758d4, 0x060e856c, 0x106bd3d6, 0x143f55a0, 0x5c618d}}, - {{0x034a7dee, 0x05c2c1db, 0x089e32b0, 0x06cc92c8, 0x19671ecd, 0x071c24fe, 0x067622e0, 0x02f79e74, 0x4c7191}}}, - /* 7*16^29*G: */ - {{{0x16635396, 0x0c49a132, 0x029b0309, 0x15c2b46d, 0x1c11ef2c, 0x116ef338, 0x1a8b9617, 0x0d522b40, 0xab8a88}}, - {{0x1fc92c23, 0x11c7d351, 0x14b5ab5f, 0x0c0b07ef, 0x0d5abb93, 0x1fc1245e, 0x0c6559a3, 0x0f8fb508, 0xe773cf}}}, - /* 9*16^29*G: */ - {{{0x01df49c3, 0x0121f2c4, 0x01a68d6b, 0x11210cda, 0x1604aa9e, 0x125c5b4a, 0x0e337b19, 0x0a284830, 0x62b7c8}}, - {{0x16341c21, 0x1f1b407f, 0x1f2d5426, 0x0a76c270, 0x122db8fb, 0x0b5746a4, 0x0cd56522, 0x042a55c0, 0xa71ed6}}}, - /* 11*16^29*G: */ - {{{0x044f47d0, 0x178a3717, 0x07c00bce, 0x13ebbd29, 0x1c9791b5, 0x0f8434ef, 0x0717e5d4, 0x17f48b91, 0x4897bd}}, - {{0x0e1320bf, 0x0f280d56, 0x1c046560, 0x1b400351, 0x1093f526, 0x1654a0bd, 0x0e30d3a3, 0x01ef5f82, 0xe77dc2}}}, - /* 13*16^29*G: */ - {{{0x11581bd3, 0x10de74db, 0x0641e1b9, 0x14631bec, 0x02f2ecbf, 0x103ded39, 0x15db1147, 0x16aac90c, 0xeb1cfc}}, - {{0x1cd98a09, 0x1e746cc2, 0x0f469916, 0x19e6338b, 0x16e3cb39, 0x002f5f26, 0x14814110, 0x0eae3f29, 0xfd47ce}}}, - /* 15*16^29*G: */ - {{{0x073a3111, 0x00915edb, 0x132063e4, 0x105c82f6, 0x176a018b, 0x05617392, 0x18270355, 0x177c91c3, 0xa1fd8b}}, - {{0x18c704ef, 0x043f3285, 0x15445a6e, 0x18928b7f, 0x116c0c7e, 0x1f03de04, 0x015a6f5d, 0x11469461, 0xad215d}}} - }, - { - /* 1*16^30*G: */ - {{{0x12bd05a0, 0x01c64253, 0x07f2034d, 0x0466fa16, 0x11f90ba8, 0x1ccaf9b6, 0x0173b70b, 0x06c74631, 0xe5e892}}, - {{0x01a69f5d, 0x09b6f15f, 0x14266bb2, 0x0732b739, 0x15c3eca7, 0x1580f3cd, 0x1f484c07, 0x1c9b4370, 0x77439d}}}, - /* 3*16^30*G: */ - {{{0x01467d6b, 0x184a9408, 0x0892d453, 0x1ae252a5, 0x0f1d8357, 0x0308b216, 0x13d74406, 0x1bf286b9, 0x5d2393}}, - {{0x11bc5458, 0x1e339e35, 0x011cea01, 0x0e0f4ea2, 0x0f46d72a, 0x0c2d96ad, 0x1df5eb2f, 0x1e4c7fa1, 0xe66e63}}}, - /* 5*16^30*G: */ - {{{0x1d159f7a, 0x058f49e4, 0x10b9643c, 0x127539e4, 0x1873fecf, 0x1d95e97f, 0x04fceb73, 0x14a75571, 0x453657}}, - {{0x0a02fb78, 0x0e115b84, 0x07769766, 0x0937a9d0, 0x1c7286f9, 0x18489d00, 0x171768bb, 0x1ff10047, 0xbfb5ae}}}, - /* 7*16^30*G: */ - {{{0x146cb42a, 0x0f6f6f9e, 0x08e424cc, 0x0a50a74e, 0x173e7bc0, 0x16f5509e, 0x11193452, 0x1960f609, 0x435b54}}, - {{0x1af72dd0, 0x1f126f6e, 0x0e5269ad, 0x1898f286, 0x0585d5ed, 0x12a660f0, 0x086927d2, 0x063c8e31, 0xd726c0}}}, - /* 9*16^30*G: */ - {{{0x1d2fc263, 0x0beca0d8, 0x19755eea, 0x1f027cb6, 0x1da0e89c, 0x023e2709, 0x15f867ef, 0x033c29db, 0x1805b8}}, - {{0x10870ec7, 0x132385a7, 0x147b2bc9, 0x1835f1ca, 0x131489c8, 0x0d5435e5, 0x05c56163, 0x05012870, 0x101f64}}}, - /* 11*16^30*G: */ - {{{0x0076d1df, 0x1158db86, 0x1fe86ce6, 0x1c410284, 0x15f45f41, 0x1d45153b, 0x053d0185, 0x086cda63, 0xc73aaf}}, - {{0x05ad6605, 0x13cea8b7, 0x024dc834, 0x16af4a3b, 0x0dcfef75, 0x00df1dde, 0x05bbe738, 0x0d3d99f2, 0x9201ec}}}, - /* 13*16^30*G: */ - {{{0x05a745c7, 0x1b41fbcc, 0x1fab01f4, 0x144e7182, 0x152c1bc8, 0x0db57b0e, 0x1b49dc62, 0x11efab86, 0xe3ddee}}, - {{0x178efcc2, 0x1cf84a03, 0x1409ec68, 0x1185e2f7, 0x1d8f47c2, 0x0dc3553d, 0x0e1c6f94, 0x1a723265, 0x487199}}}, - /* 15*16^30*G: */ - {{{0x0d4170b3, 0x06399f42, 0x0e8d61fd, 0x0882adf8, 0x0a1d5401, 0x1508c360, 0x0796bda2, 0x1b8406be, 0x45c78d}}, - {{0x111faa1d, 0x177d1f6a, 0x08331cc5, 0x008cc0c8, 0x13a512cb, 0x14e8a27d, 0x1032c386, 0x08c471ab, 0x11af99}}} - }, - { - /* 1*16^31*G: */ - {{{0x1ab5c2cf, 0x0abccc97, 0x0c213788, 0x05e1843f, 0x090a4531, 0x03a0827d, 0x1d41c79d, 0x0863c443, 0xe4107e}}, - {{0x0b955c2b, 0x014201f9, 0x1ec90434, 0x1125b9fe, 0x02b323c7, 0x03343a0e, 0x1268e523, 0x1cd9ee03, 0x1e5f11}}}, - /* 3*16^31*G: */ - {{{0x09b67b7e, 0x1dadb1e0, 0x070f5216, 0x16f65722, 0x01142766, 0x0b80ef5e, 0x1df6ab3e, 0x0cbdc2f3, 0x85df9a}}, - {{0x030a36e3, 0x059c34f4, 0x0f1ba962, 0x15293a3f, 0x0297386f, 0x1eaf7f87, 0x0c22edad, 0x154735ec, 0xa6b4b7}}}, - /* 5*16^31*G: */ - {{{0x0b3510d3, 0x13e7ef30, 0x0875b904, 0x062cce09, 0x1292885d, 0x10c32e16, 0x1422a362, 0x1fcff3f9, 0x23c493}}, - {{0x1ae89a47, 0x1a317621, 0x0e76f5c4, 0x13c6bc4d, 0x1e6d8f79, 0x0ecf277f, 0x108c309d, 0x153c8682, 0xadf456}}}, - /* 7*16^31*G: */ - {{{0x0b49a71f, 0x06348c04, 0x089f0e6b, 0x0dd6d8c8, 0x035ddac3, 0x09f5d579, 0x03b77966, 0x016629ba, 0x94406d}}, - {{0x10b249a9, 0x18e0ca26, 0x18f3e511, 0x04e4c394, 0x1e897d0e, 0x1e484837, 0x05e73481, 0x0fd0c9be, 0x61aae7}}}, - /* 9*16^31*G: */ - {{{0x00e50c32, 0x0e6f19e3, 0x11a1cff9, 0x0212e5d1, 0x08d3877f, 0x1b6fadf7, 0x1050cdc4, 0x087bd10d, 0x3c2ebf}}, - {{0x0a93c124, 0x117c48be, 0x1a326627, 0x1a118735, 0x028e7be2, 0x1c9e9017, 0x06719496, 0x14d8bd07, 0xa703d9}}}, - /* 11*16^31*G: */ - {{{0x03a2355a, 0x041ecef6, 0x1812641c, 0x0a37e6b8, 0x15f12996, 0x12dc4f62, 0x1ae7ce47, 0x1ae4f281, 0x987536}}, - {{0x1bd05276, 0x063ae260, 0x0eb7337c, 0x1ed8f8d0, 0x17b48b85, 0x18e0a4f2, 0x05c90f82, 0x1ace9e22, 0x12f19a}}}, - /* 13*16^31*G: */ - {{{0x12f3ec22, 0x0782a3e2, 0x0a3e29ac, 0x10db9ee3, 0x0ddddd1f, 0x1c58bf79, 0x11a3c674, 0x08134988, 0xd515ac}}, - {{0x05a2863b, 0x10a31759, 0x06e01bb2, 0x0afbe006, 0x0bd464cd, 0x12420029, 0x0cb87a97, 0x02844893, 0x51c048}}}, - /* 15*16^31*G: */ - {{{0x1971c857, 0x0cd0f4d2, 0x19824fe9, 0x133cdb57, 0x1cf3ddec, 0x1e61c5b0, 0x02eb8914, 0x0930bcb6, 0x70b9d}}, - {{0x0ac8dfc1, 0x1ce5b1ee, 0x15186abf, 0x107b43d8, 0x13cfb33a, 0x0857231b, 0x09421ae0, 0x037fe96c, 0xed8046}}} - }, - { - /* 1*16^32*G: */ - {{{0x1789bd85, 0x1e427e4e, 0x05fab0d5, 0x0bfefb85, 0x0766efc3, 0x17eac463, 0x199fee60, 0x137ddb6b, 0x447d73}}, - {{0x12e25b32, 0x03f19e4b, 0x1eb94003, 0x09372b4f, 0x0aff73d3, 0x0eca9d25, 0x07bb84ba, 0x15706826, 0x2d4825}}}, - /* 3*16^32*G: */ - {{{0x1ea6db68, 0x1f0ccc76, 0x098cb09c, 0x15b0ac10, 0x0f4f6ddf, 0x06fcb2ef, 0x05fd62c5, 0x07c07940, 0xf8b653}}, - {{0x0e760da9, 0x0de92d85, 0x17283b5a, 0x1ae1bb38, 0x03ec66bb, 0x16ed2855, 0x1218bc11, 0x1ebd888a, 0xc30f4e}}}, - /* 5*16^32*G: */ - {{{0x1924e753, 0x16aea75f, 0x1e1c9f19, 0x02e60e59, 0x1fb755f0, 0x18c394f6, 0x11f1523b, 0x1a6ab050, 0xf35289}}, - {{0x0b13a20c, 0x122dae17, 0x0b43c12a, 0x05f8ae52, 0x01bd8c56, 0x0450da87, 0x0fee4f7c, 0x03d8bd82, 0x75c178}}}, - /* 7*16^32*G: */ - {{{0x1018017e, 0x1cae5b39, 0x17c8f5c8, 0x083fffad, 0x14e01af1, 0x0c2fdb39, 0x1c5920d0, 0x0e9b4882, 0xcfd06b}}, - {{0x0e0dff50, 0x0573df26, 0x1de5dde8, 0x0060f0d6, 0x07950003, 0x19cac3ed, 0x044e040e, 0x1536e575, 0xb647b7}}}, - /* 9*16^32*G: */ - {{{0x192db860, 0x0640c82b, 0x06891ec1, 0x11251065, 0x1dbe9810, 0x0b68478a, 0x1344544b, 0x09895abb, 0x755e7}}, - {{0x00d09849, 0x0b3006dd, 0x109dde9f, 0x06e8c99f, 0x15bc2b29, 0x196c11c0, 0x19374926, 0x14ea75b3, 0xfe16af}}}, - /* 11*16^32*G: */ - {{{0x0a26ba6b, 0x0f7b4aaf, 0x1684b0ea, 0x1945492d, 0x0bbdedd2, 0x0606bf58, 0x05a5a284, 0x09986e59, 0x88fba8}}, - {{0x044972f8, 0x020a3c0f, 0x033f73a0, 0x153c51c0, 0x0788d484, 0x0d22da8a, 0x183f499b, 0x0c93a737, 0x512aef}}}, - /* 13*16^32*G: */ - {{{0x14720cab, 0x0e245214, 0x0e6c5f8e, 0x1d4ba82e, 0x06f2c1a1, 0x1b73aaae, 0x0fae3943, 0x197d80ab, 0xe1a0ac}}, - {{0x14b185c9, 0x16a29fab, 0x000953a9, 0x1454e3a1, 0x0bcbf084, 0x1c183bf7, 0x015060db, 0x1f6fd319, 0xe07968}}}, - /* 15*16^32*G: */ - {{{0x0c26c42a, 0x14147eff, 0x0c46ed8a, 0x17f6fc8d, 0x1e6a0249, 0x1ac498f3, 0x11f9436c, 0x10dcd4e7, 0xae93b}}, - {{0x19f808ca, 0x08319a1d, 0x0ab6d924, 0x1473ddeb, 0x00b37278, 0x11f6e0f1, 0x184ea50b, 0x1ba28f0f, 0x7028f6}}} - }, - { - /* 1*16^33*G: */ - {{{0x137de736, 0x15ec5d60, 0x02338907, 0x11aac30d, 0x0c18ea2f, 0x0a15c66f, 0x1cfa24dd, 0x02929399, 0x9022e3}}, - {{0x04c42ecc, 0x077ae042, 0x1a9d95fd, 0x126cd889, 0x0ce087f4, 0x1d822913, 0x0e519b42, 0x09e52094, 0x2fae5e}}}, - /* 3*16^33*G: */ - {{{0x109b01f5, 0x0b8365c6, 0x1cf01464, 0x1e6a3064, 0x1857af73, 0x169f8d7b, 0x0517ec3c, 0x1c60edfd, 0x6e5872}}, - {{0x0bcd5fde, 0x183ac6cd, 0x06a169f0, 0x02f3a9c1, 0x0f0ebc13, 0x0ea579df, 0x05c60330, 0x05d91aee, 0x4213c0}}}, - /* 5*16^33*G: */ - {{{0x0fe45b1f, 0x09cdba3f, 0x185a30ad, 0x02abf65c, 0x1df827bd, 0x0f1a260b, 0x1d412bf4, 0x1634bb47, 0x292220}}, - {{0x134bb026, 0x1f205c5a, 0x17504117, 0x06886099, 0x18d7ff7c, 0x1caffd74, 0x16bb8df1, 0x0a657e2e, 0xe316a0}}}, - /* 7*16^33*G: */ - {{{0x03abd540, 0x14283315, 0x059b790f, 0x0080ca96, 0x13a340e8, 0x07c39084, 0x1c2b0c89, 0x0900f489, 0x3644e1}}, - {{0x155da631, 0x0e37f0e6, 0x1be85378, 0x0ef9db4c, 0x1e293001, 0x02984fd0, 0x05d8470a, 0x0a1b784f, 0xec5a91}}}, - /* 9*16^33*G: */ - {{{0x09142ccb, 0x117e90f4, 0x01fb78c6, 0x0414b58d, 0x1b4824c9, 0x1c7a4c9d, 0x00e3956c, 0x15c2ff9b, 0xedfe7d}}, - {{0x0c593d75, 0x1ca8e98d, 0x14450bae, 0x08856d3a, 0x1beb81da, 0x0e95a7aa, 0x1c858615, 0x0245c1b5, 0xc88692}}}, - /* 11*16^33*G: */ - {{{0x0a41b208, 0x1ed38e32, 0x189c003c, 0x0e8eb9bd, 0x00de8e7f, 0x00135e75, 0x1a5661c5, 0x11680b34, 0x531196}}, - {{0x048e4b69, 0x08f0fcf0, 0x0da1dfda, 0x183b8048, 0x1da113b3, 0x0c0f19d9, 0x05e29b19, 0x0567b845, 0xb78d73}}}, - /* 13*16^33*G: */ - {{{0x095daae7, 0x1e80dae2, 0x1c0cef2c, 0x0dcdd8f8, 0x0e1d5af4, 0x15fb7ab0, 0x1653de88, 0x1e45ff74, 0xf65dd1}}, - {{0x02556738, 0x0a72d4ce, 0x0b366ca3, 0x0c301f3d, 0x04cd0eb0, 0x1f31be7e, 0x1ba0839b, 0x0419c36c, 0x9d71b8}}}, - /* 15*16^33*G: */ - {{{0x1afcf1ee, 0x1f7e0af1, 0x01a6846a, 0x155008e4, 0x007c60af, 0x1a405554, 0x0922d06f, 0x0fdb995c, 0xa6670e}}, - {{0x00c67fc8, 0x1c43855f, 0x0f3ce28d, 0x07312392, 0x1ac131ef, 0x1b97a4ab, 0x0bce8e57, 0x19274a38, 0xa7fd14}}} - }, - { - /* 1*16^34*G: */ - {{{0x04cd3397, 0x008a2e0a, 0x1457ad5d, 0x09820c32, 0x16deddc3, 0x16795a8a, 0x1c8e24e1, 0x00833db4, 0x73baff}}, - {{0x1adcb8e4, 0x0f79509c, 0x0984d250, 0x1df259f0, 0x1825e779, 0x08f460c7, 0x117da803, 0x0c692ef5, 0x1e97de}}}, - /* 3*16^34*G: */ - {{{0x161fb913, 0x1587ca90, 0x14c4a5df, 0x0048c2ad, 0x0d04e3e1, 0x046f225f, 0x0860d10e, 0x01867cc1, 0x45f833}}, - {{0x0c15c3bc, 0x06a40be0, 0x1f0cdcdc, 0x1a10f3ed, 0x07760f06, 0x003b6c5d, 0x01bbe03a, 0x0db7fad2, 0xc212cf}}}, - /* 5*16^34*G: */ - {{{0x0e393654, 0x177cb48f, 0x1b75f1d6, 0x1a97c3e7, 0x15991965, 0x100e45e6, 0x16ad97d6, 0x09359af7, 0x5544dc}}, - {{0x0f53206f, 0x1b085dfc, 0x15639cc8, 0x1dfd2e07, 0x15192241, 0x02dadc49, 0x152b0130, 0x112a10ff, 0xed3e85}}}, - /* 7*16^34*G: */ - {{{0x08a15dfd, 0x1f9acca1, 0x1ea79544, 0x1b75804b, 0x0f695741, 0x176aad71, 0x1dcd2cf4, 0x120c33dc, 0x2757b7}}, - {{0x1042c341, 0x04742067, 0x09c55b7f, 0x112f1479, 0x1500d176, 0x1a909e6a, 0x04b97325, 0x1aaa9856, 0xdf46d2}}}, - /* 9*16^34*G: */ - {{{0x1f840a5b, 0x1f6fa135, 0x0b52613b, 0x195b4ba7, 0x03ccd148, 0x10e6608a, 0x0f236610, 0x0fbca1c5, 0xe87243}}, - {{0x1377e86a, 0x0272c2a8, 0x0e59192e, 0x1468d9f2, 0x08bf5ac3, 0x048fb312, 0x185964ef, 0x11224e52, 0xf984bc}}}, - /* 11*16^34*G: */ - {{{0x136afd6a, 0x0ab54dc5, 0x1e078f52, 0x03f8a142, 0x1334a926, 0x1b6af379, 0x1700e4bb, 0x15749aee, 0xc56cdc}}, - {{0x13f87c26, 0x10435f77, 0x0331c8f9, 0x090764ad, 0x14ef566f, 0x0f58bfac, 0x01c334bb, 0x1c5e70d6, 0xd16056}}}, - /* 13*16^34*G: */ - {{{0x0cfd2cd0, 0x0d6cc069, 0x070304c7, 0x08266883, 0x0abb1239, 0x142c1f24, 0x0a1a73f4, 0x0e71e7fe, 0xd3d6e6}}, - {{0x194ae2dc, 0x02bce3bb, 0x1dbe3c53, 0x1f4ad185, 0x1e59b001, 0x147fb9be, 0x0da14db6, 0x0bf9a2b3, 0xff448f}}}, - /* 15*16^34*G: */ - {{{0x1ab7a64c, 0x0ac442ae, 0x026ade82, 0x011ad474, 0x1d406565, 0x196b911b, 0x101ec0c4, 0x110adc8b, 0x88f977}}, - {{0x1575f103, 0x02f4c708, 0x1b499ce8, 0x06012442, 0x09e5836c, 0x0d792bcb, 0x11d0d14c, 0x1ba8d6ab, 0x4a745c}}} - }, - { - /* 1*16^35*G: */ - {{{0x1fa4e33c, 0x1172fd98, 0x02632cc3, 0x077d8f16, 0x0fb98268, 0x023614bb, 0x16ef25d1, 0x17234984, 0x9cf646}}, - {{0x0e0d4563, 0x0e22f030, 0x10580c86, 0x00b04fd7, 0x01f319e2, 0x0712c5c1, 0x0a247902, 0x09b83ecb, 0x37b062}}}, - /* 3*16^35*G: */ - {{{0x06bf1e67, 0x0c5b0c66, 0x172bd8fa, 0x0cce93fc, 0x04e0f4c5, 0x129c13bb, 0x126675e9, 0x1bc2a36c, 0x83cb43}}, - {{0x099acc97, 0x13f74598, 0x1445a7a8, 0x0884597b, 0x018f8287, 0x00373122, 0x1be3bec6, 0x1449731e, 0xbce28c}}}, - /* 5*16^35*G: */ - {{{0x1c0f057e, 0x1856ba46, 0x154f7608, 0x10c50e03, 0x1022484e, 0x07e0af12, 0x02300cd0, 0x1cac19d6, 0x3ff3b3}}, - {{0x0817965e, 0x0a0fbed5, 0x1c05d88b, 0x0046dd88, 0x07843a01, 0x08b82bc3, 0x1e3dbdff, 0x0de776ca, 0x7f17ad}}}, - /* 7*16^35*G: */ - {{{0x125e69f1, 0x088a5a01, 0x08af2d45, 0x0f51e5a8, 0x0af99636, 0x0ef0b9eb, 0x00ff7686, 0x05bb1ffb, 0x6e9edb}}, - {{0x002b7e9b, 0x1070bf1a, 0x07ca06dc, 0x04e8a8f3, 0x1bff61c7, 0x0b55b2f9, 0x153aacd5, 0x02d9dff2, 0xc08222}}}, - /* 9*16^35*G: */ - {{{0x0288f038, 0x19297b35, 0x17fe082f, 0x0ed129d6, 0x02d32f08, 0x00cef376, 0x112fbeaf, 0x1d009883, 0x5ee280}}, - {{0x16f1ee6e, 0x02d55c35, 0x19b1bd07, 0x0f067531, 0x1eec011d, 0x0c37f664, 0x0e4a1301, 0x1f28cefc, 0xbcd969}}}, - /* 11*16^35*G: */ - {{{0x00c708c8, 0x05f992b6, 0x1c2a1aa8, 0x08609e5e, 0x0288c2c3, 0x1b2ec8ff, 0x15cdb7f8, 0x0dc0b840, 0xe1f016}}, - {{0x1896ed38, 0x18c6b9d9, 0x0d6802b9, 0x0abe45df, 0x13016fb6, 0x1195f451, 0x0d481111, 0x07d22d87, 0xe64765}}}, - /* 13*16^35*G: */ - {{{0x076edefb, 0x10784e52, 0x039f575f, 0x117b0020, 0x1c7badd5, 0x0d5a14bc, 0x1171fc48, 0x10f57ec6, 0x280896}}, - {{0x1d1b0ae0, 0x17a2b914, 0x00e4848b, 0x06360f7c, 0x141c44dd, 0x0cf5ec82, 0x064699f8, 0x1e67a766, 0x5d071c}}}, - /* 15*16^35*G: */ - {{{0x1344897a, 0x096ccde7, 0x1309a774, 0x1da60eb4, 0x1edab7b9, 0x0f429212, 0x132dc161, 0x1bc50320, 0xeb15b0}}, - {{0x05bfe7ee, 0x0cef41e7, 0x1f42e0ab, 0x0d3165f2, 0x12f85814, 0x157c66b9, 0x01c42262, 0x02d384cc, 0x96cdd}}} - }, - { - /* 1*16^36*G: */ - {{{0x123b716d, 0x137d6e02, 0x13869ae0, 0x0712cdee, 0x0df9e0d2, 0x03c9c68c, 0x14d3a297, 0x1c717194, 0xf81f5b}}, - {{0x12632401, 0x120017a8, 0x01e0cc11, 0x0eb0a075, 0x00328660, 0x094e9c07, 0x1b7c755b, 0x065383e0, 0xdc7f49}}}, - /* 3*16^36*G: */ - {{{0x19d19d8a, 0x062b4281, 0x09548561, 0x024f12a3, 0x1490a3b4, 0x161ae0b6, 0x18e16bdb, 0x0a1f6250, 0xa60084}}, - {{0x190d2c4f, 0x0caedd9a, 0x0995cf7f, 0x1c011f4e, 0x1ca84f0f, 0x0a2f3df4, 0x11cb23db, 0x180cf46f, 0x7b4b79}}}, - /* 5*16^36*G: */ - {{{0x096cac9f, 0x14c3d9ca, 0x11379c89, 0x0719d4b8, 0x10e1c59e, 0x04bcc7f5, 0x0d531930, 0x1632cfbe, 0xde5382}}, - {{0x0fa473d3, 0x070417ed, 0x1610455f, 0x07c528e7, 0x19f2bc2e, 0x1804c8e7, 0x06158b0e, 0x0f16d392, 0x9c47b6}}}, - /* 7*16^36*G: */ - {{{0x06807a23, 0x0594b1bc, 0x097fcf9f, 0x0040a2d4, 0x14ec8400, 0x1ccea88c, 0x04214d12, 0x0100fe55, 0xa7227b}}, - {{0x14115894, 0x0238cc1e, 0x0a337247, 0x1f02af6e, 0x075abe7b, 0x023c9050, 0x07a1176a, 0x04ba8ba7, 0xf55075}}}, - /* 9*16^36*G: */ - {{{0x044d14c0, 0x13cbfe10, 0x0a3cd796, 0x1956bf43, 0x01d39005, 0x1f39d1b3, 0x1659196a, 0x11a84688, 0xcd2b2e}}, - {{0x02496315, 0x0b056791, 0x0b33b3a9, 0x16de1973, 0x0f671fdd, 0x0f76ed60, 0x02893541, 0x1bf3610e, 0xf13012}}}, - /* 11*16^36*G: */ - {{{0x199a1566, 0x17a75891, 0x08a3da59, 0x18cab5fe, 0x19dd8f25, 0x1e4dc1ef, 0x1fad33be, 0x0991e1be, 0x11b2e8}}, - {{0x1c56bb73, 0x0d259e02, 0x16025a16, 0x16ab0819, 0x005cc824, 0x0b4c3cba, 0x05d7410b, 0x13b79446, 0x610376}}}, - /* 13*16^36*G: */ - {{{0x1ba6f34a, 0x084f5946, 0x1171be1f, 0x10d41fc4, 0x11485312, 0x1051f7cc, 0x01c1d676, 0x052be574, 0xfb6d19}}, - {{0x0bcf0452, 0x1af9e411, 0x1a16c7e6, 0x19f45b92, 0x191b9ecf, 0x07ea6253, 0x1b7678e2, 0x053af7e8, 0xf29b2d}}}, - /* 15*16^36*G: */ - {{{0x0a435427, 0x06516950, 0x1936d41d, 0x0021304f, 0x06651a69, 0x13b286c8, 0x0f042abd, 0x19820782, 0xff429f}}, - {{0x19853824, 0x12822869, 0x0e8368a3, 0x17dca694, 0x06876205, 0x04e42b0c, 0x16c25350, 0x0cd149d9, 0x2addf9}}} - }, - { - /* 1*16^37*G: */ - {{{0x07354b7a, 0x16ce3f3c, 0x045725e3, 0x1d94ad87, 0x0de1d022, 0x1a31f29e, 0x01208e5f, 0x0e9aefc1, 0x856854}}, - {{0x116e04c6, 0x0aa2015e, 0x15bf6f62, 0x1123b83f, 0x1728706a, 0x089d9537, 0x1edbbaf2, 0x16a17eb0, 0x20b50e}}}, - /* 3*16^37*G: */ - {{{0x1b26165d, 0x1b663fd3, 0x1dc4dfab, 0x07442bec, 0x092dea71, 0x090497e6, 0x199527a7, 0x18ea5647, 0x617344}}, - {{0x06b2a286, 0x04dfee5c, 0x1c5c6931, 0x13582dc6, 0x020b2989, 0x0885e8c1, 0x0d6926df, 0x02f486f0, 0xe99016}}}, - /* 5*16^37*G: */ - {{{0x10442770, 0x10dfbb32, 0x006eb440, 0x11ef4dc2, 0x0fc2e901, 0x00ed4f20, 0x088b6813, 0x1dcabf6d, 0xf8ac03}}, - {{0x1b00c82d, 0x11432788, 0x0107408e, 0x0c057f2a, 0x06d17a97, 0x03a8d9a7, 0x1a3a90db, 0x0cab33a3, 0x5a358e}}}, - /* 7*16^37*G: */ - {{{0x165460de, 0x1f036c37, 0x0fddee3e, 0x07f1a155, 0x08ea60c7, 0x1e5f1866, 0x1719b1b2, 0x16a4b792, 0x8a731f}}, - {{0x1f8dc207, 0x0c2cd0ef, 0x1423b8fa, 0x0cfc78a4, 0x04dc4358, 0x0aa5ffd8, 0x0c663d4a, 0x18bc556c, 0x585855}}}, - /* 9*16^37*G: */ - {{{0x151634a5, 0x0155d6fd, 0x1b549399, 0x1214f06b, 0x1967f3cf, 0x15d0166b, 0x0892fc29, 0x0c26551e, 0xa20b60}}, - {{0x1226afad, 0x1609bcaf, 0x1517b7c9, 0x08eafc79, 0x1315bc67, 0x0ff41b9d, 0x0676b4f5, 0x13ed2fb7, 0x9c43ce}}}, - /* 11*16^37*G: */ - {{{0x13ba54a8, 0x02191225, 0x0eaa5c1c, 0x164c6ac0, 0x1cc0ab58, 0x0761a7e2, 0x1c26450e, 0x127e24ac, 0x16f1f}}, - {{0x064f2889, 0x0be30fd3, 0x08ed39bb, 0x15e4ea8d, 0x0e658d93, 0x188df24e, 0x055dbca6, 0x0822b12a, 0x8bcd3}}}, - /* 13*16^37*G: */ - {{{0x07c16d94, 0x177249e7, 0x0a117f77, 0x103a1540, 0x0c31fe25, 0x1eb3e667, 0x11e23023, 0x0ce17a06, 0xe61586}}, - {{0x114810ab, 0x1a768cd5, 0x0910eefe, 0x0b9a3c8f, 0x0f0ee4e6, 0x15c9fa5b, 0x12fa316c, 0x15d3ce24, 0x65ca03}}}, - /* 15*16^37*G: */ - {{{0x13ce728d, 0x0b6e5332, 0x1c7342f3, 0x1b20fc50, 0x05347f4c, 0x04510b64, 0x08995568, 0x01671aad, 0xdcd37f}}, - {{0x17cacbcb, 0x0be89b4c, 0x076afae3, 0x19a68da5, 0x0d6f3caa, 0x1db159e3, 0x1061cb0d, 0x1aef9b49, 0x6574db}}} - }, - { - /* 1*16^38*G: */ - {{{0x12378c16, 0x0e36e0d8, 0x05588ab7, 0x0c0eaa8c, 0x1597d9e3, 0x1296b5fc, 0x0c46cc67, 0x0b382567, 0x1136b7}}, - {{0x13488127, 0x0facde85, 0x147338de, 0x095451ce, 0x1ecb2961, 0x15e307f4, 0x1f7427c2, 0x19e8a2d1, 0x7dec0f}}}, - /* 3*16^38*G: */ - {{{0x1b299740, 0x18736c13, 0x0f6c4d25, 0x1e8cfae2, 0x0ad48f40, 0x089bc9fd, 0x0cdb312b, 0x16e39ba8, 0x53893e}}, - {{0x1fff7509, 0x0f5378d9, 0x1f7a3354, 0x0265de43, 0x1dc8dd8a, 0x0714753a, 0x0f60e107, 0x0fd290bf, 0x27728a}}}, - /* 5*16^38*G: */ - {{{0x138000fc, 0x059e4ab3, 0x1c0ef04c, 0x1c4ee0f7, 0x0e5604e1, 0x1b5d78fd, 0x089d5f8d, 0x1baea99b, 0xdd64e9}}, - {{0x1df4ac12, 0x1d50e286, 0x07923e2f, 0x0ba04572, 0x079ffbe4, 0x0f1f0ce5, 0x0b25b7e2, 0x1d618526, 0x432193}}}, - /* 7*16^38*G: */ - {{{0x13878c4a, 0x1c10a8b9, 0x1470157b, 0x07a0790a, 0x11b21d88, 0x0e307254, 0x145bcb1a, 0x150fdffa, 0xff9845}}, - {{0x1488df68, 0x1d3423eb, 0x173faf1a, 0x066e8d6c, 0x1e8ddf1f, 0x12476ffa, 0x0a3e3f62, 0x1e949c48, 0x835b9a}}}, - /* 9*16^38*G: */ - {{{0x00f51524, 0x054dc40a, 0x0be1bf23, 0x1d6d42b7, 0x093de5fa, 0x1d184229, 0x0273a1d9, 0x1d17722c, 0x954e13}}, - {{0x05e30a69, 0x0fed9eca, 0x079f2f7a, 0x1d486228, 0x0cbcfa9e, 0x1121a3cf, 0x010764f1, 0x07ff2548, 0xecc836}}}, - /* 11*16^38*G: */ - {{{0x04f77287, 0x1bcc6a9e, 0x0c3678c7, 0x12a786d2, 0x00497412, 0x0862e0ec, 0x0e4f7f35, 0x1edf483f, 0xb2217e}}, - {{0x04e7b5da, 0x1d0253b9, 0x17a4f2e5, 0x13b8e738, 0x0c843d70, 0x1e7c469c, 0x0e8ad77e, 0x1c19cf9e, 0xfb5153}}}, - /* 13*16^38*G: */ - {{{0x05c723e9, 0x17a9cb64, 0x09e05c62, 0x0e775535, 0x15c351f9, 0x175748ae, 0x16b448b1, 0x162f6f37, 0x3c3950}}, - {{0x16834763, 0x11c3bafb, 0x1241ab97, 0x1b596af8, 0x0a8b0b01, 0x1dbf50c3, 0x036ed252, 0x0c441222, 0xb99b73}}}, - /* 15*16^38*G: */ - {{{0x1c18abeb, 0x18beb711, 0x09758a8d, 0x1b9a320e, 0x0a944d59, 0x097c225d, 0x136b477b, 0x0599f2c3, 0x803c7a}}, - {{0x029bfa78, 0x121cdf87, 0x19c8735a, 0x18887854, 0x14409ed7, 0x078b4e25, 0x04a1ac6b, 0x0814f2dd, 0x83fb50}}} - }, - { - /* 1*16^39*G: */ - {{{0x143e832a, 0x03b1778c, 0x01b7dc27, 0x0a15602f, 0x1f18e07e, 0x19d412c4, 0x146a43d5, 0x1174f854, 0xd2bf2}}, - {{0x1b20d37c, 0x0131d78a, 0x15451192, 0x193b72c0, 0x0e7ed27e, 0x10854a5a, 0x02b1c21e, 0x086277a0, 0xcac3f}}}, - /* 3*16^39*G: */ - {{{0x112c9666, 0x0f5625e0, 0x1ff37cd8, 0x118d86cb, 0x1531b1cf, 0x061adbec, 0x00b3f66f, 0x0bd72cff, 0x34e5e8}}, - {{0x192a3666, 0x0d0c29e4, 0x18e949ad, 0x0fdac783, 0x046330f4, 0x12bae65e, 0x0dae0a11, 0x06264434, 0xc0ce68}}}, - /* 5*16^39*G: */ - {{{0x11209502, 0x0b295f1a, 0x16499970, 0x02e4004b, 0x1e154594, 0x09f7848c, 0x018e9b12, 0x198b3e9b, 0x727362}}, - {{0x17042b0d, 0x13be8e9e, 0x09d82ef1, 0x1a6ff376, 0x11d20a18, 0x05c61674, 0x0d627c40, 0x04537575, 0x17b0f4}}}, - /* 7*16^39*G: */ - {{{0x0447f959, 0x0af3c945, 0x1c74da11, 0x0fb57504, 0x1eee9f94, 0x0a625da4, 0x13b25ce8, 0x0c00a94d, 0xa0c3f2}}, - {{0x168b671f, 0x01ce9244, 0x149cb26c, 0x0aa804b1, 0x08208b1b, 0x060865b1, 0x113ce0be, 0x0121c965, 0x508c73}}}, - /* 9*16^39*G: */ - {{{0x1b37e1d3, 0x10fcf812, 0x193788c0, 0x0c37c279, 0x1fd04107, 0x019df20a, 0x09e9032d, 0x063ef2b9, 0x7e81b2}}, - {{0x0155681a, 0x1afe5132, 0x10b8380f, 0x1097e563, 0x07c4e4ec, 0x04b67736, 0x144c497a, 0x0361d37d, 0xf3855a}}}, - /* 11*16^39*G: */ - {{{0x16c051a0, 0x04bb8afa, 0x16cf9b71, 0x1e5248de, 0x12abddcd, 0x0c736d87, 0x1b6128db, 0x038fb004, 0x8035e2}}, - {{0x12d0dd12, 0x00f5d97d, 0x02d88d58, 0x0fb8c613, 0x1d318b3e, 0x1f341bde, 0x0fbcdd76, 0x14896f45, 0xb8810}}}, - /* 13*16^39*G: */ - {{{0x1f12c69e, 0x1006184f, 0x194658f3, 0x0b5deb12, 0x0fcecafe, 0x18008102, 0x14cc1aeb, 0x1bfac314, 0x196908}}, - {{0x1d114831, 0x0998c820, 0x1ee21ae3, 0x05c66e3f, 0x1054eb6b, 0x0ef56e90, 0x18102fb8, 0x0d65f22d, 0x3f65bf}}}, - /* 15*16^39*G: */ - {{{0x0b89c5ed, 0x04c700fe, 0x1e9e31f9, 0x0a619ef2, 0x10f3577b, 0x10e90856, 0x0abd1b9b, 0x1d712c34, 0xdb77fc}}, - {{0x0d25b46e, 0x0ff8e3f7, 0x0266be96, 0x0d8f56d1, 0x1ad411f1, 0x1cdf264c, 0x173bb3cc, 0x070e39dc, 0x7fd1dc}}} - }, - { - /* 1*16^40*G: */ - {{{0x17f82f2a, 0x174e3aef, 0x1f7d0eab, 0x186b0e95, 0x113269e4, 0x16fa1b9b, 0x185fd588, 0x0acdd8e6, 0x8a535f}}, - {{0x023094b7, 0x0fcd0561, 0x031d9a71, 0x0a670c99, 0x092bfcde, 0x140c842d, 0x0f5cdf80, 0x108d1611, 0x455c0}}}, - /* 3*16^40*G: */ - {{{0x0b348fa0, 0x18a790bd, 0x0550777e, 0x1c48b20a, 0x0b4bce0f, 0x1191b612, 0x00b70a88, 0x07bbbd71, 0x86eac9}}, - {{0x0da51cee, 0x171c04aa, 0x13fba293, 0x0db2c6a3, 0x146716c2, 0x17cf46b7, 0x1635690d, 0x0a797789, 0x948f38}}}, - /* 5*16^40*G: */ - {{{0x19222c03, 0x17a0ffe4, 0x197840de, 0x19cefd0f, 0x1f407948, 0x1ebc242c, 0x0ab8fd79, 0x175f3f67, 0x8bf09e}}, - {{0x0a72bb54, 0x0a2fba17, 0x08387528, 0x1d81c3bc, 0x1ba309c9, 0x18edf3f2, 0x09cced22, 0x15fc5c4f, 0x509cba}}}, - /* 7*16^40*G: */ - {{{0x11ae9300, 0x029d160e, 0x1120a02d, 0x188e08eb, 0x1735b5e1, 0x05d6d179, 0x1f18644c, 0x1976fce1, 0xe85e2d}}, - {{0x1546e25e, 0x1506fee8, 0x030c6edc, 0x0fc30bbf, 0x02707deb, 0x1dadc11e, 0x02ff1ee9, 0x14daa39c, 0x451aaf}}}, - /* 9*16^40*G: */ - {{{0x05260cb8, 0x092eaab0, 0x0c854bc9, 0x1e95019d, 0x1dbf6836, 0x13ed0dd3, 0x1e0a8fc0, 0x1e451925, 0x3f5fb0}}, - {{0x1852c964, 0x17da5a20, 0x17b0cc9c, 0x1d0ea3f8, 0x183f2fa3, 0x0f0a9b33, 0x061c38e3, 0x1b5b4933, 0xc55834}}}, - /* 11*16^40*G: */ - {{{0x1a1cd60f, 0x15222216, 0x0c24ba92, 0x0d315398, 0x0002b9f9, 0x083a5a6d, 0x06595ebb, 0x045631b3, 0x336856}}, - {{0x0fd57d67, 0x1fb9bb28, 0x142e2c92, 0x1eb49978, 0x1af175fe, 0x06006f53, 0x1366ea16, 0x13de248f, 0xd42f50}}}, - /* 13*16^40*G: */ - {{{0x17576342, 0x029db75d, 0x06488abc, 0x19110673, 0x179d95b2, 0x1cec4b04, 0x0203df43, 0x0b811e00, 0x4813eb}}, - {{0x17376316, 0x060aaf5c, 0x1aa413d9, 0x1b8cfaa0, 0x1524aca2, 0x0b424719, 0x0903d980, 0x1a846748, 0x043f}}}, - /* 15*16^40*G: */ - {{{0x1f69b2be, 0x1b38b8ef, 0x04447027, 0x03ee9db8, 0x06e56ba4, 0x16ddd71c, 0x05ebc4c8, 0x1f34b5d3, 0x80c3f1}}, - {{0x0102d2f5, 0x0825cbe2, 0x0dea2fe2, 0x16e966b9, 0x15a9bf14, 0x113b2d8e, 0x1a14a603, 0x0814013b, 0xa9321}}} - }, - { - /* 1*16^41*G: */ - {{{0x0476c81d, 0x041bfa7f, 0x194f57a7, 0x06061d33, 0x0a366b7a, 0x06939ed4, 0x08066bdf, 0x1bfb9683, 0xad6090}}, - {{0x0e6705dd, 0x0c55e427, 0x0c1237e0, 0x1fb86c9e, 0x1d8a8393, 0x1ae1662d, 0x047ab335, 0x1ba91e99, 0x77b5d1}}}, - /* 3*16^41*G: */ - {{{0x02725490, 0x11239be7, 0x12d66402, 0x06480c47, 0x1863c4ac, 0x15299d84, 0x05f28ab6, 0x176e35ad, 0xd90b45}}, - {{0x0feb1299, 0x07c27c25, 0x1119b32c, 0x180f7fe7, 0x0cbd80cd, 0x1ab439bc, 0x143c2762, 0x11d83766, 0x332692}}}, - /* 5*16^41*G: */ - {{{0x1e933668, 0x1b59d32b, 0x1aeafc29, 0x05b099f0, 0x106befb0, 0x1c9d7d0f, 0x1f1eb014, 0x02e62427, 0xac2592}}, - {{0x12776fb5, 0x173bfb39, 0x07879e85, 0x0c83138d, 0x0ed7c6f8, 0x009f75ec, 0x02ea143b, 0x070e1b75, 0x6c79a0}}}, - /* 7*16^41*G: */ - {{{0x128de7e3, 0x130be090, 0x1aa65b66, 0x08558757, 0x031bf868, 0x07ded3da, 0x0ea21cc8, 0x095d2f3e, 0x7bc337}}, - {{0x0e6e5e29, 0x1d059975, 0x10333c19, 0x05b67369, 0x1acbd55f, 0x1bd73725, 0x19778031, 0x048c10a9, 0xb431f0}}}, - /* 9*16^41*G: */ - {{{0x035e057d, 0x1659191c, 0x162696d2, 0x1e21b5ed, 0x1119329c, 0x0397e1a0, 0x0ac9a2f2, 0x128a75c0, 0xbf9c14}}, - {{0x0da20fea, 0x1ab25941, 0x1711e6db, 0x173c3038, 0x1a542440, 0x189f82e3, 0x0f83ce14, 0x13e4be47, 0x92acb8}}}, - /* 11*16^41*G: */ - {{{0x021d6584, 0x1566be10, 0x0cf67974, 0x00bac887, 0x1014ef27, 0x1ed1ad6f, 0x1e2a5ba5, 0x0736af09, 0x55bf08}}, - {{0x0ed744ea, 0x0ab27a14, 0x19696a03, 0x1c284055, 0x07dcf089, 0x1fb5d45e, 0x133c9eb2, 0x067c96c3, 0x3d9807}}}, - /* 13*16^41*G: */ - {{{0x01068c5e, 0x0b4efb72, 0x195cf437, 0x0bdcdc97, 0x1d4872a4, 0x10a73c0a, 0x15467cab, 0x02ca66f1, 0xfcf24e}}, - {{0x07c19d75, 0x10fa29f9, 0x052156dd, 0x0ed49650, 0x0e7aee91, 0x0f10dac9, 0x1f8d719d, 0x1ca66dff, 0x186bb0}}}, - /* 15*16^41*G: */ - {{{0x020da860, 0x1becaf83, 0x12744022, 0x08a35490, 0x11f2f843, 0x1b29a1ec, 0x1fb287f6, 0x1a05ea2c, 0x7bc280}}, - {{0x07aac76d, 0x11488208, 0x1058cbaf, 0x03345fb9, 0x0e6e0f2e, 0x15fd382f, 0x07978989, 0x0ef777a6, 0xb33f6d}}} - }, - { - /* 1*16^42*G: */ - {{{0x13c4a205, 0x097961b4, 0x042a1229, 0x15bf13ea, 0x129fcde1, 0x0ab83adc, 0x0f139199, 0x0a2c60b7, 0xb6e06c}}, - {{0x1db36d05, 0x1bfa6c32, 0x0aa7e1d4, 0x13283350, 0x0d73b63f, 0x189373cf, 0x0fd71787, 0x0f843664, 0xbdb427}}}, - /* 3*16^42*G: */ - {{{0x19e27907, 0x17c10fb7, 0x167935a4, 0x15a96711, 0x1bd68771, 0x0eaeb7ef, 0x1139ace5, 0x07f08483, 0xed9e4}}, - {{0x0e78c4fb, 0x09fa7a83, 0x0e86417c, 0x0a39fd71, 0x00e0ce91, 0x07ec7589, 0x0d1fd6f0, 0x095fed64, 0xb5af87}}}, - /* 5*16^42*G: */ - {{{0x15b38f54, 0x1682b929, 0x0bc1f38d, 0x150c1cb9, 0x0e1f92e2, 0x146da47f, 0x1df71549, 0x0200edb1, 0x57a7e4}}, - {{0x045f2809, 0x1d3c0f31, 0x01fae9d7, 0x0edc7352, 0x0dd21dfd, 0x0511de41, 0x14906532, 0x00791d95, 0xfd7f0f}}}, - /* 7*16^42*G: */ - {{{0x07a79593, 0x17f5dfcd, 0x17125e51, 0x14e493a4, 0x05cf3347, 0x0d92c665, 0x16fbd4b6, 0x1c5e7deb, 0x24799a}}, - {{0x10920d55, 0x11c46bae, 0x1ac4e635, 0x086c3f37, 0x1e300999, 0x08d4e9b1, 0x0deccb0f, 0x04c5d90f, 0x9436b5}}}, - /* 9*16^42*G: */ - {{{0x0bf5abdc, 0x010b75a8, 0x02d94198, 0x19a75f7a, 0x15d60456, 0x08e58406, 0x009bb4c4, 0x18d1098e, 0xf15017}}, - {{0x0def85b7, 0x1aef15c5, 0x0e15612d, 0x18ceb84f, 0x1e232cbd, 0x1a0f1fe2, 0x0aa3b360, 0x03858be0, 0xdea7ef}}}, - /* 11*16^42*G: */ - {{{0x1e78e9b1, 0x0f92958f, 0x10507a1a, 0x11cdb89d, 0x0dfcc897, 0x018fba89, 0x1aa9b83e, 0x01f13697, 0xe196e2}}, - {{0x0a77eed7, 0x00bab0fe, 0x1b4d7d11, 0x1a02257d, 0x0ed9a908, 0x045f3b59, 0x1698a990, 0x10bf0350, 0xa5d66d}}}, - /* 13*16^42*G: */ - {{{0x1b1cb64b, 0x17719f2b, 0x02b0f55d, 0x13ca4ac3, 0x1ed14d60, 0x1e6b8a9c, 0x0c0bce5f, 0x1bcd8360, 0x7779f5}}, - {{0x1aba3aab, 0x070c68e5, 0x0aa54cf6, 0x10528479, 0x0e3fae2a, 0x189a53d1, 0x1afab7ea, 0x07e8e987, 0x9a842}}}, - /* 15*16^42*G: */ - {{{0x11d1b492, 0x16c2c3b4, 0x0669bd4f, 0x00c31840, 0x08ce8dfa, 0x16cd5759, 0x0bc4797d, 0x097c8474, 0x8605b9}}, - {{0x18ac6598, 0x18ebbdfb, 0x07a49715, 0x06a4da90, 0x1d1a8ee2, 0x170610a1, 0x1d63cfbd, 0x050fbcea, 0xa8e561}}} - }, - { - /* 1*16^43*G: */ - {{{0x09aa52df, 0x06afa725, 0x0a989fcf, 0x08a56368, 0x1ece618c, 0x00c4ecc8, 0x0fddb6f1, 0x192fec11, 0x45a511}}, - {{0x125ec16c, 0x1a95e890, 0x0a55739e, 0x03364fa4, 0x05ad25a9, 0x19bfe5b1, 0x0db4ff8c, 0x18ee7d53, 0x73be0e}}}, - /* 3*16^43*G: */ - {{{0x0e75bc7f, 0x0b3a9f7d, 0x1dfec7d9, 0x0e2e1b6d, 0x14c7b95c, 0x07890be6, 0x0d0e3bd0, 0x09fce572, 0xb57ac}}, - {{0x0972e9a9, 0x078b96e8, 0x127f1881, 0x12d81c80, 0x094fab1f, 0x1a67d2bf, 0x0ed7ca30, 0x104ef53e, 0xceedbf}}}, - /* 5*16^43*G: */ - {{{0x033125ff, 0x1ba19e7c, 0x16a05084, 0x0aaf60b4, 0x0ae99354, 0x016ce50e, 0x05233d1a, 0x1f6dc97a, 0x1178b3}}, - {{0x18486abd, 0x007cb84e, 0x195346fa, 0x115b9a11, 0x10ed10dc, 0x131bf518, 0x056ce0b7, 0x1d53757b, 0xdfd697}}}, - /* 7*16^43*G: */ - {{{0x1662d955, 0x19b4ae67, 0x033913ce, 0x09ad0b69, 0x15693844, 0x1dbf4693, 0x041fe2a0, 0x104df29d, 0x8ac7a0}}, - {{0x046b3dae, 0x03516df3, 0x1b04e36f, 0x09038b7a, 0x19ad9e3f, 0x1291a65a, 0x0c73275f, 0x1241e664, 0xc80f40}}}, - /* 9*16^43*G: */ - {{{0x088803e5, 0x06c3cd6f, 0x0d1972df, 0x156f9c1a, 0x09e02cc1, 0x1d43802b, 0x08446adf, 0x050b3bbe, 0xc0f48b}}, - {{0x076619ee, 0x14991014, 0x00a3b6e9, 0x1c9c0e17, 0x0d7d3932, 0x12393f30, 0x08da7269, 0x16df1079, 0x3d4326}}}, - /* 11*16^43*G: */ - {{{0x1e1f515c, 0x0b6b384c, 0x194e6bea, 0x09146442, 0x1b8c0e2b, 0x047087fb, 0x19b68067, 0x01e06a2e, 0x2ce870}}, - {{0x052eed6e, 0x08c9b24c, 0x10f54b25, 0x13b9a7c5, 0x15d2ca7a, 0x17a17bf7, 0x129eeb2c, 0x09e76bd8, 0x73879f}}}, - /* 13*16^43*G: */ - {{{0x04dcf274, 0x0d51bbaf, 0x0b3a8911, 0x0400d059, 0x0ca1d807, 0x0dd87ebe, 0x04245178, 0x0c3b96f8, 0xfac442}}, - {{0x112f0472, 0x1b4c3007, 0x11652c58, 0x004f8c4e, 0x097bd732, 0x11eaea77, 0x02a1f31c, 0x18c2acd5, 0x9713fd}}}, - /* 15*16^43*G: */ - {{{0x1dc39d21, 0x1af25b55, 0x06b71a0a, 0x0e7d7a81, 0x12813683, 0x0f21d0cc, 0x18011964, 0x02cb6807, 0xf891e6}}, - {{0x05ca579f, 0x0c8470be, 0x11809535, 0x12fd89ea, 0x1c43b73a, 0x1c54716d, 0x13b462ba, 0x162577bf, 0x129f53}}} - }, - { - /* 1*16^44*G: */ - {{{0x1076f57b, 0x0678d5cc, 0x12b181ca, 0x170dc79d, 0x0a53f030, 0x11a80e79, 0x1e72e49f, 0x0ac91018, 0x20e118}}, - {{0x0da7afe6, 0x0c1df6dd, 0x186dc7a1, 0x01b93681, 0x1e9979fe, 0x01f1fdb6, 0x1bdcc6f7, 0x0a55886f, 0xff67b3}}}, - /* 3*16^44*G: */ - {{{0x0b661da4, 0x04f1d76a, 0x0a129721, 0x14a358c9, 0x01a21940, 0x1fec8183, 0x1b3a3df1, 0x0b770cc0, 0xffca2a}}, - {{0x0f9b8a5a, 0x0c241af5, 0x1a1fdbe2, 0x1f0f5bca, 0x06c8c478, 0x04d0a47a, 0x172294f3, 0x1c656e39, 0xce1cb0}}}, - /* 5*16^44*G: */ - {{{0x1c8cfd22, 0x0560f09c, 0x0daf960f, 0x160ce36c, 0x1354a4e2, 0x1a8a86d6, 0x1aad8d94, 0x1dbff822, 0xff209c}}, - {{0x13bc5535, 0x1c4d8a74, 0x1a12e508, 0x1e972592, 0x1f1c80d4, 0x00e92667, 0x1df881f5, 0x12e8d3a1, 0xad79f3}}}, - /* 7*16^44*G: */ - {{{0x0f4e983e, 0x003f2c2c, 0x05fddf3a, 0x1cdd90e0, 0x14b156d9, 0x0040699d, 0x0ea56181, 0x05a160f3, 0x33d5f0}}, - {{0x11ea37a9, 0x0b86dc3c, 0x18c3255b, 0x035524b2, 0x1a1eb7a7, 0x0b0b2add, 0x1e11cf0f, 0x0eda7388, 0x1eb5a}}}, - /* 9*16^44*G: */ - {{{0x01e52a73, 0x14ad3cfb, 0x01686f2d, 0x0622d92e, 0x15e65d0e, 0x1a6cd6dd, 0x1a42a7a5, 0x07b4c4c2, 0x8f1bd2}}, - {{0x0bea8f2e, 0x1ed0a28f, 0x06142a15, 0x0a05cc96, 0x1eade590, 0x0f2183a1, 0x02e2e1da, 0x0c7275b5, 0x4c7a8f}}}, - /* 11*16^44*G: */ - {{{0x1d2bc078, 0x0217f617, 0x1cfbd696, 0x00ec0a53, 0x080aec4a, 0x0c5bed6c, 0x1fcfb98a, 0x1fdef6c6, 0x963bc9}}, - {{0x1afb8657, 0x0ed918fa, 0x10e8f09f, 0x180851e8, 0x0a4f1c5e, 0x128494c0, 0x188a028f, 0x07f9a3ce, 0x7ed338}}}, - /* 13*16^44*G: */ - {{{0x0fb608ad, 0x038f3b75, 0x03f64e9a, 0x00aca9b1, 0x0bc49748, 0x16ee5be4, 0x011398c6, 0x15b0c3b5, 0x89fe6d}}, - {{0x064d4dad, 0x00a0373c, 0x1c2a1ed8, 0x13aa27c1, 0x1df39aea, 0x1effdb92, 0x03f21ed5, 0x10463e9d, 0x289827}}}, - /* 15*16^44*G: */ - {{{0x19ae4a29, 0x18c4c0d8, 0x08ca82c1, 0x1fb4dd44, 0x06984df2, 0x1d62708b, 0x1d654435, 0x0fe77af2, 0xc34804}}, - {{0x0eb09235, 0x04acd626, 0x126bafcd, 0x05d33e0a, 0x1ae9a842, 0x06e90706, 0x11584f6a, 0x1e40ad43, 0x584781}}} - }, - { - /* 1*16^45*G: */ - {{{0x19273a8f, 0x08a29744, 0x13f552b7, 0x1a8f1cd2, 0x1dac93fd, 0x163fefeb, 0x09ec0c63, 0x1f0e4740, 0x5c9cc4}}, - {{0x1ce80d6e, 0x0ed6534a, 0x06b2ad6b, 0x006ceb42, 0x0af964f0, 0x0c4e9b84, 0x0966a09d, 0x0f43bfda, 0x84efe0}}}, - /* 3*16^45*G: */ - {{{0x0883e382, 0x0464c2a2, 0x154dbce3, 0x009f9dea, 0x07431d06, 0x001ca900, 0x01716f89, 0x12577bfb, 0x5ac8e1}}, - {{0x1dfeaadc, 0x09b9ecde, 0x13674b94, 0x0dd9427a, 0x03976de7, 0x1ff9784b, 0x1200e723, 0x00098f51, 0xfcb7e5}}}, - /* 5*16^45*G: */ - {{{0x0f01a3e8, 0x052183bf, 0x120253af, 0x16ca865c, 0x07362c6e, 0x0ea2706b, 0x0460b545, 0x1316f224, 0x99dc06}}, - {{0x00f61114, 0x14322ff2, 0x1e3ca514, 0x0ce069af, 0x00044b7a, 0x0388b8ec, 0x0af1a5eb, 0x1ba47730, 0x67c69c}}}, - /* 7*16^45*G: */ - {{{0x0cd535ab, 0x01fbd802, 0x1d9370ce, 0x09b107d0, 0x1b9f3772, 0x01abe7e7, 0x18591009, 0x0c31c080, 0xabe2f3}}, - {{0x117b9c1a, 0x0388d9a2, 0x0b237664, 0x1cf43187, 0x1f7957fd, 0x1f959016, 0x0a4f7836, 0x0996eab6, 0x4f02d6}}}, - /* 9*16^45*G: */ - {{{0x0909970c, 0x1a5b359b, 0x19b93836, 0x11b74b33, 0x0099e451, 0x1d8fbbf3, 0x1c84df1b, 0x1af1873c, 0x227cd0}}, - {{0x1f809727, 0x02d25718, 0x0e67b10a, 0x01d87efd, 0x15defa21, 0x043a0e7f, 0x04761f5b, 0x0e390327, 0x2225e7}}}, - /* 11*16^45*G: */ - {{{0x09e65b59, 0x0cd6fe4c, 0x113fddf3, 0x02045efa, 0x1053b7a4, 0x14985466, 0x16da09fb, 0x10415db8, 0x363146}}, - {{0x09b4c2cf, 0x0050b213, 0x116dba72, 0x0792076b, 0x07fc1c14, 0x1c7c9011, 0x0a4a3a09, 0x0c42f12e, 0x1d87db}}}, - /* 13*16^45*G: */ - {{{0x0d4c2506, 0x0bd8ac5e, 0x07a7ebc0, 0x18bb8fe3, 0x11fec5b6, 0x14670c4e, 0x028f9d29, 0x16cd0d63, 0xf65ed6}}, - {{0x1913dfac, 0x0296e129, 0x15950af3, 0x11df8699, 0x0e7bd412, 0x0e17e9bb, 0x0ba14957, 0x0d065175, 0xd6d0bc}}}, - /* 15*16^45*G: */ - {{{0x1b47a80b, 0x0f27cba9, 0x0925d5e0, 0x0f8b4cc8, 0x1dba8ff9, 0x0e13b7d5, 0x0d5ca776, 0x1f423ec2, 0x66a0de}}, - {{0x1f795e8b, 0x1b8cafc7, 0x1bb74803, 0x014850a4, 0x0f474c23, 0x0f92b0d7, 0x09072b63, 0x0dbc6f59, 0x3e24aa}}} - }, - { - /* 1*16^46*G: */ - {{{0x08523eb3, 0x1eecd599, 0x1b1b12b9, 0x1474eaaa, 0x1cde3351, 0x0c22279e, 0x16ad1ab0, 0x1d7f1516, 0xbaffd4}}, - {{0x15acf387, 0x0bc18066, 0x122dbb86, 0x02399f7e, 0x0c09c245, 0x0759bcad, 0x1a0c00ea, 0x18bb792b, 0xfa93d}}}, - /* 3*16^46*G: */ - {{{0x14737641, 0x004cda77, 0x10b84eb4, 0x158182cd, 0x03fb71af, 0x1a891b2b, 0x07b5dde2, 0x04488391, 0x91b445}}, - {{0x0101bbe0, 0x1289594f, 0x01df40fc, 0x0fb8ccdc, 0x1b428c9d, 0x11ad5817, 0x05d8b04c, 0x17a6ffb5, 0x3f4463}}}, - /* 5*16^46*G: */ - {{{0x06dd01df, 0x1515d5c1, 0x03fbee71, 0x1dfeeca7, 0x09165743, 0x1363e434, 0x01ea8dfa, 0x0bbd05b6, 0x296d13}}, - {{0x0a3a0dc8, 0x0a869905, 0x199bd812, 0x15ec31cb, 0x177cadff, 0x094bbb63, 0x1790ae1c, 0x1bb25c28, 0x14054e}}}, - /* 7*16^46*G: */ - {{{0x1650f5dd, 0x13f37836, 0x046cb231, 0x1fc24843, 0x04a9654f, 0x0178f8cf, 0x08c63c4f, 0x1e7226cf, 0x4b0942}}, - {{0x1aeddc6d, 0x1752de63, 0x19ce98b0, 0x18cf05c9, 0x1c25f023, 0x0080ab09, 0x0f038157, 0x14c6cd95, 0x7432aa}}}, - /* 9*16^46*G: */ - {{{0x04e4a96f, 0x11baf478, 0x1956c51e, 0x10c5686a, 0x0e4af188, 0x0dc7e269, 0x046a0cfb, 0x14c5fd98, 0x36377}}, - {{0x11e08cdb, 0x1d7dbf02, 0x0244c9a2, 0x13184286, 0x06263840, 0x062abc2a, 0x1e0e364c, 0x03a6a9fb, 0xa1de19}}}, - /* 11*16^46*G: */ - {{{0x079b5a59, 0x00fe9f0b, 0x1a798a85, 0x03d13d64, 0x03251c62, 0x16ab84ec, 0x058af2ef, 0x1ee61ebc, 0xa1041a}}, - {{0x0c5514a3, 0x0695a011, 0x0b19b676, 0x00d21c3d, 0x02afbfb3, 0x086c39de, 0x0c650899, 0x0d551eb1, 0xad4217}}}, - /* 13*16^46*G: */ - {{{0x0ddd597b, 0x1746d836, 0x015d637a, 0x1262e199, 0x12007d88, 0x0d687cf4, 0x191c0cdc, 0x15a163ca, 0xda2167}}, - {{0x1de7fa04, 0x140b93f1, 0x13e7d189, 0x1c54a428, 0x0ebf6cdd, 0x180753cc, 0x14d87fd9, 0x16c4a8dd, 0xa21992}}}, - /* 15*16^46*G: */ - {{{0x13f7dbb0, 0x09a51115, 0x0fca7026, 0x1c47b84d, 0x0f29df4e, 0x1dc390b2, 0x19e2f218, 0x1846fed8, 0x1c3fdb}}, - {{0x12e16d32, 0x1265ee4b, 0x083e2b75, 0x0c8c7000, 0x118d41f0, 0x129ca525, 0x004fc2ba, 0x0206f253, 0x39260f}}} - }, - { - /* 1*16^47*G: */ - {{{0x1a111101, 0x1a9046c5, 0x16cf17e0, 0x1e1634ed, 0x04c96479, 0x11a692bf, 0x1d9bb48a, 0x0131f9da, 0x6ad2a}}, - {{0x1fb37ef4, 0x0d3dd4ea, 0x03a26bb0, 0x053b056e, 0x162a0de4, 0x000ddcf5, 0x18d56693, 0x038b1f0b, 0x2d5b8b}}}, - /* 3*16^47*G: */ - {{{0x102bef6f, 0x17e1c23b, 0x0c7b90dd, 0x1c9e308a, 0x0d475bba, 0x05eb35ec, 0x15c813de, 0x0aad8779, 0xf1a2ca}}, - {{0x0f6c1ca3, 0x0d968fec, 0x154ad004, 0x08fd503f, 0x00168b0b, 0x0a0bee01, 0x04fb7d15, 0x15e09106, 0xb39b59}}}, - /* 5*16^47*G: */ - {{{0x00455367, 0x030147e5, 0x1584f820, 0x09e59049, 0x11851e6c, 0x00b2c75f, 0x00c3b864, 0x093fc770, 0xe924ad}}, - {{0x08257e92, 0x1e8c67c1, 0x099d4ad7, 0x1463549f, 0x1bb6f52d, 0x029c9eb7, 0x1b55d482, 0x12f34287, 0xfcc97d}}}, - /* 7*16^47*G: */ - {{{0x02f8f1e7, 0x08f849ca, 0x147e78ba, 0x0954ba9b, 0x122f68dd, 0x09a882fd, 0x09be802e, 0x0fb8bee0, 0xf49d9c}}, - {{0x114d9972, 0x1114558c, 0x135ea0e4, 0x0002789c, 0x0f67901b, 0x09d9dcca, 0x12b9ab97, 0x08407c75, 0xf5585d}}}, - /* 9*16^47*G: */ - {{{0x1b219a79, 0x19d4b3bf, 0x0609e9de, 0x19a882fd, 0x189e65c4, 0x01aabaa8, 0x1522c38f, 0x007c8d53, 0x28b04d}}, - {{0x102dbe24, 0x05fbe6c8, 0x0012f97e, 0x0cd99f0c, 0x0206b861, 0x12b90c1f, 0x1c51673f, 0x13cb4299, 0xf658da}}}, - /* 11*16^47*G: */ - {{{0x17774af9, 0x14116ce2, 0x1182b62c, 0x0d74ca22, 0x0efb54c1, 0x01c94435, 0x1a4f5a14, 0x17cf983f, 0x3f4766}}, - {{0x1d4de990, 0x1e6bfb26, 0x0dcc9bfd, 0x1299fbf3, 0x05f511ca, 0x1c483737, 0x12e8eac5, 0x1ad4e663, 0xcc810d}}}, - /* 13*16^47*G: */ - {{{0x08e57705, 0x020cf8f2, 0x1356639e, 0x1d6ff590, 0x1361721c, 0x0d5a0eb7, 0x19e47cab, 0x00581f1d, 0xe3249e}}, - {{0x18caec0c, 0x0a58cf41, 0x1ce10882, 0x128bae2c, 0x06b5a501, 0x1c60f924, 0x141f72dd, 0x10e026d2, 0xa66665}}}, - /* 15*16^47*G: */ - {{{0x125b93ac, 0x1c5e757d, 0x01fe34b1, 0x0404a20b, 0x1b4e917e, 0x13b49efd, 0x1872f7e7, 0x017bf6f2, 0xa68958}}, - {{0x0f589aab, 0x11e8e26b, 0x113f4eba, 0x03f02fb3, 0x19ff2fcf, 0x1780af82, 0x00faa9fc, 0x12969e0f, 0x4657ca}}} - }, - { - /* 1*16^48*G: */ - {{{0x113728be, 0x07907fd9, 0x11ae529b, 0x072b2347, 0x15fc5964, 0x1fc1a218, 0x09d89cdb, 0x0ef4f092, 0xa6d396}}, - {{0x0357f5f4, 0x15d5c19e, 0x010166fc, 0x15241845, 0x1ecdf824, 0x1d5e9693, 0x00599ae2, 0x0e936171, 0x674f84}}}, - /* 3*16^48*G: */ - {{{0x0f15d864, 0x02a5ab4e, 0x13234f30, 0x0dfb8d43, 0x0cf35240, 0x1673df13, 0x0c36bf23, 0x1af8bbdb, 0x7ef66}}, - {{0x140907fe, 0x0312a13b, 0x1392a2d5, 0x0e1c7639, 0x1505e9f4, 0x062910fe, 0x1a941b50, 0x0bb713bc, 0x2db332}}}, - /* 5*16^48*G: */ - {{{0x17c7c05e, 0x14a8a1e0, 0x19505ab1, 0x07972a59, 0x08c0bb28, 0x1397baf9, 0x118053ce, 0x0bf80db8, 0x82df4e}}, - {{0x18fff26b, 0x0b09e816, 0x0b6cc02e, 0x0bb28d08, 0x1cbd1cf1, 0x0b10890b, 0x08289d48, 0x193192c8, 0xe4e188}}}, - /* 7*16^48*G: */ - {{{0x140368b0, 0x0570ea0a, 0x1ba52760, 0x09845f1f, 0x07a62132, 0x0dc69c72, 0x11a9f679, 0x13782561, 0x261efc}}, - {{0x1deb011f, 0x1d692acd, 0x06d74c04, 0x0817c3c7, 0x1ff797e3, 0x02966b27, 0x13a7f722, 0x1b7c70df, 0x8a9d2a}}}, - /* 9*16^48*G: */ - {{{0x15eb8034, 0x0819f4a8, 0x1a3292bc, 0x1666bead, 0x1692df30, 0x1f2cecf3, 0x1e4526a9, 0x1aef4584, 0x6d48df}}, - {{0x1ab0ce30, 0x039843d2, 0x0fa2587a, 0x0421d454, 0x14763080, 0x1cb24f02, 0x04bcf579, 0x08a2cbba, 0x3cb472}}}, - /* 11*16^48*G: */ - {{{0x140535c8, 0x08a1efe2, 0x036c4fad, 0x014ac619, 0x14e6f65f, 0x11fda7e2, 0x048e9244, 0x03cf7731, 0x93a5c0}}, - {{0x1d59b844, 0x04aba041, 0x16fb7ff1, 0x02c40926, 0x1a5c166a, 0x021ac70a, 0x0bd305aa, 0x12093018, 0x2d440e}}}, - /* 13*16^48*G: */ - {{{0x1e2047ba, 0x130d2b34, 0x0c3d94a8, 0x0e0932d7, 0x07031e54, 0x10700beb, 0x0aeecd76, 0x0522c24e, 0x3fb0b9}}, - {{0x1db24158, 0x1ff66a76, 0x1c0274d5, 0x0415cee2, 0x06dc86c4, 0x110e4cb3, 0x1e5329c9, 0x1cd042fb, 0x9d467a}}}, - /* 15*16^48*G: */ - {{{0x02df71c1, 0x05ededd7, 0x0edc8e80, 0x030d7d5f, 0x1e4381c3, 0x1dd4ef19, 0x0f5741d8, 0x073c11d0, 0xdab094}}, - {{0x04c3a1e3, 0x039a4209, 0x0d138eee, 0x0c661949, 0x00b3d6e9, 0x14379069, 0x13bce16b, 0x03ca89c3, 0x763cbc}}} - }, - { - /* 1*16^49*G: */ - {{{0x0514c6fd, 0x177b17fa, 0x0ac04f9b, 0x10769a1b, 0x15936fd6, 0x0dab887f, 0x1380cf53, 0x1001139e, 0xac25da}}, - {{0x05830541, 0x05a9cbb8, 0x0efcde98, 0x1307d048, 0x1338c810, 0x1498950d, 0x11ee20f6, 0x130b9689, 0xebc69d}}}, - /* 3*16^49*G: */ - {{{0x12fd0e3d, 0x0ca0e3f1, 0x09eb5820, 0x03c9b8a8, 0x05547e63, 0x04338f0b, 0x122ed35d, 0x0d893747, 0xeea7e6}}, - {{0x191d5868, 0x0208fb46, 0x0678f304, 0x175b4460, 0x17d985ac, 0x1f93df4d, 0x0984a210, 0x0b73f112, 0x83fed4}}}, - /* 5*16^49*G: */ - {{{0x0ccb63b3, 0x0cf8a793, 0x10239744, 0x1ffcd888, 0x1c67b7dd, 0x0a59aa01, 0x06f6eb46, 0x1a7d27c4, 0x9a3de2}}, - {{0x1df93fcf, 0x0e2994bb, 0x16089800, 0x003b3fde, 0x13c4c49c, 0x139b7740, 0x0b22027c, 0x120c2222, 0x2f809b}}}, - /* 7*16^49*G: */ - {{{0x163f1117, 0x07651a6e, 0x1fdb62f9, 0x12dee174, 0x1adaf348, 0x0698091f, 0x0b6c1440, 0x1e96a772, 0xa7c382}}, - {{0x1934cb9a, 0x091062f0, 0x1129a330, 0x1d6edda7, 0x1cfb5ae4, 0x1bbbb82e, 0x1e201167, 0x022cec37, 0x1b91e5}}}, - /* 9*16^49*G: */ - {{{0x06774a96, 0x05e40e2d, 0x0e38fa14, 0x063fb230, 0x0f497e82, 0x1dfe41d3, 0x084e1c50, 0x1319b0c2, 0x555aa9}}, - {{0x06db0e34, 0x0a04b96c, 0x189be9a7, 0x1aba9791, 0x0bbb89a0, 0x00f389a8, 0x11a66751, 0x0d1a40f7, 0xb05328}}}, - /* 11*16^49*G: */ - {{{0x0f7dac7d, 0x17bf779d, 0x0904848c, 0x0e572422, 0x1c369165, 0x0bc7c6bb, 0x0b5ed633, 0x0b66914f, 0x1a42f}}, - {{0x0195e46e, 0x1c4a518c, 0x13aa5ac9, 0x15e52651, 0x19216172, 0x1caa5c5f, 0x1e04d25f, 0x070aa40e, 0x957a9c}}}, - /* 13*16^49*G: */ - {{{0x002afc36, 0x015d0ea1, 0x0c1c74f8, 0x1bddaa28, 0x1d3a3134, 0x04f78da2, 0x18f4e96c, 0x06fd60b9, 0x4b47f5}}, - {{0x0f8133ff, 0x144fbb53, 0x17ef68d3, 0x1597d364, 0x1f573345, 0x037d0746, 0x1c30b72c, 0x0073390b, 0xf2fc45}}}, - /* 15*16^49*G: */ - {{{0x17d17f68, 0x15f971e3, 0x02eb61aa, 0x0b43bf97, 0x0418f791, 0x0b7a9b57, 0x033b5594, 0x1398a49d, 0x6b3dec}}, - {{0x09232402, 0x1d73d106, 0x1732da33, 0x0552d54d, 0x15d4747f, 0x00da0b66, 0x07bc1426, 0x06ffbdfb, 0xb86539}}} - }, - { - /* 1*16^50*G: */ - {{{0x0fd20bae, 0x0ea71bd1, 0x0d2a0455, 0x06ace5ab, 0x1343a260, 0x1d090bb6, 0x136409ee, 0x1db8779f, 0x285250}}, - {{0x14e0ab97, 0x0ef22ad2, 0x1bfcc8fe, 0x163459e3, 0x0c1716e9, 0x02568823, 0x1aa0fdca, 0x10de95af, 0x7866c0}}}, - /* 3*16^50*G: */ - {{{0x0636a50b, 0x0443b55d, 0x0dd465b3, 0x1dec2d57, 0x0baf65d2, 0x1d097e3c, 0x1d7160db, 0x0ca8bab4, 0xf1e3c5}}, - {{0x0b3128b6, 0x1bbc8a75, 0x0b5e9bb7, 0x1f4aeda4, 0x1f3136b7, 0x1533fb52, 0x139db1cd, 0x0f4dc3df, 0x12b884}}}, - /* 5*16^50*G: */ - {{{0x0e583340, 0x0bf8990a, 0x0d3cec94, 0x1836d6ba, 0x1228cf45, 0x06d5fd4d, 0x129db61f, 0x13903c26, 0x584d72}}, - {{0x14fb24b9, 0x17b72f4b, 0x05301c1c, 0x0ee14cc9, 0x0affa8f1, 0x1e2c9818, 0x02af34c1, 0x148ac1b0, 0x2fdd80}}}, - /* 7*16^50*G: */ - {{{0x0235809b, 0x1641f6f0, 0x1ae05ce4, 0x0e5be16b, 0x03c453c5, 0x0146e11c, 0x1df478b8, 0x001906fb, 0xbaaeae}}, - {{0x0154fd62, 0x0b0ec52e, 0x14b9f973, 0x18788543, 0x1f299835, 0x183de5a4, 0x0e02d288, 0x1067e649, 0x325788}}}, - /* 9*16^50*G: */ - {{{0x0d612268, 0x10021620, 0x17b405bd, 0x1eb3be14, 0x0b8b906c, 0x0f7d21ca, 0x0c69944e, 0x0c6c1842, 0x6c7e4}}, - {{0x060166a0, 0x05a5b009, 0x0b9c262f, 0x1b14b4f0, 0x053ca238, 0x03ae717a, 0x0335d1ff, 0x0bbee5bb, 0xcb6ad5}}}, - /* 11*16^50*G: */ - {{{0x012fbdc8, 0x0a1d1adc, 0x1038a8ef, 0x1c419545, 0x1a36db89, 0x1663db88, 0x10f96f0b, 0x1bd57acc, 0x64131}}, - {{0x09f99380, 0x09ff984d, 0x1ec08297, 0x15c4d163, 0x17598603, 0x006c9a4a, 0x00a3cace, 0x15865ace, 0x882c7f}}}, - /* 13*16^50*G: */ - {{{0x0bac9f32, 0x0f580032, 0x1a26c19d, 0x104398b2, 0x16400443, 0x00b7f0cd, 0x08de2859, 0x15984eb8, 0x366bb7}}, - {{0x1c85d47d, 0x17872e7d, 0x1c09a290, 0x19ca180f, 0x1cfc01fd, 0x01d5c6b0, 0x1c193c1e, 0x0e10f0b5, 0x7d107b}}}, - /* 15*16^50*G: */ - {{{0x06dd27eb, 0x1e5a9294, 0x0ed588c0, 0x18ab86f6, 0x032ecb98, 0x0871cddf, 0x1001ac9f, 0x04af98e7, 0xb767db}}, - {{0x0f65dac4, 0x0a90d23e, 0x1803b505, 0x0e016890, 0x1d85b64b, 0x05c0b5cc, 0x072d73ab, 0x1864c245, 0xdc1308}}} - }, - { - /* 1*16^51*G: */ - {{{0x1e07e4f1, 0x18f9d151, 0x17099f05, 0x0a28fba1, 0x0890e1fc, 0x15e03f7c, 0x19be0637, 0x00c5da06, 0xc472c1}}, - {{0x06b0daa9, 0x18e341ec, 0x0ad76295, 0x076f63c4, 0x067d885f, 0x15ad426b, 0x03a590ca, 0x00328bee, 0x41820e}}}, - /* 3*16^51*G: */ - {{{0x02f8acb1, 0x1b4a9a55, 0x0fc14fd0, 0x1acaa8c2, 0x0c31eb39, 0x1bd25c76, 0x0f5a1786, 0x0732a8bc, 0x86f88f}}, - {{0x05098a19, 0x05821688, 0x05949c45, 0x14c57dd2, 0x1b1214ee, 0x0bc7dac8, 0x035acdf2, 0x0d34d047, 0x2ccfdd}}}, - /* 5*16^51*G: */ - {{{0x1cadab66, 0x041bbdb7, 0x14d580b6, 0x0d46787b, 0x1f9a0e1c, 0x134b306c, 0x19d1f7dd, 0x03f93291, 0xa2a3be}}, - {{0x0c1aeb12, 0x1a509242, 0x002b497b, 0x1bd14a69, 0x15ee1fb2, 0x1f6ba691, 0x199c1941, 0x1cd6a497, 0xa93bd8}}}, - /* 7*16^51*G: */ - {{{0x007c25bf, 0x04e91099, 0x0b6025ee, 0x178eef7c, 0x080be82f, 0x09233be0, 0x16e4d9f8, 0x1daadcf1, 0x354e7c}}, - {{0x1a864211, 0x091d1cca, 0x082a8854, 0x0ead960b, 0x1e5585fd, 0x0c1252e7, 0x01c39baf, 0x1d377328, 0x629d62}}}, - /* 9*16^51*G: */ - {{{0x15e1dad8, 0x13ec1703, 0x112f4b92, 0x014f0b0d, 0x19f498b8, 0x07b90604, 0x016de6d7, 0x155ebbd0, 0xc751c9}}, - {{0x0e4afc8b, 0x09b59b09, 0x02a300b4, 0x112e1474, 0x1a4ffe6f, 0x00feb6e4, 0x178afad3, 0x06ff8f33, 0xcb9864}}}, - /* 11*16^51*G: */ - {{{0x099d9ba2, 0x1890d908, 0x0aa9d5f4, 0x0cafad2f, 0x19ca80cf, 0x09435a87, 0x0085e2ad, 0x08373a3a, 0xaee9cc}}, - {{0x1ed2ad58, 0x06b0241d, 0x05d2439e, 0x1cd1c4d4, 0x0b1f5312, 0x1dfd8063, 0x0dbdefa5, 0x005b6a54, 0xb72cf3}}}, - /* 13*16^51*G: */ - {{{0x094d208d, 0x1ff84124, 0x1ce46918, 0x1b51fe1f, 0x1f0cefb0, 0x1057958f, 0x1b15affd, 0x08d4f225, 0xd0d3f}}, - {{0x1d45d1b1, 0x117a9fbc, 0x0776aff5, 0x0781a34e, 0x09ff0b21, 0x06d32fc8, 0x05a6c11d, 0x1015c3ee, 0xdc371b}}}, - /* 15*16^51*G: */ - {{{0x19cfd890, 0x17411640, 0x01c45171, 0x0d86e6f8, 0x041e1cb3, 0x0c1c3f2a, 0x14d7d1f3, 0x0d68826e, 0x778d14}}, - {{0x16f057f2, 0x0d43fd3e, 0x1482b2b2, 0x148a911d, 0x0cd3796c, 0x18c6cbc3, 0x0bdca949, 0x02676023, 0x3c85ba}}} - }, - { - /* 1*16^52*G: */ - {{{0x039bb85f, 0x10784e1c, 0x14398b0c, 0x03f60d40, 0x13458010, 0x0164cd6a, 0x0cad55d6, 0x11a2ccc8, 0x55d539}}, - {{0x0fed936f, 0x1fb188c2, 0x0cf6787d, 0x1ad4fe30, 0x0a72ad90, 0x154f475d, 0x18b41671, 0x12093ff1, 0x576e22}}}, - /* 3*16^52*G: */ - {{{0x12ea285a, 0x03f15c90, 0x0e443470, 0x0383cdef, 0x0a7a39f0, 0x02c6eee0, 0x022de160, 0x011029f1, 0x1bb464}}, - {{0x107dc702, 0x006453cc, 0x0bea53b7, 0x05469732, 0x0a4fc1e5, 0x0cdc495a, 0x0496903f, 0x17f5f5c2, 0x8a3016}}}, - /* 5*16^52*G: */ - {{{0x1539785a, 0x08094806, 0x0a5fc051, 0x11a0ed70, 0x07a548c8, 0x1f133c31, 0x053b825c, 0x0e1c05f4, 0x4bc4e}}, - {{0x0a62e3bb, 0x1cc823ae, 0x0c9d70d4, 0x002ee4f4, 0x1fb4f877, 0x10e79f9e, 0x130e97d6, 0x04971969, 0x5729f2}}}, - /* 7*16^52*G: */ - {{{0x0114cfb5, 0x096a5d8f, 0x1569a8c4, 0x0c313547, 0x10876d13, 0x1cf0dbef, 0x05cd61dc, 0x1fb83f10, 0xd3e492}}, - {{0x097f7045, 0x075cd52b, 0x1d53bbef, 0x11e0dc8c, 0x1fea39c8, 0x133b5f8a, 0x122c7fb8, 0x014e7f18, 0x3604a7}}}, - /* 9*16^52*G: */ - {{{0x0c55ddff, 0x1133a5dd, 0x152de1c6, 0x1a367ec9, 0x1c1791da, 0x091887e6, 0x094e2939, 0x0ab0c508, 0xbebfc2}}, - {{0x1ea2f303, 0x0a6d8651, 0x02ea9c1b, 0x15045aca, 0x0576c3cc, 0x08e25bbb, 0x133a28e8, 0x0cb812c0, 0x850de2}}}, - /* 11*16^52*G: */ - {{{0x099ead51, 0x0d7a0f26, 0x164893a4, 0x06a87443, 0x184715da, 0x098e8b03, 0x1580beca, 0x1b8e7a41, 0x36e984}}, - {{0x0e0e5e3e, 0x17dcea13, 0x10a02bf1, 0x177d82e0, 0x12b203ba, 0x0fe4d671, 0x017d2fef, 0x08e437e9, 0x143771}}}, - /* 13*16^52*G: */ - {{{0x03093df0, 0x145bbdd9, 0x1d91935e, 0x1c4902ce, 0x193af785, 0x0a3caa6b, 0x12bbcc54, 0x00087ec0, 0x91b675}}, - {{0x12cc9f14, 0x06f461be, 0x12bd9fd7, 0x0d0bf1f3, 0x01c5d933, 0x1d6d4b71, 0x00351df1, 0x03cb0494, 0x7fedb}}}, - /* 15*16^52*G: */ - {{{0x1b7b8dc4, 0x11b3dc37, 0x06ce1228, 0x09260515, 0x02fac5b3, 0x1f0d01b0, 0x00f9f125, 0x18f43891, 0xc5d9c3}}, - {{0x1b2df0ea, 0x0b24bc68, 0x1f524dbb, 0x11ee5fa3, 0x10af3d0d, 0x01c302e2, 0x1e796023, 0x1c4b9fb6, 0x3e59b9}}} - }, - { - /* 1*16^53*G: */ - {{{0x12513926, 0x116de4e1, 0x1b217b31, 0x0d1281df, 0x03383cc2, 0x1d5925fe, 0x1c9a53fa, 0x08c79410, 0x884286}}, - {{0x0fb8a54d, 0x17214155, 0x16f05683, 0x1d6245d7, 0x01207ce0, 0x06d9b2ec, 0x1569a598, 0x1380385b, 0xf77842}}}, - /* 3*16^53*G: */ - {{{0x0520f1f1, 0x095d60cb, 0x1fdf693b, 0x03693cc8, 0x16f4ad7f, 0x1e8b4667, 0x00675697, 0x06deede1, 0x3bad9d}}, - {{0x1698df4d, 0x10cb8392, 0x0d9c961a, 0x1303449d, 0x00e80499, 0x1d3ecef6, 0x1966f367, 0x1c67c49c, 0x49f99d}}}, - /* 5*16^53*G: */ - {{{0x1185ae66, 0x18f22545, 0x09e0f7c2, 0x182db7df, 0x0118ba6e, 0x0fa9e892, 0x11b59e9f, 0x1635b618, 0xa6b3a4}}, - {{0x0bfbf21b, 0x1f5aa9fc, 0x0c92375e, 0x1e14bbeb, 0x1e8d8bcb, 0x148e6cb4, 0x188c4d86, 0x1aec7112, 0xcb6e8}}}, - /* 7*16^53*G: */ - {{{0x0c630e3a, 0x0b426727, 0x1cfc70aa, 0x00c182ff, 0x110c1f61, 0x11d3ec3f, 0x1293889f, 0x0b4d9222, 0x1f848f}}, - {{0x06ca610a, 0x176cffb4, 0x0d65c92b, 0x0724d7fc, 0x1a4264ba, 0x041e8d4e, 0x058e18a7, 0x0599a0df, 0xa02855}}}, - /* 9*16^53*G: */ - {{{0x041bcd10, 0x0ff79e6e, 0x0d138553, 0x12aaec8b, 0x02eb211b, 0x133be365, 0x0d622c68, 0x097d2938, 0xcfd1e5}}, - {{0x0a62e732, 0x000af5cd, 0x154e596b, 0x1322ba10, 0x12fafacd, 0x08dead82, 0x02ee715d, 0x0bec012b, 0xf4e31f}}}, - /* 11*16^53*G: */ - {{{0x028da5fb, 0x1d30ec91, 0x01c39c93, 0x097ebc55, 0x1291b90e, 0x0af1f3b8, 0x19544b1e, 0x01808d93, 0x4b3e73}}, - {{0x1c169e48, 0x1f8531c5, 0x08d1caef, 0x07423938, 0x0b48c65a, 0x1d03dc70, 0x03a7a032, 0x09b446cc, 0x8c4096}}}, - /* 13*16^53*G: */ - {{{0x1f894780, 0x0748d2c4, 0x06bb176e, 0x139946b1, 0x0d8f737e, 0x1c52a5a1, 0x1f9c7552, 0x1bee8871, 0xafe915}}, - {{0x1511d444, 0x1cb4aa9e, 0x102bd14b, 0x1d17ce75, 0x12e36909, 0x01a1199f, 0x1a1aa52d, 0x0811a408, 0x3caec3}}}, - /* 15*16^53*G: */ - {{{0x1182fa6e, 0x0d18fe5e, 0x00722bfd, 0x0c65bad3, 0x1c9e7c0a, 0x11d1b69a, 0x1215619a, 0x05021ff5, 0xc0548}}, - {{0x061cd145, 0x15e7f55b, 0x1db407db, 0x0cc8b096, 0x1602bf5e, 0x05c4a32e, 0x14cf46aa, 0x195a1e3e, 0x2f9cd2}}} - }, - { - /* 1*16^54*G: */ - {{{0x14441fbb, 0x105aead6, 0x1b44578f, 0x150a414b, 0x125559ea, 0x062af6dc, 0x0751fed8, 0x09c43bc4, 0xb4958c}}, - {{0x0add7118, 0x03f1e4fa, 0x118e1053, 0x13ec265a, 0x0b7e12db, 0x00fde1c6, 0x03bf9701, 0x17f32cc8, 0xfcd6e7}}}, - /* 3*16^54*G: */ - {{{0x171f07f1, 0x176b4261, 0x15c31296, 0x19db6e61, 0x0684b878, 0x105b2303, 0x11348cba, 0x0bcf6408, 0xb3a43f}}, - {{0x001dfda5, 0x1e6917a7, 0x12c3b314, 0x10ef419b, 0x15ee7ec7, 0x1139b4cb, 0x1ae1060c, 0x0b6491fa, 0x34c64f}}}, - /* 5*16^54*G: */ - {{{0x0b559d49, 0x1be4bd23, 0x1726d13f, 0x0368d21b, 0x008b148e, 0x17fec260, 0x052b0998, 0x0d348d7c, 0x452e98}}, - {{0x1a0d6ba7, 0x03e30236, 0x07b9095d, 0x050ad876, 0x1ee52598, 0x02bdb3b0, 0x0343d700, 0x11e32bf0, 0x8c5e8a}}}, - /* 7*16^54*G: */ - {{{0x13ce94da, 0x1bd33f5a, 0x00a79814, 0x049e84ad, 0x074ee8bb, 0x106e1d62, 0x0aed4737, 0x1a918dac, 0x19a7f5}}, - {{0x1025e7bb, 0x182238b1, 0x097ac0dc, 0x04a60d5c, 0x0a2e8fb6, 0x08ea2100, 0x170cbda9, 0x14f5260e, 0xa2504b}}}, - /* 9*16^54*G: */ - {{{0x147dc697, 0x0b4b6636, 0x1856e6ee, 0x1c315f6b, 0x06fa417e, 0x18595afe, 0x1370047a, 0x004149e6, 0xbdaf5b}}, - {{0x06a479e2, 0x088e5f3c, 0x0de91dee, 0x045cf10b, 0x1aa08551, 0x1af23dab, 0x0db233d5, 0x0d97bf50, 0x3cec0c}}}, - /* 11*16^54*G: */ - {{{0x0ce05e10, 0x1005c8db, 0x1841880a, 0x1ef93e87, 0x070db8ae, 0x1bff4267, 0x0576ae12, 0x1d2be73a, 0x265dba}}, - {{0x171324f4, 0x1bf80c58, 0x19319fff, 0x07e7267a, 0x15dcb066, 0x0745ab65, 0x1eb7cecf, 0x1a134606, 0x58df63}}}, - /* 13*16^54*G: */ - {{{0x13fe5938, 0x08ade2ad, 0x0db5f37b, 0x10607b6c, 0x068669ec, 0x04ea9d2b, 0x0e5a27dd, 0x07e2fccc, 0xc43e08}}, - {{0x183732f3, 0x13cbab76, 0x1101d1dd, 0x0460e2c4, 0x0402eab6, 0x0181d5e2, 0x1160d424, 0x12473f79, 0x54c602}}}, - /* 15*16^54*G: */ - {{{0x1dd52975, 0x18e387bc, 0x0d106030, 0x1e1fa60d, 0x066ba2bc, 0x086d3bd9, 0x121996b1, 0x0e0147f0, 0x7868f1}}, - {{0x1c626fac, 0x00b76a81, 0x05a4110c, 0x0df3d94d, 0x1276c68f, 0x10e36d88, 0x1b8444fe, 0x19e6242f, 0xe89097}}} - }, - { - /* 1*16^55*G: */ - {{{0x0e12e1df, 0x0127321b, 0x1d87412b, 0x0ffa16fa, 0x0027cd8a, 0x1f89d9a3, 0x0ad904d2, 0x12d11d26, 0xd0e091}}, - {{0x1fd28fbe, 0x132a26dc, 0x11ae37da, 0x19897b30, 0x1f867544, 0x105b48ed, 0x114ad3ad, 0x0b3fcfa2, 0x69c9a}}}, - /* 3*16^55*G: */ - {{{0x084aa098, 0x186c2880, 0x1b8f80ae, 0x02028152, 0x1fa8509c, 0x1ed65fe0, 0x03ace629, 0x0a942661, 0xb517a4}}, - {{0x0540efbf, 0x0025acfa, 0x0911ff58, 0x0916a8d2, 0x06fa3a4d, 0x1f17d879, 0x1e6983a8, 0x0fa183f0, 0xa3d87}}}, - /* 5*16^55*G: */ - {{{0x0744bfa1, 0x0cad6552, 0x04d90f5b, 0x0da4f9c1, 0x1e387cc2, 0x13896c79, 0x1bd9ef08, 0x07096a2c, 0xf8ec14}}, - {{0x12b65f6d, 0x14927319, 0x04001831, 0x06f58b87, 0x00f610a6, 0x07d934eb, 0x0698c8da, 0x164227f7, 0x761134}}}, - /* 7*16^55*G: */ - {{{0x1227a4bb, 0x1161df49, 0x03667cbd, 0x0d63e01f, 0x0f2e64be, 0x075690ea, 0x0b9e539d, 0x0f1b6f7f, 0x320cff}}, - {{0x10f3d2d4, 0x00e64835, 0x18be5c16, 0x0e46e813, 0x16299604, 0x0b512a7f, 0x1a4aadde, 0x1a80e550, 0xaf9fe8}}}, - /* 9*16^55*G: */ - {{{0x1c2ca683, 0x1adad2f2, 0x0569cdce, 0x19e6bc15, 0x1426a206, 0x0ee65aa1, 0x16145fb7, 0x0f8d4f5d, 0xc08de}}, - {{0x1db5f259, 0x12036dab, 0x1a9a31a4, 0x11af6fc1, 0x00e79c3c, 0x14ce6fe7, 0x1866df20, 0x10abd42d, 0xddb76d}}}, - /* 11*16^55*G: */ - {{{0x052ae5cd, 0x033d67c1, 0x1f75e187, 0x0ca5f5e9, 0x0390995b, 0x1bd22672, 0x10f4639b, 0x0d5a188f, 0xd1f8c7}}, - {{0x1e6d2dda, 0x15cbde1f, 0x027d3f1f, 0x15d02ad3, 0x1203239b, 0x0bd80fb0, 0x000ab1e6, 0x18cc241d, 0x74d45d}}}, - /* 13*16^55*G: */ - {{{0x0bdc603f, 0x1c803355, 0x17ff96ad, 0x1acb9acf, 0x020d8c96, 0x1f63133b, 0x03024f8c, 0x0d27e712, 0xa6cb83}}, - {{0x096befcc, 0x16701f06, 0x1985cd72, 0x1d82d498, 0x10b72fb1, 0x0ded2628, 0x0bf23cb6, 0x1c8c3e79, 0xd823c8}}}, - /* 15*16^55*G: */ - {{{0x02c374b0, 0x0f1d3097, 0x1c36d28a, 0x166b316a, 0x04ef0bf5, 0x04b8a921, 0x0c84dafb, 0x123d4d86, 0x8a6c9c}}, - {{0x178c08bd, 0x1fbe7c6d, 0x03d3560e, 0x0a69e868, 0x132a0461, 0x042ee480, 0x1ebde69e, 0x09ecb9bf, 0xe4bc7f}}} - }, - { - /* 1*16^56*G: */ - {{{0x0895df07, 0x1381f887, 0x01daf61a, 0x0be7f403, 0x08ffefd7, 0x03738670, 0x1fbbad6c, 0x0a84f07b, 0x68f6b8}}, - {{0x18712655, 0x063b7c53, 0x042fdfe4, 0x0527a5e6, 0x05028cf5, 0x0226fed2, 0x139bef20, 0x17525c81, 0xcbe1fe}}}, - /* 3*16^56*G: */ - {{{0x1aa89692, 0x00c7d119, 0x1308c239, 0x1611adf2, 0x0a776713, 0x1320920c, 0x1d37a65b, 0x0e302cd1, 0x3bdfca}}, - {{0x1a510308, 0x1ededa18, 0x18bbc4e4, 0x1818c68b, 0x05333c7d, 0x10a8d76d, 0x1ee12509, 0x0d0aca2c, 0xa721f}}}, - /* 5*16^56*G: */ - {{{0x037ea1d7, 0x1cd91a16, 0x06ab9341, 0x126cb1f1, 0x19e4fb23, 0x02a928c6, 0x0158d4ca, 0x12b6ea42, 0xaca8ac}}, - {{0x1ba973a2, 0x0f7d8824, 0x0e4d7a77, 0x1b7fb882, 0x12189e1e, 0x0625c943, 0x108250c1, 0x0cfbaeb9, 0x7f12c5}}}, - /* 7*16^56*G: */ - {{{0x13245b7f, 0x0d93c0e6, 0x165fefd7, 0x1acd2d20, 0x05311a37, 0x10d7cc6c, 0x103881b0, 0x009b6ccf, 0xfa9047}}, - {{0x0ddf6bef, 0x1c19ef8a, 0x13c751fb, 0x1dd9a4c4, 0x1c189cb9, 0x11f6a078, 0x1a90b5be, 0x06ce9506, 0x1a1c8c}}}, - /* 9*16^56*G: */ - {{{0x17f0953a, 0x10fbc7eb, 0x0550e6ad, 0x122907fe, 0x092a8184, 0x1c70e97d, 0x163359ca, 0x15723eaf, 0x1d431a}}, - {{0x1d68f260, 0x1e2cebb4, 0x1c1f9f05, 0x1c535210, 0x1fae0f48, 0x0641e70a, 0x087af14c, 0x1877e322, 0x8d667}}}, - /* 11*16^56*G: */ - {{{0x05227c70, 0x1188b89b, 0x08fa9c16, 0x17d56667, 0x1c60ff32, 0x19ad9718, 0x04df7692, 0x01ab47c2, 0x6deeea}}, - {{0x0369b9b7, 0x0b6d1c08, 0x0420f6eb, 0x15d83cad, 0x0cc84287, 0x05d7f7b5, 0x19000053, 0x01f8e887, 0xcbb93f}}}, - /* 13*16^56*G: */ - {{{0x0421b54d, 0x1afeaf44, 0x159293fe, 0x1657074a, 0x09dca579, 0x0e95d8fd, 0x036352b2, 0x020c6aaf, 0x28135c}}, - {{0x0ee5d868, 0x0e6784dc, 0x18c4362b, 0x09299923, 0x18c15ef0, 0x0eba083f, 0x18541bea, 0x17c70a37, 0x9ed84a}}}, - /* 15*16^56*G: */ - {{{0x08e4ac10, 0x0bf2ac8f, 0x1892a6a4, 0x0d502559, 0x1b568799, 0x062d04ff, 0x1def5b0f, 0x0ec41620, 0x339a05}}, - {{0x0d1312a0, 0x1b6d4322, 0x07319bbd, 0x13cf11e8, 0x1553e503, 0x06fbc567, 0x11fd0e15, 0x17dbad52, 0xca985f}}} - }, - { - /* 1*16^57*G: */ - {{{0x07ea1f34, 0x1a6d58bb, 0x1ce78374, 0x17a6a808, 0x153d6646, 0x0e8bc9d9, 0x0d9b0ed0, 0x1447a8e9, 0x7f9460}}, - {{0x0d9063ec, 0x05f61656, 0x18d3ff16, 0x1f02a249, 0x16661c6f, 0x195fc783, 0x061da7c7, 0x0ef1f60c, 0xd0d516}}}, - /* 3*16^57*G: */ - {{{0x1dfc0a9d, 0x02dba64d, 0x1ddea837, 0x0846b629, 0x0a2a2de4, 0x11b23570, 0x1808a983, 0x1f098653, 0xdb43e7}}, - {{0x1e9ad713, 0x058849d4, 0x14bc153c, 0x1208e6ad, 0x19fa4883, 0x1640a677, 0x1646e295, 0x1457c6d6, 0xb0168d}}}, - /* 5*16^57*G: */ - {{{0x0283808d, 0x05e58bba, 0x190ea24c, 0x1e0f9c6a, 0x078980f8, 0x0f4890fd, 0x06bae145, 0x103dc1a4, 0xe9af30}}, - {{0x19b39d33, 0x13617c71, 0x04db4665, 0x1724a22a, 0x14971976, 0x132a87f7, 0x098216bc, 0x091388e2, 0xa976c8}}}, - /* 7*16^57*G: */ - {{{0x0d8426df, 0x1497a165, 0x1be28289, 0x0272b49c, 0x083590f4, 0x049c1dfc, 0x0601c0eb, 0x0c65900d, 0x6eb733}}, - {{0x000b4267, 0x1fbacf71, 0x1f86e0cf, 0x05d2f907, 0x08e8d925, 0x05967660, 0x0a680c39, 0x1822e60f, 0x96c56e}}}, - /* 9*16^57*G: */ - {{{0x1a16453d, 0x1e8b6be0, 0x040cf6fd, 0x1d0f7cec, 0x0d0e68b7, 0x0dc8fc5a, 0x1d1785d0, 0x0bc0f3ab, 0xd3979d}}, - {{0x07b6d737, 0x1e5dc18b, 0x1a58693c, 0x1becc514, 0x0456917d, 0x092ba9b9, 0x16e69342, 0x06baf335, 0xc55f93}}}, - /* 11*16^57*G: */ - {{{0x0d326504, 0x150ccd2f, 0x0d480b33, 0x15368c4f, 0x0fc12f65, 0x1dc460d7, 0x08d0b0e0, 0x139cb718, 0x54c392}}, - {{0x1ec9e107, 0x1f808fd3, 0x0299c9a2, 0x0a7b3cc1, 0x0ab4447a, 0x1514248a, 0x1b431226, 0x04ac1d42, 0x469630}}}, - /* 13*16^57*G: */ - {{{0x1b5ecce7, 0x0227abb5, 0x03484d4c, 0x102b1618, 0x059c8732, 0x0741e0cb, 0x1b16e13a, 0x1650ccda, 0x3744e9}}, - {{0x0a247721, 0x00990a0b, 0x09be0e48, 0x116be0a5, 0x1ec3c28e, 0x14ab7594, 0x1ea83839, 0x1f1b3208, 0x9546e0}}}, - /* 15*16^57*G: */ - {{{0x05fef996, 0x064946f2, 0x1094d454, 0x0d1ec728, 0x1f2de140, 0x08520f79, 0x154cc933, 0x02fc6cad, 0x11343e}}, - {{0x1792aded, 0x00a8573a, 0x01bc6390, 0x1c9acb41, 0x13765d0c, 0x0fc98313, 0x1bbac137, 0x101bd751, 0x4a9e84}}} - }, - { - /* 1*16^58*G: */ - {{{0x0e6d8483, 0x164da6bc, 0x059fc373, 0x05af508d, 0x0e94582f, 0x1a4f8db7, 0x18f4a563, 0x0c1467aa, 0x9c39cb}}, - {{0x0b2c50fb, 0x0599ab7b, 0x0f90da25, 0x1bca5e7b, 0x16546bba, 0x0b5bde50, 0x14400f46, 0x03dc927c, 0xf097bf}}}, - /* 3*16^58*G: */ - {{{0x07a14dda, 0x0ae18fc2, 0x12d37cfd, 0x1a0852ce, 0x13083606, 0x147b9200, 0x0b5d10dd, 0x19921d5b, 0x18f37a}}, - {{0x05ac8364, 0x117e6e19, 0x014db2f8, 0x11ef8f15, 0x1cd0b77d, 0x1ff6770d, 0x109b5eef, 0x17554125, 0x2f944b}}}, - /* 5*16^58*G: */ - {{{0x0c7d59be, 0x13a74746, 0x024cbed5, 0x1430b11c, 0x0736b98e, 0x1ff723b9, 0x07693b17, 0x118503cf, 0x541335}}, - {{0x04f80590, 0x0bf50fb7, 0x002cd9cb, 0x04b62b92, 0x0515a53e, 0x07e900b2, 0x00939f12, 0x1bd2d396, 0x680fd4}}}, - /* 7*16^58*G: */ - {{{0x076051a8, 0x15c064fc, 0x115fa963, 0x0ee72c74, 0x05280bed, 0x00d1e0dc, 0x13c1773f, 0x04d23632, 0x4e2fd1}}, - {{0x09cc9005, 0x17f63a7f, 0x113f8b9a, 0x11754b25, 0x031bcebb, 0x1ad0a845, 0x0ec8dc6c, 0x1b7ebe9f, 0x122abb}}}, - /* 9*16^58*G: */ - {{{0x16a80e09, 0x13e547d2, 0x097d7f8d, 0x0be1eecc, 0x08fa0a27, 0x1ab409e0, 0x0d648013, 0x1a97dfe3, 0x2de758}}, - {{0x036a1cd3, 0x0b176faa, 0x16b5b267, 0x15b8cd2b, 0x064a07a1, 0x1958132f, 0x199f5f00, 0x062efb1d, 0xdd9acf}}}, - /* 11*16^58*G: */ - {{{0x1a3628ac, 0x1281ad97, 0x16d593b0, 0x177459be, 0x012a4568, 0x10b9e377, 0x095ca316, 0x159b83a9, 0xf597a0}}, - {{0x0cd3550f, 0x1501886b, 0x04841b9f, 0x1d9f23a8, 0x02cc0772, 0x1db944b1, 0x1155eec6, 0x11c6657a, 0xdb916}}}, - /* 13*16^58*G: */ - {{{0x0b75d6c3, 0x06b41ea5, 0x0e8a159e, 0x14a8afaa, 0x040f3c42, 0x038c10df, 0x1ee42284, 0x10dade89, 0xaa222a}}, - {{0x044cb028, 0x1932d273, 0x0a323d84, 0x03f9296b, 0x0df42607, 0x0512d771, 0x19db3912, 0x12600351, 0x563787}}}, - /* 15*16^58*G: */ - {{{0x035790c9, 0x1d42b9c9, 0x1cf140df, 0x03722ee7, 0x15e2e9e0, 0x0321c979, 0x16dd5bc3, 0x0d79b2e2, 0x8568b2}}, - {{0x06b1f5ac, 0x09faa9c1, 0x0151e7f7, 0x0bcbf1f7, 0x03ce8014, 0x0705721b, 0x0ab7a41e, 0x034b09ba, 0xd3f226}}} - }, - { - /* 1*16^59*G: */ - {{{0x1c38d4e4, 0x0ed4be2a, 0x0c5cdd1f, 0x1acbe363, 0x01e25e2f, 0x173a180c, 0x04e25d59, 0x04c22453, 0x3d9285}}, - {{0x00ccf0d3, 0x1d577806, 0x1eaf1fdb, 0x15627032, 0x069eacc0, 0x0b81ae14, 0x0ad4ffc1, 0x14ba8d1d, 0xd32ca0}}}, - /* 3*16^59*G: */ - {{{0x0dd7718a, 0x039192c0, 0x0f9393b4, 0x1036ca33, 0x0dff891c, 0x0cd12f3b, 0x1f0fdf05, 0x06e57205, 0x3b180e}}, - {{0x1afd82db, 0x1331314c, 0x0b45341c, 0x1222ace0, 0x1211e584, 0x1e4e9482, 0x02abea92, 0x02fe6d6b, 0xf2b6b1}}}, - /* 5*16^59*G: */ - {{{0x13d3653d, 0x140d288c, 0x1919f57e, 0x1d8964e9, 0x03eb2134, 0x07a04c54, 0x127d17bd, 0x00723ad3, 0xf352ff}}, - {{0x0a44f28e, 0x0f333c64, 0x1160b41e, 0x132bf2e5, 0x0d5055c1, 0x0b9efed3, 0x1af4082f, 0x0d996d8b, 0x447262}}}, - /* 7*16^59*G: */ - {{{0x0d4478da, 0x130ef8d7, 0x03805535, 0x19ed8448, 0x13ca1f15, 0x02e6dfbc, 0x108c2bed, 0x0e2069b1, 0x670ee4}}, - {{0x14f563f0, 0x147ff27f, 0x1c91dc18, 0x07702c1f, 0x150e81cc, 0x102d89c3, 0x0b289519, 0x084b7404, 0x5ca0c7}}}, - /* 9*16^59*G: */ - {{{0x03dbd581, 0x02714822, 0x15acd6eb, 0x1d671051, 0x06fa93cf, 0x1d185676, 0x0f6fbeef, 0x0a8693b3, 0x96f2e3}}, - {{0x08f59952, 0x0cd27ff7, 0x13d75153, 0x031e3aa0, 0x1baf435a, 0x0c71cb06, 0x1b3d3f97, 0x0110baa4, 0x9fcd8}}}, - /* 11*16^59*G: */ - {{{0x04e9c2fc, 0x159a1925, 0x0f5c1a87, 0x19e19e5f, 0x09a35e72, 0x01058a30, 0x06b20106, 0x0a2fd073, 0xc4946e}}, - {{0x06398ce8, 0x01a3b1bb, 0x1188c48d, 0x17e71da2, 0x18237e48, 0x07b47a3d, 0x0933a668, 0x041630b1, 0x748901}}}, - /* 13*16^59*G: */ - {{{0x04960b03, 0x05c8b9f4, 0x0023a3d7, 0x18756191, 0x14d8fb6a, 0x0462bc04, 0x0f6fe923, 0x09b537c6, 0x1653b6}}, - {{0x10f73c69, 0x00352a75, 0x0d5939fe, 0x11c1c943, 0x1a8948b3, 0x15ec1f4a, 0x15827d2c, 0x102d3cba, 0xa58370}}}, - /* 15*16^59*G: */ - {{{0x1b63640e, 0x0abbf18d, 0x11cb7cb1, 0x176fe521, 0x1cbf4979, 0x13ce5342, 0x14fd4031, 0x1afda5e2, 0x51076d}}, - {{0x02e4476c, 0x1b4b943c, 0x083bc087, 0x1d49d3ce, 0x0fda6c8b, 0x1280b970, 0x1ddabaf9, 0x0945adbb, 0xb39727}}} - }, - { - /* 1*16^60*G: */ - {{{0x044e8de3, 0x0318258d, 0x130781d8, 0x112cd45d, 0x117915c0, 0x1ee7845e, 0x02dce969, 0x16e8d102, 0xf50b99}}, - {{0x1b7f3588, 0x11f9dd36, 0x1c87a152, 0x0be31a42, 0x1cebbe97, 0x0b9d16f6, 0x1c321e26, 0x03cabe31, 0xe2b506}}}, - /* 3*16^60*G: */ - {{{0x02accf8b, 0x0ee35b5c, 0x005be9f7, 0x05332305, 0x1430481d, 0x1871289c, 0x1dc1917c, 0x0c34aa0a, 0x598d7f}}, - {{0x0f6cb808, 0x1c2339e0, 0x0d502e46, 0x11351e6a, 0x1ebcad22, 0x08b15939, 0x182551b1, 0x1ee9f1e4, 0x9f3121}}}, - /* 5*16^60*G: */ - {{{0x04aa7b3e, 0x1d9cd2a3, 0x1b273aa7, 0x09de360a, 0x0581013c, 0x1048aa0e, 0x113593f4, 0x025e93e9, 0x715a20}}, - {{0x1c7d081d, 0x0d19ca25, 0x02d1f436, 0x178b1151, 0x13b62421, 0x1447c548, 0x10287de4, 0x16354c0d, 0x5922b3}}}, - /* 7*16^60*G: */ - {{{0x020db220, 0x0dedb4bb, 0x01eb3934, 0x1996202d, 0x07876c71, 0x0744bfdc, 0x04971027, 0x0bcd5536, 0x49ec8c}}, - {{0x077338c2, 0x0dc56503, 0x0ee733a6, 0x1860e7ca, 0x15429842, 0x061a432f, 0x0a6cf6a7, 0x09fcbd4c, 0x99a97d}}}, - /* 9*16^60*G: */ - {{{0x1e771268, 0x0f5e518a, 0x02995a14, 0x1e294fb2, 0x07b7a2f4, 0x0c8702f0, 0x1120f9bc, 0x01a90a16, 0x1f8fb7}}, - {{0x0909c8dd, 0x17e98086, 0x04aceac6, 0x1a786239, 0x192a14e1, 0x16ba3930, 0x0afc4b0b, 0x1b68c374, 0xf53e7a}}}, - /* 11*16^60*G: */ - {{{0x08d9819e, 0x0f607959, 0x0b6ac695, 0x0cf25ee8, 0x0732cd60, 0x0a15d33c, 0x187f7574, 0x034c92fe, 0xb8d5c7}}, - {{0x09138ac4, 0x03c5f475, 0x15170f37, 0x093e26c3, 0x1dc79e2f, 0x121acdb1, 0x1e08edbb, 0x1e26426f, 0x1cd14e}}}, - /* 13*16^60*G: */ - {{{0x00bca3f3, 0x149edf33, 0x1801241a, 0x0686a28a, 0x0d8c4ecb, 0x15b0e440, 0x18f7758f, 0x158cb755, 0x2265b5}}, - {{0x117409ff, 0x0c14e362, 0x0e4f5689, 0x014c25a4, 0x164983c8, 0x09d1d884, 0x183d868c, 0x17eb959f, 0x97a198}}}, - /* 15*16^60*G: */ - {{{0x05bac36e, 0x19691ffa, 0x1d77340d, 0x11328b32, 0x1abcb599, 0x054fafe4, 0x049487f6, 0x1a206b09, 0xaf381c}}, - {{0x11b119a9, 0x19ec43d5, 0x1352a43f, 0x1705e3de, 0x02648589, 0x1f914a8d, 0x1ef72515, 0x0ff6fbe1, 0x681a08}}} - }, - { - /* 1*16^61*G: */ - {{{0x0037cfb4, 0x10cca02b, 0x136aa167, 0x01e48d87, 0x0b0e0740, 0x1a4406d0, 0x142c35df, 0x1047febd, 0x42531}}, - {{0x18775d23, 0x05b992f6, 0x1b177500, 0x07c9ea69, 0x01faceea, 0x12686433, 0x1df98a32, 0x199f5c01, 0xc90e8b}}}, - /* 3*16^61*G: */ - {{{0x06c34577, 0x027b39aa, 0x094abdde, 0x013d91cd, 0x0e4bde64, 0x11847460, 0x0922c7d7, 0x141c6179, 0x27557a}}, - {{0x0416193c, 0x0ff5cdc0, 0x110e02eb, 0x0594e6e9, 0x134f318a, 0x0bad24fe, 0x0ceddf23, 0x0b08c20b, 0x8399c7}}}, - /* 5*16^61*G: */ - {{{0x0401f4d3, 0x12c7edb5, 0x056cc07b, 0x185ca1d5, 0x1d7decf6, 0x1c1dfab0, 0x0d923941, 0x02fa4b0e, 0x8e6878}}, - {{0x0294d86b, 0x0140f4a2, 0x08644a24, 0x172de25d, 0x13cae900, 0x04d02836, 0x0fe98be0, 0x110dc593, 0x989cab}}}, - /* 7*16^61*G: */ - {{{0x0d2aa8e6, 0x0cb1ef13, 0x1bff8b71, 0x06b3f881, 0x1dbee205, 0x1401e533, 0x13db440d, 0x08c4a7cb, 0x98a417}}, - {{0x006cf75b, 0x0ba05f6b, 0x1fb4865a, 0x042ff556, 0x1cec9e30, 0x017ad17a, 0x0f5ac455, 0x128fc68c, 0x579ac6}}}, - /* 9*16^61*G: */ - {{{0x152c2d31, 0x0516647b, 0x187bb35f, 0x01576118, 0x1a946180, 0x17221f10, 0x03f64885, 0x084460a8, 0xe16854}}, - {{0x04a50fec, 0x05c41b41, 0x0660e507, 0x0c3257f1, 0x1c9343e7, 0x13216815, 0x0850becb, 0x0b9251ce, 0x70085}}}, - /* 11*16^61*G: */ - {{{0x13a7cdad, 0x119dd71b, 0x02f3ebd2, 0x1b07a5ca, 0x151a53ca, 0x117299c4, 0x0fa8728a, 0x09613aa2, 0xbfa631}}, - {{0x095cb953, 0x0fc44981, 0x1011e871, 0x0321f190, 0x0d1a7261, 0x02ddd8f7, 0x11e0a97e, 0x03299005, 0xb452e8}}}, - /* 13*16^61*G: */ - {{{0x0ade0fb7, 0x0de64280, 0x1946363b, 0x1b8e9bd4, 0x18e200c6, 0x0baf36ec, 0x134fb3c2, 0x05a152c3, 0xe68708}}, - {{0x1d4d6ece, 0x0bcf0798, 0x03089664, 0x03d0bdf1, 0x1a72117c, 0x072990e8, 0x1555797c, 0x090d0992, 0x2135a4}}}, - /* 15*16^61*G: */ - {{{0x0e432daf, 0x01e5af86, 0x009eb272, 0x1db41155, 0x14975f3b, 0x146bca83, 0x07a52ff0, 0x1f0c5535, 0x7ab16e}}, - {{0x071bdc48, 0x08bac455, 0x13f6c04c, 0x139c75ce, 0x1a7c5c7e, 0x0c1f146d, 0x02c68d64, 0x0152f865, 0x584e0e}}} - }, - { - /* 1*16^62*G: */ - {{{0x085fbd44, 0x03a3894c, 0x09899eb0, 0x0595473e, 0x1222c89c, 0x18e70b6a, 0x04178151, 0x1b5b356b, 0x9bbf06}}, - {{0x1a1d3e88, 0x1a23efd3, 0x00dbb4a8, 0x097bb82a, 0x147e8c0d, 0x0d798537, 0x028d9d57, 0x1509bc24, 0x1bcc7f}}}, - /* 3*16^62*G: */ - {{{0x14a7b506, 0x1bd73c95, 0x0182f822, 0x0b1775cf, 0x00ee9227, 0x1d9573a8, 0x0f4d0a73, 0x1ecb676b, 0x646ff7}}, - {{0x0b36f946, 0x0bce0929, 0x039a6572, 0x1bf89f81, 0x08fe8492, 0x1198c025, 0x02956987, 0x13a0c943, 0xbc112a}}}, - /* 5*16^62*G: */ - {{{0x0103b553, 0x0a5b8e4e, 0x0e16a005, 0x01d44f06, 0x0507ebe6, 0x0800593f, 0x0e6a7430, 0x0f54c2fa, 0x7cc054}}, - {{0x0d45a526, 0x1cce5d1e, 0x08a2df55, 0x10b41558, 0x094c4001, 0x14659cfe, 0x116af75c, 0x17a46500, 0x7b329e}}}, - /* 7*16^62*G: */ - {{{0x19e717a4, 0x0177a2a0, 0x1c06e06b, 0x1457b559, 0x0e15468d, 0x16a9b6d7, 0x0d38158f, 0x1321783b, 0x946851}}, - {{0x1526dea3, 0x1af87e8d, 0x02b36729, 0x132b21ee, 0x07dc0579, 0x08735933, 0x06a2cee3, 0x0841b8b2, 0xca5c78}}}, - /* 9*16^62*G: */ - {{{0x08362735, 0x1c161b78, 0x0acc9ef7, 0x1166fde2, 0x0d1f5dff, 0x07c75229, 0x03eac496, 0x037cfc1d, 0xe1b98f}}, - {{0x0ecb11b7, 0x0b09c64e, 0x1d0242be, 0x13dc67be, 0x12ba27e1, 0x1a4d41dd, 0x082df816, 0x15b352ed, 0xca83e9}}}, - /* 11*16^62*G: */ - {{{0x19046346, 0x1a05dec1, 0x0510020e, 0x0b1bce60, 0x1962d56a, 0x1035ecb3, 0x1fbdb422, 0x0b91fac0, 0x3536f2}}, - {{0x0c14fea6, 0x0008315e, 0x166cf8a5, 0x187a3d45, 0x1e1c39e6, 0x0b50d294, 0x0279cee8, 0x1c2fbc6a, 0x1e271f}}}, - /* 13*16^62*G: */ - {{{0x0847f6f8, 0x1ffc1f6b, 0x103bd4c3, 0x136a3f7a, 0x18c3c102, 0x08f9a5bf, 0x1379a405, 0x08d7c47a, 0xdf502}}, - {{0x1b1633a6, 0x06654535, 0x17cd126d, 0x1c2ccd13, 0x174ab4c6, 0x1627de10, 0x0728ac8c, 0x0fe53b5e, 0x210704}}}, - /* 15*16^62*G: */ - {{{0x1d4f1b81, 0x02e7576f, 0x1d2ec546, 0x134f4919, 0x09330ad6, 0x11d99b29, 0x0e63da77, 0x1a899ea6, 0xca9dd5}}, - {{0x02b7c8bd, 0x06316572, 0x0b6843e3, 0x12ec17f5, 0x07b3e66c, 0x18fda223, 0x11590091, 0x10ca37c5, 0x6e4b98}}} - }, - { - /* 1*16^63*G: */ - {{{0x044c0448, 0x1569919a, 0x00c678c7, 0x0aed0d82, 0x093e7963, 0x1e659dbc, 0x1e95250f, 0x1ea5287b, 0xb12fad}}, - {{0x1369de57, 0x12baf3b5, 0x1f137ca5, 0x0bce0665, 0x0a6a71d0, 0x07b33bd9, 0x12b3a5be, 0x12b3361e, 0x2e245}}}, - /* 3*16^63*G: */ - {{{0x04e9151f, 0x09b622a3, 0x0361063d, 0x14673390, 0x0fb3e67e, 0x0eed48ec, 0x15a10c95, 0x069e38a0, 0x48388e}}, - {{0x0d7a9434, 0x1f724f6e, 0x17a0c406, 0x028222a7, 0x02bcc99b, 0x19c98aa4, 0x1a79a894, 0x157e9c89, 0xb0ec63}}}, - /* 5*16^63*G: */ - {{{0x0e5b833d, 0x1efda52c, 0x02c90675, 0x1400e794, 0x109c9593, 0x0fc08280, 0x0f697997, 0x08f5c28a, 0xde8e64}}, - {{0x014c5cc7, 0x07e60cd5, 0x0071b27c, 0x1c062652, 0x1e265987, 0x14465eb6, 0x0f638cc8, 0x0782a122, 0x5e146}}}, - /* 7*16^63*G: */ - {{{0x01f7df48, 0x112c9f56, 0x1c4c5ecf, 0x0e8e7d70, 0x0f385b26, 0x0da7272c, 0x1a7a3955, 0x1a149d8f, 0xb18b12}}, - {{0x0846b546, 0x0d9eac87, 0x14795664, 0x07efc907, 0x0c33b3c8, 0x0135e2d6, 0x0d1173b1, 0x04546b3f, 0xff5319}}}, - /* 9*16^63*G: */ - {{{0x19c9fd24, 0x129d6e34, 0x0847837c, 0x1bb1308a, 0x0694402c, 0x05526394, 0x10cf1f07, 0x0e391b92, 0x5f51ad}}, - {{0x0d2ffd3a, 0x01dd7443, 0x092a65a7, 0x03ec488c, 0x04d03872, 0x02fde617, 0x0528334c, 0x023befce, 0x2bbbef}}}, - /* 11*16^63*G: */ - {{{0x17cec42e, 0x1e2031fe, 0x18ef6df8, 0x1b9267dd, 0x0d8556f3, 0x117721a3, 0x1aefe960, 0x1b26e603, 0xfdf340}}, - {{0x0db6908b, 0x07b1a5be, 0x178c320e, 0x1cd57ea1, 0x0d2c4456, 0x0ff39c65, 0x1b875c30, 0x0c72d198, 0xa3e59a}}}, - /* 13*16^63*G: */ - {{{0x01dc4fe8, 0x00c4a2a7, 0x01c9057f, 0x1142752c, 0x1c983f9e, 0x0948bdbe, 0x15e7b191, 0x19173d4b, 0xe3caeb}}, - {{0x1307b403, 0x15b05b90, 0x13e1a845, 0x0006cb42, 0x1f976513, 0x1ae5c580, 0x04a34880, 0x1a4f7e0b, 0x97f093}}}, - /* 15*16^63*G: */ - {{{0x1c119eff, 0x00a6b2e9, 0x07e6e119, 0x005c1815, 0x1a003399, 0x0d2e72c7, 0x16e26bd0, 0x1728550c, 0x3312d}}, - {{0x18b1b950, 0x14ad1d4f, 0x1455617f, 0x18b3b6be, 0x1e86f0ae, 0x1518bc04, 0x137c413b, 0x0c8d66e4, 0x6e3eda}}} - }, diff --git a/deps/crypto/trezor-crypto/options.h b/deps/crypto/trezor-crypto/options.h deleted file mode 100644 index d3a9c2edf..000000000 --- a/deps/crypto/trezor-crypto/options.h +++ /dev/null @@ -1,99 +0,0 @@ -/** - * Copyright (c) 2013-2014 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __OPTIONS_H__ -#define __OPTIONS_H__ - -// use precomputed Curve Points (some scalar multiples of curve base point G) -#ifndef USE_PRECOMPUTED_CP -#define USE_PRECOMPUTED_CP 1 -#endif - -// use fast inverse method -#ifndef USE_INVERSE_FAST -#define USE_INVERSE_FAST 1 -#endif - -// support for printing bignum256 structures via printf -#ifndef USE_BN_PRINT -#define USE_BN_PRINT 0 -#endif - -// use deterministic signatures -#ifndef USE_RFC6979 -#define USE_RFC6979 1 -#endif - -// implement BIP32 caching -#ifndef USE_BIP32_CACHE -#define USE_BIP32_CACHE 1 -#define BIP32_CACHE_SIZE 10 -#define BIP32_CACHE_MAXDEPTH 8 -#endif - -// support constructing BIP32 nodes from ed25519 and curve25519 curves. -#ifndef USE_BIP32_25519_CURVES -#define USE_BIP32_25519_CURVES 1 -#endif - -// implement BIP39 caching -#ifndef USE_BIP39_CACHE -#define USE_BIP39_CACHE 1 -#define BIP39_CACHE_SIZE 4 -#endif - -// support Ethereum operations -#ifndef USE_ETHEREUM -#define USE_ETHEREUM 0 -#endif - -// support Graphene operations (STEEM, BitShares) -#ifndef USE_GRAPHENE -#define USE_GRAPHENE 0 -#endif - -// support NEM operations -#ifndef USE_NEM -#define USE_NEM 0 -#endif - -// support MONERO operations -#ifndef USE_MONERO -#define USE_MONERO 0 -#endif - -// support CARDANO operations -#ifndef USE_CARDANO -#define USE_CARDANO 0 -#endif - -// support Keccak hashing -#ifndef USE_KECCAK -#define USE_KECCAK 1 -#endif - -// add way how to mark confidential data -#ifndef CONFIDENTIAL -#define CONFIDENTIAL -#endif - -#endif diff --git a/deps/crypto/trezor-crypto/pallas.c b/deps/crypto/trezor-crypto/pallas.c deleted file mode 100644 index 1363b9240..000000000 --- a/deps/crypto/trezor-crypto/pallas.c +++ /dev/null @@ -1,809 +0,0 @@ -/** - * Copyright (c) 2025 KeepKey - * - * Pallas elliptic curve used by Zcash Orchard protocol. - * Curve equation: y^2 = x^3 + 5 over Fp - * p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001 - * Generator G = (-1 mod p, 2) - * - * IMPORTANT: The trezor-crypto bignum library assumes primes in the range - * [2^256 - 2^224, 2^256]. The Pallas prime (~2^254) falls outside this range, - * so bn_multiply/bn_inverse/bn_fast_mod produce incorrect results. - * This file implements custom field arithmetic using Barrett reduction - * to correctly handle the Pallas prime. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "pallas.h" - -#include - -#include "blake2b.h" -#include "memzero.h" - -/* bn_multiply_long is defined in bignum.c (non-static) */ -extern void bn_multiply_long(const bignum256 *k, const bignum256 *x, - uint32_t res[2 * 9]); - -#define BN_LIMBS 9 -#define BN_BITS_PER_LIMB 29 -#define BN_LIMB_MASK ((1u << BN_BITS_PER_LIMB) - 1) - -/* ==================================================================== - * Constants - * ==================================================================== */ - -const bignum256 pallas_prime = { - /*.val =*/{0x00000001, 0x09698768, 0x133e46e6, 0x0d31f812, 0x00000224, - 0x00000000, 0x00000000, 0x00000000, 0x00400000}}; - -const bignum256 pallas_order = { - /*.val =*/{0x00000001, 0x02375908, 0x052a3763, 0x0d31f813, 0x00000224, - 0x00000000, 0x00000000, 0x00000000, 0x00400000}}; - -const curve_point pallas_G = { - /*.x =*/{/*.val =*/{0x00000000, 0x09698768, 0x133e46e6, 0x0d31f812, - 0x00000224, 0x00000000, 0x00000000, 0x00000000, - 0x00400000}}, - /*.y =*/{/*.val =*/{0x00000002, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000}}}; - -/* - * Barrett reduction constant for the Pallas prime: - * mu_p = floor(2^510 / p) - */ -static const bignum256 mu_p = { - /*.val =*/{0x1ffffffc, 0x1a59e25f, 0x1306e466, 0x0b381fb5, 0x1ffff76e, - 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x00ffffff}}; - -/* - * Barrett reduction constant for the Pallas order: - * mu_q = floor(2^510 / q) - */ -static const bignum256 mu_q = { - /*.val =*/{0x1ffffffc, 0x17229bdf, 0x0b572273, 0x0b381fb3, 0x1ffff76e, - 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x00ffffff}}; - -/* - * Full ecdsa_curve struct (kept for compatibility, but point_multiply - * from ecdsa.c should NOT be used with Pallas - use pallas_scalar_mult_G). - */ -const ecdsa_curve pallas = { - /* prime */ - {/*.val =*/{0x00000001, 0x09698768, 0x133e46e6, 0x0d31f812, 0x00000224, - 0x00000000, 0x00000000, 0x00000000, 0x00400000}}, - /* G */ - {/*.x =*/{/*.val =*/{0x00000000, 0x09698768, 0x133e46e6, 0x0d31f812, - 0x00000224, 0x00000000, 0x00000000, 0x00000000, - 0x00400000}}, - /*.y =*/{/*.val =*/{0x00000002, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000}}}, - /* order */ - {/*.val =*/{0x00000001, 0x02375908, 0x052a3763, 0x0d31f813, 0x00000224, - 0x00000000, 0x00000000, 0x00000000, 0x00400000}}, - /* order_half */ - {/*.val =*/{0x00000000, 0x111bac84, 0x12951bb1, 0x0698fc09, 0x00000112, - 0x00000000, 0x00000000, 0x00000000, 0x00200000}}, - /* a */ 0, - /* b = 5 */ - {/*.val =*/{5}} -#if USE_PRECOMPUTED_CP - , - {{{{0}}}} -#endif -}; - -/* ==================================================================== - * Barrett Reduction for ~254-bit primes - * - * Given an 18-limb product (up to ~510 bits), reduce mod prime. - * Uses Barrett: q_hat = floor(floor(x / 2^254) * mu / 2^256) - * r = x - q_hat * prime - * while r >= prime: r -= prime - * ==================================================================== */ - -_Static_assert(BN_LIMBS == 9, - "Pallas Barrett helpers require nine 29-bit limbs"); - -/* - * Shift an 18-limb number right by 254 bits. - * 254 = 8*29 + 22, so we skip 8 limbs and shift remaining by 22 bits. - */ -static void shift_right_254(const uint32_t in[18], bignum256 *out) { - for (int i = 0; i < BN_LIMBS; i++) { - uint32_t lo = in[i + 8] >> 22; - uint32_t hi = in[i + 9] << 7; - out->val[i] = (lo | hi) & BN_LIMB_MASK; - } -} - -/* - * Shift an 18-limb number right by 256 bits. - * 256 = 8*29 + 24, so we skip 8 limbs and shift remaining by 24 bits. - */ -static void shift_right_256(const uint32_t in[18], bignum256 *out) { - for (int i = 0; i < BN_LIMBS; i++) { - uint32_t lo = in[i + 8] >> 24; - uint32_t hi = in[i + 9] << 5; - out->val[i] = (lo | hi) & BN_LIMB_MASK; - } -} - -/* - * Compare two bignum256 values (both must be normalized). - * Returns 1 if a >= b, 0 otherwise. - */ -static int bn_gte(const bignum256 *a, const bignum256 *b) { - for (int i = BN_LIMBS - 1; i >= 0; i--) { - if (a->val[i] > b->val[i]) return 1; - if (a->val[i] < b->val[i]) return 0; - } - return 1; /* equal */ -} - -/* - * Subtract b from a, storing result in res. Assumes a >= b. - * All operands must be normalized. - */ -static void bn_sub(const bignum256 *a, const bignum256 *b, bignum256 *res) { - int32_t borrow = 0; - for (int i = 0; i < BN_LIMBS; i++) { - int32_t diff = (int32_t)a->val[i] - (int32_t)b->val[i] + borrow; - if (diff < 0) { - diff += (1 << BN_BITS_PER_LIMB); - borrow = -1; - } else { - borrow = 0; - } - res->val[i] = (uint32_t)diff; - } -} - -/* - * Barrett reduction: reduce an 18-limb product mod a ~254-bit prime. - * - * prime: the modulus (~254-255 bits) - * mu: precomputed floor(2^510 / prime) (~256 bits) - * res[18]: input product (up to ~510 bits) - * out: output, reduced to [0, prime) - */ -static void pallas_barrett_reduce(const uint32_t res[18], - const bignum256 *prime, - const bignum256 *mu, bignum256 *out) { - /* Step 1: q_hat = floor(floor(x / 2^254) * mu / 2^256) */ - bignum256 x_shifted; - shift_right_254(res, &x_shifted); - bn_normalize(&x_shifted); - - uint32_t qmu[18] = {0}; - bn_multiply_long(&x_shifted, mu, qmu); - - bignum256 q_hat; - shift_right_256(qmu, &q_hat); - bn_normalize(&q_hat); - - /* Step 2: r = x - q_hat * prime (low 9 limbs only) */ - uint32_t qp[18] = {0}; - bn_multiply_long(&q_hat, prime, qp); - - /* Compute r = x - q*p using 9 low limbs. - * The true result fits in ~256 bits (< 3*prime). */ - int64_t borrow = 0; - for (int i = 0; i < BN_LIMBS; i++) { - int64_t diff = (int64_t)res[i] - (int64_t)qp[i] + borrow; - out->val[i] = (uint32_t)(diff & BN_LIMB_MASK); - borrow = diff >> BN_BITS_PER_LIMB; - } - bn_normalize(out); - - /* Step 3: while r >= prime, r -= prime (at most 3 times) */ - for (int i = 0; i < 3; i++) { - if (bn_gte(out, prime)) { - bn_sub(out, prime, out); - } - } -} - -/* ==================================================================== - * Pallas Field Arithmetic - * ==================================================================== */ - -/* - * Field multiplication: x = k * x mod pallas_prime - */ -void pallas_mul_mod_p(bignum256 *x, const bignum256 *k) { - uint32_t res[18] = {0}; - bn_multiply_long(k, x, res); - pallas_barrett_reduce(res, &pallas_prime, &mu_p, x); -} - -/* - * Scalar multiplication: x = k * x mod pallas_order - */ -void pallas_mul_mod_q(bignum256 *x, const bignum256 *k) { - uint32_t res[18] = {0}; - bn_multiply_long(k, x, res); - pallas_barrett_reduce(res, &pallas_order, &mu_q, x); -} - -/* - * Field addition: x = (a + b) mod pallas_prime - */ -void pallas_add_mod_p(const bignum256 *a, const bignum256 *b, - bignum256 *res) { - uint32_t carry = 0; - for (int i = 0; i < BN_LIMBS; i++) { - carry += a->val[i] + b->val[i]; - res->val[i] = carry & BN_LIMB_MASK; - carry >>= BN_BITS_PER_LIMB; - } - bn_normalize(res); - if (bn_gte(res, &pallas_prime)) { - bn_sub(res, &pallas_prime, res); - } -} - -/* - * Field subtraction: res = (a - b) mod pallas_prime - */ -void pallas_sub_mod_p(const bignum256 *a, const bignum256 *b, - bignum256 *res) { - if (bn_gte(a, b)) { - bn_sub(a, b, res); - } else { - /* a < b: res = a + prime - b = prime - (b - a) */ - bignum256 tmp; - bn_sub(b, a, &tmp); - bn_sub(&pallas_prime, &tmp, res); - } -} - -/* - * Field inversion: x = x^(-1) mod pallas_prime - * Uses Fermat's little theorem: x^(-1) = x^(p-2) mod p - */ -void pallas_inv_mod_p(bignum256 *x) { - /* Compute e = p - 2 with proper borrow (since p.val[0] = 1 < 2) */ - bignum256 e; - bn_copy(&pallas_prime, &e); - /* val[0] = 1, so 1 - 2 requires borrow from val[1] */ - e.val[0] = e.val[0] + (1u << BN_BITS_PER_LIMB) - 2; /* 1 + 2^29 - 2 = 0x1FFFFFFF */ - e.val[1] -= 1; /* borrow */ - - /* Square-and-multiply: result = x^e mod p */ - bignum256 result; - bn_one(&result); - - bignum256 base; - bn_copy(x, &base); - - /* Process each bit of e from LSB to MSB */ - for (int bit = 0; bit < 255; bit++) { - int limb_idx = bit / BN_BITS_PER_LIMB; - int bit_idx = bit % BN_BITS_PER_LIMB; - - if ((e.val[limb_idx] >> bit_idx) & 1) { - pallas_mul_mod_p(&result, &base); - } - /* Square the base */ - bignum256 tmp; - bn_copy(&base, &tmp); - pallas_mul_mod_p(&base, &tmp); - } - - bn_copy(&result, x); - memzero(&result, sizeof(result)); - memzero(&base, sizeof(base)); -} - -/* - * Simple modular reduction: x = x mod pallas_prime - * For values already < 2^261 (bignum256 range). - */ -void pallas_mod_p(bignum256 *x) { - bn_normalize(x); - while (bn_gte(x, &pallas_prime)) { - bn_sub(x, &pallas_prime, x); - } -} - -/* - * Simple modular reduction: x = x mod pallas_order - * For values already < 2^261 (bignum256 range). - */ -void pallas_mod_q(bignum256 *x) { - bn_normalize(x); - while (bn_gte(x, &pallas_order)) { - bn_sub(x, &pallas_order, x); - } -} - -/* - * Scalar addition: a = (a + b) mod pallas_order - */ -void pallas_add_mod_q(bignum256 *a, const bignum256 *b) { - uint32_t carry = 0; - for (int i = 0; i < BN_LIMBS; i++) { - carry += a->val[i] + b->val[i]; - a->val[i] = carry & BN_LIMB_MASK; - carry >>= BN_BITS_PER_LIMB; - } - pallas_mod_q(a); -} - -/* - * Modular exponentiation: result = base^exp mod pallas_prime - * Uses square-and-multiply (LSB to MSB). - */ -static void pallas_pow_mod_p(const bignum256 *base, const bignum256 *exp, - bignum256 *result) { - bn_zero(result); - result->val[0] = 1; - - bignum256 b; - bn_copy(base, &b); - - for (int bit = 0; bit < 255; bit++) { - int limb_idx = bit / BN_BITS_PER_LIMB; - int bit_idx = bit % BN_BITS_PER_LIMB; - - if ((exp->val[limb_idx] >> bit_idx) & 1) { - pallas_mul_mod_p(result, &b); - } - bignum256 tmp; - bn_copy(&b, &tmp); - pallas_mul_mod_p(&b, &tmp); - } -} - -/* - * Modular square root: n = sqrt(n) mod pallas_prime - * Uses Tonelli-Shanks algorithm (required because p ≡ 1 mod 4). - * - * For Pallas: p - 1 = Q * 2^32 where Q is odd, S = 32. - * - * Returns 0 on success (n modified to sqrt), -1 if n is not a QR. - */ -int pallas_sqrt_mod_p(bignum256 *n) { - if (bn_is_zero(n)) return 0; - - /* p - 1 */ - bignum256 pm1; - bn_copy(&pallas_prime, &pm1); - pm1.val[0]--; - - /* Compute Q = (p-1) >> 32 (where S = 32, p-1 = Q * 2^S, Q odd) */ - /* 32 = 29 + 3, so shift right by 1 limb then 3 bits */ - bignum256 Q; - int i; - for (i = 0; i < 8; i++) Q.val[i] = pm1.val[i + 1]; - Q.val[8] = 0; - for (i = 0; i < 8; i++) { - Q.val[i] = (Q.val[i] >> 3) | ((Q.val[i + 1] & 0x7) << 26); - } - Q.val[8] >>= 3; - - /* (p-1)/2 for Euler criterion (QNR test) */ - bignum256 half_pm1; - bn_copy(&pm1, &half_pm1); - for (i = 0; i < 8; i++) { - half_pm1.val[i] = (half_pm1.val[i] >> 1) | ((half_pm1.val[i + 1] & 0x1) << 28); - } - half_pm1.val[8] >>= 1; - - /* Find a quadratic non-residue z: z^((p-1)/2) ≡ -1 (mod p) */ - bignum256 z, test; - for (uint32_t zi = 2; zi < 100; zi++) { - bn_zero(&z); - z.val[0] = zi; - pallas_pow_mod_p(&z, &half_pm1, &test); - bn_normalize(&test); - if (bn_is_equal(&test, &pm1)) break; - } - - /* Tonelli-Shanks initialization */ - int M = 32; - bignum256 c; - pallas_pow_mod_p(&z, &Q, &c); /* c = z^Q mod p */ - - bignum256 t; - pallas_pow_mod_p(n, &Q, &t); /* t = n^Q mod p */ - - /* (Q+1)/2 */ - bignum256 Q_half; - bn_copy(&Q, &Q_half); - Q_half.val[0]++; /* Q is odd, so Q+1 is even */ - for (i = 0; i < 8; i++) { - Q_half.val[i] = (Q_half.val[i] >> 1) | ((Q_half.val[i + 1] & 0x1) << 28); - } - Q_half.val[8] >>= 1; - - bignum256 R; - pallas_pow_mod_p(n, &Q_half, &R); /* R = n^((Q+1)/2) mod p */ - - bignum256 one; - bn_zero(&one); - one.val[0] = 1; - - /* Main loop */ - for (;;) { - bn_normalize(&t); - if (bn_is_zero(&t)) { - bn_zero(n); - return 0; - } - if (bn_is_equal(&t, &one)) { - bn_copy(&R, n); - return 0; - } - - /* Find least i (1 ≤ i < M) such that t^(2^i) ≡ 1 (mod p) */ - bignum256 tmp; - bn_copy(&t, &tmp); - int ii; - for (ii = 1; ii < M; ii++) { - bignum256 sq; - bn_copy(&tmp, &sq); - pallas_mul_mod_p(&tmp, &sq); /* tmp = tmp^2 */ - bn_normalize(&tmp); - if (bn_is_equal(&tmp, &one)) break; - } - - if (ii >= M) { - return -1; /* n is not a quadratic residue */ - } - - /* b = c^(2^(M-ii-1)) */ - bignum256 b; - bn_copy(&c, &b); - for (int j = 0; j < M - ii - 1; j++) { - bignum256 sq; - bn_copy(&b, &sq); - pallas_mul_mod_p(&b, &sq); /* b = b^2 */ - } - - /* Update M, c, t, R */ - M = ii; - - /* c = b^2 */ - bn_copy(&b, &c); - { - bignum256 sq; - bn_copy(&c, &sq); - pallas_mul_mod_p(&c, &sq); /* c = c^2 = b^2 */ - } - - /* t = t * c (where c = b^2) */ - pallas_mul_mod_p(&t, &c); /* t = c * t = b^2 * t */ - - /* R = R * b */ - pallas_mul_mod_p(&R, &b); /* R = b * R */ - } -} - -/* ==================================================================== - * Pallas Point Operations (affine coordinates) - * ==================================================================== */ - -static int pallas_point_is_infinity(const curve_point *p) { - return bn_is_zero(&p->x) && bn_is_zero(&p->y); -} - -static void pallas_point_set_infinity(curve_point *p) { - bn_zero(&p->x); - bn_zero(&p->y); -} - -/* - * Point doubling: res = 2*P on Pallas curve (y^2 = x^3 + 5, a=0) - * Formula: lambda = 3*x^2 / (2*y) - * xr = lambda^2 - 2*x - * yr = lambda*(x - xr) - y - */ -static void pallas_point_dbl(const curve_point *p, curve_point *res) { - if (pallas_point_is_infinity(p) || bn_is_zero(&p->y)) { - pallas_point_set_infinity(res); - return; - } - - bignum256 lambda, xr, yr, tmp, tmp2; - - /* lambda = 3*x^2 / (2*y) mod p */ - /* Numerator: 3*x^2 */ - bn_copy(&p->x, &tmp); - pallas_mul_mod_p(&tmp, &p->x); /* tmp = x^2 */ - bn_copy(&tmp, &tmp2); - pallas_add_mod_p(&tmp, &tmp2, &lambda); /* lambda = 2*x^2 */ - pallas_add_mod_p(&lambda, &tmp2, &lambda); /* lambda = 3*x^2 */ - - /* Denominator: 2*y */ - pallas_add_mod_p(&p->y, &p->y, &tmp); /* tmp = 2*y */ - - /* Invert denominator */ - pallas_inv_mod_p(&tmp); /* tmp = 1/(2*y) */ - - /* lambda = 3*x^2 * (1/(2*y)) */ - pallas_mul_mod_p(&lambda, &tmp); - - /* xr = lambda^2 - 2*x */ - bn_copy(&lambda, &xr); - pallas_mul_mod_p(&xr, &lambda); /* xr = lambda^2 */ - pallas_add_mod_p(&p->x, &p->x, &tmp); /* tmp = 2*x */ - pallas_sub_mod_p(&xr, &tmp, &xr); /* xr = lambda^2 - 2*x */ - - /* yr = lambda*(x - xr) - y */ - pallas_sub_mod_p(&p->x, &xr, &yr); /* yr = x - xr */ - pallas_mul_mod_p(&yr, &lambda); /* yr = lambda*(x - xr) */ - pallas_sub_mod_p(&yr, &p->y, &yr); /* yr = lambda*(x-xr) - y */ - - bn_copy(&xr, &res->x); - bn_copy(&yr, &res->y); -} - -/* - * Point addition: res = P + Q on Pallas curve - */ -void pallas_point_add(const curve_point *p, const curve_point *q, - curve_point *res) { - if (pallas_point_is_infinity(p)) { - *res = *q; - return; - } - if (pallas_point_is_infinity(q)) { - *res = *p; - return; - } - - /* Check if P == Q (use doubling) */ - bignum256 px_norm, qx_norm, py_norm, qy_norm; - bn_copy(&p->x, &px_norm); - bn_copy(&q->x, &qx_norm); - bn_copy(&p->y, &py_norm); - bn_copy(&q->y, &qy_norm); - bn_normalize(&px_norm); - bn_normalize(&qx_norm); - bn_normalize(&py_norm); - bn_normalize(&qy_norm); - - int x_equal = 1; - for (int i = 0; i < BN_LIMBS; i++) { - if (px_norm.val[i] != qx_norm.val[i]) { x_equal = 0; break; } - } - if (x_equal) { - int y_equal = 1; - for (int i = 0; i < BN_LIMBS; i++) { - if (py_norm.val[i] != qy_norm.val[i]) { y_equal = 0; break; } - } - if (y_equal) { - pallas_point_dbl(p, res); - return; - } - /* P.x == Q.x but P.y != Q.y → P + Q = O (point at infinity) */ - pallas_point_set_infinity(res); - return; - } - - bignum256 lambda, xr, yr, tmp; - - /* lambda = (Q.y - P.y) / (Q.x - P.x) mod p */ - pallas_sub_mod_p(&q->y, &p->y, &lambda); /* num = Q.y - P.y */ - pallas_sub_mod_p(&q->x, &p->x, &tmp); /* den = Q.x - P.x */ - pallas_inv_mod_p(&tmp); /* den = 1/(Q.x - P.x) */ - pallas_mul_mod_p(&lambda, &tmp); /* lambda = num/den */ - - /* xr = lambda^2 - P.x - Q.x */ - bn_copy(&lambda, &xr); - pallas_mul_mod_p(&xr, &lambda); /* xr = lambda^2 */ - pallas_sub_mod_p(&xr, &p->x, &xr); /* xr -= P.x */ - pallas_sub_mod_p(&xr, &q->x, &xr); /* xr -= Q.x */ - - /* yr = lambda*(P.x - xr) - P.y */ - pallas_sub_mod_p(&p->x, &xr, &yr); /* yr = P.x - xr */ - pallas_mul_mod_p(&yr, &lambda); /* yr *= lambda */ - pallas_sub_mod_p(&yr, &p->y, &yr); /* yr -= P.y */ - - bn_copy(&xr, &res->x); - bn_copy(&yr, &res->y); -} - -/* ==================================================================== - * Scalar Multiplication (double-and-add, left-to-right) - * ==================================================================== */ - -/* - * Compute res = k * P on Pallas. - * Uses the double-and-add algorithm. - * k must be in [1, order-1]. - */ -static void pallas_scalar_mult_impl(const bignum256 *k, const curve_point *p, - curve_point *res) { - /* Find the highest set bit */ - int highest_bit = -1; - for (int i = BN_LIMBS - 1; i >= 0; i--) { - if (k->val[i] != 0) { - uint32_t v = k->val[i]; - int bit = BN_BITS_PER_LIMB - 1; - while (bit >= 0 && !((v >> bit) & 1)) bit--; - highest_bit = i * BN_BITS_PER_LIMB + bit; - break; - } - } - - if (highest_bit < 0) { - /* k == 0 */ - pallas_point_set_infinity(res); - return; - } - - /* Initialize res = P (for the highest bit) */ - *res = *p; - - /* Process remaining bits from second-highest down to 0 */ - for (int bit = highest_bit - 1; bit >= 0; bit--) { - /* Double */ - curve_point tmp; - pallas_point_dbl(res, &tmp); - *res = tmp; - - /* Add if bit is set */ - int limb_idx = bit / BN_BITS_PER_LIMB; - int bit_idx = bit % BN_BITS_PER_LIMB; - if ((k->val[limb_idx] >> bit_idx) & 1) { - pallas_point_add(res, p, &tmp); - *res = tmp; - } - } -} - -/* ==================================================================== - * Public API - * ==================================================================== */ - -void pallas_scalar_mult_G(const bignum256 *k, curve_point *res) { - if (bn_is_zero(k)) { - pallas_point_set_infinity(res); - return; - } - pallas_scalar_mult_impl(k, &pallas_G, res); -} - -void pallas_point_mult(const bignum256 *k, const curve_point *p, - curve_point *res) { - if (bn_is_zero(k)) { - pallas_point_set_infinity(res); - return; - } - pallas_scalar_mult_impl(k, p, res); -} - -int pallas_point_is_identity(const curve_point *p) { - if (!p) return 1; - return pallas_point_is_infinity(p); -} - -void pallas_point_encode(const curve_point *p, uint8_t out[32]) { - if (!p || !out) return; - - memset(out, 0, 32); - if (pallas_point_is_infinity(p)) return; - - bignum256 x; - bn_copy(&p->x, &x); - bn_write_le(&x, out); - if (bn_is_odd(&p->y)) { - out[31] |= 0x80; - } - memzero(&x, sizeof(x)); -} - -int pallas_expand_message_xmd_blake2b(const uint8_t *msg, size_t msg_len, - const uint8_t *dst, size_t dst_len, - uint8_t *out, size_t out_len) { - enum { - B_IN_BYTES = 64, - R_IN_BYTES = 128, - }; - - if (!out || out_len == 0 || out_len > 0xffff) return -1; - if ((!msg && msg_len != 0) || (!dst && dst_len != 0)) return -1; - if (dst_len > 255) return -1; - - size_t ell = (out_len + B_IN_BYTES - 1) / B_IN_BYTES; - if (ell == 0 || ell > 255) return -1; - - uint8_t dst_prime[256]; - uint8_t z_pad[R_IN_BYTES] = {0}; - uint8_t b0[B_IN_BYTES]; - uint8_t bi[B_IN_BYTES]; - uint8_t tmp[B_IN_BYTES]; - uint8_t len_bytes[2] = {(uint8_t)(out_len >> 8), (uint8_t)out_len}; - uint8_t zero = 0; - uint8_t personal[16] = {0}; - BLAKE2B_CTX ctx; - - if (dst_len != 0) { - memcpy(dst_prime, dst, dst_len); - } - dst_prime[dst_len] = (uint8_t)dst_len; - size_t dst_prime_len = dst_len + 1; - - if (blake2b_InitPersonal(&ctx, B_IN_BYTES, personal, sizeof(personal)) != 0) { - return -1; - } - blake2b_Update(&ctx, z_pad, sizeof(z_pad)); - blake2b_Update(&ctx, msg, msg_len); - blake2b_Update(&ctx, len_bytes, sizeof(len_bytes)); - blake2b_Update(&ctx, &zero, 1); - blake2b_Update(&ctx, dst_prime, dst_prime_len); - if (blake2b_Final(&ctx, b0, sizeof(b0)) != 0) { - memzero(&ctx, sizeof(ctx)); - return -1; - } - - uint8_t ctr = 1; - if (blake2b_InitPersonal(&ctx, B_IN_BYTES, personal, sizeof(personal)) != 0) { - memzero(&ctx, sizeof(ctx)); - return -1; - } - blake2b_Update(&ctx, b0, sizeof(b0)); - blake2b_Update(&ctx, &ctr, 1); - blake2b_Update(&ctx, dst_prime, dst_prime_len); - if (blake2b_Final(&ctx, bi, sizeof(bi)) != 0) { - memzero(&ctx, sizeof(ctx)); - return -1; - } - - size_t take = out_len < B_IN_BYTES ? out_len : B_IN_BYTES; - memcpy(out, bi, take); - size_t produced = take; - - for (size_t i = 2; i <= ell; i++) { - for (size_t j = 0; j < B_IN_BYTES; j++) { - tmp[j] = b0[j] ^ bi[j]; - } - - ctr = (uint8_t)i; - if (blake2b_InitPersonal(&ctx, B_IN_BYTES, personal, sizeof(personal)) != 0) { - memzero(&ctx, sizeof(ctx)); - return -1; - } - blake2b_Update(&ctx, tmp, sizeof(tmp)); - blake2b_Update(&ctx, &ctr, 1); - blake2b_Update(&ctx, dst_prime, dst_prime_len); - if (blake2b_Final(&ctx, bi, sizeof(bi)) != 0) { - memzero(&ctx, sizeof(ctx)); - return -1; - } - - take = out_len - produced; - if (take > B_IN_BYTES) take = B_IN_BYTES; - memcpy(out + produced, bi, take); - produced += take; - } - - memzero(&ctx, sizeof(ctx)); - memzero(dst_prime, sizeof(dst_prime)); - memzero(b0, sizeof(b0)); - memzero(bi, sizeof(bi)); - memzero(tmp, sizeof(tmp)); - return 0; -} diff --git a/deps/crypto/trezor-crypto/pallas.h b/deps/crypto/trezor-crypto/pallas.h deleted file mode 100644 index a88510d62..000000000 --- a/deps/crypto/trezor-crypto/pallas.h +++ /dev/null @@ -1,112 +0,0 @@ -/** - * Copyright (c) 2025 KeepKey - * - * Pallas elliptic curve for Zcash Orchard. - * y^2 = x^3 + 5 over Fp - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __PALLAS_H__ -#define __PALLAS_H__ - -#include -#include - -#include "bignum.h" -#include "ecdsa.h" - -/* - * The ecdsa_curve struct is kept for compatibility but the generic - * point_multiply()/bn_multiply() must NOT be used with Pallas because - * the trezor-crypto bignum library assumes primes in [2^256 - 2^224, 2^256]. - * Use the pallas_* functions below instead. - */ -extern const ecdsa_curve pallas; - -/* Pallas field prime (~254 bits) */ -extern const bignum256 pallas_prime; - -/* Pallas group order (~254 bits) */ -extern const bignum256 pallas_order; - -/* Pallas generator point G = (-1 mod p, 2) */ -extern const curve_point pallas_G; - -/* expand_message_xmd using BLAKE2b-512, per RFC 9380 §5.3.1. */ -int pallas_expand_message_xmd_blake2b(const uint8_t *msg, size_t msg_len, - const uint8_t *dst, size_t dst_len, - uint8_t *out, size_t out_len); - -/* --- Variable-time public-data arithmetic (Barrett reduction) --- - * - * These compatibility APIs are used by public Orchard group-hash and - * Sinsemilla note-commitment verification. They are not safe for private - * scalars or private field elements; secret-bearing callers must use the - * fixed-schedule pallas_ct.h API instead. */ - -/* x = k * x mod p */ -void pallas_mul_mod_p(bignum256 *x, const bignum256 *k); - -/* x = x mod p (simple reduction for values < 2^261) */ -void pallas_mod_p(bignum256 *x); - -/* x = x^(-1) mod p (Fermat's little theorem) */ -void pallas_inv_mod_p(bignum256 *x); - -/* res = (a + b) mod p */ -void pallas_add_mod_p(const bignum256 *a, const bignum256 *b, bignum256 *res); - -/* res = (a - b) mod p */ -void pallas_sub_mod_p(const bignum256 *a, const bignum256 *b, bignum256 *res); - -/* n = sqrt(n) mod p (Tonelli-Shanks). Returns 0 on success, -1 if no sqrt. */ -int pallas_sqrt_mod_p(bignum256 *n); - -/* --- Variable-time public-data scalar arithmetic mod q --- */ - -/* x = k * x mod q */ -void pallas_mul_mod_q(bignum256 *x, const bignum256 *k); - -/* x = x mod q (simple reduction for values < 2^261) */ -void pallas_mod_q(bignum256 *x); - -/* a = (a + b) mod q */ -void pallas_add_mod_q(bignum256 *a, const bignum256 *b); - -/* --- Variable-time public-data point operations on Pallas curve --- */ - -/* res = k * G */ -void pallas_scalar_mult_G(const bignum256 *k, curve_point *res); - -/* res = k * P */ -void pallas_point_mult(const bignum256 *k, const curve_point *p, - curve_point *res); - -/* res = P + Q */ -void pallas_point_add(const curve_point *p, const curve_point *q, - curve_point *res); - -/* Returns nonzero if P is the point at infinity in this implementation. */ -int pallas_point_is_identity(const curve_point *p); - -/* Serialize Pallas point as LE x-coordinate with y parity in bit 255. */ -void pallas_point_encode(const curve_point *p, uint8_t out[32]); - -#endif diff --git a/deps/crypto/trezor-crypto/pallas_ct.c b/deps/crypto/trezor-crypto/pallas_ct.c deleted file mode 100644 index 4d252abdd..000000000 --- a/deps/crypto/trezor-crypto/pallas_ct.c +++ /dev/null @@ -1,601 +0,0 @@ -/** - * Constant-time Pallas arithmetic for Zcash Orchard secret scalars. - * - * The field representation and Montgomery constants are derived from - * zcash/pasta_curves 0.5.1. Point formulas follow its Jacobian formulas, but - * exceptional cases are computed and selected with masks rather than secret- - * dependent branches. Scalar multiplication always executes 255 rounds and - * computes both the double and add result in every round. - * - * Constant-time here means control flow and memory access do not depend on - * secret scalar or field values. Physical leakage resistance still requires - * inspection of the compiled target and measurement on the device. - * The radix-2^16 multiplier deliberately avoids the Cortex-M3's - * operand-dependent UMULL/UMLAL instructions. - */ - -#include "pallas_ct.h" - -#include -#include -#include - -#include "memzero.h" - -enum { CT_LIMBS = 8 }; - -typedef struct { - uint32_t v[CT_LIMBS]; -} ct_fe; - -typedef struct { - ct_fe x; - ct_fe y; - ct_fe z; -} ct_point; - -typedef struct { - ct_fe modulus; - ct_fe r2; - ct_fe one; -} ct_modulus; - -static const ct_modulus CT_P = { - /* p */ {{0x00000001, 0x992d30ed, 0x094cf91b, 0x224698fc, 0x00000000, - 0x00000000, 0x00000000, 0x40000000}}, - /* R^2 mod p */ - {{0x0000000f, 0x8c78ecb3, 0x8b0de0e7, 0xd7d30dbd, 0xc3c95d18, 0x7797a99b, - 0x7b9cb714, 0x096d41af}}, - /* R mod p */ - {{0xfffffffd, 0x34786d38, 0xe41914ad, 0x992c350b, 0xffffffff, 0xffffffff, - 0xffffffff, 0x3fffffff}}, -}; - -static const ct_modulus CT_Q = { - /* q */ {{0x00000001, 0x8c46eb21, 0x0994a8dd, 0x224698fc, 0x00000000, - 0x00000000, 0x00000000, 0x40000000}}, - /* R^2 mod q */ - {{0x0000000f, 0xfc9678ff, 0x891a16e3, 0x67bb433d, 0x04ccf590, 0x7fae2310, - 0x7ccfdaa9, 0x096d41af}}, - /* R mod q */ - {{0xfffffffd, 0x5b2b3e9c, 0xe3420567, 0x992c350b, 0xffffffff, 0xffffffff, - 0xffffffff, 0x3fffffff}}, -}; - -/* p - 2, in normal little-endian 32-bit limbs. */ -static const uint32_t CT_P_MINUS_2[CT_LIMBS] = { - 0xffffffff, 0x992d30ec, 0x094cf91b, 0x224698fc, - 0x00000000, 0x00000000, 0x00000000, 0x40000000, -}; - -#ifdef PALLAS_CT_TESTING -static pallas_ct_counts ct_counts; -#define CT_COUNT(member) (ct_counts.member++) - -void pallas_ct_test_reset_counts(void) { - memset(&ct_counts, 0, sizeof(ct_counts)); -} - -void pallas_ct_test_get_counts(pallas_ct_counts* counts) { - if (counts != NULL) { - *counts = ct_counts; - } -} -#else -#define CT_COUNT(member) ((void)0) -#endif - -static uint32_t ct_mask(uint32_t choice) { return 0u - (choice & 1u); } - -static uint32_t ct_u32_is_zero(uint32_t value) { - return ((value | (0u - value)) >> 31) ^ 1u; -} - -/* Keep this materialization out of its caller so ARM emits arithmetic rather - * than a secret-conditioned IT block for the zero-nonce normalization. */ -__attribute__((noinline)) static uint32_t ct_secret_u32_is_zero( - uint32_t value) { - return ((value | (0u - value)) >> 31) ^ 1u; -} - -static uint32_t ct_fe_is_zero(const ct_fe* a) { - uint32_t diff = 0; - for (size_t i = 0; i < CT_LIMBS; i++) { - diff |= a->v[i]; - } - return ct_u32_is_zero(diff); -} - -static uint32_t ct_fe_equal(const ct_fe* a, const ct_fe* b) { - uint32_t diff = 0; - for (size_t i = 0; i < CT_LIMBS; i++) { - diff |= a->v[i] ^ b->v[i]; - } - return ct_u32_is_zero(diff); -} - -static void ct_fe_select(ct_fe* out, const ct_fe* a, const ct_fe* b, - uint32_t choice) { - const uint32_t mask = ct_mask(choice); - CT_COUNT(field_select); - for (size_t i = 0; i < CT_LIMBS; i++) { - out->v[i] = (a->v[i] & ~mask) | (b->v[i] & mask); - } -} - -static void ct_point_select(ct_point* out, const ct_point* a, const ct_point* b, - uint32_t choice) { - ct_fe_select(&out->x, &a->x, &b->x, choice); - ct_fe_select(&out->y, &a->y, &b->y, choice); - ct_fe_select(&out->z, &a->z, &b->z, choice); -} - -/* out = a - b. Returns 1 on underflow and 0 otherwise. */ -static uint32_t ct_sub_raw(ct_fe* out, const ct_fe* a, const ct_fe* b) { - uint64_t borrow = 0; - for (size_t i = 0; i < CT_LIMBS; i++) { - const uint64_t diff = (uint64_t)a->v[i] - b->v[i] - borrow; - out->v[i] = (uint32_t)diff; - borrow = diff >> 63; - } - return (uint32_t)borrow; -} - -static void ct_add_raw(ct_fe* out, const ct_fe* a, const ct_fe* b) { - uint64_t carry = 0; - for (size_t i = 0; i < CT_LIMBS; i++) { - const uint64_t sum = (uint64_t)a->v[i] + b->v[i] + carry; - out->v[i] = (uint32_t)sum; - carry = sum >> 32; - } -} - -static void ct_fe_add_mod(ct_fe* out, const ct_fe* a, const ct_fe* b, - const ct_modulus* mod) { - ct_fe sum; - ct_fe reduced; - CT_COUNT(field_add); - ct_add_raw(&sum, a, b); - const uint32_t borrow = ct_sub_raw(&reduced, &sum, &mod->modulus); - ct_fe_select(out, &reduced, &sum, borrow); -} - -static void ct_fe_sub_mod(ct_fe* out, const ct_fe* a, const ct_fe* b, - const ct_modulus* mod) { - ct_fe diff; - ct_fe corrected; - CT_COUNT(field_sub); - const uint32_t borrow = ct_sub_raw(&diff, a, b); - ct_add_raw(&corrected, &diff, &mod->modulus); - ct_fe_select(out, &diff, &corrected, borrow); -} - -/* Return one public-indexed 16-bit half-limb. */ -static uint32_t ct_half_limb(const ct_fe* value, size_t index) { - return (value->v[index / 2] >> ((index & 1u) * 16)) & UINT32_C(0xffff); -} - -/* - * Montgomery multiplication with radix 2^16 and sixteen limbs. - * - * Cortex-M3 UMULL/UMLAL instructions have operand-dependent early - * termination. Using 16-bit limbs keeps each product-plus-carry at or below - * UINT32_MAX, so the compiler can use the fixed-latency 32-bit MUL/MLA path. - * Both Pallas moduli have low half-limb 1, hence -m^-1 mod 2^16 = 0xffff. - * All carry propagation loops have public, fixed bounds. - * Requires a < 2^256 and b < mod. The only unreduced input is paired with a - * reduced Montgomery constant, so one final conditional subtraction suffices. - */ -static void ct_fe_mul_mod(ct_fe* out, const ct_fe* a, const ct_fe* b, - const ct_modulus* mod) { - enum { CT_HALF_LIMBS = 2 * CT_LIMBS }; - uint16_t t[2 * CT_HALF_LIMBS + 1] = {0}; - CT_COUNT(field_mul); - - for (size_t i = 0; i < CT_HALF_LIMBS; i++) { - uint32_t carry = 0; - const uint32_t lhs = ct_half_limb(a, i); - for (size_t j = 0; j < CT_HALF_LIMBS; j++) { - const size_t k = i + j; - const uint32_t accum = lhs * ct_half_limb(b, j) + t[k] + carry; - t[k] = (uint16_t)accum; - carry = accum >> 16; - } - for (size_t k = i + CT_HALF_LIMBS; k <= 2 * CT_HALF_LIMBS; k++) { - const uint32_t accum = (uint32_t)t[k] + carry; - t[k] = (uint16_t)accum; - carry = accum >> 16; - } - } - - for (size_t i = 0; i < CT_HALF_LIMBS; i++) { - const uint32_t factor = (UINT32_C(0x10000) - t[i]) & UINT32_C(0xffff); - uint32_t carry = 0; - for (size_t j = 0; j < CT_HALF_LIMBS; j++) { - const size_t k = i + j; - const uint32_t accum = - factor * ct_half_limb(&mod->modulus, j) + t[k] + carry; - t[k] = (uint16_t)accum; - carry = accum >> 16; - } - for (size_t k = i + CT_HALF_LIMBS; k <= 2 * CT_HALF_LIMBS; k++) { - const uint32_t accum = (uint32_t)t[k] + carry; - t[k] = (uint16_t)accum; - carry = accum >> 16; - } - } - - ct_fe candidate; - ct_fe reduced; - for (size_t i = 0; i < CT_LIMBS; i++) { - candidate.v[i] = (uint32_t)t[2 * (i + CT_LIMBS)] | - (uint32_t)t[2 * (i + CT_LIMBS) + 1] << 16; - } - const uint32_t borrow = ct_sub_raw(&reduced, &candidate, &mod->modulus); - ct_fe_select(out, &reduced, &candidate, borrow); - memzero(t, sizeof(t)); -} - -static void ct_fe_square_mod(ct_fe* out, const ct_fe* a, - const ct_modulus* mod) { - ct_fe_mul_mod(out, a, a, mod); -} - -static void ct_words_from_bn(const bignum256* in, ct_fe* out) { - memset(out, 0, sizeof(*out)); - for (size_t i = 0; i < BN_LIMBS - 1; i++) { - const uint64_t value = in->val[i] & BN_LIMB_MASK; - const size_t bit = i * BN_BITS_PER_LIMB; - const size_t word = bit / 32; - const unsigned shift = bit % 32; - const uint64_t shifted = value << shift; - out->v[word] |= (uint32_t)shifted; - out->v[word + 1] |= (uint32_t)(shifted >> 32); - } - /* A canonical 256-bit bignum uses only the low 24 bits of limb eight. */ - out->v[CT_LIMBS - 1] |= (in->val[BN_LIMBS - 1] & UINT32_C(0x00ffffff)) << 8; -} - -static void ct_words_to_bn(const ct_fe* in, bignum256* out) { - for (size_t i = 0; i < BN_LIMBS; i++) { - const size_t bit = i * BN_BITS_PER_LIMB; - const size_t word = bit / 32; - const unsigned shift = bit % 32; - uint64_t pair = in->v[word]; - if (word + 1 < CT_LIMBS) { - pair |= (uint64_t)in->v[word + 1] << 32; - } - out->val[i] = (uint32_t)(pair >> shift) & BN_LIMB_MASK; - } -} - -static void ct_fe_from_bn(ct_fe* out, const bignum256* in, - const ct_modulus* mod) { - ct_fe words; - ct_words_from_bn(in, &words); - ct_fe_mul_mod(out, &words, &mod->r2, mod); - memzero(&words, sizeof(words)); -} - -static void ct_fe_to_bn(bignum256* out, const ct_fe* in, - const ct_modulus* mod) { - static const ct_fe raw_one = {{1, 0, 0, 0, 0, 0, 0, 0}}; - ct_fe words; - ct_fe_mul_mod(&words, in, &raw_one, mod); - ct_words_to_bn(&words, out); - memzero(&words, sizeof(words)); -} - -static void ct_fe_inv_p(ct_fe* out, const ct_fe* a) { - ct_fe result = CT_P.one; - for (int bit = 254; bit >= 0; bit--) { - ct_fe squared; - ct_fe multiplied; - const uint32_t exponent_bit = - (CT_P_MINUS_2[(unsigned)bit / 32] >> ((unsigned)bit % 32)) & 1u; - ct_fe_square_mod(&squared, &result, &CT_P); - ct_fe_mul_mod(&multiplied, &squared, a, &CT_P); - ct_fe_select(&result, &squared, &multiplied, exponent_bit); - } - *out = result; -} - -static void ct_point_identity(ct_point* p) { - memset(p, 0, sizeof(*p)); - p->y = CT_P.one; -} - -static uint32_t ct_point_is_identity(const ct_point* p) { - return ct_fe_is_zero(&p->z); -} - -static void ct_point_from_affine(ct_point* out, const curve_point* in) { - ct_fe_from_bn(&out->x, &in->x, &CT_P); - ct_fe_from_bn(&out->y, &in->y, &CT_P); - const uint32_t identity = ct_fe_is_zero(&out->x) & ct_fe_is_zero(&out->y); - ct_fe zero = {{0}}; - ct_fe_select(&out->z, &CT_P.one, &zero, identity); -} - -static void ct_point_to_affine(curve_point* out, const ct_point* in) { - const uint32_t identity = ct_point_is_identity(in); - ct_fe z_inv; - ct_fe z2; - ct_fe z3; - ct_fe x; - ct_fe y; - ct_fe zero = {{0}}; - - ct_fe_inv_p(&z_inv, &in->z); - ct_fe_square_mod(&z2, &z_inv, &CT_P); - ct_fe_mul_mod(&z3, &z2, &z_inv, &CT_P); - ct_fe_mul_mod(&x, &in->x, &z2, &CT_P); - ct_fe_mul_mod(&y, &in->y, &z3, &CT_P); - ct_fe_select(&x, &x, &zero, identity); - ct_fe_select(&y, &y, &zero, identity); - ct_fe_to_bn(&out->x, &x, &CT_P); - ct_fe_to_bn(&out->y, &y, &CT_P); - - memzero(&z_inv, sizeof(z_inv)); - memzero(&z2, sizeof(z2)); - memzero(&z3, sizeof(z3)); - memzero(&x, sizeof(x)); - memzero(&y, sizeof(y)); -} - -/* Jacobian doubling for y^2 = x^3 + 5 (dbl-2009-l). */ -static void ct_point_double(ct_point* out, const ct_point* p) { - ct_fe a, b, c, d, e, f, t0, t1; - ct_point result; - ct_point identity; - CT_COUNT(point_double); - - ct_fe_square_mod(&a, &p->x, &CT_P); - ct_fe_square_mod(&b, &p->y, &CT_P); - ct_fe_square_mod(&c, &b, &CT_P); - ct_fe_add_mod(&t0, &p->x, &b, &CT_P); - ct_fe_square_mod(&d, &t0, &CT_P); - ct_fe_sub_mod(&d, &d, &a, &CT_P); - ct_fe_sub_mod(&d, &d, &c, &CT_P); - ct_fe_add_mod(&d, &d, &d, &CT_P); - ct_fe_add_mod(&e, &a, &a, &CT_P); - ct_fe_add_mod(&e, &e, &a, &CT_P); - ct_fe_square_mod(&f, &e, &CT_P); - ct_fe_mul_mod(&t0, &p->z, &p->y, &CT_P); - ct_fe_add_mod(&result.z, &t0, &t0, &CT_P); - ct_fe_add_mod(&t0, &d, &d, &CT_P); - ct_fe_sub_mod(&result.x, &f, &t0, &CT_P); - ct_fe_sub_mod(&t0, &d, &result.x, &CT_P); - ct_fe_mul_mod(&t1, &e, &t0, &CT_P); - ct_fe_add_mod(&t0, &c, &c, &CT_P); - ct_fe_add_mod(&t0, &t0, &t0, &CT_P); - ct_fe_add_mod(&t0, &t0, &t0, &CT_P); - ct_fe_sub_mod(&result.y, &t1, &t0, &CT_P); - - ct_point_identity(&identity); - ct_point_select(out, &result, &identity, ct_point_is_identity(p)); -} - -/* - * Complete-by-selection Jacobian addition. The generic formula, doubling, - * opposite-point result, and identity cases are all computed before masks - * select the correct result. - */ -static void ct_point_add_internal(ct_point* out, const ct_point* p, - const ct_point* q) { - ct_fe z1z1, z2z2, u1, u2, s1, s2, h, i, j, r, v, t0, t1; - ct_point generic; - ct_point doubled; - ct_point identity; - CT_COUNT(point_add); - - ct_fe_square_mod(&z1z1, &p->z, &CT_P); - ct_fe_square_mod(&z2z2, &q->z, &CT_P); - ct_fe_mul_mod(&u1, &p->x, &z2z2, &CT_P); - ct_fe_mul_mod(&u2, &q->x, &z1z1, &CT_P); - ct_fe_mul_mod(&t0, &z2z2, &q->z, &CT_P); - ct_fe_mul_mod(&s1, &p->y, &t0, &CT_P); - ct_fe_mul_mod(&t0, &z1z1, &p->z, &CT_P); - ct_fe_mul_mod(&s2, &q->y, &t0, &CT_P); - - ct_fe_sub_mod(&h, &u2, &u1, &CT_P); - ct_fe_add_mod(&t0, &h, &h, &CT_P); - ct_fe_square_mod(&i, &t0, &CT_P); - ct_fe_mul_mod(&j, &h, &i, &CT_P); - ct_fe_sub_mod(&r, &s2, &s1, &CT_P); - ct_fe_add_mod(&r, &r, &r, &CT_P); - ct_fe_mul_mod(&v, &u1, &i, &CT_P); - ct_fe_square_mod(&generic.x, &r, &CT_P); - ct_fe_sub_mod(&generic.x, &generic.x, &j, &CT_P); - ct_fe_sub_mod(&generic.x, &generic.x, &v, &CT_P); - ct_fe_sub_mod(&generic.x, &generic.x, &v, &CT_P); - ct_fe_sub_mod(&t0, &v, &generic.x, &CT_P); - ct_fe_mul_mod(&t0, &r, &t0, &CT_P); - ct_fe_mul_mod(&t1, &s1, &j, &CT_P); - ct_fe_add_mod(&t1, &t1, &t1, &CT_P); - ct_fe_sub_mod(&generic.y, &t0, &t1, &CT_P); - ct_fe_add_mod(&t0, &p->z, &q->z, &CT_P); - ct_fe_square_mod(&generic.z, &t0, &CT_P); - ct_fe_sub_mod(&generic.z, &generic.z, &z1z1, &CT_P); - ct_fe_sub_mod(&generic.z, &generic.z, &z2z2, &CT_P); - ct_fe_mul_mod(&generic.z, &generic.z, &h, &CT_P); - - ct_point_double(&doubled, p); - ct_point_identity(&identity); - - const uint32_t p_identity = ct_point_is_identity(p); - const uint32_t q_identity = ct_point_is_identity(q); - const uint32_t same_x = ct_fe_equal(&u1, &u2); - const uint32_t same_y = ct_fe_equal(&s1, &s2); - const uint32_t neither_identity = (p_identity | q_identity) ^ 1u; - const uint32_t same = same_x & same_y & neither_identity; - const uint32_t opposite = same_x & (same_y ^ 1u) & neither_identity; - - *out = generic; - ct_point_select(out, out, &doubled, same); - ct_point_select(out, out, &identity, opposite); - ct_point_select(out, out, q, p_identity); - ct_point_select(out, out, p, q_identity); -} - -void pallas_ct_point_mult(const bignum256* k, const curve_point* p, - curve_point* res) { - ct_fe scalar_mont; - ct_fe scalar; - ct_point base; - ct_point acc; - static const ct_fe raw_one = {{1, 0, 0, 0, 0, 0, 0, 0}}; - - /* Canonicalize k modulo the Pallas group order without a data branch. */ - ct_fe_from_bn(&scalar_mont, k, &CT_Q); - ct_fe_mul_mod(&scalar, &scalar_mont, &raw_one, &CT_Q); - ct_point_from_affine(&base, p); - ct_point_identity(&acc); - - for (int bit = 254; bit >= 0; bit--) { - ct_point doubled; - ct_point added; - const uint32_t scalar_bit = - (scalar.v[(unsigned)bit / 32] >> ((unsigned)bit % 32)) & 1u; - CT_COUNT(scalar_round); - ct_point_double(&doubled, &acc); - ct_point_add_internal(&added, &doubled, &base); - ct_point_select(&acc, &doubled, &added, scalar_bit); - } - - ct_point_to_affine(res, &acc); - memzero(&scalar_mont, sizeof(scalar_mont)); - memzero(&scalar, sizeof(scalar)); - memzero(&base, sizeof(base)); - memzero(&acc, sizeof(acc)); -} - -void pallas_ct_point_mult_progress(const bignum256* k, const curve_point* p, - curve_point* res, - pallas_ct_progress_callback progress, - void* progress_context) { - ct_fe scalar_mont; - ct_fe scalar; - ct_point base; - ct_point acc; - static const ct_fe raw_one = {{1, 0, 0, 0, 0, 0, 0, 0}}; - - /* This is deliberately the same fixed schedule as pallas_ct_point_mult(). - * The callback runs once after every round and receives only public loop - * counters, so OLED refreshes cannot disclose scalar bits. */ - ct_fe_from_bn(&scalar_mont, k, &CT_Q); - ct_fe_mul_mod(&scalar, &scalar_mont, &raw_one, &CT_Q); - ct_point_from_affine(&base, p); - ct_point_identity(&acc); - - for (int bit = 254; bit >= 0; bit--) { - ct_point doubled; - ct_point added; - const uint32_t scalar_bit = - (scalar.v[(unsigned)bit / 32] >> ((unsigned)bit % 32)) & 1u; - CT_COUNT(scalar_round); - ct_point_double(&doubled, &acc); - ct_point_add_internal(&added, &doubled, &base); - ct_point_select(&acc, &doubled, &added, scalar_bit); - progress((uint32_t)(255 - bit), 255, progress_context); - } - - ct_point_to_affine(res, &acc); - memzero(&scalar_mont, sizeof(scalar_mont)); - memzero(&scalar, sizeof(scalar)); - memzero(&base, sizeof(base)); - memzero(&acc, sizeof(acc)); -} - -void pallas_ct_point_add(const curve_point* p, const curve_point* q, - curve_point* res) { - ct_point lhs; - ct_point rhs; - ct_point sum; - ct_point_from_affine(&lhs, p); - ct_point_from_affine(&rhs, q); - ct_point_add_internal(&sum, &lhs, &rhs); - ct_point_to_affine(res, &sum); - memzero(&lhs, sizeof(lhs)); - memzero(&rhs, sizeof(rhs)); - memzero(&sum, sizeof(sum)); -} - -void pallas_ct_mul_mod_p(bignum256* x, const bignum256* k) { - ct_fe lhs, rhs, result; - ct_fe_from_bn(&lhs, x, &CT_P); - ct_fe_from_bn(&rhs, k, &CT_P); - ct_fe_mul_mod(&result, &lhs, &rhs, &CT_P); - ct_fe_to_bn(x, &result, &CT_P); - memzero(&lhs, sizeof(lhs)); - memzero(&rhs, sizeof(rhs)); - memzero(&result, sizeof(result)); -} - -void pallas_ct_add_mod_p(const bignum256* a, const bignum256* b, - bignum256* res) { - ct_fe lhs, rhs, result; - ct_fe_from_bn(&lhs, a, &CT_P); - ct_fe_from_bn(&rhs, b, &CT_P); - ct_fe_add_mod(&result, &lhs, &rhs, &CT_P); - ct_fe_to_bn(res, &result, &CT_P); -} - -void pallas_ct_sub_mod_p(const bignum256* a, const bignum256* b, - bignum256* res) { - ct_fe lhs, rhs, result; - ct_fe_from_bn(&lhs, a, &CT_P); - ct_fe_from_bn(&rhs, b, &CT_P); - ct_fe_sub_mod(&result, &lhs, &rhs, &CT_P); - ct_fe_to_bn(res, &result, &CT_P); -} - -void pallas_ct_inv_mod_p(bignum256* x) { - ct_fe value, inverse; - ct_fe_from_bn(&value, x, &CT_P); - ct_fe_inv_p(&inverse, &value); - ct_fe_to_bn(x, &inverse, &CT_P); - memzero(&value, sizeof(value)); - memzero(&inverse, sizeof(inverse)); -} - -void pallas_ct_mod_p(bignum256* x) { - ct_fe value; - ct_fe_from_bn(&value, x, &CT_P); - ct_fe_to_bn(x, &value, &CT_P); - memzero(&value, sizeof(value)); -} - -void pallas_ct_mul_mod_q(bignum256* x, const bignum256* k) { - ct_fe lhs, rhs, result; - ct_fe_from_bn(&lhs, x, &CT_Q); - ct_fe_from_bn(&rhs, k, &CT_Q); - ct_fe_mul_mod(&result, &lhs, &rhs, &CT_Q); - ct_fe_to_bn(x, &result, &CT_Q); - memzero(&lhs, sizeof(lhs)); - memzero(&rhs, sizeof(rhs)); - memzero(&result, sizeof(result)); -} - -void pallas_ct_add_mod_q(bignum256* a, const bignum256* b) { - ct_fe lhs, rhs, result; - ct_fe_from_bn(&lhs, a, &CT_Q); - ct_fe_from_bn(&rhs, b, &CT_Q); - ct_fe_add_mod(&result, &lhs, &rhs, &CT_Q); - ct_fe_to_bn(a, &result, &CT_Q); -} - -void pallas_ct_mod_q(bignum256* x) { - ct_fe value; - ct_fe_from_bn(&value, x, &CT_Q); - ct_fe_to_bn(x, &value, &CT_Q); - memzero(&value, sizeof(value)); -} - -void pallas_ct_scalar_replace_zero_with_one(bignum256* scalar) { - uint32_t nonzero = 0; - for (size_t i = 0; i < BN_LIMBS; i++) { - nonzero |= scalar->val[i]; - } - scalar->val[0] |= ct_secret_u32_is_zero(nonzero); -} diff --git a/deps/crypto/trezor-crypto/pallas_ct.h b/deps/crypto/trezor-crypto/pallas_ct.h deleted file mode 100644 index 6b9de542b..000000000 --- a/deps/crypto/trezor-crypto/pallas_ct.h +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Constant-time Pallas arithmetic for secret-scalar operations. - * - * This module intentionally has a narrow interface matching the legacy Pallas - * API types. Internally it uses fixed-width Montgomery arithmetic and - * branchless Jacobian point operations. It must be used for every operation - * whose inputs include Orchard secret scalars. - */ - -#ifndef __PALLAS_CT_H__ -#define __PALLAS_CT_H__ - -#include "bignum.h" -#include "ecdsa.h" - -/* Progress is reported from the fixed 255-round scalar schedule. Both values - * are public loop counters; callbacks must not inspect scalar data. */ -typedef void (*pallas_ct_progress_callback)(uint32_t completed, uint32_t total, - void* context); - -void pallas_ct_mul_mod_p(bignum256* x, const bignum256* k); -void pallas_ct_add_mod_p(const bignum256* a, const bignum256* b, - bignum256* res); -void pallas_ct_sub_mod_p(const bignum256* a, const bignum256* b, - bignum256* res); -void pallas_ct_inv_mod_p(bignum256* x); -void pallas_ct_mod_p(bignum256* x); - -void pallas_ct_mul_mod_q(bignum256* x, const bignum256* k); -void pallas_ct_add_mod_q(bignum256* a, const bignum256* b); -void pallas_ct_mod_q(bignum256* x); -void pallas_ct_scalar_replace_zero_with_one(bignum256* scalar); - -void pallas_ct_point_add(const curve_point* p, const curve_point* q, - curve_point* res); -void pallas_ct_point_mult(const bignum256* k, const curve_point* p, - curve_point* res); -void pallas_ct_point_mult_progress(const bignum256* k, const curve_point* p, - curve_point* res, - pallas_ct_progress_callback progress, - void* progress_context); - -#ifdef PALLAS_CT_TESTING -typedef struct { - uint32_t field_add; - uint32_t field_sub; - uint32_t field_mul; - uint32_t field_select; - uint32_t point_add; - uint32_t point_double; - uint32_t scalar_round; -} pallas_ct_counts; - -void pallas_ct_test_reset_counts(void); -void pallas_ct_test_get_counts(pallas_ct_counts* counts); -#endif - -#endif diff --git a/deps/crypto/trezor-crypto/pallas_sinsemilla.c b/deps/crypto/trezor-crypto/pallas_sinsemilla.c deleted file mode 100644 index 0ae8fffa5..000000000 --- a/deps/crypto/trezor-crypto/pallas_sinsemilla.c +++ /dev/null @@ -1,351 +0,0 @@ -/** - * Copyright (c) 2026 KeepKey - * - * Minimal Sinsemilla short-commit implementation for Orchard IVK derivation. - * - * This intentionally implements only: - * Commit^ivk.Output = SinsemillaShortCommit( - * "z.cash:Orchard-CommitIvk", ak || nk, rivk) - * - * S generators are derived on demand with the upstream - * "z.cash:SinsemillaS" hash-to-curve personalization. This keeps firmware - * ROM usage low by avoiding the 64 KiB precomputed generator table. - */ - -#include "pallas_sinsemilla.h" - -#include -#include - -#include "bignum.h" -#include "memzero.h" -#include "pallas.h" -#include "pallas_ct.h" -#include "pallas_swu.h" - -static const uint8_t COMMIT_IVK_Q_X[32] = { - 0xf2, 0x82, 0x0f, 0x79, 0x92, 0x2f, 0xcb, 0x6b, 0x32, 0xa2, 0x28, - 0x51, 0x24, 0xcc, 0x1b, 0x42, 0xfa, 0x41, 0xa2, 0x5a, 0xb8, 0x81, - 0xcc, 0x7d, 0x11, 0xc8, 0xa9, 0x4a, 0xf1, 0x0c, 0xbc, 0x05, -}; - -static const uint8_t COMMIT_IVK_Q_Y[32] = { - 0xbe, 0xde, 0xad, 0xcf, 0xce, 0xe5, 0x5a, 0xbe, 0xf1, 0xa5, 0x6d, - 0xc9, 0x1d, 0x35, 0xc4, 0x46, 0x4b, 0x05, 0xde, 0x20, 0x46, 0x07, - 0x59, 0xef, 0xe6, 0xbe, 0x1a, 0xd4, 0xf6, 0x4c, 0x01, 0x1b, -}; - -static const uint8_t COMMIT_IVK_R_X[32] = { - 0x18, 0xa1, 0xf8, 0x5f, 0x6e, 0x48, 0x23, 0x98, 0xc7, 0xed, 0x1a, - 0xd3, 0xe2, 0x7f, 0x95, 0x02, 0x48, 0x89, 0x80, 0x40, 0x0a, 0x29, - 0x34, 0x16, 0x4e, 0x13, 0x70, 0x50, 0xcd, 0x2c, 0xa2, 0x25, -}; - -static const uint8_t COMMIT_IVK_R_Y[32] = { - 0xa9, 0xdd, 0x7f, 0xe3, 0xb3, 0x93, 0xe7, 0x3f, 0xc7, 0xa6, 0x58, - 0x1b, 0xfb, 0x42, 0x44, 0x6b, 0x94, 0x57, 0x4b, 0x28, 0xc4, 0x90, - 0xc8, 0xc2, 0xeb, 0xfa, 0xa2, 0x66, 0x99, 0xd2, 0xcf, 0x29, -}; - -static void point_from_xy_le(const uint8_t x[32], const uint8_t y[32], - curve_point* out) { - bn_read_le(x, &out->x); - bn_read_le(y, &out->y); - bn_normalize(&out->x); - bn_normalize(&out->y); -} - -static int read_base_field(const uint8_t in[32], bignum256* out) { - if (!in || !out) return -1; - bn_read_le(in, out); - bn_normalize(out); - return bn_is_less(out, &pallas_prime) ? 0 : -1; -} - -static int read_scalar_field(const uint8_t in[32], bignum256* out) { - if (!in || !out) return -1; - bn_read_le(in, out); - bn_normalize(out); - return bn_is_less(out, &pallas_order) ? 0 : -1; -} - -static int points_same_x(const curve_point* a, const curve_point* b) { - bignum256 ax, bx; - bn_copy(&a->x, &ax); - bn_copy(&b->x, &bx); - bn_normalize(&ax); - bn_normalize(&bx); - int same = bn_is_equal(&ax, &bx); - memzero(&ax, sizeof(ax)); - memzero(&bx, sizeof(bx)); - return same; -} - -static int sinsemilla_incomplete_add(const curve_point* a, const curve_point* b, - curve_point* out) { - if (!a || !b || !out) return -1; - if (pallas_point_is_identity(a) || pallas_point_is_identity(b)) return -1; - if (points_same_x(a, b)) return -1; - - pallas_point_add(a, b, out); - return 0; -} - -static int bit_from_msg(const uint8_t* msg, size_t bit) { - return (msg[bit / 8] >> (bit % 8)) & 1; -} - -static uint32_t sinsemilla_word(const uint8_t* msg, size_t msg_bits, - size_t word_idx) { - uint32_t word = 0; - for (size_t i = 0; i < PALLAS_SINSEMILLA_K; i++) { - size_t bit = word_idx * PALLAS_SINSEMILLA_K + i; - if (bit < msg_bits && bit_from_msg(msg, bit)) { - word |= (uint32_t)1 << i; - } - } - return word; -} - -static int sinsemilla_s_generator(uint32_t word, curve_point* out) { - static const char domain[] = "z.cash:SinsemillaS"; - uint8_t word_le[4] = { - (uint8_t)(word & 0xff), - (uint8_t)((word >> 8) & 0xff), - (uint8_t)((word >> 16) & 0xff), - (uint8_t)((word >> 24) & 0xff), - }; - int ret = pallas_hash_to_curve(domain, word_le, sizeof(word_le), out); - memzero(word_le, sizeof(word_le)); - return ret; -} - -static void set_msg_bit(uint8_t* msg, size_t bit) { - msg[bit / 8] |= (uint8_t)(1u << (bit % 8)); -} - -static void pack_commit_ivk_msg(const uint8_t ak[32], const uint8_t nk[32], - uint8_t msg[64]) { - memset(msg, 0, 64); - for (size_t bit = 0; bit < 255; bit++) { - if (bit_from_msg(ak, bit)) { - set_msg_bit(msg, bit); - } - if (bit_from_msg(nk, bit)) { - set_msg_bit(msg, 255 + bit); - } - } -} - -int pallas_sinsemilla_hash_to_point_progress( - const curve_point* q, const uint8_t* msg, size_t msg_bits, curve_point* out, - PallasSinsemillaProgressCallback progress, void* progress_context) { - if (!q || (!msg && msg_bits != 0) || !out) return -1; - if (msg_bits > PALLAS_SINSEMILLA_MAX_BITS) return -1; - if (pallas_point_is_identity(q)) return -1; - - curve_point acc = *q; - size_t word_count = - (msg_bits + PALLAS_SINSEMILLA_K - 1) / PALLAS_SINSEMILLA_K; - - for (size_t i = 0; i < word_count; i++) { - uint32_t word = sinsemilla_word(msg, msg_bits, i); - curve_point s, old_acc, tmp; - if (sinsemilla_s_generator(word, &s) != 0) { - memzero(&acc, sizeof(acc)); - return -1; - } - old_acc = acc; - - if (sinsemilla_incomplete_add(&old_acc, &s, &tmp) != 0 || - sinsemilla_incomplete_add(&tmp, &old_acc, &acc) != 0) { - memzero(&acc, sizeof(acc)); - memzero(&s, sizeof(s)); - memzero(&old_acc, sizeof(old_acc)); - memzero(&tmp, sizeof(tmp)); - return -1; - } - - memzero(&s, sizeof(s)); - memzero(&old_acc, sizeof(old_acc)); - memzero(&tmp, sizeof(tmp)); - - if (progress) { - progress((uint32_t)(i + 1), (uint32_t)word_count, progress_context); - } - } - - *out = acc; - memzero(&acc, sizeof(acc)); - return 0; -} - -int pallas_sinsemilla_hash_to_point(const curve_point* q, const uint8_t* msg, - size_t msg_bits, curve_point* out) { - return pallas_sinsemilla_hash_to_point_progress(q, msg, msg_bits, out, NULL, - NULL); -} - -int pallas_sinsemilla_hash(const curve_point* q, const uint8_t* msg, - size_t msg_bits, uint8_t hash_out[32]) { - if (!hash_out) return -1; - - curve_point hash_point; - if (pallas_sinsemilla_hash_to_point(q, msg, msg_bits, &hash_point) != 0) { - return -1; - } - - bignum256 x; - bn_copy(&hash_point.x, &x); - bn_write_le(&x, hash_out); - - memzero(&hash_point, sizeof(hash_point)); - memzero(&x, sizeof(x)); - return 0; -} - -static int pallas_sinsemilla_commit_prepare( - const curve_point* q, const curve_point* r, const uint8_t* msg, - size_t msg_bits, const uint8_t blind[32], bignum256* blind_scalar, - curve_point* hash_point, PallasSinsemillaProgressCallback progress, - void* progress_context) { - if (!r || !blind || !blind_scalar || !hash_point) return -1; - if (pallas_point_is_identity(r)) return -1; - - if (read_scalar_field(blind, blind_scalar) != 0) { - memzero(blind_scalar, sizeof(*blind_scalar)); - return -1; - } - - if (pallas_sinsemilla_hash_to_point_progress( - q, msg, msg_bits, hash_point, progress, progress_context) != 0) { - memzero(blind_scalar, sizeof(*blind_scalar)); - return -1; - } - return 0; -} - -int pallas_sinsemilla_commit_progress(const curve_point* q, - const curve_point* r, const uint8_t* msg, - size_t msg_bits, const uint8_t blind[32], - curve_point* out, - PallasSinsemillaProgressCallback progress, - void* progress_context) { - if (!out) return -1; - - bignum256 blind_scalar; - curve_point hash_point, blind_point, commit; - if (pallas_sinsemilla_commit_prepare(q, r, msg, msg_bits, blind, - &blind_scalar, &hash_point, progress, - progress_context) != 0) { - return -1; - } - - /* This generic API is used to verify transaction note commitments. Its - * rcm is derived from host-supplied rseed/rho and is public PCZT data. */ - pallas_point_mult(&blind_scalar, r, &blind_point); - pallas_point_add(&hash_point, &blind_point, &commit); - *out = commit; - - memzero(&blind_scalar, sizeof(blind_scalar)); - memzero(&hash_point, sizeof(hash_point)); - memzero(&blind_point, sizeof(blind_point)); - memzero(&commit, sizeof(commit)); - return 0; -} - -int pallas_sinsemilla_commit(const curve_point* q, const curve_point* r, - const uint8_t* msg, size_t msg_bits, - const uint8_t blind[32], curve_point* out) { - return pallas_sinsemilla_commit_progress(q, r, msg, msg_bits, blind, out, - NULL, NULL); -} - -static int pallas_sinsemilla_commit_secret_blind( - const curve_point* q, const curve_point* r, const uint8_t* msg, - size_t msg_bits, const uint8_t blind[32], curve_point* out) { - if (!out) return -1; - - bignum256 blind_scalar; - curve_point hash_point, blind_point, commit; - if (pallas_sinsemilla_commit_prepare(q, r, msg, msg_bits, blind, - &blind_scalar, &hash_point, NULL, - NULL) != 0) { - return -1; - } - - /* rivk is device-secret during IVK derivation. */ - pallas_ct_point_mult(&blind_scalar, r, &blind_point); - pallas_ct_point_add(&hash_point, &blind_point, &commit); - *out = commit; - - memzero(&blind_scalar, sizeof(blind_scalar)); - memzero(&hash_point, sizeof(hash_point)); - memzero(&blind_point, sizeof(blind_point)); - memzero(&commit, sizeof(commit)); - return 0; -} - -int pallas_sinsemilla_short_commit_progress( - const curve_point* q, const curve_point* r, const uint8_t* msg, - size_t msg_bits, const uint8_t blind[32], uint8_t out[32], - PallasSinsemillaProgressCallback progress, void* progress_context) { - if (!out) return -1; - - curve_point commit; - if (pallas_sinsemilla_commit_progress(q, r, msg, msg_bits, blind, &commit, - progress, progress_context) != 0) { - return -1; - } - - bignum256 x; - bn_copy(&commit.x, &x); - bn_write_le(&x, out); - - memzero(&commit, sizeof(commit)); - memzero(&x, sizeof(x)); - return 0; -} - -int pallas_sinsemilla_short_commit(const curve_point* q, const curve_point* r, - const uint8_t* msg, size_t msg_bits, - const uint8_t blind[32], uint8_t out[32]) { - return pallas_sinsemilla_short_commit_progress(q, r, msg, msg_bits, blind, - out, NULL, NULL); -} - -int pallas_sinsemilla_commit_ivk(const uint8_t ak[32], const uint8_t nk[32], - const uint8_t rivk[32], uint8_t ivk_out[32]) { - if (!ak || !nk || !rivk || !ivk_out) return -1; - - bignum256 ak_field, nk_field; - if (read_base_field(ak, &ak_field) != 0 || - read_base_field(nk, &nk_field) != 0) { - memzero(&ak_field, sizeof(ak_field)); - memzero(&nk_field, sizeof(nk_field)); - return -1; - } - - uint8_t msg[64]; - curve_point q, r; - pack_commit_ivk_msg(ak, nk, msg); - point_from_xy_le(COMMIT_IVK_Q_X, COMMIT_IVK_Q_Y, &q); - point_from_xy_le(COMMIT_IVK_R_X, COMMIT_IVK_R_Y, &r); - curve_point commit; - int ret = - pallas_sinsemilla_commit_secret_blind(&q, &r, msg, 510, rivk, &commit); - if (ret == 0) { - bignum256 x; - bn_copy(&commit.x, &x); - bn_write_le(&x, ivk_out); - memzero(&x, sizeof(x)); - } - - memzero(&ak_field, sizeof(ak_field)); - memzero(&nk_field, sizeof(nk_field)); - memzero(msg, sizeof(msg)); - memzero(&q, sizeof(q)); - memzero(&r, sizeof(r)); - memzero(&commit, sizeof(commit)); - return ret; -} diff --git a/deps/crypto/trezor-crypto/pallas_sinsemilla.h b/deps/crypto/trezor-crypto/pallas_sinsemilla.h deleted file mode 100644 index 4548a837b..000000000 --- a/deps/crypto/trezor-crypto/pallas_sinsemilla.h +++ /dev/null @@ -1,85 +0,0 @@ -/** - * Copyright (c) 2026 KeepKey - * - * Minimal Sinsemilla primitives needed for Zcash Orchard key derivation. - */ - -#ifndef __PALLAS_SINSEMILLA_H__ -#define __PALLAS_SINSEMILLA_H__ - -#include -#include - -#include "ecdsa.h" - -#define PALLAS_SINSEMILLA_K 10 -#define PALLAS_SINSEMILLA_C 253 -#define PALLAS_SINSEMILLA_MAX_BITS (PALLAS_SINSEMILLA_K * PALLAS_SINSEMILLA_C) - -/* Progress depends only on the public message length and loop index. */ -typedef void (*PallasSinsemillaProgressCallback)(uint32_t completed, - uint32_t total, void* context); - -/* - * Compute SinsemillaHashToPoint(Q, msg). - * - * msg is a packed little-endian bit string: bit i is read from - * msg[i / 8] >> (i % 8). msg_bits must be <= PALLAS_SINSEMILLA_MAX_BITS. - */ -int pallas_sinsemilla_hash_to_point(const curve_point* q, const uint8_t* msg, - size_t msg_bits, curve_point* out); - -/* Progress-reporting form for interactive verification of public PCZT data. */ -int pallas_sinsemilla_hash_to_point_progress( - const curve_point* q, const uint8_t* msg, size_t msg_bits, curve_point* out, - PallasSinsemillaProgressCallback progress, void* progress_context); - -/* - * Compute SinsemillaHash(Q, msg), returning the little-endian Pallas base-field - * x-coordinate extracted from SinsemillaHashToPoint. - */ -int pallas_sinsemilla_hash(const curve_point* q, const uint8_t* msg, - size_t msg_bits, uint8_t hash_out[32]); - -/* - * Compute SinsemillaCommit(Q, R, msg, r). - * - * blind is a canonical Pallas scalar-field encoding and must be public - * transaction data. Secret rivk commitments use the dedicated IVK API below. - */ -int pallas_sinsemilla_commit(const curve_point* q, const curve_point* r, - const uint8_t* msg, size_t msg_bits, - const uint8_t blind[32], curve_point* out); - -int pallas_sinsemilla_commit_progress(const curve_point* q, - const curve_point* r, const uint8_t* msg, - size_t msg_bits, const uint8_t blind[32], - curve_point* out, - PallasSinsemillaProgressCallback progress, - void* progress_context); - -/* - * Compute SinsemillaShortCommit(Q, R, msg, r), returning the little-endian - * Pallas base-field x-coordinate extracted from SinsemillaCommit. - */ -int pallas_sinsemilla_short_commit(const curve_point* q, const curve_point* r, - const uint8_t* msg, size_t msg_bits, - const uint8_t blind[32], uint8_t out[32]); - -int pallas_sinsemilla_short_commit_progress( - const curve_point* q, const curve_point* r, const uint8_t* msg, - size_t msg_bits, const uint8_t blind[32], uint8_t out[32], - PallasSinsemillaProgressCallback progress, void* progress_context); - -/* - * Compute Commit^ivk.Output = SinsemillaShortCommit( - * "z.cash:Orchard-CommitIvk", I2LEBSP_255(ak) || I2LEBSP_255(nk), rivk) - * - * ak and nk are canonical Pallas base-field encodings. rivk is a canonical - * Pallas scalar-field encoding. ivk_out receives the 32-byte LE Pallas - * base-field output; callers must reject zero where required by Orchard IVKs. - */ -int pallas_sinsemilla_commit_ivk(const uint8_t ak[32], const uint8_t nk[32], - const uint8_t rivk[32], uint8_t ivk_out[32]); - -#endif diff --git a/deps/crypto/trezor-crypto/pallas_sinsemilla_table.inc b/deps/crypto/trezor-crypto/pallas_sinsemilla_table.inc deleted file mode 100644 index a7085bfc9..000000000 --- a/deps/crypto/trezor-crypto/pallas_sinsemilla_table.inc +++ /dev/null @@ -1,1026 +0,0 @@ -static const uint8_t SINSEMILLA_S_BYTES[1024][2][32] = { - {{0x5f, 0xea, 0x44, 0x20, 0x91, 0xeb, 0x91, 0x5a, 0xb5, 0x62, 0xde, 0xbe, 0xaf, 0x5b, 0xa0, 0x29, 0x7b, 0xfc, 0x4a, 0x7d, 0xea, 0xd4, 0x31, 0x14, 0x0f, 0x1f, 0x88, 0xe6, 0x8b, 0x21, 0xb5, 0x0d}, {0x83, 0x64, 0x8e, 0xbf, 0x76, 0x4f, 0xc2, 0x17, 0x01, 0xba, 0x65, 0x2e, 0x1c, 0x04, 0x4a, 0x94, 0xd0, 0xd5, 0x93, 0x84, 0x29, 0x66, 0xaf, 0x9c, 0x1c, 0xa0, 0x52, 0xf1, 0xc2, 0x40, 0x0f, 0x2f}}, - {{0x91, 0xaf, 0x08, 0xa1, 0x3e, 0xe3, 0x4a, 0xce, 0x8f, 0x9b, 0x64, 0x24, 0xca, 0x00, 0x77, 0xe6, 0x04, 0x54, 0x17, 0x39, 0xeb, 0x33, 0xfd, 0xc8, 0x18, 0x95, 0xe1, 0xb3, 0xb4, 0x12, 0x11, 0x21}, {0xee, 0xc5, 0x10, 0xf8, 0x93, 0xc2, 0x83, 0x1d, 0xbc, 0x19, 0x0e, 0x67, 0x4a, 0x74, 0x3c, 0xb4, 0xfe, 0x35, 0x5a, 0xcd, 0x79, 0x3e, 0x8a, 0xa3, 0x3b, 0xb0, 0xad, 0x93, 0x39, 0x99, 0xc5, 0x06}}, - {{0x24, 0x6d, 0x8f, 0xa1, 0x75, 0xc4, 0xe0, 0x22, 0xc0, 0x11, 0x54, 0x4b, 0x33, 0xb3, 0x0c, 0xf4, 0x33, 0x9b, 0x5b, 0x35, 0xe2, 0xa4, 0x61, 0x46, 0xa3, 0x25, 0xf9, 0x49, 0xcd, 0x2c, 0xb3, 0x25}, {0x57, 0x97, 0xfd, 0xb8, 0x8d, 0x6b, 0x7d, 0xa6, 0xd2, 0xcc, 0x45, 0xf9, 0xb9, 0xeb, 0xe1, 0x4b, 0x11, 0x47, 0xb4, 0x23, 0xf3, 0xd0, 0x53, 0x7d, 0x2c, 0x69, 0xd0, 0x70, 0xba, 0xf2, 0x0f, 0x14}}, - {{0xbc, 0xda, 0x19, 0x04, 0x0f, 0xef, 0xfa, 0xa5, 0x26, 0x18, 0x8b, 0x93, 0x12, 0xca, 0x39, 0x65, 0x1f, 0x70, 0x2c, 0xd0, 0x5c, 0x46, 0xff, 0x60, 0xc9, 0x32, 0x18, 0xe1, 0x48, 0x5a, 0x21, 0x14}, {0xdc, 0x36, 0xca, 0x25, 0x36, 0x5d, 0x1d, 0x01, 0x56, 0xad, 0xe2, 0x53, 0x4b, 0x3b, 0xb6, 0x97, 0xbd, 0x03, 0x58, 0x0b, 0xb9, 0xa0, 0x11, 0xc7, 0x4d, 0x88, 0xcb, 0xbe, 0x57, 0x69, 0x66, 0x10}}, - {{0x36, 0x09, 0xed, 0x4b, 0xf6, 0xce, 0x48, 0xcd, 0xce, 0x61, 0x38, 0xf7, 0x52, 0x8b, 0x94, 0x0e, 0x9f, 0x05, 0x3f, 0xd2, 0x95, 0xb5, 0xb9, 0x9a, 0x1c, 0x15, 0x63, 0x9e, 0x3b, 0xf9, 0x5c, 0x31}, {0x1a, 0x72, 0x1c, 0xa3, 0x84, 0x76, 0x57, 0xe2, 0x1d, 0xa5, 0x70, 0xc0, 0x86, 0x13, 0xef, 0x81, 0xca, 0x78, 0x43, 0xd0, 0x52, 0x9a, 0xfb, 0x2a, 0x40, 0xad, 0xfb, 0x8d, 0xb3, 0xc0, 0x54, 0x2c}}, - {{0xdf, 0x3f, 0x5a, 0xaa, 0x62, 0x96, 0x62, 0x1e, 0x9b, 0x38, 0x31, 0x9d, 0xdc, 0x57, 0xfb, 0x94, 0xb7, 0x3a, 0x6c, 0xbe, 0x2e, 0x54, 0xc5, 0x63, 0xc5, 0x5e, 0x92, 0x7e, 0xa5, 0x51, 0x74, 0x1d}, {0x4b, 0x45, 0xca, 0xaa, 0xc8, 0x1d, 0x4c, 0x93, 0xdd, 0xc0, 0xef, 0x4e, 0x8c, 0x04, 0x86, 0xc0, 0xbc, 0x6f, 0x4b, 0x16, 0x72, 0x14, 0x9c, 0xc4, 0xc7, 0x7e, 0x47, 0x93, 0x39, 0x51, 0x4b, 0x0a}}, - {{0x8f, 0x11, 0x44, 0xac, 0xbd, 0xce, 0x7c, 0x7e, 0x1c, 0xff, 0x29, 0x84, 0x2f, 0x27, 0x55, 0xe0, 0x24, 0x5f, 0xa7, 0x24, 0xf8, 0xb5, 0x80, 0x3c, 0x68, 0x46, 0xd4, 0x10, 0x74, 0x3c, 0x3d, 0x0d}, {0xcc, 0x55, 0x22, 0xb5, 0x1b, 0xb2, 0xea, 0x79, 0x82, 0x09, 0x4f, 0xde, 0xc0, 0x61, 0x68, 0x12, 0xe9, 0x5a, 0xa5, 0x23, 0x86, 0x31, 0x2e, 0xa0, 0x4f, 0x33, 0x58, 0x97, 0x12, 0xe7, 0x94, 0x2b}}, - {{0x2f, 0x9d, 0x12, 0xd7, 0x3e, 0x38, 0x77, 0x0e, 0x18, 0x9b, 0x0f, 0x4b, 0x71, 0xdf, 0x83, 0x62, 0x2c, 0x06, 0x66, 0xd6, 0x7c, 0x61, 0x64, 0x08, 0x57, 0x0b, 0x91, 0x74, 0xba, 0xfa, 0x7e, 0x19}, {0x27, 0xc1, 0xfd, 0x12, 0xcb, 0xe2, 0xb8, 0x85, 0xcd, 0x45, 0x27, 0xde, 0xb5, 0x75, 0x88, 0x7a, 0x1b, 0xd3, 0x99, 0xed, 0x97, 0x6a, 0xf5, 0x8d, 0xa9, 0x56, 0xe9, 0xd6, 0x47, 0x55, 0xd9, 0x34}}, - {{0x55, 0xb0, 0x24, 0x6b, 0x92, 0xd2, 0x1c, 0xd2, 0x8e, 0x41, 0x46, 0x72, 0x07, 0x7a, 0x16, 0xa4, 0x47, 0x9b, 0x54, 0xef, 0xab, 0x11, 0x29, 0x3e, 0x66, 0xee, 0x1c, 0xb1, 0xe8, 0xd0, 0x5a, 0x30}, {0x38, 0xb9, 0xbf, 0xa5, 0xcf, 0x73, 0x39, 0x9b, 0xd6, 0x80, 0x38, 0xd1, 0xa5, 0x0c, 0xa2, 0x12, 0xa4, 0x34, 0xb7, 0xc3, 0x42, 0x12, 0x07, 0x82, 0xd8, 0xbf, 0xbb, 0x6d, 0x02, 0x91, 0x25, 0x3e}}, - {{0xbe, 0x56, 0x48, 0x6b, 0x62, 0xe3, 0xbc, 0xf6, 0x84, 0x34, 0x66, 0x5b, 0xf1, 0xe6, 0x5e, 0xdf, 0x61, 0x3e, 0x66, 0x47, 0xf1, 0xbd, 0x37, 0xbc, 0x1f, 0x77, 0xcc, 0xae, 0x20, 0xed, 0x80, 0x2a}, {0x53, 0xd7, 0xd9, 0x40, 0xcd, 0x58, 0xaf, 0xae, 0xeb, 0x44, 0xa9, 0x39, 0xa1, 0x81, 0x76, 0x67, 0xae, 0xd1, 0x80, 0xd0, 0x20, 0x42, 0x78, 0xdb, 0x73, 0xc8, 0x89, 0x2f, 0x53, 0x9f, 0xed, 0x3b}}, - {{0x34, 0x3b, 0xe7, 0x69, 0x1c, 0x35, 0x6d, 0xa9, 0x32, 0xb4, 0x74, 0xbb, 0x2c, 0xe6, 0xdf, 0xe5, 0x09, 0x39, 0x63, 0xc5, 0x86, 0xf8, 0x0b, 0x3e, 0x52, 0x0f, 0x6b, 0x51, 0x9d, 0x67, 0x69, 0x11}, {0xee, 0x52, 0x56, 0x3a, 0x48, 0x26, 0x7f, 0x44, 0x12, 0x39, 0xe8, 0xaf, 0xb3, 0x03, 0xd8, 0x77, 0xd3, 0x4f, 0x8f, 0x98, 0x79, 0xa7, 0x1e, 0xbe, 0x5d, 0xf8, 0xef, 0x46, 0xd8, 0x58, 0xdc, 0x24}}, - {{0x30, 0x50, 0x87, 0xbc, 0x2e, 0xc6, 0x1d, 0x85, 0x65, 0x57, 0x3c, 0x70, 0x0c, 0x51, 0x57, 0x19, 0x92, 0xc9, 0xae, 0x3a, 0xe8, 0x8d, 0x39, 0xd4, 0xcb, 0xd1, 0xe0, 0xe0, 0x64, 0x51, 0x64, 0x0a}, {0x6d, 0x93, 0xa6, 0x1a, 0x4c, 0x49, 0x68, 0xd7, 0xa4, 0xc2, 0x48, 0xa5, 0xee, 0xd7, 0x89, 0x0c, 0xb1, 0x76, 0x78, 0x99, 0xb7, 0x87, 0x1f, 0x7e, 0x82, 0xf1, 0x79, 0x38, 0x3d, 0xb6, 0x3f, 0x15}}, - {{0x39, 0x34, 0xa8, 0x42, 0x19, 0x06, 0x65, 0xc5, 0xf2, 0x3d, 0x3a, 0x19, 0x7c, 0xf5, 0x16, 0x77, 0x0a, 0xea, 0x7a, 0x8d, 0xe1, 0xb0, 0x25, 0x13, 0x01, 0x76, 0x8b, 0xa6, 0x53, 0x17, 0xa9, 0x05}, {0x3c, 0xd4, 0xbd, 0x26, 0x16, 0x23, 0x43, 0x24, 0x5f, 0x57, 0xf2, 0xa3, 0x64, 0xe7, 0x9f, 0x95, 0x4e, 0x14, 0x99, 0x97, 0x40, 0x6a, 0x09, 0xd7, 0x08, 0x95, 0x7e, 0x34, 0x30, 0xc6, 0x29, 0x1c}}, - {{0x2a, 0xe7, 0x11, 0x14, 0x46, 0x6f, 0x43, 0xe8, 0x59, 0x2a, 0x49, 0x72, 0x34, 0x40, 0x1a, 0x2c, 0x91, 0xb6, 0x8a, 0x93, 0x8d, 0x0a, 0x47, 0x13, 0x44, 0x35, 0xc9, 0xce, 0xb5, 0x34, 0xe3, 0x25}, {0x3d, 0x4b, 0xad, 0x9c, 0x33, 0xd2, 0xc5, 0xce, 0xab, 0x45, 0xcc, 0xa4, 0x61, 0x07, 0x0d, 0xa4, 0xb2, 0x84, 0x80, 0x2d, 0x50, 0xd2, 0x4c, 0x19, 0x74, 0x24, 0x59, 0x61, 0xdb, 0x64, 0x60, 0x01}}, - {{0xc9, 0x5c, 0x37, 0x25, 0xb5, 0x65, 0xf0, 0xe2, 0xab, 0x25, 0x88, 0x8c, 0x87, 0x59, 0x28, 0x25, 0x66, 0x6a, 0x9d, 0xbc, 0xc1, 0x31, 0x52, 0x92, 0x7e, 0x9c, 0x90, 0xc1, 0xd0, 0x2b, 0x9c, 0x37}, {0x30, 0x94, 0x75, 0x63, 0xa7, 0xef, 0xfb, 0xa0, 0xf0, 0x83, 0x73, 0x7b, 0x41, 0x1e, 0x0e, 0x43, 0x40, 0x6e, 0xf3, 0x66, 0x3a, 0x12, 0xea, 0xdd, 0x1b, 0x9f, 0xd5, 0x99, 0x54, 0xc2, 0xa9, 0x11}}, - {{0xaa, 0xed, 0x2e, 0x86, 0x1e, 0x9e, 0x5a, 0x0b, 0xc6, 0x61, 0xff, 0x61, 0x82, 0x43, 0xa3, 0xc0, 0xa1, 0xf3, 0x01, 0x48, 0xdc, 0xf6, 0x41, 0x4b, 0x82, 0x6f, 0x65, 0xd3, 0xb2, 0xc7, 0x6f, 0x0c}, {0xb5, 0x3b, 0x60, 0x3e, 0xe8, 0x50, 0x0d, 0xf3, 0x5f, 0x8e, 0x54, 0x7d, 0x78, 0xb4, 0x9f, 0x58, 0xeb, 0x0e, 0xea, 0xd1, 0x32, 0xb0, 0xd5, 0x06, 0x8e, 0xfe, 0xdc, 0x96, 0x6d, 0xa7, 0x92, 0x24}}, - {{0xd9, 0xe5, 0x4f, 0x3a, 0x69, 0x4d, 0x19, 0x07, 0x22, 0x70, 0xed, 0x5c, 0xd6, 0xce, 0xf4, 0xc3, 0xb7, 0xe6, 0xee, 0xf9, 0xc3, 0xc5, 0x65, 0x19, 0x04, 0x0e, 0xb5, 0x3b, 0x45, 0x5d, 0x17, 0x0c}, {0x9a, 0x97, 0xa8, 0x02, 0x5c, 0xe6, 0x28, 0x6e, 0xc2, 0x1e, 0x3a, 0x21, 0xb2, 0xbd, 0x55, 0x91, 0x8a, 0xa0, 0x1b, 0xac, 0xd2, 0x5d, 0x92, 0xa5, 0x90, 0x29, 0x01, 0x2d, 0x4f, 0x3d, 0x6e, 0x10}}, - {{0x0a, 0x6d, 0x8f, 0x71, 0x69, 0x57, 0xf5, 0x2a, 0x80, 0x9c, 0x3d, 0xdb, 0x35, 0x01, 0xcc, 0x0a, 0x05, 0x5e, 0x13, 0x93, 0x95, 0x9d, 0xf8, 0x31, 0x55, 0xb1, 0xed, 0x20, 0xe3, 0xea, 0xe5, 0x26}, {0xc9, 0xd1, 0x5f, 0xb9, 0xee, 0xfd, 0x5b, 0xd7, 0x74, 0x53, 0x8c, 0x81, 0x0a, 0xa8, 0x63, 0x1e, 0x40, 0xc0, 0x0b, 0x0f, 0xe6, 0xc3, 0xb1, 0x4b, 0x0c, 0x4b, 0x14, 0xcd, 0x2a, 0x88, 0x05, 0x1d}}, - {{0x94, 0x5b, 0x39, 0x5e, 0xf2, 0x90, 0xc3, 0x7e, 0x49, 0xa5, 0x8f, 0xc6, 0x55, 0x07, 0x30, 0x42, 0x07, 0x04, 0x81, 0xaf, 0x33, 0x97, 0x10, 0x92, 0xd9, 0x00, 0xeb, 0x14, 0xd7, 0x60, 0x0d, 0x31}, {0x0a, 0x65, 0x10, 0x44, 0xcb, 0x43, 0x04, 0xce, 0x43, 0xef, 0x00, 0xf9, 0x53, 0x40, 0xc0, 0xb1, 0xdd, 0x1f, 0x12, 0x93, 0xa3, 0xe7, 0x87, 0x40, 0x5c, 0xec, 0xce, 0xcd, 0x9e, 0x55, 0xe2, 0x3e}}, - {{0x43, 0xeb, 0x09, 0xc7, 0xbb, 0xb2, 0xa0, 0xa2, 0x24, 0x06, 0x18, 0xbf, 0xea, 0x17, 0xde, 0x8a, 0x87, 0x81, 0xac, 0x1e, 0xe5, 0xce, 0x3d, 0xbe, 0x8d, 0xac, 0xec, 0x09, 0x81, 0x04, 0x19, 0x17}, {0x5b, 0xa0, 0x15, 0xcc, 0x3a, 0x97, 0xbc, 0x2a, 0x3a, 0x19, 0x0a, 0x57, 0x0b, 0xdf, 0xa8, 0x50, 0x44, 0x1d, 0x0e, 0x4f, 0x98, 0xe0, 0xf1, 0x87, 0xc5, 0xf8, 0xfe, 0xb9, 0xc5, 0x3a, 0x67, 0x12}}, - {{0x69, 0x33, 0x58, 0x6d, 0xfe, 0xd0, 0x61, 0xb4, 0x87, 0x92, 0x82, 0xc9, 0x0f, 0x11, 0xbc, 0xcc, 0xf0, 0xa5, 0x26, 0x26, 0x47, 0xda, 0x63, 0x02, 0xc6, 0x19, 0x37, 0x9c, 0x22, 0xd2, 0x89, 0x12}, {0x12, 0x62, 0x69, 0xf8, 0x09, 0xd1, 0x84, 0x7f, 0x7e, 0xf3, 0xc9, 0x60, 0x35, 0x84, 0xb6, 0xe7, 0xaa, 0xb9, 0xa3, 0xa8, 0xa3, 0x26, 0xab, 0xc9, 0x44, 0x1e, 0xad, 0xd4, 0xe9, 0xe5, 0xa7, 0x08}}, - {{0xfb, 0xcf, 0xa6, 0x67, 0x0e, 0xd7, 0x57, 0xd6, 0x63, 0xd6, 0xd8, 0xf5, 0x7a, 0x8f, 0xc2, 0x1b, 0xdd, 0xac, 0x2e, 0x5e, 0x97, 0xcb, 0x6c, 0x17, 0x2a, 0x22, 0x1c, 0xa9, 0xf1, 0x48, 0xdc, 0x08}, {0x8c, 0x12, 0xb6, 0x40, 0xeb, 0x0c, 0xaa, 0xc6, 0x17, 0xa2, 0x70, 0xc2, 0xe5, 0x9e, 0xa1, 0x94, 0x3a, 0x08, 0xf4, 0xa1, 0x14, 0xf1, 0x79, 0x9f, 0xd0, 0xb3, 0x55, 0xaa, 0x41, 0x09, 0xf4, 0x21}}, - {{0xc1, 0xc2, 0x13, 0x71, 0x03, 0xe7, 0xc6, 0x84, 0x21, 0xf5, 0x2c, 0x5e, 0x9a, 0x5a, 0x49, 0x95, 0x5e, 0xb8, 0xc8, 0x1b, 0xa2, 0xc0, 0x9d, 0xae, 0x02, 0x2d, 0x7f, 0x25, 0x09, 0x78, 0xde, 0x2b}, {0xf9, 0xd2, 0x4e, 0x31, 0xa6, 0xc0, 0x14, 0xa1, 0x6f, 0x87, 0x7e, 0x3d, 0x08, 0xe6, 0xe7, 0x9b, 0x2a, 0xfd, 0x29, 0xd9, 0x23, 0x68, 0x05, 0xc1, 0xbd, 0x50, 0xe2, 0x83, 0x2a, 0x6d, 0xac, 0x15}}, - {{0x0b, 0x34, 0x21, 0xa4, 0xd5, 0x9f, 0xfe, 0xb0, 0x26, 0xcd, 0x9e, 0x3c, 0x71, 0xf1, 0xe4, 0x48, 0xbc, 0x95, 0x4a, 0x3d, 0x71, 0xac, 0xf4, 0xe4, 0x33, 0xd0, 0xb5, 0x1a, 0x28, 0x61, 0x2b, 0x31}, {0x9c, 0x5d, 0xdb, 0xaf, 0x00, 0xd4, 0x5b, 0x40, 0x90, 0x93, 0x6b, 0xef, 0x90, 0x80, 0xeb, 0xaa, 0xdd, 0x53, 0x3c, 0xe2, 0xb3, 0xc0, 0x69, 0x74, 0x59, 0x45, 0x5d, 0xb0, 0xbf, 0x21, 0x4f, 0x2e}}, - {{0x84, 0x2e, 0x12, 0x76, 0x2b, 0xd8, 0xbf, 0xa0, 0x27, 0x2d, 0x48, 0xb5, 0x0a, 0xca, 0x78, 0x6c, 0x1d, 0xeb, 0xaf, 0x62, 0x53, 0x56, 0xae, 0x75, 0x08, 0xea, 0xd4, 0x8b, 0x7f, 0x3b, 0x9b, 0x08}, {0x79, 0x25, 0x70, 0xc6, 0x34, 0x38, 0xca, 0x7f, 0x58, 0x62, 0x5d, 0x08, 0xd2, 0x31, 0x62, 0xa0, 0x34, 0xeb, 0x82, 0xd7, 0x36, 0x68, 0x2f, 0xb3, 0xc4, 0x10, 0xae, 0x35, 0x31, 0xe8, 0x08, 0x37}}, - {{0xfe, 0xc7, 0x05, 0x6c, 0x14, 0xc0, 0x6d, 0x9f, 0x5f, 0xa6, 0x7c, 0xd6, 0xb5, 0xb3, 0x19, 0x11, 0x54, 0xfe, 0xe6, 0xf7, 0x2e, 0x6d, 0xbf, 0x45, 0x4f, 0x3e, 0xb6, 0x9a, 0xac, 0x08, 0x41, 0x01}, {0x73, 0xd1, 0x14, 0xa5, 0xe7, 0x36, 0xf9, 0x57, 0xf2, 0xa3, 0x3e, 0x28, 0xb8, 0xa9, 0x4e, 0x3d, 0xdf, 0xd8, 0x56, 0xbf, 0xbe, 0x9b, 0x45, 0x0b, 0xce, 0xc3, 0x17, 0x64, 0x83, 0xbe, 0x96, 0x00}}, - {{0x10, 0x1e, 0x0a, 0xa6, 0x6e, 0x7e, 0x84, 0xbf, 0xf7, 0x8a, 0xa1, 0x59, 0xa9, 0x0d, 0x7d, 0x00, 0x6e, 0xf2, 0x5d, 0x80, 0x39, 0x6f, 0x66, 0x9b, 0x98, 0x47, 0x0d, 0xc7, 0xb1, 0xa8, 0xda, 0x2d}, {0x15, 0x32, 0x04, 0x21, 0xa1, 0xe4, 0xfa, 0x8a, 0x5f, 0x43, 0x5c, 0x66, 0x1d, 0x28, 0x45, 0xfc, 0xd6, 0xd0, 0xa4, 0x97, 0x23, 0x5d, 0x42, 0xcf, 0x16, 0xe4, 0x44, 0x35, 0xe4, 0xd5, 0x3b, 0x20}}, - {{0x91, 0xb9, 0x69, 0xc7, 0x42, 0xa3, 0x55, 0x63, 0xa5, 0xfb, 0xa8, 0x7c, 0x61, 0x35, 0x94, 0xaf, 0x7c, 0x86, 0xc6, 0x1b, 0x53, 0x19, 0xc6, 0x9b, 0x84, 0x8c, 0xe9, 0x7c, 0xb2, 0xb4, 0xc6, 0x35}, {0xe2, 0xd0, 0x05, 0xaa, 0xf2, 0x52, 0x8b, 0x35, 0xa7, 0x11, 0x69, 0x10, 0x04, 0xf4, 0x36, 0x1e, 0x5e, 0x92, 0x12, 0xf5, 0x5d, 0x77, 0xb1, 0xdf, 0x60, 0x56, 0x85, 0x28, 0xff, 0x4c, 0x0e, 0x2f}}, - {{0x4f, 0x39, 0x9d, 0x65, 0xaa, 0x45, 0xc6, 0x9b, 0xc2, 0x52, 0xf5, 0xaf, 0xd5, 0xf9, 0xfb, 0x63, 0xdf, 0x0d, 0x7d, 0x15, 0xf9, 0xa1, 0x81, 0x2a, 0xdd, 0x1b, 0x2b, 0x79, 0x6d, 0x8d, 0x40, 0x08}, {0xed, 0x6f, 0x42, 0xa4, 0xe0, 0xc9, 0x14, 0x62, 0xb0, 0x4d, 0xdc, 0xb2, 0xc1, 0x2d, 0x0c, 0x58, 0x91, 0x8b, 0x07, 0x7c, 0xe6, 0x7c, 0x6e, 0xdf, 0x07, 0x58, 0x0a, 0xaa, 0xc7, 0x86, 0x9b, 0x14}}, - {{0x5d, 0xd1, 0x6a, 0x01, 0x20, 0xfb, 0x66, 0x23, 0xa2, 0x92, 0xbe, 0x32, 0x09, 0xa5, 0x11, 0x7e, 0xdb, 0x85, 0x4d, 0xd3, 0x90, 0x3c, 0x46, 0xdf, 0xae, 0xdd, 0xfb, 0x37, 0x24, 0x35, 0x7d, 0x3b}, {0x2c, 0x3b, 0xe7, 0xe2, 0xa2, 0x78, 0x01, 0xd7, 0x17, 0xfd, 0xbb, 0x49, 0x60, 0x7a, 0x76, 0xeb, 0x04, 0x85, 0x18, 0x71, 0x5a, 0x0c, 0x81, 0xa0, 0x8a, 0xac, 0x31, 0x7a, 0x14, 0xda, 0xe1, 0x30}}, - {{0xe2, 0x05, 0xa3, 0x79, 0xc3, 0x1c, 0x6c, 0x99, 0xdf, 0xf9, 0x7f, 0xda, 0xa7, 0x35, 0xd9, 0x61, 0xfe, 0xd1, 0x84, 0x0e, 0x50, 0x3c, 0x7e, 0xe7, 0x09, 0xc0, 0xdf, 0xc1, 0x98, 0x60, 0x9d, 0x11}, {0x89, 0xad, 0xac, 0x0b, 0xf6, 0x68, 0x3c, 0xe8, 0xea, 0x8a, 0x33, 0x7f, 0x6b, 0x5f, 0xe4, 0xe3, 0x11, 0x0a, 0x03, 0x27, 0xb7, 0xed, 0x02, 0xcb, 0xd2, 0x37, 0xa0, 0xc7, 0xd8, 0xfc, 0xfe, 0x0d}}, - {{0x3f, 0x2e, 0xc1, 0xc0, 0xef, 0xe1, 0x49, 0x02, 0x0e, 0x14, 0x1b, 0xfc, 0x50, 0xf7, 0x35, 0xfd, 0xa4, 0x24, 0x0a, 0xee, 0x25, 0xfd, 0xcc, 0x34, 0x36, 0xe9, 0x50, 0x14, 0x37, 0xea, 0x85, 0x2d}, {0xa6, 0xc6, 0x76, 0x70, 0x87, 0x7e, 0x03, 0xea, 0x98, 0x9a, 0x81, 0x71, 0x4a, 0x05, 0x86, 0x1e, 0xdd, 0xff, 0x55, 0xde, 0x67, 0x0a, 0xb2, 0xc8, 0xad, 0x6e, 0x60, 0xc5, 0xdc, 0xf1, 0xa0, 0x2f}}, - {{0x2a, 0x14, 0x69, 0x82, 0x58, 0x40, 0x9d, 0x14, 0x7e, 0x0c, 0xcd, 0x87, 0x99, 0x86, 0x7e, 0xc4, 0x60, 0xc2, 0xe8, 0x4c, 0xe4, 0x84, 0x83, 0x90, 0x51, 0x3d, 0xef, 0x99, 0xec, 0xcc, 0x65, 0x0d}, {0x5c, 0xbb, 0x95, 0x1b, 0xce, 0xbe, 0x9f, 0x3d, 0xce, 0x60, 0x12, 0x5b, 0xea, 0x87, 0x69, 0x73, 0x2c, 0x3c, 0x99, 0xe0, 0x43, 0xcc, 0xc5, 0x69, 0x3d, 0x5e, 0xb2, 0xbc, 0x05, 0x28, 0x96, 0x12}}, - {{0xf6, 0x70, 0x57, 0xf8, 0xac, 0x79, 0x0f, 0xfd, 0xf2, 0x58, 0x87, 0x3b, 0xd0, 0x5a, 0xad, 0x2c, 0x87, 0xf0, 0x3a, 0x95, 0xba, 0x4e, 0x9d, 0xd7, 0x63, 0x03, 0xd8, 0x62, 0x8c, 0x77, 0x74, 0x00}, {0xb2, 0x04, 0xb7, 0x75, 0xbd, 0x43, 0x53, 0x4d, 0x6c, 0xbd, 0x9f, 0x38, 0xdf, 0x64, 0x69, 0xfb, 0x14, 0xc4, 0xf1, 0x36, 0x51, 0x4f, 0x99, 0x09, 0x85, 0x4e, 0xcb, 0xc6, 0xae, 0xf4, 0x76, 0x07}}, - {{0xc4, 0x9d, 0xac, 0x8c, 0x6e, 0xb1, 0x07, 0x22, 0x65, 0x02, 0xc3, 0x92, 0x64, 0x24, 0xcc, 0x6f, 0x45, 0xb8, 0xf4, 0x14, 0x0a, 0xe0, 0x05, 0x1f, 0x72, 0xe8, 0x04, 0xc2, 0xbe, 0xd4, 0xa9, 0x01}, {0xa8, 0x81, 0xfb, 0x24, 0xae, 0x69, 0x83, 0xf7, 0x67, 0x99, 0xae, 0x38, 0xa2, 0xa8, 0x41, 0xf7, 0x0d, 0xb3, 0xae, 0xfa, 0x85, 0x08, 0x08, 0x44, 0xe6, 0x18, 0xb9, 0x49, 0x1f, 0x7f, 0xf7, 0x03}}, - {{0x01, 0xc1, 0x4b, 0xfd, 0x83, 0xe0, 0x73, 0xad, 0x7f, 0x19, 0x3b, 0xca, 0x06, 0xc6, 0x99, 0xb2, 0x06, 0x65, 0xa8, 0x0b, 0x00, 0x00, 0xc8, 0x61, 0x76, 0x4f, 0xb5, 0xc4, 0xf3, 0x35, 0x91, 0x16}, {0x8c, 0xe2, 0x92, 0xeb, 0xce, 0x58, 0x60, 0x87, 0x2d, 0x0e, 0x6c, 0xf8, 0xe0, 0x16, 0xf0, 0x34, 0x50, 0x3f, 0x7b, 0xc4, 0x5e, 0x49, 0xb0, 0x86, 0xff, 0x85, 0xc5, 0xc4, 0x2b, 0xc4, 0xf1, 0x03}}, - {{0x8c, 0x79, 0xab, 0x2c, 0xb7, 0x94, 0x7d, 0x01, 0x23, 0xf5, 0xaa, 0x18, 0x5b, 0xcb, 0x6d, 0x8d, 0x0b, 0xc2, 0x94, 0x89, 0x5d, 0x8b, 0x08, 0x8e, 0x13, 0xfe, 0x35, 0xe6, 0x78, 0xe1, 0xba, 0x19}, {0x19, 0x01, 0x4a, 0x99, 0xb4, 0x84, 0x27, 0xab, 0x33, 0x7e, 0x5c, 0x63, 0x0e, 0xfe, 0xa4, 0x9d, 0xc4, 0xaf, 0xa2, 0xca, 0x12, 0x81, 0x43, 0x11, 0xe7, 0xc4, 0xd9, 0xde, 0x94, 0xda, 0xcf, 0x3a}}, - {{0xbc, 0x55, 0x7a, 0x31, 0x08, 0xcb, 0xce, 0xbb, 0xe6, 0xf0, 0x38, 0x32, 0xcd, 0xdd, 0xaa, 0x36, 0x1e, 0xd6, 0xab, 0xe6, 0xb6, 0x05, 0x00, 0xdf, 0x7c, 0x08, 0x3d, 0x05, 0x4e, 0xc6, 0x27, 0x25}, {0xef, 0x68, 0x3a, 0x03, 0xee, 0x48, 0xe8, 0x6b, 0xe1, 0xce, 0xf4, 0xd4, 0xac, 0xf9, 0xa3, 0x55, 0xbf, 0x28, 0x65, 0xd4, 0xce, 0x57, 0xdd, 0xf6, 0x96, 0xcc, 0x09, 0xb5, 0x7d, 0xea, 0x27, 0x1e}}, - {{0x80, 0x42, 0x16, 0x95, 0xd9, 0x12, 0xbc, 0xe5, 0xf6, 0x5d, 0x25, 0x51, 0xc2, 0x0d, 0x00, 0x2a, 0x82, 0xd8, 0x4c, 0x16, 0x4b, 0x92, 0x36, 0xa9, 0x49, 0xce, 0xa8, 0x32, 0x8a, 0x35, 0xa9, 0x34}, {0xa2, 0xac, 0xcb, 0xdf, 0xe4, 0x77, 0xe8, 0x60, 0x21, 0xa5, 0xf8, 0x25, 0x88, 0x3e, 0xa5, 0x0a, 0x98, 0xf0, 0xdd, 0x83, 0xc5, 0x6c, 0x25, 0xe3, 0xb8, 0xcd, 0xa3, 0x5a, 0x5c, 0xfc, 0xdb, 0x3b}}, - {{0xd8, 0x16, 0x3d, 0xea, 0xea, 0xf7, 0x95, 0x6d, 0x83, 0x53, 0xd6, 0x6b, 0x9a, 0x4e, 0xc0, 0x03, 0x83, 0xb2, 0xfe, 0xc4, 0x17, 0xbb, 0x05, 0xec, 0x07, 0x3b, 0x1f, 0xed, 0xa5, 0x03, 0x9e, 0x28}, {0x86, 0x76, 0xb1, 0xfe, 0x2f, 0xc5, 0x6a, 0x2b, 0x48, 0x89, 0x49, 0x4e, 0x92, 0xda, 0xb7, 0xbc, 0xd3, 0xdb, 0x4d, 0xd0, 0x81, 0xcd, 0x95, 0xa9, 0x4a, 0x22, 0x59, 0x11, 0x57, 0x6c, 0x46, 0x0c}}, - {{0x0c, 0x9f, 0xd2, 0xa4, 0xe7, 0x9b, 0x93, 0x60, 0xa2, 0x0a, 0x99, 0xb7, 0xa2, 0x62, 0x18, 0x15, 0xc2, 0x8c, 0xe7, 0x1c, 0x2c, 0xe6, 0xa3, 0x44, 0xf3, 0xe5, 0x7d, 0x42, 0xea, 0x25, 0x1e, 0x20}, {0x4f, 0x6b, 0xff, 0x27, 0xe9, 0x5e, 0x53, 0x58, 0x26, 0x71, 0x92, 0x95, 0xb3, 0xb5, 0xba, 0xa9, 0x81, 0x56, 0x1e, 0xe6, 0x08, 0x07, 0x60, 0x2c, 0x6d, 0x02, 0xa7, 0x37, 0xf6, 0x68, 0xd4, 0x31}}, - {{0xb3, 0x27, 0xf9, 0x32, 0xda, 0x2b, 0xec, 0x97, 0x87, 0xed, 0x61, 0xc3, 0x38, 0x9f, 0x79, 0x7e, 0x88, 0xfa, 0x01, 0xd6, 0x0b, 0xac, 0x8f, 0x58, 0xfe, 0x27, 0x4d, 0x73, 0x36, 0x77, 0x5f, 0x27}, {0xb9, 0xd9, 0x45, 0xc5, 0x27, 0x8a, 0x26, 0x64, 0xeb, 0x01, 0x23, 0xc4, 0x3d, 0xa2, 0xa0, 0x46, 0x1c, 0xc8, 0xcf, 0xdc, 0x4c, 0xe0, 0x7d, 0xac, 0x99, 0xb4, 0x12, 0x83, 0x78, 0x47, 0x30, 0x30}}, - {{0x28, 0x80, 0x15, 0x32, 0x46, 0xa1, 0x91, 0x94, 0xab, 0xe1, 0x01, 0x64, 0xc2, 0xc9, 0x63, 0xee, 0x7b, 0x84, 0xe6, 0xe3, 0x9c, 0x13, 0x8f, 0xe6, 0x2f, 0x84, 0xca, 0x9a, 0x03, 0xe8, 0xe9, 0x0c}, {0x09, 0x46, 0xc7, 0x25, 0xd1, 0x04, 0x9d, 0xe0, 0xad, 0xf8, 0x5e, 0xc0, 0xd0, 0xbb, 0x70, 0x37, 0x67, 0x95, 0x69, 0xa1, 0x88, 0x8c, 0x8b, 0xdd, 0xe4, 0xa6, 0x27, 0xf1, 0x12, 0x39, 0x99, 0x2d}}, - {{0x08, 0xdd, 0x63, 0x6f, 0x59, 0x54, 0x31, 0xe5, 0xc0, 0x9f, 0xa1, 0x10, 0xfe, 0x13, 0xa0, 0xf7, 0x40, 0xa0, 0x74, 0xac, 0xdc, 0x76, 0xb4, 0xd7, 0x3f, 0x78, 0x3f, 0x2f, 0xbf, 0x75, 0xa0, 0x08}, {0x00, 0xb2, 0xd2, 0x80, 0x09, 0x32, 0x62, 0x19, 0x77, 0x19, 0x7f, 0x5f, 0xb6, 0xe1, 0xa6, 0x3d, 0x35, 0x9c, 0xdb, 0xf2, 0xbf, 0x4d, 0x68, 0x61, 0x04, 0x92, 0x81, 0xb3, 0xf5, 0x4b, 0x21, 0x3c}}, - {{0x9d, 0x8e, 0x05, 0xe3, 0x8d, 0x69, 0xfc, 0x46, 0x53, 0x0e, 0x8b, 0xe5, 0x29, 0x74, 0x82, 0xed, 0xe8, 0x30, 0xd8, 0x65, 0xb5, 0x2a, 0x3b, 0xff, 0x50, 0x1e, 0x25, 0x6f, 0x8e, 0x89, 0xe6, 0x2e}, {0x9e, 0x7f, 0x78, 0xb7, 0x65, 0x16, 0xea, 0x2f, 0x83, 0x90, 0x9e, 0x33, 0x52, 0xeb, 0x4c, 0xa8, 0xf6, 0x9b, 0x06, 0x69, 0x09, 0x28, 0x32, 0xfc, 0xa4, 0x95, 0x44, 0xd2, 0x70, 0x75, 0xa0, 0x22}}, - {{0x50, 0x93, 0x8d, 0x02, 0x30, 0x14, 0x2e, 0x8b, 0xc0, 0x26, 0x86, 0xbf, 0xfb, 0x41, 0xad, 0xa9, 0xa7, 0xb4, 0x63, 0x0a, 0x98, 0x67, 0xff, 0xec, 0xd2, 0xab, 0x84, 0x0d, 0x0b, 0x64, 0xec, 0x38}, {0xc4, 0xdd, 0xd9, 0x9f, 0x9d, 0x24, 0x17, 0xda, 0x13, 0x2c, 0x18, 0xa3, 0x42, 0x5d, 0x62, 0x38, 0x62, 0xa2, 0x77, 0x53, 0x68, 0x4c, 0xb0, 0x74, 0xed, 0x80, 0x50, 0xab, 0xab, 0xc8, 0x61, 0x1e}}, - {{0x8c, 0xdb, 0x92, 0x9d, 0xf4, 0x3b, 0x63, 0x92, 0xc3, 0xfc, 0xd6, 0x12, 0x02, 0x7e, 0x42, 0x5b, 0x68, 0x9c, 0x99, 0x3c, 0x5b, 0x2b, 0x0c, 0xd2, 0x35, 0x36, 0x6d, 0x73, 0xa8, 0x46, 0xa7, 0x34}, {0x20, 0x73, 0xc0, 0x9f, 0xf1, 0x9a, 0x4c, 0x48, 0xc2, 0xdd, 0xb0, 0x4e, 0x04, 0x4c, 0x62, 0x23, 0x73, 0x3b, 0x4d, 0x85, 0x14, 0x35, 0xe8, 0x27, 0x3b, 0xc7, 0xa7, 0x7c, 0xe8, 0x16, 0x64, 0x30}}, - {{0x6b, 0x35, 0x45, 0xcc, 0x0d, 0x11, 0xd4, 0x32, 0xae, 0x07, 0x03, 0xfc, 0x5e, 0x7f, 0xf4, 0x48, 0x83, 0x96, 0xff, 0xf3, 0x2b, 0x0e, 0x53, 0x78, 0x5f, 0x2e, 0x05, 0xda, 0xab, 0x91, 0xd6, 0x36}, {0x2e, 0xff, 0x02, 0x53, 0x77, 0xda, 0xdb, 0xbe, 0x24, 0x70, 0x79, 0xf2, 0x17, 0x59, 0x4c, 0x4a, 0xf5, 0xd7, 0xe3, 0x02, 0x1c, 0x7f, 0x89, 0x0a, 0xe4, 0xa0, 0x4f, 0x61, 0xf3, 0xb0, 0xac, 0x01}}, - {{0xff, 0xd8, 0x46, 0xf0, 0xc0, 0x24, 0xd3, 0x4e, 0xb4, 0x54, 0xbc, 0x41, 0xca, 0x1a, 0x1f, 0xd8, 0x50, 0x58, 0x93, 0x31, 0xfd, 0x70, 0x3d, 0x63, 0x0e, 0xa9, 0x98, 0x93, 0x03, 0xeb, 0x15, 0x2f}, {0xc9, 0x37, 0xf7, 0x5a, 0x99, 0x44, 0xbe, 0xe7, 0xe7, 0x2c, 0x33, 0x03, 0x1b, 0x91, 0x3c, 0x07, 0xda, 0x2d, 0xff, 0xf5, 0xed, 0x25, 0xa6, 0x6e, 0xdf, 0xd3, 0x2d, 0x09, 0xf6, 0x63, 0x90, 0x02}}, - {{0xc1, 0xc6, 0x92, 0x70, 0x0b, 0x26, 0xf2, 0x15, 0x24, 0x24, 0x8b, 0x67, 0xe3, 0x36, 0xfd, 0x00, 0x90, 0x32, 0x3d, 0x40, 0xd5, 0x36, 0x63, 0x14, 0xbe, 0xa6, 0xdd, 0xa8, 0x20, 0xd6, 0xcc, 0x26}, {0xf6, 0x5b, 0x3c, 0xd9, 0xf8, 0x05, 0xd6, 0x24, 0x94, 0x08, 0xca, 0x75, 0x90, 0x14, 0x50, 0xbe, 0x18, 0x11, 0x83, 0x41, 0x43, 0xd5, 0xea, 0x70, 0x14, 0xe5, 0x61, 0xbe, 0x93, 0x42, 0x7e, 0x19}}, - {{0x56, 0x44, 0x73, 0x5c, 0x71, 0x32, 0x50, 0x9b, 0x1f, 0x88, 0x29, 0xb3, 0xcf, 0x79, 0xff, 0x2a, 0x05, 0x23, 0x77, 0x86, 0xf7, 0x27, 0xad, 0x20, 0x54, 0x62, 0x84, 0x00, 0x9c, 0xdf, 0xb2, 0x1f}, {0x8f, 0xd2, 0x3c, 0x63, 0x1c, 0x50, 0x26, 0xd7, 0x7e, 0x1d, 0xc7, 0x87, 0xbd, 0xe9, 0x75, 0xee, 0xdc, 0xa3, 0x7a, 0x3d, 0xd1, 0xff, 0xa0, 0xe5, 0xed, 0x9a, 0xab, 0x8a, 0x18, 0x2a, 0x01, 0x35}}, - {{0x38, 0xa0, 0x25, 0x17, 0xb7, 0x3b, 0xe3, 0xa5, 0xec, 0xca, 0x26, 0xd1, 0xfa, 0x44, 0x6f, 0x1a, 0x11, 0x3c, 0x6b, 0x8b, 0x7b, 0x0c, 0x82, 0xc6, 0x92, 0x4f, 0x4b, 0xf2, 0x87, 0x1a, 0x69, 0x1e}, {0x42, 0xce, 0x8d, 0xcd, 0x4f, 0xcf, 0x4b, 0xef, 0x8a, 0x0c, 0x17, 0x5a, 0xf9, 0x61, 0xd4, 0x9e, 0x33, 0x7b, 0x3e, 0xcc, 0x1a, 0x45, 0x5b, 0x88, 0xb4, 0x95, 0xb0, 0xff, 0xc9, 0x4d, 0xe0, 0x17}}, - {{0x32, 0xe0, 0xf0, 0x1a, 0xde, 0xa4, 0x34, 0xe1, 0x29, 0xaa, 0x65, 0xfd, 0xca, 0xab, 0x55, 0x60, 0xf6, 0x29, 0x63, 0x75, 0x0f, 0xbd, 0x09, 0x81, 0xa6, 0x9b, 0xcd, 0x6f, 0x0c, 0x2e, 0x92, 0x3d}, {0xed, 0x49, 0x01, 0xc9, 0xff, 0xb5, 0x1d, 0xa5, 0xda, 0x44, 0x3a, 0xbe, 0x3c, 0x22, 0x86, 0x88, 0xf1, 0x63, 0xc7, 0x8b, 0x83, 0x0d, 0xf3, 0x9c, 0x9a, 0xd0, 0x76, 0x55, 0x61, 0xdc, 0xd6, 0x23}}, - {{0x0c, 0x99, 0x2a, 0x2b, 0x6e, 0x83, 0xe2, 0x79, 0xb9, 0x7e, 0x4f, 0x43, 0x03, 0x0f, 0x2d, 0x98, 0xab, 0xd5, 0x6c, 0xe7, 0x7f, 0xb4, 0xd2, 0x8b, 0x02, 0x90, 0xce, 0x02, 0xd5, 0xa3, 0x60, 0x15}, {0x38, 0xf5, 0xf6, 0x79, 0x1d, 0x70, 0xca, 0x38, 0xa7, 0x5c, 0x5a, 0x26, 0xa2, 0x15, 0x6a, 0x0e, 0xdb, 0x3c, 0x8a, 0xce, 0xbd, 0xbb, 0x41, 0x69, 0xc2, 0x71, 0x5d, 0x72, 0xbd, 0xbc, 0xed, 0x22}}, - {{0xcc, 0x17, 0x2b, 0x9b, 0xb4, 0x42, 0x62, 0xeb, 0x08, 0xb7, 0xb3, 0xcf, 0xbf, 0xc0, 0x45, 0xdc, 0x3e, 0x3f, 0x1a, 0xfd, 0xab, 0x71, 0xe9, 0x1a, 0xd5, 0xf9, 0x16, 0x61, 0x6a, 0x92, 0x50, 0x38}, {0x3a, 0x1a, 0xd5, 0x99, 0xf9, 0x22, 0x46, 0xdb, 0xf3, 0x1e, 0x98, 0x73, 0x18, 0x26, 0xcd, 0xdd, 0x94, 0x38, 0xd1, 0xb3, 0x08, 0x85, 0xb5, 0x3b, 0x67, 0x6a, 0xee, 0xa7, 0xe8, 0x6e, 0x01, 0x20}}, - {{0x20, 0xa6, 0x4d, 0xba, 0xbf, 0xfd, 0xe7, 0x40, 0xce, 0xf9, 0xe3, 0x22, 0x30, 0xb9, 0x56, 0xf0, 0x25, 0x73, 0x34, 0xe7, 0x49, 0xee, 0xb8, 0x02, 0xe3, 0x8d, 0xbc, 0xe1, 0x61, 0xf5, 0x6f, 0x1d}, {0x9d, 0x36, 0x89, 0x81, 0x7a, 0x02, 0x4e, 0xb8, 0x1d, 0x03, 0x66, 0x07, 0xda, 0x75, 0xf2, 0x22, 0xec, 0xf2, 0x70, 0xc1, 0x87, 0x16, 0xe5, 0x4f, 0xd1, 0x17, 0xe1, 0x39, 0x69, 0xc0, 0x2a, 0x3b}}, - {{0x0c, 0xb2, 0xef, 0x79, 0xeb, 0x1e, 0x07, 0x62, 0x1a, 0x6b, 0x6f, 0x9c, 0x01, 0x01, 0x39, 0x0e, 0x3d, 0x08, 0x63, 0x08, 0xd4, 0xb2, 0x9a, 0xad, 0x0c, 0x43, 0x8e, 0xd9, 0xa6, 0x0d, 0xbb, 0x24}, {0x84, 0x27, 0x28, 0x53, 0x52, 0x75, 0x8e, 0xdc, 0x23, 0x5e, 0x9a, 0x38, 0x6b, 0xd3, 0xf0, 0x97, 0xb4, 0x9b, 0xdf, 0x4d, 0xec, 0x27, 0x59, 0xdf, 0x40, 0x4d, 0x27, 0xf8, 0x78, 0x0b, 0x5f, 0x20}}, - {{0xce, 0x43, 0x0d, 0x68, 0xf6, 0x96, 0xcd, 0x01, 0xef, 0x56, 0x89, 0xb5, 0x81, 0xe9, 0xd1, 0xea, 0xb6, 0x59, 0xd3, 0x61, 0x8f, 0x19, 0x6c, 0x7c, 0xab, 0xca, 0x8e, 0xa2, 0x2c, 0x65, 0x8e, 0x2f}, {0xf0, 0x0f, 0x4a, 0xf3, 0xc8, 0xe5, 0x93, 0xf8, 0x27, 0x0e, 0x20, 0x45, 0x32, 0xcb, 0x0a, 0xc7, 0xc6, 0x6d, 0x29, 0xae, 0xea, 0x36, 0xc6, 0xf8, 0x89, 0x44, 0x67, 0x1d, 0xc1, 0x82, 0x28, 0x23}}, - {{0x7f, 0x2a, 0xbe, 0x68, 0x48, 0x2c, 0x8e, 0xd4, 0x85, 0x37, 0x7c, 0xe9, 0x24, 0x31, 0x76, 0xfd, 0x76, 0x5a, 0x62, 0x28, 0xa0, 0x17, 0x94, 0x24, 0xb6, 0x6b, 0x14, 0x58, 0x39, 0x8e, 0xdb, 0x1a}, {0x71, 0x22, 0xd8, 0x33, 0x33, 0xa9, 0xb2, 0xc5, 0xeb, 0xcc, 0x8d, 0x03, 0x1f, 0x10, 0x34, 0xc2, 0xab, 0xef, 0x60, 0x9f, 0x90, 0xb6, 0xf3, 0x14, 0x71, 0xa7, 0x05, 0xba, 0x97, 0xde, 0xba, 0x27}}, - {{0x41, 0x53, 0x54, 0xa4, 0x14, 0xa8, 0x81, 0x37, 0x87, 0xdb, 0xb0, 0x8d, 0x11, 0x4f, 0x39, 0xa8, 0xe2, 0x04, 0x08, 0x44, 0x40, 0x93, 0x89, 0x5f, 0x18, 0x50, 0x81, 0xa5, 0xf2, 0x7a, 0xc2, 0x32}, {0x21, 0x45, 0xd8, 0x53, 0x0a, 0x47, 0x72, 0x50, 0x19, 0x4d, 0x78, 0xf8, 0x26, 0xf4, 0xca, 0xf3, 0x14, 0xa3, 0x03, 0x0d, 0x07, 0xfc, 0xc7, 0x59, 0x15, 0x2a, 0x2a, 0xd8, 0x81, 0x47, 0xc9, 0x05}}, - {{0x5c, 0x0e, 0x21, 0x70, 0x05, 0x82, 0xd1, 0x80, 0xfd, 0xc3, 0x05, 0xbb, 0x74, 0x9d, 0xc1, 0xc3, 0x32, 0xdc, 0x5d, 0x79, 0x72, 0x09, 0xd7, 0xb4, 0xf2, 0x1f, 0xb0, 0x90, 0x58, 0xd8, 0x03, 0x17}, {0x1c, 0x8f, 0x5b, 0xd9, 0x30, 0xba, 0xa1, 0x48, 0x06, 0x23, 0x1d, 0xcf, 0x72, 0x0c, 0xf0, 0xd8, 0x52, 0x9a, 0x28, 0x31, 0x4c, 0xce, 0xac, 0x13, 0x12, 0xdf, 0x46, 0xf0, 0x4b, 0x5f, 0x18, 0x3e}}, - {{0xce, 0x5a, 0xbe, 0x15, 0xdf, 0x75, 0xe5, 0x6f, 0x25, 0x0b, 0x46, 0x77, 0x80, 0xad, 0x1f, 0x2c, 0x80, 0xe5, 0xff, 0x95, 0x91, 0x8d, 0xb9, 0x1f, 0x74, 0x03, 0xf6, 0x25, 0x6b, 0xf8, 0xd2, 0x25}, {0x4d, 0xa0, 0xaa, 0xad, 0x9b, 0xdd, 0x6d, 0xe5, 0x0c, 0x3d, 0x3d, 0x10, 0x52, 0x54, 0x3a, 0x44, 0x0f, 0xc3, 0x01, 0x2b, 0x54, 0xe3, 0x8f, 0x26, 0xec, 0xb6, 0x36, 0xc0, 0xaf, 0xd0, 0x0a, 0x36}}, - {{0x23, 0xdf, 0x58, 0x73, 0x19, 0x32, 0xbe, 0xd5, 0x4d, 0x9b, 0xc0, 0x65, 0x6c, 0x6c, 0xcd, 0x36, 0x12, 0xf2, 0x3a, 0x7d, 0x9d, 0xca, 0x86, 0x28, 0x3f, 0xf8, 0x7f, 0x2c, 0x00, 0xc1, 0xd0, 0x0a}, {0x30, 0xea, 0x68, 0xc2, 0x80, 0x36, 0x5c, 0x96, 0xbd, 0x7a, 0x8f, 0xc7, 0x88, 0x1c, 0xc2, 0x90, 0x81, 0xb4, 0x2e, 0xd3, 0xfd, 0x7d, 0xbd, 0xad, 0xc8, 0x9c, 0x7e, 0xfe, 0x87, 0x3f, 0x32, 0x3e}}, - {{0xc9, 0x65, 0xbc, 0xbc, 0xf7, 0xc4, 0x27, 0xa9, 0x95, 0xda, 0x6c, 0x35, 0xb4, 0x54, 0x6b, 0xb1, 0x6a, 0x94, 0xa1, 0xc0, 0xce, 0x21, 0x7d, 0x46, 0xf3, 0xfc, 0xa8, 0x8b, 0x7a, 0x7a, 0x94, 0x3a}, {0x2b, 0x80, 0x6b, 0x2e, 0x2f, 0xc8, 0xd5, 0x6a, 0x8c, 0xda, 0xfa, 0x9a, 0x22, 0x5b, 0x34, 0x21, 0xd5, 0xa1, 0x9c, 0xfa, 0xbb, 0x90, 0x8f, 0xfc, 0xfb, 0x1c, 0xf4, 0x3e, 0x23, 0x5d, 0x60, 0x17}}, - {{0xff, 0xb6, 0xf8, 0x84, 0x36, 0x47, 0x5b, 0x74, 0x26, 0xf2, 0x28, 0x7d, 0xe6, 0x72, 0xa7, 0x2f, 0x12, 0x3d, 0x58, 0x0a, 0x1c, 0x28, 0x5c, 0x7f, 0x3a, 0x2e, 0x06, 0x39, 0x74, 0xb9, 0x01, 0x21}, {0x62, 0x3a, 0x4e, 0xcf, 0x09, 0x11, 0x16, 0xe6, 0x42, 0x18, 0x9d, 0x11, 0xad, 0xba, 0x0e, 0x25, 0x49, 0x0f, 0xbc, 0x24, 0x6a, 0x35, 0xd4, 0xfb, 0xe4, 0xfb, 0xa6, 0x7d, 0xa7, 0x86, 0x7f, 0x19}}, - {{0x22, 0xa0, 0xb4, 0x65, 0xf0, 0xcc, 0x78, 0x50, 0xc1, 0xce, 0x0c, 0x76, 0x79, 0xf6, 0xdd, 0xca, 0xf2, 0xa0, 0x50, 0x95, 0x31, 0x19, 0xf9, 0x57, 0x81, 0x4b, 0x2f, 0x20, 0x51, 0x03, 0x99, 0x19}, {0x32, 0x9f, 0x7d, 0xd5, 0x93, 0x10, 0x4c, 0xba, 0x0f, 0xe9, 0x0f, 0x0a, 0x45, 0xf1, 0x0a, 0xa8, 0xf7, 0x6a, 0x13, 0x73, 0x28, 0x43, 0x0a, 0x64, 0x38, 0xc1, 0xeb, 0xd2, 0x5f, 0x46, 0x65, 0x19}}, - {{0xfc, 0x6f, 0x6d, 0xd8, 0xdf, 0x75, 0x75, 0x4d, 0xb5, 0xba, 0x99, 0x14, 0xc0, 0x72, 0x7b, 0x8c, 0xf6, 0x40, 0x86, 0x43, 0xe9, 0x9f, 0x54, 0x83, 0xc7, 0x92, 0x7d, 0x6d, 0x23, 0x17, 0xa5, 0x01}, {0x66, 0x9d, 0x2d, 0x15, 0xdf, 0x9a, 0x0e, 0x85, 0x6e, 0x36, 0xee, 0x43, 0x56, 0xf2, 0x7b, 0xb8, 0x9c, 0xf2, 0x6d, 0x08, 0xaf, 0x1c, 0xdd, 0x39, 0xfa, 0x5c, 0x18, 0x0c, 0xfa, 0xcb, 0x2e, 0x2b}}, - {{0x5e, 0xfb, 0x0c, 0x2c, 0xc3, 0xd2, 0xf4, 0x2f, 0x48, 0x2e, 0x78, 0x1e, 0xfb, 0x20, 0x66, 0x5b, 0x39, 0xa1, 0xa6, 0xa6, 0x8f, 0x04, 0x4e, 0x16, 0x89, 0xd2, 0x17, 0x74, 0x98, 0xde, 0x77, 0x11}, {0xf8, 0x96, 0x63, 0x8b, 0x3c, 0xf6, 0x73, 0x44, 0x68, 0x76, 0x7c, 0xe4, 0x18, 0x70, 0x13, 0x88, 0xd6, 0x58, 0x65, 0x93, 0x8a, 0x65, 0x54, 0x6e, 0x16, 0x4d, 0x24, 0xc1, 0x2e, 0xf3, 0x65, 0x15}}, - {{0xca, 0x54, 0x64, 0xad, 0x46, 0xb0, 0xf8, 0xd3, 0xfb, 0x59, 0x74, 0xf0, 0x28, 0x8e, 0x83, 0x07, 0x35, 0x10, 0x20, 0x39, 0x07, 0x6e, 0x26, 0x2c, 0xb4, 0x58, 0x1e, 0x96, 0x43, 0xae, 0xde, 0x1a}, {0x85, 0x08, 0xcc, 0x97, 0x25, 0x92, 0xac, 0xcb, 0x41, 0xbb, 0xb8, 0xec, 0xf2, 0x41, 0x97, 0x02, 0xfe, 0x0f, 0xa8, 0xbc, 0x81, 0x88, 0xf7, 0x52, 0x97, 0x39, 0xea, 0xd9, 0xd7, 0x3b, 0x26, 0x26}}, - {{0xee, 0x15, 0xba, 0x10, 0x1c, 0xb0, 0x9b, 0x23, 0xd9, 0x21, 0x83, 0xe8, 0x2f, 0x2e, 0xde, 0xe0, 0x58, 0x84, 0xb2, 0x0d, 0x3d, 0xa0, 0x9e, 0x24, 0xea, 0xa8, 0x64, 0xc3, 0x10, 0x10, 0xa1, 0x02}, {0x55, 0xbf, 0xd3, 0x80, 0xbd, 0x66, 0x63, 0xbd, 0xd0, 0x70, 0x85, 0xdf, 0x0e, 0x3e, 0x68, 0xb9, 0x6b, 0xe3, 0xed, 0x04, 0x2f, 0x64, 0x0a, 0xf0, 0x04, 0xa5, 0x0b, 0xb3, 0x22, 0xd6, 0xff, 0x37}}, - {{0xbe, 0x79, 0xf5, 0xd2, 0xa7, 0x07, 0x1a, 0xc3, 0x3b, 0x73, 0x86, 0xdd, 0x16, 0x4a, 0xe0, 0x93, 0x07, 0xac, 0x6f, 0x38, 0xd1, 0x12, 0xc9, 0xbe, 0x39, 0xe7, 0x6c, 0xb7, 0xd9, 0x25, 0x91, 0x19}, {0x31, 0xa7, 0x17, 0x0d, 0x8c, 0x9a, 0x6a, 0x97, 0x56, 0x72, 0x20, 0x44, 0xc4, 0xc9, 0x6f, 0xaf, 0x8d, 0xbf, 0x7e, 0x95, 0xf8, 0x0e, 0x5b, 0x7e, 0x32, 0x95, 0x12, 0x75, 0x1a, 0x40, 0xfe, 0x1a}}, - {{0xfa, 0xb0, 0x13, 0x66, 0x65, 0xfa, 0xe4, 0x3b, 0xe4, 0x94, 0x26, 0x2e, 0x61, 0xbe, 0x1f, 0x3a, 0x57, 0xdd, 0x5e, 0x3b, 0xfc, 0xa6, 0x91, 0x00, 0xd4, 0xea, 0x6b, 0xcf, 0xda, 0x5d, 0xfd, 0x39}, {0x8d, 0x93, 0x2d, 0xa0, 0x10, 0x8e, 0x1e, 0xf6, 0x24, 0x5c, 0xb1, 0xe1, 0xfb, 0x5a, 0x3d, 0x30, 0x15, 0x94, 0xc5, 0xf1, 0x83, 0xc2, 0x3b, 0x4f, 0x68, 0x6d, 0xee, 0x25, 0x6b, 0x63, 0xea, 0x19}}, - {{0x79, 0xc3, 0x08, 0x11, 0xff, 0xd6, 0x71, 0x2f, 0x16, 0x24, 0xf8, 0xc8, 0x9b, 0x64, 0x38, 0x33, 0x00, 0x10, 0x70, 0x09, 0xba, 0x7f, 0xcb, 0x29, 0x1c, 0xc7, 0xbb, 0xde, 0x8d, 0xbe, 0x06, 0x32}, {0xc0, 0x3d, 0xff, 0x97, 0x0c, 0x99, 0x97, 0x47, 0xbc, 0x97, 0x1b, 0xbc, 0x3c, 0x24, 0xf3, 0xb0, 0x59, 0x8a, 0xf3, 0x4c, 0xaf, 0x28, 0x17, 0x80, 0x96, 0x11, 0xdf, 0x53, 0x32, 0xeb, 0x56, 0x3f}}, - {{0x1f, 0x2e, 0x09, 0x6e, 0x74, 0x34, 0x66, 0x5b, 0x82, 0x0a, 0xef, 0xf9, 0xf5, 0x87, 0xe2, 0xc2, 0xca, 0x66, 0x0c, 0x21, 0xdd, 0x95, 0x42, 0x24, 0xae, 0x95, 0x4c, 0xbc, 0x2d, 0xea, 0x88, 0x1d}, {0x56, 0x33, 0x61, 0xf8, 0xb8, 0x8e, 0x9d, 0xe1, 0x71, 0xe9, 0x10, 0x7f, 0xd6, 0x10, 0x53, 0x4b, 0xbf, 0x00, 0x61, 0x28, 0x4e, 0x39, 0xe6, 0x1a, 0xe3, 0x35, 0xa3, 0x3e, 0x8e, 0x98, 0xc9, 0x0b}}, - {{0xde, 0xf2, 0x0e, 0xc2, 0xb7, 0xad, 0xbe, 0xc3, 0x08, 0x97, 0x32, 0x5b, 0x5c, 0xeb, 0xca, 0xe8, 0x1b, 0x63, 0x1d, 0xa9, 0xf5, 0xc8, 0x0b, 0x7c, 0x7f, 0xa8, 0x96, 0xbb, 0x0d, 0x7b, 0x7d, 0x35}, {0x85, 0xed, 0xf6, 0xe6, 0x6d, 0x6f, 0x73, 0xad, 0x09, 0x63, 0x1e, 0x07, 0xea, 0x6f, 0x76, 0xa1, 0x00, 0x44, 0x6e, 0x54, 0x19, 0x11, 0xff, 0x73, 0xb9, 0x6e, 0x32, 0x17, 0xa3, 0xa0, 0xb5, 0x37}}, - {{0x7b, 0x45, 0x81, 0xec, 0xb6, 0xd7, 0xfb, 0x71, 0xf8, 0xe2, 0xbd, 0x8e, 0x0b, 0x88, 0xdb, 0xa3, 0x82, 0x72, 0xf7, 0x77, 0x5e, 0x9d, 0xae, 0x6f, 0xd8, 0xf4, 0xe5, 0xaa, 0xfe, 0x33, 0x22, 0x39}, {0x80, 0x6d, 0x6f, 0x73, 0x8c, 0x93, 0xdb, 0x10, 0x31, 0x97, 0xd1, 0x56, 0x23, 0xe7, 0x3d, 0x34, 0x68, 0xa4, 0x5d, 0x9d, 0x7a, 0xc3, 0xb3, 0x78, 0x2b, 0x0a, 0x60, 0x91, 0x0e, 0x30, 0x17, 0x16}}, - {{0xa3, 0x1a, 0xac, 0x5b, 0x77, 0x88, 0x4a, 0x42, 0xe5, 0xc0, 0x8c, 0x7e, 0xe8, 0x36, 0xc8, 0xa8, 0x64, 0x92, 0xfe, 0x03, 0x74, 0x23, 0x71, 0xc3, 0x0e, 0xa3, 0x66, 0x7a, 0x8a, 0xc9, 0xf1, 0x26}, {0xd9, 0x44, 0xb2, 0x0d, 0x6e, 0xb3, 0xa3, 0x51, 0x35, 0xe0, 0x7d, 0x88, 0x88, 0x1d, 0xea, 0x3e, 0xda, 0xf3, 0x1f, 0xd5, 0x02, 0xa9, 0xcb, 0x25, 0x68, 0x64, 0x48, 0x45, 0x90, 0x0b, 0xe7, 0x36}}, - {{0xc1, 0xd1, 0x61, 0x0b, 0xb5, 0xfd, 0x28, 0x27, 0x21, 0x15, 0xd1, 0x6e, 0x70, 0xa0, 0x71, 0xcb, 0x6f, 0xab, 0x07, 0x1d, 0xbe, 0x29, 0x09, 0x05, 0x4c, 0xc8, 0x7e, 0x2b, 0x62, 0x7b, 0xd2, 0x21}, {0x80, 0xcf, 0xe0, 0x7e, 0xfe, 0x1c, 0x3a, 0xe1, 0x16, 0x64, 0xe1, 0xa8, 0x36, 0x8c, 0x30, 0xae, 0x84, 0x6d, 0xe0, 0x9c, 0x9e, 0xfb, 0x99, 0xed, 0x42, 0x18, 0x03, 0x98, 0xb8, 0xca, 0xa7, 0x34}}, - {{0x8f, 0xc2, 0xeb, 0x3a, 0xef, 0x35, 0xbb, 0xfd, 0x87, 0x0e, 0x44, 0x1e, 0x06, 0x28, 0x4b, 0x83, 0x0d, 0x15, 0x07, 0x66, 0xe3, 0x25, 0x65, 0xbd, 0x87, 0xd9, 0x6a, 0x88, 0x98, 0x3d, 0x3c, 0x18}, {0xa9, 0x5b, 0x3d, 0xbf, 0x6e, 0xe0, 0xb2, 0xef, 0x57, 0xb9, 0x1a, 0x37, 0x83, 0xe7, 0x2e, 0x8d, 0xf8, 0x07, 0xc7, 0xb0, 0xbd, 0x80, 0x32, 0xca, 0xf0, 0x68, 0xf5, 0x08, 0x88, 0x6b, 0xe1, 0x1d}}, - {{0x5b, 0xec, 0x4e, 0x92, 0xc0, 0xbd, 0x6d, 0x78, 0x47, 0x41, 0x9c, 0x18, 0x1c, 0x6c, 0x10, 0xe2, 0xd5, 0x0a, 0x17, 0xbb, 0xab, 0xa8, 0x4b, 0x7a, 0xc8, 0x5e, 0x6a, 0x17, 0xca, 0x5c, 0xd2, 0x27}, {0xe3, 0x38, 0x1a, 0x6a, 0x9c, 0x54, 0xcc, 0xbc, 0xc1, 0xf8, 0xd5, 0xbc, 0x83, 0xd3, 0xe7, 0xff, 0x70, 0xc8, 0x4b, 0xf2, 0x33, 0x06, 0x45, 0x1e, 0xc1, 0x21, 0x95, 0xab, 0x09, 0x07, 0x6e, 0x34}}, - {{0x3e, 0x5a, 0xca, 0x3c, 0x4f, 0xf4, 0x73, 0x5e, 0x35, 0x7e, 0x6c, 0xdd, 0xa3, 0xc7, 0x65, 0xa9, 0xdc, 0x89, 0x49, 0x11, 0xe4, 0xee, 0xc6, 0x3e, 0x07, 0x6b, 0xbe, 0xd4, 0xea, 0xdf, 0x83, 0x10}, {0x9c, 0xcf, 0xdb, 0x9d, 0x25, 0x4b, 0x4d, 0x29, 0xc6, 0x61, 0x45, 0x80, 0x4e, 0x97, 0xce, 0x7a, 0xcd, 0xc0, 0x68, 0x4d, 0x3f, 0x84, 0x7e, 0x50, 0x25, 0xe9, 0xc0, 0xfe, 0x78, 0x8f, 0x2d, 0x0a}}, - {{0x05, 0xb2, 0x6d, 0x2d, 0x8b, 0xc7, 0x5e, 0xf0, 0xc5, 0x3f, 0xa6, 0x8d, 0x3b, 0xd9, 0xed, 0x74, 0xb5, 0xe1, 0x62, 0xc9, 0x3d, 0xee, 0x14, 0x2d, 0xe2, 0x75, 0x06, 0xa2, 0x79, 0xe7, 0x96, 0x3d}, {0xdf, 0x53, 0x42, 0x24, 0xfc, 0x20, 0xb0, 0x74, 0xe5, 0xc1, 0x84, 0x8a, 0x1c, 0x73, 0x67, 0x5e, 0xca, 0x9c, 0x83, 0xee, 0x2f, 0x57, 0xb9, 0x76, 0x3d, 0x79, 0x84, 0xe5, 0xc7, 0x4f, 0xec, 0x20}}, - {{0x6c, 0x9c, 0x2f, 0xbf, 0x50, 0x3a, 0x8d, 0x61, 0xc9, 0x53, 0x9d, 0xd0, 0xad, 0x12, 0x9e, 0x2c, 0x9c, 0xa7, 0x71, 0x99, 0x2a, 0xe1, 0x0e, 0xc4, 0xf2, 0x4a, 0xdb, 0x8c, 0x49, 0x5e, 0x93, 0x21}, {0x71, 0x0d, 0x47, 0x48, 0x71, 0xa4, 0x6d, 0x52, 0xfd, 0x44, 0x06, 0x7e, 0xa6, 0xad, 0xb6, 0x91, 0xb0, 0x8e, 0xf1, 0xf6, 0xc8, 0x0f, 0xd3, 0x0e, 0x03, 0xd5, 0xce, 0xa7, 0xd2, 0xa9, 0x39, 0x33}}, - {{0xd2, 0xc4, 0xe2, 0xeb, 0xa9, 0x6b, 0x83, 0x50, 0x9f, 0xb8, 0x4e, 0xcf, 0x48, 0x6e, 0x97, 0x1a, 0xad, 0x17, 0x6c, 0xd7, 0x36, 0x39, 0x04, 0x87, 0x51, 0x17, 0xb4, 0x94, 0x13, 0x22, 0xaf, 0x29}, {0xc3, 0x50, 0x09, 0x7f, 0x10, 0xcd, 0x44, 0xf6, 0xbc, 0x94, 0xea, 0x01, 0xc3, 0x71, 0x84, 0x88, 0x58, 0x52, 0xe6, 0x3b, 0xcf, 0xb2, 0x37, 0x89, 0xcb, 0x98, 0x02, 0xe2, 0xf5, 0x20, 0x47, 0x26}}, - {{0xdd, 0x6b, 0x5a, 0x4e, 0x72, 0x29, 0xc7, 0x95, 0x0b, 0x75, 0x1e, 0x2f, 0x97, 0xa6, 0x55, 0xcc, 0x75, 0xc3, 0x13, 0xf9, 0xc3, 0x90, 0xb7, 0xb9, 0x6c, 0x12, 0xd6, 0xbc, 0x2a, 0x0c, 0xdf, 0x1d}, {0xc2, 0x68, 0x1f, 0xe5, 0xe7, 0x7f, 0x61, 0xb2, 0xd1, 0x8c, 0xe2, 0x27, 0x00, 0xf7, 0x6a, 0xaf, 0x77, 0x2e, 0x2c, 0x4a, 0xb5, 0x5b, 0xe8, 0x22, 0x31, 0x1c, 0xbe, 0x6a, 0xfe, 0x6c, 0xaf, 0x04}}, - {{0xf3, 0xe2, 0x5f, 0xc0, 0x4e, 0x8c, 0xa6, 0x8e, 0xef, 0x31, 0x7b, 0xba, 0xad, 0xd4, 0x55, 0x01, 0xd9, 0xea, 0x84, 0x1d, 0xdf, 0x74, 0xea, 0xa5, 0x97, 0xe8, 0x38, 0x0a, 0x90, 0x08, 0x23, 0x25}, {0x51, 0x21, 0x63, 0x11, 0x3e, 0x88, 0x4a, 0xa6, 0xff, 0xf8, 0x77, 0x24, 0x43, 0xd7, 0x07, 0xd1, 0xfc, 0x36, 0x58, 0x71, 0xf8, 0x49, 0xaf, 0x0d, 0x35, 0x64, 0x7a, 0x68, 0x63, 0x0b, 0x81, 0x3e}}, - {{0x27, 0x13, 0x83, 0x9d, 0xd3, 0xf1, 0xe8, 0xb8, 0x16, 0xfb, 0x23, 0x2f, 0x9a, 0x12, 0xfd, 0xee, 0x58, 0x4b, 0x7c, 0x41, 0xe9, 0x95, 0xe7, 0x5c, 0x70, 0xa1, 0x75, 0x8c, 0x8c, 0x50, 0x79, 0x35}, {0x71, 0x5e, 0xb2, 0xe4, 0x4c, 0x57, 0xb9, 0xe1, 0x15, 0xb5, 0x7e, 0xe8, 0x4d, 0xb4, 0x7c, 0xa3, 0xb8, 0x8a, 0x55, 0x9d, 0xb9, 0x24, 0x92, 0xf4, 0x23, 0xf6, 0x5b, 0x9e, 0x7f, 0x99, 0xc4, 0x09}}, - {{0x07, 0xf9, 0xee, 0x13, 0x05, 0x39, 0x10, 0x50, 0x99, 0xa8, 0x9a, 0xd3, 0xaa, 0x6a, 0x19, 0x47, 0x02, 0x1a, 0x09, 0xe7, 0x1b, 0x85, 0xde, 0x54, 0x0e, 0xe7, 0x57, 0x49, 0x97, 0xa2, 0x84, 0x27}, {0xab, 0xdf, 0x85, 0x98, 0xef, 0xca, 0xee, 0x24, 0x78, 0xf6, 0x27, 0x5f, 0x09, 0x30, 0x89, 0xd1, 0x1f, 0x09, 0xd9, 0x15, 0xf4, 0x6a, 0xd3, 0x1f, 0x44, 0x8e, 0x37, 0xb4, 0x81, 0xec, 0x4b, 0x08}}, - {{0x13, 0x4f, 0x93, 0xe4, 0xb4, 0x74, 0x9f, 0xb1, 0x3c, 0xe2, 0x84, 0xf0, 0x1b, 0xe8, 0xa0, 0xe3, 0x1b, 0x23, 0xa3, 0xae, 0x1f, 0xef, 0xb2, 0xaf, 0xee, 0x87, 0xc0, 0xac, 0x46, 0xe8, 0x81, 0x02}, {0x2f, 0x54, 0x93, 0x73, 0x0f, 0xd0, 0x75, 0xd9, 0xd0, 0x59, 0x9e, 0xec, 0x1e, 0xf9, 0xae, 0xf8, 0x0c, 0x28, 0xc5, 0xb9, 0x11, 0x8c, 0x85, 0xd2, 0x83, 0xf8, 0xdd, 0x5a, 0x52, 0x5d, 0x00, 0x3b}}, - {{0xec, 0xf3, 0x21, 0xe2, 0xea, 0x98, 0x66, 0x7b, 0x9d, 0xef, 0xe3, 0x81, 0x99, 0x8c, 0x52, 0xaa, 0x22, 0xaf, 0x14, 0xbb, 0x1a, 0x5e, 0x94, 0x85, 0xe0, 0x01, 0x42, 0xd6, 0x76, 0x56, 0x5a, 0x00}, {0x1b, 0x02, 0x31, 0x0a, 0xaa, 0x21, 0x03, 0xf4, 0xce, 0x01, 0xe9, 0x43, 0x72, 0x41, 0x9d, 0x4b, 0xe4, 0x6f, 0xfd, 0xff, 0xa1, 0x30, 0xef, 0xdc, 0x6b, 0x5c, 0xe7, 0x17, 0x90, 0x5d, 0x5c, 0x11}}, - {{0x5f, 0x73, 0xee, 0x29, 0x1a, 0xa3, 0x0b, 0xb5, 0x05, 0x9f, 0xbe, 0x55, 0x44, 0x42, 0x87, 0xe0, 0x41, 0xbb, 0x34, 0x7f, 0x56, 0x53, 0x3d, 0x4b, 0xd5, 0x8f, 0x73, 0xef, 0xa2, 0xdf, 0x92, 0x35}, {0x7f, 0xac, 0xaa, 0x5e, 0xb4, 0xa2, 0xea, 0x5e, 0x51, 0xda, 0xf4, 0x5d, 0x58, 0xa1, 0x64, 0xba, 0x8b, 0xa1, 0xa1, 0xe2, 0x18, 0x1e, 0xf2, 0x64, 0xf4, 0xf4, 0xb3, 0x60, 0x2c, 0x47, 0x44, 0x27}}, - {{0x76, 0xd0, 0x3a, 0x5a, 0x4c, 0x7d, 0xb7, 0x1a, 0xa9, 0x55, 0x8f, 0x13, 0x2e, 0x34, 0xef, 0xec, 0x3b, 0xf9, 0xbd, 0x1c, 0xcf, 0xd4, 0x81, 0xe5, 0x5c, 0x3d, 0x7d, 0x9f, 0x59, 0xf3, 0xa1, 0x0e}, {0x5f, 0xc1, 0xe3, 0x9f, 0xa5, 0xae, 0x25, 0xfc, 0xe0, 0x64, 0x4f, 0xf4, 0x1a, 0xd7, 0xeb, 0xc8, 0xed, 0xa5, 0xb5, 0x38, 0x54, 0x2e, 0x6b, 0xaa, 0x20, 0xfb, 0x7e, 0x1f, 0x50, 0xd9, 0xd7, 0x1c}}, - {{0xf9, 0x7e, 0xf6, 0xd2, 0x75, 0xcc, 0x2c, 0xb9, 0x6c, 0xc7, 0x4b, 0xbb, 0x50, 0x70, 0x8c, 0x7c, 0x05, 0xb7, 0x7c, 0x3e, 0x71, 0xdd, 0x06, 0xae, 0x6f, 0x9a, 0x99, 0x0a, 0x6e, 0xb6, 0xe7, 0x12}, {0x90, 0x1a, 0xde, 0x46, 0x4c, 0x17, 0x73, 0xce, 0x24, 0x36, 0xe6, 0xdc, 0x5c, 0x8c, 0x33, 0xf2, 0xba, 0xca, 0x07, 0x61, 0xf1, 0xd0, 0x11, 0x73, 0xc1, 0x3b, 0x6e, 0x2f, 0xd8, 0x3c, 0xc5, 0x07}}, - {{0x0c, 0x88, 0x63, 0x06, 0xcb, 0x68, 0x9f, 0x67, 0x33, 0xc7, 0xf2, 0xb8, 0xb9, 0x3a, 0xeb, 0x22, 0xd5, 0x7a, 0x17, 0xee, 0xf2, 0xcb, 0x9a, 0x8c, 0x05, 0xc9, 0xb2, 0x96, 0xc2, 0x4c, 0x15, 0x02}, {0x4c, 0xde, 0x53, 0xbb, 0x98, 0x72, 0xf8, 0xf9, 0x90, 0x16, 0xc4, 0x1e, 0x20, 0x8c, 0x36, 0xdf, 0x0e, 0x2e, 0xab, 0xc5, 0x82, 0xd6, 0x64, 0x49, 0x69, 0xcd, 0xb7, 0x1f, 0x23, 0xfd, 0x40, 0x1c}}, - {{0x5d, 0xb7, 0x56, 0x89, 0xfc, 0x8b, 0x19, 0x21, 0x65, 0xb5, 0xa4, 0x35, 0x0b, 0x62, 0x1d, 0x99, 0x6d, 0xd8, 0x4e, 0x81, 0x45, 0xc4, 0xea, 0x71, 0x32, 0x3f, 0x39, 0x47, 0xb6, 0x9d, 0xc7, 0x28}, {0x13, 0xf1, 0x17, 0xae, 0x60, 0x20, 0xce, 0x14, 0x50, 0xfc, 0x46, 0x12, 0xc5, 0xfd, 0x45, 0xbe, 0x73, 0xbe, 0xac, 0x10, 0x19, 0x43, 0x1c, 0x8e, 0x2e, 0x91, 0x83, 0x17, 0xc6, 0x53, 0x12, 0x13}}, - {{0x37, 0xdd, 0x05, 0x10, 0x7e, 0x76, 0x6d, 0x02, 0x8a, 0x42, 0x64, 0x1a, 0xa2, 0x23, 0x59, 0x07, 0x0e, 0x6a, 0x9d, 0xb7, 0x07, 0x45, 0xae, 0xee, 0x6b, 0x25, 0x73, 0x81, 0x0d, 0x76, 0xd5, 0x37}, {0xc0, 0x56, 0x6f, 0x93, 0x9e, 0xd9, 0x14, 0x52, 0x58, 0x2f, 0x31, 0x67, 0x0e, 0xb5, 0xa0, 0x26, 0x38, 0xd2, 0xc1, 0x6e, 0x29, 0x70, 0xfa, 0x3d, 0x90, 0x1a, 0x28, 0x5f, 0xf2, 0x0d, 0x0c, 0x17}}, - {{0x68, 0xbd, 0x4d, 0xba, 0xcb, 0x3b, 0x7a, 0x39, 0xf5, 0x1a, 0xd1, 0x06, 0x16, 0x28, 0x77, 0xf5, 0x6e, 0x1e, 0x0c, 0x22, 0xb5, 0x30, 0x14, 0x08, 0xc9, 0x73, 0xe3, 0x45, 0xc4, 0xca, 0xee, 0x04}, {0xd1, 0x65, 0x4f, 0x1a, 0x9d, 0x61, 0xe6, 0x3d, 0x7a, 0x6b, 0x54, 0xeb, 0x2b, 0xa9, 0x0e, 0x68, 0xbf, 0x51, 0xfc, 0x19, 0xba, 0x31, 0xd4, 0x01, 0x30, 0x07, 0xa7, 0x13, 0xd1, 0x35, 0x0c, 0x07}}, - {{0x0b, 0xc5, 0x4b, 0xe3, 0xda, 0x43, 0x7a, 0x32, 0x17, 0x63, 0xef, 0xf9, 0x0c, 0xb8, 0x27, 0x92, 0xf5, 0x65, 0x7a, 0x72, 0x31, 0xc3, 0x7b, 0x20, 0x87, 0x04, 0x19, 0x95, 0x8e, 0x36, 0x5b, 0x2f}, {0xc1, 0x8b, 0x4b, 0x04, 0xc7, 0xf9, 0xda, 0x59, 0x84, 0x50, 0x78, 0x4c, 0x4a, 0x94, 0xb3, 0x1a, 0x30, 0xa1, 0x9f, 0xed, 0x13, 0x6a, 0x16, 0xb7, 0xb9, 0xe0, 0x00, 0xc3, 0xe0, 0x91, 0x65, 0x21}}, - {{0x5f, 0xb9, 0x1f, 0xf2, 0x88, 0x12, 0xa9, 0x5f, 0x44, 0x47, 0x7b, 0x83, 0xa8, 0x13, 0xd2, 0xbb, 0x8c, 0x5d, 0x38, 0x69, 0x70, 0x32, 0x4a, 0x0a, 0xc1, 0xc9, 0xc5, 0xd5, 0x93, 0xf1, 0xb9, 0x2d}, {0xff, 0x9b, 0x1a, 0x1a, 0x98, 0x98, 0xbd, 0x7b, 0x0e, 0x06, 0x54, 0xef, 0x15, 0x4d, 0xd2, 0x4a, 0x5e, 0x03, 0x5e, 0x91, 0xa3, 0xc7, 0x24, 0x88, 0x16, 0xe3, 0x52, 0x81, 0x3b, 0xa0, 0xea, 0x04}}, - {{0x0c, 0xd0, 0x11, 0xe2, 0x17, 0x51, 0x8e, 0x71, 0x61, 0x2c, 0x06, 0xe8, 0xa7, 0x04, 0x20, 0x68, 0x06, 0x88, 0xee, 0x02, 0x52, 0x12, 0x4d, 0xe1, 0xbe, 0xd8, 0xad, 0x17, 0xce, 0xbb, 0xd6, 0x35}, {0x3e, 0x85, 0x3e, 0x57, 0x95, 0x90, 0x50, 0x6d, 0x54, 0xff, 0x5d, 0xbd, 0x45, 0xbb, 0xe9, 0x9b, 0x0a, 0xe5, 0xb2, 0xc2, 0x15, 0xd6, 0x42, 0xd1, 0x1c, 0x83, 0x49, 0xb0, 0xdc, 0x45, 0x21, 0x0d}}, - {{0xfb, 0x54, 0x77, 0x35, 0xaa, 0x32, 0xe4, 0x8f, 0x8b, 0x89, 0xd3, 0x94, 0x13, 0x85, 0x66, 0x47, 0xc4, 0x75, 0x9d, 0xc8, 0xd0, 0x85, 0x6f, 0x77, 0x34, 0x81, 0xb0, 0x1e, 0x1e, 0x09, 0x44, 0x11}, {0x64, 0x93, 0xb4, 0xdc, 0x36, 0x90, 0x8f, 0x39, 0x3e, 0x1c, 0x46, 0xdd, 0x19, 0x1f, 0xa7, 0xaa, 0x9e, 0x65, 0x5d, 0x7b, 0xf3, 0x0b, 0x24, 0xda, 0x70, 0x38, 0xf2, 0x7b, 0x38, 0x82, 0x09, 0x1c}}, - {{0xfd, 0xd9, 0x5f, 0xe7, 0x93, 0xc9, 0x70, 0x65, 0xf9, 0x37, 0x87, 0xe1, 0xee, 0xd3, 0x95, 0x55, 0x58, 0x4b, 0xc7, 0xce, 0xa7, 0x32, 0x29, 0x06, 0xfa, 0xb4, 0x84, 0xbc, 0x6c, 0x81, 0x02, 0x02}, {0x74, 0xda, 0xb9, 0x5f, 0x9c, 0x9e, 0xf0, 0x1d, 0xee, 0x50, 0xf4, 0x42, 0x71, 0xf2, 0x47, 0xb8, 0xa6, 0xdc, 0x75, 0xda, 0x3b, 0x34, 0x99, 0xf4, 0x26, 0x67, 0x25, 0x74, 0x3b, 0x32, 0x81, 0x17}}, - {{0xd2, 0x51, 0x88, 0x7f, 0x37, 0x0d, 0xff, 0x5a, 0xb3, 0xbf, 0x7d, 0xe8, 0x59, 0x29, 0x53, 0x73, 0x96, 0x1c, 0xb7, 0xfb, 0x6c, 0x47, 0x4c, 0x63, 0x83, 0x76, 0xfd, 0xce, 0x18, 0x88, 0xdf, 0x11}, {0x3d, 0x54, 0x77, 0x45, 0xc4, 0xfa, 0xac, 0x35, 0xfc, 0x61, 0x58, 0x16, 0x44, 0xdb, 0x8f, 0x5c, 0x30, 0xfb, 0x3c, 0xcf, 0x39, 0x0f, 0x19, 0x4b, 0xb8, 0xd6, 0xa3, 0x42, 0x68, 0xc8, 0xdc, 0x27}}, - {{0x34, 0x63, 0xe1, 0xbc, 0xb5, 0x36, 0x6f, 0x70, 0x0d, 0x8f, 0x7e, 0xd6, 0x8e, 0xbc, 0x63, 0xed, 0x8b, 0x14, 0xa1, 0xd9, 0x11, 0x82, 0x89, 0x53, 0x9a, 0x9f, 0x1d, 0xed, 0x66, 0x1a, 0x4e, 0x08}, {0xe5, 0x6e, 0x83, 0x93, 0x24, 0xe9, 0xe0, 0xa9, 0x61, 0x08, 0x95, 0x8f, 0x64, 0xd6, 0xc4, 0x54, 0x06, 0x43, 0x23, 0x8d, 0xff, 0xbe, 0xde, 0xe2, 0x10, 0x2b, 0x48, 0x0b, 0x89, 0x19, 0x38, 0x20}}, - {{0xd7, 0x8a, 0x0c, 0x33, 0x1c, 0xf8, 0xfe, 0x3a, 0x46, 0x7f, 0xb7, 0x3c, 0x8b, 0xb3, 0x31, 0x8f, 0x37, 0xf2, 0xbc, 0xb4, 0xe3, 0xa9, 0xe8, 0x0b, 0x58, 0xae, 0x17, 0x79, 0x9b, 0x72, 0xce, 0x09}, {0xe0, 0x8d, 0x32, 0x47, 0x86, 0xef, 0x99, 0xd1, 0x44, 0x81, 0xf5, 0xa3, 0x44, 0x67, 0x03, 0x7b, 0x94, 0x79, 0x0a, 0x58, 0xef, 0xb8, 0x45, 0xa5, 0xab, 0x07, 0x69, 0x97, 0x11, 0x1c, 0x74, 0x10}}, - {{0xaf, 0xb9, 0xda, 0x86, 0x9a, 0xd6, 0x3d, 0xcc, 0x3e, 0x0b, 0x2b, 0xd5, 0x09, 0x5a, 0xe7, 0xd4, 0x75, 0x7f, 0x10, 0x8b, 0x1d, 0x09, 0xad, 0xe8, 0x1e, 0xf0, 0xd8, 0xf8, 0x2e, 0xcc, 0x43, 0x2b}, {0x63, 0x0f, 0x3d, 0xb0, 0x51, 0x0c, 0x14, 0xbd, 0x5d, 0x28, 0xcf, 0x4b, 0x3c, 0x92, 0x06, 0x10, 0x11, 0x79, 0x0c, 0x12, 0x99, 0x7a, 0x21, 0x72, 0x6f, 0x05, 0x53, 0x8f, 0x79, 0x2b, 0x2f, 0x01}}, - {{0x6c, 0x48, 0x13, 0xa3, 0x9f, 0x94, 0xeb, 0x0b, 0xf8, 0xab, 0x9d, 0x05, 0xd6, 0xe4, 0x5c, 0x0d, 0x16, 0x2b, 0xf5, 0x76, 0x41, 0x4b, 0x91, 0x49, 0x4c, 0xeb, 0xb5, 0x97, 0xc7, 0x5d, 0x14, 0x1a}, {0x02, 0xdc, 0xfb, 0xb5, 0x2b, 0xfb, 0x0a, 0x9b, 0x7e, 0xe6, 0x32, 0x8b, 0x01, 0xd0, 0x2e, 0xb7, 0xa1, 0x40, 0xf6, 0xe7, 0xac, 0xf4, 0xc1, 0x8d, 0xe8, 0x35, 0xc1, 0xe2, 0xe6, 0x99, 0x03, 0x0a}}, - {{0xd6, 0x3b, 0x85, 0x0a, 0xfc, 0x3c, 0xe5, 0x24, 0x8a, 0x53, 0x84, 0x52, 0x40, 0xa4, 0x91, 0xc6, 0x67, 0x3f, 0xca, 0xa2, 0x87, 0x85, 0x5f, 0x28, 0xac, 0xb1, 0x9a, 0x58, 0xba, 0x29, 0x49, 0x00}, {0xb5, 0x11, 0x9e, 0xb5, 0x51, 0x0f, 0xd0, 0x47, 0x18, 0xd0, 0x24, 0x4f, 0xc5, 0xe6, 0x4c, 0x03, 0x77, 0x22, 0x52, 0x93, 0xf5, 0xfd, 0xfa, 0xcd, 0x59, 0xe4, 0x80, 0xcd, 0xa4, 0x01, 0x40, 0x17}}, - {{0xcd, 0x64, 0xe4, 0x88, 0xa6, 0xfb, 0xf2, 0x05, 0x4e, 0xde, 0x93, 0x83, 0x11, 0x4f, 0x07, 0xcc, 0x16, 0xf6, 0x3a, 0x2d, 0xd1, 0x84, 0xd3, 0x8c, 0xdb, 0xc5, 0xbd, 0x65, 0x61, 0xc5, 0x2e, 0x08}, {0x38, 0x14, 0xf6, 0xcd, 0x63, 0xd4, 0xf4, 0x0f, 0x0b, 0x82, 0x97, 0x12, 0x13, 0x85, 0xd4, 0xb9, 0x6f, 0x7b, 0x11, 0x60, 0x49, 0xab, 0x7a, 0x57, 0x49, 0xde, 0x47, 0x6f, 0xa5, 0xca, 0x9f, 0x18}}, - {{0x05, 0x9c, 0x9d, 0x45, 0x34, 0xf2, 0x66, 0x6a, 0xa2, 0x0c, 0x6a, 0x04, 0xe7, 0xb4, 0xb3, 0x52, 0x73, 0x86, 0x0b, 0xac, 0xc7, 0xf5, 0x0c, 0x5f, 0x4d, 0x0f, 0xb7, 0x8a, 0x8b, 0x37, 0x4d, 0x2d}, {0xe3, 0x7d, 0x3b, 0x46, 0xf3, 0xc3, 0xe8, 0x25, 0x0c, 0xdd, 0x23, 0xb3, 0x93, 0x64, 0xb7, 0x1d, 0x7f, 0x7c, 0xf8, 0x69, 0xc7, 0xcb, 0xa6, 0x96, 0xe1, 0x65, 0x7b, 0xd5, 0xe4, 0x09, 0x33, 0x04}}, - {{0xa0, 0xe0, 0x20, 0xc5, 0x04, 0x4d, 0x05, 0xcf, 0xf1, 0x3a, 0xa1, 0x1c, 0xc7, 0xed, 0x40, 0xd5, 0x00, 0x04, 0xdd, 0x77, 0x4b, 0x04, 0x93, 0x49, 0x99, 0xff, 0x7e, 0xb7, 0xcd, 0xa9, 0x0e, 0x1b}, {0x3b, 0xcd, 0x1c, 0x32, 0xa8, 0x0e, 0x28, 0x69, 0x3d, 0xf0, 0xa8, 0xa1, 0x95, 0xb8, 0xab, 0x72, 0x34, 0x77, 0x87, 0x2c, 0x8f, 0x93, 0xd3, 0xf3, 0xcf, 0x6b, 0x73, 0xae, 0x69, 0x17, 0x70, 0x12}}, - {{0x2d, 0xa1, 0x5f, 0xad, 0xf0, 0xa2, 0x52, 0x3e, 0x64, 0xb0, 0xbc, 0x38, 0xa6, 0x5b, 0x18, 0x44, 0x22, 0x66, 0xf1, 0x5b, 0xef, 0xd3, 0x8b, 0xef, 0xbf, 0x28, 0xb2, 0x16, 0xc2, 0x5e, 0xf5, 0x3e}, {0x05, 0x9c, 0xf4, 0xf2, 0x14, 0xcb, 0x2b, 0xb8, 0x58, 0x09, 0x6e, 0x35, 0xe5, 0xae, 0xcb, 0x1e, 0x3a, 0xd8, 0xcd, 0x85, 0x1c, 0x68, 0x50, 0xd8, 0x8a, 0xc1, 0xcd, 0xa3, 0x30, 0x7a, 0x28, 0x13}}, - {{0xd2, 0xe4, 0x5b, 0x67, 0x31, 0x15, 0xc9, 0x76, 0xd5, 0xa3, 0xe7, 0xf5, 0xc0, 0xef, 0xf3, 0xbf, 0x5a, 0x2e, 0x04, 0xc7, 0xeb, 0x1f, 0x16, 0xbf, 0x2d, 0x21, 0x3e, 0x5e, 0x5c, 0xa8, 0x33, 0x00}, {0x07, 0x16, 0x5b, 0x73, 0x5f, 0x29, 0xfe, 0xb3, 0x11, 0x88, 0x85, 0x2f, 0x9f, 0x16, 0x07, 0x4c, 0x4b, 0xe2, 0x14, 0xe3, 0x3d, 0xcd, 0xaf, 0x53, 0xfc, 0x44, 0x46, 0x9d, 0x1a, 0x2f, 0xdd, 0x33}}, - {{0x71, 0x81, 0xe7, 0x97, 0x96, 0x06, 0x41, 0x8e, 0x95, 0xc7, 0xbf, 0x32, 0x08, 0x12, 0xff, 0x26, 0x8a, 0x80, 0x96, 0x11, 0xa4, 0x0a, 0xd7, 0x0b, 0xf5, 0x99, 0xd2, 0x40, 0x44, 0xf3, 0xe0, 0x3a}, {0x9a, 0x66, 0xad, 0x2d, 0x0b, 0xb7, 0x74, 0x24, 0x3f, 0x71, 0x98, 0xe8, 0xa7, 0x66, 0x03, 0x46, 0xba, 0xae, 0xd9, 0x0b, 0x24, 0x5b, 0x69, 0xb3, 0xea, 0xe2, 0x5e, 0x46, 0x6d, 0xbb, 0x74, 0x3c}}, - {{0xea, 0xc2, 0xdd, 0x91, 0xa3, 0x42, 0x89, 0x6e, 0xa9, 0xfb, 0xf3, 0xfc, 0xe1, 0x28, 0x8a, 0xc3, 0x78, 0xf1, 0x79, 0x5a, 0x51, 0x26, 0x31, 0xeb, 0x5b, 0x41, 0x3a, 0x2d, 0x3d, 0x5e, 0x1f, 0x34}, {0xa8, 0x4c, 0x5e, 0x37, 0x64, 0xce, 0x49, 0x74, 0x33, 0x6d, 0xb3, 0x0f, 0x5a, 0x74, 0x02, 0x06, 0x55, 0x90, 0x70, 0xd3, 0x91, 0xf8, 0x58, 0x29, 0x43, 0xe0, 0xc8, 0x2d, 0x12, 0x22, 0xb2, 0x09}}, - {{0x17, 0x1a, 0x86, 0x7f, 0x62, 0xc6, 0xb4, 0x06, 0x30, 0x1a, 0xf7, 0x09, 0x55, 0x8a, 0x92, 0x68, 0x14, 0xc5, 0x6f, 0x21, 0x0c, 0x7e, 0x16, 0x0f, 0x26, 0x5c, 0x2a, 0xd0, 0x95, 0xaf, 0x3a, 0x3d}, {0xc6, 0x9b, 0x31, 0x43, 0xff, 0x9d, 0xdf, 0xf1, 0x55, 0xf7, 0xa6, 0xc9, 0x5b, 0xab, 0x28, 0x37, 0x95, 0x3f, 0xd7, 0x2e, 0x35, 0x02, 0x73, 0x8c, 0xa0, 0x2b, 0x90, 0xc7, 0x0c, 0x6e, 0x65, 0x3f}}, - {{0x0a, 0x3f, 0x62, 0xd0, 0x04, 0x59, 0x45, 0x9f, 0xb6, 0x7b, 0xa6, 0x72, 0x9e, 0x02, 0x23, 0x78, 0xe4, 0x2b, 0x0a, 0x51, 0x2c, 0xf2, 0xfb, 0x99, 0xe7, 0x8a, 0x23, 0x47, 0x2d, 0xdf, 0x85, 0x2e}, {0xe3, 0x66, 0x78, 0xe8, 0x7b, 0x31, 0x7d, 0x32, 0x94, 0x3e, 0xdf, 0x95, 0xef, 0x75, 0x5e, 0xa4, 0x49, 0x0f, 0x02, 0xc4, 0x6d, 0xc7, 0x1a, 0x7b, 0x5e, 0x81, 0x7c, 0xa3, 0xcd, 0xfb, 0x60, 0x3a}}, - {{0xc2, 0xa5, 0xa4, 0xe2, 0x8e, 0xa0, 0xdf, 0x17, 0xc8, 0x3c, 0x39, 0x7f, 0xbf, 0xfd, 0x37, 0x0d, 0xab, 0x3a, 0xa3, 0x69, 0xee, 0x0a, 0x65, 0x5f, 0xef, 0x6f, 0x2f, 0x51, 0x3f, 0xcd, 0xcc, 0x21}, {0xbb, 0x3b, 0x34, 0x19, 0x7b, 0xf4, 0x01, 0x55, 0x03, 0x57, 0x9b, 0x83, 0xda, 0x25, 0x29, 0xc6, 0xdb, 0x98, 0xc7, 0x4a, 0xff, 0x5d, 0x69, 0xe8, 0xb3, 0xb1, 0xe8, 0xe0, 0xc0, 0x31, 0x16, 0x26}}, - {{0xdf, 0x27, 0x00, 0x9e, 0xf9, 0x7a, 0xb8, 0x11, 0xf1, 0xa4, 0xfc, 0xd6, 0x48, 0xbf, 0xd7, 0xaf, 0x33, 0xc2, 0xf4, 0x42, 0xff, 0x1a, 0x40, 0xd5, 0xb2, 0x37, 0x40, 0x8d, 0x45, 0x62, 0x8d, 0x15}, {0x36, 0xeb, 0x43, 0x62, 0x47, 0xfd, 0x6f, 0x8b, 0x2e, 0x19, 0x5d, 0x42, 0xa6, 0x2a, 0x6d, 0x6c, 0x4c, 0x62, 0x60, 0xde, 0x15, 0xaf, 0x48, 0x91, 0xa0, 0x00, 0x86, 0x38, 0x38, 0x99, 0x87, 0x3e}}, - {{0xc2, 0xe7, 0xe1, 0xe4, 0x77, 0x2c, 0x07, 0xfe, 0xde, 0x68, 0x62, 0xe6, 0x8c, 0x3c, 0xd8, 0x93, 0x9b, 0x73, 0xbc, 0x29, 0x02, 0x51, 0x9f, 0x61, 0x59, 0xaf, 0x2b, 0xc0, 0x24, 0x5f, 0x66, 0x3a}, {0x76, 0xa8, 0xc8, 0x58, 0x98, 0xf1, 0x57, 0xc5, 0xf9, 0x1a, 0x81, 0x73, 0x95, 0x98, 0x31, 0x77, 0xe6, 0x93, 0x5d, 0x99, 0x8d, 0x91, 0x7d, 0x6b, 0x36, 0x96, 0x8e, 0xc9, 0x7d, 0x06, 0x7f, 0x30}}, - {{0x75, 0xc6, 0x68, 0x6a, 0x75, 0x54, 0x36, 0xa4, 0x53, 0x35, 0x4f, 0x79, 0x99, 0xf2, 0xf2, 0x88, 0xc7, 0x62, 0xae, 0x74, 0xb8, 0x45, 0x11, 0x7f, 0x81, 0xb4, 0x27, 0x0f, 0x1a, 0xf8, 0xee, 0x0d}, {0x8c, 0xcf, 0x5e, 0x7f, 0xcf, 0x47, 0x3e, 0x99, 0x47, 0x04, 0x5e, 0x1b, 0x2c, 0x5d, 0x10, 0xe8, 0x82, 0xac, 0x1d, 0x1a, 0x23, 0xb9, 0xad, 0xca, 0x30, 0xe2, 0x2b, 0x4b, 0x69, 0x89, 0x7a, 0x14}}, - {{0x84, 0x61, 0x1e, 0xae, 0x66, 0xe3, 0x23, 0x47, 0x9b, 0xea, 0x19, 0xd7, 0x7f, 0x32, 0x04, 0xee, 0x7d, 0xf2, 0x52, 0xe1, 0x73, 0xbe, 0xdb, 0x24, 0x8d, 0x43, 0x71, 0x61, 0x76, 0x99, 0x00, 0x21}, {0x67, 0x12, 0x94, 0x9b, 0x4e, 0x8e, 0xe4, 0xef, 0x84, 0xa0, 0xb0, 0xfa, 0x86, 0x89, 0xb1, 0xac, 0x5e, 0xea, 0x11, 0xae, 0x63, 0x56, 0x10, 0x7b, 0x0c, 0x40, 0x1c, 0x77, 0x1d, 0x22, 0x4f, 0x27}}, - {{0x1e, 0x3d, 0x57, 0x86, 0x90, 0x17, 0xb8, 0x5c, 0xc4, 0xdd, 0xdd, 0x2e, 0xde, 0x63, 0x05, 0xdd, 0xeb, 0xff, 0x88, 0xb3, 0x57, 0xe5, 0xba, 0x78, 0x5d, 0x36, 0xd0, 0x4a, 0xf1, 0xb9, 0x84, 0x1a}, {0x6a, 0x23, 0x66, 0xe9, 0xb8, 0xbf, 0xda, 0xd1, 0xc8, 0x0c, 0xd6, 0xcb, 0x91, 0xfa, 0xd3, 0x57, 0x3a, 0x33, 0x48, 0x02, 0x96, 0x80, 0x92, 0xdc, 0x7f, 0x99, 0x47, 0x52, 0xb4, 0x21, 0x6c, 0x37}}, - {{0xb1, 0xf7, 0x21, 0xdc, 0x7a, 0xc0, 0xf0, 0x13, 0x4b, 0x85, 0xfe, 0x05, 0xe9, 0x69, 0x5c, 0x2a, 0x4f, 0xda, 0x7d, 0x1d, 0x4d, 0xd1, 0x73, 0x05, 0x9d, 0xa4, 0x74, 0xb6, 0xda, 0xe5, 0x3e, 0x19}, {0x90, 0x4b, 0x4a, 0x71, 0xca, 0x74, 0xa1, 0x7f, 0x93, 0xa7, 0xa5, 0x52, 0x2e, 0xaa, 0x21, 0xfe, 0x91, 0xc7, 0x5b, 0x0f, 0x36, 0xb5, 0xdc, 0x69, 0x6c, 0xe2, 0xd7, 0x03, 0x37, 0xb2, 0x16, 0x1b}}, - {{0xe6, 0xb8, 0xd4, 0x27, 0x65, 0x68, 0xf6, 0xea, 0xcf, 0x1f, 0x66, 0x26, 0xb4, 0xaa, 0xa0, 0x1a, 0x73, 0x5e, 0xa0, 0xa2, 0xaf, 0x9b, 0xa7, 0x1a, 0x85, 0x40, 0xc2, 0x8e, 0x2c, 0x72, 0x89, 0x35}, {0x8f, 0xfb, 0x47, 0xd7, 0x91, 0x04, 0x42, 0x41, 0x57, 0xbf, 0x8a, 0x72, 0xf7, 0x63, 0x0b, 0xc2, 0x0b, 0xd2, 0x2a, 0xab, 0x74, 0x19, 0x1d, 0xf6, 0x78, 0xa9, 0xcd, 0x28, 0xb3, 0xa2, 0x16, 0x3a}}, - {{0x11, 0xe0, 0x84, 0xe8, 0xc8, 0x9a, 0x9a, 0x47, 0x26, 0xae, 0x03, 0xcd, 0xb0, 0x93, 0x4e, 0x50, 0x77, 0xe9, 0x19, 0x13, 0x1f, 0x9e, 0x11, 0xc7, 0xe7, 0x15, 0x77, 0xdb, 0xe7, 0x11, 0x93, 0x37}, {0x58, 0xec, 0x78, 0x65, 0x48, 0xef, 0x5b, 0xf0, 0xdd, 0x50, 0xca, 0xde, 0x2f, 0xb5, 0xb9, 0x05, 0xa2, 0x95, 0xf6, 0x9b, 0xfe, 0xc4, 0x92, 0x6c, 0x6d, 0x55, 0xd7, 0x8a, 0xe4, 0x65, 0xe6, 0x2a}}, - {{0x39, 0x50, 0x11, 0x3a, 0x07, 0xf0, 0x18, 0x94, 0x1d, 0xaa, 0x3c, 0x29, 0xe6, 0xf7, 0xba, 0x84, 0xe8, 0xe8, 0x37, 0x6c, 0xb5, 0x7b, 0xe5, 0x4b, 0x9e, 0x2f, 0x9d, 0xba, 0x6c, 0x0c, 0x01, 0x2e}, {0x73, 0x13, 0x3a, 0x79, 0xc5, 0x63, 0x0c, 0xb3, 0x92, 0xa6, 0xda, 0xe4, 0x68, 0xa8, 0xa7, 0xc2, 0xdd, 0xb6, 0x1f, 0xb7, 0x7b, 0xe6, 0x9f, 0x78, 0x2a, 0x8e, 0x26, 0x31, 0x92, 0xc1, 0x12, 0x28}}, - {{0xb6, 0xbc, 0xfb, 0xd6, 0x6d, 0x8b, 0x3e, 0x8a, 0xe2, 0xcb, 0x83, 0x35, 0x86, 0x95, 0xb6, 0xfa, 0xa1, 0xb5, 0xbf, 0xa4, 0x47, 0x3c, 0x2e, 0x3d, 0x9d, 0xe9, 0x51, 0xb3, 0x76, 0x0e, 0x15, 0x17}, {0x57, 0x77, 0xa4, 0x65, 0xfa, 0x22, 0xa8, 0x2e, 0x1c, 0x74, 0x55, 0xc6, 0x4a, 0xe6, 0x2f, 0x1f, 0x70, 0x95, 0xac, 0xf5, 0x5a, 0x20, 0xaa, 0xd1, 0xe9, 0xc8, 0x36, 0x08, 0x88, 0xdd, 0xcf, 0x27}}, - {{0x79, 0x79, 0x2a, 0x82, 0x29, 0x5f, 0x30, 0x7d, 0xe2, 0x96, 0x64, 0xa3, 0xc1, 0x4f, 0x82, 0x80, 0x4d, 0x0f, 0x7a, 0xc7, 0xf4, 0x1c, 0x3d, 0xf7, 0xbe, 0x26, 0x19, 0x6a, 0x3c, 0xbe, 0x9c, 0x1c}, {0x23, 0x18, 0x76, 0x1c, 0x8c, 0xaf, 0x17, 0xaa, 0x26, 0xe9, 0xf6, 0xba, 0x90, 0xa2, 0xd0, 0x09, 0x2b, 0xc2, 0xd6, 0xb5, 0xf8, 0x06, 0x1c, 0xf6, 0xcd, 0xd9, 0x32, 0xfc, 0x6d, 0x1a, 0x2f, 0x17}}, - {{0xb9, 0x2f, 0x20, 0xb5, 0x43, 0x87, 0xd3, 0x5a, 0xd2, 0x40, 0xbe, 0x50, 0x95, 0x26, 0x3a, 0x08, 0xe3, 0xcd, 0x67, 0x3f, 0x03, 0x18, 0x11, 0xb9, 0x10, 0xb8, 0xcf, 0x30, 0x62, 0xf4, 0x46, 0x28}, {0x4c, 0xc5, 0x37, 0xe9, 0xe7, 0xb5, 0x23, 0xe2, 0x21, 0x3f, 0x8b, 0xb0, 0xfd, 0x77, 0xc5, 0xf2, 0xd3, 0xa7, 0x05, 0x75, 0x2b, 0x65, 0xc1, 0xb6, 0x30, 0xe1, 0x60, 0x2e, 0x98, 0xa4, 0x8f, 0x2c}}, - {{0xf3, 0x95, 0x75, 0x41, 0x85, 0xe1, 0xbb, 0x56, 0x02, 0xc2, 0x07, 0x94, 0x53, 0x00, 0xc1, 0xec, 0x2e, 0xfd, 0x30, 0x76, 0x15, 0xc4, 0xa5, 0x90, 0x20, 0xce, 0x10, 0x64, 0xf2, 0x8e, 0x33, 0x1f}, {0xd4, 0xb7, 0x56, 0x1a, 0x59, 0x54, 0x3b, 0x1a, 0x25, 0xbd, 0xc8, 0xcf, 0x2b, 0xc4, 0x11, 0x27, 0x65, 0x19, 0x62, 0xa4, 0xd6, 0x42, 0x13, 0xb3, 0x28, 0xbe, 0x6a, 0x6c, 0x27, 0x57, 0x04, 0x1e}}, - {{0xd6, 0xe9, 0xc2, 0x1f, 0x2d, 0x12, 0xf0, 0x33, 0xf4, 0xb5, 0x0d, 0x6d, 0xe2, 0x07, 0xaf, 0xbb, 0x28, 0x09, 0xf2, 0x90, 0xdb, 0xe1, 0xa4, 0xad, 0x51, 0x9b, 0x1f, 0x7e, 0xd3, 0x78, 0x0d, 0x32}, {0xf9, 0x79, 0x0e, 0xb8, 0x2f, 0xfe, 0x4f, 0x6d, 0x4d, 0x9c, 0x60, 0x01, 0xf5, 0x46, 0x97, 0x16, 0x17, 0xe1, 0x1f, 0x37, 0x69, 0xaa, 0x94, 0x9c, 0x61, 0x76, 0x97, 0x82, 0x7d, 0xa4, 0xff, 0x08}}, - {{0x15, 0x17, 0x55, 0x7d, 0x5f, 0x41, 0xed, 0x0e, 0x7b, 0x45, 0x11, 0xaa, 0x98, 0x3b, 0x20, 0xf4, 0xfb, 0x0a, 0x76, 0x44, 0xd5, 0xf3, 0x53, 0x90, 0xa1, 0x76, 0xa2, 0xde, 0xba, 0x03, 0xc2, 0x02}, {0xaf, 0xa5, 0x42, 0xe8, 0x4a, 0x02, 0xd7, 0x55, 0x2f, 0xcd, 0xeb, 0x9d, 0xba, 0x03, 0x8c, 0xb5, 0xb5, 0x42, 0xaa, 0xce, 0xb6, 0xc8, 0x6b, 0x0c, 0x3e, 0x5c, 0x35, 0x6e, 0xab, 0x7f, 0x4e, 0x3b}}, - {{0xe9, 0xdb, 0x0d, 0x6a, 0xf8, 0x81, 0x9d, 0xea, 0xf1, 0xe6, 0x57, 0x32, 0x09, 0x28, 0x0f, 0xce, 0x04, 0xff, 0x52, 0xfd, 0x64, 0x3b, 0x39, 0x00, 0x24, 0xef, 0x23, 0x8d, 0x21, 0x58, 0x42, 0x29}, {0x5b, 0xdc, 0x17, 0x95, 0x0f, 0x71, 0x7f, 0xbb, 0xca, 0x48, 0xab, 0x43, 0x53, 0x14, 0xdb, 0xb9, 0x51, 0x34, 0xe8, 0x1f, 0xe3, 0x60, 0xcd, 0x94, 0x8b, 0xbe, 0x98, 0xf7, 0xe0, 0x7c, 0xe1, 0x2b}}, - {{0xa2, 0x3a, 0x1f, 0x07, 0x8b, 0xee, 0x71, 0xd9, 0x48, 0x66, 0x21, 0x2f, 0x6f, 0x04, 0x42, 0x65, 0xeb, 0x2f, 0xc5, 0xc4, 0xb4, 0xa0, 0x11, 0x70, 0xcb, 0xc7, 0x5d, 0x30, 0xe4, 0x75, 0x6a, 0x17}, {0x24, 0xae, 0x75, 0xce, 0x0b, 0x68, 0xfe, 0xb8, 0x44, 0x7b, 0xd2, 0xc3, 0xf6, 0xcb, 0x49, 0x85, 0x87, 0xc5, 0x40, 0x6a, 0xa7, 0x92, 0xee, 0xa8, 0x31, 0xf1, 0x3d, 0x01, 0xba, 0xb0, 0xe6, 0x09}}, - {{0x65, 0xda, 0xfd, 0x64, 0x97, 0x9e, 0x0b, 0xb8, 0x2d, 0x8a, 0xc5, 0x0b, 0x11, 0xb4, 0xc0, 0xb0, 0x55, 0x5c, 0xe1, 0xc6, 0xa0, 0xb1, 0x1b, 0xac, 0xe8, 0x70, 0x7a, 0xd3, 0x41, 0x4d, 0xa4, 0x36}, {0x2f, 0xe7, 0xaa, 0x81, 0xb2, 0xef, 0x77, 0x6a, 0xa7, 0xfa, 0x58, 0x9b, 0x86, 0x86, 0x78, 0xc5, 0xdc, 0x68, 0x33, 0x7e, 0xbd, 0x33, 0x74, 0xab, 0x00, 0xa0, 0x54, 0x7f, 0x2e, 0xad, 0x92, 0x17}}, - {{0xa7, 0xa9, 0x95, 0x03, 0xef, 0xf6, 0x92, 0x87, 0x29, 0x72, 0xc2, 0x66, 0x3d, 0x7f, 0x75, 0xd3, 0x10, 0x90, 0xc7, 0xd5, 0x76, 0xe8, 0x49, 0x69, 0xa7, 0x8b, 0x7f, 0x0c, 0x16, 0xf1, 0x6c, 0x17}, {0xbf, 0xc2, 0x8d, 0xa9, 0xf0, 0xd8, 0xf5, 0xf0, 0xe9, 0xd9, 0x6c, 0xac, 0x9e, 0xe0, 0x18, 0x41, 0x57, 0xf6, 0x97, 0x5f, 0xe4, 0x51, 0xd1, 0x4e, 0xe4, 0x54, 0xb8, 0x26, 0x56, 0x37, 0xe7, 0x13}}, - {{0xd0, 0x06, 0xc2, 0xf3, 0x57, 0x32, 0xcd, 0xbc, 0x42, 0xa3, 0x91, 0xf9, 0xae, 0x8e, 0x39, 0x31, 0x6c, 0x5a, 0xa3, 0x2f, 0x14, 0x44, 0x2d, 0x5a, 0x52, 0x31, 0xf6, 0x13, 0xc7, 0xbc, 0xef, 0x3c}, {0xab, 0x00, 0x7e, 0x01, 0x97, 0x3b, 0x06, 0xc8, 0xc3, 0xac, 0xb5, 0x44, 0xd5, 0xfd, 0x20, 0x5e, 0xcd, 0x18, 0x8f, 0xef, 0xf6, 0xc0, 0xce, 0x6c, 0xeb, 0xbf, 0x6a, 0xec, 0x77, 0x4b, 0xee, 0x14}}, - {{0xb3, 0xea, 0xdb, 0x58, 0x38, 0x22, 0x96, 0xc0, 0x29, 0xef, 0x10, 0xdb, 0xb0, 0x61, 0x0e, 0x5c, 0xa4, 0x1d, 0xcb, 0x8a, 0xed, 0xf1, 0x9a, 0x6c, 0x39, 0xd9, 0x25, 0xc4, 0x73, 0xfe, 0x76, 0x3f}, {0x6f, 0x55, 0x80, 0xb2, 0xe8, 0x82, 0xd4, 0xda, 0x4e, 0xc5, 0xdc, 0x7f, 0xde, 0x06, 0xf4, 0xc3, 0xb9, 0x54, 0x36, 0x1d, 0xb8, 0x88, 0xca, 0x37, 0xd3, 0xa4, 0x44, 0x72, 0x76, 0xf7, 0x61, 0x02}}, - {{0xfe, 0x8e, 0x2a, 0xa1, 0x9a, 0xca, 0x1c, 0x7e, 0x9b, 0xec, 0x22, 0xc5, 0xa8, 0x62, 0x8b, 0x94, 0xf8, 0x3d, 0x8c, 0x21, 0x9b, 0x04, 0xbb, 0x9d, 0x78, 0xaf, 0x55, 0xd2, 0x6c, 0x3a, 0xfd, 0x1e}, {0x1f, 0x0a, 0x65, 0x4d, 0x75, 0x0f, 0xb5, 0xa4, 0x13, 0x2c, 0x5e, 0xa7, 0x86, 0x6c, 0xb7, 0x25, 0x53, 0x1d, 0x4d, 0xef, 0x87, 0x68, 0x6c, 0xfd, 0xf0, 0x51, 0xbc, 0x71, 0xd3, 0x0b, 0x59, 0x0a}}, - {{0x50, 0xd6, 0xd0, 0xb8, 0xa8, 0xce, 0xee, 0xdc, 0xd4, 0xf2, 0x29, 0x6a, 0x8d, 0x8b, 0x2d, 0x4f, 0xeb, 0x11, 0xf9, 0xea, 0x8f, 0x52, 0xd0, 0x43, 0x52, 0x2b, 0x6c, 0x54, 0x52, 0x4c, 0x04, 0x24}, {0xf6, 0xd9, 0xf0, 0x1c, 0xcd, 0xfa, 0xc3, 0x96, 0xd8, 0x6a, 0x50, 0x9f, 0x12, 0x67, 0x63, 0xca, 0x5b, 0x9b, 0x5f, 0xfa, 0x05, 0xd0, 0x85, 0x2f, 0x30, 0xc1, 0x96, 0x98, 0x3f, 0x15, 0x9e, 0x06}}, - {{0x57, 0xd9, 0x61, 0x4c, 0x12, 0x82, 0x6e, 0x68, 0x9e, 0x64, 0x86, 0xa4, 0xde, 0x9b, 0xaa, 0xc7, 0x8d, 0x7a, 0xa3, 0xd4, 0xe0, 0x91, 0xc2, 0xd3, 0xf3, 0x28, 0x5f, 0x2c, 0xe3, 0xe2, 0x07, 0x01}, {0x1b, 0x59, 0xd7, 0xc3, 0xdf, 0x45, 0x0b, 0xab, 0x3d, 0xf6, 0x0b, 0x71, 0x4a, 0x85, 0xb5, 0xf7, 0xf3, 0x26, 0x0c, 0x2e, 0xf1, 0xc8, 0x4d, 0x54, 0x85, 0xea, 0xcc, 0x30, 0xa7, 0x95, 0x9b, 0x2d}}, - {{0xf0, 0x56, 0xce, 0x95, 0xc2, 0x33, 0x3d, 0x51, 0x31, 0x70, 0xd7, 0x7f, 0xdd, 0x2f, 0x2b, 0xbd, 0x31, 0xe0, 0xe2, 0x09, 0xfe, 0x47, 0x4f, 0x5d, 0xb4, 0x54, 0x80, 0x7b, 0x42, 0x48, 0x94, 0x2f}, {0x67, 0x74, 0x6a, 0xd3, 0x65, 0xd6, 0x6f, 0xdf, 0x07, 0x6b, 0xea, 0x2f, 0x1f, 0x19, 0xc9, 0x5d, 0x22, 0x64, 0x40, 0x71, 0x63, 0xef, 0xa2, 0xec, 0x2c, 0xf7, 0xda, 0x96, 0xc0, 0x50, 0x71, 0x01}}, - {{0x58, 0x28, 0xce, 0x87, 0x4f, 0x1d, 0x7a, 0x36, 0x19, 0xcd, 0x37, 0x81, 0x07, 0x5c, 0x54, 0x9d, 0xfd, 0x3b, 0x8f, 0x73, 0x72, 0x20, 0x1a, 0xdf, 0xd4, 0x25, 0xf0, 0x52, 0x20, 0x41, 0x4e, 0x11}, {0xea, 0xd5, 0x66, 0xbf, 0xdf, 0x28, 0xfd, 0x18, 0x75, 0x9a, 0x49, 0xf9, 0xf0, 0x77, 0xbd, 0x8b, 0x3b, 0x45, 0xe8, 0xf3, 0x99, 0x4f, 0x62, 0x63, 0x49, 0x84, 0x38, 0x8a, 0xfe, 0xed, 0x80, 0x27}}, - {{0xd4, 0x5a, 0xa9, 0x0e, 0x82, 0x30, 0x02, 0x74, 0xfd, 0x2f, 0x50, 0x35, 0xe5, 0x7b, 0xb2, 0x63, 0xb6, 0x60, 0xe2, 0xfb, 0x3e, 0xcb, 0xdc, 0x91, 0x77, 0x34, 0x32, 0x0f, 0xb1, 0xbf, 0xe2, 0x25}, {0x4f, 0x09, 0xb4, 0x39, 0x71, 0x3a, 0xc0, 0xad, 0xbb, 0xc2, 0xd1, 0xb4, 0x0f, 0xc6, 0xf8, 0xed, 0xcb, 0x9f, 0x02, 0xb7, 0x47, 0x09, 0x11, 0x69, 0x65, 0x80, 0x50, 0xa8, 0xe0, 0x2f, 0xf4, 0x01}}, - {{0xd0, 0xb4, 0x96, 0xe5, 0x62, 0xcd, 0x2d, 0xff, 0xc8, 0x0f, 0xf5, 0x5a, 0xd4, 0x1a, 0xd3, 0xc7, 0xfd, 0x63, 0xa6, 0xb1, 0xfa, 0x73, 0xbf, 0xa0, 0x05, 0xa0, 0x3e, 0x7e, 0x95, 0x46, 0xc5, 0x01}, {0x79, 0x67, 0x8f, 0x93, 0xcf, 0xaa, 0xeb, 0xef, 0x91, 0x72, 0xde, 0x07, 0x6e, 0x3f, 0x86, 0x69, 0x96, 0xe7, 0xe6, 0xad, 0x67, 0x8e, 0x6e, 0xc0, 0xe9, 0x9a, 0x66, 0x79, 0xe7, 0xab, 0x4b, 0x16}}, - {{0xe0, 0x8f, 0x27, 0xb5, 0x51, 0x6e, 0x33, 0x1c, 0x0b, 0x06, 0xb0, 0x88, 0x67, 0x02, 0x0f, 0x83, 0xf4, 0xcd, 0x36, 0x61, 0x8a, 0xfe, 0x89, 0xe5, 0x5b, 0x31, 0x30, 0xec, 0x36, 0xbb, 0xe2, 0x04}, {0xfb, 0x5b, 0x34, 0x93, 0xb5, 0x5c, 0xe6, 0xcd, 0xf4, 0xf5, 0x87, 0x42, 0x83, 0xfb, 0xa1, 0x10, 0xc1, 0x28, 0x19, 0x46, 0x0c, 0xa2, 0xc7, 0x37, 0x62, 0x6b, 0x26, 0x41, 0x85, 0x5a, 0xdc, 0x2a}}, - {{0xba, 0x61, 0xe2, 0x42, 0x35, 0xba, 0x32, 0x39, 0xcd, 0x4d, 0xde, 0x82, 0x9e, 0x39, 0x1e, 0x3a, 0x73, 0x3c, 0xac, 0x03, 0xff, 0x6d, 0x5f, 0x3a, 0xa9, 0x16, 0xd9, 0x53, 0xf4, 0x15, 0xbd, 0x2c}, {0x37, 0x89, 0x8d, 0xa9, 0x5f, 0xa3, 0x25, 0x24, 0x8c, 0x58, 0x9f, 0x5d, 0xd3, 0xa2, 0x66, 0x0a, 0x2b, 0x85, 0x51, 0x39, 0x5a, 0x8c, 0x32, 0xf8, 0x55, 0xdd, 0xa2, 0xb4, 0x66, 0x6f, 0x48, 0x08}}, - {{0x64, 0x95, 0x4d, 0x3a, 0x80, 0x83, 0xc3, 0xa4, 0xf2, 0x54, 0xeb, 0x31, 0x0c, 0xbd, 0x9a, 0x10, 0x11, 0xa2, 0x12, 0xb0, 0xb4, 0x57, 0x3d, 0xa8, 0x85, 0x3f, 0xfd, 0x4c, 0x0c, 0xc8, 0x49, 0x39}, {0x40, 0x9e, 0xf1, 0x1e, 0x0d, 0x3f, 0xcd, 0xfd, 0x81, 0xb4, 0x92, 0x46, 0x77, 0x54, 0xf8, 0x47, 0x07, 0x86, 0x2f, 0x25, 0x1d, 0x0e, 0xfc, 0x60, 0x19, 0xdc, 0xc3, 0x45, 0x08, 0x2a, 0x47, 0x15}}, - {{0xaf, 0x7b, 0xe5, 0x48, 0x6d, 0x59, 0x2e, 0x04, 0x28, 0xf6, 0x15, 0xcb, 0x41, 0x30, 0xd7, 0xd9, 0x16, 0x09, 0x88, 0x4e, 0x78, 0xa3, 0xec, 0x65, 0xda, 0x01, 0xe9, 0x27, 0x0d, 0x7f, 0x9f, 0x05}, {0x43, 0xb4, 0xf8, 0x4c, 0xd4, 0x77, 0x7d, 0xd3, 0xec, 0x76, 0x41, 0x7d, 0xa6, 0x72, 0xa1, 0xbf, 0x4e, 0x7b, 0x24, 0x25, 0x61, 0xb7, 0xc8, 0xd8, 0xf5, 0x24, 0x2d, 0x5c, 0x88, 0x64, 0x9b, 0x07}}, - {{0xbe, 0x6d, 0xb5, 0xa4, 0x03, 0x07, 0x9f, 0xd2, 0xfc, 0x46, 0x6b, 0x95, 0xa8, 0x6a, 0xe2, 0x75, 0x06, 0x28, 0xe2, 0x02, 0xe7, 0x49, 0xa4, 0x84, 0x1c, 0x12, 0xac, 0xce, 0xd6, 0xf1, 0xbb, 0x38}, {0xd1, 0xb6, 0x66, 0x30, 0x73, 0x1a, 0x72, 0xc7, 0x06, 0xec, 0x3b, 0xb5, 0xf3, 0x55, 0x37, 0x17, 0x21, 0x2c, 0x1e, 0x3e, 0x62, 0xbd, 0x2a, 0x3c, 0x16, 0x01, 0x66, 0x63, 0x3b, 0xd4, 0x8d, 0x08}}, - {{0xb6, 0x8b, 0x5a, 0x05, 0x77, 0x6f, 0x16, 0xa1, 0xa4, 0x8d, 0x89, 0x58, 0x8c, 0x2d, 0x85, 0x63, 0x17, 0x77, 0x4b, 0x75, 0xcd, 0xf4, 0xb4, 0x34, 0x5f, 0x51, 0xe7, 0xf3, 0x2d, 0xaa, 0x26, 0x15}, {0xb8, 0xe4, 0x57, 0x26, 0x1a, 0xc5, 0x85, 0x40, 0x45, 0x86, 0x24, 0x46, 0xa4, 0x5e, 0x79, 0x96, 0x98, 0x39, 0xd6, 0xe3, 0xa1, 0x03, 0x04, 0xc8, 0x08, 0x4b, 0x32, 0x21, 0xb0, 0xc2, 0x9c, 0x19}}, - {{0xc2, 0x77, 0x68, 0xd1, 0x5d, 0xdb, 0x2a, 0xa5, 0x2e, 0xaf, 0x52, 0x0b, 0x22, 0xf9, 0x03, 0x6b, 0xbd, 0x22, 0xef, 0xb4, 0xe8, 0x01, 0xc8, 0x7f, 0x1d, 0x2f, 0x81, 0xec, 0xc2, 0x67, 0xe5, 0x12}, {0x0b, 0xc2, 0xe8, 0xa4, 0x14, 0x40, 0x09, 0x03, 0xcc, 0xa8, 0x00, 0xa2, 0xd6, 0x0c, 0xbf, 0xe7, 0xea, 0x94, 0x5b, 0xfb, 0xfe, 0x65, 0x08, 0xc6, 0xac, 0x41, 0x68, 0x3f, 0x45, 0x14, 0x93, 0x09}}, - {{0xd8, 0x75, 0x6f, 0x8b, 0x57, 0xfd, 0xd7, 0xbf, 0x6a, 0x29, 0x3d, 0xd3, 0x6e, 0xf8, 0x7e, 0xf0, 0x12, 0xee, 0x8e, 0xd4, 0x78, 0xc9, 0x54, 0x50, 0x3a, 0xc4, 0x6f, 0x4f, 0xcb, 0x76, 0x3d, 0x0b}, {0xeb, 0x90, 0xed, 0x4e, 0x5a, 0x62, 0xf7, 0xbe, 0xf7, 0x73, 0xfe, 0x22, 0xde, 0xba, 0x8d, 0x1f, 0xfe, 0x1b, 0xe5, 0x3a, 0x94, 0xab, 0x60, 0xc9, 0x3e, 0x97, 0x5c, 0x86, 0xd8, 0xb2, 0x58, 0x08}}, - {{0xdd, 0x04, 0x3a, 0x84, 0x37, 0x3c, 0xe4, 0xe2, 0xc0, 0xe7, 0x66, 0x69, 0x1e, 0x8a, 0xe9, 0x28, 0xa1, 0xf5, 0x29, 0xd6, 0x4f, 0x30, 0xc4, 0x6a, 0xfb, 0x32, 0x0c, 0xec, 0xe1, 0xf1, 0xfc, 0x2d}, {0x6e, 0x7f, 0xd0, 0x99, 0xf8, 0x15, 0x67, 0xbd, 0xff, 0x47, 0xcc, 0x89, 0x99, 0x5a, 0x85, 0xcb, 0xc4, 0x35, 0x72, 0x68, 0x26, 0x24, 0x2d, 0xdd, 0xb8, 0xfc, 0xa3, 0xa3, 0xc6, 0x0e, 0x68, 0x19}}, - {{0x76, 0x10, 0x94, 0x1f, 0x6e, 0xb9, 0xab, 0xa5, 0x68, 0x02, 0x7a, 0xb9, 0x51, 0xb4, 0xb5, 0x51, 0x75, 0xe3, 0xed, 0x58, 0x4f, 0xdc, 0xe0, 0xd7, 0x63, 0x7e, 0x6d, 0xf7, 0xa5, 0x18, 0xee, 0x2b}, {0xb4, 0xd7, 0x1d, 0x44, 0xbe, 0x80, 0x7d, 0xed, 0x3b, 0xcf, 0x19, 0x3c, 0x0a, 0xd3, 0xc2, 0xa4, 0xed, 0x91, 0x1f, 0x2e, 0x9b, 0x73, 0x4f, 0xac, 0x81, 0x3d, 0x89, 0xe3, 0xda, 0x48, 0x62, 0x35}}, - {{0xc0, 0xa1, 0xcb, 0x4d, 0x8c, 0xfc, 0x79, 0x7c, 0xa1, 0xc1, 0x58, 0xb9, 0x35, 0x1c, 0x62, 0x81, 0x4d, 0xf0, 0x65, 0x32, 0x19, 0x6e, 0x41, 0x0a, 0x41, 0x7f, 0xe1, 0x45, 0x48, 0x48, 0x9e, 0x00}, {0xd1, 0xeb, 0x35, 0xab, 0x94, 0x93, 0x2d, 0x71, 0xfb, 0x49, 0xe1, 0xd8, 0x1e, 0xe1, 0x12, 0x63, 0xde, 0x1a, 0xe5, 0x77, 0x33, 0x99, 0xaf, 0x84, 0xc9, 0x1d, 0x36, 0xcd, 0x6c, 0x3c, 0x42, 0x3f}}, - {{0xe1, 0xb1, 0x23, 0x7f, 0x56, 0x6e, 0x71, 0xf3, 0x94, 0x49, 0x0d, 0x6a, 0x4d, 0x3c, 0x8f, 0x53, 0xec, 0x32, 0x89, 0xb0, 0x2a, 0x6e, 0x2a, 0xaf, 0xaf, 0x98, 0xa2, 0x37, 0xc7, 0x49, 0x3e, 0x2f}, {0xcc, 0x18, 0xc3, 0xdc, 0xba, 0xaf, 0xeb, 0xc5, 0x3d, 0xfd, 0x39, 0x63, 0x4c, 0x6b, 0xf2, 0x64, 0xcc, 0xb6, 0x27, 0xfa, 0x54, 0x95, 0xf0, 0x5e, 0x35, 0xe1, 0xe4, 0x51, 0xc1, 0x5e, 0xdd, 0x21}}, - {{0x3c, 0x4b, 0xe5, 0xf9, 0xea, 0xc4, 0x82, 0xc3, 0x43, 0xc1, 0x3e, 0xb1, 0x7a, 0xf2, 0xea, 0x47, 0x0f, 0x40, 0xaf, 0xca, 0x75, 0x37, 0x6c, 0x2a, 0xdf, 0x26, 0xee, 0x65, 0xa6, 0xcb, 0xd1, 0x08}, {0x25, 0xcd, 0x82, 0xf3, 0x0d, 0xf1, 0xf2, 0xfd, 0xf3, 0xd2, 0x45, 0x40, 0x72, 0x4d, 0x2b, 0x81, 0x4b, 0x08, 0x22, 0x64, 0xe2, 0x32, 0xc3, 0xc1, 0xd3, 0x8c, 0x76, 0xf1, 0xa4, 0x9e, 0xa4, 0x26}}, - {{0x53, 0x93, 0xe5, 0x94, 0xea, 0x91, 0x32, 0xe1, 0xe5, 0x82, 0x7b, 0xfc, 0x80, 0x56, 0x69, 0x7d, 0x02, 0xfe, 0xd7, 0xfc, 0x9f, 0xbc, 0xa6, 0xad, 0x35, 0x13, 0x41, 0xac, 0x4f, 0xe9, 0xd4, 0x2a}, {0xef, 0x98, 0x45, 0xd8, 0x57, 0x85, 0x66, 0xf1, 0x6a, 0x5c, 0x3a, 0x9c, 0xdf, 0x78, 0xf8, 0xb6, 0xcf, 0x8c, 0x73, 0x00, 0xb9, 0xe2, 0x93, 0x09, 0x31, 0xae, 0x85, 0x48, 0x67, 0x68, 0xb0, 0x09}}, - {{0x76, 0xa1, 0x51, 0x2c, 0xa7, 0xde, 0x61, 0x41, 0x17, 0x8e, 0xc1, 0x82, 0x28, 0xe2, 0x7b, 0x14, 0xcd, 0x8b, 0xaf, 0xd4, 0x27, 0xb8, 0x7c, 0xf4, 0x33, 0xaa, 0xa9, 0x90, 0xc4, 0x5e, 0xa0, 0x30}, {0x41, 0xa8, 0xa8, 0x3e, 0xdb, 0xf6, 0x09, 0x32, 0x05, 0x69, 0x2d, 0xea, 0xc6, 0x06, 0x9c, 0x1d, 0x8f, 0x62, 0x39, 0xac, 0xc8, 0x34, 0xfe, 0x6a, 0xde, 0xac, 0x2f, 0xac, 0xed, 0x03, 0xf8, 0x35}}, - {{0xed, 0xb5, 0xeb, 0x83, 0xdb, 0xdf, 0x8d, 0xbe, 0xc3, 0x07, 0xab, 0x57, 0x55, 0x8a, 0x5a, 0x18, 0xb0, 0xeb, 0xd5, 0x64, 0xb1, 0x99, 0x9c, 0x10, 0xf7, 0xc4, 0xe7, 0xc0, 0xbe, 0x40, 0x43, 0x02}, {0x39, 0x04, 0x10, 0x6b, 0xb6, 0x37, 0x51, 0x6b, 0xcd, 0x1e, 0x1d, 0x1a, 0xfe, 0x00, 0x2e, 0x6f, 0x97, 0x5f, 0xb4, 0x7a, 0x62, 0xff, 0xaf, 0xe2, 0x68, 0x43, 0xad, 0x0b, 0xbc, 0x3e, 0xd1, 0x31}}, - {{0x5b, 0x80, 0xe0, 0x77, 0xc2, 0x00, 0x2c, 0xe5, 0x3e, 0x61, 0xe4, 0x00, 0xfc, 0x6c, 0x9a, 0x28, 0x43, 0xaf, 0x0e, 0xb8, 0xe6, 0x64, 0x6d, 0xba, 0xe1, 0x10, 0xeb, 0xa2, 0x3a, 0xbb, 0x8d, 0x02}, {0x71, 0xaf, 0xc2, 0xb2, 0x84, 0x5d, 0xe0, 0xb5, 0xb4, 0xd4, 0x2d, 0xed, 0xc8, 0x19, 0xa8, 0x8c, 0x1d, 0x18, 0x4e, 0x89, 0x85, 0x12, 0x23, 0xbf, 0x20, 0x28, 0x42, 0xaf, 0xec, 0x55, 0xdd, 0x13}}, - {{0x78, 0x55, 0x79, 0xf4, 0x64, 0x9e, 0xd5, 0x7c, 0x12, 0x1d, 0xad, 0x4d, 0x01, 0x83, 0xe4, 0xb2, 0x7b, 0x7a, 0xae, 0xf3, 0x33, 0x33, 0xbc, 0x69, 0x73, 0xce, 0x56, 0x8e, 0xe3, 0xbe, 0x8b, 0x1d}, {0x8e, 0x6d, 0xf3, 0x93, 0x32, 0xe0, 0xed, 0x62, 0x90, 0x4d, 0xfd, 0x42, 0x70, 0xb6, 0xff, 0xe0, 0x11, 0x18, 0x9d, 0x3c, 0x7c, 0xb9, 0xe5, 0x28, 0x30, 0xb2, 0xc2, 0x56, 0xd7, 0x4e, 0x6e, 0x1a}}, - {{0x45, 0x86, 0xa1, 0x7c, 0x8e, 0x35, 0x28, 0x08, 0x41, 0xfc, 0x31, 0xc8, 0xd0, 0x04, 0x14, 0x4e, 0xb9, 0x82, 0xed, 0x1d, 0xef, 0x42, 0xd9, 0xa2, 0xc9, 0x41, 0xe6, 0x33, 0x78, 0x99, 0xb8, 0x2f}, {0x51, 0xe3, 0x22, 0x12, 0x3b, 0x88, 0xa1, 0x1f, 0x98, 0x29, 0x5c, 0xa6, 0x72, 0xe6, 0x92, 0x8a, 0xac, 0x66, 0xe3, 0x0c, 0xae, 0x70, 0x95, 0x2c, 0x79, 0x8f, 0x94, 0x2f, 0x30, 0xc4, 0x82, 0x21}}, - {{0x55, 0x44, 0x9c, 0x90, 0x20, 0x14, 0x37, 0x71, 0x95, 0x48, 0xff, 0xe5, 0xfa, 0x72, 0xa8, 0x79, 0x60, 0x2d, 0x9d, 0x25, 0x11, 0x8a, 0xc5, 0x64, 0x0b, 0x9d, 0x40, 0x2c, 0x3f, 0x24, 0x4a, 0x1b}, {0xcf, 0x77, 0x5c, 0x3e, 0x7b, 0x09, 0xb7, 0x24, 0xc1, 0xd3, 0x2c, 0x8a, 0xe4, 0xbb, 0x3c, 0x10, 0xc1, 0x0a, 0x2b, 0xbd, 0x35, 0xff, 0x53, 0xfb, 0xc3, 0x93, 0x2f, 0xda, 0x5c, 0x07, 0x20, 0x35}}, - {{0x2b, 0x19, 0x11, 0x73, 0x1e, 0xd6, 0x0f, 0xf7, 0xbb, 0x66, 0x78, 0x1f, 0x58, 0x66, 0x3f, 0x66, 0xc2, 0x76, 0x99, 0x60, 0xf3, 0xdc, 0x23, 0xb2, 0x66, 0xb1, 0x28, 0xc6, 0xd3, 0xce, 0xc3, 0x22}, {0xea, 0x71, 0x56, 0x46, 0x5b, 0xe1, 0x90, 0xc3, 0x5b, 0xd8, 0xc7, 0x12, 0x74, 0x7a, 0x9c, 0x83, 0xc2, 0xf2, 0x8d, 0x47, 0x65, 0xc1, 0xab, 0x9e, 0x51, 0xb9, 0x9f, 0x27, 0x5e, 0x24, 0x26, 0x04}}, - {{0x6a, 0xa1, 0xac, 0x08, 0x7b, 0x58, 0x2e, 0xf3, 0xd6, 0x18, 0xd1, 0xa0, 0x54, 0x09, 0x0f, 0xef, 0x1b, 0x71, 0x93, 0x0f, 0x0e, 0x0d, 0x3a, 0x66, 0x86, 0x15, 0xc2, 0x09, 0x89, 0xd9, 0xa9, 0x3b}, {0x9b, 0xf3, 0xfa, 0x78, 0x69, 0xfe, 0xb0, 0x67, 0x17, 0x88, 0x17, 0x5d, 0x97, 0x7c, 0x65, 0x43, 0x91, 0xd3, 0x26, 0x9a, 0x54, 0x39, 0x34, 0x36, 0x1d, 0xd6, 0x05, 0x3c, 0xa5, 0x61, 0x12, 0x29}}, - {{0x35, 0x49, 0xd9, 0x16, 0xdc, 0xf8, 0x13, 0xb2, 0xd8, 0xb3, 0x3f, 0x8b, 0xb9, 0x5b, 0x08, 0x6c, 0xcb, 0x61, 0x23, 0xa3, 0x12, 0x77, 0x8e, 0x3c, 0xbf, 0x8d, 0x91, 0x96, 0x28, 0x53, 0x86, 0x11}, {0x61, 0x04, 0x95, 0xc3, 0x6f, 0x6a, 0x0f, 0xdd, 0x9a, 0x8b, 0x0a, 0xf3, 0xec, 0xcd, 0x2e, 0x40, 0x82, 0x9c, 0x3d, 0x4a, 0x42, 0x54, 0xc0, 0x63, 0x34, 0x47, 0x01, 0xe6, 0xb0, 0x87, 0x3b, 0x1e}}, - {{0xaa, 0xf8, 0x25, 0x3f, 0x22, 0xfe, 0xbf, 0xd2, 0x9a, 0x89, 0xe3, 0x88, 0xd2, 0xda, 0x13, 0x3d, 0x96, 0x17, 0x47, 0x10, 0x2b, 0x04, 0x0c, 0xe4, 0xa4, 0xb7, 0xb9, 0xb2, 0x5f, 0x35, 0xef, 0x20}, {0xb7, 0x4e, 0xa4, 0x05, 0x90, 0xfc, 0x84, 0x25, 0x5e, 0x28, 0x60, 0xe8, 0xaa, 0x0f, 0x3d, 0xc7, 0xf6, 0x93, 0xce, 0x9d, 0xb5, 0xe4, 0xa9, 0xa3, 0xfa, 0x73, 0x67, 0x5a, 0x64, 0x47, 0x02, 0x10}}, - {{0x9d, 0xee, 0x5f, 0xf0, 0xef, 0xd4, 0x4d, 0xb4, 0x04, 0xaf, 0xc3, 0x57, 0x5e, 0xe3, 0x11, 0xd3, 0xe0, 0xac, 0x35, 0xdf, 0x48, 0xe7, 0xfa, 0x6a, 0x05, 0xaf, 0x5c, 0xed, 0xbf, 0x47, 0x52, 0x28}, {0x59, 0x59, 0x09, 0x04, 0xc4, 0xbb, 0xe1, 0x67, 0x06, 0xc6, 0xce, 0xf1, 0x3c, 0x02, 0x64, 0x10, 0x2c, 0x8d, 0x55, 0x77, 0x93, 0x7b, 0xea, 0x12, 0xa4, 0x0d, 0xca, 0xa6, 0x5a, 0x9d, 0xe6, 0x14}}, - {{0x58, 0xbf, 0xcc, 0x41, 0xa1, 0x64, 0xad, 0x3d, 0x96, 0x6d, 0xbb, 0xe1, 0x95, 0xcc, 0x45, 0xcd, 0x44, 0x9f, 0x68, 0xc1, 0x71, 0x10, 0x71, 0x4f, 0x2c, 0x60, 0xad, 0x35, 0xce, 0x27, 0x42, 0x0f}, {0x5c, 0xf6, 0x2a, 0xe7, 0x24, 0x05, 0xef, 0x54, 0xbc, 0xdf, 0x2e, 0x43, 0x83, 0x4d, 0xaf, 0x7b, 0x17, 0x99, 0xeb, 0xb7, 0xfb, 0x4b, 0x79, 0x34, 0x5e, 0x3f, 0x75, 0xbc, 0xf2, 0x5f, 0xad, 0x1b}}, - {{0xa0, 0xe4, 0xb4, 0x6e, 0x23, 0x63, 0xdf, 0x17, 0x73, 0xb9, 0x80, 0xc2, 0x58, 0x1e, 0x9a, 0xec, 0x17, 0xe2, 0xab, 0x12, 0xad, 0x46, 0x8d, 0x5a, 0xa4, 0x79, 0x1f, 0x4b, 0xcc, 0x2e, 0x22, 0x02}, {0xc3, 0xcf, 0x7e, 0x62, 0x6b, 0xc2, 0xc6, 0x8d, 0xac, 0xfe, 0x57, 0x8c, 0x92, 0x34, 0xd4, 0xca, 0x1e, 0x76, 0x01, 0xf2, 0x7f, 0xc5, 0x7e, 0x4c, 0x9f, 0xa0, 0xec, 0xeb, 0xc9, 0x19, 0x7a, 0x1a}}, - {{0x8f, 0x3e, 0xf4, 0xde, 0x3a, 0xd3, 0xdd, 0xfb, 0x0a, 0xe3, 0x0f, 0x0b, 0x5d, 0x1c, 0x50, 0xd6, 0x1b, 0xef, 0xc8, 0xc4, 0x34, 0xfd, 0xd5, 0x6f, 0x4e, 0x3a, 0xb3, 0xc8, 0xbe, 0x4f, 0x7e, 0x33}, {0xb1, 0x6f, 0x98, 0x7c, 0x11, 0x53, 0x9a, 0xfe, 0x9c, 0x89, 0x12, 0xd1, 0xee, 0xd9, 0xfe, 0x90, 0x14, 0x88, 0x71, 0xc1, 0xdb, 0x19, 0x35, 0xa9, 0x32, 0xf1, 0x42, 0x2e, 0x59, 0xd8, 0x32, 0x1a}}, - {{0x4c, 0xab, 0x95, 0xd5, 0x0e, 0x57, 0x1f, 0xbd, 0xeb, 0xbc, 0x17, 0xdc, 0x9e, 0x06, 0x11, 0x2e, 0xe8, 0x93, 0xd2, 0x02, 0xf5, 0x4e, 0x63, 0x5c, 0xc5, 0x53, 0x7b, 0x9d, 0x9d, 0x94, 0xe4, 0x3b}, {0xac, 0x0e, 0xc0, 0x6c, 0x6a, 0x45, 0x87, 0xf0, 0xeb, 0xed, 0xb7, 0x73, 0x24, 0x67, 0x8e, 0xb6, 0x99, 0x9a, 0x91, 0x83, 0x52, 0xe5, 0x48, 0x95, 0xd6, 0xb5, 0xae, 0x04, 0x1f, 0x0f, 0x07, 0x01}}, - {{0x17, 0x6e, 0x62, 0x32, 0xea, 0x9a, 0x3a, 0x49, 0x69, 0xe9, 0xb2, 0x74, 0x15, 0x4c, 0x8e, 0x7b, 0x98, 0xca, 0xf2, 0xb5, 0xb6, 0x61, 0x53, 0x80, 0xa3, 0x79, 0x92, 0x17, 0x01, 0xc5, 0xd7, 0x39}, {0xe9, 0xf2, 0xdc, 0x43, 0x19, 0x5c, 0xd3, 0x53, 0x60, 0x32, 0xbf, 0x47, 0x4f, 0x60, 0x13, 0xba, 0x6a, 0x59, 0x46, 0x4d, 0xe7, 0xb8, 0x24, 0x83, 0xeb, 0x45, 0xd8, 0xb7, 0xdb, 0x9b, 0x82, 0x18}}, - {{0xe8, 0xe9, 0x83, 0xf1, 0x51, 0x0a, 0x27, 0x0d, 0x03, 0x8f, 0x66, 0x30, 0xf9, 0xa7, 0x76, 0xd2, 0xe9, 0x88, 0x5d, 0x9e, 0xb5, 0x97, 0x8d, 0xd4, 0xe1, 0x44, 0xa1, 0x45, 0x90, 0xee, 0x8a, 0x0e}, {0x40, 0xbb, 0xa0, 0x3f, 0x9f, 0x4a, 0x18, 0x28, 0x64, 0xaf, 0x50, 0x04, 0xd0, 0xac, 0x0f, 0x71, 0x9f, 0x6e, 0x74, 0x19, 0xdf, 0x4b, 0x0f, 0x90, 0xd4, 0x76, 0x15, 0x21, 0xa3, 0x2d, 0xa4, 0x27}}, - {{0x8d, 0x66, 0xdc, 0x37, 0x40, 0xcf, 0x89, 0xb6, 0x28, 0xc4, 0x2d, 0x14, 0x01, 0x0a, 0x77, 0x93, 0xfd, 0x08, 0x78, 0xc8, 0xc4, 0xea, 0x34, 0x31, 0xed, 0x68, 0x65, 0x80, 0x61, 0x90, 0xfc, 0x3a}, {0xb6, 0x57, 0xad, 0x3f, 0x3d, 0x7d, 0xc7, 0x60, 0xb3, 0x59, 0xaa, 0x34, 0xbc, 0x9e, 0xf4, 0x59, 0x84, 0x73, 0x0a, 0x0c, 0x09, 0xd0, 0x63, 0x9d, 0xce, 0x61, 0x86, 0xbc, 0x58, 0xc3, 0x59, 0x25}}, - {{0xb4, 0x79, 0x5c, 0x14, 0x92, 0x56, 0x09, 0x5c, 0xb4, 0xb0, 0xbd, 0x49, 0x5f, 0xbb, 0x8b, 0xda, 0xd7, 0x9d, 0xbf, 0x9d, 0x94, 0x2c, 0x35, 0x41, 0x78, 0x81, 0x74, 0x9e, 0x79, 0xdc, 0x53, 0x04}, {0x39, 0x95, 0xc7, 0x07, 0x05, 0x9f, 0x01, 0xda, 0x32, 0x6d, 0xef, 0x2a, 0xd5, 0x45, 0x39, 0xe6, 0xe2, 0x39, 0x43, 0x49, 0xc6, 0x4e, 0x19, 0x41, 0x44, 0xfd, 0x81, 0xbe, 0x55, 0xef, 0xa2, 0x2e}}, - {{0x92, 0xf8, 0xbe, 0x04, 0xa9, 0x4f, 0x9f, 0xf4, 0xfb, 0x3f, 0x00, 0x37, 0x8b, 0x97, 0xdc, 0x62, 0xa6, 0x44, 0x63, 0x42, 0x25, 0xe6, 0x02, 0x67, 0xfc, 0x7e, 0x8e, 0xdc, 0x2c, 0xe1, 0x3b, 0x3b}, {0x90, 0x10, 0xe4, 0x93, 0x7f, 0xe6, 0xbd, 0x10, 0x1e, 0x99, 0xb0, 0xec, 0x1e, 0xa1, 0xcc, 0x8c, 0x00, 0xe4, 0x8a, 0xeb, 0xf0, 0x72, 0xdd, 0x50, 0xad, 0x8a, 0x87, 0xa7, 0x56, 0xdb, 0x3c, 0x3f}}, - {{0x30, 0xb4, 0xf4, 0x55, 0xa6, 0x53, 0x0a, 0xff, 0x6b, 0x8e, 0x1c, 0x84, 0xa2, 0x41, 0xbe, 0x0f, 0xda, 0x24, 0x34, 0x55, 0x49, 0x62, 0x4a, 0xe4, 0xf3, 0xe4, 0xd9, 0xcf, 0x83, 0xd1, 0x16, 0x3d}, {0x0d, 0x01, 0x12, 0x4a, 0x47, 0x7a, 0x73, 0xf1, 0x0c, 0x01, 0xe3, 0x5a, 0x20, 0x2a, 0x86, 0x33, 0xb2, 0x6e, 0xc9, 0x7c, 0x8c, 0xac, 0x75, 0x94, 0x7e, 0x78, 0xe3, 0x92, 0xba, 0xed, 0x5e, 0x2d}}, - {{0xc8, 0x8b, 0xb6, 0x3a, 0xcc, 0xbd, 0x32, 0xec, 0xa8, 0x6b, 0x05, 0x82, 0x8d, 0xc6, 0xf1, 0x5e, 0x0a, 0x23, 0x0f, 0x76, 0xb1, 0xc6, 0x79, 0x2a, 0x02, 0xac, 0x42, 0x48, 0x07, 0xc0, 0x69, 0x02}, {0xd7, 0x0d, 0xf7, 0xac, 0x73, 0x6a, 0xa5, 0xde, 0x2c, 0xd3, 0x05, 0xd6, 0xfd, 0x24, 0xae, 0xef, 0x8f, 0x8a, 0x72, 0x5a, 0x79, 0x01, 0x44, 0x76, 0x0d, 0xcf, 0x3b, 0xee, 0x35, 0x59, 0xbf, 0x29}}, - {{0xe0, 0x57, 0x28, 0xd9, 0xa4, 0xfc, 0xec, 0xaf, 0x2a, 0x46, 0x8d, 0x2d, 0x25, 0x4a, 0xef, 0xa2, 0x08, 0x8c, 0x1f, 0x7b, 0xd2, 0x1c, 0x9c, 0x3f, 0x4e, 0xe7, 0x86, 0xae, 0x65, 0xe8, 0x06, 0x3f}, {0xce, 0x5c, 0x2a, 0x54, 0xc6, 0x60, 0xca, 0x2b, 0x45, 0x1f, 0xf9, 0xdd, 0xca, 0xa0, 0x17, 0x20, 0xcf, 0xb9, 0x03, 0xf1, 0x4f, 0x6a, 0xe1, 0x9e, 0x2a, 0xdd, 0x80, 0x45, 0xec, 0x5b, 0x95, 0x37}}, - {{0xc6, 0xed, 0xcf, 0xc1, 0xb4, 0xe4, 0x91, 0x86, 0x13, 0xfd, 0x20, 0x81, 0x8c, 0x46, 0xf6, 0xb4, 0x89, 0xdc, 0x26, 0xb8, 0x17, 0x75, 0xb1, 0x05, 0x0c, 0x71, 0xef, 0x3c, 0x68, 0x35, 0x61, 0x0c}, {0x59, 0x1c, 0xe2, 0x6b, 0x5f, 0x02, 0x19, 0xb1, 0xda, 0x34, 0x1a, 0xcc, 0xd4, 0xc8, 0x0e, 0xe6, 0xff, 0x34, 0x7a, 0xbd, 0xf8, 0xa8, 0xba, 0x61, 0xba, 0xd3, 0x33, 0xa4, 0x98, 0x2a, 0x27, 0x1c}}, - {{0xc4, 0x53, 0x9b, 0x22, 0x6e, 0x8f, 0x75, 0xc7, 0x4f, 0x83, 0xd4, 0x1f, 0xe3, 0x14, 0x87, 0x81, 0xf4, 0xb1, 0x92, 0x52, 0x14, 0x1c, 0x72, 0x9b, 0xa0, 0x69, 0x85, 0xfd, 0x5e, 0x63, 0xd0, 0x2a}, {0x3e, 0xd8, 0x19, 0xa1, 0xe7, 0xb6, 0x9a, 0x35, 0xf0, 0x1e, 0x64, 0x1f, 0x63, 0xfc, 0x8f, 0x59, 0xfd, 0x20, 0x92, 0x77, 0x2b, 0x4b, 0x4e, 0x44, 0x79, 0x92, 0xc9, 0xe7, 0x58, 0x52, 0xdf, 0x03}}, - {{0x2e, 0x5e, 0x30, 0xbe, 0x61, 0x52, 0x34, 0x91, 0x74, 0x28, 0x7a, 0xa3, 0x1d, 0xa1, 0xd4, 0xe6, 0xec, 0xe7, 0x44, 0xb3, 0x1f, 0x28, 0x1c, 0xba, 0xb5, 0x88, 0xda, 0x58, 0xd7, 0xd9, 0x0d, 0x16}, {0x6a, 0x56, 0xfe, 0xbb, 0x8f, 0x8f, 0xde, 0xda, 0x5f, 0xf3, 0x23, 0x54, 0x26, 0x65, 0x00, 0x20, 0xa5, 0x22, 0xa6, 0x71, 0xf2, 0x01, 0x19, 0x0f, 0x20, 0x23, 0xcb, 0xfe, 0x3a, 0x50, 0xa0, 0x32}}, - {{0xba, 0x55, 0x17, 0x12, 0x97, 0x59, 0x83, 0x06, 0x1b, 0x2e, 0x30, 0x87, 0xd0, 0xc9, 0x57, 0x2a, 0x76, 0xd0, 0xdc, 0x3f, 0x7b, 0xc5, 0x07, 0x8f, 0xb5, 0x13, 0x11, 0xec, 0xaf, 0xb2, 0x49, 0x08}, {0x2d, 0x88, 0x27, 0x9c, 0x61, 0x53, 0xd6, 0x13, 0x93, 0x5d, 0x0f, 0xa6, 0x8a, 0x02, 0xd9, 0x84, 0xf2, 0x62, 0xfa, 0x33, 0x7b, 0x43, 0xee, 0xf1, 0x1d, 0x97, 0xdb, 0x3f, 0xe4, 0x0d, 0x6f, 0x0c}}, - {{0x67, 0xef, 0x93, 0x97, 0x04, 0x44, 0x23, 0x6e, 0x41, 0x3c, 0x92, 0x4c, 0xe5, 0x90, 0xd5, 0x7c, 0xfe, 0x45, 0x11, 0x16, 0xd1, 0x0e, 0xdc, 0x27, 0xb1, 0xc9, 0xb4, 0xcf, 0xf4, 0x4e, 0xe0, 0x1c}, {0x67, 0xd3, 0xcf, 0xdd, 0x8f, 0x9f, 0x5b, 0xfd, 0xc2, 0xc9, 0x79, 0x93, 0xbd, 0xc6, 0x5d, 0x6a, 0xb8, 0x63, 0x7b, 0x52, 0xce, 0x9e, 0x97, 0xc2, 0x72, 0x2a, 0x0f, 0x58, 0x3d, 0x87, 0x3d, 0x32}}, - {{0x89, 0x7a, 0x1d, 0xc3, 0xc7, 0x82, 0xf9, 0x44, 0xb5, 0x60, 0x8d, 0x17, 0x59, 0xe8, 0x46, 0x98, 0xac, 0x70, 0xd6, 0x85, 0x97, 0x51, 0x0a, 0xa5, 0xb7, 0x56, 0x38, 0x91, 0x11, 0x87, 0x77, 0x07}, {0x4c, 0x05, 0x40, 0x70, 0x93, 0x50, 0xa1, 0x8f, 0x94, 0xb3, 0xa8, 0x84, 0xe4, 0x8d, 0xaf, 0xe0, 0x1d, 0x26, 0x8f, 0x46, 0x7f, 0xfa, 0xd9, 0x6e, 0x8a, 0x04, 0x70, 0x2f, 0x4c, 0x8f, 0xe0, 0x26}}, - {{0x15, 0x9b, 0x41, 0xbf, 0x6a, 0x36, 0x10, 0x16, 0xcf, 0x49, 0x04, 0xf5, 0xa5, 0x33, 0x95, 0x54, 0x94, 0x74, 0xb9, 0x34, 0x86, 0x74, 0x03, 0xff, 0x23, 0x6a, 0x09, 0xe5, 0x83, 0xde, 0xcd, 0x2c}, {0xb2, 0xd7, 0xfe, 0x1f, 0x25, 0xc7, 0x24, 0x97, 0xa7, 0xbb, 0xb7, 0xb3, 0xd1, 0xa2, 0x4a, 0x01, 0xb9, 0x03, 0xbd, 0x01, 0xab, 0xd6, 0x28, 0xed, 0xfd, 0x37, 0xc8, 0x3c, 0x55, 0x9a, 0xd8, 0x04}}, - {{0x3d, 0xce, 0xcb, 0xa8, 0xc7, 0x2d, 0x53, 0x50, 0x93, 0x6c, 0x79, 0x89, 0x1a, 0x68, 0x32, 0x93, 0x9f, 0x95, 0xaa, 0xe7, 0x55, 0xf3, 0x1c, 0x1b, 0x8b, 0xec, 0x97, 0x98, 0x61, 0xc4, 0x04, 0x0b}, {0x03, 0x60, 0xc2, 0xea, 0x15, 0x98, 0xc0, 0x91, 0x05, 0x8f, 0x52, 0x8b, 0x5a, 0xc9, 0x44, 0xdf, 0xc5, 0x96, 0xa2, 0x32, 0xb9, 0x53, 0x9d, 0xfb, 0x81, 0x94, 0x4d, 0x51, 0xc0, 0xa7, 0xf7, 0x05}}, - {{0xaa, 0xc3, 0x6a, 0xf3, 0xbd, 0x2e, 0xe8, 0xe9, 0xc6, 0x84, 0xe3, 0xdd, 0xba, 0x3a, 0x3c, 0xd6, 0xd2, 0x57, 0xd5, 0xbb, 0x94, 0x47, 0x65, 0xa0, 0xb4, 0x6b, 0xeb, 0xb8, 0xe3, 0x74, 0xf1, 0x2a}, {0x1c, 0xbc, 0x1c, 0xb6, 0x28, 0xec, 0xb7, 0xc1, 0xa5, 0xad, 0x44, 0x3b, 0xd9, 0x1f, 0xdf, 0xa6, 0xe1, 0x40, 0xb7, 0x54, 0xbd, 0x1f, 0xb4, 0x41, 0xae, 0xd6, 0x00, 0x62, 0xb5, 0xb7, 0xb6, 0x07}}, - {{0x25, 0x7c, 0x0c, 0xc6, 0xb1, 0x14, 0x09, 0xf8, 0xbb, 0x0b, 0xd2, 0xd9, 0x7a, 0x9d, 0x6e, 0xc9, 0x90, 0x60, 0x5a, 0x06, 0xb6, 0x14, 0xf1, 0x9b, 0x1c, 0x63, 0x99, 0x39, 0x75, 0xc0, 0xf3, 0x07}, {0x71, 0xfe, 0xfb, 0x41, 0x70, 0xa9, 0x84, 0x6d, 0xed, 0x6a, 0x32, 0x48, 0xcc, 0xf8, 0x67, 0x73, 0x0d, 0x98, 0x98, 0xb9, 0x9a, 0xb0, 0xa4, 0x9f, 0x9b, 0x9d, 0x81, 0x40, 0xf4, 0x51, 0xb5, 0x10}}, - {{0xeb, 0x06, 0x88, 0x84, 0x1f, 0x21, 0xb2, 0x13, 0x3f, 0xa9, 0xbd, 0x68, 0xe5, 0xa8, 0x61, 0x87, 0xdb, 0xbe, 0xc7, 0xb2, 0xb0, 0x18, 0x79, 0xfe, 0xe6, 0x66, 0xfa, 0xe7, 0x28, 0x94, 0xb8, 0x0e}, {0x0f, 0x02, 0xdd, 0x74, 0xd1, 0x5c, 0xae, 0xa4, 0xd5, 0xeb, 0xbc, 0xd7, 0x83, 0x74, 0x36, 0x0a, 0x9f, 0xb4, 0x89, 0xa5, 0x79, 0xe4, 0xee, 0x02, 0x02, 0x3d, 0x03, 0xf7, 0x3f, 0x44, 0x1f, 0x38}}, - {{0x6c, 0xab, 0xea, 0x65, 0x99, 0x72, 0xe9, 0xbf, 0x3e, 0x22, 0x96, 0xd1, 0x43, 0xc6, 0xd7, 0x91, 0xe2, 0x0e, 0xba, 0x2f, 0xe0, 0x1e, 0xc4, 0xc1, 0x11, 0x92, 0xd5, 0xee, 0x82, 0xa5, 0x91, 0x03}, {0x0a, 0x87, 0xbe, 0x5f, 0x50, 0xac, 0xf5, 0xf6, 0xb7, 0x10, 0xa9, 0xa3, 0x4f, 0xce, 0x32, 0x45, 0xfc, 0xed, 0x6f, 0x07, 0xdc, 0x95, 0x04, 0x2e, 0x8e, 0xc7, 0x70, 0xb0, 0x99, 0x68, 0x66, 0x25}}, - {{0x99, 0x46, 0x3a, 0xf7, 0xf8, 0x31, 0xd3, 0x59, 0x84, 0xec, 0x3e, 0x6b, 0x33, 0xa1, 0x9e, 0xb8, 0xda, 0x95, 0x8f, 0xe6, 0x92, 0x85, 0xbb, 0x67, 0xfc, 0xfa, 0xed, 0x03, 0x6e, 0x43, 0x17, 0x09}, {0x7e, 0x6f, 0x68, 0x77, 0x3f, 0xc1, 0x28, 0x27, 0xeb, 0xf8, 0x2a, 0xf4, 0xe8, 0xd6, 0x15, 0x26, 0x26, 0x57, 0xfb, 0x1f, 0x77, 0xdf, 0xc5, 0x5c, 0x97, 0xb4, 0x2d, 0x91, 0x9f, 0xeb, 0xa0, 0x00}}, - {{0xde, 0x61, 0xc1, 0x5f, 0xf7, 0x12, 0xa5, 0x45, 0x54, 0x55, 0x96, 0x3c, 0x44, 0xe3, 0xc6, 0x0f, 0xd0, 0xeb, 0x55, 0x21, 0xc5, 0x37, 0xea, 0x4f, 0x91, 0xe8, 0x9f, 0x59, 0xac, 0xcf, 0xc2, 0x07}, {0xbb, 0x02, 0x0c, 0x3c, 0x5d, 0x93, 0x2a, 0xd3, 0x9c, 0x5e, 0x2b, 0x43, 0x68, 0x1e, 0x63, 0x62, 0x93, 0xb3, 0x3d, 0x1f, 0xd2, 0xbe, 0x2c, 0x07, 0x16, 0x4b, 0xdc, 0x83, 0x49, 0xe7, 0xed, 0x28}}, - {{0xee, 0xba, 0xa8, 0x8d, 0x39, 0x48, 0xde, 0x06, 0xe0, 0xf4, 0x93, 0x02, 0xa7, 0x20, 0xcc, 0x68, 0x54, 0x76, 0x77, 0x24, 0xe2, 0xa9, 0x3f, 0xde, 0xb5, 0xbe, 0x6a, 0x17, 0x54, 0xfa, 0xd6, 0x3f}, {0x99, 0x97, 0xa7, 0xe5, 0x9f, 0xf5, 0x53, 0x53, 0x6d, 0xd4, 0x3b, 0xf8, 0x05, 0x1d, 0x82, 0x17, 0xc3, 0x5f, 0x5e, 0xa0, 0x8d, 0x07, 0x6d, 0x42, 0xe7, 0xd6, 0x43, 0x74, 0x06, 0xe8, 0x8e, 0x27}}, - {{0x63, 0x3f, 0x29, 0x83, 0xcb, 0x01, 0x62, 0xc0, 0xa8, 0x5c, 0xc3, 0xe6, 0x03, 0xbb, 0x12, 0x26, 0xb2, 0xb2, 0x5f, 0x48, 0xc9, 0xe8, 0xf4, 0x6c, 0x9e, 0xd8, 0x70, 0x35, 0x99, 0x2e, 0xf7, 0x1d}, {0xa7, 0x70, 0x6d, 0x1b, 0xc2, 0xd3, 0xa4, 0x78, 0x69, 0x2f, 0xc1, 0xb0, 0x2f, 0xc8, 0xd8, 0x14, 0xe3, 0x4a, 0x88, 0x49, 0xaa, 0x2d, 0x78, 0xf6, 0x4f, 0xfd, 0x12, 0xdf, 0xf4, 0xee, 0xd2, 0x35}}, - {{0xed, 0x19, 0xb0, 0x23, 0xcc, 0xfd, 0xae, 0xb4, 0x99, 0x99, 0x89, 0xc1, 0xb7, 0xa1, 0x89, 0xac, 0x2d, 0x0a, 0x7a, 0x4f, 0x65, 0x81, 0x5b, 0x3c, 0x3f, 0x1d, 0x65, 0x17, 0x69, 0x7d, 0xb3, 0x0a}, {0x10, 0x7b, 0x3d, 0xd0, 0x49, 0xf5, 0x30, 0xa1, 0xc7, 0xb8, 0x76, 0xaf, 0xa5, 0xfb, 0x3e, 0xfe, 0x68, 0x4d, 0x15, 0xd5, 0x92, 0xb2, 0x9c, 0x47, 0x37, 0x57, 0xd1, 0x7c, 0x27, 0xb1, 0xed, 0x08}}, - {{0x66, 0x9e, 0xd1, 0x4a, 0x81, 0x35, 0x50, 0x72, 0xc1, 0x09, 0xa2, 0x94, 0x01, 0x6a, 0xad, 0x9f, 0x13, 0x1a, 0x38, 0x01, 0x3f, 0x3f, 0x98, 0xea, 0x5b, 0x88, 0x1f, 0x78, 0x7c, 0xe9, 0xb3, 0x17}, {0xdf, 0xb6, 0x5d, 0x52, 0xed, 0x12, 0x1a, 0x87, 0xd7, 0xa3, 0x09, 0x59, 0xb0, 0x9d, 0xc2, 0xad, 0xce, 0xda, 0xcc, 0x70, 0x73, 0xdf, 0x07, 0x98, 0x04, 0x18, 0xe8, 0x16, 0xe8, 0xcb, 0xcc, 0x31}}, - {{0x1a, 0x30, 0x16, 0x85, 0xa3, 0xc7, 0xb6, 0x42, 0xec, 0x3f, 0xaa, 0x58, 0x4d, 0x54, 0x85, 0x64, 0x01, 0x2a, 0x25, 0x0c, 0xa4, 0x5c, 0x05, 0xe1, 0x85, 0x68, 0xe8, 0xad, 0xc5, 0xac, 0xed, 0x3c}, {0x0c, 0xc2, 0x63, 0xe5, 0xcc, 0xed, 0xe5, 0x4d, 0xea, 0x36, 0x36, 0x6a, 0xb7, 0x53, 0x79, 0x08, 0xa3, 0xa3, 0xca, 0xe6, 0x9c, 0xcf, 0xda, 0x1e, 0xb1, 0xb3, 0x98, 0x41, 0x15, 0xb4, 0x82, 0x3f}}, - {{0x58, 0x76, 0xf5, 0x15, 0x03, 0x61, 0x81, 0x27, 0x82, 0xa5, 0x1d, 0xa5, 0x79, 0xb7, 0xc0, 0xfc, 0xd7, 0xe1, 0xf2, 0x92, 0xf3, 0xbf, 0xdf, 0x99, 0x01, 0xae, 0x4d, 0xa8, 0x1e, 0x2f, 0x09, 0x1e}, {0x80, 0x20, 0xa2, 0x8e, 0xc5, 0x2b, 0x6f, 0x1e, 0x75, 0x5f, 0x99, 0x03, 0x5d, 0xb1, 0xd9, 0x8e, 0xaf, 0x20, 0x0e, 0x91, 0xa9, 0xeb, 0x7a, 0x72, 0xb1, 0xcb, 0x5a, 0x92, 0x55, 0xdc, 0xc6, 0x38}}, - {{0x47, 0x27, 0x22, 0xdb, 0x05, 0xbc, 0xfc, 0x91, 0x2c, 0x0c, 0x6b, 0x33, 0xc1, 0x36, 0xbc, 0x25, 0x63, 0x52, 0xfe, 0xdc, 0x49, 0xc9, 0xf4, 0x4d, 0x5a, 0xbe, 0x90, 0xec, 0x5b, 0x78, 0xec, 0x2e}, {0x65, 0x5b, 0xb1, 0xc1, 0x93, 0xfc, 0x7e, 0x4d, 0x6b, 0x98, 0xdc, 0x0f, 0xcc, 0xfa, 0xef, 0x2d, 0x4d, 0xa7, 0xa3, 0xca, 0xef, 0x98, 0x50, 0x12, 0xc1, 0x41, 0x83, 0x59, 0xfe, 0x77, 0x24, 0x06}}, - {{0xea, 0xe3, 0xd5, 0x55, 0x66, 0x7e, 0x3d, 0xb6, 0x87, 0xcc, 0x65, 0x61, 0xcb, 0xb4, 0x16, 0xfb, 0x90, 0x16, 0xe2, 0x6a, 0x4d, 0x6c, 0xd2, 0x36, 0x9d, 0x44, 0xf8, 0x81, 0x6c, 0xc7, 0x6a, 0x16}, {0x2b, 0x5c, 0x88, 0x93, 0x68, 0x39, 0xe2, 0x82, 0x30, 0x6a, 0xdf, 0x85, 0x98, 0x9d, 0x87, 0x1b, 0x04, 0xce, 0xad, 0x69, 0x6d, 0x15, 0x07, 0x54, 0xfa, 0xfa, 0xcc, 0xe5, 0x2d, 0xbd, 0x06, 0x09}}, - {{0x23, 0x78, 0x96, 0x97, 0x41, 0xcc, 0x7c, 0x73, 0x97, 0xec, 0x6f, 0x1f, 0xe0, 0x28, 0x07, 0x10, 0x24, 0x2d, 0x9e, 0xba, 0xd3, 0x08, 0x9b, 0xfc, 0x65, 0xc9, 0x40, 0x29, 0xe5, 0xaa, 0xf5, 0x06}, {0xbe, 0x43, 0x85, 0x28, 0xcd, 0x62, 0xf1, 0x28, 0x65, 0x38, 0xad, 0xfc, 0x0d, 0x68, 0x9e, 0x3f, 0xce, 0x13, 0xb3, 0x76, 0x21, 0x03, 0x61, 0x86, 0x2f, 0x37, 0xb9, 0xab, 0xcd, 0xd4, 0xbd, 0x14}}, - {{0xdf, 0x4e, 0x4e, 0xe7, 0xd7, 0xb3, 0x25, 0x6c, 0x39, 0x04, 0xad, 0x2e, 0x65, 0xae, 0xfb, 0x67, 0x51, 0x8a, 0x0b, 0xbf, 0x37, 0x08, 0x82, 0xc1, 0x84, 0x7d, 0xf3, 0x4d, 0x19, 0xce, 0xc9, 0x3b}, {0xb8, 0x40, 0xde, 0x98, 0x74, 0x2e, 0x05, 0x6a, 0xc7, 0x7f, 0x6d, 0x4c, 0x73, 0xa0, 0x78, 0xca, 0x62, 0xec, 0x69, 0x74, 0x26, 0xa1, 0x0a, 0x5a, 0xed, 0xc7, 0x0f, 0x85, 0x1c, 0x85, 0x17, 0x2f}}, - {{0x0d, 0xfc, 0x91, 0xfd, 0x3a, 0xc0, 0x17, 0x33, 0x3c, 0xa9, 0xa8, 0xfe, 0xcf, 0x9e, 0x0d, 0x38, 0x6e, 0xb8, 0x9f, 0x3a, 0xbc, 0xe1, 0xcd, 0x7e, 0xe3, 0xaf, 0xa4, 0x98, 0x7b, 0x3f, 0x70, 0x17}, {0xc7, 0xf2, 0xa0, 0xc9, 0x20, 0x50, 0x4b, 0xc5, 0x8c, 0xc9, 0xef, 0xad, 0xc3, 0x05, 0x6b, 0xc6, 0x10, 0x7d, 0x47, 0x8e, 0xae, 0xa7, 0x8d, 0xf3, 0xf5, 0xef, 0x1b, 0x9c, 0x9a, 0x0c, 0x84, 0x37}}, - {{0x1e, 0x82, 0x39, 0xa7, 0xfe, 0x7e, 0x93, 0x50, 0x6e, 0x10, 0xa1, 0xfa, 0xa2, 0x6c, 0xf8, 0x7f, 0xf1, 0x2c, 0x9d, 0x7e, 0x4b, 0x97, 0x2a, 0x25, 0x10, 0xb0, 0x2b, 0xd6, 0x9c, 0xd1, 0x69, 0x1b}, {0x4e, 0x84, 0xa2, 0x12, 0x7f, 0x5a, 0x6f, 0xc1, 0x14, 0x57, 0xad, 0x8e, 0xbb, 0xd0, 0x53, 0xae, 0x67, 0x4f, 0x66, 0x66, 0xf5, 0x0a, 0xc7, 0xa3, 0x76, 0x12, 0x51, 0x93, 0x8a, 0xb9, 0xcb, 0x3e}}, - {{0xe9, 0xf0, 0x48, 0xe8, 0x53, 0x48, 0xc5, 0xbd, 0x85, 0x24, 0x77, 0x1e, 0xbe, 0x67, 0x28, 0x1b, 0x94, 0x9e, 0xca, 0xda, 0x54, 0x15, 0xf5, 0xe0, 0x70, 0xb6, 0xc4, 0x89, 0x13, 0xda, 0x86, 0x11}, {0x00, 0x2b, 0x76, 0xc7, 0x05, 0x3d, 0x51, 0x16, 0x2b, 0x87, 0x5f, 0xb9, 0xa4, 0xe3, 0xb2, 0x20, 0x32, 0x13, 0xfc, 0x15, 0x39, 0xeb, 0x7c, 0xbf, 0x6a, 0x49, 0x90, 0xac, 0xcc, 0x5a, 0x23, 0x04}}, - {{0x9f, 0x25, 0x56, 0xd8, 0x5d, 0x7e, 0xb0, 0x01, 0xc1, 0xb0, 0x55, 0xa1, 0x8f, 0x20, 0x43, 0x7f, 0x73, 0x8b, 0x93, 0x21, 0x15, 0xe8, 0x28, 0x89, 0xac, 0x7e, 0x38, 0xa5, 0x14, 0x97, 0x8d, 0x17}, {0xbb, 0x46, 0x20, 0x4c, 0x8a, 0x65, 0xb4, 0xfc, 0x7f, 0xc7, 0x35, 0xa2, 0x82, 0xe4, 0xc7, 0x6b, 0xff, 0x88, 0xb7, 0x3f, 0xb0, 0xf7, 0xe8, 0x44, 0x42, 0x37, 0x04, 0x6e, 0x72, 0x77, 0xe7, 0x3c}}, - {{0xda, 0x91, 0x3e, 0xd4, 0xa0, 0xea, 0xee, 0x55, 0x27, 0x5f, 0xca, 0x78, 0x24, 0x60, 0x0e, 0xc9, 0x51, 0xe0, 0xb6, 0xcb, 0x40, 0xec, 0x2a, 0x6c, 0x7c, 0xbe, 0x48, 0x4a, 0x5c, 0x36, 0xff, 0x0b}, {0xc9, 0x8d, 0xea, 0xd8, 0x04, 0xef, 0x5a, 0x14, 0x4d, 0x41, 0xc8, 0xe5, 0x48, 0x9b, 0x56, 0x2d, 0x73, 0xfe, 0x8f, 0x06, 0x3a, 0x94, 0x1c, 0x78, 0x7b, 0xb9, 0x7a, 0x96, 0x38, 0x9f, 0x61, 0x33}}, - {{0xd4, 0x2b, 0x96, 0x79, 0xa5, 0x71, 0xbe, 0xac, 0x2b, 0xe7, 0xb9, 0x9c, 0x6b, 0x76, 0x08, 0x3a, 0x65, 0xb0, 0x3d, 0x53, 0x2c, 0xd8, 0x88, 0x15, 0xe6, 0xc3, 0x67, 0x77, 0xd1, 0xc1, 0xd6, 0x30}, {0x17, 0x6e, 0xe4, 0xef, 0xac, 0x0d, 0x52, 0x5d, 0x3f, 0x7d, 0xab, 0x6e, 0x1f, 0x65, 0x7a, 0xd8, 0xdb, 0xb6, 0x4e, 0x32, 0x1f, 0x59, 0x75, 0x6a, 0xe4, 0xd8, 0x74, 0x77, 0x98, 0x9a, 0x5d, 0x1a}}, - {{0x6b, 0xff, 0x01, 0xae, 0xe9, 0x72, 0x25, 0x02, 0x2b, 0x21, 0x36, 0xef, 0xd2, 0x1a, 0x5a, 0xce, 0xad, 0xb3, 0x3d, 0xda, 0x42, 0x0f, 0xc1, 0x14, 0x0e, 0x0f, 0xa9, 0x16, 0x5e, 0x62, 0x67, 0x22}, {0xec, 0x71, 0xd6, 0xd6, 0xd3, 0x5d, 0xf4, 0x7b, 0xac, 0xcc, 0x98, 0x11, 0x02, 0x0a, 0xbb, 0x01, 0xfa, 0x48, 0xfa, 0x24, 0xca, 0x34, 0xd0, 0x15, 0xe2, 0xc0, 0x76, 0xdd, 0x5b, 0x8c, 0xa8, 0x19}}, - {{0x2d, 0x1e, 0xfa, 0x34, 0xc1, 0x7c, 0xd9, 0xfd, 0x34, 0x81, 0xcf, 0x9c, 0x75, 0xb7, 0x14, 0x37, 0x77, 0x6b, 0x82, 0xd9, 0xe3, 0x7a, 0x6b, 0xb7, 0xa2, 0x91, 0xbd, 0xe1, 0x31, 0xf6, 0xcb, 0x1e}, {0xde, 0x4e, 0xd1, 0xea, 0xce, 0x00, 0x11, 0xb6, 0x3c, 0x63, 0xf7, 0x9b, 0x5c, 0xdc, 0x64, 0x9f, 0xe6, 0xc2, 0x6e, 0xf0, 0x26, 0x4d, 0x5e, 0x31, 0x26, 0x6f, 0x88, 0x50, 0x5a, 0x53, 0x4a, 0x02}}, - {{0x41, 0x23, 0xb6, 0x74, 0x1e, 0x4f, 0x75, 0x9c, 0xa1, 0x2c, 0xa3, 0xcf, 0xf2, 0xdb, 0x29, 0xc2, 0x78, 0x96, 0xb9, 0xe1, 0x06, 0xa0, 0x12, 0x80, 0x05, 0x22, 0x8e, 0x9f, 0xf4, 0x7d, 0x9a, 0x28}, {0x4c, 0x85, 0xcc, 0x14, 0xb7, 0x86, 0x92, 0xa2, 0x39, 0xb2, 0xb8, 0xba, 0x80, 0x5a, 0xc0, 0x63, 0xdf, 0x16, 0x93, 0x33, 0x5b, 0xa9, 0xbc, 0x77, 0x06, 0x6e, 0xc4, 0x67, 0xe8, 0x78, 0xa1, 0x0a}}, - {{0xfc, 0xb0, 0xeb, 0xab, 0x05, 0xe3, 0x83, 0x69, 0x24, 0xc6, 0xe4, 0xcd, 0x11, 0x86, 0x47, 0x40, 0xed, 0xb7, 0x7f, 0x55, 0xfe, 0xdb, 0xee, 0xcd, 0xd1, 0x18, 0x02, 0x8e, 0x14, 0x1c, 0xe8, 0x04}, {0x29, 0x06, 0xa8, 0x21, 0x33, 0x8d, 0x56, 0xe5, 0x53, 0xae, 0xbb, 0xf2, 0xe9, 0x66, 0xf8, 0x97, 0xbb, 0x2b, 0x02, 0x50, 0x4e, 0xb6, 0xa5, 0xce, 0x1a, 0xf5, 0xea, 0xac, 0xe0, 0x52, 0x34, 0x1a}}, - {{0x52, 0x2c, 0xc7, 0x8c, 0x17, 0xd7, 0x05, 0x34, 0x1b, 0x1e, 0x9a, 0x39, 0x04, 0xa5, 0xa7, 0x28, 0x44, 0xc8, 0xe9, 0xf7, 0x39, 0xe2, 0x70, 0xf1, 0x88, 0xdc, 0x69, 0xbb, 0x95, 0x63, 0xd3, 0x1c}, {0x2d, 0x8e, 0xe6, 0x04, 0x51, 0x0b, 0x5b, 0x67, 0x63, 0x21, 0xed, 0x1d, 0xcc, 0x6e, 0x7f, 0x18, 0x79, 0x70, 0xe3, 0x85, 0x1e, 0x42, 0x53, 0x1a, 0x51, 0x77, 0x2b, 0x75, 0xc7, 0xe3, 0x8a, 0x15}}, - {{0xd7, 0xcf, 0xa9, 0x12, 0x3e, 0x88, 0x00, 0x55, 0x53, 0x47, 0xbd, 0x12, 0x02, 0x04, 0xd8, 0x9c, 0xd5, 0xda, 0x2b, 0xf6, 0x54, 0x89, 0x75, 0x1f, 0xd0, 0xd2, 0xfe, 0xc2, 0x9c, 0xfa, 0xbb, 0x0b}, {0x8d, 0xa2, 0x24, 0x48, 0x09, 0xd9, 0xe6, 0x19, 0x51, 0x3e, 0x83, 0x98, 0xc0, 0xc4, 0xd6, 0x8c, 0x59, 0x6f, 0xcc, 0xbe, 0x4f, 0x19, 0x46, 0xb6, 0xe5, 0x13, 0x34, 0xd7, 0xec, 0xe2, 0x20, 0x34}}, - {{0x9e, 0xf6, 0x10, 0x16, 0xe3, 0xe5, 0xa9, 0x80, 0x20, 0x8e, 0x56, 0x10, 0x92, 0x4a, 0x9c, 0xdd, 0x56, 0x43, 0x5c, 0xc8, 0xb6, 0xae, 0x6c, 0xf8, 0x0d, 0x70, 0x4b, 0x5e, 0xcc, 0xdf, 0xad, 0x31}, {0x04, 0xdf, 0xe1, 0x79, 0x14, 0xd9, 0xab, 0xe9, 0xdc, 0x74, 0xf6, 0x36, 0xf3, 0x23, 0xf0, 0xb7, 0xb6, 0x8b, 0x13, 0x7f, 0x71, 0x33, 0xd2, 0xa9, 0x6f, 0x97, 0x34, 0xcb, 0x17, 0x26, 0x15, 0x1f}}, - {{0x78, 0x50, 0x22, 0xfb, 0xa3, 0x00, 0x0d, 0x96, 0x5f, 0x3f, 0x61, 0x0e, 0x56, 0x71, 0x88, 0x99, 0xeb, 0xa3, 0xa6, 0xcc, 0x97, 0xaf, 0xba, 0xb2, 0xfd, 0xb5, 0x04, 0xc7, 0xe7, 0x19, 0x7f, 0x2e}, {0x09, 0xb2, 0xd9, 0x0d, 0x9f, 0x46, 0xbb, 0x57, 0x26, 0xbd, 0x4a, 0xc8, 0x86, 0x81, 0x40, 0x9c, 0x60, 0x97, 0x45, 0x24, 0xb7, 0x30, 0x13, 0x54, 0x50, 0xb8, 0x4f, 0xee, 0x77, 0x37, 0xa7, 0x3e}}, - {{0x53, 0x00, 0x88, 0xbe, 0x2d, 0x5e, 0x41, 0x62, 0x7a, 0x5f, 0x95, 0x05, 0x5b, 0x81, 0x5d, 0xe6, 0x74, 0x54, 0xe0, 0x43, 0xed, 0xe7, 0x5b, 0x6b, 0xff, 0x20, 0x3d, 0x01, 0x3c, 0xef, 0xf9, 0x29}, {0x1a, 0x71, 0xf0, 0xcf, 0x74, 0xe0, 0x5c, 0x64, 0xdc, 0x30, 0xe6, 0x0a, 0x5e, 0x6e, 0x08, 0x9b, 0xdf, 0x68, 0xf2, 0x7f, 0xe6, 0x5e, 0x65, 0x17, 0xa9, 0x62, 0xea, 0xe6, 0x0f, 0x19, 0x30, 0x28}}, - {{0x81, 0x42, 0x61, 0x9c, 0x8b, 0x56, 0xa6, 0xf9, 0xce, 0xd5, 0x46, 0xd5, 0x7b, 0xf3, 0xf3, 0x4b, 0x14, 0x7b, 0x74, 0x34, 0x10, 0x77, 0xfc, 0x47, 0xef, 0xf9, 0x6a, 0xf7, 0xa4, 0x2a, 0x46, 0x3a}, {0x79, 0x4c, 0xef, 0xae, 0xd7, 0x19, 0x0d, 0x48, 0x1d, 0x93, 0xfb, 0xae, 0x75, 0xe1, 0x60, 0xab, 0xb4, 0xa5, 0x1f, 0xc7, 0xd0, 0x85, 0x55, 0x4d, 0x35, 0x95, 0xd5, 0x97, 0x62, 0x8e, 0x96, 0x0a}}, - {{0xf9, 0x9d, 0xac, 0x24, 0x3f, 0x90, 0x36, 0xe4, 0xa6, 0x17, 0xa8, 0x1d, 0xf0, 0xdd, 0x00, 0x93, 0x2a, 0x93, 0xbc, 0xb4, 0x39, 0x68, 0x3e, 0x12, 0x7f, 0xd7, 0xfd, 0x35, 0x88, 0x84, 0x18, 0x27}, {0xbc, 0x46, 0x09, 0x9b, 0xbd, 0x7a, 0xe4, 0x52, 0xa5, 0xe4, 0xeb, 0x0f, 0xce, 0x3e, 0x85, 0xc0, 0x5d, 0x99, 0x7e, 0x34, 0xc8, 0x35, 0xf8, 0xf3, 0x24, 0xa2, 0xc0, 0x2c, 0x13, 0xe9, 0xde, 0x19}}, - {{0x58, 0xa7, 0xe6, 0xb4, 0xa9, 0x83, 0x53, 0xa4, 0x47, 0xe4, 0xc1, 0x23, 0xb5, 0x00, 0x15, 0x90, 0x36, 0x57, 0x26, 0x86, 0xc8, 0xc0, 0x5e, 0xe8, 0x5a, 0xf8, 0xc8, 0x40, 0xe6, 0xa8, 0x61, 0x14}, {0xc8, 0xb2, 0x72, 0xfd, 0xea, 0x08, 0x1d, 0x50, 0x03, 0xf4, 0x6d, 0x4f, 0x79, 0xec, 0x63, 0xeb, 0x19, 0x0d, 0x53, 0x1c, 0x50, 0xf2, 0xe3, 0xf1, 0xd8, 0x19, 0x3d, 0x69, 0x59, 0xd7, 0x2e, 0x06}}, - {{0x75, 0xfc, 0x49, 0xb2, 0x8d, 0xa3, 0xc4, 0xa2, 0x90, 0x85, 0xc7, 0x77, 0x21, 0x07, 0xe4, 0x8a, 0xa5, 0x9e, 0x5b, 0x8d, 0x04, 0x4b, 0xdc, 0x03, 0x7d, 0x31, 0x03, 0xe8, 0x38, 0x0d, 0x89, 0x0d}, {0xa7, 0xad, 0x58, 0x93, 0x60, 0xee, 0x10, 0x3e, 0x0e, 0xd7, 0x62, 0x08, 0xeb, 0x48, 0x09, 0x35, 0x1c, 0x8c, 0x5a, 0x18, 0xdf, 0x80, 0xaa, 0x75, 0x77, 0xa8, 0x27, 0xd0, 0x80, 0xc3, 0xe7, 0x37}}, - {{0xcf, 0x06, 0x9a, 0xf0, 0x65, 0xa5, 0xfd, 0xaa, 0xeb, 0x00, 0x68, 0xb6, 0xc0, 0xf0, 0xe9, 0x91, 0xeb, 0x5d, 0x9a, 0x9a, 0x61, 0x4a, 0x89, 0xba, 0xa5, 0x67, 0x2a, 0xa7, 0x2f, 0x6c, 0xab, 0x35}, {0x6f, 0xa2, 0xc1, 0xbb, 0x30, 0x58, 0x34, 0xdd, 0x47, 0x97, 0xc3, 0x6f, 0x0c, 0x14, 0xd2, 0xc3, 0x2c, 0xf6, 0xa3, 0xa4, 0xaa, 0x4a, 0x80, 0x65, 0x5f, 0x9e, 0x04, 0x1b, 0x2b, 0xda, 0x8a, 0x2c}}, - {{0x0f, 0x63, 0xad, 0x98, 0x6a, 0x24, 0x1e, 0x64, 0x2c, 0x2e, 0xb3, 0x19, 0xde, 0x91, 0xab, 0x72, 0x61, 0xb6, 0x69, 0x21, 0x4b, 0x77, 0x92, 0x5c, 0xcd, 0x61, 0xce, 0x70, 0x43, 0xc5, 0x1a, 0x1e}, {0x48, 0x84, 0x5b, 0x28, 0xf5, 0x3f, 0xb2, 0x9c, 0x27, 0x67, 0x31, 0xf3, 0x2b, 0xa4, 0xb4, 0x9b, 0x20, 0x47, 0x6e, 0xc8, 0x13, 0xa5, 0xdd, 0x62, 0x85, 0xae, 0xd0, 0x4f, 0xf0, 0xa0, 0x38, 0x21}}, - {{0xc0, 0xc2, 0xc8, 0x31, 0x30, 0x8a, 0xff, 0x05, 0xaf, 0x13, 0x7d, 0xb3, 0x8a, 0x4e, 0x0c, 0x32, 0x62, 0x0a, 0xe0, 0x7d, 0x92, 0x61, 0xe1, 0x5f, 0x01, 0xdf, 0x99, 0xc8, 0xec, 0x6e, 0x39, 0x32}, {0x0b, 0xdb, 0x4c, 0x25, 0xa7, 0x5a, 0x6a, 0xf8, 0x01, 0x40, 0x50, 0x7c, 0x43, 0x63, 0xf8, 0xff, 0x34, 0x28, 0xc4, 0x13, 0x31, 0xce, 0x7e, 0x90, 0x04, 0x4f, 0xf6, 0xfe, 0x20, 0x91, 0x83, 0x00}}, - {{0x05, 0x71, 0x0b, 0xe8, 0x15, 0x56, 0xa3, 0x0d, 0x68, 0xea, 0xf5, 0x83, 0xc7, 0x35, 0x0d, 0xcd, 0x84, 0xc7, 0x14, 0xfd, 0x17, 0x8f, 0x56, 0x19, 0x80, 0x5b, 0x21, 0x8e, 0x9d, 0x16, 0x44, 0x38}, {0x51, 0xed, 0x9b, 0x1c, 0xf4, 0x6f, 0xcc, 0x1f, 0x6b, 0xec, 0xd7, 0x5d, 0x81, 0x94, 0xe5, 0x34, 0x5d, 0x7c, 0xad, 0x7c, 0x16, 0xd3, 0xa0, 0x0b, 0x8e, 0x63, 0x8a, 0x39, 0x3c, 0xc8, 0xc0, 0x3e}}, - {{0x23, 0x9e, 0xa8, 0xca, 0x2a, 0xdd, 0xe3, 0x30, 0xaa, 0x34, 0x21, 0xa9, 0xc7, 0x24, 0x56, 0xca, 0x0a, 0x0c, 0x62, 0xbe, 0x5d, 0x4c, 0x9a, 0x56, 0xe1, 0x07, 0x64, 0xf0, 0x35, 0xf4, 0xb5, 0x0b}, {0x3b, 0xf5, 0x22, 0x5e, 0x97, 0xe1, 0xe8, 0xdf, 0xfb, 0xb1, 0x37, 0x71, 0xc5, 0xbe, 0xfa, 0x8d, 0x1a, 0xae, 0x85, 0xb6, 0x98, 0x9f, 0xe1, 0x01, 0xc1, 0xc2, 0x28, 0x05, 0x90, 0x14, 0xc1, 0x28}}, - {{0xf8, 0xe4, 0xd8, 0x0a, 0xce, 0xf7, 0xcc, 0x3d, 0x3b, 0x76, 0x9e, 0x19, 0x2e, 0x31, 0x8e, 0x58, 0x8d, 0x55, 0x25, 0x03, 0x2f, 0xa5, 0x6a, 0x8c, 0xf3, 0xf4, 0x72, 0xc6, 0x69, 0xba, 0xc4, 0x29}, {0xd7, 0x52, 0x71, 0x71, 0x18, 0xf2, 0xec, 0x19, 0x4e, 0xba, 0x38, 0xfa, 0x55, 0x7a, 0xee, 0x06, 0x95, 0xfd, 0x3c, 0x6c, 0xf2, 0xa4, 0xf0, 0xd8, 0x0c, 0x7f, 0xbb, 0x4d, 0xaf, 0x61, 0xf7, 0x3e}}, - {{0x75, 0x5f, 0xbb, 0x04, 0xad, 0xba, 0x0f, 0x1f, 0xf0, 0xe2, 0xf4, 0x56, 0xb6, 0x02, 0xef, 0x4a, 0xa4, 0x8e, 0xa0, 0xb8, 0xff, 0x9b, 0x89, 0x4c, 0x8d, 0x70, 0xc7, 0xa1, 0x2c, 0x7e, 0x4e, 0x3f}, {0xbf, 0x9b, 0x9c, 0x1c, 0x10, 0x7a, 0xf6, 0x02, 0xd6, 0x8a, 0xa2, 0x8b, 0xdb, 0x0c, 0xf3, 0x05, 0xe2, 0xa8, 0x60, 0x15, 0x9a, 0xc4, 0x3a, 0xc1, 0x18, 0x59, 0x35, 0x94, 0xdb, 0xbe, 0x34, 0x15}}, - {{0x23, 0xbe, 0x10, 0xb8, 0xff, 0x6d, 0x87, 0xfa, 0x41, 0x20, 0x75, 0xe0, 0xe1, 0x0c, 0xc7, 0x72, 0xef, 0x3c, 0x1f, 0x51, 0x38, 0xbf, 0xc8, 0x07, 0x5b, 0xe2, 0x1b, 0xed, 0x3e, 0x5f, 0x6c, 0x1a}, {0xb0, 0x65, 0xfa, 0x85, 0xae, 0xc0, 0xdd, 0x51, 0x47, 0x3f, 0xc3, 0x4c, 0xca, 0x4d, 0x5b, 0x83, 0x07, 0x68, 0x1a, 0x22, 0xbd, 0x02, 0xd6, 0x1b, 0x9f, 0xae, 0x90, 0x8a, 0x1a, 0x3d, 0xc2, 0x32}}, - {{0x0d, 0x96, 0x14, 0xa1, 0x2c, 0x53, 0xed, 0x0e, 0x0d, 0x03, 0x45, 0x97, 0x07, 0x2d, 0x83, 0x69, 0x92, 0x87, 0x97, 0xc5, 0x0e, 0x8c, 0xb8, 0x0c, 0xbc, 0x8f, 0xbd, 0xba, 0xf3, 0x46, 0xd4, 0x3e}, {0xbb, 0x6e, 0xe7, 0x7c, 0x62, 0x95, 0xa7, 0x2f, 0x0b, 0x5e, 0x86, 0x7c, 0x19, 0x50, 0x21, 0x7e, 0x09, 0x26, 0x16, 0x0b, 0x86, 0x69, 0x0e, 0x6d, 0xbd, 0x9d, 0xd2, 0x03, 0x03, 0xa8, 0xed, 0x17}}, - {{0x6e, 0x4f, 0x75, 0x28, 0x7f, 0xf0, 0xdd, 0x5a, 0x69, 0x6e, 0x38, 0xce, 0x19, 0x10, 0xd2, 0xde, 0x46, 0x45, 0x46, 0xd1, 0x0e, 0x5d, 0x11, 0xba, 0x7b, 0xd5, 0xf7, 0x6b, 0xf5, 0xad, 0xb8, 0x1c}, {0x9f, 0x5c, 0x67, 0x30, 0xe7, 0x43, 0xb3, 0x74, 0x0c, 0x25, 0x38, 0xc0, 0x6c, 0x1a, 0xbe, 0xaa, 0x68, 0xeb, 0x5c, 0x7c, 0x02, 0x58, 0xf9, 0x8e, 0xf3, 0xcb, 0x34, 0xb6, 0x08, 0x23, 0xf7, 0x26}}, - {{0xa3, 0x09, 0x2a, 0x2e, 0xd0, 0x9c, 0x97, 0xe6, 0xb6, 0x08, 0x41, 0xb1, 0xb4, 0x1a, 0xb4, 0xbf, 0x61, 0x57, 0xb0, 0x2c, 0x81, 0xdd, 0x0d, 0x29, 0x82, 0xe5, 0x10, 0x8d, 0x2d, 0x64, 0x6c, 0x2a}, {0xa4, 0x84, 0x3e, 0xe1, 0x2a, 0x8a, 0x36, 0x85, 0xd2, 0x86, 0x9e, 0x49, 0xb2, 0x6c, 0xce, 0x9e, 0x11, 0x68, 0x4e, 0x1f, 0x04, 0x03, 0xd1, 0xa6, 0x0b, 0xc0, 0x4f, 0x29, 0x86, 0x35, 0x49, 0x17}}, - {{0xec, 0xc9, 0x88, 0xb2, 0x33, 0xf9, 0x00, 0xd0, 0x6c, 0xf8, 0xfc, 0xb1, 0x27, 0xfa, 0x08, 0x00, 0xf6, 0x0a, 0xde, 0x5e, 0x36, 0xdc, 0xb8, 0x77, 0x26, 0x3f, 0xeb, 0x59, 0x2d, 0xea, 0x9d, 0x28}, {0xfc, 0x4d, 0x6e, 0x2b, 0xad, 0x9a, 0xe9, 0x6e, 0x8d, 0x5c, 0xb5, 0x63, 0xfb, 0xf9, 0x57, 0xa3, 0x10, 0xd7, 0xa8, 0x98, 0xc4, 0x03, 0x9d, 0xb9, 0x19, 0x4f, 0xc3, 0x9d, 0x80, 0xb9, 0xfd, 0x2c}}, - {{0xdf, 0x5c, 0xbd, 0xfa, 0x4b, 0xf2, 0x3f, 0x4a, 0xe8, 0x20, 0x33, 0x36, 0xb3, 0x5b, 0x15, 0x74, 0xb6, 0xa3, 0xa6, 0x99, 0xd9, 0xad, 0x05, 0xf6, 0x58, 0x3f, 0xa5, 0x3d, 0xf1, 0x39, 0x65, 0x03}, {0x08, 0xc4, 0x59, 0x04, 0x10, 0xe9, 0xa5, 0x4a, 0x99, 0x30, 0xfc, 0xdb, 0xe4, 0xd4, 0xdf, 0xe4, 0xae, 0x8b, 0xe1, 0x47, 0x1e, 0x6d, 0xe4, 0xec, 0x52, 0x0f, 0xaf, 0x3a, 0xf8, 0xfb, 0x71, 0x25}}, - {{0xf0, 0x56, 0xa6, 0x6f, 0x5a, 0x75, 0x8b, 0xc0, 0xa6, 0x19, 0x58, 0x35, 0xd2, 0xcb, 0x17, 0xac, 0x9f, 0xd5, 0xde, 0x76, 0xa9, 0x63, 0x1d, 0x0e, 0x71, 0xcd, 0x8f, 0x06, 0xcc, 0xba, 0x0d, 0x0f}, {0x36, 0xc2, 0x66, 0xd3, 0x17, 0x88, 0xb6, 0x9a, 0xd7, 0x5f, 0x88, 0x3f, 0x76, 0x42, 0xda, 0x7a, 0xec, 0x44, 0xe3, 0x9f, 0x4f, 0xde, 0x3d, 0x08, 0x09, 0x4d, 0xf7, 0xca, 0x93, 0xe1, 0xde, 0x33}}, - {{0x6e, 0xb4, 0x87, 0x28, 0xfd, 0x8b, 0x95, 0x35, 0x28, 0x4e, 0xbe, 0xf1, 0x01, 0x91, 0x38, 0x5f, 0xd5, 0x08, 0xed, 0x99, 0xba, 0xac, 0xd1, 0xf9, 0x3e, 0x37, 0x73, 0xfa, 0x66, 0xa6, 0xae, 0x34}, {0xc2, 0x6c, 0x69, 0xb2, 0x6d, 0x38, 0x50, 0x85, 0xc0, 0x9e, 0x04, 0x85, 0x6f, 0xf2, 0xe0, 0xac, 0x54, 0x54, 0x3d, 0x9d, 0x6d, 0xd4, 0x1e, 0x8e, 0xee, 0xae, 0x44, 0x5b, 0xd8, 0x82, 0x78, 0x09}}, - {{0x60, 0xa7, 0x35, 0x54, 0xa0, 0x19, 0x37, 0x13, 0xd0, 0xfa, 0xce, 0x0f, 0xb7, 0x3a, 0x59, 0xeb, 0x3a, 0x85, 0x0d, 0xbf, 0xa8, 0x89, 0x6b, 0x06, 0x6e, 0x01, 0xf7, 0x1b, 0x20, 0xdf, 0x05, 0x1a}, {0xc6, 0x6a, 0x88, 0x7e, 0x8a, 0x56, 0xf0, 0x69, 0x0d, 0x88, 0xb8, 0xcc, 0x1a, 0xfb, 0xd1, 0x90, 0xf4, 0x03, 0x87, 0x0f, 0x9b, 0xcb, 0xf3, 0x81, 0xcf, 0x6e, 0x36, 0xa9, 0x89, 0x03, 0xe5, 0x28}}, - {{0x15, 0xd7, 0xdd, 0x64, 0x29, 0x3f, 0xbb, 0x50, 0x06, 0x77, 0x3f, 0xdc, 0xa6, 0xf9, 0xaa, 0xd5, 0x3d, 0x3c, 0x9c, 0xc4, 0x33, 0x14, 0x6d, 0x6e, 0x40, 0x44, 0x06, 0xb0, 0x90, 0x0e, 0x87, 0x1a}, {0x67, 0x2a, 0xfe, 0x9f, 0x0d, 0x8f, 0x4a, 0x8f, 0xb2, 0xe8, 0x3d, 0x8b, 0x37, 0xff, 0xf7, 0x3d, 0x4a, 0x22, 0xe5, 0xb2, 0x50, 0xac, 0x00, 0xe2, 0xd6, 0x19, 0x5f, 0x62, 0x75, 0xbe, 0xa8, 0x2e}}, - {{0xa6, 0x84, 0xdf, 0x79, 0xae, 0xf3, 0x52, 0x93, 0xd2, 0x7c, 0x1e, 0xb9, 0x6a, 0xc7, 0x21, 0xd8, 0x9b, 0x36, 0xe5, 0xaf, 0x7d, 0x8b, 0x16, 0x15, 0x01, 0x28, 0x5f, 0xed, 0xb3, 0xd1, 0xb2, 0x39}, {0xed, 0xcd, 0xc0, 0x4a, 0xd3, 0xc8, 0xc1, 0xe3, 0xb2, 0x12, 0xb8, 0x7f, 0xbb, 0x48, 0x67, 0x24, 0xca, 0xe9, 0x23, 0x9a, 0xf6, 0x46, 0x8d, 0xf1, 0x73, 0x57, 0xbd, 0x3c, 0xbf, 0x73, 0xb1, 0x12}}, - {{0x4d, 0xc7, 0x6a, 0x47, 0x07, 0xcb, 0x92, 0x0d, 0xa2, 0x9e, 0xe5, 0x91, 0x2a, 0xb8, 0x79, 0x91, 0xe0, 0xf5, 0x92, 0xd6, 0xb3, 0x3a, 0xfc, 0xd5, 0x50, 0x3a, 0xc3, 0x00, 0xd0, 0xef, 0xee, 0x3d}, {0xcd, 0x43, 0x32, 0xfa, 0x44, 0x70, 0x37, 0xce, 0x83, 0xa1, 0x75, 0xa9, 0xca, 0x04, 0xea, 0x23, 0x71, 0xb8, 0x62, 0xec, 0x2e, 0xb0, 0xa3, 0x3a, 0xf0, 0x8e, 0x58, 0xc5, 0x11, 0x21, 0xa9, 0x04}}, - {{0x5f, 0x66, 0xa5, 0x7d, 0x02, 0xa1, 0x97, 0xdc, 0x18, 0x58, 0xfd, 0xce, 0x5d, 0x5b, 0xbb, 0xa1, 0x71, 0x35, 0xcd, 0x62, 0x76, 0x1a, 0x4e, 0x7b, 0x70, 0x2d, 0x76, 0x52, 0x9b, 0xd9, 0xa3, 0x3a}, {0x59, 0x77, 0xc3, 0xfe, 0x36, 0x79, 0xbd, 0x94, 0x3c, 0x5a, 0x2e, 0x23, 0x55, 0x4b, 0x16, 0x72, 0x71, 0xb2, 0xbd, 0x52, 0xa2, 0xe2, 0x6b, 0x75, 0x3b, 0x6f, 0x56, 0xd6, 0x74, 0xbb, 0xf2, 0x33}}, - {{0xb9, 0xd9, 0xdc, 0xd6, 0x56, 0x72, 0xfd, 0xc8, 0x5e, 0x7f, 0x65, 0x7f, 0xd8, 0xc9, 0x03, 0xca, 0xdb, 0x46, 0xf6, 0x2b, 0xfa, 0x43, 0x39, 0xfd, 0x91, 0xa5, 0x99, 0x63, 0x4f, 0x59, 0xc1, 0x22}, {0x6c, 0x06, 0xbe, 0x58, 0x89, 0x1b, 0xd3, 0xa3, 0x51, 0xd7, 0x71, 0x43, 0x4c, 0xdf, 0x76, 0x37, 0x87, 0x7a, 0x00, 0x00, 0xcd, 0x1d, 0x4f, 0x6b, 0x19, 0xe2, 0x33, 0xa4, 0xe9, 0x83, 0x6d, 0x3a}}, - {{0xa1, 0x8c, 0x9d, 0x74, 0xca, 0x92, 0xac, 0x2b, 0xc1, 0x64, 0x83, 0xd9, 0x6a, 0xb7, 0xff, 0xcd, 0x66, 0xe2, 0x4b, 0x07, 0x43, 0x9e, 0x71, 0x4a, 0x31, 0x3d, 0xf1, 0x4a, 0x9f, 0x19, 0x1d, 0x21}, {0x72, 0x3f, 0x8a, 0x7d, 0x75, 0xf3, 0x5c, 0x61, 0xcf, 0xe0, 0x25, 0x2b, 0x4e, 0x0a, 0x71, 0xe2, 0x0f, 0x18, 0xe1, 0xa9, 0xf8, 0x62, 0x7e, 0xe0, 0x63, 0x46, 0x8f, 0xd2, 0x69, 0x51, 0x68, 0x36}}, - {{0x11, 0x72, 0x25, 0xa0, 0x2b, 0xb9, 0x26, 0x50, 0x8b, 0x55, 0x03, 0x2a, 0x9a, 0xbe, 0x61, 0x0f, 0xce, 0x57, 0x58, 0xc5, 0xce, 0x4f, 0xb5, 0x6e, 0xd7, 0x6b, 0x0e, 0x38, 0xa0, 0x20, 0x93, 0x31}, {0xa8, 0xf6, 0x4a, 0x55, 0x43, 0x1d, 0xe5, 0x6f, 0x72, 0xf9, 0xc9, 0xb9, 0xc0, 0x48, 0xf0, 0x6f, 0x77, 0x04, 0xa3, 0x07, 0xca, 0x7b, 0xf3, 0xb6, 0xa1, 0x6e, 0x97, 0xf3, 0x0c, 0x08, 0xb4, 0x01}}, - {{0x83, 0xbf, 0xc5, 0x21, 0xb2, 0x14, 0x85, 0x0c, 0xe3, 0xf1, 0x86, 0xf7, 0xf8, 0xf7, 0x65, 0x6a, 0x46, 0xf0, 0x5b, 0x86, 0x2c, 0x3a, 0x45, 0x3c, 0x07, 0xe7, 0xc1, 0xfb, 0x3f, 0x8c, 0xe2, 0x18}, {0xbd, 0x60, 0xe0, 0x19, 0x90, 0x7e, 0x11, 0xb3, 0x79, 0xf2, 0xd5, 0x85, 0x29, 0xb0, 0x2c, 0x68, 0x80, 0x3c, 0xf3, 0xac, 0x39, 0x18, 0x07, 0x2d, 0x2a, 0x25, 0xe4, 0x09, 0x5a, 0xbe, 0xfb, 0x24}}, - {{0xdd, 0x13, 0x30, 0xfd, 0x49, 0x13, 0x38, 0x3f, 0xc4, 0xac, 0xf9, 0x64, 0x2c, 0x3f, 0xa3, 0x50, 0x52, 0x48, 0xae, 0xea, 0x9a, 0xc2, 0xfc, 0xbd, 0x1f, 0x4d, 0x7e, 0x73, 0xf1, 0xe7, 0xcd, 0x08}, {0xf9, 0xcf, 0x2e, 0x0d, 0xf1, 0x95, 0xeb, 0xc9, 0xb8, 0x7c, 0xfa, 0xe8, 0x1e, 0x09, 0x16, 0x2e, 0xdf, 0x87, 0xb1, 0xb2, 0x45, 0xd5, 0x38, 0x23, 0xa5, 0x39, 0x4a, 0x93, 0xcd, 0x01, 0x9c, 0x2f}}, - {{0x32, 0xdd, 0x98, 0xfa, 0x86, 0x24, 0x4f, 0x2f, 0x02, 0xab, 0x29, 0x94, 0xb9, 0x50, 0xb3, 0x5a, 0x09, 0xfb, 0xf9, 0x67, 0x08, 0x5b, 0x00, 0x4d, 0x4c, 0xfb, 0x44, 0x62, 0x28, 0x1b, 0x79, 0x37}, {0xed, 0x19, 0x70, 0xad, 0x41, 0x1b, 0x7a, 0xf3, 0xf3, 0xef, 0x04, 0x04, 0x91, 0x62, 0x58, 0x3d, 0x31, 0x71, 0x0b, 0x69, 0x64, 0x9d, 0x10, 0x37, 0x01, 0x0a, 0x8a, 0x64, 0x2b, 0xfe, 0x3d, 0x32}}, - {{0xac, 0x90, 0x4c, 0x42, 0x63, 0x1b, 0x99, 0x2c, 0xb1, 0x19, 0x01, 0x92, 0x48, 0xe1, 0xe0, 0xcd, 0xdd, 0x23, 0x4e, 0xa9, 0xcd, 0xcd, 0x0a, 0x6b, 0x5b, 0xa2, 0x67, 0x54, 0x85, 0xec, 0x83, 0x0a}, {0xf5, 0x5f, 0x29, 0xe0, 0x56, 0xb4, 0xae, 0xe2, 0x9e, 0x0f, 0xd4, 0x95, 0x7e, 0x15, 0xf2, 0xbb, 0x23, 0x21, 0x86, 0x52, 0x85, 0x83, 0xf3, 0xfc, 0x60, 0x18, 0x21, 0x63, 0xb8, 0xc6, 0xd4, 0x09}}, - {{0x6a, 0xdd, 0x8a, 0xb6, 0x9b, 0x26, 0x98, 0x5a, 0x2a, 0xb2, 0x39, 0x46, 0x41, 0xb9, 0xfe, 0x1e, 0x2b, 0x62, 0xae, 0x46, 0x04, 0x1c, 0x71, 0x35, 0x04, 0xc4, 0xe2, 0x61, 0x4e, 0x0c, 0x24, 0x07}, {0x79, 0xbf, 0xe0, 0xb9, 0xc5, 0x32, 0xf2, 0x4e, 0x79, 0x46, 0xb9, 0x82, 0x6d, 0x2c, 0x49, 0x28, 0xce, 0x5a, 0x95, 0xd5, 0x62, 0xc1, 0xc9, 0x6d, 0x4b, 0x7e, 0x46, 0xcb, 0xc9, 0x46, 0xa1, 0x23}}, - {{0x44, 0x57, 0x88, 0x16, 0x67, 0xe4, 0xa6, 0x0e, 0x51, 0x0f, 0x06, 0x3c, 0xa9, 0xc7, 0x3a, 0xd7, 0xf0, 0x0f, 0x11, 0x09, 0xef, 0x3e, 0x46, 0x1b, 0xb0, 0x15, 0x2b, 0x8b, 0x1b, 0x1a, 0xf5, 0x25}, {0xf0, 0xcf, 0x47, 0xd8, 0xd7, 0x24, 0x94, 0x0e, 0x22, 0x4d, 0xd3, 0xc8, 0x26, 0x1c, 0xca, 0x9e, 0x8a, 0x35, 0x71, 0xa0, 0xf4, 0x44, 0x7c, 0x3e, 0xcc, 0x2a, 0x85, 0x9e, 0x55, 0x3e, 0xe0, 0x02}}, - {{0x8c, 0x54, 0x72, 0x4f, 0x63, 0xe9, 0xf6, 0xfa, 0x18, 0x30, 0xcb, 0x06, 0x78, 0x66, 0xba, 0x75, 0xd0, 0x1e, 0xa6, 0xf6, 0xc1, 0x4d, 0x5c, 0xdd, 0x11, 0x7d, 0x9c, 0x96, 0x4a, 0xaa, 0x8a, 0x35}, {0xf7, 0x26, 0x41, 0x0b, 0x8c, 0xb8, 0x92, 0x71, 0x72, 0xd6, 0x73, 0x51, 0xaa, 0x5f, 0xbf, 0xdc, 0x6b, 0x38, 0xc5, 0xd7, 0x7b, 0x3f, 0x44, 0x28, 0x82, 0x88, 0x54, 0x0d, 0x2d, 0x62, 0x26, 0x03}}, - {{0x8d, 0xf0, 0x49, 0x16, 0x20, 0x86, 0x1d, 0xf3, 0xdb, 0x1c, 0x2e, 0xc6, 0xc9, 0x50, 0xc2, 0x1f, 0x8b, 0x30, 0x2a, 0xc1, 0x7f, 0x7d, 0xa2, 0x3f, 0xd6, 0x40, 0x2b, 0x3f, 0x98, 0x76, 0x7a, 0x08}, {0x1f, 0xcf, 0x1a, 0xf1, 0xf8, 0x55, 0xfe, 0x1d, 0xef, 0x34, 0x95, 0x99, 0xfd, 0xc9, 0x33, 0xee, 0x18, 0x23, 0xaa, 0x68, 0x6a, 0x77, 0x06, 0xc3, 0xac, 0x64, 0xf0, 0x37, 0xfb, 0x5a, 0xc3, 0x2a}}, - {{0x97, 0x34, 0xe3, 0xe5, 0xe8, 0xcf, 0xde, 0x3a, 0xed, 0xcb, 0x4a, 0x37, 0x0f, 0x93, 0x41, 0x6c, 0xd8, 0x8a, 0xa8, 0xc7, 0x64, 0xf8, 0xb0, 0x12, 0x58, 0x25, 0xf4, 0x97, 0xb0, 0xdf, 0x0f, 0x37}, {0x99, 0xcf, 0xb5, 0x1a, 0xe4, 0xb1, 0x20, 0x72, 0x3c, 0x62, 0x9c, 0x77, 0xde, 0x92, 0x32, 0x16, 0xe7, 0x86, 0x4a, 0x4b, 0x22, 0x00, 0x34, 0xb0, 0x5b, 0x92, 0xf2, 0x6e, 0xa2, 0xaf, 0x9b, 0x30}}, - {{0x27, 0x51, 0xc0, 0xf9, 0x12, 0x50, 0x06, 0x34, 0x75, 0x4b, 0x00, 0x99, 0x19, 0xf4, 0x28, 0xc8, 0xf3, 0xe3, 0x80, 0xf4, 0x1d, 0xa1, 0xd7, 0xf6, 0x07, 0xf2, 0x42, 0xfc, 0x46, 0x2d, 0x33, 0x2d}, {0xe3, 0x6e, 0x68, 0x9e, 0x50, 0x62, 0x46, 0x2e, 0x25, 0x5e, 0x9e, 0xdf, 0x7c, 0xde, 0xfd, 0xab, 0xd5, 0x75, 0x02, 0x4b, 0x95, 0x0e, 0x57, 0xfd, 0x13, 0x9a, 0xea, 0x28, 0x02, 0xef, 0x77, 0x24}}, - {{0xbe, 0x58, 0xca, 0x76, 0x2f, 0xe2, 0x3e, 0xbc, 0x0b, 0xc5, 0x9b, 0xd5, 0xd8, 0x77, 0xa8, 0x3e, 0x46, 0xd7, 0x8b, 0x77, 0x65, 0x9b, 0x8b, 0xa8, 0x63, 0x15, 0x82, 0xa6, 0x81, 0x76, 0xc6, 0x3a}, {0x0c, 0xa6, 0xa2, 0x75, 0xa1, 0x26, 0x2d, 0x01, 0x0e, 0x52, 0x9e, 0x5b, 0x75, 0x16, 0x93, 0xd2, 0x04, 0x08, 0x0a, 0xf9, 0xb2, 0x81, 0xb3, 0x7b, 0x89, 0x7a, 0xde, 0x70, 0x0d, 0xbb, 0xa1, 0x33}}, - {{0x90, 0xee, 0x44, 0x84, 0xca, 0xc9, 0xca, 0xb0, 0x61, 0x1d, 0x27, 0xff, 0xad, 0x19, 0x8e, 0x96, 0x6b, 0xf6, 0x5a, 0x83, 0x09, 0x3e, 0x26, 0x3f, 0x64, 0x0c, 0x1c, 0xda, 0xf7, 0x71, 0xbd, 0x05}, {0x82, 0x25, 0x85, 0x6f, 0xce, 0xde, 0xe9, 0x61, 0xf5, 0xc9, 0xf5, 0x5d, 0xee, 0x17, 0xd1, 0xe5, 0x47, 0x81, 0x5d, 0xbc, 0x5f, 0x5b, 0xd6, 0xa3, 0x4e, 0x75, 0x3c, 0x1b, 0x9c, 0x82, 0x58, 0x3b}}, - {{0x80, 0xef, 0x9c, 0xb5, 0x16, 0x91, 0xe8, 0x39, 0x99, 0x9a, 0x8d, 0x86, 0x15, 0x3f, 0xee, 0xe8, 0x44, 0x84, 0xd5, 0xa5, 0xdd, 0x6a, 0x32, 0x4b, 0x66, 0x9f, 0xf7, 0x9f, 0x02, 0x94, 0xfe, 0x14}, {0xcb, 0xb5, 0x12, 0x00, 0x20, 0x40, 0x66, 0x8f, 0x13, 0xfa, 0x37, 0x15, 0x79, 0xc9, 0xcc, 0x6f, 0x82, 0x82, 0x6a, 0x38, 0xcc, 0x3e, 0x9e, 0xd1, 0xdd, 0x74, 0x5c, 0x6d, 0x85, 0xc7, 0x2c, 0x16}}, - {{0xaf, 0x88, 0xfe, 0x07, 0x8e, 0x2e, 0xc0, 0xdc, 0x34, 0xf8, 0xae, 0xff, 0x17, 0x2a, 0x3b, 0xbd, 0xd5, 0x78, 0x0b, 0x64, 0x98, 0x32, 0x6f, 0x0c, 0x56, 0xcf, 0x10, 0xe0, 0x83, 0xa6, 0xa4, 0x34}, {0x33, 0xea, 0x73, 0x72, 0xee, 0xab, 0xf3, 0x63, 0xa5, 0x92, 0x0b, 0x04, 0x2e, 0x70, 0x37, 0x05, 0xc9, 0x3b, 0xd6, 0x8d, 0xc3, 0x6e, 0x7d, 0x54, 0x45, 0x15, 0x8a, 0x75, 0x12, 0x5b, 0x64, 0x00}}, - {{0x75, 0x51, 0x0f, 0xb3, 0x91, 0x7e, 0x8e, 0xee, 0x4f, 0x2a, 0xb1, 0x98, 0x8b, 0x32, 0x18, 0x91, 0xf5, 0x2e, 0x19, 0xce, 0x43, 0x7d, 0x6b, 0x0c, 0xc2, 0x77, 0x07, 0xf7, 0x45, 0x65, 0x83, 0x26}, {0x29, 0xf8, 0xd5, 0x8f, 0x0b, 0x78, 0x98, 0xd7, 0xa4, 0xeb, 0x78, 0x02, 0x5e, 0xa0, 0x68, 0xc4, 0xc1, 0x7a, 0x64, 0x00, 0x3c, 0xf1, 0xfa, 0xb7, 0x76, 0xd1, 0xa4, 0x3b, 0xee, 0x6a, 0x2a, 0x32}}, - {{0xdd, 0x13, 0x89, 0x61, 0xd6, 0x4d, 0x3b, 0x1e, 0x94, 0x8f, 0x95, 0xda, 0xdd, 0xf2, 0x8b, 0x24, 0x26, 0x18, 0xe1, 0x97, 0x26, 0x48, 0x16, 0x82, 0xec, 0xdc, 0xe7, 0xa5, 0x98, 0x93, 0xac, 0x21}, {0xf4, 0x3f, 0x4c, 0x5b, 0x75, 0x8d, 0x2d, 0x77, 0xe3, 0xbc, 0xdf, 0xff, 0xf9, 0xd0, 0x77, 0x76, 0x1f, 0x40, 0x8e, 0xa2, 0x08, 0xb8, 0xa3, 0x10, 0x6e, 0xc8, 0x49, 0xb3, 0x46, 0x5b, 0x6e, 0x3f}}, - {{0x7c, 0x36, 0xbe, 0xf1, 0x87, 0xd8, 0x85, 0x55, 0x59, 0xb6, 0x3a, 0xa5, 0x5a, 0xcc, 0x07, 0xaf, 0x46, 0x17, 0xa8, 0x35, 0xe1, 0x92, 0x3e, 0x92, 0x83, 0xf1, 0x4d, 0xf2, 0x8c, 0x26, 0xf2, 0x3b}, {0x4d, 0xa7, 0x78, 0x5e, 0x73, 0x04, 0xe6, 0x6f, 0x47, 0x84, 0x46, 0xb7, 0x91, 0x90, 0xa1, 0x39, 0xeb, 0xcb, 0xed, 0xb7, 0x5e, 0xc4, 0x94, 0xa5, 0xc3, 0xec, 0xca, 0x4c, 0xda, 0x13, 0xc9, 0x0b}}, - {{0x03, 0x49, 0x37, 0xc5, 0x2c, 0x2c, 0xd4, 0x1d, 0x61, 0xae, 0x39, 0xd4, 0xe7, 0x7d, 0xcd, 0xa6, 0x07, 0x4b, 0x7a, 0x3b, 0x7f, 0x89, 0xdb, 0x15, 0xd7, 0x3d, 0x51, 0xce, 0xf8, 0x81, 0x5c, 0x38}, {0xc9, 0x8d, 0x9e, 0x19, 0x1c, 0x0b, 0xd8, 0x0e, 0xed, 0x39, 0x1d, 0x5b, 0x22, 0x67, 0xe2, 0x79, 0x2f, 0x07, 0x0b, 0x6c, 0x41, 0x79, 0x04, 0x8b, 0x34, 0xd9, 0x25, 0x53, 0x37, 0xa6, 0x07, 0x15}}, - {{0x35, 0x46, 0xad, 0x84, 0xeb, 0x86, 0x31, 0xaf, 0x36, 0x03, 0xd3, 0xcc, 0x31, 0x63, 0x79, 0xa7, 0x1f, 0x67, 0x7c, 0xc6, 0xe2, 0x6c, 0x28, 0xf1, 0x0a, 0x7c, 0xb2, 0x5c, 0x69, 0xb4, 0xc1, 0x00}, {0xda, 0xa3, 0xae, 0x1c, 0x0e, 0xbe, 0x4f, 0x7c, 0x18, 0xbe, 0x48, 0x02, 0xad, 0x1b, 0x7b, 0xc1, 0x61, 0x6c, 0x0f, 0xc5, 0x03, 0xf9, 0xdd, 0xbd, 0xe7, 0x03, 0xa9, 0xea, 0x5e, 0x84, 0x3f, 0x2f}}, - {{0x7f, 0x14, 0x4b, 0x26, 0x10, 0x66, 0x38, 0x73, 0x05, 0x70, 0x18, 0xe0, 0xe6, 0xea, 0x8a, 0xe7, 0xfc, 0xb8, 0x92, 0x6e, 0x4d, 0x4f, 0x9e, 0x90, 0x28, 0x3f, 0xb4, 0x98, 0xc4, 0x33, 0xec, 0x20}, {0xea, 0x3e, 0x07, 0x55, 0xa1, 0xea, 0xa8, 0x29, 0x0f, 0x1b, 0x31, 0x2a, 0x7c, 0x22, 0x9d, 0x72, 0x1b, 0x65, 0xee, 0x6d, 0x99, 0x9c, 0x54, 0xb1, 0xf5, 0x17, 0x24, 0x8a, 0xc3, 0x2a, 0x60, 0x30}}, - {{0xe7, 0xd1, 0x38, 0xfc, 0x32, 0x0f, 0xa1, 0x3f, 0x12, 0x2e, 0x0c, 0xd0, 0x6c, 0x71, 0x30, 0x11, 0x07, 0xcf, 0x9c, 0xbb, 0xee, 0xe7, 0x7b, 0x8b, 0xc8, 0xb4, 0x25, 0x7c, 0x4e, 0x0d, 0xdc, 0x03}, {0x4e, 0x49, 0xf0, 0x1c, 0x2f, 0x2d, 0x37, 0xcc, 0xcb, 0xa7, 0x3f, 0x69, 0x71, 0x19, 0x81, 0xf2, 0x89, 0xd7, 0x12, 0x01, 0x23, 0x57, 0xc8, 0x71, 0x5a, 0xd3, 0x68, 0xde, 0x62, 0x40, 0x3a, 0x0b}}, - {{0xf5, 0x3c, 0xe6, 0x8f, 0x5d, 0x96, 0x57, 0x2e, 0x2f, 0xb4, 0xcf, 0x96, 0x75, 0x03, 0x7d, 0x1e, 0x21, 0xf2, 0x71, 0xe0, 0xfa, 0xac, 0xeb, 0xe4, 0x6b, 0xb9, 0xa9, 0x25, 0xaa, 0x30, 0xc8, 0x18}, {0xa5, 0xdb, 0x45, 0xb1, 0x55, 0xc9, 0x35, 0x1e, 0x55, 0x8c, 0x66, 0x4c, 0x39, 0xa2, 0xbf, 0x38, 0xe5, 0x44, 0xe1, 0x0a, 0xc0, 0xb6, 0x79, 0x2b, 0x18, 0xde, 0x1a, 0x2a, 0xf2, 0x70, 0x06, 0x33}}, - {{0x2c, 0x52, 0x89, 0x80, 0x7d, 0xc1, 0x37, 0x03, 0x93, 0x1e, 0x09, 0xe5, 0xf9, 0xb7, 0xf3, 0x8c, 0x82, 0x28, 0xf9, 0x5b, 0x95, 0x00, 0xc2, 0x30, 0x8f, 0x30, 0x74, 0x34, 0x94, 0x6e, 0x03, 0x18}, {0xbb, 0xf3, 0xab, 0x14, 0x60, 0xe9, 0xac, 0x83, 0x48, 0xa2, 0x58, 0x67, 0x89, 0x4c, 0xe9, 0x39, 0x78, 0x22, 0xbb, 0xba, 0xaf, 0x4e, 0x82, 0x3b, 0xbe, 0xab, 0x0e, 0x77, 0x8a, 0xdc, 0xfc, 0x05}}, - {{0xec, 0x11, 0xdc, 0xa6, 0x9f, 0xaf, 0x15, 0x4d, 0x56, 0xb7, 0x83, 0xfa, 0xf7, 0xb4, 0x88, 0x96, 0x12, 0x2c, 0x56, 0xc5, 0x92, 0x95, 0x00, 0xa9, 0xa9, 0x76, 0x3e, 0xc2, 0xb2, 0xf9, 0x31, 0x31}, {0xd1, 0x17, 0x8d, 0x41, 0x0b, 0xbc, 0x77, 0x63, 0x5e, 0x20, 0xa8, 0xa1, 0x2f, 0xc6, 0xc7, 0xbd, 0xe1, 0x27, 0x75, 0xdc, 0x8c, 0xe5, 0x08, 0xb8, 0xa0, 0x0a, 0xea, 0x42, 0x6a, 0x9a, 0xe3, 0x3c}}, - {{0xe0, 0xaa, 0x95, 0x1b, 0x61, 0x36, 0x9c, 0x91, 0x29, 0x1f, 0x70, 0x85, 0xf5, 0xad, 0xc0, 0x21, 0x95, 0x7e, 0x43, 0x0a, 0x24, 0xa8, 0xd8, 0x15, 0x50, 0xe2, 0x5b, 0x97, 0x7f, 0x0e, 0x87, 0x24}, {0x8f, 0x4f, 0x25, 0xd3, 0x42, 0xf9, 0x8a, 0x2b, 0x03, 0x28, 0x0e, 0x9d, 0x93, 0xf2, 0xbf, 0xb8, 0x11, 0x36, 0xe5, 0xfd, 0x01, 0x14, 0x36, 0x2b, 0xe0, 0x6f, 0x25, 0x1e, 0x3d, 0x97, 0x5f, 0x09}}, - {{0xf7, 0xaf, 0xd7, 0xaf, 0x69, 0xca, 0xb5, 0x25, 0x5f, 0x96, 0x67, 0xb6, 0x1b, 0x76, 0x31, 0x57, 0xf6, 0xd5, 0x78, 0xe0, 0x00, 0x80, 0xdb, 0xf0, 0x6c, 0x48, 0x6f, 0x9a, 0x51, 0xd6, 0x5f, 0x10}, {0x25, 0x3a, 0xdf, 0x4e, 0x18, 0x7c, 0xed, 0xf6, 0xc1, 0x26, 0x4c, 0xb5, 0xfc, 0xd2, 0x16, 0xf7, 0x0a, 0xc7, 0xf8, 0xde, 0x72, 0x30, 0x03, 0x83, 0xa8, 0xd8, 0xf9, 0xc6, 0xcc, 0x43, 0x72, 0x3c}}, - {{0x13, 0x29, 0xaf, 0xa1, 0x40, 0xf5, 0x9a, 0xd2, 0x9a, 0xf0, 0x00, 0xed, 0x75, 0x17, 0xf8, 0x86, 0xb6, 0xfc, 0x96, 0x79, 0x8d, 0x72, 0x78, 0xc9, 0xcf, 0x2b, 0x52, 0x5c, 0xcf, 0xc4, 0xaa, 0x15}, {0xa2, 0x65, 0xf6, 0x5b, 0x65, 0x8b, 0xad, 0xcc, 0x0a, 0x8a, 0x3d, 0xfe, 0x29, 0x44, 0x7e, 0x19, 0xef, 0xf7, 0xc8, 0xcb, 0x82, 0x5a, 0x26, 0xbc, 0x7a, 0xcc, 0x33, 0x0c, 0xe9, 0x7b, 0x63, 0x09}}, - {{0x63, 0xf1, 0xa5, 0x9c, 0xce, 0x37, 0xdc, 0x75, 0x67, 0x0d, 0x01, 0xf8, 0x1c, 0x4f, 0xe4, 0x3c, 0x70, 0xae, 0x04, 0xd3, 0x6f, 0x91, 0x33, 0x19, 0xd0, 0x3e, 0xa7, 0x3d, 0x82, 0x28, 0xc9, 0x09}, {0x29, 0x8d, 0x35, 0xeb, 0x5b, 0x78, 0x1a, 0x14, 0x36, 0xca, 0xb8, 0x6b, 0x21, 0x75, 0xa1, 0x10, 0x26, 0x82, 0x64, 0x99, 0x7e, 0xd7, 0x51, 0xcd, 0x6c, 0xb5, 0x38, 0x25, 0xb1, 0x15, 0x96, 0x1d}}, - {{0xd3, 0x54, 0x57, 0x6f, 0xbd, 0xc1, 0x71, 0x7c, 0x6c, 0xb1, 0xdf, 0x95, 0x3d, 0x53, 0xa0, 0xc9, 0xc6, 0x86, 0xeb, 0x48, 0x60, 0x11, 0x45, 0xc9, 0x2e, 0x0d, 0x44, 0x8c, 0xf3, 0xf8, 0xa8, 0x05}, {0x60, 0xf4, 0x88, 0xcf, 0x95, 0x59, 0xd8, 0x11, 0x42, 0x3f, 0xbb, 0xf7, 0x8a, 0x7f, 0xeb, 0x44, 0x5b, 0xea, 0xee, 0x79, 0x43, 0xbb, 0x8c, 0xbe, 0x86, 0x2f, 0x50, 0xed, 0x8f, 0xb9, 0xdc, 0x02}}, - {{0x15, 0xa9, 0x5d, 0x4d, 0xbe, 0xae, 0xa2, 0x4a, 0xec, 0x62, 0x33, 0xb9, 0xb2, 0x6c, 0x25, 0x34, 0x07, 0x66, 0x44, 0x6a, 0x1e, 0xad, 0x29, 0xd2, 0xf8, 0xcb, 0x5f, 0xe6, 0xb2, 0xe2, 0xfd, 0x35}, {0xc0, 0x7c, 0x0a, 0xe1, 0xcc, 0xe5, 0x36, 0x9a, 0x9e, 0x8e, 0x42, 0x64, 0xbf, 0xad, 0x41, 0x7d, 0xc3, 0xdd, 0x7d, 0xe7, 0xb0, 0xaa, 0x4a, 0xc6, 0x86, 0xb0, 0x17, 0xdd, 0x44, 0xce, 0xb6, 0x28}}, - {{0x09, 0xde, 0x57, 0xc7, 0x3e, 0xf0, 0x29, 0x17, 0xd6, 0xdd, 0xae, 0x3c, 0x98, 0xd5, 0x14, 0x87, 0xbe, 0x5c, 0xf8, 0x76, 0x1b, 0x98, 0xbc, 0x46, 0xb6, 0x34, 0xd4, 0x98, 0x5d, 0x7a, 0x7c, 0x1b}, {0xfc, 0xfa, 0x97, 0x0f, 0x81, 0x88, 0x61, 0xfb, 0x00, 0x7d, 0x44, 0x47, 0x53, 0x12, 0x9e, 0x76, 0x66, 0xac, 0x37, 0x6b, 0xe5, 0x94, 0x66, 0xe1, 0xd6, 0x40, 0xa4, 0xaa, 0x2c, 0x59, 0x0d, 0x0e}}, - {{0x74, 0x4e, 0x9a, 0x7b, 0x1c, 0x69, 0x77, 0xb4, 0x8a, 0x99, 0x73, 0xb2, 0xa0, 0xea, 0x61, 0x1c, 0x38, 0x87, 0x69, 0xa8, 0x04, 0x2b, 0x95, 0x92, 0xcb, 0x31, 0x4d, 0xf9, 0xc7, 0xd1, 0xae, 0x18}, {0xa0, 0x3a, 0xa0, 0x91, 0x02, 0xa1, 0xb4, 0x63, 0xe8, 0xe2, 0x00, 0xcd, 0x59, 0x6a, 0x56, 0x84, 0xea, 0x99, 0xfb, 0xf4, 0x76, 0x8f, 0xac, 0xd9, 0x6c, 0x00, 0x19, 0x1f, 0x3c, 0xc3, 0x9a, 0x24}}, - {{0x29, 0xc1, 0xd9, 0x9d, 0xc5, 0xc5, 0x11, 0xa6, 0x9a, 0x3b, 0x0c, 0x46, 0x1e, 0x43, 0x49, 0xb4, 0x07, 0x64, 0xac, 0x50, 0xde, 0x28, 0xca, 0x8a, 0x47, 0xef, 0xa7, 0xa7, 0xa6, 0xf2, 0xe1, 0x2b}, {0x52, 0x1f, 0xca, 0x87, 0xc9, 0x46, 0x4c, 0xa1, 0x62, 0x93, 0xf9, 0xa4, 0xbb, 0xf4, 0xfd, 0x40, 0x47, 0x5d, 0xf0, 0xff, 0xe2, 0x8c, 0xf2, 0x99, 0x23, 0x62, 0xfd, 0x20, 0x72, 0xe6, 0x39, 0x23}}, - {{0xdf, 0x19, 0x53, 0xd5, 0xee, 0x39, 0x7e, 0xb0, 0x9e, 0x7b, 0x63, 0xcd, 0xb6, 0xa2, 0x2e, 0x2e, 0x85, 0x4d, 0x76, 0x58, 0x5c, 0x1c, 0x30, 0xb2, 0x11, 0x6e, 0x3f, 0x85, 0x76, 0x88, 0x01, 0x31}, {0x40, 0xf7, 0x88, 0xfd, 0xbb, 0x01, 0x1c, 0x6d, 0xf9, 0xf0, 0x0e, 0x81, 0x78, 0xec, 0x45, 0xac, 0x53, 0x7c, 0xd9, 0x5e, 0xe7, 0x89, 0x78, 0x91, 0x64, 0xa8, 0xfb, 0x12, 0x72, 0xe7, 0x02, 0x2e}}, - {{0xd8, 0xfb, 0x04, 0xa9, 0x95, 0xce, 0x2b, 0x48, 0x4e, 0xdf, 0xd4, 0xd9, 0xef, 0x45, 0x9f, 0x09, 0xa5, 0x32, 0x6c, 0x03, 0x56, 0x16, 0x70, 0x6e, 0xdf, 0x12, 0xd5, 0x47, 0xd7, 0xcf, 0x38, 0x0a}, {0x79, 0x48, 0x76, 0xac, 0x01, 0x11, 0x0e, 0x57, 0x1a, 0xe4, 0x5e, 0x20, 0x14, 0xff, 0xd6, 0x99, 0x7d, 0xca, 0x64, 0x83, 0xe1, 0x4c, 0xcb, 0xc0, 0xab, 0x88, 0x27, 0x21, 0x0f, 0x3a, 0x21, 0x3f}}, - {{0x89, 0x31, 0x8e, 0x99, 0x05, 0xd7, 0x91, 0xd4, 0x2a, 0x14, 0x3c, 0x66, 0xdc, 0xba, 0xbe, 0x7b, 0xbf, 0x18, 0xcb, 0x63, 0x90, 0x98, 0x71, 0x1d, 0x7b, 0xe5, 0xcc, 0x2b, 0xc5, 0xa1, 0xf8, 0x24}, {0x52, 0x6f, 0x46, 0xb9, 0xab, 0x3f, 0x52, 0x10, 0x17, 0x76, 0x1b, 0x6b, 0x50, 0x61, 0x21, 0x46, 0xbb, 0x15, 0x66, 0x5f, 0x33, 0xb1, 0x2b, 0xe2, 0xe3, 0xd4, 0x4c, 0xc3, 0x2e, 0xbe, 0xf7, 0x00}}, - {{0xa9, 0x11, 0x18, 0x19, 0xc0, 0xba, 0x7c, 0x9b, 0xcd, 0x13, 0x27, 0xbf, 0x33, 0x1c, 0x4a, 0xe1, 0x71, 0x07, 0xd5, 0x4e, 0x6f, 0x67, 0x34, 0x9c, 0xdf, 0xcb, 0xc7, 0xe4, 0xf9, 0xb8, 0xc3, 0x3b}, {0xbe, 0x2b, 0x19, 0x3a, 0xa5, 0xe7, 0xc3, 0xc0, 0x5b, 0x60, 0xa8, 0xd8, 0xc0, 0xbe, 0x97, 0x96, 0xb0, 0x48, 0x8d, 0xd0, 0x8b, 0xdc, 0x32, 0xf8, 0x47, 0xdb, 0x36, 0x7a, 0x64, 0x7d, 0xd3, 0x0a}}, - {{0xa0, 0x77, 0x69, 0xd5, 0xca, 0xdc, 0x49, 0x1a, 0x61, 0xe4, 0x48, 0x2b, 0x40, 0x74, 0x69, 0x27, 0x4a, 0x42, 0xc1, 0xf6, 0xb2, 0xb7, 0x35, 0x76, 0x9f, 0xb8, 0x89, 0xa2, 0xf4, 0x10, 0xe6, 0x2b}, {0x04, 0xfc, 0xf3, 0x3e, 0x67, 0xc1, 0x61, 0x3e, 0xed, 0xf0, 0x47, 0xce, 0x8b, 0x26, 0x4f, 0x70, 0x36, 0xd8, 0xde, 0xd2, 0x5f, 0x3f, 0x45, 0x14, 0xd8, 0x1d, 0xcd, 0x4e, 0x34, 0xd8, 0xc9, 0x2c}}, - {{0x43, 0xe2, 0x43, 0x7c, 0xa7, 0xa2, 0xbe, 0x11, 0x6a, 0x1e, 0x49, 0xbb, 0x58, 0x1a, 0xcc, 0xae, 0x3e, 0x4f, 0x4b, 0x84, 0x6c, 0x3b, 0x18, 0xad, 0x01, 0x8c, 0x78, 0x1e, 0xa8, 0x29, 0xf2, 0x3a}, {0xdd, 0x46, 0x57, 0x38, 0x11, 0x88, 0xc9, 0xe5, 0x5b, 0x06, 0x4b, 0x3f, 0xa6, 0x37, 0xa2, 0x18, 0x6e, 0x50, 0x4f, 0x8a, 0xa3, 0x77, 0xeb, 0x95, 0x9f, 0x9e, 0x81, 0xbb, 0xb4, 0xe7, 0x19, 0x0f}}, - {{0xc9, 0xcc, 0x0d, 0x12, 0x95, 0x86, 0x89, 0x42, 0x0d, 0x50, 0x8f, 0xb2, 0xb5, 0x76, 0x47, 0x7c, 0x43, 0x0e, 0x57, 0x62, 0xf6, 0xa0, 0x87, 0x73, 0x6f, 0x72, 0x03, 0x04, 0x75, 0x1a, 0x0a, 0x3e}, {0xd0, 0xe2, 0xa5, 0xf5, 0x7f, 0x61, 0xb8, 0xa4, 0x8f, 0xbe, 0xc0, 0x8d, 0x17, 0x75, 0x01, 0xbf, 0xce, 0xaa, 0x63, 0x57, 0x0f, 0x8a, 0x12, 0x3e, 0xf2, 0xc5, 0x1b, 0x1b, 0xb6, 0x05, 0x19, 0x10}}, - {{0xb0, 0x69, 0x7a, 0xc3, 0x36, 0x63, 0x1c, 0x6a, 0x38, 0xc9, 0x9c, 0x4c, 0xf5, 0xb8, 0x01, 0xab, 0xf1, 0x0f, 0x58, 0x88, 0xc2, 0x77, 0x70, 0x4b, 0x13, 0x93, 0x57, 0x26, 0x62, 0x94, 0x9d, 0x21}, {0xb4, 0xb8, 0x1d, 0x48, 0x54, 0xec, 0xca, 0xf0, 0x19, 0xf8, 0xed, 0x8c, 0x6e, 0x70, 0xaa, 0x9c, 0x27, 0xd9, 0x2d, 0x34, 0xf8, 0x4c, 0x2e, 0x89, 0x19, 0x95, 0xa8, 0xc2, 0x80, 0x19, 0x1c, 0x24}}, - {{0xc3, 0x4c, 0x36, 0xeb, 0x3e, 0x58, 0x57, 0x22, 0x88, 0x50, 0x28, 0xd5, 0x7e, 0x3e, 0x29, 0x27, 0xcd, 0x6f, 0xf9, 0x60, 0x57, 0x14, 0xca, 0x7e, 0xb6, 0x9b, 0x40, 0xd5, 0xfd, 0x41, 0x6d, 0x36}, {0xf9, 0x19, 0x82, 0x1e, 0x59, 0x29, 0xfe, 0x8b, 0x16, 0xe2, 0xec, 0xef, 0x22, 0x17, 0xcf, 0xbb, 0xfe, 0xa5, 0xee, 0x03, 0x43, 0xfd, 0x60, 0x95, 0xa8, 0xfa, 0x6f, 0x05, 0xf4, 0xcc, 0xa2, 0x01}}, - {{0x4c, 0xa9, 0x18, 0x52, 0x0b, 0xad, 0xb5, 0xf4, 0x54, 0x93, 0x6d, 0xdd, 0x90, 0x90, 0x24, 0x3a, 0x7c, 0xc5, 0x87, 0xde, 0x69, 0x0f, 0xdc, 0x98, 0x3e, 0x40, 0xf1, 0x5f, 0x7c, 0x35, 0xda, 0x3d}, {0x3a, 0xb1, 0x5d, 0xc8, 0x9b, 0x45, 0x19, 0x51, 0x40, 0x7f, 0xb0, 0x90, 0x0c, 0x72, 0xfc, 0x2b, 0x81, 0xd5, 0x8b, 0xf8, 0x1d, 0x0f, 0x37, 0x85, 0x98, 0xa2, 0x0e, 0xc0, 0x6e, 0x22, 0xdb, 0x37}}, - {{0xd2, 0x77, 0xa1, 0x39, 0xa9, 0x23, 0xb3, 0x63, 0xcc, 0x01, 0x3d, 0x71, 0x48, 0x97, 0x2f, 0xe6, 0xbf, 0x59, 0xa1, 0xa0, 0x50, 0x90, 0x08, 0x25, 0x1d, 0x85, 0xb8, 0xe9, 0x78, 0x7c, 0x7c, 0x3d}, {0xce, 0x6f, 0xb2, 0xb4, 0xcb, 0x54, 0x84, 0x39, 0xb9, 0xd4, 0x1f, 0xb1, 0xb1, 0xf1, 0x6e, 0xc0, 0x97, 0xa2, 0xd7, 0xe7, 0x1c, 0x78, 0x56, 0x44, 0x53, 0xf4, 0xb8, 0xf1, 0x94, 0x81, 0xcd, 0x04}}, - {{0xf4, 0x7a, 0x17, 0xb6, 0xcb, 0x83, 0x48, 0x18, 0xd5, 0xc3, 0xfe, 0xa4, 0x6c, 0x54, 0x57, 0x2d, 0x0a, 0xdc, 0x32, 0x92, 0xa8, 0xe3, 0x4d, 0x98, 0x76, 0xf5, 0x13, 0xb3, 0x7a, 0x7d, 0xe5, 0x0f}, {0xb7, 0x2d, 0x0e, 0x70, 0xb1, 0x4a, 0x5f, 0x67, 0x27, 0x71, 0x0d, 0x3a, 0xdd, 0x6b, 0x44, 0xb0, 0x80, 0x80, 0x74, 0xc1, 0xa3, 0xc6, 0x66, 0x8d, 0xfb, 0x92, 0x52, 0x05, 0x89, 0xae, 0x9e, 0x33}}, - {{0xce, 0xb6, 0x97, 0x54, 0xe7, 0x46, 0xc6, 0x28, 0x01, 0xd1, 0x08, 0x09, 0x3a, 0x75, 0xfa, 0xa3, 0xdc, 0x2a, 0x5d, 0x06, 0xf5, 0xd0, 0x09, 0x1f, 0x73, 0x15, 0x6e, 0x21, 0xdd, 0xd1, 0x8a, 0x17}, {0x57, 0x1e, 0x41, 0xb0, 0x06, 0xa3, 0x0e, 0x03, 0xa9, 0xbd, 0x28, 0xdf, 0xec, 0x03, 0x2a, 0x76, 0x1c, 0xb5, 0xc9, 0xec, 0x5a, 0xf3, 0xc1, 0xa2, 0x31, 0xe1, 0x3f, 0x80, 0x14, 0x71, 0x7f, 0x03}}, - {{0x66, 0x83, 0x53, 0x94, 0xbb, 0xb5, 0xea, 0x59, 0x24, 0x30, 0xf0, 0xc2, 0xf8, 0x07, 0xd1, 0x5f, 0xf2, 0x85, 0xa0, 0x77, 0x0a, 0x9e, 0x1f, 0x49, 0x46, 0x33, 0xd6, 0x5a, 0xba, 0x5b, 0x48, 0x19}, {0x40, 0xf7, 0xf6, 0x5f, 0x70, 0x85, 0x7d, 0xe0, 0xfb, 0xeb, 0x8f, 0xf7, 0x4b, 0x9f, 0xeb, 0xa7, 0xe2, 0x87, 0x74, 0xba, 0xd5, 0xd8, 0xc7, 0x4e, 0x48, 0xa4, 0xd3, 0x1a, 0x0c, 0xbf, 0x2f, 0x15}}, - {{0x04, 0xe3, 0x8a, 0xb8, 0xb7, 0xa4, 0x51, 0x89, 0xe5, 0x2d, 0xd6, 0x63, 0x94, 0xf4, 0xba, 0xfb, 0x04, 0xb6, 0xfb, 0x46, 0xcf, 0xf4, 0xdc, 0x52, 0x53, 0x82, 0xa2, 0xf0, 0xaf, 0x61, 0x67, 0x38}, {0x55, 0xf2, 0x3d, 0x0c, 0x33, 0xa3, 0x9e, 0xa7, 0xfa, 0x7b, 0xf3, 0xef, 0x06, 0x18, 0xc0, 0x98, 0xd6, 0xbc, 0xb8, 0x36, 0x7b, 0x7c, 0x04, 0xce, 0xea, 0xed, 0x63, 0xc3, 0xf4, 0xa7, 0x8b, 0x3c}}, - {{0xef, 0x0a, 0xab, 0x71, 0x61, 0xf6, 0x3d, 0xaf, 0xb0, 0xcc, 0xb7, 0xfe, 0x27, 0xdf, 0x2a, 0xf4, 0x4e, 0x71, 0xe0, 0x95, 0x6a, 0x09, 0x52, 0xf6, 0x00, 0xdc, 0x9f, 0xbb, 0x2e, 0x2f, 0xd2, 0x12}, {0x1a, 0x7e, 0x5c, 0x74, 0x3b, 0xe1, 0xd3, 0x2b, 0x31, 0x47, 0x3b, 0x1c, 0xed, 0x8b, 0xd5, 0x30, 0x6c, 0x0e, 0x6d, 0x15, 0x60, 0xde, 0xe9, 0x4f, 0xe1, 0xa5, 0x6c, 0x04, 0xca, 0x82, 0x75, 0x1e}}, - {{0x4e, 0xbe, 0x30, 0x2d, 0x3a, 0x3b, 0x26, 0x4b, 0x4e, 0x9c, 0x9e, 0xef, 0xb5, 0xe1, 0x03, 0xa3, 0x4d, 0xd3, 0x78, 0x1f, 0xc7, 0xd3, 0x0c, 0x1a, 0x09, 0x1a, 0x93, 0x2b, 0xe2, 0xcb, 0xc6, 0x0b}, {0xe6, 0x78, 0x50, 0xc9, 0x0a, 0x54, 0xf8, 0x5e, 0x85, 0x5e, 0x65, 0x85, 0x0b, 0xb7, 0x90, 0x5d, 0x78, 0x4c, 0xe6, 0x36, 0x17, 0xc7, 0x53, 0xed, 0x66, 0x91, 0x79, 0x30, 0x8a, 0x46, 0x86, 0x16}}, - {{0x48, 0x9e, 0x31, 0xb7, 0x14, 0xdd, 0x0d, 0x0d, 0xdc, 0x3f, 0x91, 0x53, 0x82, 0xbc, 0x2e, 0x71, 0xba, 0x08, 0x1e, 0xb5, 0xa4, 0xdd, 0xcf, 0x5f, 0x78, 0xfe, 0x44, 0x2d, 0xeb, 0x06, 0x3d, 0x2f}, {0x2d, 0xf3, 0xb3, 0xa0, 0x34, 0x86, 0x69, 0xa5, 0x50, 0x95, 0x30, 0x0d, 0xd0, 0xe6, 0xa6, 0xc8, 0x58, 0x9f, 0x20, 0x96, 0x74, 0x82, 0xe7, 0x89, 0x05, 0x64, 0x90, 0x5b, 0x04, 0xf1, 0xb3, 0x05}}, - {{0xf1, 0x5e, 0x3f, 0xc9, 0xab, 0x9f, 0x56, 0x65, 0xf0, 0x3f, 0xb0, 0xe5, 0x45, 0xfb, 0x77, 0x8c, 0x5d, 0x0d, 0x61, 0xa6, 0x04, 0x44, 0x62, 0x14, 0xa9, 0x8c, 0x12, 0x8c, 0x82, 0xfd, 0x31, 0x14}, {0x2a, 0x53, 0x81, 0x7a, 0xe0, 0xff, 0xf4, 0xe0, 0x73, 0xe5, 0x45, 0x76, 0x69, 0xe0, 0x54, 0x62, 0x2a, 0x82, 0xfd, 0x19, 0x4b, 0xfa, 0x42, 0x36, 0x52, 0xbb, 0x91, 0x03, 0x35, 0xd1, 0x85, 0x24}}, - {{0x25, 0x49, 0x66, 0xb2, 0x06, 0xe3, 0x68, 0x57, 0x52, 0xf6, 0x29, 0xe7, 0xa1, 0xfd, 0xef, 0xd2, 0xc0, 0xa9, 0x9c, 0x31, 0x7c, 0xd4, 0xc6, 0x21, 0xee, 0xb3, 0x4d, 0xe5, 0x36, 0x0c, 0x01, 0x24}, {0x80, 0x0b, 0x1b, 0xeb, 0xfc, 0x90, 0x51, 0x49, 0xf2, 0x91, 0x04, 0xee, 0x15, 0xc3, 0xc2, 0xf0, 0xd6, 0xb3, 0x07, 0x13, 0x08, 0x9d, 0xbc, 0x61, 0x64, 0xa2, 0x07, 0x36, 0x3e, 0xb7, 0x4a, 0x02}}, - {{0x3f, 0xef, 0xf4, 0x54, 0x7e, 0x38, 0x7f, 0x10, 0x6b, 0xf5, 0x43, 0x0a, 0xda, 0x32, 0x0a, 0x29, 0x09, 0x09, 0x83, 0x4e, 0x56, 0x86, 0x9f, 0x8b, 0x03, 0x62, 0xae, 0xb6, 0x45, 0x0f, 0x7f, 0x27}, {0x0e, 0x4c, 0xcc, 0xf5, 0x65, 0x28, 0x6b, 0x54, 0x10, 0x00, 0xbf, 0x07, 0xd6, 0x55, 0x70, 0x82, 0x71, 0x03, 0x61, 0xfe, 0xbd, 0x68, 0x7e, 0x3f, 0x35, 0x72, 0x4d, 0x0f, 0x45, 0xeb, 0x87, 0x16}}, - {{0x48, 0x26, 0x6d, 0x31, 0xac, 0x4e, 0xa6, 0x78, 0xaa, 0x50, 0x7f, 0xa6, 0x21, 0x25, 0x3e, 0x75, 0xfd, 0x46, 0x1f, 0xf1, 0xa5, 0x79, 0x78, 0x6e, 0xb7, 0x6e, 0xda, 0xb1, 0xff, 0x18, 0xd9, 0x05}, {0xe9, 0x3a, 0xc9, 0x9b, 0x63, 0x58, 0xb9, 0xba, 0x55, 0x57, 0xcf, 0x04, 0x46, 0x3f, 0x7b, 0xc3, 0xdf, 0xd2, 0x29, 0x9f, 0x79, 0xae, 0xe4, 0x7d, 0xa3, 0x00, 0x0c, 0x06, 0xa6, 0xe1, 0x7b, 0x04}}, - {{0xb6, 0x7c, 0xdf, 0x61, 0xc2, 0x71, 0xc8, 0x49, 0x1a, 0x0b, 0xea, 0xe9, 0x6c, 0xca, 0x80, 0x53, 0x0e, 0xfe, 0xb8, 0x41, 0x03, 0x44, 0x5a, 0xd0, 0x1c, 0x3d, 0x5f, 0x03, 0x8c, 0xd1, 0x0c, 0x08}, {0x4a, 0x24, 0x94, 0xa8, 0xb3, 0xe1, 0x74, 0x52, 0xb2, 0x7f, 0x1e, 0xa2, 0xaf, 0x74, 0xdc, 0xde, 0xb4, 0x54, 0xee, 0x99, 0x0d, 0x5f, 0xb1, 0xef, 0xf6, 0xdb, 0xb6, 0x4e, 0x62, 0x32, 0x4c, 0x16}}, - {{0x77, 0x68, 0x88, 0xd5, 0x53, 0xab, 0x0a, 0x72, 0xae, 0xdf, 0x71, 0x16, 0xf8, 0x5c, 0xaa, 0xce, 0xe7, 0x52, 0x05, 0x54, 0x16, 0x9e, 0x4b, 0x6d, 0xbe, 0x06, 0x3f, 0x23, 0xfa, 0x47, 0x6c, 0x1c}, {0x3f, 0xaa, 0xa4, 0xf4, 0x0a, 0x3c, 0xf5, 0x61, 0x9a, 0x38, 0xf0, 0xb4, 0x34, 0x23, 0x58, 0x52, 0xfe, 0xf8, 0xaa, 0x50, 0x30, 0xdb, 0xa1, 0xc8, 0x5c, 0x47, 0x6c, 0xc4, 0x34, 0xdb, 0xdc, 0x26}}, - {{0x89, 0x3e, 0x40, 0x38, 0x70, 0x29, 0x08, 0x32, 0xe3, 0x4f, 0xf1, 0x19, 0x3b, 0x59, 0xa1, 0x90, 0xe4, 0x1b, 0xd7, 0xe6, 0x71, 0xee, 0xf3, 0x09, 0x5e, 0x53, 0x4a, 0x13, 0x25, 0x8f, 0x1f, 0x0e}, {0x12, 0x76, 0xac, 0xb1, 0xf9, 0xb8, 0x19, 0xd5, 0x46, 0x58, 0x74, 0x90, 0x0e, 0x85, 0xf7, 0x91, 0x28, 0x2b, 0xcf, 0x08, 0x11, 0x36, 0x46, 0x88, 0x4c, 0x0d, 0xe0, 0x73, 0x2b, 0xa6, 0xea, 0x13}}, - {{0x6f, 0xc6, 0x5a, 0x44, 0x53, 0xa3, 0x39, 0x4f, 0xb7, 0x84, 0xba, 0xe1, 0x67, 0xa7, 0x9d, 0xb5, 0xa8, 0xaf, 0x54, 0x09, 0x04, 0x9c, 0x17, 0x37, 0xd8, 0xb6, 0x6a, 0xd6, 0x36, 0xf2, 0xcf, 0x2f}, {0x7b, 0x59, 0x6a, 0x0d, 0x95, 0xf2, 0x1a, 0x68, 0x0a, 0x72, 0x25, 0x60, 0xae, 0x9c, 0x42, 0x56, 0x4d, 0x57, 0x5c, 0x76, 0x8d, 0x99, 0x44, 0x8a, 0xd2, 0x6e, 0x17, 0x10, 0x7e, 0xe6, 0xee, 0x12}}, - {{0xee, 0xbf, 0x04, 0xaf, 0xf1, 0x66, 0x10, 0xa3, 0x90, 0x65, 0x79, 0xfb, 0x36, 0xea, 0x37, 0x25, 0xb9, 0x75, 0xe1, 0x64, 0xf6, 0x25, 0xa7, 0xb3, 0x5e, 0xd0, 0x35, 0x9e, 0x7e, 0x93, 0x88, 0x07}, {0xa2, 0xa0, 0x9f, 0x8f, 0x7e, 0xdf, 0x4e, 0xb5, 0x21, 0xa9, 0x73, 0x9b, 0x00, 0x20, 0x62, 0xe3, 0xfb, 0xae, 0x4f, 0xcd, 0x46, 0x8c, 0xdb, 0xf8, 0xda, 0xde, 0x90, 0xb5, 0xee, 0x43, 0x19, 0x25}}, - {{0xcb, 0x77, 0x18, 0xde, 0x82, 0x2b, 0x8e, 0xa8, 0x59, 0xd0, 0x6c, 0xe4, 0xd7, 0xf5, 0x94, 0x8b, 0xda, 0x1f, 0x54, 0x32, 0x81, 0x03, 0xa7, 0x87, 0x91, 0x2e, 0xf3, 0xf5, 0x8f, 0x72, 0xb7, 0x22}, {0x97, 0xf9, 0x50, 0xfa, 0x69, 0x78, 0x3d, 0x67, 0xa3, 0x51, 0xd2, 0xf4, 0x99, 0x24, 0x19, 0x97, 0xd3, 0xb1, 0xc7, 0xcf, 0xa8, 0x1d, 0x21, 0x1c, 0x37, 0x99, 0xac, 0x77, 0x60, 0x9b, 0xcb, 0x2b}}, - {{0xb6, 0xae, 0x91, 0x0e, 0x35, 0x8e, 0x85, 0xa6, 0xe8, 0xda, 0x3e, 0x42, 0x16, 0x6a, 0xa5, 0x97, 0x54, 0x0e, 0xa0, 0x28, 0xa2, 0x8d, 0xd3, 0xf9, 0x3a, 0x57, 0xaa, 0x12, 0xfb, 0x88, 0x9b, 0x1e}, {0x22, 0xc3, 0x0c, 0x2d, 0xb7, 0x63, 0xe1, 0x9b, 0xed, 0x8c, 0x70, 0x39, 0xd4, 0x4c, 0x50, 0x66, 0x37, 0xab, 0x3e, 0xc4, 0xca, 0xff, 0xb1, 0xd3, 0xfe, 0x60, 0x97, 0x9f, 0x8a, 0xb2, 0x46, 0x11}}, - {{0x34, 0x89, 0xb1, 0xa8, 0x9e, 0xd2, 0xda, 0xda, 0x9b, 0x53, 0x06, 0x36, 0x0f, 0x94, 0x50, 0x12, 0x76, 0x88, 0xf1, 0x6c, 0x39, 0xb1, 0x2b, 0xde, 0x65, 0x63, 0x28, 0x9f, 0x63, 0xcf, 0xe8, 0x11}, {0xa6, 0x5a, 0x02, 0x21, 0x8c, 0x5f, 0x15, 0x50, 0xfb, 0x1d, 0x67, 0x45, 0x88, 0xd8, 0xa1, 0xa1, 0xb2, 0x0f, 0x36, 0xd2, 0x35, 0x08, 0x27, 0x49, 0x7b, 0xb8, 0x96, 0xb9, 0x82, 0x55, 0x53, 0x27}}, - {{0x8f, 0xca, 0xb4, 0xe0, 0x92, 0xe4, 0xc5, 0x8c, 0x48, 0x3c, 0xc6, 0xb0, 0xf7, 0x29, 0x8f, 0xb2, 0x1e, 0x77, 0xa2, 0x32, 0x10, 0xef, 0x38, 0x7e, 0xad, 0x32, 0x37, 0xe6, 0x43, 0xc5, 0x13, 0x33}, {0x0c, 0x73, 0x2c, 0xeb, 0x57, 0x4d, 0x69, 0x76, 0x08, 0xfe, 0xf7, 0xb3, 0xc0, 0x9e, 0x74, 0x05, 0xa4, 0xf1, 0x49, 0xe4, 0x53, 0x24, 0xa7, 0x20, 0x12, 0x80, 0x60, 0x4f, 0x56, 0xc6, 0x70, 0x20}}, - {{0x4c, 0x00, 0x6a, 0x23, 0x43, 0x1a, 0xc2, 0x7e, 0xdb, 0x56, 0x13, 0x5d, 0x43, 0x0e, 0x75, 0xa0, 0x7d, 0x76, 0xd9, 0xa0, 0xde, 0x38, 0xfe, 0xf3, 0x10, 0x01, 0x62, 0xb5, 0x93, 0xf0, 0x37, 0x03}, {0x24, 0x5d, 0x06, 0x74, 0x84, 0x71, 0xce, 0x62, 0xaf, 0x55, 0xd5, 0x81, 0xa5, 0xc9, 0xbb, 0x6b, 0xea, 0xbe, 0x18, 0x60, 0xe6, 0x4e, 0x2d, 0xfa, 0xa0, 0xdc, 0xe7, 0xe7, 0x54, 0xc6, 0x0b, 0x28}}, - {{0xfb, 0x44, 0xc2, 0xb0, 0x3d, 0x91, 0xe1, 0xb0, 0x38, 0x59, 0x8e, 0x21, 0xc4, 0xd9, 0xa4, 0xaa, 0xc6, 0x28, 0xd6, 0x5f, 0x6b, 0x9b, 0x46, 0x35, 0x22, 0xb2, 0xd3, 0x43, 0x07, 0x91, 0x95, 0x23}, {0x9e, 0xe9, 0x4c, 0x4b, 0x9b, 0x12, 0xaa, 0x5c, 0xec, 0x85, 0x13, 0x53, 0xaa, 0xec, 0x45, 0xef, 0x2b, 0xfb, 0xc2, 0xc8, 0xcc, 0xa2, 0x0f, 0x9c, 0x0a, 0xb8, 0x18, 0xf5, 0x31, 0x81, 0x9c, 0x18}}, - {{0xdd, 0xa4, 0x13, 0xb0, 0x6c, 0x42, 0x2c, 0x03, 0xa0, 0xd9, 0x17, 0x33, 0x5a, 0x5e, 0x1b, 0xe1, 0x80, 0x3b, 0x0d, 0x83, 0xfd, 0xb9, 0x92, 0x14, 0xd4, 0x55, 0x5c, 0xcf, 0x94, 0x9d, 0xf1, 0x05}, {0x03, 0xd0, 0x3d, 0x67, 0x04, 0x47, 0x4c, 0x2c, 0x07, 0x8d, 0xd8, 0x97, 0xaf, 0x29, 0x8e, 0xc4, 0xdf, 0x53, 0xd8, 0x91, 0x3d, 0xdd, 0x27, 0xd1, 0x05, 0x64, 0xd8, 0xf2, 0x52, 0xc0, 0x94, 0x0d}}, - {{0x09, 0x36, 0xb9, 0xd4, 0xc9, 0x7b, 0x81, 0x02, 0x92, 0xa5, 0xd4, 0x2d, 0x0d, 0x6a, 0x46, 0xfd, 0x94, 0xc4, 0x3c, 0x05, 0xad, 0xd5, 0xbf, 0xd7, 0xf6, 0x06, 0x06, 0xc9, 0x6d, 0x09, 0x23, 0x3e}, {0xbb, 0xd0, 0x48, 0xcf, 0xad, 0xa2, 0x1b, 0xca, 0xbd, 0x5e, 0x12, 0xe6, 0x9e, 0x2a, 0x88, 0x48, 0xaa, 0xfa, 0xcd, 0x33, 0x00, 0xf3, 0x57, 0xa8, 0x77, 0x9f, 0x10, 0x29, 0xb5, 0xd8, 0x0d, 0x0c}}, - {{0x1b, 0x57, 0x16, 0xcd, 0x76, 0x2c, 0xaa, 0x63, 0xee, 0x9e, 0x5d, 0xf3, 0xee, 0x27, 0x08, 0x67, 0x28, 0x8f, 0x30, 0xed, 0x0c, 0x37, 0x32, 0xf7, 0x28, 0xb2, 0x45, 0x9c, 0x0f, 0x69, 0xe7, 0x2c}, {0x00, 0x22, 0xda, 0xd2, 0xe5, 0x8f, 0x08, 0xcf, 0x4a, 0x5a, 0x79, 0x3b, 0xa5, 0x35, 0x75, 0x6b, 0x58, 0x3d, 0xeb, 0x35, 0xc6, 0x78, 0xdd, 0x6c, 0xd4, 0xbe, 0x94, 0xe7, 0x57, 0xda, 0x8b, 0x08}}, - {{0xfa, 0x04, 0x82, 0x35, 0xf2, 0x90, 0x92, 0x4f, 0x0f, 0x6e, 0x7a, 0xce, 0xd5, 0x9b, 0x25, 0xbc, 0x6a, 0x59, 0x99, 0xfd, 0xba, 0x7d, 0x44, 0xe9, 0x27, 0xa6, 0xea, 0xbb, 0x69, 0xa3, 0x51, 0x21}, {0xd1, 0x83, 0x99, 0x4d, 0x08, 0x3f, 0x1e, 0xc1, 0x9b, 0x61, 0x7b, 0x3a, 0x0e, 0x88, 0x2d, 0x3a, 0xfc, 0x11, 0xf2, 0x75, 0x46, 0xdf, 0xce, 0xa9, 0xa8, 0x79, 0x41, 0x8a, 0x40, 0xe1, 0x3b, 0x15}}, - {{0x15, 0x4e, 0xaa, 0x32, 0x0b, 0xed, 0xb4, 0x16, 0x3e, 0x16, 0x03, 0xe0, 0x26, 0x98, 0x02, 0x5d, 0xc2, 0xfe, 0xf9, 0x12, 0xa0, 0x90, 0x74, 0xa6, 0xde, 0xe0, 0xd4, 0x13, 0xf3, 0x0d, 0xb1, 0x13}, {0xc9, 0x6f, 0xbf, 0x0d, 0x14, 0x58, 0xc3, 0xfa, 0xd8, 0x64, 0xdd, 0xf3, 0xe3, 0xdb, 0x97, 0x8d, 0x8e, 0x19, 0x73, 0xb9, 0xc5, 0x80, 0x04, 0xf6, 0xfe, 0x30, 0xc7, 0xc4, 0xa1, 0x6b, 0x44, 0x0e}}, - {{0xfc, 0xb3, 0x67, 0xd6, 0xce, 0x02, 0xe5, 0x53, 0x31, 0xb6, 0x35, 0x2d, 0x92, 0xf2, 0x6f, 0xbd, 0x89, 0xb2, 0x78, 0x0c, 0x81, 0x76, 0x1e, 0x51, 0xa6, 0xc3, 0xeb, 0xf2, 0x68, 0xb9, 0xd9, 0x35}, {0x8d, 0x3f, 0x59, 0x17, 0xa7, 0xf3, 0x3b, 0x4b, 0xbf, 0x7e, 0x76, 0x99, 0x38, 0x76, 0x20, 0x48, 0x60, 0x4f, 0x4e, 0x96, 0x03, 0x67, 0x49, 0x15, 0xf0, 0x33, 0xf0, 0x43, 0xa1, 0x81, 0x3d, 0x15}}, - {{0x01, 0xff, 0xe5, 0x3d, 0xfc, 0x52, 0xba, 0x31, 0xe2, 0xec, 0xd1, 0xb9, 0x41, 0x2b, 0x6a, 0x37, 0xa0, 0x2d, 0xe8, 0xdc, 0x31, 0x83, 0xfc, 0x62, 0x80, 0xa7, 0xac, 0xf6, 0x44, 0x57, 0x8f, 0x11}, {0xa0, 0xf7, 0xa7, 0x1e, 0x68, 0xdf, 0xe6, 0xb1, 0x95, 0xf4, 0xeb, 0x1d, 0x63, 0xd3, 0xad, 0x40, 0x8b, 0xcb, 0x5f, 0x08, 0xbb, 0xda, 0xbc, 0x41, 0x47, 0x22, 0xc1, 0x42, 0x20, 0xf0, 0x4f, 0x36}}, - {{0x0e, 0xd0, 0x9e, 0x0c, 0x38, 0x16, 0xb4, 0x36, 0xdb, 0xd1, 0xa4, 0x10, 0xdc, 0xbf, 0xe0, 0x51, 0xab, 0xae, 0xb5, 0x4a, 0x35, 0x58, 0x3c, 0x91, 0x89, 0x13, 0x29, 0x6a, 0x64, 0x7d, 0xab, 0x0f}, {0xab, 0x99, 0x38, 0xc4, 0xa5, 0x18, 0x21, 0x33, 0xa2, 0xff, 0x9a, 0xec, 0x69, 0xef, 0x16, 0xaf, 0x00, 0xd1, 0x0b, 0xaf, 0xaa, 0x59, 0xb2, 0xc1, 0x47, 0x73, 0x7c, 0xef, 0x07, 0x66, 0x75, 0x05}}, - {{0x34, 0x98, 0xa1, 0xfa, 0x18, 0x08, 0xe0, 0x74, 0xfd, 0x60, 0xed, 0x6b, 0x7c, 0x2b, 0x98, 0xfb, 0x74, 0x46, 0xbd, 0x2e, 0x5a, 0x23, 0xe3, 0xdd, 0xb6, 0xf4, 0xa3, 0xfd, 0x74, 0x52, 0x5a, 0x21}, {0xce, 0xcd, 0x4d, 0xc5, 0x83, 0x97, 0x6c, 0x10, 0x54, 0x54, 0x71, 0x1a, 0x46, 0x72, 0x28, 0xe1, 0xc3, 0x1d, 0x3a, 0xc9, 0x85, 0x6b, 0xf3, 0xd4, 0x70, 0x4b, 0xf9, 0xd9, 0xc5, 0x92, 0x6e, 0x0c}}, - {{0x15, 0x46, 0xc0, 0xc0, 0x26, 0xd7, 0x65, 0x1b, 0xda, 0x7e, 0x7b, 0x19, 0x63, 0xe8, 0x8b, 0xbf, 0xd1, 0xbf, 0x52, 0x24, 0xb1, 0xe0, 0xd7, 0xaa, 0x89, 0x9c, 0xd8, 0xa5, 0x5c, 0x41, 0x11, 0x35}, {0x63, 0x6f, 0x96, 0x49, 0x78, 0x0a, 0x33, 0xd8, 0xd4, 0xf6, 0x6b, 0x4b, 0x47, 0x64, 0xe1, 0x30, 0x7c, 0x10, 0x59, 0x13, 0x50, 0x7c, 0xff, 0xca, 0x61, 0x5c, 0xf1, 0x91, 0x5e, 0xff, 0x52, 0x09}}, - {{0x74, 0xe9, 0x4a, 0xa3, 0xde, 0x79, 0x03, 0x0d, 0x1a, 0xd7, 0x73, 0x86, 0x1f, 0x56, 0x94, 0xcc, 0xbf, 0xfd, 0x1b, 0xd1, 0xe3, 0xc0, 0x1a, 0x13, 0xd8, 0x41, 0xc7, 0x6a, 0x19, 0xc0, 0xf8, 0x25}, {0x4e, 0x30, 0x4d, 0x89, 0x04, 0x34, 0x4d, 0xc1, 0xe9, 0x16, 0xb3, 0x6a, 0xa9, 0x69, 0x83, 0x16, 0xa8, 0xed, 0x9c, 0xcd, 0x70, 0xbc, 0x35, 0x37, 0xa5, 0x48, 0x23, 0xf5, 0x3a, 0x44, 0xb4, 0x37}}, - {{0x68, 0x75, 0x2e, 0x19, 0x6e, 0x1c, 0x56, 0x99, 0xa8, 0x44, 0x9a, 0xd7, 0x87, 0xbe, 0xe7, 0x65, 0xa5, 0xcf, 0xf7, 0x88, 0x69, 0x13, 0x77, 0xc4, 0x1f, 0xf9, 0x6a, 0x1f, 0xd1, 0xd2, 0x08, 0x2e}, {0xeb, 0xaf, 0x4d, 0xcf, 0x78, 0x68, 0x16, 0x8a, 0x6c, 0xde, 0x05, 0xe7, 0xd6, 0x04, 0xb3, 0xab, 0xa7, 0x15, 0xdc, 0x89, 0x14, 0xc8, 0x59, 0x08, 0x6f, 0xb4, 0x79, 0xa0, 0x75, 0x07, 0x4d, 0x27}}, - {{0x13, 0xeb, 0xa8, 0x4f, 0xa8, 0x11, 0x3d, 0xdb, 0xaf, 0xd6, 0xd3, 0x9a, 0xa8, 0x7e, 0x3a, 0xea, 0xae, 0x4c, 0xf1, 0x3a, 0x35, 0xaf, 0x81, 0x99, 0xd9, 0xdf, 0xe8, 0x7a, 0x1e, 0xc0, 0x38, 0x2b}, {0x77, 0x80, 0x06, 0x3c, 0xc0, 0xde, 0x0d, 0x83, 0x38, 0xeb, 0xe2, 0x51, 0x90, 0xfa, 0x2d, 0x42, 0xbc, 0x76, 0x0c, 0xd1, 0x0d, 0x0d, 0xf7, 0xb8, 0xac, 0x88, 0x51, 0x0e, 0x67, 0x5d, 0x9f, 0x05}}, - {{0x0e, 0xe1, 0xbd, 0xe2, 0xf8, 0x97, 0x10, 0xd9, 0xa0, 0x53, 0x28, 0x8f, 0x52, 0x4c, 0x49, 0x2f, 0x3b, 0x92, 0xab, 0xb3, 0x81, 0xd4, 0xce, 0x18, 0x82, 0x84, 0x18, 0xa7, 0xdb, 0xe3, 0xd9, 0x25}, {0x86, 0x09, 0x95, 0xba, 0x05, 0x80, 0xa7, 0xd5, 0x56, 0x25, 0x6d, 0xd7, 0x67, 0x23, 0xff, 0xca, 0x94, 0x10, 0xf5, 0xd2, 0x15, 0x0e, 0x49, 0xfd, 0x01, 0xc1, 0x2e, 0x73, 0xa9, 0x51, 0xec, 0x04}}, - {{0x37, 0xc2, 0x08, 0x2d, 0x55, 0xb0, 0x75, 0x9f, 0x1f, 0x55, 0x4b, 0xb9, 0xf6, 0x40, 0x7b, 0x8f, 0xd4, 0x02, 0x12, 0x65, 0x65, 0x1d, 0x0a, 0xff, 0x0e, 0x2a, 0xad, 0x44, 0x07, 0x35, 0x59, 0x32}, {0xfc, 0x87, 0x35, 0x56, 0x7b, 0x00, 0xb0, 0xc3, 0x8b, 0x00, 0x56, 0x15, 0x4c, 0x66, 0xfe, 0x67, 0x4b, 0xa1, 0x90, 0x7c, 0x4e, 0xd1, 0x33, 0x39, 0xf5, 0x9e, 0xf5, 0x37, 0x66, 0xb0, 0xdc, 0x08}}, - {{0x1e, 0x6f, 0xf4, 0xd7, 0x91, 0x56, 0xd6, 0x66, 0x7a, 0xed, 0x39, 0xa0, 0xe4, 0x25, 0x74, 0x57, 0x8b, 0x09, 0xdd, 0xc7, 0xf5, 0xc3, 0x27, 0xfe, 0x31, 0xa2, 0xf1, 0x22, 0x7a, 0xb7, 0xaf, 0x1d}, {0x9b, 0xac, 0x9d, 0x9f, 0x10, 0xe6, 0xbf, 0xa3, 0x5c, 0x86, 0x14, 0x53, 0xf2, 0xe6, 0x38, 0xa5, 0x35, 0x61, 0xf2, 0x13, 0x19, 0x56, 0x8c, 0xd4, 0x67, 0x55, 0xc3, 0xeb, 0xbd, 0x66, 0x7d, 0x26}}, - {{0x9a, 0xfd, 0x5a, 0x00, 0xb7, 0x55, 0xc0, 0x22, 0xc1, 0xdf, 0x4d, 0x54, 0xb4, 0x5f, 0xe9, 0xfb, 0xcc, 0xc6, 0xd1, 0x43, 0x41, 0x26, 0xd5, 0x48, 0x08, 0x3c, 0x7a, 0xea, 0x2a, 0xa7, 0xc3, 0x37}, {0xa4, 0xd2, 0x2f, 0xeb, 0xd5, 0xaf, 0xe1, 0x77, 0x9c, 0x52, 0x8c, 0x24, 0xbf, 0x76, 0xcf, 0xbf, 0x4a, 0xa4, 0xfa, 0x9f, 0xaa, 0x07, 0x89, 0x85, 0x11, 0x98, 0x3d, 0xa2, 0xad, 0xb3, 0x8a, 0x28}}, - {{0x83, 0xa2, 0x9a, 0xb0, 0x2e, 0x2f, 0x7f, 0x84, 0x88, 0xa0, 0xec, 0x5f, 0xee, 0xcb, 0x74, 0x28, 0x72, 0x86, 0xf2, 0x9a, 0x8d, 0xfc, 0xd9, 0x34, 0x35, 0xff, 0x79, 0xd5, 0x4f, 0x11, 0x01, 0x3e}, {0x0b, 0xc6, 0x54, 0x22, 0x37, 0xd2, 0x04, 0x55, 0x27, 0xb7, 0xa7, 0x6b, 0xcd, 0x14, 0x8f, 0x8f, 0x07, 0xd5, 0x80, 0x11, 0x3f, 0x9f, 0x39, 0x75, 0x4b, 0xc2, 0x20, 0x83, 0x97, 0x56, 0x77, 0x19}}, - {{0x54, 0x37, 0xef, 0xa4, 0x7d, 0x67, 0xd8, 0x21, 0xcc, 0x71, 0xfe, 0xc4, 0xca, 0x79, 0x0f, 0x97, 0xf0, 0xa2, 0xe7, 0x93, 0x38, 0x56, 0x02, 0x92, 0x72, 0x81, 0x7d, 0x59, 0x65, 0x31, 0x6c, 0x27}, {0xee, 0x4f, 0xa1, 0xa9, 0xd9, 0x83, 0xdb, 0xcd, 0x2c, 0xce, 0xdf, 0x95, 0x1e, 0x2b, 0xfa, 0x05, 0x84, 0x7c, 0xb6, 0xe1, 0xef, 0x11, 0x8c, 0xd5, 0xe1, 0xfd, 0xe0, 0x23, 0xc6, 0xcb, 0xc7, 0x01}}, - {{0xf8, 0x9b, 0x41, 0xbe, 0xb7, 0x11, 0xc4, 0x5d, 0x9e, 0x50, 0xfd, 0x71, 0xde, 0x61, 0x02, 0x61, 0xc1, 0x15, 0x6f, 0x4b, 0xe5, 0x5f, 0xdf, 0x93, 0x8c, 0xfc, 0x55, 0xef, 0x2a, 0xa6, 0x17, 0x2b}, {0x43, 0xfe, 0x28, 0x54, 0xe7, 0x27, 0xe9, 0x13, 0x48, 0xd9, 0x58, 0x53, 0x3a, 0x6e, 0x07, 0x3d, 0x94, 0x73, 0xa0, 0x07, 0x85, 0x90, 0x1d, 0x32, 0xf9, 0xf5, 0x85, 0x3f, 0xbc, 0x17, 0x48, 0x26}}, - {{0x4a, 0x54, 0xc9, 0xc5, 0x8c, 0x66, 0x55, 0xda, 0xe9, 0x4a, 0xf1, 0x06, 0xc2, 0x42, 0xd5, 0x7d, 0x22, 0xee, 0x1c, 0x3d, 0xeb, 0xaf, 0x8a, 0xb8, 0xdc, 0xd6, 0xa6, 0x42, 0xc2, 0x25, 0x12, 0x1a}, {0xe7, 0xf4, 0x61, 0x70, 0xd6, 0x02, 0xd8, 0xd8, 0xe2, 0xe0, 0x3e, 0xed, 0xe6, 0xe3, 0x21, 0x1a, 0x6b, 0x85, 0xe5, 0x89, 0x38, 0x92, 0xe5, 0xcb, 0x89, 0xbd, 0x17, 0x2e, 0xab, 0x44, 0x90, 0x03}}, - {{0x0b, 0x29, 0xb7, 0xe3, 0xdf, 0x41, 0xe8, 0x3a, 0x70, 0x61, 0x80, 0xfd, 0xde, 0xec, 0x3f, 0xf1, 0x97, 0x3f, 0xe5, 0x4c, 0x4e, 0xa2, 0x39, 0xac, 0x22, 0xe1, 0xd5, 0xb2, 0xc5, 0x75, 0xce, 0x26}, {0x5d, 0x11, 0x79, 0xdc, 0x56, 0xf0, 0x73, 0xe4, 0xae, 0x0d, 0x62, 0xad, 0xa5, 0x15, 0xe3, 0x76, 0x21, 0x97, 0x3c, 0x48, 0x1e, 0x6c, 0x13, 0xa3, 0x26, 0xd9, 0xd5, 0x86, 0xea, 0x83, 0x6d, 0x3e}}, - {{0xf1, 0x16, 0x83, 0xd9, 0x1a, 0x74, 0x2f, 0xae, 0xbd, 0x44, 0x9d, 0xcf, 0x58, 0x58, 0x2d, 0x38, 0xbe, 0x0f, 0x2d, 0xf7, 0xab, 0x98, 0x4e, 0x38, 0x04, 0x38, 0x6d, 0x40, 0x4b, 0xd3, 0xf3, 0x30}, {0x63, 0x80, 0x47, 0x22, 0x62, 0x53, 0x45, 0xc2, 0x4b, 0xbb, 0xb4, 0x60, 0x08, 0x26, 0x17, 0x3e, 0xd6, 0x27, 0x00, 0xc5, 0xfc, 0xda, 0x6d, 0xb8, 0x18, 0x2c, 0x29, 0x5f, 0x41, 0x48, 0xe8, 0x2f}}, - {{0xfa, 0x80, 0x3c, 0x3c, 0x28, 0x11, 0x6a, 0x7b, 0xb4, 0xf3, 0xf3, 0xdf, 0xc2, 0xb9, 0xa2, 0x9c, 0x80, 0x37, 0xd1, 0x7e, 0x61, 0xf2, 0x0f, 0x34, 0xec, 0x2b, 0x7d, 0xec, 0xac, 0xe5, 0x0c, 0x3e}, {0x89, 0xfb, 0x37, 0x3d, 0x2b, 0x2e, 0x41, 0xd7, 0xd8, 0xfe, 0xb1, 0xc8, 0x6a, 0x86, 0x47, 0x62, 0x0c, 0x59, 0x05, 0x28, 0x39, 0x02, 0x6b, 0x6f, 0xf4, 0xf3, 0x68, 0x92, 0x2c, 0x38, 0xed, 0x0c}}, - {{0xab, 0xe3, 0xe9, 0x62, 0xec, 0xdc, 0x17, 0xf5, 0x35, 0x67, 0x0c, 0x1b, 0xeb, 0x7e, 0x0f, 0xef, 0xcf, 0x37, 0xf9, 0x70, 0x7c, 0xf2, 0x97, 0x8b, 0xfc, 0xee, 0x3c, 0xf8, 0x37, 0x7d, 0x8f, 0x3b}, {0xe0, 0xca, 0x26, 0x71, 0xe6, 0xa8, 0x9c, 0xc8, 0x08, 0xe2, 0x05, 0x79, 0xf9, 0x8a, 0x34, 0xbb, 0xf5, 0x6f, 0xe2, 0x15, 0x6d, 0xe5, 0x4a, 0x45, 0xf4, 0xbd, 0x82, 0x2c, 0x1f, 0x8d, 0x45, 0x1e}}, - {{0x90, 0x5b, 0xaa, 0xac, 0x55, 0xd2, 0x21, 0x8f, 0xfb, 0xe7, 0x40, 0x08, 0xa0, 0xe5, 0x29, 0xe7, 0x5d, 0xeb, 0x63, 0x0b, 0x75, 0x9b, 0xc6, 0x56, 0xf7, 0x82, 0xc3, 0x4c, 0xb9, 0xc9, 0xaa, 0x1e}, {0xf4, 0xad, 0xf0, 0xd4, 0x67, 0xd4, 0x70, 0xa3, 0xe2, 0x0b, 0x7c, 0x19, 0xcf, 0xc5, 0xc1, 0x5e, 0x42, 0x6d, 0x3f, 0xf0, 0xf4, 0x51, 0xcf, 0xc1, 0xff, 0x27, 0xdc, 0x4e, 0x44, 0x04, 0xfb, 0x09}}, - {{0xfe, 0x31, 0x5c, 0x20, 0x2f, 0x0d, 0x2c, 0xb1, 0x91, 0x15, 0xfb, 0x6b, 0x1c, 0xf7, 0xa6, 0xee, 0xb2, 0x03, 0x50, 0xf7, 0x9c, 0x0a, 0xaf, 0x67, 0xe7, 0x47, 0x37, 0x1d, 0x66, 0xbc, 0x98, 0x03}, {0x86, 0xe8, 0x1c, 0xa7, 0x9b, 0xc5, 0xcb, 0xcf, 0xe3, 0xf8, 0xed, 0xab, 0xea, 0xdc, 0xc5, 0x13, 0x7f, 0x13, 0x37, 0xe3, 0x2b, 0xf9, 0xcc, 0x94, 0x0e, 0x26, 0x99, 0x71, 0xf8, 0x13, 0x84, 0x06}}, - {{0x2b, 0x98, 0x8d, 0x30, 0xf7, 0x26, 0x2d, 0xf8, 0x37, 0xd7, 0x64, 0x51, 0x95, 0xf7, 0x63, 0xa4, 0x93, 0x27, 0x01, 0x2a, 0xdb, 0x0c, 0x3b, 0x94, 0xd2, 0x77, 0x77, 0xd9, 0xc7, 0x43, 0xdc, 0x36}, {0xd4, 0x9c, 0x00, 0xc9, 0x9c, 0x72, 0xd0, 0x28, 0x38, 0x64, 0xb7, 0x83, 0x1e, 0x75, 0xce, 0x95, 0x2f, 0xd8, 0xe4, 0x1e, 0x0c, 0x8d, 0x75, 0x7f, 0xb2, 0x23, 0x03, 0x87, 0x5c, 0x97, 0x84, 0x04}}, - {{0x03, 0xbc, 0x95, 0xc2, 0x07, 0x64, 0x3b, 0x57, 0x76, 0xb2, 0x53, 0x36, 0x62, 0x43, 0x81, 0x3d, 0x99, 0x62, 0x19, 0x16, 0x38, 0x55, 0x5a, 0x71, 0xdd, 0x13, 0x24, 0x29, 0x4c, 0x54, 0x2d, 0x1a}, {0xb9, 0xeb, 0x2a, 0xa8, 0x37, 0x0d, 0xeb, 0x35, 0x2b, 0xff, 0x68, 0x76, 0x74, 0xbf, 0x3b, 0xc4, 0x6f, 0xe3, 0xbe, 0xca, 0x7f, 0xe2, 0x86, 0xb0, 0x68, 0xe8, 0x5e, 0x0d, 0x8b, 0x49, 0xa3, 0x2a}}, - {{0x45, 0x4e, 0x2e, 0x36, 0xad, 0xbf, 0xc2, 0xbd, 0x90, 0x92, 0x9d, 0xa9, 0xc4, 0x1d, 0xa5, 0xe6, 0x5d, 0x7d, 0xf6, 0x60, 0xf1, 0x06, 0x7b, 0x7a, 0xd8, 0xd9, 0xa7, 0x65, 0x77, 0x88, 0xcd, 0x19}, {0x6f, 0x93, 0xff, 0x64, 0x05, 0x63, 0x51, 0x8d, 0xef, 0x97, 0x13, 0x50, 0x4d, 0xc6, 0xdb, 0xfa, 0xbc, 0xe5, 0xe4, 0x10, 0x0f, 0x7c, 0x9f, 0xc6, 0x9d, 0x98, 0xb6, 0xd1, 0xea, 0xdb, 0x2a, 0x2d}}, - {{0x63, 0x72, 0x55, 0xcd, 0xb1, 0xb4, 0x3a, 0x58, 0x56, 0x8c, 0x2f, 0x31, 0x10, 0xf8, 0xe4, 0xaa, 0x4d, 0xdf, 0xd9, 0x07, 0x1d, 0x2a, 0x23, 0x2f, 0x3a, 0x77, 0xc6, 0xc4, 0xa3, 0xb5, 0xba, 0x2f}, {0xf2, 0xbe, 0x5d, 0xd3, 0x12, 0x44, 0xe5, 0x73, 0xa8, 0xe5, 0xec, 0x67, 0xa1, 0x87, 0xce, 0x3e, 0x81, 0x67, 0xe9, 0x59, 0x3f, 0xf6, 0x23, 0x92, 0x5d, 0x05, 0x98, 0xf5, 0x10, 0xe0, 0xe5, 0x0e}}, - {{0xa4, 0x45, 0xf2, 0xd0, 0xcf, 0x6d, 0x69, 0x29, 0xa0, 0x66, 0xc3, 0x73, 0xbf, 0xfc, 0x77, 0x82, 0xcf, 0x74, 0x99, 0x1f, 0x74, 0xc2, 0x41, 0x68, 0x9b, 0x28, 0xe6, 0x18, 0x4c, 0x2e, 0x09, 0x37}, {0x82, 0xf2, 0x37, 0x2d, 0x53, 0x2b, 0x8f, 0x83, 0x16, 0x60, 0xb0, 0xc4, 0x60, 0x5e, 0xdd, 0x81, 0x5d, 0x4e, 0x11, 0x45, 0x34, 0xb0, 0x7c, 0xfc, 0x1f, 0x34, 0xa9, 0x4d, 0x63, 0x9c, 0xff, 0x32}}, - {{0x6d, 0x5d, 0x44, 0x00, 0x31, 0xae, 0xf0, 0x9f, 0x4e, 0xf6, 0x8c, 0x96, 0x2c, 0xe2, 0xd8, 0x7c, 0x2d, 0xbc, 0x3f, 0xfd, 0x99, 0x70, 0xc7, 0x6e, 0x7a, 0x75, 0xce, 0x4a, 0x09, 0xd4, 0xed, 0x03}, {0xab, 0xda, 0x7d, 0xaa, 0xf4, 0xd0, 0x49, 0xb9, 0x51, 0xce, 0x21, 0xe4, 0xa6, 0x75, 0x79, 0x95, 0x9a, 0x19, 0xd4, 0x68, 0xc9, 0xf7, 0x87, 0xe3, 0x8c, 0x37, 0xc2, 0xac, 0xd8, 0x83, 0x76, 0x10}}, - {{0x92, 0xf9, 0x02, 0x0d, 0x16, 0xca, 0x36, 0x7c, 0x1b, 0xcf, 0x2a, 0xbd, 0x44, 0x77, 0xc4, 0xb3, 0x7d, 0x23, 0x8e, 0x2a, 0x7a, 0x87, 0xfa, 0xd4, 0x9a, 0x81, 0xc5, 0xf7, 0xda, 0xa3, 0x94, 0x13}, {0x5a, 0x45, 0x63, 0x1b, 0x52, 0x5e, 0x13, 0xb6, 0x5a, 0xe1, 0x38, 0xac, 0xa0, 0x1f, 0xf9, 0x4b, 0xb6, 0x55, 0xe8, 0x1b, 0x64, 0x9f, 0xd9, 0x81, 0x21, 0x14, 0x5d, 0xd7, 0x8b, 0x1b, 0x24, 0x22}}, - {{0x1b, 0xfe, 0x89, 0xb9, 0x69, 0x5f, 0xb4, 0xce, 0x45, 0x8d, 0x97, 0xc7, 0xed, 0x93, 0xe7, 0xb7, 0x39, 0x0c, 0x03, 0x41, 0x63, 0x5a, 0x07, 0x3b, 0xe6, 0xd2, 0x00, 0x6c, 0x8f, 0xb6, 0x76, 0x2d}, {0x3e, 0x0c, 0x1f, 0xce, 0x11, 0x1f, 0xc8, 0x3a, 0x0c, 0x05, 0xb5, 0x2a, 0x29, 0xaf, 0x65, 0x50, 0xf1, 0x43, 0xba, 0xa9, 0x5a, 0x30, 0xc1, 0x8a, 0x67, 0x30, 0xd9, 0xe7, 0xba, 0x81, 0x97, 0x16}}, - {{0x8f, 0xa4, 0x35, 0xd8, 0x89, 0xf0, 0xfe, 0x20, 0x64, 0x2a, 0x07, 0xd6, 0x66, 0x77, 0x23, 0xcb, 0x7c, 0x3b, 0x7c, 0xdd, 0x57, 0x0b, 0xef, 0x18, 0xa0, 0xa4, 0x57, 0x8f, 0x57, 0x5f, 0x3d, 0x1a}, {0x89, 0xc9, 0x32, 0x3e, 0x97, 0x25, 0x74, 0x25, 0xee, 0x9a, 0xb5, 0x38, 0x1a, 0xcb, 0x95, 0xde, 0x08, 0xae, 0x8e, 0x32, 0x5a, 0xc4, 0x69, 0x5e, 0x17, 0x90, 0x45, 0x51, 0x70, 0x38, 0xfa, 0x12}}, - {{0xf3, 0x00, 0x15, 0xb1, 0x1d, 0xb7, 0xcc, 0x54, 0x07, 0x4e, 0x55, 0xc9, 0x08, 0x7b, 0xe2, 0xea, 0x5d, 0x81, 0x33, 0x6e, 0x91, 0xa0, 0xac, 0xd7, 0x53, 0xa8, 0xdd, 0x11, 0x73, 0xe2, 0x24, 0x09}, {0x2a, 0x94, 0xe9, 0xcc, 0x3c, 0xf9, 0x61, 0x6d, 0x33, 0xe8, 0x83, 0x7e, 0xd1, 0x5d, 0x9e, 0x2d, 0x50, 0xf7, 0x67, 0x6d, 0xea, 0x7a, 0x10, 0x84, 0xa5, 0xa1, 0x7c, 0x75, 0x62, 0x6e, 0xbe, 0x3c}}, - {{0x76, 0x73, 0x97, 0xb7, 0xd0, 0x11, 0x96, 0x74, 0x34, 0xec, 0xcd, 0x4c, 0x46, 0x16, 0xee, 0x91, 0x1a, 0x12, 0x2a, 0xa8, 0x11, 0xee, 0x1a, 0xa7, 0x95, 0xde, 0x85, 0xd1, 0xbf, 0x4b, 0x9f, 0x0b}, {0x6d, 0xa2, 0x7e, 0xea, 0xcc, 0x72, 0x57, 0xd1, 0x27, 0x6d, 0x08, 0x87, 0xdb, 0x58, 0x71, 0xd1, 0x4d, 0x2b, 0xea, 0x1e, 0xae, 0x1f, 0x93, 0x60, 0x99, 0xdd, 0x28, 0xb8, 0x13, 0x46, 0xdc, 0x34}}, - {{0x6f, 0xf9, 0xe5, 0x1e, 0xd8, 0x03, 0xbd, 0x1f, 0x7a, 0x07, 0x91, 0xb6, 0x82, 0x97, 0x1c, 0x37, 0xe5, 0x5c, 0xbf, 0x19, 0xa7, 0xf5, 0x2d, 0xf5, 0x53, 0x9d, 0x1d, 0x45, 0xb2, 0xca, 0xd6, 0x02}, {0xc3, 0xf9, 0x90, 0x5e, 0x71, 0x53, 0xb8, 0x19, 0x2b, 0xe0, 0xb7, 0x62, 0x9e, 0x10, 0x1e, 0x6e, 0x35, 0x5b, 0x4a, 0x1d, 0x2c, 0xb7, 0x02, 0x43, 0xf8, 0x46, 0x21, 0xe2, 0x6d, 0xbe, 0xb0, 0x10}}, - {{0x22, 0x73, 0xaa, 0x81, 0xc7, 0x34, 0xcf, 0x24, 0xe3, 0x5e, 0xc4, 0xb1, 0x2e, 0xbd, 0x47, 0x32, 0x39, 0xea, 0x13, 0x04, 0x78, 0x43, 0xae, 0xf9, 0xa6, 0x78, 0x65, 0x78, 0xb8, 0xdc, 0x16, 0x0d}, {0xc8, 0xb1, 0xa7, 0x3b, 0x02, 0xe5, 0x41, 0x9d, 0x81, 0x1a, 0x66, 0xfc, 0x86, 0x2c, 0x5e, 0xfe, 0xc3, 0x0f, 0x7e, 0x42, 0xd6, 0xc0, 0x29, 0xe7, 0xcb, 0x05, 0x71, 0x49, 0xca, 0x05, 0xf3, 0x05}}, - {{0x9d, 0x7b, 0x2f, 0x25, 0x68, 0xa8, 0xfa, 0x1a, 0x2c, 0xb4, 0xe9, 0x52, 0x7b, 0x61, 0x19, 0x9e, 0x83, 0xf1, 0xe3, 0xe9, 0x9d, 0x44, 0xf4, 0xd5, 0xe8, 0x20, 0xce, 0x63, 0x11, 0x0e, 0x2a, 0x32}, {0x73, 0xbf, 0x51, 0x63, 0x0a, 0xcb, 0x91, 0xb3, 0xcd, 0x6a, 0x5a, 0x4f, 0x7b, 0x1f, 0x0b, 0x61, 0x26, 0xaa, 0x20, 0xcd, 0x31, 0x9f, 0x76, 0x3a, 0x67, 0xbf, 0x1b, 0x56, 0xa2, 0x28, 0xe3, 0x3c}}, - {{0xb2, 0x3f, 0x40, 0xfd, 0x39, 0x9e, 0xc7, 0x30, 0x04, 0xf5, 0x6f, 0x91, 0x56, 0x12, 0x82, 0x1d, 0x6b, 0x2b, 0xd6, 0x65, 0xde, 0xef, 0x73, 0xfe, 0xe2, 0x4d, 0xa3, 0xc6, 0x42, 0x47, 0x94, 0x29}, {0x17, 0x4d, 0xa5, 0xb2, 0x41, 0x99, 0x6e, 0xaa, 0xca, 0xd4, 0x34, 0x1b, 0x96, 0x44, 0xe2, 0x50, 0x45, 0xcb, 0x99, 0xa1, 0xc4, 0x42, 0x06, 0x6b, 0x0c, 0xa0, 0xfd, 0xee, 0x9d, 0x60, 0xf3, 0x01}}, - {{0x9e, 0x4a, 0x77, 0xe0, 0xa5, 0x06, 0xab, 0x4b, 0x99, 0x53, 0xbd, 0x52, 0x42, 0x3b, 0x30, 0xa3, 0x20, 0x95, 0x29, 0xe7, 0x7b, 0x1f, 0xb4, 0x4b, 0xb4, 0xfa, 0xeb, 0xd0, 0xef, 0xed, 0x21, 0x3e}, {0xe5, 0x99, 0x64, 0xcb, 0x5f, 0x14, 0x4c, 0x46, 0x10, 0x48, 0xca, 0x1a, 0xb7, 0x61, 0x35, 0xdf, 0x35, 0x56, 0x56, 0x37, 0xfc, 0x58, 0xbc, 0x04, 0x50, 0x57, 0xbf, 0x6b, 0x9a, 0x27, 0x58, 0x1c}}, - {{0x44, 0xca, 0xc0, 0x9d, 0xfe, 0xf0, 0xf4, 0x99, 0x02, 0x17, 0x42, 0xb0, 0x82, 0xd6, 0xfb, 0x02, 0x90, 0xd8, 0x68, 0x29, 0x31, 0xf1, 0xfe, 0x2e, 0x10, 0x44, 0xb1, 0x6d, 0x2e, 0x22, 0xe2, 0x15}, {0x67, 0x06, 0x9a, 0xc9, 0xe2, 0x83, 0xa0, 0x67, 0xfb, 0x87, 0xd2, 0x6b, 0x4a, 0xd1, 0xab, 0x23, 0xb0, 0xfd, 0x5d, 0x2a, 0x1e, 0xeb, 0xdd, 0xab, 0x7e, 0x66, 0x90, 0xbe, 0x0a, 0x96, 0x60, 0x0b}}, - {{0xaf, 0x4f, 0x5a, 0xba, 0x4e, 0x68, 0x40, 0xc7, 0x6c, 0xc3, 0x7c, 0x13, 0x95, 0xce, 0x22, 0x4c, 0x1a, 0x2b, 0x5a, 0xc4, 0x2b, 0xa4, 0x1a, 0x28, 0x59, 0x9a, 0xe0, 0x97, 0x6b, 0x14, 0x6b, 0x37}, {0x89, 0xe2, 0x2a, 0x98, 0xb0, 0xbd, 0xef, 0xc4, 0xfc, 0x83, 0x4c, 0x56, 0xb6, 0xa7, 0x54, 0xf5, 0xdf, 0xf8, 0x31, 0xbe, 0x0f, 0xd2, 0x67, 0x8a, 0xf6, 0x6d, 0x78, 0x41, 0x03, 0x9f, 0x37, 0x2c}}, - {{0x4f, 0x8e, 0x1f, 0x4b, 0xa8, 0x2f, 0xb6, 0x2a, 0xd4, 0xd7, 0xe0, 0x51, 0x52, 0x76, 0x04, 0x56, 0x9b, 0x0b, 0x61, 0x62, 0xb4, 0x2e, 0x1d, 0x86, 0x50, 0x6e, 0x0e, 0x45, 0xbd, 0xe0, 0xc4, 0x31}, {0x1e, 0xbe, 0x2a, 0xf7, 0x9e, 0x3e, 0xd3, 0xd8, 0xef, 0x6c, 0x4a, 0x7f, 0x7b, 0xee, 0x03, 0xb8, 0xa6, 0x4d, 0x39, 0x0c, 0x38, 0xb4, 0x3c, 0x9a, 0xf0, 0xb5, 0xb3, 0x13, 0x27, 0x8e, 0x28, 0x12}}, - {{0x3e, 0x0f, 0xea, 0x1f, 0x9e, 0x11, 0x8c, 0x1d, 0x53, 0xa7, 0xc0, 0xaf, 0x23, 0x84, 0x48, 0xcf, 0xf4, 0x1a, 0x1d, 0x42, 0x85, 0xdc, 0x6e, 0x0b, 0x8e, 0x5d, 0x1f, 0xff, 0xdd, 0xf1, 0x1f, 0x26}, {0xaa, 0x6c, 0x9e, 0xd1, 0x50, 0x57, 0x99, 0x01, 0xd4, 0x8e, 0x49, 0xb7, 0xdf, 0x82, 0x1d, 0xad, 0xb7, 0x31, 0x91, 0xb6, 0x09, 0xd7, 0x7b, 0x24, 0x80, 0xf7, 0xa5, 0x15, 0x79, 0xb8, 0x39, 0x25}}, - {{0x9a, 0x93, 0xe8, 0xf8, 0x80, 0xfb, 0x89, 0x75, 0xcd, 0xbc, 0x5a, 0xd4, 0x10, 0x08, 0xbd, 0x9e, 0x44, 0x9b, 0xcc, 0x0c, 0xca, 0x79, 0xba, 0xfd, 0x80, 0xc9, 0x5d, 0x8f, 0xea, 0x1a, 0xa0, 0x1a}, {0x0b, 0xe3, 0x83, 0x6b, 0x27, 0xfa, 0x55, 0xa5, 0x1b, 0x8a, 0xa4, 0x8c, 0xd3, 0x1d, 0x8f, 0x57, 0x0d, 0x37, 0x6b, 0xf8, 0x02, 0xd1, 0xf7, 0x1d, 0x91, 0x53, 0x33, 0x4e, 0x63, 0x46, 0x4a, 0x39}}, - {{0x05, 0x60, 0xa0, 0xb2, 0xb4, 0xff, 0xa6, 0x20, 0xe2, 0xc4, 0x24, 0xfb, 0x71, 0x8f, 0xeb, 0x92, 0xf8, 0x84, 0xf7, 0x96, 0x67, 0x09, 0x8d, 0xaa, 0x0d, 0x33, 0x0e, 0x8d, 0x07, 0x16, 0xe3, 0x16}, {0x70, 0x50, 0x32, 0xd4, 0x60, 0x1a, 0x44, 0xdd, 0x5b, 0x7b, 0x21, 0x1b, 0x1a, 0x77, 0x11, 0x4b, 0x48, 0x2f, 0xda, 0x26, 0x4e, 0x50, 0x9b, 0xcd, 0x7e, 0x47, 0x72, 0x2a, 0xe3, 0xeb, 0x0a, 0x30}}, - {{0x8c, 0x50, 0xd4, 0xd1, 0x87, 0x4c, 0x4f, 0x74, 0x73, 0xa5, 0x48, 0xd9, 0x58, 0x60, 0xec, 0xb3, 0xea, 0x9f, 0xb9, 0x43, 0x79, 0xb4, 0xcc, 0xc4, 0xf2, 0x3f, 0xeb, 0x7c, 0x8f, 0x92, 0x2e, 0x29}, {0xad, 0x27, 0xd0, 0x03, 0x76, 0x44, 0xce, 0x87, 0x20, 0x0b, 0x88, 0xe6, 0xca, 0x90, 0xb9, 0x9b, 0x5a, 0x74, 0x65, 0xe4, 0xda, 0x41, 0x2d, 0xc9, 0x9c, 0x27, 0x29, 0x2d, 0xf5, 0x81, 0x23, 0x02}}, - {{0xe3, 0x1d, 0xd6, 0x30, 0x07, 0x38, 0x62, 0x07, 0x05, 0xcc, 0x71, 0x37, 0xf3, 0xe3, 0xdd, 0x1e, 0xb3, 0x4a, 0xb6, 0xc2, 0x1c, 0x05, 0x7f, 0x1b, 0x93, 0x0e, 0x0a, 0x8a, 0x02, 0xef, 0x53, 0x04}, {0x3f, 0xb8, 0x06, 0x51, 0x8c, 0x20, 0xf4, 0x4a, 0xb2, 0xe9, 0x11, 0x19, 0xb8, 0x0b, 0x2f, 0xa1, 0x84, 0x62, 0xca, 0x13, 0xe3, 0x55, 0x23, 0x8d, 0x2d, 0xe4, 0xdd, 0x77, 0x26, 0xc6, 0x9a, 0x19}}, - {{0xcb, 0x31, 0xa5, 0x65, 0x8b, 0x07, 0xd5, 0xa5, 0xad, 0xde, 0xa8, 0x40, 0x96, 0xd3, 0xd4, 0xd6, 0x4a, 0x19, 0x84, 0x2e, 0xa3, 0x10, 0x95, 0x73, 0xda, 0xb2, 0x24, 0x2d, 0x7f, 0x7e, 0x46, 0x07}, {0xe5, 0x65, 0x51, 0x18, 0x5d, 0xd5, 0xca, 0x2a, 0xad, 0xc7, 0xc9, 0x77, 0x6a, 0x14, 0xb2, 0x0f, 0x3d, 0x79, 0x25, 0x5a, 0xc7, 0xf9, 0x21, 0x4a, 0x9a, 0x66, 0x5c, 0x7e, 0x53, 0xb6, 0x1f, 0x05}}, - {{0xfc, 0xe3, 0x39, 0x27, 0x3e, 0x2c, 0x77, 0x5c, 0xfd, 0x20, 0xdc, 0xc5, 0x27, 0x51, 0xf3, 0xfe, 0x04, 0xb0, 0xf0, 0x43, 0x2b, 0x09, 0xd1, 0x93, 0x81, 0x2e, 0x30, 0x3a, 0xb4, 0x1a, 0x10, 0x36}, {0x61, 0x29, 0x27, 0x69, 0x8a, 0x2c, 0x06, 0xa2, 0x3c, 0x55, 0xfe, 0x33, 0xda, 0x1e, 0xae, 0x95, 0x9f, 0x1d, 0xc3, 0x13, 0xd6, 0x8e, 0x55, 0x0c, 0x18, 0xf5, 0xb1, 0x0b, 0xad, 0xb3, 0x79, 0x26}}, - {{0x87, 0x65, 0x56, 0x93, 0x2d, 0x4a, 0x99, 0x4c, 0x60, 0x2d, 0xd1, 0x95, 0x82, 0x0d, 0xeb, 0xde, 0xc4, 0x8d, 0xec, 0x45, 0x93, 0x25, 0xc2, 0xe1, 0xeb, 0x88, 0x72, 0x37, 0xf2, 0xd2, 0x35, 0x2a}, {0x4d, 0xee, 0x9d, 0xaf, 0x3f, 0x20, 0x98, 0xdd, 0xb8, 0x19, 0x21, 0xc5, 0x8c, 0x2c, 0x66, 0x5c, 0x4e, 0x51, 0x80, 0x84, 0xcb, 0xcd, 0x3e, 0xa6, 0xaa, 0x1b, 0x2a, 0x33, 0xd5, 0xf4, 0xda, 0x18}}, - {{0xc3, 0x70, 0xfa, 0xcc, 0xad, 0xd0, 0x4c, 0xd8, 0xa0, 0x09, 0x31, 0xcc, 0x09, 0xd2, 0x7c, 0x00, 0x0f, 0xfa, 0x25, 0x32, 0x5e, 0x58, 0xed, 0x78, 0xa0, 0xbe, 0x8a, 0x42, 0x43, 0xaa, 0x9e, 0x03}, {0x5c, 0xc6, 0x61, 0xaa, 0xf9, 0x04, 0xf7, 0xb8, 0xd1, 0x1f, 0x81, 0xd7, 0xee, 0x1e, 0x02, 0xb5, 0xb6, 0xc3, 0x41, 0x06, 0xe1, 0xd1, 0x3a, 0x5e, 0xc8, 0x09, 0xfb, 0x97, 0x99, 0x2d, 0x6d, 0x28}}, - {{0x73, 0x9c, 0x43, 0xf5, 0xb3, 0x78, 0x16, 0x2f, 0x1b, 0x11, 0x0a, 0xd3, 0xdd, 0x1c, 0x1b, 0x9f, 0x4d, 0x83, 0x32, 0x9b, 0x9f, 0x47, 0x01, 0x16, 0x1b, 0x72, 0x20, 0x94, 0xb6, 0xc1, 0xc1, 0x17}, {0x1a, 0x20, 0xc2, 0x90, 0x72, 0x0b, 0x68, 0x5b, 0x23, 0xbc, 0x1a, 0xb0, 0x4d, 0xcb, 0xf9, 0xf9, 0x04, 0xe5, 0x6a, 0xf2, 0xd4, 0x6b, 0x4e, 0x1d, 0x2f, 0x82, 0x88, 0x59, 0x69, 0xe0, 0x9d, 0x38}}, - {{0x86, 0xbd, 0x6c, 0xa2, 0x46, 0xa5, 0xcc, 0xb1, 0x30, 0x75, 0x48, 0x8d, 0xf0, 0x36, 0x81, 0xd5, 0x07, 0x2f, 0xc4, 0x93, 0x61, 0x5c, 0x22, 0xc0, 0xd4, 0x6b, 0xdc, 0x1c, 0xd2, 0x59, 0x00, 0x39}, {0xd4, 0x22, 0x8e, 0x31, 0xde, 0x72, 0x0c, 0x6b, 0xb6, 0xb6, 0x2f, 0x54, 0x3a, 0x9e, 0x5b, 0xc2, 0x40, 0x74, 0x9f, 0xda, 0xe6, 0x06, 0xa8, 0xa7, 0x4d, 0x8d, 0x26, 0x43, 0xce, 0x71, 0x2a, 0x3c}}, - {{0x22, 0xf1, 0x89, 0x04, 0xa2, 0x11, 0xe1, 0x50, 0xcb, 0x8e, 0x5f, 0xfd, 0xda, 0x1a, 0xdb, 0x07, 0xb9, 0x02, 0x90, 0x1f, 0xee, 0x51, 0xa6, 0xf6, 0xca, 0x57, 0xca, 0x41, 0x85, 0x8f, 0xdc, 0x25}, {0xdc, 0xee, 0xed, 0xc4, 0xe0, 0xe6, 0x41, 0x82, 0x92, 0x53, 0xa0, 0x57, 0x05, 0x5a, 0xdb, 0xe1, 0xa3, 0x32, 0xe5, 0x6e, 0xa1, 0xd4, 0x07, 0x4b, 0x32, 0xf4, 0xed, 0x70, 0x97, 0x0c, 0x1a, 0x1d}}, - {{0xf4, 0x71, 0x86, 0x00, 0xf6, 0x68, 0x6b, 0xb2, 0x07, 0x43, 0x9e, 0x0b, 0x0b, 0xa0, 0xdb, 0x75, 0x1f, 0x71, 0x2f, 0xc8, 0xb7, 0x65, 0xa7, 0xd9, 0x53, 0xe8, 0xcb, 0x27, 0xc0, 0xf4, 0x65, 0x27}, {0x5b, 0xb6, 0x7a, 0xe9, 0x24, 0xd0, 0xa7, 0xb2, 0x6d, 0x2a, 0x27, 0x77, 0x26, 0xee, 0xf5, 0x1d, 0x3d, 0x27, 0x89, 0xc7, 0x51, 0x45, 0x0e, 0x6c, 0x9d, 0x63, 0x75, 0x28, 0x99, 0x7d, 0xa1, 0x27}}, - {{0x8d, 0xd6, 0x60, 0x42, 0xfe, 0xfc, 0x10, 0xdb, 0x63, 0x26, 0xbe, 0xa7, 0x95, 0x7c, 0x54, 0x71, 0xa3, 0xa1, 0xce, 0xd0, 0x6a, 0x28, 0x58, 0x12, 0xea, 0x47, 0xe9, 0x88, 0xac, 0x52, 0xdf, 0x27}, {0xb7, 0x0f, 0xc3, 0x00, 0x53, 0x5b, 0x4e, 0x3d, 0x32, 0x6e, 0x88, 0x36, 0xe4, 0xbe, 0xf6, 0x93, 0x5d, 0x55, 0xd9, 0xbd, 0x1c, 0xcf, 0xe4, 0xbc, 0xe2, 0x10, 0x55, 0xc3, 0xcf, 0x32, 0x46, 0x20}}, - {{0xa6, 0xc2, 0xec, 0xd7, 0xf8, 0x28, 0x7c, 0x8b, 0x17, 0x2a, 0xd2, 0x04, 0xb7, 0xba, 0x84, 0x34, 0xcd, 0xbf, 0xd8, 0xe6, 0x38, 0x55, 0xeb, 0x68, 0x2f, 0xfd, 0x09, 0x05, 0x25, 0x8d, 0x08, 0x04}, {0x08, 0xb9, 0x2e, 0x75, 0x8e, 0x01, 0xf8, 0x57, 0xe9, 0xb3, 0x60, 0x33, 0xe2, 0x94, 0x09, 0xc7, 0x64, 0x13, 0x9a, 0x96, 0xc5, 0xe0, 0xb5, 0x31, 0x51, 0x1c, 0x4c, 0xb6, 0x9c, 0x3b, 0x1d, 0x24}}, - {{0x37, 0x8b, 0x32, 0x63, 0x07, 0xa9, 0x0f, 0x07, 0x4e, 0x45, 0xd1, 0xf7, 0xc9, 0x7f, 0xb7, 0x80, 0x9f, 0x9b, 0x1c, 0xb0, 0x95, 0xba, 0x51, 0xa8, 0x3c, 0xdf, 0x20, 0x72, 0x54, 0x17, 0x4f, 0x10}, {0xfb, 0x19, 0xe7, 0x05, 0x53, 0x7e, 0xc8, 0x7d, 0x87, 0x8b, 0xd5, 0xfb, 0xd5, 0xf6, 0x8f, 0x33, 0x5f, 0x32, 0xf7, 0x14, 0x20, 0xe7, 0xc5, 0xf8, 0x88, 0xfe, 0x51, 0x0c, 0xfc, 0xfe, 0x09, 0x03}}, - {{0x80, 0x15, 0xf8, 0x9c, 0x47, 0x81, 0x3e, 0xb3, 0xd8, 0x39, 0x1a, 0x43, 0x78, 0xf7, 0x43, 0x3d, 0xd1, 0x16, 0xaf, 0xf8, 0x67, 0x25, 0x34, 0xca, 0xdb, 0x0c, 0x4b, 0x21, 0x0a, 0x43, 0x13, 0x31}, {0x99, 0x43, 0x4f, 0x0b, 0x73, 0x59, 0xc9, 0x13, 0xb0, 0xa2, 0x5c, 0xc6, 0x6e, 0x1a, 0x34, 0xe5, 0xd3, 0xe4, 0x14, 0x33, 0x23, 0xa6, 0x52, 0xcb, 0x21, 0xda, 0xfc, 0xf9, 0x52, 0xc5, 0xed, 0x2c}}, - {{0xa7, 0x2c, 0x0b, 0xbc, 0x21, 0xd3, 0xf2, 0xe2, 0x5b, 0x41, 0xf2, 0xb9, 0x8b, 0x6d, 0x52, 0xb2, 0x01, 0x10, 0xfe, 0x52, 0x8f, 0x2a, 0x60, 0xbf, 0xbc, 0x8e, 0xeb, 0x95, 0x89, 0xf2, 0x68, 0x3d}, {0xae, 0xe0, 0x60, 0xf2, 0x8c, 0x98, 0xbc, 0x15, 0xb4, 0x73, 0x15, 0xa7, 0x53, 0x72, 0xfe, 0xd3, 0xb9, 0x55, 0x30, 0x5a, 0x86, 0xa0, 0x6e, 0x5d, 0xfe, 0x40, 0x67, 0xec, 0xfd, 0x9a, 0xef, 0x08}}, - {{0x14, 0xc5, 0xbe, 0x91, 0xc3, 0xd6, 0xa6, 0x4f, 0xb8, 0xec, 0x64, 0xb8, 0x29, 0x32, 0xa8, 0xb5, 0x67, 0x21, 0x98, 0x41, 0x27, 0x3f, 0x59, 0x35, 0xe4, 0x91, 0xb4, 0x64, 0xd3, 0xab, 0x02, 0x14}, {0xbf, 0x9c, 0x82, 0x5f, 0xb5, 0x91, 0x4f, 0xad, 0xc1, 0x46, 0x17, 0xbd, 0xce, 0x24, 0x78, 0x60, 0xaf, 0x5c, 0x35, 0xad, 0xad, 0x5a, 0x41, 0x89, 0x02, 0xaa, 0x31, 0x8e, 0xb1, 0x54, 0x1d, 0x1e}}, - {{0xf0, 0x92, 0x17, 0xff, 0xe3, 0xff, 0x68, 0xf2, 0xb7, 0x7a, 0x24, 0xc1, 0x6d, 0x82, 0x0d, 0xd3, 0x6a, 0x54, 0x51, 0x04, 0xa8, 0xde, 0x35, 0xd8, 0x28, 0x67, 0x1b, 0x5b, 0x7f, 0x78, 0xf3, 0x07}, {0x48, 0x5b, 0xda, 0x22, 0x30, 0x7c, 0xbe, 0x06, 0xce, 0xee, 0x7e, 0xe5, 0xaf, 0xb0, 0x19, 0x61, 0xed, 0xeb, 0xd0, 0x3b, 0x93, 0xef, 0xb2, 0xff, 0xcb, 0x2f, 0x1b, 0xdb, 0x2c, 0xf7, 0x69, 0x01}}, - {{0x8d, 0x88, 0x4b, 0x29, 0x34, 0x28, 0x56, 0xe4, 0x84, 0x56, 0xf2, 0x64, 0x3b, 0x51, 0xfd, 0xbc, 0x23, 0xd4, 0xab, 0xc4, 0xfb, 0xb8, 0x8e, 0xf0, 0x9f, 0xb4, 0x6b, 0xc8, 0xe3, 0x00, 0xb6, 0x0f}, {0xde, 0xf8, 0x3f, 0x3b, 0x0e, 0xfc, 0xbc, 0xe7, 0x1e, 0xd7, 0xae, 0xf9, 0xea, 0x5e, 0xa6, 0xbe, 0x58, 0x1b, 0x8a, 0xcd, 0x85, 0xec, 0xdf, 0x70, 0xa6, 0xd8, 0x6c, 0x89, 0x67, 0x53, 0xf6, 0x19}}, - {{0x33, 0x1b, 0x22, 0x3c, 0xcf, 0xbf, 0xfa, 0x34, 0x7b, 0x09, 0xc6, 0xd5, 0x3c, 0x88, 0x4b, 0x04, 0x7c, 0x0c, 0xcc, 0x00, 0x5a, 0x71, 0xb0, 0xbf, 0xf5, 0xc9, 0x44, 0x20, 0xd0, 0x54, 0x79, 0x06}, {0x07, 0x8d, 0xdf, 0x61, 0xda, 0x1b, 0x19, 0xd9, 0x75, 0x44, 0x85, 0xa6, 0x46, 0xa4, 0x2a, 0x6d, 0x13, 0xdb, 0x8a, 0xa5, 0xbb, 0xbf, 0xbc, 0x92, 0x39, 0x4f, 0x1c, 0xba, 0xfb, 0xec, 0x5a, 0x06}}, - {{0x57, 0xbd, 0x88, 0x7c, 0x48, 0xeb, 0xc3, 0x86, 0x8e, 0xf8, 0xd2, 0x11, 0xd0, 0xd4, 0x8b, 0xdb, 0xcf, 0x4d, 0xe4, 0xa7, 0xea, 0x69, 0xd8, 0xfa, 0x28, 0x6e, 0x9c, 0x6e, 0xed, 0x30, 0x22, 0x30}, {0xf6, 0x91, 0xa2, 0xbb, 0xa5, 0xed, 0xbe, 0x0f, 0x9a, 0x35, 0x91, 0xab, 0x64, 0x6a, 0xea, 0x92, 0x73, 0x83, 0x8b, 0x4b, 0x70, 0x72, 0x65, 0x2e, 0xf4, 0x02, 0x84, 0xe5, 0x73, 0x76, 0xfd, 0x30}}, - {{0x3a, 0xbf, 0x55, 0xa9, 0xab, 0x2e, 0x84, 0xea, 0xb9, 0x19, 0x1d, 0x65, 0xa2, 0x8c, 0x0d, 0xa2, 0x7a, 0xfb, 0xeb, 0x8c, 0x50, 0x31, 0x2e, 0xab, 0x53, 0xe8, 0x73, 0x83, 0x91, 0xf4, 0xca, 0x3a}, {0x97, 0xca, 0xec, 0x92, 0xf6, 0xa4, 0xca, 0x44, 0xd3, 0xd3, 0xac, 0x22, 0x9a, 0x4b, 0x2e, 0x2b, 0xaa, 0xe6, 0x7b, 0xff, 0x9e, 0x27, 0x30, 0xbc, 0x15, 0x17, 0x5b, 0x84, 0x71, 0x6c, 0x91, 0x3b}}, - {{0x47, 0xd0, 0xd1, 0x21, 0x3b, 0xb0, 0x02, 0x12, 0xbe, 0xb5, 0x54, 0xaa, 0x52, 0x57, 0xae, 0x03, 0x3c, 0x2a, 0xaf, 0x2e, 0x08, 0x41, 0x25, 0xc9, 0x7a, 0x0b, 0x29, 0x5d, 0x1c, 0xe5, 0xad, 0x13}, {0x4c, 0x97, 0x36, 0x5c, 0xdc, 0x8c, 0x41, 0x80, 0x9f, 0xc2, 0x81, 0x1a, 0x73, 0x04, 0x04, 0xd6, 0x6d, 0x1b, 0x89, 0x93, 0x06, 0xba, 0xa2, 0x23, 0xa1, 0x36, 0x16, 0x4b, 0xdc, 0x9a, 0x6f, 0x26}}, - {{0x02, 0x0c, 0xca, 0x40, 0x5e, 0xaa, 0xfd, 0x9a, 0x51, 0x8a, 0x14, 0xa4, 0x4d, 0x98, 0x58, 0xa3, 0x78, 0x0f, 0x42, 0x99, 0x7c, 0xcc, 0xd4, 0xac, 0x8b, 0x31, 0x2c, 0x23, 0x85, 0xc1, 0x87, 0x21}, {0x80, 0x45, 0x9f, 0x49, 0x5d, 0x3d, 0x81, 0x8a, 0x26, 0xd8, 0xa2, 0xdf, 0x3e, 0x11, 0x13, 0xa5, 0x66, 0xf4, 0x2d, 0xf2, 0xf7, 0xfe, 0x8d, 0xeb, 0xd0, 0x99, 0x59, 0x43, 0x3b, 0xfd, 0x31, 0x20}}, - {{0x9a, 0x30, 0x18, 0x33, 0x61, 0x65, 0x8e, 0x03, 0x18, 0x16, 0x67, 0x68, 0x98, 0xcc, 0xbc, 0xfb, 0xed, 0x87, 0x90, 0x0b, 0x5f, 0xf4, 0x78, 0xc0, 0xbb, 0xbd, 0x9c, 0x84, 0xef, 0xe8, 0xf2, 0x30}, {0x91, 0xda, 0xef, 0x49, 0x01, 0x5a, 0x6b, 0xa3, 0x74, 0x93, 0x20, 0x1b, 0x96, 0xde, 0x95, 0x7a, 0xb8, 0x5a, 0x3b, 0x0f, 0xaa, 0x06, 0xca, 0xec, 0x15, 0xde, 0xcb, 0x64, 0xb8, 0x63, 0xdd, 0x31}}, - {{0xb3, 0x93, 0x8e, 0xf9, 0x97, 0xb2, 0x96, 0x47, 0x1e, 0x02, 0xd9, 0x1e, 0x41, 0xb3, 0x93, 0xf4, 0x22, 0xc9, 0x11, 0x5a, 0xf0, 0x49, 0x59, 0x19, 0x86, 0x87, 0xc5, 0x4c, 0x32, 0xa0, 0xc5, 0x35}, {0x04, 0x18, 0x63, 0x26, 0xa7, 0xce, 0x71, 0xfe, 0xed, 0x07, 0xbb, 0xe5, 0x5d, 0x54, 0x35, 0x3b, 0xe0, 0x9b, 0x08, 0x64, 0x02, 0x8c, 0x0c, 0x1e, 0x7e, 0x82, 0x9e, 0x13, 0x27, 0x4b, 0xb2, 0x24}}, - {{0x1b, 0x70, 0x18, 0x48, 0x1e, 0x52, 0x3d, 0xf3, 0xeb, 0x12, 0xb1, 0x4f, 0x9b, 0x6b, 0xd0, 0x0e, 0x38, 0x57, 0x68, 0xd5, 0xb1, 0xf6, 0x8d, 0xd3, 0x2d, 0x1f, 0x64, 0xe3, 0xa3, 0x54, 0x83, 0x2f}, {0x9c, 0x48, 0x5d, 0x8e, 0x8b, 0xb5, 0x57, 0x2f, 0xc5, 0x61, 0xc3, 0x4d, 0x17, 0xab, 0xb1, 0x88, 0x91, 0xa0, 0x07, 0x17, 0x60, 0x61, 0xfe, 0xff, 0x26, 0x40, 0xd9, 0x3f, 0xd9, 0x75, 0x97, 0x07}}, - {{0xe0, 0x34, 0x06, 0x9f, 0x08, 0x4b, 0x09, 0x7d, 0xf3, 0xb4, 0x97, 0x20, 0x73, 0x42, 0x60, 0x32, 0xe3, 0x4a, 0x05, 0x8f, 0x56, 0x5d, 0x95, 0x2d, 0x37, 0xa8, 0xb0, 0xa0, 0xe1, 0x83, 0x94, 0x20}, {0x65, 0x21, 0x8b, 0xc6, 0x32, 0xcb, 0x32, 0x74, 0x3f, 0x2d, 0xb0, 0x7f, 0x65, 0x21, 0xd9, 0x7b, 0x8a, 0xed, 0x43, 0x61, 0x9e, 0xcd, 0x8e, 0x0f, 0x49, 0xec, 0x4a, 0xb9, 0xa9, 0x5f, 0x80, 0x1e}}, - {{0x04, 0xca, 0x44, 0x83, 0x6c, 0x89, 0x13, 0x51, 0x62, 0xb0, 0xdc, 0x14, 0x40, 0x81, 0xf8, 0x3e, 0x36, 0x86, 0xe3, 0x64, 0x2a, 0x40, 0x12, 0x44, 0xab, 0x3a, 0xdf, 0x7f, 0xca, 0xc0, 0xa2, 0x2c}, {0x4e, 0x33, 0x39, 0xdd, 0xb6, 0x11, 0xd4, 0xae, 0xf5, 0x59, 0x88, 0x3c, 0xe8, 0x64, 0xbf, 0xac, 0x0f, 0x8b, 0xf1, 0xbb, 0x0f, 0x90, 0x8a, 0xc6, 0x1c, 0xad, 0xb7, 0x59, 0x97, 0xa1, 0xc2, 0x35}}, - {{0xfa, 0x62, 0xd8, 0x68, 0xaf, 0x18, 0x3e, 0x3d, 0x13, 0x6b, 0x05, 0x7f, 0x49, 0x06, 0xd5, 0xe3, 0xd3, 0x7f, 0x7b, 0xbe, 0xad, 0xfa, 0x45, 0x4e, 0x57, 0xe9, 0xcd, 0x20, 0x3e, 0xda, 0x59, 0x18}, {0x49, 0xe7, 0x6a, 0xf3, 0x90, 0xa0, 0x5d, 0x64, 0xf1, 0x2a, 0x46, 0xa0, 0xb2, 0xb3, 0x1d, 0xd4, 0x58, 0x3c, 0x97, 0x65, 0x5e, 0x2c, 0x6d, 0xa9, 0xd0, 0xe0, 0x51, 0x8f, 0x18, 0x14, 0x1e, 0x14}}, - {{0xf0, 0xfe, 0x67, 0x7a, 0xbe, 0x00, 0xbb, 0xda, 0xda, 0xed, 0xd7, 0x6a, 0x1c, 0xcf, 0x7b, 0x5c, 0xa1, 0x55, 0x6c, 0x31, 0x56, 0xf4, 0x6c, 0x93, 0x06, 0x7f, 0x67, 0xe1, 0xba, 0x6b, 0x3a, 0x0d}, {0xa3, 0xba, 0x60, 0x00, 0x75, 0x80, 0x9b, 0xd3, 0xaf, 0x61, 0x51, 0x30, 0xfa, 0x40, 0xe3, 0xe8, 0x2d, 0x65, 0x85, 0x05, 0x4b, 0xc4, 0x5d, 0x19, 0xd1, 0x07, 0xa9, 0x0b, 0x6b, 0x79, 0xd3, 0x00}}, - {{0x81, 0x1d, 0x33, 0xc0, 0x5e, 0xb9, 0x72, 0x0f, 0xf0, 0x3a, 0x36, 0x8e, 0xb4, 0x70, 0x09, 0xc5, 0xc4, 0xfc, 0x16, 0xa7, 0x23, 0x30, 0x67, 0x8d, 0x14, 0x68, 0x24, 0xfb, 0x5d, 0x48, 0x2d, 0x01}, {0xde, 0x17, 0x24, 0x26, 0xb8, 0x6b, 0x91, 0xed, 0xd3, 0x49, 0x70, 0x01, 0x8d, 0x02, 0x6d, 0x42, 0x8c, 0x0d, 0xe3, 0xb9, 0x50, 0x15, 0x8f, 0x39, 0xee, 0xfd, 0xb5, 0xac, 0x46, 0xc2, 0x18, 0x09}}, - {{0x44, 0x40, 0x25, 0x07, 0xc9, 0xb9, 0x93, 0x12, 0xdc, 0xac, 0x2f, 0x1a, 0xdf, 0x0c, 0x88, 0x40, 0xbe, 0x03, 0x05, 0xf4, 0x80, 0xcd, 0xe3, 0x4d, 0x1d, 0x5c, 0x21, 0xe0, 0x8c, 0xdc, 0xc9, 0x21}, {0xbb, 0xa3, 0xd9, 0x23, 0xe0, 0x32, 0x0b, 0x2a, 0x5d, 0xa8, 0x4d, 0x2c, 0x00, 0x33, 0xfd, 0x8d, 0x2c, 0x03, 0xdc, 0xea, 0x54, 0xfa, 0xfa, 0x90, 0x94, 0xbb, 0x76, 0xd9, 0xb4, 0xe6, 0x22, 0x2b}}, - {{0xf5, 0x6d, 0x43, 0x36, 0x22, 0xfb, 0x67, 0x7f, 0xf4, 0xbf, 0x05, 0x69, 0x40, 0xa9, 0xb7, 0x8c, 0x0a, 0xf2, 0x1f, 0x48, 0xc6, 0x85, 0x00, 0x07, 0x58, 0x61, 0xb8, 0xc4, 0xf1, 0x6b, 0x67, 0x2c}, {0x9e, 0x1a, 0x9c, 0x4a, 0x00, 0x8c, 0xf1, 0x7c, 0x6c, 0xb0, 0x5f, 0xa1, 0x8f, 0xe6, 0x31, 0xf9, 0x87, 0x95, 0x7e, 0x67, 0x21, 0x00, 0x5a, 0x4b, 0x60, 0x6c, 0x5e, 0xa3, 0x4a, 0xf6, 0xb0, 0x2f}}, - {{0x5f, 0x59, 0x70, 0x02, 0x35, 0x11, 0x0c, 0x98, 0x60, 0x8a, 0x80, 0x54, 0xc2, 0xa0, 0x07, 0xda, 0x81, 0x88, 0x15, 0xdd, 0xe1, 0x67, 0xaa, 0xb0, 0xfb, 0xc6, 0xfc, 0x9f, 0x46, 0xe4, 0x75, 0x20}, {0x32, 0x19, 0x0a, 0xaa, 0xf6, 0xd6, 0xd0, 0x44, 0x1b, 0xe0, 0x04, 0xf3, 0xb6, 0x52, 0x2b, 0x86, 0x5e, 0x13, 0x17, 0xb5, 0x48, 0x6e, 0x0d, 0x69, 0x3f, 0xe3, 0x92, 0x63, 0x2c, 0x93, 0xe5, 0x22}}, - {{0x46, 0xfa, 0x5e, 0xd5, 0x4d, 0xd2, 0x61, 0xf2, 0x1d, 0x2d, 0xce, 0x2e, 0xe1, 0x8c, 0xa2, 0xe3, 0x3c, 0x1a, 0xe4, 0x5d, 0x0f, 0xed, 0xc3, 0xb6, 0xa0, 0xcf, 0x87, 0x1a, 0x91, 0xda, 0xb0, 0x1c}, {0x42, 0x1f, 0x36, 0x53, 0x55, 0x56, 0x42, 0x54, 0xf5, 0x38, 0x48, 0xa0, 0x45, 0xc2, 0x9b, 0x08, 0x9e, 0x5a, 0x41, 0x79, 0x66, 0x4e, 0xcc, 0x8d, 0x1b, 0x66, 0xd7, 0x1d, 0xfb, 0x80, 0xc6, 0x34}}, - {{0x18, 0x5b, 0x6e, 0xd5, 0x72, 0x90, 0x65, 0x2d, 0xf3, 0xdb, 0xbd, 0x22, 0xb4, 0x24, 0x87, 0x79, 0x23, 0x6f, 0x78, 0x17, 0xd1, 0x5b, 0x46, 0xa3, 0x85, 0xe3, 0x13, 0x4b, 0x0e, 0x40, 0x61, 0x39}, {0x3c, 0x5d, 0xd2, 0xae, 0x92, 0x62, 0x5e, 0xfd, 0x3f, 0x78, 0xcb, 0xb3, 0xbc, 0x16, 0x75, 0x48, 0x56, 0x58, 0x3c, 0x29, 0x18, 0xfe, 0x9f, 0x8e, 0xcf, 0xd0, 0xc3, 0x99, 0xa9, 0xcd, 0x7e, 0x25}}, - {{0x12, 0x0f, 0x56, 0xaa, 0x7e, 0xe4, 0x13, 0x83, 0xce, 0xc1, 0xd0, 0x19, 0xce, 0xd1, 0x88, 0xa2, 0xce, 0xd9, 0xb5, 0x24, 0xc8, 0x47, 0xe7, 0x0d, 0xb8, 0xf9, 0x50, 0x60, 0xf6, 0x17, 0xf9, 0x1e}, {0x12, 0xd5, 0xe3, 0xaa, 0x17, 0xc4, 0xb3, 0x51, 0x20, 0xb5, 0xf9, 0x3e, 0xcb, 0x26, 0x8c, 0x30, 0x24, 0xc1, 0x10, 0x05, 0xe2, 0xfe, 0x24, 0x9e, 0xfa, 0x09, 0x45, 0x4a, 0x20, 0x59, 0xc4, 0x10}}, - {{0x0b, 0x1d, 0xb1, 0x26, 0xf6, 0x70, 0x54, 0x53, 0xb4, 0x51, 0xf8, 0xc3, 0x98, 0x2b, 0x6e, 0x36, 0x5e, 0x70, 0x19, 0xb0, 0xef, 0x1a, 0x2a, 0xc0, 0x29, 0x3a, 0xc4, 0xde, 0x78, 0xf8, 0xf2, 0x0e}, {0xfb, 0xd6, 0xf8, 0xc8, 0xfd, 0xea, 0xe1, 0xbb, 0xc1, 0x0f, 0x62, 0xc0, 0x4a, 0x35, 0x82, 0xba, 0x7c, 0x91, 0x9b, 0xd3, 0x9a, 0x28, 0x84, 0x49, 0x14, 0x1e, 0xd5, 0xbb, 0x6e, 0x04, 0xb0, 0x32}}, - {{0x73, 0xcf, 0x16, 0x32, 0x09, 0xe7, 0xaf, 0xe5, 0x80, 0xe5, 0x92, 0x25, 0x62, 0xea, 0x7c, 0xce, 0x3d, 0x46, 0x7b, 0x9d, 0x3d, 0xbe, 0x3b, 0x07, 0xd7, 0xb9, 0xc1, 0xe9, 0x6f, 0x97, 0x05, 0x02}, {0xdc, 0x16, 0xab, 0xb9, 0x46, 0x29, 0xef, 0x1e, 0xc4, 0xa5, 0xab, 0x5c, 0x0e, 0xea, 0x13, 0x55, 0x25, 0x14, 0xf9, 0x88, 0x8f, 0xf3, 0x74, 0x01, 0xe9, 0x4d, 0x48, 0x65, 0xc6, 0xf6, 0xb7, 0x16}}, - {{0x85, 0x5c, 0x62, 0x77, 0x9c, 0x2e, 0xcb, 0x07, 0xec, 0x1a, 0x51, 0x73, 0x24, 0xd3, 0xf6, 0x33, 0xae, 0xe7, 0xf1, 0xf1, 0x0e, 0xac, 0xf0, 0xf7, 0xef, 0x90, 0x97, 0x4e, 0x94, 0xc5, 0x3f, 0x3e}, {0xad, 0x23, 0x8c, 0xe2, 0xff, 0x21, 0x86, 0xf2, 0xe6, 0xfa, 0xb5, 0x2e, 0xd2, 0x45, 0xe4, 0x44, 0xf0, 0x57, 0xdf, 0x5b, 0xad, 0x91, 0xc6, 0xdd, 0xa9, 0xdc, 0x5d, 0x39, 0x6f, 0x15, 0xbf, 0x36}}, - {{0x9a, 0x7d, 0x26, 0x44, 0x65, 0xa1, 0x24, 0xd5, 0xab, 0xae, 0xb2, 0x84, 0x96, 0x2e, 0x66, 0x1f, 0xef, 0x47, 0xb1, 0x13, 0x45, 0x68, 0x89, 0x2c, 0xf1, 0x54, 0xd0, 0x31, 0xde, 0xc6, 0xc9, 0x38}, {0x1d, 0xe2, 0x68, 0x5a, 0x2b, 0x03, 0xac, 0x05, 0xab, 0x20, 0x6c, 0x60, 0xc0, 0xdd, 0xbb, 0x13, 0x3a, 0x8b, 0x7c, 0x22, 0xda, 0x8a, 0x26, 0x30, 0x46, 0xff, 0x71, 0x7b, 0xbe, 0x3f, 0x5b, 0x2d}}, - {{0x2b, 0xc9, 0x2e, 0x84, 0xe3, 0x85, 0xb6, 0x11, 0x8b, 0x49, 0x24, 0xa6, 0xdb, 0xf4, 0x44, 0x99, 0x97, 0x6a, 0x40, 0xb0, 0x41, 0xd6, 0xc0, 0x9f, 0x7f, 0x37, 0x4c, 0x12, 0x51, 0x4f, 0x47, 0x16}, {0xae, 0x2d, 0x34, 0xaf, 0xf3, 0x60, 0x68, 0x11, 0xc5, 0xfc, 0xc3, 0xf3, 0x48, 0xc2, 0x05, 0x78, 0x8a, 0x09, 0xd3, 0xd1, 0x52, 0xd1, 0x13, 0x48, 0xf9, 0xe5, 0x3b, 0x82, 0xdf, 0xc6, 0x8f, 0x20}}, - {{0x3e, 0xbe, 0x5e, 0x83, 0x99, 0x7a, 0x69, 0xc1, 0xca, 0x1a, 0x99, 0x31, 0xbb, 0xb7, 0xf1, 0x5e, 0x37, 0xc9, 0xb8, 0xfa, 0x3b, 0xd9, 0x3b, 0x42, 0xdd, 0x0b, 0x18, 0x04, 0xa3, 0x35, 0x67, 0x29}, {0xda, 0xd1, 0xa2, 0x07, 0x09, 0xc0, 0xb7, 0xbd, 0xa1, 0xe0, 0x43, 0xb5, 0x5b, 0x8c, 0x8c, 0x36, 0x8e, 0x74, 0x8c, 0x86, 0x20, 0x95, 0x13, 0xc2, 0x7c, 0xfe, 0xc2, 0x46, 0x1f, 0x17, 0x8a, 0x0f}}, - {{0xc1, 0xe0, 0xc0, 0xaa, 0x16, 0xfb, 0xdb, 0x6a, 0x5c, 0xf2, 0x29, 0xa3, 0x7f, 0x9f, 0x70, 0xe6, 0xa1, 0xad, 0xcd, 0x36, 0x50, 0x33, 0x45, 0x03, 0xb7, 0xef, 0x5d, 0x1a, 0x0e, 0x22, 0x7c, 0x06}, {0xca, 0x52, 0xd4, 0x1f, 0x08, 0x7a, 0xfb, 0xef, 0x41, 0xfa, 0x95, 0x39, 0x9e, 0x53, 0xc5, 0x91, 0xc2, 0x2b, 0x09, 0xb2, 0x70, 0xe2, 0x9f, 0x94, 0xf5, 0x63, 0x6c, 0x95, 0x80, 0xeb, 0x94, 0x0c}}, - {{0xe9, 0x3c, 0xb9, 0xc4, 0x8f, 0xf0, 0xce, 0x76, 0x9b, 0xd1, 0x89, 0xd8, 0xbb, 0x00, 0x65, 0xcd, 0xba, 0xc0, 0x14, 0xe5, 0x91, 0xbc, 0x76, 0xcb, 0x35, 0xcc, 0x7f, 0xf1, 0xed, 0xb3, 0x76, 0x26}, {0xb1, 0x3b, 0x0d, 0x44, 0xfc, 0x7c, 0xee, 0xa6, 0x68, 0xb5, 0x9f, 0x55, 0x37, 0xfa, 0xf0, 0xf9, 0xfd, 0xe0, 0x7b, 0x98, 0x22, 0x99, 0x75, 0x5c, 0xcc, 0x1e, 0xb9, 0x9f, 0x25, 0x9b, 0xba, 0x18}}, - {{0xe5, 0xf1, 0xaa, 0xb7, 0x70, 0x90, 0xaa, 0x88, 0x67, 0xbb, 0x33, 0x2b, 0x4a, 0x12, 0x19, 0xed, 0x13, 0xf8, 0xd2, 0xc5, 0x69, 0xe5, 0x6e, 0xe5, 0x45, 0x65, 0x9c, 0x68, 0x48, 0x3d, 0x6d, 0x3c}, {0x37, 0x27, 0x92, 0x6d, 0x98, 0x3c, 0xd3, 0x2d, 0xc5, 0xd3, 0x68, 0xcc, 0xc9, 0x67, 0x38, 0x4a, 0x89, 0x84, 0x50, 0x23, 0x4b, 0x10, 0xd8, 0x0d, 0x55, 0xd5, 0x29, 0x51, 0x03, 0xa7, 0x20, 0x12}}, - {{0xf6, 0xe3, 0x9e, 0xc2, 0xdc, 0xb7, 0x4f, 0xf3, 0xb4, 0xd6, 0x7f, 0x78, 0x9f, 0x41, 0xff, 0x68, 0x24, 0xfd, 0x50, 0xb6, 0x44, 0x60, 0x13, 0xe1, 0xbb, 0x06, 0x0a, 0x3f, 0x4e, 0xbb, 0x07, 0x0f}, {0x68, 0x48, 0xd6, 0x30, 0x9b, 0x3c, 0x2f, 0xaf, 0x41, 0x8d, 0xbc, 0xee, 0xbd, 0xd0, 0x76, 0xb8, 0x1d, 0x97, 0x31, 0xa5, 0xea, 0xcf, 0xe1, 0xd5, 0xb0, 0xe7, 0x45, 0x95, 0x3f, 0x73, 0x9f, 0x04}}, - {{0x34, 0x26, 0xba, 0x1d, 0xca, 0xf7, 0x30, 0x07, 0x5d, 0xa9, 0x49, 0xac, 0x6c, 0xc8, 0x9c, 0x22, 0xff, 0x5b, 0xf0, 0x67, 0x87, 0x54, 0x9f, 0x29, 0x65, 0x72, 0xc9, 0xbb, 0x6f, 0x6c, 0xf0, 0x1f}, {0x9e, 0xfb, 0x43, 0xc3, 0xb3, 0x85, 0xd4, 0x42, 0xed, 0x32, 0xf4, 0xd7, 0x09, 0xb5, 0xa0, 0xa6, 0x41, 0xc3, 0x54, 0x3e, 0x25, 0x75, 0x60, 0xea, 0x1e, 0x26, 0x9b, 0x8e, 0x3d, 0x14, 0x00, 0x2c}}, - {{0x47, 0xf2, 0xfc, 0x2e, 0xae, 0x58, 0xda, 0x8f, 0x0e, 0xe1, 0xf7, 0x54, 0x22, 0x00, 0x35, 0xee, 0x54, 0x68, 0xd8, 0xa1, 0x67, 0xf0, 0x6e, 0x73, 0xdb, 0x7b, 0x81, 0xf3, 0xf6, 0x73, 0x1b, 0x17}, {0x65, 0x11, 0x78, 0x28, 0x82, 0xb4, 0x4f, 0xc3, 0x8f, 0xfc, 0x61, 0xa1, 0xaf, 0x16, 0xa5, 0xf1, 0x21, 0xf7, 0x9f, 0x6d, 0xbd, 0x8c, 0xc7, 0x98, 0xc1, 0x11, 0x9f, 0xb9, 0xd3, 0x7d, 0x38, 0x3b}}, - {{0xc2, 0x01, 0x5b, 0xff, 0xdc, 0x8d, 0x2c, 0xf5, 0x28, 0xca, 0x93, 0xbd, 0xdf, 0x70, 0x3d, 0x52, 0x74, 0x37, 0xc1, 0xc4, 0xa5, 0xd3, 0x29, 0x9c, 0xc3, 0x73, 0xde, 0x38, 0xcb, 0xfe, 0xcd, 0x31}, {0xb8, 0x9c, 0xb1, 0x26, 0x28, 0x3f, 0x8c, 0xc6, 0x60, 0xfe, 0x10, 0x06, 0x93, 0x75, 0x8b, 0xfa, 0x84, 0x99, 0x51, 0x2f, 0x95, 0xd4, 0xf2, 0xde, 0x85, 0xb1, 0xad, 0xdd, 0xb6, 0x6c, 0x21, 0x22}}, - {{0x4e, 0xd2, 0xc0, 0xf3, 0xdf, 0x8e, 0xed, 0x6b, 0xd4, 0xa0, 0xba, 0xcd, 0xb9, 0x37, 0xef, 0x99, 0xdb, 0x54, 0xfd, 0x65, 0x49, 0x74, 0x57, 0xaf, 0x44, 0xca, 0x19, 0x24, 0x4e, 0xec, 0x04, 0x27}, {0xc2, 0xb1, 0x7e, 0xb6, 0xd0, 0x2b, 0xdf, 0x8c, 0x6b, 0xe8, 0x26, 0xb4, 0x3d, 0xa3, 0xf8, 0x58, 0x7f, 0x96, 0x66, 0xfe, 0x62, 0xaf, 0x3b, 0x65, 0x08, 0x47, 0xce, 0x4d, 0x58, 0x7f, 0x26, 0x23}}, - {{0x34, 0x22, 0xb7, 0xad, 0x84, 0xf2, 0x12, 0x63, 0x96, 0xab, 0x1c, 0xfa, 0xa2, 0x0a, 0x4f, 0x77, 0x95, 0x56, 0x7c, 0x13, 0xe7, 0x4c, 0x2f, 0x7b, 0xd2, 0xe0, 0xda, 0x83, 0x03, 0xb2, 0x64, 0x08}, {0x6c, 0xb7, 0xfe, 0x53, 0xd1, 0x3e, 0x1d, 0x73, 0x3e, 0x4c, 0xc9, 0xd5, 0xbc, 0x32, 0xf0, 0xca, 0xc6, 0xaa, 0xb2, 0x83, 0x28, 0x0b, 0xb6, 0xc4, 0xb5, 0xc0, 0xcf, 0xb9, 0x3c, 0xd6, 0x25, 0x21}}, - {{0x59, 0x97, 0xd9, 0xa1, 0x17, 0x3f, 0xe9, 0x53, 0x20, 0xa0, 0x1b, 0xe0, 0x3e, 0xc7, 0xbd, 0x5b, 0x75, 0x2f, 0xd3, 0xf9, 0xa6, 0xbb, 0xf7, 0xac, 0x75, 0x6a, 0x35, 0x16, 0xc8, 0xc1, 0x52, 0x19}, {0xe0, 0xd4, 0xf3, 0x1a, 0xb6, 0xf0, 0xec, 0x66, 0x90, 0x1a, 0x6e, 0xed, 0x24, 0x09, 0x1c, 0x57, 0xc0, 0x14, 0xc0, 0x1f, 0xde, 0xb5, 0x05, 0x77, 0x80, 0xea, 0x73, 0xf6, 0x22, 0x5a, 0xd7, 0x1f}}, - {{0xd6, 0xaa, 0x91, 0x8c, 0x40, 0xea, 0xe1, 0x51, 0xa3, 0x5d, 0xd7, 0x6d, 0x4a, 0xdc, 0xb3, 0x9d, 0x96, 0x9a, 0x1f, 0xe8, 0x06, 0x5a, 0x5d, 0x56, 0x90, 0x53, 0x99, 0xed, 0x0f, 0xfb, 0x2a, 0x0b}, {0xa3, 0xea, 0xeb, 0x24, 0xf7, 0xe6, 0x85, 0xcb, 0xdc, 0xb9, 0x27, 0x95, 0xb8, 0x3d, 0xe7, 0x0a, 0x68, 0x7a, 0x1c, 0x95, 0xe1, 0x28, 0xe3, 0xcb, 0x71, 0x15, 0x9e, 0x23, 0x1a, 0xae, 0x2f, 0x2e}}, - {{0xd5, 0x89, 0xc1, 0x64, 0xa2, 0xea, 0x58, 0xf9, 0xf7, 0x4f, 0x1c, 0x12, 0xd1, 0xb7, 0x66, 0xfd, 0x1b, 0x54, 0x6d, 0xe9, 0x0c, 0x6c, 0xb3, 0x34, 0x25, 0x00, 0x3b, 0x6c, 0x09, 0x86, 0x73, 0x0e}, {0xec, 0xb8, 0x3b, 0x7f, 0xde, 0x19, 0xbd, 0x2c, 0x7f, 0x17, 0xc9, 0x0d, 0x74, 0x98, 0x9d, 0x04, 0x50, 0x6c, 0x8b, 0xdc, 0x94, 0xe4, 0x76, 0xdc, 0x1a, 0xab, 0x68, 0xa9, 0x6c, 0xea, 0x16, 0x3c}}, - {{0xf3, 0xda, 0xb7, 0x89, 0xcc, 0xad, 0x5a, 0x91, 0x85, 0x97, 0x1f, 0x0e, 0x1c, 0xff, 0x09, 0x29, 0xf2, 0x7e, 0x9a, 0x01, 0x28, 0xa1, 0xbd, 0xd5, 0x51, 0x8d, 0xea, 0x9e, 0x8f, 0xfb, 0x37, 0x3d}, {0x38, 0xf1, 0x80, 0xa0, 0x28, 0xe3, 0xbe, 0x09, 0x20, 0x21, 0xfe, 0x07, 0x90, 0x58, 0x73, 0xe6, 0x10, 0x91, 0x7c, 0x5d, 0xe1, 0x15, 0x13, 0x21, 0x77, 0x54, 0xfd, 0xee, 0xf4, 0x69, 0x0f, 0x19}}, - {{0x9b, 0x45, 0x14, 0xc8, 0x28, 0xd0, 0x87, 0x98, 0x7d, 0x9a, 0x77, 0xc9, 0x14, 0x97, 0xfe, 0x0b, 0x37, 0x2c, 0x70, 0xa0, 0x23, 0xa1, 0xbc, 0x09, 0xef, 0x33, 0xf9, 0x55, 0x3f, 0xd6, 0xb5, 0x2a}, {0xaa, 0xcb, 0x9a, 0x66, 0x75, 0x31, 0x04, 0x77, 0xaf, 0xaa, 0x9c, 0x27, 0x56, 0x32, 0xd9, 0xd2, 0x03, 0x0d, 0x2e, 0x99, 0x14, 0xf4, 0x3b, 0x16, 0x8a, 0x37, 0x23, 0x07, 0x25, 0xad, 0xd3, 0x2d}}, - {{0xe1, 0x1e, 0x62, 0x2c, 0x4d, 0xaf, 0x70, 0xaa, 0x6a, 0xe1, 0x4f, 0xa4, 0xf9, 0x76, 0xbf, 0x82, 0xf4, 0x1b, 0xe9, 0x28, 0xb3, 0xdf, 0x23, 0xd8, 0xce, 0x50, 0xef, 0x8f, 0xa7, 0x86, 0x2e, 0x0e}, {0x90, 0x9e, 0xe6, 0x95, 0xdd, 0x97, 0xdf, 0x96, 0xd6, 0xbc, 0x59, 0xe9, 0x75, 0x7d, 0x40, 0xa3, 0x55, 0x92, 0x9f, 0xd8, 0xc5, 0x08, 0x06, 0x88, 0x33, 0x2b, 0xc1, 0x6d, 0xe1, 0xb3, 0xe3, 0x2d}}, - {{0xcb, 0xb2, 0xec, 0x58, 0x34, 0x29, 0x96, 0x0c, 0x0e, 0x56, 0x1e, 0x7d, 0x4d, 0x86, 0x7d, 0x0d, 0x55, 0xc5, 0xdd, 0x3c, 0xa6, 0xd3, 0x28, 0xec, 0x1a, 0x74, 0x63, 0x02, 0x00, 0xeb, 0xe0, 0x0d}, {0x0e, 0x6f, 0x7b, 0x93, 0x7d, 0x20, 0xc8, 0x1c, 0xc6, 0xc8, 0x7e, 0xdc, 0xee, 0xe7, 0x97, 0x97, 0x7a, 0xe7, 0x41, 0xe4, 0x8a, 0x08, 0x86, 0x22, 0xa4, 0xc5, 0x4f, 0xc5, 0x11, 0x48, 0x2f, 0x24}}, - {{0x91, 0x30, 0x21, 0xb4, 0xb8, 0x08, 0xe6, 0x02, 0xfb, 0x83, 0xaf, 0x26, 0x2c, 0xd8, 0xf9, 0x04, 0x25, 0x25, 0x2f, 0xba, 0x44, 0xe5, 0x9c, 0x4d, 0x3b, 0xa5, 0x51, 0x48, 0x48, 0xe2, 0x8e, 0x3f}, {0xb4, 0x2a, 0x3d, 0xf9, 0x3c, 0x0a, 0xac, 0x9d, 0x67, 0xed, 0x1b, 0xf3, 0x69, 0x55, 0xd7, 0x7e, 0x31, 0x87, 0xe7, 0x14, 0x3f, 0xb7, 0x30, 0xb5, 0xd8, 0xb1, 0xef, 0xc7, 0x58, 0x68, 0x0a, 0x32}}, - {{0xef, 0x5b, 0x8c, 0xc1, 0x73, 0x9c, 0xc7, 0xf1, 0x33, 0xaf, 0x5d, 0xbe, 0x27, 0xfb, 0xdc, 0xb4, 0xb8, 0x9a, 0x13, 0xa4, 0x37, 0x34, 0xfb, 0x00, 0x58, 0x46, 0xb8, 0xfe, 0x26, 0x69, 0xa9, 0x27}, {0x01, 0x59, 0x05, 0xa8, 0x04, 0x95, 0x4f, 0xf9, 0x86, 0xc1, 0x8c, 0x5f, 0xb5, 0x70, 0x16, 0xd8, 0x4c, 0xd4, 0xca, 0x3f, 0xc9, 0x41, 0x0a, 0xd8, 0xf9, 0xfa, 0x96, 0x69, 0xfa, 0x6d, 0xfb, 0x35}}, - {{0x08, 0xdd, 0xfd, 0x8a, 0xc8, 0x1c, 0xd4, 0xba, 0x27, 0xeb, 0x81, 0x31, 0xa3, 0xbd, 0xd2, 0x49, 0x87, 0xf2, 0x64, 0xe7, 0x2e, 0xa4, 0xd9, 0x6b, 0xd3, 0x3d, 0xd6, 0xaa, 0xbc, 0x7f, 0xf9, 0x1b}, {0x79, 0x34, 0x3f, 0xb9, 0xb6, 0x14, 0x70, 0x9e, 0x8e, 0x0a, 0xd9, 0x85, 0xcc, 0x3a, 0xcd, 0x2e, 0xbf, 0x73, 0x7e, 0x38, 0x24, 0xda, 0xdc, 0x9a, 0xa1, 0xe6, 0x13, 0xee, 0x8e, 0x20, 0x46, 0x1e}}, - {{0xe7, 0x12, 0xe2, 0x32, 0x37, 0x4b, 0xfc, 0xbe, 0xc7, 0x82, 0x43, 0x19, 0x4e, 0x0a, 0x94, 0x79, 0xcb, 0x76, 0x54, 0xba, 0x41, 0x21, 0xb5, 0x31, 0x7e, 0x09, 0xc6, 0x11, 0xd9, 0xb8, 0xd7, 0x0d}, {0xf7, 0x24, 0xa6, 0x45, 0xbe, 0x37, 0x8f, 0x87, 0x0e, 0x29, 0x8d, 0xb5, 0x10, 0xf7, 0x03, 0x9e, 0xf8, 0x08, 0xca, 0x79, 0xc0, 0xae, 0xeb, 0x9d, 0xbd, 0xb8, 0x00, 0x15, 0xac, 0x3e, 0xc9, 0x00}}, - {{0xfb, 0x42, 0x09, 0x03, 0x89, 0xeb, 0x08, 0xd8, 0x91, 0xe6, 0x1f, 0x81, 0xe4, 0x47, 0xff, 0xbc, 0x56, 0x91, 0x22, 0x74, 0xb6, 0xd2, 0xa7, 0x48, 0xbf, 0xfd, 0x0e, 0xe0, 0x52, 0xa7, 0x8e, 0x22}, {0xca, 0xd4, 0x4c, 0xc2, 0x0a, 0xca, 0x99, 0xf1, 0x21, 0x86, 0x52, 0x07, 0xa7, 0x07, 0x0f, 0x6b, 0x36, 0xdb, 0x2d, 0x03, 0x36, 0x65, 0x45, 0x8d, 0x78, 0x33, 0xb1, 0x40, 0x48, 0x3b, 0x88, 0x02}}, - {{0x1b, 0x5b, 0x9e, 0x9f, 0xb4, 0x43, 0x93, 0xe6, 0xc7, 0x13, 0xfd, 0x32, 0x6a, 0xce, 0xd5, 0x89, 0x97, 0x9a, 0xa1, 0x5a, 0x5c, 0x6f, 0xd7, 0x9e, 0xd1, 0xbb, 0xe1, 0x00, 0xc9, 0x33, 0xc4, 0x2e}, {0xe1, 0xab, 0x3e, 0x40, 0x86, 0xed, 0xc3, 0xea, 0x4e, 0x8a, 0xb8, 0xdf, 0x5e, 0x9a, 0xfe, 0xf6, 0x20, 0xdb, 0xb0, 0x97, 0x51, 0x63, 0x6a, 0x8f, 0xa2, 0xcf, 0x11, 0x05, 0x3d, 0x04, 0x2c, 0x1e}}, - {{0xd4, 0x94, 0xa3, 0xba, 0x15, 0xf2, 0xb7, 0x9a, 0x6f, 0xa2, 0x8f, 0xe3, 0x16, 0x3e, 0x8f, 0x1d, 0x56, 0x74, 0x38, 0x77, 0x19, 0xfc, 0x59, 0x41, 0xdb, 0x25, 0xc0, 0xf3, 0xa1, 0x08, 0xab, 0x00}, {0xaa, 0x84, 0x53, 0x22, 0x47, 0x42, 0x27, 0x71, 0x8b, 0xa6, 0x1e, 0xfc, 0x39, 0xd2, 0x16, 0xbb, 0x70, 0x35, 0xe4, 0x0b, 0xc2, 0xb7, 0x3b, 0x0e, 0x8e, 0x9c, 0x76, 0x3b, 0xd7, 0xd9, 0x0e, 0x10}}, - {{0xff, 0x24, 0xe9, 0x48, 0xc9, 0xae, 0xc3, 0x42, 0x14, 0xf4, 0x4b, 0xca, 0x8f, 0x1a, 0x63, 0x9b, 0x16, 0xa4, 0x0e, 0x06, 0xfe, 0xf7, 0xf2, 0x9e, 0xd1, 0x81, 0x95, 0xf0, 0x9f, 0x8d, 0xb4, 0x25}, {0x6e, 0x76, 0xa0, 0x35, 0x3a, 0x2d, 0xe4, 0x8a, 0xd6, 0x72, 0xcd, 0xe9, 0xd8, 0xf6, 0x4d, 0x10, 0x63, 0x29, 0x23, 0x04, 0xb2, 0x5c, 0xdf, 0x71, 0x36, 0x62, 0x54, 0x78, 0xd7, 0x58, 0x99, 0x08}}, - {{0xbf, 0x67, 0x5b, 0xa6, 0xad, 0x0b, 0xdc, 0xa5, 0x57, 0xb0, 0x44, 0x22, 0xa2, 0xe8, 0x9f, 0xf2, 0x90, 0xb1, 0xb8, 0x8d, 0xee, 0x3e, 0x11, 0x55, 0x85, 0xd4, 0x7b, 0x2f, 0x19, 0xc1, 0x10, 0x12}, {0x23, 0xdf, 0xe9, 0x60, 0xe5, 0xe8, 0x62, 0x4b, 0xdb, 0x5e, 0x69, 0x22, 0xa0, 0x32, 0x25, 0xe6, 0xe4, 0xf9, 0xa2, 0xbf, 0x17, 0xa3, 0xfe, 0x4a, 0x88, 0x4b, 0x26, 0x1d, 0xf6, 0x67, 0x34, 0x01}}, - {{0x9d, 0x20, 0x78, 0x9f, 0x8c, 0x3c, 0xd5, 0xd1, 0xd1, 0xf6, 0xc7, 0x9d, 0x54, 0x2e, 0x13, 0x97, 0x8f, 0xce, 0xe2, 0x19, 0xb6, 0xfe, 0x99, 0x99, 0x83, 0xad, 0xb2, 0x45, 0xc1, 0x19, 0x27, 0x18}, {0xca, 0xeb, 0x1b, 0x0d, 0xe8, 0x07, 0x40, 0x64, 0xaa, 0xc8, 0xc2, 0x21, 0x5a, 0xb4, 0x9a, 0xb5, 0xe9, 0xbd, 0x1b, 0x13, 0x6a, 0x16, 0xcd, 0x37, 0xae, 0x11, 0x39, 0x05, 0xf1, 0x79, 0x88, 0x3e}}, - {{0xd1, 0xaf, 0xb3, 0x80, 0xa7, 0x47, 0x28, 0x21, 0x7b, 0x14, 0x9d, 0x72, 0xa3, 0x98, 0x2d, 0xd6, 0x55, 0xe4, 0x80, 0x77, 0x5b, 0xcd, 0x76, 0xac, 0x57, 0x79, 0x93, 0x64, 0x55, 0xd8, 0x71, 0x13}, {0x61, 0xd8, 0x21, 0x78, 0xac, 0x35, 0xc5, 0x03, 0xff, 0x21, 0xd3, 0xd4, 0xb8, 0x7f, 0x97, 0x18, 0x4c, 0xd9, 0xd2, 0x09, 0x9d, 0x5e, 0xec, 0x57, 0x3d, 0xc3, 0x25, 0x3d, 0x96, 0x88, 0x33, 0x29}}, - {{0x33, 0xb7, 0x5b, 0x4f, 0x09, 0x90, 0x64, 0x4c, 0x3d, 0x12, 0x38, 0xb6, 0x9e, 0x14, 0x25, 0x2f, 0x56, 0xfe, 0x07, 0x3c, 0xe6, 0xd5, 0x3b, 0x58, 0xfc, 0xd8, 0x9a, 0xcf, 0xbe, 0xe3, 0xd0, 0x38}, {0x57, 0xf3, 0x82, 0x02, 0x10, 0x76, 0x82, 0x94, 0x74, 0xd4, 0x55, 0xfd, 0x5d, 0x4a, 0x35, 0x90, 0x61, 0x34, 0xd7, 0x46, 0x5f, 0x06, 0x90, 0xdf, 0x62, 0x11, 0xf7, 0xa7, 0xe9, 0xe8, 0xe2, 0x1e}}, - {{0xf6, 0xf9, 0x25, 0x83, 0xda, 0x20, 0xcf, 0xc2, 0x6c, 0xe0, 0xb5, 0x3a, 0x2b, 0x32, 0x58, 0x41, 0xaf, 0xde, 0x5f, 0xe7, 0x70, 0x03, 0xea, 0x55, 0x45, 0xb3, 0x07, 0x23, 0x55, 0x51, 0x91, 0x04}, {0x56, 0x11, 0xd2, 0x58, 0xc7, 0xb7, 0x6c, 0x3a, 0xd4, 0xc8, 0x0a, 0x42, 0xa9, 0xac, 0xe5, 0x3e, 0x2b, 0x04, 0xb0, 0x93, 0xfc, 0x78, 0x4e, 0x82, 0x67, 0xd6, 0x79, 0x86, 0x5f, 0xec, 0x00, 0x23}}, - {{0x86, 0x12, 0x4a, 0xcd, 0xe7, 0x4d, 0x34, 0x45, 0x95, 0xbd, 0x45, 0xd5, 0xbe, 0x9f, 0x00, 0x70, 0x4d, 0xfe, 0x9c, 0x32, 0xdc, 0x45, 0xf3, 0x56, 0x70, 0x86, 0x22, 0x4c, 0x10, 0x0f, 0x11, 0x1b}, {0x13, 0x0b, 0x03, 0x4d, 0xee, 0x67, 0x7e, 0x58, 0xfd, 0xe3, 0xa1, 0xcf, 0xe0, 0x4e, 0xd6, 0x26, 0x66, 0x31, 0x5b, 0xe4, 0xbc, 0x3d, 0xa4, 0x31, 0x87, 0x7d, 0x99, 0xcf, 0x74, 0x1a, 0x4c, 0x38}}, - {{0xde, 0x5b, 0xaf, 0x03, 0x15, 0xb8, 0x39, 0xa7, 0x51, 0x37, 0x16, 0x59, 0xc3, 0x4f, 0x73, 0xfe, 0x68, 0x0f, 0x71, 0xa5, 0xab, 0xe2, 0xae, 0x87, 0x69, 0x60, 0xdb, 0xfb, 0x09, 0x7f, 0x80, 0x28}, {0xfe, 0x91, 0xc3, 0x08, 0x52, 0xef, 0x9a, 0x95, 0x5c, 0xc3, 0x96, 0xb2, 0x94, 0x48, 0x83, 0x92, 0x73, 0x5f, 0xf0, 0x99, 0x7f, 0xc4, 0x5c, 0x4a, 0xf2, 0xe5, 0x50, 0x95, 0xd4, 0x23, 0xa5, 0x04}}, - {{0xf0, 0xa2, 0x73, 0x84, 0x55, 0xa1, 0xaa, 0xbb, 0x97, 0x70, 0x4a, 0x59, 0xdd, 0x48, 0x8d, 0x84, 0xc1, 0xdd, 0xee, 0xfa, 0x5c, 0xec, 0xdc, 0xe3, 0x2e, 0xd9, 0xc4, 0xd7, 0x5a, 0x2c, 0x8c, 0x3a}, {0xe1, 0x2b, 0xfe, 0xd4, 0x50, 0x77, 0xbc, 0x3b, 0xff, 0xba, 0x3b, 0xe5, 0x48, 0x0c, 0xba, 0x70, 0x04, 0x68, 0x0d, 0xc1, 0x83, 0x56, 0x04, 0xa8, 0xfe, 0x0d, 0x7f, 0xc6, 0x31, 0x66, 0x94, 0x10}}, - {{0xd7, 0xcc, 0x77, 0x36, 0xc5, 0x21, 0x02, 0x36, 0xb3, 0x11, 0x9e, 0x60, 0xd9, 0x46, 0xe8, 0x9d, 0x1e, 0xe5, 0xc5, 0x0f, 0x59, 0x0f, 0x00, 0xc6, 0xf3, 0x83, 0x2a, 0xba, 0x18, 0x6f, 0xe5, 0x12}, {0xfd, 0x7c, 0x6e, 0x63, 0x33, 0xc9, 0x72, 0xb4, 0x2b, 0x25, 0xf1, 0xb1, 0x5e, 0x50, 0x7b, 0x74, 0x69, 0x9e, 0xbe, 0x0f, 0x8b, 0x8b, 0x4f, 0x94, 0xcd, 0x1f, 0x35, 0xcc, 0xb2, 0x05, 0x1b, 0x08}}, - {{0xcc, 0x02, 0xe6, 0xa2, 0x36, 0x27, 0x9f, 0xf6, 0x1f, 0x62, 0xc4, 0xd5, 0xb7, 0x25, 0xb6, 0x40, 0x80, 0xbc, 0xc9, 0x4b, 0xa7, 0xe2, 0xba, 0x09, 0xb4, 0xa1, 0x98, 0x32, 0x42, 0x39, 0xb0, 0x19}, {0xdd, 0x6d, 0xdd, 0x92, 0x06, 0x9c, 0x25, 0xab, 0x77, 0x26, 0x5a, 0x71, 0x85, 0x0e, 0x30, 0x89, 0x91, 0x7b, 0x96, 0x6d, 0x35, 0x4d, 0x18, 0x15, 0x77, 0xf7, 0x25, 0xc0, 0x7e, 0x01, 0xfc, 0x1a}}, - {{0xc4, 0x47, 0xd1, 0xc9, 0x1d, 0xa1, 0x9c, 0xbd, 0x65, 0xf6, 0xea, 0x74, 0xe7, 0x70, 0x29, 0xa7, 0x9b, 0x8d, 0x50, 0xe3, 0x51, 0x7f, 0xb2, 0x4a, 0xf1, 0x65, 0xe2, 0x52, 0x5f, 0x85, 0x80, 0x1b}, {0x31, 0x4c, 0xbe, 0x25, 0xf3, 0x3e, 0xcd, 0x47, 0x9b, 0xad, 0x2a, 0xf5, 0x95, 0x38, 0xc1, 0xe4, 0x27, 0x7f, 0x99, 0x93, 0xa3, 0x9d, 0x33, 0x35, 0x6f, 0xcf, 0x5a, 0xf4, 0x28, 0x7e, 0x88, 0x23}}, - {{0xe2, 0x11, 0xa6, 0xe1, 0x44, 0xf0, 0x63, 0x08, 0xf8, 0x78, 0x7a, 0x8e, 0x75, 0x55, 0xe4, 0x79, 0xd6, 0x30, 0x54, 0x0f, 0x15, 0x9c, 0xfc, 0xc8, 0x4d, 0x27, 0xde, 0x84, 0x36, 0x8e, 0x7a, 0x3a}, {0x4d, 0x3a, 0xb3, 0xba, 0xb5, 0x2f, 0xa3, 0x03, 0x67, 0x78, 0x64, 0x5c, 0xa6, 0x34, 0xd2, 0x0b, 0xc1, 0xd7, 0x13, 0xd0, 0xad, 0x19, 0x2b, 0x97, 0x60, 0xf2, 0x2e, 0xe2, 0x94, 0x2c, 0x12, 0x16}}, - {{0xfb, 0xf8, 0x53, 0xc5, 0x4d, 0x18, 0x78, 0xdf, 0x14, 0x28, 0x55, 0x37, 0x38, 0xea, 0xe8, 0x95, 0x38, 0xdb, 0x39, 0x6d, 0x2f, 0x09, 0x03, 0x16, 0x9f, 0xbb, 0x01, 0xc9, 0xea, 0xe6, 0x69, 0x27}, {0x45, 0x2d, 0xb6, 0x22, 0xd2, 0x1a, 0xae, 0x6a, 0xa9, 0x1e, 0x0d, 0x98, 0x4f, 0x70, 0x41, 0x83, 0xa6, 0x23, 0x60, 0xda, 0x03, 0xb5, 0x17, 0x73, 0xe6, 0x92, 0x7c, 0xa7, 0xaa, 0x5b, 0xb1, 0x16}}, - {{0xe5, 0x93, 0xf3, 0xd3, 0x4f, 0x69, 0xad, 0x35, 0x5d, 0x63, 0xc1, 0xec, 0xab, 0x6b, 0x77, 0xb9, 0x7f, 0x84, 0x0f, 0xa8, 0x52, 0x25, 0x3e, 0x67, 0x2d, 0x6c, 0xfd, 0x6f, 0x2e, 0x56, 0x2a, 0x28}, {0x33, 0x76, 0x9b, 0xaf, 0x0f, 0x30, 0x61, 0xcd, 0x7a, 0x76, 0xb9, 0x6f, 0xdd, 0x7b, 0x78, 0x5f, 0x2e, 0xa8, 0xcb, 0xa3, 0x0b, 0x3e, 0xe6, 0xf8, 0x26, 0x58, 0xf6, 0x70, 0x6c, 0x8b, 0x29, 0x3c}}, - {{0xf0, 0x85, 0x33, 0x40, 0x0b, 0x92, 0x78, 0xf9, 0xed, 0xf4, 0xe7, 0x87, 0xed, 0xdf, 0x41, 0x47, 0x40, 0xb0, 0x97, 0xa0, 0x50, 0x9a, 0xf7, 0x9a, 0x55, 0x3d, 0x7f, 0x7a, 0x01, 0x04, 0xf2, 0x09}, {0xde, 0xcf, 0x1d, 0x1e, 0xc7, 0xa7, 0x4c, 0x48, 0xc1, 0xcb, 0xa5, 0xc8, 0x17, 0xfe, 0x5e, 0x43, 0x57, 0x50, 0x04, 0x71, 0xaa, 0x12, 0x81, 0xe9, 0x26, 0x80, 0xc5, 0xb8, 0x05, 0x99, 0x2c, 0x1d}}, - {{0x87, 0xe6, 0xa4, 0xe2, 0xc1, 0xdd, 0x4e, 0x8a, 0x8f, 0x85, 0x8e, 0x01, 0xe2, 0x5c, 0xff, 0x5b, 0x6a, 0xe5, 0xa1, 0x83, 0x2f, 0x66, 0xe5, 0xc6, 0xba, 0x2d, 0x9b, 0x67, 0x0d, 0x00, 0xa2, 0x02}, {0xa0, 0xb2, 0x76, 0x7c, 0xea, 0xf6, 0x6a, 0x2f, 0x56, 0x40, 0x69, 0x9b, 0xfa, 0x4b, 0xc7, 0xb8, 0x14, 0x1e, 0x6d, 0x49, 0xad, 0x16, 0x79, 0xfb, 0xe2, 0x04, 0x4d, 0xf1, 0x05, 0xca, 0xf4, 0x1d}}, - {{0x5c, 0xea, 0x36, 0xe3, 0xef, 0xf6, 0x88, 0x60, 0xc8, 0x54, 0xb5, 0x3a, 0x0a, 0x11, 0x97, 0x74, 0x70, 0x1b, 0xab, 0x90, 0x7e, 0x8a, 0x4a, 0xbb, 0x07, 0xe3, 0x44, 0xa6, 0xa8, 0x05, 0xca, 0x16}, {0xcf, 0x03, 0xe0, 0xee, 0xf6, 0x4b, 0x6b, 0xbc, 0x4c, 0x31, 0x17, 0x5d, 0x39, 0xc2, 0x97, 0x94, 0xeb, 0x57, 0xdf, 0x96, 0x4e, 0x8c, 0x28, 0xa5, 0x2f, 0xc3, 0xb2, 0x70, 0xd2, 0x2c, 0xec, 0x05}}, - {{0x44, 0x68, 0x51, 0x2d, 0xba, 0x5a, 0x4b, 0x1d, 0xf0, 0xcf, 0xac, 0x14, 0x63, 0xe7, 0xbb, 0x0e, 0x47, 0x59, 0x50, 0x19, 0xc3, 0x52, 0xe2, 0xca, 0xec, 0x58, 0x6b, 0x98, 0x69, 0x77, 0x6f, 0x10}, {0x91, 0x26, 0x53, 0xbd, 0x24, 0xde, 0x32, 0xec, 0xaa, 0xb8, 0xba, 0x9f, 0x79, 0xb1, 0x82, 0xaf, 0x51, 0x4d, 0xf3, 0x33, 0x2d, 0x59, 0xf7, 0xad, 0xdb, 0x22, 0x80, 0x53, 0x82, 0xab, 0xd7, 0x1d}}, - {{0xf9, 0x94, 0x6c, 0x35, 0xcc, 0x5d, 0x01, 0x77, 0xab, 0x73, 0x9f, 0xf8, 0x5f, 0x8f, 0x5b, 0xe7, 0x37, 0x47, 0xe2, 0x81, 0x89, 0x7c, 0x4a, 0x93, 0xe3, 0x9e, 0x04, 0xe7, 0x05, 0xea, 0x52, 0x09}, {0xf7, 0x75, 0x50, 0x9d, 0x2d, 0xc9, 0xdb, 0x7b, 0xd4, 0x9e, 0x28, 0x5f, 0xf0, 0x21, 0x85, 0x99, 0xb2, 0x6f, 0x28, 0x7a, 0xfe, 0x4f, 0x0d, 0x92, 0x92, 0x32, 0x69, 0x4b, 0xf6, 0xed, 0xb4, 0x19}}, - {{0xac, 0xb3, 0xf9, 0x18, 0xb7, 0x48, 0x93, 0x2d, 0x72, 0xcb, 0xe9, 0x07, 0xd8, 0xc3, 0xe6, 0x1e, 0x59, 0x0b, 0x7b, 0xbd, 0xe3, 0x47, 0xf7, 0x27, 0xaf, 0x39, 0x0f, 0x0e, 0x4e, 0x26, 0x44, 0x33}, {0x85, 0x7f, 0x27, 0x9f, 0xe5, 0x14, 0x92, 0x53, 0x84, 0xfa, 0xc7, 0x75, 0x5c, 0xf1, 0xb5, 0xba, 0x8a, 0xa8, 0xcb, 0x1b, 0x01, 0xa5, 0x92, 0x5e, 0xef, 0xeb, 0x98, 0x6e, 0xc4, 0x7b, 0xbe, 0x39}}, - {{0x36, 0x7d, 0x98, 0x57, 0xb8, 0x5c, 0xfc, 0xef, 0x06, 0x1c, 0x8a, 0xe0, 0x83, 0xe3, 0x31, 0x42, 0xe5, 0x5f, 0xb4, 0x99, 0xe7, 0xc3, 0xf4, 0x83, 0x24, 0xb3, 0x8d, 0x62, 0xd9, 0x4a, 0xc4, 0x1b}, {0xbc, 0x83, 0x60, 0x1a, 0xed, 0x73, 0x51, 0xb0, 0x0f, 0x55, 0x7c, 0x37, 0x9d, 0xb4, 0x3f, 0x5d, 0x56, 0xc9, 0x34, 0xc6, 0x7e, 0x1f, 0xc4, 0x9e, 0x52, 0xe3, 0x49, 0x79, 0xbd, 0xa4, 0xa2, 0x2e}}, - {{0xc5, 0x15, 0xab, 0x18, 0x6d, 0xb8, 0x11, 0xce, 0xbd, 0xeb, 0xcf, 0xe7, 0xbb, 0x58, 0xfd, 0xfd, 0x41, 0xa7, 0xde, 0x1a, 0x65, 0x16, 0x1a, 0x01, 0xbe, 0xdc, 0xfc, 0x03, 0x83, 0x76, 0x67, 0x18}, {0xa6, 0x63, 0x36, 0x74, 0xb3, 0xa7, 0x65, 0x8c, 0xca, 0xbc, 0xb4, 0x82, 0x2c, 0xf6, 0x95, 0x08, 0x42, 0xbf, 0xe5, 0x19, 0x48, 0x26, 0x7f, 0x69, 0x55, 0xc1, 0x3a, 0x69, 0x89, 0x8a, 0x9e, 0x1c}}, - {{0x62, 0xd9, 0x83, 0xb5, 0xc1, 0x50, 0xf1, 0x20, 0xa4, 0x33, 0xf3, 0x6b, 0xdd, 0x4f, 0x7c, 0x5b, 0x95, 0x06, 0x56, 0x6b, 0x14, 0xf2, 0x16, 0x66, 0xd7, 0xf9, 0x39, 0xae, 0x2a, 0x15, 0x09, 0x3c}, {0x76, 0x5f, 0xe4, 0x11, 0x5c, 0xd1, 0x4c, 0x8d, 0x95, 0x7a, 0x65, 0xa3, 0xa2, 0xfb, 0xe6, 0x3e, 0x68, 0xae, 0x90, 0x29, 0x4d, 0x94, 0xdf, 0x57, 0xfd, 0xfc, 0x7f, 0xdd, 0x06, 0x96, 0x40, 0x3e}}, - {{0x7f, 0x20, 0x4e, 0xc6, 0xaa, 0xcb, 0x1d, 0x0f, 0xaf, 0x74, 0xe8, 0x04, 0x96, 0x00, 0xce, 0x24, 0x2b, 0x3b, 0x16, 0x4f, 0x41, 0xa3, 0x06, 0x82, 0x83, 0x53, 0x60, 0x95, 0xa5, 0xff, 0x41, 0x18}, {0xb7, 0xdf, 0x2d, 0x17, 0x84, 0x4a, 0x45, 0x74, 0x87, 0x8c, 0x74, 0xe9, 0x3d, 0x66, 0x61, 0x4e, 0x10, 0xae, 0x52, 0x76, 0x6f, 0xc4, 0xac, 0x49, 0x40, 0x3d, 0xa0, 0x2d, 0x31, 0xeb, 0xf9, 0x35}}, - {{0xd2, 0x7c, 0x21, 0xe6, 0x29, 0xcf, 0xb2, 0x71, 0x72, 0xc7, 0xdc, 0x0c, 0xe4, 0x6d, 0xfb, 0x85, 0x7a, 0x87, 0x46, 0x0a, 0x60, 0x2d, 0xb0, 0xfc, 0x34, 0x62, 0x83, 0x25, 0xa8, 0xcb, 0xcd, 0x0d}, {0x7b, 0x32, 0x11, 0xd6, 0x58, 0xe0, 0xe7, 0xa5, 0xdd, 0x02, 0x46, 0xd4, 0xdc, 0xda, 0x29, 0x1f, 0xe5, 0x60, 0xaa, 0x22, 0x16, 0x06, 0xd2, 0x50, 0x28, 0x5d, 0x11, 0x69, 0xd7, 0x4a, 0xc1, 0x1b}}, - {{0x9f, 0x41, 0x3b, 0xab, 0xd4, 0x98, 0xad, 0x76, 0xff, 0x97, 0x25, 0x6e, 0x50, 0x8c, 0xad, 0xff, 0xbd, 0x1e, 0xea, 0x43, 0xb6, 0xbb, 0x06, 0x3a, 0xf7, 0xc5, 0xfb, 0x6f, 0xf3, 0xb0, 0xa3, 0x3d}, {0x6d, 0x29, 0xf0, 0x6b, 0x0e, 0xed, 0x47, 0xf7, 0xb0, 0x93, 0x58, 0xd3, 0x63, 0x98, 0xb5, 0x08, 0x4e, 0x06, 0x7f, 0xa7, 0x01, 0xa3, 0xc9, 0xfe, 0x86, 0x03, 0xdc, 0xd7, 0x9e, 0xb5, 0xe9, 0x18}}, - {{0x4f, 0x68, 0xa0, 0x65, 0x9b, 0x7b, 0x65, 0x19, 0x69, 0x1b, 0xc4, 0x19, 0x2d, 0x8c, 0x38, 0x21, 0xfa, 0x87, 0x83, 0xd7, 0x0b, 0x21, 0x4f, 0xae, 0x1b, 0xaa, 0xf9, 0x17, 0x56, 0xf1, 0x4a, 0x2e}, {0xac, 0x23, 0xbb, 0x7d, 0x88, 0xda, 0x5a, 0x7e, 0xa5, 0xce, 0x1a, 0xaa, 0xda, 0x81, 0x6a, 0x07, 0xc7, 0x12, 0x29, 0x46, 0x4a, 0x2c, 0xf5, 0x46, 0x00, 0xcd, 0x9a, 0xa7, 0x47, 0x3c, 0x7c, 0x37}}, - {{0x60, 0x89, 0x5a, 0x77, 0x4f, 0x9b, 0xe6, 0xd9, 0x53, 0x22, 0x8c, 0x3a, 0x6d, 0x68, 0xf8, 0x3c, 0x50, 0xf6, 0xdd, 0x38, 0xe7, 0x16, 0x7c, 0x00, 0xfb, 0xaf, 0xa9, 0xd1, 0x7f, 0xd8, 0x5c, 0x27}, {0xdc, 0x39, 0xbe, 0x83, 0xe8, 0xfa, 0xac, 0x2e, 0x92, 0x97, 0x5e, 0x54, 0x90, 0xcb, 0x47, 0xa1, 0x56, 0x21, 0xa5, 0x0c, 0x0b, 0x66, 0x94, 0xb8, 0x1f, 0x2a, 0xe6, 0x54, 0xd5, 0x7b, 0x2c, 0x10}}, - {{0x43, 0xd7, 0x8a, 0x81, 0x25, 0x52, 0x50, 0x3d, 0x51, 0x44, 0x96, 0x22, 0xda, 0xa4, 0x10, 0x76, 0x38, 0xe1, 0xcd, 0x15, 0xa3, 0xdb, 0xc1, 0x4a, 0x68, 0x8b, 0xb4, 0x93, 0xea, 0xe9, 0x63, 0x2a}, {0xae, 0xa0, 0x7c, 0x98, 0x8a, 0x7b, 0x2f, 0x60, 0xa2, 0x9c, 0x2b, 0xd1, 0xff, 0xd9, 0x6d, 0xf2, 0x74, 0x51, 0xde, 0x6c, 0x96, 0x36, 0x34, 0x74, 0xf6, 0x98, 0x8d, 0x59, 0x01, 0x2b, 0x77, 0x1d}}, - {{0x2d, 0xf1, 0x03, 0x25, 0xfa, 0x79, 0xe6, 0x9e, 0xa7, 0xc1, 0x7c, 0xab, 0xa8, 0x67, 0xa0, 0xe3, 0x0d, 0x5d, 0x00, 0xa9, 0xd6, 0xcf, 0x04, 0x4a, 0x0e, 0x35, 0xce, 0x03, 0x1f, 0xe7, 0xb6, 0x20}, {0xc0, 0xe9, 0xd9, 0x01, 0x2e, 0x35, 0x99, 0xff, 0x8a, 0x91, 0x8b, 0xf3, 0x28, 0xeb, 0xff, 0x1c, 0x4b, 0x6a, 0x2f, 0x6b, 0x1d, 0x21, 0x5a, 0x3f, 0x78, 0x3f, 0x33, 0xb9, 0xc5, 0x1a, 0xfc, 0x35}}, - {{0x3b, 0xc1, 0x2e, 0x0d, 0x30, 0xac, 0x29, 0xfd, 0x9d, 0x26, 0x90, 0xa0, 0x28, 0x88, 0x86, 0x6d, 0x3f, 0x6e, 0x1d, 0xdf, 0xe3, 0xb4, 0x7b, 0x61, 0x22, 0x3d, 0x99, 0x20, 0xbd, 0x44, 0x62, 0x10}, {0x53, 0xb0, 0x83, 0x7d, 0x07, 0x62, 0x4b, 0xba, 0xb4, 0xa5, 0x54, 0x05, 0xb3, 0x22, 0x2b, 0x75, 0xc4, 0x12, 0xa0, 0xf3, 0x20, 0x83, 0x99, 0x93, 0xf3, 0x53, 0xa7, 0xf9, 0x95, 0x12, 0x32, 0x3e}}, - {{0xf6, 0x2d, 0xda, 0x67, 0x13, 0x2a, 0xb0, 0x21, 0xe5, 0x71, 0xbb, 0x2a, 0x36, 0xf5, 0x5e, 0xd9, 0x8d, 0xbb, 0x9a, 0x81, 0x97, 0xcf, 0x66, 0xc4, 0x8d, 0xd1, 0xef, 0xa9, 0xf5, 0xd2, 0xc1, 0x0a}, {0x3d, 0x05, 0x6f, 0xe5, 0xda, 0x72, 0x2c, 0x65, 0xf8, 0x25, 0x09, 0xdd, 0x3c, 0xdf, 0x16, 0x3e, 0x8e, 0xae, 0xae, 0xf0, 0x64, 0xdc, 0x86, 0x44, 0x28, 0x3d, 0xcc, 0xaf, 0xd6, 0xd1, 0x83, 0x10}}, - {{0x22, 0xcb, 0x04, 0x15, 0x3f, 0x90, 0x6d, 0xd6, 0xa2, 0xf1, 0xfd, 0x24, 0x95, 0x1d, 0x74, 0x7d, 0x1d, 0x70, 0x05, 0x5b, 0x42, 0x11, 0x20, 0x04, 0xf9, 0x28, 0xa6, 0xa4, 0xdb, 0xa1, 0x81, 0x25}, {0xe8, 0x04, 0x35, 0x94, 0x61, 0x31, 0xf5, 0x31, 0xee, 0x27, 0x23, 0xe9, 0x6a, 0x08, 0xb5, 0x56, 0x0b, 0xd4, 0x53, 0xf4, 0xa6, 0xdb, 0x70, 0x04, 0xc3, 0x8b, 0x46, 0x6a, 0xbb, 0x3c, 0xb7, 0x37}}, - {{0x5a, 0x09, 0x62, 0x2a, 0xe6, 0xfa, 0x64, 0x5a, 0xe1, 0x09, 0xcc, 0xa3, 0x9a, 0xb9, 0x5d, 0x1a, 0xcf, 0xd4, 0xf1, 0xb4, 0x4d, 0xbf, 0x87, 0x5c, 0x25, 0xce, 0xc7, 0x5a, 0x45, 0xe1, 0x54, 0x35}, {0x3c, 0x65, 0x59, 0xb2, 0xaa, 0x29, 0xfb, 0x62, 0x99, 0xbf, 0x69, 0xf6, 0x28, 0xe0, 0x79, 0x10, 0xd3, 0x56, 0x6a, 0xb6, 0xa2, 0xe1, 0xb5, 0xc7, 0x3d, 0x66, 0x79, 0x06, 0x27, 0x6c, 0xa9, 0x1d}}, - {{0x95, 0xc5, 0xe4, 0x05, 0x97, 0x75, 0x8a, 0xa3, 0x04, 0x91, 0x79, 0x36, 0xbf, 0x16, 0xb5, 0x93, 0xa9, 0xec, 0xb7, 0x06, 0x7c, 0x61, 0xf3, 0xdc, 0x0a, 0xd9, 0x46, 0x62, 0x49, 0x96, 0x04, 0x1c}, {0x10, 0xb0, 0x98, 0x20, 0xde, 0x62, 0x9b, 0xcb, 0x5b, 0x3c, 0xc4, 0xe6, 0xdc, 0xbd, 0x11, 0x0b, 0xb5, 0xa4, 0x71, 0x21, 0x19, 0x96, 0x06, 0x0e, 0x63, 0xb5, 0x5e, 0x54, 0xbd, 0xf9, 0xa0, 0x0c}}, - {{0x8c, 0xd6, 0xe1, 0x5c, 0xbb, 0xcc, 0xcc, 0xab, 0x82, 0xa2, 0x0d, 0xe5, 0x47, 0xaf, 0x7c, 0x6f, 0x6f, 0x80, 0xaa, 0xab, 0x5e, 0x13, 0x6a, 0xf3, 0xe8, 0xaa, 0x95, 0x10, 0xde, 0xba, 0x6e, 0x0c}, {0xe2, 0xb3, 0xe6, 0x69, 0x9e, 0xcc, 0x9c, 0x75, 0xbf, 0x63, 0xa2, 0x05, 0xdf, 0x54, 0xdd, 0xf9, 0x6b, 0x94, 0x47, 0xcf, 0x3c, 0xd7, 0xda, 0x89, 0x52, 0xbc, 0x83, 0x2b, 0xaf, 0xd8, 0x12, 0x03}}, - {{0x84, 0x40, 0x09, 0x32, 0x19, 0xf4, 0x63, 0x3d, 0xbd, 0xd3, 0x0d, 0xa1, 0x39, 0x09, 0x2e, 0xa8, 0x24, 0xca, 0x16, 0xe0, 0x48, 0x2d, 0xa4, 0x09, 0xd6, 0xa5, 0xfb, 0x48, 0x60, 0x25, 0xd5, 0x22}, {0x8e, 0xf0, 0x85, 0xe3, 0x7b, 0x91, 0x5f, 0x20, 0xc5, 0x96, 0x82, 0x15, 0xea, 0x59, 0xba, 0xe8, 0xf4, 0x61, 0x02, 0x12, 0x05, 0x5f, 0xdb, 0x07, 0x81, 0x2d, 0x0d, 0xcf, 0x10, 0xfe, 0x27, 0x1b}}, - {{0xbc, 0xcd, 0xc0, 0xc4, 0x26, 0x20, 0xc5, 0xc3, 0xf1, 0xc4, 0x04, 0x98, 0x75, 0xa0, 0xc9, 0xe5, 0x01, 0x6d, 0x9b, 0x89, 0x4f, 0xa3, 0x3d, 0x33, 0xf1, 0x9f, 0xee, 0x69, 0x6f, 0x9b, 0x93, 0x08}, {0x29, 0x6a, 0x0b, 0xa6, 0x90, 0x5c, 0x38, 0x57, 0xe3, 0x9e, 0x89, 0x98, 0xf0, 0x0a, 0xfe, 0xcb, 0xc2, 0x94, 0x05, 0xed, 0x49, 0x4f, 0x6c, 0xe5, 0xd0, 0xfe, 0xe4, 0xa7, 0xdf, 0x87, 0x8c, 0x1a}}, - {{0x52, 0x70, 0x4a, 0x52, 0x17, 0x86, 0xcc, 0x9b, 0x39, 0x80, 0x3b, 0xa5, 0x3e, 0xbc, 0xd1, 0x9e, 0xae, 0xb3, 0xc1, 0x98, 0x28, 0x0a, 0x3b, 0xe8, 0x5f, 0x00, 0x78, 0xf3, 0x79, 0xb8, 0x56, 0x21}, {0x03, 0x0c, 0x4c, 0x1a, 0xd6, 0x4f, 0x45, 0xe4, 0x37, 0xd1, 0x45, 0x9e, 0xee, 0x77, 0x2d, 0xfd, 0x2e, 0x46, 0xca, 0xbe, 0xd1, 0xd7, 0x4c, 0x36, 0x24, 0x02, 0x06, 0x6d, 0xa0, 0x61, 0x54, 0x04}}, - {{0xdf, 0xc8, 0x42, 0x77, 0x0b, 0xe4, 0xdc, 0xa6, 0xbb, 0x4c, 0x5e, 0x2f, 0x9f, 0xfb, 0xf6, 0x77, 0xf6, 0x01, 0xa1, 0xc8, 0xf2, 0xa6, 0x71, 0x89, 0x7e, 0x55, 0x8d, 0xe6, 0x1d, 0x89, 0xf6, 0x06}, {0x60, 0x93, 0x2c, 0xf3, 0x32, 0xeb, 0x36, 0xe1, 0xe3, 0x94, 0x83, 0x15, 0x7a, 0x80, 0xcc, 0x43, 0x85, 0x0e, 0x3f, 0xbd, 0xd8, 0x68, 0x83, 0xb8, 0x9b, 0xd9, 0xff, 0xa3, 0x43, 0xf7, 0xc7, 0x39}}, - {{0x88, 0xa1, 0xc5, 0xde, 0x24, 0x80, 0x92, 0x4d, 0x3e, 0x35, 0x86, 0xd3, 0x2b, 0xa9, 0xfc, 0xc6, 0x66, 0x76, 0x1b, 0xf5, 0x5d, 0xc8, 0x12, 0x58, 0x75, 0xad, 0x85, 0xb9, 0xae, 0x96, 0x22, 0x36}, {0x5b, 0xcc, 0xbc, 0x0e, 0x47, 0x43, 0x74, 0xaf, 0x4e, 0xe0, 0x4f, 0xbd, 0x03, 0xdf, 0x64, 0x86, 0xe1, 0xa6, 0xed, 0x90, 0xe1, 0xdf, 0x7c, 0xbb, 0x6d, 0x8d, 0xc1, 0x6a, 0xf0, 0x49, 0xb7, 0x04}}, - {{0x64, 0x5d, 0xe6, 0x61, 0x3a, 0x7e, 0xcb, 0x47, 0x8b, 0x16, 0x1d, 0x61, 0x4b, 0x8f, 0x68, 0x26, 0x0a, 0x27, 0x81, 0xf0, 0xc6, 0xb1, 0x1e, 0x85, 0xd3, 0xc4, 0xd9, 0x07, 0x77, 0x65, 0xcd, 0x0b}, {0x59, 0x6e, 0x64, 0x01, 0x1d, 0x9c, 0xa7, 0xb8, 0x14, 0x8d, 0xbe, 0x3c, 0x81, 0x0a, 0xa0, 0xac, 0x61, 0x22, 0xd4, 0xa4, 0x22, 0xd6, 0xe3, 0x9b, 0xaf, 0x0a, 0x21, 0xff, 0xec, 0x44, 0x8f, 0x22}}, - {{0xd8, 0x77, 0xfc, 0x32, 0xeb, 0x32, 0xe8, 0x01, 0x1d, 0x6d, 0x1e, 0xcf, 0x9f, 0xd4, 0x7b, 0xa3, 0x02, 0x69, 0x3a, 0x00, 0x26, 0x76, 0xde, 0x4a, 0x5b, 0x28, 0x73, 0x68, 0xba, 0x18, 0x10, 0x28}, {0xf7, 0xe0, 0x6a, 0x3f, 0x8c, 0xbd, 0x22, 0x3b, 0xf9, 0x9d, 0x9e, 0xcc, 0xe9, 0xd4, 0x7a, 0x64, 0x1a, 0x86, 0xe2, 0xe5, 0x4e, 0x26, 0x9f, 0x59, 0x1b, 0xe1, 0x11, 0xc7, 0xbb, 0x4d, 0xc7, 0x1b}}, - {{0x15, 0x0e, 0xb8, 0xf1, 0x2c, 0x50, 0x31, 0xea, 0x28, 0xb4, 0x48, 0xcd, 0x60, 0x51, 0x3d, 0xc3, 0xec, 0xad, 0x17, 0xde, 0x10, 0xc9, 0x23, 0xcc, 0x47, 0x9c, 0xa5, 0x1a, 0xce, 0xf9, 0xde, 0x07}, {0x32, 0x59, 0x64, 0xb4, 0xba, 0xee, 0xae, 0xa4, 0x65, 0x4d, 0x87, 0x10, 0x50, 0x14, 0x23, 0xb1, 0xd6, 0xfb, 0xb3, 0xe2, 0x73, 0x28, 0x4f, 0xd7, 0x2f, 0x46, 0xe4, 0x56, 0xe5, 0x28, 0xf7, 0x37}}, - {{0xb4, 0xc5, 0x4b, 0xbb, 0x95, 0x9f, 0x30, 0x7e, 0x80, 0xc5, 0x61, 0x72, 0x7d, 0xf4, 0x62, 0x60, 0x90, 0x85, 0x15, 0x6d, 0x2a, 0x4f, 0x3d, 0x8e, 0x98, 0xa3, 0x38, 0x16, 0x94, 0xe2, 0xd5, 0x01}, {0x52, 0x62, 0x76, 0x51, 0xe0, 0x25, 0x94, 0x2d, 0x2b, 0x2f, 0x6d, 0x6d, 0x26, 0x3a, 0x1f, 0x66, 0xdd, 0xb8, 0xf4, 0x2f, 0x37, 0x60, 0x26, 0xe2, 0xa5, 0xe4, 0x8e, 0x77, 0xc3, 0x12, 0x17, 0x12}}, - {{0x7c, 0x6f, 0xce, 0x77, 0x3e, 0xbc, 0x89, 0x80, 0xc0, 0x7f, 0x0f, 0xd8, 0xeb, 0x22, 0xb2, 0xa6, 0x50, 0x82, 0x3e, 0x94, 0x90, 0xb7, 0xb8, 0xe9, 0xb1, 0x15, 0xb4, 0x66, 0x60, 0x06, 0x95, 0x10}, {0x6c, 0x21, 0x30, 0xaa, 0x23, 0x58, 0xaf, 0xec, 0x67, 0xc8, 0x8c, 0xae, 0x76, 0x71, 0xd3, 0x1b, 0x92, 0x4c, 0x00, 0x3a, 0x17, 0x5d, 0x46, 0x66, 0xa2, 0x5f, 0xac, 0xbb, 0xda, 0xb8, 0x08, 0x17}}, - {{0x06, 0x04, 0xd5, 0x1e, 0xf4, 0xb3, 0x5a, 0x0f, 0x93, 0x81, 0x8e, 0x6b, 0x24, 0xb8, 0xd6, 0x3e, 0xef, 0x72, 0x66, 0xc1, 0xa7, 0x17, 0xc8, 0xef, 0xed, 0x6f, 0xe0, 0x55, 0x5c, 0xe6, 0xd9, 0x03}, {0xd9, 0xef, 0x15, 0x3a, 0x0a, 0x0a, 0x66, 0xd2, 0x3a, 0x60, 0x38, 0x02, 0x60, 0x31, 0x58, 0x31, 0x07, 0x04, 0x04, 0xef, 0x6e, 0x57, 0x8a, 0xd0, 0xad, 0x02, 0x86, 0x33, 0x79, 0xfc, 0xb5, 0x12}}, - {{0x61, 0xb2, 0x1a, 0x86, 0x38, 0x50, 0xb4, 0xaf, 0xef, 0xdd, 0xa2, 0x0e, 0x12, 0x25, 0x36, 0x33, 0xf0, 0xc3, 0xe9, 0xbd, 0x8a, 0x1e, 0xd2, 0xd0, 0x67, 0x66, 0x44, 0x0f, 0x07, 0x56, 0x42, 0x31}, {0x26, 0x95, 0xcd, 0xb0, 0xf6, 0x2b, 0x7d, 0xd4, 0x97, 0x59, 0xea, 0x03, 0x62, 0x51, 0xb6, 0xdf, 0x86, 0x3d, 0xf1, 0xd9, 0x3a, 0xe9, 0xc8, 0x6b, 0xfe, 0xa3, 0x9f, 0x87, 0x1e, 0x7b, 0xe3, 0x36}}, - {{0xf8, 0x63, 0x71, 0x38, 0x25, 0xb7, 0x41, 0x96, 0x89, 0xfb, 0x7d, 0x97, 0x13, 0xe2, 0x14, 0x2f, 0x01, 0x24, 0x8e, 0x81, 0x0f, 0x0f, 0x2e, 0x87, 0x55, 0x52, 0x01, 0x94, 0x42, 0x47, 0x05, 0x27}, {0x3e, 0xbf, 0x77, 0xe2, 0xe9, 0x98, 0x14, 0xe9, 0xe8, 0x0d, 0xcc, 0x46, 0x36, 0x13, 0x1c, 0xbc, 0xc2, 0x24, 0xbb, 0x9d, 0x5f, 0x26, 0x0d, 0x81, 0x17, 0xd4, 0x22, 0x0c, 0xa7, 0x4f, 0x3c, 0x07}}, - {{0xdb, 0xcb, 0x57, 0x4f, 0x76, 0x84, 0xe0, 0x72, 0x74, 0xec, 0x5a, 0xed, 0xbe, 0x43, 0xde, 0xaa, 0xa8, 0xef, 0xaa, 0x38, 0xe7, 0x19, 0x7a, 0x6b, 0x38, 0x9c, 0x03, 0xb2, 0xe4, 0x03, 0xe1, 0x3f}, {0xfc, 0x5f, 0x47, 0x90, 0x09, 0xa4, 0xb0, 0xf7, 0x7f, 0xd4, 0x6c, 0x59, 0x45, 0x8b, 0x27, 0xf2, 0x20, 0x9b, 0x61, 0x00, 0x33, 0x3c, 0x89, 0x8e, 0x44, 0xb3, 0x51, 0x99, 0x12, 0x0a, 0x9a, 0x1e}}, - {{0xf7, 0xde, 0xf4, 0x25, 0x1d, 0x1d, 0x3e, 0x27, 0xb1, 0xbe, 0x71, 0x31, 0x5a, 0x84, 0x03, 0x20, 0xd4, 0xf2, 0x29, 0x5f, 0x65, 0x81, 0x17, 0x6d, 0xc0, 0x29, 0x5b, 0x5d, 0x7f, 0x5e, 0x70, 0x08}, {0xff, 0x7c, 0x5d, 0xfa, 0x29, 0x58, 0x93, 0x55, 0x7e, 0x5d, 0x89, 0xf7, 0xcd, 0x41, 0x2a, 0xf3, 0x3d, 0xe7, 0xa2, 0xd1, 0x43, 0xea, 0xf2, 0x1b, 0x54, 0xd6, 0x53, 0x04, 0x08, 0xbf, 0x0f, 0x02}}, - {{0x13, 0x9a, 0xb8, 0x2d, 0xc7, 0x99, 0xcc, 0xc7, 0x7f, 0x45, 0x3e, 0x1a, 0x72, 0xf8, 0x69, 0xe8, 0x27, 0x5e, 0xe9, 0xf9, 0x75, 0x9b, 0xd5, 0xf8, 0x21, 0x72, 0xec, 0xb0, 0xb9, 0xdf, 0x3c, 0x2a}, {0xae, 0x43, 0xb3, 0xc8, 0x87, 0x9b, 0x92, 0xda, 0xf0, 0x23, 0xca, 0x1a, 0xe3, 0x22, 0x3c, 0xb3, 0x9b, 0x02, 0xd5, 0x43, 0x20, 0xc0, 0xf6, 0x7e, 0x16, 0x60, 0x1b, 0xfb, 0xe5, 0x75, 0x16, 0x0f}}, - {{0xf5, 0xa8, 0x1e, 0x58, 0x9c, 0xc4, 0xa7, 0xda, 0xa4, 0x68, 0xf6, 0x0b, 0xdf, 0x60, 0x24, 0x5e, 0x46, 0x61, 0xaf, 0x9c, 0x29, 0xec, 0xe2, 0x04, 0x89, 0x62, 0xb6, 0xc6, 0xee, 0xe7, 0x38, 0x24}, {0xe3, 0x5c, 0x90, 0x09, 0x50, 0xc5, 0x4c, 0xd9, 0xbb, 0xac, 0x98, 0x7c, 0xc9, 0x39, 0x49, 0x91, 0x4f, 0x00, 0x9d, 0xe6, 0xd5, 0xa0, 0xd6, 0x90, 0x5e, 0x00, 0x0a, 0x43, 0x99, 0x97, 0x30, 0x0e}}, - {{0x37, 0xba, 0x3d, 0xdf, 0x71, 0xba, 0xd2, 0x16, 0xf3, 0x46, 0x72, 0x90, 0x39, 0x3a, 0x87, 0xf9, 0x78, 0x89, 0x2c, 0x2e, 0xc7, 0x0f, 0x09, 0x73, 0xd8, 0xdb, 0x93, 0x76, 0x9f, 0xca, 0x6a, 0x3e}, {0x42, 0x82, 0x2f, 0xe1, 0x67, 0xc6, 0xbb, 0x14, 0x8e, 0xce, 0xc7, 0x64, 0xdf, 0xda, 0xab, 0xb8, 0x2a, 0xea, 0xb2, 0x7b, 0xc1, 0x5b, 0x94, 0x1a, 0xec, 0x3a, 0x71, 0xaf, 0xf6, 0xbb, 0x2d, 0x01}}, - {{0xac, 0x36, 0xd7, 0xc9, 0xda, 0x00, 0x0d, 0x24, 0x54, 0x60, 0xd5, 0x1e, 0x24, 0x54, 0x01, 0x5e, 0xfb, 0x9c, 0x42, 0x3e, 0x76, 0x8e, 0x7b, 0xb7, 0xef, 0xba, 0xcd, 0x38, 0xec, 0x95, 0x43, 0x14}, {0xf8, 0xf4, 0xef, 0x18, 0x3f, 0x46, 0xd5, 0xa1, 0x12, 0xe9, 0xec, 0x6e, 0x2b, 0x6a, 0x13, 0xac, 0xb6, 0xab, 0x5b, 0x65, 0x1a, 0x2f, 0x5b, 0x17, 0x12, 0xdc, 0x62, 0x88, 0x77, 0xe5, 0xf8, 0x11}}, - {{0x26, 0x9f, 0x8e, 0x1b, 0xa5, 0x91, 0x7d, 0x91, 0xf9, 0x2e, 0xdb, 0xe2, 0xb3, 0xd4, 0xa7, 0x96, 0xa5, 0x80, 0xec, 0xeb, 0x93, 0x28, 0x67, 0x64, 0xad, 0xa7, 0xdd, 0x6a, 0x2c, 0xc7, 0x15, 0x04}, {0x9d, 0xb6, 0x1c, 0x54, 0xe5, 0x78, 0xfe, 0x31, 0x07, 0xa9, 0x64, 0xa1, 0x2e, 0xa4, 0xd0, 0x6f, 0x9d, 0xa9, 0xe7, 0x59, 0x38, 0xfe, 0x9b, 0x77, 0x53, 0xcc, 0xea, 0xf9, 0x13, 0xf3, 0x02, 0x15}}, - {{0x2c, 0x96, 0x09, 0xf5, 0xd0, 0x68, 0x99, 0x62, 0xe8, 0xa1, 0xb9, 0xa5, 0x6c, 0x54, 0xd8, 0x0f, 0x4d, 0x86, 0xee, 0x88, 0x37, 0x71, 0x71, 0x4f, 0xff, 0x98, 0x78, 0xbb, 0xd7, 0x39, 0xbe, 0x21}, {0xfa, 0xb4, 0xa1, 0x56, 0x7c, 0x59, 0x30, 0x2e, 0xe1, 0x07, 0x81, 0x83, 0x53, 0xad, 0x02, 0x1a, 0x33, 0x6d, 0xfd, 0x1c, 0x9e, 0x2a, 0x02, 0x4d, 0xc1, 0xb4, 0xaa, 0x51, 0x7d, 0xe3, 0x3c, 0x1f}}, - {{0x9b, 0xad, 0x87, 0x97, 0x7a, 0x27, 0xe8, 0xd2, 0xf3, 0xde, 0x81, 0x3d, 0x87, 0xef, 0xb8, 0x06, 0x94, 0x92, 0xdc, 0x0c, 0x58, 0xa0, 0x3f, 0xcb, 0xd5, 0xda, 0x10, 0xb6, 0x66, 0xb8, 0x0e, 0x3e}, {0xe1, 0xfc, 0x0b, 0x29, 0x8d, 0x98, 0x6f, 0x41, 0xfc, 0xa7, 0xea, 0x9e, 0x46, 0x9c, 0x9d, 0xe9, 0x1a, 0xf3, 0x8c, 0x96, 0x7c, 0xd3, 0x26, 0xe8, 0x3e, 0xbc, 0x96, 0x29, 0x65, 0x50, 0x3a, 0x30}}, - {{0x96, 0x65, 0xf9, 0xb7, 0x3d, 0xc4, 0x0d, 0x97, 0x7a, 0xb3, 0xbe, 0x7b, 0x04, 0xa0, 0xbe, 0x8b, 0x20, 0xff, 0x86, 0x4f, 0x7c, 0xc0, 0xbf, 0xff, 0x7b, 0x81, 0x5b, 0x2a, 0x70, 0xe8, 0xb0, 0x2e}, {0x15, 0xcf, 0x3a, 0xc7, 0x92, 0xdf, 0xec, 0xcd, 0x4b, 0x1a, 0xc1, 0x4b, 0xf4, 0xb8, 0x49, 0xa3, 0x86, 0x04, 0x35, 0x1a, 0x82, 0x5c, 0xa2, 0x4c, 0x4e, 0xce, 0x63, 0x8f, 0xee, 0xa8, 0x35, 0x0c}}, - {{0x9d, 0x90, 0xc5, 0x82, 0xff, 0xfe, 0x30, 0x33, 0x65, 0x8f, 0x76, 0x15, 0xf5, 0xcc, 0x37, 0xa0, 0x7e, 0xab, 0x65, 0xd1, 0xbf, 0xe5, 0xb4, 0x04, 0x1f, 0x70, 0x98, 0x2e, 0x0d, 0xd3, 0x8f, 0x3d}, {0x16, 0x69, 0x3f, 0x61, 0x4c, 0x35, 0xcf, 0x76, 0xe4, 0xb8, 0x68, 0xef, 0xfc, 0x8c, 0xac, 0xb3, 0x48, 0x33, 0x6d, 0xfb, 0xec, 0x23, 0x1e, 0x12, 0x7e, 0x00, 0x65, 0x69, 0x76, 0x46, 0x9c, 0x04}}, - {{0x16, 0xad, 0x8a, 0x20, 0xf8, 0x5a, 0x8b, 0xd2, 0xc1, 0x9e, 0x22, 0x25, 0x01, 0x0c, 0xcc, 0x85, 0x44, 0xb7, 0xba, 0xfc, 0xb7, 0x00, 0x10, 0x00, 0xda, 0x50, 0x59, 0xe1, 0xb5, 0x3c, 0x16, 0x2f}, {0x0c, 0x8f, 0x4c, 0x85, 0xa6, 0xa5, 0x04, 0x82, 0xf3, 0x1b, 0x9c, 0x9f, 0xed, 0x50, 0xc2, 0xae, 0xba, 0xcf, 0xa8, 0x4c, 0x3b, 0x97, 0x78, 0xa6, 0xf6, 0xad, 0x62, 0x10, 0xc2, 0x78, 0x60, 0x20}}, - {{0xe7, 0xba, 0x44, 0xae, 0xa2, 0xbf, 0x72, 0xb5, 0xd9, 0x65, 0x58, 0xed, 0xe5, 0x7b, 0x39, 0x47, 0x9d, 0xcd, 0xd5, 0xd7, 0x60, 0x26, 0xd8, 0x12, 0xf4, 0x11, 0xfb, 0xd0, 0xb0, 0x91, 0x02, 0x38}, {0xed, 0x00, 0x4f, 0xe3, 0x04, 0xf0, 0x9e, 0xda, 0x9e, 0x71, 0x45, 0xf1, 0xc5, 0xc9, 0xc7, 0xd1, 0x77, 0x9c, 0x32, 0xe0, 0x71, 0xb0, 0x07, 0x5d, 0x6c, 0xcc, 0xca, 0x5a, 0xf3, 0x1b, 0x1f, 0x11}}, - {{0x4b, 0xf7, 0xec, 0xdb, 0xe9, 0xfe, 0x4e, 0x9d, 0x40, 0x1c, 0xd1, 0x6e, 0x98, 0x6b, 0xb6, 0x54, 0x77, 0x92, 0x2a, 0x1f, 0x67, 0xe9, 0x9d, 0xc6, 0x19, 0x6f, 0x01, 0x09, 0xc2, 0xf7, 0x1e, 0x38}, {0x70, 0x48, 0x3d, 0x4c, 0x91, 0x62, 0xcd, 0x78, 0xc9, 0xa7, 0x66, 0x43, 0x3f, 0xb0, 0x9d, 0x96, 0xca, 0x8c, 0x98, 0xad, 0xfc, 0xed, 0x3f, 0xc6, 0x39, 0xed, 0x6c, 0x19, 0xf1, 0xc3, 0x71, 0x08}}, - {{0xe4, 0x88, 0x25, 0xcd, 0xe0, 0x5a, 0x95, 0xbf, 0xc6, 0x85, 0xc1, 0x5b, 0x45, 0xbe, 0x5d, 0x1a, 0x70, 0x1b, 0xe7, 0x93, 0x1f, 0xfb, 0x0f, 0x80, 0xb8, 0x93, 0xa4, 0x1f, 0x52, 0x68, 0x99, 0x04}, {0x7f, 0x44, 0xa4, 0x46, 0x2b, 0xa0, 0x88, 0x08, 0x28, 0x8c, 0xb9, 0x9c, 0x8f, 0x42, 0x4f, 0xbf, 0xe2, 0x9d, 0xff, 0x14, 0x03, 0x07, 0x37, 0x81, 0x10, 0xb4, 0x10, 0x43, 0x76, 0x90, 0x87, 0x13}}, - {{0xdf, 0x07, 0x6b, 0x0f, 0xc0, 0xb4, 0x2e, 0xd1, 0xf4, 0x39, 0x77, 0xf3, 0xb7, 0x9c, 0x67, 0x48, 0x00, 0x44, 0x7d, 0xb1, 0x85, 0x9c, 0x8d, 0xd2, 0x49, 0xe3, 0x75, 0xa8, 0xe1, 0x47, 0xd9, 0x0b}, {0xba, 0xe1, 0x6c, 0xe5, 0x27, 0x8d, 0x62, 0xda, 0xd8, 0x9f, 0xb8, 0x96, 0xd5, 0xf8, 0xb9, 0x3f, 0x37, 0x62, 0x58, 0xf6, 0x29, 0xb9, 0xe3, 0x5d, 0xb6, 0x2e, 0x38, 0x26, 0xa4, 0x62, 0x35, 0x15}}, - {{0x5c, 0xaf, 0xe6, 0xbd, 0x03, 0x3b, 0xaf, 0x36, 0xc6, 0x0d, 0xf6, 0xd7, 0x15, 0x33, 0xa4, 0x4f, 0x97, 0x91, 0x91, 0xa4, 0x20, 0xa0, 0x67, 0x70, 0xee, 0xdd, 0x06, 0xb3, 0xf1, 0x47, 0x32, 0x1c}, {0x96, 0xf6, 0x0f, 0x65, 0x5a, 0xbb, 0x52, 0xc6, 0xe1, 0x64, 0xfe, 0xd2, 0x0c, 0x89, 0x3e, 0xf5, 0x51, 0xac, 0x0e, 0x67, 0x20, 0xc1, 0xbd, 0x9d, 0x8a, 0xb0, 0x23, 0x44, 0xe0, 0xcc, 0x86, 0x07}}, - {{0xe2, 0xab, 0x02, 0x5c, 0x04, 0x5a, 0x52, 0x9b, 0x10, 0xfc, 0x69, 0x3c, 0xcd, 0x03, 0x88, 0xab, 0x22, 0xf8, 0x67, 0x49, 0xe7, 0x04, 0x5c, 0x4f, 0x73, 0xc9, 0x24, 0x8d, 0x8b, 0xba, 0x7c, 0x3d}, {0xa7, 0x8c, 0x0e, 0xc2, 0xa9, 0x6d, 0x6f, 0xc3, 0x4d, 0x05, 0xc7, 0x18, 0xd3, 0x0c, 0xb8, 0x3a, 0xd8, 0x88, 0xfb, 0xf1, 0x8b, 0xc4, 0x00, 0xea, 0xd5, 0x75, 0xe9, 0x78, 0x4f, 0xcd, 0x85, 0x2a}}, - {{0xa2, 0x11, 0xb6, 0xd4, 0x5e, 0xf9, 0x5b, 0xac, 0x43, 0x2c, 0xc7, 0x80, 0x81, 0x4d, 0x6d, 0x13, 0x4e, 0x8d, 0x8c, 0xd2, 0x88, 0xdf, 0xb6, 0x1f, 0x11, 0x60, 0xd5, 0x17, 0x1b, 0xfe, 0x6a, 0x24}, {0x72, 0x49, 0x56, 0x47, 0x33, 0x7b, 0x68, 0x36, 0x64, 0xbc, 0x0d, 0x36, 0x2d, 0xdd, 0x67, 0x14, 0x58, 0x62, 0xa9, 0x93, 0x5f, 0xdf, 0x0c, 0x41, 0xa0, 0xe8, 0xc6, 0x24, 0x68, 0x8b, 0x88, 0x35}}, - {{0x92, 0xd4, 0x62, 0x4a, 0x72, 0x2a, 0xc2, 0x5d, 0x8c, 0x8d, 0x50, 0xa7, 0x2b, 0x9b, 0x60, 0x26, 0x71, 0x84, 0x53, 0x1b, 0xe6, 0x5a, 0x59, 0x50, 0xff, 0xcd, 0x65, 0x97, 0xb1, 0x34, 0x6a, 0x26}, {0xcb, 0xa2, 0x58, 0xd3, 0xdb, 0x5b, 0xbe, 0x7f, 0x6a, 0xa7, 0xa8, 0x1c, 0xfd, 0xf7, 0xa4, 0x40, 0x4a, 0x00, 0x0e, 0xa5, 0x73, 0x32, 0x1d, 0x49, 0xad, 0x62, 0x4f, 0xdc, 0x4a, 0x0e, 0x68, 0x35}}, - {{0x4e, 0xfd, 0x77, 0xf9, 0x0c, 0x99, 0xdb, 0xbf, 0x9e, 0xcc, 0x6d, 0xca, 0x9d, 0x36, 0x37, 0x64, 0xee, 0x51, 0x50, 0xb5, 0x48, 0xd0, 0xb5, 0xc7, 0x45, 0x46, 0xd5, 0x71, 0xec, 0x73, 0x0b, 0x25}, {0x81, 0xb3, 0x12, 0x44, 0x6b, 0xe4, 0xae, 0x41, 0xfb, 0x61, 0xdc, 0x6d, 0x00, 0xe5, 0x9e, 0x9e, 0x94, 0xcf, 0xce, 0xbb, 0xf5, 0x6d, 0x2f, 0xec, 0x3d, 0x60, 0x16, 0x0b, 0x15, 0xe2, 0x93, 0x17}}, - {{0x47, 0x62, 0x0c, 0x77, 0x79, 0x6d, 0x88, 0x6f, 0x82, 0xe1, 0xa1, 0x0f, 0x74, 0x03, 0x00, 0x15, 0x82, 0x2f, 0x69, 0x17, 0xb2, 0x03, 0x76, 0xf3, 0xec, 0xb7, 0xf5, 0x0a, 0x68, 0x73, 0x1f, 0x3d}, {0x9e, 0x72, 0xf9, 0xe4, 0x5a, 0xa7, 0xb6, 0x81, 0x17, 0xae, 0x1f, 0x34, 0xaa, 0xae, 0x35, 0xe7, 0x0a, 0xbb, 0xaa, 0xe1, 0xc5, 0xb7, 0xff, 0x4e, 0x4a, 0xc3, 0x5d, 0x4c, 0xd4, 0xc1, 0x23, 0x02}}, - {{0x32, 0x75, 0x45, 0x79, 0x4d, 0xf1, 0x9d, 0x41, 0x12, 0xc5, 0x02, 0x4e, 0x3f, 0x28, 0x80, 0xd7, 0x36, 0xc5, 0x6c, 0x75, 0xa1, 0x47, 0xfc, 0xf0, 0x82, 0xed, 0x6b, 0xa0, 0x02, 0x07, 0xe3, 0x1c}, {0x60, 0x68, 0x79, 0x14, 0x53, 0x97, 0x20, 0xaa, 0xa0, 0x53, 0x50, 0xd9, 0x71, 0x96, 0x7b, 0xb7, 0xba, 0x84, 0xdd, 0x09, 0x3e, 0xe6, 0x4e, 0x80, 0x06, 0xa8, 0xdd, 0x96, 0x1b, 0x71, 0xe1, 0x09}}, - {{0x19, 0xc0, 0x89, 0xa5, 0x34, 0xba, 0x7f, 0x60, 0x98, 0x59, 0x82, 0x5d, 0xb6, 0xba, 0xbd, 0x79, 0x38, 0xd9, 0xbb, 0x7f, 0xbd, 0xa4, 0xca, 0xca, 0x4d, 0xe5, 0xf8, 0x2c, 0x85, 0xca, 0x94, 0x36}, {0x54, 0x7e, 0xb3, 0x3f, 0xc0, 0x28, 0x55, 0xf5, 0xe4, 0x66, 0xbb, 0x11, 0x81, 0xb7, 0x49, 0x4a, 0x5b, 0x51, 0xc5, 0x59, 0xe7, 0x77, 0xe4, 0x94, 0x48, 0xfe, 0x09, 0x0b, 0xf2, 0xa0, 0x9b, 0x36}}, - {{0x61, 0xe7, 0x41, 0x3c, 0x43, 0x48, 0x03, 0xa9, 0xae, 0xb2, 0xda, 0x07, 0x0e, 0x6c, 0x4f, 0x33, 0xe1, 0xe8, 0x75, 0x07, 0xb1, 0x35, 0x76, 0xfa, 0x21, 0x19, 0x1d, 0x90, 0xd1, 0x43, 0xdd, 0x1f}, {0xa3, 0xe1, 0xf5, 0x11, 0x7e, 0xaf, 0x42, 0xb0, 0xda, 0x0a, 0x84, 0x05, 0x43, 0xc3, 0xdc, 0x72, 0x4a, 0x7a, 0xa0, 0x40, 0xf3, 0x22, 0x1f, 0xec, 0xa7, 0xaf, 0x46, 0x0c, 0x14, 0xcd, 0x4d, 0x3d}}, - {{0x63, 0xb8, 0x5a, 0xad, 0xa1, 0x53, 0x16, 0x65, 0x99, 0x72, 0x3a, 0x3f, 0xa4, 0xc5, 0x09, 0x31, 0xd9, 0x8c, 0x51, 0xac, 0xfe, 0x89, 0x26, 0x4a, 0x25, 0x4b, 0x6f, 0x30, 0xe5, 0x28, 0xcb, 0x32}, {0x32, 0x07, 0x70, 0x77, 0xf1, 0x41, 0x22, 0xce, 0x1a, 0xf8, 0x77, 0x14, 0xbf, 0x68, 0xc2, 0xe9, 0x7c, 0xf5, 0xd9, 0xbe, 0xf5, 0xc5, 0x43, 0xb6, 0xaf, 0x3e, 0xed, 0x8f, 0x0c, 0x8e, 0xb3, 0x1a}}, - {{0x29, 0xc9, 0x5b, 0xcf, 0x7d, 0xf4, 0x37, 0xad, 0x20, 0xb6, 0xa6, 0x3c, 0xcb, 0x68, 0xc4, 0xfe, 0x5d, 0x62, 0xcd, 0xe2, 0x60, 0x52, 0x8c, 0x38, 0x61, 0xb4, 0x47, 0xbf, 0x94, 0x20, 0x14, 0x3e}, {0xd6, 0xdb, 0xc4, 0xb9, 0xcc, 0x3b, 0x91, 0xe1, 0xfe, 0x94, 0xd3, 0xcb, 0x8e, 0x01, 0x6b, 0xf5, 0x48, 0xd1, 0xd8, 0xb2, 0x8b, 0xd8, 0x84, 0x7a, 0x1a, 0x57, 0xd1, 0x31, 0x8b, 0xd0, 0x95, 0x10}}, - {{0xa4, 0x18, 0x3b, 0xa4, 0x73, 0xda, 0x24, 0x4c, 0x1c, 0x4f, 0x6d, 0x88, 0x49, 0xad, 0x2f, 0x19, 0x9e, 0xfd, 0xb0, 0x29, 0x00, 0x22, 0xca, 0xb9, 0x61, 0x3f, 0x0e, 0x91, 0x8e, 0xcd, 0xc3, 0x23}, {0x5b, 0x99, 0x53, 0x0c, 0x2c, 0x7b, 0x6a, 0x44, 0xc6, 0xd6, 0x46, 0xf7, 0x82, 0x9e, 0x40, 0xf6, 0x46, 0xf0, 0x60, 0xd6, 0xa5, 0xf1, 0x9a, 0xd4, 0xda, 0xa7, 0xf7, 0xc8, 0x88, 0x66, 0x9f, 0x28}}, - {{0xea, 0x19, 0x69, 0xf4, 0x89, 0x2f, 0x22, 0x93, 0xaf, 0x41, 0x2f, 0xd5, 0x6d, 0xce, 0xca, 0x23, 0xec, 0xb7, 0xb5, 0xa0, 0x36, 0x00, 0x9f, 0x7b, 0xf8, 0x1b, 0xf7, 0x3a, 0xcc, 0x0e, 0xa9, 0x36}, {0x6e, 0xe9, 0xed, 0x2f, 0x5a, 0x4d, 0x78, 0xac, 0xa1, 0x48, 0xcc, 0xe5, 0xc2, 0x0e, 0xc7, 0x83, 0x88, 0x65, 0xbe, 0xda, 0xcd, 0x7a, 0x3c, 0x62, 0xc2, 0x55, 0x9f, 0x68, 0x3c, 0x4d, 0x2e, 0x26}}, - {{0x0e, 0x13, 0xdd, 0xd3, 0x3e, 0xb0, 0x8b, 0xc4, 0xc0, 0xc4, 0xe8, 0xe3, 0x8d, 0x66, 0xda, 0xc8, 0x78, 0x4d, 0x0e, 0x62, 0xfb, 0x8d, 0x96, 0x84, 0x07, 0x3a, 0x14, 0xef, 0x83, 0x8b, 0xd2, 0x21}, {0x2b, 0x51, 0x9f, 0x7c, 0xba, 0x41, 0x07, 0xa6, 0x8f, 0x04, 0x3f, 0xb2, 0x59, 0x6b, 0xaf, 0xe9, 0x6b, 0xdd, 0x97, 0x9a, 0xe3, 0xff, 0x9b, 0xb4, 0x7c, 0xe6, 0xb5, 0xea, 0x7a, 0xef, 0x3c, 0x07}}, - {{0x02, 0x5c, 0xef, 0x02, 0xbd, 0x2e, 0x8c, 0xbb, 0xe7, 0xd5, 0xa3, 0xa8, 0x6b, 0xfb, 0x3e, 0x9f, 0xfd, 0x7a, 0x24, 0x82, 0xd6, 0xaf, 0x5e, 0xdd, 0x49, 0x1d, 0xc2, 0x34, 0x96, 0x06, 0x4d, 0x0a}, {0x17, 0x21, 0x45, 0x74, 0x93, 0x26, 0x8b, 0xde, 0x75, 0x91, 0xc8, 0x9a, 0x13, 0x3e, 0x27, 0x88, 0x22, 0xce, 0xfa, 0x60, 0x11, 0x3f, 0x4d, 0xaf, 0xb0, 0xf5, 0x0c, 0x42, 0xde, 0xf7, 0x2e, 0x37}}, - {{0x4f, 0xad, 0x94, 0xe6, 0x71, 0x31, 0x7a, 0x00, 0x83, 0x64, 0x99, 0xb4, 0x43, 0x7d, 0x63, 0x0b, 0x1e, 0xe3, 0xd9, 0x71, 0xa4, 0xd9, 0x41, 0x3f, 0xe2, 0x5f, 0x67, 0xf7, 0x59, 0x41, 0x04, 0x23}, {0xc3, 0x22, 0xf0, 0x98, 0xd9, 0xd9, 0x89, 0xc6, 0xea, 0xf3, 0xef, 0x96, 0xa4, 0x04, 0x43, 0x38, 0x98, 0x96, 0x86, 0xa7, 0xfb, 0x07, 0xf7, 0xcd, 0x75, 0x10, 0xf3, 0x52, 0x52, 0xaa, 0xff, 0x00}}, - {{0x0c, 0xae, 0xbd, 0x3b, 0x50, 0x59, 0xed, 0xc7, 0xcf, 0xa8, 0x63, 0xf3, 0x4e, 0x0a, 0x71, 0x07, 0x22, 0x22, 0x24, 0x25, 0x1d, 0xa4, 0x54, 0xb8, 0xd1, 0xf7, 0x71, 0x8c, 0x98, 0xd9, 0x1c, 0x36}, {0x5e, 0xe8, 0x1d, 0xe3, 0xa8, 0xf5, 0xc3, 0xd1, 0xf5, 0x72, 0xed, 0xa2, 0xe1, 0x1f, 0xf9, 0x61, 0x6b, 0x7a, 0x42, 0xb4, 0x47, 0x30, 0x2a, 0xd0, 0x61, 0x7f, 0x0a, 0x14, 0xc8, 0x2a, 0xa9, 0x28}}, - {{0xef, 0x09, 0xdb, 0x68, 0xf5, 0x8f, 0x9b, 0xe6, 0x1d, 0x1b, 0xb6, 0x45, 0x84, 0xa8, 0x55, 0xa9, 0x37, 0x0a, 0xc0, 0x0b, 0xf8, 0x0f, 0x81, 0x01, 0x34, 0xb6, 0xa1, 0x2d, 0x87, 0x74, 0x77, 0x3f}, {0x9e, 0x11, 0x58, 0x5f, 0x97, 0x61, 0xfc, 0xba, 0x02, 0x4a, 0xcf, 0x94, 0x17, 0x68, 0xc8, 0x8e, 0x6b, 0x58, 0x61, 0xef, 0xf7, 0xb4, 0x9d, 0xf7, 0x32, 0xb3, 0xe9, 0xde, 0xff, 0x0e, 0xcb, 0x1e}}, - {{0x02, 0x6b, 0x9a, 0x5d, 0x51, 0x1b, 0x7c, 0x2e, 0x63, 0x5b, 0x41, 0xbc, 0xd9, 0x5e, 0xb8, 0x6d, 0xe1, 0x31, 0x78, 0xf2, 0x61, 0xc7, 0x61, 0x9e, 0xc5, 0x68, 0xe7, 0x1d, 0x07, 0x7f, 0x63, 0x1d}, {0xfc, 0xe8, 0x8a, 0xa8, 0x3b, 0x01, 0x95, 0xb6, 0xf5, 0x9b, 0x52, 0x56, 0x1a, 0x86, 0x87, 0x60, 0xd0, 0xc3, 0x9e, 0x44, 0xe2, 0x54, 0xe4, 0x37, 0xb1, 0xa6, 0x89, 0xa8, 0x34, 0xac, 0xf1, 0x32}}, - {{0x9d, 0x8f, 0xc8, 0x95, 0x79, 0xe9, 0xc6, 0x45, 0x11, 0x35, 0x4f, 0x36, 0xbd, 0x13, 0x77, 0x91, 0xec, 0x4c, 0x37, 0xf7, 0x8a, 0xd4, 0xb5, 0x18, 0xf3, 0x21, 0xbc, 0x82, 0xaa, 0x50, 0xcb, 0x1a}, {0x7c, 0x13, 0x73, 0x0e, 0x1e, 0xac, 0xb5, 0xa0, 0xdd, 0x33, 0x2a, 0x7c, 0x69, 0x3b, 0xcc, 0xe9, 0xb9, 0x46, 0x7f, 0x83, 0xd6, 0xfb, 0x43, 0x38, 0x22, 0xf0, 0xbd, 0xda, 0x07, 0xc3, 0xf2, 0x3a}}, - {{0xaf, 0x80, 0x85, 0xb1, 0x7d, 0x51, 0x20, 0xf3, 0xfa, 0xae, 0xb8, 0xda, 0x5d, 0x76, 0xe4, 0x4e, 0xec, 0x34, 0x2c, 0xcb, 0xc8, 0x9e, 0x87, 0x6b, 0xa7, 0x9a, 0x2c, 0xd0, 0x61, 0x0e, 0x04, 0x18}, {0xd5, 0x44, 0x66, 0xca, 0x31, 0x9a, 0x99, 0x77, 0x37, 0x8c, 0x52, 0xdf, 0xbb, 0x40, 0x57, 0x5c, 0xc2, 0x5c, 0x73, 0x99, 0x5b, 0xfa, 0x6f, 0x3c, 0xb2, 0x02, 0xe3, 0x2d, 0xcb, 0x7f, 0x42, 0x2d}}, - {{0x14, 0xd3, 0x8b, 0x24, 0x4e, 0x1f, 0x02, 0xb7, 0x6f, 0xfc, 0x77, 0x1e, 0x7d, 0xd4, 0xa6, 0x45, 0xb3, 0xc0, 0x47, 0x94, 0x7e, 0x17, 0xde, 0x71, 0x95, 0x82, 0x81, 0xfc, 0x8e, 0x6f, 0x36, 0x2c}, {0xbe, 0x59, 0xf7, 0x3e, 0x1c, 0x64, 0x17, 0xd4, 0xea, 0x27, 0x6d, 0x37, 0x93, 0xa4, 0xf0, 0x46, 0x94, 0x3e, 0x98, 0xa3, 0xf3, 0x89, 0x58, 0xcc, 0x0c, 0x6a, 0x24, 0x95, 0x04, 0x82, 0xca, 0x24}}, - {{0x2d, 0x02, 0xf9, 0xfd, 0xa1, 0x08, 0x41, 0x4d, 0x2a, 0xab, 0x38, 0xff, 0xf6, 0xc1, 0x5b, 0x44, 0xcd, 0x67, 0xc5, 0x08, 0x8f, 0x46, 0x34, 0x2c, 0xfb, 0xf2, 0x05, 0xb0, 0x4e, 0x22, 0xc9, 0x27}, {0x58, 0x58, 0xd8, 0x3a, 0x86, 0xe3, 0x7f, 0xb6, 0xe0, 0x0a, 0x70, 0x32, 0xc1, 0x89, 0xe7, 0x35, 0xc2, 0x72, 0x9c, 0xbe, 0x8e, 0xea, 0x43, 0xaf, 0x42, 0x01, 0x93, 0xa5, 0x7b, 0xb9, 0xff, 0x35}}, - {{0xea, 0xad, 0x3e, 0xfa, 0x77, 0x9c, 0x9c, 0x67, 0xdd, 0xe9, 0x59, 0xc1, 0x7e, 0x61, 0x0c, 0x05, 0x53, 0x5d, 0x9e, 0x27, 0x0b, 0xad, 0xd0, 0xe4, 0xd0, 0xd2, 0xca, 0xac, 0xa7, 0x85, 0x13, 0x1c}, {0x9e, 0xf9, 0xd8, 0x76, 0x8c, 0x75, 0x05, 0xa6, 0x09, 0xc1, 0x3e, 0x23, 0xb6, 0x09, 0x5c, 0x24, 0x4f, 0xc9, 0xde, 0xfa, 0x3f, 0x12, 0x51, 0x99, 0x9e, 0xdb, 0x1a, 0xe1, 0x32, 0xcb, 0x06, 0x0e}}, - {{0xa1, 0xe3, 0xfa, 0x97, 0x46, 0xc6, 0xa6, 0xdd, 0xbc, 0xd2, 0xb9, 0x51, 0x80, 0x3e, 0xf4, 0x57, 0x5d, 0x45, 0xfa, 0x2b, 0x26, 0x16, 0xac, 0x05, 0xea, 0xb4, 0x6d, 0xc4, 0x14, 0xb2, 0xe6, 0x27}, {0xe4, 0xca, 0x65, 0x72, 0x24, 0x39, 0xdf, 0xe0, 0x5b, 0x7a, 0xd4, 0xc3, 0xb2, 0x1e, 0xc0, 0x09, 0x3c, 0xdc, 0x18, 0xa7, 0xdd, 0xd6, 0x07, 0x4b, 0x80, 0xd6, 0xa4, 0x16, 0xb1, 0xe6, 0x6e, 0x04}}, - {{0xfb, 0x93, 0x84, 0x0d, 0x4a, 0x88, 0x27, 0x88, 0x25, 0x2a, 0xe5, 0x17, 0xbe, 0xd4, 0x41, 0xb6, 0xe5, 0xf1, 0x13, 0xca, 0x5e, 0xd6, 0xbb, 0xd1, 0xb7, 0xf9, 0xbd, 0x9d, 0x75, 0x83, 0xe6, 0x14}, {0xd6, 0x09, 0x3e, 0x04, 0xf2, 0x27, 0xbc, 0xc5, 0xbc, 0x18, 0x0d, 0x74, 0xd8, 0x1b, 0x83, 0x43, 0x6c, 0x64, 0x51, 0xdb, 0x51, 0xb9, 0x28, 0x4d, 0x06, 0x41, 0x35, 0xae, 0x5c, 0x92, 0xf2, 0x2f}}, - {{0x65, 0xc0, 0x09, 0xa8, 0xea, 0xb8, 0xab, 0xd2, 0xf7, 0x42, 0x58, 0xd5, 0x4f, 0x4c, 0x26, 0xa5, 0x6a, 0x68, 0xed, 0x52, 0x33, 0x68, 0xbd, 0x36, 0x8e, 0x02, 0xd9, 0xa2, 0x20, 0xa1, 0x03, 0x3e}, {0xff, 0xbc, 0x64, 0x2b, 0xa2, 0x15, 0xcd, 0xad, 0x4e, 0x1d, 0x41, 0xfa, 0xcf, 0xfb, 0x41, 0x8b, 0x18, 0x17, 0xc4, 0xaa, 0x29, 0xe7, 0x75, 0x62, 0xca, 0x76, 0x28, 0xa5, 0xdd, 0xd1, 0xf4, 0x05}}, - {{0x92, 0x42, 0x18, 0xdb, 0xdf, 0x45, 0x9f, 0x25, 0xa2, 0x88, 0x27, 0xbd, 0x21, 0x9f, 0xa3, 0x85, 0x69, 0xa4, 0x2b, 0x9d, 0x50, 0xd0, 0x41, 0x77, 0xaf, 0x7c, 0xd3, 0xfa, 0x8a, 0xe4, 0x28, 0x36}, {0xd4, 0xed, 0xc2, 0x52, 0x09, 0xa5, 0x8c, 0xf3, 0x4f, 0x96, 0x5d, 0xfa, 0xce, 0x3d, 0xc8, 0xdb, 0x0d, 0xdc, 0x4a, 0x70, 0x58, 0x13, 0xe5, 0x67, 0x2a, 0xb7, 0x72, 0x77, 0x7f, 0x03, 0xd7, 0x2d}}, - {{0x57, 0x3d, 0xbb, 0x92, 0xbd, 0x38, 0x93, 0xde, 0x41, 0x94, 0x60, 0xc8, 0x38, 0x72, 0x4b, 0x94, 0x55, 0x42, 0xeb, 0x6c, 0xc0, 0x5b, 0x3d, 0xe0, 0x43, 0xbe, 0x03, 0x16, 0xf6, 0x0b, 0x89, 0x28}, {0xc4, 0x91, 0x5b, 0xff, 0xbe, 0xdf, 0x8d, 0x59, 0xd8, 0x66, 0x40, 0xb0, 0x24, 0x7d, 0x17, 0x90, 0x92, 0x95, 0x62, 0xca, 0xaa, 0x24, 0xfe, 0x29, 0x5d, 0xee, 0x0f, 0xd0, 0x6d, 0xb5, 0x1b, 0x0e}}, - {{0xc3, 0xa2, 0x31, 0xcd, 0xd9, 0xb1, 0xf2, 0x80, 0x2b, 0xe8, 0x64, 0x53, 0x34, 0x81, 0xca, 0xfe, 0x26, 0x78, 0x86, 0x47, 0x05, 0x84, 0x7e, 0x66, 0x04, 0x24, 0xcc, 0xdf, 0xa5, 0x2a, 0x6a, 0x19}, {0x22, 0x7b, 0xcb, 0x50, 0x4e, 0xea, 0xf2, 0x44, 0x87, 0x25, 0x2b, 0x84, 0xa9, 0xac, 0x03, 0xa2, 0x7d, 0x48, 0x3f, 0xe0, 0x5e, 0x52, 0x3f, 0x9c, 0xc8, 0x36, 0x24, 0xd6, 0xc6, 0x0f, 0xbb, 0x1d}}, - {{0xa7, 0x2e, 0x26, 0x17, 0x1d, 0xf8, 0xf8, 0xd9, 0xbc, 0x8b, 0xba, 0x3e, 0x8d, 0x21, 0xc2, 0x48, 0xeb, 0xab, 0x2a, 0x90, 0xc9, 0xac, 0x31, 0x6a, 0x82, 0x93, 0xc6, 0xc6, 0x57, 0xbe, 0x86, 0x10}, {0xb0, 0x3f, 0x38, 0x44, 0xee, 0xc4, 0x21, 0x9b, 0x13, 0x71, 0xc6, 0xd2, 0x7c, 0x18, 0xbb, 0xff, 0xf9, 0x9d, 0x9c, 0x0d, 0xa0, 0x86, 0xdf, 0xbb, 0x39, 0xef, 0x15, 0x69, 0xbd, 0x0d, 0x00, 0x19}}, - {{0x83, 0xf0, 0x50, 0x71, 0xa1, 0xe6, 0x7e, 0xb8, 0x4c, 0xbb, 0xca, 0xc7, 0x2a, 0x17, 0xd3, 0x1d, 0xa7, 0x2a, 0x53, 0x75, 0x85, 0x60, 0x0d, 0x45, 0xa9, 0xbe, 0xea, 0xa4, 0xf5, 0x4a, 0x87, 0x0e}, {0xf0, 0xbd, 0x39, 0x6a, 0x05, 0x30, 0xd9, 0x27, 0x75, 0x24, 0xac, 0xfa, 0x8f, 0xea, 0xfc, 0xaf, 0xd1, 0x26, 0x1e, 0xac, 0x2b, 0xf9, 0xce, 0x27, 0x55, 0xe8, 0xf2, 0x93, 0xf2, 0xec, 0xce, 0x1d}}, - {{0xa6, 0xb6, 0x7c, 0xf6, 0x24, 0xf1, 0x32, 0xec, 0xc7, 0x6f, 0x04, 0xbb, 0xa9, 0xc0, 0x6f, 0xe7, 0x4b, 0x9d, 0x69, 0xa8, 0xb9, 0x2f, 0xc9, 0x08, 0x19, 0x1f, 0x13, 0x36, 0xca, 0xf0, 0xa4, 0x0a}, {0x8c, 0x29, 0xf9, 0xf5, 0x3a, 0x38, 0x7a, 0xc7, 0x6a, 0x7a, 0x61, 0x8f, 0x57, 0x0c, 0x2a, 0x6c, 0x23, 0x57, 0x69, 0x87, 0xf4, 0x83, 0xfb, 0xa8, 0x74, 0x7d, 0xb1, 0x2f, 0x38, 0x93, 0xac, 0x0d}}, - {{0xaf, 0xf7, 0xd7, 0x9b, 0x26, 0xed, 0xae, 0xa4, 0x65, 0x81, 0x79, 0xbe, 0x90, 0x55, 0x45, 0xcf, 0x02, 0xba, 0x07, 0xca, 0xc2, 0xa5, 0x66, 0xbb, 0x3b, 0x2f, 0xe0, 0x33, 0xfb, 0x97, 0x71, 0x2f}, {0xff, 0x55, 0xdc, 0x26, 0x79, 0xfa, 0xf5, 0xc6, 0x75, 0xb8, 0x2c, 0x79, 0x00, 0x1d, 0xd7, 0xb1, 0x81, 0xfc, 0x4b, 0xb3, 0x82, 0x1b, 0x00, 0x43, 0xff, 0x35, 0x9d, 0x24, 0xf9, 0x89, 0x85, 0x25}}, - {{0x26, 0xc3, 0xea, 0x84, 0x54, 0x69, 0x86, 0xca, 0x8f, 0x52, 0x05, 0x76, 0x54, 0xb4, 0xd8, 0x64, 0x14, 0x69, 0xc8, 0xf1, 0x98, 0x13, 0xa1, 0x47, 0x96, 0x8b, 0x94, 0x66, 0x33, 0xf3, 0x26, 0x06}, {0x1a, 0xac, 0xdf, 0x8c, 0x95, 0xc6, 0x9a, 0xcb, 0x56, 0x5a, 0x8c, 0xf2, 0x5d, 0x39, 0xa2, 0x51, 0x62, 0x87, 0x43, 0x01, 0x7a, 0x99, 0x82, 0x29, 0xea, 0xcd, 0x87, 0xe5, 0x34, 0x36, 0xa0, 0x20}}, - {{0x87, 0xaf, 0x6a, 0xad, 0x15, 0x38, 0x22, 0x4a, 0x14, 0xf1, 0x51, 0xfe, 0x39, 0xc2, 0x3d, 0xb2, 0xf9, 0x71, 0x76, 0x1d, 0xbc, 0x6f, 0x44, 0xe7, 0x41, 0x62, 0x77, 0xf2, 0xc4, 0xb3, 0x8f, 0x00}, {0xe1, 0x2b, 0xcf, 0x38, 0xbc, 0xff, 0x35, 0xef, 0x2a, 0x15, 0x4b, 0x6e, 0x67, 0x10, 0x06, 0x64, 0xca, 0x55, 0x43, 0xf7, 0x65, 0x1b, 0x39, 0xcd, 0xc4, 0x2d, 0xaa, 0x8f, 0x54, 0xac, 0xa9, 0x33}}, - {{0x1a, 0xac, 0xb7, 0x16, 0x60, 0x61, 0x3e, 0xb4, 0xbe, 0xdb, 0xdd, 0x33, 0xfa, 0x45, 0x17, 0x2d, 0x96, 0xb9, 0x8c, 0x15, 0xdc, 0xc7, 0xf2, 0xfc, 0xda, 0x41, 0xf5, 0x22, 0xb4, 0xd6, 0x2d, 0x22}, {0x71, 0x19, 0x9a, 0x6b, 0xb6, 0x8e, 0x5f, 0xd1, 0x8c, 0xde, 0x76, 0x8b, 0x37, 0xb4, 0x5e, 0x73, 0x2f, 0xcb, 0x1c, 0xe2, 0x09, 0xfd, 0x9e, 0x7a, 0xe3, 0x47, 0xd0, 0x36, 0x91, 0x68, 0x05, 0x26}}, - {{0x27, 0x0c, 0x7d, 0xb2, 0x0e, 0x67, 0x28, 0xa7, 0xf4, 0x09, 0x6e, 0xd8, 0x9b, 0x85, 0xfa, 0x0f, 0x3e, 0x1d, 0xca, 0x5b, 0xdd, 0x1d, 0x12, 0xfc, 0x15, 0x39, 0x70, 0x92, 0xac, 0xf5, 0xd5, 0x3e}, {0xb5, 0x9e, 0xb0, 0xf3, 0x9c, 0xad, 0x66, 0x2d, 0x3f, 0x49, 0x75, 0x39, 0x1b, 0x4a, 0x76, 0x0f, 0xe4, 0x80, 0x6c, 0xde, 0x39, 0x7d, 0x1c, 0x31, 0x61, 0x21, 0x8e, 0x53, 0x10, 0xa9, 0xc5, 0x10}}, - {{0x9e, 0x44, 0xfe, 0x08, 0x55, 0x2e, 0xef, 0xd8, 0xdc, 0x21, 0x38, 0x9b, 0xb4, 0xf0, 0x95, 0x97, 0x92, 0xff, 0x56, 0x19, 0x59, 0x33, 0x6d, 0x43, 0x2f, 0x56, 0x67, 0xff, 0xa1, 0xc2, 0xf0, 0x2e}, {0x2c, 0x25, 0x96, 0x23, 0xc0, 0x5a, 0x61, 0xea, 0xec, 0xf4, 0x8f, 0x24, 0x72, 0xe5, 0xc3, 0xd3, 0xf8, 0x15, 0xef, 0x35, 0x93, 0x51, 0x91, 0x08, 0x53, 0xd0, 0x09, 0xc5, 0xdf, 0x7d, 0x0b, 0x0e}}, - {{0xd1, 0x3a, 0x9b, 0x52, 0x75, 0x74, 0x5f, 0x59, 0x1a, 0xef, 0x14, 0xe1, 0xa2, 0x93, 0x02, 0xc2, 0xf2, 0x03, 0x87, 0x4b, 0x31, 0x79, 0x18, 0xa3, 0x31, 0x81, 0xdf, 0x56, 0xfe, 0xde, 0xb5, 0x25}, {0x9a, 0xc8, 0x75, 0xce, 0x3d, 0x68, 0x07, 0x32, 0x3e, 0x6a, 0x66, 0xee, 0xcc, 0x95, 0xa3, 0x0a, 0x63, 0x3a, 0x70, 0xdb, 0x4b, 0x0d, 0x75, 0x1d, 0xf2, 0x50, 0x5d, 0x6d, 0x14, 0x8c, 0xa8, 0x21}}, - {{0xd0, 0x54, 0x44, 0xfe, 0x57, 0xa1, 0xa0, 0xf1, 0x48, 0x8e, 0xa1, 0xb9, 0x83, 0xea, 0x8f, 0xe5, 0x75, 0xbd, 0x21, 0xb3, 0xbe, 0x1e, 0x5f, 0xe7, 0x99, 0xeb, 0x3d, 0x26, 0xe1, 0xcd, 0xf0, 0x2f}, {0x8b, 0xd5, 0x71, 0x38, 0xcb, 0x13, 0xad, 0x78, 0x15, 0x4a, 0xdf, 0xde, 0x0a, 0xf9, 0x0b, 0xd7, 0x55, 0x18, 0x86, 0x4a, 0x9b, 0x46, 0x59, 0xce, 0xb3, 0xf8, 0xb0, 0xd8, 0xf2, 0xb9, 0xd0, 0x07}}, - {{0x60, 0x81, 0x94, 0x3d, 0xc8, 0x5f, 0x86, 0x11, 0xac, 0xf8, 0x9d, 0x7d, 0xf6, 0xcd, 0x33, 0xef, 0x16, 0x08, 0x87, 0x1b, 0x1f, 0xc8, 0xfe, 0x77, 0x08, 0xf2, 0xbc, 0x81, 0x8e, 0x5c, 0xe4, 0x33}, {0x39, 0x80, 0x8f, 0x5f, 0x7d, 0xf5, 0x9c, 0xa7, 0x8d, 0x1e, 0x2f, 0x18, 0xab, 0xdb, 0xbd, 0x46, 0x1b, 0x2d, 0xe6, 0xc3, 0x62, 0x1e, 0x1e, 0x12, 0x6b, 0x12, 0x08, 0x7a, 0x26, 0x86, 0xab, 0x2a}}, - {{0x26, 0x4e, 0x57, 0x92, 0x4e, 0x5f, 0x09, 0x73, 0xab, 0xd0, 0xc6, 0x65, 0xc5, 0x92, 0x0a, 0x80, 0x3e, 0xdf, 0x33, 0x8c, 0x96, 0x73, 0x9b, 0x95, 0x6e, 0x66, 0x9a, 0xdb, 0xbc, 0x0a, 0x12, 0x17}, {0xa4, 0xdd, 0xbf, 0xdc, 0x71, 0xdb, 0xce, 0xa4, 0x25, 0x71, 0x45, 0xcc, 0x12, 0xbb, 0xa9, 0x23, 0x12, 0x50, 0x44, 0x50, 0x98, 0x65, 0x84, 0x49, 0x1a, 0x15, 0x2d, 0x45, 0x23, 0xa8, 0xb9, 0x15}}, - {{0xb3, 0x37, 0xf8, 0xd4, 0xc9, 0x58, 0x81, 0x18, 0xbf, 0xd4, 0xea, 0x12, 0x3a, 0xf5, 0xe1, 0x35, 0x72, 0x96, 0x05, 0x71, 0x80, 0x10, 0xb0, 0x43, 0xf4, 0xaf, 0xae, 0xf6, 0x18, 0xbb, 0xa1, 0x12}, {0xff, 0xae, 0x05, 0x64, 0x8c, 0x3a, 0xc9, 0xd0, 0x68, 0xb8, 0xed, 0x21, 0x4b, 0xdb, 0x79, 0x7c, 0x0d, 0x58, 0x85, 0x32, 0x4d, 0xab, 0x64, 0xfe, 0xd6, 0x4a, 0x96, 0x4e, 0x9b, 0x6e, 0xf2, 0x21}}, - {{0xbe, 0x93, 0xbc, 0xd8, 0x27, 0x74, 0xad, 0x5e, 0x10, 0xdc, 0x40, 0xa2, 0x9b, 0xdf, 0x74, 0x10, 0x75, 0xe4, 0x83, 0xb8, 0x58, 0xf4, 0x02, 0x5e, 0xba, 0x48, 0x71, 0x1a, 0x88, 0x94, 0x58, 0x16}, {0x93, 0xe4, 0xb6, 0x30, 0xa3, 0xd6, 0x20, 0xcf, 0xca, 0xb5, 0x2a, 0x3e, 0x5b, 0xfc, 0x50, 0xc0, 0x4d, 0x4b, 0x1c, 0x52, 0x64, 0xca, 0xd1, 0xca, 0xa9, 0x4d, 0xa9, 0x4f, 0xeb, 0x99, 0x9b, 0x2d}}, - {{0xc0, 0x1f, 0xab, 0x20, 0x52, 0x9e, 0x05, 0xbf, 0x3a, 0x0e, 0x1e, 0x8a, 0x2b, 0x61, 0x7d, 0x8a, 0x8c, 0xb3, 0xcd, 0xf4, 0x44, 0x42, 0xde, 0xea, 0xf2, 0x54, 0x24, 0x81, 0x8e, 0x7f, 0x31, 0x33}, {0x5e, 0x4c, 0x93, 0x05, 0x91, 0x9b, 0x88, 0xc8, 0xf6, 0x97, 0x7c, 0x0a, 0x0e, 0xc7, 0x69, 0xe5, 0xf4, 0x48, 0x91, 0xf8, 0xc8, 0xb9, 0xd5, 0x44, 0x2f, 0xc7, 0xf5, 0x68, 0x5b, 0x5a, 0x12, 0x23}}, - {{0x28, 0x14, 0xa6, 0xf2, 0x9b, 0xbf, 0xe4, 0x94, 0x10, 0xf3, 0x89, 0xdf, 0x68, 0x57, 0x90, 0xa5, 0x48, 0xbf, 0xd7, 0xe6, 0xc4, 0xea, 0x26, 0x5f, 0xef, 0x42, 0x31, 0x3a, 0x61, 0x84, 0x77, 0x17}, {0x44, 0xe9, 0xa9, 0x01, 0x3d, 0xa9, 0xc5, 0xd4, 0xb4, 0x1a, 0x82, 0xf3, 0xb3, 0x0b, 0xf3, 0x00, 0x5c, 0x11, 0x01, 0x90, 0x5e, 0xb0, 0x30, 0x3e, 0x01, 0xd5, 0x62, 0x0d, 0x7d, 0x86, 0xaa, 0x13}}, - {{0x84, 0x68, 0xd5, 0x83, 0xe6, 0x6e, 0x77, 0x0d, 0xad, 0x7f, 0xb0, 0x0c, 0x33, 0x31, 0x90, 0xc6, 0xac, 0xb6, 0x3c, 0xd8, 0x71, 0xfa, 0xf9, 0x03, 0x4e, 0x2e, 0xf2, 0x69, 0x3f, 0x2c, 0x5b, 0x38}, {0x9c, 0x47, 0x26, 0xf9, 0x77, 0xda, 0x2a, 0xe5, 0xd5, 0xf7, 0xf9, 0xa3, 0xdd, 0x18, 0x32, 0x40, 0x63, 0x3b, 0xe0, 0x0f, 0x67, 0xca, 0x8a, 0x69, 0x73, 0x0d, 0xa9, 0x45, 0x6f, 0xe4, 0xe6, 0x1b}}, - {{0xf3, 0x23, 0x4c, 0xb3, 0x88, 0x24, 0x4f, 0xb5, 0x6c, 0x55, 0xf3, 0xdc, 0x0f, 0x4d, 0xf7, 0x20, 0x83, 0x51, 0xca, 0x87, 0x6b, 0xc4, 0x29, 0xb6, 0x7d, 0x4d, 0xe5, 0x97, 0x07, 0x1b, 0x05, 0x3e}, {0xa9, 0xc4, 0xf4, 0xa7, 0x6b, 0xdf, 0x45, 0x28, 0x12, 0x32, 0xc5, 0xef, 0xb3, 0x7b, 0xd8, 0x01, 0xeb, 0x68, 0xc3, 0xf0, 0x6f, 0x84, 0x38, 0x74, 0x3e, 0x78, 0x68, 0x95, 0xcd, 0x4c, 0x4c, 0x05}}, - {{0x1e, 0x60, 0xf2, 0xed, 0x41, 0x2b, 0x03, 0x0e, 0xab, 0xa1, 0x56, 0x26, 0x80, 0x63, 0x56, 0xca, 0xba, 0x4a, 0x36, 0x5b, 0xf4, 0x73, 0xc1, 0xa9, 0xc7, 0x98, 0xfe, 0x76, 0xa4, 0xf6, 0x0b, 0x37}, {0xc8, 0x23, 0x73, 0x70, 0xc8, 0xb9, 0x3a, 0xe8, 0x63, 0xe4, 0x2c, 0x92, 0xfc, 0x12, 0xcb, 0x68, 0x1d, 0xcd, 0xe2, 0xaa, 0xa7, 0xcb, 0x58, 0x1d, 0xac, 0x85, 0x73, 0xd7, 0xbe, 0xdc, 0x41, 0x16}}, - {{0xb1, 0x8c, 0x86, 0x07, 0xb2, 0x50, 0xd9, 0x33, 0x81, 0x18, 0xb0, 0x79, 0x24, 0x4d, 0x46, 0x55, 0xcf, 0xe7, 0xb3, 0x70, 0x63, 0xae, 0xf8, 0xce, 0x9f, 0xdf, 0x54, 0x56, 0x6f, 0x0d, 0xdd, 0x1e}, {0x7d, 0x6d, 0xf8, 0x3b, 0xd2, 0x5f, 0x19, 0xca, 0x87, 0x0c, 0x1d, 0x48, 0x8b, 0x77, 0x88, 0xd8, 0x04, 0xa0, 0x9c, 0x9a, 0xb6, 0x4c, 0x18, 0x77, 0x85, 0x17, 0x39, 0xc5, 0x22, 0x84, 0xcd, 0x18}}, - {{0xa9, 0x38, 0x40, 0x3c, 0x1d, 0x06, 0xd0, 0xd3, 0x7d, 0x33, 0x3a, 0xb3, 0x6f, 0xba, 0xd2, 0x35, 0x8c, 0x8c, 0x48, 0xa0, 0xd0, 0xcc, 0x5a, 0x2b, 0xc8, 0x55, 0xf0, 0x70, 0xf9, 0x51, 0x77, 0x31}, {0x44, 0xcf, 0xdc, 0xe5, 0x46, 0x2d, 0xa0, 0x7d, 0x87, 0xac, 0xfd, 0x00, 0x04, 0x72, 0x48, 0x19, 0xed, 0x09, 0x52, 0x79, 0x05, 0x2f, 0x5d, 0xd3, 0xae, 0x40, 0xd4, 0x8f, 0xe4, 0x66, 0x7b, 0x06}}, - {{0x19, 0x62, 0x3b, 0xc5, 0xc1, 0xf5, 0x67, 0xbe, 0x41, 0x51, 0xdc, 0x49, 0xeb, 0xd3, 0x4d, 0x0c, 0x72, 0xdc, 0x3d, 0xc8, 0x06, 0x6e, 0x85, 0x19, 0x9d, 0xf3, 0x60, 0x6c, 0x34, 0x4e, 0x80, 0x05}, {0xca, 0x2e, 0x4e, 0xe8, 0xf8, 0xb5, 0x70, 0xd9, 0x0a, 0x0b, 0xaa, 0x6f, 0xe7, 0xba, 0xee, 0x8d, 0xdd, 0xcf, 0x75, 0x4c, 0x0d, 0x46, 0x36, 0xce, 0xff, 0xc2, 0xb6, 0x4e, 0xa8, 0x30, 0x0b, 0x0c}}, - {{0x37, 0xf3, 0xda, 0x85, 0xb4, 0xb3, 0x11, 0xd2, 0x9b, 0x8b, 0x76, 0xd1, 0xc9, 0xc1, 0xaf, 0x7c, 0x91, 0x66, 0xa0, 0x6a, 0x08, 0x6d, 0x29, 0x4f, 0x50, 0xe4, 0x6e, 0x39, 0x56, 0x17, 0x69, 0x14}, {0x18, 0x93, 0xb7, 0x6c, 0xbe, 0x5e, 0x8c, 0x90, 0x93, 0x19, 0x7a, 0x8a, 0x3c, 0x12, 0x5e, 0x48, 0x4d, 0x54, 0x30, 0xdc, 0x97, 0x82, 0x9c, 0xba, 0x9f, 0x57, 0xad, 0x67, 0xc8, 0xb3, 0x1b, 0x0b}}, - {{0x38, 0x8e, 0x89, 0x9c, 0x6a, 0x12, 0xbb, 0xfd, 0x6a, 0xe1, 0xc7, 0x24, 0xe3, 0xb9, 0xb0, 0xee, 0x76, 0x39, 0xbd, 0xa4, 0x9b, 0x64, 0x63, 0x2a, 0x67, 0x2e, 0xcf, 0x38, 0xe3, 0x8a, 0xbe, 0x2c}, {0x10, 0xdf, 0x87, 0x42, 0x97, 0xe2, 0xc8, 0x02, 0x36, 0x5e, 0xcb, 0xff, 0x3a, 0x30, 0x4b, 0xfd, 0x80, 0x26, 0xc2, 0x99, 0x64, 0x5d, 0x24, 0xfe, 0x42, 0x09, 0x6a, 0xac, 0x03, 0xf0, 0xd4, 0x2a}}, - {{0x2e, 0x47, 0xf2, 0x5c, 0xe4, 0x45, 0x66, 0x63, 0xf3, 0x06, 0x70, 0x8c, 0x20, 0xfa, 0x1b, 0x58, 0xb6, 0x53, 0x8c, 0xa6, 0x2f, 0xfc, 0x42, 0x7f, 0x85, 0x3e, 0x96, 0xa5, 0x59, 0x5c, 0x5f, 0x3e}, {0x98, 0x74, 0x95, 0x17, 0xd7, 0x7c, 0xae, 0x3f, 0xcd, 0x17, 0x0f, 0x33, 0x0d, 0xf7, 0x97, 0x18, 0x24, 0x96, 0xbe, 0x93, 0xa8, 0xc4, 0xbc, 0x08, 0x96, 0x11, 0x0a, 0x88, 0x70, 0x5a, 0xb6, 0x16}}, - {{0x00, 0x64, 0xfa, 0x6c, 0x4e, 0xa3, 0xb8, 0xec, 0x69, 0xb0, 0x37, 0x17, 0x8d, 0xa6, 0x2b, 0x87, 0xd6, 0x00, 0x30, 0x4d, 0x56, 0x8b, 0x2b, 0x69, 0xf7, 0x28, 0xbd, 0xc2, 0x32, 0x6b, 0xc8, 0x1a}, {0xb6, 0xec, 0xb8, 0x4a, 0xd7, 0x73, 0x15, 0xcd, 0x59, 0x89, 0x6f, 0xd0, 0x56, 0xd4, 0xd8, 0x10, 0xa6, 0xa6, 0xb8, 0x40, 0xdb, 0x94, 0xd7, 0xc4, 0xe8, 0x01, 0x22, 0xf6, 0x05, 0x14, 0xc4, 0x0f}}, - {{0x29, 0xcc, 0x86, 0xfb, 0x21, 0x4e, 0x3c, 0xb1, 0x41, 0xa8, 0x0b, 0x22, 0x56, 0x22, 0xd4, 0x6d, 0xf6, 0x44, 0x09, 0x91, 0x57, 0xd3, 0x5d, 0x48, 0x36, 0x62, 0x5c, 0xe8, 0xf3, 0x37, 0xe6, 0x13}, {0x20, 0x25, 0x95, 0xd1, 0xd6, 0xd2, 0x3e, 0x39, 0xd9, 0x41, 0x4d, 0x7d, 0xe0, 0x20, 0x14, 0x87, 0xa0, 0xd5, 0x4d, 0x1b, 0xc9, 0xe4, 0x97, 0x4f, 0x99, 0x79, 0x56, 0x93, 0x26, 0x6e, 0xe1, 0x0e}}, - {{0xc4, 0x78, 0x7f, 0xb6, 0x18, 0xe8, 0xf0, 0x18, 0xd7, 0x52, 0xfe, 0x5c, 0x76, 0x82, 0x8e, 0xc7, 0x49, 0x52, 0x72, 0x33, 0x8e, 0x10, 0x29, 0x10, 0xbb, 0x15, 0x32, 0x3e, 0x9f, 0x77, 0xe7, 0x1c}, {0xef, 0x7d, 0xf4, 0x69, 0x79, 0x2c, 0x3c, 0x0a, 0x77, 0xb2, 0x0a, 0xc1, 0xd3, 0x5b, 0x4a, 0x92, 0xde, 0x00, 0xda, 0x3f, 0x02, 0x51, 0x84, 0xa6, 0x1e, 0x35, 0x86, 0x8b, 0x7f, 0xc6, 0x48, 0x28}}, - {{0x19, 0x0a, 0xf4, 0x6e, 0x70, 0x00, 0x5a, 0x78, 0x0c, 0x45, 0x79, 0x1e, 0x6d, 0xe1, 0x9e, 0xfc, 0x31, 0xee, 0x13, 0x8f, 0x13, 0xbe, 0xb0, 0x21, 0x15, 0xe5, 0x30, 0xeb, 0x79, 0x6e, 0x5a, 0x20}, {0x92, 0xff, 0xcd, 0x54, 0x36, 0x7b, 0x9b, 0x10, 0x64, 0xd6, 0x44, 0xbb, 0x76, 0xfd, 0x19, 0xe2, 0xd4, 0xcf, 0xc6, 0xa4, 0xf5, 0x47, 0xdc, 0x26, 0x73, 0x8e, 0x38, 0x96, 0x22, 0x00, 0x96, 0x13}}, - {{0x0a, 0x7e, 0xdb, 0xde, 0xe3, 0xee, 0x4f, 0x28, 0x34, 0x86, 0x74, 0xab, 0xd6, 0xd6, 0xa3, 0xeb, 0xb3, 0x88, 0x87, 0x73, 0x3e, 0x13, 0x6d, 0x20, 0xd2, 0x67, 0x19, 0x08, 0x44, 0x94, 0xe2, 0x06}, {0x26, 0xfa, 0x5d, 0xdd, 0x45, 0x77, 0xf2, 0x32, 0x7e, 0x6c, 0x1d, 0x43, 0x69, 0xff, 0xb9, 0x61, 0xdd, 0xec, 0x68, 0xd8, 0x81, 0xc3, 0x5e, 0x7b, 0x8e, 0x99, 0x1f, 0x1b, 0x42, 0xb4, 0x6d, 0x39}}, - {{0x5a, 0x43, 0xb3, 0x09, 0x25, 0x29, 0x9f, 0xf0, 0x89, 0x62, 0x0e, 0x70, 0x72, 0x7f, 0xd8, 0x5d, 0xe7, 0xe4, 0x27, 0x30, 0x6b, 0x03, 0x8f, 0x42, 0xc2, 0xc4, 0x2a, 0x85, 0xab, 0x38, 0xa1, 0x3b}, {0xc9, 0x63, 0xa6, 0xe3, 0xf7, 0x6e, 0xeb, 0x31, 0xef, 0x5e, 0x2a, 0x22, 0x19, 0xa5, 0xfb, 0x66, 0x2d, 0x5f, 0xa5, 0xd9, 0x85, 0xea, 0x56, 0xf0, 0x7b, 0xaf, 0xc7, 0x42, 0x6e, 0x1a, 0x9d, 0x0f}}, - {{0x4d, 0x5c, 0x7d, 0x5a, 0x0f, 0xb6, 0xd8, 0x2e, 0xd4, 0x0b, 0x2b, 0xbb, 0x81, 0xec, 0x41, 0x3c, 0x57, 0xcc, 0xd3, 0xcf, 0xc1, 0x51, 0x62, 0x51, 0x7a, 0x25, 0x92, 0x84, 0x47, 0xf8, 0x28, 0x16}, {0xd2, 0x3a, 0x49, 0xdf, 0xa0, 0xde, 0x28, 0x10, 0x5d, 0x1f, 0xba, 0x54, 0xe0, 0x8e, 0x64, 0x9f, 0x71, 0x50, 0x4b, 0x33, 0xa6, 0x00, 0xc3, 0xa5, 0xcb, 0x8d, 0x9d, 0x4c, 0x47, 0xd6, 0xec, 0x22}}, - {{0xc9, 0xb4, 0x18, 0xa6, 0x4f, 0x88, 0x78, 0xba, 0xde, 0xb8, 0x1c, 0xef, 0xbd, 0xcf, 0x90, 0x24, 0xcf, 0xa7, 0xb8, 0x49, 0x55, 0x45, 0x62, 0x62, 0x2e, 0x82, 0xd8, 0x52, 0x00, 0x6c, 0xde, 0x22}, {0x3b, 0xf1, 0xb4, 0x4e, 0xb6, 0xd8, 0x74, 0xb5, 0x91, 0x74, 0xfd, 0xc6, 0xa8, 0x7d, 0xe5, 0x3a, 0xeb, 0xd2, 0x6a, 0xc5, 0x9a, 0x84, 0x51, 0xd9, 0x67, 0xbb, 0xf5, 0x8a, 0x43, 0x27, 0x95, 0x3d}}, - {{0x02, 0xe5, 0xae, 0xa9, 0xc9, 0x21, 0x3b, 0x42, 0x2a, 0x37, 0x59, 0xa1, 0x4f, 0x58, 0x60, 0xb5, 0xf3, 0x27, 0x54, 0xe1, 0x52, 0xa6, 0xe3, 0xbd, 0x48, 0x66, 0x6a, 0x10, 0xee, 0x25, 0xe9, 0x13}, {0xd4, 0x3c, 0x51, 0xf0, 0xc5, 0x83, 0xc0, 0x21, 0x0f, 0x67, 0xfb, 0xbb, 0x06, 0x9c, 0xa4, 0x1a, 0xc4, 0xde, 0x35, 0xa9, 0x20, 0x26, 0x3e, 0x00, 0x00, 0xd3, 0xfc, 0xfe, 0x9b, 0x2c, 0xd0, 0x06}}, - {{0x9d, 0xdf, 0x68, 0x39, 0x9a, 0x34, 0xac, 0x1b, 0xf4, 0x8c, 0x94, 0xdd, 0x88, 0x95, 0x7a, 0x4f, 0xda, 0x41, 0x5b, 0x42, 0xb9, 0xb2, 0x25, 0x9c, 0x22, 0x04, 0x06, 0x67, 0x80, 0xc3, 0xbc, 0x34}, {0x6a, 0xab, 0x7d, 0x76, 0x08, 0xe5, 0x43, 0x2e, 0x22, 0xd5, 0xde, 0x30, 0x57, 0x13, 0x2e, 0x8f, 0x7b, 0xb9, 0x9c, 0x7b, 0x5e, 0x42, 0x5d, 0x1e, 0xd1, 0xa1, 0x4c, 0x3a, 0x68, 0xc0, 0x61, 0x3b}}, - {{0xb3, 0x33, 0x8d, 0xdc, 0x15, 0x15, 0x22, 0x2f, 0x44, 0x57, 0xcf, 0xf4, 0xd2, 0x45, 0x44, 0x87, 0x4b, 0x70, 0x24, 0x7a, 0x9c, 0x9e, 0x39, 0xd4, 0x6d, 0xcb, 0xaa, 0xb7, 0xcd, 0xd0, 0x48, 0x0a}, {0xf8, 0xb4, 0xed, 0x76, 0x94, 0xa9, 0x65, 0x32, 0xfb, 0x34, 0xdb, 0x83, 0x4c, 0x4f, 0x35, 0xad, 0x6b, 0xf5, 0x83, 0x01, 0x9a, 0x97, 0x76, 0x8c, 0x4b, 0xf3, 0x3c, 0x38, 0x4a, 0x3c, 0xc0, 0x24}}, - {{0x36, 0x8f, 0xde, 0x6b, 0xde, 0x48, 0x64, 0x02, 0xcc, 0x94, 0x5b, 0x06, 0x8c, 0xc9, 0xdf, 0x47, 0xd4, 0x65, 0x7b, 0x8f, 0x86, 0x00, 0xae, 0x1b, 0x27, 0xfc, 0xfa, 0x49, 0xe4, 0xed, 0x25, 0x37}, {0xad, 0xab, 0xa0, 0xc2, 0x74, 0x2c, 0x84, 0x07, 0x5c, 0xc6, 0xfa, 0xa1, 0x31, 0x69, 0xb0, 0x98, 0x49, 0xd6, 0xa0, 0xc5, 0xf5, 0xf3, 0xa2, 0xa0, 0xaa, 0xf6, 0x7a, 0xf0, 0xb4, 0x0a, 0xe4, 0x34}}, - {{0x2d, 0x80, 0x5a, 0x98, 0xa5, 0x82, 0x4a, 0xc0, 0xe3, 0xf8, 0xf2, 0x0f, 0xc2, 0x11, 0xdc, 0xf0, 0x5b, 0xab, 0x43, 0xc3, 0x42, 0x88, 0x9c, 0xf9, 0x1e, 0xbc, 0x43, 0x49, 0x60, 0xd5, 0xfe, 0x1e}, {0x87, 0x7c, 0xb1, 0x72, 0xaf, 0x38, 0x73, 0x2b, 0x8a, 0x45, 0x1f, 0x13, 0x90, 0x3e, 0x76, 0x7a, 0x7e, 0x79, 0xe7, 0xed, 0x8c, 0x1a, 0x58, 0xf5, 0x48, 0x52, 0xe5, 0x54, 0x7f, 0x88, 0x60, 0x21}}, - {{0x19, 0x82, 0x78, 0xbd, 0x29, 0x79, 0x06, 0xa8, 0xa6, 0x4b, 0x68, 0x08, 0xc2, 0xb7, 0x02, 0x45, 0x62, 0x86, 0xfa, 0x12, 0x13, 0xa7, 0x24, 0x18, 0xc0, 0x82, 0x9c, 0xec, 0x68, 0xeb, 0x5f, 0x1d}, {0x7e, 0x19, 0xff, 0xa0, 0xd8, 0x6f, 0x0c, 0xb5, 0xef, 0x17, 0x98, 0x1a, 0xc8, 0x67, 0xcb, 0x1e, 0xad, 0xe9, 0xe2, 0xc3, 0x8e, 0x66, 0x02, 0x38, 0xc5, 0xbd, 0xea, 0xb8, 0xe8, 0xbf, 0x1f, 0x17}}, - {{0x20, 0x0b, 0xa3, 0x1a, 0xcb, 0x32, 0x04, 0x38, 0xf5, 0xdb, 0x8a, 0x12, 0x76, 0x9e, 0x06, 0x72, 0x3e, 0x41, 0xf9, 0x13, 0x81, 0x62, 0x30, 0xfe, 0x3d, 0xa2, 0xc0, 0xa3, 0xf6, 0xfa, 0x95, 0x3d}, {0x0c, 0x5f, 0x70, 0x7b, 0x6d, 0x68, 0x91, 0x5c, 0x9a, 0xf7, 0x76, 0xab, 0xab, 0x25, 0x32, 0xa4, 0x10, 0x0e, 0x52, 0xb0, 0xe8, 0xba, 0x34, 0x15, 0x2d, 0x8a, 0x93, 0x7d, 0xf7, 0x24, 0x51, 0x13}}, - {{0x9a, 0xa4, 0x33, 0x07, 0x3e, 0xd4, 0xa5, 0xd8, 0x5b, 0x68, 0xf8, 0x4d, 0x6c, 0x16, 0xfc, 0x59, 0x80, 0xd5, 0x1e, 0x48, 0x0b, 0x73, 0x2c, 0x6b, 0x39, 0x87, 0xa5, 0xb3, 0xc9, 0xb4, 0x74, 0x0b}, {0x68, 0xe9, 0x4b, 0x03, 0x4c, 0xaf, 0xc3, 0xf7, 0x42, 0xb7, 0x46, 0xda, 0xd1, 0x4d, 0x0b, 0x28, 0xf1, 0x2b, 0xa5, 0x92, 0x43, 0x63, 0x7c, 0x81, 0x21, 0xfd, 0xa4, 0x0f, 0x19, 0x72, 0xc6, 0x20}}, - {{0xa9, 0xce, 0x8c, 0xcc, 0x85, 0x5d, 0x9a, 0x9b, 0xe0, 0x69, 0x5f, 0x63, 0x6c, 0xdb, 0x3a, 0x8a, 0x84, 0x11, 0x60, 0x15, 0x8c, 0xbb, 0xe9, 0xd9, 0xee, 0xb5, 0x2a, 0x29, 0x60, 0x42, 0xcc, 0x1d}, {0x66, 0x69, 0x6d, 0xf6, 0x46, 0xc6, 0x91, 0x12, 0xdc, 0xfa, 0xaf, 0x6b, 0x60, 0xd8, 0xb2, 0xd0, 0x8e, 0x39, 0xf2, 0x21, 0xf8, 0x42, 0xe4, 0x5f, 0x0c, 0x62, 0xeb, 0x35, 0x42, 0xd0, 0x97, 0x1b}}, - {{0xcb, 0xb0, 0x21, 0x86, 0xed, 0x47, 0x11, 0x91, 0xd4, 0x13, 0x75, 0x90, 0xc5, 0xa0, 0xd9, 0x15, 0x14, 0x57, 0xb5, 0xf6, 0x41, 0x82, 0xb6, 0x55, 0xa8, 0x18, 0xba, 0xbd, 0xcd, 0x21, 0x8f, 0x38}, {0xe9, 0x0b, 0xdd, 0x57, 0xed, 0xb6, 0xf4, 0xd7, 0x8f, 0x71, 0x2f, 0xc7, 0xa1, 0xdc, 0x59, 0xc6, 0x30, 0xc2, 0x80, 0x04, 0x01, 0xb0, 0x3b, 0x67, 0x1d, 0x2b, 0x14, 0xb0, 0x34, 0x37, 0x9f, 0x08}}, - {{0xd3, 0x64, 0xf0, 0x66, 0x11, 0xe2, 0xef, 0x3f, 0x74, 0xfe, 0x23, 0x2b, 0x92, 0xa6, 0x1e, 0xab, 0xd3, 0xed, 0x13, 0x5b, 0xb8, 0x16, 0xcc, 0xab, 0x02, 0x97, 0xfd, 0x5b, 0x92, 0x58, 0x1e, 0x2f}, {0x0c, 0x6e, 0x6b, 0xcd, 0xf5, 0x5f, 0x11, 0xe1, 0xd3, 0xc9, 0x62, 0x6a, 0x60, 0x60, 0x8e, 0x3b, 0x2a, 0x96, 0x29, 0x23, 0x0a, 0x2c, 0x71, 0x2a, 0xb5, 0xa3, 0xc2, 0xe5, 0x1d, 0x1f, 0x8a, 0x39}}, - {{0x27, 0x55, 0x6c, 0x51, 0xaf, 0x5f, 0xf7, 0xb1, 0x74, 0x5d, 0x54, 0xa9, 0x11, 0xe4, 0x34, 0x18, 0xe5, 0x48, 0x92, 0x51, 0x22, 0x8f, 0x3d, 0x5a, 0xe4, 0xe2, 0xe5, 0x99, 0x3b, 0x5c, 0x9b, 0x0c}, {0x78, 0x91, 0x4c, 0xcd, 0x97, 0x1b, 0x19, 0xc5, 0x37, 0x9f, 0x1d, 0xec, 0xfd, 0x2c, 0x1f, 0x3d, 0x12, 0x9b, 0x74, 0xa6, 0xb5, 0x1a, 0xea, 0x77, 0x19, 0x92, 0x50, 0x1a, 0x37, 0x75, 0x54, 0x1c}}, - {{0xa3, 0xec, 0xf0, 0xbd, 0x7c, 0xbb, 0x48, 0xeb, 0xf9, 0x23, 0x8a, 0x3f, 0x8f, 0xaf, 0x18, 0x38, 0xc2, 0x52, 0x51, 0x82, 0xc6, 0x2b, 0x25, 0x12, 0x6b, 0x75, 0x91, 0x6b, 0x1c, 0x23, 0xf2, 0x20}, {0xdf, 0x64, 0xbc, 0x41, 0x70, 0xb7, 0x6c, 0xe5, 0xeb, 0x88, 0x7c, 0xec, 0xfb, 0x3e, 0x07, 0x65, 0xa3, 0xe9, 0xe3, 0xe0, 0x10, 0xfc, 0xb8, 0x4d, 0x7a, 0xe3, 0xd0, 0x7e, 0x8d, 0xaa, 0xf5, 0x25}}, - {{0x92, 0x15, 0xb5, 0xc5, 0x74, 0x11, 0x9d, 0x98, 0x3d, 0x4f, 0x18, 0xd3, 0x23, 0xde, 0x22, 0xbc, 0x16, 0x92, 0x0c, 0xc3, 0xe1, 0xe3, 0x74, 0x0d, 0x0e, 0xef, 0x74, 0x99, 0xe6, 0x46, 0x9f, 0x3c}, {0x8f, 0xa6, 0x4e, 0x27, 0x9f, 0xbc, 0x71, 0xca, 0xb0, 0x77, 0x87, 0xb7, 0xd4, 0xf4, 0x0a, 0xda, 0x52, 0x54, 0x25, 0x54, 0x7f, 0x19, 0x11, 0xe0, 0xce, 0x07, 0xad, 0x5f, 0x24, 0x1f, 0xbc, 0x02}}, - {{0x17, 0xb0, 0x81, 0xa0, 0x06, 0xe1, 0x6e, 0xf6, 0x66, 0xed, 0x1a, 0x14, 0xb9, 0x9f, 0xa0, 0xbd, 0x8f, 0x21, 0xb2, 0xa5, 0xd3, 0x85, 0x9b, 0x8d, 0x05, 0x52, 0xa0, 0x9a, 0xdf, 0x44, 0x68, 0x33}, {0x3e, 0x28, 0x50, 0x7a, 0xc2, 0x9e, 0xcb, 0x21, 0x5e, 0x35, 0x98, 0x8a, 0x8d, 0xeb, 0x26, 0x65, 0xd2, 0x5b, 0x5b, 0x5a, 0x51, 0x66, 0x25, 0x46, 0xaa, 0x31, 0xbb, 0xea, 0xa2, 0xcf, 0xcc, 0x0d}}, - {{0x78, 0x10, 0xd5, 0xd5, 0xdc, 0xeb, 0x01, 0xdf, 0xa9, 0x40, 0x97, 0x45, 0xfe, 0x4f, 0xe7, 0xdc, 0x6f, 0x92, 0xd4, 0x88, 0x21, 0xc7, 0x30, 0xec, 0xd2, 0x0b, 0xd0, 0x66, 0xba, 0xe3, 0xf4, 0x25}, {0x48, 0xbd, 0x5d, 0x30, 0x28, 0xcf, 0xa4, 0x1a, 0xce, 0x2f, 0xc5, 0x29, 0x41, 0xed, 0xac, 0xf1, 0x23, 0x20, 0x9d, 0x41, 0x99, 0xae, 0x79, 0x6a, 0xa2, 0xdd, 0xa7, 0xab, 0xc2, 0xcc, 0x7a, 0x28}}, - {{0x01, 0x37, 0xe4, 0x61, 0xb1, 0x67, 0xc9, 0xf6, 0x4a, 0x31, 0x75, 0xcf, 0x71, 0x41, 0x59, 0xba, 0x26, 0xd3, 0x45, 0x98, 0x0c, 0xfd, 0x66, 0x23, 0x43, 0x10, 0x55, 0x2e, 0xef, 0x75, 0xea, 0x07}, {0xb3, 0x02, 0x50, 0x1d, 0x63, 0xb3, 0x6a, 0x5f, 0x86, 0x18, 0xf7, 0x8d, 0xd3, 0xf1, 0xa7, 0x42, 0xb1, 0x41, 0x44, 0xe2, 0xda, 0x5f, 0x75, 0xb1, 0x84, 0xe8, 0xe9, 0x47, 0x81, 0xb8, 0xd8, 0x06}}, - {{0x97, 0xf7, 0x69, 0x24, 0xe1, 0x0e, 0x60, 0x77, 0x00, 0x21, 0xcf, 0x63, 0x11, 0x94, 0x28, 0x9d, 0xac, 0xd7, 0x38, 0x1e, 0xbc, 0xd9, 0xf5, 0x94, 0xd8, 0xf1, 0x48, 0x23, 0xed, 0xa8, 0x9d, 0x0d}, {0x81, 0x43, 0xf9, 0x7e, 0x45, 0x10, 0xcb, 0x9d, 0x0d, 0x25, 0xde, 0x41, 0x8e, 0x88, 0x6f, 0xf2, 0xff, 0x98, 0xbe, 0xa5, 0x9e, 0x56, 0xb4, 0x4d, 0xb6, 0xb1, 0x83, 0xe7, 0xfe, 0x26, 0x6e, 0x2c}}, - {{0x7e, 0xe7, 0x68, 0x8b, 0x17, 0x21, 0x52, 0x82, 0xdb, 0x0e, 0xaf, 0xda, 0x04, 0x4c, 0xb6, 0x62, 0x21, 0x9b, 0xce, 0xc5, 0x6a, 0xef, 0xfc, 0x56, 0x0f, 0xb2, 0xa9, 0x26, 0x83, 0x21, 0x60, 0x00}, {0xbe, 0x57, 0x58, 0xc7, 0x56, 0xf7, 0x81, 0x93, 0xd0, 0xaa, 0xb2, 0xe9, 0x22, 0x87, 0x64, 0x2c, 0x9f, 0x89, 0xb7, 0x22, 0x97, 0xfa, 0x1d, 0xd2, 0x97, 0x3b, 0xd1, 0x36, 0xab, 0x34, 0xb3, 0x37}}, - {{0x7e, 0x25, 0xac, 0xc9, 0xa7, 0xd2, 0xca, 0x1d, 0x1e, 0x56, 0xde, 0xdf, 0x41, 0xbd, 0x81, 0xf4, 0xa1, 0x9b, 0x4f, 0xe1, 0x59, 0x5d, 0xb9, 0x7f, 0xf1, 0x5f, 0x75, 0x3a, 0xae, 0xe5, 0x4f, 0x16}, {0xb9, 0x04, 0xed, 0x04, 0x80, 0x23, 0x5d, 0xd8, 0xbe, 0x67, 0x0b, 0x24, 0xca, 0xf4, 0xa2, 0xf0, 0xc0, 0xe8, 0x37, 0xb1, 0x39, 0x65, 0x8d, 0x32, 0x38, 0x29, 0x72, 0x3c, 0xd2, 0x7a, 0x91, 0x1f}}, - {{0xc8, 0xdd, 0x1d, 0x51, 0x69, 0x1f, 0x1a, 0x7c, 0xbb, 0xc6, 0x93, 0x8a, 0xd0, 0x22, 0xef, 0xaf, 0x86, 0x8e, 0xfb, 0x5d, 0x6e, 0xde, 0x7d, 0x6b, 0xdf, 0x1f, 0x1b, 0x9b, 0xfb, 0x14, 0x18, 0x04}, {0x19, 0xee, 0xde, 0x5a, 0x8d, 0x8d, 0x32, 0xc2, 0x8c, 0x32, 0xaa, 0x1f, 0x3e, 0x23, 0xcd, 0xfc, 0x5d, 0x08, 0xd2, 0xbf, 0x62, 0xeb, 0x4a, 0xb7, 0x74, 0xb6, 0xda, 0xe2, 0x7a, 0x49, 0x9b, 0x34}}, - {{0x40, 0x8c, 0x05, 0xde, 0x2e, 0x49, 0x76, 0xee, 0xfd, 0x0d, 0x21, 0x63, 0xa9, 0xce, 0x67, 0x96, 0x78, 0x4d, 0xaf, 0xbb, 0xe7, 0xdf, 0xfb, 0x9f, 0xfb, 0xed, 0xf2, 0xbb, 0x47, 0x7f, 0x4a, 0x02}, {0xa6, 0xb6, 0xc0, 0x54, 0x53, 0x94, 0x98, 0x27, 0x06, 0x93, 0x7c, 0xe9, 0xf1, 0x04, 0x58, 0x02, 0xf8, 0x31, 0x0f, 0xf7, 0x5b, 0x74, 0x89, 0xa5, 0xd5, 0x1b, 0xa0, 0xd2, 0x3e, 0x75, 0x80, 0x29}}, - {{0x1f, 0xcf, 0x8d, 0xfb, 0xea, 0x79, 0x17, 0xc2, 0x99, 0x1a, 0xe8, 0x74, 0x68, 0x3d, 0xd4, 0xc7, 0x25, 0x02, 0xa7, 0x3d, 0x7a, 0xe8, 0x4e, 0xdf, 0xec, 0x66, 0xc0, 0x7e, 0x64, 0x66, 0x74, 0x26}, {0xff, 0x71, 0x66, 0x3e, 0x8d, 0x43, 0x08, 0x9a, 0x33, 0xe0, 0xf0, 0x7e, 0xfd, 0xf5, 0x97, 0x25, 0x6b, 0x33, 0xe4, 0x16, 0xb3, 0xd2, 0x90, 0x34, 0xd0, 0x50, 0xe5, 0x2c, 0xb8, 0x68, 0xf1, 0x0a}}, - {{0xb9, 0xd7, 0x81, 0xad, 0xce, 0x3a, 0xe7, 0x9e, 0x87, 0x22, 0x20, 0xc4, 0x51, 0x4d, 0x7d, 0x7f, 0xd5, 0x21, 0x2c, 0xf7, 0xda, 0x8c, 0xa4, 0x7e, 0x62, 0x92, 0x05, 0x7c, 0x89, 0xab, 0xa5, 0x3b}, {0x62, 0x1f, 0xaf, 0xe7, 0xf6, 0x2d, 0xa7, 0x65, 0x01, 0x6e, 0x87, 0xed, 0x79, 0x70, 0x18, 0x50, 0x33, 0xf5, 0xf8, 0xb2, 0xac, 0x7b, 0x49, 0xdd, 0x48, 0x83, 0xca, 0x10, 0xe1, 0xb1, 0x05, 0x23}}, - {{0x66, 0x08, 0x81, 0x6f, 0x6e, 0x85, 0xb8, 0x7b, 0x2c, 0x34, 0x58, 0x35, 0xa6, 0x87, 0x10, 0x29, 0xee, 0x2a, 0xec, 0xa5, 0xa1, 0xf6, 0x97, 0x01, 0x36, 0xa9, 0x82, 0xbe, 0x84, 0x0e, 0x3f, 0x2e}, {0x6e, 0xd2, 0xfe, 0xde, 0x23, 0x4f, 0xd2, 0x24, 0x1f, 0x53, 0x23, 0xe1, 0xcb, 0xfd, 0xa3, 0xa6, 0x7a, 0x9b, 0x59, 0x90, 0x4f, 0x54, 0x54, 0xf5, 0x88, 0xd7, 0x05, 0x2c, 0x74, 0x2c, 0x2b, 0x1b}}, - {{0xb7, 0x61, 0x5f, 0xe7, 0xc5, 0x8c, 0xaa, 0x77, 0x5d, 0x22, 0x7a, 0x2c, 0x2c, 0xd2, 0xb0, 0x7a, 0x33, 0x62, 0x04, 0xd9, 0xae, 0x0b, 0x1a, 0x26, 0x96, 0xfe, 0xe6, 0xdf, 0x27, 0x54, 0xca, 0x23}, {0xf1, 0xf4, 0xe5, 0x8b, 0x26, 0xf1, 0x65, 0x39, 0x68, 0x44, 0xe0, 0x19, 0x5d, 0xf0, 0xbc, 0xfb, 0x90, 0xda, 0xa3, 0xdd, 0x1a, 0x7a, 0x20, 0xcf, 0x9f, 0xae, 0x58, 0xe7, 0xb3, 0x38, 0xc1, 0x2d}}, - {{0x97, 0x3a, 0xf1, 0x51, 0xbb, 0xd4, 0xcd, 0xe4, 0x66, 0xf1, 0x47, 0xd9, 0x07, 0xb3, 0xe0, 0x0a, 0xdd, 0x61, 0x54, 0x95, 0x80, 0x0d, 0xc1, 0x95, 0x6b, 0xa2, 0x8c, 0xf5, 0xcd, 0x0d, 0x63, 0x26}, {0xfb, 0xe7, 0x25, 0x7f, 0xce, 0x76, 0x69, 0xec, 0xb9, 0xb2, 0x3e, 0x60, 0x67, 0xef, 0xf1, 0x21, 0xef, 0xd7, 0xdc, 0x65, 0xae, 0x45, 0x38, 0xb5, 0xf0, 0xd4, 0x75, 0x34, 0xd2, 0xe5, 0x6b, 0x00}}, - {{0xb5, 0x37, 0x4d, 0xc7, 0xf5, 0xda, 0x37, 0xd9, 0xd4, 0x78, 0xb0, 0xd7, 0x60, 0xad, 0x6f, 0x7b, 0x8e, 0x2e, 0x19, 0xcc, 0xf9, 0x48, 0xa2, 0xea, 0xf3, 0x61, 0x9c, 0x3f, 0x49, 0x98, 0xff, 0x1b}, {0xb8, 0x79, 0x93, 0x69, 0x71, 0xde, 0xb4, 0x1e, 0x28, 0xc6, 0xb0, 0x84, 0xa7, 0xad, 0x31, 0x16, 0xcc, 0x74, 0xfa, 0x06, 0x00, 0x52, 0xaf, 0x00, 0x83, 0x2a, 0xc5, 0x9a, 0x48, 0x0f, 0x97, 0x14}}, - {{0x6c, 0xc3, 0x7b, 0xb0, 0xa2, 0x8c, 0x5d, 0x58, 0x53, 0x31, 0xfb, 0xb3, 0x5b, 0x12, 0x0e, 0x6a, 0xe5, 0x48, 0x1c, 0xa3, 0xd8, 0x99, 0x56, 0x16, 0xcd, 0x2e, 0x3d, 0x2d, 0x43, 0x28, 0x90, 0x0c}, {0x53, 0x05, 0x9f, 0x0a, 0xaa, 0xc3, 0xb6, 0x37, 0x06, 0x09, 0x31, 0x3b, 0x83, 0x7c, 0x5f, 0xe7, 0xf0, 0x80, 0xdd, 0xfe, 0x59, 0x13, 0x28, 0x0b, 0xe7, 0x2a, 0xe4, 0x78, 0x1d, 0xf2, 0xea, 0x2a}}, - {{0xbb, 0xab, 0x98, 0xf0, 0x92, 0xb4, 0x05, 0xf9, 0xb9, 0xfb, 0x3d, 0x15, 0xad, 0x32, 0xe7, 0x91, 0x6e, 0x95, 0x6f, 0xc2, 0x3d, 0x9b, 0xb7, 0x23, 0x02, 0x08, 0xde, 0xb4, 0x99, 0x69, 0xa8, 0x30}, {0x80, 0xce, 0x1a, 0xef, 0x4a, 0x1e, 0x98, 0xab, 0xf7, 0x76, 0x7f, 0xcc, 0xb7, 0x1a, 0x6a, 0x3e, 0xbd, 0x24, 0xa9, 0xb0, 0x90, 0xac, 0xfc, 0xfc, 0xf0, 0xd9, 0x64, 0xb3, 0x1a, 0x7b, 0x0c, 0x29}}, - {{0x10, 0x23, 0x95, 0x14, 0x03, 0x59, 0xd2, 0x89, 0x02, 0x9b, 0xfe, 0xe3, 0x93, 0x47, 0xf6, 0xb8, 0xed, 0xdd, 0x48, 0x10, 0x4c, 0x31, 0x98, 0x12, 0x47, 0x5f, 0x87, 0x3f, 0xef, 0x6a, 0xf6, 0x35}, {0x00, 0x9a, 0x0b, 0x4e, 0xec, 0xc9, 0x09, 0x7f, 0xe8, 0xc5, 0x63, 0x8b, 0xa8, 0x58, 0xe5, 0x02, 0x4d, 0xd2, 0x34, 0xeb, 0xab, 0xa2, 0xf2, 0xdf, 0xa5, 0x3e, 0xa5, 0x61, 0xc6, 0x04, 0x2a, 0x18}}, - {{0xc0, 0xc3, 0x8d, 0x5a, 0x48, 0x9a, 0x49, 0x77, 0xa8, 0x54, 0x0b, 0xd6, 0xb7, 0x8b, 0x01, 0x73, 0xd3, 0xf4, 0x34, 0xe1, 0xec, 0x5a, 0x74, 0xbd, 0x25, 0x9f, 0x96, 0x98, 0x40, 0x43, 0xe6, 0x0c}, {0xc9, 0x5a, 0xe8, 0xa5, 0x4a, 0xa9, 0x14, 0xb2, 0xbf, 0x71, 0x5b, 0x2c, 0xdb, 0x00, 0x7b, 0x3a, 0xa7, 0x3e, 0x95, 0x4a, 0xe9, 0x97, 0x1f, 0x1f, 0xc3, 0xbd, 0xf2, 0x90, 0x13, 0x1f, 0xdc, 0x0f}}, - {{0x49, 0x92, 0x34, 0x36, 0x12, 0x37, 0x7b, 0xfd, 0x01, 0xe9, 0x3e, 0xa2, 0xf6, 0x31, 0x9c, 0xb2, 0xb0, 0x19, 0x6a, 0xab, 0xb7, 0x09, 0x8c, 0x42, 0xc3, 0x7f, 0x4a, 0x7f, 0xac, 0x6e, 0xdb, 0x3e}, {0xfe, 0x39, 0xd0, 0x33, 0x62, 0x5f, 0xae, 0x41, 0xae, 0x3f, 0x83, 0x6a, 0xad, 0x2f, 0x1b, 0x35, 0xd6, 0xab, 0x3c, 0xdc, 0x87, 0xde, 0x27, 0xb0, 0xe6, 0xfb, 0xf4, 0x8f, 0x89, 0x6b, 0x3c, 0x1c}}, - {{0x79, 0x73, 0xd7, 0x36, 0xb4, 0xea, 0x79, 0x85, 0x4f, 0x6a, 0xad, 0xa7, 0x0e, 0xf6, 0x76, 0x69, 0xe0, 0x82, 0x7f, 0xbd, 0x86, 0x04, 0x44, 0x4d, 0x33, 0x6b, 0x69, 0xd1, 0x7b, 0x08, 0xdf, 0x33}, {0xb1, 0xe1, 0x04, 0x77, 0x3e, 0x25, 0xae, 0xd8, 0x72, 0xcb, 0xa9, 0x5c, 0x98, 0x3c, 0x80, 0x6c, 0x2a, 0xe7, 0x73, 0x71, 0x94, 0x0a, 0x76, 0x4f, 0x3e, 0xb5, 0x76, 0xa5, 0x2a, 0x3c, 0x49, 0x17}}, - {{0xa8, 0xd2, 0xe5, 0xbe, 0xe3, 0x9c, 0x8d, 0x0d, 0xc7, 0x7e, 0x16, 0x14, 0x32, 0x1e, 0x11, 0x3b, 0x29, 0x24, 0xbc, 0xf7, 0x44, 0x56, 0x6a, 0x86, 0x69, 0x6b, 0x70, 0xd6, 0x5c, 0xe6, 0x53, 0x2f}, {0xb9, 0x54, 0x27, 0x53, 0x8d, 0xa9, 0xbc, 0xc9, 0x52, 0xac, 0x60, 0x33, 0x22, 0x0a, 0x20, 0x1c, 0x67, 0x5f, 0x49, 0x32, 0x1f, 0x44, 0xd1, 0x8f, 0x4c, 0xa0, 0x7a, 0x7b, 0xa6, 0xe7, 0x91, 0x08}}, - {{0x5e, 0xe6, 0x36, 0x33, 0xc2, 0xb0, 0xac, 0x33, 0x80, 0xb2, 0x5f, 0x36, 0xb7, 0xf7, 0xbd, 0xe9, 0x9c, 0x35, 0x24, 0xb1, 0x1c, 0x30, 0xdb, 0x3f, 0xfc, 0x0b, 0xfb, 0x48, 0xa4, 0xf8, 0x5c, 0x22}, {0xf5, 0x37, 0x01, 0x7c, 0x5c, 0x52, 0xd0, 0x7b, 0xac, 0x3c, 0xf5, 0x5e, 0x9e, 0x2e, 0xcc, 0x25, 0x65, 0x58, 0xf6, 0x33, 0xe7, 0x86, 0xbf, 0x0a, 0xfd, 0x34, 0xd5, 0x9b, 0x37, 0xf8, 0xec, 0x25}}, - {{0x39, 0x0d, 0x3a, 0x43, 0xdf, 0x74, 0x59, 0x19, 0xc1, 0x45, 0x66, 0xfe, 0x55, 0xd5, 0x2a, 0xf9, 0xa3, 0x05, 0x67, 0x6b, 0x69, 0xfe, 0x22, 0xde, 0x7f, 0xcf, 0x89, 0x52, 0xcd, 0x33, 0xc6, 0x30}, {0xb9, 0xcd, 0x5b, 0x21, 0xae, 0x06, 0xe2, 0x2d, 0x6f, 0xf0, 0x1c, 0x5d, 0x3a, 0x73, 0xba, 0x1d, 0xb6, 0x07, 0x29, 0x7c, 0x62, 0x05, 0x95, 0x77, 0x5f, 0x29, 0xf8, 0x58, 0x43, 0xa4, 0x05, 0x2e}}, - {{0xe2, 0x27, 0x9e, 0x0e, 0x5a, 0x3e, 0x8d, 0x8c, 0xd5, 0x9a, 0x83, 0x33, 0x34, 0xac, 0xa7, 0x33, 0xf2, 0x27, 0xca, 0x67, 0x88, 0xef, 0x3a, 0x81, 0xea, 0x93, 0x57, 0xaa, 0xc5, 0x82, 0x51, 0x03}, {0x75, 0x9e, 0x19, 0x05, 0x28, 0xd3, 0x7a, 0xe3, 0x8f, 0x4d, 0x25, 0x72, 0xb8, 0xec, 0x92, 0x94, 0x4f, 0x3b, 0xd9, 0x32, 0x58, 0x0d, 0x40, 0xe4, 0x04, 0x0e, 0xde, 0x31, 0x34, 0xf6, 0xd7, 0x23}}, - {{0xc7, 0xd2, 0x7c, 0x8b, 0x4d, 0xfc, 0x93, 0xed, 0x39, 0x10, 0x13, 0x28, 0x2a, 0xe8, 0xf9, 0x2f, 0x82, 0x74, 0xdd, 0x8e, 0x2f, 0x40, 0x41, 0x9b, 0x26, 0x55, 0x7c, 0xe8, 0x8a, 0x40, 0xe8, 0x2d}, {0x5b, 0x6f, 0x78, 0x90, 0xee, 0x7a, 0x82, 0x84, 0x6f, 0x8a, 0xa9, 0x7a, 0xcc, 0x1a, 0xa5, 0xfc, 0x41, 0x76, 0xb1, 0x1f, 0xd8, 0xc0, 0x26, 0x3b, 0x4f, 0xce, 0x30, 0x34, 0xa5, 0xcf, 0x97, 0x1e}}, - {{0x4b, 0x2e, 0x30, 0xdd, 0x6f, 0x3f, 0xd8, 0x28, 0x62, 0xb1, 0x48, 0xdf, 0x16, 0x16, 0x33, 0x8b, 0xc6, 0xd5, 0xbe, 0xab, 0x0b, 0x7f, 0x66, 0xeb, 0x2d, 0x99, 0x00, 0x2f, 0x7d, 0x9f, 0xb4, 0x1b}, {0x8f, 0x5b, 0x75, 0x59, 0x85, 0x25, 0x1b, 0x8f, 0xa4, 0x49, 0x44, 0xac, 0x45, 0x56, 0x2a, 0x99, 0x8e, 0x87, 0x8a, 0x37, 0x78, 0xa7, 0xf8, 0xc7, 0x14, 0x2f, 0x9a, 0xaa, 0x95, 0xd4, 0x88, 0x23}}, - {{0x5c, 0xe1, 0xa6, 0xcc, 0x2b, 0x83, 0xee, 0xb3, 0xb0, 0xf5, 0x9c, 0xd0, 0x76, 0x09, 0x2e, 0x30, 0x90, 0x05, 0xca, 0x07, 0x11, 0xc9, 0x73, 0x3b, 0xe5, 0x20, 0x2a, 0xe3, 0x9d, 0x72, 0x33, 0x10}, {0x97, 0xfb, 0xab, 0x62, 0xc9, 0x03, 0x4d, 0x82, 0x48, 0xda, 0xa4, 0xfc, 0xc3, 0x05, 0x76, 0x33, 0x7b, 0xeb, 0xb1, 0xc1, 0x92, 0x5b, 0x38, 0xd9, 0x53, 0x03, 0xd7, 0x9d, 0x3b, 0xd5, 0xe9, 0x04}}, - {{0x89, 0x1b, 0xfe, 0x2b, 0xea, 0xce, 0x31, 0x2a, 0xb2, 0xfa, 0xed, 0x3e, 0x64, 0x78, 0x9c, 0x45, 0xf7, 0x21, 0x08, 0x9a, 0xda, 0xeb, 0x15, 0x80, 0x38, 0x8f, 0x2e, 0xed, 0x48, 0x5d, 0x76, 0x31}, {0x67, 0xa5, 0x00, 0x22, 0x2e, 0xe1, 0xd2, 0xbb, 0x61, 0x31, 0xc9, 0x60, 0x8e, 0x8b, 0x7e, 0xee, 0x7f, 0xa1, 0x1e, 0xb5, 0xa8, 0x13, 0x50, 0x44, 0x0f, 0x60, 0x3f, 0x41, 0x3d, 0xea, 0xb3, 0x3f}}, - {{0x99, 0x54, 0xaf, 0x65, 0xbb, 0xe1, 0x92, 0x57, 0xdb, 0x90, 0xd1, 0xd9, 0xce, 0xec, 0x8e, 0xf3, 0xed, 0xa1, 0xf9, 0xae, 0x7f, 0x77, 0x2e, 0x78, 0xf4, 0x89, 0x7e, 0xd4, 0xf6, 0x1a, 0x75, 0x32}, {0xac, 0x9f, 0x9c, 0xd7, 0x57, 0x86, 0x58, 0x05, 0xaa, 0x3f, 0x97, 0xc7, 0x59, 0xfa, 0xfc, 0x4c, 0x25, 0xe0, 0x3a, 0x3e, 0x9c, 0x52, 0xec, 0x46, 0x90, 0xb5, 0xfe, 0x1c, 0xc7, 0x9f, 0x88, 0x2e}}, - {{0xcf, 0x98, 0xdf, 0x27, 0x89, 0x5a, 0x36, 0x4f, 0xd4, 0x90, 0xdf, 0xe1, 0x2a, 0xad, 0x4d, 0xdc, 0xa6, 0xa3, 0x34, 0xf5, 0xc9, 0xf8, 0xc7, 0xe8, 0xb1, 0x88, 0x6f, 0x54, 0x72, 0xdb, 0x53, 0x1f}, {0x8e, 0x45, 0xf3, 0x64, 0x10, 0xf7, 0x21, 0xc5, 0x44, 0xca, 0xeb, 0xb4, 0x13, 0xb8, 0xf4, 0x55, 0xf7, 0xc1, 0xc2, 0x69, 0xa1, 0xfc, 0xbe, 0x1f, 0x08, 0xdb, 0x69, 0x05, 0xd0, 0x72, 0x70, 0x32}}, - {{0x0a, 0xc3, 0x34, 0x45, 0x5e, 0xbf, 0x1c, 0xe5, 0x9b, 0xac, 0x82, 0x5b, 0xfe, 0x38, 0x11, 0x9f, 0x40, 0x67, 0xc9, 0x64, 0x8e, 0x61, 0xe5, 0x31, 0x1f, 0xae, 0x65, 0x80, 0x08, 0xa0, 0x26, 0x16}, {0x2b, 0x3b, 0x62, 0x03, 0xca, 0x35, 0x4f, 0x4e, 0x66, 0xca, 0x43, 0x4b, 0xc7, 0x4e, 0x9e, 0x58, 0x79, 0x17, 0x39, 0x97, 0x52, 0xa8, 0xfc, 0xad, 0xfc, 0xb4, 0x7f, 0x30, 0xc2, 0xc8, 0xc9, 0x3e}}, - {{0xc5, 0xfc, 0x26, 0x2b, 0x72, 0x17, 0x58, 0xe5, 0x6b, 0xbc, 0xd7, 0x57, 0xc7, 0x78, 0xd2, 0x8c, 0x13, 0x8c, 0x83, 0x56, 0xd7, 0x0e, 0x6f, 0x21, 0xef, 0x67, 0xa1, 0x0c, 0x14, 0xb2, 0xad, 0x2b}, {0x74, 0x5d, 0xe4, 0xbd, 0xac, 0x54, 0x8e, 0x7b, 0x2b, 0xef, 0x85, 0xf0, 0x08, 0xee, 0x2b, 0xf1, 0xba, 0x7c, 0xb3, 0x9b, 0x38, 0xcb, 0xbe, 0x59, 0x05, 0x32, 0x89, 0xd2, 0x3a, 0xe5, 0xc2, 0x10}}, - {{0x2b, 0x92, 0xcc, 0xa2, 0x73, 0x60, 0xbf, 0x05, 0xf5, 0xa6, 0x61, 0xc1, 0xb1, 0xa1, 0x40, 0xaa, 0xbe, 0xf2, 0xb3, 0xd7, 0x99, 0xa1, 0xaa, 0xe7, 0x76, 0x53, 0x5b, 0xff, 0x5a, 0x89, 0xc8, 0x2e}, {0x34, 0xad, 0x37, 0x5c, 0x6f, 0x2a, 0xa9, 0x21, 0x54, 0xd3, 0x30, 0x4c, 0x7e, 0x8f, 0xd0, 0x9e, 0xf0, 0xdd, 0xd0, 0x73, 0x6b, 0xae, 0x92, 0x0c, 0x24, 0x85, 0xd8, 0xf6, 0xc9, 0xe3, 0xaf, 0x02}}, - {{0x5f, 0x44, 0xf7, 0x2e, 0x63, 0x1c, 0x64, 0xa3, 0xe9, 0x06, 0x17, 0xab, 0x41, 0x44, 0x01, 0x16, 0x5c, 0x6d, 0x68, 0xd2, 0xdd, 0xe5, 0x0c, 0x5e, 0xb2, 0x49, 0x5a, 0x58, 0x56, 0xbd, 0x62, 0x29}, {0x90, 0xc4, 0x08, 0x69, 0x12, 0x39, 0x33, 0x8f, 0xc6, 0xf2, 0xfb, 0xf6, 0xa1, 0x01, 0x37, 0xb3, 0x7e, 0x58, 0xa1, 0xd5, 0x95, 0xed, 0x5d, 0x5b, 0xfa, 0xdc, 0x0b, 0x9d, 0xc9, 0x30, 0x5a, 0x17}}, - {{0xec, 0x84, 0x89, 0xaa, 0x5c, 0x0b, 0x82, 0xf9, 0x00, 0x00, 0xf7, 0x04, 0x8a, 0x6f, 0xd5, 0x8c, 0x68, 0xc6, 0xe6, 0x42, 0x43, 0x1e, 0xbf, 0x45, 0x83, 0x0c, 0xc8, 0xcf, 0xf2, 0x5e, 0x33, 0x2b}, {0x4c, 0xeb, 0x73, 0xa9, 0x9a, 0x8c, 0x8e, 0xd2, 0xb8, 0x5e, 0x65, 0xc5, 0x3c, 0x63, 0x8d, 0xfc, 0x60, 0x24, 0xf8, 0xb1, 0x8f, 0x80, 0xf8, 0x49, 0x6c, 0xe5, 0x32, 0xc7, 0x92, 0x24, 0xdf, 0x26}}, - {{0xdf, 0x15, 0x10, 0xed, 0x4a, 0xe1, 0x02, 0xcc, 0x32, 0x1b, 0x48, 0x61, 0xda, 0xe6, 0xb2, 0x7a, 0x1f, 0x7c, 0x59, 0x79, 0xf5, 0xcc, 0xb8, 0xf1, 0xd4, 0x87, 0xa5, 0xd2, 0x76, 0x1c, 0x39, 0x1f}, {0x78, 0xc0, 0x00, 0xc9, 0x3c, 0x8e, 0x61, 0x61, 0x06, 0xca, 0xb8, 0x5d, 0xda, 0xd2, 0x51, 0x80, 0x59, 0x7e, 0x81, 0x4a, 0xa6, 0xbb, 0x0c, 0xf0, 0xa4, 0x28, 0x61, 0x99, 0x79, 0xf2, 0x12, 0x02}}, - {{0x2d, 0x35, 0xd1, 0x1e, 0xa4, 0xbe, 0x12, 0xba, 0x06, 0x4e, 0x74, 0x30, 0x38, 0x12, 0x2a, 0xc7, 0x1e, 0x52, 0xce, 0x7b, 0x80, 0x46, 0x4b, 0x77, 0x44, 0x19, 0x83, 0x44, 0x07, 0xf3, 0x55, 0x1b}, {0x56, 0xf7, 0x99, 0x71, 0xb5, 0x05, 0x39, 0x43, 0xcd, 0x18, 0x74, 0x83, 0xd2, 0xa2, 0x18, 0x50, 0x3f, 0xe3, 0x2c, 0x48, 0x35, 0x37, 0x69, 0xc3, 0x22, 0xed, 0x35, 0xe9, 0xc4, 0x33, 0xd1, 0x06}}, - {{0x6b, 0x9a, 0xf8, 0x42, 0x55, 0xe0, 0xd2, 0x17, 0x11, 0x99, 0x4a, 0x83, 0x2c, 0x57, 0xc4, 0x63, 0xb9, 0x06, 0xe9, 0x30, 0x7d, 0x19, 0x98, 0x7c, 0x73, 0xa7, 0x1c, 0x7b, 0x9c, 0x0e, 0xb8, 0x1b}, {0xdd, 0x82, 0xdd, 0xf5, 0x77, 0x56, 0x7f, 0x75, 0x2b, 0x18, 0xbb, 0x57, 0x92, 0x53, 0x30, 0x60, 0xf2, 0x46, 0x3b, 0x49, 0x11, 0xe7, 0xe8, 0x22, 0x39, 0x63, 0x07, 0x11, 0x6c, 0x9d, 0x62, 0x24}}, - {{0xfa, 0x67, 0x48, 0x0d, 0x07, 0x00, 0x27, 0xc2, 0x4c, 0x16, 0x5a, 0x8e, 0xed, 0xa6, 0x14, 0x5a, 0xdc, 0xa4, 0xfa, 0xe4, 0x9b, 0x97, 0x1b, 0xf3, 0xe1, 0x2f, 0x8a, 0xae, 0x32, 0x9c, 0x60, 0x22}, {0x7a, 0x6c, 0xba, 0x36, 0x59, 0xcd, 0xbe, 0xcb, 0xe0, 0x39, 0xb9, 0xdd, 0x86, 0x77, 0x8f, 0x76, 0x23, 0xe1, 0x06, 0xe2, 0x03, 0x86, 0xe0, 0x8e, 0x52, 0x98, 0xad, 0x19, 0x3e, 0xbb, 0xf1, 0x14}}, - {{0x8a, 0x1f, 0x5e, 0x86, 0xfe, 0xd0, 0xcc, 0x36, 0x83, 0x01, 0x9b, 0x2f, 0xf1, 0x6d, 0x2a, 0xd1, 0x58, 0x37, 0x75, 0x80, 0x86, 0x79, 0xc1, 0x8f, 0xa6, 0x5f, 0xb2, 0xfe, 0x92, 0xa7, 0x0a, 0x23}, {0xe0, 0xba, 0xc0, 0x0c, 0xcd, 0xa5, 0x89, 0x24, 0x76, 0x46, 0x4f, 0x92, 0xd3, 0xc5, 0x0d, 0x6f, 0x71, 0x9b, 0x34, 0x97, 0x02, 0x65, 0x2a, 0xea, 0xed, 0x40, 0xcd, 0x6b, 0xb5, 0x75, 0x96, 0x25}}, - {{0xb0, 0x6c, 0xce, 0x14, 0xf6, 0xad, 0x11, 0xc1, 0x92, 0x00, 0xb9, 0xba, 0x21, 0x0e, 0xba, 0x4a, 0xd0, 0xea, 0x39, 0x1d, 0xdc, 0xd9, 0xe9, 0x99, 0x84, 0xea, 0x15, 0x92, 0xc6, 0x4e, 0x84, 0x1d}, {0x28, 0x3a, 0xd6, 0x34, 0xce, 0x32, 0x5f, 0x66, 0xda, 0x51, 0xf3, 0xb4, 0xaf, 0x7f, 0x6d, 0x16, 0x37, 0x08, 0x3a, 0x4a, 0xc9, 0x1d, 0xf2, 0x71, 0x07, 0x7a, 0x02, 0xd8, 0x75, 0xdd, 0xbd, 0x1c}}, - {{0x44, 0x34, 0x07, 0xb4, 0x4f, 0x0c, 0x16, 0xbb, 0xf7, 0xa4, 0x00, 0xac, 0x61, 0x3c, 0x4f, 0x4f, 0x8b, 0x98, 0x2b, 0x01, 0x1a, 0x27, 0x3a, 0x3c, 0x10, 0xae, 0xd3, 0x2b, 0x60, 0x41, 0x4d, 0x1b}, {0x5b, 0xb2, 0xf7, 0x22, 0x12, 0x91, 0xf2, 0x61, 0x64, 0x23, 0xdf, 0xd3, 0xe7, 0xee, 0xe6, 0xd2, 0x96, 0x9b, 0xef, 0xa1, 0xe6, 0x24, 0x6e, 0x15, 0x19, 0x94, 0x98, 0x2b, 0xf6, 0xb4, 0xc4, 0x2c}}, - {{0x52, 0x50, 0x99, 0xcf, 0x9e, 0x37, 0xad, 0x90, 0x0f, 0xf1, 0x2e, 0x45, 0x06, 0x5b, 0xd3, 0xfd, 0x47, 0x58, 0xd6, 0xcc, 0xe1, 0x9f, 0x31, 0x32, 0x7d, 0x15, 0x9b, 0x6f, 0x5c, 0x0e, 0xd6, 0x37}, {0x11, 0x36, 0x11, 0x8a, 0x6d, 0x4b, 0x5e, 0xef, 0x8f, 0xe6, 0x19, 0x97, 0xed, 0x8a, 0xf2, 0xff, 0x86, 0x4b, 0xc5, 0x2b, 0x04, 0xf7, 0x22, 0x00, 0x0f, 0x15, 0xa0, 0x87, 0x39, 0x17, 0xd1, 0x24}}, - {{0x29, 0xdf, 0x76, 0x5b, 0x04, 0xa0, 0xb6, 0x67, 0xc5, 0x72, 0xd1, 0x5d, 0x58, 0x77, 0x80, 0xd7, 0x47, 0x61, 0x47, 0x1b, 0xda, 0xba, 0x94, 0xfd, 0x75, 0x79, 0xb1, 0x3b, 0x12, 0xef, 0x5a, 0x05}, {0x59, 0x00, 0xfd, 0xb6, 0x14, 0x79, 0x0d, 0xc4, 0xcf, 0xc0, 0x21, 0x96, 0xe5, 0x03, 0x4b, 0xcd, 0xb4, 0x5c, 0x1b, 0xaa, 0x59, 0x39, 0x04, 0x58, 0x5c, 0x9f, 0x3c, 0x33, 0x93, 0x7d, 0x9e, 0x39}}, - {{0xf3, 0xa8, 0xf3, 0x6f, 0xb6, 0x36, 0x87, 0xe9, 0x29, 0x1c, 0xd0, 0xe2, 0x7c, 0x6b, 0x33, 0xb6, 0x94, 0x85, 0x71, 0xe8, 0x38, 0xe1, 0xb5, 0x72, 0x94, 0x2d, 0x59, 0xf7, 0xf0, 0x1a, 0xe3, 0x39}, {0x91, 0x69, 0xe9, 0xa9, 0xd2, 0xaa, 0x84, 0x25, 0xf8, 0x00, 0xa0, 0x57, 0xb6, 0xc9, 0x67, 0x4d, 0x6b, 0xf6, 0x5d, 0x24, 0x39, 0x7c, 0xef, 0x1f, 0xce, 0x13, 0x0e, 0xb6, 0xf5, 0x61, 0xa5, 0x39}}, - {{0x7d, 0x2e, 0x9d, 0x67, 0xb3, 0x2b, 0xa8, 0x12, 0x6e, 0x26, 0x92, 0xcf, 0x9d, 0x94, 0x23, 0x79, 0x46, 0xa7, 0xda, 0x8e, 0xd1, 0xe0, 0x97, 0xb9, 0x9d, 0x91, 0x7a, 0x93, 0xbf, 0xd4, 0x22, 0x27}, {0x91, 0x73, 0x79, 0x5c, 0xfd, 0x3a, 0xc8, 0xdc, 0xac, 0x98, 0x33, 0xa7, 0x3d, 0x83, 0xa7, 0x25, 0x8b, 0x3f, 0x0f, 0xc0, 0x3f, 0x90, 0x2e, 0xd8, 0x1a, 0xb4, 0x3f, 0x26, 0xe6, 0x7a, 0xb2, 0x20}}, - {{0xab, 0xaa, 0xec, 0x52, 0x2a, 0xec, 0x97, 0xef, 0x32, 0x05, 0x4c, 0xb8, 0x73, 0x0e, 0x56, 0x64, 0xbc, 0x9d, 0x64, 0x21, 0x1e, 0x0f, 0x2e, 0xf4, 0x9b, 0x42, 0x3b, 0x3e, 0x9b, 0x76, 0x2d, 0x36}, {0xc7, 0x07, 0x29, 0x82, 0xd4, 0x45, 0x49, 0xa8, 0x24, 0xeb, 0xfd, 0x9d, 0x9a, 0x31, 0x19, 0x83, 0x47, 0x9d, 0x2f, 0x83, 0xbd, 0x33, 0x53, 0x1b, 0xeb, 0x14, 0x0e, 0x44, 0x05, 0x46, 0x8d, 0x1a}}, - {{0x84, 0xc4, 0x0e, 0x52, 0x55, 0xf0, 0xfe, 0x2c, 0x89, 0x85, 0x10, 0x5e, 0xd9, 0x1a, 0x9b, 0xd3, 0x08, 0x4b, 0x02, 0x81, 0xa7, 0x3b, 0xaf, 0x1a, 0x09, 0x60, 0xfe, 0x22, 0x28, 0xc6, 0xc3, 0x39}, {0xac, 0x67, 0x32, 0x22, 0x4e, 0x89, 0xf8, 0x45, 0x79, 0xd8, 0xf2, 0x94, 0xd4, 0x0e, 0x96, 0x42, 0x28, 0xa6, 0x2e, 0x0a, 0x75, 0x59, 0xc3, 0x91, 0xd8, 0xb9, 0xa2, 0x2e, 0x58, 0x3f, 0x55, 0x00}}, - {{0x4c, 0xa2, 0x8d, 0x73, 0xf4, 0x97, 0xd7, 0x9d, 0x58, 0x31, 0x90, 0x33, 0xca, 0x7d, 0x59, 0x27, 0x88, 0x39, 0xe1, 0x55, 0x2d, 0xcf, 0x69, 0x25, 0xc7, 0xec, 0x5a, 0x85, 0x03, 0x44, 0x35, 0x3a}, {0x58, 0x8d, 0x21, 0x24, 0xdf, 0x53, 0xd4, 0x8c, 0xba, 0x7b, 0xdf, 0x39, 0x6a, 0x60, 0xb8, 0x3e, 0x04, 0x2c, 0x6d, 0x01, 0xcd, 0xb3, 0xb6, 0xe1, 0x59, 0x28, 0x2f, 0x12, 0x01, 0x1e, 0xc0, 0x2a}}, - {{0xef, 0xbb, 0x74, 0xee, 0xc3, 0xbe, 0xee, 0x05, 0x20, 0x76, 0x61, 0xd2, 0xb6, 0xbe, 0x35, 0x92, 0xfd, 0x92, 0x4f, 0xc3, 0x9b, 0xe8, 0x1b, 0xbe, 0x8b, 0xb8, 0x2c, 0x75, 0x1c, 0xf0, 0x52, 0x3e}, {0x53, 0xaf, 0x8a, 0xcd, 0xca, 0x51, 0xa9, 0xf3, 0x43, 0xc3, 0x7e, 0x09, 0xe4, 0x97, 0x4a, 0xc7, 0x22, 0x9a, 0xfc, 0xbf, 0x05, 0x9e, 0x2e, 0x09, 0x39, 0xba, 0xe3, 0x11, 0xc8, 0x5f, 0x5a, 0x3d}}, - {{0x58, 0x3a, 0x38, 0xd5, 0x2c, 0x3d, 0xe5, 0x0c, 0x2f, 0xe7, 0xa3, 0x6c, 0x32, 0xeb, 0xf1, 0x3e, 0x9b, 0xfc, 0x98, 0x76, 0x88, 0x76, 0x78, 0x3c, 0xc6, 0xc6, 0xd2, 0x49, 0xd7, 0xca, 0x74, 0x3e}, {0xd5, 0x13, 0x97, 0x0c, 0xed, 0xfa, 0x1c, 0x1f, 0x78, 0x18, 0x3b, 0xd4, 0xd9, 0xcd, 0x44, 0x3c, 0xbe, 0x8d, 0xa6, 0x45, 0xe2, 0x49, 0x9e, 0xa9, 0x90, 0x2e, 0x57, 0x67, 0xac, 0x8b, 0x13, 0x3d}}, - {{0x2f, 0xc7, 0x6e, 0xd7, 0x35, 0xda, 0xf7, 0x83, 0xe5, 0x06, 0x9e, 0x35, 0xe6, 0x36, 0x1b, 0x5d, 0x07, 0x15, 0x08, 0x0e, 0x98, 0xa1, 0x67, 0x44, 0x58, 0xfc, 0xcf, 0x12, 0xd4, 0xe9, 0x16, 0x34}, {0x65, 0x77, 0xd4, 0x8e, 0x07, 0x09, 0x30, 0x27, 0x90, 0x7d, 0x2b, 0x91, 0xb4, 0x0a, 0x22, 0xb0, 0xc9, 0xe9, 0x19, 0x63, 0x2b, 0xbc, 0x16, 0xb4, 0x2c, 0x34, 0x9a, 0xa1, 0xcc, 0xd4, 0xfa, 0x10}}, - {{0x4f, 0x88, 0x21, 0x91, 0x94, 0x27, 0xce, 0xa6, 0x44, 0x8e, 0xe8, 0x02, 0x8f, 0xa1, 0xa8, 0x92, 0xe9, 0x43, 0x95, 0x39, 0xd1, 0x04, 0xdf, 0xca, 0x76, 0x17, 0x7e, 0xa2, 0x7c, 0x98, 0xf2, 0x35}, {0x63, 0xf8, 0xd8, 0xe5, 0xa3, 0x1e, 0x73, 0x4f, 0x28, 0x80, 0xcb, 0xda, 0xc9, 0xb1, 0xfa, 0xbe, 0xd4, 0x02, 0x4e, 0xab, 0xef, 0xd4, 0xbd, 0x91, 0xec, 0x47, 0xb8, 0x6c, 0x5e, 0x3c, 0xea, 0x39}}, - {{0x26, 0xa5, 0x40, 0x90, 0x38, 0xd6, 0x0e, 0xba, 0x2f, 0xce, 0x46, 0x10, 0x2d, 0x6a, 0xe3, 0xad, 0xda, 0xbf, 0x63, 0x7d, 0x1f, 0x03, 0xc4, 0x07, 0x4b, 0x6d, 0xf1, 0xef, 0xe5, 0x7f, 0x05, 0x37}, {0x4f, 0x7d, 0x0f, 0x23, 0x9a, 0xda, 0x3d, 0xcb, 0x2c, 0xe2, 0xc4, 0xac, 0xc7, 0xfa, 0xc2, 0x3e, 0xca, 0x52, 0x22, 0x60, 0xc8, 0x83, 0xbc, 0x09, 0x50, 0x18, 0x90, 0x7b, 0x69, 0xc1, 0xd7, 0x01}}, - {{0x8b, 0xaa, 0x62, 0x70, 0x75, 0x22, 0x16, 0x03, 0x68, 0xeb, 0x01, 0xc3, 0x78, 0xbf, 0xe7, 0x06, 0xfe, 0xe8, 0x8d, 0x51, 0x8c, 0xea, 0x45, 0x5a, 0x16, 0x5a, 0xd8, 0xfd, 0x76, 0xf1, 0x8b, 0x1a}, {0xa9, 0x3d, 0x61, 0x62, 0x97, 0xed, 0xe4, 0x1d, 0x8e, 0xc5, 0xa5, 0x75, 0x5b, 0x26, 0x2d, 0x7c, 0x3c, 0x49, 0xa6, 0x13, 0xe1, 0x84, 0xcf, 0xde, 0xd9, 0x1a, 0x18, 0xfc, 0xac, 0xc9, 0x53, 0x18}}, - {{0x7a, 0x85, 0x5c, 0xda, 0x90, 0xf6, 0xf8, 0x18, 0x66, 0x4c, 0x7a, 0xf4, 0x54, 0x5e, 0xaf, 0x8b, 0x87, 0xe4, 0x56, 0x90, 0xdb, 0x5a, 0x96, 0xc5, 0x23, 0x47, 0x0b, 0xc5, 0x4f, 0x5e, 0x41, 0x0b}, {0x33, 0x52, 0xc1, 0xd1, 0x8b, 0x8e, 0x58, 0xf7, 0x4e, 0xa0, 0x1e, 0x7b, 0x2d, 0x51, 0xb8, 0x3b, 0xda, 0x73, 0xda, 0xb3, 0x10, 0x0e, 0x82, 0x37, 0xaf, 0xe0, 0x5a, 0x01, 0x26, 0x10, 0x2a, 0x2c}}, - {{0xfa, 0x38, 0x40, 0xab, 0xa2, 0x0d, 0x91, 0xc4, 0xb0, 0x4b, 0x17, 0x21, 0xf6, 0x0b, 0x19, 0x89, 0x31, 0x1c, 0x70, 0xfe, 0x46, 0x33, 0xb6, 0x11, 0x50, 0x93, 0x3f, 0x58, 0x81, 0xfd, 0xe3, 0x01}, {0x1e, 0x60, 0xc1, 0x98, 0xc0, 0x17, 0x61, 0xdc, 0x1e, 0xf8, 0x5e, 0xe4, 0x7b, 0xa2, 0xb5, 0x1a, 0x12, 0x16, 0x7e, 0xf3, 0x16, 0x3f, 0xa2, 0x52, 0xcf, 0xe6, 0xe2, 0x97, 0x80, 0x7f, 0x0a, 0x0b}}, - {{0xa4, 0xe7, 0x8a, 0xe7, 0x2f, 0x06, 0x0b, 0x52, 0x5e, 0xe1, 0xc5, 0x15, 0xc9, 0x2a, 0xfd, 0x3c, 0x42, 0xd5, 0xc1, 0x41, 0x82, 0x0d, 0x6f, 0x6f, 0x32, 0x9f, 0x13, 0x60, 0xb4, 0xbb, 0x45, 0x3d}, {0x79, 0x38, 0x7a, 0xc9, 0x97, 0x5c, 0xac, 0xb1, 0x21, 0x53, 0xab, 0x56, 0xf2, 0xc0, 0x0c, 0xef, 0xc6, 0x60, 0x84, 0xe1, 0x6f, 0x37, 0x2a, 0x62, 0xb5, 0x32, 0x4c, 0x37, 0xfd, 0x7e, 0x29, 0x05}}, - {{0x0a, 0xc6, 0x5f, 0x4c, 0x73, 0x49, 0x26, 0xc2, 0xe6, 0x50, 0x5a, 0xb1, 0x28, 0x2f, 0x93, 0xda, 0xd4, 0xce, 0x75, 0x9c, 0x13, 0xe4, 0xe7, 0xcc, 0x0c, 0xca, 0xf3, 0x84, 0xdf, 0x7e, 0x0a, 0x2a}, {0xc6, 0xe9, 0x51, 0xcf, 0x4d, 0xae, 0xe9, 0x97, 0x62, 0xeb, 0xf8, 0x34, 0x76, 0x6a, 0x63, 0x77, 0xd7, 0x84, 0xd6, 0x15, 0x1f, 0x73, 0xdb, 0xc1, 0x80, 0x22, 0x11, 0x28, 0xa0, 0x45, 0xae, 0x28}}, - {{0x06, 0xf9, 0x6f, 0x52, 0x04, 0x79, 0xe1, 0x48, 0x5d, 0xd2, 0x18, 0x31, 0xaf, 0x96, 0xfd, 0xd5, 0x85, 0x3e, 0x5a, 0x29, 0x79, 0x13, 0xf2, 0x16, 0x65, 0xf0, 0x09, 0x12, 0x82, 0x66, 0x6e, 0x05}, {0x53, 0x48, 0xf0, 0x18, 0x0c, 0x3b, 0x09, 0x4d, 0xed, 0x36, 0x57, 0xc7, 0xcf, 0xae, 0x8c, 0xf2, 0x9b, 0xa6, 0x6f, 0x96, 0xba, 0x3c, 0x24, 0x01, 0x95, 0xe1, 0xf4, 0xa8, 0xd1, 0x69, 0xf0, 0x2b}}, - {{0x18, 0x8c, 0x7a, 0x3f, 0xa3, 0x2c, 0xab, 0xa2, 0xee, 0x3f, 0x2c, 0x29, 0x9e, 0x9a, 0xbf, 0x5f, 0x6f, 0xbf, 0xd4, 0x62, 0x9b, 0xfb, 0xd2, 0x42, 0xa8, 0xb2, 0x19, 0x50, 0xc4, 0x87, 0x13, 0x15}, {0x92, 0x8f, 0x9d, 0x70, 0x99, 0x0a, 0xde, 0x45, 0x51, 0x2d, 0x8c, 0xf1, 0x2b, 0xc6, 0x3b, 0x01, 0xb5, 0xa5, 0x51, 0xe4, 0x77, 0xe4, 0x17, 0xdc, 0xfa, 0xcc, 0x48, 0x27, 0xb3, 0xe9, 0x9b, 0x18}}, - {{0x97, 0x36, 0x38, 0xc3, 0xc0, 0x10, 0xd2, 0xb1, 0x1e, 0x9f, 0x98, 0x0a, 0xf0, 0x1f, 0xe9, 0xdd, 0x0b, 0xae, 0xc4, 0xfa, 0x11, 0x55, 0xb1, 0x57, 0x3a, 0xfb, 0xa9, 0xed, 0x09, 0x55, 0x15, 0x34}, {0xa0, 0xf2, 0x04, 0x4d, 0xe4, 0xa0, 0x36, 0x03, 0x68, 0x11, 0x1d, 0xf5, 0x30, 0x80, 0x38, 0x0c, 0xb6, 0x52, 0x9b, 0x35, 0x18, 0x02, 0x88, 0xdb, 0x04, 0x19, 0x29, 0x37, 0x54, 0x79, 0x69, 0x16}}, - {{0x46, 0xd6, 0x15, 0x2e, 0x39, 0x4d, 0x54, 0xf7, 0xfe, 0xbf, 0x5c, 0xe7, 0xb5, 0x85, 0x2c, 0x04, 0x1e, 0x37, 0xa3, 0xc3, 0xe1, 0xc7, 0x8b, 0xe3, 0xfd, 0x3f, 0x55, 0x39, 0x54, 0x49, 0x78, 0x1f}, {0x55, 0xfe, 0x95, 0xce, 0xef, 0x03, 0xb0, 0xb3, 0x21, 0xa2, 0x43, 0x3e, 0x20, 0xf0, 0x47, 0x34, 0xa7, 0xa4, 0x01, 0xf1, 0x00, 0x5b, 0xec, 0xd3, 0xbb, 0xe9, 0xca, 0xfd, 0x55, 0xfb, 0xaf, 0x1d}}, - {{0x71, 0x57, 0x43, 0x3b, 0xe4, 0xb2, 0x22, 0xd0, 0xa9, 0x5f, 0xae, 0x0d, 0x73, 0x80, 0x98, 0x1f, 0x79, 0x22, 0x9d, 0xee, 0xae, 0x1d, 0x9c, 0xa1, 0xe2, 0xfb, 0x8a, 0x1f, 0xf1, 0x10, 0x7c, 0x2d}, {0x51, 0x9e, 0xc6, 0xe5, 0xc4, 0x4d, 0x3e, 0xe5, 0xc3, 0xbf, 0x3c, 0xe7, 0x7b, 0x1c, 0xf4, 0x2a, 0x18, 0x70, 0x8b, 0x6a, 0x36, 0x11, 0xe0, 0xf0, 0xbf, 0xfc, 0x77, 0x8c, 0xc8, 0x44, 0x77, 0x0b}}, - {{0xb9, 0xbc, 0x40, 0x3b, 0x62, 0xbe, 0xd7, 0x9e, 0x96, 0xeb, 0xdf, 0x58, 0x60, 0xf6, 0x31, 0x3e, 0x0d, 0x43, 0x31, 0x63, 0xc1, 0x90, 0x58, 0x01, 0xa9, 0x64, 0x86, 0xf1, 0xae, 0x7e, 0xad, 0x21}, {0x0b, 0xf6, 0x57, 0xde, 0xd6, 0x85, 0x97, 0x49, 0x61, 0x28, 0x6b, 0xc4, 0x1d, 0x9c, 0x83, 0x3a, 0x9a, 0xdf, 0xcd, 0xe1, 0x0e, 0xad, 0xa4, 0xae, 0xb2, 0x53, 0x0b, 0x1d, 0x0e, 0x29, 0x72, 0x24}}, - {{0xcf, 0xd3, 0xb0, 0x1e, 0x84, 0x32, 0x3e, 0xa7, 0x57, 0xcd, 0xcb, 0x16, 0xb8, 0xc1, 0xd2, 0x5d, 0xb6, 0x66, 0xc2, 0xa9, 0x59, 0x78, 0x16, 0xac, 0xdc, 0x5f, 0x2f, 0xee, 0x80, 0x2f, 0xd0, 0x39}, {0xe5, 0x08, 0xf4, 0x81, 0x23, 0xb5, 0x3d, 0xf3, 0xce, 0x94, 0xb6, 0xdd, 0x64, 0xd4, 0x67, 0xa2, 0x7a, 0x3f, 0xaf, 0x83, 0x54, 0x2c, 0x0d, 0xde, 0xfc, 0x8a, 0xb0, 0x4e, 0xd7, 0xd9, 0x05, 0x31}}, - {{0x1c, 0x74, 0x51, 0xae, 0xf2, 0xd3, 0x06, 0x0f, 0x80, 0x5a, 0xb9, 0xa4, 0x5c, 0x9d, 0x47, 0xb7, 0xb0, 0x89, 0x15, 0x47, 0xab, 0x36, 0x39, 0x78, 0xce, 0xab, 0x73, 0xcf, 0xf7, 0x7c, 0xe1, 0x17}, {0xa6, 0x0c, 0x39, 0x7e, 0xf0, 0x32, 0x8e, 0x22, 0xa8, 0x16, 0x4d, 0x74, 0xe7, 0x35, 0xfe, 0x92, 0xa7, 0xdf, 0xd9, 0xa1, 0x1c, 0x5e, 0x5f, 0x23, 0x26, 0x67, 0xd6, 0x3b, 0x5b, 0x4c, 0xdb, 0x2a}}, - {{0x41, 0x38, 0x66, 0x32, 0x66, 0x60, 0x19, 0x58, 0x04, 0x9f, 0x28, 0x6b, 0x1e, 0xb9, 0xda, 0x24, 0x05, 0x41, 0xa4, 0x63, 0x49, 0xcf, 0x9a, 0xb7, 0x03, 0x77, 0xb6, 0x0c, 0xc6, 0xe5, 0xda, 0x21}, {0x6e, 0x57, 0x06, 0x64, 0x7e, 0x48, 0x23, 0xa2, 0xb2, 0x7e, 0x67, 0x74, 0x9e, 0x9d, 0xb6, 0x86, 0xe2, 0x6a, 0x8b, 0x04, 0x1d, 0x53, 0x2e, 0x7e, 0x67, 0x05, 0xb9, 0x46, 0x64, 0xbb, 0x96, 0x17}}, - {{0xdc, 0x04, 0x1d, 0x56, 0x45, 0xeb, 0x90, 0x6b, 0x9a, 0xae, 0x1c, 0x13, 0x60, 0x94, 0x43, 0xe7, 0x74, 0x32, 0xb1, 0xd3, 0x72, 0x4e, 0x35, 0x27, 0xf2, 0xdb, 0xe6, 0x1c, 0x96, 0x89, 0x1b, 0x18}, {0xcb, 0xeb, 0x7d, 0x6e, 0x74, 0xa5, 0x93, 0x43, 0x21, 0x73, 0x4b, 0x37, 0xb0, 0x57, 0xb9, 0x17, 0xff, 0xf4, 0xeb, 0x0a, 0x99, 0x14, 0x8f, 0xf4, 0x59, 0xad, 0xd8, 0x80, 0xcc, 0xa0, 0xf0, 0x2a}}, - {{0xa9, 0xc5, 0x81, 0x9a, 0x9c, 0xd2, 0x86, 0x8a, 0x97, 0x1f, 0x1a, 0x41, 0x2f, 0x6d, 0x93, 0x23, 0x25, 0x95, 0xfa, 0x40, 0x2a, 0x24, 0xf6, 0x50, 0x4b, 0x0a, 0x15, 0xc3, 0xf1, 0xfa, 0xb0, 0x05}, {0x95, 0x1c, 0x83, 0xab, 0x93, 0x9a, 0x0c, 0xc7, 0xb1, 0xef, 0xea, 0xce, 0xe9, 0x9a, 0xd2, 0x6e, 0x03, 0xcf, 0xe1, 0x22, 0xb2, 0x68, 0xfe, 0xc7, 0xb4, 0x44, 0x18, 0x19, 0xd0, 0xcf, 0x1d, 0x38}}, - {{0xd9, 0xb7, 0xbe, 0x5d, 0x27, 0x31, 0x5a, 0x7d, 0xb6, 0xda, 0xce, 0x25, 0xe5, 0x3d, 0xe0, 0x79, 0xb4, 0xea, 0xdc, 0x9f, 0xdc, 0x02, 0x5a, 0x93, 0x48, 0x44, 0x11, 0x78, 0x19, 0x47, 0x4d, 0x2b}, {0xb2, 0x1e, 0xfe, 0xe2, 0xdf, 0x78, 0x73, 0x76, 0x18, 0x5f, 0xaa, 0xc9, 0x01, 0x93, 0x91, 0xbe, 0x8e, 0xa2, 0x96, 0x47, 0xc0, 0x48, 0xee, 0x60, 0x93, 0x46, 0x7f, 0x7b, 0x8c, 0x3e, 0x24, 0x2f}}, - {{0x02, 0x63, 0x6a, 0x3b, 0xec, 0xfc, 0xac, 0x58, 0xb4, 0xff, 0x49, 0x8a, 0xb2, 0xce, 0x8c, 0x77, 0x04, 0x8a, 0x71, 0x27, 0x5d, 0xf5, 0x28, 0x8c, 0xb3, 0x7d, 0x24, 0x6f, 0x86, 0xcb, 0x4e, 0x3c}, {0x86, 0xfc, 0x3f, 0x7b, 0xdf, 0xd4, 0xbe, 0x7f, 0xed, 0xf2, 0x70, 0xd4, 0xc9, 0x6c, 0x40, 0x85, 0x20, 0x02, 0x0e, 0x83, 0x3d, 0x5e, 0xef, 0x0b, 0x8e, 0xd7, 0x7a, 0x45, 0x74, 0xc8, 0x60, 0x2c}}, - {{0x76, 0x56, 0x18, 0xf9, 0xb7, 0xb9, 0xb1, 0x2f, 0x85, 0xe3, 0x79, 0xf9, 0x85, 0x09, 0x9c, 0x3b, 0x3f, 0xdf, 0x9e, 0xb1, 0x99, 0xe2, 0x64, 0x3c, 0x1a, 0xe2, 0xc2, 0xf4, 0xc7, 0x03, 0xc6, 0x38}, {0xf9, 0x34, 0xc3, 0x3b, 0x4b, 0x4e, 0x28, 0xb3, 0x21, 0x9b, 0xa6, 0x9c, 0x9d, 0x4a, 0x14, 0x1a, 0xb6, 0xb9, 0x92, 0x49, 0x79, 0xc2, 0x0c, 0x8d, 0x85, 0x10, 0x7c, 0xd5, 0xca, 0x19, 0xe6, 0x0c}}, - {{0x7a, 0x61, 0x95, 0xa6, 0xa8, 0xd1, 0x55, 0x95, 0x5e, 0x4c, 0x64, 0x80, 0xfe, 0x43, 0x38, 0x9f, 0xe7, 0xc2, 0x85, 0x8d, 0xcb, 0x35, 0x95, 0xa4, 0x6f, 0x97, 0x7c, 0xeb, 0x13, 0x21, 0x01, 0x2d}, {0xb5, 0x50, 0x91, 0x64, 0xbd, 0x72, 0xb7, 0xb4, 0xd5, 0x1f, 0xeb, 0xbd, 0x2f, 0xd9, 0xdd, 0x45, 0x41, 0x1b, 0xd8, 0x41, 0x43, 0x64, 0xaa, 0xed, 0x92, 0x02, 0xe0, 0x12, 0xc6, 0xc1, 0x66, 0x29}}, - {{0x23, 0x9f, 0xd5, 0xff, 0xb2, 0x00, 0x95, 0x60, 0x48, 0xde, 0x58, 0xb2, 0xef, 0x61, 0xc2, 0xc0, 0xac, 0x00, 0xc2, 0x51, 0x7b, 0xb9, 0xcd, 0xcb, 0xa6, 0x70, 0x4a, 0x5b, 0x3a, 0x2f, 0xef, 0x0b}, {0x26, 0xc2, 0x73, 0xdf, 0xcf, 0xff, 0xf9, 0x69, 0xdf, 0x5d, 0x51, 0x5b, 0x1d, 0xf5, 0x86, 0x3c, 0x20, 0xe0, 0x5e, 0xef, 0x6c, 0x40, 0x26, 0x08, 0xc9, 0xe8, 0x5f, 0x22, 0xfe, 0x31, 0xf0, 0x05}}, - {{0x6c, 0x73, 0x19, 0x09, 0x2e, 0xd5, 0x4d, 0x31, 0xff, 0x39, 0xe9, 0x55, 0xea, 0xb5, 0x54, 0xf5, 0x27, 0x9f, 0x7f, 0xd0, 0xd8, 0xa5, 0x75, 0x77, 0xd4, 0xaf, 0xbe, 0x57, 0xfb, 0x43, 0xb9, 0x18}, {0xe7, 0x63, 0x45, 0x87, 0x74, 0x13, 0x63, 0xf5, 0xd2, 0x8c, 0x2e, 0x62, 0xd6, 0xa9, 0x1c, 0xbd, 0x4e, 0xcc, 0x1b, 0x61, 0x06, 0x60, 0x60, 0xd0, 0xa0, 0x02, 0xf6, 0x38, 0x5e, 0x02, 0x0d, 0x36}}, - {{0xb9, 0xd3, 0x2d, 0x4e, 0x74, 0x2e, 0x9e, 0x39, 0xba, 0x0c, 0x83, 0x8b, 0xf8, 0x74, 0xe3, 0x43, 0xe0, 0xf4, 0xcd, 0x48, 0xc4, 0xa1, 0x89, 0x42, 0x16, 0x97, 0x94, 0xb5, 0x15, 0xf3, 0x6d, 0x19}, {0xeb, 0x4d, 0x3f, 0x67, 0xd6, 0x6c, 0x88, 0xc2, 0xd3, 0x4e, 0x9f, 0xb8, 0x28, 0x27, 0xf2, 0x21, 0xfe, 0x48, 0xa9, 0xd9, 0x66, 0x6d, 0x39, 0x34, 0x75, 0xbb, 0xfe, 0x40, 0xb4, 0x5f, 0x89, 0x10}}, - {{0x4a, 0xdd, 0x82, 0xfc, 0x51, 0xa3, 0x16, 0x43, 0x50, 0xed, 0xfc, 0x4c, 0x50, 0x79, 0x59, 0xc9, 0x5e, 0xd1, 0xcf, 0x84, 0x3a, 0x94, 0x73, 0x72, 0xc1, 0x6a, 0xb9, 0xc1, 0x6c, 0xaa, 0xaa, 0x15}, {0x6d, 0x79, 0x2b, 0x51, 0x76, 0xd6, 0x99, 0x1b, 0xbb, 0xdb, 0xa5, 0xcb, 0xf1, 0xdf, 0x39, 0xce, 0x44, 0x6d, 0x62, 0x14, 0xa7, 0x4f, 0x1d, 0x42, 0x69, 0x5b, 0xaf, 0xdf, 0x2a, 0x9d, 0xad, 0x34}}, - {{0xef, 0x6e, 0x4a, 0x10, 0xd1, 0xa6, 0xad, 0x49, 0xcf, 0xb7, 0xb5, 0xcf, 0x4f, 0x02, 0x8b, 0xcf, 0x91, 0xcc, 0x3b, 0x3a, 0x9d, 0xcc, 0x0c, 0x84, 0xfc, 0xdd, 0xe1, 0x64, 0x44, 0x57, 0xb9, 0x29}, {0x80, 0xc2, 0x8c, 0x70, 0x6a, 0x71, 0x87, 0x0b, 0x35, 0x44, 0x21, 0x6f, 0x0f, 0x80, 0x3d, 0xf9, 0xff, 0x83, 0x6a, 0x2d, 0x67, 0x3c, 0x51, 0x1d, 0xbc, 0xf3, 0xbd, 0xc1, 0x91, 0xd4, 0xe6, 0x0a}}, - {{0x72, 0xc1, 0xfc, 0xf1, 0xb0, 0x41, 0x5e, 0x47, 0xb0, 0x0b, 0xc4, 0x69, 0x08, 0x14, 0xb7, 0x09, 0x14, 0x0c, 0x58, 0x6b, 0xaa, 0x2e, 0xed, 0xc7, 0xae, 0x7e, 0x56, 0x45, 0xce, 0xdd, 0x5a, 0x1d}, {0xa9, 0x19, 0x0a, 0xed, 0x89, 0xa9, 0x05, 0xb8, 0x6a, 0xce, 0x48, 0x4a, 0x92, 0xa0, 0xf0, 0x18, 0xba, 0x48, 0x67, 0x66, 0x90, 0xc3, 0x7c, 0x37, 0x84, 0x87, 0x9b, 0x5e, 0xec, 0x7b, 0x01, 0x01}}, - {{0xd1, 0x4f, 0x4a, 0xdf, 0x9d, 0x86, 0x24, 0xc4, 0x77, 0x8e, 0x06, 0x15, 0xc6, 0xe9, 0x89, 0xcb, 0x1e, 0xad, 0x64, 0x0d, 0x9d, 0x5f, 0x73, 0x65, 0xa8, 0xd2, 0xef, 0xf3, 0x10, 0x19, 0x16, 0x1a}, {0xb9, 0xe2, 0x96, 0x2e, 0x44, 0xec, 0x2a, 0x1c, 0xd1, 0x3c, 0x93, 0xe7, 0xbb, 0x6c, 0xe2, 0xe5, 0x33, 0x0b, 0xcf, 0xaf, 0xa5, 0xf5, 0x52, 0x41, 0xc2, 0xaf, 0xd7, 0x2c, 0xf6, 0x33, 0xbd, 0x18}}, - {{0xa3, 0x62, 0x12, 0x0f, 0xd4, 0x2e, 0xef, 0x6c, 0xb6, 0x13, 0x08, 0x9a, 0x6a, 0xbe, 0x9f, 0x62, 0x9a, 0x5e, 0x70, 0xfd, 0x7a, 0xe9, 0x88, 0xe1, 0xdd, 0xbb, 0x5e, 0x08, 0xae, 0xab, 0x81, 0x1c}, {0xcc, 0x14, 0x3d, 0xd8, 0x2d, 0xe3, 0x64, 0x6b, 0x72, 0x8e, 0xd3, 0xb7, 0x12, 0xe8, 0x1c, 0x05, 0x5d, 0x95, 0xab, 0x9d, 0xff, 0xe5, 0x9c, 0x7c, 0x3a, 0x55, 0xd5, 0x7e, 0xb2, 0xdc, 0x11, 0x2c}}, - {{0x5c, 0x7c, 0x43, 0x65, 0x53, 0x10, 0x86, 0xa4, 0xb5, 0x99, 0x49, 0x59, 0x28, 0x35, 0xef, 0xba, 0x56, 0x78, 0xd5, 0x8b, 0x21, 0x2d, 0xbc, 0x6e, 0xd8, 0x20, 0x8d, 0x8f, 0xa8, 0xf3, 0x94, 0x11}, {0x44, 0x0b, 0xc6, 0x02, 0xcf, 0x16, 0x83, 0xc5, 0x2c, 0x4f, 0x95, 0x66, 0x73, 0xdb, 0xe8, 0xba, 0x74, 0xff, 0xc8, 0x4b, 0x4b, 0xfe, 0x21, 0x13, 0xc9, 0x66, 0xdb, 0x5c, 0x5d, 0xec, 0x90, 0x1f}}, - {{0x1b, 0x06, 0x0b, 0x50, 0xbc, 0x8b, 0x78, 0x3e, 0xb4, 0xd1, 0x40, 0x7d, 0xd5, 0x04, 0x9f, 0xa3, 0x2e, 0x32, 0x95, 0xe6, 0x0a, 0xff, 0x75, 0x10, 0x6f, 0xd7, 0xeb, 0x17, 0xf2, 0xf7, 0xe8, 0x29}, {0xc9, 0x1f, 0x13, 0x6b, 0x79, 0x0b, 0x38, 0xbf, 0x97, 0x45, 0x3b, 0xf5, 0x0d, 0xa7, 0x64, 0x64, 0x44, 0x46, 0x97, 0xdd, 0xe6, 0x66, 0x26, 0x70, 0x50, 0xe6, 0x89, 0x96, 0xd1, 0xb0, 0xfe, 0x12}}, - {{0x71, 0x49, 0x5d, 0x4e, 0x00, 0x2e, 0x13, 0xfd, 0x72, 0x60, 0xea, 0xb5, 0xd2, 0x01, 0x05, 0xc5, 0xd7, 0x9e, 0x65, 0x2e, 0x52, 0xb9, 0x02, 0x92, 0x11, 0x7b, 0x43, 0x10, 0xaa, 0x84, 0xb2, 0x3a}, {0xe1, 0xf5, 0xf7, 0x70, 0x20, 0x8d, 0xe0, 0x4d, 0x08, 0xc5, 0x48, 0x56, 0x7d, 0xb4, 0x0f, 0x55, 0x33, 0x9c, 0x73, 0x60, 0x30, 0x5a, 0x4a, 0xf7, 0xec, 0x48, 0xdb, 0x59, 0x8c, 0xc9, 0x52, 0x3b}}, - {{0x66, 0xf2, 0x9d, 0x4d, 0xc3, 0x72, 0x65, 0xb5, 0x25, 0xe6, 0x6e, 0x2f, 0x31, 0x8d, 0xcb, 0xd4, 0x01, 0xa5, 0x0a, 0x6f, 0x93, 0x21, 0x7e, 0xcd, 0xb7, 0xbc, 0xb9, 0xe1, 0xb5, 0xb0, 0x73, 0x31}, {0x2b, 0x38, 0x36, 0xd9, 0x67, 0x03, 0xb7, 0x7b, 0xa0, 0x9f, 0x24, 0x1a, 0xe0, 0x03, 0xd5, 0x90, 0x5a, 0x29, 0xeb, 0x21, 0xeb, 0xfc, 0x1a, 0x1d, 0xde, 0xf2, 0xb7, 0x0a, 0x86, 0x55, 0x42, 0x2a}}, - {{0x8a, 0x42, 0xda, 0xc9, 0x65, 0xff, 0x5b, 0xea, 0x54, 0x53, 0xdb, 0xea, 0x20, 0xa5, 0xcb, 0xa4, 0xdb, 0x7b, 0x03, 0x0b, 0x43, 0x50, 0x0d, 0xd8, 0x71, 0xd4, 0xbf, 0x17, 0x3e, 0x49, 0xf5, 0x30}, {0xa5, 0xdb, 0x99, 0xdd, 0x7f, 0x0e, 0x52, 0xa7, 0x25, 0x2a, 0xa3, 0xd9, 0xd0, 0x6e, 0x12, 0x5d, 0x66, 0x9c, 0x3e, 0x52, 0xc5, 0x77, 0x35, 0xf8, 0x2a, 0xd4, 0x12, 0x5f, 0x36, 0x0d, 0x96, 0x30}}, - {{0xa6, 0x6a, 0x44, 0xac, 0x13, 0x5d, 0x98, 0x66, 0x12, 0x6e, 0x77, 0x96, 0x26, 0x2f, 0x73, 0xb7, 0xb1, 0x50, 0x01, 0x85, 0x40, 0xb6, 0xb7, 0x1f, 0x29, 0xa8, 0xac, 0xe3, 0x5c, 0x04, 0x5c, 0x33}, {0x01, 0xae, 0xdf, 0xbd, 0xf8, 0xb8, 0x34, 0x11, 0x4d, 0x9e, 0x0b, 0x11, 0x22, 0x96, 0x14, 0xfc, 0x5a, 0x49, 0xd2, 0xfe, 0xfe, 0x9d, 0x2a, 0x29, 0x8c, 0x9f, 0xd6, 0x78, 0x74, 0x47, 0x23, 0x2d}}, - {{0xb9, 0xe7, 0xe0, 0xbf, 0x84, 0xa3, 0x97, 0xe6, 0x61, 0x8f, 0xec, 0x7e, 0x48, 0xe5, 0x00, 0x96, 0x80, 0x40, 0x0d, 0xd0, 0x11, 0xd9, 0xf6, 0x5c, 0x3d, 0x9c, 0xb4, 0x7f, 0xef, 0x9f, 0x72, 0x2f}, {0xea, 0xcc, 0xb3, 0x0e, 0xcd, 0x44, 0x27, 0x6f, 0xee, 0x75, 0x0f, 0x85, 0x82, 0xf5, 0xa3, 0x20, 0x26, 0xf6, 0xa9, 0x44, 0x13, 0xde, 0x5d, 0x0a, 0x99, 0x11, 0xba, 0x5a, 0x74, 0x72, 0xce, 0x35}}, - {{0x66, 0xa4, 0xad, 0x21, 0x33, 0xe7, 0x45, 0x77, 0xc1, 0xea, 0x4e, 0x9e, 0xaf, 0xb0, 0x96, 0x7e, 0x08, 0x41, 0xfe, 0xd2, 0xd2, 0x89, 0x76, 0x90, 0x59, 0xde, 0x9a, 0x27, 0xec, 0x74, 0xd7, 0x0a}, {0x45, 0xf9, 0x30, 0xfa, 0xd2, 0x26, 0x87, 0xeb, 0x8e, 0x75, 0x2a, 0x95, 0x36, 0xfb, 0x9f, 0xf5, 0x5b, 0xf1, 0x7b, 0x27, 0x97, 0xd3, 0x6c, 0xf4, 0x1e, 0x4e, 0x88, 0xa7, 0x00, 0xe6, 0x42, 0x0e}}, - {{0x39, 0x7d, 0x54, 0x1a, 0xe8, 0xc6, 0xd7, 0x42, 0x62, 0xbd, 0xa8, 0x50, 0x5f, 0x69, 0x71, 0xb1, 0xba, 0x16, 0x39, 0x57, 0x93, 0x5f, 0x87, 0xfe, 0x47, 0xf1, 0x1a, 0x9e, 0xa1, 0x81, 0x7b, 0x2b}, {0xf0, 0x7c, 0x58, 0xeb, 0xbc, 0xf6, 0x79, 0x54, 0xab, 0x06, 0x9e, 0xf3, 0x7c, 0x82, 0xa1, 0x55, 0xae, 0xaa, 0xe9, 0xd3, 0xc4, 0x0f, 0x9c, 0x2a, 0x82, 0xe6, 0x19, 0x9c, 0x67, 0xb5, 0x34, 0x19}}, - {{0xfb, 0x21, 0x8f, 0x01, 0x78, 0xeb, 0x8f, 0xe1, 0x07, 0x00, 0xa5, 0x0f, 0x75, 0x40, 0xa5, 0xcf, 0x8b, 0x5e, 0x0f, 0x9d, 0xd5, 0xf7, 0xe3, 0x05, 0x54, 0x37, 0x1a, 0xfe, 0xc1, 0x4c, 0xc9, 0x2c}, {0x1c, 0xae, 0x4c, 0x8b, 0x24, 0xf3, 0xd2, 0xc2, 0xdd, 0xde, 0xa9, 0xc5, 0x45, 0x77, 0x7f, 0x44, 0x68, 0x9c, 0xf6, 0x32, 0xcb, 0x26, 0x21, 0x3c, 0x5b, 0x5d, 0xa5, 0xfb, 0xf6, 0xcf, 0xd2, 0x08}}, - {{0x12, 0xc2, 0x4c, 0x44, 0x90, 0x53, 0xd8, 0xb5, 0x10, 0x3c, 0xf6, 0xbe, 0x9d, 0xcf, 0x8f, 0xe0, 0xe3, 0x80, 0x3c, 0xfb, 0x6a, 0x86, 0xcc, 0xe6, 0xa4, 0x0f, 0x2f, 0xd0, 0xe7, 0xff, 0x73, 0x19}, {0x80, 0xe3, 0x39, 0xb6, 0x74, 0x19, 0x3d, 0x43, 0xb2, 0x3b, 0x9c, 0xd7, 0xf5, 0xa8, 0xe3, 0x10, 0x97, 0xf5, 0x98, 0xc7, 0x33, 0x76, 0x8b, 0xc4, 0x34, 0xe4, 0x43, 0xaf, 0x88, 0x6a, 0x49, 0x2b}}, - {{0x0a, 0x9b, 0x46, 0x46, 0x9e, 0x5a, 0xe3, 0x6b, 0x30, 0xf6, 0x07, 0xd1, 0x57, 0xd6, 0xfe, 0x21, 0x62, 0x8d, 0x7b, 0xab, 0xbd, 0x0a, 0xd3, 0x99, 0x2f, 0xe3, 0x0e, 0x4a, 0x66, 0x18, 0x09, 0x35}, {0x23, 0x87, 0x38, 0x2b, 0x7b, 0xba, 0x54, 0x04, 0xd3, 0xad, 0x35, 0x05, 0x44, 0xfd, 0x4c, 0x99, 0x82, 0x10, 0x94, 0xa6, 0xd5, 0xe7, 0x3e, 0x5c, 0xe2, 0x57, 0xbb, 0x16, 0x1f, 0x3a, 0x6b, 0x3e}}, - {{0x3d, 0x27, 0xf9, 0xf4, 0x7a, 0xe8, 0xb6, 0xff, 0xf0, 0xd1, 0x4f, 0x84, 0x90, 0x92, 0xb4, 0xa3, 0xa2, 0x03, 0x41, 0xac, 0x77, 0x91, 0xd9, 0xd9, 0xe0, 0x5d, 0xad, 0x98, 0xf8, 0xf2, 0xa6, 0x1b}, {0xd2, 0x20, 0x0a, 0x0e, 0xd0, 0xf2, 0x99, 0x21, 0x48, 0x7f, 0x69, 0x1c, 0x92, 0x5d, 0xbf, 0x47, 0x95, 0x4e, 0x42, 0xb3, 0x9d, 0x40, 0x0d, 0xb5, 0xa4, 0x8f, 0x69, 0xb9, 0x05, 0x68, 0xc8, 0x0f}}, - {{0xf4, 0x16, 0xd6, 0x26, 0xe6, 0x72, 0xee, 0x36, 0xd1, 0xe5, 0x2e, 0x8f, 0x1e, 0x13, 0x5c, 0xa8, 0x77, 0xbc, 0xfe, 0xd5, 0xb6, 0x49, 0x4d, 0x54, 0xfd, 0x23, 0xdf, 0x10, 0x79, 0x2d, 0x00, 0x09}, {0x0b, 0x92, 0xa7, 0x47, 0x41, 0xc6, 0x8f, 0x76, 0xf3, 0x7e, 0x91, 0x37, 0x26, 0x4d, 0xed, 0xaf, 0x3c, 0xa8, 0x72, 0xb9, 0x62, 0xbc, 0xef, 0x25, 0x55, 0xe6, 0xfe, 0xa0, 0x46, 0xb6, 0x20, 0x0a}}, - {{0x2c, 0x6a, 0x03, 0x67, 0xde, 0x09, 0x3e, 0xb8, 0x6f, 0x8a, 0x1c, 0x9a, 0x86, 0x2d, 0xe4, 0xc6, 0x57, 0x37, 0x40, 0xa1, 0x28, 0x99, 0xcf, 0x26, 0x2b, 0xd6, 0x61, 0xbb, 0xa4, 0x20, 0xa1, 0x2e}, {0xfd, 0xea, 0x21, 0xb1, 0x56, 0x52, 0xaa, 0xc7, 0x45, 0xfb, 0xa1, 0x91, 0x99, 0xd8, 0xa9, 0x37, 0xbd, 0x4b, 0x34, 0x51, 0xa8, 0x29, 0x6b, 0x0c, 0x19, 0xfb, 0x24, 0xf2, 0x6a, 0xcc, 0x47, 0x00}}, - {{0x2f, 0x8c, 0x69, 0x94, 0x82, 0x5b, 0x0e, 0x9c, 0x14, 0xeb, 0xf7, 0x57, 0x8d, 0xab, 0x6a, 0x24, 0x5c, 0x01, 0x8b, 0xd2, 0xf8, 0x27, 0xcc, 0x6a, 0xbb, 0xb6, 0x2e, 0x2e, 0xc2, 0xc3, 0xbc, 0x14}, {0x84, 0xac, 0x03, 0x98, 0x65, 0x9f, 0xfd, 0xbc, 0xa8, 0xf1, 0x1a, 0x7b, 0x67, 0x8c, 0x65, 0x90, 0x34, 0x9d, 0xca, 0xfb, 0xd7, 0x13, 0x9e, 0x77, 0xf5, 0x1d, 0x4e, 0x32, 0xbd, 0xf9, 0xde, 0x0c}}, - {{0xf1, 0x61, 0x90, 0xb4, 0xdd, 0x5d, 0xb5, 0x2f, 0x60, 0xff, 0x8c, 0xf4, 0xf6, 0xc4, 0x8d, 0xe1, 0x22, 0x8e, 0x95, 0x1f, 0x49, 0x17, 0x9e, 0x20, 0xc6, 0x11, 0xd8, 0xe0, 0x74, 0xe4, 0x51, 0x06}, {0xbb, 0xcb, 0x3c, 0xec, 0xc2, 0x45, 0xb6, 0xad, 0x10, 0x02, 0xd3, 0xb2, 0xc6, 0xea, 0xa0, 0x35, 0x94, 0xa1, 0x43, 0x3d, 0xad, 0x2e, 0xd9, 0x4a, 0xb6, 0x85, 0x18, 0xbc, 0x7a, 0x0f, 0x39, 0x2e}}, - {{0x86, 0x87, 0x99, 0x4a, 0xf8, 0xec, 0xca, 0x23, 0x18, 0x33, 0xd6, 0x2b, 0x27, 0xdb, 0xda, 0x48, 0x99, 0x77, 0xd3, 0xb2, 0xf9, 0x40, 0x89, 0x9d, 0x87, 0x89, 0xa5, 0x05, 0xd6, 0x61, 0xfa, 0x17}, {0xaf, 0x8d, 0x26, 0x1d, 0xe1, 0x47, 0x8f, 0xc8, 0xbc, 0x62, 0xff, 0x55, 0x12, 0xa0, 0x0d, 0xfb, 0xca, 0x2c, 0x83, 0xdf, 0x88, 0xcf, 0x10, 0xac, 0x29, 0xab, 0xeb, 0x19, 0x77, 0x0c, 0xf1, 0x32}}, - {{0x31, 0x9b, 0x27, 0xc3, 0x2f, 0x10, 0x95, 0x31, 0x78, 0xd8, 0xa5, 0x89, 0xc5, 0xb6, 0xfe, 0xac, 0x23, 0xa4, 0xe8, 0xd8, 0xb2, 0x2a, 0x67, 0x93, 0x07, 0xba, 0x69, 0x66, 0xc6, 0x50, 0xac, 0x14}, {0x0e, 0xe7, 0x3a, 0x09, 0x70, 0xfc, 0x54, 0x84, 0x16, 0x97, 0xea, 0x71, 0x18, 0xe2, 0xcf, 0x83, 0x97, 0x88, 0x60, 0x25, 0x3a, 0x51, 0x87, 0x8f, 0xfd, 0x82, 0xf3, 0x65, 0x5c, 0x84, 0x42, 0x30}}, - {{0x48, 0xb9, 0x62, 0xcf, 0xe1, 0x44, 0xbd, 0xe3, 0xf9, 0xf8, 0x97, 0xf0, 0x96, 0x83, 0xa4, 0xac, 0x59, 0xdd, 0x33, 0xe5, 0xf2, 0x28, 0xe7, 0xaa, 0x0e, 0x79, 0x92, 0xd2, 0x02, 0x00, 0x5a, 0x20}, {0x58, 0xda, 0x40, 0x63, 0x3a, 0x57, 0x47, 0x37, 0x4c, 0xc3, 0x66, 0xe6, 0x08, 0xbe, 0x62, 0xc4, 0xd1, 0x0d, 0xef, 0x22, 0xbd, 0xa9, 0x2b, 0x93, 0xc2, 0x55, 0x23, 0x75, 0xd9, 0x7d, 0x05, 0x3c}}, - {{0xe9, 0xc7, 0x01, 0x3b, 0xf6, 0x7a, 0xbc, 0x21, 0x77, 0xdc, 0xba, 0xb6, 0x2a, 0x73, 0x52, 0x62, 0xaf, 0x3e, 0xda, 0xa6, 0xd2, 0x7a, 0x36, 0x89, 0x8c, 0x64, 0xb2, 0xa8, 0x5a, 0x22, 0x23, 0x34}, {0xbd, 0xcd, 0x7e, 0xd3, 0xb4, 0x96, 0x9f, 0xbf, 0x1e, 0xc2, 0xb5, 0xa6, 0x31, 0x57, 0x88, 0x97, 0x3f, 0xd0, 0xbd, 0x53, 0xb0, 0xde, 0x53, 0x8e, 0x57, 0x9d, 0x41, 0x8e, 0x59, 0xf6, 0x67, 0x02}}, - {{0x32, 0x4e, 0xd8, 0x99, 0x25, 0xc5, 0xce, 0x16, 0x1a, 0x79, 0x6b, 0xf7, 0xcf, 0x87, 0xe9, 0x0b, 0xcb, 0x90, 0xed, 0x3d, 0x24, 0xf7, 0xe9, 0x64, 0x5b, 0x0a, 0xfd, 0xf7, 0x45, 0x7c, 0x4b, 0x3f}, {0x9b, 0x6f, 0x5e, 0x0a, 0x2d, 0xf5, 0x4d, 0x50, 0x5e, 0xc2, 0x71, 0xc4, 0x14, 0x7f, 0xfd, 0x0f, 0x35, 0x32, 0xe4, 0xf4, 0xa6, 0xf6, 0xf5, 0x05, 0x2f, 0x8e, 0x9b, 0x1b, 0xf6, 0x4d, 0xed, 0x03}}, - {{0x76, 0xb0, 0xbc, 0xd9, 0xcd, 0x7e, 0x55, 0x4d, 0xe4, 0x78, 0x07, 0xd2, 0x9b, 0x52, 0x08, 0x54, 0xd5, 0x9b, 0xef, 0x83, 0x33, 0xce, 0xde, 0x58, 0xce, 0xf1, 0xc4, 0x80, 0x7f, 0x3b, 0xe2, 0x08}, {0xe7, 0x5f, 0x3f, 0x1d, 0x0a, 0x55, 0x39, 0x24, 0xde, 0xe7, 0x29, 0xc2, 0xba, 0x49, 0x35, 0x6f, 0x4c, 0xc3, 0x58, 0x54, 0x63, 0x81, 0xf1, 0x4f, 0x2d, 0x5b, 0x6c, 0xf8, 0x33, 0x10, 0xb0, 0x18}}, - {{0xb6, 0xac, 0x90, 0x14, 0x1f, 0x98, 0x32, 0x79, 0x87, 0xba, 0xf1, 0x69, 0xc6, 0xd1, 0x32, 0xae, 0x2f, 0xad, 0xde, 0x98, 0x38, 0x3e, 0x7d, 0x48, 0xbb, 0xe4, 0xb9, 0x1c, 0x96, 0x9d, 0x60, 0x33}, {0xd9, 0x42, 0xe0, 0x9d, 0x07, 0xc1, 0xf5, 0x2d, 0x8e, 0x33, 0x95, 0x4f, 0xd8, 0xe2, 0x5e, 0x3a, 0x71, 0x60, 0x5d, 0x8e, 0x54, 0x1e, 0x61, 0x0f, 0x6a, 0x4f, 0x86, 0xb6, 0x99, 0xf5, 0x4a, 0x31}}, - {{0x9c, 0x4c, 0x34, 0xfb, 0xda, 0x74, 0xec, 0x12, 0xb0, 0xb2, 0x8c, 0x39, 0x94, 0xc3, 0xe7, 0x86, 0xb3, 0x55, 0x41, 0x0f, 0x55, 0x5e, 0x50, 0xb3, 0x04, 0x96, 0x0f, 0xd1, 0x74, 0xc2, 0x82, 0x38}, {0xc8, 0x3c, 0x40, 0xa7, 0x16, 0x54, 0x75, 0x04, 0x17, 0x84, 0xbe, 0x18, 0x57, 0x5c, 0xc7, 0x7b, 0xbb, 0xf0, 0xef, 0x5d, 0x87, 0xcf, 0x25, 0x72, 0xb5, 0x8a, 0xb7, 0xe4, 0xaf, 0xa5, 0x4b, 0x35}}, - {{0x6b, 0xcf, 0x60, 0xae, 0x66, 0x8c, 0x28, 0xb9, 0x33, 0x61, 0x67, 0x83, 0xed, 0x3b, 0x01, 0x8a, 0xaf, 0x61, 0x69, 0xa2, 0xe7, 0xd4, 0xd3, 0xf9, 0x0f, 0x8a, 0x17, 0xb7, 0x3d, 0xbf, 0x90, 0x15}, {0x3b, 0xb6, 0x9d, 0xe0, 0xe5, 0x6d, 0x88, 0x29, 0x31, 0x59, 0x3f, 0x59, 0xe1, 0x8d, 0xee, 0xff, 0xb0, 0x4a, 0x4a, 0x78, 0x9c, 0xc9, 0x10, 0x6c, 0x8f, 0xc1, 0x4e, 0x7a, 0x40, 0x0c, 0xb8, 0x08}}, - {{0x64, 0x6a, 0x84, 0x76, 0x82, 0x5d, 0xef, 0x07, 0xe4, 0x83, 0x16, 0x33, 0x42, 0x75, 0x66, 0xf2, 0xa8, 0x98, 0xe0, 0xb6, 0xb2, 0xe5, 0xe8, 0x63, 0x15, 0x39, 0x16, 0xa1, 0xde, 0x36, 0x5d, 0x11}, {0x17, 0xb8, 0x81, 0x69, 0xd4, 0xcc, 0xcb, 0xf5, 0xc1, 0xac, 0x3a, 0x5a, 0x08, 0x6e, 0x9c, 0x73, 0x1b, 0x4a, 0xc8, 0x0d, 0xdc, 0xa2, 0xc3, 0x43, 0x8c, 0x72, 0xc9, 0xbe, 0x0b, 0x05, 0x61, 0x30}}, - {{0x97, 0x98, 0xc4, 0x84, 0xba, 0x97, 0x84, 0xa7, 0x7b, 0x47, 0x11, 0x6f, 0x54, 0x4a, 0xdf, 0x0b, 0xc4, 0x4f, 0xb4, 0x61, 0xc7, 0x5b, 0xd4, 0x78, 0x27, 0xbd, 0xe4, 0x01, 0x5a, 0x26, 0x9c, 0x00}, {0x2f, 0x44, 0x24, 0x31, 0xe2, 0x88, 0xd6, 0x83, 0x28, 0x72, 0x37, 0x73, 0x10, 0x41, 0xf5, 0xda, 0x6c, 0xa9, 0x5f, 0xa3, 0x4e, 0xe7, 0x76, 0x04, 0xce, 0xa6, 0xc5, 0x31, 0x0c, 0xb1, 0xbc, 0x1c}}, - {{0x41, 0xc9, 0x25, 0x74, 0xef, 0x09, 0x5f, 0x81, 0x6e, 0xb1, 0x1f, 0xaf, 0x91, 0x5b, 0xea, 0xdd, 0x5b, 0x4d, 0x4c, 0x6e, 0xc0, 0x8e, 0xc4, 0x44, 0x7a, 0x34, 0xdd, 0x09, 0x44, 0x69, 0xb2, 0x3e}, {0xe1, 0x36, 0x7d, 0x08, 0x3b, 0x85, 0x75, 0x50, 0xd2, 0x8c, 0xb9, 0x4f, 0xed, 0x4c, 0x37, 0xa6, 0x4d, 0x76, 0x56, 0xfa, 0x71, 0x04, 0x41, 0x8f, 0x31, 0x54, 0x0a, 0xe5, 0x49, 0x29, 0x49, 0x2a}}, - {{0xb1, 0xc7, 0xca, 0x80, 0xc5, 0x94, 0x44, 0x2a, 0x20, 0x4c, 0x0c, 0xbe, 0x62, 0xbc, 0x80, 0x5c, 0x9d, 0xa2, 0xee, 0x76, 0xa6, 0xc8, 0x9b, 0x3e, 0x52, 0x02, 0x73, 0x53, 0x89, 0xf4, 0xe9, 0x31}, {0x5f, 0x79, 0x44, 0x2d, 0xcc, 0x99, 0xc5, 0x0c, 0x69, 0xd7, 0xbb, 0x6d, 0x7a, 0x2d, 0x34, 0x5f, 0x70, 0x3b, 0xb1, 0x5b, 0xac, 0x83, 0x03, 0x1e, 0x90, 0x53, 0xcc, 0xee, 0xfa, 0xb8, 0x76, 0x35}}, - {{0x24, 0x9a, 0x2c, 0xf1, 0x02, 0x88, 0x73, 0x0d, 0x47, 0xfc, 0x88, 0x7a, 0x1a, 0xd3, 0x4b, 0x57, 0x92, 0x35, 0x93, 0x5d, 0x6a, 0x3f, 0x84, 0xfc, 0x27, 0x9c, 0xbe, 0xf8, 0xfb, 0xf0, 0x86, 0x13}, {0x44, 0xf0, 0x6c, 0x29, 0x0a, 0x54, 0x23, 0x5a, 0x98, 0x7a, 0x08, 0x15, 0xf4, 0x3a, 0x92, 0x61, 0x10, 0x28, 0xcc, 0x15, 0xcf, 0xb4, 0x95, 0x59, 0x36, 0xf0, 0xa0, 0x50, 0x76, 0x32, 0x06, 0x17}}, - {{0x0b, 0xa9, 0xde, 0x85, 0x55, 0xf1, 0x53, 0x26, 0x2f, 0x48, 0xa1, 0x8a, 0xd0, 0x94, 0x3d, 0xd6, 0x55, 0xd1, 0x27, 0x80, 0x15, 0x47, 0x82, 0x6a, 0x4c, 0xda, 0xb8, 0x50, 0xc5, 0x02, 0xf5, 0x1d}, {0x37, 0xeb, 0x62, 0xda, 0xbe, 0xbe, 0x94, 0x1c, 0x67, 0x12, 0xb8, 0x04, 0xbc, 0x52, 0x7d, 0x0d, 0xe4, 0x04, 0x00, 0xeb, 0x33, 0xbe, 0x2f, 0x8c, 0x2f, 0x61, 0x35, 0xea, 0x84, 0x0a, 0x40, 0x04}}, - {{0x36, 0x45, 0x59, 0x56, 0x52, 0x8f, 0x1b, 0x5c, 0x5f, 0x82, 0x97, 0x23, 0x4d, 0x4d, 0x79, 0x9b, 0x1c, 0xba, 0x7d, 0x0f, 0xdf, 0xa8, 0xde, 0xbb, 0x64, 0x55, 0x2a, 0x08, 0xf0, 0xb2, 0x29, 0x3d}, {0x81, 0xc3, 0xe8, 0xa8, 0xbe, 0xe0, 0x7a, 0x99, 0x27, 0x7e, 0x46, 0x39, 0x89, 0x2e, 0xfb, 0xd8, 0x9c, 0x74, 0xae, 0x32, 0x6b, 0x4e, 0xe9, 0x23, 0xf1, 0x6e, 0xd3, 0x96, 0xa7, 0xd4, 0xbe, 0x37}}, - {{0x15, 0xaf, 0xa0, 0x49, 0x72, 0xfd, 0x55, 0x2b, 0x19, 0x22, 0xbf, 0x00, 0x86, 0xef, 0xb6, 0x84, 0xe1, 0x25, 0x88, 0x41, 0xda, 0x27, 0x42, 0xa7, 0x87, 0x4b, 0x48, 0xd3, 0x50, 0xdd, 0xe3, 0x2d}, {0xaf, 0x19, 0x87, 0x01, 0x35, 0x99, 0x51, 0x7c, 0x80, 0x33, 0xad, 0xf5, 0x42, 0xc3, 0x2b, 0xe1, 0xdb, 0x6f, 0xb6, 0xd6, 0x97, 0x39, 0x71, 0x47, 0xbd, 0x88, 0x80, 0xf0, 0x1a, 0xcf, 0x81, 0x27}}, - {{0x28, 0x62, 0x2e, 0xe4, 0x67, 0x85, 0xb5, 0xd6, 0x84, 0x16, 0xab, 0xca, 0xee, 0xc9, 0x55, 0xba, 0xa9, 0xbf, 0xe2, 0xc0, 0x3e, 0xb0, 0x98, 0xb0, 0x72, 0xab, 0x6c, 0x2d, 0xf6, 0x92, 0x58, 0x16}, {0x0a, 0x75, 0x04, 0x70, 0xc2, 0xf3, 0xce, 0x7c, 0xbd, 0x0f, 0xaf, 0x87, 0xec, 0xb8, 0x64, 0x67, 0xda, 0x10, 0x8f, 0xb8, 0x23, 0x3e, 0x4a, 0x95, 0xb4, 0x6e, 0x75, 0xed, 0x55, 0x7c, 0x6b, 0x01}}, - {{0x81, 0x6a, 0x41, 0xf4, 0x92, 0x37, 0x72, 0x15, 0x4f, 0x56, 0x87, 0x4d, 0x29, 0xd3, 0x95, 0xf9, 0xe8, 0x2e, 0x5c, 0xcc, 0x0e, 0x1f, 0xd2, 0xb0, 0xba, 0x22, 0xbd, 0xd4, 0x0b, 0xc3, 0xd0, 0x27}, {0x73, 0x04, 0x47, 0xab, 0xc7, 0xfd, 0x2c, 0xdb, 0xb9, 0x03, 0x56, 0x22, 0x3d, 0xd1, 0xf3, 0x6c, 0xca, 0x23, 0x53, 0xb0, 0x49, 0x3b, 0x32, 0x20, 0x92, 0x2a, 0x24, 0x3a, 0xf6, 0x12, 0x74, 0x38}}, - {{0x3c, 0xb8, 0x44, 0xd0, 0x38, 0x0c, 0x6a, 0x99, 0xa5, 0xcd, 0x92, 0x5b, 0x18, 0x06, 0x09, 0xde, 0x55, 0xa2, 0x00, 0xd5, 0x67, 0x0a, 0x43, 0x46, 0x7e, 0xac, 0x77, 0xeb, 0x85, 0x96, 0xf5, 0x27}, {0xdf, 0x5e, 0xd1, 0xdf, 0x6e, 0x23, 0x9a, 0x05, 0x63, 0x1f, 0xe6, 0xea, 0x5f, 0x31, 0x61, 0xe5, 0x3a, 0xb3, 0xa4, 0x85, 0x94, 0xa5, 0x05, 0xbb, 0xd8, 0x1e, 0xac, 0x14, 0xba, 0xdd, 0x85, 0x32}}, - {{0xc3, 0x9d, 0xeb, 0x0c, 0xd0, 0xc0, 0x49, 0xe5, 0x39, 0xaa, 0x21, 0xb4, 0xf6, 0x7c, 0x73, 0xd2, 0x2b, 0x3a, 0x8f, 0x5a, 0xa0, 0x32, 0xd6, 0x97, 0x6c, 0xa3, 0x0c, 0x8e, 0x47, 0x5f, 0x24, 0x3c}, {0x8b, 0x7d, 0x4a, 0xaa, 0x37, 0x8a, 0x0b, 0xf2, 0xda, 0x23, 0x20, 0x56, 0x0c, 0xe0, 0x89, 0x81, 0x47, 0x81, 0x27, 0x2f, 0x54, 0xd1, 0xff, 0x5a, 0x15, 0x1c, 0x90, 0x16, 0x9b, 0xd6, 0xa2, 0x03}}, - {{0xb8, 0x63, 0x43, 0x2a, 0x71, 0xec, 0xb8, 0x1d, 0x60, 0xc0, 0x26, 0x68, 0x49, 0x3a, 0x20, 0x89, 0xdd, 0x0a, 0x30, 0xda, 0xe8, 0x38, 0x52, 0xab, 0x83, 0xfd, 0xf9, 0x05, 0x64, 0xc0, 0xba, 0x1f}, {0x48, 0xc7, 0x3e, 0xfd, 0x6a, 0x28, 0xca, 0x35, 0x3a, 0x2a, 0xd4, 0xdb, 0x71, 0xe2, 0x74, 0x4d, 0x4b, 0x30, 0x10, 0xe3, 0xff, 0x48, 0xf7, 0x1a, 0x9c, 0x70, 0xbe, 0x6b, 0x64, 0x48, 0xe5, 0x38}}, - {{0xa5, 0x46, 0x17, 0xc4, 0x80, 0x64, 0x3f, 0x9c, 0x10, 0xec, 0x55, 0x96, 0xcb, 0x11, 0x55, 0x74, 0xba, 0xc3, 0xdf, 0x92, 0x95, 0xd9, 0x30, 0x0b, 0x95, 0x56, 0x2d, 0xaa, 0x08, 0xd2, 0xb5, 0x04}, {0x0b, 0x2f, 0x80, 0xdb, 0x8a, 0x14, 0xfa, 0xe3, 0x7b, 0xf2, 0x21, 0xcc, 0xdb, 0xde, 0x2a, 0x69, 0x61, 0x01, 0x5e, 0x81, 0x53, 0x32, 0xbd, 0xe5, 0xb3, 0xd7, 0xb7, 0x74, 0x6a, 0x83, 0xae, 0x06}}, - {{0x33, 0x82, 0x3a, 0x63, 0xe7, 0x7f, 0xa6, 0x23, 0xac, 0x4f, 0x71, 0x7e, 0xca, 0x4e, 0x9a, 0xfb, 0xcd, 0x24, 0xbd, 0xa5, 0x5f, 0xef, 0x0d, 0x95, 0x6c, 0xe3, 0xdd, 0x68, 0x53, 0x48, 0x7a, 0x18}, {0x54, 0x3e, 0x66, 0x96, 0x76, 0x63, 0xd9, 0x4a, 0xab, 0x7e, 0x44, 0x47, 0x72, 0x60, 0x5b, 0x93, 0x17, 0xba, 0xf4, 0x0c, 0x01, 0xef, 0xd0, 0x40, 0x4e, 0xef, 0x7b, 0xe0, 0x8f, 0x8f, 0xd6, 0x2b}}, - {{0x18, 0x8c, 0x7b, 0x14, 0xa7, 0x82, 0x69, 0xe2, 0x5d, 0xbe, 0xb9, 0xb9, 0xc4, 0xe6, 0x7b, 0x60, 0xef, 0xe0, 0xdb, 0xb3, 0x7b, 0x30, 0x2d, 0xe3, 0xb0, 0xc8, 0xd3, 0x80, 0x0b, 0x01, 0x76, 0x3a}, {0x92, 0x84, 0x74, 0xa6, 0x6c, 0x14, 0xa9, 0x06, 0x1b, 0x73, 0xaa, 0x49, 0x6b, 0x2d, 0x4b, 0xce, 0xbb, 0x95, 0x5a, 0x4a, 0x3d, 0x87, 0x5b, 0x79, 0x46, 0x7a, 0x76, 0x98, 0x8d, 0x77, 0xe5, 0x19}}, - {{0xca, 0xfd, 0x69, 0x83, 0x28, 0xe5, 0xc9, 0x02, 0xec, 0x62, 0x46, 0xd9, 0xed, 0x8e, 0x6f, 0x54, 0x88, 0xa0, 0xbd, 0x12, 0x26, 0x8b, 0xc4, 0xa4, 0x53, 0x2c, 0x49, 0xcb, 0xbc, 0xab, 0x51, 0x35}, {0xf7, 0xb4, 0xa1, 0x29, 0x04, 0xb7, 0xbe, 0xdf, 0x61, 0x19, 0xa9, 0x0c, 0x50, 0x73, 0x43, 0x69, 0x05, 0x57, 0xd1, 0x2d, 0x5d, 0xbc, 0xf2, 0x4c, 0x76, 0x04, 0x4d, 0x49, 0x7f, 0x16, 0x41, 0x23}}, - {{0x6f, 0x35, 0xab, 0x8b, 0xd5, 0x67, 0xc8, 0xae, 0x66, 0x26, 0x97, 0xe7, 0x89, 0x34, 0x07, 0x5a, 0x87, 0x58, 0x88, 0x85, 0x0b, 0xe0, 0x93, 0xe5, 0xcc, 0x1b, 0xd8, 0x8b, 0xb7, 0x8e, 0x98, 0x32}, {0xbe, 0xbd, 0x27, 0xd1, 0x3b, 0x44, 0x3c, 0xca, 0x2f, 0x23, 0xf9, 0xcb, 0x87, 0xdb, 0xf6, 0x53, 0x8d, 0x40, 0x75, 0x13, 0x81, 0x3c, 0x5e, 0x92, 0x11, 0x9c, 0x48, 0xda, 0xbb, 0xd3, 0x2f, 0x36}}, - {{0xac, 0xe3, 0x4c, 0x79, 0xd0, 0x85, 0x10, 0x60, 0x0a, 0xff, 0x2e, 0x42, 0x69, 0x79, 0x2b, 0x16, 0x4d, 0x32, 0x18, 0x97, 0x4b, 0x7c, 0x12, 0xfa, 0xb0, 0x6e, 0x18, 0xac, 0xba, 0x74, 0xeb, 0x05}, {0xd4, 0xdb, 0xad, 0x37, 0x76, 0x61, 0x9c, 0xfa, 0x49, 0xc9, 0x26, 0x96, 0x5f, 0x98, 0x7b, 0xd7, 0x7a, 0x4e, 0xa6, 0x34, 0xb7, 0xde, 0xe4, 0x53, 0xcf, 0x93, 0xbb, 0x91, 0x31, 0x27, 0x33, 0x11}}, - {{0x34, 0x16, 0xb4, 0x08, 0x17, 0xfb, 0xc9, 0x96, 0x92, 0xcb, 0x24, 0x2d, 0x5e, 0xbc, 0xa6, 0xa9, 0x70, 0x38, 0x16, 0xfd, 0x2b, 0xa2, 0x4c, 0x83, 0x99, 0xfc, 0x41, 0x11, 0x12, 0xae, 0x56, 0x3e}, {0x93, 0x9f, 0x3f, 0x16, 0xbc, 0x4d, 0xbb, 0x50, 0x93, 0x3b, 0x60, 0xff, 0x15, 0x6f, 0x25, 0x1e, 0x6b, 0x8a, 0x6c, 0xb6, 0x6f, 0xaa, 0x61, 0x3e, 0xc0, 0xe3, 0xb8, 0x06, 0x21, 0xda, 0xe2, 0x00}}, - {{0x13, 0xb5, 0xb6, 0x23, 0x79, 0x8b, 0xdd, 0x42, 0x9d, 0x77, 0x9a, 0xb5, 0x04, 0xbf, 0x85, 0xea, 0xdd, 0x72, 0x1a, 0xa0, 0x50, 0xfa, 0xa9, 0xb0, 0xf4, 0x1f, 0x74, 0x41, 0x38, 0x0b, 0xa0, 0x08}, {0x9b, 0xff, 0x1e, 0x3f, 0x14, 0xe0, 0xcb, 0x64, 0xb9, 0x15, 0xe7, 0x67, 0xf2, 0x12, 0x45, 0xa1, 0x11, 0x36, 0x1b, 0x8d, 0xcc, 0x3a, 0xfc, 0xd5, 0x6b, 0xee, 0x6d, 0x7f, 0x1f, 0xcf, 0x17, 0x27}}, - {{0x3d, 0xc3, 0xdb, 0x0c, 0x5e, 0x92, 0xe3, 0x11, 0x78, 0x47, 0xc3, 0x51, 0x34, 0xd4, 0x8e, 0xbc, 0x31, 0x9b, 0x43, 0x97, 0x3c, 0x85, 0x04, 0x73, 0x1d, 0x62, 0x6c, 0x95, 0xd3, 0x7a, 0xda, 0x1a}, {0x7b, 0x91, 0x72, 0x7f, 0x05, 0xed, 0x0f, 0x55, 0x78, 0x60, 0xcd, 0x73, 0x15, 0xcf, 0x45, 0x23, 0x21, 0xf9, 0x99, 0x84, 0xde, 0xbe, 0x0f, 0xc0, 0x65, 0x33, 0x2e, 0xeb, 0xfc, 0x21, 0x35, 0x39}}, - {{0x35, 0xf2, 0xa3, 0x16, 0x3c, 0xcc, 0xdc, 0x0a, 0x03, 0xac, 0x85, 0x8d, 0xb3, 0xdc, 0x76, 0x26, 0x54, 0x3f, 0x32, 0x32, 0x06, 0xfa, 0xc2, 0xb7, 0x6c, 0x26, 0x68, 0x81, 0x4e, 0xc0, 0x00, 0x1b}, {0x81, 0x63, 0xb2, 0xc6, 0x75, 0xf9, 0xb8, 0x22, 0x89, 0x65, 0x7f, 0x87, 0x21, 0xf5, 0xa0, 0x64, 0xb2, 0xb2, 0x46, 0x62, 0x34, 0x39, 0xe4, 0x0d, 0x68, 0xc9, 0x67, 0xc8, 0x63, 0x0d, 0xab, 0x10}}, - {{0x10, 0xcb, 0x4e, 0x05, 0x9f, 0x4d, 0xff, 0x72, 0x53, 0x3c, 0x71, 0x10, 0xc5, 0xc6, 0xcc, 0x28, 0xcf, 0x7b, 0x40, 0x36, 0xa1, 0x3c, 0x44, 0x41, 0xe3, 0xdc, 0x48, 0x82, 0x54, 0x8a, 0xa1, 0x3c}, {0xa9, 0x23, 0xf6, 0xc4, 0x07, 0x86, 0xb5, 0x74, 0xe8, 0xb4, 0x24, 0x40, 0xce, 0x86, 0xcf, 0x52, 0xb8, 0x9e, 0xa9, 0x8f, 0xde, 0x22, 0x1f, 0x0c, 0x12, 0x28, 0x17, 0x28, 0x7c, 0x9d, 0xd1, 0x06}}, - {{0x1a, 0xb4, 0x25, 0x1a, 0xcb, 0x9e, 0x29, 0x34, 0x53, 0x4f, 0x0f, 0x43, 0xcd, 0xe2, 0x20, 0x4c, 0x85, 0x63, 0xfa, 0x5d, 0xe7, 0x8d, 0xac, 0xd3, 0xaa, 0x49, 0x0d, 0x29, 0x9f, 0x54, 0x5d, 0x31}, {0xda, 0x01, 0x91, 0x73, 0x7a, 0x7a, 0x0a, 0x95, 0xc5, 0x15, 0x59, 0x2b, 0x17, 0x44, 0x6e, 0xd0, 0x5b, 0x8a, 0x2c, 0xc3, 0x6b, 0xd5, 0x72, 0x88, 0x4c, 0x64, 0xf9, 0x64, 0x5d, 0xa4, 0x28, 0x1f}}, - {{0x5a, 0xdd, 0x9c, 0x3f, 0x2b, 0xb8, 0x62, 0xec, 0x0f, 0x26, 0x89, 0xba, 0xe0, 0x68, 0xe4, 0x53, 0x63, 0x8a, 0x44, 0x66, 0x40, 0xb8, 0x71, 0xbf, 0xca, 0xa6, 0x0e, 0x30, 0x78, 0x25, 0x7d, 0x1a}, {0x43, 0x34, 0x52, 0x79, 0xe1, 0xea, 0xd2, 0xdf, 0x43, 0x3e, 0x58, 0x90, 0x4b, 0x28, 0x53, 0xe7, 0xec, 0xb2, 0x3e, 0xe0, 0x70, 0xe3, 0x50, 0x38, 0xca, 0x41, 0xb5, 0x10, 0x42, 0x1e, 0xf2, 0x24}}, - {{0x6b, 0x05, 0x39, 0xd7, 0xf3, 0x69, 0x60, 0x39, 0x9b, 0xa9, 0x0a, 0x24, 0x7d, 0x25, 0x84, 0x2f, 0x47, 0x3e, 0x2e, 0x1d, 0x3e, 0x6a, 0xbc, 0xcb, 0x88, 0x6c, 0xf5, 0x60, 0xfd, 0x11, 0xf2, 0x32}, {0xd6, 0x01, 0xe7, 0xf3, 0x0a, 0xdc, 0x93, 0x89, 0xfb, 0x1f, 0x5f, 0x3d, 0x08, 0x7f, 0x49, 0x3c, 0x80, 0x40, 0x2e, 0x76, 0xc3, 0x98, 0x69, 0x7c, 0x62, 0x49, 0xd8, 0x47, 0x09, 0xcd, 0xff, 0x25}}, - {{0x05, 0x05, 0x5e, 0xa0, 0x7a, 0xdf, 0xeb, 0x00, 0x9a, 0x76, 0x8d, 0x8a, 0xfe, 0x73, 0xd7, 0x32, 0x5d, 0xc7, 0x94, 0xba, 0xe0, 0x4a, 0xd7, 0xa0, 0xb8, 0x6a, 0x19, 0xbf, 0x28, 0x68, 0x8f, 0x02}, {0x3f, 0xcb, 0xa1, 0xdb, 0x61, 0x07, 0x40, 0x12, 0x21, 0xc1, 0xee, 0x5a, 0x09, 0x7e, 0x39, 0xf4, 0x85, 0xc0, 0xaf, 0xcd, 0xbe, 0x26, 0x39, 0x9a, 0x55, 0xd9, 0x22, 0x22, 0x6d, 0x6e, 0xd1, 0x11}}, - {{0xfe, 0x50, 0x5e, 0xa4, 0xc8, 0xea, 0x43, 0xeb, 0xca, 0xe4, 0xb9, 0x9f, 0x55, 0x31, 0xe1, 0x76, 0x78, 0x0d, 0x1b, 0x3f, 0x04, 0x71, 0x66, 0x8f, 0xa5, 0x3b, 0x26, 0x62, 0xa3, 0x64, 0xc9, 0x0d}, {0xea, 0xd9, 0xf7, 0x98, 0x80, 0xa2, 0x43, 0x24, 0x2d, 0x18, 0xfc, 0x13, 0x11, 0x9d, 0x73, 0x78, 0x7e, 0x27, 0xdf, 0x30, 0x84, 0x6c, 0x2c, 0xd6, 0xad, 0x77, 0xf0, 0x29, 0xf2, 0x79, 0x81, 0x39}}, - {{0xa6, 0x41, 0x8b, 0xe1, 0xe1, 0x83, 0x3b, 0x3f, 0x0e, 0x1f, 0x99, 0xd4, 0xd0, 0xb7, 0x79, 0xe8, 0xa4, 0xa3, 0x57, 0xdc, 0x91, 0x52, 0x14, 0x3a, 0x8d, 0x42, 0x1b, 0xa5, 0xa3, 0x64, 0x06, 0x11}, {0x7e, 0xfc, 0x93, 0xd7, 0x5d, 0x83, 0xcb, 0x9a, 0xac, 0x69, 0x1d, 0x7b, 0xbc, 0xbb, 0x5e, 0x69, 0xeb, 0x77, 0x41, 0x24, 0xef, 0xbf, 0x8d, 0x41, 0x31, 0xc6, 0x61, 0x88, 0x59, 0x0d, 0x03, 0x0e}}, - {{0x17, 0x4a, 0x79, 0x3d, 0xbb, 0x1b, 0x6c, 0x67, 0x24, 0x18, 0x0b, 0xa3, 0xb1, 0x40, 0xf7, 0x86, 0xcd, 0xd6, 0x6e, 0x2c, 0x38, 0x81, 0x14, 0x04, 0x88, 0xb8, 0xa9, 0xac, 0x7a, 0x26, 0x60, 0x24}, {0xa3, 0x91, 0xde, 0xc2, 0xe4, 0x28, 0x8e, 0x4b, 0xe7, 0x72, 0x90, 0xbb, 0xe6, 0x23, 0xb9, 0x0e, 0x4b, 0xd6, 0x18, 0x95, 0xa1, 0xc9, 0xa5, 0x84, 0x63, 0xf5, 0xfe, 0xc7, 0x4f, 0x85, 0x28, 0x20}}, - {{0xdc, 0x5e, 0xb3, 0xb4, 0x1b, 0x0b, 0x55, 0xec, 0xf1, 0x44, 0xa0, 0xa2, 0x13, 0xe7, 0xd6, 0x9b, 0x9b, 0x84, 0x15, 0xe2, 0x2f, 0xd5, 0xb7, 0x1b, 0x89, 0xe5, 0xa8, 0x60, 0x5a, 0x4a, 0x3b, 0x2a}, {0x7b, 0x90, 0xf9, 0x47, 0x09, 0x82, 0xdb, 0x37, 0x37, 0xec, 0xd0, 0xfe, 0x5f, 0xa9, 0x06, 0x96, 0x91, 0x2a, 0xdb, 0x06, 0x91, 0xf4, 0xa5, 0xa4, 0x7b, 0x96, 0x44, 0x8a, 0x45, 0x8e, 0xc3, 0x2d}}, - {{0x6c, 0xeb, 0xf9, 0xd9, 0x99, 0x34, 0x40, 0xac, 0x88, 0x2e, 0xa1, 0xf3, 0xc4, 0xa7, 0x6d, 0x02, 0x6b, 0xa6, 0x67, 0x18, 0xff, 0x04, 0xfa, 0x7d, 0xa9, 0x13, 0x24, 0xe4, 0x29, 0x4e, 0x80, 0x09}, {0x5f, 0x05, 0x0a, 0x3a, 0x8c, 0x21, 0xb5, 0x51, 0xbb, 0x34, 0x61, 0x74, 0xfd, 0xc1, 0xdc, 0x5d, 0x00, 0xc4, 0x53, 0xcf, 0xf0, 0xcd, 0x96, 0x36, 0x20, 0x0c, 0x8f, 0x79, 0x64, 0x13, 0x94, 0x35}}, - {{0x42, 0x32, 0xcb, 0x25, 0xfc, 0x7c, 0xa7, 0xe6, 0x88, 0x29, 0x37, 0x88, 0xf5, 0xd7, 0x31, 0x2c, 0x85, 0xac, 0x07, 0xa4, 0x94, 0x90, 0x2e, 0x56, 0x80, 0xe1, 0x22, 0x26, 0xfb, 0xef, 0xb1, 0x3a}, {0x57, 0x65, 0x7c, 0x59, 0xcf, 0xbd, 0x24, 0xb4, 0x19, 0x22, 0x67, 0xba, 0xf9, 0x48, 0xa3, 0xed, 0xcd, 0xd3, 0xf2, 0x63, 0x7b, 0xe3, 0x1a, 0x8c, 0x9a, 0x09, 0x2f, 0x5a, 0x5a, 0xed, 0xf7, 0x26}}, - {{0x12, 0x72, 0xed, 0xdd, 0x3e, 0x86, 0x97, 0xd2, 0xbc, 0xbe, 0x36, 0x3e, 0x7e, 0x2b, 0x1b, 0xf9, 0xb9, 0x08, 0xbf, 0x04, 0x46, 0xd4, 0xff, 0xae, 0x4e, 0xc7, 0x7c, 0xab, 0xdd, 0x95, 0x67, 0x24}, {0x04, 0xf7, 0x75, 0xe9, 0xde, 0x53, 0x13, 0xc7, 0x08, 0x04, 0x4d, 0x64, 0x3d, 0x04, 0x76, 0xb2, 0xad, 0xde, 0x75, 0x30, 0xed, 0x7f, 0x78, 0x58, 0x7a, 0xae, 0x9b, 0x20, 0x39, 0xe9, 0x71, 0x27}}, - {{0xf9, 0x99, 0x3d, 0x37, 0xd7, 0x9a, 0xdd, 0x06, 0x6a, 0xfa, 0x08, 0xb6, 0x54, 0x60, 0x73, 0x8a, 0xb5, 0x33, 0x93, 0x22, 0xd3, 0x7e, 0x11, 0x34, 0xde, 0x02, 0x21, 0x20, 0x8a, 0x7d, 0x33, 0x2e}, {0x33, 0xd6, 0x3b, 0xa7, 0xd0, 0x16, 0xee, 0xc3, 0x88, 0xb2, 0x65, 0x2b, 0xe9, 0x08, 0x5f, 0xd2, 0xb9, 0x28, 0x1a, 0x30, 0xce, 0x08, 0x6a, 0xc2, 0xbe, 0x39, 0x6f, 0x14, 0x8f, 0x35, 0x35, 0x39}}, - {{0x5b, 0xce, 0xef, 0xf6, 0x0c, 0xb5, 0x5b, 0x3f, 0x5d, 0x4c, 0x67, 0x5f, 0xe4, 0x32, 0x6d, 0xb7, 0x4b, 0xbb, 0xd7, 0x2b, 0xf1, 0x7f, 0xa1, 0xca, 0xb2, 0x06, 0x4d, 0xb9, 0xfd, 0xce, 0x8d, 0x1b}, {0x78, 0x20, 0x83, 0x2c, 0x14, 0xb0, 0x69, 0xa4, 0x8f, 0x47, 0x58, 0x2a, 0x69, 0xae, 0x17, 0x4d, 0x6b, 0x38, 0x47, 0x69, 0xee, 0xc0, 0x08, 0xcc, 0x51, 0x48, 0x2d, 0x31, 0xa3, 0x6b, 0x28, 0x14}}, - {{0x37, 0x03, 0x1a, 0xa4, 0xe9, 0xb3, 0x3d, 0x2f, 0x6d, 0xa2, 0x67, 0x3f, 0x23, 0x7f, 0xa4, 0x03, 0x5b, 0x35, 0xc3, 0xbf, 0xcf, 0xfe, 0xc2, 0x28, 0x81, 0xf4, 0x2e, 0xbd, 0x0a, 0x96, 0xbc, 0x2b}, {0x86, 0x21, 0x21, 0xb1, 0x52, 0x09, 0x11, 0xc3, 0x53, 0xfc, 0xd5, 0x48, 0x01, 0x52, 0x87, 0x2e, 0x2c, 0xda, 0x6a, 0xa9, 0xf6, 0x9f, 0x5c, 0x87, 0xe5, 0xa5, 0x15, 0xd4, 0x35, 0x49, 0x23, 0x02}}, - {{0xfe, 0x56, 0xe2, 0x22, 0x15, 0x84, 0xf0, 0x36, 0x26, 0xf1, 0xb1, 0x1c, 0x96, 0x4c, 0x55, 0x6d, 0xd6, 0x0f, 0xeb, 0xdc, 0xc5, 0xe6, 0xbe, 0xef, 0x0c, 0x18, 0x7a, 0xd9, 0xec, 0xb1, 0xe2, 0x3d}, {0x66, 0x9b, 0xe6, 0xaa, 0x95, 0xab, 0x04, 0x53, 0x93, 0x79, 0x80, 0x0c, 0x93, 0x38, 0xed, 0x60, 0x3e, 0x4a, 0xf5, 0x6f, 0x8d, 0x3e, 0xb4, 0xd9, 0x90, 0x30, 0xba, 0x16, 0x36, 0x8e, 0xfc, 0x18}}, - {{0xf0, 0x69, 0xfe, 0x4d, 0x85, 0xd8, 0x22, 0x08, 0x38, 0xdc, 0xf1, 0xcc, 0x45, 0x1f, 0x5e, 0x50, 0x84, 0x8b, 0xec, 0x7e, 0x0a, 0x64, 0x8a, 0x62, 0x01, 0x9c, 0xc8, 0x14, 0xd3, 0x23, 0x27, 0x01}, {0x36, 0x77, 0xd4, 0xd5, 0xcb, 0xf3, 0x4e, 0x7e, 0xac, 0x5b, 0xe5, 0xd6, 0xbd, 0x2f, 0x0b, 0x85, 0x02, 0x96, 0xf3, 0x18, 0xc2, 0x3b, 0x2f, 0x6c, 0x1f, 0xf1, 0xdc, 0x28, 0x70, 0x13, 0x35, 0x25}}, - {{0xfe, 0xa6, 0xd2, 0x3a, 0xeb, 0x90, 0x34, 0xa1, 0x0a, 0x31, 0x4d, 0x08, 0x63, 0x11, 0x67, 0x0b, 0x13, 0x16, 0xca, 0x08, 0xcb, 0x15, 0xdf, 0x86, 0x67, 0x61, 0x1c, 0x8d, 0x67, 0x09, 0x86, 0x21}, {0x43, 0x90, 0x3d, 0x61, 0x4b, 0x95, 0xde, 0x58, 0xde, 0x5c, 0x4a, 0x9d, 0x72, 0xa0, 0xdf, 0x4c, 0x09, 0x75, 0x00, 0xb9, 0x58, 0xf0, 0xa4, 0xd2, 0xfb, 0x94, 0x5e, 0xe8, 0x63, 0x6d, 0x60, 0x26}}, - {{0x59, 0x30, 0x2e, 0x51, 0x83, 0xc3, 0xee, 0x1b, 0x31, 0xb5, 0x35, 0xaf, 0xef, 0x6d, 0xe4, 0x75, 0x69, 0x74, 0xfa, 0x89, 0x6c, 0x86, 0xcb, 0x25, 0x35, 0xc6, 0x9c, 0x70, 0xc8, 0xa9, 0x00, 0x23}, {0x3a, 0xdd, 0xb6, 0xd8, 0x0a, 0xba, 0xfe, 0x30, 0x7b, 0xa1, 0x6c, 0x3c, 0x9a, 0x28, 0x7b, 0xfe, 0x95, 0x05, 0x92, 0x4f, 0x3f, 0x76, 0x6a, 0x7a, 0x1c, 0xf8, 0x7d, 0x78, 0xfe, 0xe3, 0x69, 0x06}}, - {{0x5a, 0xfb, 0xc1, 0x2b, 0x7e, 0xaf, 0x17, 0x23, 0x7a, 0xc5, 0x76, 0x0f, 0x3c, 0xa8, 0xa0, 0x4f, 0xf4, 0x2a, 0x18, 0xe9, 0x50, 0x18, 0x4d, 0xad, 0x24, 0xa7, 0x09, 0x99, 0x4e, 0x29, 0x95, 0x30}, {0xee, 0x15, 0x22, 0xc0, 0x2b, 0x71, 0x4c, 0xb0, 0x5d, 0x37, 0x88, 0xc5, 0x20, 0x0f, 0x18, 0xf1, 0x93, 0xbf, 0x7d, 0x9f, 0xd2, 0xde, 0xbd, 0xaa, 0x04, 0xdc, 0xf6, 0x7f, 0x0e, 0xa1, 0x0b, 0x17}}, - {{0x5d, 0x16, 0x11, 0x64, 0x37, 0xca, 0x14, 0x46, 0xea, 0xd2, 0xf2, 0x1c, 0xff, 0x19, 0x5e, 0xfe, 0x9b, 0xf2, 0xb7, 0x75, 0x2b, 0x70, 0x57, 0xfd, 0x1a, 0x32, 0xb5, 0x4e, 0x96, 0x3d, 0x1b, 0x2d}, {0xd7, 0x94, 0x52, 0x8c, 0xb1, 0x6f, 0xb0, 0x03, 0xaf, 0x83, 0x58, 0xa6, 0xa7, 0xd2, 0x82, 0xd2, 0x4e, 0x25, 0xef, 0xb3, 0xbc, 0xb5, 0x6d, 0x13, 0xeb, 0x9a, 0xfe, 0x61, 0xf8, 0x5e, 0x8c, 0x2e}}, - {{0x0f, 0xfe, 0xd7, 0x18, 0xaa, 0xd5, 0xcc, 0x79, 0xc5, 0x9f, 0x84, 0x7f, 0x2a, 0xe4, 0xfb, 0x21, 0x1c, 0xf9, 0xa4, 0x52, 0x6b, 0xf3, 0x28, 0x6a, 0x69, 0x04, 0xda, 0x2d, 0x72, 0xe6, 0x1d, 0x01}, {0x9c, 0xdc, 0x53, 0x2c, 0x30, 0x97, 0x07, 0x4f, 0x85, 0xcf, 0x2b, 0xb0, 0x09, 0xa7, 0x9d, 0x6c, 0x53, 0x37, 0x08, 0x27, 0xa1, 0xcd, 0xf0, 0x6b, 0x60, 0xeb, 0x96, 0x45, 0xfa, 0xa1, 0xad, 0x02}}, - {{0xb7, 0x11, 0x5e, 0xd4, 0x26, 0xd9, 0xf1, 0x74, 0xa2, 0x87, 0x37, 0x0e, 0x4b, 0x97, 0x48, 0x1c, 0x08, 0xee, 0x60, 0x25, 0xb1, 0x54, 0x4f, 0x57, 0x8b, 0xfa, 0x9b, 0xff, 0xcd, 0xa6, 0x17, 0x1a}, {0xdd, 0x6f, 0xc2, 0x18, 0x0a, 0x43, 0xbd, 0x65, 0xb4, 0x44, 0xff, 0x5f, 0x26, 0xf2, 0xa7, 0x06, 0xa6, 0xd4, 0x0e, 0x32, 0x17, 0x27, 0x0f, 0x60, 0x6b, 0xa0, 0x95, 0xac, 0x95, 0x4e, 0x3b, 0x0c}}, - {{0x69, 0x26, 0xe6, 0x26, 0xc6, 0xaf, 0x8b, 0xb1, 0x0b, 0x29, 0x7d, 0x40, 0xc8, 0x90, 0xde, 0x34, 0x0e, 0x68, 0x58, 0xfe, 0x71, 0x80, 0xc9, 0x47, 0x16, 0x4b, 0x20, 0xc9, 0xe0, 0x01, 0x74, 0x12}, {0x45, 0xfc, 0x92, 0x2f, 0xa5, 0xe7, 0x2d, 0x33, 0x9d, 0x1a, 0x6b, 0x68, 0xc6, 0xcd, 0x17, 0xc9, 0x68, 0x8b, 0xe0, 0x72, 0xfe, 0x76, 0x6c, 0xb8, 0x0f, 0xb7, 0x5a, 0x54, 0xca, 0x39, 0x4f, 0x0b}}, - {{0x4a, 0xcc, 0xb9, 0xbc, 0x70, 0x36, 0x17, 0xc4, 0x92, 0x21, 0x64, 0x0b, 0xb8, 0xf1, 0x5c, 0xbd, 0xfb, 0xc2, 0x09, 0x8e, 0x02, 0x6a, 0x97, 0x18, 0x32, 0x87, 0xa4, 0x79, 0x1a, 0x65, 0x7e, 0x18}, {0xaf, 0xc1, 0x94, 0x52, 0x7d, 0x5d, 0x69, 0xae, 0x54, 0xbf, 0x13, 0xe8, 0x4c, 0x65, 0x34, 0x19, 0xdd, 0xc2, 0x3d, 0x29, 0x6f, 0xb2, 0x2c, 0x64, 0x63, 0xda, 0x7b, 0x51, 0x31, 0xe0, 0x2c, 0x09}}, - {{0x79, 0xbc, 0xc9, 0xec, 0x07, 0x8a, 0x62, 0x76, 0xb3, 0x5b, 0xa6, 0xaa, 0x86, 0x1f, 0xb2, 0x8c, 0x26, 0xd2, 0x56, 0x8a, 0x23, 0xcf, 0x09, 0xbb, 0x1a, 0x35, 0xa6, 0x19, 0x7b, 0x5d, 0x1a, 0x1c}, {0xaf, 0x71, 0x5c, 0xfe, 0x31, 0x87, 0x9f, 0xfe, 0xcf, 0xc6, 0x60, 0x76, 0x82, 0x80, 0x8d, 0xdd, 0xf6, 0xb4, 0x7d, 0x60, 0x46, 0xbb, 0xfb, 0xa2, 0xf4, 0x02, 0xfa, 0x29, 0xc4, 0xde, 0x6c, 0x06}}, - {{0xb9, 0xfa, 0xcd, 0x4d, 0x99, 0x38, 0xba, 0xfe, 0xe9, 0xb2, 0xa8, 0x53, 0xe0, 0xbe, 0x85, 0x01, 0x6c, 0xda, 0x19, 0x67, 0xe3, 0x4a, 0x18, 0x2d, 0x8c, 0x4e, 0xfc, 0x97, 0x43, 0xde, 0xde, 0x38}, {0x96, 0x5a, 0x49, 0x97, 0x56, 0x1a, 0x8c, 0xaf, 0xf8, 0x3f, 0x61, 0x56, 0xef, 0x43, 0xaf, 0x1e, 0xed, 0xfc, 0xc4, 0x44, 0xce, 0x2c, 0x65, 0xfe, 0xf4, 0xf2, 0x91, 0x2d, 0x9b, 0xf6, 0xca, 0x24}}, - {{0x8a, 0x88, 0xe8, 0x3f, 0x15, 0x23, 0x0e, 0x05, 0xda, 0xea, 0xfb, 0xd7, 0x94, 0x75, 0xd6, 0x5c, 0x9e, 0x16, 0xfa, 0x5f, 0xac, 0x89, 0x90, 0x58, 0x77, 0x0a, 0x79, 0x02, 0x4e, 0xdb, 0x7a, 0x2c}, {0x0b, 0x31, 0x89, 0x48, 0x4c, 0x6f, 0xe5, 0xac, 0x97, 0x2d, 0xa8, 0x49, 0xe6, 0xa3, 0xcb, 0x36, 0xef, 0x02, 0x72, 0x4d, 0x71, 0x5f, 0x3f, 0x0a, 0xd8, 0xb3, 0x66, 0xec, 0xc6, 0x12, 0xe9, 0x34}}, - {{0x38, 0x44, 0x3c, 0x93, 0xa6, 0x8c, 0x2d, 0x8d, 0x61, 0x3f, 0xf3, 0x54, 0x09, 0xb6, 0xf0, 0xd7, 0x4c, 0xf9, 0xed, 0x13, 0xcc, 0xe7, 0x3b, 0xe9, 0x86, 0xaf, 0x55, 0x6b, 0x4c, 0xbe, 0x4a, 0x11}, {0xb7, 0x22, 0x10, 0x70, 0xf1, 0x62, 0x37, 0x18, 0x98, 0xa6, 0xa2, 0xd2, 0x3d, 0x6b, 0x11, 0x48, 0x8e, 0x18, 0xf3, 0xa3, 0x7f, 0x85, 0x41, 0xea, 0x43, 0x77, 0xba, 0x65, 0x38, 0x18, 0xb5, 0x1f}}, - {{0x78, 0xf5, 0xa3, 0xd8, 0x60, 0x8c, 0x82, 0xa0, 0x8f, 0x6c, 0x3f, 0x65, 0x4f, 0x68, 0x25, 0x0a, 0x26, 0x77, 0x66, 0xdc, 0xc4, 0x9d, 0x4d, 0x2b, 0x1d, 0x65, 0x81, 0xd6, 0x48, 0x20, 0xc8, 0x36}, {0x9c, 0xc2, 0x0a, 0x23, 0x96, 0x91, 0x6c, 0xe2, 0x1b, 0x07, 0x18, 0xbc, 0x78, 0x03, 0xfb, 0x08, 0x27, 0xa7, 0x78, 0xc5, 0x44, 0x8f, 0xa0, 0x75, 0x10, 0x9c, 0xdc, 0x24, 0x96, 0x71, 0xee, 0x15}}, - {{0x18, 0xcc, 0xf3, 0xd7, 0xbf, 0x76, 0xaa, 0xfe, 0xa5, 0xe9, 0x2b, 0xff, 0xbe, 0xd0, 0x70, 0x7d, 0x99, 0xe8, 0x9f, 0x81, 0xe3, 0xad, 0xb7, 0xbf, 0xa2, 0x89, 0x01, 0x82, 0x7f, 0x59, 0x80, 0x0a}, {0xcb, 0xab, 0x73, 0x5e, 0xf8, 0x7c, 0x0c, 0x7c, 0xee, 0x04, 0x06, 0xc1, 0x40, 0x39, 0xb0, 0xef, 0x43, 0xef, 0x14, 0x3d, 0x88, 0xc5, 0xe4, 0x85, 0xb7, 0x97, 0x0a, 0x9d, 0xb2, 0xfb, 0xfe, 0x27}}, - {{0xbe, 0xbd, 0x4f, 0x68, 0x88, 0xa8, 0xc6, 0x47, 0x79, 0x52, 0x19, 0x0e, 0x44, 0x21, 0x27, 0x54, 0xea, 0xac, 0x9c, 0x84, 0x23, 0x79, 0xb3, 0xf6, 0xf1, 0x34, 0x33, 0x33, 0x73, 0x41, 0xf3, 0x34}, {0xd4, 0xda, 0xaa, 0xd2, 0x69, 0x18, 0x04, 0x0a, 0x6f, 0xb6, 0xa6, 0xf7, 0x4d, 0x9c, 0xa7, 0x34, 0x3a, 0x6d, 0x1b, 0x12, 0xe9, 0xe1, 0x7b, 0x7b, 0xbc, 0x09, 0xbb, 0xb1, 0x52, 0x7f, 0x21, 0x24}}, - {{0xc0, 0x40, 0xdc, 0x3d, 0xe7, 0xfd, 0x01, 0xfe, 0xde, 0x27, 0xe0, 0x9d, 0xdf, 0x87, 0x31, 0x67, 0xf9, 0x84, 0x24, 0x21, 0xc8, 0x0d, 0x50, 0x21, 0xd1, 0x05, 0xbf, 0x4f, 0xfe, 0x90, 0x64, 0x17}, {0x60, 0x27, 0xde, 0x83, 0xcc, 0xff, 0x96, 0x3e, 0x91, 0x11, 0x69, 0x6e, 0xcc, 0x6c, 0xd3, 0xff, 0xf7, 0x1a, 0xa6, 0x54, 0x5b, 0x95, 0xce, 0xe3, 0x86, 0x18, 0xa0, 0xc2, 0xc1, 0x70, 0x1d, 0x09}}, - {{0x75, 0x60, 0x3e, 0xd1, 0x18, 0x1b, 0x0c, 0xdf, 0x8c, 0xa2, 0x7c, 0x6d, 0xcd, 0xd9, 0x60, 0x36, 0x70, 0x5a, 0x85, 0x5e, 0x2a, 0x74, 0xdb, 0xc8, 0x18, 0xb7, 0xde, 0xfc, 0xdf, 0x63, 0x56, 0x08}, {0xa9, 0x4b, 0xcb, 0xbf, 0x44, 0x3b, 0xc6, 0xdf, 0xa3, 0xe5, 0xda, 0xc6, 0x7a, 0x07, 0xab, 0xe1, 0x6f, 0x10, 0x0a, 0x1d, 0xf8, 0x31, 0x4a, 0x2b, 0x1a, 0xba, 0x41, 0x3c, 0x38, 0x9d, 0xe9, 0x26}}, - {{0xb6, 0x8e, 0xc8, 0x22, 0x19, 0xb7, 0x5b, 0xa5, 0xfd, 0x01, 0x76, 0xf7, 0xd9, 0x93, 0xa9, 0x2b, 0x55, 0xb9, 0x90, 0x45, 0xc3, 0x38, 0x9d, 0xef, 0x85, 0x88, 0xb2, 0x8a, 0xd8, 0x90, 0x3c, 0x39}, {0x18, 0xdc, 0x98, 0x86, 0x6c, 0x9c, 0x67, 0x23, 0x77, 0xed, 0x04, 0xe2, 0x89, 0x1a, 0x75, 0xc3, 0xc5, 0x42, 0xc0, 0x2c, 0x0a, 0xf6, 0xcc, 0xa2, 0xc9, 0xef, 0xf5, 0x31, 0x64, 0x7e, 0x1a, 0x3b}}, - {{0x28, 0x12, 0xd8, 0x93, 0x03, 0x20, 0xaa, 0x01, 0x6a, 0x42, 0x65, 0x61, 0xb4, 0xde, 0x65, 0xd5, 0x19, 0xa2, 0xc3, 0x23, 0xb2, 0xc8, 0x59, 0x13, 0xea, 0xfb, 0x6d, 0x65, 0x3b, 0x22, 0x41, 0x17}, {0x17, 0x66, 0xd2, 0x99, 0x8d, 0xaa, 0xa2, 0x68, 0x5c, 0xe0, 0x95, 0x8e, 0xe3, 0xd5, 0x48, 0x32, 0x5c, 0xa9, 0x53, 0x36, 0x64, 0xe2, 0x47, 0x43, 0x40, 0x2a, 0x9e, 0x00, 0x30, 0xab, 0x6a, 0x3b}}, - {{0xb7, 0xd7, 0x0b, 0xb8, 0xf5, 0xca, 0x01, 0xc4, 0xe4, 0x8d, 0xbc, 0xbb, 0x2f, 0x06, 0x75, 0xd4, 0x4e, 0xd4, 0xa9, 0x55, 0x22, 0xa3, 0x88, 0xf8, 0x4d, 0x46, 0x21, 0x3b, 0xfb, 0x8b, 0x01, 0x1a}, {0x86, 0x43, 0xd2, 0x1c, 0x4e, 0x72, 0x8f, 0x5d, 0xd4, 0xef, 0x40, 0x86, 0x5f, 0x53, 0xa3, 0x78, 0xa1, 0x53, 0x05, 0x49, 0x0a, 0x29, 0xce, 0x47, 0x4c, 0x4a, 0x73, 0x3b, 0xea, 0x7a, 0x91, 0x2a}}, - {{0x09, 0x6e, 0xf2, 0x99, 0xdd, 0x89, 0x4e, 0x03, 0xa9, 0x62, 0xda, 0xe4, 0x00, 0xbd, 0xb5, 0x45, 0x1e, 0x27, 0x88, 0xba, 0xff, 0xdb, 0xf3, 0xeb, 0x0f, 0xaf, 0x98, 0xea, 0x9c, 0x2b, 0xc8, 0x02}, {0x4f, 0xbd, 0x68, 0x65, 0xde, 0xa2, 0xca, 0x3a, 0x43, 0x66, 0xed, 0x3a, 0xfc, 0xcf, 0x44, 0x55, 0x1d, 0x13, 0x59, 0x26, 0x05, 0xd1, 0xf8, 0x52, 0x34, 0xa5, 0x48, 0xf2, 0x44, 0x47, 0x1f, 0x01}}, - {{0x8e, 0xa6, 0x83, 0x51, 0x54, 0x9c, 0x04, 0xe5, 0xfd, 0xdd, 0x04, 0xfd, 0xd0, 0x76, 0xd8, 0xb2, 0x06, 0xfa, 0x17, 0x44, 0xda, 0x0c, 0x66, 0xe2, 0xad, 0x66, 0x2f, 0x29, 0xd1, 0xf5, 0xc0, 0x2b}, {0x04, 0x4d, 0xe4, 0xc7, 0xc1, 0x34, 0xfa, 0x98, 0x54, 0x6a, 0x2c, 0xc9, 0x5a, 0xdf, 0xf0, 0x86, 0x86, 0x6a, 0xc6, 0xe1, 0xbc, 0x25, 0x8a, 0x45, 0x21, 0x74, 0x5f, 0x9a, 0xb7, 0xdd, 0xc6, 0x36}}, - {{0xf5, 0x5d, 0xf9, 0xea, 0xce, 0xb8, 0x9b, 0x30, 0x01, 0xea, 0xba, 0xa4, 0x0f, 0x4b, 0x49, 0x01, 0x72, 0xd1, 0xe6, 0xcc, 0x65, 0x46, 0x24, 0xa1, 0xcd, 0xe4, 0x59, 0x85, 0xee, 0xac, 0x12, 0x34}, {0x9c, 0x03, 0x21, 0x99, 0x37, 0x80, 0x0c, 0xa0, 0x29, 0xf9, 0x26, 0x26, 0xf0, 0x3f, 0xec, 0x26, 0x15, 0x61, 0xc7, 0x1e, 0x84, 0x51, 0x42, 0x7f, 0x3f, 0xde, 0x11, 0x51, 0xa9, 0x4d, 0x32, 0x0d}}, - {{0x48, 0xc3, 0x26, 0x84, 0x14, 0x49, 0x23, 0x06, 0xae, 0xc2, 0xfb, 0x75, 0x8a, 0x75, 0x3b, 0x92, 0x18, 0x3a, 0x1c, 0x8a, 0x9a, 0x47, 0x63, 0x85, 0x26, 0x90, 0x30, 0x6b, 0x89, 0xf1, 0x22, 0x02}, {0x66, 0x9f, 0x58, 0x3a, 0x7a, 0xb8, 0x83, 0x63, 0x04, 0x08, 0x4c, 0xc0, 0xdb, 0x22, 0x68, 0x5d, 0x26, 0x5e, 0xc8, 0xb8, 0x0d, 0x30, 0xd5, 0x3c, 0x81, 0x7f, 0xa9, 0xf5, 0xaf, 0x87, 0xd6, 0x1e}}, - {{0x5a, 0xe0, 0xf4, 0x23, 0xd9, 0xa9, 0x76, 0x49, 0x37, 0x50, 0xf3, 0x80, 0x56, 0xd3, 0xa9, 0x89, 0x79, 0xa6, 0xff, 0x20, 0x0b, 0xd8, 0xce, 0xfc, 0x2e, 0x8c, 0x72, 0xe5, 0x6a, 0xc9, 0xaa, 0x2e}, {0x94, 0xa8, 0xb1, 0x35, 0xc8, 0x9e, 0x26, 0xe3, 0x84, 0xf5, 0xd5, 0x38, 0x5d, 0x6c, 0x34, 0xe3, 0x68, 0x15, 0xb6, 0x9e, 0x5b, 0x99, 0xd6, 0x58, 0xab, 0x2c, 0x1e, 0x18, 0x37, 0x13, 0x13, 0x3b}}, - {{0x5e, 0x22, 0xab, 0x8f, 0x8c, 0x3c, 0x26, 0xd6, 0xd6, 0x0c, 0x49, 0xc2, 0x8a, 0xaf, 0x11, 0x61, 0xd6, 0x86, 0x7c, 0x14, 0x29, 0x6c, 0xef, 0xf2, 0xad, 0xc0, 0x62, 0x39, 0x89, 0x4f, 0xf5, 0x27}, {0x86, 0x59, 0x5c, 0x18, 0x35, 0x3c, 0x42, 0xa8, 0xa3, 0xbf, 0x9c, 0x77, 0x50, 0xf8, 0xae, 0x70, 0x6e, 0xb7, 0xc8, 0x1f, 0x88, 0xf4, 0x28, 0xf6, 0xfa, 0x9d, 0x41, 0xfe, 0x92, 0xf2, 0x9c, 0x0a}}, - {{0x3f, 0xf5, 0x1c, 0x3a, 0xe1, 0x08, 0x7c, 0x53, 0x61, 0xfc, 0x2b, 0x7b, 0x65, 0x42, 0xdf, 0x78, 0xc6, 0x35, 0xc6, 0xea, 0x8a, 0xa5, 0x00, 0x25, 0x23, 0xf1, 0x99, 0xbc, 0xc2, 0xc9, 0xcf, 0x0f}, {0x4a, 0x1b, 0xbe, 0x8f, 0x47, 0x0e, 0x47, 0x31, 0xb9, 0xe3, 0x85, 0xb4, 0x18, 0xe3, 0x1e, 0x99, 0x0e, 0xbb, 0x42, 0x30, 0xdd, 0x47, 0x3d, 0x63, 0x27, 0xa5, 0xb0, 0x99, 0x03, 0x81, 0x60, 0x33}}, - {{0x72, 0x69, 0x89, 0xf9, 0x17, 0x1d, 0xa2, 0xd7, 0x2b, 0xaa, 0xd7, 0x30, 0x6b, 0x6e, 0x8b, 0x5e, 0x05, 0xa3, 0x97, 0xee, 0xae, 0x73, 0x54, 0x84, 0xe5, 0x18, 0xc1, 0x7c, 0x56, 0x21, 0x16, 0x31}, {0x81, 0xdf, 0x1e, 0xb1, 0x9f, 0x5d, 0xcf, 0xfc, 0x00, 0xb2, 0x3e, 0xc0, 0x58, 0x77, 0x12, 0x2e, 0x21, 0x19, 0xaa, 0xee, 0xb9, 0x7d, 0x04, 0x5f, 0x24, 0xf5, 0xb3, 0x77, 0x45, 0xfc, 0x86, 0x3a}}, - {{0x93, 0x84, 0x48, 0xc1, 0xc8, 0x1c, 0x93, 0x9e, 0x92, 0xe3, 0x69, 0x25, 0x13, 0xcf, 0x0f, 0x90, 0x22, 0xd0, 0xb5, 0x48, 0xe9, 0x58, 0x5e, 0x76, 0xc0, 0x64, 0x69, 0xef, 0x2e, 0xc3, 0xde, 0x2e}, {0xd4, 0xeb, 0xeb, 0xbf, 0xac, 0xeb, 0x95, 0x56, 0xff, 0x21, 0x64, 0xfd, 0xa8, 0x74, 0xcc, 0x98, 0x38, 0x32, 0x31, 0x19, 0xcb, 0x5e, 0xd8, 0x27, 0x3c, 0xda, 0x23, 0x54, 0xb5, 0x65, 0x53, 0x10}}, - {{0xed, 0xd3, 0x70, 0x2d, 0x18, 0x98, 0x22, 0xf2, 0xeb, 0xfb, 0x8b, 0xb9, 0xdb, 0x0d, 0x8e, 0xdf, 0x0b, 0x55, 0xef, 0x57, 0xc2, 0xa0, 0xec, 0x44, 0x3a, 0xa0, 0x99, 0x4f, 0x8e, 0x83, 0xe2, 0x12}, {0x71, 0xd9, 0x8e, 0x8d, 0x7c, 0xb0, 0x55, 0x66, 0x35, 0xc6, 0x99, 0xf7, 0xe8, 0xb9, 0x54, 0x9d, 0xe0, 0x0a, 0xb0, 0x31, 0xab, 0xf7, 0xac, 0xd3, 0xb4, 0xce, 0x9d, 0x04, 0x34, 0xb0, 0xb7, 0x3d}}, - {{0x30, 0xf7, 0xc6, 0xc8, 0x3a, 0x76, 0xba, 0x10, 0x7a, 0xc6, 0x50, 0x91, 0xb4, 0x86, 0x79, 0xae, 0x74, 0xa9, 0x11, 0xe4, 0xf2, 0x80, 0xed, 0x82, 0x89, 0x65, 0x2c, 0x0b, 0xd6, 0x22, 0xe0, 0x04}, {0xe4, 0xc3, 0xad, 0xe8, 0xa2, 0x79, 0x8c, 0x08, 0x4f, 0xd6, 0xe1, 0x60, 0xb2, 0xbf, 0xb1, 0xa2, 0xa8, 0x03, 0xf5, 0x50, 0xdf, 0xea, 0x53, 0x21, 0x06, 0xc1, 0x45, 0x1f, 0x95, 0xd7, 0x71, 0x04}}, - {{0x2a, 0x1d, 0x0a, 0x54, 0x34, 0x68, 0xaf, 0xa0, 0x7d, 0x33, 0x09, 0xa6, 0x0b, 0x53, 0x22, 0xbc, 0x06, 0x12, 0x92, 0xff, 0x01, 0x74, 0x7e, 0xb2, 0x48, 0x7a, 0xce, 0x5f, 0x47, 0x0b, 0x66, 0x0f}, {0x91, 0x1e, 0x34, 0x5d, 0xe4, 0x0c, 0x2d, 0x0d, 0xe5, 0x73, 0x48, 0x62, 0x9b, 0xed, 0xd6, 0x5e, 0xa8, 0x04, 0x6f, 0x85, 0x88, 0xb3, 0x0d, 0xdb, 0xad, 0xec, 0x4d, 0x6b, 0xe5, 0x13, 0x09, 0x39}}, - {{0x85, 0x8d, 0x32, 0x34, 0xf4, 0xeb, 0x1f, 0x93, 0x8f, 0x77, 0xf3, 0x13, 0xb4, 0xdf, 0xac, 0xb4, 0x46, 0x47, 0x5a, 0x06, 0xf0, 0x10, 0x98, 0x21, 0xac, 0x28, 0xee, 0xd0, 0xe6, 0x25, 0x4b, 0x27}, {0x1e, 0x0d, 0xf8, 0x2a, 0xcf, 0x5d, 0xff, 0x85, 0xaa, 0x6a, 0xd5, 0x73, 0x75, 0xda, 0xcf, 0x4f, 0x17, 0xde, 0x55, 0xf6, 0xd6, 0x10, 0xbf, 0xfe, 0xaa, 0x3d, 0xfb, 0xe2, 0x1e, 0xed, 0xc4, 0x0f}}, - {{0x47, 0xfb, 0x07, 0x08, 0x2b, 0x68, 0x88, 0x2c, 0x33, 0x98, 0x2a, 0x76, 0x61, 0xe2, 0x72, 0xe5, 0xd6, 0xe2, 0x97, 0xdd, 0xb7, 0x94, 0xa5, 0x92, 0xf1, 0x92, 0x67, 0xae, 0x08, 0x0f, 0x0c, 0x29}, {0xf2, 0xe2, 0xbd, 0x9f, 0x2a, 0xa2, 0x3e, 0x9f, 0x9d, 0x3f, 0x48, 0xb5, 0x1a, 0xc1, 0x28, 0x78, 0x49, 0xfc, 0x71, 0x60, 0x4d, 0xbe, 0x9f, 0x88, 0xff, 0x31, 0x34, 0xa4, 0x2a, 0x23, 0x27, 0x21}}, - {{0xd2, 0x7f, 0x2f, 0xcd, 0x6a, 0x27, 0x50, 0xdf, 0x09, 0x4c, 0x32, 0x05, 0x8a, 0x30, 0x21, 0x62, 0xe4, 0x99, 0xb6, 0x3f, 0x54, 0x3f, 0x28, 0x1c, 0x03, 0xd9, 0x3a, 0x09, 0x94, 0xbf, 0x91, 0x26}, {0x33, 0x97, 0x8c, 0xff, 0xff, 0x82, 0xf0, 0x6a, 0xc0, 0xd8, 0x6e, 0xe3, 0xf0, 0xfa, 0xf9, 0x5f, 0x0f, 0x60, 0x88, 0x17, 0x4a, 0xf4, 0x94, 0xce, 0x9b, 0xc4, 0x35, 0x1c, 0x5d, 0xd6, 0x18, 0x13}}, - {{0x1c, 0xbb, 0x89, 0xbe, 0x9a, 0x55, 0x63, 0x91, 0xa7, 0x01, 0x49, 0x77, 0xcf, 0xbf, 0x51, 0x52, 0x1e, 0xcf, 0x93, 0x81, 0xe2, 0x6d, 0xfb, 0x3e, 0x49, 0x69, 0x5b, 0xfe, 0xc3, 0x18, 0x42, 0x19}, {0xe0, 0xed, 0x3b, 0xcc, 0xc0, 0xf4, 0x74, 0x71, 0x87, 0x46, 0x7f, 0x88, 0xc2, 0xe3, 0x5b, 0x73, 0x20, 0x05, 0x97, 0x56, 0xf4, 0x3d, 0xab, 0x93, 0x51, 0x86, 0x12, 0xf6, 0x03, 0xd8, 0x9d, 0x0d}}, - {{0xa4, 0xec, 0xc3, 0x1f, 0x33, 0xe0, 0x74, 0x7f, 0x56, 0xc8, 0x07, 0x5f, 0x48, 0x78, 0x5f, 0xd5, 0x79, 0xfd, 0x34, 0x4f, 0x42, 0x55, 0x3f, 0x4a, 0xfc, 0x64, 0xbb, 0xe6, 0x64, 0x77, 0x48, 0x0a}, {0xa9, 0x53, 0x7c, 0xb0, 0x1b, 0xae, 0x46, 0x77, 0x82, 0xf1, 0x4e, 0xb5, 0xa8, 0x26, 0xd8, 0x0c, 0xf5, 0x2e, 0xa7, 0xc7, 0x90, 0xd5, 0xd2, 0x64, 0x2f, 0xa7, 0x19, 0xdb, 0x7c, 0x9a, 0xe7, 0x34}}, - {{0xfe, 0xc6, 0x74, 0x99, 0x2c, 0x82, 0xe7, 0x9e, 0x62, 0xdf, 0xf8, 0xec, 0xe6, 0x96, 0x79, 0x6d, 0xf0, 0x4a, 0xdf, 0xf5, 0x2e, 0x2b, 0x63, 0x32, 0xe5, 0x30, 0x81, 0xb4, 0x27, 0xbe, 0xf9, 0x10}, {0x3a, 0x62, 0xb2, 0x8a, 0x17, 0x0f, 0x72, 0x12, 0x48, 0x08, 0x25, 0x6f, 0x3b, 0xea, 0x50, 0xa0, 0xd4, 0xe6, 0x47, 0x99, 0x95, 0x84, 0xf1, 0x01, 0x08, 0xb5, 0x42, 0xe8, 0x31, 0xd5, 0x25, 0x3e}}, - {{0xcb, 0x38, 0xf2, 0x8f, 0xac, 0x5d, 0x20, 0x1c, 0xd7, 0x0c, 0x46, 0x73, 0x71, 0x7a, 0x0e, 0x4c, 0xe7, 0x19, 0x49, 0x4c, 0xa1, 0xb1, 0xb8, 0x5c, 0x1c, 0xa3, 0x6c, 0x7f, 0x43, 0xcc, 0x17, 0x10}, {0xab, 0xcf, 0xd7, 0xb0, 0x29, 0x93, 0xa7, 0xc7, 0xef, 0x57, 0x2e, 0xb2, 0x4e, 0x05, 0x10, 0xf9, 0x9a, 0xe3, 0xf3, 0x3e, 0xe2, 0x9b, 0x7e, 0xa2, 0x1c, 0x47, 0xa3, 0xde, 0xd3, 0x8f, 0x1a, 0x22}}, - {{0x1d, 0x51, 0x56, 0xc1, 0xaa, 0xc8, 0xa5, 0x8d, 0x19, 0x95, 0xad, 0x01, 0x50, 0x29, 0xf5, 0x3d, 0xd2, 0x95, 0xfe, 0xfe, 0xc1, 0x3c, 0x4e, 0x65, 0x94, 0xc5, 0xf3, 0xf7, 0xe8, 0x50, 0x26, 0x18}, {0xcc, 0x27, 0xe2, 0x4f, 0x90, 0x57, 0x14, 0x6a, 0xde, 0x90, 0x7f, 0x38, 0x0a, 0x60, 0xdc, 0xdb, 0xbd, 0xd3, 0x06, 0x89, 0x36, 0xa7, 0x7f, 0xb4, 0x8b, 0x5c, 0x53, 0x28, 0xf4, 0x7a, 0x19, 0x29}}, - {{0x5b, 0xa1, 0x92, 0xc2, 0x90, 0x47, 0x60, 0x0e, 0xc0, 0x70, 0x02, 0xb5, 0x3d, 0xbf, 0x8d, 0x56, 0xde, 0xd7, 0x45, 0xbb, 0x35, 0xc9, 0xae, 0x54, 0x8a, 0xe5, 0x62, 0x3c, 0xd9, 0x56, 0xeb, 0x30}, {0xf4, 0x14, 0xd7, 0xce, 0x00, 0x2e, 0x0f, 0x94, 0xbb, 0xc6, 0xd8, 0x5d, 0x90, 0x1a, 0xd0, 0xf3, 0x8f, 0xec, 0x9c, 0x36, 0xb3, 0x66, 0x88, 0x21, 0x22, 0xf0, 0x9e, 0x92, 0x60, 0x3c, 0xad, 0x16}}, - {{0x1f, 0xc4, 0x46, 0x64, 0xc3, 0xe5, 0x17, 0x0c, 0x01, 0x31, 0x59, 0x64, 0xb7, 0xae, 0x36, 0xbc, 0xbb, 0x1c, 0x9f, 0xf8, 0x2b, 0x22, 0xb3, 0xe6, 0xa6, 0x65, 0x94, 0x26, 0xf7, 0x07, 0x55, 0x0a}, {0x7c, 0xc0, 0xb0, 0x13, 0x02, 0x92, 0x8e, 0x5d, 0x25, 0xef, 0x53, 0x66, 0x80, 0x20, 0x75, 0x0c, 0x48, 0xec, 0x71, 0x9e, 0x9c, 0xc9, 0x8a, 0x0a, 0x7a, 0x9c, 0x48, 0x12, 0xfc, 0x69, 0xea, 0x0c}}, - {{0xe4, 0xbf, 0x67, 0x2e, 0x25, 0xaa, 0xf7, 0x6b, 0xb2, 0xef, 0x64, 0x32, 0x62, 0xdd, 0x38, 0xf6, 0xeb, 0x95, 0xb8, 0x7a, 0xdd, 0xd3, 0xd9, 0xc5, 0x0f, 0x40, 0xea, 0xd5, 0x41, 0x6f, 0xcc, 0x19}, {0x24, 0xa4, 0x3d, 0xc9, 0xac, 0x31, 0xf9, 0xb5, 0x0b, 0xab, 0x68, 0xf0, 0xe6, 0x28, 0x69, 0x06, 0x63, 0x85, 0x16, 0x25, 0xf0, 0xd1, 0x97, 0xaa, 0x7e, 0x02, 0x1a, 0xf4, 0x45, 0x2e, 0xc9, 0x12}}, - {{0x8c, 0x2d, 0x6f, 0x54, 0xf6, 0x03, 0xcd, 0xb5, 0xcc, 0xd8, 0xb4, 0x5f, 0x8d, 0xed, 0x8b, 0x00, 0x34, 0x5e, 0x82, 0xde, 0x13, 0x86, 0xcb, 0xfb, 0x27, 0xbf, 0xa1, 0x27, 0x74, 0x95, 0x1d, 0x32}, {0x7e, 0xf6, 0x5a, 0x5d, 0x71, 0xef, 0x6e, 0xf4, 0x69, 0xa9, 0xdf, 0xd7, 0xa5, 0x6a, 0x18, 0x07, 0x54, 0x65, 0x0a, 0x72, 0x43, 0x65, 0xd8, 0xcd, 0x49, 0x81, 0x21, 0x2d, 0x38, 0x07, 0x09, 0x01}}, - {{0xf2, 0x6a, 0x1d, 0x2f, 0x14, 0xd0, 0x0a, 0x3b, 0x14, 0xfc, 0x34, 0xd2, 0xda, 0x56, 0xd7, 0x99, 0xfb, 0x5d, 0x4c, 0x45, 0xc4, 0xb1, 0xa8, 0x45, 0x29, 0xf6, 0x27, 0xad, 0x77, 0x4f, 0xe7, 0x1e}, {0x0f, 0x5a, 0x92, 0xdf, 0x64, 0x12, 0x8f, 0xf3, 0xd7, 0x18, 0xac, 0x05, 0xc9, 0x81, 0x8a, 0x19, 0x42, 0xed, 0xf4, 0x24, 0xaf, 0x1c, 0x50, 0xcc, 0x40, 0x38, 0xd1, 0xd4, 0x1d, 0x53, 0x9e, 0x39}}, - {{0xbf, 0x6b, 0xc8, 0xb8, 0x9a, 0xb3, 0x29, 0xb5, 0x8e, 0x67, 0x2d, 0xe0, 0xda, 0xeb, 0x8f, 0x7d, 0x02, 0x83, 0x8e, 0xca, 0x95, 0xd7, 0xae, 0x7f, 0x2c, 0xac, 0x02, 0xe0, 0x41, 0xa4, 0xed, 0x31}, {0xbb, 0x6c, 0x55, 0x68, 0xf8, 0x1e, 0x9d, 0x61, 0xd6, 0xab, 0x81, 0xa3, 0xed, 0x2f, 0x8c, 0xd8, 0xd0, 0xdd, 0x1f, 0x1e, 0xa1, 0x42, 0x45, 0x68, 0x93, 0x22, 0x9c, 0xa3, 0xca, 0x38, 0x71, 0x07}}, - {{0x63, 0x9c, 0xbe, 0xf2, 0x0a, 0x04, 0x3c, 0x8e, 0xe2, 0xe1, 0xb0, 0x41, 0xc4, 0xac, 0xfc, 0x0c, 0x3f, 0x36, 0x06, 0x1f, 0x75, 0x28, 0x52, 0xf7, 0xcc, 0xe3, 0x81, 0x2b, 0xbd, 0x71, 0x32, 0x00}, {0x80, 0x61, 0xdc, 0x26, 0xdb, 0xae, 0xad, 0xc3, 0x86, 0x79, 0x77, 0x2e, 0x13, 0x7b, 0xd6, 0x2a, 0x54, 0xde, 0x7b, 0x02, 0x63, 0xe0, 0xc6, 0x2d, 0xa4, 0x04, 0x28, 0x6e, 0xe5, 0xda, 0xf4, 0x0a}}, - {{0x2e, 0xdc, 0xd0, 0x94, 0xc9, 0x53, 0x75, 0x50, 0xa7, 0x26, 0x9a, 0x64, 0x12, 0x40, 0x0f, 0x94, 0xdb, 0x7b, 0x07, 0xcb, 0x3d, 0x6f, 0x62, 0x91, 0x97, 0x8e, 0x99, 0xba, 0x61, 0x90, 0x6c, 0x3c}, {0x45, 0x3f, 0x32, 0x07, 0x4b, 0xff, 0x78, 0x21, 0x48, 0x37, 0xa7, 0xb4, 0x17, 0x6c, 0xbd, 0xc7, 0x3f, 0x1f, 0x36, 0xd3, 0xaf, 0x30, 0x7e, 0x56, 0xd2, 0x92, 0x98, 0xdc, 0x2e, 0x0d, 0xe0, 0x0f}}, - {{0x8b, 0x83, 0x71, 0xfc, 0xf9, 0x5e, 0x3e, 0x92, 0x2f, 0xa7, 0x40, 0xd2, 0x35, 0x03, 0x0f, 0x7d, 0x3e, 0xbb, 0xc7, 0x1b, 0x95, 0x48, 0x95, 0x19, 0x41, 0x77, 0x38, 0x8b, 0xc3, 0x30, 0xab, 0x21}, {0xb2, 0x2c, 0x1c, 0x4d, 0xb8, 0x52, 0xa5, 0x28, 0xf9, 0xc6, 0x7d, 0xdb, 0x6b, 0xb6, 0x79, 0x78, 0xc3, 0xc3, 0x07, 0xb2, 0xa2, 0xe4, 0xcb, 0x66, 0xc2, 0x1f, 0x7e, 0xce, 0x4e, 0x32, 0x5e, 0x1c}}, - {{0xe3, 0x5d, 0x6e, 0x7a, 0x37, 0x8b, 0xea, 0x0b, 0x88, 0xc8, 0x8f, 0x7b, 0xbe, 0xfc, 0xad, 0xe8, 0x44, 0x15, 0x54, 0xeb, 0xff, 0x7d, 0x43, 0x64, 0x08, 0xd7, 0x98, 0xe0, 0x01, 0x71, 0xe3, 0x17}, {0x49, 0x75, 0x18, 0xea, 0xee, 0x16, 0x3c, 0x5e, 0xdc, 0x4f, 0xda, 0x5d, 0x7b, 0xd0, 0xbc, 0xce, 0x17, 0x13, 0x65, 0xc3, 0x61, 0xd0, 0xef, 0xca, 0x79, 0xf5, 0xb0, 0xc8, 0xac, 0xaf, 0xba, 0x08}}, - {{0x60, 0xc3, 0xdc, 0xdf, 0xd3, 0x64, 0x45, 0x0c, 0x43, 0xb7, 0x7a, 0x62, 0xdb, 0xd6, 0x34, 0x3c, 0x7d, 0xe5, 0xce, 0xae, 0xef, 0x66, 0xd6, 0x19, 0xb8, 0x7c, 0xb6, 0xd1, 0x7c, 0x13, 0x2c, 0x20}, {0xbc, 0x1a, 0x32, 0xc4, 0x7f, 0xc6, 0xee, 0x0d, 0x83, 0x87, 0x4a, 0xbc, 0x68, 0x45, 0xcb, 0xc5, 0x0c, 0x55, 0xca, 0xec, 0x51, 0x14, 0xb1, 0x86, 0x77, 0x2e, 0x20, 0x48, 0xf7, 0x09, 0xf0, 0x0f}}, - {{0x8b, 0x3c, 0x05, 0xa9, 0xe2, 0xeb, 0x99, 0xf2, 0x9d, 0xa2, 0xdf, 0x89, 0x01, 0x13, 0x4d, 0x42, 0x4b, 0x4a, 0x0d, 0x49, 0x64, 0xf3, 0x28, 0xea, 0x81, 0xd8, 0x7f, 0x33, 0xa0, 0xa2, 0x08, 0x25}, {0x33, 0xbc, 0xa9, 0x16, 0x8b, 0xbf, 0x5c, 0xd2, 0xf0, 0xd5, 0x72, 0xa9, 0xed, 0xc1, 0xa1, 0x11, 0x4e, 0x31, 0x7d, 0x9d, 0xda, 0x8a, 0xef, 0x9c, 0xd3, 0x2e, 0xd1, 0xba, 0xdf, 0xb4, 0xa8, 0x00}}, - {{0x73, 0x19, 0x9d, 0x9a, 0xeb, 0x9b, 0xbe, 0x23, 0x1a, 0x89, 0xbe, 0xd6, 0x9c, 0xa7, 0xcb, 0x08, 0x76, 0xca, 0x9e, 0x0d, 0x74, 0x6d, 0x6b, 0xfe, 0x72, 0xc7, 0xad, 0x7c, 0x3d, 0x8a, 0xf9, 0x1c}, {0x67, 0x13, 0xa6, 0x8c, 0xa9, 0x48, 0xb5, 0x37, 0xe9, 0xf7, 0xb5, 0xa9, 0x6a, 0x85, 0x17, 0x77, 0x38, 0xe3, 0x85, 0xa6, 0x77, 0xed, 0xc3, 0xbb, 0x4f, 0x82, 0x7a, 0xa6, 0xad, 0x1c, 0x21, 0x37}}, - {{0xb6, 0x90, 0x63, 0x51, 0xff, 0x2e, 0x8f, 0xec, 0xaa, 0xb6, 0x35, 0x70, 0xeb, 0x81, 0x2b, 0x50, 0x3e, 0x4d, 0xfa, 0x5d, 0xf9, 0x0d, 0xf2, 0xc6, 0x49, 0x59, 0x97, 0xc1, 0x2b, 0x84, 0x19, 0x0a}, {0x0d, 0x61, 0xbe, 0x8f, 0x17, 0xa3, 0x0b, 0x76, 0x05, 0xb3, 0xbd, 0x6a, 0x62, 0xd5, 0x70, 0x03, 0x4c, 0x2d, 0x18, 0x6e, 0xbf, 0xae, 0x05, 0xb0, 0x27, 0x64, 0x56, 0xeb, 0xda, 0x19, 0xfb, 0x0b}}, - {{0x50, 0x07, 0xfc, 0x60, 0x79, 0x5c, 0x7e, 0x57, 0x27, 0x73, 0x0d, 0xca, 0xac, 0x42, 0x55, 0xef, 0xb2, 0x85, 0x1b, 0xce, 0x26, 0xe1, 0x01, 0x1f, 0x3e, 0xa8, 0xf1, 0x4f, 0xd0, 0x42, 0x4a, 0x2a}, {0xb6, 0x15, 0xda, 0x05, 0x4d, 0x59, 0xfb, 0x89, 0x67, 0x6e, 0x92, 0xc2, 0xa7, 0xa8, 0x9f, 0x40, 0xbc, 0xd7, 0xd8, 0xaa, 0x98, 0x18, 0x1d, 0xf5, 0xa1, 0xcc, 0x1d, 0xd5, 0x49, 0x29, 0xa2, 0x11}}, - {{0xfd, 0xdd, 0x54, 0x6c, 0x54, 0xce, 0x3a, 0xa1, 0x24, 0xc6, 0x6b, 0x3b, 0xd0, 0x05, 0x2f, 0x4f, 0xd6, 0xbe, 0x1b, 0x6f, 0x2b, 0x34, 0xd8, 0x24, 0xb0, 0x49, 0x58, 0x30, 0xfd, 0xdc, 0xf6, 0x10}, {0x8b, 0x2c, 0x1e, 0xb1, 0x6c, 0x77, 0xe4, 0x45, 0xb1, 0x9f, 0x31, 0x73, 0x40, 0x78, 0xdd, 0x21, 0x91, 0xf3, 0x94, 0x2c, 0x29, 0x9a, 0x3d, 0x9b, 0x49, 0x09, 0xeb, 0x6b, 0xc1, 0x66, 0x76, 0x24}}, - {{0xd1, 0x97, 0x86, 0x0f, 0x5b, 0xa7, 0x42, 0x69, 0xb9, 0xff, 0xde, 0x73, 0x55, 0x35, 0x65, 0x1e, 0x4f, 0x17, 0xcc, 0x14, 0x77, 0x52, 0xa7, 0xca, 0x3f, 0x9e, 0xd8, 0xfd, 0x52, 0x3c, 0xd5, 0x0b}, {0x56, 0x2a, 0x79, 0x07, 0xab, 0x85, 0xbd, 0xef, 0x09, 0xb6, 0xe0, 0x5b, 0xd3, 0x6d, 0xee, 0x94, 0xad, 0x80, 0x60, 0x4c, 0xf4, 0xeb, 0xe2, 0xe2, 0x64, 0xf5, 0xa4, 0x6d, 0xb5, 0xf6, 0xe7, 0x37}}, - {{0x2c, 0xa8, 0xf0, 0xda, 0x8c, 0x93, 0x85, 0xa7, 0x1a, 0xe0, 0x0f, 0x6b, 0x2c, 0x05, 0xf1, 0x0f, 0x06, 0xd5, 0x45, 0x96, 0x92, 0x48, 0xa3, 0xa3, 0x0c, 0xee, 0xe4, 0x25, 0x9f, 0x4d, 0xfc, 0x35}, {0xd0, 0xee, 0xd5, 0x35, 0x87, 0x13, 0xd8, 0x1b, 0x10, 0x22, 0x02, 0x44, 0x2b, 0x6e, 0x31, 0x20, 0xc8, 0x18, 0x82, 0x33, 0xe5, 0x87, 0xe4, 0x1d, 0x86, 0xac, 0xb7, 0x7b, 0xef, 0x15, 0x39, 0x26}}, - {{0x25, 0xaf, 0x68, 0x9d, 0x94, 0x53, 0x70, 0x72, 0x12, 0x85, 0x55, 0xbc, 0x68, 0x3a, 0xec, 0x31, 0x45, 0x47, 0x90, 0x41, 0xb9, 0xb2, 0x24, 0x62, 0x92, 0x7f, 0xa0, 0xbf, 0xfb, 0xd2, 0xae, 0x2b}, {0xe7, 0x17, 0x9d, 0xc3, 0x6e, 0xad, 0x85, 0x15, 0xe0, 0x30, 0x09, 0x79, 0x31, 0x5d, 0xf4, 0xb3, 0xab, 0x27, 0xce, 0x6d, 0x93, 0xcf, 0xf2, 0x10, 0x5b, 0x5a, 0xcc, 0xa3, 0xdc, 0x25, 0xc7, 0x3a}}, - {{0xd3, 0xe6, 0x5e, 0x79, 0xfd, 0x99, 0xd5, 0x16, 0x8d, 0x26, 0x5a, 0x53, 0x0c, 0x7e, 0x32, 0xa8, 0xa0, 0xc9, 0xd0, 0xa2, 0xf1, 0x59, 0xf3, 0x66, 0x13, 0xef, 0x55, 0xc7, 0xcf, 0xb8, 0x43, 0x0b}, {0x4f, 0x73, 0x93, 0x99, 0x8c, 0xbb, 0x1e, 0x77, 0x78, 0x89, 0x0e, 0x7f, 0xfa, 0x9e, 0x2b, 0xe2, 0xf5, 0x95, 0xaa, 0xa0, 0x6e, 0x28, 0x47, 0xf8, 0x65, 0x4e, 0xcb, 0xf0, 0xdc, 0x00, 0xab, 0x3c}}, - {{0xd6, 0x5e, 0x81, 0x93, 0x99, 0x5b, 0x0e, 0x94, 0x72, 0x84, 0xc9, 0x4a, 0x32, 0xf9, 0x58, 0xe4, 0x96, 0x6b, 0xc6, 0xa4, 0xb2, 0xa9, 0x77, 0x72, 0xff, 0x6a, 0x71, 0x35, 0xbb, 0x1d, 0x9b, 0x2a}, {0xfa, 0x74, 0x5f, 0x7c, 0x61, 0x85, 0x1e, 0x1d, 0xec, 0xbd, 0x5e, 0x2d, 0x57, 0xd9, 0xe0, 0x04, 0xdd, 0x36, 0x0e, 0x73, 0x0f, 0x9f, 0x7f, 0x69, 0xae, 0x29, 0x6b, 0x7d, 0x63, 0x68, 0x96, 0x31}}, - {{0xba, 0xce, 0x5d, 0xbe, 0x6a, 0x66, 0xec, 0xf4, 0x70, 0x36, 0x20, 0x62, 0x54, 0x75, 0x55, 0x4e, 0x56, 0xcb, 0x37, 0xa2, 0xb4, 0x90, 0xc0, 0xc2, 0x33, 0xe4, 0x7a, 0xd9, 0x8d, 0x22, 0xae, 0x32}, {0x98, 0xa9, 0x6e, 0xe7, 0xb3, 0x69, 0x96, 0xad, 0x7c, 0x7b, 0x57, 0xed, 0x9f, 0x87, 0xe7, 0x91, 0xd7, 0x94, 0x6c, 0x9e, 0x83, 0x9d, 0x41, 0x1e, 0x00, 0x08, 0xe3, 0xa0, 0xba, 0x94, 0x8d, 0x04}}, - {{0x19, 0x76, 0x6a, 0x57, 0x9f, 0x7b, 0x90, 0x6c, 0x20, 0x91, 0x1c, 0x1d, 0x9f, 0x59, 0xb1, 0x7b, 0x0c, 0xe9, 0x29, 0xd4, 0x4d, 0xe8, 0x2f, 0x3b, 0xe9, 0x5a, 0xcc, 0x8a, 0xea, 0xfb, 0xd9, 0x33}, {0xec, 0x17, 0xca, 0x44, 0x50, 0xec, 0x9a, 0x54, 0xd2, 0x2c, 0xae, 0xdb, 0xee, 0x16, 0x5d, 0x64, 0xef, 0xfe, 0x8b, 0x9c, 0x27, 0x6a, 0xb1, 0x0a, 0xf2, 0x08, 0xec, 0x6f, 0xb9, 0x42, 0xe8, 0x3c}}, - {{0x29, 0xbc, 0x9c, 0xb4, 0xea, 0xab, 0xfe, 0x66, 0xd0, 0x1a, 0x80, 0x4f, 0xfd, 0x43, 0x1b, 0x83, 0x77, 0x9f, 0x5b, 0xa9, 0x1f, 0xb8, 0x63, 0x89, 0xda, 0xc8, 0xa9, 0x33, 0x9f, 0x5b, 0xff, 0x3f}, {0xf6, 0xc0, 0xce, 0x3e, 0xb3, 0xfd, 0x46, 0xb8, 0xc1, 0x2d, 0x86, 0x2d, 0xde, 0xee, 0x8f, 0x02, 0x53, 0x84, 0x83, 0xd7, 0xa0, 0xb8, 0xfe, 0xb6, 0x84, 0xf1, 0x47, 0xea, 0x3e, 0xfb, 0xbf, 0x1e}}, - {{0x02, 0xd1, 0x7e, 0x18, 0xa6, 0x28, 0xd3, 0xdb, 0x08, 0xc4, 0xb1, 0xfa, 0xe1, 0xba, 0x92, 0x4d, 0x5c, 0x3f, 0xc4, 0x4d, 0xa9, 0x8c, 0x36, 0x50, 0x5e, 0x7f, 0x35, 0x91, 0x90, 0x65, 0xe9, 0x03}, {0xbe, 0x3c, 0x64, 0x51, 0x25, 0x10, 0x29, 0x69, 0x53, 0x9b, 0x56, 0xbc, 0xf3, 0x9b, 0x88, 0xa4, 0x13, 0xf4, 0xcd, 0x2c, 0xe6, 0xbf, 0x20, 0xf0, 0x46, 0x87, 0xa2, 0x0a, 0x40, 0x5e, 0x28, 0x01}}, - {{0xb6, 0x12, 0xa2, 0xb4, 0xaf, 0x35, 0x24, 0x8a, 0x84, 0x93, 0xfa, 0x3f, 0x88, 0x15, 0x32, 0x51, 0x02, 0xb3, 0x41, 0xc7, 0x35, 0xb5, 0x59, 0xba, 0x14, 0x50, 0x46, 0xc5, 0xe6, 0x79, 0x4f, 0x02}, {0xbd, 0xb6, 0x7d, 0x74, 0x44, 0x07, 0x8d, 0x70, 0xb8, 0x4a, 0x56, 0x99, 0x9c, 0x0f, 0xa0, 0x4b, 0x85, 0x0d, 0x2b, 0x80, 0x26, 0x86, 0xa1, 0xa6, 0x5f, 0x9f, 0xbe, 0x83, 0xb3, 0x93, 0x80, 0x11}}, - {{0x41, 0x33, 0x86, 0xac, 0x80, 0xe8, 0x81, 0x4e, 0x52, 0xd0, 0x5c, 0xee, 0xa5, 0xdd, 0x99, 0xb1, 0xbf, 0x40, 0x9e, 0x2b, 0xdb, 0x9e, 0xfb, 0x4b, 0x71, 0x4e, 0x82, 0xbc, 0xf9, 0xcc, 0xf3, 0x31}, {0x9a, 0xa3, 0x4c, 0x41, 0x27, 0xac, 0x7e, 0xc7, 0x63, 0x80, 0x2d, 0x3e, 0x0b, 0x9a, 0xe7, 0x75, 0x83, 0x73, 0x2c, 0x39, 0x29, 0x16, 0x22, 0x06, 0x9a, 0x54, 0xdb, 0x01, 0xa6, 0xf9, 0x3f, 0x00}}, - {{0x77, 0x99, 0x19, 0x89, 0x6e, 0xfe, 0xa3, 0x19, 0xdc, 0x1f, 0x2a, 0x3a, 0xab, 0xdc, 0xae, 0xca, 0x5d, 0xb0, 0x71, 0xb8, 0xfb, 0x6f, 0x08, 0x5d, 0x0b, 0x54, 0xa2, 0x10, 0xda, 0xd4, 0x09, 0x10}, {0xd2, 0xd8, 0x6e, 0xe5, 0x0b, 0xb6, 0x52, 0x3e, 0x02, 0x55, 0x20, 0x52, 0xc0, 0x62, 0xd1, 0xa1, 0xe2, 0x40, 0xff, 0x9e, 0x5f, 0x4b, 0x1e, 0xdf, 0x5e, 0x7d, 0x75, 0xa4, 0x83, 0x04, 0x83, 0x39}}, - {{0x28, 0xfc, 0x3e, 0xfd, 0x9e, 0x97, 0x0e, 0x8a, 0x68, 0x89, 0xe0, 0x94, 0x2d, 0x28, 0x49, 0x49, 0xeb, 0x6b, 0x13, 0x9c, 0x4b, 0x9f, 0xb2, 0xf2, 0x78, 0xca, 0x11, 0xf7, 0xf3, 0x7b, 0xff, 0x10}, {0x2b, 0x9a, 0x6f, 0xfe, 0x39, 0xa7, 0xac, 0xf3, 0xe1, 0x89, 0x09, 0x3b, 0xdd, 0x32, 0xa4, 0x24, 0x58, 0x88, 0x9c, 0xe6, 0xec, 0x37, 0x22, 0x2f, 0x9f, 0x01, 0x48, 0x64, 0xa5, 0x82, 0x7e, 0x2d}}, - {{0x7c, 0x2f, 0xb2, 0xb2, 0xb4, 0x25, 0xd9, 0x0d, 0x23, 0x36, 0xb3, 0xa5, 0x2a, 0xb2, 0x56, 0x5f, 0x4c, 0xa8, 0x91, 0xf2, 0xe0, 0x9f, 0xd5, 0x57, 0x14, 0xbe, 0xf1, 0x30, 0x2b, 0x97, 0x09, 0x0d}, {0xb4, 0xd6, 0xf8, 0x52, 0xc2, 0xd4, 0x74, 0x33, 0x3b, 0xd0, 0xd1, 0xbd, 0xb4, 0x3c, 0x76, 0xc0, 0x62, 0xc7, 0x9b, 0xfa, 0xd7, 0xca, 0x75, 0x00, 0x5f, 0x3b, 0x25, 0x5a, 0x43, 0xc5, 0x31, 0x32}}, - {{0xc6, 0x5e, 0x1b, 0x36, 0x5d, 0x39, 0x7e, 0xd2, 0x57, 0xaa, 0xa3, 0x5f, 0x0b, 0xb4, 0x65, 0xbf, 0x47, 0xd0, 0x4c, 0x73, 0x7a, 0xd4, 0xbe, 0x6e, 0x0b, 0x52, 0x59, 0x99, 0xcb, 0x49, 0x72, 0x1c}, {0x38, 0xef, 0x1f, 0x92, 0xe5, 0xb8, 0xa7, 0xda, 0x3f, 0xee, 0x05, 0xad, 0x6d, 0x2a, 0xef, 0x96, 0xa4, 0x18, 0x0b, 0xfc, 0xe2, 0x76, 0xf1, 0xc6, 0x4d, 0x8a, 0x75, 0x70, 0x81, 0x67, 0x9f, 0x38}}, - {{0xe7, 0xee, 0x3e, 0x9e, 0xe7, 0xca, 0x19, 0xb7, 0xa0, 0x15, 0xb1, 0x1d, 0x78, 0x05, 0x95, 0x71, 0x1a, 0x10, 0xd4, 0x89, 0x1d, 0xdf, 0xf3, 0x4b, 0xfe, 0xb2, 0x88, 0x06, 0x8a, 0x02, 0x80, 0x11}, {0xfa, 0x84, 0x81, 0xc1, 0x5b, 0x6a, 0xd4, 0xea, 0x59, 0xd2, 0xd1, 0x9e, 0xf1, 0x4e, 0x2e, 0x75, 0x0f, 0x6e, 0x42, 0x44, 0x4e, 0x46, 0x87, 0x69, 0x51, 0x9e, 0x2d, 0x84, 0x02, 0x4f, 0x76, 0x0e}}, - {{0xfb, 0x7a, 0xe3, 0xe0, 0x1b, 0x56, 0xc8, 0x4f, 0x43, 0x81, 0xaf, 0xb7, 0xcd, 0x7e, 0x22, 0x4e, 0x60, 0x44, 0x30, 0x3d, 0xcc, 0xad, 0xe5, 0x18, 0x8a, 0x5b, 0x90, 0x5c, 0x61, 0x1e, 0x1d, 0x1c}, {0x02, 0x32, 0x1a, 0xfa, 0xc9, 0x9f, 0x4b, 0xe8, 0x9f, 0x97, 0xa5, 0xde, 0x73, 0x8a, 0xd2, 0x64, 0xe3, 0xac, 0xc4, 0x52, 0x78, 0x2a, 0xb7, 0xa1, 0x88, 0xe0, 0x90, 0x90, 0x2e, 0x46, 0x76, 0x31}}, - {{0x6e, 0x40, 0x7d, 0x42, 0xc4, 0x58, 0x3d, 0x07, 0x73, 0xb9, 0xa4, 0x9d, 0x4c, 0xa6, 0xae, 0xea, 0xfd, 0x98, 0x9c, 0xce, 0x6a, 0x60, 0x2b, 0xdb, 0xf0, 0xcf, 0x06, 0x06, 0x61, 0xab, 0x0d, 0x32}, {0x38, 0xb7, 0x67, 0xe5, 0x17, 0x60, 0xf5, 0xf6, 0xcf, 0x6d, 0x0d, 0xc8, 0xa4, 0x2f, 0x8b, 0xad, 0xc6, 0xee, 0xc5, 0xac, 0x87, 0x67, 0x76, 0xef, 0xfd, 0x8c, 0xc2, 0x0c, 0x02, 0xaf, 0x46, 0x20}}, - {{0xe2, 0x93, 0x45, 0xea, 0x8c, 0xbe, 0xe0, 0xdf, 0x57, 0xa7, 0x01, 0x2c, 0xe6, 0x71, 0x25, 0xbf, 0xe4, 0xcd, 0x1f, 0x72, 0x2a, 0xbd, 0x46, 0x56, 0x5a, 0xdf, 0x5e, 0x0c, 0x65, 0x84, 0x56, 0x2e}, {0xe0, 0x3d, 0x23, 0xe7, 0x9b, 0x11, 0x67, 0xc3, 0xe2, 0xd7, 0x19, 0x83, 0xd3, 0x64, 0x59, 0xa8, 0xb3, 0x44, 0x72, 0x77, 0x06, 0x41, 0x56, 0xbf, 0xe3, 0x3f, 0x1c, 0xf9, 0xa3, 0xa0, 0xa7, 0x05}}, - {{0xcf, 0xb1, 0xbd, 0x7e, 0xb9, 0x1f, 0x57, 0xa1, 0xfb, 0x4a, 0x84, 0x94, 0xd4, 0x58, 0x70, 0xad, 0xda, 0x34, 0xf9, 0xfd, 0x3e, 0x38, 0xff, 0x22, 0x55, 0xa5, 0x8d, 0x62, 0x36, 0xf5, 0xa8, 0x03}, {0xdf, 0x83, 0x35, 0x8b, 0x60, 0xb5, 0xa6, 0x89, 0xbe, 0x3a, 0xb6, 0x4b, 0x5b, 0x76, 0xd8, 0x93, 0xce, 0x39, 0x5e, 0xc7, 0x89, 0xc2, 0x07, 0x66, 0x93, 0x3c, 0x13, 0xd6, 0xc7, 0x7a, 0x46, 0x08}}, - {{0x6d, 0x59, 0xf7, 0xc0, 0xa5, 0x0a, 0xbb, 0x09, 0x09, 0x3f, 0x31, 0x0a, 0x5e, 0x9d, 0xb7, 0xc0, 0x2d, 0xdf, 0xc8, 0x63, 0x48, 0xae, 0xc7, 0x25, 0xf5, 0xc4, 0xc8, 0x57, 0x78, 0x71, 0x0f, 0x34}, {0x5c, 0x17, 0xbd, 0xe9, 0x99, 0x09, 0xd6, 0x58, 0xcc, 0x3d, 0x36, 0x69, 0xe3, 0x51, 0x3c, 0x41, 0x5f, 0xcc, 0xbd, 0xa5, 0xfb, 0x08, 0xbf, 0x44, 0x33, 0x72, 0x10, 0x42, 0xab, 0x43, 0xd9, 0x09}}, - {{0xa3, 0x69, 0x0b, 0x19, 0xb2, 0xe2, 0x60, 0x76, 0xba, 0x5a, 0x68, 0x12, 0xbd, 0xe6, 0x75, 0xa6, 0xa3, 0x61, 0x5f, 0x34, 0x4c, 0x46, 0xc3, 0x70, 0x5c, 0x83, 0x3a, 0x20, 0x69, 0xa2, 0x06, 0x0c}, {0xb8, 0x4a, 0x7f, 0x2f, 0xb8, 0x81, 0xa9, 0x5e, 0x95, 0x6b, 0x02, 0x5e, 0x6c, 0x89, 0x0c, 0x27, 0x54, 0x79, 0x16, 0x11, 0xeb, 0x6b, 0x0a, 0x41, 0x3f, 0x41, 0xf9, 0x51, 0x5d, 0xf4, 0xcc, 0x25}}, - {{0x8f, 0xc2, 0x6a, 0x1a, 0x9a, 0x8e, 0xb6, 0x83, 0x2b, 0x8c, 0x5e, 0xe8, 0x79, 0x90, 0x2f, 0x25, 0x23, 0x7d, 0x27, 0x3f, 0x34, 0xa3, 0xd5, 0x3d, 0x86, 0xd3, 0xfe, 0xbd, 0x77, 0x66, 0x00, 0x1f}, {0x39, 0x4b, 0x1e, 0xa0, 0x7c, 0x59, 0xc2, 0x21, 0xa8, 0x3a, 0xb6, 0xca, 0x79, 0xb2, 0x95, 0x11, 0x1c, 0x37, 0xd5, 0x89, 0x5d, 0xc4, 0x47, 0x59, 0x9a, 0xf6, 0xf2, 0x76, 0x05, 0xbc, 0xfd, 0x0b}}, - {{0xae, 0xae, 0xd6, 0xf6, 0xa5, 0xcc, 0xaa, 0x56, 0x5d, 0x17, 0x56, 0x5b, 0xed, 0xb6, 0xde, 0x00, 0x48, 0xac, 0xe3, 0xf6, 0x20, 0x09, 0x9e, 0xe9, 0x68, 0x70, 0x50, 0xfa, 0xf9, 0x6d, 0x70, 0x19}, {0xfb, 0x93, 0xd8, 0xdc, 0x52, 0x01, 0xd1, 0x68, 0x47, 0x7f, 0xb3, 0xe5, 0x1d, 0xc8, 0xce, 0x05, 0x14, 0x9c, 0x1f, 0x2c, 0x62, 0xe0, 0x83, 0x7f, 0x35, 0x7b, 0x05, 0xed, 0x5d, 0x80, 0xcb, 0x31}}, - {{0x01, 0x3c, 0xf5, 0x84, 0x33, 0x89, 0x40, 0xf7, 0x91, 0x3a, 0x70, 0x4b, 0xad, 0x85, 0x5d, 0xa6, 0xb4, 0x9e, 0x16, 0x9c, 0x51, 0xf1, 0x88, 0xe9, 0x37, 0x45, 0x50, 0x9c, 0x68, 0x63, 0xb7, 0x39}, {0x3c, 0x9d, 0x89, 0x8f, 0x81, 0x28, 0xcc, 0x8f, 0xed, 0xb7, 0x4e, 0x34, 0x67, 0x76, 0x09, 0x9a, 0xac, 0xb9, 0x99, 0x10, 0x9a, 0xff, 0x7a, 0xc7, 0x40, 0x9a, 0x3f, 0xe5, 0x28, 0xf2, 0x20, 0x3c}}, - {{0x2f, 0x51, 0x99, 0x04, 0xb6, 0x02, 0x5f, 0x3e, 0x3e, 0x7e, 0xfc, 0xb5, 0xd0, 0x35, 0xaa, 0xc6, 0x77, 0x90, 0x3b, 0x99, 0x54, 0x15, 0x0d, 0x31, 0x98, 0xe5, 0xa7, 0x97, 0x1c, 0xaf, 0x2e, 0x3b}, {0xbf, 0x42, 0x4c, 0x9b, 0x64, 0xcb, 0xeb, 0xc7, 0x19, 0xce, 0xf2, 0x10, 0x91, 0x2b, 0xf3, 0x2b, 0x8e, 0xa2, 0x84, 0x68, 0x68, 0xb8, 0xeb, 0xd0, 0x68, 0xe9, 0xa4, 0x95, 0xd6, 0x43, 0x5e, 0x02}}, - {{0xa3, 0x77, 0xe9, 0x05, 0xed, 0x3a, 0x21, 0xe5, 0x89, 0x60, 0x6e, 0x36, 0xc6, 0x23, 0x91, 0xfe, 0xc7, 0x55, 0xbd, 0x4b, 0xbf, 0xb1, 0x9d, 0xff, 0x87, 0x43, 0xeb, 0x7f, 0x09, 0xf8, 0x06, 0x28}, {0xa3, 0x3f, 0xfc, 0xd0, 0xd7, 0xf9, 0xcd, 0xf2, 0xb7, 0x6a, 0xe8, 0xe9, 0x9b, 0xe7, 0x7e, 0x27, 0x4e, 0x9c, 0x38, 0x82, 0xf8, 0x96, 0xc9, 0x37, 0x31, 0x62, 0xad, 0xfa, 0xcf, 0x9e, 0xd0, 0x37}}, - {{0x65, 0xa1, 0x3a, 0x3d, 0x2d, 0xb1, 0x97, 0x6d, 0x43, 0x07, 0xdb, 0x97, 0x33, 0xbd, 0xa0, 0x3c, 0x4c, 0x2a, 0xec, 0x27, 0xf5, 0xcd, 0xeb, 0xc6, 0xe2, 0xc8, 0x7b, 0x58, 0x72, 0x77, 0x7f, 0x37}, {0x65, 0x2e, 0xfd, 0x3f, 0x30, 0xf9, 0x63, 0x25, 0x21, 0x9b, 0x1a, 0xef, 0x2c, 0x47, 0xe7, 0x54, 0x52, 0x49, 0xba, 0xa4, 0x09, 0xb2, 0xf1, 0xfd, 0x30, 0x76, 0xad, 0x09, 0x94, 0xbf, 0x5e, 0x28}}, - {{0xbb, 0x0a, 0x4f, 0xf8, 0x13, 0x9e, 0x0d, 0x30, 0xd6, 0xc8, 0x8d, 0x9c, 0x40, 0x77, 0x6d, 0xd1, 0x05, 0x97, 0xc4, 0x02, 0xdb, 0x6e, 0xb4, 0x88, 0x6d, 0xd3, 0xda, 0xba, 0xfb, 0xe9, 0xc4, 0x05}, {0x02, 0x76, 0xad, 0xbe, 0xe8, 0x5c, 0x51, 0xf1, 0xae, 0x02, 0x22, 0x9b, 0x28, 0xbb, 0x28, 0x39, 0xd9, 0x38, 0xb5, 0x58, 0x76, 0x80, 0xdd, 0x11, 0x74, 0x79, 0x87, 0x2c, 0x47, 0x8f, 0xef, 0x0b}}, - {{0x23, 0x4b, 0xdb, 0xac, 0x76, 0x50, 0x82, 0x91, 0x01, 0x5e, 0x52, 0x2b, 0xb6, 0xaa, 0x1d, 0x5e, 0xab, 0x7e, 0x00, 0xcf, 0x94, 0xf6, 0x48, 0xd3, 0x56, 0xb0, 0x27, 0x25, 0xbf, 0x10, 0xcc, 0x0f}, {0x51, 0xcb, 0x58, 0x92, 0xc9, 0xac, 0xf6, 0x80, 0x46, 0x70, 0x48, 0x1e, 0x31, 0x6f, 0x5d, 0xc1, 0x8a, 0x07, 0xab, 0x8b, 0x8e, 0xb4, 0x42, 0x30, 0x1b, 0x5d, 0xab, 0x48, 0xcf, 0x7f, 0xf4, 0x3c}}, - {{0xfd, 0x58, 0xce, 0x49, 0x12, 0x9e, 0x13, 0x6c, 0xe8, 0xd9, 0xc7, 0x23, 0xf9, 0x81, 0xb0, 0x04, 0x43, 0x0d, 0xe5, 0x88, 0x39, 0x92, 0x7a, 0x8f, 0xbe, 0xa3, 0x25, 0xb3, 0x8d, 0x3b, 0xca, 0x1f}, {0xe1, 0xef, 0xc7, 0x5b, 0x92, 0xf2, 0x2f, 0x69, 0x95, 0xd8, 0x02, 0xb1, 0x8d, 0x35, 0x5d, 0x37, 0x7e, 0xee, 0x12, 0x21, 0x46, 0xf1, 0x77, 0x73, 0xcf, 0xac, 0xd3, 0x74, 0x2a, 0xca, 0xb9, 0x22}}, - {{0x94, 0x77, 0x91, 0x94, 0x58, 0xd3, 0x8d, 0xda, 0x4b, 0x05, 0x77, 0x89, 0x6d, 0xe0, 0x67, 0xe0, 0x99, 0x3e, 0x35, 0xe8, 0xcf, 0x65, 0xe7, 0x68, 0xc6, 0x05, 0x60, 0x7c, 0x76, 0xae, 0x7b, 0x2c}, {0x4f, 0xe3, 0x5e, 0x4e, 0x06, 0x5d, 0x71, 0xbf, 0xeb, 0xab, 0x46, 0x87, 0xe1, 0xa7, 0x99, 0x9c, 0xc4, 0xcc, 0x16, 0x5e, 0xeb, 0xe9, 0x15, 0x76, 0xfa, 0xf7, 0xab, 0x73, 0xb7, 0x84, 0x8e, 0x32}}, - {{0xee, 0xb8, 0xa3, 0x7f, 0xce, 0xfc, 0x57, 0xfe, 0x7a, 0x68, 0xc2, 0xf7, 0x8c, 0x44, 0xc2, 0xc9, 0xd4, 0xc2, 0xd3, 0xef, 0x38, 0xbe, 0xd2, 0x6f, 0xa2, 0x3c, 0x64, 0xad, 0x02, 0x65, 0x88, 0x02}, {0x5c, 0x4d, 0x3f, 0xb0, 0x41, 0x98, 0xc1, 0x4b, 0x01, 0x74, 0xb0, 0xdc, 0x82, 0xea, 0x0b, 0x46, 0xb4, 0x84, 0x57, 0x6c, 0x5e, 0x4a, 0xb2, 0x95, 0x92, 0x9c, 0xa6, 0x7d, 0xee, 0xf8, 0xfb, 0x2b}}, - {{0x2c, 0x23, 0x15, 0xc4, 0x30, 0xac, 0x9f, 0xd3, 0x8d, 0x41, 0xac, 0x3b, 0x9e, 0xa7, 0xdd, 0x76, 0xbd, 0xa8, 0x03, 0xcc, 0x61, 0x50, 0x6a, 0x14, 0xc8, 0x45, 0xb0, 0x23, 0x1b, 0xe6, 0xd1, 0x33}, {0x67, 0x61, 0xc1, 0xa0, 0x38, 0x1d, 0x86, 0x0a, 0x76, 0xfd, 0x25, 0x36, 0x50, 0xd7, 0x03, 0x34, 0x11, 0x51, 0xfc, 0x4d, 0xd8, 0x43, 0x14, 0x5c, 0xb8, 0x34, 0xca, 0x43, 0x6d, 0x16, 0xc4, 0x11}}, - {{0x32, 0xdc, 0xf3, 0x73, 0x01, 0x49, 0xd0, 0x59, 0x64, 0x39, 0xc4, 0xfe, 0x5b, 0x8d, 0x05, 0xba, 0x5a, 0xb9, 0x39, 0x66, 0x16, 0xdd, 0x34, 0xe9, 0xe0, 0xcd, 0x03, 0xbb, 0xea, 0xc6, 0xbb, 0x2b}, {0x07, 0x3d, 0x23, 0x45, 0x18, 0xcf, 0x85, 0xee, 0xf3, 0x3c, 0xa9, 0xe0, 0xb6, 0x4c, 0x68, 0xee, 0xd0, 0x21, 0xee, 0x79, 0xba, 0x3b, 0x6b, 0x25, 0xb9, 0x7b, 0x7f, 0x0f, 0xec, 0x24, 0x22, 0x19}}, - {{0xae, 0xe7, 0x70, 0x26, 0x24, 0x42, 0x0d, 0x5e, 0x12, 0x7a, 0xa1, 0x14, 0x15, 0x3e, 0x25, 0x16, 0xee, 0xfe, 0x06, 0x5d, 0x27, 0x77, 0x19, 0xdc, 0xdd, 0x75, 0x05, 0x3e, 0xc3, 0xe2, 0x45, 0x19}, {0x34, 0x76, 0x99, 0x72, 0x0f, 0x15, 0x3a, 0xd1, 0x78, 0xd8, 0xb3, 0xae, 0xc0, 0x5f, 0x54, 0xfb, 0xb9, 0xfa, 0x5b, 0x4f, 0x6d, 0x97, 0xf3, 0x30, 0xc2, 0x57, 0x4e, 0x96, 0xd6, 0x8d, 0xe2, 0x39}}, - {{0x31, 0x13, 0xef, 0x1d, 0xe3, 0x94, 0x38, 0x63, 0xf0, 0x17, 0x72, 0x91, 0xd2, 0xdc, 0x8a, 0x17, 0x83, 0x38, 0xe1, 0x6b, 0x78, 0x38, 0x1d, 0x66, 0xe2, 0x2c, 0xc8, 0x6f, 0x10, 0xa7, 0x08, 0x34}, {0x3f, 0xed, 0x1b, 0xc7, 0x44, 0x2e, 0x2c, 0x34, 0xd6, 0x70, 0xee, 0x09, 0xe1, 0x42, 0xde, 0x96, 0x0f, 0x82, 0x66, 0xdd, 0x91, 0x68, 0x89, 0x85, 0xcf, 0x7b, 0x70, 0x5d, 0x93, 0x87, 0x41, 0x07}}, - {{0x1d, 0x89, 0xdc, 0xf2, 0x08, 0x7e, 0x0b, 0xc1, 0x1e, 0xd0, 0xe6, 0xd9, 0x3c, 0x91, 0x68, 0x5d, 0x03, 0x39, 0x0b, 0x09, 0x4c, 0x23, 0x5d, 0xdd, 0x4d, 0xb3, 0x16, 0xa2, 0x8d, 0x5b, 0xf0, 0x15}, {0x57, 0xf2, 0x7a, 0xcf, 0xa0, 0xfa, 0x62, 0x79, 0x7d, 0xa4, 0x52, 0x12, 0x1c, 0x18, 0xb0, 0xae, 0xa5, 0xe2, 0xca, 0xf1, 0x4b, 0x6f, 0x61, 0x12, 0x22, 0x91, 0xbd, 0x1f, 0x04, 0xda, 0x22, 0x23}}, - {{0x54, 0xb5, 0x10, 0x49, 0xd7, 0xd4, 0x1f, 0x6a, 0xfb, 0x2d, 0x4e, 0xa3, 0x07, 0x11, 0x8f, 0xe3, 0xa4, 0x3e, 0x6b, 0x80, 0xcb, 0xf5, 0xc6, 0x68, 0xda, 0x07, 0x56, 0x8c, 0x11, 0x47, 0x4a, 0x2b}, {0x26, 0x10, 0xaa, 0x01, 0xcb, 0xe3, 0x83, 0xc7, 0x99, 0x51, 0x8f, 0x28, 0x54, 0x26, 0x61, 0x5c, 0xfd, 0x1a, 0x7a, 0x4c, 0xa7, 0x5a, 0x08, 0x63, 0x2c, 0xc6, 0x93, 0x60, 0x2c, 0xc5, 0xe0, 0x2b}}, - {{0x3a, 0x67, 0x84, 0xb9, 0x7f, 0x88, 0xd8, 0xcf, 0x7a, 0x84, 0x2d, 0x57, 0xf5, 0x4a, 0x45, 0x7d, 0xfa, 0xca, 0x57, 0xe4, 0x6b, 0x5e, 0xcc, 0xb8, 0x31, 0x6b, 0x14, 0x15, 0x4a, 0x5b, 0xf0, 0x05}, {0xdf, 0xb9, 0x66, 0x33, 0x07, 0xb1, 0x83, 0x9b, 0x83, 0xad, 0x08, 0x62, 0x6e, 0x4e, 0x64, 0x7e, 0xbe, 0xec, 0x7f, 0x4f, 0x6b, 0xff, 0xf1, 0xe7, 0xa1, 0x5a, 0x07, 0xe2, 0x07, 0x47, 0x5c, 0x31}}, - {{0x60, 0x9b, 0xf4, 0x75, 0x39, 0xa4, 0x7f, 0x93, 0x00, 0x87, 0xe5, 0x40, 0x08, 0xb8, 0x2b, 0x30, 0x68, 0x26, 0x5d, 0x3f, 0x91, 0xc1, 0x39, 0xb1, 0x55, 0x8e, 0x38, 0x3f, 0x47, 0xf7, 0xd0, 0x37}, {0xaf, 0x51, 0xbb, 0xe1, 0x85, 0xde, 0xc8, 0x85, 0xfe, 0xa3, 0x54, 0x67, 0xa6, 0x5c, 0x8e, 0x24, 0x73, 0xc8, 0xf9, 0xd4, 0x4a, 0x2e, 0xd6, 0xfc, 0xc7, 0xd5, 0xa7, 0x6b, 0x68, 0x03, 0xff, 0x33}}, - {{0x43, 0x04, 0xfb, 0xd5, 0xbc, 0xad, 0x5b, 0x5e, 0x13, 0x66, 0x35, 0x95, 0x8d, 0xd6, 0xc4, 0x78, 0xf9, 0xce, 0x25, 0xe8, 0x1d, 0xf9, 0x3a, 0xfc, 0x1c, 0x4f, 0x2d, 0xe1, 0x87, 0xce, 0xa7, 0x0d}, {0x77, 0xd3, 0x74, 0x60, 0x88, 0x5e, 0xf0, 0x7e, 0x9c, 0x60, 0xb5, 0x52, 0x08, 0xaf, 0x7f, 0x4a, 0x86, 0x89, 0x81, 0x2f, 0xa2, 0x33, 0x09, 0x0b, 0x90, 0x86, 0x55, 0xde, 0xc5, 0xbb, 0x6f, 0x0d}}, - {{0x32, 0xe1, 0xec, 0xb5, 0xbf, 0x03, 0x91, 0xaa, 0x14, 0x9c, 0x6c, 0x12, 0xeb, 0xaa, 0x04, 0x11, 0x08, 0x66, 0x6f, 0x57, 0xc6, 0x39, 0xd5, 0x03, 0x23, 0xe3, 0xb4, 0xc5, 0xd2, 0xa2, 0x97, 0x22}, {0xbe, 0xe7, 0x9c, 0x21, 0x48, 0xc8, 0xd6, 0x60, 0xb0, 0x63, 0xcd, 0x00, 0xe1, 0x10, 0x5a, 0xb0, 0x88, 0x4b, 0x3f, 0x7b, 0x17, 0xea, 0x9b, 0x42, 0xba, 0xe7, 0x23, 0xf3, 0x16, 0xc9, 0x1d, 0x0c}}, - {{0xf4, 0x8b, 0xb0, 0x41, 0x55, 0xaf, 0x91, 0x7e, 0xb1, 0xd6, 0x5f, 0xce, 0xf3, 0x87, 0xb7, 0x7e, 0x56, 0x2b, 0xf1, 0x45, 0x88, 0xa3, 0x6d, 0x71, 0x4d, 0x6f, 0x64, 0xac, 0x98, 0x6e, 0x63, 0x0b}, {0xdb, 0x13, 0x3e, 0xa4, 0xd1, 0x12, 0xb7, 0x4a, 0xbf, 0x27, 0x4b, 0xe2, 0xeb, 0x52, 0x0a, 0xe6, 0x09, 0x7f, 0x55, 0x2b, 0xa5, 0xfb, 0x6c, 0x05, 0x36, 0xf2, 0xcd, 0x32, 0xf4, 0x62, 0xac, 0x1f}}, - {{0x31, 0xe6, 0xbd, 0xeb, 0xb7, 0x15, 0xfa, 0x2d, 0xaf, 0x63, 0xc0, 0xa9, 0x4d, 0xf9, 0x20, 0xb3, 0x37, 0x6a, 0xe8, 0x50, 0x1c, 0x60, 0x77, 0x1b, 0x76, 0x38, 0x0a, 0xd0, 0xf5, 0x2f, 0x4c, 0x3d}, {0xbc, 0x26, 0xde, 0x43, 0x17, 0x34, 0x2a, 0x27, 0x71, 0x3c, 0x92, 0x49, 0x59, 0x4b, 0xa5, 0xae, 0x83, 0xb1, 0x35, 0xc5, 0x07, 0xe8, 0x4d, 0x0c, 0xa7, 0x71, 0xc7, 0xae, 0x06, 0xc8, 0x65, 0x27}}, - {{0x3a, 0xe1, 0x63, 0x7b, 0x25, 0x8f, 0xec, 0x55, 0xe8, 0x9e, 0xec, 0x66, 0xd5, 0x34, 0xfc, 0xd5, 0x78, 0x82, 0xd0, 0x91, 0x20, 0xe3, 0xc2, 0x56, 0x23, 0xdc, 0x3d, 0x0e, 0x85, 0x21, 0x91, 0x16}, {0x8d, 0x63, 0xe5, 0xbe, 0x83, 0x49, 0x48, 0xa1, 0x71, 0x8b, 0x92, 0xc4, 0x1b, 0xeb, 0x79, 0x8a, 0x4b, 0x98, 0x29, 0xd0, 0xfc, 0xd4, 0xdf, 0xd6, 0xe9, 0x9a, 0x2f, 0x16, 0x98, 0x36, 0xbd, 0x2c}}, - {{0x20, 0x73, 0xc4, 0xe3, 0xbc, 0x05, 0x1b, 0x7a, 0x09, 0x84, 0x7e, 0x29, 0x39, 0x60, 0xa7, 0x32, 0x97, 0xa9, 0x80, 0x53, 0xe5, 0x44, 0x2f, 0x73, 0x4e, 0xa4, 0x70, 0xe8, 0x4a, 0xa3, 0x2a, 0x20}, {0xe7, 0x74, 0x31, 0x4f, 0x6e, 0x6f, 0x68, 0x48, 0xe3, 0xa1, 0x12, 0xae, 0x5c, 0x57, 0xff, 0x36, 0xa7, 0x50, 0x1b, 0x58, 0x2d, 0xf4, 0x9a, 0xe0, 0x25, 0xf8, 0x1c, 0x0a, 0x37, 0x49, 0x14, 0x21}}, - {{0x02, 0x11, 0x83, 0xb1, 0x77, 0x2a, 0x42, 0xdb, 0xb1, 0x98, 0x49, 0x10, 0x1d, 0xc2, 0xf8, 0x7b, 0xf9, 0x75, 0xd6, 0x9a, 0x9c, 0xb7, 0x43, 0xce, 0x21, 0x89, 0x18, 0xa7, 0xc6, 0x78, 0x9d, 0x34}, {0x0f, 0x08, 0x9f, 0x69, 0x0f, 0xba, 0x70, 0x30, 0x8a, 0xc1, 0xb8, 0x36, 0xe0, 0xf6, 0x34, 0xd1, 0x3f, 0xaa, 0xd2, 0x2c, 0xa7, 0xd0, 0x34, 0xda, 0x20, 0xb0, 0xc3, 0x37, 0x3e, 0x7a, 0x45, 0x29}}, - {{0x4e, 0x77, 0x1b, 0xd2, 0x66, 0x66, 0xa1, 0x6f, 0x7c, 0x76, 0x6f, 0x0e, 0xb1, 0xc4, 0x1f, 0xb9, 0x0b, 0xdf, 0x6c, 0x41, 0x01, 0x84, 0xaf, 0x12, 0xa0, 0xd1, 0xc1, 0x4c, 0xa3, 0x43, 0x0f, 0x22}, {0x92, 0xf8, 0x6e, 0xb2, 0x0c, 0x06, 0x2b, 0xab, 0xe2, 0x10, 0x38, 0xa5, 0xb1, 0x8a, 0x80, 0xe5, 0x0c, 0x57, 0x13, 0x33, 0x72, 0xe4, 0x6f, 0xf3, 0xb1, 0x59, 0x34, 0x39, 0x73, 0x3b, 0xf1, 0x36}}, - {{0x88, 0xb4, 0x7d, 0x94, 0xb2, 0xeb, 0x49, 0x4e, 0x53, 0xc2, 0x7d, 0xd9, 0xd3, 0x04, 0x2c, 0x24, 0x17, 0xb0, 0xfd, 0xd7, 0xd8, 0xd8, 0x41, 0x9f, 0xe0, 0x81, 0xff, 0xad, 0xdc, 0x52, 0x3c, 0x01}, {0xd9, 0xeb, 0xca, 0x54, 0xca, 0x7a, 0x29, 0x0a, 0x09, 0x9e, 0x34, 0xe4, 0xde, 0xab, 0xb0, 0x63, 0x0b, 0xf2, 0x49, 0xc7, 0x8c, 0x94, 0xd0, 0x51, 0xf4, 0xb0, 0x55, 0x9a, 0xb0, 0x8d, 0x9a, 0x06}}, - {{0x32, 0x80, 0xf7, 0x71, 0x8a, 0xb2, 0x6f, 0x40, 0x29, 0x49, 0xfe, 0x82, 0x29, 0xb4, 0x9e, 0x96, 0x95, 0x20, 0xc8, 0x53, 0xa1, 0x24, 0xaf, 0xb1, 0xa7, 0x23, 0x65, 0xa1, 0x55, 0x32, 0x2a, 0x05}, {0xd2, 0xdc, 0xc3, 0x5a, 0xb9, 0x82, 0xf1, 0x98, 0xa8, 0xf3, 0x43, 0xbf, 0x0c, 0xed, 0x88, 0xb0, 0x22, 0xdb, 0x59, 0xc0, 0x2d, 0xfe, 0x50, 0xf9, 0x39, 0xd5, 0x6f, 0xcd, 0xda, 0x06, 0x40, 0x14}}, - {{0x1e, 0x3f, 0x9d, 0xac, 0xdf, 0xfe, 0x59, 0xda, 0xb1, 0x29, 0x98, 0x3e, 0x4a, 0xcb, 0x6a, 0x22, 0xdc, 0x88, 0x04, 0xa5, 0x88, 0x33, 0x73, 0x3a, 0x57, 0xa4, 0x3b, 0x13, 0x0a, 0xf7, 0x91, 0x38}, {0x1f, 0xd7, 0xf2, 0x4b, 0xd8, 0x6e, 0xc4, 0x25, 0x37, 0xe7, 0x00, 0x1b, 0xe2, 0x2f, 0xf1, 0xbf, 0x87, 0x87, 0x3f, 0x1e, 0x77, 0x63, 0xdc, 0xae, 0xac, 0xd5, 0xef, 0xc7, 0x7c, 0xb2, 0xd1, 0x0e}}, - {{0x81, 0xcc, 0xd3, 0x40, 0x6d, 0x51, 0xd0, 0xc0, 0xc9, 0x43, 0x77, 0x16, 0x16, 0x08, 0x49, 0xa6, 0xd5, 0xc1, 0x43, 0x42, 0xc4, 0xf4, 0x42, 0xca, 0x5e, 0x8b, 0x3d, 0xb2, 0x5b, 0x8f, 0xb3, 0x23}, {0x23, 0xfa, 0xc3, 0xdc, 0x2c, 0xa3, 0x2a, 0xed, 0xc3, 0x02, 0xf1, 0xfe, 0x63, 0x34, 0xda, 0x8c, 0x3c, 0xce, 0x33, 0xe4, 0x06, 0xf0, 0x5a, 0x6b, 0xb2, 0x56, 0x84, 0x7f, 0x05, 0xdf, 0x25, 0x12}}, - {{0x4c, 0xe0, 0xa0, 0x56, 0x73, 0x0d, 0x91, 0x82, 0xf0, 0x66, 0x8f, 0xc3, 0xac, 0x73, 0xb6, 0x64, 0x32, 0x09, 0x03, 0x9d, 0x57, 0xf6, 0x23, 0xdd, 0xcd, 0x73, 0x28, 0x03, 0x8d, 0xcf, 0x91, 0x2e}, {0xb3, 0xd6, 0xc0, 0x64, 0x50, 0x85, 0x94, 0x6c, 0xb0, 0xbe, 0x0a, 0x5e, 0xd2, 0x80, 0x29, 0x7a, 0x56, 0x16, 0xb8, 0x26, 0xfb, 0xe0, 0x51, 0xb6, 0x32, 0x15, 0x40, 0x96, 0x40, 0x84, 0x5a, 0x3b}}, - {{0xfb, 0xbb, 0x71, 0x95, 0x27, 0x86, 0xdb, 0xba, 0x35, 0x88, 0x5e, 0xa7, 0x09, 0x48, 0x4b, 0x12, 0x17, 0x1c, 0x61, 0x47, 0xa7, 0x00, 0xe7, 0xc9, 0xcd, 0x5b, 0x07, 0xf2, 0x57, 0xb0, 0x20, 0x09}, {0x69, 0x6e, 0x57, 0x7f, 0xd2, 0x28, 0xf4, 0xed, 0x38, 0xb4, 0xe9, 0x29, 0x61, 0xb8, 0xdb, 0x81, 0x93, 0xec, 0x15, 0x1e, 0xd3, 0xee, 0x8e, 0xfa, 0xed, 0x0b, 0x4e, 0x89, 0xbe, 0x9f, 0x26, 0x11}}, - {{0x1f, 0x7f, 0x44, 0x7c, 0x1d, 0xfe, 0xf4, 0xb1, 0xfc, 0x51, 0x58, 0x97, 0x9d, 0x25, 0xc4, 0x83, 0x1b, 0x60, 0x1e, 0xbf, 0xb5, 0x2c, 0x7c, 0x11, 0xdd, 0x00, 0x54, 0xd9, 0x09, 0x4c, 0xd9, 0x22}, {0x24, 0x49, 0xd2, 0xb5, 0x9f, 0x7d, 0x83, 0xd6, 0x19, 0x06, 0x04, 0xf5, 0x36, 0x26, 0x3b, 0x31, 0xd6, 0x48, 0xe0, 0x08, 0x49, 0xfc, 0x63, 0x2b, 0x9c, 0xac, 0x53, 0x05, 0xd2, 0xde, 0x44, 0x11}}, - {{0x94, 0x53, 0x42, 0xa2, 0x08, 0xb4, 0x7c, 0x38, 0xd9, 0x53, 0x4c, 0xb2, 0x9b, 0x36, 0x79, 0xd0, 0xc3, 0xd4, 0xe9, 0xd9, 0x08, 0xd0, 0x15, 0x8f, 0x9d, 0xf4, 0xc6, 0xe2, 0xbf, 0xc6, 0x50, 0x31}, {0x9d, 0x72, 0xf7, 0xc1, 0x8f, 0x72, 0x04, 0x04, 0x8c, 0xfc, 0x54, 0x24, 0xbd, 0xa4, 0x67, 0x78, 0xe2, 0x12, 0x8a, 0x3e, 0x2d, 0x53, 0xce, 0x41, 0x5f, 0xf3, 0x8e, 0x46, 0xa9, 0x02, 0xa3, 0x1b}}, - {{0xc5, 0x4e, 0xb3, 0xc9, 0xbf, 0x09, 0xb3, 0x3d, 0xcc, 0x8b, 0xca, 0x20, 0x96, 0x0f, 0x33, 0x50, 0xe0, 0x2b, 0xaa, 0x76, 0x58, 0xc0, 0xba, 0xa8, 0xeb, 0x7a, 0x53, 0x52, 0x6c, 0xb1, 0x48, 0x14}, {0x6f, 0x2a, 0xd8, 0x00, 0x90, 0xae, 0x39, 0xc1, 0xb5, 0x47, 0x43, 0xe2, 0xa0, 0x76, 0x82, 0xe8, 0x5b, 0xaf, 0x82, 0x1e, 0x6e, 0x9c, 0xdd, 0x3d, 0xb8, 0x70, 0x20, 0xc0, 0x12, 0x29, 0xf6, 0x36}}, - {{0x8f, 0xfd, 0x61, 0xd8, 0x05, 0x2b, 0x02, 0x14, 0xe6, 0xa9, 0xb6, 0x50, 0xf5, 0x89, 0xd7, 0x41, 0x32, 0x23, 0xc8, 0x6f, 0x5d, 0x6c, 0xd2, 0x87, 0x2e, 0x56, 0xb6, 0x95, 0xe2, 0x35, 0xf8, 0x02}, {0xd8, 0x4a, 0xf7, 0x52, 0x06, 0x3c, 0xb9, 0xbe, 0x9d, 0xcd, 0xe4, 0x05, 0xc1, 0x72, 0x19, 0xe6, 0xdd, 0x75, 0x8f, 0x67, 0x7f, 0x8d, 0x4a, 0x88, 0x6f, 0x88, 0xc8, 0x1c, 0x06, 0x60, 0x74, 0x28}}, - {{0xf2, 0x58, 0xb9, 0xc3, 0xca, 0x75, 0xf1, 0x69, 0x98, 0x39, 0xb5, 0xab, 0xef, 0xf1, 0x47, 0x67, 0x4c, 0xf4, 0x49, 0x09, 0x53, 0x4c, 0xec, 0x46, 0x0e, 0x1e, 0xe1, 0x46, 0xf2, 0xe7, 0xba, 0x07}, {0x41, 0xdc, 0x19, 0x0c, 0x5b, 0xd2, 0x21, 0x10, 0xf4, 0x28, 0x97, 0x94, 0xbd, 0x36, 0x7a, 0xea, 0xa7, 0xc8, 0xea, 0x2c, 0xcd, 0xe7, 0x59, 0xa8, 0x90, 0x39, 0x25, 0xf8, 0x8c, 0x9a, 0xfc, 0x0e}}, - {{0x7b, 0xa7, 0xa5, 0x0d, 0xb9, 0x1f, 0xea, 0x5d, 0xc6, 0xbc, 0x4a, 0x13, 0xb8, 0x3b, 0xe1, 0xc0, 0xd4, 0xb2, 0xea, 0xc9, 0x5c, 0xd3, 0x38, 0x99, 0x1f, 0xcd, 0x6b, 0xa1, 0x12, 0x55, 0x83, 0x22}, {0x7e, 0xad, 0x0f, 0x1b, 0xf3, 0xea, 0xe9, 0x9b, 0xf9, 0x71, 0xa1, 0x0c, 0x52, 0x2b, 0x91, 0x34, 0x7e, 0xac, 0xb9, 0x31, 0x00, 0x8f, 0x21, 0x07, 0x2f, 0x69, 0xc4, 0x90, 0xe8, 0xf8, 0x74, 0x0e}}, - {{0xb9, 0x5f, 0xac, 0x26, 0xe4, 0x0c, 0x4a, 0x6b, 0x7e, 0x70, 0x71, 0xe1, 0x31, 0x23, 0xcf, 0x13, 0xa1, 0x6e, 0xcd, 0x4f, 0x2e, 0x19, 0x39, 0x85, 0xab, 0x01, 0x03, 0x6e, 0x53, 0xaa, 0x8c, 0x12}, {0xba, 0xfc, 0xa7, 0x43, 0xb3, 0x8c, 0x6b, 0x6e, 0x3d, 0x32, 0x72, 0x64, 0x3a, 0x35, 0xb2, 0xb4, 0xa2, 0x61, 0xfd, 0xa8, 0x71, 0x08, 0x67, 0x48, 0x4d, 0x1c, 0xca, 0xbd, 0xf8, 0xbc, 0xc8, 0x11}}, - {{0x93, 0x76, 0x0c, 0x6f, 0x6f, 0xbb, 0x8f, 0x8f, 0xda, 0x9e, 0x6f, 0x9f, 0x9f, 0x2c, 0xcd, 0xa8, 0xfa, 0xda, 0xab, 0x01, 0x1d, 0x1e, 0xf7, 0xf8, 0xdc, 0xa1, 0x12, 0x05, 0xe0, 0x41, 0x1a, 0x30}, {0x8f, 0x86, 0x80, 0x9d, 0x7b, 0x6c, 0x70, 0xcb, 0xf4, 0x64, 0x03, 0x5c, 0x79, 0xd2, 0xa6, 0xf2, 0x43, 0x73, 0x6b, 0xec, 0x48, 0xe1, 0x2a, 0xbf, 0xb8, 0x59, 0xc4, 0x74, 0x4b, 0x3b, 0x3f, 0x30}}, - {{0x3b, 0x8e, 0x07, 0xe0, 0xc8, 0xa5, 0x67, 0x4c, 0xcb, 0x6b, 0x59, 0xf2, 0x87, 0xf4, 0x11, 0x5a, 0xaa, 0xb8, 0x98, 0xe4, 0xc8, 0x26, 0xd4, 0x52, 0xd6, 0xe1, 0x46, 0x45, 0xee, 0x81, 0xf9, 0x1b}, {0xce, 0x0a, 0xc4, 0xf3, 0xda, 0x9e, 0x5b, 0xb2, 0x8e, 0xa6, 0xf9, 0x5f, 0xe5, 0x57, 0xd8, 0x4c, 0xaa, 0xe5, 0x0b, 0xa5, 0x95, 0x42, 0x57, 0x4c, 0x72, 0xef, 0x13, 0x9f, 0xd8, 0xbc, 0x57, 0x14}}, - {{0x23, 0x50, 0xf9, 0x9a, 0x96, 0x81, 0x49, 0x6e, 0x4d, 0xfd, 0x85, 0xda, 0x41, 0xad, 0xf4, 0xa9, 0x79, 0xda, 0xdb, 0xfc, 0xf0, 0xd9, 0x43, 0xf6, 0x75, 0x62, 0xd6, 0x2d, 0xdf, 0x61, 0x77, 0x10}, {0x6e, 0xc7, 0xaf, 0xb1, 0x06, 0xbd, 0x32, 0xfa, 0x0e, 0xcb, 0xa2, 0x1d, 0xa4, 0x2f, 0x1c, 0xe6, 0xed, 0xe9, 0x3c, 0x04, 0x9c, 0x28, 0x70, 0x4c, 0x91, 0xd3, 0xfb, 0xdd, 0x5d, 0xdd, 0x56, 0x20}}, - {{0xf4, 0x8a, 0xeb, 0xa5, 0x11, 0xb3, 0xf7, 0xe6, 0x3d, 0xc1, 0x28, 0x4f, 0xa1, 0xde, 0xcb, 0xbb, 0xc0, 0x48, 0x6b, 0xc0, 0x2a, 0xfc, 0x2a, 0x83, 0xd1, 0x39, 0x23, 0x9a, 0x84, 0xc4, 0x84, 0x18}, {0x7e, 0x14, 0x05, 0xcf, 0x27, 0xea, 0x85, 0xae, 0x70, 0x87, 0xd7, 0x5a, 0x54, 0xd6, 0x61, 0xa6, 0x02, 0x1e, 0xcd, 0x23, 0xbd, 0xb5, 0xff, 0x8c, 0xb0, 0x87, 0x59, 0x3d, 0x7a, 0xa1, 0x4a, 0x0c}}, - {{0xd6, 0xc6, 0xd2, 0x20, 0x71, 0x2b, 0x03, 0x09, 0xc6, 0xcc, 0x6d, 0xd0, 0x5d, 0x35, 0x1f, 0x63, 0x96, 0x6b, 0x4a, 0xef, 0x8c, 0xc7, 0x7c, 0xf8, 0x9d, 0x9f, 0x6f, 0xdc, 0xd1, 0xd7, 0xf8, 0x3e}, {0xd2, 0xc9, 0xdd, 0x48, 0x49, 0xad, 0xce, 0x43, 0xfc, 0x9f, 0xca, 0x7c, 0x07, 0x74, 0xc3, 0x2d, 0x8d, 0x3e, 0xdb, 0x67, 0xbd, 0xdd, 0x61, 0xac, 0xdc, 0xde, 0x3f, 0xd0, 0xb8, 0xf7, 0x97, 0x02}}, - {{0x0d, 0xa0, 0xba, 0xaf, 0xb5, 0x0e, 0x1c, 0x36, 0x25, 0x82, 0xc8, 0x48, 0x9c, 0x78, 0x51, 0x80, 0x22, 0x2d, 0x49, 0x26, 0x16, 0x16, 0x87, 0x98, 0xa2, 0x18, 0x1f, 0x50, 0x90, 0x66, 0x51, 0x3d}, {0x26, 0xd1, 0x3d, 0x84, 0xfb, 0x1b, 0x63, 0x3a, 0x22, 0x05, 0xeb, 0xc4, 0xd0, 0x64, 0x8c, 0x4a, 0xf3, 0x76, 0x15, 0x30, 0x2e, 0x95, 0x24, 0x91, 0xc8, 0x10, 0xaf, 0x79, 0x83, 0x25, 0x00, 0x1a}}, - {{0x43, 0x6e, 0xee, 0x1e, 0x60, 0xd0, 0xb3, 0xd1, 0x7c, 0x3d, 0xcb, 0xaf, 0x77, 0xf7, 0xc5, 0xc4, 0x41, 0x4f, 0xee, 0xcd, 0x65, 0xcf, 0x90, 0x58, 0x69, 0x08, 0xa7, 0x6c, 0xcd, 0x6d, 0xac, 0x3b}, {0xc6, 0x0f, 0x7d, 0x9c, 0xc5, 0x20, 0xf9, 0xdd, 0x3d, 0x2d, 0xfe, 0x6a, 0x0c, 0x3a, 0x86, 0x05, 0x16, 0xf4, 0x17, 0x93, 0x76, 0xe2, 0xd2, 0x14, 0x97, 0xb0, 0xc7, 0xda, 0xba, 0x6e, 0x0a, 0x1b}}, - {{0x39, 0xaa, 0xaa, 0x46, 0xb6, 0x4a, 0x96, 0x13, 0x1b, 0xf3, 0x54, 0xae, 0x7a, 0x08, 0xab, 0x63, 0x20, 0x53, 0x03, 0xb9, 0x8d, 0x90, 0x98, 0x6d, 0xe0, 0x9e, 0xd6, 0x6e, 0x93, 0xa5, 0xd0, 0x38}, {0x2a, 0x57, 0xe3, 0xae, 0x45, 0xdf, 0xad, 0x63, 0xfe, 0x96, 0xa8, 0x3a, 0x42, 0x22, 0x8b, 0xce, 0x07, 0x5d, 0x24, 0xc7, 0x61, 0x42, 0xc1, 0xdd, 0xa2, 0x1b, 0xf9, 0xd4, 0xd4, 0x1c, 0x35, 0x35}}, - {{0xdd, 0xe9, 0x44, 0xa7, 0x6f, 0xa0, 0xca, 0xb5, 0x57, 0xd4, 0x70, 0x56, 0x58, 0x7f, 0xe3, 0x38, 0xbb, 0x0b, 0x6f, 0x54, 0x67, 0xa4, 0xdf, 0xb4, 0x94, 0xc3, 0xe9, 0x87, 0x21, 0x18, 0xc3, 0x01}, {0x6f, 0xa4, 0x86, 0x1c, 0xf3, 0x1d, 0x5c, 0x73, 0x84, 0x87, 0x30, 0x95, 0xe7, 0x47, 0x5a, 0xc3, 0x15, 0xd7, 0xad, 0x17, 0x84, 0xcd, 0x2d, 0x0b, 0xaa, 0x2b, 0x3a, 0xb6, 0xe8, 0xdf, 0x6c, 0x10}}, - {{0xbb, 0x0a, 0x07, 0x0c, 0x6d, 0x02, 0x6e, 0x1a, 0xb2, 0x32, 0xb5, 0x15, 0x62, 0xb5, 0xa9, 0xac, 0x0a, 0xf3, 0x5c, 0x36, 0x95, 0x5c, 0x1e, 0xd4, 0xdc, 0x36, 0xc0, 0x8d, 0x02, 0xca, 0x8d, 0x28}, {0xed, 0x98, 0x23, 0x85, 0xed, 0x4d, 0x2c, 0x66, 0x3d, 0x42, 0x12, 0x1d, 0x0a, 0xbe, 0xd7, 0xb2, 0x5c, 0x81, 0x20, 0xde, 0xb5, 0xe3, 0xc6, 0x3e, 0x8f, 0xaf, 0x24, 0xd0, 0x61, 0xf4, 0x1f, 0x29}}, - {{0xec, 0x27, 0x6c, 0xd1, 0x66, 0xfa, 0x9f, 0xb0, 0x2a, 0xd7, 0x93, 0x85, 0xb0, 0x22, 0xda, 0xa1, 0x20, 0xeb, 0x54, 0xdc, 0x40, 0x92, 0x32, 0xe6, 0x8d, 0x67, 0x44, 0xe0, 0x54, 0x79, 0x76, 0x1a}, {0x27, 0x04, 0xa5, 0x85, 0x09, 0xcd, 0xfa, 0xe6, 0xb2, 0xf7, 0xdd, 0xed, 0x98, 0x85, 0x48, 0xd3, 0xc4, 0xbc, 0xc8, 0x08, 0x6f, 0x30, 0xa2, 0xd7, 0x59, 0xe4, 0x16, 0x03, 0xd5, 0xfc, 0xf0, 0x14}}, - {{0x4e, 0x6f, 0x64, 0x5b, 0xf3, 0xc8, 0x32, 0x8f, 0xef, 0x4d, 0xeb, 0x88, 0xfc, 0x08, 0xaa, 0x21, 0x34, 0x9a, 0x58, 0xde, 0x7f, 0x59, 0x01, 0x28, 0x66, 0x04, 0xd6, 0x2a, 0x17, 0xa4, 0x30, 0x3a}, {0xee, 0x19, 0x11, 0xe0, 0x40, 0x95, 0x06, 0x7d, 0x56, 0x73, 0x1b, 0x73, 0x7c, 0x55, 0x67, 0xc9, 0x1d, 0x2f, 0xa4, 0x83, 0x02, 0x4c, 0x5a, 0xda, 0xe0, 0xc1, 0x72, 0xc9, 0xfb, 0x57, 0x3a, 0x3d}}, - {{0x53, 0x2a, 0xe0, 0xc3, 0xcc, 0xf6, 0xc1, 0xd3, 0x68, 0x12, 0xc7, 0x7e, 0xdc, 0x5f, 0x47, 0x05, 0x9d, 0x5b, 0x9f, 0xf1, 0x37, 0x96, 0x00, 0xf0, 0x81, 0xbd, 0x48, 0xca, 0xfd, 0xde, 0xff, 0x30}, {0x9a, 0xc2, 0x15, 0x82, 0x09, 0x94, 0xae, 0x91, 0xf6, 0x03, 0xeb, 0x20, 0xd0, 0x5e, 0x32, 0x61, 0xdc, 0x18, 0xbe, 0x04, 0x95, 0xc7, 0x02, 0x79, 0xe2, 0xff, 0x6b, 0xcb, 0x09, 0x0d, 0xd2, 0x2f}}, - {{0xdc, 0x73, 0x42, 0xd5, 0x0b, 0xa6, 0x31, 0x1a, 0x50, 0xb1, 0xb6, 0x04, 0xc7, 0x1c, 0x7f, 0xdb, 0x13, 0xd0, 0x21, 0x01, 0x54, 0xc0, 0x61, 0x18, 0xa3, 0xa5, 0x53, 0x91, 0x73, 0xc1, 0x6c, 0x20}, {0xd5, 0xfb, 0x75, 0x57, 0x82, 0xcb, 0xe9, 0xe0, 0xdf, 0xf7, 0x24, 0x75, 0xcc, 0x49, 0x76, 0x43, 0x15, 0xcd, 0x34, 0x21, 0x0e, 0x08, 0xd2, 0x7b, 0x71, 0x7e, 0xda, 0xe2, 0x88, 0xde, 0xf0, 0x31}}, - {{0xa5, 0xd7, 0x0b, 0x78, 0x73, 0x81, 0x72, 0xfc, 0x5b, 0x06, 0xbf, 0xbc, 0x64, 0xd6, 0xef, 0x7a, 0x55, 0xe3, 0x2c, 0x0b, 0xb7, 0xa3, 0x0b, 0xb0, 0xdb, 0xf5, 0xc9, 0x28, 0xa7, 0x84, 0x99, 0x36}, {0x17, 0x42, 0x9f, 0x83, 0x05, 0x10, 0x09, 0xce, 0xa3, 0x58, 0x7c, 0xfe, 0xc5, 0xdc, 0x95, 0x32, 0x0a, 0xb6, 0xa0, 0xbd, 0x09, 0x06, 0xa3, 0x5a, 0xf2, 0xb0, 0xbb, 0xcd, 0x89, 0xcf, 0x41, 0x02}}, - {{0xb1, 0x29, 0xba, 0x9e, 0x31, 0x19, 0x00, 0x1b, 0xa3, 0x8d, 0xf9, 0x26, 0x55, 0x7d, 0x16, 0x72, 0x4f, 0x75, 0x99, 0xa7, 0x05, 0xf7, 0xcf, 0xe7, 0x2b, 0xdc, 0xf8, 0x70, 0x50, 0xfd, 0x90, 0x29}, {0x99, 0x3e, 0xc6, 0x49, 0xc4, 0xc7, 0xed, 0x1e, 0x44, 0x55, 0x85, 0xef, 0x38, 0x26, 0xf4, 0xbb, 0x2e, 0xa4, 0xf0, 0x23, 0x96, 0xcb, 0x55, 0xf7, 0x97, 0x1d, 0xe3, 0x5f, 0xe0, 0xb0, 0xee, 0x01}}, - {{0xa3, 0x54, 0xb1, 0x40, 0x9e, 0x1f, 0x7e, 0xe3, 0x6d, 0x02, 0x13, 0xcc, 0xf0, 0x23, 0x2d, 0x65, 0xe8, 0x7e, 0x49, 0x1d, 0x90, 0x41, 0x86, 0x8e, 0xb9, 0xb3, 0x25, 0x07, 0x66, 0x9f, 0x64, 0x06}, {0xf4, 0x56, 0xc0, 0x83, 0xbc, 0xdc, 0x7e, 0xf1, 0x3f, 0x38, 0xc1, 0x3d, 0xc3, 0xce, 0x63, 0xbb, 0x36, 0xa5, 0x4f, 0x89, 0x21, 0x61, 0x3f, 0x8e, 0x7c, 0xb0, 0x60, 0x1c, 0x8a, 0x2d, 0x11, 0x3c}}, - {{0x12, 0xfe, 0xbb, 0x56, 0x79, 0x7d, 0x3e, 0x1a, 0xbe, 0x37, 0x1d, 0x4c, 0x39, 0xca, 0xa9, 0xa7, 0x2e, 0xa8, 0xc4, 0xc9, 0xaf, 0x4a, 0x40, 0x97, 0x8a, 0x37, 0x7c, 0x3d, 0xa0, 0x35, 0xaa, 0x38}, {0x5d, 0xbb, 0xe0, 0x8d, 0x5e, 0x7d, 0x31, 0xb6, 0xd0, 0x69, 0xbc, 0xad, 0x17, 0x99, 0x67, 0xdc, 0x66, 0x85, 0xf3, 0xc7, 0xfe, 0x71, 0xb9, 0x68, 0x95, 0x7a, 0x70, 0x99, 0x89, 0xcd, 0x89, 0x19}}, - {{0xbb, 0x96, 0x92, 0xba, 0x13, 0x50, 0x20, 0xb2, 0x76, 0xa7, 0xfa, 0x36, 0x75, 0xda, 0x58, 0x20, 0x88, 0xc0, 0x4a, 0xf8, 0xe3, 0x5b, 0x36, 0x04, 0x32, 0xa0, 0x0f, 0x3b, 0x2f, 0x7a, 0xf4, 0x1a}, {0x8f, 0xd5, 0x43, 0x3d, 0x96, 0x47, 0xbf, 0x2a, 0xf1, 0xf0, 0x3d, 0x40, 0x75, 0x0d, 0x35, 0xb2, 0x5a, 0x3e, 0xfe, 0x77, 0x06, 0xf7, 0x21, 0xa0, 0x90, 0x7b, 0x07, 0x4c, 0xad, 0xcd, 0x2f, 0x32}}, - {{0xd4, 0xd5, 0xe5, 0xcb, 0x6c, 0xae, 0xa9, 0x06, 0xf6, 0xe6, 0xa5, 0x03, 0xd7, 0x45, 0x6b, 0xaa, 0x32, 0x09, 0xbe, 0xbe, 0x8b, 0xa7, 0x14, 0x46, 0x21, 0xec, 0x90, 0x2c, 0xd2, 0x6b, 0xcc, 0x18}, {0xb8, 0xa0, 0xd8, 0xfe, 0x8d, 0x71, 0x7c, 0x96, 0x47, 0x42, 0xb3, 0x31, 0x7f, 0xbc, 0xa7, 0x95, 0x2c, 0xda, 0xe0, 0x19, 0xaf, 0x1f, 0x19, 0x5a, 0x8f, 0x48, 0x38, 0x13, 0x41, 0xc8, 0x5b, 0x11}}, - {{0x85, 0xa4, 0x5e, 0x91, 0x19, 0xca, 0x51, 0x1d, 0xaf, 0xb7, 0x1d, 0x25, 0xf8, 0x77, 0x43, 0x0b, 0x48, 0x5a, 0xea, 0xe0, 0x37, 0xfb, 0x25, 0x08, 0xbf, 0x9c, 0x8c, 0x3b, 0x2e, 0x07, 0x48, 0x15}, {0x29, 0x4b, 0x54, 0xab, 0xb8, 0x6b, 0xeb, 0x48, 0x3a, 0xea, 0x75, 0xec, 0x9c, 0xf2, 0x66, 0xae, 0x9c, 0xb4, 0x7a, 0x16, 0xa2, 0x4b, 0x95, 0x31, 0x7b, 0x5f, 0x93, 0xdb, 0xaa, 0xaa, 0x57, 0x3d}}, - {{0x97, 0x43, 0x14, 0xd4, 0x90, 0x33, 0x46, 0x0c, 0xf6, 0x80, 0xf0, 0x4b, 0xdc, 0x52, 0x83, 0xb6, 0x45, 0x0e, 0x37, 0x07, 0x61, 0x58, 0xa1, 0xa6, 0x41, 0xd3, 0xbc, 0xff, 0xaa, 0x81, 0x00, 0x24}, {0x03, 0xa8, 0xb3, 0x46, 0xca, 0xdf, 0xef, 0xbb, 0x77, 0x68, 0x04, 0x0c, 0x85, 0x0e, 0xdd, 0xc3, 0x64, 0xec, 0xeb, 0x2f, 0xe2, 0xe8, 0xe3, 0x71, 0xfc, 0x39, 0xa5, 0xb5, 0xf7, 0xea, 0xa9, 0x08}}, - {{0xb4, 0x93, 0x1b, 0xb3, 0xb1, 0xc2, 0x06, 0x5e, 0x75, 0xdc, 0x20, 0x43, 0x7c, 0xa3, 0x13, 0xc3, 0x7b, 0x6f, 0x12, 0x26, 0x95, 0xa2, 0xfc, 0x7e, 0x41, 0x17, 0xbf, 0x40, 0x3d, 0xf8, 0xff, 0x0a}, {0x4b, 0x1d, 0xc8, 0xfd, 0x4c, 0x8f, 0xcb, 0xc7, 0x57, 0x84, 0x0c, 0xf4, 0x94, 0xfd, 0x50, 0x5a, 0x2b, 0xf1, 0x74, 0x1e, 0x91, 0x47, 0xd6, 0x71, 0x70, 0x7c, 0x80, 0xee, 0x61, 0x66, 0x41, 0x15}}, - {{0x61, 0x5d, 0xe9, 0x89, 0xf2, 0xc3, 0x02, 0x28, 0x84, 0xea, 0x07, 0x6c, 0xfb, 0x77, 0x3c, 0xf3, 0x3a, 0x14, 0xf4, 0x0d, 0x0f, 0x32, 0xc9, 0xbb, 0x80, 0x4f, 0xc0, 0x9c, 0xdf, 0xa3, 0x6c, 0x35}, {0xaa, 0x1d, 0xd8, 0x9f, 0x2b, 0xfa, 0x45, 0x4f, 0x6e, 0x61, 0x99, 0x71, 0x59, 0x5e, 0x47, 0x7f, 0xb5, 0xdf, 0x4e, 0xce, 0x29, 0xdf, 0x3b, 0x7d, 0x87, 0x1f, 0x27, 0xf9, 0x6b, 0x8d, 0xae, 0x1d}}, - {{0x2f, 0x19, 0x94, 0x7e, 0xde, 0x87, 0x3f, 0x47, 0xb0, 0x44, 0x11, 0x12, 0x88, 0x9d, 0x93, 0xd3, 0xea, 0xc5, 0x10, 0x10, 0x98, 0xe7, 0x3b, 0x96, 0x2e, 0xde, 0x23, 0xdf, 0x97, 0x35, 0xef, 0x17}, {0x76, 0xdb, 0xe3, 0x55, 0xac, 0x8d, 0x95, 0x1e, 0x9c, 0xed, 0x2e, 0xd8, 0x81, 0xc6, 0xd2, 0x12, 0xcf, 0xe0, 0x5e, 0x1d, 0x84, 0x16, 0xd5, 0xd3, 0x47, 0x34, 0xea, 0x9c, 0xdd, 0x26, 0xc9, 0x0a}}, - {{0x08, 0x8b, 0x05, 0x15, 0xc4, 0x89, 0x58, 0x68, 0xaf, 0x97, 0x13, 0xdb, 0xe4, 0xb0, 0xb7, 0x6d, 0x77, 0xa7, 0x5c, 0xf6, 0x48, 0x15, 0x80, 0x5b, 0x4b, 0x08, 0x5e, 0x14, 0x44, 0xe8, 0xc7, 0x0b}, {0x8a, 0x20, 0x79, 0x3f, 0x8c, 0x4d, 0x38, 0xe5, 0x54, 0x33, 0xfd, 0x29, 0xe1, 0x22, 0x1f, 0x15, 0xdb, 0x21, 0xac, 0x27, 0x5c, 0xa9, 0x90, 0x7a, 0x55, 0xa6, 0x02, 0x22, 0x45, 0xe4, 0xed, 0x19}}, - {{0x89, 0x37, 0x32, 0xee, 0xfc, 0x57, 0xd8, 0xde, 0x33, 0x6f, 0x1d, 0x30, 0x0f, 0xaa, 0xfe, 0x0b, 0x6d, 0xbf, 0x9b, 0x5d, 0xd3, 0x96, 0x9c, 0xf3, 0x6f, 0x97, 0xbf, 0xfa, 0x09, 0x83, 0x9d, 0x2a}, {0x61, 0x31, 0xee, 0x53, 0x45, 0x0f, 0x8c, 0x52, 0x93, 0xaa, 0x93, 0xef, 0xcc, 0xd2, 0xca, 0x6d, 0x6c, 0x99, 0xc9, 0x2e, 0x8a, 0xf0, 0x04, 0xe7, 0x3f, 0x2d, 0x0d, 0xcc, 0xda, 0x16, 0xfd, 0x1b}}, - {{0x40, 0x36, 0x0c, 0xe4, 0x71, 0x84, 0x8b, 0x18, 0xd0, 0x76, 0x97, 0x06, 0x59, 0x86, 0x01, 0xa2, 0x71, 0x05, 0x9d, 0x20, 0xe0, 0x57, 0x8d, 0xd0, 0xae, 0x64, 0x54, 0xe1, 0xbb, 0x63, 0x90, 0x1a}, {0x96, 0xc0, 0x97, 0xe5, 0x49, 0x90, 0x8d, 0x56, 0xc5, 0x87, 0xaa, 0x87, 0xd0, 0x78, 0x50, 0xdd, 0xf2, 0x5e, 0x87, 0x71, 0xd9, 0x73, 0x15, 0x3c, 0xf4, 0x23, 0x9e, 0xea, 0x1e, 0x69, 0x8e, 0x38}}, - {{0x60, 0x15, 0x70, 0x93, 0xc1, 0x3f, 0xab, 0x40, 0xf5, 0x40, 0xc8, 0x2e, 0x90, 0xa2, 0xce, 0x29, 0x7b, 0xf9, 0xf7, 0xa9, 0x95, 0x0b, 0x5d, 0xd7, 0x13, 0xc6, 0xd8, 0xab, 0x79, 0x79, 0xf0, 0x0a}, {0xed, 0x9c, 0x53, 0x05, 0xd2, 0xca, 0x15, 0x5c, 0x1b, 0x09, 0x6b, 0x03, 0x43, 0x09, 0x02, 0xc6, 0x5e, 0x7f, 0x91, 0xe5, 0xce, 0x78, 0x2c, 0x4c, 0xf9, 0x4b, 0xa3, 0xf5, 0xff, 0xac, 0x59, 0x19}}, - {{0xb8, 0x0f, 0xc0, 0x7c, 0x6d, 0x87, 0x8d, 0xfa, 0xa1, 0x19, 0x6d, 0x78, 0x97, 0x4a, 0x9c, 0x5a, 0xe9, 0xae, 0x9b, 0x3b, 0x15, 0x81, 0xbe, 0x12, 0x3f, 0xd4, 0x94, 0x85, 0x78, 0x29, 0x0f, 0x1a}, {0xf7, 0x8d, 0xe8, 0xd4, 0xbc, 0x14, 0x97, 0xed, 0xa3, 0x9e, 0xd8, 0x0d, 0xd3, 0xc0, 0x34, 0xe7, 0xf5, 0xe1, 0x6d, 0xc8, 0x59, 0x22, 0x5d, 0xec, 0xaf, 0x8f, 0x88, 0x57, 0xf3, 0x03, 0x22, 0x13}}, - {{0x93, 0x8f, 0x84, 0x04, 0x69, 0x3b, 0xb5, 0x93, 0x22, 0xcf, 0x8c, 0xdf, 0x0d, 0x8c, 0x39, 0x13, 0x42, 0x4f, 0x66, 0xa5, 0x2e, 0x11, 0x6d, 0xf4, 0x40, 0x86, 0xd6, 0xf2, 0xf5, 0xe2, 0x41, 0x00}, {0x60, 0x77, 0x10, 0xbc, 0x79, 0x0c, 0x05, 0xb6, 0xac, 0xad, 0x49, 0x4b, 0xea, 0x15, 0x50, 0xee, 0x68, 0x22, 0xf4, 0x22, 0x82, 0x21, 0xe3, 0x65, 0xad, 0xc0, 0xa9, 0x41, 0x94, 0x69, 0xcc, 0x31}}, - {{0xab, 0x81, 0x62, 0xeb, 0x7c, 0xab, 0xae, 0x94, 0xab, 0x56, 0xf1, 0xd8, 0x94, 0xca, 0x28, 0x52, 0x4e, 0x88, 0xb9, 0x16, 0x93, 0xaf, 0x5a, 0x47, 0x6d, 0xb1, 0x3e, 0x6c, 0x4a, 0x0f, 0x86, 0x19}, {0x40, 0x6d, 0x8c, 0xed, 0x8f, 0xe9, 0xdc, 0xeb, 0x7f, 0x30, 0x4e, 0x45, 0x97, 0x82, 0x40, 0x05, 0x03, 0x67, 0x4a, 0x3f, 0x25, 0x32, 0x24, 0xd0, 0xe3, 0x5b, 0x7d, 0xf5, 0xe4, 0xa0, 0xf1, 0x1a}}, - {{0x34, 0xe6, 0x5b, 0xb8, 0x2e, 0xa9, 0x36, 0xfa, 0x50, 0x88, 0xb7, 0xea, 0x3d, 0xed, 0x4a, 0xb4, 0x4b, 0xc1, 0x70, 0x67, 0xd6, 0x58, 0x32, 0xbe, 0x4f, 0x63, 0x6d, 0x81, 0x41, 0x51, 0xff, 0x35}, {0x2c, 0xbd, 0xaa, 0xce, 0x1b, 0x0c, 0x0c, 0x50, 0x2e, 0xef, 0x8a, 0xf6, 0x9b, 0x66, 0xd6, 0xf0, 0x72, 0x9c, 0x39, 0x94, 0x04, 0xf9, 0x8d, 0xbd, 0xd3, 0x69, 0xad, 0x35, 0x2c, 0xef, 0xb1, 0x2d}}, - {{0x0c, 0xc1, 0xff, 0x58, 0x5d, 0x8b, 0xb4, 0xc0, 0xd2, 0x8c, 0x8e, 0xa2, 0xbe, 0x70, 0xca, 0xe5, 0xbd, 0xfb, 0xab, 0x87, 0xaf, 0x95, 0x39, 0xf4, 0x77, 0xd3, 0x83, 0xd5, 0xf6, 0x82, 0x30, 0x07}, {0x13, 0x0d, 0x05, 0xd5, 0xa0, 0x30, 0x62, 0x10, 0x50, 0xc3, 0x4b, 0xf3, 0x80, 0x3c, 0x6a, 0x4b, 0x19, 0xa3, 0x96, 0x30, 0x27, 0x83, 0xfe, 0xc6, 0xf0, 0x89, 0xc2, 0x0c, 0x7f, 0x63, 0x30, 0x22}}, - {{0x09, 0xb0, 0x8b, 0xc1, 0x91, 0x91, 0xe8, 0x25, 0xad, 0x8a, 0xa1, 0xb2, 0xc5, 0x29, 0xf9, 0x82, 0x06, 0x97, 0x2a, 0x6a, 0x20, 0x15, 0x85, 0x3f, 0x7c, 0x73, 0xd7, 0x1e, 0x61, 0x42, 0xfe, 0x25}, {0xf6, 0x02, 0x3e, 0xd6, 0x52, 0xc5, 0x37, 0x83, 0xb4, 0x5f, 0x10, 0x0b, 0xa9, 0x77, 0xcc, 0x73, 0x8c, 0x7a, 0xad, 0x3b, 0x61, 0xe5, 0xdb, 0x94, 0x40, 0xc4, 0x9f, 0xa3, 0xb7, 0x36, 0xe7, 0x26}}, - {{0x43, 0x87, 0xc0, 0xb1, 0x50, 0xb6, 0x46, 0x09, 0x65, 0x8c, 0xb8, 0x11, 0x20, 0xc0, 0xb9, 0x9d, 0x13, 0xff, 0xf8, 0xcb, 0xca, 0x4d, 0x3c, 0xfa, 0xbc, 0x24, 0x13, 0xeb, 0x44, 0xc8, 0xe5, 0x06}, {0xa1, 0x70, 0xa3, 0xa8, 0xf9, 0x57, 0x8f, 0x3c, 0xaf, 0x1b, 0xfc, 0xe0, 0x38, 0x8b, 0xc5, 0x37, 0x3b, 0x81, 0xc8, 0xaf, 0x15, 0x35, 0x33, 0x6b, 0x3a, 0x57, 0x9f, 0x79, 0xf2, 0xf5, 0x82, 0x1a}}, - {{0x9b, 0x27, 0x0a, 0x42, 0x63, 0x5e, 0xa1, 0xbe, 0x1d, 0x35, 0x12, 0x89, 0x2b, 0x28, 0x07, 0x8e, 0x7d, 0xfd, 0x6a, 0xd8, 0x99, 0xf7, 0x8f, 0x40, 0xe4, 0x22, 0x6e, 0xce, 0x8e, 0x7b, 0x8f, 0x07}, {0xdf, 0xec, 0xf1, 0xce, 0x99, 0xd9, 0xbc, 0x88, 0xec, 0x0b, 0xe7, 0xd4, 0x44, 0x9c, 0x3d, 0x33, 0x8e, 0xb1, 0x1a, 0x69, 0xbd, 0xfe, 0x35, 0x80, 0x48, 0x11, 0xa5, 0x70, 0x98, 0xa0, 0x07, 0x14}}, - {{0x5f, 0xaa, 0x84, 0x25, 0xde, 0x97, 0x4c, 0x45, 0x99, 0xa8, 0x27, 0x7a, 0x06, 0x94, 0xc7, 0xee, 0x02, 0x47, 0xd3, 0x80, 0x27, 0xd4, 0x55, 0x09, 0xff, 0xd6, 0x43, 0xc1, 0x59, 0x97, 0x35, 0x1d}, {0x5c, 0x60, 0xf6, 0x15, 0x30, 0xaf, 0x16, 0xa8, 0x43, 0xa9, 0x9b, 0x68, 0xd6, 0x71, 0x10, 0x07, 0xe1, 0xa8, 0x3c, 0xc7, 0x8a, 0x14, 0x02, 0xdb, 0x77, 0xa7, 0x65, 0xb7, 0xec, 0x3d, 0xdd, 0x05}}, - {{0x2f, 0xfb, 0x6a, 0xd7, 0xeb, 0x38, 0x80, 0xdb, 0x5d, 0x32, 0x88, 0x1c, 0x9f, 0x0a, 0xc9, 0x0d, 0xf5, 0x6c, 0x22, 0x16, 0x1e, 0xc8, 0x8c, 0xcf, 0x72, 0xa1, 0x71, 0xa7, 0x7b, 0x7c, 0x99, 0x2a}, {0x2f, 0xe2, 0x55, 0x21, 0xbd, 0xd9, 0xc2, 0xe8, 0xa9, 0xe9, 0x8f, 0xbd, 0xa0, 0x25, 0x70, 0x8a, 0x41, 0xe8, 0x28, 0x1d, 0x92, 0xc1, 0xe9, 0x5b, 0x3b, 0x9c, 0x8a, 0x5c, 0x63, 0x87, 0xea, 0x12}}, - {{0x3c, 0x93, 0xb8, 0x84, 0x98, 0x22, 0x5c, 0x4e, 0x4c, 0x99, 0xa8, 0xb2, 0xa0, 0x86, 0x77, 0x46, 0x30, 0x5b, 0x23, 0xc3, 0x0b, 0x90, 0x25, 0x13, 0x18, 0xcc, 0xae, 0xa4, 0x23, 0x46, 0x1e, 0x2a}, {0x9b, 0xd4, 0x4b, 0x6e, 0x2b, 0x51, 0x6c, 0x56, 0x5d, 0x0b, 0x2f, 0x1e, 0x1c, 0x0f, 0x4e, 0xa7, 0x1d, 0x6e, 0x83, 0x55, 0x3c, 0x55, 0x43, 0xcb, 0x46, 0xa3, 0x30, 0x69, 0x75, 0xa1, 0xa4, 0x13}}, - {{0x10, 0x22, 0x21, 0x89, 0xf0, 0x48, 0x3c, 0x50, 0xd0, 0x86, 0x5d, 0x78, 0x32, 0x72, 0x91, 0xed, 0xfa, 0x35, 0xfd, 0xb9, 0x95, 0xad, 0xc2, 0xc0, 0xf6, 0x17, 0x38, 0x1e, 0x6a, 0xca, 0x03, 0x0b}, {0xb6, 0xbe, 0x3b, 0xf4, 0x2e, 0x4c, 0x85, 0x4c, 0x12, 0xc7, 0x97, 0x07, 0xe3, 0x8f, 0x25, 0x33, 0x7f, 0xd1, 0xd7, 0x71, 0xb2, 0x65, 0x2b, 0x7b, 0xd7, 0xfe, 0xcb, 0x59, 0xd2, 0x45, 0x08, 0x26}}, - {{0x42, 0x16, 0xca, 0x16, 0x65, 0x96, 0x43, 0x51, 0x4d, 0xad, 0x4f, 0x09, 0xc5, 0x77, 0xa0, 0xfa, 0xeb, 0x14, 0x7d, 0xaa, 0x69, 0xd8, 0xc1, 0xcb, 0x25, 0x10, 0xc2, 0x34, 0x0a, 0x0f, 0xf2, 0x2c}, {0xc6, 0xcd, 0x21, 0x99, 0xa9, 0xee, 0x36, 0xad, 0x41, 0x0a, 0x7f, 0x29, 0x0d, 0x37, 0x1d, 0x2e, 0x41, 0x93, 0x15, 0x09, 0x6f, 0x08, 0x57, 0xc9, 0xaf, 0x1d, 0x1e, 0xe2, 0x10, 0xcf, 0xcc, 0x22}}, - {{0x4c, 0xad, 0x14, 0xc3, 0x14, 0xe6, 0x44, 0xfb, 0x7d, 0x61, 0xd8, 0xdf, 0x0b, 0xdb, 0x24, 0x8b, 0x26, 0x9e, 0x6a, 0x3f, 0x6f, 0x19, 0x7d, 0xd1, 0x64, 0x77, 0xdf, 0x32, 0xd6, 0xff, 0xc8, 0x27}, {0xdc, 0x42, 0x0c, 0x39, 0xb4, 0x43, 0xca, 0xa5, 0x8b, 0x56, 0x1b, 0x6a, 0x1f, 0x79, 0xa2, 0xd7, 0x51, 0xb2, 0x63, 0x9c, 0x22, 0x1f, 0xa7, 0x98, 0x9d, 0x77, 0xa9, 0xe7, 0x03, 0x0d, 0xa3, 0x31}}, - {{0x0d, 0x55, 0x22, 0x87, 0xe9, 0x4c, 0xb4, 0xf4, 0xc8, 0x0a, 0x39, 0x01, 0x22, 0x8b, 0x93, 0xdd, 0xaa, 0xee, 0x27, 0x52, 0x23, 0xf4, 0x86, 0xfe, 0xcb, 0xad, 0xb7, 0xad, 0xfe, 0x8d, 0xd2, 0x31}, {0xdc, 0x7b, 0xbc, 0x74, 0x33, 0x7f, 0xdb, 0x5a, 0x30, 0x86, 0xb8, 0x2b, 0xb1, 0xd1, 0x0f, 0xc1, 0x1c, 0xf4, 0x5b, 0x93, 0xe5, 0x7c, 0x28, 0xae, 0x9f, 0xa3, 0x54, 0x80, 0x73, 0x97, 0x20, 0x2a}}, - {{0x6b, 0x14, 0x67, 0x3d, 0x3e, 0x41, 0xe7, 0x3b, 0xbd, 0x75, 0x17, 0x2e, 0xa9, 0xcd, 0x57, 0xad, 0xe9, 0xae, 0x71, 0xe3, 0xc4, 0xf9, 0x5f, 0x2c, 0x49, 0x4e, 0x33, 0x2f, 0x0e, 0x7a, 0x81, 0x1b}, {0x37, 0x27, 0x6d, 0xcd, 0xfb, 0x8d, 0x5d, 0xa1, 0xcb, 0x8f, 0x43, 0x5f, 0x19, 0xce, 0x49, 0x2a, 0xd1, 0xcf, 0x1a, 0x1b, 0x52, 0x1b, 0x38, 0x4d, 0x3c, 0xa2, 0x28, 0x58, 0x94, 0xce, 0x93, 0x0e}}, - {{0xa2, 0xce, 0x76, 0xd4, 0x5d, 0xce, 0x51, 0x1f, 0xd4, 0x73, 0x84, 0x21, 0xcf, 0x92, 0x2f, 0xdd, 0x6b, 0x0b, 0x66, 0xc7, 0x31, 0x92, 0x6a, 0x66, 0xfb, 0xb3, 0x56, 0x97, 0xae, 0xa9, 0x1a, 0x2b}, {0xa3, 0xcc, 0x15, 0x8c, 0xce, 0x9c, 0xa9, 0x46, 0xaa, 0xd9, 0x60, 0xc4, 0xce, 0xbb, 0x85, 0xbf, 0x21, 0x10, 0xa4, 0x4a, 0xb8, 0xa7, 0x8a, 0x4e, 0x4c, 0xe5, 0x2a, 0x6a, 0x1a, 0xa8, 0x80, 0x17}}, - {{0x8a, 0xc0, 0x68, 0x95, 0x50, 0x6b, 0x7a, 0xe1, 0x82, 0xfd, 0x4e, 0x9e, 0x60, 0xae, 0x9f, 0x25, 0xdc, 0x4b, 0xc4, 0x3e, 0x28, 0xd1, 0x7f, 0xaf, 0xad, 0x91, 0xa6, 0x74, 0xd3, 0xde, 0x09, 0x1c}, {0xd5, 0xa4, 0x51, 0x35, 0xa3, 0xb9, 0xdf, 0x70, 0x82, 0xc5, 0x87, 0x11, 0xcc, 0xee, 0x2e, 0xfe, 0x56, 0x14, 0x21, 0xdb, 0x26, 0xf4, 0x86, 0x85, 0xca, 0x0f, 0x50, 0x93, 0xa8, 0x2b, 0xa6, 0x26}}, - {{0x58, 0x66, 0x24, 0x56, 0x23, 0xcd, 0xc3, 0x5e, 0x7f, 0xb0, 0xfe, 0x14, 0x6b, 0x69, 0xab, 0x0b, 0x25, 0x1b, 0x80, 0x5b, 0x72, 0x9a, 0x0e, 0xf7, 0x80, 0xcd, 0xc6, 0xa1, 0x7b, 0x98, 0xff, 0x22}, {0x41, 0xee, 0x7c, 0x8b, 0xb5, 0x0f, 0x08, 0x78, 0x9b, 0x92, 0x56, 0xb9, 0x3d, 0xd8, 0x4d, 0xce, 0xc4, 0xdd, 0x4d, 0xa7, 0xce, 0x39, 0xc8, 0xea, 0x6d, 0xa8, 0x06, 0x2b, 0xea, 0x33, 0x17, 0x23}}, - {{0x1f, 0xfe, 0x5d, 0x68, 0x46, 0x67, 0xc8, 0xae, 0x68, 0x51, 0x1e, 0xb7, 0x0a, 0x0c, 0x18, 0xc2, 0xfa, 0x70, 0x70, 0x1a, 0x76, 0x69, 0x76, 0x8d, 0xdb, 0x9c, 0xfc, 0x7b, 0xa2, 0xc8, 0x08, 0x00}, {0x77, 0xca, 0x71, 0x98, 0x36, 0x3a, 0x4f, 0xaa, 0x6f, 0x69, 0xad, 0xc1, 0xa1, 0x0e, 0x4c, 0x7b, 0x80, 0xf9, 0xb0, 0xfa, 0x10, 0x52, 0xd8, 0x4e, 0xdb, 0x1b, 0x9c, 0xb4, 0x12, 0xbd, 0x6c, 0x3e}}, - {{0xc8, 0x7b, 0xe1, 0x47, 0xea, 0x0c, 0x6a, 0x8f, 0x26, 0xaf, 0x91, 0x07, 0xeb, 0x1f, 0x64, 0x28, 0x89, 0x2b, 0x2a, 0xc7, 0x79, 0xc1, 0xa3, 0x60, 0xf3, 0xcb, 0xe0, 0x7c, 0x30, 0x44, 0xee, 0x10}, {0x63, 0xa4, 0xc0, 0xf4, 0x97, 0xdb, 0xaa, 0x66, 0x6d, 0x57, 0xd5, 0x78, 0xdb, 0xd7, 0x02, 0xe3, 0x2f, 0x1e, 0xcb, 0x87, 0x94, 0x91, 0x2d, 0x48, 0x81, 0x18, 0xad, 0x36, 0x4a, 0x4a, 0x9a, 0x0e}}, - {{0x70, 0x64, 0x98, 0xf8, 0x29, 0x5c, 0x34, 0x4c, 0x80, 0x60, 0xf7, 0xe1, 0xe0, 0x47, 0xf4, 0xdf, 0x70, 0x19, 0x2c, 0x06, 0xba, 0xc0, 0xdb, 0xf9, 0x77, 0xe2, 0x7c, 0xac, 0x93, 0x61, 0xcd, 0x06}, {0x97, 0x35, 0x7d, 0x34, 0x61, 0xa7, 0x04, 0x61, 0x04, 0xe1, 0xa1, 0x48, 0xa1, 0xfa, 0x80, 0x82, 0x47, 0x37, 0x37, 0x2f, 0x0a, 0x5d, 0x11, 0xa0, 0x3b, 0xb7, 0x9e, 0x82, 0xb8, 0x50, 0x73, 0x0c}}, - {{0xf0, 0x03, 0x18, 0x1d, 0xa0, 0x41, 0x98, 0x7a, 0x30, 0xd0, 0x9d, 0xea, 0x39, 0xa6, 0xcd, 0x9d, 0x14, 0xd4, 0xfc, 0xf2, 0x1f, 0x8c, 0x1c, 0xd9, 0x7f, 0x4d, 0xfc, 0x75, 0x59, 0x7e, 0xb1, 0x22}, {0x21, 0xdd, 0x74, 0x54, 0x61, 0xf4, 0xea, 0xca, 0x0e, 0x15, 0x35, 0x4e, 0xe9, 0x49, 0x3b, 0x97, 0x49, 0xbc, 0xcb, 0x03, 0xe4, 0x3e, 0x20, 0x1a, 0x2c, 0x2c, 0x3d, 0x94, 0xe4, 0x40, 0x12, 0x20}}, - {{0x51, 0x53, 0x56, 0x14, 0xd9, 0x33, 0xf1, 0x75, 0x54, 0x28, 0x87, 0x00, 0x4f, 0x21, 0x96, 0x18, 0x9d, 0xea, 0xfe, 0x26, 0xe7, 0x7c, 0xd4, 0x0c, 0x6e, 0x28, 0x05, 0x70, 0xf8, 0x26, 0x63, 0x26}, {0x5f, 0xf3, 0x71, 0x42, 0x26, 0x38, 0x37, 0x17, 0x1f, 0x7c, 0x0a, 0x6e, 0x40, 0xf9, 0xd8, 0xc7, 0x5c, 0x9d, 0x7f, 0x76, 0x83, 0xd2, 0x24, 0x59, 0x7d, 0x57, 0x27, 0x31, 0x0e, 0x0f, 0xb5, 0x0e}}, - {{0x4c, 0xc1, 0x39, 0xbd, 0x5e, 0x0f, 0xe2, 0x68, 0xcb, 0x77, 0x9f, 0xa9, 0x56, 0x69, 0x7b, 0x47, 0xce, 0x99, 0x70, 0xa1, 0x85, 0x98, 0x3a, 0x31, 0x73, 0xdf, 0xa2, 0x04, 0x1d, 0x5d, 0x86, 0x1a}, {0xbb, 0x65, 0x52, 0xc1, 0xc4, 0x0f, 0x23, 0x06, 0x76, 0xe3, 0x81, 0x27, 0xd4, 0x72, 0xdd, 0x52, 0x35, 0x66, 0x4e, 0x86, 0xf5, 0x49, 0x18, 0xa4, 0x0d, 0x27, 0x03, 0xeb, 0x9d, 0xc2, 0xfa, 0x10}}, - {{0x15, 0xfb, 0x64, 0x4a, 0x95, 0x38, 0x7d, 0xa5, 0xe2, 0xca, 0x21, 0x74, 0x4e, 0xc6, 0x09, 0xca, 0x7f, 0xfe, 0x60, 0xec, 0x2b, 0x5c, 0x17, 0xf0, 0x7e, 0xac, 0x5a, 0xb0, 0xa1, 0x07, 0x95, 0x01}, {0xac, 0x77, 0xab, 0x63, 0x27, 0xdd, 0x75, 0x60, 0x07, 0x8a, 0xb7, 0x7b, 0x90, 0x60, 0xa0, 0x1a, 0x5f, 0x63, 0x68, 0x8c, 0xdb, 0xbd, 0x6a, 0xef, 0x82, 0xf8, 0x7a, 0x1b, 0xe0, 0xb5, 0x09, 0x1b}}, - {{0xc3, 0x37, 0xe0, 0x1a, 0xec, 0x72, 0x49, 0x78, 0xbd, 0xd8, 0x26, 0x47, 0xbe, 0x69, 0x42, 0x5a, 0xc7, 0x6d, 0x65, 0xe1, 0xa2, 0x19, 0xa7, 0x56, 0x83, 0xd3, 0xda, 0x50, 0x78, 0x9c, 0x18, 0x14}, {0x95, 0xeb, 0x53, 0xca, 0x2b, 0xcd, 0x5b, 0x81, 0xf6, 0xdb, 0x51, 0x77, 0xb4, 0x78, 0x6c, 0x55, 0xc1, 0x08, 0x20, 0x1a, 0x13, 0xfd, 0x53, 0xf0, 0xd2, 0x68, 0xab, 0xfe, 0x8c, 0xc7, 0x81, 0x28}}, - {{0x9e, 0x7a, 0xe0, 0x4a, 0x13, 0x19, 0x06, 0xf3, 0x10, 0x4a, 0x6b, 0xbd, 0x26, 0x6f, 0x06, 0xd3, 0xfc, 0x51, 0x9a, 0xc2, 0xea, 0xd8, 0x30, 0xd2, 0xf0, 0xc0, 0xea, 0xd1, 0xf8, 0xd0, 0x6c, 0x0e}, {0xb8, 0x9b, 0xec, 0xac, 0xbe, 0x27, 0xa4, 0x9f, 0x7f, 0x69, 0xaa, 0x80, 0x50, 0xc2, 0x2b, 0x2a, 0x95, 0xbd, 0x4d, 0xdb, 0x2f, 0x9c, 0xf7, 0xdb, 0xf5, 0x43, 0x22, 0x86, 0x6a, 0xbb, 0x28, 0x00}}, - {{0x99, 0x18, 0x96, 0xcc, 0x49, 0x84, 0x13, 0xf0, 0x6a, 0x87, 0xbf, 0x9e, 0x9d, 0xac, 0x9d, 0x37, 0x3d, 0xe9, 0xcd, 0x31, 0xd0, 0x99, 0x7f, 0xeb, 0xfd, 0x08, 0xbe, 0x19, 0x85, 0x5b, 0x0b, 0x13}, {0xeb, 0xba, 0x2c, 0x42, 0x43, 0x7e, 0xed, 0xa4, 0xf1, 0x99, 0xd0, 0xcf, 0x65, 0xa5, 0xbd, 0x15, 0x08, 0x82, 0x12, 0xef, 0xae, 0x3f, 0xe7, 0x75, 0xbc, 0x1f, 0xf1, 0x3c, 0x27, 0xb0, 0x96, 0x11}}, - {{0xe5, 0xba, 0x30, 0x55, 0x9e, 0xf9, 0x11, 0xc3, 0xc0, 0x67, 0x98, 0x2f, 0x91, 0x21, 0x96, 0x5e, 0x1f, 0x79, 0x32, 0x08, 0x79, 0x61, 0xc4, 0x0e, 0xbc, 0xca, 0x1f, 0x79, 0x62, 0x8c, 0xb8, 0x3a}, {0xf3, 0x46, 0xa3, 0xd1, 0xb2, 0xdb, 0x0c, 0xe3, 0x73, 0xd5, 0x57, 0x21, 0x1b, 0x88, 0x0d, 0x30, 0x32, 0xb0, 0x62, 0xaf, 0x2b, 0x29, 0x62, 0xe3, 0xa1, 0xa3, 0xf4, 0x26, 0xea, 0x23, 0xc4, 0x02}}, - {{0x15, 0x5b, 0x4a, 0xf1, 0x82, 0xfb, 0x44, 0x72, 0xa0, 0xc5, 0x80, 0xc8, 0xf8, 0xdb, 0x16, 0x17, 0x30, 0xd1, 0x04, 0xfa, 0x0d, 0xbb, 0x4b, 0x13, 0x1f, 0x97, 0x16, 0xac, 0x43, 0x09, 0x80, 0x2c}, {0x31, 0x5c, 0x9a, 0x08, 0xca, 0xd2, 0x8a, 0x97, 0x49, 0x3f, 0x63, 0x01, 0xbd, 0x1b, 0xe6, 0xe1, 0xd0, 0xcb, 0x42, 0xb6, 0xf3, 0xaa, 0x30, 0x33, 0x2c, 0x3d, 0x6b, 0xba, 0xd2, 0xc6, 0xa1, 0x09}}, - {{0xbe, 0xd5, 0x33, 0xbc, 0xf3, 0x4f, 0xa5, 0x28, 0x5c, 0x39, 0x48, 0xcf, 0x2e, 0xb1, 0xf6, 0x3b, 0x43, 0x90, 0x7c, 0x55, 0x1b, 0xc7, 0x2d, 0x22, 0x5b, 0xa8, 0x74, 0x1f, 0x65, 0x8b, 0x40, 0x24}, {0xc0, 0x52, 0xaf, 0x04, 0x95, 0x08, 0x66, 0x90, 0xd1, 0x15, 0xc0, 0x66, 0xf7, 0xe8, 0xe4, 0x35, 0x84, 0x24, 0x9f, 0x65, 0x29, 0x92, 0x86, 0xa3, 0xc7, 0x6b, 0xdf, 0x11, 0x98, 0x31, 0x7d, 0x20}}, - {{0x54, 0xc0, 0x7c, 0xd9, 0x2b, 0x72, 0xd9, 0x15, 0xf9, 0x45, 0x39, 0x62, 0x40, 0x04, 0xa4, 0xc0, 0x9c, 0x98, 0xfd, 0x73, 0xe5, 0x37, 0x6b, 0xb4, 0x66, 0x91, 0x3a, 0xac, 0xe7, 0x6c, 0x58, 0x2b}, {0xef, 0xdb, 0x31, 0x3f, 0x9d, 0x2d, 0xd6, 0xb9, 0xa5, 0xa7, 0xe6, 0xb7, 0x16, 0xcd, 0x75, 0x72, 0x4d, 0x7a, 0xd5, 0x6d, 0x44, 0xc0, 0x85, 0x8d, 0x05, 0x05, 0x53, 0xda, 0xfc, 0xa9, 0x86, 0x0d}}, - {{0x27, 0xe7, 0x16, 0x20, 0xbc, 0xc1, 0xc3, 0x6c, 0x4b, 0x16, 0x0a, 0x18, 0xd8, 0x0d, 0x7b, 0x61, 0x1e, 0x97, 0x61, 0x9f, 0xde, 0x39, 0xd6, 0x4f, 0xf0, 0x27, 0xba, 0x19, 0xd8, 0x6f, 0x4a, 0x3d}, {0xd4, 0x8b, 0x57, 0xaa, 0x0e, 0xe8, 0x13, 0x34, 0x9f, 0x76, 0xbb, 0x63, 0x5e, 0x48, 0x16, 0x7b, 0xa2, 0x4a, 0x4c, 0x8c, 0x21, 0x59, 0xbb, 0x62, 0x6f, 0x58, 0xaf, 0xf8, 0x57, 0x98, 0x98, 0x10}}, - {{0x3d, 0xe5, 0x3a, 0x2e, 0xd2, 0xb7, 0x33, 0x4d, 0xa1, 0x5a, 0x24, 0xb7, 0x7e, 0xaf, 0x88, 0xe8, 0x96, 0xb8, 0x76, 0x0b, 0xf3, 0xf0, 0xe6, 0x78, 0x61, 0x8e, 0x50, 0xf8, 0xca, 0xf0, 0xf9, 0x15}, {0x6a, 0xcb, 0x33, 0xe2, 0x0d, 0x4f, 0xce, 0xbe, 0x89, 0x9b, 0xc3, 0xd0, 0xdf, 0xa9, 0x3f, 0xeb, 0xc6, 0xca, 0xcb, 0x43, 0x58, 0xff, 0x51, 0xb3, 0x30, 0x3f, 0x20, 0xe9, 0x1b, 0xa6, 0x2a, 0x37}}, - {{0x26, 0xf2, 0xd5, 0xa5, 0x0c, 0x4a, 0xf7, 0x74, 0xb6, 0x7c, 0x03, 0xe7, 0x52, 0xb8, 0x51, 0x37, 0x91, 0x18, 0x9a, 0x75, 0xfa, 0xc8, 0xd1, 0x9a, 0x42, 0x84, 0x34, 0x24, 0xb7, 0xb6, 0xfd, 0x10}, {0x75, 0xe4, 0x16, 0x67, 0x2c, 0xaa, 0xd7, 0xfc, 0x92, 0xc3, 0xde, 0xce, 0x46, 0x22, 0x9c, 0x4f, 0xe3, 0x97, 0xb9, 0x01, 0x36, 0xa4, 0xaa, 0x06, 0x10, 0xc0, 0x7e, 0xd5, 0x4b, 0x80, 0x26, 0x0a}}, - {{0x36, 0x48, 0x64, 0xf1, 0x81, 0xf7, 0x9f, 0x53, 0xc6, 0xa0, 0x99, 0x3d, 0x87, 0xdc, 0xdc, 0xd1, 0x89, 0x0b, 0xf1, 0x8e, 0x96, 0x73, 0xe4, 0x2d, 0x4c, 0x33, 0xba, 0x82, 0xa9, 0x67, 0xf1, 0x0f}, {0x47, 0x8e, 0x88, 0x51, 0x91, 0xab, 0x0d, 0xb5, 0xcb, 0x88, 0xdf, 0x97, 0xfa, 0x55, 0xe0, 0xc1, 0x5d, 0x75, 0xdd, 0xe0, 0xa1, 0xe3, 0x47, 0x35, 0x0a, 0xed, 0xfb, 0x9a, 0x5e, 0x73, 0x28, 0x2d}}, - {{0x96, 0xd6, 0x89, 0xc0, 0x09, 0x8a, 0x78, 0xa2, 0x1e, 0x71, 0x00, 0x06, 0xd9, 0xcb, 0x29, 0xf5, 0x3e, 0x52, 0xf8, 0x1e, 0x7a, 0xbb, 0x66, 0xcb, 0xac, 0x2b, 0xeb, 0x34, 0xaa, 0x17, 0xb9, 0x29}, {0x96, 0xbf, 0xa4, 0x85, 0x39, 0xa6, 0x7f, 0xed, 0x64, 0x86, 0xa4, 0xce, 0xa4, 0xb5, 0x46, 0xbc, 0xde, 0x3f, 0x52, 0x16, 0x91, 0x86, 0x0b, 0x2c, 0x17, 0x74, 0xdc, 0x7d, 0xc2, 0x43, 0x30, 0x3d}}, - {{0xfc, 0xc6, 0x45, 0x65, 0x12, 0xe7, 0x6e, 0x3c, 0xb5, 0x72, 0x64, 0x9a, 0xa3, 0x60, 0x1e, 0x36, 0x72, 0x37, 0x5a, 0x6f, 0xc5, 0x2b, 0xfa, 0xa4, 0x4a, 0x84, 0x5d, 0xab, 0x68, 0x09, 0x6b, 0x20}, {0x08, 0xad, 0x43, 0xba, 0x87, 0x6e, 0xc3, 0x7c, 0xdc, 0xb1, 0xa6, 0xec, 0xeb, 0x23, 0x15, 0xf9, 0x5a, 0x94, 0x1f, 0x38, 0xda, 0xd1, 0xa9, 0x2f, 0x43, 0xaa, 0x6c, 0x8a, 0xc6, 0x57, 0xff, 0x25}}, - {{0xe0, 0x2b, 0xc2, 0xc1, 0xa3, 0x42, 0x26, 0x77, 0xae, 0xda, 0xb7, 0x7a, 0x08, 0x84, 0x61, 0x50, 0xe4, 0xc3, 0xe3, 0x89, 0x82, 0xd9, 0xee, 0x67, 0x79, 0x73, 0xe1, 0x12, 0x32, 0x78, 0x40, 0x1c}, {0x01, 0xce, 0xb9, 0xfc, 0xcb, 0xbe, 0x43, 0xaa, 0x52, 0x4a, 0xb9, 0xea, 0xfd, 0x4a, 0x38, 0xe5, 0xff, 0x33, 0x24, 0x8d, 0x32, 0x4b, 0x9c, 0x3e, 0xa2, 0x24, 0xe5, 0xa2, 0xff, 0x5a, 0x57, 0x00}}, - {{0x4f, 0x85, 0xe1, 0x54, 0x17, 0xce, 0x0e, 0xea, 0xc4, 0x86, 0xc0, 0x9f, 0x94, 0x60, 0x59, 0x44, 0x66, 0xe7, 0x3d, 0xc2, 0x59, 0x67, 0x5e, 0x83, 0x4d, 0x48, 0xec, 0xee, 0x41, 0xab, 0xe3, 0x0b}, {0xe1, 0x6b, 0x01, 0x62, 0x09, 0xa6, 0xf9, 0x48, 0x49, 0xd5, 0xb7, 0xef, 0x63, 0x38, 0x09, 0x19, 0xce, 0x39, 0xcf, 0xac, 0xf2, 0x8f, 0x59, 0x2b, 0xe9, 0xb1, 0xa1, 0xe5, 0x7e, 0x84, 0x9d, 0x38}}, - {{0x37, 0x65, 0x6b, 0x69, 0x37, 0xc0, 0x6a, 0x93, 0xa8, 0x28, 0x13, 0xa3, 0xb4, 0xe5, 0x60, 0x35, 0x90, 0x28, 0xcb, 0xcf, 0xa4, 0xfe, 0x47, 0x1f, 0x28, 0x3c, 0x57, 0x49, 0x4d, 0xbc, 0x6b, 0x0c}, {0x46, 0x87, 0xa6, 0xfb, 0x2f, 0x7e, 0xc6, 0x2a, 0x38, 0xe5, 0xb1, 0x95, 0xee, 0xd8, 0xe1, 0x80, 0x19, 0xa3, 0x93, 0x47, 0xf0, 0x37, 0xf9, 0x0f, 0x18, 0x27, 0x71, 0xa6, 0x8b, 0xa3, 0x94, 0x10}}, - {{0xe3, 0xfa, 0xb8, 0xb2, 0x2c, 0xdf, 0xc7, 0x8e, 0x89, 0xef, 0x2c, 0x65, 0xe1, 0xcb, 0x40, 0xeb, 0x85, 0x18, 0xdf, 0xaa, 0x53, 0xa3, 0x2d, 0xa0, 0x85, 0xe4, 0xcb, 0x84, 0x5e, 0x88, 0x64, 0x2c}, {0x77, 0xe2, 0x26, 0xd9, 0xa7, 0x06, 0xf9, 0xcc, 0x3e, 0x5c, 0xf5, 0x57, 0x08, 0x8f, 0x7e, 0x5d, 0xf2, 0xd5, 0x72, 0x17, 0x47, 0x1b, 0x71, 0xdf, 0x33, 0xb3, 0x85, 0xf1, 0x0c, 0x26, 0xa8, 0x0c}}, - {{0x07, 0x23, 0x99, 0xd9, 0x1d, 0x50, 0xba, 0xef, 0xda, 0x86, 0x0a, 0xbc, 0xbf, 0xe2, 0xce, 0xcb, 0x58, 0x0e, 0xca, 0x8c, 0x66, 0xc3, 0xa9, 0x7b, 0x28, 0xfc, 0x33, 0x67, 0xda, 0x7b, 0xe0, 0x10}, {0xc3, 0xeb, 0x7d, 0xdf, 0x6f, 0xe6, 0x72, 0x0a, 0xb9, 0x75, 0xa2, 0x2a, 0xd6, 0x67, 0x6a, 0xf1, 0x6f, 0x2a, 0x84, 0xaa, 0x00, 0x5e, 0xd2, 0x03, 0x70, 0xce, 0xdb, 0xdf, 0xbc, 0x55, 0xc7, 0x26}}, - {{0xff, 0x2d, 0xef, 0x9a, 0x64, 0x76, 0x53, 0x18, 0x17, 0x97, 0xa4, 0x10, 0x4f, 0x4c, 0x94, 0x7f, 0x99, 0xac, 0xf5, 0xb9, 0xff, 0x80, 0x35, 0xe2, 0x52, 0x4a, 0x7f, 0x5f, 0xb6, 0x7f, 0x38, 0x1d}, {0x9e, 0xc1, 0x1f, 0xb4, 0x06, 0x69, 0x9f, 0xb5, 0x6b, 0xd2, 0x4b, 0xba, 0x26, 0xf2, 0xe3, 0x6a, 0x0c, 0xcb, 0xe3, 0xd3, 0xca, 0x2a, 0x71, 0x51, 0x25, 0x0e, 0x50, 0x92, 0xab, 0xb3, 0x19, 0x30}}, - {{0xec, 0x97, 0x13, 0x8d, 0x8c, 0xdb, 0x05, 0x74, 0xb2, 0xb4, 0xb8, 0x44, 0x63, 0x5c, 0x1f, 0x3a, 0xcb, 0xea, 0x99, 0xdf, 0x5b, 0x17, 0x16, 0x3b, 0x66, 0x49, 0x61, 0x5a, 0x36, 0x39, 0x5c, 0x0e}, {0xee, 0x26, 0x3b, 0x2a, 0x4f, 0x82, 0x2a, 0x3c, 0xc9, 0x4d, 0x77, 0x2e, 0x14, 0xc8, 0xb5, 0x0c, 0xf6, 0x90, 0x5f, 0xe4, 0xf6, 0x7d, 0x48, 0xe6, 0x79, 0xe4, 0x0a, 0xe2, 0xc5, 0x71, 0x37, 0x3a}}, - {{0xa9, 0x08, 0x29, 0x96, 0xa8, 0x40, 0x51, 0x0f, 0xc5, 0xc6, 0x37, 0x46, 0x99, 0xd0, 0x28, 0xab, 0x7d, 0x59, 0xbb, 0xdf, 0x2d, 0x0c, 0x40, 0x8d, 0x23, 0x98, 0xf2, 0xb4, 0x63, 0xfe, 0x9a, 0x35}, {0xcc, 0x75, 0x42, 0xdb, 0x14, 0xf0, 0xc4, 0x1f, 0x3c, 0x50, 0x04, 0x54, 0xd6, 0x5f, 0x6d, 0x13, 0x3a, 0x52, 0x86, 0xce, 0x43, 0x9c, 0x44, 0x08, 0x8f, 0x09, 0x4e, 0x03, 0x6e, 0x00, 0x77, 0x06}}, - {{0x93, 0x0a, 0xfc, 0xec, 0xb7, 0x4b, 0xb5, 0x7c, 0xaf, 0xa1, 0xba, 0x53, 0x54, 0x3b, 0xfc, 0x64, 0xd5, 0x86, 0x6a, 0x2e, 0x19, 0xe6, 0x53, 0xc4, 0x17, 0x99, 0x98, 0xac, 0x5c, 0x03, 0x38, 0x28}, {0x40, 0x86, 0xf8, 0xdf, 0x39, 0x58, 0x6e, 0x0f, 0xdf, 0x73, 0xbc, 0x7e, 0x82, 0x41, 0x90, 0x12, 0x8a, 0x7e, 0x1f, 0x4a, 0x6f, 0x3b, 0x35, 0x47, 0x4c, 0x7f, 0x93, 0xca, 0xad, 0xa1, 0xaa, 0x31}}, - {{0x4d, 0x53, 0x2b, 0x6d, 0xc3, 0x37, 0x43, 0x9f, 0xc3, 0x0b, 0xe7, 0xed, 0x39, 0xbb, 0xc4, 0x3b, 0x55, 0x8a, 0x4b, 0x10, 0xae, 0x79, 0x38, 0x2f, 0xc8, 0x4f, 0x7a, 0xd9, 0x71, 0xc1, 0xb0, 0x13}, {0x21, 0x54, 0x0c, 0x37, 0xfa, 0xd1, 0x46, 0x0d, 0x53, 0xb7, 0xbe, 0x65, 0x28, 0x7f, 0x97, 0x83, 0xd8, 0xdf, 0x9e, 0xe4, 0x7d, 0x7e, 0xf4, 0x63, 0x9f, 0xa1, 0xf3, 0x17, 0xbf, 0x46, 0x8c, 0x11}}, - {{0xbf, 0x48, 0x69, 0x89, 0xce, 0xa0, 0xeb, 0xb4, 0xf3, 0x0c, 0x6d, 0x65, 0xd9, 0x98, 0x2a, 0xad, 0x8a, 0x66, 0x5c, 0x4d, 0x1d, 0x74, 0x51, 0xc6, 0x6f, 0x4d, 0x42, 0xe9, 0x84, 0xbf, 0x9e, 0x03}, {0xa2, 0x81, 0x6c, 0x47, 0x78, 0xc8, 0x95, 0xe0, 0x0e, 0x68, 0x9d, 0x67, 0x68, 0xbc, 0xc7, 0xed, 0xf1, 0x2a, 0xed, 0x4e, 0x2b, 0x85, 0x63, 0xf7, 0x1b, 0x6e, 0x8e, 0xe9, 0xb1, 0x98, 0xe9, 0x15}}, - {{0x21, 0x8d, 0x28, 0x2b, 0x18, 0x9a, 0x66, 0x85, 0x13, 0xda, 0x1f, 0x0a, 0x7f, 0x35, 0x44, 0x93, 0xed, 0xb8, 0x79, 0xa1, 0x44, 0xd7, 0x72, 0x37, 0x5a, 0xb5, 0xc0, 0x4e, 0x34, 0x85, 0x03, 0x1b}, {0x21, 0x04, 0xb6, 0x39, 0xac, 0x8d, 0x61, 0x46, 0xb6, 0x01, 0x3c, 0xb1, 0x88, 0x5d, 0xf5, 0x4e, 0x34, 0x97, 0xc6, 0x50, 0x47, 0x7c, 0x15, 0x53, 0x95, 0x03, 0x74, 0x21, 0x07, 0x6e, 0x3a, 0x2a}}, - {{0x91, 0x3b, 0x99, 0x43, 0x75, 0xb7, 0x17, 0x1e, 0x3d, 0x6f, 0x03, 0xc4, 0xac, 0xec, 0x37, 0x28, 0xb4, 0x8f, 0x4d, 0x66, 0x0a, 0x0a, 0xb4, 0x56, 0x54, 0xd5, 0xe4, 0xe7, 0x71, 0x0f, 0x04, 0x2f}, {0x69, 0xc2, 0x8f, 0xb9, 0xde, 0x51, 0xf0, 0xcb, 0x96, 0x94, 0x88, 0x75, 0x04, 0xa7, 0x6a, 0x5c, 0xfe, 0xbc, 0x9f, 0x29, 0xf8, 0xc5, 0xfa, 0x42, 0x5b, 0x64, 0x49, 0x78, 0xcd, 0xec, 0x47, 0x12}}, - {{0x40, 0x71, 0x5f, 0x4d, 0xad, 0x3a, 0x3e, 0x16, 0xa5, 0x67, 0x10, 0x74, 0x58, 0x81, 0x92, 0xb6, 0xa2, 0x8b, 0x9f, 0x50, 0x68, 0x68, 0xb5, 0x26, 0xff, 0xa4, 0x3f, 0x6a, 0x3d, 0x5c, 0xb1, 0x05}, {0xc7, 0x1d, 0xd0, 0xa8, 0xa8, 0x64, 0xab, 0x7c, 0x07, 0x36, 0x68, 0x2d, 0x69, 0xf2, 0x3b, 0x5b, 0x34, 0x39, 0x87, 0x67, 0x48, 0x84, 0x15, 0x2a, 0xa1, 0x39, 0x04, 0x1c, 0x62, 0x0f, 0x9a, 0x25}}, - {{0xf5, 0x6d, 0xfb, 0xbd, 0xcf, 0xea, 0xda, 0x5b, 0x3d, 0xa4, 0xb9, 0x32, 0xd7, 0x56, 0x6e, 0xff, 0xc9, 0xaf, 0xf9, 0xef, 0x7b, 0x5d, 0x57, 0x45, 0x60, 0xbb, 0x70, 0xb3, 0x25, 0x3e, 0x5f, 0x11}, {0xaa, 0x8d, 0xc8, 0xda, 0xbd, 0xdf, 0x75, 0xfa, 0xb3, 0xfd, 0x39, 0x6e, 0xf7, 0x93, 0x30, 0x2f, 0xff, 0x95, 0xc5, 0x7d, 0x27, 0xe2, 0xc1, 0xc8, 0x9d, 0x67, 0x8c, 0x14, 0xc5, 0x7e, 0xa1, 0x3e}}, - {{0xd1, 0x6a, 0x93, 0x99, 0x8c, 0x5f, 0x47, 0x24, 0xc0, 0x87, 0x78, 0x1f, 0x62, 0x63, 0xee, 0x51, 0x28, 0xf6, 0x29, 0xab, 0xd0, 0xd1, 0x5e, 0x47, 0xb7, 0xa0, 0x30, 0x24, 0xaa, 0xff, 0x03, 0x03}, {0x9d, 0x18, 0xa5, 0xd5, 0x52, 0xa9, 0xd2, 0x1d, 0x71, 0x42, 0x41, 0x50, 0xbf, 0xa0, 0xcc, 0x22, 0x27, 0xc6, 0x2c, 0x62, 0x58, 0x34, 0xb2, 0x49, 0x89, 0x7f, 0xf8, 0x40, 0x36, 0xc2, 0x30, 0x01}}, - {{0x28, 0x1c, 0xd7, 0xca, 0x5a, 0x9c, 0xf1, 0xaa, 0x58, 0x78, 0x7a, 0x8b, 0x18, 0x29, 0xb1, 0x8b, 0x6a, 0xd6, 0xdc, 0x92, 0x2d, 0xce, 0xe7, 0x23, 0x23, 0x2f, 0x3a, 0x8e, 0x51, 0x37, 0x42, 0x19}, {0xd9, 0xd4, 0x3e, 0x4b, 0x66, 0xeb, 0x2c, 0xa3, 0x73, 0x67, 0xb0, 0xf2, 0x3e, 0x68, 0x2b, 0xeb, 0x07, 0x3a, 0x6e, 0x39, 0x19, 0x55, 0xf3, 0xa6, 0x4c, 0xc3, 0x1e, 0xb6, 0x4d, 0xb9, 0x2b, 0x1d}}, - {{0xd9, 0x0e, 0x0b, 0xed, 0x83, 0xde, 0x21, 0x4d, 0x3b, 0x5e, 0xf2, 0xa5, 0xab, 0xda, 0xdf, 0xbd, 0xd5, 0x59, 0x5e, 0x49, 0x86, 0xa4, 0xbc, 0x0b, 0xad, 0xe3, 0xa6, 0x9d, 0x68, 0x47, 0x85, 0x16}, {0x25, 0x6e, 0x59, 0xe0, 0xfb, 0x6a, 0x04, 0x87, 0x88, 0x59, 0x4a, 0x6f, 0x21, 0xef, 0x4f, 0xbf, 0x97, 0x70, 0x21, 0x5d, 0xd0, 0xe9, 0x6a, 0x33, 0xe5, 0x02, 0x8e, 0x75, 0xb0, 0x13, 0x21, 0x0a}}, - {{0xc2, 0x4e, 0xf6, 0x90, 0x19, 0x4f, 0x2a, 0x1b, 0x69, 0x05, 0x02, 0x5d, 0x9f, 0x84, 0xab, 0x56, 0xed, 0xa9, 0xbf, 0xf7, 0xaa, 0x07, 0x14, 0x28, 0x41, 0x8b, 0x06, 0x21, 0x1a, 0xc9, 0x01, 0x06}, {0x3d, 0xbc, 0x8e, 0x80, 0xdd, 0xa0, 0x15, 0xcb, 0x56, 0xd5, 0x64, 0xc0, 0x85, 0xf3, 0xde, 0x07, 0xd8, 0x64, 0x93, 0x1e, 0x28, 0x5a, 0x6e, 0x2d, 0x54, 0xa1, 0x9e, 0xcb, 0x0a, 0xdc, 0x39, 0x10}}, - {{0x82, 0xec, 0x8f, 0x2f, 0x05, 0xe9, 0x0a, 0xed, 0xb2, 0x54, 0x30, 0xe5, 0x2c, 0xbd, 0x13, 0xc1, 0x9b, 0x77, 0x03, 0xf3, 0xfc, 0xa4, 0x7a, 0x0c, 0x08, 0xa7, 0x8c, 0xcd, 0x29, 0x28, 0x74, 0x08}, {0xf0, 0xc3, 0x99, 0x78, 0x87, 0x2f, 0x82, 0x68, 0xb3, 0x67, 0x9e, 0x5b, 0xab, 0xa6, 0x96, 0x18, 0x30, 0x63, 0x6c, 0x35, 0x99, 0x52, 0x49, 0xcd, 0x13, 0xb6, 0xdc, 0x3a, 0x29, 0xee, 0xa6, 0x28}}, - {{0xb1, 0x5c, 0x83, 0x35, 0x5b, 0x4d, 0x5e, 0x4b, 0xe4, 0x48, 0xa9, 0xaa, 0x85, 0x2a, 0x02, 0x7c, 0x20, 0xd3, 0x4b, 0x8d, 0x9b, 0x4a, 0x1f, 0x8e, 0xc6, 0x3f, 0xa9, 0xa7, 0xdb, 0x94, 0x17, 0x3a}, {0xd3, 0x59, 0xfe, 0xe0, 0xe9, 0x72, 0x55, 0xdd, 0xcb, 0x5a, 0x4a, 0x52, 0xc9, 0xd3, 0x10, 0x7b, 0x7c, 0x64, 0x63, 0x7b, 0x82, 0x2d, 0xfd, 0xfd, 0xac, 0x01, 0xe5, 0xef, 0xb5, 0x11, 0x9a, 0x0f}}, - {{0xda, 0xdf, 0x8a, 0xf8, 0x66, 0xdb, 0x46, 0x8a, 0x61, 0x91, 0x14, 0xd9, 0x30, 0xf1, 0x1a, 0x23, 0x4d, 0x04, 0x37, 0xa0, 0xb8, 0xb0, 0xfc, 0x9a, 0x76, 0x06, 0xd6, 0x43, 0x78, 0xba, 0x80, 0x2f}, {0xac, 0xf9, 0xb0, 0xb3, 0x86, 0x44, 0x8b, 0x7b, 0x2a, 0x23, 0xff, 0x03, 0x52, 0x01, 0xb8, 0xe9, 0x27, 0x2e, 0x6b, 0xbf, 0x3f, 0xb6, 0x52, 0x31, 0xcd, 0x25, 0x9a, 0x3b, 0xdd, 0x0a, 0x41, 0x2c}}, - {{0xe5, 0x95, 0x76, 0xbe, 0xf0, 0xdb, 0x6c, 0x34, 0x6a, 0xd7, 0x16, 0xed, 0x6a, 0xf6, 0xe3, 0x67, 0xa3, 0x60, 0x63, 0x87, 0xa2, 0xf1, 0x61, 0x04, 0xd5, 0xa1, 0x91, 0x9f, 0xce, 0x29, 0x18, 0x0a}, {0x92, 0x83, 0xc8, 0x6f, 0x2b, 0x9a, 0x7b, 0xf1, 0x52, 0xfd, 0x5d, 0xbc, 0xa2, 0xa7, 0x4e, 0x2c, 0xac, 0xa2, 0x65, 0x53, 0x2f, 0x09, 0x12, 0xf5, 0x96, 0x56, 0xce, 0xef, 0x6d, 0x2e, 0x5f, 0x2c}}, - {{0xd0, 0x9b, 0x0d, 0x46, 0xf8, 0xe1, 0xc1, 0xa5, 0x42, 0x22, 0xb6, 0xfb, 0xe1, 0xce, 0x39, 0xb1, 0x38, 0x25, 0x85, 0x27, 0xa0, 0x14, 0xe6, 0xf5, 0x91, 0xdf, 0x71, 0x09, 0x23, 0xce, 0x3b, 0x13}, {0x52, 0xda, 0xf7, 0x00, 0x97, 0xcd, 0x9c, 0x18, 0xce, 0x65, 0x47, 0xcb, 0xf0, 0x79, 0xbf, 0x0e, 0x11, 0x1d, 0x7d, 0x1e, 0xef, 0x44, 0x9c, 0x74, 0x04, 0xc2, 0xe7, 0xbb, 0x99, 0xad, 0x2f, 0x31}}, - {{0xe2, 0x6b, 0x7a, 0x91, 0xbc, 0x8b, 0x52, 0xe7, 0x52, 0xcf, 0x04, 0x25, 0x1e, 0xab, 0xc2, 0x0b, 0x31, 0x40, 0xca, 0x09, 0x26, 0x17, 0x48, 0x3a, 0x9a, 0x52, 0x7c, 0x0a, 0xe1, 0x37, 0xe5, 0x2c}, {0x79, 0x2d, 0xc4, 0xf4, 0xef, 0x9a, 0xf7, 0x64, 0x64, 0xed, 0x92, 0x85, 0x65, 0xdb, 0xd8, 0x9f, 0xaf, 0x9f, 0x86, 0x88, 0xda, 0x04, 0x42, 0xf8, 0x0c, 0x86, 0x1b, 0x3a, 0x5c, 0x98, 0x7a, 0x37}}, - {{0xfa, 0x05, 0xd2, 0x25, 0xc6, 0xbf, 0x3e, 0x5d, 0x3f, 0xff, 0xe6, 0x20, 0xb3, 0xda, 0xfa, 0x10, 0xca, 0x30, 0x9a, 0xe2, 0x63, 0xf6, 0x84, 0x17, 0x73, 0x96, 0xc5, 0x3a, 0xbb, 0x96, 0x69, 0x2a}, {0x88, 0x04, 0xd6, 0xe6, 0xc2, 0xa9, 0xb6, 0x3f, 0xbf, 0x79, 0x01, 0xa4, 0x21, 0x92, 0xb5, 0x90, 0xcb, 0xfa, 0x28, 0x75, 0x4b, 0xa9, 0x88, 0xdc, 0x89, 0x9a, 0xbd, 0x7f, 0xd6, 0xee, 0x29, 0x2c}}, - {{0x4c, 0xaf, 0xa6, 0x74, 0x82, 0x2c, 0xa6, 0xfe, 0xfe, 0x73, 0x8c, 0x22, 0xcf, 0x7b, 0x8c, 0x38, 0xd7, 0xdd, 0x55, 0xe9, 0x19, 0xea, 0xc7, 0xc0, 0xca, 0xc1, 0x2b, 0x7b, 0x02, 0x46, 0x46, 0x1e}, {0x01, 0x3c, 0x9c, 0xe3, 0xe1, 0xe0, 0x09, 0xca, 0xfc, 0xaf, 0x7e, 0x47, 0xec, 0x20, 0x1a, 0x70, 0x67, 0x43, 0xe9, 0x79, 0x8e, 0xdb, 0xa5, 0x0f, 0xd1, 0x04, 0x3a, 0xe7, 0x48, 0x3c, 0xfc, 0x3c}}, - {{0x79, 0x41, 0x33, 0xeb, 0xf5, 0xcc, 0x4c, 0xd8, 0xc7, 0xf8, 0xde, 0x15, 0x98, 0x18, 0x23, 0xce, 0x1f, 0x8e, 0xb5, 0x7d, 0xea, 0x8d, 0x6c, 0xe7, 0x8a, 0x9d, 0xb4, 0xf6, 0x9f, 0x47, 0xca, 0x3a}, {0x60, 0x7a, 0x23, 0xf1, 0x6d, 0x24, 0xf1, 0x17, 0xa6, 0x2f, 0x2f, 0x8d, 0x8f, 0x9d, 0x17, 0x2e, 0x4f, 0xf6, 0x3e, 0x42, 0x13, 0xe6, 0xd0, 0x32, 0xae, 0xc1, 0x6e, 0x8b, 0x3d, 0x29, 0x7c, 0x06}}, - {{0x19, 0x8a, 0xa7, 0x17, 0x0a, 0x0c, 0xcd, 0x8e, 0x88, 0xb1, 0x60, 0x7f, 0xa6, 0x7b, 0x36, 0x71, 0x3a, 0xd6, 0xaa, 0xd1, 0x2c, 0xbf, 0x5a, 0xff, 0xb5, 0xed, 0x5e, 0xd1, 0x9b, 0x09, 0x56, 0x36}, {0xbc, 0x9e, 0xe2, 0xd1, 0x63, 0x10, 0xdf, 0xc0, 0xb5, 0x5a, 0xf3, 0x3d, 0xeb, 0x45, 0xec, 0x9a, 0xa1, 0xcb, 0x86, 0x7b, 0x49, 0x3f, 0x71, 0x6e, 0xca, 0x59, 0x23, 0xb5, 0x1d, 0x9f, 0x44, 0x2e}}, - {{0x69, 0x0e, 0xba, 0xaf, 0x0e, 0x44, 0x6e, 0xa5, 0x1a, 0xbe, 0x3e, 0x43, 0xc0, 0x4a, 0xfb, 0x10, 0x6d, 0xee, 0x71, 0x8d, 0x2c, 0x39, 0x5f, 0xd9, 0xdb, 0x75, 0xf4, 0x8a, 0x9e, 0x08, 0xef, 0x34}, {0x29, 0xee, 0xaf, 0x4f, 0x68, 0x89, 0xde, 0x9c, 0x93, 0x46, 0x45, 0x46, 0x2b, 0x7c, 0x90, 0xd3, 0xef, 0x6d, 0xb2, 0x9e, 0x45, 0xc0, 0x58, 0xf8, 0x9e, 0x19, 0x96, 0xfc, 0x36, 0x61, 0x59, 0x2a}}, - {{0x4b, 0x09, 0xa0, 0x68, 0xb8, 0x83, 0x41, 0xd3, 0x4f, 0xb2, 0x24, 0x12, 0x30, 0x63, 0xc5, 0x46, 0x4b, 0x39, 0x0b, 0xdc, 0x11, 0xac, 0x9f, 0x93, 0x85, 0xed, 0x5f, 0xb4, 0xdc, 0x5d, 0x98, 0x11}, {0xac, 0xbd, 0x23, 0x8c, 0x52, 0x52, 0x03, 0x45, 0xa8, 0x31, 0x79, 0x04, 0x78, 0xe2, 0x8c, 0x81, 0x68, 0x0a, 0xbe, 0x33, 0xaf, 0x05, 0x8b, 0x4d, 0x47, 0x29, 0xfe, 0x01, 0x40, 0xb2, 0x54, 0x28}}, - {{0x57, 0x27, 0xba, 0x9d, 0x3b, 0x92, 0xea, 0x21, 0xa4, 0xba, 0x67, 0x72, 0xee, 0x32, 0x2d, 0x10, 0x6d, 0xd9, 0x5b, 0xff, 0x17, 0x8d, 0x7e, 0xe0, 0x44, 0xcb, 0x3b, 0x59, 0x92, 0xfe, 0x39, 0x05}, {0xda, 0x2c, 0x98, 0xa7, 0x8c, 0xe7, 0xa6, 0x89, 0x45, 0xfc, 0xc1, 0xc6, 0xae, 0x98, 0x6a, 0x77, 0xc5, 0x20, 0xfb, 0x5e, 0x4e, 0xcc, 0xc1, 0xa4, 0x2c, 0xfe, 0x53, 0x89, 0x00, 0x1e, 0x15, 0x2f}}, - {{0x97, 0x1d, 0xb9, 0x83, 0x41, 0x50, 0x23, 0x10, 0x60, 0xca, 0x77, 0x88, 0x2a, 0xbc, 0xfe, 0x81, 0x4c, 0xbb, 0x3f, 0xfe, 0x49, 0x5c, 0x24, 0x19, 0xf3, 0x74, 0xf3, 0xe3, 0x3f, 0xa1, 0x38, 0x0d}, {0xde, 0x45, 0xa1, 0x44, 0x31, 0x17, 0x43, 0xd6, 0x87, 0x5f, 0x57, 0x73, 0x8b, 0xd7, 0x95, 0xcd, 0xe3, 0x09, 0x29, 0xd3, 0x3f, 0x6c, 0xd2, 0x6e, 0x2a, 0x34, 0x5f, 0xe8, 0x80, 0x83, 0x60, 0x09}}, - {{0x5e, 0xc0, 0x2f, 0xbe, 0xdb, 0x8c, 0x91, 0x42, 0x95, 0xd4, 0x66, 0xb1, 0x57, 0x4a, 0xcf, 0x9a, 0xab, 0x49, 0x5e, 0xf4, 0x23, 0xc9, 0x99, 0xca, 0xe9, 0xa1, 0xb7, 0x04, 0xab, 0x33, 0xa1, 0x3f}, {0xa0, 0x4d, 0x4d, 0x52, 0x82, 0xa9, 0x31, 0xd7, 0x72, 0x11, 0x21, 0x03, 0x8d, 0x87, 0xec, 0x55, 0xcd, 0x92, 0x24, 0xe3, 0xed, 0xea, 0xd5, 0x48, 0x98, 0x71, 0x67, 0xd1, 0x57, 0xb9, 0xff, 0x0c}}, - {{0xc2, 0xa4, 0x29, 0xc4, 0x8a, 0xad, 0x28, 0xf5, 0x7e, 0x92, 0xcb, 0x8b, 0xcd, 0x85, 0x9b, 0xd9, 0x1d, 0xf1, 0xcd, 0x3e, 0x3f, 0x6c, 0x3a, 0x85, 0xb0, 0xec, 0x91, 0x0d, 0xe9, 0xd9, 0xb4, 0x3f}, {0x70, 0xa7, 0x88, 0x70, 0xbd, 0x5c, 0x37, 0x91, 0x5d, 0xfc, 0x63, 0x40, 0xbd, 0x46, 0x73, 0xbc, 0x1c, 0xa3, 0x34, 0x19, 0xa0, 0xb5, 0xee, 0x52, 0x34, 0x13, 0xc1, 0x0d, 0x9b, 0x38, 0x97, 0x35}}, - {{0x02, 0x38, 0xa3, 0xc6, 0xbd, 0xe2, 0x04, 0xdb, 0x78, 0x09, 0xbe, 0xce, 0xc3, 0x61, 0x96, 0x48, 0x97, 0xf5, 0x9e, 0xa4, 0xcc, 0x61, 0xf9, 0x21, 0x42, 0x22, 0x94, 0xb3, 0xb7, 0xc0, 0xc8, 0x0f}, {0xd6, 0xbe, 0x8a, 0x94, 0x56, 0x9b, 0x85, 0x8f, 0x47, 0x23, 0x7c, 0xbb, 0xa1, 0x52, 0xb1, 0x72, 0xd3, 0x88, 0xb4, 0x34, 0xd5, 0x82, 0xda, 0xfc, 0xf7, 0xdc, 0xbf, 0xc1, 0x0b, 0x04, 0x4d, 0x3e}}, - {{0x4c, 0xfb, 0xf8, 0xf5, 0xd9, 0xd7, 0xa9, 0x24, 0x64, 0x65, 0x7a, 0xda, 0x2f, 0xe9, 0x4b, 0xa8, 0xf6, 0x9f, 0xac, 0x1b, 0xc0, 0xa2, 0x10, 0x7c, 0xf9, 0x9e, 0x70, 0x2e, 0xbb, 0xec, 0x3d, 0x34}, {0x54, 0xe6, 0xfd, 0xd7, 0x2e, 0x64, 0x38, 0xf5, 0x4b, 0x58, 0x2e, 0x43, 0xa6, 0xfa, 0x30, 0x6d, 0xcc, 0x2b, 0x56, 0x28, 0xad, 0x02, 0xf2, 0x18, 0x1d, 0xd2, 0x52, 0x23, 0x66, 0x71, 0x0c, 0x1a}}, - {{0x6a, 0x3f, 0xd3, 0x14, 0x11, 0x90, 0xe8, 0x08, 0xa2, 0x28, 0x8c, 0xf4, 0xea, 0x62, 0x82, 0x0d, 0x46, 0x65, 0x50, 0x27, 0x7b, 0x08, 0xfe, 0x89, 0xe6, 0xe8, 0xaa, 0xef, 0x7a, 0x2f, 0x95, 0x08}, {0xad, 0x84, 0x55, 0x95, 0x0f, 0x28, 0x63, 0xca, 0x22, 0xd5, 0xa5, 0xe8, 0x03, 0xa1, 0xbe, 0xc7, 0x91, 0xe4, 0x41, 0x54, 0x13, 0xd9, 0x95, 0xb7, 0x32, 0xa0, 0xab, 0x62, 0xad, 0x13, 0xa2, 0x3a}}, - {{0xa1, 0xaf, 0x6d, 0xa4, 0xe2, 0xe3, 0x4d, 0x15, 0x41, 0x96, 0x7c, 0xaf, 0x7e, 0xcb, 0x1b, 0xef, 0xb7, 0x48, 0x9c, 0x0b, 0x3f, 0x1e, 0xcc, 0xc4, 0x2e, 0x2a, 0x99, 0x1a, 0xa3, 0x14, 0x7b, 0x22}, {0x61, 0x4a, 0xfb, 0x71, 0x90, 0xe2, 0xe2, 0xe7, 0x73, 0x3b, 0x2c, 0x9e, 0xfe, 0xa7, 0xf4, 0x28, 0x6a, 0xc8, 0x25, 0x19, 0x36, 0x80, 0xc8, 0x2f, 0x6a, 0xf9, 0x92, 0x3d, 0x3d, 0x37, 0xde, 0x2c}}, - {{0xc8, 0xf4, 0xd6, 0xa7, 0x42, 0x18, 0x19, 0x6c, 0x70, 0x3d, 0x39, 0x30, 0x99, 0xba, 0x1d, 0xa3, 0x76, 0x70, 0x06, 0x3e, 0x26, 0x6c, 0x14, 0x35, 0x6b, 0x48, 0x46, 0x46, 0x47, 0x9a, 0x03, 0x38}, {0xc5, 0x96, 0x82, 0x59, 0x49, 0xd2, 0xaf, 0x27, 0x52, 0xd2, 0xb2, 0xf5, 0xaa, 0xb6, 0xf6, 0xfc, 0xec, 0xdf, 0x95, 0x74, 0x1e, 0xb9, 0x22, 0x5c, 0x07, 0x65, 0xa4, 0xdf, 0x70, 0x9b, 0x57, 0x2d}}, - {{0xdf, 0x64, 0x76, 0x43, 0x11, 0xb1, 0xaf, 0x50, 0x25, 0x53, 0x6f, 0xfe, 0xf4, 0x72, 0x85, 0x1a, 0x0e, 0x63, 0xcf, 0xea, 0x8b, 0xbf, 0x88, 0x13, 0x13, 0x76, 0x09, 0xe1, 0x99, 0x37, 0x6b, 0x38}, {0x2a, 0xe1, 0x43, 0x91, 0x5b, 0x2f, 0x70, 0x1d, 0x8d, 0x42, 0xf3, 0xc5, 0x7e, 0xaf, 0xc6, 0xaa, 0xf2, 0x52, 0x1f, 0x55, 0x11, 0x6b, 0xdc, 0x17, 0x93, 0xe7, 0x35, 0xe8, 0xb0, 0x38, 0x7c, 0x0f}}, - {{0x46, 0x3e, 0xd4, 0x9b, 0x75, 0xbd, 0xe1, 0xc6, 0xaf, 0x0b, 0xe1, 0x41, 0x52, 0xcc, 0xa0, 0xb4, 0xab, 0xf6, 0x6e, 0xc4, 0x75, 0xed, 0x77, 0x9b, 0x03, 0xff, 0x48, 0x52, 0x29, 0xf9, 0x02, 0x0c}, {0x25, 0x68, 0x56, 0x09, 0x24, 0x50, 0x45, 0xc4, 0x18, 0x79, 0xe1, 0xb2, 0x5c, 0xb6, 0x96, 0x09, 0xa6, 0x49, 0xb1, 0x1e, 0x0f, 0x9f, 0x22, 0xec, 0x87, 0x58, 0x62, 0x44, 0x28, 0x88, 0x64, 0x0c}}, - {{0x18, 0xba, 0x97, 0x27, 0xbd, 0x8b, 0x12, 0xc4, 0x08, 0x5b, 0xd3, 0x69, 0x04, 0x1f, 0x47, 0xbd, 0x64, 0x23, 0x6c, 0x84, 0xe6, 0x0a, 0x1a, 0x02, 0x79, 0x63, 0xea, 0xf4, 0x1e, 0x3b, 0x0d, 0x1e}, {0x78, 0x9f, 0xab, 0x1c, 0xb2, 0x8e, 0xbd, 0xd0, 0xe3, 0x74, 0x72, 0xfe, 0x11, 0xe6, 0xfb, 0x1b, 0xde, 0xd7, 0xe3, 0x10, 0x15, 0x88, 0x44, 0xf8, 0x96, 0x93, 0xac, 0xa5, 0xbb, 0x00, 0x0b, 0x15}}, - {{0xde, 0xc0, 0x69, 0x91, 0x2b, 0x2b, 0x2e, 0x75, 0x56, 0x16, 0x2b, 0x5a, 0xeb, 0x7f, 0xe4, 0xf2, 0x12, 0x79, 0x4b, 0x31, 0x31, 0x78, 0xf7, 0x61, 0x6c, 0x14, 0x30, 0x15, 0xbf, 0x36, 0xd5, 0x29}, {0x72, 0x0c, 0xff, 0x9a, 0x54, 0xbb, 0x90, 0xc8, 0x2a, 0xb4, 0xdb, 0x76, 0xe0, 0xa4, 0x7d, 0x19, 0x06, 0x52, 0x21, 0x38, 0x42, 0x01, 0x6f, 0x74, 0x1e, 0x95, 0x5a, 0x4c, 0x7e, 0xc5, 0x12, 0x25}}, - {{0x6c, 0x68, 0xaa, 0xc1, 0x45, 0x6a, 0xe6, 0xe7, 0x67, 0x12, 0x46, 0xbd, 0x74, 0xb4, 0x98, 0x8c, 0xdf, 0x4c, 0xc1, 0x4c, 0x14, 0xd4, 0xe1, 0x8a, 0x67, 0x8c, 0x5c, 0x94, 0xfa, 0x33, 0x9f, 0x1b}, {0x21, 0x6b, 0x6d, 0xad, 0x95, 0x74, 0x02, 0x98, 0x1b, 0x1b, 0xcc, 0xce, 0x29, 0xed, 0xc8, 0xcc, 0x44, 0x70, 0x30, 0x69, 0x51, 0x0f, 0xc8, 0x74, 0x38, 0x22, 0x06, 0x3b, 0xec, 0xd2, 0x4b, 0x33}}, - {{0x42, 0x45, 0x8a, 0xe4, 0x4a, 0xe3, 0xe3, 0xe2, 0x3a, 0x23, 0x72, 0xee, 0x9d, 0x9d, 0xa7, 0x77, 0x99, 0x3f, 0x97, 0x5d, 0xcd, 0x2f, 0x90, 0x92, 0x6b, 0xd8, 0x7b, 0x53, 0x80, 0xdf, 0x28, 0x0e}, {0x9a, 0x5b, 0x98, 0xa1, 0xb7, 0xf5, 0x57, 0xb2, 0x19, 0x8f, 0xc2, 0xcb, 0x70, 0x7e, 0xdd, 0xad, 0x77, 0xbb, 0xd3, 0x11, 0xdf, 0x17, 0x5b, 0xc3, 0x4c, 0x98, 0x5b, 0xe8, 0x76, 0x8a, 0xf4, 0x28}}, - {{0x83, 0x7f, 0xa5, 0x7a, 0xb9, 0x64, 0xd2, 0xc1, 0xba, 0xd3, 0x31, 0x10, 0x7d, 0x69, 0xa7, 0xc8, 0xba, 0xc1, 0xc1, 0xd6, 0xc8, 0x33, 0x54, 0x1e, 0x95, 0x7a, 0x85, 0x7c, 0x62, 0x43, 0x28, 0x1a}, {0x3b, 0x80, 0x38, 0xf6, 0x05, 0x70, 0x00, 0x5c, 0x36, 0x34, 0xd1, 0x33, 0x10, 0x68, 0x3c, 0x15, 0xcf, 0xc4, 0xec, 0x65, 0xfa, 0x84, 0xca, 0x39, 0xa1, 0x2d, 0xe3, 0xeb, 0x69, 0x73, 0xa5, 0x36}}, - {{0xd1, 0x88, 0xd6, 0x1e, 0xb7, 0xfa, 0x3b, 0xcb, 0x70, 0x44, 0xda, 0xc3, 0xb1, 0x75, 0x9d, 0x95, 0x2b, 0x3d, 0x2e, 0x21, 0x88, 0xcf, 0x6b, 0xff, 0x99, 0x6b, 0x0b, 0x99, 0xe5, 0x0e, 0xb4, 0x1a}, {0x43, 0x8e, 0xe5, 0xd6, 0x71, 0xcc, 0xfc, 0x18, 0x21, 0x0d, 0x00, 0x1c, 0xcf, 0xe1, 0xfa, 0x52, 0x25, 0xa2, 0xa4, 0x42, 0xc1, 0x97, 0x55, 0xfe, 0xba, 0x13, 0xa3, 0x72, 0xab, 0x53, 0x8a, 0x0a}}, - {{0x4b, 0x8e, 0x16, 0x54, 0x37, 0x3a, 0xce, 0xf4, 0x4a, 0x43, 0x52, 0xec, 0x6a, 0x54, 0xc7, 0x61, 0xe8, 0x57, 0x93, 0x68, 0x66, 0xac, 0x70, 0x7d, 0xc8, 0xef, 0x7d, 0x9a, 0x75, 0x44, 0x12, 0x1c}, {0x5a, 0xdb, 0x6e, 0xa9, 0xb6, 0x2c, 0x5f, 0x3b, 0x4f, 0x5d, 0x59, 0x23, 0x86, 0xe8, 0x71, 0xef, 0xe0, 0xc9, 0xfd, 0x5a, 0x36, 0x74, 0xa2, 0xe5, 0xfe, 0x3e, 0x74, 0x27, 0x1f, 0xf9, 0x0a, 0x11}}, - {{0x95, 0xde, 0x77, 0xe6, 0x2a, 0xe2, 0x95, 0x68, 0xc3, 0x3d, 0x7b, 0x93, 0x3d, 0x9b, 0xbb, 0x9f, 0x66, 0xbd, 0xd5, 0xd4, 0xd9, 0xf4, 0xc1, 0x0b, 0x8a, 0xe7, 0xec, 0x1f, 0x7f, 0xb6, 0xf2, 0x27}, {0xc4, 0xef, 0xbc, 0x50, 0x11, 0x94, 0x34, 0x72, 0x62, 0x03, 0xf5, 0xa8, 0x53, 0x57, 0x8e, 0xac, 0x6c, 0x46, 0x28, 0xe4, 0x41, 0x8c, 0xe3, 0xf7, 0x13, 0xcf, 0x4d, 0x5d, 0x5b, 0x64, 0x5e, 0x31}}, - {{0x93, 0x69, 0x08, 0xe8, 0x94, 0xbb, 0x94, 0x54, 0xe8, 0xef, 0x21, 0xc4, 0x5b, 0x79, 0x9a, 0x90, 0x33, 0xf4, 0x45, 0x6b, 0x01, 0xcb, 0x8b, 0x03, 0xdd, 0xd6, 0xb6, 0xcb, 0x36, 0x46, 0xc4, 0x2f}, {0x87, 0xbb, 0xbd, 0x0c, 0xe0, 0x6f, 0x7f, 0xa3, 0x06, 0x05, 0x08, 0xbe, 0x06, 0xcb, 0xae, 0x0a, 0x6f, 0xf3, 0x4d, 0xe8, 0x2f, 0xa1, 0x80, 0xdd, 0x50, 0xe2, 0xf9, 0x7a, 0xe0, 0x84, 0xc8, 0x1d}}, - {{0x0b, 0x0e, 0x6d, 0xa5, 0x05, 0x1d, 0xa4, 0xda, 0x3c, 0x44, 0xeb, 0x13, 0x75, 0x5c, 0xed, 0x6f, 0x50, 0xcd, 0xb1, 0x65, 0x4c, 0x0e, 0x8b, 0x7a, 0xef, 0xb0, 0x8b, 0xed, 0x8e, 0x7c, 0x4f, 0x21}, {0x16, 0xea, 0x81, 0x18, 0xd5, 0xd9, 0x49, 0xfe, 0x37, 0x13, 0x34, 0xed, 0x64, 0xdd, 0x53, 0x23, 0xd9, 0x26, 0xf1, 0xd9, 0x8e, 0x0c, 0xb2, 0x56, 0xe8, 0x0d, 0x2b, 0x4c, 0xb4, 0x92, 0x22, 0x2c}}, - {{0xbb, 0x04, 0x7c, 0x9b, 0x4e, 0x96, 0x4d, 0xa7, 0xec, 0x2d, 0xc0, 0x4e, 0x5b, 0xbb, 0x5c, 0x33, 0x9f, 0x32, 0x94, 0x69, 0xec, 0x7b, 0x84, 0x8a, 0xd4, 0xc5, 0xe7, 0x0d, 0x22, 0x1c, 0xa7, 0x1a}, {0x93, 0xf5, 0xf9, 0xd6, 0xa6, 0x82, 0xb8, 0xc3, 0xe6, 0x8a, 0x9f, 0x25, 0x1b, 0x9e, 0xa7, 0x9b, 0x26, 0xcc, 0x79, 0xbd, 0x63, 0xb7, 0xb6, 0x8a, 0x40, 0xb7, 0xfa, 0x34, 0xaf, 0x61, 0x83, 0x21}}, - {{0x61, 0x36, 0xd5, 0x5b, 0x79, 0x5e, 0xb6, 0x97, 0x38, 0x8b, 0xdc, 0xf4, 0x4b, 0xb2, 0x0b, 0x56, 0xda, 0x12, 0x55, 0xc0, 0xc1, 0xdc, 0xce, 0x16, 0x5b, 0x10, 0xf2, 0xb4, 0xae, 0x6c, 0x71, 0x15}, {0x25, 0x7f, 0x91, 0xab, 0xa4, 0xb4, 0x1a, 0x3f, 0xc7, 0x2e, 0x48, 0x4e, 0x6e, 0xf1, 0x97, 0x45, 0x4b, 0x54, 0x78, 0x9f, 0xe2, 0xb3, 0xc4, 0x43, 0x59, 0x1c, 0xbf, 0x26, 0xc2, 0xee, 0xbf, 0x0a}}, - {{0xd7, 0x91, 0xb6, 0x41, 0x39, 0xa7, 0xeb, 0x9b, 0xa3, 0xeb, 0x08, 0x9d, 0x9b, 0xe4, 0x15, 0xcf, 0x6e, 0xbb, 0x9b, 0x4f, 0x65, 0x24, 0x43, 0xd4, 0xf6, 0xb4, 0x75, 0x59, 0x0c, 0xf1, 0x42, 0x25}, {0x1c, 0x22, 0xc7, 0xf3, 0xa6, 0xc2, 0x0d, 0x41, 0x1d, 0x82, 0x38, 0xf1, 0x82, 0xef, 0x64, 0x9e, 0x50, 0xcb, 0x2a, 0xdf, 0xe2, 0x68, 0x07, 0x36, 0x46, 0xa9, 0xa1, 0xa2, 0x0c, 0x28, 0xf0, 0x2a}}, - {{0xcc, 0x32, 0x25, 0x25, 0xa4, 0x4d, 0xaa, 0x40, 0x18, 0x69, 0x50, 0x68, 0xf5, 0x25, 0x47, 0xa0, 0x4a, 0xe1, 0xfc, 0xfe, 0x44, 0x86, 0x96, 0xd0, 0x85, 0xa1, 0xa9, 0x96, 0x22, 0xae, 0x91, 0x05}, {0x23, 0xc2, 0xe9, 0x2d, 0x56, 0xea, 0x9d, 0xc5, 0xf1, 0x94, 0x62, 0x8a, 0x85, 0x1b, 0x48, 0x15, 0xa2, 0x25, 0xb6, 0xc1, 0x8d, 0xa0, 0xac, 0x0a, 0xa1, 0xdd, 0xce, 0x21, 0x9a, 0xcf, 0x05, 0x0f}}, - {{0xcc, 0x72, 0x76, 0x50, 0xd1, 0xb7, 0x4b, 0xd1, 0xd5, 0x3a, 0xce, 0x52, 0x6f, 0x7f, 0x30, 0x63, 0x72, 0x30, 0x24, 0xad, 0x25, 0x1e, 0xe5, 0x7c, 0xa0, 0x6e, 0x7c, 0xdd, 0xac, 0x2b, 0xdc, 0x07}, {0xae, 0xff, 0x40, 0x7c, 0xd5, 0xc3, 0x36, 0x58, 0x09, 0xae, 0xb7, 0x44, 0x9e, 0x81, 0xf5, 0x46, 0x85, 0x97, 0x9c, 0xe0, 0x55, 0xfb, 0x96, 0xb7, 0xd1, 0x5d, 0xd5, 0x55, 0x7b, 0x73, 0x95, 0x2d}}, - {{0xaf, 0x82, 0x15, 0x01, 0xbf, 0xa9, 0xdd, 0x86, 0x44, 0x6b, 0x90, 0x36, 0x1e, 0xe4, 0xd9, 0x40, 0xa2, 0xbf, 0x83, 0x89, 0xaa, 0x20, 0x87, 0x57, 0xfb, 0x8a, 0xf1, 0x18, 0x06, 0x17, 0x1a, 0x2f}, {0xc6, 0xa8, 0xe4, 0x75, 0x09, 0x93, 0xf8, 0x09, 0x79, 0x9f, 0x1c, 0xbe, 0x7d, 0x96, 0x85, 0xef, 0xd4, 0xbc, 0xb7, 0x32, 0xba, 0x18, 0x38, 0x4a, 0xb7, 0x5c, 0xb5, 0x63, 0x95, 0x12, 0x8f, 0x0a}}, - {{0x38, 0x2a, 0x4e, 0xa8, 0x0f, 0x85, 0xe5, 0x64, 0x92, 0x28, 0xcb, 0xa1, 0xd2, 0xf9, 0xa1, 0x67, 0xdc, 0x1a, 0x3d, 0x6a, 0xa9, 0xe8, 0xb6, 0x34, 0xc0, 0xa0, 0xd6, 0x86, 0xe3, 0x30, 0x6f, 0x2e}, {0x6a, 0xff, 0x65, 0x8e, 0x17, 0x3f, 0xd1, 0xb9, 0x48, 0x78, 0x5a, 0xe2, 0x20, 0x0b, 0xfb, 0x4f, 0xd3, 0xe2, 0x68, 0xe6, 0xd2, 0xdc, 0x2f, 0x6c, 0x9c, 0x23, 0xfa, 0xa6, 0x54, 0x9c, 0x93, 0x1e}}, - {{0xf6, 0xe7, 0xce, 0x79, 0x67, 0x84, 0x16, 0x33, 0x60, 0xc3, 0x60, 0x55, 0x7b, 0xd0, 0x6e, 0xfb, 0x57, 0x63, 0xff, 0x55, 0x59, 0x2f, 0x8f, 0x4a, 0x8d, 0x6d, 0x75, 0x93, 0xfc, 0x77, 0xfb, 0x28}, {0x12, 0x56, 0xcf, 0xb2, 0x78, 0x1b, 0xe2, 0xe3, 0x88, 0x76, 0x22, 0xcb, 0xe2, 0x70, 0xd4, 0xc8, 0x4b, 0xf2, 0xd4, 0xe1, 0x6e, 0x0c, 0x1b, 0x73, 0xc2, 0x55, 0x19, 0x46, 0xff, 0x02, 0xcd, 0x30}}, - {{0x26, 0x91, 0xea, 0xe5, 0x02, 0x4a, 0x9c, 0x8e, 0xdd, 0x96, 0x5e, 0x4e, 0x8e, 0xf1, 0xb9, 0x6f, 0x31, 0x11, 0x49, 0x68, 0x74, 0x32, 0x4c, 0x49, 0x12, 0x09, 0xaa, 0x35, 0x24, 0xfe, 0xb5, 0x18}, {0x75, 0x8d, 0xfc, 0x8d, 0x92, 0x0a, 0x56, 0x49, 0x7e, 0x26, 0x11, 0x3b, 0x69, 0x7b, 0x48, 0xc9, 0x9f, 0x78, 0x42, 0x1b, 0x1d, 0xda, 0x5e, 0x31, 0x9a, 0xbf, 0x73, 0x9f, 0x03, 0x35, 0xd4, 0x35}}, - {{0x62, 0x2f, 0x96, 0x9f, 0x21, 0x68, 0x10, 0x00, 0xe7, 0xe2, 0x30, 0x6b, 0x4d, 0x2d, 0x31, 0x39, 0xc6, 0xc2, 0x36, 0xad, 0x9a, 0xb2, 0xbe, 0x94, 0xd2, 0x73, 0x07, 0xc0, 0x28, 0x53, 0xf4, 0x36}, {0xb5, 0xd8, 0x5d, 0x1e, 0x41, 0x0b, 0xf3, 0xe4, 0xd8, 0xcb, 0x23, 0x48, 0x6f, 0x1f, 0xe5, 0x65, 0x99, 0xf2, 0xb6, 0xd0, 0xd3, 0x3f, 0x7f, 0xf4, 0xbe, 0x56, 0x51, 0xe9, 0xf8, 0x8f, 0x27, 0x14}}, - {{0x15, 0x20, 0x1e, 0xd9, 0xad, 0xd0, 0x4f, 0xe1, 0xab, 0xfd, 0xa9, 0x60, 0xd9, 0xcc, 0xbc, 0xa2, 0x72, 0xb5, 0x1c, 0xf7, 0xb5, 0xaa, 0x5f, 0x71, 0x8c, 0x8c, 0x3f, 0xe2, 0x3b, 0xed, 0x60, 0x19}, {0xb0, 0x75, 0xd9, 0x32, 0x92, 0xe7, 0x4d, 0x6d, 0x90, 0x44, 0x9c, 0xf7, 0x6f, 0xd8, 0xe0, 0xa0, 0xd9, 0x08, 0x3c, 0x5f, 0x8e, 0xec, 0x7e, 0x94, 0xb6, 0xee, 0x76, 0xf1, 0xd0, 0xf9, 0x2a, 0x16}}, - {{0x4f, 0x4e, 0x4f, 0x64, 0x89, 0x2a, 0xbe, 0x77, 0xf8, 0x19, 0x79, 0xf9, 0x2f, 0xfd, 0xc2, 0xda, 0x6e, 0x33, 0xa4, 0x0a, 0x5e, 0x41, 0x2d, 0x48, 0xea, 0xdd, 0x5d, 0xc2, 0x67, 0x8f, 0xb4, 0x12}, {0xc2, 0xfd, 0x95, 0x54, 0x56, 0xb3, 0x47, 0x14, 0xbd, 0xa6, 0x46, 0x20, 0x2d, 0x15, 0x86, 0xfa, 0x30, 0x34, 0xb6, 0x96, 0xee, 0x3c, 0x48, 0x0e, 0x6b, 0x35, 0x04, 0x9f, 0x69, 0xf9, 0x0a, 0x31}}, - {{0xb2, 0x90, 0x49, 0x4b, 0x8f, 0x56, 0xd9, 0x49, 0xed, 0x0e, 0x43, 0x6c, 0xe9, 0x52, 0x1d, 0xff, 0xbc, 0x7f, 0xb6, 0x0a, 0x7e, 0xc6, 0xab, 0x9d, 0xd0, 0x6b, 0xfc, 0xda, 0xf0, 0xac, 0xb8, 0x15}, {0xe1, 0xeb, 0xaf, 0xc8, 0xbc, 0x2a, 0xdb, 0x04, 0xde, 0xae, 0xed, 0xb8, 0x02, 0x43, 0x8a, 0x85, 0x1a, 0x37, 0x83, 0x96, 0xdf, 0xf9, 0x7e, 0x85, 0xa9, 0x56, 0xbc, 0xc5, 0x92, 0x67, 0xd5, 0x0e}}, - {{0xb8, 0x29, 0xbe, 0x97, 0xbb, 0xc4, 0xc8, 0x8f, 0x88, 0x93, 0xfd, 0xc6, 0x3a, 0xec, 0x3f, 0x72, 0x00, 0x38, 0xce, 0x14, 0x44, 0x5b, 0x18, 0xcc, 0x8c, 0xaf, 0x7c, 0xed, 0xa9, 0x31, 0x03, 0x19}, {0x68, 0x17, 0x0c, 0x82, 0xb0, 0x8e, 0x48, 0x6e, 0x49, 0xca, 0xf1, 0x98, 0x2c, 0x5d, 0xcb, 0x7f, 0x25, 0x41, 0x8e, 0x23, 0x66, 0x89, 0xc6, 0x32, 0xcc, 0xea, 0x65, 0xb1, 0x5e, 0xd0, 0xca, 0x06}}, - {{0x38, 0x4c, 0x42, 0x99, 0xc0, 0x73, 0xd6, 0x05, 0x6c, 0xd3, 0xd8, 0x65, 0x44, 0xe9, 0x1c, 0x9b, 0x99, 0x0b, 0x65, 0xf3, 0xf4, 0xc0, 0x92, 0x41, 0x71, 0xb8, 0x4d, 0x08, 0x85, 0xb3, 0x83, 0x33}, {0xdc, 0x42, 0xb4, 0xab, 0x62, 0xb1, 0xa3, 0x41, 0xed, 0x46, 0x83, 0x25, 0xb0, 0x86, 0x7f, 0x01, 0xb5, 0xa2, 0xed, 0xe3, 0x83, 0x97, 0x8e, 0x45, 0x81, 0x6b, 0xd3, 0x29, 0xcb, 0xe1, 0x3e, 0x08}}, - {{0x7d, 0x76, 0x77, 0x79, 0x43, 0x95, 0x76, 0xe4, 0x5f, 0x17, 0x6c, 0xf6, 0x2a, 0x7b, 0x9c, 0xed, 0x5e, 0xcd, 0x41, 0x57, 0x88, 0xa5, 0x33, 0xb8, 0x2c, 0xd7, 0x58, 0xcd, 0xfb, 0xb7, 0x3d, 0x36}, {0xe3, 0x02, 0xf8, 0xd9, 0xcb, 0x93, 0x13, 0xf3, 0x8b, 0x07, 0x43, 0x2b, 0x6c, 0x36, 0xeb, 0xe6, 0x4e, 0x59, 0x12, 0x32, 0xdc, 0xb4, 0xa3, 0xbc, 0x34, 0x1b, 0x11, 0xdf, 0x78, 0x19, 0xb1, 0x08}}, - {{0x6c, 0x00, 0x6f, 0x9e, 0x05, 0xa7, 0xce, 0x77, 0xab, 0x66, 0x08, 0xdc, 0x7d, 0xdb, 0x5b, 0xa3, 0xea, 0x97, 0xf1, 0x56, 0x2e, 0xf9, 0x5a, 0x71, 0x6e, 0xd8, 0xc4, 0x05, 0x45, 0x93, 0x64, 0x36}, {0xfc, 0xcf, 0x1d, 0xa1, 0x68, 0xe4, 0x53, 0x9c, 0x2c, 0x60, 0xdd, 0x68, 0x67, 0x0f, 0x3e, 0x1c, 0x77, 0x45, 0x5c, 0xd6, 0xb8, 0x77, 0xa5, 0x1b, 0xe6, 0x9a, 0xf6, 0x67, 0xb8, 0x09, 0x42, 0x1d}}, - {{0x80, 0x58, 0x0f, 0xa1, 0x80, 0x53, 0x0a, 0x26, 0xe5, 0x04, 0x5a, 0xb6, 0xcc, 0xb8, 0x1b, 0x7a, 0x08, 0x23, 0x8b, 0xd2, 0xff, 0xf9, 0xa8, 0x27, 0xc3, 0xf3, 0xbe, 0xac, 0x37, 0xfb, 0x32, 0x3a}, {0x54, 0x99, 0x74, 0xa3, 0x46, 0x9b, 0x4a, 0x91, 0x35, 0x81, 0x61, 0x0c, 0xfc, 0xb9, 0xd9, 0xfe, 0x1e, 0xf2, 0x72, 0xa1, 0xc9, 0x3e, 0x45, 0xfe, 0x0f, 0xec, 0x78, 0x57, 0xfd, 0x90, 0x9f, 0x1c}}, - {{0x08, 0x31, 0x09, 0xc2, 0x61, 0xa4, 0x10, 0x99, 0x04, 0x90, 0x9e, 0xb3, 0x23, 0xd0, 0x2e, 0x2c, 0x3b, 0x91, 0x7f, 0xa2, 0x33, 0x9b, 0x03, 0x2c, 0xec, 0x4d, 0x77, 0x95, 0x54, 0x69, 0x0e, 0x0a}, {0xd8, 0x90, 0x49, 0x45, 0x3d, 0xb7, 0xb9, 0xe6, 0xed, 0x1e, 0x52, 0x23, 0x67, 0xdd, 0xba, 0x47, 0x00, 0xcc, 0xa5, 0x81, 0x46, 0xe0, 0xbe, 0x40, 0x2d, 0x93, 0xff, 0x1e, 0x1f, 0xea, 0xb5, 0x36}}, - {{0xa3, 0xf7, 0x61, 0x46, 0x98, 0x03, 0xe0, 0xd2, 0xe1, 0x51, 0xe6, 0x09, 0x7c, 0xc1, 0x79, 0xca, 0x38, 0xa5, 0x0b, 0x41, 0xd3, 0x47, 0x36, 0x78, 0x5d, 0x9a, 0xcb, 0x8a, 0xa4, 0x55, 0x7c, 0x21}, {0x63, 0xe2, 0xfd, 0x04, 0x6c, 0x0b, 0xd2, 0x1b, 0x59, 0xa3, 0x6d, 0xdc, 0x94, 0xb6, 0xc7, 0x02, 0x1c, 0x9a, 0x1b, 0x8a, 0xfc, 0x9c, 0x71, 0x3a, 0xbe, 0x9b, 0x48, 0x5b, 0x23, 0x53, 0xff, 0x3f}}, - {{0xd2, 0x16, 0xfc, 0x66, 0xf6, 0xd2, 0x5b, 0xe2, 0xc2, 0x75, 0x9c, 0xdb, 0xa1, 0xb1, 0x99, 0xf9, 0x2d, 0x16, 0x4f, 0x79, 0xcf, 0xf6, 0xf6, 0xd0, 0x98, 0x5f, 0x52, 0x53, 0xde, 0x32, 0x66, 0x33}, {0x98, 0xe0, 0x30, 0x92, 0x79, 0x3a, 0x68, 0x1c, 0xed, 0x04, 0x2c, 0xa7, 0x25, 0x7b, 0x7c, 0x80, 0x62, 0xe7, 0x08, 0x0c, 0x05, 0x0c, 0x4e, 0x53, 0xb0, 0xba, 0xb2, 0x88, 0x1f, 0x1d, 0xc6, 0x2b}}, - {{0x06, 0x38, 0x11, 0x6d, 0x02, 0xad, 0xe1, 0x6e, 0xf8, 0xc2, 0x69, 0x0c, 0x86, 0xcf, 0x02, 0xc4, 0x48, 0x79, 0xd4, 0x7a, 0x98, 0x0a, 0x43, 0x1b, 0x73, 0x40, 0xe7, 0x04, 0xb0, 0xca, 0x23, 0x31}, {0x93, 0x11, 0x74, 0xaf, 0x1e, 0xc0, 0xac, 0x28, 0xb5, 0xb2, 0x65, 0x3e, 0x06, 0x2c, 0x35, 0x3d, 0xab, 0x52, 0x2a, 0x3d, 0x88, 0x81, 0xa6, 0x5d, 0x7a, 0x51, 0x69, 0x55, 0xb3, 0x4a, 0xf2, 0x38}}, - {{0x80, 0x9a, 0x02, 0x27, 0x1c, 0x34, 0xaf, 0x6b, 0xc1, 0x22, 0x26, 0x23, 0x3d, 0xcf, 0xd7, 0x31, 0xa3, 0x7d, 0x6f, 0x45, 0x61, 0xe3, 0x6b, 0xb5, 0x94, 0x04, 0x47, 0x5b, 0xc2, 0x07, 0xd9, 0x22}, {0xe1, 0xb2, 0x21, 0x93, 0xea, 0x08, 0x10, 0x81, 0xc1, 0x0e, 0x04, 0x8b, 0x9c, 0xc1, 0x15, 0x9e, 0x1a, 0x0f, 0xfd, 0xa4, 0x0c, 0x86, 0xb4, 0xc7, 0x92, 0xce, 0xf2, 0x9f, 0x5c, 0x5b, 0xb3, 0x3f}}, - {{0x5d, 0x21, 0xc3, 0x57, 0xe9, 0xcb, 0xb4, 0x3e, 0x18, 0x20, 0x5a, 0xaa, 0x30, 0x1c, 0xbb, 0xe3, 0x6a, 0xce, 0xdf, 0x04, 0x64, 0xf3, 0x29, 0x68, 0x02, 0x35, 0x77, 0x5e, 0xb8, 0x9b, 0x4c, 0x1e}, {0x92, 0xb6, 0x5a, 0xc3, 0x06, 0x54, 0x27, 0xf9, 0xeb, 0xd2, 0xf8, 0x43, 0xcf, 0xca, 0xb3, 0xed, 0x8d, 0xfa, 0x2f, 0xe8, 0x41, 0x6f, 0x04, 0x5b, 0x2e, 0x77, 0xe1, 0x1b, 0x90, 0xb4, 0xc2, 0x16}}, - {{0x25, 0xb3, 0xf3, 0x0d, 0xb0, 0x5b, 0xf2, 0x91, 0x0e, 0x31, 0x14, 0xbf, 0x2e, 0x04, 0xa2, 0x9f, 0x05, 0x5a, 0xb1, 0x8b, 0x06, 0x8c, 0x0d, 0x44, 0xb6, 0x51, 0x17, 0x11, 0x5a, 0xe0, 0x0a, 0x00}, {0xfc, 0x96, 0xdc, 0xe8, 0x52, 0xf2, 0xa9, 0x71, 0xfc, 0x47, 0x48, 0xa9, 0x94, 0x0e, 0xe9, 0x93, 0x22, 0x65, 0xe4, 0x82, 0x6d, 0x75, 0xbd, 0x35, 0xad, 0x90, 0x22, 0x09, 0x2d, 0x18, 0xd4, 0x0d}}, - {{0x5a, 0x39, 0x2e, 0x15, 0x8a, 0x89, 0x7d, 0xac, 0xda, 0x33, 0xb3, 0x1a, 0x51, 0x88, 0x3e, 0x89, 0x12, 0x18, 0x1e, 0x79, 0xb1, 0x82, 0x69, 0xf0, 0x02, 0xd0, 0x65, 0xcf, 0xc4, 0xf3, 0xb6, 0x1f}, {0x38, 0xbc, 0xa2, 0xbc, 0x04, 0xe1, 0xc5, 0x65, 0x62, 0xa2, 0x3f, 0x11, 0x3c, 0x88, 0x1b, 0xcd, 0x5e, 0xd4, 0xae, 0x58, 0x49, 0xaf, 0xbc, 0x96, 0x72, 0xa3, 0xb9, 0x6e, 0xd2, 0xe7, 0x4c, 0x3c}}, - {{0xea, 0x02, 0x90, 0xed, 0x0f, 0xb4, 0x7f, 0x86, 0x76, 0xa7, 0xba, 0x7c, 0x1b, 0x04, 0xa5, 0x40, 0x98, 0xac, 0xc4, 0xc7, 0xa4, 0x37, 0x06, 0xc2, 0xbe, 0x8f, 0x46, 0x0e, 0xa2, 0x9d, 0x70, 0x25}, {0x53, 0xfd, 0xc0, 0x4e, 0x9f, 0x68, 0x1a, 0x65, 0x98, 0xe0, 0xea, 0x41, 0x08, 0x30, 0x1e, 0x4a, 0xd2, 0x49, 0x83, 0xca, 0x05, 0xec, 0x4d, 0x9e, 0x95, 0x07, 0xc6, 0x57, 0x31, 0xed, 0xcb, 0x2f}}, - {{0xd1, 0x6f, 0x17, 0xe8, 0x60, 0x1c, 0xb5, 0xa5, 0x0f, 0x75, 0xb9, 0xbf, 0xe3, 0x21, 0x8f, 0x2e, 0x41, 0xa9, 0x74, 0x8b, 0x3c, 0xe5, 0x5c, 0xf4, 0x99, 0x7b, 0x4a, 0xe0, 0x36, 0x1a, 0xfd, 0x04}, {0xf9, 0xd4, 0x5a, 0x9b, 0xc9, 0x72, 0xa7, 0x5c, 0xee, 0xca, 0x93, 0x83, 0x3d, 0xaa, 0x3c, 0xea, 0xa6, 0x0b, 0x18, 0x28, 0x20, 0xad, 0x08, 0x35, 0x0f, 0x07, 0x2c, 0xc5, 0x69, 0xcd, 0x7d, 0x1b}}, - {{0x0e, 0xd2, 0xf1, 0xb3, 0x26, 0x4e, 0x76, 0xf0, 0xc8, 0xe9, 0x25, 0x86, 0x2e, 0x14, 0xc7, 0x18, 0xe2, 0xdc, 0xde, 0x7d, 0x4f, 0x7d, 0xf7, 0x51, 0x22, 0x3f, 0x2b, 0x23, 0x50, 0xbf, 0x73, 0x23}, {0x60, 0xc6, 0x8c, 0x32, 0x3d, 0xd6, 0xb8, 0x47, 0x5d, 0xae, 0x05, 0x0e, 0xc4, 0xf5, 0xfe, 0xda, 0x89, 0x12, 0xc9, 0x47, 0x65, 0xa9, 0xb5, 0x98, 0x6c, 0x0a, 0x05, 0x09, 0x91, 0x04, 0xad, 0x01}}, - {{0xdf, 0x94, 0x7f, 0x94, 0x89, 0xa1, 0x44, 0x11, 0xba, 0x22, 0x10, 0xcd, 0x16, 0xdf, 0x28, 0xe4, 0xa8, 0xc4, 0x76, 0x34, 0xea, 0xd9, 0x65, 0x75, 0xdc, 0xc3, 0x65, 0x12, 0xe3, 0xa6, 0x70, 0x20}, {0x46, 0xe1, 0xc9, 0xde, 0x7d, 0x7f, 0xdf, 0x91, 0xe7, 0xdb, 0x9e, 0x34, 0x1c, 0x87, 0x35, 0x91, 0x0a, 0xbb, 0xe8, 0xd0, 0xb4, 0xdc, 0xdb, 0x7e, 0x15, 0x8d, 0x75, 0x05, 0x09, 0xc9, 0x90, 0x0c}}, - {{0xa6, 0x1e, 0x1f, 0xb3, 0x18, 0x9d, 0x7e, 0x49, 0xe3, 0xb0, 0xec, 0x1b, 0x39, 0x5e, 0x7a, 0x08, 0x64, 0x8c, 0x44, 0x6a, 0x9c, 0x4d, 0xde, 0xe8, 0xb8, 0x22, 0x85, 0xdf, 0xad, 0x4a, 0x1d, 0x14}, {0x64, 0x3c, 0xae, 0xb7, 0x77, 0x62, 0x15, 0xff, 0x3c, 0xa7, 0x5b, 0x0f, 0x96, 0xb0, 0x55, 0x34, 0x61, 0xe8, 0xf9, 0x04, 0xe3, 0xcf, 0x51, 0x20, 0xd7, 0xd6, 0xe2, 0x52, 0x8b, 0x6f, 0xf8, 0x19}}, - {{0xa4, 0x46, 0x0c, 0xee, 0xac, 0x3c, 0xb2, 0x9e, 0xd6, 0x7c, 0xa7, 0xcb, 0x93, 0xc2, 0x1a, 0xe6, 0xaf, 0x30, 0x07, 0x9c, 0x71, 0x65, 0x0e, 0xc5, 0x26, 0xd9, 0xc9, 0x0d, 0x4f, 0x2c, 0x25, 0x22}, {0x35, 0x43, 0x20, 0x2d, 0x10, 0x8f, 0xee, 0x99, 0xd3, 0x02, 0xf6, 0x3b, 0x54, 0xc1, 0xd9, 0x09, 0x19, 0xc5, 0x64, 0x9e, 0xd0, 0xe3, 0xd7, 0x61, 0xf3, 0xb8, 0x27, 0xc2, 0xbc, 0xb8, 0x3f, 0x1b}}, - {{0x3f, 0xcb, 0x65, 0xdf, 0xea, 0xa4, 0x9e, 0x6b, 0x27, 0xeb, 0x17, 0x67, 0x22, 0xf8, 0xfe, 0xc1, 0x2c, 0x4f, 0xf3, 0xa0, 0x2e, 0xb8, 0x69, 0xfb, 0x4c, 0x6c, 0x2c, 0x92, 0xaf, 0xf3, 0x94, 0x25}, {0xae, 0xa9, 0x21, 0x6a, 0xb7, 0xa2, 0x31, 0xc4, 0xaa, 0x4c, 0x49, 0xa7, 0x4e, 0xfa, 0x4f, 0xba, 0xf9, 0xc4, 0x36, 0xab, 0x08, 0xe3, 0x4d, 0x35, 0x1b, 0x71, 0x78, 0x5d, 0xc7, 0x96, 0x4b, 0x24}}, - {{0x92, 0x51, 0x42, 0x65, 0xc3, 0xed, 0x68, 0x47, 0xfe, 0xfe, 0x47, 0xa3, 0x8a, 0x8e, 0x35, 0x66, 0xce, 0x73, 0xb9, 0xe5, 0xd5, 0xdf, 0xf4, 0xb5, 0x54, 0xf4, 0xbf, 0x25, 0xc5, 0x51, 0x59, 0x1a}, {0x8a, 0xfd, 0xf5, 0x8d, 0x9a, 0x04, 0x01, 0x7e, 0xdd, 0x19, 0xd2, 0x41, 0x90, 0x28, 0x01, 0x6b, 0x12, 0xe0, 0x00, 0xe5, 0x89, 0x3e, 0x44, 0x38, 0x77, 0x6d, 0xf5, 0x4a, 0x34, 0xf2, 0xe0, 0x2b}}, - {{0x3a, 0x21, 0x60, 0x18, 0xfc, 0x74, 0x1e, 0xae, 0x2c, 0xf2, 0x86, 0x28, 0x3a, 0x3c, 0xe4, 0x3f, 0xe1, 0xc1, 0xbe, 0xed, 0x1e, 0x9b, 0xfa, 0xde, 0xaf, 0x5f, 0x9f, 0x4e, 0xb6, 0x5a, 0xbc, 0x31}, {0x13, 0x85, 0x2a, 0x57, 0x96, 0xb1, 0x19, 0xbd, 0xc9, 0xf2, 0x26, 0xf4, 0x9b, 0xe0, 0x72, 0x42, 0xf7, 0xdd, 0x11, 0xae, 0x75, 0xf8, 0x25, 0x99, 0x63, 0x0d, 0xfb, 0x53, 0x9e, 0x5b, 0xb9, 0x1f}}, - {{0x26, 0x73, 0xe8, 0x08, 0x63, 0xa7, 0x36, 0xb2, 0xa3, 0xdc, 0xe8, 0x45, 0x2e, 0xb0, 0x74, 0x89, 0xd8, 0x10, 0x33, 0xff, 0x04, 0xb9, 0x75, 0x05, 0xca, 0xef, 0x04, 0x4f, 0x41, 0xed, 0x47, 0x03}, {0xd8, 0x0a, 0xb5, 0x32, 0x89, 0xfd, 0xeb, 0x18, 0x5d, 0x51, 0xd0, 0x4e, 0x74, 0x55, 0xa2, 0x82, 0x2a, 0x15, 0x77, 0x03, 0xbf, 0xd6, 0x35, 0xb1, 0x80, 0x98, 0x9a, 0xbc, 0xdb, 0xa1, 0x19, 0x34}}, - {{0x00, 0xe4, 0x42, 0x8c, 0x14, 0x07, 0x84, 0x8c, 0x67, 0x83, 0x99, 0x61, 0x72, 0xbd, 0x8a, 0xee, 0xd9, 0x4c, 0x51, 0x5c, 0xe9, 0xc3, 0x4e, 0xfe, 0x07, 0xcf, 0xc8, 0x0b, 0x9a, 0x7f, 0x7d, 0x2b}, {0xd4, 0xdf, 0x68, 0x30, 0x61, 0x7f, 0x8f, 0xe5, 0xd4, 0x7d, 0x92, 0x71, 0x82, 0xd4, 0xc9, 0x31, 0x74, 0xfe, 0x5e, 0xdb, 0x90, 0x1e, 0x9f, 0xa0, 0x46, 0xb5, 0x54, 0x7e, 0x57, 0xf9, 0x12, 0x2e}}, - {{0xc1, 0x14, 0x56, 0xeb, 0xf3, 0xc1, 0x25, 0x3d, 0xdc, 0x5a, 0x91, 0xdb, 0xf0, 0x2f, 0xb0, 0x78, 0xbb, 0x1a, 0x45, 0x47, 0x5a, 0x59, 0xe4, 0x52, 0x62, 0x26, 0x28, 0x5d, 0x2b, 0x81, 0xc0, 0x20}, {0x74, 0x97, 0xff, 0xa3, 0x32, 0xe0, 0x66, 0xc1, 0xc1, 0x5c, 0x7f, 0x88, 0x3f, 0x61, 0x21, 0xbf, 0xb3, 0xac, 0x5a, 0xe4, 0xcc, 0x23, 0x66, 0x66, 0x15, 0x54, 0xae, 0x47, 0x0a, 0x67, 0x8a, 0x1f}}, - {{0xb3, 0x1b, 0x94, 0xb2, 0x98, 0xea, 0x32, 0x0e, 0x4b, 0x17, 0xd0, 0xd5, 0xf6, 0xf5, 0x40, 0x00, 0xa4, 0x65, 0x71, 0x32, 0xe7, 0x87, 0x7c, 0x13, 0x0a, 0xda, 0x9b, 0xf9, 0x65, 0x8c, 0x14, 0x06}, {0xdc, 0x7e, 0x4d, 0xf4, 0x06, 0x5e, 0x48, 0x63, 0xab, 0x07, 0x80, 0xb1, 0xa4, 0x37, 0x2b, 0x3b, 0x6d, 0x3b, 0x23, 0x40, 0x2e, 0x30, 0x96, 0xfe, 0xd1, 0x80, 0xca, 0xef, 0xda, 0x9d, 0x86, 0x0c}}, - {{0xf1, 0x1c, 0xd4, 0x17, 0x3e, 0x30, 0xe3, 0x74, 0xc1, 0xd1, 0x45, 0x89, 0x56, 0x50, 0xb5, 0xb9, 0xee, 0xc8, 0xb0, 0xba, 0xd6, 0xf3, 0xca, 0xf5, 0x16, 0x18, 0xdc, 0xdc, 0xce, 0xc0, 0xaa, 0x20}, {0x76, 0xa8, 0x0c, 0xf8, 0x4b, 0x2a, 0x5b, 0x46, 0x07, 0x49, 0x30, 0xeb, 0xed, 0xde, 0x65, 0x7f, 0xe2, 0x77, 0x38, 0x9f, 0x80, 0xc8, 0x39, 0xcf, 0x3b, 0x74, 0xe5, 0x71, 0x46, 0xa3, 0x86, 0x02}}, - {{0x4b, 0xb0, 0x7f, 0x12, 0x68, 0xa1, 0x50, 0xfb, 0x03, 0xdf, 0xf5, 0x04, 0xe3, 0x01, 0xf8, 0x40, 0xeb, 0x50, 0x59, 0xc9, 0x34, 0xc0, 0xe1, 0xb4, 0x07, 0x5d, 0xf7, 0xca, 0x17, 0x93, 0x26, 0x11}, {0xad, 0x93, 0xbe, 0x71, 0xbd, 0x97, 0xc5, 0x42, 0x4b, 0x2e, 0x7d, 0xf8, 0x27, 0x1b, 0x20, 0xe2, 0x34, 0x69, 0x1c, 0xa8, 0xf5, 0xa2, 0xf2, 0x11, 0xdf, 0xad, 0x5b, 0x1d, 0x53, 0x0d, 0xa7, 0x25}}, - {{0xa4, 0x3f, 0x8d, 0x1d, 0x12, 0xb6, 0xc3, 0x86, 0x5f, 0xf1, 0xa4, 0x0c, 0x83, 0xc7, 0x14, 0x49, 0xec, 0xa7, 0x86, 0xf9, 0xe6, 0x4f, 0xea, 0x04, 0x0c, 0x7b, 0x50, 0x4a, 0x68, 0xf4, 0x26, 0x20}, {0xeb, 0x66, 0x74, 0x79, 0xf3, 0x50, 0x5e, 0x43, 0x33, 0x00, 0x0e, 0xb7, 0xb6, 0x73, 0x5c, 0x8b, 0xbf, 0x18, 0x4a, 0x14, 0xb6, 0x4a, 0xd9, 0x7e, 0x75, 0xd7, 0xa9, 0xff, 0xf0, 0x91, 0x10, 0x2b}}, - {{0xa5, 0x85, 0xf2, 0x15, 0xd6, 0xa5, 0x35, 0x73, 0x53, 0x46, 0x9a, 0x37, 0x55, 0xce, 0xe3, 0x65, 0xf0, 0x2a, 0x76, 0xcc, 0x4a, 0xed, 0x9c, 0xc5, 0x76, 0x7f, 0x46, 0x60, 0x2c, 0x7a, 0x29, 0x04}, {0x57, 0x62, 0x86, 0x02, 0x3f, 0xec, 0xf3, 0x38, 0xc0, 0xa5, 0x9e, 0xa4, 0x10, 0xf0, 0x13, 0x1e, 0xec, 0x2e, 0xca, 0x06, 0xbb, 0xe8, 0xf1, 0xda, 0x2d, 0x92, 0x5a, 0x9b, 0xdb, 0x3d, 0x9d, 0x32}}, - {{0x88, 0x1b, 0x3b, 0x11, 0xf0, 0xe7, 0x0a, 0x40, 0xd9, 0x0e, 0x9f, 0x72, 0x5a, 0xdd, 0x05, 0x65, 0xc8, 0xb4, 0x61, 0x82, 0xa6, 0x81, 0x6d, 0xf4, 0x20, 0x38, 0x87, 0xe8, 0x90, 0x84, 0x50, 0x24}, {0x21, 0x86, 0xea, 0x7f, 0x5b, 0x1e, 0xb8, 0x35, 0x86, 0x6a, 0x06, 0x5e, 0xbd, 0x93, 0xb1, 0x9a, 0xc3, 0x8f, 0x66, 0xd2, 0xf1, 0x12, 0x92, 0x86, 0x1e, 0x0d, 0x54, 0x2b, 0x70, 0xd0, 0xea, 0x15}}, - {{0xda, 0x66, 0x2e, 0xf4, 0x6a, 0x8b, 0x8c, 0x95, 0xf5, 0xd6, 0x14, 0x1c, 0x1f, 0x95, 0xcd, 0xdf, 0x0a, 0xf3, 0x54, 0x6f, 0xdc, 0x07, 0xbc, 0xb5, 0xda, 0x56, 0x16, 0x70, 0x49, 0xd6, 0x82, 0x1d}, {0xf9, 0x01, 0x6e, 0xa3, 0xe3, 0xa7, 0xbe, 0x05, 0xbe, 0x47, 0x18, 0x46, 0x6c, 0xd9, 0xab, 0x77, 0xf3, 0x5f, 0x67, 0x97, 0xd3, 0x16, 0xb5, 0xa7, 0xbe, 0xe4, 0x3c, 0xcc, 0x76, 0x5e, 0x85, 0x17}}, - {{0x5a, 0x5f, 0xfb, 0xb4, 0x0a, 0x31, 0x0a, 0xfd, 0x6f, 0xbb, 0x18, 0x46, 0xc2, 0xe1, 0x5f, 0xd0, 0x84, 0xe3, 0x3d, 0x01, 0x67, 0xe0, 0x41, 0x57, 0xf1, 0x4b, 0x9c, 0x87, 0xd6, 0x0e, 0x73, 0x23}, {0x16, 0x5d, 0x4c, 0xb9, 0xbc, 0xf7, 0x9f, 0x7e, 0x96, 0xfd, 0x76, 0x9f, 0xb3, 0x56, 0x5e, 0xd7, 0x0f, 0xea, 0x6d, 0x25, 0xb1, 0x35, 0x62, 0x55, 0x6d, 0x05, 0x08, 0x4f, 0xbe, 0x11, 0xcd, 0x3e}}, - {{0xa6, 0x8c, 0xb7, 0xd2, 0x38, 0x44, 0x04, 0x3d, 0xb0, 0xdc, 0xf3, 0x51, 0x14, 0xdb, 0x79, 0xa6, 0x15, 0xbb, 0xb2, 0xa2, 0x6c, 0x16, 0x2b, 0x92, 0x8a, 0x77, 0x3d, 0x6e, 0x35, 0x38, 0x07, 0x11}, {0xe2, 0xb7, 0x3e, 0xd6, 0x5d, 0xa4, 0xce, 0x95, 0x26, 0xd5, 0x26, 0xe6, 0x17, 0xc6, 0xf0, 0x2a, 0x5d, 0xd9, 0x31, 0x91, 0x37, 0x35, 0x55, 0x9d, 0x77, 0x3a, 0x99, 0x6b, 0x1a, 0x16, 0x84, 0x0d}}, - {{0x91, 0x51, 0x61, 0xf1, 0xc2, 0x74, 0xf8, 0x4d, 0xf4, 0x1f, 0x43, 0x08, 0x9a, 0x0d, 0x97, 0xd2, 0x89, 0xf8, 0x5d, 0x52, 0x9b, 0x4b, 0xc1, 0x66, 0x9a, 0xed, 0x22, 0x8a, 0x77, 0x8a, 0x83, 0x3b}, {0xae, 0xca, 0xcb, 0x06, 0x21, 0x96, 0x86, 0x67, 0x2b, 0xf6, 0x3f, 0x43, 0x98, 0x0b, 0xf2, 0x83, 0x0e, 0x97, 0x11, 0x4d, 0xa9, 0xc2, 0x05, 0xff, 0x4c, 0x89, 0x6c, 0x59, 0x0c, 0x3f, 0xdb, 0x32}}, - {{0xb4, 0x95, 0xb7, 0xc5, 0x17, 0x6b, 0xd2, 0x18, 0x6b, 0x3d, 0xdf, 0x31, 0x4c, 0x01, 0x97, 0x50, 0x47, 0x6f, 0xa3, 0xa9, 0xb7, 0x54, 0xbc, 0xc1, 0xa4, 0x2c, 0x52, 0x42, 0x49, 0x01, 0x3f, 0x00}, {0x5d, 0x2b, 0x71, 0x68, 0x73, 0x17, 0x04, 0xe7, 0xd0, 0x6e, 0x25, 0x14, 0x17, 0x3a, 0x2a, 0x01, 0xba, 0x4d, 0xc8, 0xda, 0xe1, 0x6a, 0x0f, 0x75, 0xec, 0xdc, 0xa9, 0x0d, 0xac, 0xe6, 0xfa, 0x39}}, - {{0x17, 0x30, 0x96, 0xc1, 0x4f, 0xfc, 0x22, 0x00, 0xf2, 0xa6, 0x5a, 0xb7, 0x91, 0xa8, 0x6d, 0x6e, 0x41, 0x84, 0xc7, 0xd9, 0x60, 0xaa, 0x65, 0x8e, 0xa8, 0x9f, 0x1a, 0x18, 0x81, 0xf1, 0xf0, 0x2f}, {0xf3, 0x74, 0xa0, 0xea, 0x6a, 0x64, 0xea, 0x08, 0x00, 0xbe, 0xbb, 0x01, 0xca, 0x09, 0x93, 0xe8, 0x64, 0x24, 0xf7, 0x55, 0x36, 0xc9, 0x21, 0x00, 0x4f, 0xaf, 0x8c, 0xb3, 0xdc, 0x5f, 0x6f, 0x2e}}, - {{0x01, 0xc5, 0x84, 0x57, 0xd6, 0x57, 0xbf, 0x99, 0x2c, 0xb5, 0x8e, 0x7c, 0x72, 0xbd, 0x17, 0x70, 0x5d, 0x8f, 0x32, 0x2d, 0x1c, 0xd3, 0x19, 0xe9, 0xb7, 0x2f, 0xf5, 0xaa, 0xaf, 0x43, 0xcd, 0x0b}, {0xa8, 0xe2, 0xd4, 0xc3, 0xa3, 0x5b, 0xd0, 0x60, 0xd2, 0x02, 0x52, 0xdf, 0xf0, 0x39, 0xa1, 0x03, 0x81, 0x94, 0xe1, 0x21, 0x6e, 0x8a, 0xc8, 0xe5, 0xa5, 0x9b, 0x52, 0x1d, 0xa4, 0xd0, 0x4a, 0x38}}, - {{0xfb, 0xc3, 0x3b, 0x69, 0x53, 0x11, 0x1f, 0xac, 0x64, 0x08, 0xf8, 0x26, 0x54, 0x3d, 0xcb, 0x95, 0xa7, 0x17, 0xc2, 0x91, 0x1f, 0x53, 0xc9, 0xac, 0xd6, 0xba, 0x62, 0x2b, 0xab, 0x65, 0xa0, 0x37}, {0x98, 0xcc, 0x28, 0xd7, 0x33, 0x28, 0x56, 0x25, 0x86, 0x7a, 0xdc, 0x6b, 0xe3, 0x5f, 0x7a, 0x15, 0x96, 0x6e, 0x03, 0x17, 0xbe, 0xfa, 0xa9, 0x45, 0xfb, 0x6e, 0x84, 0x3e, 0x9a, 0x2e, 0xa6, 0x15}}, - {{0x7e, 0x7d, 0xb5, 0x60, 0x66, 0x09, 0xeb, 0x84, 0xb6, 0x69, 0x9f, 0x68, 0x83, 0xc1, 0xb3, 0xbc, 0x8d, 0x7a, 0xa2, 0x1a, 0x0c, 0x6b, 0x79, 0xc1, 0xe3, 0x73, 0x77, 0x6b, 0xb0, 0x12, 0x47, 0x1f}, {0x66, 0x6f, 0xc4, 0xf3, 0x0a, 0xa1, 0x00, 0x2e, 0x1e, 0xe3, 0x58, 0x49, 0xa4, 0xd9, 0xd2, 0xd4, 0x6a, 0x6e, 0x8c, 0x9f, 0xf9, 0xc9, 0xe5, 0xaa, 0xaa, 0xc3, 0x4a, 0x6c, 0x9c, 0x5c, 0xfb, 0x0f}}, - {{0x32, 0x60, 0xaa, 0xe6, 0x7c, 0x42, 0xdf, 0xeb, 0x3a, 0xcc, 0x8f, 0x88, 0xb0, 0xd8, 0x84, 0x22, 0x8d, 0xfe, 0xf2, 0x83, 0x66, 0x81, 0x9c, 0x3f, 0xb0, 0xd2, 0x62, 0x18, 0xd2, 0xc3, 0xe0, 0x3b}, {0x82, 0x03, 0x25, 0x78, 0xe3, 0x4f, 0x68, 0xd0, 0x8f, 0x53, 0x3b, 0x56, 0xcf, 0x85, 0xa3, 0x29, 0x61, 0x91, 0xb0, 0x07, 0xc9, 0x2a, 0x01, 0xb4, 0x16, 0x06, 0x26, 0x5f, 0xbe, 0xfa, 0xe4, 0x3f}}, - {{0x9a, 0xc2, 0x4d, 0x8d, 0xa7, 0x86, 0xc2, 0x0b, 0x72, 0x7c, 0xcb, 0x57, 0xc0, 0xba, 0x08, 0xa8, 0xcd, 0xd6, 0xad, 0xe7, 0x13, 0xe2, 0x71, 0x1e, 0x11, 0x0b, 0x96, 0x95, 0x7c, 0x98, 0x6b, 0x3d}, {0x5a, 0x47, 0x1d, 0x7e, 0xd3, 0xcd, 0xac, 0xe4, 0x7c, 0xe9, 0x9a, 0x8e, 0xb2, 0xaf, 0xb1, 0xe6, 0x1b, 0x77, 0x38, 0xdc, 0x42, 0x79, 0x3c, 0xb4, 0x1d, 0x58, 0x76, 0x5b, 0x2c, 0x62, 0x9f, 0x0a}}, - {{0x0d, 0xd2, 0x15, 0xd3, 0x37, 0x1c, 0x6d, 0x34, 0x32, 0x22, 0x59, 0x97, 0xb6, 0x33, 0x90, 0x2f, 0x03, 0xfd, 0x46, 0xc4, 0x95, 0x99, 0xfa, 0x19, 0x42, 0xfc, 0x67, 0xb3, 0xfa, 0xa5, 0x97, 0x0e}, {0x80, 0x3a, 0x47, 0x7b, 0x58, 0x78, 0xf9, 0xa4, 0xcc, 0x9b, 0x48, 0x58, 0xcf, 0x72, 0x3a, 0x5c, 0x99, 0xa2, 0x21, 0x24, 0xe4, 0x72, 0x2b, 0x81, 0xf7, 0xbe, 0x6d, 0x41, 0xab, 0x99, 0x11, 0x2b}}, - {{0x48, 0x4e, 0x3a, 0xb7, 0xb3, 0xf1, 0x07, 0x5e, 0x83, 0x6b, 0x8f, 0x6f, 0x5f, 0x92, 0xb0, 0x19, 0xb2, 0x9c, 0x9a, 0x7f, 0xcc, 0xc5, 0x98, 0xcf, 0x17, 0x16, 0x39, 0x9b, 0x41, 0x0d, 0x1a, 0x0f}, {0xec, 0xfd, 0x90, 0xf0, 0x3e, 0xc8, 0x2f, 0x63, 0x60, 0xd6, 0x8e, 0xa1, 0x5b, 0x0e, 0x3c, 0x2f, 0xbf, 0xca, 0xe7, 0x46, 0x80, 0xd8, 0x90, 0xce, 0x59, 0xea, 0x2e, 0xa4, 0x0b, 0xfd, 0xad, 0x0c}}, - {{0x23, 0x50, 0xab, 0x76, 0x74, 0xcf, 0x8c, 0x23, 0x35, 0x00, 0x1b, 0xfb, 0x8a, 0x88, 0x4a, 0x07, 0xee, 0xec, 0xeb, 0xef, 0xe8, 0x56, 0x63, 0x37, 0x54, 0xdb, 0x51, 0x44, 0x97, 0x1e, 0x3e, 0x20}, {0xb7, 0xd1, 0x57, 0xd8, 0xcc, 0xa8, 0x5f, 0x20, 0x84, 0x72, 0x4f, 0x27, 0x9b, 0x37, 0x71, 0xa2, 0xfc, 0xd8, 0x2f, 0x53, 0x66, 0x8f, 0x47, 0x3d, 0x71, 0xe7, 0xb9, 0x56, 0xbe, 0x88, 0x66, 0x13}}, - {{0x6f, 0x74, 0x1c, 0xbb, 0x3d, 0xb5, 0x08, 0x2b, 0xf9, 0x59, 0x0e, 0x13, 0x32, 0x63, 0xd6, 0xde, 0xb3, 0x11, 0x0f, 0x89, 0x70, 0x7d, 0x3e, 0xec, 0x71, 0xa5, 0x57, 0x05, 0x94, 0x83, 0x0b, 0x07}, {0xbc, 0xfe, 0x6c, 0x00, 0x85, 0x2c, 0x20, 0x93, 0x4d, 0x5b, 0xc6, 0x3f, 0x93, 0x36, 0x9f, 0x67, 0xe1, 0x06, 0x2a, 0x0d, 0x30, 0xf0, 0x12, 0xea, 0x2c, 0x79, 0x2f, 0x80, 0x23, 0x47, 0x11, 0x2e}}, - {{0x47, 0xe2, 0x67, 0x2e, 0x5c, 0xe8, 0x6f, 0x35, 0x6d, 0x5f, 0x00, 0xa3, 0x5e, 0x77, 0x0d, 0x1d, 0x6c, 0xc1, 0xd0, 0xbb, 0xc6, 0x64, 0xf8, 0x80, 0xf0, 0xe9, 0x4e, 0x11, 0xa0, 0xed, 0x7a, 0x31}, {0x55, 0x04, 0xfc, 0x4b, 0x89, 0x45, 0xa6, 0xcd, 0x1f, 0x3c, 0x88, 0xac, 0x76, 0x3a, 0xfc, 0xf9, 0xec, 0x28, 0x8d, 0x79, 0x08, 0xa2, 0xf6, 0x61, 0x49, 0x9b, 0xc2, 0xa8, 0xe9, 0x1b, 0x02, 0x2c}}, - {{0x89, 0xbe, 0xc5, 0xf5, 0x37, 0xa1, 0x7a, 0x71, 0x5b, 0x98, 0x02, 0x31, 0x59, 0x53, 0x28, 0x90, 0x50, 0x07, 0x5a, 0x2c, 0x33, 0x0b, 0xfc, 0x4f, 0x53, 0x3a, 0x84, 0xed, 0x9c, 0x2c, 0x94, 0x24}, {0xa7, 0x4f, 0xae, 0x0c, 0x8d, 0x19, 0xdb, 0xfb, 0x29, 0xae, 0x9f, 0x33, 0x66, 0xd6, 0x1e, 0x30, 0xc1, 0x54, 0x1f, 0x35, 0x1b, 0x27, 0xdb, 0xe8, 0xda, 0x48, 0x0c, 0xe4, 0x1d, 0xb8, 0xc6, 0x1e}}, - {{0xe3, 0x61, 0x49, 0x71, 0xb9, 0xff, 0xad, 0x1f, 0xeb, 0x6f, 0xe4, 0x04, 0x27, 0x39, 0x76, 0xa1, 0x8d, 0x03, 0x91, 0x20, 0xf8, 0x89, 0x5d, 0x33, 0x4a, 0x03, 0x8a, 0xb6, 0xa5, 0x0d, 0x56, 0x05}, {0x29, 0x31, 0xef, 0x15, 0x61, 0xa0, 0xbc, 0x7c, 0x8d, 0x00, 0x9c, 0xdb, 0x8d, 0xe0, 0x19, 0x8e, 0xfb, 0x36, 0xa1, 0xb7, 0xb6, 0xab, 0x45, 0xa7, 0x45, 0x55, 0xde, 0x6b, 0x07, 0xb7, 0xcc, 0x2c}}, - {{0x40, 0x1b, 0x88, 0x6f, 0x9c, 0xc5, 0xba, 0x66, 0x6c, 0xf9, 0xc5, 0x51, 0x86, 0x1f, 0x9b, 0xae, 0xe1, 0x52, 0xdc, 0x9b, 0x00, 0x7e, 0x8e, 0x68, 0x33, 0xd7, 0x2e, 0x84, 0x0e, 0x38, 0xe4, 0x27}, {0xdb, 0x78, 0x8d, 0x61, 0xf3, 0x47, 0xe8, 0x1b, 0x7f, 0xf5, 0x8b, 0x6c, 0x3d, 0xc6, 0xf1, 0xcb, 0xdc, 0x91, 0x9f, 0xa3, 0x48, 0x3b, 0xcb, 0x62, 0x52, 0x85, 0x84, 0x0b, 0x2b, 0x7d, 0xed, 0x0c}}, - {{0xae, 0x9d, 0xb1, 0xd3, 0x47, 0xed, 0xc3, 0x2b, 0x80, 0x68, 0xdf, 0x2b, 0x5c, 0x23, 0x29, 0x79, 0xae, 0xde, 0x23, 0x4d, 0x66, 0x71, 0xc8, 0x4e, 0x47, 0x96, 0x92, 0xd7, 0x29, 0xbf, 0x6a, 0x02}, {0x96, 0x6b, 0x62, 0x52, 0x4b, 0x20, 0x51, 0x89, 0xd2, 0xfa, 0x72, 0xc6, 0xc7, 0x29, 0xba, 0x15, 0x4c, 0x13, 0x80, 0xa4, 0xa7, 0x9b, 0x49, 0x0d, 0xce, 0x65, 0x54, 0x4d, 0xb1, 0xdf, 0x7c, 0x39}}, -}; diff --git a/deps/crypto/trezor-crypto/pallas_swu.c b/deps/crypto/trezor-crypto/pallas_swu.c deleted file mode 100644 index 7a4fa43d7..000000000 --- a/deps/crypto/trezor-crypto/pallas_swu.c +++ /dev/null @@ -1,712 +0,0 @@ -/** - * Copyright (c) 2026 KeepKey - * - * Pallas simplified SWU, iso-Pallas isogeny, and hash-to-curve primitives. - * - * This follows pasta_curves 0.5.1: - * hash_to_field("pallas", domain, msg) - * map_to_curve_simple_swu:: - * iso_map:: - */ - -#include "pallas_swu.h" - -#include - -#include "memzero.h" -#include "pallas.h" - -typedef pallas_jacobian_point iso_point; - -static const uint8_t TWO_256_MOD_P[32] = { - 0xfd, 0xff, 0xff, 0xff, 0x38, 0x6d, 0x78, 0x34, - 0xad, 0x14, 0x19, 0xe4, 0x0b, 0x35, 0x2c, 0x99, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, -}; - -static const uint64_t ISO_A_RAW[4] = { - UINT64_C(0x92bb4b0b657a014b), - UINT64_C(0xb74134581a27a59f), - UINT64_C(0x49be2d7258370742), - UINT64_C(0x18354a2eb0ea8c9c), -}; - -static const uint64_t ISO_B_RAW[4] = { - UINT64_C(1265), - UINT64_C(0), - UINT64_C(0), - UINT64_C(0), -}; - -static const uint64_t PALLAS_Z_RAW[4] = { - UINT64_C(0x992d30ecfffffff4), - UINT64_C(0x224698fc094cf91b), - UINT64_C(0x0000000000000000), - UINT64_C(0x4000000000000000), -}; - -static const uint64_t PALLAS_THETA_RAW[4] = { - UINT64_C(0xca330bcc09ac318e), - UINT64_C(0x51f64fc4dc888857), - UINT64_C(0x4647aef782d5cdc8), - UINT64_C(0x0f7bdb65814179b4), -}; - -static const uint64_t PALLAS_ROOT_OF_UNITY_RAW[4] = { - UINT64_C(0xbdad6fabd87ea32f), - UINT64_C(0xea322bf2b7bb7584), - UINT64_C(0x362120830561f81a), - UINT64_C(0x2bce74deac30ebda), -}; - -static const uint64_t ISOGENY_RAW[13][4] = { - {UINT64_C(0x775f6034aaaaaaab), UINT64_C(0x4081775473d8375b), - UINT64_C(0xe38e38e38e38e38e), UINT64_C(0x0e38e38e38e38e38)}, - {UINT64_C(0x08cf863b02814fb76), UINT64_C(0x0f93b82ee4b99495), - UINT64_C(0x267c7ffa51cf412a), UINT64_C(0x3509afd51872d88e)}, - {UINT64_C(0x0eb64faef37ea4f7), UINT64_C(0x380af066cfeb6d69), - UINT64_C(0x98c7d7ac3d98fd13), UINT64_C(0x17329b9ec5253753)}, - {UINT64_C(0xeebec06955555580), UINT64_C(0x8102eea8e7b06eb6), - UINT64_C(0xc71c71c71c71c71c), UINT64_C(0x1c71c71c71c71c71)}, - {UINT64_C(0xc47f2ab668bcd71f), UINT64_C(0x9c434ac1c96b6980), - UINT64_C(0x5a607fcce0494a79), UINT64_C(0x1d572e7ddc099cff)}, - {UINT64_C(0x2aa3af1eae5b6604), UINT64_C(0xb4abf9fb9a1fc81c), - UINT64_C(0x1d13bf2a7f22b105), UINT64_C(0x325669becaecd5d1)}, - {UINT64_C(0x5ad985b5e38e38e4), UINT64_C(0x7642b01ad461bad2), - UINT64_C(0x4bda12f684bda12f), UINT64_C(0x1a12f684bda12f68)}, - {UINT64_C(0xc67c31d8140a7dbb), UINT64_C(0x07c9dc17725cca4a), - UINT64_C(0x133e3ffd28e7a095), UINT64_C(0x1a84d7ea8c396c47)}, - {UINT64_C(0x02e2be87d225b234), UINT64_C(0x1765e924f7459378), - UINT64_C(0x303216cce1db9ff1), UINT64_C(0x3fb98ff0d2ddcadd)}, - {UINT64_C(0x93e53ab371c71c4f), UINT64_C(0x0ac03e8e134eb3e4), - UINT64_C(0x7b425ed097b425ed), UINT64_C(0x025ed097b425ed09)}, - {UINT64_C(0x5a28279b1d1b42ae), UINT64_C(0x5941a3a4a97aa1b3), - UINT64_C(0x0790bfb3506defb6), UINT64_C(0x0c02c5bcca0e6b7f)}, - {UINT64_C(0x4d90ab820b12320a), UINT64_C(0xd976bbfabbc5661d), - UINT64_C(0x573b3d7f7d681310), UINT64_C(0x17033d3c60c68173)}, - {UINT64_C(0x992d30ecfffffde5), UINT64_C(0x224698fc094cf91b), - UINT64_C(0x0000000000000000), UINT64_C(0x4000000000000000)}, -}; - -static void fp_from_raw_u64(const uint64_t raw[4], bignum256 *out) { - uint8_t le[32]; - for (int i = 0; i < 4; i++) { - uint64_t v = raw[i]; - for (int j = 0; j < 8; j++) { - le[i * 8 + j] = (uint8_t)(v & 0xff); - v >>= 8; - } - } - bn_read_le(le, out); - pallas_mod_p(out); - memzero(le, sizeof(le)); -} - -static void fp_from_u32(uint32_t v, bignum256 *out) { - bn_zero(out); - out->val[0] = v; - pallas_mod_p(out); -} - -static void fp_one(bignum256 *out) { fp_from_u32(1, out); } - -static int fp_is_zero(const bignum256 *a) { return bn_is_zero(a); } - -static int fp_is_equal(const bignum256 *a, const bignum256 *b) { - bignum256 aa, bb; - bn_copy(a, &aa); - bn_copy(b, &bb); - bn_normalize(&aa); - bn_normalize(&bb); - return bn_is_equal(&aa, &bb); -} - -static void fp_add(const bignum256 *a, const bignum256 *b, bignum256 *out) { - pallas_add_mod_p(a, b, out); -} - -static void fp_sub(const bignum256 *a, const bignum256 *b, bignum256 *out) { - pallas_sub_mod_p(a, b, out); -} - -static void fp_neg(const bignum256 *a, bignum256 *out) { - if (bn_is_zero(a)) { - bn_zero(out); - } else { - pallas_sub_mod_p(&pallas_prime, a, out); - } -} - -static void fp_mul(const bignum256 *a, const bignum256 *b, bignum256 *out) { - bignum256 aa, bb; - bn_copy(a, &aa); - bn_copy(b, &bb); - pallas_mul_mod_p(&aa, &bb); - bn_copy(&aa, out); - memzero(&aa, sizeof(aa)); - memzero(&bb, sizeof(bb)); -} - -static void fp_square(const bignum256 *a, bignum256 *out) { - fp_mul(a, a, out); -} - -static void fp_double(const bignum256 *a, bignum256 *out) { - fp_add(a, a, out); -} - -static void fp_inv0(const bignum256 *a, bignum256 *out) { - if (bn_is_zero(a)) { - bn_zero(out); - } else { - bn_copy(a, out); - pallas_inv_mod_p(out); - } -} - -static int fp_sqrt_ratio(const bignum256 *num, const bignum256 *div, - bignum256 *out) { - bignum256 inv_div, a, candidate; - - if (bn_is_zero(div)) { - bn_zero(out); - return bn_is_zero(num); - } - - fp_inv0(div, &inv_div); - fp_mul(num, &inv_div, &a); - - bn_copy(&a, &candidate); - if (pallas_sqrt_mod_p(&candidate) == 0) { - bn_copy(&candidate, out); - memzero(&inv_div, sizeof(inv_div)); - memzero(&a, sizeof(a)); - memzero(&candidate, sizeof(candidate)); - return 1; - } - - bignum256 root_of_unity; - fp_from_raw_u64(PALLAS_ROOT_OF_UNITY_RAW, &root_of_unity); - fp_mul(&a, &root_of_unity, &candidate); - if (pallas_sqrt_mod_p(&candidate) == 0) { - bn_copy(&candidate, out); - } else { - bn_zero(out); - } - - memzero(&inv_div, sizeof(inv_div)); - memzero(&a, sizeof(a)); - memzero(&candidate, sizeof(candidate)); - memzero(&root_of_unity, sizeof(root_of_unity)); - return 0; -} - -static void fp_from_uniform64(const uint8_t in[64], bignum256 *out) { - bignum256 lo, hi, two_256, tmp; - - bn_read_le(in, &lo); - pallas_mod_p(&lo); - - bn_read_le(in + 32, &hi); - pallas_mod_p(&hi); - - bn_read_le(TWO_256_MOD_P, &two_256); - - bn_copy(&hi, &tmp); - pallas_mul_mod_p(&tmp, &two_256); - pallas_add_mod_p(&tmp, &lo, out); - - memzero(&lo, sizeof(lo)); - memzero(&hi, sizeof(hi)); - memzero(&two_256, sizeof(two_256)); - memzero(&tmp, sizeof(tmp)); -} - -static int iso_is_identity(const iso_point *p) { - return !p || bn_is_zero(&p->z); -} - -static void iso_set_identity(iso_point *p) { - bn_zero(&p->x); - bn_zero(&p->y); - bn_zero(&p->z); -} - -static int iso_is_on_curve(const iso_point *p) { - if (iso_is_identity(p)) return 1; - - bignum256 a, b, y2, x2, x3, z2, z4, z6, axz4, bz6, rhs, tmp; - fp_from_raw_u64(ISO_A_RAW, &a); - fp_from_raw_u64(ISO_B_RAW, &b); - - fp_square(&p->y, &y2); - fp_square(&p->x, &x2); - fp_mul(&x2, &p->x, &x3); - fp_square(&p->z, &z2); - fp_square(&z2, &z4); - fp_mul(&z4, &z2, &z6); - fp_mul(&a, &p->x, &axz4); - fp_mul(&axz4, &z4, &axz4); - fp_mul(&b, &z6, &bz6); - fp_add(&x3, &axz4, &tmp); - fp_add(&tmp, &bz6, &rhs); - - int ok = fp_is_equal(&y2, &rhs); - memzero(&a, sizeof(a)); - memzero(&b, sizeof(b)); - memzero(&y2, sizeof(y2)); - memzero(&x2, sizeof(x2)); - memzero(&x3, sizeof(x3)); - memzero(&z2, sizeof(z2)); - memzero(&z4, sizeof(z4)); - memzero(&z6, sizeof(z6)); - memzero(&axz4, sizeof(axz4)); - memzero(&bz6, sizeof(bz6)); - memzero(&rhs, sizeof(rhs)); - memzero(&tmp, sizeof(tmp)); - return ok; -} - -static void iso_double(const iso_point *p, iso_point *out) { - if (iso_is_identity(p)) { - iso_set_identity(out); - return; - } - - bignum256 curve_a; - fp_from_raw_u64(ISO_A_RAW, &curve_a); - - bignum256 xx, yy, yyyy, zz, s, m, x3, y3, z3, tmp1, tmp2; - fp_square(&p->x, &xx); - fp_square(&p->y, &yy); - fp_square(&yy, &yyyy); - fp_square(&p->z, &zz); - - fp_add(&p->x, &yy, &tmp1); - fp_square(&tmp1, &tmp1); - fp_sub(&tmp1, &xx, &tmp1); - fp_sub(&tmp1, &yyyy, &tmp1); - fp_double(&tmp1, &s); - - fp_double(&xx, &tmp1); - fp_add(&tmp1, &xx, &m); - fp_square(&zz, &tmp1); - fp_mul(&curve_a, &tmp1, &tmp1); - fp_add(&m, &tmp1, &m); - - fp_square(&m, &x3); - fp_double(&s, &tmp1); - fp_sub(&x3, &tmp1, &x3); - - fp_sub(&s, &x3, &tmp1); - fp_mul(&m, &tmp1, &y3); - fp_double(&yyyy, &tmp2); - fp_double(&tmp2, &tmp2); - fp_double(&tmp2, &tmp2); - fp_sub(&y3, &tmp2, &y3); - - fp_add(&p->y, &p->z, &z3); - fp_square(&z3, &z3); - fp_sub(&z3, &yy, &z3); - fp_sub(&z3, &zz, &z3); - - bn_copy(&x3, &out->x); - bn_copy(&y3, &out->y); - bn_copy(&z3, &out->z); - - memzero(&curve_a, sizeof(curve_a)); - memzero(&xx, sizeof(xx)); - memzero(&yy, sizeof(yy)); - memzero(&yyyy, sizeof(yyyy)); - memzero(&zz, sizeof(zz)); - memzero(&s, sizeof(s)); - memzero(&m, sizeof(m)); - memzero(&x3, sizeof(x3)); - memzero(&y3, sizeof(y3)); - memzero(&z3, sizeof(z3)); - memzero(&tmp1, sizeof(tmp1)); - memzero(&tmp2, sizeof(tmp2)); -} - -static void iso_add(const iso_point *p, const iso_point *q, iso_point *out) { - if (iso_is_identity(p)) { - *out = *q; - return; - } - if (iso_is_identity(q)) { - *out = *p; - return; - } - - bignum256 z1z1, z2z2, u1, u2, s1, s2, h, i, j, r, v; - bignum256 x3, y3, z3; - - fp_square(&p->z, &z1z1); - fp_square(&q->z, &z2z2); - fp_mul(&p->x, &z2z2, &u1); - fp_mul(&q->x, &z1z1, &u2); - fp_mul(&p->y, &z2z2, &s1); - fp_mul(&s1, &q->z, &s1); - fp_mul(&q->y, &z1z1, &s2); - fp_mul(&s2, &p->z, &s2); - - if (fp_is_equal(&u1, &u2)) { - if (fp_is_equal(&s1, &s2)) { - iso_double(p, out); - } else { - iso_set_identity(out); - } - return; - } - - fp_sub(&u2, &u1, &h); - fp_double(&h, &i); - fp_square(&i, &i); - fp_mul(&h, &i, &j); - fp_sub(&s2, &s1, &r); - fp_double(&r, &r); - fp_mul(&u1, &i, &v); - - fp_square(&r, &x3); - fp_sub(&x3, &j, &x3); - fp_sub(&x3, &v, &x3); - fp_sub(&x3, &v, &x3); - - fp_mul(&s1, &j, &s1); - fp_double(&s1, &s1); - fp_sub(&v, &x3, &y3); - fp_mul(&r, &y3, &y3); - fp_sub(&y3, &s1, &y3); - - fp_add(&p->z, &q->z, &z3); - fp_square(&z3, &z3); - fp_sub(&z3, &z1z1, &z3); - fp_sub(&z3, &z2z2, &z3); - fp_mul(&z3, &h, &z3); - - bn_copy(&x3, &out->x); - bn_copy(&y3, &out->y); - bn_copy(&z3, &out->z); - - memzero(&z1z1, sizeof(z1z1)); - memzero(&z2z2, sizeof(z2z2)); - memzero(&u1, sizeof(u1)); - memzero(&u2, sizeof(u2)); - memzero(&s1, sizeof(s1)); - memzero(&s2, sizeof(s2)); - memzero(&h, sizeof(h)); - memzero(&i, sizeof(i)); - memzero(&j, sizeof(j)); - memzero(&r, sizeof(r)); - memzero(&v, sizeof(v)); - memzero(&x3, sizeof(x3)); - memzero(&y3, sizeof(y3)); - memzero(&z3, sizeof(z3)); -} - -int pallas_map_to_curve_simple_swu(const uint8_t u_le[32], - pallas_jacobian_point *out) { - if (!u_le || !out) return -1; - - bignum256 u, a, b, z, theta, one; - bignum256 u2, z_u2, ta, num_x1, div, num2_x1, div2, div3; - bignum256 num_gx1, num_x2, y1, y2, num_x, y, tmp1, tmp2; - - bn_read_le(u_le, &u); - pallas_mod_p(&u); - fp_from_raw_u64(ISO_A_RAW, &a); - fp_from_raw_u64(ISO_B_RAW, &b); - fp_from_raw_u64(PALLAS_Z_RAW, &z); - fp_from_raw_u64(PALLAS_THETA_RAW, &theta); - fp_one(&one); - - fp_square(&u, &u2); - fp_mul(&z, &u2, &z_u2); - fp_square(&z_u2, &ta); - fp_add(&ta, &z_u2, &ta); - - fp_add(&ta, &one, &tmp1); - fp_mul(&b, &tmp1, &num_x1); - - if (fp_is_zero(&ta)) { - bn_copy(&z, &tmp1); - } else { - fp_neg(&ta, &tmp1); - } - fp_mul(&a, &tmp1, &div); - - fp_square(&num_x1, &num2_x1); - fp_square(&div, &div2); - fp_mul(&div2, &div, &div3); - fp_mul(&a, &div2, &tmp1); - fp_add(&num2_x1, &tmp1, &tmp1); - fp_mul(&tmp1, &num_x1, &tmp1); - fp_mul(&b, &div3, &tmp2); - fp_add(&tmp1, &tmp2, &num_gx1); - - fp_mul(&z_u2, &num_x1, &num_x2); - - int gx1_square = fp_sqrt_ratio(&num_gx1, &div3, &y1); - - fp_mul(&theta, &z_u2, &y2); - fp_mul(&y2, &u, &y2); - fp_mul(&y2, &y1, &y2); - - if (gx1_square) { - bn_copy(&num_x1, &num_x); - bn_copy(&y1, &y); - } else { - bn_copy(&num_x2, &num_x); - bn_copy(&y2, &y); - } - - if (bn_is_odd(&u) != bn_is_odd(&y)) { - fp_neg(&y, &y); - } - - fp_mul(&num_x, &div, &out->x); - fp_mul(&y, &div3, &out->y); - bn_copy(&div, &out->z); - - int ok = iso_is_on_curve(out); - - memzero(&u, sizeof(u)); - memzero(&a, sizeof(a)); - memzero(&b, sizeof(b)); - memzero(&z, sizeof(z)); - memzero(&theta, sizeof(theta)); - memzero(&one, sizeof(one)); - memzero(&u2, sizeof(u2)); - memzero(&z_u2, sizeof(z_u2)); - memzero(&ta, sizeof(ta)); - memzero(&num_x1, sizeof(num_x1)); - memzero(&div, sizeof(div)); - memzero(&num2_x1, sizeof(num2_x1)); - memzero(&div2, sizeof(div2)); - memzero(&div3, sizeof(div3)); - memzero(&num_gx1, sizeof(num_gx1)); - memzero(&num_x2, sizeof(num_x2)); - memzero(&y1, sizeof(y1)); - memzero(&y2, sizeof(y2)); - memzero(&num_x, sizeof(num_x)); - memzero(&y, sizeof(y)); - memzero(&tmp1, sizeof(tmp1)); - memzero(&tmp2, sizeof(tmp2)); - - return ok ? 0 : -1; -} - -static void pallas_projective_to_affine(const bignum256 *x, const bignum256 *y, - const bignum256 *z, curve_point *out) { - if (bn_is_zero(z)) { - bn_zero(&out->x); - bn_zero(&out->y); - return; - } - - bignum256 z_inv, z_inv2, z_inv3; - bn_copy(z, &z_inv); - pallas_inv_mod_p(&z_inv); - fp_square(&z_inv, &z_inv2); - fp_mul(&z_inv2, &z_inv, &z_inv3); - fp_mul(x, &z_inv2, &out->x); - fp_mul(y, &z_inv3, &out->y); - - memzero(&z_inv, sizeof(z_inv)); - memzero(&z_inv2, sizeof(z_inv2)); - memzero(&z_inv3, sizeof(z_inv3)); -} - -static int pallas_point_on_curve(const curve_point *p) { - if (pallas_point_is_identity(p)) return 1; - - bignum256 y2, x2, x3, five, rhs; - fp_square(&p->y, &y2); - fp_square(&p->x, &x2); - fp_mul(&x2, &p->x, &x3); - fp_from_u32(5, &five); - fp_add(&x3, &five, &rhs); - int ok = fp_is_equal(&y2, &rhs); - memzero(&y2, sizeof(y2)); - memzero(&x2, sizeof(x2)); - memzero(&x3, sizeof(x3)); - memzero(&five, sizeof(five)); - memzero(&rhs, sizeof(rhs)); - return ok; -} - -int pallas_iso_map_to_pallas(const pallas_jacobian_point *iso, - curve_point *out) { - if (!iso || !out) return -1; - if (iso_is_identity(iso)) { - bn_zero(&out->x); - bn_zero(&out->y); - return 0; - } - - bignum256 c[13]; - for (int i = 0; i < 13; i++) { - fp_from_raw_u64(ISOGENY_RAW[i], &c[i]); - } - - bignum256 z2, z3, z4, z6, num_x, div_x, num_y, div_y; - bignum256 zo, xo, yo, tmp1, tmp2, tmp3; - - fp_square(&iso->z, &z2); - fp_mul(&z2, &iso->z, &z3); - fp_square(&z2, &z4); - fp_square(&z3, &z6); - - fp_mul(&c[0], &iso->x, &tmp1); - fp_mul(&c[1], &z2, &tmp2); - fp_add(&tmp1, &tmp2, &tmp1); - fp_mul(&tmp1, &iso->x, &tmp1); - fp_mul(&c[2], &z4, &tmp2); - fp_add(&tmp1, &tmp2, &tmp1); - fp_mul(&tmp1, &iso->x, &tmp1); - fp_mul(&c[3], &z6, &tmp2); - fp_add(&tmp1, &tmp2, &num_x); - - fp_mul(&z2, &iso->x, &tmp1); - fp_mul(&c[4], &z4, &tmp2); - fp_add(&tmp1, &tmp2, &tmp1); - fp_mul(&tmp1, &iso->x, &tmp1); - fp_mul(&c[5], &z6, &tmp2); - fp_add(&tmp1, &tmp2, &div_x); - - fp_mul(&c[6], &iso->x, &tmp1); - fp_mul(&c[7], &z2, &tmp2); - fp_add(&tmp1, &tmp2, &tmp1); - fp_mul(&tmp1, &iso->x, &tmp1); - fp_mul(&c[8], &z4, &tmp2); - fp_add(&tmp1, &tmp2, &tmp1); - fp_mul(&tmp1, &iso->x, &tmp1); - fp_mul(&c[9], &z6, &tmp2); - fp_add(&tmp1, &tmp2, &tmp1); - fp_mul(&tmp1, &iso->y, &num_y); - - fp_mul(&c[10], &z2, &tmp1); - fp_add(&iso->x, &tmp1, &tmp1); - fp_mul(&tmp1, &iso->x, &tmp1); - fp_mul(&c[11], &z4, &tmp2); - fp_add(&tmp1, &tmp2, &tmp1); - fp_mul(&tmp1, &iso->x, &tmp1); - fp_mul(&c[12], &z6, &tmp2); - fp_add(&tmp1, &tmp2, &tmp1); - fp_mul(&tmp1, &z3, &div_y); - - fp_mul(&div_x, &div_y, &zo); - fp_mul(&num_x, &div_y, &xo); - fp_mul(&xo, &zo, &xo); - fp_mul(&num_y, &div_x, &yo); - fp_square(&zo, &tmp3); - fp_mul(&yo, &tmp3, &yo); - - pallas_projective_to_affine(&xo, &yo, &zo, out); - int ok = pallas_point_on_curve(out); - - for (int i = 0; i < 13; i++) { - memzero(&c[i], sizeof(c[i])); - } - memzero(&z2, sizeof(z2)); - memzero(&z3, sizeof(z3)); - memzero(&z4, sizeof(z4)); - memzero(&z6, sizeof(z6)); - memzero(&num_x, sizeof(num_x)); - memzero(&div_x, sizeof(div_x)); - memzero(&num_y, sizeof(num_y)); - memzero(&div_y, sizeof(div_y)); - memzero(&zo, sizeof(zo)); - memzero(&xo, sizeof(xo)); - memzero(&yo, sizeof(yo)); - memzero(&tmp1, sizeof(tmp1)); - memzero(&tmp2, sizeof(tmp2)); - memzero(&tmp3, sizeof(tmp3)); - - return ok ? 0 : -1; -} - -static int hash_to_field(const char *domain_prefix, const uint8_t *msg, - size_t msg_len, bignum256 out[2]) { - static const char curve_id[] = "pallas"; - static const char suffix[] = "_XMD:BLAKE2b_SSWU_RO_"; - - if (!domain_prefix || (!msg && msg_len != 0) || !out) return -1; - - size_t domain_len = strlen(domain_prefix); - size_t curve_len = sizeof(curve_id) - 1; - size_t suffix_len = sizeof(suffix) - 1; - size_t dst_len = domain_len + 1 + curve_len + suffix_len; - if (domain_len >= 256 || dst_len >= 256) return -1; - - uint8_t dst[255]; - uint8_t uniform[128]; - uint8_t le[64]; - - memcpy(dst, domain_prefix, domain_len); - dst[domain_len] = '-'; - memcpy(dst + domain_len + 1, curve_id, curve_len); - memcpy(dst + domain_len + 1 + curve_len, suffix, suffix_len); - - if (pallas_expand_message_xmd_blake2b(msg, msg_len, dst, dst_len, uniform, - sizeof(uniform)) != 0) { - memzero(dst, sizeof(dst)); - return -1; - } - - for (int i = 0; i < 2; i++) { - for (int j = 0; j < 64; j++) { - le[j] = uniform[i * 64 + (63 - j)]; - } - fp_from_uniform64(le, &out[i]); - } - - memzero(dst, sizeof(dst)); - memzero(uniform, sizeof(uniform)); - memzero(le, sizeof(le)); - return 0; -} - -int pallas_hash_to_curve(const char *domain_prefix, const uint8_t *msg, - size_t msg_len, curve_point *out) { - if (!domain_prefix || (!msg && msg_len != 0) || !out) return -1; - - bignum256 u[2]; - iso_point q0, q1, r; - uint8_t u_le[32]; - - if (hash_to_field(domain_prefix, msg, msg_len, u) != 0) { - return -1; - } - - bn_write_le(&u[0], u_le); - if (pallas_map_to_curve_simple_swu(u_le, &q0) != 0) { - memzero(u, sizeof(u)); - memzero(u_le, sizeof(u_le)); - return -1; - } - - bn_write_le(&u[1], u_le); - if (pallas_map_to_curve_simple_swu(u_le, &q1) != 0) { - memzero(u, sizeof(u)); - memzero(u_le, sizeof(u_le)); - memzero(&q0, sizeof(q0)); - return -1; - } - - iso_add(&q0, &q1, &r); - int ret = pallas_iso_map_to_pallas(&r, out); - - memzero(u, sizeof(u)); - memzero(u_le, sizeof(u_le)); - memzero(&q0, sizeof(q0)); - memzero(&q1, sizeof(q1)); - memzero(&r, sizeof(r)); - return ret; -} - -int pallas_group_hash(const char *domain_prefix, const uint8_t *msg, - size_t msg_len, curve_point *out) { - return pallas_hash_to_curve(domain_prefix, msg, msg_len, out); -} diff --git a/deps/crypto/trezor-crypto/pallas_swu.h b/deps/crypto/trezor-crypto/pallas_swu.h deleted file mode 100644 index eff414ee2..000000000 --- a/deps/crypto/trezor-crypto/pallas_swu.h +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright (c) 2026 KeepKey - * - * Pallas hash-to-curve primitives for Zcash Orchard. - */ - -#ifndef __PALLAS_SWU_H__ -#define __PALLAS_SWU_H__ - -#include -#include - -#include "bignum.h" -#include "ecdsa.h" - -typedef struct { - bignum256 x; - bignum256 y; - bignum256 z; -} pallas_jacobian_point; - -/* - * Map a Pallas base-field element to the iso-Pallas curve using the - * simplified SWU map used by pasta_curves. - */ -int pallas_map_to_curve_simple_swu(const uint8_t u_le[32], - pallas_jacobian_point *out); - -/* Apply the degree-3 isogeny from iso-Pallas to Pallas. */ -int pallas_iso_map_to_pallas(const pallas_jacobian_point *iso, - curve_point *out); - -/* Hash to Pallas using domain_prefix as in pasta_curves::Point::hash_to_curve. */ -int pallas_hash_to_curve(const char *domain_prefix, const uint8_t *msg, - size_t msg_len, curve_point *out); - -/* Alias for protocol GroupHash^Pallas call sites. */ -int pallas_group_hash(const char *domain_prefix, const uint8_t *msg, - size_t msg_len, curve_point *out); - -#endif diff --git a/deps/crypto/trezor-crypto/pbkdf2.c b/deps/crypto/trezor-crypto/pbkdf2.c deleted file mode 100644 index d9e142297..000000000 --- a/deps/crypto/trezor-crypto/pbkdf2.c +++ /dev/null @@ -1,179 +0,0 @@ -/** - * Copyright (c) 2013-2014 Tomas Dzetkulic - * Copyright (c) 2013-2014 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "pbkdf2.h" -#include -#include "hmac.h" -#include "memzero.h" -#include "sha2.h" - -void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass, - int passlen, const uint8_t *salt, int saltlen, - uint32_t blocknr) { - SHA256_CTX ctx = {0}; -#if BYTE_ORDER == LITTLE_ENDIAN - REVERSE32(blocknr, blocknr); -#endif - - hmac_sha256_prepare(pass, passlen, pctx->odig, pctx->idig); - memzero(pctx->g, sizeof(pctx->g)); - pctx->g[8] = 0x80000000; - pctx->g[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8; - - memcpy(ctx.state, pctx->idig, sizeof(pctx->idig)); - ctx.bitcount = SHA256_BLOCK_LENGTH * 8; - sha256_Update(&ctx, salt, saltlen); - sha256_Update(&ctx, (uint8_t *)&blocknr, sizeof(blocknr)); - sha256_Final(&ctx, (uint8_t *)pctx->g); -#if BYTE_ORDER == LITTLE_ENDIAN - for (uint32_t k = 0; k < SHA256_DIGEST_LENGTH / sizeof(uint32_t); k++) { - REVERSE32(pctx->g[k], pctx->g[k]); - } -#endif - sha256_Transform(pctx->odig, pctx->g, pctx->g); - memcpy(pctx->f, pctx->g, SHA256_DIGEST_LENGTH); - pctx->first = 1; -} - -void pbkdf2_hmac_sha256_Update(PBKDF2_HMAC_SHA256_CTX *pctx, - uint32_t iterations) { - for (uint32_t i = pctx->first; i < iterations; i++) { - sha256_Transform(pctx->idig, pctx->g, pctx->g); - sha256_Transform(pctx->odig, pctx->g, pctx->g); - for (uint32_t j = 0; j < SHA256_DIGEST_LENGTH / sizeof(uint32_t); j++) { - pctx->f[j] ^= pctx->g[j]; - } - } - pctx->first = 0; -} - -void pbkdf2_hmac_sha256_Final(PBKDF2_HMAC_SHA256_CTX *pctx, uint8_t *key) { -#if BYTE_ORDER == LITTLE_ENDIAN - for (uint32_t k = 0; k < SHA256_DIGEST_LENGTH / sizeof(uint32_t); k++) { - REVERSE32(pctx->f[k], pctx->f[k]); - } -#endif - memcpy(key, pctx->f, SHA256_DIGEST_LENGTH); - memzero(pctx, sizeof(PBKDF2_HMAC_SHA256_CTX)); -} - -void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, const uint8_t *salt, - int saltlen, uint32_t iterations, uint8_t *key, - int keylen) { - uint32_t last_block_size = keylen % SHA256_DIGEST_LENGTH; - uint32_t blocks_count = keylen / SHA256_DIGEST_LENGTH; - if (last_block_size) { - blocks_count++; - } else { - last_block_size = SHA256_DIGEST_LENGTH; - } - for (uint32_t blocknr = 1; blocknr <= blocks_count; blocknr++) { - PBKDF2_HMAC_SHA256_CTX pctx = {0}; - pbkdf2_hmac_sha256_Init(&pctx, pass, passlen, salt, saltlen, blocknr); - pbkdf2_hmac_sha256_Update(&pctx, iterations); - uint8_t digest[SHA256_DIGEST_LENGTH] = {0}; - pbkdf2_hmac_sha256_Final(&pctx, digest); - uint32_t key_offset = (blocknr - 1) * SHA256_DIGEST_LENGTH; - if (blocknr < blocks_count) { - memcpy(key + key_offset, digest, SHA256_DIGEST_LENGTH); - } else { - memcpy(key + key_offset, digest, last_block_size); - } - } -} - -void pbkdf2_hmac_sha512_Init(PBKDF2_HMAC_SHA512_CTX *pctx, const uint8_t *pass, - int passlen, const uint8_t *salt, int saltlen, - uint32_t blocknr) { - SHA512_CTX ctx = {0}; -#if BYTE_ORDER == LITTLE_ENDIAN - REVERSE32(blocknr, blocknr); -#endif - - hmac_sha512_prepare(pass, passlen, pctx->odig, pctx->idig); - memzero(pctx->g, sizeof(pctx->g)); - pctx->g[8] = 0x8000000000000000; - pctx->g[15] = (SHA512_BLOCK_LENGTH + SHA512_DIGEST_LENGTH) * 8; - - memcpy(ctx.state, pctx->idig, sizeof(pctx->idig)); - ctx.bitcount[0] = SHA512_BLOCK_LENGTH * 8; - ctx.bitcount[1] = 0; - sha512_Update(&ctx, salt, saltlen); - sha512_Update(&ctx, (uint8_t *)&blocknr, sizeof(blocknr)); - sha512_Final(&ctx, (uint8_t *)pctx->g); -#if BYTE_ORDER == LITTLE_ENDIAN - for (uint32_t k = 0; k < SHA512_DIGEST_LENGTH / sizeof(uint64_t); k++) { - REVERSE64(pctx->g[k], pctx->g[k]); - } -#endif - sha512_Transform(pctx->odig, pctx->g, pctx->g); - memcpy(pctx->f, pctx->g, SHA512_DIGEST_LENGTH); - pctx->first = 1; -} - -void pbkdf2_hmac_sha512_Update(PBKDF2_HMAC_SHA512_CTX *pctx, - uint32_t iterations) { - for (uint32_t i = pctx->first; i < iterations; i++) { - sha512_Transform(pctx->idig, pctx->g, pctx->g); - sha512_Transform(pctx->odig, pctx->g, pctx->g); - for (uint32_t j = 0; j < SHA512_DIGEST_LENGTH / sizeof(uint64_t); j++) { - pctx->f[j] ^= pctx->g[j]; - } - } - pctx->first = 0; -} - -void pbkdf2_hmac_sha512_Final(PBKDF2_HMAC_SHA512_CTX *pctx, uint8_t *key) { -#if BYTE_ORDER == LITTLE_ENDIAN - for (uint32_t k = 0; k < SHA512_DIGEST_LENGTH / sizeof(uint64_t); k++) { - REVERSE64(pctx->f[k], pctx->f[k]); - } -#endif - memcpy(key, pctx->f, SHA512_DIGEST_LENGTH); - memzero(pctx, sizeof(PBKDF2_HMAC_SHA512_CTX)); -} - -void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, const uint8_t *salt, - int saltlen, uint32_t iterations, uint8_t *key, - int keylen) { - uint32_t last_block_size = keylen % SHA512_DIGEST_LENGTH; - uint32_t blocks_count = keylen / SHA512_DIGEST_LENGTH; - if (last_block_size) { - blocks_count++; - } else { - last_block_size = SHA512_DIGEST_LENGTH; - } - for (uint32_t blocknr = 1; blocknr <= blocks_count; blocknr++) { - PBKDF2_HMAC_SHA512_CTX pctx = {0}; - pbkdf2_hmac_sha512_Init(&pctx, pass, passlen, salt, saltlen, blocknr); - pbkdf2_hmac_sha512_Update(&pctx, iterations); - uint8_t digest[SHA512_DIGEST_LENGTH] = {0}; - pbkdf2_hmac_sha512_Final(&pctx, digest); - uint32_t key_offset = (blocknr - 1) * SHA512_DIGEST_LENGTH; - if (blocknr < blocks_count) { - memcpy(key + key_offset, digest, SHA512_DIGEST_LENGTH); - } else { - memcpy(key + key_offset, digest, last_block_size); - } - } -} diff --git a/deps/crypto/trezor-crypto/pbkdf2.h b/deps/crypto/trezor-crypto/pbkdf2.h deleted file mode 100644 index c2e3f04a6..000000000 --- a/deps/crypto/trezor-crypto/pbkdf2.h +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Copyright (c) 2013-2014 Tomas Dzetkulic - * Copyright (c) 2013-2014 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __PBKDF2_H__ -#define __PBKDF2_H__ - -#include -#include "sha2.h" - -typedef struct _PBKDF2_HMAC_SHA256_CTX { - uint32_t odig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; - uint32_t idig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; - uint32_t f[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; - uint32_t g[SHA256_BLOCK_LENGTH / sizeof(uint32_t)]; - char first; -} PBKDF2_HMAC_SHA256_CTX; - -typedef struct _PBKDF2_HMAC_SHA512_CTX { - uint64_t odig[SHA512_DIGEST_LENGTH / sizeof(uint64_t)]; - uint64_t idig[SHA512_DIGEST_LENGTH / sizeof(uint64_t)]; - uint64_t f[SHA512_DIGEST_LENGTH / sizeof(uint64_t)]; - uint64_t g[SHA512_BLOCK_LENGTH / sizeof(uint64_t)]; - char first; -} PBKDF2_HMAC_SHA512_CTX; - -void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass, - int passlen, const uint8_t *salt, int saltlen, - uint32_t blocknr); -void pbkdf2_hmac_sha256_Update(PBKDF2_HMAC_SHA256_CTX *pctx, - uint32_t iterations); -void pbkdf2_hmac_sha256_Final(PBKDF2_HMAC_SHA256_CTX *pctx, uint8_t *key); -void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, const uint8_t *salt, - int saltlen, uint32_t iterations, uint8_t *key, - int keylen); - -void pbkdf2_hmac_sha512_Init(PBKDF2_HMAC_SHA512_CTX *pctx, const uint8_t *pass, - int passlen, const uint8_t *salt, int saltlen, - uint32_t blocknr); -void pbkdf2_hmac_sha512_Update(PBKDF2_HMAC_SHA512_CTX *pctx, - uint32_t iterations); -void pbkdf2_hmac_sha512_Final(PBKDF2_HMAC_SHA512_CTX *pctx, uint8_t *key); -void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, const uint8_t *salt, - int saltlen, uint32_t iterations, uint8_t *key, - int keylen); - -#endif diff --git a/deps/crypto/trezor-crypto/rand.c b/deps/crypto/trezor-crypto/rand.c deleted file mode 100644 index ea95d143b..000000000 --- a/deps/crypto/trezor-crypto/rand.c +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Copyright (c) 2013-2014 Tomas Dzetkulic - * Copyright (c) 2013-2014 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "rand.h" - -#ifndef RAND_PLATFORM_INDEPENDENT - -#pragma message( \ - "NOT SUITABLE FOR PRODUCTION USE! Replace random32() function with your own secure code.") - -// The following code is not supposed to be used in a production environment. -// It's included only to make the library testable. -// The message above tries to prevent any accidental use outside of the test -// environment. -// -// You are supposed to replace the random8() and random32() function with your -// own secure code. There is also a possibility to replace the random_buffer() -// function as it is defined as a weak symbol. - -static uint32_t seed = 0; - -void random_reseed(const uint32_t value) { seed = value; } - -uint32_t random32(void) { - // Linear congruential generator from Numerical Recipes - // https://en.wikipedia.org/wiki/Linear_congruential_generator - seed = 1664525 * seed + 1013904223; - return seed; -} - -#endif /* RAND_PLATFORM_INDEPENDENT */ - -// -// The following code is platform independent -// - -void __attribute__((weak)) random_buffer(uint8_t *buf, size_t len) { - uint32_t r = 0; - for (size_t i = 0; i < len; i++) { - if (i % 4 == 0) { - r = random32(); - } - buf[i] = (r >> ((i % 4) * 8)) & 0xFF; - } -} - -uint32_t random_uniform(uint32_t n) { - uint32_t x = 0, max = 0xFFFFFFFF - (0xFFFFFFFF % n); - while ((x = random32()) >= max) - ; - return x / (max / n); -} - -void random_permute(char *str, size_t len) { - for (int i = len - 1; i >= 1; i--) { - int j = random_uniform(i + 1); - char t = str[j]; - str[j] = str[i]; - str[i] = t; - } -} diff --git a/deps/crypto/trezor-crypto/rand.h b/deps/crypto/trezor-crypto/rand.h deleted file mode 100644 index 49d9cfaf2..000000000 --- a/deps/crypto/trezor-crypto/rand.h +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) 2013-2014 Tomas Dzetkulic - * Copyright (c) 2013-2014 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __RAND_H__ -#define __RAND_H__ - -#include -#include - -void random_reseed(const uint32_t value); -uint32_t random32(void); -void random_buffer(uint8_t *buf, size_t len); - -uint32_t random_uniform(uint32_t n); -void random_permute(char *buf, size_t len); - -#endif diff --git a/deps/crypto/trezor-crypto/rc4.c b/deps/crypto/trezor-crypto/rc4.c deleted file mode 100644 index fea73cab1..000000000 --- a/deps/crypto/trezor-crypto/rc4.c +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Copyright (c) 2017 Saleem Rashid - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, E1PRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "rc4.h" - -static inline void rc4_swap(RC4_CTX *ctx, uint8_t i, uint8_t j) { - uint8_t temp = ctx->S[i]; - ctx->S[i] = ctx->S[j]; - ctx->S[j] = temp; -} - -void rc4_init(RC4_CTX *ctx, const uint8_t *key, size_t length) { - ctx->i = 0; - ctx->j = 0; - - for (size_t i = 0; i < 256; i++) { - ctx->S[i] = i; - } - - uint8_t j = 0; - for (size_t i = 0; i < 256; i++) { - j += ctx->S[i] + key[i % length]; - rc4_swap(ctx, i, j); - } -} - -void rc4_encrypt(RC4_CTX *ctx, uint8_t *buffer, size_t length) { - for (size_t idx = 0; idx < length; idx++) { - ctx->i++; - ctx->j += ctx->S[ctx->i]; - - rc4_swap(ctx, ctx->i, ctx->j); - - uint8_t K = ctx->S[(ctx->S[ctx->i] + ctx->S[ctx->j]) % 256]; - buffer[idx] ^= K; - } -} diff --git a/deps/crypto/trezor-crypto/rc4.h b/deps/crypto/trezor-crypto/rc4.h deleted file mode 100644 index 8ba8a9b25..000000000 --- a/deps/crypto/trezor-crypto/rc4.h +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) 2017 Saleem Rashid - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __RC4_H__ -#define __RC4_H__ - -#include -#include - -typedef struct { - uint8_t S[256]; - uint8_t i, j; -} RC4_CTX; - -void rc4_init(RC4_CTX *ctx, const uint8_t *key, size_t length); -void rc4_encrypt(RC4_CTX *ctx, uint8_t *buffer, size_t length); - -#endif diff --git a/deps/crypto/trezor-crypto/redpallas.c b/deps/crypto/trezor-crypto/redpallas.c deleted file mode 100644 index 432f85e5a..000000000 --- a/deps/crypto/trezor-crypto/redpallas.c +++ /dev/null @@ -1,501 +0,0 @@ -/** - * Copyright (c) 2025 KeepKey - * - * RedPallas (re-randomized Schnorr) signature scheme for Zcash Orchard. - * - * IMPORTANT: All modular arithmetic uses pallas_mul_mod_p/q etc. from pallas.c. - * The generic bn_multiply/bn_mod/bn_sqrt from bignum.c MUST NOT be used - * because they assume primes in [2^256 - 2^224, 2^256], while the Pallas - * prime is only ~2^254. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "redpallas.h" - -#include - -#include "bignum.h" -#include "blake2b.h" -#include "ecdsa.h" -#include "memzero.h" -#include "pallas.h" -#include "pallas_ct.h" -#include "rand.h" - -/* - * Zcash Orchard SpendAuth basepoint. - * - * This is NOT the standard Pallas generator G = (-1 mod p, 2). - * It is the hash-derived basepoint: GroupHash^P("z.cash:Orchard", "G") - * as specified in ZIP-224 / the reddsa crate. - * - * Serialized as compressed Pallas point (LE x-coordinate, sign bit in MSB). - * Source: reddsa-0.5.1 ORCHARD_SPENDAUTHSIG_BASEPOINT_BYTES constant. - */ -static const uint8_t pallas_spendauth_G_bytes[32] = { - 0x63, 0xc9, 0x75, 0xb8, 0x84, 0x72, 0x1a, 0x8d, 0x0c, 0xa1, 0x70, - 0x7b, 0xe3, 0x0c, 0x7f, 0x0c, 0x5f, 0x44, 0x5f, 0x3e, 0x7c, 0x18, - 0x8d, 0x3b, 0x06, 0xd6, 0xf1, 0x28, 0xb3, 0x23, 0x55, 0xb7, -}; - -/* Cached SpendAuth basepoint (lazy-initialized from compressed bytes) */ -static curve_point spendauth_G_cache; -static int spendauth_G_initialized = 0; - -/* - * Pallas point serialization (Pasta encoding): - * 32 bytes, little-endian x-coordinate, with the sign of y encoded - * in the most significant bit of the last byte. - * - * sign(y) = y is odd (bit 0 of y) - */ - -static void pallas_point_serialize(const curve_point* p, uint8_t out[32]) { - bignum256 x_copy; - bn_copy(&p->x, &x_copy); - bn_write_le(&x_copy, out); - if (bn_is_odd(&p->y)) { - out[31] |= 0x80; - } -} - -static int pallas_point_deserialize(const uint8_t in[32], curve_point* p) { - uint8_t buf[32]; - memcpy(buf, in, 32); - /* Extract sign bit */ - int y_odd = (buf[31] >> 7) & 1; - buf[31] &= 0x7f; - - /* Read x-coordinate (little-endian) */ - bn_read_le(buf, &p->x); - - /* Check x < prime */ - if (!bn_is_less(&p->x, &pallas_prime)) { - return -1; - } - - /* Compute y^2 = x^3 + 5 mod p using custom Pallas arithmetic */ - bignum256 y2; - bn_copy(&p->x, &y2); - pallas_mul_mod_p(&y2, &p->x); /* y2 = x^2 */ - pallas_mul_mod_p(&y2, &p->x); /* y2 = x^3 */ - bignum256 b; - bn_zero(&b); - b.val[0] = 5; - pallas_add_mod_p(&y2, &b, &y2); /* y2 = x^3 + 5 mod p */ - - /* Compute y = sqrt(y2) mod p using Tonelli-Shanks */ - bn_copy(&y2, &p->y); - if (pallas_sqrt_mod_p(&p->y) != 0) { - return -1; /* Not a valid point (y2 is not a QR) */ - } - - /* Verify sqrt is correct: check y^2 == y2 */ - bignum256 check; - bn_copy(&p->y, &check); - pallas_mul_mod_p(&check, &p->y); /* check = y^2 */ - - /* Normalize both for comparison */ - bn_normalize(&check); - bn_normalize(&y2); - if (!bn_is_equal(&check, &y2)) { - return -1; /* Not a valid point */ - } - - /* Fix sign of y */ - if (bn_is_odd(&p->y) != y_odd) { - /* y = p - y */ - pallas_sub_mod_p(&pallas_prime, &p->y, &p->y); - } - - return 0; -} - -/* - * Scalar multiplication by the SpendAuth basepoint. - * Uses lazy initialization: decompresses the basepoint once, then caches it. - * - * res = k * G_spendauth - */ -static void pallas_scalar_mult_spendauth(const bignum256* k, curve_point* res) { - if (!spendauth_G_initialized) { - pallas_point_deserialize(pallas_spendauth_G_bytes, &spendauth_G_cache); - spendauth_G_initialized = 1; - } - /* k is an authorization scalar or nonce on signing/derivation paths. Keep - * it on the fixed-schedule projective implementation; pallas_point_mult() - * is the variable-time public-data API used by Sinsemilla verification. */ - pallas_ct_point_mult(k, &spendauth_G_cache, res); -} - -static void pallas_scalar_mult_spendauth_public(const bignum256* k, - curve_point* res) { - if (!spendauth_G_initialized) { - pallas_point_deserialize(pallas_spendauth_G_bytes, &spendauth_G_cache); - spendauth_G_initialized = 1; - } - /* alpha is transmitted by the host and committed by the Orchard action. - * This path must never be used with ask, rsk, a nonce, or another secret. */ - pallas_point_mult(k, &spendauth_G_cache, res); -} - -/* - * Public API: Scalar multiplication by SpendAuth basepoint. - * For use by FVK export (ak = [ask]*G_spendauth). - */ -void redpallas_scalar_mult_spendauth_G(const bignum256* k, curve_point* res) { - pallas_scalar_mult_spendauth(k, res); -} - -void redpallas_scalar_mult_spendauth_G_progress( - const bignum256* k, curve_point* res, redpallas_progress_callback progress, - void* progress_context) { - if (!spendauth_G_initialized) { - pallas_point_deserialize(pallas_spendauth_G_bytes, &spendauth_G_cache); - spendauth_G_initialized = 1; - } - if (progress) { - pallas_ct_point_mult_progress(k, &spendauth_G_cache, res, progress, - progress_context); - } else { - pallas_ct_point_mult(k, &spendauth_G_cache, res); - } -} - -/* - * Constant: 2^256 mod q (Pallas scalar field order). - * - * q = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001 - * 2^256 mod q = 2^254 - 3*(q - 2^254) - * = - * 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF992C350BE34205675B2B3E9CFFFFFFFD - * - * Stored as 32 bytes little-endian. - * Source: pasta_curves Montgomery radix R for the Pallas scalar field (Fq). - * Verified: R + 3*q == 2^256. - */ -static const uint8_t two_256_mod_q[32] = { - 0xfd, 0xff, 0xff, 0xff, 0x9c, 0x3e, 0x2b, 0x5b, 0x67, 0x05, 0x42, - 0xe3, 0x0b, 0x35, 0x2c, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, -}; - -/* - * Wide reduction: reduce a 512-bit LE value mod Pallas scalar order q. - * - * Matches the orchard crate's pallas::Scalar::from_uniform_bytes(): - * result = (lo + hi * 2^256) mod q - * - * where lo = input[0..31] and hi = input[32..63], both little-endian. - * - * This MUST be used instead of simple truncation (taking low 256 bits) - * because the orchard crate verifies against from_uniform_bytes — the - * values differ whenever hi != 0, which is ~100% of the time. - */ -static void pallas_from_uniform_bytes(const uint8_t input[64], bignum256* out) { - bignum256 lo, hi, t256; - - bn_read_le(input, &lo); - pallas_mod_q(&lo); - - bn_read_le(input + 32, &hi); - pallas_mod_q(&hi); - - bn_read_le(two_256_mod_q, &t256); - - /* out = hi * (2^256 mod q) mod q */ - bn_copy(&hi, out); - pallas_mul_mod_q(out, &t256); - - /* out = out + lo mod q */ - pallas_add_mod_q(out, &lo); - - memzero(&lo, sizeof(lo)); - memzero(&hi, sizeof(hi)); -} - -/* - * RedPallas challenge hash: - * H = BLAKE2b-512("Zcash_RedPallasH", R_bytes || rk_bytes || sighash) - * Reduced to a scalar mod order using wide reduction (from_uniform_bytes). - */ -static void redpallas_hash_challenge(const uint8_t R_bytes[32], - const uint8_t rk_bytes[32], - const uint8_t sighash[32], bignum256* c) { - uint8_t hash_out[64]; - BLAKE2B_CTX ctx; - - blake2b_InitPersonal(&ctx, 64, "Zcash_RedPallasH", 16); - blake2b_Update(&ctx, R_bytes, 32); - blake2b_Update(&ctx, rk_bytes, 32); - blake2b_Update(&ctx, sighash, 32); - blake2b_Final(&ctx, hash_out, 64); - - /* Wide reduction matching orchard crate's from_uniform_bytes */ - pallas_from_uniform_bytes(hash_out, c); - - memzero(hash_out, sizeof(hash_out)); -} - -typedef struct { - redpallas_progress_callback callback; - void* context; - uint32_t base; - uint32_t span; -} redpallas_progress_bridge; - -static void redpallas_nonce_progress(uint32_t completed, uint32_t total, - void* context) { - redpallas_progress_bridge* bridge = (redpallas_progress_bridge*)context; - bridge->callback(bridge->base + (bridge->span * completed) / total, 1000, - bridge->context); -} - -static int redpallas_sign_with_rsk( - const bignum256* rsk, const uint8_t rk_bytes[32], const uint8_t* sighash, - uint8_t* sig_out, redpallas_progress_callback progress, - void* progress_context, uint32_t progress_base, uint32_t progress_span) { - bignum256 r, c, s; - curve_point R_point; - uint8_t R_bytes[32]; - - /* Generate random nonce r */ - uint8_t rbuf[32]; - random_buffer(rbuf, 32); - bn_read_le(rbuf, &r); - pallas_ct_mod_q(&r); - - /* Ensure r is not zero without branching on the secret nonce. */ - pallas_ct_scalar_replace_zero_with_one(&r); - - /* R = [r]G_spendauth - nonce commitment */ - if (progress) { - redpallas_progress_bridge bridge = {progress, progress_context, - progress_base, progress_span}; - pallas_ct_point_mult_progress(&r, &spendauth_G_cache, &R_point, - redpallas_nonce_progress, &bridge); - } else { - pallas_scalar_mult_spendauth(&r, &R_point); - } - pallas_point_serialize(&R_point, R_bytes); - - /* c = H("Zcash_RedPallasH", R || rk || sighash) mod order */ - redpallas_hash_challenge(R_bytes, rk_bytes, sighash, &c); - - /* S = r + c * rsk (mod order) */ - pallas_ct_mul_mod_q(&c, rsk); /* c = c * rsk mod order */ - bn_copy(&r, &s); - pallas_ct_add_mod_q(&s, &c); /* s = r + c*rsk mod order */ - - /* Output: R (32 bytes LE) || S (32 bytes LE) */ - memcpy(sig_out, R_bytes, 32); - bn_write_le(&s, sig_out + 32); - - /* Clean up sensitive data */ - memzero(&r, sizeof(r)); - memzero(&c, sizeof(c)); - memzero(&s, sizeof(s)); - memzero(&R_point, sizeof(R_point)); - memzero(R_bytes, sizeof(R_bytes)); - memzero(rbuf, sizeof(rbuf)); - - return 0; -} - -int redpallas_sign_digest_for_rk(const uint8_t* ask, const uint8_t* alpha, - const uint8_t* rk, const uint8_t* sighash, - uint8_t* sig_out, - redpallas_progress_callback progress, - void* progress_context) { - if (!ask || !alpha || !rk || !sighash || !sig_out) return -1; - - if (!spendauth_G_initialized) { - if (pallas_point_deserialize(pallas_spendauth_G_bytes, - &spendauth_G_cache) != 0) { - return -1; - } - spendauth_G_initialized = 1; - } - - bignum256 ask_scalar, alpha_scalar, rsk; - if (progress) progress(0, 1000, progress_context); - - bn_read_le(ask, &ask_scalar); - bn_read_le(alpha, &alpha_scalar); - bn_copy(&ask_scalar, &rsk); - pallas_ct_add_mod_q(&rsk, &alpha_scalar); - - const int result = redpallas_sign_with_rsk( - &rsk, rk, sighash, sig_out, progress, progress_context, 0, 1000); - memzero(&ask_scalar, sizeof(ask_scalar)); - memzero(&alpha_scalar, sizeof(alpha_scalar)); - memzero(&rsk, sizeof(rsk)); - return result; -} - -int redpallas_derive_rk_from_ak(const uint8_t* ak, const uint8_t* alpha, - uint8_t* rk_out) { - if (!ak || !alpha || !rk_out) return -1; - - curve_point ak_point, alpha_point, rk_point; - bignum256 alpha_scalar; - if (pallas_point_deserialize(ak, &ak_point) != 0) { - return -1; - } - - bn_read_le(alpha, &alpha_scalar); - pallas_mod_q(&alpha_scalar); - pallas_scalar_mult_spendauth_public(&alpha_scalar, &alpha_point); - pallas_point_add(&ak_point, &alpha_point, &rk_point); - pallas_point_serialize(&rk_point, rk_out); - - memzero(&alpha_scalar, sizeof(alpha_scalar)); - memzero(&ak_point, sizeof(ak_point)); - memzero(&alpha_point, sizeof(alpha_point)); - memzero(&rk_point, sizeof(rk_point)); - return 0; -} - -int redpallas_sign_digest_with_ak(const uint8_t* ask, const uint8_t* ak, - const uint8_t* alpha, - const uint8_t* expected_rk, - const uint8_t* sighash, uint8_t* sig_out, - redpallas_progress_callback progress, - void* progress_context) { - if (!ask || !ak || !alpha || !expected_rk || !sighash || !sig_out) return -1; - - bignum256 ask_scalar, alpha_scalar, rsk; - uint8_t rk_bytes[32]; - if (progress) progress(0, 1000, progress_context); - - if (redpallas_derive_rk_from_ak(ak, alpha, rk_bytes) != 0 || - memcmp(rk_bytes, expected_rk, sizeof(rk_bytes)) != 0) { - memzero(rk_bytes, sizeof(rk_bytes)); - return -1; - } - if (progress) progress(100, 1000, progress_context); - - bn_read_le(ask, &ask_scalar); - bn_read_le(alpha, &alpha_scalar); - bn_copy(&ask_scalar, &rsk); - pallas_ct_add_mod_q(&rsk, &alpha_scalar); - - int result = redpallas_sign_with_rsk(&rsk, rk_bytes, sighash, sig_out, - progress, progress_context, 100, 900); - memzero(&ask_scalar, sizeof(ask_scalar)); - memzero(&alpha_scalar, sizeof(alpha_scalar)); - memzero(&rsk, sizeof(rsk)); - memzero(rk_bytes, sizeof(rk_bytes)); - return result; -} - -int redpallas_sign_digest(const uint8_t* ask, const uint8_t* alpha, - const uint8_t* sighash, uint8_t* sig_out) { - bignum256 ask_scalar, alpha_scalar, rsk; - curve_point rk_point; - uint8_t rk_bytes[32]; - - bn_read_le(ask, &ask_scalar); - bn_read_le(alpha, &alpha_scalar); - bn_copy(&ask_scalar, &rsk); - pallas_ct_add_mod_q(&rsk, &alpha_scalar); - - /* Compatibility API: without a cached ak, derive rk from secret rsk. */ - pallas_scalar_mult_spendauth(&rsk, &rk_point); - pallas_point_serialize(&rk_point, rk_bytes); - int result = redpallas_sign_with_rsk(&rsk, rk_bytes, sighash, sig_out, NULL, - NULL, 0, 1000); - - memzero(&ask_scalar, sizeof(ask_scalar)); - memzero(&alpha_scalar, sizeof(alpha_scalar)); - memzero(&rsk, sizeof(rsk)); - memzero(&rk_point, sizeof(rk_point)); - memzero(rk_bytes, sizeof(rk_bytes)); - return result; -} - -int redpallas_verify_digest(const uint8_t* rk, const uint8_t* sighash, - const uint8_t* sig) { - bignum256 c, s; - curve_point R_point, rk_point, lhs, rhs, cR; - - /* Deserialize R from signature */ - if (pallas_point_deserialize(sig, &R_point) != 0) { - return -1; - } - - /* Read S from signature */ - bn_read_le(sig + 32, &s); - if (!bn_is_less(&s, &pallas_order)) { - return -2; - } - - /* Deserialize rk */ - if (pallas_point_deserialize(rk, &rk_point) != 0) { - return -3; - } - - /* Recompute challenge: c = H("Zcash_RedPallasH", R || rk || sighash) */ - uint8_t R_bytes[32]; - pallas_point_serialize(&R_point, R_bytes); - redpallas_hash_challenge(R_bytes, rk, sighash, &c); - - /* Verify: [S]G_spendauth == R + [c]rk */ - /* LHS: [S]G_spendauth */ - pallas_scalar_mult_spendauth(&s, &lhs); - - /* RHS: [c]rk + R */ - pallas_point_mult(&c, &rk_point, &cR); - pallas_point_add(&cR, &R_point, &rhs); - - /* Compare (both should be normalized from our custom operations) */ - bn_normalize(&lhs.x); - bn_normalize(&lhs.y); - bn_normalize(&rhs.x); - bn_normalize(&rhs.y); - if (!bn_is_equal(&lhs.x, &rhs.x) || !bn_is_equal(&lhs.y, &rhs.y)) { - return -4; - } - - return 0; -} - -int redpallas_derive_rk(const uint8_t* ask, const uint8_t* alpha, - uint8_t* rk_out) { - bignum256 ask_scalar, alpha_scalar, rsk; - curve_point rk_point; - - bn_read_le(ask, &ask_scalar); - bn_read_le(alpha, &alpha_scalar); - - /* rsk = (ask + alpha) mod order */ - bn_copy(&ask_scalar, &rsk); - pallas_ct_add_mod_q(&rsk, &alpha_scalar); - - /* rk = [rsk]G_spendauth */ - pallas_scalar_mult_spendauth(&rsk, &rk_point); - pallas_point_serialize(&rk_point, rk_out); - - memzero(&ask_scalar, sizeof(ask_scalar)); - memzero(&alpha_scalar, sizeof(alpha_scalar)); - memzero(&rsk, sizeof(rsk)); - - return 0; -} diff --git a/deps/crypto/trezor-crypto/redpallas.h b/deps/crypto/trezor-crypto/redpallas.h deleted file mode 100644 index 0ce8b8e3b..000000000 --- a/deps/crypto/trezor-crypto/redpallas.h +++ /dev/null @@ -1,133 +0,0 @@ -/** - * Copyright (c) 2025 KeepKey - * - * RedPallas (re-randomized Schnorr) signature scheme for Zcash Orchard. - * Used for spend authorization signatures in the Orchard shielded protocol. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __REDPALLAS_H__ -#define __REDPALLAS_H__ - -#include -#include "bignum.h" -#include "ecdsa.h" - -typedef void (*redpallas_progress_callback)(uint32_t completed, uint32_t total, - void* context); - -/** - * RedPallas spend authorization signature. - * - * Computes a re-randomized Schnorr signature over the Pallas curve: - * rsk = ask + alpha (mod order) -- randomized signing key - * rk = [rsk]G -- randomized verification key - * r = random_scalar() -- nonce - * R = [r]G -- nonce commitment - * c = H("Zcash_RedPallasH", R || rk || sighash) -- challenge (mod order) - * S = r + c * rsk (mod order) -- response - * sig = R || S (64 bytes) - * - * @param ask 32-byte spend authorizing key (little-endian scalar) - * @param alpha 32-byte randomizer from PCZT (little-endian scalar) - * @param sighash 32-byte transaction sighash (ZIP 244) - * @param sig_out 64-byte output: R (32 bytes) || S (32 bytes), little-endian - * @return 0 on success, non-zero on error - */ -int redpallas_sign_digest(const uint8_t* ask, const uint8_t* alpha, - const uint8_t* sighash, uint8_t* sig_out); - -/** - * Sign a PCZT spend using its transaction-bound randomized verification key. - * - * The caller must independently bind rk to the transaction digest. If rk does - * not correspond to ask + alpha, the resulting signature cannot verify. This - * avoids a redundant fixed-base multiplication on the constrained device and - * leaves only the fixed-schedule secret nonce multiplication in the hot path. - * Progress reports public work units in the range 0..1000. - */ -int redpallas_sign_digest_for_rk(const uint8_t* ask, const uint8_t* alpha, - const uint8_t* rk, const uint8_t* sighash, - uint8_t* sig_out, - redpallas_progress_callback progress, - void* progress_context); - -/** - * Sign using the cached public ak and verify the host-provided rk first. - * - * rk = ak + [alpha]G is derived entirely from public data, avoiding a second - * secret-scalar multiplication during each signature. The nonce commitment - * remains on the fixed-schedule implementation. Progress reports fixed public - * work units in the range 0..1000. - */ -int redpallas_sign_digest_with_ak(const uint8_t* ask, const uint8_t* ak, - const uint8_t* alpha, - const uint8_t* expected_rk, - const uint8_t* sighash, uint8_t* sig_out, - redpallas_progress_callback progress, - void* progress_context); - -/** Derive rk = ak + [alpha]G from public Orchard transaction data. */ -int redpallas_derive_rk_from_ak(const uint8_t* ak, const uint8_t* alpha, - uint8_t* rk_out); - -/** - * Verify a RedPallas signature. - * - * @param rk 32-byte randomized verification key (compressed point, LE) - * @param sighash 32-byte transaction sighash - * @param sig 64-byte signature: R (32 bytes) || S (32 bytes) - * @return 0 if signature is valid, non-zero otherwise - */ -int redpallas_verify_digest(const uint8_t* rk, const uint8_t* sighash, - const uint8_t* sig); - -/** - * Derive randomized verification key: rk = [(ask + alpha) mod order] * G - * - * @param ask 32-byte spend authorizing key (little-endian) - * @param alpha 32-byte randomizer (little-endian) - * @param rk_out 32-byte output: compressed point (little-endian x-coordinate) - * @return 0 on success - */ -int redpallas_derive_rk(const uint8_t* ask, const uint8_t* alpha, - uint8_t* rk_out); - -/** - * Scalar multiplication by the Orchard SpendAuth basepoint. - * Computes res = k * G_spendauth where G_spendauth = - * GroupHash^P("z.cash:Orchard", "G"). - * - * @param k Scalar to multiply (bignum256) - * @param res Output point - */ -void redpallas_scalar_mult_spendauth_G(const bignum256* k, curve_point* res); - -/** - * Progress-reporting form of redpallas_scalar_mult_spendauth_G(). - * - * The callback receives only the fixed public loop counter; it is independent - * of scalar bits and therefore safe to use while deriving ak from secret ask. - */ -void redpallas_scalar_mult_spendauth_G_progress( - const bignum256* k, curve_point* res, redpallas_progress_callback progress, - void* progress_context); - -#endif diff --git a/deps/crypto/trezor-crypto/rfc6979.c b/deps/crypto/trezor-crypto/rfc6979.c deleted file mode 100644 index 96f4dfcbf..000000000 --- a/deps/crypto/trezor-crypto/rfc6979.c +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Copyright (c) 2013-2014 Tomas Dzetkulic - * Copyright (c) 2013-2014 Pavol Rusnak - * Copyright (c) 2015 Jochen Hoenicke - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ -#include - -#include "hmac_drbg.h" -#include "memzero.h" -#include "rfc6979.h" - -void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, - const ecdsa_curve *curve, rfc6979_state *state) { - if (curve) { - bignum256 hash_bn = {0}; - bn_read_be(hash, &hash_bn); - - // Make sure hash is partly reduced modulo order - assert(bn_bitcount(&curve->order) >= 256); - bn_mod(&hash_bn, &curve->order); - - uint8_t hash_reduced[32] = {0}; - bn_write_be(&hash_bn, hash_reduced); - memzero(&hash_bn, sizeof(hash_bn)); - hmac_drbg_init(state, priv_key, 32, hash_reduced, 32); - memzero(hash_reduced, sizeof(hash_reduced)); - } else { - hmac_drbg_init(state, priv_key, 32, hash, 32); - } -} - -// generate next number from deterministic random number generator -void generate_rfc6979(uint8_t rnd[32], rfc6979_state *state) { - hmac_drbg_generate(state, rnd, 32); -} - -// generate K in a deterministic way, according to RFC6979 -// http://tools.ietf.org/html/rfc6979 -void generate_k_rfc6979(bignum256 *k, rfc6979_state *state) { - uint8_t buf[32] = {0}; - generate_rfc6979(buf, state); - bn_read_be(buf, k); - memzero(buf, sizeof(buf)); -} diff --git a/deps/crypto/trezor-crypto/rfc6979.h b/deps/crypto/trezor-crypto/rfc6979.h deleted file mode 100644 index e4cb9ff04..000000000 --- a/deps/crypto/trezor-crypto/rfc6979.h +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright (c) 2013-2014 Tomas Dzetkulic - * Copyright (c) 2013-2014 Pavol Rusnak - * Copyright (c) 2015-2017 Jochen Hoenicke - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __RFC6979_H__ -#define __RFC6979_H__ - -#include -#include "bignum.h" -#include "ecdsa.h" -#include "hmac_drbg.h" - -// rfc6979 pseudo random number generator state -typedef HMAC_DRBG_CTX rfc6979_state; - -void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, - const ecdsa_curve *curve, rfc6979_state *rng); -void generate_rfc6979(uint8_t rnd[32], rfc6979_state *rng); -void generate_k_rfc6979(bignum256 *k, rfc6979_state *rng); - -#endif diff --git a/deps/crypto/trezor-crypto/ripemd160.c b/deps/crypto/trezor-crypto/ripemd160.c deleted file mode 100644 index 5aef8b8d3..000000000 --- a/deps/crypto/trezor-crypto/ripemd160.c +++ /dev/null @@ -1,343 +0,0 @@ -/* - * RIPE MD-160 implementation - * - * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * This file is part of mbed TLS (https://tls.mbed.org) - */ - -/* - * The RIPEMD-160 algorithm was designed by RIPE in 1996 - * http://homes.esat.kuleuven.be/~bosselae/ripemd160.html - * http://ehash.iaik.tugraz.at/wiki/RIPEMD-160 - */ - -#include - -#include "ripemd160.h" -#include "memzero.h" - -/* - * 32-bit integer manipulation macros (little endian) - */ -#ifndef GET_UINT32_LE -#define GET_UINT32_LE(n,b,i) \ -{ \ - (n) = ( (uint32_t) (b)[(i) ] ) \ - | ( (uint32_t) (b)[(i) + 1] << 8 ) \ - | ( (uint32_t) (b)[(i) + 2] << 16 ) \ - | ( (uint32_t) (b)[(i) + 3] << 24 ); \ -} -#endif - -#ifndef PUT_UINT32_LE -#define PUT_UINT32_LE(n,b,i) \ -{ \ - (b)[(i) ] = (uint8_t) ( ( (n) ) & 0xFF ); \ - (b)[(i) + 1] = (uint8_t) ( ( (n) >> 8 ) & 0xFF ); \ - (b)[(i) + 2] = (uint8_t) ( ( (n) >> 16 ) & 0xFF ); \ - (b)[(i) + 3] = (uint8_t) ( ( (n) >> 24 ) & 0xFF ); \ -} -#endif - -/* - * RIPEMD-160 context setup - */ -void ripemd160_Init(RIPEMD160_CTX *ctx) -{ - memzero(ctx, sizeof(RIPEMD160_CTX)); - ctx->total[0] = 0; - ctx->total[1] = 0; - ctx->state[0] = 0x67452301; - ctx->state[1] = 0xEFCDAB89; - ctx->state[2] = 0x98BADCFE; - ctx->state[3] = 0x10325476; - ctx->state[4] = 0xC3D2E1F0; -} - -#if !defined(MBEDTLS_RIPEMD160_PROCESS_ALT) -/* - * Process one block - */ -void ripemd160_process( RIPEMD160_CTX *ctx, const uint8_t data[RIPEMD160_BLOCK_LENGTH] ) -{ - uint32_t A = 0, B = 0, C = 0, D = 0, E = 0, Ap = 0, Bp = 0, Cp = 0, Dp = 0, Ep = 0, X[16] = {0}; - - GET_UINT32_LE( X[ 0], data, 0 ); - GET_UINT32_LE( X[ 1], data, 4 ); - GET_UINT32_LE( X[ 2], data, 8 ); - GET_UINT32_LE( X[ 3], data, 12 ); - GET_UINT32_LE( X[ 4], data, 16 ); - GET_UINT32_LE( X[ 5], data, 20 ); - GET_UINT32_LE( X[ 6], data, 24 ); - GET_UINT32_LE( X[ 7], data, 28 ); - GET_UINT32_LE( X[ 8], data, 32 ); - GET_UINT32_LE( X[ 9], data, 36 ); - GET_UINT32_LE( X[10], data, 40 ); - GET_UINT32_LE( X[11], data, 44 ); - GET_UINT32_LE( X[12], data, 48 ); - GET_UINT32_LE( X[13], data, 52 ); - GET_UINT32_LE( X[14], data, 56 ); - GET_UINT32_LE( X[15], data, 60 ); - - A = Ap = ctx->state[0]; - B = Bp = ctx->state[1]; - C = Cp = ctx->state[2]; - D = Dp = ctx->state[3]; - E = Ep = ctx->state[4]; - -#define F1( x, y, z ) ( x ^ y ^ z ) -#define F2( x, y, z ) ( ( x & y ) | ( ~x & z ) ) -#define F3( x, y, z ) ( ( x | ~y ) ^ z ) -#define F4( x, y, z ) ( ( x & z ) | ( y & ~z ) ) -#define F5( x, y, z ) ( x ^ ( y | ~z ) ) - -#define S( x, n ) ( ( x << n ) | ( x >> (32 - n) ) ) - -#define P( a, b, c, d, e, r, s, f, k ) \ - a += f( b, c, d ) + X[r] + k; \ - a = S( a, s ) + e; \ - c = S( c, 10 ); - -#define P2( a, b, c, d, e, r, s, rp, sp ) \ - P( a, b, c, d, e, r, s, F, K ); \ - P( a ## p, b ## p, c ## p, d ## p, e ## p, rp, sp, Fp, Kp ); - -#define F F1 -#define K 0x00000000 -#define Fp F5 -#define Kp 0x50A28BE6 - P2( A, B, C, D, E, 0, 11, 5, 8 ); - P2( E, A, B, C, D, 1, 14, 14, 9 ); - P2( D, E, A, B, C, 2, 15, 7, 9 ); - P2( C, D, E, A, B, 3, 12, 0, 11 ); - P2( B, C, D, E, A, 4, 5, 9, 13 ); - P2( A, B, C, D, E, 5, 8, 2, 15 ); - P2( E, A, B, C, D, 6, 7, 11, 15 ); - P2( D, E, A, B, C, 7, 9, 4, 5 ); - P2( C, D, E, A, B, 8, 11, 13, 7 ); - P2( B, C, D, E, A, 9, 13, 6, 7 ); - P2( A, B, C, D, E, 10, 14, 15, 8 ); - P2( E, A, B, C, D, 11, 15, 8, 11 ); - P2( D, E, A, B, C, 12, 6, 1, 14 ); - P2( C, D, E, A, B, 13, 7, 10, 14 ); - P2( B, C, D, E, A, 14, 9, 3, 12 ); - P2( A, B, C, D, E, 15, 8, 12, 6 ); -#undef F -#undef K -#undef Fp -#undef Kp - -#define F F2 -#define K 0x5A827999 -#define Fp F4 -#define Kp 0x5C4DD124 - P2( E, A, B, C, D, 7, 7, 6, 9 ); - P2( D, E, A, B, C, 4, 6, 11, 13 ); - P2( C, D, E, A, B, 13, 8, 3, 15 ); - P2( B, C, D, E, A, 1, 13, 7, 7 ); - P2( A, B, C, D, E, 10, 11, 0, 12 ); - P2( E, A, B, C, D, 6, 9, 13, 8 ); - P2( D, E, A, B, C, 15, 7, 5, 9 ); - P2( C, D, E, A, B, 3, 15, 10, 11 ); - P2( B, C, D, E, A, 12, 7, 14, 7 ); - P2( A, B, C, D, E, 0, 12, 15, 7 ); - P2( E, A, B, C, D, 9, 15, 8, 12 ); - P2( D, E, A, B, C, 5, 9, 12, 7 ); - P2( C, D, E, A, B, 2, 11, 4, 6 ); - P2( B, C, D, E, A, 14, 7, 9, 15 ); - P2( A, B, C, D, E, 11, 13, 1, 13 ); - P2( E, A, B, C, D, 8, 12, 2, 11 ); -#undef F -#undef K -#undef Fp -#undef Kp - -#define F F3 -#define K 0x6ED9EBA1 -#define Fp F3 -#define Kp 0x6D703EF3 - P2( D, E, A, B, C, 3, 11, 15, 9 ); - P2( C, D, E, A, B, 10, 13, 5, 7 ); - P2( B, C, D, E, A, 14, 6, 1, 15 ); - P2( A, B, C, D, E, 4, 7, 3, 11 ); - P2( E, A, B, C, D, 9, 14, 7, 8 ); - P2( D, E, A, B, C, 15, 9, 14, 6 ); - P2( C, D, E, A, B, 8, 13, 6, 6 ); - P2( B, C, D, E, A, 1, 15, 9, 14 ); - P2( A, B, C, D, E, 2, 14, 11, 12 ); - P2( E, A, B, C, D, 7, 8, 8, 13 ); - P2( D, E, A, B, C, 0, 13, 12, 5 ); - P2( C, D, E, A, B, 6, 6, 2, 14 ); - P2( B, C, D, E, A, 13, 5, 10, 13 ); - P2( A, B, C, D, E, 11, 12, 0, 13 ); - P2( E, A, B, C, D, 5, 7, 4, 7 ); - P2( D, E, A, B, C, 12, 5, 13, 5 ); -#undef F -#undef K -#undef Fp -#undef Kp - -#define F F4 -#define K 0x8F1BBCDC -#define Fp F2 -#define Kp 0x7A6D76E9 - P2( C, D, E, A, B, 1, 11, 8, 15 ); - P2( B, C, D, E, A, 9, 12, 6, 5 ); - P2( A, B, C, D, E, 11, 14, 4, 8 ); - P2( E, A, B, C, D, 10, 15, 1, 11 ); - P2( D, E, A, B, C, 0, 14, 3, 14 ); - P2( C, D, E, A, B, 8, 15, 11, 14 ); - P2( B, C, D, E, A, 12, 9, 15, 6 ); - P2( A, B, C, D, E, 4, 8, 0, 14 ); - P2( E, A, B, C, D, 13, 9, 5, 6 ); - P2( D, E, A, B, C, 3, 14, 12, 9 ); - P2( C, D, E, A, B, 7, 5, 2, 12 ); - P2( B, C, D, E, A, 15, 6, 13, 9 ); - P2( A, B, C, D, E, 14, 8, 9, 12 ); - P2( E, A, B, C, D, 5, 6, 7, 5 ); - P2( D, E, A, B, C, 6, 5, 10, 15 ); - P2( C, D, E, A, B, 2, 12, 14, 8 ); -#undef F -#undef K -#undef Fp -#undef Kp - -#define F F5 -#define K 0xA953FD4E -#define Fp F1 -#define Kp 0x00000000 - P2( B, C, D, E, A, 4, 9, 12, 8 ); - P2( A, B, C, D, E, 0, 15, 15, 5 ); - P2( E, A, B, C, D, 5, 5, 10, 12 ); - P2( D, E, A, B, C, 9, 11, 4, 9 ); - P2( C, D, E, A, B, 7, 6, 1, 12 ); - P2( B, C, D, E, A, 12, 8, 5, 5 ); - P2( A, B, C, D, E, 2, 13, 8, 14 ); - P2( E, A, B, C, D, 10, 12, 7, 6 ); - P2( D, E, A, B, C, 14, 5, 6, 8 ); - P2( C, D, E, A, B, 1, 12, 2, 13 ); - P2( B, C, D, E, A, 3, 13, 13, 6 ); - P2( A, B, C, D, E, 8, 14, 14, 5 ); - P2( E, A, B, C, D, 11, 11, 0, 15 ); - P2( D, E, A, B, C, 6, 8, 3, 13 ); - P2( C, D, E, A, B, 15, 5, 9, 11 ); - P2( B, C, D, E, A, 13, 6, 11, 11 ); -#undef F -#undef K -#undef Fp -#undef Kp - - C = ctx->state[1] + C + Dp; - ctx->state[1] = ctx->state[2] + D + Ep; - ctx->state[2] = ctx->state[3] + E + Ap; - ctx->state[3] = ctx->state[4] + A + Bp; - ctx->state[4] = ctx->state[0] + B + Cp; - ctx->state[0] = C; -} -#endif /* !MBEDTLS_RIPEMD160_PROCESS_ALT */ - -/* - * RIPEMD-160 process buffer - */ -void ripemd160_Update( RIPEMD160_CTX *ctx, const uint8_t *input, uint32_t ilen ) -{ - uint32_t fill = 0; - uint32_t left = 0; - - if( ilen == 0 ) - return; - - left = ctx->total[0] & 0x3F; - fill = RIPEMD160_BLOCK_LENGTH - left; - - ctx->total[0] += (uint32_t) ilen; - ctx->total[0] &= 0xFFFFFFFF; - - if( ctx->total[0] < (uint32_t) ilen ) - ctx->total[1]++; - - if( left && ilen >= fill ) - { - memcpy( (void *) (ctx->buffer + left), input, fill ); - ripemd160_process( ctx, ctx->buffer ); - input += fill; - ilen -= fill; - left = 0; - } - - while( ilen >= RIPEMD160_BLOCK_LENGTH ) - { - ripemd160_process( ctx, input ); - input += RIPEMD160_BLOCK_LENGTH; - ilen -= RIPEMD160_BLOCK_LENGTH; - } - - if( ilen > 0 ) - { - memcpy( (void *) (ctx->buffer + left), input, ilen ); - } -} - -static const uint8_t ripemd160_padding[RIPEMD160_BLOCK_LENGTH] = -{ - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -/* - * RIPEMD-160 final digest - */ -void ripemd160_Final( RIPEMD160_CTX *ctx, uint8_t output[RIPEMD160_DIGEST_LENGTH] ) -{ - uint32_t last = 0; uint32_t padn = 0; - uint32_t high = 0; uint32_t low = 0; - uint8_t msglen[8] = {0}; - - high = ( ctx->total[0] >> 29 ) - | ( ctx->total[1] << 3 ); - low = ( ctx->total[0] << 3 ); - - PUT_UINT32_LE( low, msglen, 0 ); - PUT_UINT32_LE( high, msglen, 4 ); - - last = ctx->total[0] & 0x3F; - padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); - - ripemd160_Update( ctx, ripemd160_padding, padn ); - ripemd160_Update( ctx, msglen, 8 ); - - PUT_UINT32_LE( ctx->state[0], output, 0 ); - PUT_UINT32_LE( ctx->state[1], output, 4 ); - PUT_UINT32_LE( ctx->state[2], output, 8 ); - PUT_UINT32_LE( ctx->state[3], output, 12 ); - PUT_UINT32_LE( ctx->state[4], output, 16 ); - - memzero(ctx, sizeof(RIPEMD160_CTX)); -} - -/* - * output = RIPEMD-160( input buffer ) - */ -void ripemd160(const uint8_t *msg, uint32_t msg_len, uint8_t hash[RIPEMD160_DIGEST_LENGTH]) -{ - RIPEMD160_CTX ctx = {0}; - ripemd160_Init( &ctx ); - ripemd160_Update( &ctx, msg, msg_len ); - ripemd160_Final( &ctx, hash ); -} diff --git a/deps/crypto/trezor-crypto/ripemd160.h b/deps/crypto/trezor-crypto/ripemd160.h deleted file mode 100644 index 8256b08a1..000000000 --- a/deps/crypto/trezor-crypto/ripemd160.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef __RIPEMD160_H__ -#define __RIPEMD160_H__ - -#include - -#define RIPEMD160_BLOCK_LENGTH 64 -#define RIPEMD160_DIGEST_LENGTH 20 - -typedef struct _RIPEMD160_CTX { - uint32_t total[2]; /*!< number of bytes processed */ - uint32_t state[5]; /*!< intermediate digest state */ - uint8_t buffer[RIPEMD160_BLOCK_LENGTH]; /*!< data block being processed */ -} RIPEMD160_CTX; - -void ripemd160_Init(RIPEMD160_CTX *ctx); -void ripemd160_Update(RIPEMD160_CTX *ctx, const uint8_t *input, uint32_t ilen); -void ripemd160_Final(RIPEMD160_CTX *ctx, - uint8_t output[RIPEMD160_DIGEST_LENGTH]); -void ripemd160(const uint8_t *msg, uint32_t msg_len, - uint8_t hash[RIPEMD160_DIGEST_LENGTH]); - -#endif diff --git a/deps/crypto/trezor-crypto/schnorr.c b/deps/crypto/trezor-crypto/schnorr.c deleted file mode 100644 index ac704fba7..000000000 --- a/deps/crypto/trezor-crypto/schnorr.c +++ /dev/null @@ -1,215 +0,0 @@ -/** - * Copyright (c) 2021 The Bitcoin ABC developers - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "schnorr.h" -#include "hmac_drbg.h" -#include "memzero.h" -#include "rfc6979.h" - -#include -#include -#include - -static int jacobi(const bignum256 *_n, const bignum256 *_k) { - assert(!bn_is_zero(_k) && bn_is_odd(_k)); - - bignum256 n_copy = {0}; - bignum256 *n = &n_copy; - bn_copy(_n, n); - - bignum256 k_copy = {0}; - bignum256 *k = &k_copy; - bn_copy(_k, k); - - int t = 0; - while (!bn_is_zero(n)) { - while (bn_is_even(n)) { - // jacobi(2 * n, k) = jacobi(n, k) if k = 1 (mod 8) or k = 7 (mod 8) - // jacobi(2 * n, k) = -jacobi(n, k) if k = 3 (mod 8) or k = 5 (mod 8) - uint32_t r = k->val[0] & 0x07; - t ^= (r == 3 || r == 5); - bn_rshift(n); - } - - if (bn_is_less(n, k)) { - // jacobi(n, k) = jacobi(k, n) if k = n = 1 (mod 4) - // jacobi(n, k) = -jacobi(k, n) if k = n = 3 (mod 4) - t ^= ((n->val[0] & k->val[0] & 3) == 3); - bignum256 *temp = n; - n = k; - k = temp; - } - - // jacobi(n, k) = jacobi(n - k, k) - bn_subtract(n, k, n); - } - - int k_is_one = bn_is_one(k); - - // Cleanup - memzero(&n_copy, sizeof(n_copy)); - memzero(&k_copy, sizeof(k_copy)); - - // Map t: [0] => 1, [1] => -1 - t = -2 * t + 1; - - return k_is_one * t; -} - -static int is_non_quad_residue(const bignum256 *n, const bignum256 *prime) { - return jacobi(n, prime) == -1; -} - -static int generate_k_schnorr(const ecdsa_curve *curve, const uint8_t *priv_key, - const uint8_t *hash, bignum256 *k) { - rfc6979_state rng = {0}; - uint8_t hmac_data[SHA256_DIGEST_LENGTH + 16] = {0}; - - /* - * Init the HMAC with additional data specific to Schnorr. This prevents from - * leaking the private key in the case the same message is signed with both - * Schnorr and ECDSA. - */ - memcpy(hmac_data, hash, SHA256_DIGEST_LENGTH); - memcpy(hmac_data + SHA256_DIGEST_LENGTH, "Schnorr+SHA256 ", 16); - hmac_drbg_init(&rng, priv_key, 32, hmac_data, SHA256_DIGEST_LENGTH + 16); - - for (int i = 0; i < 10000; i++) { - generate_k_rfc6979(k, &rng); - // If k is too big or too small, we don't like it - if (bn_is_zero(k) || !bn_is_less(k, &curve->order)) { - continue; - } - - memzero(&rng, sizeof(rng)); - return 0; - } - - memzero(&rng, sizeof(rng)); - return 1; -} - -// e = H(Rx, pub_key, msg_hash) -static void calc_e(const ecdsa_curve *curve, const bignum256 *Rx, - const uint8_t pub_key[33], const uint8_t *msg_hash, - bignum256 *e) { - uint8_t Rxbuf[32] = {0}; - SHA256_CTX ctx = {0}; - uint8_t digest[SHA256_DIGEST_LENGTH] = {0}; - - bn_write_be(Rx, Rxbuf); - - sha256_Init(&ctx); - sha256_Update(&ctx, Rxbuf, sizeof(Rxbuf)); - sha256_Update(&ctx, pub_key, 33); - sha256_Update(&ctx, msg_hash, SHA256_DIGEST_LENGTH); - sha256_Final(&ctx, digest); - - bn_read_be(digest, e); - bn_fast_mod(e, &curve->order); - bn_mod(e, &curve->order); -} - -int schnorr_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, - const uint8_t *digest, uint8_t *sign) { - uint8_t pub_key[33] = {0}; - curve_point R = {0}; - bignum256 e = {0}, s = {0}, k = {0}; - - if (ecdsa_get_public_key33(curve, priv_key, pub_key) != 0) { - return 1; - } - - // Compute k - if (generate_k_schnorr(curve, priv_key, digest, &k) != 0) { - memzero(&k, sizeof(k)); - return 1; - } - - // Compute R = k * G - scalar_multiply(curve, &k, &R); - - // If R.y is not a quadratic residue, negate the nonce - bn_cnegate(is_non_quad_residue(&R.y, &curve->prime), &k, &curve->order); - - bn_write_be(&R.x, sign); - - // Compute e = H(Rx, pub_key, msg_hash) - calc_e(curve, &R.x, pub_key, digest, &e); - - // Compute s = k + e * priv_key - bn_read_be(priv_key, &s); - bn_multiply(&e, &s, &curve->order); - bn_addmod(&s, &k, &curve->order); - memzero(&k, sizeof(k)); - bn_mod(&s, &curve->order); - bn_write_be(&s, sign + 32); - - return 0; -} - -int schnorr_verify_digest(const ecdsa_curve *curve, const uint8_t *pub_key, - const uint8_t *digest, const uint8_t *sign) { - curve_point P = {0}, sG = {0}, R = {0}; - bignum256 r = {0}, s = {0}, e = {0}; - - bn_read_be(sign, &r); - bn_read_be(sign + 32, &s); - - // Signature is invalid if s >= n or r >= p. - if (!bn_is_less(&r, &curve->prime) || !bn_is_less(&s, &curve->order)) { - return 1; - } - - if (!ecdsa_read_pubkey(curve, pub_key, &P)) { - return 2; - } - - // Compute e - calc_e(curve, &r, pub_key, digest, &e); - - if (bn_is_zero(&e)) { - return 3; - } - - // Compute R = sG - eP - bn_subtract(&curve->order, &e, &e); - scalar_multiply(curve, &s, &sG); - point_multiply(curve, &e, &P, &R); - point_add(curve, &sG, &R); - - if (point_is_infinity(&R)) { - return 4; - } - - // Check r == Rx - if (!bn_is_equal(&r, &R.x)) { - return 5; - } - - // Check Ry is a quadratic residue - if (is_non_quad_residue(&R.y, &curve->prime)) { - return 6; - } - - return 0; -} diff --git a/deps/crypto/trezor-crypto/schnorr.h b/deps/crypto/trezor-crypto/schnorr.h deleted file mode 100644 index 781452bab..000000000 --- a/deps/crypto/trezor-crypto/schnorr.h +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (c) 2021 The Bitcoin ABC developers - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __SCHNORR_H__ -#define __SCHNORR_H__ - -#include "ecdsa.h" - -/* A Schnorr signature is always 64 bytes */ -#define SCHNORR_SIG_LENGTH 64 - -// sign/verify returns 0 if operation succeeded -int schnorr_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, - const uint8_t *digest, uint8_t *result); -int schnorr_verify_digest(const ecdsa_curve *curve, const uint8_t *pub_key, - const uint8_t *msg_hash, const uint8_t *sign); -#endif diff --git a/deps/crypto/trezor-crypto/script.c b/deps/crypto/trezor-crypto/script.c deleted file mode 100644 index cbc71b219..000000000 --- a/deps/crypto/trezor-crypto/script.c +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Copyright (c) 2016 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "script.h" -#include -#include "base58.h" - -int script_output_to_address(const uint8_t *script, int scriptlen, char *addr, - int addrsize) { - uint8_t raw[35] = {0}; - - // P2PKH - if (scriptlen == 25 && script[0] == 0x76 && script[1] == 0xA9 && - script[2] == 0x14 && script[23] == 0x88 && script[24] == 0xAC) { - raw[0] = 0x00; - memcpy(raw + 1, script + 3, 20); - return base58_encode_check(raw, 1 + 20, HASHER_SHA2D, addr, addrsize); - } - - // P2SH - if (scriptlen == 23 && script[0] == 0xA9 && script[1] == 0x14 && - script[22] == 0x87) { - raw[0] = 0x05; - memcpy(raw + 1, script + 2, 20); - return base58_encode_check(raw, 1 + 20, HASHER_SHA2D, addr, addrsize); - } - - // P2WPKH - if (scriptlen == 22 && script[0] == 0x00 && script[1] == 0x14) { - raw[0] = 0x06; - raw[1] = 0x00; - raw[2] = 0x00; - memcpy(raw + 3, script + 2, 20); - return base58_encode_check(raw, 3 + 20, HASHER_SHA2D, addr, addrsize); - } - - // P2WSH - if (scriptlen == 34 && script[0] == 0x00 && script[1] == 0x20) { - raw[0] = 0x0A; - raw[1] = 0x00; - raw[2] = 0x00; - memcpy(raw + 3, script + 2, 32); - return base58_encode_check(raw, 3 + 32, HASHER_SHA2D, addr, addrsize); - } - - return 0; -} diff --git a/deps/crypto/trezor-crypto/script.h b/deps/crypto/trezor-crypto/script.h deleted file mode 100644 index c9cc003b8..000000000 --- a/deps/crypto/trezor-crypto/script.h +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2016 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __SCRIPT_H__ -#define __SCRIPT_H__ - -#include - -int script_output_to_address(const uint8_t *script, int scriptlen, char *addr, - int addrsize); - -#endif diff --git a/deps/crypto/trezor-crypto/secp256k1.c b/deps/crypto/trezor-crypto/secp256k1.c deleted file mode 100644 index 34ccaaacb..000000000 --- a/deps/crypto/trezor-crypto/secp256k1.c +++ /dev/null @@ -1,94 +0,0 @@ -/** - * Copyright (c) 2013-2014 Tomas Dzetkulic - * Copyright (c) 2013-2014 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "secp256k1.h" - -const ecdsa_curve secp256k1 = { - /* .prime */ {/*.val =*/{0x1ffffc2f, 0x1ffffff7, 0x1fffffff, 0x1fffffff, - 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, - 0xffffff}}, - - /* G */ - {/*.x =*/{/*.val =*/{0x16f81798, 0x0f940ad8, 0x138a3656, 0x17f9b65b, - 0x10b07029, 0x114ae743, 0x0eb15681, 0x0fdf3b97, - 0x79be66}}, - /*.y =*/{/*.val =*/{0x1b10d4b8, 0x023e847f, 0x01550667, 0x0f68914d, - 0x108a8fd1, 0x1dfe0708, 0x11957693, 0x0ee4d478, - 0x483ada}}}, - - /* order */ - {/*.val =*/{0x10364141, 0x1e92f466, 0x12280eef, 0x1db9cd5e, 0x1fffebaa, - 0x1fffffff, 0x1fffffff, 0x1fffffff, 0xffffff}}, - - /* order_half */ - {/*.val =*/{0x081b20a0, 0x1f497a33, 0x09140777, 0x0edce6af, 0x1ffff5d5, - 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x7fffff}}, - - /* a */ 0, - - /* b */ {/*.val =*/{7}} - -#if USE_PRECOMPUTED_CP - , - /* cp */ - { -#include "secp256k1.table" - } -#endif -}; - -const curve_info secp256k1_info = { - .bip32_name = "Bitcoin seed", - .params = &secp256k1, - .hasher_base58 = HASHER_SHA2D, - .hasher_sign = HASHER_SHA2D, - .hasher_pubkey = HASHER_SHA2_RIPEMD, - .hasher_script = HASHER_SHA2, -}; - -const curve_info secp256k1_decred_info = { - .bip32_name = "Bitcoin seed", - .params = &secp256k1, - .hasher_base58 = HASHER_BLAKED, - .hasher_sign = HASHER_BLAKE, - .hasher_pubkey = HASHER_BLAKE_RIPEMD, - .hasher_script = HASHER_BLAKE, -}; - -const curve_info secp256k1_groestl_info = { - .bip32_name = "Bitcoin seed", - .params = &secp256k1, - .hasher_base58 = HASHER_GROESTLD_TRUNC, - .hasher_sign = HASHER_SHA2, - .hasher_pubkey = HASHER_SHA2_RIPEMD, - .hasher_script = HASHER_SHA2, -}; - -const curve_info secp256k1_smart_info = { - .bip32_name = "Bitcoin seed", - .params = &secp256k1, - .hasher_base58 = HASHER_SHA3K, - .hasher_sign = HASHER_SHA2, - .hasher_pubkey = HASHER_SHA2_RIPEMD, - .hasher_script = HASHER_SHA2, -}; diff --git a/deps/crypto/trezor-crypto/secp256k1.h b/deps/crypto/trezor-crypto/secp256k1.h deleted file mode 100644 index 3b45e48fe..000000000 --- a/deps/crypto/trezor-crypto/secp256k1.h +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright (c) 2013-2014 Tomas Dzetkulic - * Copyright (c) 2013-2014 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __SECP256K1_H__ -#define __SECP256K1_H__ - -#include - -#include "bip32.h" -#include "ecdsa.h" - -extern const ecdsa_curve secp256k1; -extern const curve_info secp256k1_info; -extern const curve_info secp256k1_decred_info; -extern const curve_info secp256k1_groestl_info; -extern const curve_info secp256k1_smart_info; - -#endif diff --git a/deps/crypto/trezor-crypto/secp256k1.table b/deps/crypto/trezor-crypto/secp256k1.table deleted file mode 100644 index 0fa87a8b1..000000000 --- a/deps/crypto/trezor-crypto/secp256k1.table +++ /dev/null @@ -1,1664 +0,0 @@ - { - /* 1*16^0*G: */ - {{{0x16f81798, 0x0f940ad8, 0x138a3656, 0x17f9b65b, 0x10b07029, 0x114ae743, 0x0eb15681, 0x0fdf3b97, 0x79be66}}, - {{0x1b10d4b8, 0x023e847f, 0x01550667, 0x0f68914d, 0x108a8fd1, 0x1dfe0708, 0x11957693, 0x0ee4d478, 0x483ada}}}, - /* 3*16^0*G: */ - {{{0x1ce036f9, 0x100f889d, 0x1be66c21, 0x03908b06, 0x15229b53, 0x07c2fc4e, 0x0c4124d1, 0x00324b18, 0xf9308a}}, - {{0x04b8e672, 0x05cfebac, 0x1088c6db, 0x01533269, 0x1f356650, 0x1bf3151b, 0x00503f8c, 0x01ec65bd, 0x388f7b}}}, - /* 5*16^0*G: */ - {{{0x1240efe4, 0x1d46ab4d, 0x1866adf2, 0x17097bb8, 0x05128e88, 0x1392852e, 0x024d56d2, 0x09a340e4, 0x2f8bde}}, - {{0x06ac62d6, 0x0543e9d5, 0x035a1037, 0x104e3756, 0x1c426f78, 0x14eed364, 0x0f5b536e, 0x04c6dcbc, 0xd8ac22}}}, - /* 7*16^0*G: */ - {{{0x0ac4f9bc, 0x095eef6e, 0x0c38e73a, 0x0336fc06, 0x07a0e3d4, 0x19b2f975, 0x13aa8e63, 0x0c8dcbb6, 0x5cbdf0}}, - {{0x087264da, 0x08413140, 0x1f79ed69, 0x07a17027, 0x054dba81, 0x06b6c30d, 0x05828c5e, 0x081744ab, 0x6aebca}}}, - /* 9*16^0*G: */ - {{{0x1c27ccbe, 0x1af8886f, 0x15f9c530, 0x0f2d2e98, 0x19abde09, 0x0bc54faa, 0x194c26b4, 0x1c5e18fe, 0xacd484}}, - {{0x064f9c37, 0x0e613156, 0x17e383c1, 0x1111486e, 0x161e9add, 0x04b8bb1d, 0x07f590e0, 0x043614fb, 0xcc3389}}}, - /* 11*16^0*G: */ - {{{0x1da008cb, 0x1f60bc4a, 0x105e246e, 0x133017cb, 0x05aac564, 0x1235b863, 0x04797bd0, 0x1f0b1528, 0x774ae7}}, - {{0x0953c61b, 0x00eba64e, 0x1e75aa0c, 0x1b63c5bf, 0x1b365372, 0x0eab6bdb, 0x1864090f, 0x065d6d6b, 0xd984a0}}}, - /* 13*16^0*G: */ - {{{0x19405aa8, 0x176efc78, 0x03963377, 0x0bf78cc2, 0x08651b07, 0x0902e1ba, 0x022f1f47, 0x185b2ea5, 0xf28773}}, - {{0x1b03ed81, 0x0dae5a96, 0x07ea47ca, 0x140db4a4, 0x1af473a1, 0x0975b2e6, 0x0a25d608, 0x05d1b101, 0xab090}}}, - /* 15*16^0*G: */ - {{{0x027e080e, 0x056de7c7, 0x017de791, 0x0b28de79, 0x1f41131e, 0x0d7184af, 0x0a596919, 0x09efa87d, 0xd7924d}}, - {{0x16a26b58, 0x0826e4ff, 0x05b4e971, 0x015e57b1, 0x06defea4, 0x17611466, 0x0a9a0e10, 0x0e550d8e, 0x581e28}}} - }, - { - /* 1*16^1*G: */ - {{{0x0a6dec0a, 0x027744f1, 0x1e96ba71, 0x0626d370, 0x03e97b2a, 0x155e10e1, 0x1b14c046, 0x1276b3d3, 0xe60fce}}, - {{0x09616821, 0x0f996673, 0x148fc2f8, 0x0d123c89, 0x13710129, 0x0f9a7abc, 0x164a76e6, 0x0e733cb2, 0xf7e350}}}, - /* 3*16^1*G: */ - {{{0x1118e5c3, 0x1ec38550, 0x0afaf066, 0x0f364e8a, 0x05b4bfc5, 0x12b77a73, 0x01f6d105, 0x0bb2c8a6, 0x6eca33}}, - {{0x05a08668, 0x0c517bc0, 0x1e3b0d12, 0x12d47477, 0x075a03a4, 0x0bc83a5c, 0x1c4164bd, 0x16af4f40, 0xd50123}}}, - /* 5*16^1*G: */ - {{{0x0f87f62e, 0x16698f0a, 0x1c5849c3, 0x0dcc70c6, 0x059f010e, 0x1a2769a3, 0x03b035f1, 0x17de37f2, 0xe9623b}}, - {{0x044ee737, 0x1809f57d, 0x1a211394, 0x008793ba, 0x0a929fe6, 0x0a9d476d, 0x07a783fa, 0x07697853, 0x38a974}}}, - /* 7*16^1*G: */ - {{{0x0a8d733c, 0x18556fc1, 0x1f2a3e7a, 0x04e97ec5, 0x0d682ffc, 0x11b79040, 0x16e82212, 0x0e7ca2c3, 0xbc82dd}}, - {{0x147797f0, 0x13c30827, 0x0e25cc07, 0x074175ce, 0x102dfae9, 0x1a5fb8cf, 0x12b152a6, 0x07408963, 0xe5f28c}}}, - /* 9*16^1*G: */ - {{{0x1fbc7671, 0x1f7f118a, 0x01638cb5, 0x1e3790a5, 0x0f490743, 0x08e70bcc, 0x0847480a, 0x0918ecae, 0x8e3d12}}, - {{0x18717dec, 0x178ee320, 0x0f85129f, 0x0a57554c, 0x1e90eb93, 0x0070c9c9, 0x0e07d912, 0x1c21d9f9, 0x99a48}}}, - /* 11*16^1*G: */ - {{{0x1eb31db2, 0x1943a195, 0x1d41a83c, 0x15d04f11, 0x0a2b68fc, 0x0c9f6844, 0x126225a8, 0x15444694, 0x78a891}}, - {{0x19fa4343, 0x034eb11d, 0x002e0b4c, 0x0f379bb0, 0x02df6543, 0x192a9398, 0x172ff3d7, 0x0b7d6a06, 0x6912a3}}}, - /* 13*16^1*G: */ - {{{0x0db0e595, 0x09a47bbc, 0x0820aed9, 0x0c7973f7, 0x076eba71, 0x1bb2c0b0, 0x0c5f5f38, 0x030abb63, 0x7d8678}}, - {{0x1c733de8, 0x0ca8f1d5, 0x09754ca6, 0x0f089c1c, 0x18838293, 0x1715f6a7, 0x01dcb958, 0x1bfd90df, 0xe2b99a}}}, - /* 15*16^1*G: */ - {{{0x16060dfc, 0x047f7c28, 0x179a8a80, 0x08bf0840, 0x0b086765, 0x05cee20d, 0x0b212125, 0x01e00b05, 0xddc531}}, - {{0x07820ca8, 0x1afc55b7, 0x1411cc3e, 0x175f8d57, 0x10e9041d, 0x15b6e647, 0x1a480646, 0x075e41b2, 0xba0d2f}}} - }, - { - /* 1*16^2*G: */ - {{{0x15f51508, 0x123711fe, 0x0b072841, 0x073957ab, 0x1e238d8c, 0x171f0b96, 0x0767a8a9, 0x064258c1, 0x828226}}, - {{0x16e26caf, 0x18db757f, 0x1ec5efb4, 0x0c27585e, 0x00ace62d, 0x0b74185b, 0x1f917a09, 0x0130aafb, 0x11f8a8}}}, - /* 3*16^2*G: */ - {{{0x057e8dfa, 0x07e065cf, 0x11f8613f, 0x01232347, 0x18ca0098, 0x187c5654, 0x11303668, 0x05fe0f33, 0x8262cf}}, - {{0x1bac376a, 0x0e7fc6c7, 0x05311e0d, 0x0dda6656, 0x14f3457b, 0x111762d9, 0x19399bfb, 0x1c412213, 0x83fd95}}}, - /* 5*16^2*G: */ - {{{0x026bdb6f, 0x02972458, 0x1cd2e524, 0x0837a8f6, 0x19c877ca, 0x02d92674, 0x17545a04, 0x1163b41b, 0x19825c}}, - {{0x049cfc9b, 0x0efb8426, 0x1db4e9ad, 0x13dd9919, 0x19f6cebe, 0x10e64a7a, 0x1e3cc809, 0x01e1a990, 0x629431}}}, - /* 7*16^2*G: */ - {{{0x1d82824c, 0x07684a91, 0x054d3994, 0x0b1c68bc, 0x0999edfa, 0x1ab76361, 0x04510f17, 0x0d822c03, 0x6f12d8}}, - {{0x06eb34d0, 0x0bce1a40, 0x152f16e1, 0x19248210, 0x03769391, 0x0a79feb1, 0x1e821d66, 0x1e895677, 0x5c4ff7}}}, - /* 9*16^2*G: */ - {{{0x1b453629, 0x1b6ee016, 0x167980c1, 0x1fb9b81e, 0x0bef645c, 0x138b511d, 0x09745098, 0x0df34155, 0x203a8c}}, - {{0x1ff89f84, 0x0b8e3c29, 0x0a17b516, 0x1bd64b8a, 0x10612686, 0x1b68afa0, 0x06e4db31, 0x0a7bcbbb, 0x3b0f0b}}}, - /* 11*16^2*G: */ - {{{0x046c7ecb, 0x018986ef, 0x0ed33a5e, 0x15da7fcb, 0x0e1ec9d3, 0x1b99a433, 0x0607207b, 0x1d67a068, 0x6e2aca}}, - {{0x0ebc8720, 0x024900f7, 0x19d44b21, 0x0e0d7236, 0x1643afac, 0x026d787d, 0x18527603, 0x0cf2fdfd, 0x9e61a4}}}, - /* 13*16^2*G: */ - {{{0x10a4147e, 0x1b80c79f, 0x1d7c807a, 0x0fbb17ee, 0x10a58274, 0x18bf4524, 0x15aebd85, 0x125d3d22, 0xd5a704}}, - {{0x13fb65ff, 0x1259e5c1, 0x19fd5fe3, 0x09b308f2, 0x00532f4c, 0x04c83b2f, 0x071bf124, 0x1ebb7571, 0x9db526}}}, - /* 15*16^2*G: */ - {{{0x18edcec6, 0x16eda35e, 0x18d3d153, 0x0c3985a6, 0x0dac6a10, 0x17e31816, 0x0ea0148f, 0x13557c31, 0x38c511}}, - {{0x1933db08, 0x0b705fd8, 0x154c2991, 0x02d90456, 0x1282f28a, 0x196d13af, 0x0ca99a32, 0x0450bb2e, 0xe649dd}}} - }, - { - /* 1*16^3*G: */ - {{{0x11e5b739, 0x1fe72daa, 0x0888bb5c, 0x127067fa, 0x0846de0b, 0x0e63637e, 0x1969cbe6, 0x13ee5170, 0x175e15}}, - {{0x09fed695, 0x17d37ff7, 0x090d171b, 0x0b2ab5ba, 0x11f5eacb, 0x0bd28ffb, 0x07ae93be, 0x01b3c78f, 0xd3506e}}}, - /* 3*16^3*G: */ - {{{0x05041216, 0x0dbfc78e, 0x0ae0da99, 0x066bed08, 0x1ed523f7, 0x0cf7ee17, 0x13d04a2d, 0x0f643ef5, 0xda7531}}, - {{0x0e708572, 0x176994c3, 0x1eb3b6b6, 0x1580f5ce, 0x17fc6e9a, 0x110d9a16, 0x17c37c67, 0x08d7ee5a, 0x73f8a0}}}, - /* 5*16^3*G: */ - {{{0x0465a930, 0x00a1f38f, 0x04d4bf6c, 0x0fe382d6, 0x0eb1e258, 0x02c62541, 0x075c15cf, 0x1691d2e9, 0x1c71c5}}, - {{0x034638b5, 0x0c39fb66, 0x05d351c7, 0x08bc7f6e, 0x1b68c793, 0x18f94125, 0x08309c4f, 0x069d1ebf, 0x4a91c3}}}, - /* 7*16^3*G: */ - {{{0x1adb6ee7, 0x18c6d72d, 0x11281df8, 0x01ba864e, 0x14c9c785, 0x01bd484d, 0x159a4dba, 0x1f83e634, 0xd84e4a}}, - {{0x142ebed2, 0x16aab736, 0x08f99260, 0x11592e95, 0x1de4dfdd, 0x06ac7ab2, 0x07384a8e, 0x134f8f6f, 0xe52580}}}, - /* 9*16^3*G: */ - {{{0x049e6d10, 0x0a74f67d, 0x0b26748e, 0x15bfe75d, 0x16ed3f60, 0x15c942ff, 0x053506c8, 0x097bccd0, 0xf3d444}}, - {{0x1347da3f, 0x101c6602, 0x075b18c2, 0x15b4a19d, 0x04b5bfc1, 0x0ad60cc5, 0x18f52eae, 0x1bf4de02, 0xa4324}}}, - /* 11*16^3*G: */ - {{{0x09d33a07, 0x0659a037, 0x0e6f2ad2, 0x05dc1154, 0x1f4044e7, 0x0a9066de, 0x1627e421, 0x0593b383, 0xae3065}}, - {{0x00a0b2a6, 0x0438607b, 0x15fa571d, 0x186febbf, 0x0d5cf1c9, 0x13e99edc, 0x195fbf33, 0x1871ac7f, 0x6cb9d9}}}, - /* 13*16^3*G: */ - {{{0x0c28caca, 0x0cb2a5c8, 0x00a0769d, 0x138f7799, 0x08c9a186, 0x1f3ac19c, 0x07205785, 0x054b7abc, 0xd8dc1b}}, - {{0x03b3ec7a, 0x0db3b751, 0x004a3db3, 0x02ba59d9, 0x07d947d3, 0x06d21012, 0x1f5631b6, 0x1b24f9d8, 0x8cec0a}}}, - /* 15*16^3*G: */ - {{{0x1bc4416f, 0x090fdb31, 0x02c100a2, 0x1dfa47e6, 0x0f31da7a, 0x12d46819, 0x1b335650, 0x1258bf09, 0x2749e2}}, - {{0x1c6bbd8e, 0x14c5ef17, 0x1a58415f, 0x1d3f6cbd, 0x0db3ef59, 0x0a4c87e5, 0x0f1100f6, 0x09c6ece5, 0x50cc2d}}} - }, - { - /* 1*16^4*G: */ - {{{0x03ff4640, 0x135d6c7c, 0x154bff94, 0x0838fcaa, 0x02ee0534, 0x1602db13, 0x1272673a, 0x1a88f601, 0x363d90}}, - {{0x1bee9de9, 0x1001e3f9, 0x0667b2d8, 0x13512010, 0x1363145b, 0x0229cbf9, 0x088654ed, 0x15bf8e64, 0x4e273}}}, - /* 3*16^4*G: */ - {{{0x16e55dc8, 0x1c4890b7, 0x12810e52, 0x12b56dd5, 0x094426ff, 0x12206028, 0x1ecaea12, 0x08f218bf, 0x443140}}, - {{0x1be323b3, 0x0eca2576, 0x0a8b940c, 0x14536f3d, 0x0fed7a66, 0x01bfab21, 0x1be3fa66, 0x085cca6c, 0x96b0c1}}}, - /* 5*16^4*G: */ - {{{0x101b23a8, 0x1f4a42eb, 0x01fb82b7, 0x16fa8e15, 0x1089dab7, 0x01eadc90, 0x01f04989, 0x11b0cd95, 0x9e22fe}}, - {{0x0884edae, 0x1d209e28, 0x14473b3d, 0x0f9293f6, 0x01533c0f, 0x1f8104ce, 0x14405dfc, 0x1d394245, 0xfd2ff0}}}, - /* 7*16^4*G: */ - {{{0x071a70e4, 0x0ba045f8, 0x173d1d77, 0x1dca3ebe, 0x1306dcd5, 0x14f32382, 0x0a34bb75, 0x1aa079c5, 0x508df6}}, - {{0x09950984, 0x1972dfb9, 0x02ab7fb7, 0x006451dd, 0x049c54ec, 0x0255399f, 0x10b5ddcc, 0x13726778, 0x154c43}}}, - /* 9*16^4*G: */ - {{{0x0e1abe11, 0x157ed3b6, 0x12c883db, 0x124384b3, 0x125b2dab, 0x1ac0c980, 0x1d8cce37, 0x108aa212, 0xe3dbff}}, - {{0x1fa8de63, 0x1a4d6aa4, 0x1ad71052, 0x12fb2078, 0x08ef3d3c, 0x1d3aedc5, 0x108590e3, 0x01334682, 0x6f2f9}}}, - /* 11*16^4*G: */ - {{{0x03593449, 0x078d91b0, 0x0a91bff7, 0x16f825c8, 0x1014af61, 0x0e09d03e, 0x10361e36, 0x0c98fbd2, 0x19ace0}}, - {{0x0df83631, 0x120a5c9d, 0x0101a28e, 0x02173e81, 0x02c46ac7, 0x0b9ceca0, 0x0cceffaf, 0x006a4d14, 0xe37992}}}, - /* 13*16^4*G: */ - {{{0x0cba6b63, 0x11f4c496, 0x02ceed7b, 0x1fcce9fa, 0x08e310a0, 0x19914754, 0x16a84230, 0x1d841f0f, 0xd8740c}}, - {{0x0934c5f3, 0x1751b603, 0x005a52af, 0x009eb987, 0x0c37d401, 0x1774c81d, 0x0afcde29, 0x0678d726, 0x6472c1}}}, - /* 15*16^4*G: */ - {{{0x1b3ec038, 0x0ca7f960, 0x031ac9d8, 0x1aa2d5cc, 0x10a50d9f, 0x1f3b1794, 0x020d9220, 0x07236a0c, 0x58ac33}}, - {{0x10246279, 0x17551f88, 0x13eef285, 0x12087816, 0x1fe97021, 0x0924f4c8, 0x0b65e1de, 0x00daab92, 0x9163d7}}} - }, - { - /* 1*16^5*G: */ - {{{0x1ffdf80c, 0x0fbcd2ae, 0x16f346da, 0x094f0342, 0x1638843e, 0x025adba2, 0x0afa3189, 0x02cbbe78, 0x8b4b5f}}, - {{0x1fd4fd36, 0x1f7f8632, 0x18bb95ac, 0x066ca8c2, 0x0da04f9e, 0x0bc09d58, 0x02d2cfef, 0x0ded1a61, 0x4aad0a}}}, - /* 3*16^5*G: */ - {{{0x155812dd, 0x05152c17, 0x0b4c38a8, 0x08ce46aa, 0x0f78e3d4, 0x1f6b602c, 0x14bc2daa, 0x0f525fe6, 0x7029bd}}, - {{0x1a2d2927, 0x10e63358, 0x0cb1cf1c, 0x15d08487, 0x083ac47d, 0x0a257183, 0x0f49f759, 0x1b5fbd16, 0xb0eefa}}}, - /* 5*16^5*G: */ - {{{0x1d486ed1, 0x0e72b41d, 0x1596da92, 0x0b7d7492, 0x17560574, 0x0084ec67, 0x12640275, 0x195d5ccb, 0x9ccfed}}, - {{0x15e95d8d, 0x1b6acf6b, 0x164aa893, 0x02ceb2d2, 0x13411242, 0x12409005, 0x0b3ed848, 0x0e27ad46, 0x7c2f4d}}}, - /* 7*16^5*G: */ - {{{0x1bd0eaca, 0x10358d3a, 0x0b52ade8, 0x0e8aed74, 0x0df19d0c, 0x1ef19e52, 0x050cd6a3, 0x10ec6828, 0xcd9a4b}}, - {{0x0bff4acc, 0x137d7dad, 0x1bd8d3db, 0x0f671dda, 0x0a08b012, 0x0457499f, 0x08fa0552, 0x0f343d1e, 0xf04558}}}, - /* 9*16^5*G: */ - {{{0x07bc57c6, 0x104a9d1e, 0x0c9db2fc, 0x07af447d, 0x03094490, 0x169749eb, 0x0faa213c, 0x05f11db3, 0xad0988}}, - {{0x0e4a0ab8, 0x1196076d, 0x0438b4f2, 0x023a6e6b, 0x0be5f7b3, 0x036394ed, 0x14ae8a06, 0x11885f74, 0x7243c0}}}, - /* 11*16^5*G: */ - {{{0x0ba56302, 0x14186395, 0x03c618ba, 0x0d526f5e, 0x0d2e0f50, 0x116954fd, 0x107c7ab6, 0x015d6794, 0xd9d129}}, - {{0x08291c29, 0x156ed7d4, 0x09d3caba, 0x135d9b3f, 0x186e4173, 0x0ae33931, 0x1bb40a5c, 0x027d85a7, 0x7eb531}}}, - /* 13*16^5*G: */ - {{{0x14d1243a, 0x1669b827, 0x15297f6e, 0x024c047e, 0x1558402b, 0x10d6031f, 0x13be4734, 0x1bca73ad, 0xbc5079}}, - {{0x055db68a, 0x0e4a8b44, 0x1d1c5a7d, 0x1dc9eb63, 0x1c8d75f7, 0x195ca6ff, 0x12ee3bb1, 0x07674e0b, 0x65062a}}}, - /* 15*16^5*G: */ - {{{0x174a3f9f, 0x06922735, 0x02605a42, 0x0f4ccbb8, 0x0625ac28, 0x15573ed9, 0x1fa244f7, 0x0fca0bf8, 0x4d31a7}}, - {{0x101e0ba7, 0x1e581209, 0x18029d53, 0x0df6a36d, 0x02753cbf, 0x079c63c0, 0x1d6c1ac6, 0x192c130a, 0x22241e}}} - }, - { - /* 1*16^6*G: */ - {{{0x1232fcda, 0x1b08ac92, 0x1039def2, 0x01b7ff4d, 0x148c7b70, 0x18e005ea, 0x05b5afdd, 0x14dcbb73, 0x723cba}}, - {{0x1eb39f5f, 0x0ee034ec, 0x1e525200, 0x0140ca6e, 0x04d6e266, 0x09ba4441, 0x1262a484, 0x16ab2b98, 0x96e867}}}, - /* 3*16^6*G: */ - {{{0x00633cb1, 0x0b3f04f4, 0x140844c9, 0x144496d3, 0x01fcb575, 0x1399090c, 0x0b500318, 0x1e62f559, 0x6dde9c}}, - {{0x07ce6b34, 0x1eea4d53, 0x0167bcd5, 0x04ffb59f, 0x066a880b, 0x17c350dd, 0x10757267, 0x1cf4e0fc, 0x9188fb}}}, - /* 5*16^6*G: */ - {{{0x0933f3c5, 0x0cd28c69, 0x1c494890, 0x141ee22b, 0x1b850085, 0x1dbfc723, 0x17a04f12, 0x059ab6b9, 0x486fa7}}, - {{0x0afb0f53, 0x16a538d6, 0x03c8ede6, 0x136f079e, 0x0f19f62d, 0x045d7664, 0x150f9231, 0x033ead7b, 0x62e123}}}, - /* 7*16^6*G: */ - {{{0x1e99f728, 0x1eaca112, 0x1c48813a, 0x06ebf7cd, 0x05303677, 0x1f93dbb5, 0x1d3ed993, 0x0e951295, 0x247969}}, - {{0x0baaebff, 0x1d0028b7, 0x1d68b60d, 0x17e7812a, 0x1664a5ad, 0x143f3ec6, 0x0007b14b, 0x088d11e6, 0xe3d78d}}}, - /* 9*16^6*G: */ - {{{0x0fb0079a, 0x0f0636a1, 0x04981272, 0x1f3dee47, 0x18324916, 0x0cf73b59, 0x1fc18c69, 0x1b547aab, 0x2f39cb}}, - {{0x0c5690ba, 0x1114b981, 0x0a808c3f, 0x167f7910, 0x1a58b9bf, 0x1b6813c6, 0x060d36a4, 0x1bc270c7, 0xabeadb}}}, - /* 11*16^6*G: */ - {{{0x04f7ab73, 0x09980597, 0x1110e9de, 0x07a9d53a, 0x0aed262e, 0x0f43629a, 0x06e95a8e, 0x0d864fac, 0xe5a31d}}, - {{0x10561f42, 0x089d1fe3, 0x032e884e, 0x18889350, 0x0ce5dbf8, 0x054bbd27, 0x15e83046, 0x07b1a3d3, 0x37788c}}}, - /* 13*16^6*G: */ - {{{0x014dcd86, 0x07c94d1e, 0x0fdc6d62, 0x0ba8412d, 0x1dcf11fc, 0x0ecc1028, 0x111f7d43, 0x0941a2a6, 0xcc389d}}, - {{0x08f0a873, 0x075b6ece, 0x1f9e1d1a, 0x0afc31fc, 0x110ca05c, 0x05eddf54, 0x0fb66d5a, 0x1acc1ed7, 0x93ae4f}}}, - /* 15*16^6*G: */ - {{{0x18819311, 0x07ce375b, 0x01dc51c9, 0x1c3dc421, 0x1ed1f0b3, 0x10bf067a, 0x0408dd42, 0x1913ae3d, 0x7f9291}}, - {{0x0c2eb125, 0x14fcdabd, 0x01a85d2a, 0x15548139, 0x015b6120, 0x0f462292, 0x1bc3d743, 0x020c7d87, 0x9da00d}}} - }, - { - /* 1*16^7*G: */ - {{{0x0e7dd7fa, 0x1299f650, 0x0a4660e6, 0x0f2c246f, 0x0d3b5094, 0x17640961, 0x1e62e97f, 0x1a9277d7, 0xeebfa4}}, - {{0x01de8999, 0x0fea7ed7, 0x047dc4b7, 0x099b874e, 0x0089d9ae, 0x1f6d78bc, 0x03c9a7b9, 0x1472e1de, 0x5d9a8c}}}, - /* 3*16^7*G: */ - {{{0x1b7ceceb, 0x1fb3c7fd, 0x05febc3c, 0x0b3f2711, 0x0681473a, 0x1c0937b7, 0x1140dbfe, 0x04084eda, 0x437a86}}, - {{0x16c181e1, 0x1b1de61a, 0x03e5e09c, 0x041f9fb9, 0x097ff872, 0x1f5b4ce9, 0x0cbda6e3, 0x1427dd58, 0xb916b}}}, - /* 5*16^7*G: */ - {{{0x097f96f2, 0x0c6b94f0, 0x121cd735, 0x046a53a5, 0x0c273358, 0x1f1dcd1e, 0x06f20f2d, 0x027c5491, 0xa9ef9f}}, - {{0x16c04be4, 0x01eaad82, 0x06d1c0b0, 0x1f135eb5, 0x1613db74, 0x170b075d, 0x15f3655b, 0x1cb28ab3, 0xe814cc}}}, - /* 7*16^7*G: */ - {{{0x150cf77e, 0x0055ad09, 0x0a2ac36f, 0x17eae8a9, 0x0064207d, 0x13eb4fd5, 0x16f954e0, 0x083dc3a6, 0x66d805}}, - {{0x00eaa3a6, 0x12fcbd7d, 0x0c6ddb4a, 0x0968756f, 0x013f6944, 0x0a1029ab, 0x0d0b0fc7, 0x1ce65fff, 0x51cfdf}}}, - /* 9*16^7*G: */ - {{{0x07213a5a, 0x1aa43144, 0x17e98ae4, 0x064094f0, 0x0c3c80b7, 0x0450e326, 0x1e8afcd4, 0x1c26ca07, 0x62ac05}}, - {{0x146a9e45, 0x08690e07, 0x1e653bf0, 0x12120302, 0x12579e55, 0x13cf03d4, 0x1b934e57, 0x1e741a34, 0x236fbd}}}, - /* 11*16^7*G: */ - {{{0x07bad12b, 0x187ea4c3, 0x1d9b87b0, 0x0bd401d5, 0x12db385d, 0x09d7ae37, 0x1d6d6fd8, 0x092e4891, 0xca13c4}}, - {{0x1723b0f2, 0x0b4cfa34, 0x095d59a2, 0x0156e223, 0x1a3d6637, 0x1d327556, 0x1f22b057, 0x106c3850, 0x83aa09}}}, - /* 13*16^7*G: */ - {{{0x1c80414e, 0x0d772fca, 0x19b3dff7, 0x1f150c5a, 0x09e4914e, 0x0e27a230, 0x0ba16b04, 0x0034e0a5, 0x1cecb1}}, - {{0x12169a3b, 0x0574a496, 0x1c8c7437, 0x0aafca88, 0x1ad16907, 0x11941af6, 0x13ed396a, 0x0cd2c12f, 0xf34360}}}, - /* 15*16^7*G: */ - {{{0x0ed810a9, 0x07ade462, 0x1c005571, 0x113a7e78, 0x123924f8, 0x0d7af8ef, 0x1e732543, 0x0ea09af1, 0x2a6990}}, - {{0x1a9b4728, 0x1c359c47, 0x105171f3, 0x1a8fd2fd, 0x104fc667, 0x0c34aa7d, 0x1f6b0fb1, 0x136d87bf, 0x54f903}}} - }, - { - /* 1*16^8*G: */ - {{{0x19a48db0, 0x1ebc1ad9, 0x0f00effb, 0x042b4536, 0x1de459f1, 0x08504dbd, 0x059c9e47, 0x1b4d2dce, 0x100f44}}, - {{0x0bc65a09, 0x1deae6b1, 0x14656b03, 0x1e9431fe, 0x10666b7f, 0x19980604, 0x0ddcbb23, 0x06325401, 0xcdd9e1}}}, - /* 3*16^8*G: */ - {{{0x15bc15b4, 0x05cd09a4, 0x168bb9a7, 0x0a051c8c, 0x1ca8d927, 0x0774e76b, 0x1727b616, 0x05ca3dd5, 0x10e90e}}, - {{0x18aa258d, 0x075f304a, 0x0edaa20d, 0x0b12c605, 0x11f754ca, 0x14630b56, 0x0109355e, 0x00701abc, 0xc68a37}}}, - /* 5*16^8*G: */ - {{{0x1fe75269, 0x0e9fe181, 0x0f4cc60b, 0x0f47980a, 0x17dcda37, 0x1c85b8a5, 0x18e115d6, 0x085b4a82, 0xf7422f}}, - {{0x17e49bd5, 0x04c07438, 0x08e63806, 0x07446fe9, 0x035977fb, 0x13ee5cfb, 0x04ff4633, 0x03466261, 0x406c2f}}}, - /* 7*16^8*G: */ - {{{0x15a7175f, 0x09db34b7, 0x073d0a99, 0x11cee3a6, 0x1debbedb, 0x0d2ac16a, 0x13fdca1e, 0x0082fa87, 0x2d8cad}}, - {{0x1b9d592a, 0x19bddc8d, 0x0d797833, 0x08d7fb39, 0x09d377a8, 0x197d3096, 0x0529eec8, 0x10663195, 0xc73f3b}}}, - /* 9*16^8*G: */ - {{{0x14b51045, 0x1a64de1c, 0x07096cf8, 0x0d912de6, 0x0cf73bbc, 0x1ea758f4, 0x1a962b9c, 0x03b7314d, 0x1ecbfd}}, - {{0x02c70026, 0x1d338808, 0x0d908b54, 0x000c8d68, 0x09b38b19, 0x05d8c24d, 0x0e9911f4, 0x06117338, 0x1cf6e2}}}, - /* 11*16^8*G: */ - {{{0x09358533, 0x1d66bb37, 0x1ed2e77d, 0x1267f3a9, 0x12a8c10a, 0x0ad148e9, 0x14a20fa5, 0x18bfcaee, 0x9a0894}}, - {{0x0360ba08, 0x19f0e2ee, 0x00376b7e, 0x0dcb7b77, 0x1c32165a, 0x1eafcaa7, 0x1f0c7e45, 0x18840371, 0xa79883}}}, - /* 13*16^8*G: */ - {{{0x198ef7f6, 0x0a202eb0, 0x01e3e7da, 0x07e7eef4, 0x0aea6592, 0x042939dc, 0x0b8d6f67, 0x093b69fa, 0x664dd8}}, - {{0x1d1eac94, 0x1a4b7f9a, 0x039bb3b9, 0x1a756637, 0x058cffc3, 0x0672ee82, 0x04ca8512, 0x02e2fe4f, 0xad5120}}}, - /* 15*16^8*G: */ - {{{0x03c934b3, 0x060535be, 0x02b8b138, 0x03eb00b6, 0x1a7022b3, 0x0cb34c08, 0x018e08c7, 0x126efa17, 0x82113a}}, - {{0x042c6a0f, 0x1f2f3156, 0x111a00dd, 0x1ef84d34, 0x0c628aa1, 0x16795ad0, 0x19982119, 0x1b5935c6, 0x8da1b8}}} - }, - { - /* 1*16^9*G: */ - {{{0x0534fd2d, 0x04566f37, 0x1cece14b, 0x1f1a88c9, 0x0c017a77, 0x113d2502, 0x146c7724, 0x1c4c58fd, 0xe1031b}}, - {{0x1456a00d, 0x0278c794, 0x073b5e69, 0x05ba833c, 0x1535af29, 0x120bb2cb, 0x0179aeda, 0x12512808, 0x9d7061}}}, - /* 3*16^9*G: */ - {{{0x0f028d83, 0x1cb11d77, 0x1d0e5855, 0x0b24db74, 0x069db619, 0x1f2d0aef, 0x17b1a96a, 0x189c78f0, 0xa7ebf7}}, - {{0x19d0bed1, 0x1201c95c, 0x014e4665, 0x07124e96, 0x0804b47a, 0x039bb822, 0x0b573f67, 0x05f7fc6c, 0x620515}}}, - /* 5*16^9*G: */ - {{{0x07dd5cfa, 0x17072011, 0x02752d6e, 0x138a26fe, 0x146336a8, 0x1529a131, 0x1d307371, 0x11b96049, 0x5b5ca0}}, - {{0x1e48e98c, 0x132537cc, 0x0c9a74f9, 0x00cf995e, 0x09094bfd, 0x18675443, 0x0097a647, 0x1ee1542b, 0x3eccb6}}}, - /* 7*16^9*G: */ - {{{0x03531f82, 0x1ca94719, 0x030b27ca, 0x0264d762, 0x02c29ff5, 0x1f3a44e1, 0x0ed733bc, 0x15982229, 0x46f26}}, - {{0x0bceda07, 0x082fe458, 0x0d571fe9, 0x0b28b9b5, 0x12579d02, 0x185617e1, 0x0bab388d, 0x062c6b70, 0x6b804b}}}, - /* 9*16^9*G: */ - {{{0x10432711, 0x058aa1b8, 0x045ae418, 0x08165fbb, 0x1645acf1, 0x1787844c, 0x1ed4d7e5, 0x1b263c1d, 0xc11926}}, - {{0x0fe2610c, 0x04930f17, 0x1cd01579, 0x17245941, 0x0c6cf83a, 0x05f8c366, 0x1a246125, 0x198fa4b6, 0x8be1f8}}}, - /* 11*16^9*G: */ - {{{0x01257963, 0x0bcc3a7d, 0x12aa1870, 0x031aa586, 0x179c45b0, 0x1aa5a9c4, 0x1cb9b36e, 0x1d3d6d11, 0x690846}}, - {{0x066f9835, 0x12bb2cca, 0x124ac94e, 0x18795043, 0x1bb7f6cb, 0x18127c97, 0x0f16d005, 0x196fe7fd, 0xe2485f}}}, - /* 13*16^9*G: */ - {{{0x1ee23ace, 0x0889ca5e, 0x1374bf4b, 0x10f8cb6a, 0x12915dec, 0x0a96fa51, 0x02eaee9d, 0x1f719244, 0xfb3df7}}, - {{0x1722e8de, 0x04ef7a64, 0x149fd7b8, 0x04e285fd, 0x0b58a9e7, 0x08aa06dd, 0x11594a89, 0x178238e7, 0x510e29}}}, - /* 15*16^9*G: */ - {{{0x10272351, 0x103e7f7a, 0x07fc4261, 0x06967bf3, 0x1cd41707, 0x11f59d58, 0x062cfae2, 0x1849eb8a, 0x6dd85e}}, - {{0x1fc7664b, 0x183fd15b, 0x18205f26, 0x18dfef87, 0x041b7877, 0x03fcd7ae, 0x09f82750, 0x1e8243e8, 0x16ea67}}} - }, - { - /* 1*16^10*G: */ - {{{0x1094696d, 0x0af3446c, 0x075abd4b, 0x1164cd48, 0x1d7ec5cf, 0x01cf8a1d, 0x0d4c2b0a, 0x15c8daab, 0xfeea6c}}, - {{0x18090088, 0x0aaef5f8, 0x10510b4c, 0x1912af98, 0x0cd5c981, 0x07095f9f, 0x06eac1b9, 0x0d92fb9c, 0xe57c6b}}}, - /* 3*16^10*G: */ - {{{0x08dfd587, 0x1c9b0dda, 0x0c099581, 0x09747193, 0x1a12d5ec, 0x1d55167a, 0x022cd219, 0x03759e8a, 0x5084b4}}, - {{0x11470e89, 0x13cf4bfc, 0x047d581b, 0x0deac0d1, 0x127475db, 0x13642a94, 0x14c5866a, 0x0343b301, 0x34a963}}}, - /* 5*16^10*G: */ - {{{0x1ab34cc6, 0x0411930b, 0x1cc284b4, 0x1852ecf9, 0x17128c80, 0x1f8fe8c6, 0x17a94fec, 0x07c0c85a, 0x4f14c0}}, - {{0x187e681f, 0x0f61297c, 0x00774089, 0x1c799d1d, 0x02540b9d, 0x1387a1d3, 0x0253194e, 0x1519549d, 0x7b53d0}}}, - /* 7*16^10*G: */ - {{{0x1241d90d, 0x013b8808, 0x09113e0d, 0x19e283b6, 0x1d363e81, 0x1b04af6e, 0x1b475050, 0x0fc938f3, 0xa74db8}}, - {{0x1f7adad4, 0x1928c5c1, 0x0828c4fc, 0x1ca12689, 0x171c8a9e, 0x08452c40, 0x1bcc9ff7, 0x19b5e47d, 0xf78691}}}, - /* 9*16^10*G: */ - {{{0x11c1ae1f, 0x0f665111, 0x13502ca9, 0x1cb18d15, 0x15658456, 0x06a275d1, 0x0b3e6b37, 0x0ae89754, 0x6901fa}}, - {{0x122838b0, 0x1c19832e, 0x11dea4c3, 0x1e774bcb, 0x0900dd79, 0x09c0614e, 0x0849186d, 0x11044e78, 0x35de5c}}}, - /* 11*16^10*G: */ - {{{0x127a4bdb, 0x1818840d, 0x12532b12, 0x14da086a, 0x1a35d046, 0x1b21f8dd, 0x049e8912, 0x05a3a870, 0x8d3cd8}}, - {{0x069a8a2c, 0x1e9a63e7, 0x02b4a5b0, 0x0700fa6e, 0x0236ed4e, 0x1fce803b, 0x07d1c33e, 0x0c301dc8, 0x9bd425}}}, - /* 13*16^10*G: */ - {{{0x14ec1d2d, 0x00669e35, 0x1f63d151, 0x133eb8dc, 0x1691fd90, 0x0b394b3d, 0x1ce6bfa7, 0x0c7ac0c8, 0xeaf983}}, - {{0x0c838452, 0x07f3ab02, 0x1a12d4ff, 0x0a5aa8af, 0x199aaa9f, 0x14507358, 0x1489dd48, 0x074ffcf1, 0xe51818}}}, - /* 15*16^10*G: */ - {{{0x045ae767, 0x059adfb8, 0x025dc72f, 0x0753973d, 0x0e5d8c27, 0x07029603, 0x18d19bd0, 0x02c75db6, 0xfb95bd}}, - {{0x1bbf0e11, 0x029f5057, 0x167c4d06, 0x0de8e314, 0x0275bb81, 0x06ce9b41, 0x16f14801, 0x1b02351b, 0x664c14}}} - }, - { - /* 1*16^11*G: */ - {{{0x01ec6cb1, 0x1fd4bc5e, 0x0160f78c, 0x1acafb01, 0x1ca3cfee, 0x1f25f37f, 0x1372cd9e, 0x03b22093, 0xda67a9}}, - {{0x1a68be1d, 0x14f54713, 0x1dd0285f, 0x0f5b8a11, 0x180e5dec, 0x11fbf64b, 0x0af107d1, 0x06a902c8, 0x9bacaa}}}, - /* 3*16^11*G: */ - {{{0x15bc8a44, 0x17ee8328, 0x18546867, 0x0202ef97, 0x05fc7684, 0x12d25d2d, 0x168f4e15, 0x0b079f9d, 0x4d0180}}, - {{0x1adbc09e, 0x18fca648, 0x00b68d8b, 0x08408d0b, 0x03813969, 0x1d4003eb, 0x174d9fa6, 0x1831969e, 0x3a33c6}}}, - /* 5*16^11*G: */ - {{{0x05daeb00, 0x00d5a943, 0x1917ddaf, 0x07d6499c, 0x0e9d1592, 0x1b5139db, 0x055c20b2, 0x00fbeb9f, 0x2f6615}}, - {{0x033992c0, 0x113b3c4c, 0x174c2304, 0x1bdc4e32, 0x0add06ec, 0x09bd4100, 0x0cfdbbe5, 0x026dea56, 0xfd5c12}}}, - /* 7*16^11*G: */ - {{{0x116aa6d9, 0x01548504, 0x1c0b73c6, 0x05916c8e, 0x15a38366, 0x0ba6d0c1, 0x1f48953c, 0x0fa0bfc8, 0xf59411}}, - {{0x1f2e50cf, 0x1e834b75, 0x1ad6e1b1, 0x04ef107c, 0x0bceb7a9, 0x0ded584a, 0x0c4b3d97, 0x14add2e3, 0xcaa761}}}, - /* 9*16^11*G: */ - {{{0x1ac6f4c0, 0x15701cab, 0x12f71332, 0x1d1bd198, 0x0711dda4, 0x01c5f34b, 0x137b1387, 0x0fe3e9b3, 0xf2d4d}}, - {{0x12339b58, 0x1f3ddd6b, 0x090995b9, 0x14214f20, 0x1e71e8f6, 0x13fef9c0, 0x19345fec, 0x10afd27b, 0x3ec89f}}}, - /* 11*16^11*G: */ - {{{0x1f428cb2, 0x02a829fe, 0x088ad576, 0x1045facd, 0x0d0f1233, 0x10c0acac, 0x0ef47ade, 0x185c5429, 0x1d5dce}}, - {{0x095b189b, 0x12f68804, 0x18112947, 0x1d225f0e, 0x10b88bd3, 0x03c12437, 0x0314341e, 0x10762859, 0x6e5c40}}}, - /* 13*16^11*G: */ - {{{0x08381273, 0x1875447d, 0x04f6b97e, 0x06ed2c0d, 0x126ced84, 0x14d96620, 0x1d0e7f7a, 0x1fa6012c, 0x89d9a2}}, - {{0x1309773d, 0x01f59f76, 0x049cc928, 0x03ad015a, 0x162f58f6, 0x17903b67, 0x1d40ddea, 0x168a3acd, 0xdfca25}}}, - /* 15*16^11*G: */ - {{{0x15c71d91, 0x06195965, 0x0253f487, 0x08bc5c55, 0x0fece239, 0x0e0988ad, 0x0b8714a8, 0x10f074a1, 0x83191b}}, - {{0x02148a61, 0x05cf6047, 0x01117b9c, 0x023ea2ea, 0x0ae8a17a, 0x0f09e8be, 0x0dc2781b, 0x02ae7003, 0xe0ac7f}}} - }, - { - /* 1*16^12*G: */ - {{{0x1a37b7c0, 0x1aa2e660, 0x0441a7d5, 0x11a1ef76, 0x02151ec0, 0x0049af79, 0x13769b80, 0x15416669, 0x53904f}}, - {{0x022771c8, 0x0e584b58, 0x110d1a67, 0x133303c2, 0x13c1c139, 0x16656106, 0x01b62327, 0x1a179002, 0x5bc087}}}, - /* 3*16^12*G: */ - {{{0x08a2050e, 0x0d6217f2, 0x17e299dc, 0x1deaaec2, 0x19b89742, 0x14e63723, 0x0c625add, 0x1fa4978e, 0x673724}}, - {{0x061d3d70, 0x0864d248, 0x0d2730ae, 0x1759fa86, 0x06b6dbe6, 0x01604d44, 0x088080d2, 0x0af12d49, 0xe4cf82}}}, - /* 5*16^12*G: */ - {{{0x02de63bf, 0x1fb7241c, 0x098719b2, 0x15ea650e, 0x166a8e03, 0x05318fb0, 0x10c27966, 0x148e5be9, 0x4366ef}}, - {{0x017924cd, 0x16352047, 0x0a9b5ac0, 0x1618a4b5, 0x068eaf33, 0x09bf0981, 0x1f38bb89, 0x0137dc5a, 0x2e7dd9}}}, - /* 7*16^12*G: */ - {{{0x06f96190, 0x08293ff8, 0x125497bc, 0x005bd20f, 0x0a75fd1f, 0x0ab4b33d, 0x0c7e5ef9, 0x0c4f3235, 0x7bd753}}, - {{0x0bda00f6, 0x1e8b9025, 0x03a9a568, 0x1f98b83c, 0x027d6ce0, 0x123a4a1c, 0x0c2757b5, 0x167b774c, 0x8336f2}}}, - /* 9*16^12*G: */ - {{{0x16ad41ed, 0x1d8a98aa, 0x1c0d490c, 0x11586be9, 0x0dc92030, 0x00cf448c, 0x1706be8d, 0x0f7bb55a, 0x4f7e92}}, - {{0x1e642d57, 0x1a1abc33, 0x0bddd6f7, 0x0628e29d, 0x0f6a62e7, 0x006fa9d4, 0x0c4154a6, 0x0a2ad511, 0xdfe774}}}, - /* 11*16^12*G: */ - {{{0x07748690, 0x1d302893, 0x18c2c073, 0x0f209bb0, 0x13d007d5, 0x0958f6e9, 0x133252d1, 0x10cfa523, 0x2355cb}}, - {{0x0c89582b, 0x1e23a98a, 0x0724e451, 0x10d0b19a, 0x07c58582, 0x02f60ad5, 0x07e3d56e, 0x114b4e3c, 0x21c2f1}}}, - /* 13*16^12*G: */ - {{{0x0ade7f16, 0x0d7510b0, 0x0f80a31b, 0x1975d279, 0x15d24ae9, 0x0955b613, 0x15b004d6, 0x0b7367b4, 0xb6682}}, - {{0x08c56217, 0x0a221342, 0x19f34af6, 0x08781be7, 0x1a97fb72, 0x1b5d45ab, 0x0cffbce9, 0x17031c13, 0xa1fba0}}}, - /* 15*16^12*G: */ - {{{0x19060d5b, 0x08358114, 0x0e8e9f0a, 0x0c276238, 0x151cb904, 0x0d97ecfc, 0x08b2d842, 0x079e17a0, 0xf60204}}, - {{0x1af88f13, 0x17b7a858, 0x17468fdd, 0x14ada56f, 0x17bea37a, 0x07b25627, 0x1c66206a, 0x00d83e19, 0xf036b7}}} - }, - { - /* 1*16^13*G: */ - {{{0x1ad86047, 0x1fcacfa1, 0x06e2f2bb, 0x0a740875, 0x0906779b, 0x053bb265, 0x0e9dc673, 0x017a6b30, 0x8e7bcd}}, - {{0x0460372a, 0x108023f4, 0x1f5a2cfa, 0x111c5c8f, 0x1514579e, 0x08210654, 0x12ce500c, 0x016547b4, 0x10b777}}}, - /* 3*16^13*G: */ - {{{0x041ead4b, 0x1f443cd0, 0x06c0f07f, 0x0bdbf6d2, 0x076be3a7, 0x19a77d7f, 0x0dfb1c51, 0x019191e6, 0xbfc90c}}, - {{0x06fedaed, 0x02963784, 0x182b8f9d, 0x0d1dfe65, 0x02d36fb4, 0x18c6ea82, 0x1b4936e9, 0x163c139b, 0x7a9481}}}, - /* 5*16^13*G: */ - {{{0x15bb3b3e, 0x173de83b, 0x07dcf2c9, 0x0a6c2fdf, 0x13f5b507, 0x0c9f4616, 0x0a937296, 0x0397c7f5, 0x732df1}}, - {{0x17366693, 0x02bbf0f6, 0x11610db3, 0x1b5adac9, 0x13916e69, 0x12ac2012, 0x05df2df8, 0x07dbd1f3, 0x7f4190}}}, - /* 7*16^13*G: */ - {{{0x088dc3b9, 0x0fad9e0c, 0x1dd32671, 0x0cd249d2, 0x1ef6019a, 0x0420664b, 0x1ed0a36a, 0x172c0728, 0x4ce094}}, - {{0x05c0de52, 0x00a7bdb7, 0x1a81940b, 0x00b64193, 0x0aca2162, 0x06c0653b, 0x0cfb55ed, 0x1757e353, 0x5390f}}}, - /* 9*16^13*G: */ - {{{0x0aaafe5a, 0x01baf058, 0x026bb753, 0x08e1674a, 0x03fd0e25, 0x1354ad81, 0x1f7a5b62, 0x16edf8cc, 0x9a968e}}, - {{0x0ed975c0, 0x135fea12, 0x19c33033, 0x0b1014cb, 0x01d0ee7b, 0x13681ec3, 0x08a553f1, 0x00f4da77, 0xabf6fb}}}, - /* 11*16^13*G: */ - {{{0x134c6397, 0x1a8e5fcf, 0x1d33424d, 0x1a7b6a00, 0x0b22107d, 0x17c0129b, 0x06553c2b, 0x1da02e2c, 0xd3c6fb}}, - {{0x08cb3f9c, 0x0fe4682b, 0x1783802c, 0x18ee1120, 0x0b6468a0, 0x1ca6c975, 0x0bc65160, 0x18abcbc5, 0x4a0dd2}}}, - /* 13*16^13*G: */ - {{{0x0ac3137e, 0x0dc12c98, 0x0bd91186, 0x04b6c54b, 0x13953fe9, 0x0353b555, 0x0ee380bc, 0x13025248, 0x4cbde3}}, - {{0x0ec02fe6, 0x00478ae7, 0x03ab5830, 0x074f5cb1, 0x0c370d19, 0x1509a5ca, 0x05654024, 0x0c11e26c, 0x6ce554}}}, - /* 15*16^13*G: */ - {{{0x00fbf84b, 0x1d118367, 0x0fc2e291, 0x091f9778, 0x0cebb03c, 0x0e39860a, 0x091ee2f6, 0x0790562c, 0x4b9d33}}, - {{0x036c3c48, 0x1cf725a5, 0x1d6d7988, 0x0daa87c5, 0x1b7eb676, 0x1ecc133c, 0x054954c4, 0x1f7c4998, 0xfd7fc7}}} - }, - { - /* 1*16^14*G: */ - {{{0x19c43862, 0x1420f0ac, 0x05f99a42, 0x0fe9e307, 0x01bde71a, 0x00c344dc, 0x1c879b42, 0x069839bf, 0x385eed}}, - {{0x142e5453, 0x022c7f2a, 0x01b72330, 0x009dd841, 0x1f4576b3, 0x0f0cf4f5, 0x0fd59c07, 0x187d1d44, 0x283beb}}}, - /* 3*16^14*G: */ - {{{0x16e2d9b3, 0x05e98355, 0x0e358d45, 0x17250636, 0x1845641d, 0x15309ce7, 0x179d784b, 0x1e72f8e0, 0x19a314}}, - {{0x0baaaf33, 0x0a97712e, 0x012f95b5, 0x043a3a48, 0x128b3a50, 0x12fc43fa, 0x03748d25, 0x1ebb58e5, 0x6cacd8}}}, - /* 5*16^14*G: */ - {{{0x12f00480, 0x0c2c3f58, 0x00373b9f, 0x0b100942, 0x07219203, 0x0c31b27b, 0x0a8d5772, 0x0972b51b, 0x5840ed}}, - {{0x1e22cf9e, 0x0c96af15, 0x0b8e1c85, 0x0a44a8a5, 0x1d8daba7, 0x06f550ae, 0x05041e5a, 0x0d64417e, 0x670cda}}}, - /* 7*16^14*G: */ - {{{0x03f54c42, 0x0426f741, 0x068f7239, 0x1834784d, 0x0532545d, 0x060fa767, 0x03ec7716, 0x14a68d23, 0x9f5701}}, - {{0x0feb6a21, 0x1070e249, 0x067949e1, 0x1cf09564, 0x1bfdd89e, 0x0db5ab94, 0x195efee5, 0x171003b3, 0xce7b8f}}}, - /* 9*16^14*G: */ - {{{0x1522461a, 0x14a09994, 0x11c60c9f, 0x06144cb7, 0x0f9a0bcb, 0x0380833f, 0x13f006ee, 0x0d246b51, 0x27f611}}, - {{0x07301a2d, 0x152657ce, 0x018e511a, 0x103641b5, 0x08ee8e49, 0x02b093a1, 0x0b4ba923, 0x1532014d, 0xe512f1}}}, - /* 11*16^14*G: */ - {{{0x114f36b9, 0x07164d96, 0x0e7ce433, 0x119576c7, 0x0a981259, 0x197a1afa, 0x0504986f, 0x10ad9ddf, 0x640779}}, - {{0x04b4b50a, 0x0a58f74f, 0x073baca2, 0x1410e093, 0x07b6c8cd, 0x0bafec2d, 0x1bebbe43, 0x11e89cad, 0xda6192}}}, - /* 13*16^14*G: */ - {{{0x14d6b76f, 0x17b1efcc, 0x120576f3, 0x0b53f769, 0x1feae7fe, 0x1845e04e, 0x1a7d14bd, 0x1c6390ac, 0xa23750}}, - {{0x0dcca8da, 0x0ec96664, 0x0e123450, 0x00f823fb, 0x11113e77, 0x1d1f26a0, 0x19b6b0cb, 0x0294dcfb, 0xf7339b}}}, - /* 15*16^14*G: */ - {{{0x1ceee475, 0x1774e327, 0x1b5e0ac4, 0x15905081, 0x0ff41ab6, 0x0010f9e5, 0x1e357b4f, 0x00f47e46, 0xbbf1ac}}, - {{0x07fe5067, 0x03115004, 0x02d075a1, 0x173b1287, 0x15fe324e, 0x1e641b58, 0x03984220, 0x1bdd5a8c, 0xb4bfb8}}} - }, - { - /* 1*16^15*G: */ - {{{0x03fac3a7, 0x10376c36, 0x11fef271, 0x1bf094b2, 0x1fa180fd, 0x19d2209e, 0x06458df1, 0x17007d9e, 0x6f9d9}}, - {{0x1a842160, 0x03448301, 0x0a0400b6, 0x09ba5eb8, 0x1c4d47ea, 0x11518722, 0x06e9a6e3, 0x11cc060b, 0x7c80c6}}}, - /* 3*16^15*G: */ - {{{0x121ce204, 0x076baf46, 0x19d8f549, 0x0e4b1c84, 0x0f72fb2a, 0x06c2ce53, 0x193ee0dd, 0x1a2c5678, 0x43ca41}}, - {{0x134a8f6b, 0x09282274, 0x09291a39, 0x0d8f667d, 0x1a31f9ab, 0x07c90c6d, 0x0fe87194, 0x105c6e04, 0xdcea5a}}}, - /* 5*16^15*G: */ - {{{0x0be6efda, 0x07e74967, 0x1ca01659, 0x1a9fe7f0, 0x0506d922, 0x1b91bc2d, 0x0fd6d99b, 0x1de45125, 0x9c3e06}}, - {{0x07aefc7d, 0x18a07995, 0x0dbf7df7, 0x1790d0f6, 0x06fd5d43, 0x196a2671, 0x08f62bc2, 0x1cbcec52, 0xa7b709}}}, - /* 7*16^15*G: */ - {{{0x06c88be2, 0x0893d5ae, 0x1bb9789e, 0x18f041a0, 0x0775bea2, 0x13acec18, 0x1c0ceedc, 0x14627c41, 0x5d6f8a}}, - {{0x0d7ad75d, 0x0972a9f8, 0x0fe4b0a2, 0x16df1d4d, 0x0bc20eda, 0x1799d584, 0x13a31c6a, 0x11b1aada, 0xadc4b1}}}, - /* 9*16^15*G: */ - {{{0x12d1b844, 0x1449a8dc, 0x1cf9213c, 0x18070582, 0x08bc5c69, 0x0ae1e09c, 0x157f21ac, 0x186094c1, 0xf57d35}}, - {{0x01266837, 0x125d5deb, 0x04571a91, 0x0d2e4061, 0x0634c700, 0x09fad4f2, 0x1365e413, 0x13d531de, 0x707f3d}}}, - /* 11*16^15*G: */ - {{{0x1cc7cb09, 0x1a6803f9, 0x146d0d48, 0x0fd6d143, 0x071463bc, 0x10ff71ec, 0x1297d65b, 0x0f474cb2, 0x13e760}}, - {{0x08079160, 0x1f3ad450, 0x0d5d9046, 0x15c576cd, 0x0299d65e, 0x1eec2d9a, 0x02c78c97, 0x11bd1f77, 0x284dc8}}}, - /* 13*16^15*G: */ - {{{0x18cdee05, 0x03067092, 0x0bb0ee40, 0x0c3f642e, 0x0901da87, 0x12858d83, 0x0b989000, 0x044ad030, 0x29bea3}}, - {{0x062651c8, 0x12501acd, 0x11a638e7, 0x18636d91, 0x05ec7f9f, 0x0d9fdc38, 0x083aa402, 0x144d21d3, 0x7c40d9}}}, - /* 15*16^15*G: */ - {{{0x12f18ada, 0x0db63ab0, 0x16f6f304, 0x017b2777, 0x14a59d46, 0x17d7f99e, 0x039f670d, 0x0da47051, 0xf52178}}, - {{0x03953516, 0x0eb457e9, 0x16fc2607, 0x1de946d8, 0x1d1d6aa5, 0x10815e68, 0x0d5fb309, 0x17ec071b, 0xe0686f}}} - }, - { - /* 1*16^16*G: */ - {{{0x02d0e6bd, 0x1dbf073a, 0x03d794c4, 0x09a2c7b6, 0x16ecbf77, 0x0a3e0826, 0x18960a88, 0x00248789, 0x3322d4}}, - {{0x0c28b2a0, 0x079d174b, 0x01cebd89, 0x0bec7d45, 0x0f9b7280, 0x0cde26ed, 0x1bd6fec0, 0x12fd2cc9, 0x56e707}}}, - /* 3*16^16*G: */ - {{{0x059ab499, 0x1ece9f90, 0x1cf0cc2a, 0x065338dc, 0x101bc0b1, 0x0b59e33f, 0x16e97486, 0x1e602b80, 0x78baaf}}, - {{0x1ee097fd, 0x00e918c7, 0x0494665a, 0x065ddd1a, 0x0082e916, 0x027076c1, 0x02bebf2a, 0x1b7b60d8, 0xad4bdc}}}, - /* 5*16^16*G: */ - {{{0x1d06ace6, 0x049f0b67, 0x0e883291, 0x01366df0, 0x1ab1a237, 0x024c2494, 0x0f53082e, 0x0234295c, 0x6f70f2}}, - {{0x1602d5de, 0x045f69a5, 0x16b17b81, 0x052acd7c, 0x19f50753, 0x0c79a3dc, 0x0dcdbe57, 0x0612804f, 0x791e8a}}}, - /* 7*16^16*G: */ - {{{0x00ee1b40, 0x04771f73, 0x1a5891f7, 0x1a90b6e3, 0x1ccd48ce, 0x04f8c881, 0x1057e025, 0x1653ad54, 0xe1599d}}, - {{0x178f93a6, 0x0eb132f6, 0x0ca66778, 0x0c74e978, 0x1c7cfa63, 0x04a55517, 0x1283bebe, 0x0465503a, 0x793362}}}, - /* 9*16^16*G: */ - {{{0x09c00c3e, 0x00efd142, 0x048238be, 0x1d1e0792, 0x11859f00, 0x11699ea2, 0x05590d95, 0x12e0880d, 0xbb0b04}}, - {{0x11955a35, 0x0cd4c168, 0x1772429e, 0x0e089d20, 0x1b052fe6, 0x17d0bd58, 0x1d8d9574, 0x0b0a75f3, 0x4067e4}}}, - /* 11*16^16*G: */ - {{{0x05dd32e6, 0x073adce0, 0x0f97b9f8, 0x076aa36a, 0x05fbfc66, 0x0edf03ad, 0x027a6d92, 0x0aa832af, 0xdc5a41}}, - {{0x154a99b9, 0x073edbd3, 0x1926f3e0, 0x05dd20ed, 0x159442ff, 0x12f100df, 0x1e9db73a, 0x14c7f3ec, 0x4af3a8}}}, - /* 13*16^16*G: */ - {{{0x0544e7cb, 0x16a2dd62, 0x0a580d67, 0x0c844b6a, 0x14e99a10, 0x0a52b880, 0x0e76f8cd, 0x0e0730e7, 0x156e19}}, - {{0x0d250a37, 0x0a9c9605, 0x0d0e735b, 0x0dab1abd, 0x14be8949, 0x0b9531c1, 0x01f6a4e5, 0x13f1e632, 0x6bc08d}}}, - /* 15*16^16*G: */ - {{{0x059853ca, 0x1fde14e6, 0x066fd536, 0x12c4d73e, 0x1161348e, 0x1b511473, 0x0e09af29, 0x19d96d08, 0x4269bc}}, - {{0x15b8d367, 0x14ac77a9, 0x196a28f6, 0x12814bf3, 0x1a409fd3, 0x0654e218, 0x1adc8f21, 0x03505802, 0xed2b1c}}} - }, - { - /* 1*16^17*G: */ - {{{0x0134ab83, 0x10eba694, 0x190ce5dc, 0x167f35ee, 0x05868741, 0x1b86c4b3, 0x1f68af45, 0x0fa5bc16, 0x85672c}}, - {{0x190313a6, 0x07184a7b, 0x0a63d132, 0x1e2ff98a, 0x0c2e5e77, 0x024dfd31, 0x0bad8dd0, 0x136b6876, 0x7c481b}}}, - /* 3*16^17*G: */ - {{{0x03ba9000, 0x0f8391d4, 0x097a2dbf, 0x0e5f38d0, 0x0143dc48, 0x1b03ac20, 0x0305a121, 0x1f3ffe3b, 0xac3874}}, - {{0x0f10cf0a, 0x0d1e3ecb, 0x19ba7e93, 0x1c6a1afe, 0x17f93085, 0x0ef44a08, 0x01a6e18b, 0x04611438, 0xaa65e9}}}, - /* 5*16^17*G: */ - {{{0x0d06dbd4, 0x13037b37, 0x08834206, 0x1c7f0af1, 0x1e729ec0, 0x003af4d1, 0x004e6b45, 0x1cf54d0e, 0x570d5c}}, - {{0x1d1ed495, 0x132df675, 0x1182fb56, 0x0746db8c, 0x01bbbb68, 0x173388e8, 0x0bd816d9, 0x092841c0, 0xa6ae53}}}, - /* 7*16^17*G: */ - {{{0x092d230e, 0x1a60fc90, 0x04ce4a10, 0x1c6541a5, 0x06ef5dae, 0x114f701b, 0x0edbe1f0, 0x0e0504d1, 0x75b5f8}}, - {{0x151570b8, 0x1be5efde, 0x047e3ec0, 0x0f49600a, 0x1fa8e026, 0x03a2aa6e, 0x148d8f5e, 0x043c74f0, 0x527cce}}}, - /* 9*16^17*G: */ - {{{0x034fcc0e, 0x1db5fb56, 0x18e21311, 0x1e214857, 0x059c8927, 0x1c0713e9, 0x1b0ac296, 0x1f5c3dbb, 0x44fc8e}}, - {{0x119c420a, 0x07f818f3, 0x14122767, 0x1d294979, 0x1d3d7720, 0x13f3c419, 0x0d9f9249, 0x12975362, 0xd2c7de}}}, - /* 11*16^17*G: */ - {{{0x0bb69991, 0x0d240fe4, 0x0c1c5d75, 0x167f4586, 0x0f535fff, 0x0b310701, 0x0f1a19a8, 0x08f759cf, 0xdea2ba}}, - {{0x116fe2df, 0x033a154f, 0x07b66f1c, 0x1b9b66c4, 0x1b9e7229, 0x1ff6427b, 0x0392b172, 0x1adb2185, 0xae28bf}}}, - /* 13*16^17*G: */ - {{{0x114fc9cc, 0x01206812, 0x09185963, 0x00157853, 0x0a83626d, 0x07b6625c, 0x035bbf07, 0x1314dc2d, 0x3968fc}}, - {{0x1fad37dd, 0x0c9ca44a, 0x023ccd00, 0x08caedff, 0x132c91a1, 0x0c168d56, 0x04a048de, 0x1a1b696b, 0x789cbb}}}, - /* 15*16^17*G: */ - {{{0x0e0c85f1, 0x17610c8d, 0x0e8e8942, 0x0a5ca6c0, 0x145d5a6a, 0x0ef84abc, 0x08a49ac9, 0x00d31c0d, 0x689691}}, - {{0x0dc1de21, 0x03a41199, 0x1540e48b, 0x01833b41, 0x1d72d1f4, 0x02e0ec22, 0x1e495bcc, 0x16967192, 0xaefd3f}}} - }, - { - /* 1*16^18*G: */ - {{{0x00c82a0a, 0x1ecacd7b, 0x19a20cbf, 0x044d8c1e, 0x013b10f9, 0x04f8c8ca, 0x0291ac1b, 0x10136331, 0x948bf}}, - {{0x18c8e589, 0x065bfc46, 0x1f34afb5, 0x1bfe1192, 0x1418c6d4, 0x1a62e8e1, 0x191b71ad, 0x10adb96c, 0x53a562}}}, - /* 3*16^18*G: */ - {{{0x18c8ac7f, 0x1417f2fd, 0x18aa949c, 0x0485dccb, 0x0f849641, 0x1cb6902b, 0x0ef2d70c, 0x1f7c7045, 0x9945b2}}, - {{0x09aea3b0, 0x16ca1d0b, 0x16b37ea5, 0x1ef447dd, 0x0eff5282, 0x1a27fd94, 0x00b581f6, 0x104961e5, 0x3eefed}}}, - /* 5*16^18*G: */ - {{{0x169e353a, 0x08ebcf1c, 0x0ef87dbb, 0x008810a5, 0x1d5fe10a, 0x01113883, 0x03988d7e, 0x0d640b0e, 0x2a314c}}, - {{0x05746067, 0x12c9370f, 0x09962ff0, 0x14a955b6, 0x01ba0138, 0x1f23b5d5, 0x1eb06918, 0x017e6b44, 0x15a4ac}}}, - /* 7*16^18*G: */ - {{{0x09b84966, 0x0f17a4f7, 0x1fcffe62, 0x1e820dba, 0x16c911b4, 0x17d79d35, 0x10b5262d, 0x0016e07f, 0x5959a5}}, - {{0x07473a6a, 0x0533190c, 0x1f890990, 0x01b98119, 0x02a70910, 0x094106e4, 0x025fe50c, 0x0e83eb95, 0x370e6}}}, - /* 9*16^18*G: */ - {{{0x0bc6b173, 0x1864dc91, 0x1b4fface, 0x10c478fd, 0x15f9d7dd, 0x0623182d, 0x1fa38458, 0x0726e445, 0x9eeb31}}, - {{0x1723a71d, 0x09cb106c, 0x19c312e5, 0x0e357da1, 0x01ae30ea, 0x15fedddd, 0x163654aa, 0x1c0221da, 0xe121f1}}}, - /* 11*16^18*G: */ - {{{0x1ec805f3, 0x1b9221fb, 0x16656455, 0x081eea13, 0x097887de, 0x191c4037, 0x03d45bae, 0x1c98fee3, 0x39cc4f}}, - {{0x1a3c48d3, 0x0c8d0609, 0x1244b934, 0x12ae6e7f, 0x0de7dbbb, 0x1349e7a1, 0x03cc5479, 0x058b48df, 0xecb147}}}, - /* 13*16^18*G: */ - {{{0x0e22580e, 0x1eb17dae, 0x15be21e4, 0x06512da5, 0x1d4d2c71, 0x1fef326d, 0x11a5a24b, 0x0e8cdd9b, 0xf94c80}}, - {{0x1127db82, 0x0f291fb3, 0x0dc753a0, 0x0fd88a64, 0x081f6988, 0x1ffb55ad, 0x096a4652, 0x1b8cf0a4, 0x5e9c7f}}}, - /* 15*16^18*G: */ - {{{0x10c4f21f, 0x1f205d68, 0x00f69e9a, 0x0952b29a, 0x199d2502, 0x10346d8c, 0x058bf300, 0x0d8d5aba, 0x8cccb8}}, - {{0x129dfea0, 0x1f893753, 0x192f8a3d, 0x05b95904, 0x158a54b9, 0x17aa4e43, 0x110da66f, 0x0b0c4ea3, 0x57f896}}} - }, - { - /* 1*16^19*G: */ - {{{0x138fd8e8, 0x0766c0cf, 0x1a5d4ab3, 0x01c89bf8, 0x073a8f1b, 0x1e707814, 0x070d3c19, 0x0fe8c300, 0x6260ce}}, - {{0x12b4ae17, 0x0d4274ad, 0x14706630, 0x05244700, 0x01ef7ecd, 0x0824bbb5, 0x15c69fc2, 0x056df4b6, 0xbc2da8}}}, - /* 3*16^19*G: */ - {{{0x01136602, 0x185d232a, 0x078e96ee, 0x08de901b, 0x13b3d38c, 0x049bf919, 0x1f0cf416, 0x0500905b, 0x87d127}}, - {{0x18af6aac, 0x1b41e20e, 0x14efdf13, 0x1108e8df, 0x1745387a, 0x13b67fb3, 0x0f7a49a8, 0x10e14b40, 0x71ce24}}}, - /* 5*16^19*G: */ - {{{0x08c5a916, 0x1902eb9a, 0x15843c96, 0x18881aa6, 0x14aa13f5, 0x0631ed5a, 0x05d1ac2b, 0x07fc4c3d, 0xfd5d7d}}, - {{0x1adb8bda, 0x0a59bd83, 0x13dbeaac, 0x0e70297b, 0x1b52fe5d, 0x1e533ce3, 0x0c1f4ad0, 0x1a1dd6ab, 0xdd83e}}}, - /* 7*16^19*G: */ - {{{0x15f7529c, 0x0ecc84b1, 0x0f547751, 0x0cb7316b, 0x04381387, 0x09e1969a, 0x1848ae91, 0x02130384, 0xde0dd4}}, - {{0x04cd88fe, 0x1e106017, 0x06ddd018, 0x12498d11, 0x03570178, 0x04c116bd, 0x117e6c84, 0x13a21442, 0xd70a6e}}}, - /* 9*16^19*G: */ - {{{0x18f76d11, 0x0417a469, 0x014555cf, 0x02001f7f, 0x092a2151, 0x1f7e1ce1, 0x1139a716, 0x115b499e, 0xb26c20}}, - {{0x03b7356b, 0x00e0058f, 0x009892f7, 0x0060cb3b, 0x16433050, 0x143ec866, 0x0cf3c313, 0x1041293a, 0x1f1cf8}}}, - /* 11*16^19*G: */ - {{{0x069e22db, 0x0a71d833, 0x07224cfe, 0x127feb3f, 0x0294eac9, 0x1e9480c6, 0x148e9f8e, 0x171f8ffe, 0xfceb14}}, - {{0x1c2260a1, 0x1ab96d92, 0x13af932f, 0x0a1cf274, 0x10924ad5, 0x12d3a92f, 0x0347f362, 0x07481ad7, 0x64aa6b}}}, - /* 13*16^19*G: */ - {{{0x038a2755, 0x18420bcd, 0x1271541b, 0x0434e2ca, 0x07faa537, 0x1abba5a8, 0x12b15705, 0x0c4799ab, 0x4e909a}}, - {{0x03cca3de, 0x1bd24fb1, 0x0a60032b, 0x1aa729a4, 0x159dbb6c, 0x036ea83a, 0x16bb3bc9, 0x10f199c6, 0xae56da}}}, - /* 15*16^19*G: */ - {{{0x183ba64d, 0x012c4acc, 0x116568ea, 0x0c1eef11, 0x040e2bde, 0x10a2f5c7, 0x100efec2, 0x0b845c09, 0xc36745}}, - {{0x0a2181fd, 0x0a6647cb, 0x1de3c518, 0x04d55942, 0x164c7426, 0x0737426c, 0x00cc2038, 0x1a0d396c, 0x3a520a}}} - }, - { - /* 1*16^20*G: */ - {{{0x0037fa2d, 0x0a9e6469, 0x0ff710ca, 0x1d91eaeb, 0x14103043, 0x0420a5df, 0x0350f60d, 0x1c15f83b, 0xe5037d}}, - {{0x1d755bda, 0x072ee420, 0x1207c438, 0x1eb607d8, 0x10bddbd5, 0x0684fdcc, 0x0ed7e7e6, 0x0975529a, 0x457153}}}, - /* 3*16^20*G: */ - {{{0x177e7775, 0x04545370, 0x1b657d8e, 0x02ab2711, 0x091aeb5e, 0x01dd67a9, 0x0f3b9615, 0x075ff2c6, 0x9d896a}}, - {{0x1a056691, 0x1e7b69d5, 0x06494efb, 0x139afdc5, 0x0927de89, 0x1276b928, 0x1c2e53a5, 0x1c87e937, 0xdd91a9}}}, - /* 5*16^20*G: */ - {{{0x1c2a3293, 0x1ef026f1, 0x00d1db17, 0x1170ddd2, 0x0f4cd568, 0x052b9941, 0x1e4b43ac, 0x1dce22c6, 0x8327b8}}, - {{0x0e0df9bd, 0x1e42a70c, 0x0c9a905a, 0x1fb569dc, 0x1708496a, 0x1f53313c, 0x063862ec, 0x04cddc15, 0x4997e}}}, - /* 7*16^20*G: */ - {{{0x0562c042, 0x010d9362, 0x037ec689, 0x1a464697, 0x08ed6092, 0x130ec7cd, 0x05a25f59, 0x15454db6, 0x5ae42a}}, - {{0x0f79269c, 0x082e66fc, 0x1f3636fe, 0x01b72a20, 0x09d4a94e, 0x0eee301c, 0x147aad70, 0x0f80bfe0, 0x99d93a}}}, - /* 9*16^20*G: */ - {{{0x1e85af61, 0x1a440942, 0x12b9d9ac, 0x1dae45ba, 0x01b0f4e8, 0x1b47fb61, 0x03ad66ba, 0x1c84d439, 0x92c23a}}, - {{0x036a2b09, 0x1391b34e, 0x0a1bfb53, 0x075b056c, 0x0d5792d2, 0x0beae39c, 0x0ed027c8, 0x11e02aa3, 0x414cf8}}}, - /* 11*16^20*G: */ - {{{0x07b5eba8, 0x11578d96, 0x063a8db3, 0x17db8ff2, 0x0df422da, 0x1a0bb57c, 0x1c422343, 0x118ed5fb, 0xfee560}}, - {{0x0d0b9b5c, 0x1a8ae9b4, 0x04151e4f, 0x01fe857f, 0x1c14ee38, 0x017cc943, 0x02bec450, 0x12269fcb, 0x380759}}}, - /* 13*16^20*G: */ - {{{0x1c63caf4, 0x0f1dd259, 0x1d4f54a0, 0x1fe75651, 0x06afca28, 0x09da6315, 0x1f988284, 0x1d725ccc, 0x42e544}}, - {{0x169c29c8, 0x03d7604c, 0x1bf17c46, 0x0a1cf6d7, 0x15e7873a, 0x11060ba0, 0x19c7dc7c, 0x1c1f2398, 0x9ff854}}}, - /* 15*16^20*G: */ - {{{0x1e0f09a1, 0x0515ecc2, 0x100ca0e0, 0x0213e372, 0x00efef0a, 0x17695238, 0x138e0e65, 0x16ccaa65, 0x7aed83}}, - {{0x05857d73, 0x02ec66f4, 0x0fd29501, 0x165e601e, 0x12d8ed88, 0x1e855881, 0x1df1f76b, 0x0bf3463d, 0xf5b854}}} - }, - { - /* 1*16^21*G: */ - {{{0x04fce725, 0x0c335057, 0x09b16dc9, 0x11b7a38d, 0x171b4e7e, 0x082f478b, 0x1eb7d7aa, 0x161e9440, 0xe06372}}, - {{0x0eee31dd, 0x1381a7ca, 0x04121c2c, 0x1094ef0e, 0x0488cd74, 0x1dd956ad, 0x13f84a89, 0x0e979c31, 0x7a9089}}}, - /* 3*16^21*G: */ - {{{0x1a328d6a, 0x1d540c46, 0x0b7062f6, 0x1aee752b, 0x08fa7b24, 0x04c8c2d8, 0x18028d1a, 0x0b74c469, 0xc663c0}}, - {{0x1ec9b8c0, 0x1d85db55, 0x0afe7308, 0x0aa3d4a2, 0x11317dd8, 0x1ee793ab, 0x10e34e6b, 0x11abee43, 0x3331e9}}}, - /* 5*16^21*G: */ - {{{0x1996de2f, 0x048e4241, 0x0c94452f, 0x1dbe5dc1, 0x1e4e977c, 0x186f7507, 0x091673ac, 0x105bf70d, 0xd3fc26}}, - {{0x14526f8c, 0x0249120e, 0x1eafc5a3, 0x136931be, 0x181da4e5, 0x03aa6a7b, 0x0863da2d, 0x13348be1, 0xc4f0df}}}, - /* 7*16^21*G: */ - {{{0x03e697ea, 0x03624688, 0x17e0fa17, 0x0cf1f730, 0x1abd19ce, 0x0ff64d1f, 0x008df728, 0x087fd658, 0xc17a4b}}, - {{0x1edc6c87, 0x171dc3ee, 0x07c0aac3, 0x03436aff, 0x01fae96e, 0x1c7b8cb0, 0x05532b85, 0x05aab56b, 0x39355c}}}, - /* 9*16^21*G: */ - {{{0x1163da1b, 0x16961811, 0x04e8c460, 0x1dbdcc1f, 0x11fde9a0, 0x1a4ebfe0, 0x02d1a324, 0x0f944cf2, 0x8f618b}}, - {{0x03bdd76e, 0x1f989088, 0x126db9f1, 0x018cd464, 0x05a42645, 0x0d3a6bd6, 0x0dbad7ef, 0x04be117d, 0x78233f}}}, - /* 11*16^21*G: */ - {{{0x0ec8ae90, 0x142c87f0, 0x0ef177bb, 0x04d725d1, 0x1f1b8cfb, 0x0dc6d641, 0x19bae1b5, 0x1e2b6f43, 0x9798c0}}, - {{0x052844d3, 0x14d61757, 0x0c62389e, 0x092cb7a0, 0x073bee2e, 0x04a4a7ce, 0x1b4f74bb, 0x154eb485, 0xba40e2}}}, - /* 13*16^21*G: */ - {{{0x11d66b7f, 0x0d0cbc78, 0x01f72041, 0x0d24a0a3, 0x084757aa, 0x0dc85c49, 0x159d1f3c, 0x1c7f6b45, 0xfdfa6e}}, - {{0x18e5178b, 0x1547c033, 0x15e37a76, 0x0df3ba27, 0x018c4d84, 0x00e4d1ed, 0x036e4f03, 0x03c44933, 0x4d9cf3}}}, - /* 15*16^21*G: */ - {{{0x1265bcf0, 0x003abc24, 0x071f4c2e, 0x1c56f082, 0x1220e69c, 0x14d230e7, 0x190eb77a, 0x071bc453, 0xfd58ce}}, - {{0x0b996292, 0x19f3d4e7, 0x1c73477c, 0x0c37fc51, 0x1e4fb872, 0x155cd242, 0x056f54e0, 0x1ca6ec64, 0xffe0a5}}} - }, - { - /* 1*16^22*G: */ - {{{0x10559754, 0x056b4846, 0x08fd6150, 0x0217bbc5, 0x0e02204b, 0x1dfcee06, 0x114d6342, 0x0e2b9aba, 0x213c7a}}, - {{0x14b458f2, 0x1f9613a9, 0x1a9fbb77, 0x10a1ebe6, 0x1a190bb4, 0x1683122d, 0x0941c04e, 0x016b5c8c, 0x4b6dad}}}, - /* 3*16^22*G: */ - {{{0x1e05dccc, 0x196c008c, 0x066a4f94, 0x1f47da98, 0x1d172ae3, 0x104b5ca9, 0x00c2551b, 0x1c2ea7b4, 0xb8cef6}}, - {{0x0c6d5750, 0x00a5067e, 0x1ada04cc, 0x0aff86d4, 0x0bd99df7, 0x053a7269, 0x0efda935, 0x0c14d993, 0x302b8a}}}, - /* 5*16^22*G: */ - {{{0x173bb31a, 0x0deff709, 0x16e5ed21, 0x1ef6d6bf, 0x15f49701, 0x05ef175d, 0x0e1780a8, 0x1cef368e, 0x3fb33}}, - {{0x1d215c9e, 0x1a65f34b, 0x1d903538, 0x14f8ed88, 0x1572bc65, 0x0b0d55dd, 0x18a07830, 0x0a4a91df, 0xf36ad9}}}, - /* 7*16^22*G: */ - {{{0x1d9a4ab4, 0x0da8af5e, 0x16edf029, 0x186d830a, 0x17a36717, 0x17bda687, 0x184587c5, 0x1a213d87, 0x4b177c}}, - {{0x035ab6f7, 0x156eff23, 0x1d07d562, 0x0fc4abe2, 0x06b486e3, 0x1b3949b1, 0x0997f6a3, 0x1d34bc5f, 0x3ec966}}}, - /* 9*16^22*G: */ - {{{0x101c23a4, 0x1a37d94d, 0x09273d5b, 0x1482b08f, 0x1cd75c22, 0x1c14dcdc, 0x081b0a80, 0x0a40d44f, 0x5e8703}}, - {{0x10d986f9, 0x10bccb58, 0x1333f684, 0x0e3b0e94, 0x06e2da21, 0x0ae8d716, 0x08879c5d, 0x09df7392, 0x5b9664}}}, - /* 11*16^22*G: */ - {{{0x007b0c66, 0x19f9ae90, 0x1b21bec7, 0x0ffdc8ca, 0x0eb7434a, 0x1227b056, 0x002911c8, 0x003261ad, 0xe545c3}}, - {{0x11f2d470, 0x03fabe93, 0x1688e776, 0x0b051c36, 0x1bcbf97e, 0x17ed1cac, 0x1579f971, 0x01d18c52, 0xe06a34}}}, - /* 13*16^22*G: */ - {{{0x03648bba, 0x12c0c85c, 0x10f1d112, 0x01e160d3, 0x1b39882a, 0x17112f80, 0x160284cf, 0x02af4a9e, 0xb2a442}}, - {{0x00fb6452, 0x037d5a50, 0x0705eec9, 0x10aa2a39, 0x17e31c0d, 0x1e4bc7de, 0x19867a7e, 0x1856d26c, 0xfe4f5f}}}, - /* 15*16^22*G: */ - {{{0x0bab27d0, 0x1b6e9177, 0x11440ff3, 0x1683f458, 0x17007f70, 0x180c8c6c, 0x01946ea5, 0x01e7a8a7, 0x1b908e}}, - {{0x00d3d110, 0x0f433af2, 0x1f946d5c, 0x179526b0, 0x04b9ab5b, 0x1e48c0be, 0x0d79bcd5, 0x0bdd88cd, 0x9b6d62}}} - }, - { - /* 1*16^23*G: */ - {{{0x08fbd53c, 0x0661d1d8, 0x118b377c, 0x0718e15b, 0x19a87e28, 0x09a952a0, 0x0d3a36ee, 0x054f5e96, 0x4e7c27}}, - {{0x17dcaae6, 0x059ca0c0, 0x1df74cf8, 0x172c297f, 0x1681b530, 0x084fb6f7, 0x0c6385bf, 0x0ecd93a1, 0x17749c}}}, - /* 3*16^23*G: */ - {{{0x0521b3ff, 0x114c2327, 0x0a9d433b, 0x180e2fd3, 0x024a5233, 0x0695f4d7, 0x1571d791, 0x06021928, 0x2484e}}, - {{0x0269da7e, 0x00d725c8, 0x0eb22ef3, 0x000dbd24, 0x10eebad7, 0x159e1596, 0x0c341fb0, 0x1415447c, 0x9619d0}}}, - /* 5*16^23*G: */ - {{{0x004ba7b9, 0x0b5bcfd4, 0x1d05d47e, 0x0d48e060, 0x0954e20d, 0x1b86b396, 0x195fbde6, 0x04d9f6d9, 0x16c1c5}}, - {{0x1c5bd741, 0x1adf1d28, 0x126a7311, 0x0ab8037b, 0x094deec7, 0x13a2ce45, 0x10e41898, 0x0f868062, 0xdb157f}}}, - /* 7*16^23*G: */ - {{{0x036683fa, 0x01b243d5, 0x1b02097a, 0x0436a701, 0x07b66958, 0x0e73ba29, 0x06be1ea2, 0x1aea7f26, 0x3973c}}, - {{0x1f4a577f, 0x1afd95bb, 0x1a6077b7, 0x1109c31f, 0x1a26cd77, 0x095b195a, 0x0e8d90f8, 0x05986194, 0x38cf5a}}}, - /* 9*16^23*G: */ - {{{0x00bf6f06, 0x0059ccce, 0x010ed5c6, 0x1826644a, 0x05765713, 0x027a5810, 0x054470b0, 0x174e5d9e, 0xba6a9b}}, - {{0x181db551, 0x195f7b83, 0x1a5eabf8, 0x1a29ef58, 0x0bd8e9e5, 0x05f972ac, 0x06c0c808, 0x07166942, 0x13771e}}}, - /* 11*16^23*G: */ - {{{0x11231a43, 0x08f7cf83, 0x0b50ee7f, 0x0a29accb, 0x0442f44d, 0x0ca8326f, 0x174b62bb, 0x1984f989, 0x35c5bc}}, - {{0x1620c8f6, 0x0db97228, 0x0f3c2b9f, 0x0f49980c, 0x0589d4cf, 0x0c105b7d, 0x1b39cd39, 0x0e4772e8, 0xe3675}}}, - /* 13*16^23*G: */ - {{{0x1dd40609, 0x1a05e2b7, 0x00735daf, 0x0321301b, 0x0356ac74, 0x1897e2c4, 0x1af2848b, 0x048b8ab0, 0xfd479c}}, - {{0x0a64ca53, 0x0f1789b3, 0x07291ce7, 0x075dae4c, 0x041fd911, 0x0bd21e4c, 0x1fbfcb2b, 0x16a4d295, 0x3069cf}}}, - /* 15*16^23*G: */ - {{{0x0b799a7f, 0x0db817a9, 0x0e3a1093, 0x116d9aa7, 0x07d544f1, 0x075cd796, 0x0192f7b6, 0x0547599b, 0x6c4000}}, - {{0x13c81e32, 0x1ae64166, 0x0120fda2, 0x157a9904, 0x1dcbdc07, 0x01b5070e, 0x16f9a42e, 0x02a616c6, 0x95c2dc}}} - }, - { - /* 1*16^24*G: */ - {{{0x00fb27b6, 0x1213f142, 0x10c15d8c, 0x1c7b657c, 0x06aa5c76, 0x1c56b0b4, 0x0c6c43c8, 0x07b7cef1, 0xfea74e}}, - {{0x123cb96f, 0x00e9edbf, 0x0fdedddc, 0x16b2d72e, 0x0af93126, 0x1a6f665b, 0x0ca5f3d9, 0x1b736162, 0x6e0568}}}, - /* 3*16^24*G: */ - {{{0x1e889756, 0x0ec0d74d, 0x0012ec97, 0x16c932f6, 0x099f3f27, 0x0cbd938c, 0x1aa089b3, 0x1866423f, 0x762e8b}}, - {{0x1ca6b774, 0x0f12cf03, 0x013e9789, 0x05b66291, 0x0e347197, 0x0278a4c1, 0x05f0f1f3, 0x04c15e7d, 0xc02894}}}, - /* 5*16^24*G: */ - {{{0x0975d2ea, 0x17baf4b8, 0x053a3a89, 0x0559f420, 0x0f4a91e5, 0x1edd9184, 0x14d23866, 0x08fbec12, 0xdf077d}}, - {{0x11936f95, 0x11e16cf1, 0x0f749dea, 0x1d8b709f, 0x0527c8a1, 0x012e4c51, 0x1d109321, 0x11001def, 0xf8617a}}}, - /* 7*16^24*G: */ - {{{0x1c4c92d7, 0x1c248fdd, 0x10e46d16, 0x169addca, 0x1142935d, 0x0f5419a5, 0x080cb85f, 0x0eb17a7b, 0x9f3e7d}}, - {{0x114906dd, 0x05ddfe7d, 0x0538461b, 0x144607ad, 0x11502452, 0x1590e5d5, 0x19ad6218, 0x03d4efa8, 0xecd284}}}, - /* 9*16^24*G: */ - {{{0x12a8c483, 0x1706b995, 0x0102b0d6, 0x1619118a, 0x15281174, 0x01e9177c, 0x1e7b70e3, 0x0baf6b99, 0xa0cc79}}, - {{0x12cc6ba9, 0x04b3a2ac, 0x1a4d8154, 0x091e37be, 0x1df786b3, 0x07e4b918, 0x1cfb88dd, 0x045f1670, 0xabc301}}}, - /* 11*16^24*G: */ - {{{0x05dd3aee, 0x1878db5e, 0x05b4bc85, 0x0a75151f, 0x176ca131, 0x154d6354, 0x1f338388, 0x14a2aa78, 0x6d1c50}}, - {{0x1df597f7, 0x171aa727, 0x1b54eb7f, 0x1c621551, 0x1d474851, 0x19001143, 0x1f725dc9, 0x11c0d57b, 0xafff14}}}, - /* 13*16^24*G: */ - {{{0x04a6d0bb, 0x1c654dbf, 0x086bf719, 0x1a6245eb, 0x0418f659, 0x136c5453, 0x07cfcc46, 0x0c3172ff, 0x5e5f1d}}, - {{0x1033eaf9, 0x141c23c8, 0x1bd94e85, 0x0abe5ca0, 0x121da725, 0x15e68273, 0x1bdcd63d, 0x0560d4fc, 0xd7b150}}}, - /* 15*16^24*G: */ - {{{0x0f005e3f, 0x0d4daf22, 0x10e6f4b7, 0x0d1c637d, 0x1a1495af, 0x05cd6700, 0x09ffff4f, 0x0d6782c8, 0xf8138a}}, - {{0x0f357eb7, 0x16bf0101, 0x12f884d0, 0x18837aaa, 0x1cb51f4e, 0x0af2bd52, 0x0f67e740, 0x077df69d, 0xca758f}}} - }, - { - /* 1*16^25*G: */ - {{{0x17bdde39, 0x16015220, 0x1810ca54, 0x09c2f36e, 0x168d3154, 0x0b86accc, 0x1c384289, 0x027ecef9, 0x76e641}}, - {{0x1901ac01, 0x058ba968, 0x1b480cad, 0x1467a56a, 0x1f0d35e2, 0x136b8340, 0x173d5dc1, 0x11bdc9d2, 0xc90ddf}}}, - /* 3*16^25*G: */ - {{{0x0078ee8d, 0x182848e6, 0x1a46510b, 0x1e419ca0, 0x14ff64eb, 0x1931d54d, 0x06f897fd, 0x15b0b3b5, 0xd08e57}}, - {{0x0da63e86, 0x0cbfa6e1, 0x08bb677a, 0x1def9f28, 0x06df4123, 0x19773abf, 0x035cb585, 0x13095691, 0x852e97}}}, - /* 5*16^25*G: */ - {{{0x029129ec, 0x0c8a3382, 0x12095205, 0x1c759e3c, 0x11d080ca, 0x1f407669, 0x149d7d62, 0x10bc9a89, 0x7da6c0}}, - {{0x0cd9ff0e, 0x1a857715, 0x12961aba, 0x11810ca9, 0x027bf044, 0x0103a48b, 0x015d4474, 0x0d773e83, 0xf49814}}}, - /* 7*16^25*G: */ - {{{0x11654f22, 0x1c1ea4aa, 0x06abba53, 0x0fe72846, 0x1d94fb2f, 0x0800df34, 0x19b886fa, 0x19feb837, 0x90d090}}, - {{0x001a43e1, 0x1aef02bb, 0x08fe1d03, 0x0c6aca7b, 0x170336dd, 0x010f035f, 0x186a54fc, 0x03a5759e, 0xcd569a}}}, - /* 9*16^25*G: */ - {{{0x076b19fa, 0x1b77b28e, 0x020675c6, 0x0dc0da0d, 0x1292ed9d, 0x16188410, 0x07b31cc8, 0x0b0f9e3a, 0xda4798}}, - {{0x126f5af7, 0x15137759, 0x14ff081a, 0x17a27d2a, 0x0569ea67, 0x1483bf0b, 0x1c0745cd, 0x0f137995, 0xebb1d7}}}, - /* 11*16^25*G: */ - {{{0x19135dbd, 0x0c97db2d, 0x1618c7b3, 0x010f5e73, 0x1897cf0c, 0x157ac174, 0x19ab605e, 0x00951bbd, 0xe3e475}}, - {{0x0748045d, 0x083579f2, 0x12576a5a, 0x0405febd, 0x03ffea5a, 0x040ca95c, 0x1b102e63, 0x1f013978, 0x930a5b}}}, - /* 13*16^25*G: */ - {{{0x0dee455f, 0x1f85cf2e, 0x13901d72, 0x0fffcdd1, 0x1db4aff6, 0x099c7c05, 0x06c291d1, 0x0dfd0e15, 0x7e8c65}}, - {{0x171b9cba, 0x19ef4cc0, 0x1d1989c5, 0x05a2ce8d, 0x1a53b4aa, 0x1b07a401, 0x103ca8fd, 0x0659460e, 0xbdddc6}}}, - /* 15*16^25*G: */ - {{{0x0698b59e, 0x1bcb5cdb, 0x0d11e90d, 0x06b24b12, 0x1c7260a3, 0x01ad59f1, 0x1ac56fac, 0x1f12352b, 0x3df841}}, - {{0x0b92baf5, 0x07c733cb, 0x12527e2f, 0x190cf642, 0x0f3867bf, 0x1d74788e, 0x0307680a, 0x1bf31612, 0xb38fe6}}} - }, - { - /* 1*16^26*G: */ - {{{0x0bcbb891, 0x158a8121, 0x09b2fb8e, 0x198c87be, 0x18f9a8f7, 0x0dd53a1f, 0x0f87a0a0, 0x0d607655, 0xc738c5}}, - {{0x099a84c3, 0x1f39aecb, 0x0033fa45, 0x029ddef1, 0x1bbbb823, 0x0797565f, 0x094dfdc6, 0x0f12a35a, 0x893fb5}}}, - /* 3*16^26*G: */ - {{{0x0761d58d, 0x05d5799c, 0x15838bcd, 0x1937c811, 0x0df7aca4, 0x0051ab90, 0x05184289, 0x04f047ec, 0xb8c461}}, - {{0x1d1051a4, 0x1c7505d4, 0x041f16d8, 0x0a08f0bc, 0x1c5053f7, 0x0c7b4bf9, 0x0df45291, 0x0d8a2e1c, 0x8f9ed9}}}, - /* 5*16^26*G: */ - {{{0x050b0040, 0x0d859820, 0x04d2b70b, 0x08fb73e0, 0x03671f3f, 0x04c9ff4d, 0x07de8d43, 0x13ee204e, 0x8d56e}}, - {{0x1b3fd0a1, 0x0c7133d2, 0x05e0afad, 0x0f88e41c, 0x1b285f6d, 0x0a8546bc, 0x0a887ff4, 0x15d7a153, 0xa12185}}}, - /* 7*16^26*G: */ - {{{0x13573b7f, 0x0b2b1ef8, 0x02d89c3d, 0x1438bda6, 0x05a37889, 0x07cbbdf3, 0x198d0788, 0x065a85f9, 0xdc13f2}}, - {{0x0c1f2ba6, 0x15669142, 0x1012c710, 0x0aa8e02e, 0x10a76704, 0x086d4254, 0x1030f1d0, 0x100853c6, 0xc909ba}}}, - /* 9*16^26*G: */ - {{{0x07ae9ceb, 0x017ac85c, 0x1bcb452c, 0x1843d4e1, 0x119a8226, 0x0ab2ed90, 0x1c1cebc6, 0x1cc03bef, 0x25c02d}}, - {{0x0bc6e275, 0x1848689a, 0x1961c991, 0x0c83be14, 0x111d537c, 0x0706e7d6, 0x00f03221, 0x1a590247, 0x8a9fea}}}, - /* 11*16^26*G: */ - {{{0x0c5a3c34, 0x1c04c7b7, 0x16527f87, 0x1d058052, 0x03e58aec, 0x0fa653d7, 0x1273a2ae, 0x03659f1c, 0xfedd9d}}, - {{0x013d7714, 0x15aa5fa7, 0x0fe0a5d8, 0x1d6a8d33, 0x14b00ada, 0x02989647, 0x0382c2fa, 0x18630a77, 0xa52e24}}}, - /* 13*16^26*G: */ - {{{0x0ab6a396, 0x1a72a68d, 0x04d81da6, 0x04372342, 0x088b3730, 0x16bfaf42, 0x1230b7b8, 0x10d78dd4, 0x3e0e32}}, - {{0x1980e27e, 0x1598f246, 0x11a3da8b, 0x002083e6, 0x13fc66ab, 0x1f0ef5a2, 0x1e593cc7, 0x0e5f4766, 0xca4481}}}, - /* 15*16^26*G: */ - {{{0x141023ec, 0x179ac311, 0x1b3d5c2a, 0x0bb1eedf, 0x0b9af564, 0x101004c1, 0x14a1260b, 0x06101865, 0x344ab9}}, - {{0x1e1eeb87, 0x07c4c148, 0x0e6575c1, 0x1d2ed5f8, 0x14c5ffc4, 0x1968f528, 0x18a9cfe3, 0x00856488, 0x6e1c2b}}} - }, - { - /* 1*16^27*G: */ - {{{0x08f6c14b, 0x1974fb2c, 0x0494050d, 0x0e5cbe75, 0x12877d1d, 0x03b1be4b, 0x0e078993, 0x0ca916cb, 0xd89562}}, - {{0x1d7d991f, 0x09b1f6ba, 0x0c19f85e, 0x051ac657, 0x140eb034, 0x03040c61, 0x1ab9ca3b, 0x071e578f, 0xfebfaa}}}, - /* 3*16^27*G: */ - {{{0x0127b756, 0x05d43ffb, 0x0825c120, 0x0517c957, 0x0b416034, 0x116d2830, 0x0499cb4d, 0x05ee2dbe, 0x6d8c78}}, - {{0x1f172571, 0x0a8fba55, 0x1f373299, 0x154db45a, 0x14daf4e3, 0x14169b69, 0x04445166, 0x0112dfb7, 0x99aedf}}}, - /* 5*16^27*G: */ - {{{0x158cf17a, 0x0f70d39b, 0x0208d493, 0x10bb974b, 0x097f8f1f, 0x0d778da0, 0x0b2a3416, 0x1bb2b7ef, 0xebcabe}}, - {{0x1caa0ccd, 0x0366e2fa, 0x0b3a5711, 0x15a425a1, 0x12e6b10f, 0x050db3e1, 0x072c0b00, 0x01f1e457, 0x47d3ce}}}, - /* 7*16^27*G: */ - {{{0x0c855c5b, 0x077728ad, 0x1f22beef, 0x0ac43402, 0x1fc28118, 0x0d1b4f0b, 0x189114cc, 0x05c97a99, 0xe8df4d}}, - {{0x0e465650, 0x0eaf3961, 0x07935f56, 0x076abe3c, 0x132c5966, 0x0da7acf7, 0x0c991113, 0x0e188ff3, 0x6c57fd}}}, - /* 9*16^27*G: */ - {{{0x12e7e454, 0x047aded2, 0x03985434, 0x05dfde1e, 0x01662fe3, 0x03011d4c, 0x00ca4492, 0x1ae31d95, 0x4068d3}}, - {{0x18ef191e, 0x1cd66f2e, 0x10dccc9d, 0x1a43da27, 0x138d1988, 0x0a2cbece, 0x1eaae7b0, 0x16e4a948, 0x8cd853}}}, - /* 11*16^27*G: */ - {{{0x06c5d939, 0x02bd6fc2, 0x0a4cf782, 0x0b450ef7, 0x0027ea47, 0x19973065, 0x1782d56f, 0x19b63b04, 0x12550e}}, - {{0x19e757c9, 0x153a7e2a, 0x16350c64, 0x16e83fd9, 0x04a72838, 0x121e0bb9, 0x1e9d5123, 0x069f0e5a, 0x7b8f83}}}, - /* 13*16^27*G: */ - {{{0x16c8a56f, 0x06855632, 0x1cdd084e, 0x1278a869, 0x0d08f850, 0x1bda9d7d, 0x17531a6e, 0x035876b0, 0x944d67}}, - {{0x1a7be289, 0x0fa6e32e, 0x01945fae, 0x0982e9ba, 0x0c61967d, 0x1c9b099d, 0x1ffd3050, 0x12ef6a03, 0xa71065}}}, - /* 15*16^27*G: */ - {{{0x0e08f15a, 0x175c50c5, 0x04a402eb, 0x13cadb90, 0x1c305fd6, 0x01b2ad69, 0x0833f9ac, 0x1239a133, 0x86a54e}}, - {{0x01388308, 0x09268f3e, 0x0d49534d, 0x053a24b6, 0x16867771, 0x146836ba, 0x1180e9ca, 0x0906f4f0, 0xcfee61}}} - }, - { - /* 1*16^28*G: */ - {{{0x0f676e03, 0x08a852b2, 0x1a13b752, 0x1f8e6d27, 0x08761cef, 0x1219ab8f, 0x1463ac3d, 0x006552ae, 0xb8da94}}, - {{0x0efdf6e7, 0x0447273a, 0x1fced445, 0x18b09b2b, 0x008b092c, 0x0e64bb14, 0x07935f26, 0x148900b4, 0x2804df}}}, - /* 3*16^28*G: */ - {{{0x06e1346b, 0x10cc24ee, 0x16bc717a, 0x1cf62070, 0x152c05ab, 0x1b0f8a68, 0x042f9531, 0x1fe1305a, 0x69068}}, - {{0x17226c13, 0x1dac52a6, 0x11809b9e, 0x0d127329, 0x0442aa4f, 0x0d95e843, 0x189b6a17, 0x1c1217fb, 0xb863e3}}}, - /* 5*16^28*G: */ - {{{0x1ca1f6a1, 0x07348fe6, 0x033fc68c, 0x197a2869, 0x06ce1068, 0x0e2e58f4, 0x1d854a1b, 0x127964b2, 0x898c34}}, - {{0x164f647c, 0x056e1078, 0x0af5e729, 0x0f9f2f3e, 0x06e93b2a, 0x0a122956, 0x15527611, 0x10d56ad4, 0x75f759}}}, - /* 7*16^28*G: */ - {{{0x1d1e3998, 0x134f01e1, 0x0810ca2a, 0x0d91722f, 0x0274e5e5, 0x0ceb8115, 0x0fc0694a, 0x1fda5231, 0xb213e2}}, - {{0x125fb81e, 0x0165ee31, 0x17b45d7b, 0x082cb7d7, 0x03bc3d53, 0x0f5fc1d2, 0x104b0f58, 0x1841e5a7, 0x229f8e}}}, - /* 9*16^28*G: */ - {{{0x025be234, 0x05f0ff65, 0x17cd41c0, 0x07c7ce1b, 0x06e060e8, 0x05d348b0, 0x04f97474, 0x1b02d8ff, 0x4b3b3a}}, - {{0x120e8362, 0x11dbf01c, 0x0846e101, 0x0ffb259e, 0x0c04c41e, 0x14b6fec6, 0x1271e1d7, 0x0770bb57, 0x5eec02}}}, - /* 11*16^28*G: */ - {{{0x0289f55e, 0x0b31a53f, 0x11d9c1ee, 0x0d61e1c5, 0x165be297, 0x08d813c4, 0x1e580809, 0x16dbb609, 0x9f7b88}}, - {{0x1e1e4bde, 0x1e69db2f, 0x0428ac6c, 0x0a6dc1d6, 0x1c71fc0e, 0x035a14c7, 0x03def8c5, 0x1098e082, 0x32f9f7}}}, - /* 13*16^28*G: */ - {{{0x1dfe1d2b, 0x12a4e460, 0x1a1e3945, 0x07ea13ca, 0x173a4c49, 0x056fe9fd, 0x038f9db3, 0x1d396e89, 0xd58a43}}, - {{0x0cd50922, 0x0793cadc, 0x0f5befff, 0x137442b9, 0x0276b54d, 0x14899414, 0x0f3c429c, 0x0d740b10, 0xfc1786}}}, - /* 15*16^28*G: */ - {{{0x049c795e, 0x120a8df1, 0x13a01784, 0x080d5533, 0x1ea4eed4, 0x0b4e1e13, 0x0c4335b6, 0x072e2230, 0x21d271}}, - {{0x19208ece, 0x0009761c, 0x17edd86c, 0x03289495, 0x1b4c3d67, 0x0dc2a915, 0x13a85dcd, 0x16960eb5, 0x94c5f9}}} - }, - { - /* 1*16^29*G: */ - {{{0x03c0df5d, 0x0d08bbc7, 0x15a9e4bc, 0x13dff6a2, 0x17fab201, 0x0d5ca3ae, 0x0ce9f62b, 0x028883f6, 0xe80fea}}, - {{0x0ac9ec78, 0x05a148db, 0x0c8baa7f, 0x0abd015e, 0x094472d1, 0x1b4651e5, 0x01dc7a25, 0x0fec71c0, 0xeed1de}}}, - /* 3*16^29*G: */ - {{{0x17592d55, 0x001acf66, 0x18d4064b, 0x0b728e81, 0x0e3b106d, 0x17b4b19e, 0x149822bf, 0x1b789420, 0x5d2ec6}}, - {{0x0f5183a7, 0x1372e875, 0x04545d09, 0x14f79b5a, 0x0d6950e2, 0x087d1346, 0x17ad63dc, 0x1f138dc8, 0xa92cd}}}, - /* 5*16^29*G: */ - {{{0x1e8f9f5c, 0x08fa5a4f, 0x02029466, 0x03e3c2b3, 0x1404d736, 0x171a10af, 0x1d0bf8b2, 0x1876237e, 0xac371d}}, - {{0x125a503c, 0x1d41ff99, 0x1d478745, 0x0a68b1dc, 0x0e735229, 0x00f3992a, 0x11dffc84, 0x1830e134, 0xc51616}}}, - /* 7*16^29*G: */ - {{{0x19e33446, 0x050e46a8, 0x0bce177d, 0x127788a5, 0x0a17a408, 0x005e8111, 0x10324d23, 0x07429e30, 0x894200}}, - {{0x06387689, 0x069c5007, 0x19d3e610, 0x1aee6cf3, 0x1e4e06bf, 0x16b6877e, 0x1de9362c, 0x12b2b4a0, 0xa9fd03}}}, - /* 9*16^29*G: */ - {{{0x1913cb26, 0x0b9464ad, 0x0ef5b40f, 0x16833802, 0x05c9899e, 0x1227faa8, 0x0aa28b36, 0x0d661468, 0x277026}}, - {{0x1348a7a2, 0x1f38b99f, 0x0056faef, 0x01923799, 0x0b324e94, 0x092683f9, 0x0c69554b, 0x0bcf361b, 0xf649bc}}}, - /* 11*16^29*G: */ - {{{0x195e8247, 0x0555010a, 0x01b346bc, 0x1fb88aad, 0x0ba9097b, 0x13700e7c, 0x1485e397, 0x1a70797d, 0x75e4d0}}, - {{0x19982d22, 0x111fecea, 0x06b624f2, 0x156b6dd5, 0x126d47dd, 0x0b8763db, 0x0641d07e, 0x142ea821, 0x1fce42}}}, - /* 13*16^29*G: */ - {{{0x06333323, 0x03cfa26d, 0x1d2afd1d, 0x177838d1, 0x0da849cb, 0x06b02cc2, 0x0fc0fc08, 0x07066c37, 0x3ed1b6}}, - {{0x15d61ba3, 0x189fe245, 0x1e3dca52, 0x0e514216, 0x1929ea9b, 0x04c4b447, 0x1b9d765f, 0x14916b69, 0xd84f2d}}}, - /* 15*16^29*G: */ - {{{0x133980bf, 0x1282bea5, 0x17402ebc, 0x06e05ca1, 0x0dd4368a, 0x1ebb91a4, 0x0606e11b, 0x1e0d4eb0, 0x70fdd2}}, - {{0x00b75785, 0x17754675, 0x15d29584, 0x006b070b, 0x0596b0a1, 0x008688f7, 0x1a5a55e9, 0x181a1ab0, 0x5edfca}}} - }, - { - /* 1*16^30*G: */ - {{{0x04e16070, 0x0e03dde6, 0x1f5a4577, 0x0304063d, 0x07543f2a, 0x04728eab, 0x010c4ee9, 0x0f7bf9ae, 0xa30169}}, - {{0x1e177ea1, 0x0068d020, 0x084684c3, 0x0bb7ef81, 0x00f9b173, 0x04fd12ea, 0x13d42060, 0x039f6cfc, 0x7370f9}}}, - /* 3*16^30*G: */ - {{{0x138011fc, 0x18093800, 0x1ca15899, 0x12d4cf5a, 0x00a4d835, 0x09984110, 0x0c4455ac, 0x146102bd, 0x6e8313}}, - {{0x1f15ab7d, 0x165b4fd1, 0x1147e69a, 0x1f22b5d3, 0x0c30426a, 0x16d900ed, 0x08130684, 0x117b849e, 0xc14781}}}, - /* 5*16^30*G: */ - {{{0x100e6ba7, 0x1d3a4dc6, 0x045bdfd4, 0x0dd8b689, 0x1e1b43d3, 0x101c526c, 0x147caf47, 0x0132f090, 0xf952a9}}, - {{0x0175e4c1, 0x0dd77728, 0x18a8ae63, 0x0e2cf698, 0x1a0f6555, 0x1b51713f, 0x1afe184d, 0x0b611579, 0xd8a93a}}}, - /* 7*16^30*G: */ - {{{0x03aa0e93, 0x08032d14, 0x1ec7d89a, 0x1c72875d, 0x0893a8f2, 0x18d0cecf, 0x1b9d4100, 0x0bc63a7f, 0x94016d}}, - {{0x07addac2, 0x07769344, 0x15ec1e8e, 0x086e7754, 0x06fd7f48, 0x0e9aa777, 0x165900d5, 0x1dcb88a9, 0x675032}}}, - /* 9*16^30*G: */ - {{{0x0266b17b, 0x07a43170, 0x18aeccac, 0x0ad14404, 0x109c2023, 0x1c42354f, 0x0a246ee5, 0x0e9ab3f6, 0xef22d1}}, - {{0x19dac83e, 0x1537021b, 0x10d06dcc, 0x0e4edee3, 0x0a1073ee, 0x0661d71a, 0x11d5a3e7, 0x192f5649, 0xbc5784}}}, - /* 11*16^30*G: */ - {{{0x12d382a0, 0x18980ad4, 0x1b366b88, 0x1b9779c5, 0x1f927f28, 0x063c0596, 0x04b4e72b, 0x19c99d71, 0xb5f7ef}}, - {{0x05b4b532, 0x117855dd, 0x0b3e316e, 0x1612da53, 0x1ddd371f, 0x0be37065, 0x08d4f025, 0x0b6a387e, 0x684354}}}, - /* 13*16^30*G: */ - {{{0x012cffa5, 0x13492322, 0x0331711f, 0x1a8410cd, 0x0624389e, 0x0a6c7dea, 0x01d9021d, 0x1a565ce2, 0x1cddc3}}, - {{0x1521954e, 0x0f36c4e6, 0x0dad4a2b, 0x193084d6, 0x0b08ac41, 0x0935fca1, 0x0298ff6c, 0x01965e3f, 0x1e476a}}}, - /* 15*16^30*G: */ - {{{0x14a9f22f, 0x1aff21c9, 0x1ea38ab4, 0x10338a42, 0x035b0cc0, 0x05c5ca44, 0x04e7c87e, 0x0b3e4b9d, 0x2accb3}}, - {{0x175c4927, 0x1baee59d, 0x0e9542de, 0x17af7d8b, 0x0edf1154, 0x1d1bf6f8, 0x0b946484, 0x1d2b115a, 0xd518a4}}} - }, - { - /* 1*16^31*G: */ - {{{0x1fb04ed4, 0x1bd631f1, 0x0c1fffea, 0x18661622, 0x18de208c, 0x0e828933, 0x04d918fe, 0x16713ad7, 0x90ad85}}, - {{0x0b6ef150, 0x08ea6a46, 0x00a25366, 0x1df57c2b, 0x022b839a, 0x05eca139, 0x0986bff7, 0x06c41470, 0xe507a}}}, - /* 3*16^31*G: */ - {{{0x10b7b678, 0x13aed99d, 0x1d8e0598, 0x18862379, 0x16c76f13, 0x15e52135, 0x0c6e8661, 0x0e669c84, 0x186e49}}, - {{0x18d91fc1, 0x1d03b797, 0x054d7729, 0x0ee44a89, 0x1e67e110, 0x0412e05b, 0x1612a9ff, 0x1c9300f7, 0xc0d460}}}, - /* 5*16^31*G: */ - {{{0x13421fb8, 0x18372e5d, 0x16957433, 0x12e3e5de, 0x12412984, 0x159a61db, 0x1d8b9f81, 0x1069edb7, 0x61c8d}}, - {{0x0e3ccd80, 0x0af7b342, 0x1bf374a6, 0x0e269674, 0x1eb5c806, 0x092c8702, 0x12deea4e, 0x1b320076, 0x6dfc6a}}}, - /* 7*16^31*G: */ - {{{0x0f6b35a4, 0x0925f0c5, 0x09fed21c, 0x1e6f4d56, 0x068ad889, 0x1920399d, 0x144edcd8, 0x074411dc, 0xf6a6b6}}, - {{0x01f422a6, 0x175b7f64, 0x1b8618b2, 0x0aeadceb, 0x0186f19d, 0x1b827ab0, 0x0e2c72b4, 0x150005a2, 0x3df7c8}}}, - /* 9*16^31*G: */ - {{{0x06954c11, 0x0b411f45, 0x1834062e, 0x1148782a, 0x178ff7fa, 0x0d878a83, 0x0dd88834, 0x051850d8, 0x87a2fc}}, - {{0x072a8b45, 0x0b719971, 0x1e0492dd, 0x11267e54, 0x07532cc4, 0x0a46d069, 0x13be5ec6, 0x1168b55d, 0x33ad51}}}, - /* 11*16^31*G: */ - {{{0x02706ab6, 0x123a3957, 0x194f036b, 0x16683ba5, 0x04cfe3c0, 0x177e5e1c, 0x069a1155, 0x008dcf10, 0xe1472e}}, - {{0x1d58de05, 0x174350b4, 0x0f349d4d, 0x113aaa8a, 0x021f8aa5, 0x08cbc643, 0x1f1a0fda, 0x1548f8b1, 0x82cd92}}}, - /* 13*16^31*G: */ - {{{0x07a84fb6, 0x1fd72a10, 0x0854087a, 0x06d0ea1f, 0x0b9ebc42, 0x06b00f24, 0x1bd77a2d, 0x19009f15, 0x1caf92}}, - {{0x07149109, 0x158c0c81, 0x0b399d85, 0x1982d2d4, 0x01622ec1, 0x127c7f88, 0x14e92069, 0x0b592edc, 0xbc24b8}}}, - /* 15*16^31*G: */ - {{{0x0a955911, 0x1b467f0a, 0x17b54b6d, 0x1c2d44c1, 0x18397107, 0x17f4d9eb, 0x14349627, 0x0d35e12c, 0x705bfd}}, - {{0x1fd200e4, 0x1dbe349f, 0x10b9cb62, 0x1e76a454, 0x051fa297, 0x1ec0faa0, 0x06429f98, 0x02616e7f, 0xe14aa4}}} - }, - { - /* 1*16^32*G: */ - {{{0x1ec4c0da, 0x1bda2264, 0x0fa8cd46, 0x18acf0e4, 0x1162ee88, 0x00d6cc0f, 0x1cce48e7, 0x1a5ec76b, 0x8f68b9}}, - {{0x101fff82, 0x11e5fbca, 0x1442ff7c, 0x1459fd2a, 0x0215dbbe, 0x08615b5f, 0x061b7876, 0x05b740c7, 0x662a9f}}}, - /* 3*16^32*G: */ - {{{0x123809fa, 0x0715c76e, 0x16552f86, 0x08b966a3, 0x11f08fd8, 0x19b1f922, 0x1c8a2ea4, 0x17c5ca13, 0x38381d}}, - {{0x131fed52, 0x0b83a8c1, 0x163c936f, 0x03f99665, 0x0b1cc368, 0x02d2a907, 0x1f72c250, 0x0141f722, 0xe4a32d}}}, - /* 5*16^32*G: */ - {{{0x17c2a310, 0x15213244, 0x04898c0f, 0x0d5d4a80, 0x099a1f18, 0x0dc15523, 0x0b9bda48, 0x049c86e5, 0x492627}}, - {{0x1e27ded0, 0x020db40a, 0x17fe3383, 0x0c6c254e, 0x0303b6d1, 0x1d2b4b8a, 0x0fe568b3, 0x0e7794f5, 0x1337e7}}}, - /* 7*16^32*G: */ - {{{0x0ebd2d31, 0x1c2583ce, 0x01b6e344, 0x1834adfe, 0x1e2f84dc, 0x09d9f23b, 0x12435789, 0x11834481, 0xe30656}}, - {{0x12546e44, 0x095a041c, 0x0dce099a, 0x1900857c, 0x10db6ffb, 0x15883fbe, 0x0982223c, 0x1c6f1268, 0xeac6f}}}, - /* 9*16^32*G: */ - {{{0x163136b0, 0x09861cf1, 0x0d077671, 0x17f1b355, 0x1d63374e, 0x073b11fd, 0x1bf09c6c, 0x01c48519, 0x3b9e10}}, - {{0x0cdbbc8a, 0x09f60b7b, 0x14c7e065, 0x1c514675, 0x15b26a2a, 0x19f5c7a3, 0x0dc77c54, 0x02a5a2d7, 0xfafb98}}}, - /* 11*16^32*G: */ - {{{0x0f485d3f, 0x10478239, 0x01efbba5, 0x140ed102, 0x0def717c, 0x05407aef, 0x06a4addb, 0x092e2559, 0xbb0aad}}, - {{0x1ca2f975, 0x1c9c9281, 0x19c2fff9, 0x14b5f462, 0x1da34895, 0x100fb94b, 0x11e63b34, 0x0a78b06a, 0xea699c}}}, - /* 13*16^32*G: */ - {{{0x16718dc9, 0x177699d1, 0x0448f792, 0x0b169b60, 0x00113e1e, 0x158cbd7f, 0x130353a3, 0x191c9ddf, 0x79090a}}, - {{0x1cfae7c5, 0x11991588, 0x0a4022e5, 0x0d5f6e17, 0x0aa56dd3, 0x0b65e6cd, 0x0e3c4f60, 0x0572320b, 0xeaab72}}}, - /* 15*16^32*G: */ - {{{0x1f60c7d1, 0x134b4a63, 0x1dd6b4a8, 0x0e3bcf9a, 0x1ba668dd, 0x0dde72a4, 0x0d54700f, 0x15bd3f2f, 0xe77c81}}, - {{0x02d72449, 0x162c0f94, 0x0a61b4d3, 0x08e1ee38, 0x01543631, 0x1d991f54, 0x0c8717f0, 0x0f1ddf02, 0x3acf14}}} - }, - { - /* 1*16^33*G: */ - {{{0x13231e11, 0x1437ea82, 0x1a078f99, 0x11d0ca06, 0x036091f4, 0x0ffc8cc6, 0x17597fe6, 0x002ed5f0, 0xe4f3fb}}, - {{0x0feb73bc, 0x1161c2bb, 0x14747260, 0x0fce9d92, 0x0b7286cc, 0x13687501, 0x1c705986, 0x075a1de9, 0x1e6363}}}, - /* 3*16^33*G: */ - {{{0x0bf05bd6, 0x1ccf8273, 0x0aa65194, 0x0adc0642, 0x10deca2f, 0x1a8ff5a3, 0x1fa420cb, 0x0837dc89, 0x900c32}}, - {{0x100d358b, 0x129569df, 0x13bec577, 0x10a6b078, 0x12439d69, 0x19022b85, 0x03d7e571, 0x1d1d163e, 0x6c31f9}}}, - /* 5*16^33*G: */ - {{{0x1f105c50, 0x13e14664, 0x04e1495e, 0x01bddef6, 0x033cd82e, 0x061a01e1, 0x02ab58a3, 0x0c5560b2, 0x5a8d03}}, - {{0x18a4cde9, 0x04d900c1, 0x1404f0d7, 0x0bed14cd, 0x1ff74a60, 0x15b920a1, 0x14da4da9, 0x16227a9c, 0xc059ea}}}, - /* 7*16^33*G: */ - {{{0x12d64feb, 0x03f0c5cd, 0x048a4b19, 0x05f14b25, 0x1a4e8377, 0x1d2bbb65, 0x182923bc, 0x0062465e, 0xd93f4d}}, - {{0x14698359, 0x187deac9, 0x124368de, 0x008617dd, 0x08c4d93e, 0x188e2a6e, 0x1cce88dc, 0x0ba8b964, 0x792555}}}, - /* 9*16^33*G: */ - {{{0x039fbc84, 0x1110266a, 0x15e8059c, 0x00c522c0, 0x0c65b7e7, 0x115e3315, 0x01106c53, 0x18dc6de5, 0x2f0769}}, - {{0x1c201bec, 0x1dc816f0, 0x137575cf, 0x0f36d498, 0x02149cca, 0x1803cc87, 0x1777e977, 0x0e49ae77, 0xb434f3}}}, - /* 11*16^33*G: */ - {{{0x06a758ea, 0x09bf5664, 0x1fc67135, 0x11063124, 0x16e39911, 0x04ad0aa0, 0x0c26561a, 0x100ab3c0, 0xfe7e67}}, - {{0x1b7ab649, 0x07916cae, 0x0c483479, 0x002e0e88, 0x1251f3b8, 0x070b4c24, 0x12e62302, 0x0cf4503b, 0x38aa69}}}, - /* 13*16^33*G: */ - {{{0x0cfffefa, 0x138ab134, 0x1946beb7, 0x10089ee0, 0x1af85101, 0x17c8a861, 0x049f5b7d, 0x194ea706, 0x91baf5}}, - {{0x1f7f6faf, 0x1e9b79a6, 0x1f4c0f71, 0x1de621cd, 0x13d92f4b, 0x14f893ee, 0x13af9765, 0x023268f7, 0x4e5cf}}}, - /* 15*16^33*G: */ - {{{0x0d33c546, 0x1e048bf4, 0x17b6bccb, 0x0ebf6650, 0x1ddd7825, 0x09b9f07a, 0x029f2cb1, 0x043967ef, 0x445841}}, - {{0x000b4fd4, 0x05368c38, 0x0b29cd98, 0x1e1479f6, 0x0da20852, 0x0f571c8d, 0x14e9dc89, 0x0efe7f0e, 0x308d93}}} - }, - { - /* 1*16^34*G: */ - {{{0x00eae29e, 0x17db7571, 0x138741c5, 0x069e5e1a, 0x04266c70, 0x0a9bd22d, 0x0cc7ae58, 0x13631d7e, 0x8c00fa}}, - {{0x0702414b, 0x1e952633, 0x18db1539, 0x15b5f503, 0x0c974c2f, 0x1a1d1b9b, 0x0686a770, 0x0cffd4a4, 0xefa472}}}, - /* 3*16^34*G: */ - {{{0x0bfd913d, 0x1fcab01f, 0x15327ab0, 0x0d01cddc, 0x08d2050a, 0x1d042615, 0x17e1d341, 0x14fd20fb, 0x36362a}}, - {{0x052e243d, 0x027cd756, 0x0cbeabf1, 0x017621ad, 0x02a82d83, 0x1221b86d, 0x1f54d058, 0x0ced9715, 0x48f278}}}, - /* 5*16^34*G: */ - {{{0x0d132896, 0x055d5fcd, 0x0f1b259f, 0x03c7756f, 0x1200dfcb, 0x16cb16ec, 0x180bca56, 0x0dbe6543, 0x448797}}, - {{0x0f685248, 0x0600d895, 0x1daa9e92, 0x081ab4c4, 0x01a3306b, 0x1483ba2b, 0x1f87bf26, 0x0c1a22b5, 0x27bd58}}}, - /* 7*16^34*G: */ - {{{0x1fa2670c, 0x040ab7b5, 0x189cf9b8, 0x01f05740, 0x10324740, 0x0e55419a, 0x0de22daa, 0x18517970, 0x4a4d3a}}, - {{0x16c1764d, 0x045cffee, 0x0a6fbb60, 0x00b2997e, 0x02b9d493, 0x188eef78, 0x093c5f9d, 0x0380308b, 0x70abb9}}}, - /* 9*16^34*G: */ - {{{0x0cb24aa7, 0x0cb57f12, 0x0d1714c3, 0x02118c72, 0x0fe18903, 0x17ec4ffc, 0x000b0eb9, 0x03215d23, 0x5f7b2d}}, - {{0x0a693d7d, 0x0bc03a1a, 0x1207431b, 0x1bd6e127, 0x07c47ce8, 0x1c051e73, 0x0accc28f, 0x00189fbe, 0x77036}}}, - /* 11*16^34*G: */ - {{{0x0f7fb8bd, 0x0c8de2f9, 0x19024290, 0x08c942bf, 0x086d87bc, 0x12736ca4, 0x0340abb0, 0x0a2673b2, 0x513974}}, - {{0x03908c0f, 0x04a5616c, 0x1e6356a0, 0x1865a7c7, 0x15c47faf, 0x1f7ed740, 0x0fcd2e23, 0x07c8ec87, 0xfcd714}}}, - /* 13*16^34*G: */ - {{{0x0e36ca73, 0x15ba48af, 0x0efcfb78, 0x10c9a6d7, 0x14887eac, 0x08895f80, 0x1ee2a90a, 0x1ac57f7b, 0xcf8316}}, - {{0x0ec25534, 0x1a490ca1, 0x035c43d6, 0x0c2b31b1, 0x0ca681c9, 0x0284486e, 0x15cf8e11, 0x11bd6bb3, 0x9feb5}}}, - /* 15*16^34*G: */ - {{{0x1752f97d, 0x0449beb5, 0x0d1d984f, 0x1df78ebe, 0x1a6165a2, 0x09433467, 0x127794e7, 0x13498976, 0x8610de}}, - {{0x1f1b1af2, 0x02bee6a0, 0x1550f820, 0x169b3ea8, 0x1f99e57a, 0x0ccd9299, 0x0ef24df3, 0x14056c61, 0xd31997}}} - }, - { - /* 1*16^35*G: */ - {{{0x00cb3e41, 0x0bfeefe3, 0x02e4b026, 0x1a109e61, 0x18ed3143, 0x076054f4, 0x0a7cf843, 0x1cd3ba90, 0xe7a26c}}, - {{0x0f2cfd51, 0x1454a10e, 0x03a0f883, 0x0d658084, 0x1bb18d0a, 0x00350d57, 0x012d1c6c, 0x0601f4f3, 0x2a758e}}}, - /* 3*16^35*G: */ - {{{0x1aee42db, 0x07cfe95f, 0x0c1c529c, 0x1778b68e, 0x0bfc1d9b, 0x176dc8f6, 0x0543f1ed, 0x1cfb36b2, 0xcc3427}}, - {{0x15d87bdb, 0x1114e008, 0x1c908b71, 0x0b975b1c, 0x1520010e, 0x1fe9fd90, 0x1a862178, 0x0834a438, 0xea2498}}}, - /* 5*16^35*G: */ - {{{0x1ed4a086, 0x1a1b3633, 0x071043bf, 0x0eb82b1d, 0x15cf4b1d, 0x02c2fde5, 0x1177b20f, 0x1759b308, 0x948f05}}, - {{0x1e2bca4b, 0x150c007c, 0x0fe8b468, 0x06514e38, 0x139411c2, 0x08533008, 0x08ce0bd1, 0x13ff6b45, 0x864ca8}}}, - /* 7*16^35*G: */ - {{{0x17542c21, 0x065f5365, 0x09930570, 0x13e9a51d, 0x16d43ae1, 0x1e22a28e, 0x0b24195b, 0x0c525233, 0x258419}}, - {{0x072bfabf, 0x1f5f18cb, 0x10ab5ece, 0x07430dc9, 0x113d5f3e, 0x0d52663a, 0x11200797, 0x03e39b64, 0xfcb35b}}}, - /* 9*16^35*G: */ - {{{0x0c1ecbf8, 0x1e230fa0, 0x1bb5f290, 0x13e1bd35, 0x0421f648, 0x1aa660f4, 0x14948aa5, 0x18826e78, 0x7e12cd}}, - {{0x10bed615, 0x0a2dc66d, 0x18767d67, 0x13ec3b1f, 0x11259c96, 0x0a6d5f26, 0x00dc50fe, 0x111111b9, 0x71284f}}}, - /* 11*16^35*G: */ - {{{0x14557d86, 0x1f3328e0, 0x199ffd05, 0x1dd88f1c, 0x1a6cf1cf, 0x08e53d02, 0x0a99dcae, 0x1fe546e8, 0x4b8ec2}}, - {{0x15167eb9, 0x0ecd8c8d, 0x10fda4af, 0x0be5de1f, 0x1ac5f28d, 0x0396f293, 0x1eac5290, 0x1fe0982a, 0xfde6c3}}}, - /* 13*16^35*G: */ - {{{0x0780763c, 0x15c169da, 0x195a4754, 0x14dabd24, 0x0c07e5f8, 0x1b6e34bd, 0x09094c90, 0x00e672c7, 0xfcd5c1}}, - {{0x18e851cb, 0x0a73a101, 0x1918e92d, 0x13645ce2, 0x0e38cb11, 0x06d9afb9, 0x1118edc8, 0x1c5caa45, 0x18ddab}}}, - /* 15*16^35*G: */ - {{{0x1d8ef686, 0x071df182, 0x09cb99af, 0x1c91e804, 0x06e53f68, 0x12ed7c13, 0x0f9488e2, 0x1dcb0879, 0x900f2c}}, - {{0x0121a8cf, 0x19d24b3f, 0x0455b541, 0x19bfe879, 0x1d110596, 0x0a8d89a4, 0x096b5871, 0x0abd8c08, 0x732ac1}}} - }, - { - /* 1*16^36*G: */ - {{{0x1e6b80ef, 0x0794f59e, 0x1e5093cf, 0x17972cfa, 0x0bdc571c, 0x006111de, 0x1b2348d5, 0x01dc6cc5, 0xb6459e}}, - {{0x1a71ba45, 0x185f85b0, 0x18d6cbfc, 0x075cda91, 0x01db3c4b, 0x0f8b72b3, 0x01b7876b, 0x0da0de7c, 0x67c87}}}, - /* 3*16^36*G: */ - {{{0x119888e9, 0x1ce793c9, 0x1122a2d0, 0x0574d7e4, 0x081673d1, 0x069814b3, 0x1b8b7798, 0x0ee75874, 0x1f90ea}}, - {{0x0f113b79, 0x17efe4bf, 0x0548b995, 0x0ea3fdcb, 0x196a8213, 0x09e938f5, 0x043a5605, 0x0f82bb54, 0x89be36}}}, - /* 5*16^36*G: */ - {{{0x1562222c, 0x02f7db79, 0x19bcb182, 0x0688f323, 0x152bade0, 0x15d699a5, 0x02b5b9c0, 0x09bdbffc, 0x13a4e5}}, - {{0x08200145, 0x058b3465, 0x12413023, 0x138aef5b, 0x09a52d4f, 0x017c0eb0, 0x004ecb2b, 0x09cb02dd, 0xc9d67d}}}, - /* 7*16^36*G: */ - {{{0x143b46bb, 0x1bf26e07, 0x12494950, 0x1a74c7f5, 0x15dbd12e, 0x1e02ec22, 0x0b747501, 0x17e46795, 0x61991e}}, - {{0x0c20a848, 0x047ac80e, 0x0bb363bd, 0x10e5394a, 0x1adf11ca, 0x1c38b37d, 0x124a54bc, 0x011e7fbc, 0x1c5e3}}}, - /* 9*16^36*G: */ - {{{0x121add3b, 0x12df1eee, 0x1c9f63df, 0x15289e8a, 0x026118b9, 0x0e6d868b, 0x0e1d240e, 0x1496f0fa, 0xea27ae}}, - {{0x168ce7dd, 0x1af148ed, 0x1386f9c6, 0x0425ad1c, 0x02f6278b, 0x0759192e, 0x1f795c8f, 0x1cdc8542, 0xc70ff1}}}, - /* 11*16^36*G: */ - {{{0x011ff757, 0x1457c5db, 0x13089b9b, 0x19d2e838, 0x0b6da9b4, 0x087c5b71, 0x1552ea40, 0x06ad6fff, 0x594651}}, - {{0x094d031a, 0x05337654, 0x0fff8eca, 0x1778f6ff, 0x006f9961, 0x1c680ae2, 0x1d401080, 0x019cbbe4, 0x361136}}}, - /* 13*16^36*G: */ - {{{0x036160b5, 0x1b12c51b, 0x19faf019, 0x0a7e48e1, 0x11ec0ccc, 0x17bcb804, 0x0a43a10e, 0x0722bee6, 0x16b26e}}, - {{0x18a1dc0e, 0x0312fdfa, 0x0e8fbe05, 0x0c7558e1, 0x054d4e13, 0x01a9231b, 0x1e2ed8d9, 0x0b4c605d, 0x60f56}}}, - /* 15*16^36*G: */ - {{{0x17b32db8, 0x0b269449, 0x11de47ce, 0x1dae93ec, 0x0ea85c91, 0x0a1e4216, 0x1e4c6fa8, 0x12b88ab3, 0x24b52}}, - {{0x0a64f760, 0x0a2a7d55, 0x16e06a56, 0x16d02240, 0x05be862a, 0x1410e62f, 0x0271edb8, 0x11eb7fe6, 0x609fef}}} - }, - { - /* 1*16^37*G: */ - {{{0x096943e8, 0x16d07ada, 0x1cf16977, 0x1e3f8cfc, 0x106231d6, 0x1a5508c7, 0x0101e4c8, 0x19050177, 0xd68a80}}, - {{0x0b133120, 0x0a642133, 0x114a568a, 0x1cf71ef0, 0x0e28b5b0, 0x0fc8bbd8, 0x1b40312c, 0x1ffe96b0, 0xdb8ba9}}}, - /* 3*16^37*G: */ - {{{0x0ca1c4f9, 0x0da1550c, 0x0df8a08d, 0x1dfc6995, 0x116f44f4, 0x1c1ed30f, 0x0a313102, 0x11e457ae, 0x7815f7}}, - {{0x1778bc15, 0x158f51b5, 0x1df47866, 0x085bcc2a, 0x0c35d5cb, 0x1e798a2c, 0x1da9f764, 0x1d19a735, 0xc1c601}}}, - /* 5*16^37*G: */ - {{{0x0e8c8530, 0x09370e1f, 0x03d3639b, 0x1bed03df, 0x06c6d512, 0x1e3200b5, 0x005db8dd, 0x19b41d88, 0xc39273}}, - {{0x198446c7, 0x0018787b, 0x1bb5c571, 0x1bf97b45, 0x1199850e, 0x09ca20e1, 0x123a7407, 0x084ae867, 0x8c41be}}}, - /* 7*16^37*G: */ - {{{0x037a26c1, 0x0f9205d9, 0x16fda94c, 0x18dcb181, 0x03b25166, 0x1218e0e8, 0x06c09d48, 0x08feb082, 0xda3174}}, - {{0x0cf74d6f, 0x08c1b767, 0x0a05497d, 0x106d8baf, 0x1d8b7d36, 0x00b3e12c, 0x11a748e1, 0x170febb1, 0x753b97}}}, - /* 9*16^37*G: */ - {{{0x1739dc49, 0x15b14549, 0x1d5580f4, 0x0725b4cd, 0x1231a239, 0x162845ff, 0x19b04192, 0x196055e1, 0x6a4be6}}, - {{0x12edd5cf, 0x13515cef, 0x1292934f, 0x1c569962, 0x08058ab7, 0x1371b07d, 0x1d65f705, 0x15455120, 0xf15d8f}}}, - /* 11*16^37*G: */ - {{{0x06987fac, 0x05f45062, 0x0a1bd9e6, 0x121f0c81, 0x18a3c8bc, 0x01301f64, 0x1c4d13a6, 0x13e275cf, 0x1f7c6}}, - {{0x19174c68, 0x1c8f39c0, 0x1daf098f, 0x1ebbc433, 0x0b6f9cb7, 0x01b7194d, 0x08b796c4, 0x07e6dfb4, 0x9d4ecc}}}, - /* 13*16^37*G: */ - {{{0x16daba4d, 0x099d0deb, 0x0c658987, 0x0bf61c40, 0x02bcb9c6, 0x1176ec7d, 0x0e072dc1, 0x002ec3fa, 0x557e94}}, - {{0x17a52316, 0x09ba50dd, 0x10d64294, 0x1371ebf4, 0x0bc86c5e, 0x0e7d0ae6, 0x1f811b4d, 0x074c03f4, 0x7a7e8f}}}, - /* 15*16^37*G: */ - {{{0x09f5341a, 0x1c7a97f9, 0x058dae00, 0x0f4658cd, 0x101419cc, 0x0a0753d8, 0x16a4eca7, 0x10433310, 0x3adada}}, - {{0x0586c6cc, 0x08ac049b, 0x17a3ef2d, 0x0da5cb68, 0x11017e9d, 0x1adf9b55, 0x1a7d54b8, 0x04513326, 0xbfea1e}}} - }, - { - /* 1*16^38*G: */ - {{{0x028d3d5d, 0x04acc07e, 0x11273a90, 0x055d72e6, 0x030b0961, 0x0138483d, 0x01094b70, 0x0fbecb90, 0x324aed}}, - {{0x16ab7c84, 0x1391257c, 0x0cca10e5, 0x027618fc, 0x01f4f192, 0x0061ad76, 0x1cbfc4c3, 0x0aee96c3, 0x648a36}}}, - /* 3*16^38*G: */ - {{{0x0fd53ed3, 0x0e48bac1, 0x095b33bd, 0x1ee9f73b, 0x17c49163, 0x105c98ef, 0x0ab56e3d, 0x1ab32cee, 0x20840b}}, - {{0x1a7a7132, 0x18a1ff28, 0x19c22661, 0x0f88e729, 0x0fac2548, 0x0a3b535d, 0x090d21ef, 0x12f9d830, 0xf29934}}}, - /* 5*16^38*G: */ - {{{0x08a35b35, 0x1e965dac, 0x028487b6, 0x0bb114b8, 0x0ebfd1ab, 0x0814f2c4, 0x06eef44f, 0x1ec1d667, 0xe6b6bf}}, - {{0x1c1007bd, 0x0b949edc, 0x1a6671f1, 0x16d93a77, 0x161ddfe3, 0x01f1c1ac, 0x0bcc99bd, 0x17a6601a, 0x1a5ff2}}}, - /* 7*16^38*G: */ - {{{0x00360dd3, 0x0a77c696, 0x14388243, 0x11506db0, 0x0e3bb47a, 0x1c043706, 0x06ca22c2, 0x0e8b7c93, 0xe05317}}, - {{0x1c24f87b, 0x15766c89, 0x040f70ac, 0x130fbd30, 0x0a01461b, 0x0ac15adb, 0x1ce73602, 0x0e34bb25, 0xdc1c3b}}}, - /* 9*16^38*G: */ - {{{0x1098dfea, 0x00a33316, 0x099e1e5f, 0x1967925d, 0x05e57fad, 0x12e9541d, 0x11678063, 0x074ef10d, 0xa8153b}}, - {{0x0e6d892f, 0x124d4efb, 0x16bd0562, 0x0bc1ee85, 0x13e03b1b, 0x0dce2bc2, 0x03f14f63, 0x0c8c3a0c, 0x2a4739}}}, - /* 11*16^38*G: */ - {{{0x0bcecfa5, 0x13f3bd24, 0x05aec082, 0x1ac5b436, 0x0da3b2a0, 0x14ae31c7, 0x176b7ad1, 0x1661fd95, 0x4f05c3}}, - {{0x15d37b53, 0x16681254, 0x06d2334b, 0x1dc863e0, 0x134b9447, 0x191b0aca, 0x09beb758, 0x1d4c07a8, 0x53a499}}}, - /* 13*16^38*G: */ - {{{0x084b96aa, 0x10f3b2c8, 0x0aaf3391, 0x130c6aa4, 0x1980ed02, 0x02f0d51d, 0x046f8990, 0x1733ecf5, 0xd9309a}}, - {{0x02b28a86, 0x136279be, 0x13fa5e3c, 0x0d93f75f, 0x0cb5fd3b, 0x0783313a, 0x155f5f84, 0x055369d8, 0x6ef99b}}}, - /* 15*16^38*G: */ - {{{0x1f8fcf0e, 0x1bdc682c, 0x1129beb3, 0x16dffbcf, 0x03411d65, 0x1a236f55, 0x14d6ea70, 0x14270ac5, 0x7d587c}}, - {{0x18bc9459, 0x00e0d04e, 0x08de0294, 0x072015a6, 0x16ad0c46, 0x0005b67e, 0x11849c8d, 0x00710609, 0xa7295c}}} - }, - { - /* 1*16^39*G: */ - {{{0x1d054c96, 0x145e9b9f, 0x1472a223, 0x08287751, 0x0e5dceec, 0x0fedf2ff, 0x187db547, 0x092339bc, 0x4df9c1}}, - {{0x0ad10d5d, 0x175d6036, 0x02124064, 0x0a0d9b85, 0x185d4b5d, 0x1a611d0e, 0x1ca01425, 0x0a2125b0, 0x35ec}}}, - /* 3*16^39*G: */ - {{{0x1def001d, 0x07912ed2, 0x06e89fbd, 0x1377ad31, 0x1b64b21f, 0x1e8e04f1, 0x12bc8382, 0x05b64fc5, 0xa549a3}}, - {{0x10624783, 0x0aed8d3f, 0x125c16b7, 0x083c54c5, 0x19456eb1, 0x01876c52, 0x1b2f7d33, 0x0f20db2c, 0x799b7a}}}, - /* 5*16^39*G: */ - {{{0x052ed4cb, 0x0d778f2e, 0x027b1681, 0x09bdf678, 0x12e6ec95, 0x05ecc1a9, 0x13448fc2, 0x061b40fd, 0x7e798f}}, - {{0x14bb9462, 0x0b8b303c, 0x07cde849, 0x06ae37ff, 0x0f057b17, 0x0aa4ef79, 0x120c106a, 0x189449b5, 0xd23dcc}}}, - /* 7*16^39*G: */ - {{{0x13630834, 0x0f9d07de, 0x16b019ff, 0x07e250c7, 0x08108846, 0x0f4b5d46, 0x1e0eb56e, 0x00062a28, 0x224fa2}}, - {{0x047a2272, 0x09e239be, 0x0943dd73, 0x05249d81, 0x109f53d6, 0x187d1c8e, 0x0970f12d, 0x065767db, 0xbbe54e}}}, - /* 9*16^39*G: */ - {{{0x183c19d7, 0x13b24e8a, 0x0b3d5eed, 0x16bc8b58, 0x08ef2bbb, 0x12e67211, 0x07904a68, 0x198c0147, 0xc2d4a0}}, - {{0x0507928d, 0x17945c16, 0x0d1725dc, 0x0095062e, 0x1260d268, 0x1dafbfa0, 0x0a535060, 0x1f38100c, 0x65ada0}}}, - /* 11*16^39*G: */ - {{{0x1c940c9a, 0x064056a5, 0x1d08cc21, 0x1e79c275, 0x1dc2113c, 0x02f13a26, 0x0c643956, 0x0fd860be, 0x2ec22a}}, - {{0x051e7a4d, 0x08ca7ecc, 0x08d6f6b3, 0x00a307b3, 0x07feb124, 0x127a814e, 0x05a130b8, 0x0d1bc66f, 0x8b1da4}}}, - /* 13*16^39*G: */ - {{{0x1d683eeb, 0x138772fe, 0x034c4cea, 0x0dd67141, 0x0b8f33e3, 0x1b292842, 0x13b2ac6b, 0x0e71f351, 0xafc669}}, - {{0x10cd4509, 0x0f14e559, 0x1b77f724, 0x1756aa4b, 0x19c16570, 0x0e3fe511, 0x1d4af0d6, 0x12edba44, 0x2c21}}}, - /* 15*16^39*G: */ - {{{0x176f4293, 0x1100fc3d, 0x0f144e7a, 0x12f16aca, 0x1282e10e, 0x04679b85, 0x0c24486f, 0x0b53e686, 0xd2557b}}, - {{0x1282740a, 0x0d8c3d12, 0x101697c7, 0x16d071bc, 0x0d21fe34, 0x178375a5, 0x1fc049a0, 0x086abc84, 0xa787b3}}} - }, - { - /* 1*16^40*G: */ - {{{0x0c1f98cd, 0x1fe4ce45, 0x1fc0c232, 0x09120a9a, 0x06021523, 0x054e0e63, 0x01c3ebb6, 0x150948e9, 0x9c3919}}, - {{0x14fc599d, 0x13f2f01e, 0x193239af, 0x064deed8, 0x0e641905, 0x0225f930, 0x155d613c, 0x01e949bb, 0xddb84f}}}, - /* 3*16^40*G: */ - {{{0x0fb64db3, 0x1dcc6a9c, 0x1754e105, 0x1bc99473, 0x1b8d6a7e, 0x1c1fdf29, 0x12dd02ee, 0x124537b9, 0xc11423}}, - {{0x1c0259be, 0x118674ff, 0x1159f478, 0x0b01209a, 0x18bd1a87, 0x06f27f4b, 0x1f0a973b, 0x1b8b690d, 0x1237f6}}}, - /* 5*16^40*G: */ - {{{0x03081e46, 0x16f6c1a0, 0x11567a87, 0x044318aa, 0x034713a5, 0x0e160c93, 0x089020b6, 0x1f0634ee, 0x6c5b4b}}, - {{0x0bfbcd70, 0x08fce5c0, 0x108a98bb, 0x019f04d5, 0x1e47841d, 0x1c31e715, 0x10bec8d1, 0x0e2924da, 0xcb0513}}}, - /* 7*16^40*G: */ - {{{0x064dcd4b, 0x0572d762, 0x04704937, 0x018fab32, 0x10a450c3, 0x0332e558, 0x1792d59c, 0x0acce195, 0xe1e9a8}}, - {{0x1b041f2c, 0x085b12f5, 0x085aca4b, 0x09a33559, 0x177927f4, 0x01accd92, 0x14c6deb1, 0x12a88ab8, 0x562b0a}}}, - /* 9*16^40*G: */ - {{{0x0badd73c, 0x02c3b7f1, 0x0992df40, 0x139bb205, 0x014208fd, 0x1a72176e, 0x0265de29, 0x0af5a236, 0x51b21a}}, - {{0x0b36d8d1, 0x1bea570f, 0x11cd2e9b, 0x00261e51, 0x01cfa6c2, 0x03f80e96, 0x0f975528, 0x020003fa, 0x7930}}}, - /* 11*16^40*G: */ - {{{0x1b09f34b, 0x0bae85b9, 0x1319b39b, 0x10e7cc11, 0x19d61e58, 0x114b79f9, 0x1e6186ad, 0x14c76396, 0x9701f3}}, - {{0x00df5793, 0x06e42866, 0x1731e52b, 0x097872ff, 0x08337710, 0x18da98ab, 0x1b4575c0, 0x177195e1, 0x3dd44b}}}, - /* 13*16^40*G: */ - {{{0x1f1e2f46, 0x0e73111d, 0x09de0c05, 0x01ee3d0e, 0x03c57527, 0x0970206b, 0x1b311156, 0x03a593cc, 0xa036b4}}, - {{0x1effb349, 0x198f134a, 0x1c2c7d3d, 0x01c5059f, 0x0b08d068, 0x1b5523cf, 0x0cf5f7c7, 0x14007d2d, 0xc3bf91}}}, - /* 15*16^40*G: */ - {{{0x0c4cea08, 0x06c5c81c, 0x03a8876f, 0x16b1741c, 0x04652654, 0x108a9a00, 0x1141bd29, 0x1b7549d1, 0x6a85fa}}, - {{0x1862f4f3, 0x0cef672c, 0x15c86da8, 0x0e349687, 0x06230b42, 0x19e0a47f, 0x16754c64, 0x00975c8c, 0xb646}}} - }, - { - /* 1*16^41*G: */ - {{{0x00a959e5, 0x1109c109, 0x04753316, 0x02927517, 0x006bb91e, 0x0f940ec7, 0x1f7e3781, 0x0163ba25, 0x605717}}, - {{0x0385a2a8, 0x04cdf499, 0x1893197a, 0x02a5787d, 0x1f262465, 0x116d7b8e, 0x001eb766, 0x164d4d49, 0x9a1af0}}}, - /* 3*16^41*G: */ - {{{0x171c032b, 0x0a6d0b14, 0x0bf72603, 0x16cd142f, 0x166c5ff6, 0x0dafefe3, 0x0980f744, 0x1f9adc00, 0x71eba8}}, - {{0x1668359f, 0x1d5ad470, 0x12d1d579, 0x0635a2ee, 0x0bb7f719, 0x028b7aa6, 0x0e77bd98, 0x0c496c3a, 0xd2ff12}}}, - /* 5*16^41*G: */ - {{{0x0a03a61c, 0x03723a29, 0x01c15d34, 0x10d1e8d2, 0x09dd0507, 0x1a215d55, 0x148cb285, 0x00b66493, 0x855ec3}}, - {{0x065dfc07, 0x0fe37556, 0x1f912597, 0x05ee9d42, 0x0fb4ed33, 0x05ffcda1, 0x105fd50f, 0x05d8be03, 0xdd85d}}}, - /* 7*16^41*G: */ - {{{0x1f32d706, 0x00605240, 0x1a819e2c, 0x119948e8, 0x1bfa2061, 0x094d184a, 0x0fc7c543, 0x0d57567f, 0x3ce448}}, - {{0x1c7fd9e4, 0x05b9b1bf, 0x187a27d0, 0x02ac879a, 0x14906edd, 0x08235884, 0x014a23bf, 0x11b55c6f, 0xe77540}}}, - /* 9*16^41*G: */ - {{{0x191cd3fb, 0x0da065db, 0x0a6f9a1b, 0x1467fb2e, 0x044eb4a2, 0x0190c7c4, 0x1febc0b8, 0x0287e9c6, 0x11ccc5}}, - {{0x15160d86, 0x09b8b5d2, 0x174d1caa, 0x163dfa59, 0x0c239fa0, 0x112249c6, 0x077ad4a3, 0x05520562, 0x4aa56b}}}, - /* 11*16^41*G: */ - {{{0x018f7552, 0x03dc88cb, 0x0153eb0e, 0x02271730, 0x182ddbd4, 0x1bba7c11, 0x11bd0ee5, 0x02fca293, 0x250bb}}, - {{0x1510b14d, 0x18424b11, 0x0f5bc78f, 0x00de7866, 0x1d817da0, 0x1efbaff4, 0x0208d0b5, 0x1f9377d0, 0x731930}}}, - /* 13*16^41*G: */ - {{{0x1f725d12, 0x0e89f49c, 0x0d7d1d41, 0x0c8577b9, 0x02fbfd94, 0x1ce70501, 0x1f4ead28, 0x111668cf, 0x1a749c}}, - {{0x03ac56e4, 0x09b28a69, 0x0436a9c0, 0x0410d313, 0x13d8f607, 0x1f3ae157, 0x18b3d162, 0x12ae7d81, 0x7e91d1}}}, - /* 15*16^41*G: */ - {{{0x09fae458, 0x10824729, 0x1bb25ff5, 0x14b884ec, 0x17b328b0, 0x0ab52efd, 0x06304274, 0x0b7c1f04, 0xc75068}}, - {{0x1757b598, 0x00b420ca, 0x165468ac, 0x1b94a066, 0x0c7b40a5, 0x1a0a6339, 0x1817ed4b, 0x1f19f243, 0xead795}}} - }, - { - /* 1*16^42*G: */ - {{{0x0cb94266, 0x0d34b9f7, 0x1537c4ac, 0x1de1f74f, 0x1a31880c, 0x1cd228c6, 0x10450850, 0x11c47410, 0xa576df}}, - {{0x01b28ec8, 0x145f08d7, 0x05367cfb, 0x1c214fea, 0x0d82c432, 0x0bd7f2c6, 0x02cb24ae, 0x041cecc8, 0x40a6bf}}}, - /* 3*16^42*G: */ - {{{0x0d9ed6c1, 0x14575ac6, 0x1564f5ad, 0x1ce8b787, 0x0dd0ec24, 0x00c3b82f, 0x14fa02ff, 0x0db96e9e, 0x32833}}, - {{0x18fafeee, 0x16375f37, 0x12d252b7, 0x17e9be4b, 0x17c8c265, 0x0ca1d106, 0x1ca311b5, 0x07025fb3, 0x71a898}}}, - /* 5*16^42*G: */ - {{{0x1235983a, 0x0cd4d469, 0x0ef3aca4, 0x14206e02, 0x01531e38, 0x0936b87f, 0x1153718e, 0x15d17223, 0xce4f4e}}, - {{0x0d3cdecf, 0x07eb58c8, 0x0fdd02bb, 0x18ca451d, 0x07543526, 0x10124f38, 0x0eecfab7, 0x0e78721f, 0xf3c9f9}}}, - /* 7*16^42*G: */ - {{{0x15b0e6c9, 0x16d55b32, 0x1b932269, 0x1ff39ef0, 0x0bcbddb5, 0x07d9b6fc, 0x0889e38a, 0x14a9730c, 0x4dbebf}}, - {{0x1eb2cc25, 0x0a53c2aa, 0x1413beba, 0x06236578, 0x029f3589, 0x11373711, 0x0bb7d169, 0x16079227, 0x10fee7}}}, - /* 9*16^42*G: */ - {{{0x05857295, 0x0700d08d, 0x10cfc059, 0x11c8fe06, 0x0a12069c, 0x08c7e50e, 0x10862cb8, 0x017fde8b, 0xa42a24}}, - {{0x0a7eb9c1, 0x159bbff6, 0x1464e555, 0x038459a2, 0x1a4c427a, 0x1915926e, 0x15159e9a, 0x1e4c200b, 0x3aa0b3}}}, - /* 11*16^42*G: */ - {{{0x0fcdc098, 0x1107faab, 0x191a00c8, 0x15c01ed5, 0x099c1550, 0x0fc36062, 0x0899e9fc, 0x05f2df64, 0x34e12b}}, - {{0x0a7474e2, 0x0658d6f3, 0x0620fd99, 0x1ea261e3, 0x172db04d, 0x05e420bc, 0x0c8b65d3, 0x1bbaf6ba, 0xa64ac2}}}, - /* 13*16^42*G: */ - {{{0x0f173b92, 0x06b75af4, 0x07edd847, 0x1ce5e82d, 0x165683b7, 0x0d10c7a6, 0x07ca6f8c, 0x081b3772, 0x10f4d2}}, - {{0x033146c2, 0x0810036b, 0x01ab6df2, 0x16ed3a29, 0x108ba90b, 0x12d2d19c, 0x0eb4846c, 0x12a122ea, 0x850e2d}}}, - /* 15*16^42*G: */ - {{{0x08d84958, 0x137e8ecd, 0x0b3172bb, 0x03bd62d9, 0x0cc866a1, 0x0dcbb6a0, 0x1f9d27c6, 0x016d36ce, 0xe846e8}}, - {{0x1882cf9f, 0x062323db, 0x18306990, 0x03466ce3, 0x0b76fad5, 0x0c8823cc, 0x1895076f, 0x1f91298f, 0xa29cb8}}} - }, - { - /* 1*16^43*G: */ - {{{0x1e58ad71, 0x1bb1c44d, 0x068e8823, 0x01a3eb9f, 0x08c38bb3, 0x1f4b14ef, 0x0f8c2817, 0x11851bd8, 0x7778a7}}, - {{0x1d9f43ac, 0x1a89fe0f, 0x092b158e, 0x070823fe, 0x1580087b, 0x0709797f, 0x08bfdc26, 0x1356b4b6, 0x34626d}}}, - /* 3*16^43*G: */ - {{{0x1319c869, 0x1be37571, 0x07ac9c0b, 0x13f2baec, 0x0acdc18a, 0x1c8117e6, 0x1f234060, 0x0bb302e7, 0x301804}}, - {{0x12b856f0, 0x0063b64e, 0x0f669eff, 0x15099494, 0x02e3bca2, 0x121906b1, 0x1edbe198, 0x0f04a076, 0xac5fc5}}}, - /* 5*16^43*G: */ - {{{0x05ed29b5, 0x0334c37d, 0x0ab746d3, 0x0616c0e2, 0x1c885f58, 0x13edcd31, 0x1bcd0ead, 0x16c3dcaf, 0x322881}}, - {{0x1cd15ad2, 0x1a789373, 0x1b9d813b, 0x075d5729, 0x131e1ca8, 0x18cefa0a, 0x113ac442, 0x1082f406, 0x167702}}}, - /* 7*16^43*G: */ - {{{0x06c96100, 0x1fd4203c, 0x1a72398e, 0x0602354d, 0x1dbcca16, 0x0ecd96f9, 0x0e7fed0f, 0x07581f63, 0x3f3847}}, - {{0x12624707, 0x0f1560df, 0x1d7c6f3c, 0x0e38f816, 0x19ce5665, 0x02231783, 0x0e5494d3, 0x0abeba80, 0x70c69c}}}, - /* 9*16^43*G: */ - {{{0x1d22d2ac, 0x1a637637, 0x12ab3808, 0x1bfc24db, 0x1df2f10d, 0x00704bc2, 0x1db72d0f, 0x18bfa4f4, 0x288113}}, - {{0x0f42a268, 0x00f5aafc, 0x12323f42, 0x07a8942a, 0x16137ddc, 0x1b93064b, 0x1723c81d, 0x002b1f78, 0xa1a7eb}}}, - /* 11*16^43*G: */ - {{{0x045f8ea8, 0x05d406e9, 0x134a4035, 0x0491c72c, 0x19fe5d17, 0x06caeb88, 0x08a954fd, 0x001908c7, 0xf963a2}}, - {{0x19bc99eb, 0x1e2afd82, 0x02d82092, 0x11e46b3b, 0x027208bb, 0x11180ffa, 0x0f028edc, 0x04d18ff0, 0x9c8594}}}, - /* 13*16^43*G: */ - {{{0x0606a315, 0x10d44189, 0x1a58eb67, 0x04c0e5e4, 0x0097e407, 0x05952c87, 0x069fe636, 0x099fee1b, 0xa5d922}}, - {{0x1e3b68d1, 0x1ab099ac, 0x0469f274, 0x1a1a68fa, 0x00de9ed4, 0x0355ebcc, 0x096cd0cc, 0x0007641b, 0x87328b}}}, - /* 15*16^43*G: */ - {{{0x06231493, 0x06dbdaa0, 0x131351a7, 0x02350619, 0x1e6a4964, 0x120e8072, 0x0d813ad3, 0x05c36e78, 0xf1fe98}}, - {{0x158848c1, 0x0b54cd33, 0x17fc3406, 0x07f668dc, 0x199d3f17, 0x1e102fbe, 0x177085b4, 0x1d5db349, 0x2e2019}}} - }, - { - /* 1*16^44*G: */ - {{{0x06d903ac, 0x04f6d4e0, 0x0b5f972c, 0x12c4e9cb, 0x0fd2ed5f, 0x0fe9873d, 0x01118dca, 0x0bdcc6f5, 0x92895}}, - {{0x1bcd091f, 0x08c0749a, 0x0a360ff1, 0x1a4ddf51, 0x095eeac3, 0x0509849d, 0x0aa09ede, 0x0007a7e8, 0xc25621}}}, - /* 3*16^44*G: */ - {{{0x1874b839, 0x088943ab, 0x0f4ad060, 0x022b672a, 0x0b6aebe4, 0x186fd918, 0x16a014f7, 0x03f81c3c, 0x3e03b8}}, - {{0x1c0594ba, 0x060e72b3, 0x0ad6e368, 0x0b8be1fb, 0x18f667de, 0x1303ab8c, 0x1d0b113d, 0x0c7bfe0f, 0xd13ae1}}}, - /* 5*16^44*G: */ - {{{0x0357a513, 0x11fbc734, 0x0cc08fce, 0x037a268b, 0x122c5f15, 0x1141d514, 0x04b358be, 0x16f45e89, 0xe662c0}}, - {{0x0017d07e, 0x095100e5, 0x14e36246, 0x06b9ac4a, 0x1a419d80, 0x11045090, 0x148c176b, 0x079cc248, 0xab0b19}}}, - /* 7*16^44*G: */ - {{{0x1f37d242, 0x0cafbf7e, 0x07052c12, 0x1fd94c0f, 0x1587dc29, 0x1163e5f1, 0x1b2e10e1, 0x1639299e, 0x40bf80}}, - {{0x06405088, 0x08ec13cd, 0x0f4d560f, 0x043d7485, 0x0fe12743, 0x1f4d8d93, 0x0bc13d4f, 0x06bb0ad5, 0xb579dd}}}, - /* 9*16^44*G: */ - {{{0x195a3558, 0x17959b22, 0x0d29fcae, 0x0e3f0bc4, 0x159f6ac0, 0x0bc09c6d, 0x09c201be, 0x12ec03b9, 0x3d14fe}}, - {{0x0443df4c, 0x156d9d63, 0x1075c9f1, 0x0145c28f, 0x16e1482e, 0x1498edfa, 0x07be3ca6, 0x1add08d0, 0x16c6bd}}}, - /* 11*16^44*G: */ - {{{0x02b1fc24, 0x0f4fad6c, 0x0fdd5c3b, 0x11b038fc, 0x04865252, 0x16269649, 0x14947306, 0x081d05cc, 0xdd6fa5}}, - {{0x0e9b74ca, 0x1218e230, 0x1cc88c12, 0x01bcd7da, 0x17e77ec1, 0x18f5f8b2, 0x01bf8d9b, 0x0fd63a63, 0x67e62b}}}, - /* 13*16^44*G: */ - {{{0x1dd08e02, 0x0f548ac9, 0x0b7c0a20, 0x0a8f6ffb, 0x11e80108, 0x0a4cd51e, 0x15e03e1a, 0x1505bcab, 0x13fa2d}}, - {{0x1cb03410, 0x12aa0ee1, 0x090ae5f6, 0x095f7633, 0x032c7e64, 0x0b1035da, 0x09c8c4cd, 0x1608aabb, 0x136338}}}, - /* 15*16^44*G: */ - {{{0x144ee41a, 0x0119d5cc, 0x1f5a69ab, 0x16adba76, 0x08282879, 0x085b3963, 0x0910fdf0, 0x0a3a78e1, 0xd06c48}}, - {{0x0b295e6f, 0x18fc274c, 0x18bb894b, 0x170868c2, 0x030919b7, 0x166a7a7b, 0x02b6eec2, 0x0980b09a, 0x5815fd}}} - }, - { - /* 1*16^45*G: */ - {{{0x03d82751, 0x1d573a8b, 0x0b4d5149, 0x0b69520f, 0x1b285564, 0x1279d071, 0x0424e641, 0x1e7d8db6, 0x85d0fe}}, - {{0x0eb1f962, 0x1611bd12, 0x1dccc560, 0x0ea3d2d0, 0x0f5663e8, 0x04b72c16, 0x102f8a75, 0x10827471, 0x1f0364}}}, - /* 3*16^45*G: */ - {{{0x0cde4cf3, 0x0caa830f, 0x02819aae, 0x01ca6a8f, 0x19ae7934, 0x169368ae, 0x0b0ef9f0, 0x09582284, 0x384dab}}, - {{0x052d0566, 0x1e3cb591, 0x146e9ced, 0x0614672e, 0x0c6f01f4, 0x16b6d15a, 0x090efed3, 0x179a3739, 0xd6e3c5}}}, - /* 5*16^45*G: */ - {{{0x1e5238c2, 0x0579f490, 0x03b2e2e6, 0x0abeb870, 0x0ed48403, 0x1085a741, 0x16a906c5, 0x01d6fa82, 0x14f0ec}}, - {{0x12f07922, 0x14351a3c, 0x0124e75b, 0x1801b006, 0x0747fd25, 0x039f1c21, 0x1602487f, 0x07ba906b, 0xab12d5}}}, - /* 7*16^45*G: */ - {{{0x1543e94d, 0x1b1a977e, 0x1e638623, 0x06054ead, 0x00ddadd1, 0x1a33c52d, 0x01fb1070, 0x176f0585, 0xeb42f3}}, - {{0x05924d89, 0x02acef22, 0x035b5090, 0x108d1bcc, 0x1fb774cd, 0x0eab97e6, 0x04b72683, 0x00e9e4bb, 0x234a6d}}}, - /* 9*16^45*G: */ - {{{0x1e19aaed, 0x19272dab, 0x199cc9c0, 0x1759bd18, 0x0a920459, 0x0017b703, 0x0366a7bb, 0x194a2d04, 0x1cf138}}, - {{0x092f400e, 0x09b752eb, 0x11dffef0, 0x1ddf1fdf, 0x1de17479, 0x195335b6, 0x0e197d0d, 0x1e62e38c, 0xd6ffda}}}, - /* 11*16^45*G: */ - {{{0x16a8aa39, 0x1b6074fd, 0x1e3eb157, 0x0cc6f694, 0x190d937a, 0x104b424c, 0x104b21d6, 0x17cbe81a, 0xb58686}}, - {{0x0b493c1f, 0x1e3c9ae9, 0x16cd1ee3, 0x1b5f31cd, 0x0a91dabb, 0x1c6a2a60, 0x10b05251, 0x086498f1, 0x5632d5}}}, - /* 13*16^45*G: */ - {{{0x103b4cc5, 0x148f5f1d, 0x071df0bb, 0x106374b4, 0x1a802572, 0x1e27f3f9, 0x10ad9ed6, 0x160d7179, 0x5fc19d}}, - {{0x05b57c28, 0x1d9cfdc3, 0x021fb128, 0x0dea0798, 0x05ef4927, 0x09c7cd1d, 0x1f19bb88, 0x181d9318, 0xec8e84}}}, - /* 15*16^45*G: */ - {{{0x0cb38cb5, 0x1a5c2bea, 0x0e22522e, 0x16ffbe9a, 0x0ea1be10, 0x05207e9f, 0x0a277aea, 0x01a85dbc, 0xb88fb7}}, - {{0x1965f3d7, 0x1dfd3ab2, 0x0be31c65, 0x1e7c244f, 0x1a8e24d4, 0x1dcca59a, 0x0a0180d2, 0x15a8dd46, 0xd6c736}}} - }, - { - /* 1*16^46*G: */ - {{{0x0526087e, 0x1aa02412, 0x16880c23, 0x16db1105, 0x0b85dfdf, 0x1b020bcc, 0x1a5f0726, 0x19d2fdd9, 0xff2b0d}}, - {{0x10c29907, 0x04a8f00f, 0x038b3acb, 0x0fdadf72, 0x07936c7b, 0x026e2a68, 0x08622bd3, 0x1fdea497, 0x493d13}}}, - /* 3*16^46*G: */ - {{{0x19d681f9, 0x0c82a7f3, 0x03fae7f1, 0x1c1ddf59, 0x094b066c, 0x1f92f016, 0x0c2222df, 0x1e4eebe4, 0xc745fd}}, - {{0x1bbb1247, 0x018b9a1b, 0x1f5171d8, 0x17a66b8c, 0x018678cd, 0x1ca63874, 0x179e29c4, 0x1e5ed73c, 0x590222}}}, - /* 5*16^46*G: */ - {{{0x15cd0ea3, 0x10267769, 0x12b12057, 0x08f1d041, 0x0e7f2b34, 0x0f2f5b39, 0x142c9e96, 0x1e752ea0, 0xabb279}}, - {{0x1c307bce, 0x1849899b, 0x00bced91, 0x0ed20b3c, 0x18ed47c9, 0x1f060183, 0x1c367ed2, 0x0777e2f2, 0x5dee10}}}, - /* 7*16^46*G: */ - {{{0x1bc9ee3e, 0x017179f8, 0x19ce0b17, 0x1f4352c7, 0x1ed11ea9, 0x1553a133, 0x00a09feb, 0x016b3f8d, 0x3f8115}}, - {{0x199aae06, 0x0756d862, 0x16a0580f, 0x0765b9f9, 0x15662762, 0x1f59e23c, 0x00b519c6, 0x0d1fb7f5, 0x19c88a}}}, - /* 9*16^46*G: */ - {{{0x18e4a007, 0x0b8df7d7, 0x0ecd62d8, 0x19dd9e11, 0x0c7ec15e, 0x1d19d52b, 0x179a5652, 0x05ba0105, 0x5cf813}}, - {{0x1068b883, 0x131f8484, 0x071ffa33, 0x08df2d8f, 0x03df6c89, 0x00ac4246, 0x0837d2b5, 0x0b81ac3f, 0xb45aee}}}, - /* 11*16^46*G: */ - {{{0x06c2d4a7, 0x0ab7f3d9, 0x13ffec42, 0x06df2677, 0x04ed21bc, 0x19cb9e20, 0x125194f8, 0x09a1a974, 0xb6d5fe}}, - {{0x1ae86371, 0x0c6e73f1, 0x178f3204, 0x16fc9cde, 0x1fd8e745, 0x1c904eff, 0x1b0537f3, 0x1427577a, 0x47f373}}}, - /* 13*16^46*G: */ - {{{0x1c66dd33, 0x0499b117, 0x171db714, 0x1f791fe3, 0x1b022ea8, 0x0d8a8014, 0x021c1aec, 0x180cd9eb, 0x61c8bb}}, - {{0x16f10bfa, 0x1ddd4f9d, 0x00832328, 0x020dd585, 0x1d3fb6a5, 0x0cca5cc2, 0x1c0d119a, 0x0473ca9e, 0x93599e}}}, - /* 15*16^46*G: */ - {{{0x1d6b2ff8, 0x002dbe66, 0x01b23ea6, 0x066d82e5, 0x1bdf1876, 0x1a9b9f61, 0x01461f27, 0x14ae84cf, 0x94e32b}}, - {{0x0ce1af3e, 0x0ea42aa9, 0x1aff84eb, 0x15e084a4, 0x19e8cb33, 0x12443316, 0x13864bc7, 0x11687b40, 0xd1b44}}} - }, - { - /* 1*16^47*G: */ - {{{0x1856e241, 0x0072f167, 0x15b74a1e, 0x03dc2919, 0x1212b57f, 0x1973180d, 0x03aa7b4a, 0x1c963d10, 0x827fbb}}, - {{0x0ec293ec, 0x102db45d, 0x040c59b5, 0x0f4c630d, 0x112687ff, 0x19633e8e, 0x0c2dc6fb, 0x12478e4f, 0xc60f9c}}}, - /* 3*16^47*G: */ - {{{0x1bb80fa7, 0x1a242e59, 0x0104e218, 0x0fb4d76e, 0x0819f3aa, 0x1035e990, 0x0bef0346, 0x03ec6118, 0x857e3}}, - {{0x09366b2d, 0x0cc108f8, 0x15c05aaf, 0x1c6e0879, 0x17147172, 0x064e8ee5, 0x1c824b5f, 0x08475c02, 0xf64393}}}, - /* 5*16^47*G: */ - {{{0x09c70e63, 0x0e8161d0, 0x14f525bd, 0x1716f1ce, 0x0672e9cb, 0x032abb25, 0x0010d517, 0x1d4ad7ac, 0x28aacc}}, - {{0x1057da4e, 0x0f81c417, 0x13687a2e, 0x18b39c88, 0x0ebb7f5f, 0x0b33e3b4, 0x18559ea2, 0x05df0341, 0x2b6932}}}, - /* 7*16^47*G: */ - {{{0x13e674b5, 0x00ee297b, 0x0182ab18, 0x11ed39ce, 0x18a4f92d, 0x1964de75, 0x19851776, 0x04b40ab4, 0xa2f3b6}}, - {{0x0e937941, 0x049c6470, 0x0cfe94ec, 0x05f462f8, 0x07c4b922, 0x05487995, 0x02ba0011, 0x0b2c298d, 0x620ea1}}}, - /* 9*16^47*G: */ - {{{0x191eb056, 0x1b00b18e, 0x13f4e1b1, 0x05dfb71d, 0x115f5a00, 0x1ae351fa, 0x048c7662, 0x193d55cb, 0x3c4f83}}, - {{0x005cecab, 0x012c49ed, 0x13dae1dd, 0x056a8903, 0x07880198, 0x12b9e1d9, 0x0da8ceb5, 0x00ea2951, 0x944790}}}, - /* 11*16^47*G: */ - {{{0x1d86dfa9, 0x0830fedd, 0x0e64e9c6, 0x11694813, 0x03baadc3, 0x0f01f408, 0x1f538a70, 0x0511532c, 0xaff8e1}}, - {{0x01d12681, 0x1881e1b6, 0x067e71c1, 0x02db5288, 0x153f4f91, 0x15d50fe7, 0x10ff4f4f, 0x166426ef, 0x8d8b4b}}}, - /* 13*16^47*G: */ - {{{0x189ba9c1, 0x07939b5c, 0x074ce38a, 0x1ef94b41, 0x0e579e40, 0x01315767, 0x02cfa116, 0x08a51b80, 0xd3fb78}}, - {{0x0b51b267, 0x10dc46ff, 0x046b7801, 0x19dbab80, 0x10fe6341, 0x102bac5b, 0x139f29f2, 0x069df4d6, 0xf894d4}}}, - /* 15*16^47*G: */ - {{{0x0f2bb909, 0x0d4b60e8, 0x16636667, 0x0204f8a6, 0x07d7f639, 0x14c41c8c, 0x0a23fd1c, 0x01c15935, 0x4ec930}}, - {{0x04cf4071, 0x0451c1fd, 0x0b0e09ee, 0x1c2d041b, 0x049bad52, 0x0e228c26, 0x13717203, 0x00d7c360, 0x782ba1}}} - }, - { - /* 1*16^48*G: */ - {{{0x0120e2b3, 0x19dac7d1, 0x11fe6a9f, 0x11fb9cfe, 0x0e5217a5, 0x0571a673, 0x16eb9ef9, 0x1e43ea37, 0xeaa649}}, - {{0x1a5ad93d, 0x03d2982d, 0x0fdf9675, 0x0d72cbe2, 0x1aa5a01a, 0x007c4c3c, 0x00eb1a6a, 0x1dab7776, 0xbe3279}}}, - /* 3*16^48*G: */ - {{{0x1f2e070d, 0x0c1fe9d1, 0x0a9aa63d, 0x156e398a, 0x047e229a, 0x18e1dc28, 0x0affd21c, 0x1d2085e9, 0x4b72a5}}, - {{0x096dd780, 0x025d4177, 0x05230f79, 0x08cbbba5, 0x13c10b0b, 0x1dd9b687, 0x073d809d, 0x09c3ad5c, 0x599e1d}}}, - /* 5*16^48*G: */ - {{{0x0a02591c, 0x0e73fec2, 0x1449687a, 0x0a932cb0, 0x1fd613ef, 0x1fdf5af0, 0x038a169a, 0x1f8ca739, 0xa9fc93}}, - {{0x09bec2dc, 0x0856ef7b, 0x13dc94de, 0x111882bf, 0x165e5ca8, 0x00bd0d48, 0x1c5cfa13, 0x073b8a70, 0x9c2ce7}}}, - /* 7*16^48*G: */ - {{{0x0d968b59, 0x08037071, 0x12ef0b84, 0x05175c27, 0x1027709a, 0x1d60904d, 0x1c29a9f5, 0x0f834df3, 0xc94001}}, - {{0x0de572fb, 0x17ebb204, 0x0432723f, 0x08596c87, 0x1742ce28, 0x10dfd2da, 0x18804ee2, 0x0a019370, 0x39d922}}}, - /* 9*16^48*G: */ - {{{0x126b3332, 0x143999ab, 0x1b9779a8, 0x0711a0e7, 0x1f8e0310, 0x09d2fb85, 0x0093b19e, 0x13afdda0, 0x1f84bb}}, - {{0x14e8d52e, 0x0a214518, 0x1b70e895, 0x199c5a86, 0x1edf0c2b, 0x013fbadc, 0x1b30951f, 0x00e57953, 0xee726d}}}, - /* 11*16^48*G: */ - {{{0x0defa98e, 0x06d52a56, 0x0b09e657, 0x1088d023, 0x1e9c7724, 0x0abd9cc8, 0x1341b2a0, 0x112128bf, 0xf13e0}}, - {{0x1e286767, 0x0453bb4d, 0x13ab3370, 0x1ce0bc2d, 0x162db287, 0x1c5853d9, 0x1140d78f, 0x1e2ec9cf, 0xadd521}}}, - /* 13*16^48*G: */ - {{{0x09f59b6b, 0x0f0e01df, 0x02238be9, 0x0718c783, 0x026d3e9b, 0x050e96ac, 0x11f6cdca, 0x14aa3bbd, 0xdde191}}, - {{0x06cb1410, 0x156cb149, 0x0553fb3d, 0x0e7177ce, 0x0e14e8b5, 0x0beb0e29, 0x172f829d, 0x0f00504e, 0x5b2bfb}}}, - /* 15*16^48*G: */ - {{{0x09c6b699, 0x1462afee, 0x191a1c6d, 0x1eae6ad7, 0x01682a86, 0x0bdfcbda, 0x1de9685b, 0x05ddb06d, 0x5fab01}}, - {{0x01c6c3aa, 0x0b990a96, 0x020d466c, 0x1622ffd5, 0x02f7b90a, 0x1a08986b, 0x0513a7ae, 0x0e14787a, 0x2d9bfa}}} - }, - { - /* 1*16^49*G: */ - {{{0x1a34d24f, 0x111b196e, 0x084dd007, 0x0db1e193, 0x02ee541b, 0x0fb6f67a, 0x1a764e47, 0x0878b9e2, 0xe4a42d}}, - {{0x1eba9414, 0x13fb898e, 0x16393c4e, 0x0dddbf51, 0x0d34ce88, 0x0ce67dc5, 0x1cd49bf2, 0x1ce2da38, 0x4d9f92}}}, - /* 3*16^49*G: */ - {{{0x1bea0c68, 0x04208579, 0x1ece4ad7, 0x060246ce, 0x16faf094, 0x1e47469c, 0x0e892526, 0x069c2ad4, 0x3e4196}}, - {{0x1a45edb6, 0x05db7fb8, 0x0f3686af, 0x02328c60, 0x093062fa, 0x05ff1b83, 0x07dfcdcf, 0x13b24964, 0x123c5}}}, - /* 5*16^49*G: */ - {{{0x139824d7, 0x1bae91e4, 0x072625eb, 0x0f6c986a, 0x10b576eb, 0x11f317bf, 0x1423bb52, 0x1ea8abae, 0x8d9438}}, - {{0x1366489f, 0x10027a44, 0x1ac18f62, 0x13c57064, 0x0ef6f8fb, 0x05e98d5b, 0x10a8b298, 0x0e69fdcd, 0x3261e0}}}, - /* 7*16^49*G: */ - {{{0x18d713de, 0x124038d4, 0x0a398823, 0x0185f6e8, 0x14543936, 0x089517f2, 0x1108352a, 0x18ab1dca, 0xb72524}}, - {{0x1b8350e9, 0x17ff292c, 0x1297f2dd, 0x05a4dfc8, 0x09415048, 0x08c174eb, 0x1914410b, 0x13514507, 0x4c51b3}}}, - /* 9*16^49*G: */ - {{{0x1e3b2cb4, 0x0636149f, 0x1c84100b, 0x13e6b7e6, 0x1149e304, 0x1b71c090, 0x09466b71, 0x0b442da2, 0x3de45f}}, - {{0x107eb02f, 0x10f19d61, 0x01c1133d, 0x1c51ccb5, 0x09106823, 0x055254be, 0x17714382, 0x13080bd5, 0xba2a85}}}, - /* 11*16^49*G: */ - {{{0x0ce4e5bf, 0x11a3b37b, 0x04016c5c, 0x0f950d41, 0x106ae9b6, 0x1e71ba44, 0x1a1f078f, 0x18d12b37, 0x8511f1}}, - {{0x01789c08, 0x1e494a26, 0x14d9498b, 0x10f11378, 0x000232da, 0x0fbf6355, 0x121d3077, 0x19f2379a, 0xecdff5}}}, - /* 13*16^49*G: */ - {{{0x1d3258ab, 0x0dab3451, 0x0f05370c, 0x04850315, 0x0ab5957d, 0x0e39770a, 0x0088b3e8, 0x05d039ec, 0x8c5a05}}, - {{0x022d0f8f, 0x0bf04298, 0x16512b79, 0x15d1f381, 0x008c246d, 0x0063c826, 0x16841e6a, 0x09768877, 0x6811db}}}, - /* 15*16^49*G: */ - {{{0x1f91bcee, 0x0c615055, 0x03036105, 0x1e3b1e3c, 0x1f137f5c, 0x1e762ab5, 0x1582f718, 0x02dbd7a6, 0xcef7f8}}, - {{0x01966b33, 0x1da6d4fc, 0x1cbdab1a, 0x1c960542, 0x1245fa63, 0x199ce00e, 0x1c04918e, 0x106c6e90, 0x67e74c}}} - }, - { - /* 1*16^50*G: */ - {{{0x0300bf19, 0x18b9dcea, 0x03fa9251, 0x0a6aed51, 0x12b6b92b, 0x07d6d59a, 0x17655058, 0x1de6c197, 0x1ec80f}}, - {{0x0107cefd, 0x18e6e0e6, 0x05681ed9, 0x0dcefec5, 0x1bf5e014, 0x04ac53d5, 0x1034bce9, 0x06ead6a6, 0xaeefe9}}}, - /* 3*16^50*G: */ - {{{0x12fea1f9, 0x18be5de2, 0x0114ae52, 0x1e16a118, 0x06531c4f, 0x0ed5b388, 0x0ba0ef3f, 0x014aba3e, 0xa6dc88}}, - {{0x1bc345e9, 0x18e0a723, 0x1a3df98e, 0x1713b6fc, 0x0bc50057, 0x01d08b56, 0x1f0c0e1a, 0x0a8fb86c, 0x7ef1a8}}}, - /* 5*16^50*G: */ - {{{0x06d6c9b3, 0x06a061f8, 0x01958df2, 0x1899d0e9, 0x081ba8c6, 0x114e3c52, 0x1664af70, 0x07fd4848, 0xfe6ba9}}, - {{0x0948bdfb, 0x0163c47d, 0x10ba6c03, 0x01e37e0b, 0x13b56d98, 0x00d9a2a0, 0x01cadaed, 0x1ae80a73, 0x7ee918}}}, - /* 7*16^50*G: */ - {{{0x0cf95151, 0x11788398, 0x0b12d910, 0x0900dc88, 0x0ded1b96, 0x04616e04, 0x02fec083, 0x1e28df93, 0x15d5e2}}, - {{0x0ff8ecf2, 0x01503e61, 0x16303e52, 0x009f72fb, 0x023f9bb2, 0x1084bc48, 0x13b1fe43, 0x06322bfa, 0xa5b72e}}}, - /* 9*16^50*G: */ - {{{0x096a5658, 0x0bc085c9, 0x1bd9590f, 0x0964a483, 0x029be381, 0x100493d7, 0x11eb631f, 0x0e4ad108, 0x84c0e8}}, - {{0x181b80d1, 0x0cb394de, 0x13c7f48b, 0x0c35303e, 0x1725ed3a, 0x118c8329, 0x0b12821f, 0x10182c04, 0x265983}}}, - /* 11*16^50*G: */ - {{{0x14dc6a0f, 0x1addae44, 0x1f855d4d, 0x06832285, 0x077c2744, 0x1273d160, 0x0c755949, 0x18e3526e, 0xfed6b1}}, - {{0x176fc7e0, 0x05c6b96c, 0x0ff10273, 0x09ab2614, 0x1ae23137, 0x0c0d7269, 0x1c2a11e4, 0x1cd61fff, 0x8de2ab}}}, - /* 13*16^50*G: */ - {{{0x18e29355, 0x19c42f88, 0x1c8361b6, 0x191d2672, 0x1b9d82f1, 0x1c302011, 0x0f1c3f3b, 0x1b325a79, 0x2a6a4d}}, - {{0x15cc2872, 0x029f007d, 0x1131db00, 0x00b474c9, 0x0f90dfe9, 0x0e40f134, 0x1831d83f, 0x174f894f, 0x8677df}}}, - /* 15*16^50*G: */ - {{{0x0148dabf, 0x1cfd447f, 0x075e3ac7, 0x1ba57269, 0x0e735c1a, 0x07611afd, 0x151b65d9, 0x004d924e, 0xe42d93}}, - {{0x011e1361, 0x1b963ab4, 0x19dfae75, 0x04eae033, 0x18530327, 0x0675fef9, 0x12c362ce, 0x058dc5b0, 0x641386}}} - }, - { - /* 1*16^51*G: */ - {{{0x166642be, 0x0edac941, 0x162ea227, 0x0920e2fa, 0x1fa8bce3, 0x057a3406, 0x10be46c0, 0x11808ce1, 0x146a77}}, - {{0x1d83efd0, 0x0594ba41, 0x1f97b474, 0x152e3a5e, 0x0b2870aa, 0x0c13fcea, 0x0a2b759a, 0x1d866a80, 0xb318e0}}}, - /* 3*16^51*G: */ - {{{0x07315443, 0x0c9c39c1, 0x1a19ca67, 0x1377aa95, 0x142a13d7, 0x04cc1050, 0x0d7fd0b2, 0x0080cc12, 0xfc696c}}, - {{0x17d28960, 0x0486b05a, 0x06f46c5d, 0x1fe90c21, 0x077b5487, 0x10e6eb4b, 0x024aefc3, 0x1d7f076b, 0xe0ce27}}}, - /* 5*16^51*G: */ - {{{0x16fdb4eb, 0x0dd97ae0, 0x0b9a9e74, 0x07baf38c, 0x0b0928fa, 0x151ab15f, 0x0ab46b95, 0x043fe9fe, 0x974af2}}, - {{0x09f6f484, 0x004e1efd, 0x1ff08d21, 0x18ae5477, 0x090ed111, 0x121e8160, 0x0f299347, 0x0faa6a00, 0x555238}}}, - /* 7*16^51*G: */ - {{{0x1d5aeee3, 0x1c8256da, 0x163204dc, 0x109786cc, 0x070c5e82, 0x0d9d3349, 0x062c2448, 0x13693bc7, 0x5baab5}}, - {{0x10f69717, 0x1694d7db, 0x14c7bb60, 0x1bb93b57, 0x1daf7215, 0x004330ff, 0x1a15b968, 0x0c2f81ef, 0x8a577f}}}, - /* 9*16^51*G: */ - {{{0x15726890, 0x08d8f227, 0x00df4561, 0x004bfd59, 0x10a0ee59, 0x17e75fc8, 0x10f4040c, 0x14fd6938, 0xfb685f}}, - {{0x1835783a, 0x0375479d, 0x039e6c98, 0x0d9625d2, 0x0ba094fa, 0x10b6cc32, 0x18ba1a72, 0x045931cb, 0xd750df}}}, - /* 11*16^51*G: */ - {{{0x08bca48a, 0x0325f89d, 0x0f7d8bd5, 0x09abe9d0, 0x1f71d78b, 0x1dc8e143, 0x05682ac9, 0x1ecb3c53, 0x5de58f}}, - {{0x12fd41cd, 0x03ca7406, 0x03e2aa56, 0x0b7b389c, 0x13c843fe, 0x111e1296, 0x0d54c269, 0x07b006b3, 0x685a3b}}}, - /* 13*16^51*G: */ - {{{0x05ef63b6, 0x0f1c1a27, 0x06c60baf, 0x09a02ce6, 0x1c1c85ab, 0x1fed1da7, 0x02febc6d, 0x19bd5ac3, 0x6f1825}}, - {{0x05c655f3, 0x1642367a, 0x1fe51504, 0x12b4c804, 0x134553c8, 0x1026bc19, 0x046e63d0, 0x0fbab232, 0xff097e}}}, - /* 15*16^51*G: */ - {{{0x14a63f3b, 0x1a823f6f, 0x1e3e5c9e, 0x00760332, 0x0c765832, 0x08afaf3b, 0x0ddad61c, 0x12beec54, 0xc5ecb8}}, - {{0x05005024, 0x09f9ba34, 0x0c2fb96d, 0x16cbdcbc, 0x033ec8be, 0x002c7fc9, 0x07cdd3a9, 0x03032f10, 0x222525}}} - }, - { - /* 1*16^52*G: */ - {{{0x1180eef9, 0x0bb543c9, 0x0a2e5ddb, 0x00244134, 0x07b128d0, 0x075d8d50, 0x17c1f8eb, 0x1ec3a45c, 0xfa50c0}}, - {{0x1f4f2811, 0x066c6be9, 0x1e884ece, 0x1065274a, 0x1a68a5e6, 0x09439140, 0x0ea6dcb3, 0x124472fd, 0x6b84c6}}}, - /* 3*16^52*G: */ - {{{0x11da5e12, 0x0f70719c, 0x12b2ca5c, 0x0c14802b, 0x0a2b6a9c, 0x14fc9d0e, 0x0c6f368c, 0x07886f3c, 0xf7502e}}, - {{0x0385f4eb, 0x125ce2f4, 0x0973af1e, 0x0da65dee, 0x072047b8, 0x04a2e1eb, 0x0bf5665c, 0x1dbacf9f, 0x3c57f5}}}, - /* 5*16^52*G: */ - {{{0x10b7d105, 0x03a49988, 0x195f27c8, 0x14b89729, 0x055b3f4c, 0x1b31271a, 0x018a8e93, 0x1f3075cb, 0x12fe78}}, - {{0x1f794a60, 0x0c5637dc, 0x1ba42e11, 0x19c4cbad, 0x1cb771de, 0x0d50ccd3, 0x13dde1ad, 0x14671ad7, 0x2062f1}}}, - /* 7*16^52*G: */ - {{{0x1e0c5d05, 0x110ec19c, 0x15cb6bfd, 0x1cd8a154, 0x04b1a480, 0x1d881404, 0x1cf56312, 0x0268fbe8, 0x76aac3}}, - {{0x11ece63e, 0x0b30cdba, 0x179bb8d5, 0x044b9e02, 0x0625f4b1, 0x19641901, 0x03beafbc, 0x1de1ab8e, 0xef5576}}}, - /* 9*16^52*G: */ - {{{0x1c53c086, 0x1137a42f, 0x0686bb27, 0x0ab86939, 0x08104c6b, 0x0618a2f4, 0x13321f98, 0x0b77cb8b, 0xa663fe}}, - {{0x05016201, 0x14e28195, 0x0653f039, 0x1d994ae7, 0x03dc3991, 0x081644c1, 0x1efd746c, 0x0fed6423, 0xb54199}}}, - /* 11*16^52*G: */ - {{{0x0b758574, 0x16c00f6a, 0x13e71ba6, 0x04cd1286, 0x0bdf3d83, 0x10813d71, 0x16096df2, 0x0f4040d9, 0xde9552}}, - {{0x1b67232a, 0x1bef8fe7, 0x168b7ad2, 0x0d420a2a, 0x09ed7bae, 0x0e423f8b, 0x05393887, 0x0ad5927a, 0x4cd3e0}}}, - /* 13*16^52*G: */ - {{{0x1d85474f, 0x1bcdc55f, 0x18d19a35, 0x18945712, 0x05aea894, 0x065f223c, 0x0b76ffb7, 0x1c0cda65, 0x8da6bc}}, - {{0x1d7b4ef7, 0x1efce3e9, 0x16f75e97, 0x198b260b, 0x1fff10b1, 0x0fae838e, 0x13fe13f7, 0x0d5e63da, 0x13fc6c}}}, - /* 15*16^52*G: */ - {{{0x1dd042ea, 0x1aea12b3, 0x03abf41a, 0x144d4c8b, 0x093beebf, 0x1324f19e, 0x08e6c6f5, 0x18f9f677, 0x7329ac}}, - {{0x0f5c94a1, 0x0d467f61, 0x1ead3c2b, 0x112ee63b, 0x168ee184, 0x073ca7d5, 0x1c5224a1, 0x06a836ed, 0x927249}}} - }, - { - /* 1*16^53*G: */ - {{{0x1f067ec2, 0x129e995a, 0x0ee94883, 0x11156bab, 0x0e8421a2, 0x1fb5bec4, 0x0846c696, 0x1a194e43, 0xda1d61}}, - {{0x1ad836f1, 0x0afdd078, 0x1e6d2299, 0x0e7133a4, 0x11e2966a, 0x1b30b0e4, 0x01b1e701, 0x0b4f9326, 0x8157f5}}}, - /* 3*16^53*G: */ - {{{0x1a95a8db, 0x0ec3b997, 0x074dbd85, 0x1d81888f, 0x11723b83, 0x13234c8d, 0x141067a5, 0x148c607b, 0xe3e90d}}, - {{0x1b0d1cf9, 0x00b67bf8, 0x06134f44, 0x03df2f99, 0x0e76afbb, 0x15486381, 0x1e2ec03e, 0x1800ad82, 0xfbe53b}}}, - /* 5*16^53*G: */ - {{{0x112ee214, 0x1d57eb20, 0x04c55005, 0x149d2f2b, 0x0c01c782, 0x086feae0, 0x1dd6a2d9, 0x18e65c7a, 0x9f4ffe}}, - {{0x1085f37a, 0x17a21112, 0x12200a0f, 0x136d2617, 0x1c69d971, 0x13417eba, 0x1cb983a5, 0x1c2631c5, 0x639ce2}}}, - /* 7*16^53*G: */ - {{{0x1f61a0a5, 0x05b40a28, 0x10538fbe, 0x04a7c367, 0x00b2c4b1, 0x10520fa2, 0x0b06c5c6, 0x05a82269, 0x431f62}}, - {{0x18cef899, 0x15bdbff3, 0x1595dc91, 0x1554086a, 0x1aa7241b, 0x1328cb91, 0x0e3db5b7, 0x0ffcf548, 0xa29832}}}, - /* 9*16^53*G: */ - {{{0x07748503, 0x16133eab, 0x04ca39f2, 0x1c1c8ee6, 0x012ac0e6, 0x1779cfc5, 0x1ee1b2d8, 0x1bbd9cf1, 0x993dba}}, - {{0x1eb0cee2, 0x1d39b09b, 0x02b6a926, 0x10f7ed37, 0x1f51a17f, 0x1c23c3d0, 0x1bade17d, 0x1dd0ad3d, 0xa521a9}}}, - /* 11*16^53*G: */ - {{{0x06d23d80, 0x0f5113ad, 0x11d351e3, 0x17a23e4c, 0x162c0e10, 0x018e5c84, 0x1a968ce5, 0x1740d5ab, 0x75f17a}}, - {{0x080dd57e, 0x03542d81, 0x13a96426, 0x1ff7db76, 0x16292372, 0x1e85f8cd, 0x0a031ff1, 0x1fc2ac73, 0xa07a62}}}, - /* 13*16^53*G: */ - {{{0x01ad3413, 0x115cdb6b, 0x09f5a12b, 0x13800806, 0x07b7a8db, 0x0fa42e5c, 0x12829ba5, 0x0bc23b3e, 0x667855}}, - {{0x1ebca672, 0x12408103, 0x17199804, 0x1c5a2a75, 0x1df9ea6c, 0x136c93e5, 0x191a4949, 0x07bc4f1e, 0x510dda}}}, - /* 15*16^53*G: */ - {{{0x06cc8563, 0x00057ad8, 0x18407aab, 0x09beb7ff, 0x03688922, 0x015ec0cb, 0x1d22b6b2, 0x06c59b4e, 0xebdc4a}}, - {{0x0394ccfa, 0x0d8bde75, 0x0813e492, 0x080f2492, 0x14f07bec, 0x11af366e, 0x0d7e6c7b, 0x089d0ada, 0x659a31}}} - }, - { - /* 1*16^54*G: */ - {{{0x0d064e13, 0x139d8308, 0x1bc7818a, 0x023bc088, 0x14166153, 0x1fcc747e, 0x1a41c857, 0x1fe192e0, 0xa8e282}}, - {{0x11f4cc0c, 0x17be3988, 0x175af5b3, 0x0f347ca1, 0x115888b6, 0x1f9e2d92, 0x1026afed, 0x0b71b703, 0x7f9735}}}, - /* 3*16^54*G: */ - {{{0x1a3979b5, 0x150ccd85, 0x1fa0a788, 0x111f1bcc, 0x00e50ba2, 0x1f858f72, 0x098c9fcd, 0x18b9b5bc, 0xae2207}}, - {{0x0450fa6f, 0x079e6b34, 0x153e225a, 0x10f6fa6f, 0x17060fca, 0x092291d6, 0x1dc6b532, 0x0a2180f3, 0xea91fe}}}, - /* 5*16^54*G: */ - {{{0x0efca824, 0x0080c880, 0x08593eb9, 0x1c189fd4, 0x05461e0b, 0x0a08032c, 0x139673b1, 0x0195ae55, 0xcb8ded}}, - {{0x0f227361, 0x0a05e82c, 0x04c5d0bc, 0x1a3fbf8f, 0x0cbc496a, 0x16243d16, 0x03216cc5, 0x11ee81b1, 0x33a500}}}, - /* 7*16^54*G: */ - {{{0x1bcbd327, 0x008da6d1, 0x192abba5, 0x1c10a443, 0x16ed6b04, 0x04806bf3, 0x0d9c23a5, 0x05315e30, 0xb0c53b}}, - {{0x0d7be436, 0x10b5e251, 0x18da83c5, 0x144418e8, 0x0b2afd82, 0x15300db3, 0x1a858e3d, 0x0803f7af, 0xee2a97}}}, - /* 9*16^54*G: */ - {{{0x17b836a1, 0x1377db1c, 0x19e7bdf7, 0x0c80bfee, 0x1f526c80, 0x0317673b, 0x04835362, 0x07e653b7, 0x6f6ba7}}, - {{0x06832b84, 0x0def97d8, 0x187fe4d3, 0x1218a511, 0x0e9c0d89, 0x1c5202df, 0x0638f6c2, 0x02ffebf8, 0xdc778a}}}, - /* 11*16^54*G: */ - {{{0x1eb39ede, 0x1771a104, 0x0184b50a, 0x110065ae, 0x04360310, 0x1a33f081, 0x0bd2ef3f, 0x0fb8e845, 0x7d471a}}, - {{0x0bf6607e, 0x04de6ca5, 0x08aa3f43, 0x0b9efa38, 0x086fa779, 0x1118f7fe, 0x15941ee0, 0x033e74d0, 0x4a7b}}}, - /* 13*16^54*G: */ - {{{0x165eb1c1, 0x0b6a4f12, 0x0b9716a9, 0x1aeacf9b, 0x0f0967fc, 0x1e618cc1, 0x1eb1c1c3, 0x0c7f36e7, 0xf00251}}, - {{0x0dde2ae0, 0x0d3eb823, 0x1344795f, 0x0dfeb9ad, 0x0afed857, 0x1a52ed13, 0x037d319a, 0x1d1107a4, 0x54ea9}}}, - /* 15*16^54*G: */ - {{{0x1ac32c64, 0x079a849e, 0x0b92fe13, 0x0dfc07d9, 0x1715e0e3, 0x074a87a3, 0x0ea83dc1, 0x00003da4, 0xac1214}}, - {{0x1eb1a867, 0x00956dd6, 0x14fc2262, 0x14ba74b4, 0x099a3ed5, 0x1b4ab982, 0x0ebc61c2, 0x19758671, 0xce8ebc}}} - }, - { - /* 1*16^55*G: */ - {{{0x0319497c, 0x179c16f4, 0x09423008, 0x1363f4a2, 0x1cab15d5, 0x12b73489, 0x161cb4e7, 0x17393450, 0x174a53}}, - {{0x079afa73, 0x1ed09d60, 0x0e6150e0, 0x16743b19, 0x1f9e6646, 0x0aaf9623, 0x10595ed0, 0x06f57f93, 0xccc9dc}}}, - /* 3*16^55*G: */ - {{{0x154b8367, 0x0a4039eb, 0x1541affa, 0x0b6efacf, 0x16a5db77, 0x12ea2c21, 0x09b9032a, 0x095c88ca, 0x5e5a09}}, - {{0x11ce85ca, 0x0994d4ec, 0x197fe911, 0x1553de7b, 0x04b7a796, 0x00f8ab95, 0x18170b24, 0x19348f2b, 0xae8af8}}}, - /* 5*16^55*G: */ - {{{0x17b10d9d, 0x0cc2bc9c, 0x07e3f2bc, 0x0a5e313a, 0x0b82de6a, 0x05c19886, 0x1a1677b3, 0x15b72e05, 0xd4e0}}, - {{0x1140dced, 0x01080243, 0x18b648fa, 0x113192f1, 0x087f70b5, 0x1c232191, 0x10251f4b, 0x130306ec, 0x87b801}}}, - /* 7*16^55*G: */ - {{{0x1c9caee8, 0x0408d304, 0x089c2ec8, 0x1c408b63, 0x0a667632, 0x10cd7762, 0x1303dbde, 0x026d1dee, 0x36652}}, - {{0x1772b711, 0x14f6351d, 0x056e9fc2, 0x17531265, 0x0944501c, 0x1e340dd3, 0x1b666527, 0x0565527b, 0x1f18c3}}}, - /* 9*16^55*G: */ - {{{0x1446c85c, 0x1ffcba8c, 0x007018d4, 0x0fbc11cc, 0x0c6eade3, 0x1b6229fb, 0x1c7ea819, 0x00adfb71, 0xe5891}}, - {{0x0148972e, 0x1b63bf39, 0x1376b757, 0x00469d01, 0x01898f49, 0x00c5d7a4, 0x0f683b1d, 0x0be23f4f, 0xe39a48}}}, - /* 11*16^55*G: */ - {{{0x022e1259, 0x18c56f9e, 0x004d8abf, 0x0e73480d, 0x17771931, 0x1afd5003, 0x18fcadb3, 0x0da4de28, 0xa74012}}, - {{0x134a5f43, 0x1bb8b921, 0x075b6b57, 0x0cbcea76, 0x07ee5178, 0x18ba533e, 0x07fc6c17, 0x175e329e, 0x5a9ff}}}, - /* 13*16^55*G: */ - {{{0x0b08f1fe, 0x0450bd1e, 0x0821eff6, 0x1cfdce17, 0x0d177d7c, 0x02bb2ec1, 0x13929950, 0x042db28e, 0x87e4b8}}, - {{0x0ed5e2ec, 0x0fba564d, 0x1e1b675d, 0x1e47b7ac, 0x0c2cc6e2, 0x1fc7517c, 0x033b35f5, 0x180ecc69, 0xf74e3a}}}, - /* 15*16^55*G: */ - {{{0x01c4d15c, 0x14380735, 0x1039d2e6, 0x1d4f7e0f, 0x14a44105, 0x11606092, 0x0696a4b0, 0x08c7fd4f, 0x35ea1b}}, - {{0x1f3fe1ea, 0x049cdd7b, 0x194257b7, 0x06754060, 0x13b185d6, 0x1d2feba6, 0x0b35e223, 0x0ca373da, 0xad2191}}} - }, - { - /* 1*16^56*G: */ - {{{0x1475b7ba, 0x027eff84, 0x0462cf62, 0x13ce61c9, 0x18cdbe03, 0x0bf6fa80, 0x0170f4f9, 0x1303286f, 0x959396}}, - {{0x1524f2fd, 0x0dc55fc3, 0x1c24e17a, 0x0a7ec990, 0x0d6849c6, 0x1c3525ce, 0x07762e80, 0x05111866, 0x2e7e55}}}, - /* 3*16^56*G: */ - {{{0x0fd69985, 0x04e2eec8, 0x17dcaba8, 0x013996db, 0x0cf149f3, 0x1486fde6, 0x1df9e23d, 0x0eb9d6e5, 0xae976}}, - {{0x1409a003, 0x0e475a08, 0x1b86bfe2, 0x133a82f5, 0x054c5d0b, 0x0ff7028d, 0x1453a6e3, 0x0e7edc91, 0x912199}}}, - /* 5*16^56*G: */ - {{{0x19262b90, 0x0e0c9efe, 0x0f30a6a7, 0x078983fc, 0x05d1fb72, 0x0f8bbc01, 0x04bb26d9, 0x054b582c, 0x2b1586}}, - {{0x083d7557, 0x08ccb732, 0x05226926, 0x0692e1f3, 0x149066f5, 0x06a96d43, 0x0fea9e8c, 0x07b54146, 0x2eb005}}}, - /* 7*16^56*G: */ - {{{0x08e7be40, 0x1fcb8a65, 0x0103b964, 0x05912922, 0x0769af2d, 0x0e0b0b72, 0x199dfba5, 0x1da352dd, 0x6af9ea}}, - {{0x0e387e1c, 0x120b7013, 0x1d655a7e, 0x07eccd41, 0x1dc8145e, 0x152141a3, 0x19259c27, 0x022d200c, 0xb3812a}}}, - /* 9*16^56*G: */ - {{{0x1482801e, 0x135b7d07, 0x0f505574, 0x129f178b, 0x0d6f9407, 0x15a1265c, 0x113bacea, 0x1dc08882, 0x596668}}, - {{0x04870c37, 0x03b8a478, 0x14d4d6b5, 0x0d8396c7, 0x1304e8db, 0x1cb043b8, 0x1d7c7b23, 0x150b775d, 0x949aa0}}}, - /* 11*16^56*G: */ - {{{0x032c19fd, 0x064d973e, 0x000a30f9, 0x1571d20b, 0x10b5b4ac, 0x068bd5ab, 0x01d8bf7d, 0x11036a0a, 0xbe84d1}}, - {{0x12f1281f, 0x1b4a529b, 0x14370dd9, 0x0b4feabc, 0x03994795, 0x12fa4184, 0x02513479, 0x19665b8a, 0xeff960}}}, - /* 13*16^56*G: */ - {{{0x16c69482, 0x08dbafea, 0x0be859ef, 0x156a8026, 0x0bc88cbe, 0x193a6579, 0x1b9507d5, 0x062981af, 0x9867a0}}, - {{0x0f792cd7, 0x178308a3, 0x158a2a45, 0x048b9ea2, 0x099639e6, 0x16aad8dd, 0x0d3e71e4, 0x0b476210, 0xd02e61}}}, - /* 15*16^56*G: */ - {{{0x1d557aa1, 0x0511cec8, 0x007f0a5e, 0x1b25fd9a, 0x1d6abdf1, 0x1975004c, 0x0569649f, 0x08a81b10, 0xa866f2}}, - {{0x01430634, 0x0c0ddda6, 0x184692de, 0x16d38cf8, 0x0e13961e, 0x0c7d2ed8, 0x0d135e4f, 0x1ed50045, 0xb58739}}} - }, - { - /* 1*16^57*G: */ - {{{0x1d82b151, 0x1a89a064, 0x07ee8b6e, 0x01487aac, 0x09a8fcca, 0x108a9d88, 0x195b5916, 0x0a15c803, 0xd2a63a}}, - {{0x1cf89405, 0x00a10ba6, 0x013294b5, 0x1eea15e9, 0x08220a70, 0x172c594a, 0x12dd596b, 0x1f6c887f, 0xe82d86}}}, - /* 3*16^57*G: */ - {{{0x0e4b3ba0, 0x02cfb1af, 0x02fc7c5e, 0x157debe3, 0x1245f5c2, 0x0b8798df, 0x0dcefbf8, 0x00a443ff, 0x410811}}, - {{0x17525595, 0x034b0ee0, 0x08191552, 0x0c930acb, 0x18498133, 0x12d70eb5, 0x19a3cb29, 0x0d2edfea, 0xdc37f3}}}, - /* 5*16^57*G: */ - {{{0x13d98ded, 0x114e4dc4, 0x02808611, 0x1e450677, 0x1d65edbd, 0x114c8298, 0x0323233c, 0x02142d98, 0x63a2a2}}, - {{0x00d1cfc2, 0x0c8cbea7, 0x11e1ce94, 0x17ed4013, 0x194461fa, 0x01992a76, 0x1dbf4194, 0x1c5cffd8, 0x882b42}}}, - /* 7*16^57*G: */ - {{{0x18045445, 0x1430d285, 0x07a35fba, 0x1ee6e320, 0x1bef080f, 0x17172eab, 0x1f28f7c4, 0x0ba893ac, 0xc1581}}, - {{0x0054a206, 0x0a7c3eaa, 0x1633a8c8, 0x00a9c86c, 0x1cd28ba3, 0x1e1db331, 0x045742a4, 0x01475d28, 0x2f30d6}}}, - /* 9*16^57*G: */ - {{{0x03857faf, 0x14891ce6, 0x05865c07, 0x1f95bc3d, 0x0ef7f882, 0x1d47a414, 0x0a70355e, 0x0d7135d1, 0xc757eb}}, - {{0x00584ca4, 0x0eced865, 0x06253040, 0x1a621a20, 0x0c61b627, 0x14f9045f, 0x1cd895cd, 0x19f9a47f, 0xf03a59}}}, - /* 11*16^57*G: */ - {{{0x1459225d, 0x1268c27a, 0x02163443, 0x15eefc5b, 0x002a244f, 0x0a04c8ce, 0x0343e057, 0x15d5b5f4, 0xfa8063}}, - {{0x1ece1507, 0x115bf1db, 0x01f1670e, 0x16d86da0, 0x0425c0a2, 0x11104126, 0x01a45837, 0x120af818, 0xba71f}}}, - /* 13*16^57*G: */ - {{{0x16f0d044, 0x13cff4a0, 0x079869e5, 0x153fa921, 0x0e0a5aab, 0x14e7c317, 0x1ea278bd, 0x18b3a04a, 0x658ca3}}, - {{0x17cb872d, 0x0e8f9977, 0x0633a26b, 0x02cec788, 0x1d37655a, 0x0eb1389d, 0x15183c59, 0x06ef5d44, 0xae5cc1}}}, - /* 15*16^57*G: */ - {{{0x1696756d, 0x1ad64ab9, 0x158505ea, 0x15e2c0ac, 0x1305c676, 0x0cc1ae9f, 0x0aeb3930, 0x0955f23e, 0x31c94b}}, - {{0x1e08ae78, 0x1e22f46e, 0x0b441c2a, 0x1dbf95cd, 0x0160683a, 0x05acd57a, 0x0ea6fd2e, 0x096aadd0, 0xf80f88}}} - }, - { - /* 1*16^58*G: */ - {{{0x1617e073, 0x01b7cda2, 0x0e4c5ecd, 0x197b7a70, 0x1dc866ba, 0x1c4b6be7, 0x1ae243b9, 0x0466a8e3, 0x64587e}}, - {{0x1faf6589, 0x014cf2f4, 0x0ebaacd6, 0x12147226, 0x099a185b, 0x0eb223e1, 0x0b8aba5b, 0x1ab7ed20, 0xd99fcd}}}, - /* 3*16^58*G: */ - {{{0x0e103dd6, 0x0fb8a390, 0x0012166b, 0x0c0980f8, 0x0a17ac34, 0x09e7e2c9, 0x0fe0da88, 0x1aab4840, 0xbc477b}}, - {{0x16f7c343, 0x1c8416c6, 0x0ed12b18, 0x126ae58c, 0x0a6395d2, 0x02a9636f, 0x1549b2eb, 0x0485351b, 0xe31e1e}}}, - /* 5*16^58*G: */ - {{{0x144eab31, 0x086e1d86, 0x198d241f, 0x0b5e2809, 0x1f8e80ac, 0x1a11933d, 0x00e00c0e, 0x1fcb4d77, 0x589db4}}, - {{0x11361f6a, 0x00d75f3a, 0x123e36e5, 0x021caa42, 0x190f31f6, 0x0310125e, 0x0a93d81c, 0x0b821154, 0x625544}}}, - /* 7*16^58*G: */ - {{{0x1a0c2c41, 0x1fcb0b94, 0x00cdb19e, 0x063838ac, 0x0db7c428, 0x0c3056b7, 0x1e8baa28, 0x06fa2dc5, 0x1339b3}}, - {{0x09f1bc2b, 0x02f82a5d, 0x1a48e906, 0x044ff0fb, 0x1a3406b1, 0x1207e889, 0x196e9e8c, 0x0c6c58f5, 0x9f9b29}}}, - /* 9*16^58*G: */ - {{{0x18fc47af, 0x18258fc2, 0x10337b0d, 0x1bfd9065, 0x1b568a8d, 0x194da800, 0x1c5f3140, 0x14226c79, 0x7ff3bb}}, - {{0x19ba43a7, 0x1c30b267, 0x02eb0a5f, 0x0a7635a3, 0x1446b17a, 0x048dba39, 0x18a682f2, 0x15d00314, 0x1f6ba7}}}, - /* 11*16^58*G: */ - {{{0x15213775, 0x0c26b004, 0x150aa640, 0x08527647, 0x07f6100b, 0x149caff6, 0x02ed8507, 0x08c79d6c, 0x8ec670}}, - {{0x1841ffff, 0x100879f3, 0x13d47a43, 0x15314179, 0x1ee0e71d, 0x01a0ae76, 0x0f8c1b99, 0x0df41b4b, 0x8f58a6}}}, - /* 13*16^58*G: */ - {{{0x1452abbb, 0x059ffc69, 0x0e570b8f, 0x154e5fc5, 0x1d495ae6, 0x161ff6ca, 0x06ee276e, 0x16883ce0, 0x83de61}}, - {{0x054eb66e, 0x1028bb58, 0x1390a462, 0x18be6d77, 0x01563d79, 0x1b57c627, 0x027e9afe, 0x0694698c, 0x32f0e3}}}, - /* 15*16^58*G: */ - {{{0x159276f1, 0x0b446137, 0x085ec57a, 0x1c4b6525, 0x0d86833a, 0x1ae007be, 0x076c6a2e, 0x1131ea18, 0x3d7663}}, - {{0x059cbcb3, 0x0f2532dc, 0x0c65e180, 0x03304033, 0x0333ef32, 0x171a6d6c, 0x176d825d, 0x0e6f430f, 0xd37669}}} - }, - { - /* 1*16^59*G: */ - {{{0x1d45e458, 0x0c6b6436, 0x1439ff4d, 0x154d9d44, 0x1de042f0, 0x0369f2a4, 0x0216ce95, 0x1c1c9c9b, 0x8481bd}}, - {{0x1779057e, 0x0b258dac, 0x098b955b, 0x14f38856, 0x0b2ca900, 0x0df9ce76, 0x13761289, 0x11974a80, 0x38ee7b}}}, - /* 3*16^59*G: */ - {{{0x152da17d, 0x10507d20, 0x14191ac5, 0x1827b611, 0x00bc811d, 0x13582ff0, 0x117c2253, 0x03c1ea31, 0x3beaed}}, - {{0x0cc768d2, 0x13824c2f, 0x1fb105b3, 0x1bcef71b, 0x0e1b554c, 0x145f5f40, 0x0b37fbd2, 0x1eab5fef, 0xc3b0d7}}}, - /* 5*16^59*G: */ - {{{0x1a4edcc5, 0x1a7d0bed, 0x00c46dc8, 0x1c644284, 0x15997e74, 0x0fe01c93, 0x15861d4b, 0x14197b93, 0x6e73db}}, - {{0x159da0e4, 0x198fbe6e, 0x019e40de, 0x14efb4e0, 0x08693278, 0x0a844441, 0x1122fa91, 0x1f893dd9, 0xee0ac1}}}, - /* 7*16^59*G: */ - {{{0x0a80b979, 0x04e26212, 0x06aecc50, 0x01ebf465, 0x1c310049, 0x0cbf5523, 0x1649d89f, 0x1126fcb6, 0x7706dd}}, - {{0x0126cfde, 0x067a4082, 0x1fbf8c85, 0x141469fa, 0x09c7117f, 0x0ebcc8f5, 0x1c51dde3, 0x104fab76, 0x8a02a9}}}, - /* 9*16^59*G: */ - {{{0x126fe285, 0x06dce25b, 0x0fbc49f7, 0x17585282, 0x1e06aa45, 0x1e3d20fc, 0x03e034bc, 0x18b25378, 0x16d422}}, - {{0x0155b441, 0x1f07ff36, 0x0d93508c, 0x1e18226e, 0x131b1e93, 0x1f34d31a, 0x1906a2ad, 0x1f4a3c44, 0xdf888}}}, - /* 11*16^59*G: */ - {{{0x1acfa513, 0x11885e55, 0x1838ebab, 0x080f3f34, 0x16a9c4e2, 0x1a23a87a, 0x158ea968, 0x08fdd8ed, 0x1fcc0e}}, - {{0x107afc9c, 0x083add20, 0x060e461d, 0x1bdba2c9, 0x1f9b44be, 0x1c3aa19c, 0x11e2d238, 0x14083c6a, 0x165dc1}}}, - /* 13*16^59*G: */ - {{{0x1edc69b2, 0x0d1383e7, 0x1addc5c8, 0x14c11364, 0x0a386a50, 0x01821ae5, 0x0285cc19, 0x0e75ad97, 0xc12b90}}, - {{0x00dd41dd, 0x19574d81, 0x09eca800, 0x1c3b7c7a, 0x14976b8e, 0x16e44fc4, 0x17c765dc, 0x07fca699, 0x3173c4}}}, - /* 15*16^59*G: */ - {{{0x1961fe4d, 0x1b7ac2ef, 0x041c65ea, 0x0910df16, 0x0a73e8a1, 0x14989896, 0x0a3e8fcf, 0x10bb864f, 0xd059bf}}, - {{0x0ae823c2, 0x0c9ad833, 0x16ad932e, 0x111743e9, 0x155b4fd3, 0x1b2ee424, 0x0978ff81, 0x0c18116a, 0x45107a}}} - }, - { - /* 1*16^60*G: */ - {{{0x0caf666b, 0x06b181fb, 0x0c738c2f, 0x19fda789, 0x1f4637ff, 0x0bcd740b, 0x0aa98ada, 0x0af4f020, 0x13464a}}, - {{0x1f6ecc27, 0x1a4ad483, 0x0250b84f, 0x0601503a, 0x0b0ca48f, 0x019a29e6, 0x1603bdf9, 0x12008c28, 0x69be15}}}, - /* 3*16^60*G: */ - {{{0x0eca5f51, 0x10b5904c, 0x1f26bafc, 0x142e3729, 0x1b5cfdde, 0x0b595f82, 0x1a58b1bb, 0x029bb3dc, 0xdde9d5}}, - {{0x10c638f7, 0x16b4d39e, 0x0255c7e6, 0x1dd7d1bd, 0x18f0950f, 0x19a5853f, 0x04476247, 0x02679c50, 0xb84e69}}}, - /* 5*16^60*G: */ - {{{0x199c88e4, 0x1c83582c, 0x0b51bb0b, 0x1aa27c41, 0x04b179ae, 0x00375890, 0x0dcdba7d, 0x02046d32, 0xfd1a62}}, - {{0x195bc8df, 0x0e4648b2, 0x13003ca6, 0x16e3a92b, 0x17782dc6, 0x0034aa4b, 0x082fec4f, 0x0a973918, 0x1ac97b}}}, - /* 7*16^60*G: */ - {{{0x1f8018ce, 0x0a8adada, 0x024b5a2f, 0x1b4ae71b, 0x06dc7cf2, 0x1e727964, 0x1ae7c4ff, 0x063b1852, 0x4ee485}}, - {{0x1e48381f, 0x01ad30d8, 0x1a01804f, 0x0e92e369, 0x1c5e6710, 0x02046863, 0x02d7f1ed, 0x1a90217f, 0xb68f9e}}}, - /* 9*16^60*G: */ - {{{0x11473678, 0x1429748f, 0x10e4bdc0, 0x00af2a12, 0x0c070cba, 0x18a62adc, 0x036ffd78, 0x13869880, 0xfd76cc}}, - {{0x0d144f4f, 0x10b27754, 0x007210df, 0x051ddc28, 0x12cd6606, 0x10539e81, 0x0f6b83fb, 0x086f0e28, 0xf20465}}}, - /* 11*16^60*G: */ - {{{0x0d7a2193, 0x1805b8a4, 0x05d51bb7, 0x123c89e3, 0x0ea212c6, 0x07413a5a, 0x1008679b, 0x14662476, 0x85a2ab}}, - {{0x10cdcf3a, 0x18641ea5, 0x0ec4909f, 0x0db5bf38, 0x0029fe1c, 0x104168e6, 0x145b60b1, 0x0afd6560, 0x9c1298}}}, - /* 13*16^60*G: */ - {{{0x177568b0, 0x0d8182d9, 0x180ec14d, 0x1d1ba033, 0x1650f35a, 0x16b62bc1, 0x19d1102d, 0x1f8e79ff, 0xd25ddb}}, - {{0x1f39929c, 0x0509c936, 0x0f0fc018, 0x04e7103c, 0x1d92b832, 0x17ba66f3, 0x024e2fab, 0x0eb27f09, 0x7a3aff}}}, - /* 15*16^60*G: */ - {{{0x071d7c13, 0x0ff288c5, 0x03fe8e15, 0x156beff4, 0x0c805641, 0x1f4d4bd5, 0x09c957c1, 0x06287d29, 0x458135}}, - {{0x1aff63cf, 0x11c5e2a9, 0x0f65ae65, 0x000caa85, 0x169c9702, 0x0878bbee, 0x0b62d5fd, 0x1d8292f3, 0x9f5858}}} - }, - { - /* 1*16^61*G: */ - {{{0x0d83f366, 0x16d1d069, 0x1ca16232, 0x1399dbc5, 0x1c97a0cd, 0x0185e60e, 0x18ba6bbd, 0x1eb6e27f, 0xbc4a9d}}, - {{0x181f33c1, 0x1ac6b332, 0x151ec5b5, 0x1153f7f4, 0x198caa6e, 0x1bd6fa5b, 0x1018e0e4, 0x194dcf0b, 0xd3a81}}}, - /* 3*16^61*G: */ - {{{0x1712be3c, 0x03517197, 0x051a99ac, 0x0be31db4, 0x01534729, 0x12edd580, 0x0de34f1c, 0x13b26636, 0x39d734}}, - {{0x1c6ff65c, 0x0180cfa0, 0x09059133, 0x1def4bd9, 0x012e8ef5, 0x1aaa6334, 0x0fdfec49, 0x09eadde7, 0x8f929b}}}, - /* 5*16^61*G: */ - {{{0x1f77f22b, 0x15727de6, 0x1e0b80d6, 0x12e47329, 0x1af26c69, 0x06b614ca, 0x17427947, 0x02fefb83, 0xf0cba6}}, - {{0x1909a03c, 0x1e47163a, 0x08255987, 0x0318fd21, 0x0d04004f, 0x1361b28b, 0x1e627bcc, 0x08627f3b, 0x1a25ab}}}, - /* 7*16^61*G: */ - {{{0x06509c12, 0x0566e6a6, 0x147d1d96, 0x17fc46b7, 0x068ed8d6, 0x18746c39, 0x134c8745, 0x173b642a, 0x381d7a}}, - {{0x0eb46102, 0x03215471, 0x19babdd5, 0x1050b0d9, 0x181e7205, 0x122b9d32, 0x16a7ad74, 0x0b6ffb47, 0xa47aab}}}, - /* 9*16^61*G: */ - {{{0x184fe955, 0x0d9da6b1, 0x18ef3923, 0x12ad4b40, 0x08a53f69, 0x1b9f34a6, 0x1f991e4e, 0x0a8cf570, 0xa703f0}}, - {{0x161344bd, 0x135977de, 0x05c9dfe8, 0x1c2c538b, 0x1199b539, 0x1c96b58c, 0x1eb703a9, 0x06b45608, 0xd500f9}}}, - /* 11*16^61*G: */ - {{{0x06eace58, 0x04cb2b60, 0x1cc8474d, 0x1c8ac745, 0x1a03f1b7, 0x1686b829, 0x035d1b1a, 0x18b55aaa, 0x73c6b3}}, - {{0x0af8654e, 0x0b8548b9, 0x0e34a45c, 0x150f1b77, 0x191c6aa6, 0x04c89b36, 0x1dd06ea4, 0x148e6749, 0x3a2fb4}}}, - /* 13*16^61*G: */ - {{{0x00181d5e, 0x059c45f8, 0x16abc815, 0x03675372, 0x0ddb8de7, 0x069d0e07, 0x1ff68740, 0x1cea0da8, 0xc627f3}}, - {{0x169f886d, 0x13c80531, 0x12f8b0e4, 0x0d600a93, 0x1f7d68ef, 0x0b009c50, 0x098ecb5a, 0x1ae3c885, 0xd78f9d}}}, - /* 15*16^61*G: */ - {{{0x17828b16, 0x07146cfd, 0x09211fcd, 0x0f2b1e51, 0x0de53a04, 0x1a053783, 0x08cfe897, 0x17c1dbfa, 0xbb88fa}}, - {{0x0aea5df7, 0x08a39d10, 0x087a5a71, 0x1502e9c7, 0x19163ec4, 0x02cb008a, 0x0374d177, 0x16609ebd, 0xb73676}}} - }, - { - /* 1*16^62*G: */ - {{{0x05324caa, 0x0a55987f, 0x051ca8e5, 0x16cbc615, 0x0a32e694, 0x063a4a29, 0x0f0348f6, 0x0f7f0531, 0x8c28a9}}, - {{0x0bef9482, 0x138ee39e, 0x072e5167, 0x0f09e08a, 0x0c0eb7ae, 0x16f98fbe, 0x064cde3f, 0x0c74660a, 0x40a304}}}, - /* 3*16^62*G: */ - {{{0x0754dd40, 0x11f438aa, 0x0d19b3e1, 0x044c63f8, 0x0f6e9a24, 0x020fe6b9, 0x1f3d16d2, 0x0e06581b, 0x972924}}, - {{0x0aa36143, 0x025a4979, 0x0b2bd24e, 0x15d0a4ab, 0x0df3690d, 0x03aee5ea, 0x08773457, 0x0884cbfd, 0x91d1a2}}}, - /* 5*16^62*G: */ - {{{0x0c2ca7ff, 0x016c175c, 0x17c0868f, 0x06c8bb2b, 0x127af180, 0x08d6ad17, 0x05b8141e, 0x12eb014f, 0x89637f}}, - {{0x10493e68, 0x16a0af0b, 0x10baadef, 0x178d471c, 0x17489f87, 0x0e78aa1a, 0x109355ee, 0x04919110, 0x2d1fe1}}}, - /* 7*16^62*G: */ - {{{0x0ca8dd7f, 0x0c36b1d0, 0x084e0698, 0x0e5006ad, 0x157421bc, 0x0ed01ea9, 0x1824bf72, 0x1ce37c4b, 0x308138}}, - {{0x0a92c7f2, 0x00af923c, 0x12b64579, 0x0cac8c86, 0x08e18c81, 0x1622e8a0, 0x124978e7, 0x1a51051f, 0x28d1e2}}}, - /* 9*16^62*G: */ - {{{0x066a3fb1, 0x06e62b44, 0x04b881b0, 0x00125033, 0x0862f6ec, 0x1a8642db, 0x0d974795, 0x1d054dbd, 0x575fc4}}, - {{0x102655ad, 0x0dc74854, 0x08ebcbc2, 0x076ae78d, 0x087daed3, 0x0de14bc7, 0x128b59c7, 0x120854df, 0x6f6edb}}}, - /* 11*16^62*G: */ - {{{0x190117df, 0x0db54523, 0x08040a48, 0x0a77779c, 0x02a8fda2, 0x137c0f75, 0x0de889fc, 0x06d6c9d5, 0xa5ec90}}, - {{0x186462fe, 0x0094099f, 0x0528d8f6, 0x08c3e0ac, 0x1a0f71c8, 0x1cc1d68f, 0x01003165, 0x0c4bd828, 0xb79dc6}}}, - /* 13*16^62*G: */ - {{{0x172ad712, 0x187cbae0, 0x0411ca42, 0x131961bc, 0x149b95a3, 0x1cbb0a31, 0x0c252779, 0x1d226621, 0xa153df}}, - {{0x0d48fdd2, 0x052fb29c, 0x1c2cca72, 0x0a7e50b5, 0x1b89abd0, 0x0c6af8f8, 0x0cbf120c, 0x0827f60b, 0xfd94d8}}}, - /* 15*16^62*G: */ - {{{0x11cf5b3a, 0x1861b808, 0x0d69e040, 0x0675077b, 0x1c824c44, 0x1a684476, 0x18564d70, 0x18d5ef28, 0x9a541a}}, - {{0x16a44ae4, 0x1faabaf9, 0x07a94b58, 0x11fdc4a4, 0x1475f554, 0x0d79b447, 0x0adf2bf8, 0x1839620d, 0xb66148}}} - }, - { - /* 1*16^63*G: */ - {{{0x1faccae0, 0x0625d088, 0x12eccdd2, 0x166a18b4, 0x11fd23c8, 0x0a672783, 0x1ea30776, 0x0cc272a4, 0x8ea96}}, - {{0x0e62b945, 0x0d79a518, 0x1c3e3a55, 0x0f077d39, 0x1c5d735b, 0x1e067dca, 0x1e0b8939, 0x17791dc4, 0x620efa}}}, - /* 3*16^63*G: */ - {{{0x06a06f5e, 0x0d205acb, 0x0820dc08, 0x0324a2dd, 0x1b716a34, 0x06a10931, 0x14eb0dec, 0x1f7d4284, 0x383b24}}, - {{0x13c6e772, 0x04fa3c36, 0x030ac102, 0x0d5ce977, 0x05a19e8f, 0x0b36aa75, 0x0881133d, 0x0d589db7, 0x54cf70}}}, - /* 5*16^63*G: */ - {{{0x0638a136, 0x1cbae0ea, 0x00e06571, 0x1a39c66d, 0x1790c2b0, 0x0ce35b06, 0x15b5e279, 0x1a07c05d, 0xe68432}}, - {{0x0c6c2584, 0x17e8c084, 0x0d5ccdaa, 0x13c7d7b6, 0x1e6472e0, 0x13981d00, 0x0998934a, 0x02731c6b, 0xca5be4}}}, - /* 7*16^63*G: */ - {{{0x16e8c10c, 0x0743e220, 0x06f5a01f, 0x0530be72, 0x06e7fb47, 0x1ef67398, 0x10a83bbe, 0x0b3c5fcb, 0x395dd5}}, - {{0x05fe638e, 0x01eb6c98, 0x19a48b2f, 0x013809b8, 0x04e274c9, 0x1f43d7fd, 0x0b174104, 0x1a968b25, 0xfd62dc}}}, - /* 9*16^63*G: */ - {{{0x0d6c14ef, 0x0b326d90, 0x1e4f23d4, 0x11f8ea0d, 0x06480085, 0x16adf771, 0x172e7dbb, 0x1b86aa4b, 0x7a514a}}, - {{0x0b3fbd13, 0x169f0c38, 0x09b893de, 0x1d5dee55, 0x15c3729b, 0x185ca647, 0x1363a25f, 0x1fda2a5c, 0x56edd1}}}, - /* 11*16^63*G: */ - {{{0x0f6d65eb, 0x14a31e82, 0x10085492, 0x1220eea8, 0x08f235a9, 0x179dfa48, 0x04363aa3, 0x0b0864bb, 0x1ee1fd}}, - {{0x1d22941c, 0x101b5c92, 0x0d60ac47, 0x05e9d30c, 0x0fcfaca3, 0x1cfe27a1, 0x1cf073ea, 0x1237bad8, 0xbb6928}}}, - /* 13*16^63*G: */ - {{{0x0e36cb44, 0x18ca8778, 0x12880647, 0x1d16d91b, 0x1357d617, 0x07e86c41, 0x0aa2f016, 0x069a71f5, 0x155156}}, - {{0x1f495a68, 0x14d7a328, 0x0830794c, 0x06e2ebe0, 0x1205da8c, 0x11f85a31, 0x08578dc3, 0x18eaaaea, 0xab4fff}}}, - /* 15*16^63*G: */ - {{{0x1427bacc, 0x0fca3083, 0x0b58b854, 0x0662c9ba, 0x1c4aa9e7, 0x07584ac6, 0x0804d8d6, 0x0c88d7ea, 0x3bc6bc}}, - {{0x0ad6fda6, 0x0619feaf, 0x02fad1c5, 0x16eb4a45, 0x0c02bd71, 0x1771136b, 0x0c1736d8, 0x180e2ed8, 0x8e305c}}} - }, diff --git a/deps/crypto/trezor-crypto/segwit_addr.c b/deps/crypto/trezor-crypto/segwit_addr.c deleted file mode 100644 index 446c0d6e6..000000000 --- a/deps/crypto/trezor-crypto/segwit_addr.c +++ /dev/null @@ -1,209 +0,0 @@ -/* Copyright (c) 2017, 2021 Pieter Wuille - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include -#include -#include - -#include "segwit_addr.h" - -static uint32_t bech32_polymod_step(uint32_t pre) { - uint8_t b = pre >> 25; - return ((pre & 0x1FFFFFF) << 5) ^ - (-((b >> 0) & 1) & 0x3b6a57b2UL) ^ - (-((b >> 1) & 1) & 0x26508e6dUL) ^ - (-((b >> 2) & 1) & 0x1ea119faUL) ^ - (-((b >> 3) & 1) & 0x3d4233ddUL) ^ - (-((b >> 4) & 1) & 0x2a1462b3UL); -} - -static uint32_t bech32_final_constant(bech32_encoding enc) { - if (enc == BECH32_ENCODING_BECH32) return 1; - if (enc == BECH32_ENCODING_BECH32M) return 0x2bc830a3; - return 0; -} - -static const char* charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; - -static const int8_t charset_rev[128] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1, - -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, - 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1, - -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, - 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1 -}; - -int bech32_encode(char *output, const char *hrp, const uint8_t *data, size_t data_len, bech32_encoding enc) { - uint32_t chk = 1; - size_t i = 0; - while (hrp[i] != 0) { - int ch = hrp[i]; - if (ch < 33 || ch > 126) { - return 0; - } - - if (ch >= 'A' && ch <= 'Z') return 0; - chk = bech32_polymod_step(chk) ^ (ch >> 5); - ++i; - } - if (i + 7 + data_len > 90) return 0; - chk = bech32_polymod_step(chk); - while (*hrp != 0) { - chk = bech32_polymod_step(chk) ^ (*hrp & 0x1f); - *(output++) = *(hrp++); - } - *(output++) = '1'; - for (i = 0; i < data_len; ++i) { - if (*data >> 5) return 0; - chk = bech32_polymod_step(chk) ^ (*data); - *(output++) = charset[*(data++)]; - } - for (i = 0; i < 6; ++i) { - chk = bech32_polymod_step(chk); - } - chk ^= bech32_final_constant(enc); - for (i = 0; i < 6; ++i) { - *(output++) = charset[(chk >> ((5 - i) * 5)) & 0x1f]; - } - *output = 0; - return 1; -} - -bech32_encoding bech32_decode(char* hrp, uint8_t *data, size_t *data_len, const char *input) { - uint32_t chk = 1; - size_t i = 0; - size_t input_len = strlen(input); - size_t hrp_len = 0; - int have_lower = 0, have_upper = 0; - if (input_len < 8) { - return BECH32_ENCODING_NONE; - } - *data_len = 0; - while (*data_len < input_len && input[(input_len - 1) - *data_len] != '1') { - ++(*data_len); - } - hrp_len = input_len - (1 + *data_len); - if (1 + *data_len >= input_len || *data_len < 6 || hrp_len > BECH32_MAX_HRP_LEN) { - return BECH32_ENCODING_NONE; - } - *(data_len) -= 6; - for (i = 0; i < hrp_len; ++i) { - int ch = input[i]; - if (ch < 33 || ch > 126) { - return BECH32_ENCODING_NONE; - } - if (ch >= 'a' && ch <= 'z') { - have_lower = 1; - } else if (ch >= 'A' && ch <= 'Z') { - have_upper = 1; - ch = (ch - 'A') + 'a'; - } - hrp[i] = ch; - chk = bech32_polymod_step(chk) ^ (ch >> 5); - } - hrp[i] = 0; - chk = bech32_polymod_step(chk); - for (i = 0; i < hrp_len; ++i) { - chk = bech32_polymod_step(chk) ^ (input[i] & 0x1f); - } - ++i; - while (i < input_len) { - int v = (input[i] & 0x80) ? -1 : charset_rev[(int)input[i]]; - if (input[i] >= 'a' && input[i] <= 'z') have_lower = 1; - if (input[i] >= 'A' && input[i] <= 'Z') have_upper = 1; - if (v == -1) { - return BECH32_ENCODING_NONE; - } - chk = bech32_polymod_step(chk) ^ v; - if (i + 6 < input_len) { - data[i - (1 + hrp_len)] = v; - } - ++i; - } - if (have_lower && have_upper) { - return BECH32_ENCODING_NONE; - } - if (chk == bech32_final_constant(BECH32_ENCODING_BECH32)) { - return BECH32_ENCODING_BECH32; - } else if (chk == bech32_final_constant(BECH32_ENCODING_BECH32M)) { - return BECH32_ENCODING_BECH32M; - } else { - return BECH32_ENCODING_NONE; - } -} - -static int convert_bits(uint8_t* out, size_t* outlen, int outbits, const uint8_t* in, size_t inlen, int inbits, int pad) { - uint32_t val = 0; - int bits = 0; - uint32_t maxv = (((uint32_t)1) << outbits) - 1; - while (inlen--) { - val = (val << inbits) | *(in++); - bits += inbits; - while (bits >= outbits) { - bits -= outbits; - out[(*outlen)++] = (val >> bits) & maxv; - } - } - if (pad) { - if (bits) { - out[(*outlen)++] = (val << (outbits - bits)) & maxv; - } - } else if (((val << (outbits - bits)) & maxv) || bits >= inbits) { - return 0; - } - return 1; -} - -int segwit_addr_encode(char *output, const char *hrp, int witver, const uint8_t *witprog, size_t witprog_len) { - uint8_t data[65] = {0}; - size_t datalen = 0; - bech32_encoding enc = BECH32_ENCODING_BECH32; - if (witver > 16) return 0; - if (witver == 0 && witprog_len != 20 && witprog_len != 32) return 0; - if (witprog_len < 2 || witprog_len > 40) return 0; - if (witver > 0) enc = BECH32_ENCODING_BECH32M; - data[0] = witver; - convert_bits(data + 1, &datalen, 5, witprog, witprog_len, 8, 1); - ++datalen; - return bech32_encode(output, hrp, data, datalen, enc); -} - -int segwit_addr_decode(int* witver, uint8_t* witdata, size_t* witdata_len, const char* hrp, const char* addr) { - uint8_t data[84] = {0}; - char hrp_actual[84] = {0}; - size_t data_len = 0; - if (strlen(addr) > 90) return 0; - bech32_encoding enc = bech32_decode(hrp_actual, data, &data_len, addr); - if (enc == BECH32_ENCODING_NONE) return 0; - if (data_len == 0 || data_len > 65) return 0; - if (strncmp(hrp, hrp_actual, 84) != 0) return 0; - if (data[0] > 16) return 0; - if (data[0] == 0 && enc != BECH32_ENCODING_BECH32) return 0; - if (data[0] > 0 && enc != BECH32_ENCODING_BECH32M) return 0; - *witdata_len = 0; - if (!convert_bits(witdata, witdata_len, 8, data + 1, data_len - 1, 5, 0)) return 0; - if (*witdata_len < 2 || *witdata_len > 40) return 0; - if (data[0] == 0 && *witdata_len != 20 && *witdata_len != 32) return 0; - *witver = data[0]; - return 1; -} diff --git a/deps/crypto/trezor-crypto/segwit_addr.h b/deps/crypto/trezor-crypto/segwit_addr.h deleted file mode 100644 index 844874ccf..000000000 --- a/deps/crypto/trezor-crypto/segwit_addr.h +++ /dev/null @@ -1,116 +0,0 @@ -/* Copyright (c) 2017, 2021 Pieter Wuille - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef _SEGWIT_ADDR_H_ -#define _SEGWIT_ADDR_H_ 1 - -#include - -// The maximum length of the Bech32 human-readable part according to BIP-173. -#define BECH32_MAX_HRP_LEN 83 - - -/** Encode a SegWit address - * - * Out: output: Pointer to a buffer of size 73 + strlen(hrp) that will be - * updated to contain the null-terminated address. - * In: hrp: Pointer to the null-terminated human readable part to use - * (chain/network specific). - * ver: Version of the witness program (between 0 and 16 inclusive). - * prog: Data bytes for the witness program (between 2 and 40 bytes). - * prog_len: Number of data bytes in prog. - * Returns 1 if successful. - */ -int segwit_addr_encode( - char *output, - const char *hrp, - int ver, - const uint8_t *prog, - size_t prog_len -); - -/** Decode a SegWit address - * - * Out: ver: Pointer to an int that will be updated to contain the witness - * program version (between 0 and 16 inclusive). - * prog: Pointer to a buffer of size 40 that will be updated to - * contain the witness program bytes. - * prog_len: Pointer to a size_t that will be updated to contain the length - * of bytes in prog. - * hrp: Pointer to the null-terminated human readable part that is - * expected (chain/network specific). - * addr: Pointer to the null-terminated address. - * Returns 1 if successful. - */ -int segwit_addr_decode( - int* ver, - uint8_t* prog, - size_t* prog_len, - const char* hrp, - const char* addr -); - -/** Supported encodings. */ -typedef enum { - BECH32_ENCODING_NONE, - BECH32_ENCODING_BECH32, - BECH32_ENCODING_BECH32M -} bech32_encoding; - -/** Encode a Bech32 or Bech32m string - * - * Out: output: Pointer to a buffer of size strlen(hrp) + data_len + 8 that - * will be updated to contain the null-terminated Bech32 string. - * In: hrp : Pointer to the null-terminated human readable part. - * data : Pointer to an array of 5-bit values. - * data_len: Length of the data array. - * enc: Which encoding to use (BECH32_ENCODING_BECH32{,M}). - * Returns 1 if successful. - */ -int bech32_encode( - char *output, - const char *hrp, - const uint8_t *data, - size_t data_len, - bech32_encoding enc -); - -/** Decode a Bech32 or Bech32m string - * - * Out: hrp: Pointer to a buffer of size BECH32_MAX_HRP_LEN + 1. Will be - * updated to contain the null-terminated human readable part. - * data: Pointer to a buffer of size strlen(input) - 8 that will - * hold the encoded 5-bit data values. - * data_len: Pointer to a size_t that will be updated to be the number - * of entries in data. - * In: input: Pointer to a null-terminated Bech32 string. - * Returns BECH32_ENCODING_BECH32{,M} to indicate decoding was successful - * with the specified encoding standard. BECH32_ENCODING_NONE is returned if - * decoding failed. - */ -bech32_encoding bech32_decode( - char *hrp, - uint8_t *data, - size_t *data_len, - const char *input -); - -#endif diff --git a/deps/crypto/trezor-crypto/setup.py b/deps/crypto/trezor-crypto/setup.py deleted file mode 100755 index aee3dd4a9..000000000 --- a/deps/crypto/trezor-crypto/setup.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python -from distutils.core import setup -from distutils.extension import Extension - -from Cython.Build import cythonize -from Cython.Distutils import build_ext - -srcs = [ - "nist256p1", - "base58", - "bignum", - "bip32", - "ecdsa", - "curve25519", - "hmac", - "rand", - "ripemd160", - "secp256k1", - "sha2", -] - -extensions = [ - Extension( - "TrezorCrypto", - sources=["TrezorCrypto.pyx", "c.pxd"] + [x + ".c" for x in srcs], - extra_compile_args=[], - ) -] - -setup( - name="TrezorCrypto", - version="0.0.0", - description="Cython wrapper around trezor-crypto library", - author="Pavol Rusnak", - author_email="stick@satoshilabs.com", - url="https://github.com/trezor/trezor-crypto", - cmdclass={"build_ext": build_ext}, - ext_modules=cythonize(extensions), -) diff --git a/deps/crypto/trezor-crypto/sha2.c b/deps/crypto/trezor-crypto/sha2.c deleted file mode 100644 index 5aa0ea38c..000000000 --- a/deps/crypto/trezor-crypto/sha2.c +++ /dev/null @@ -1,1283 +0,0 @@ -/** - * Copyright (c) 2000-2001 Aaron D. Gifford - * Copyright (c) 2013-2014 Pavol Rusnak - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holder nor the names of contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include "sha2.h" -#include "memzero.h" - -/* - * ASSERT NOTE: - * Some sanity checking code is included using assert(). On my FreeBSD - * system, this additional code can be removed by compiling with NDEBUG - * defined. Check your own systems manpage on assert() to see how to - * compile WITHOUT the sanity checking code on your system. - * - * UNROLLED TRANSFORM LOOP NOTE: - * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform - * loop version for the hash transform rounds (defined using macros - * later in this file). Either define on the command line, for example: - * - * cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c - * - * or define below: - * - * #define SHA2_UNROLL_TRANSFORM - * - */ - - -/*** SHA-256/384/512 Machine Architecture Definitions *****************/ -/* - * BYTE_ORDER NOTE: - * - * Please make sure that your system defines BYTE_ORDER. If your - * architecture is little-endian, make sure it also defines - * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are - * equivilent. - * - * If your system does not define the above, then you can do so by - * hand like this: - * - * #define LITTLE_ENDIAN 1234 - * #define BIG_ENDIAN 4321 - * - * And for little-endian machines, add: - * - * #define BYTE_ORDER LITTLE_ENDIAN - * - * Or for big-endian machines: - * - * #define BYTE_ORDER BIG_ENDIAN - * - * The FreeBSD machine this was written on defines BYTE_ORDER - * appropriately by including (which in turn includes - * where the appropriate definitions are actually - * made). - */ - -#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN) -#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN -#endif - -typedef uint8_t sha2_byte; /* Exactly 1 byte */ -typedef uint32_t sha2_word32; /* Exactly 4 bytes */ -typedef uint64_t sha2_word64; /* Exactly 8 bytes */ - -/*** SHA-256/384/512 Various Length Definitions ***********************/ -/* NOTE: Most of these are in sha2.h */ -#define SHA1_SHORT_BLOCK_LENGTH (SHA1_BLOCK_LENGTH - 8) -#define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8) -#define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16) - -/* - * Macro for incrementally adding the unsigned 64-bit integer n to the - * unsigned 128-bit integer (represented using a two-element array of - * 64-bit words): - */ -#define ADDINC128(w,n) { \ - (w)[0] += (sha2_word64)(n); \ - if ((w)[0] < (n)) { \ - (w)[1]++; \ - } \ -} - -#define MEMCPY_BCOPY(d,s,l) memcpy((d), (s), (l)) - -/*** THE SIX LOGICAL FUNCTIONS ****************************************/ -/* - * Bit shifting and rotation (used by the six SHA-XYZ logical functions: - * - * NOTE: In the original SHA-256/384/512 document, the shift-right - * function was named R and the rotate-right function was called S. - * (See: http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf on the - * web.) - * - * The newer NIST FIPS 180-2 document uses a much clearer naming - * scheme, SHR for shift-right, ROTR for rotate-right, and ROTL for - * rotate-left. (See: - * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf - * on the web.) - * - * WARNING: These macros must be used cautiously, since they reference - * supplied parameters sometimes more than once, and thus could have - * unexpected side-effects if used without taking this into account. - */ - -/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */ -#define SHR(b,x) ((x) >> (b)) -/* 32-bit Rotate-right (used in SHA-256): */ -#define ROTR32(b,x) (((x) >> (b)) | ((x) << (32 - (b)))) -/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */ -#define ROTR64(b,x) (((x) >> (b)) | ((x) << (64 - (b)))) -/* 32-bit Rotate-left (used in SHA-1): */ -#define ROTL32(b,x) (((x) << (b)) | ((x) >> (32 - (b)))) - -/* Two of six logical functions used in SHA-1, SHA-256, SHA-384, and SHA-512: */ -#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) -#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) - -/* Function used in SHA-1: */ -#define Parity(x,y,z) ((x) ^ (y) ^ (z)) - -/* Four of six logical functions used in SHA-256: */ -#define Sigma0_256(x) (ROTR32(2, (x)) ^ ROTR32(13, (x)) ^ ROTR32(22, (x))) -#define Sigma1_256(x) (ROTR32(6, (x)) ^ ROTR32(11, (x)) ^ ROTR32(25, (x))) -#define sigma0_256(x) (ROTR32(7, (x)) ^ ROTR32(18, (x)) ^ SHR(3 , (x))) -#define sigma1_256(x) (ROTR32(17, (x)) ^ ROTR32(19, (x)) ^ SHR(10, (x))) - -/* Four of six logical functions used in SHA-384 and SHA-512: */ -#define Sigma0_512(x) (ROTR64(28, (x)) ^ ROTR64(34, (x)) ^ ROTR64(39, (x))) -#define Sigma1_512(x) (ROTR64(14, (x)) ^ ROTR64(18, (x)) ^ ROTR64(41, (x))) -#define sigma0_512(x) (ROTR64( 1, (x)) ^ ROTR64( 8, (x)) ^ SHR( 7, (x))) -#define sigma1_512(x) (ROTR64(19, (x)) ^ ROTR64(61, (x)) ^ SHR( 6, (x))) - -/*** INTERNAL FUNCTION PROTOTYPES *************************************/ -/* NOTE: These should not be accessed directly from outside this - * library -- they are intended for private internal visibility/use - * only. - */ -static void sha512_Last(SHA512_CTX*); - - -/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ - -/* Hash constant words K for SHA-1: */ -#define K1_0_TO_19 0x5a827999UL -#define K1_20_TO_39 0x6ed9eba1UL -#define K1_40_TO_59 0x8f1bbcdcUL -#define K1_60_TO_79 0xca62c1d6UL - -/* Initial hash value H for SHA-1: */ -const sha2_word32 sha1_initial_hash_value[SHA1_DIGEST_LENGTH / sizeof(sha2_word32)] = { - 0x67452301UL, - 0xefcdab89UL, - 0x98badcfeUL, - 0x10325476UL, - 0xc3d2e1f0UL -}; - -/* Hash constant words K for SHA-256: */ -static const sha2_word32 K256[64] = { - 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, - 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, - 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, - 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, - 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, - 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, - 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, - 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, - 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, - 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, - 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, - 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, - 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, - 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, - 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, - 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL -}; - -/* Initial hash value H for SHA-256: */ -const sha2_word32 sha256_initial_hash_value[8] = { - 0x6a09e667UL, - 0xbb67ae85UL, - 0x3c6ef372UL, - 0xa54ff53aUL, - 0x510e527fUL, - 0x9b05688cUL, - 0x1f83d9abUL, - 0x5be0cd19UL -}; - -/* Hash constant words K for SHA-384 and SHA-512: */ -static const sha2_word64 K512[80] = { - 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, - 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, - 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, - 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, - 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, - 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, - 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, - 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, - 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, - 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, - 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, - 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, - 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, - 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, - 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, - 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, - 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, - 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, - 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, - 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, - 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, - 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, - 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, - 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, - 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, - 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, - 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, - 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, - 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, - 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, - 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, - 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, - 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, - 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, - 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, - 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, - 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, - 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, - 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, - 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL -}; - -/* Initial hash value H for SHA-512 */ -const sha2_word64 sha512_initial_hash_value[8] = { - 0x6a09e667f3bcc908ULL, - 0xbb67ae8584caa73bULL, - 0x3c6ef372fe94f82bULL, - 0xa54ff53a5f1d36f1ULL, - 0x510e527fade682d1ULL, - 0x9b05688c2b3e6c1fULL, - 0x1f83d9abfb41bd6bULL, - 0x5be0cd19137e2179ULL -}; - -/* - * Constant used by SHA256/384/512_End() functions for converting the - * digest to a readable hexadecimal character string: - */ -static const char *sha2_hex_digits = "0123456789abcdef"; - - -/*** SHA-1: ***********************************************************/ -void sha1_Init(SHA1_CTX* context) { - MEMCPY_BCOPY(context->state, sha1_initial_hash_value, SHA1_DIGEST_LENGTH); - memzero(context->buffer, SHA1_BLOCK_LENGTH); - context->bitcount = 0; -} - -#ifdef SHA2_UNROLL_TRANSFORM - -/* Unrolled SHA-1 round macros: */ - -#define ROUND1_0_TO_15(a,b,c,d,e) \ - (e) = ROTL32(5, (a)) + Ch((b), (c), (d)) + (e) + \ - K1_0_TO_19 + ( W1[j] = *data++ ); \ - (b) = ROTL32(30, (b)); \ - j++; - -#define ROUND1_16_TO_19(a,b,c,d,e) \ - T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; \ - (e) = ROTL32(5, a) + Ch(b,c,d) + e + K1_0_TO_19 + ( W1[j&0x0f] = ROTL32(1, T1) ); \ - (b) = ROTL32(30, b); \ - j++; - -#define ROUND1_20_TO_39(a,b,c,d,e) \ - T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; \ - (e) = ROTL32(5, a) + Parity(b,c,d) + e + K1_20_TO_39 + ( W1[j&0x0f] = ROTL32(1, T1) ); \ - (b) = ROTL32(30, b); \ - j++; - -#define ROUND1_40_TO_59(a,b,c,d,e) \ - T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; \ - (e) = ROTL32(5, a) + Maj(b,c,d) + e + K1_40_TO_59 + ( W1[j&0x0f] = ROTL32(1, T1) ); \ - (b) = ROTL32(30, b); \ - j++; - -#define ROUND1_60_TO_79(a,b,c,d,e) \ - T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; \ - (e) = ROTL32(5, a) + Parity(b,c,d) + e + K1_60_TO_79 + ( W1[j&0x0f] = ROTL32(1, T1) ); \ - (b) = ROTL32(30, b); \ - j++; - -void sha1_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2_word32* state_out) { - sha2_word32 a = 0, b = 0, c = 0, d = 0, e = 0; - sha2_word32 T1 = 0; - sha2_word32 W1[16] = {0}; - int j = 0; - - /* Initialize registers with the prev. intermediate value */ - a = state_in[0]; - b = state_in[1]; - c = state_in[2]; - d = state_in[3]; - e = state_in[4]; - - j = 0; - - /* Rounds 0 to 15 unrolled: */ - ROUND1_0_TO_15(a,b,c,d,e); - ROUND1_0_TO_15(e,a,b,c,d); - ROUND1_0_TO_15(d,e,a,b,c); - ROUND1_0_TO_15(c,d,e,a,b); - ROUND1_0_TO_15(b,c,d,e,a); - ROUND1_0_TO_15(a,b,c,d,e); - ROUND1_0_TO_15(e,a,b,c,d); - ROUND1_0_TO_15(d,e,a,b,c); - ROUND1_0_TO_15(c,d,e,a,b); - ROUND1_0_TO_15(b,c,d,e,a); - ROUND1_0_TO_15(a,b,c,d,e); - ROUND1_0_TO_15(e,a,b,c,d); - ROUND1_0_TO_15(d,e,a,b,c); - ROUND1_0_TO_15(c,d,e,a,b); - ROUND1_0_TO_15(b,c,d,e,a); - ROUND1_0_TO_15(a,b,c,d,e); - - /* Rounds 16 to 19 unrolled: */ - ROUND1_16_TO_19(e,a,b,c,d); - ROUND1_16_TO_19(d,e,a,b,c); - ROUND1_16_TO_19(c,d,e,a,b); - ROUND1_16_TO_19(b,c,d,e,a); - - /* Rounds 20 to 39 unrolled: */ - ROUND1_20_TO_39(a,b,c,d,e); - ROUND1_20_TO_39(e,a,b,c,d); - ROUND1_20_TO_39(d,e,a,b,c); - ROUND1_20_TO_39(c,d,e,a,b); - ROUND1_20_TO_39(b,c,d,e,a); - ROUND1_20_TO_39(a,b,c,d,e); - ROUND1_20_TO_39(e,a,b,c,d); - ROUND1_20_TO_39(d,e,a,b,c); - ROUND1_20_TO_39(c,d,e,a,b); - ROUND1_20_TO_39(b,c,d,e,a); - ROUND1_20_TO_39(a,b,c,d,e); - ROUND1_20_TO_39(e,a,b,c,d); - ROUND1_20_TO_39(d,e,a,b,c); - ROUND1_20_TO_39(c,d,e,a,b); - ROUND1_20_TO_39(b,c,d,e,a); - ROUND1_20_TO_39(a,b,c,d,e); - ROUND1_20_TO_39(e,a,b,c,d); - ROUND1_20_TO_39(d,e,a,b,c); - ROUND1_20_TO_39(c,d,e,a,b); - ROUND1_20_TO_39(b,c,d,e,a); - - /* Rounds 40 to 59 unrolled: */ - ROUND1_40_TO_59(a,b,c,d,e); - ROUND1_40_TO_59(e,a,b,c,d); - ROUND1_40_TO_59(d,e,a,b,c); - ROUND1_40_TO_59(c,d,e,a,b); - ROUND1_40_TO_59(b,c,d,e,a); - ROUND1_40_TO_59(a,b,c,d,e); - ROUND1_40_TO_59(e,a,b,c,d); - ROUND1_40_TO_59(d,e,a,b,c); - ROUND1_40_TO_59(c,d,e,a,b); - ROUND1_40_TO_59(b,c,d,e,a); - ROUND1_40_TO_59(a,b,c,d,e); - ROUND1_40_TO_59(e,a,b,c,d); - ROUND1_40_TO_59(d,e,a,b,c); - ROUND1_40_TO_59(c,d,e,a,b); - ROUND1_40_TO_59(b,c,d,e,a); - ROUND1_40_TO_59(a,b,c,d,e); - ROUND1_40_TO_59(e,a,b,c,d); - ROUND1_40_TO_59(d,e,a,b,c); - ROUND1_40_TO_59(c,d,e,a,b); - ROUND1_40_TO_59(b,c,d,e,a); - - /* Rounds 60 to 79 unrolled: */ - ROUND1_60_TO_79(a,b,c,d,e); - ROUND1_60_TO_79(e,a,b,c,d); - ROUND1_60_TO_79(d,e,a,b,c); - ROUND1_60_TO_79(c,d,e,a,b); - ROUND1_60_TO_79(b,c,d,e,a); - ROUND1_60_TO_79(a,b,c,d,e); - ROUND1_60_TO_79(e,a,b,c,d); - ROUND1_60_TO_79(d,e,a,b,c); - ROUND1_60_TO_79(c,d,e,a,b); - ROUND1_60_TO_79(b,c,d,e,a); - ROUND1_60_TO_79(a,b,c,d,e); - ROUND1_60_TO_79(e,a,b,c,d); - ROUND1_60_TO_79(d,e,a,b,c); - ROUND1_60_TO_79(c,d,e,a,b); - ROUND1_60_TO_79(b,c,d,e,a); - ROUND1_60_TO_79(a,b,c,d,e); - ROUND1_60_TO_79(e,a,b,c,d); - ROUND1_60_TO_79(d,e,a,b,c); - ROUND1_60_TO_79(c,d,e,a,b); - ROUND1_60_TO_79(b,c,d,e,a); - - /* Compute the current intermediate hash value */ - state_out[0] = state_in[0] + a; - state_out[1] = state_in[1] + b; - state_out[2] = state_in[2] + c; - state_out[3] = state_in[3] + d; - state_out[4] = state_in[4] + e; - - /* Clean up */ - a = b = c = d = e = T1 = 0; -} - -#else /* SHA2_UNROLL_TRANSFORM */ - -void sha1_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2_word32* state_out) { - sha2_word32 a = 0, b = 0, c = 0, d = 0, e = 0; - sha2_word32 T1 = 0; - sha2_word32 W1[16] = {0}; - int j = 0; - - /* Initialize registers with the prev. intermediate value */ - a = state_in[0]; - b = state_in[1]; - c = state_in[2]; - d = state_in[3]; - e = state_in[4]; - j = 0; - do { - T1 = ROTL32(5, a) + Ch(b, c, d) + e + K1_0_TO_19 + (W1[j] = *data++); - e = d; - d = c; - c = ROTL32(30, b); - b = a; - a = T1; - j++; - } while (j < 16); - - do { - T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; - T1 = ROTL32(5, a) + Ch(b,c,d) + e + K1_0_TO_19 + (W1[j&0x0f] = ROTL32(1, T1)); - e = d; - d = c; - c = ROTL32(30, b); - b = a; - a = T1; - j++; - } while (j < 20); - - do { - T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; - T1 = ROTL32(5, a) + Parity(b,c,d) + e + K1_20_TO_39 + (W1[j&0x0f] = ROTL32(1, T1)); - e = d; - d = c; - c = ROTL32(30, b); - b = a; - a = T1; - j++; - } while (j < 40); - - do { - T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; - T1 = ROTL32(5, a) + Maj(b,c,d) + e + K1_40_TO_59 + (W1[j&0x0f] = ROTL32(1, T1)); - e = d; - d = c; - c = ROTL32(30, b); - b = a; - a = T1; - j++; - } while (j < 60); - - do { - T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; - T1 = ROTL32(5, a) + Parity(b,c,d) + e + K1_60_TO_79 + (W1[j&0x0f] = ROTL32(1, T1)); - e = d; - d = c; - c = ROTL32(30, b); - b = a; - a = T1; - j++; - } while (j < 80); - - - /* Compute the current intermediate hash value */ - state_out[0] = state_in[0] + a; - state_out[1] = state_in[1] + b; - state_out[2] = state_in[2] + c; - state_out[3] = state_in[3] + d; - state_out[4] = state_in[4] + e; - - /* Clean up */ - a = b = c = d = e = T1 = 0; -} - -#endif /* SHA2_UNROLL_TRANSFORM */ - -void sha1_Update(SHA1_CTX* context, const sha2_byte *data, size_t len) { - unsigned int freespace = 0, usedspace = 0; - - if (len == 0) { - /* Calling with no data is valid - we do nothing */ - return; - } - - usedspace = (context->bitcount >> 3) % SHA1_BLOCK_LENGTH; - if (usedspace > 0) { - /* Calculate how much free space is available in the buffer */ - freespace = SHA1_BLOCK_LENGTH - usedspace; - - if (len >= freespace) { - /* Fill the buffer completely and process it */ - MEMCPY_BCOPY(((uint8_t*)context->buffer) + usedspace, data, freespace); - context->bitcount += freespace << 3; - len -= freespace; - data += freespace; -#if BYTE_ORDER == LITTLE_ENDIAN - /* Convert TO host byte order */ - for (int j = 0; j < 16; j++) { - REVERSE32(context->buffer[j],context->buffer[j]); - } -#endif - sha1_Transform(context->state, context->buffer, context->state); - } else { - /* The buffer is not yet full */ - MEMCPY_BCOPY(((uint8_t*)context->buffer) + usedspace, data, len); - context->bitcount += len << 3; - /* Clean up: */ - usedspace = freespace = 0; - return; - } - } - while (len >= SHA1_BLOCK_LENGTH) { - /* Process as many complete blocks as we can */ - MEMCPY_BCOPY(context->buffer, data, SHA1_BLOCK_LENGTH); -#if BYTE_ORDER == LITTLE_ENDIAN - /* Convert TO host byte order */ - for (int j = 0; j < 16; j++) { - REVERSE32(context->buffer[j],context->buffer[j]); - } -#endif - sha1_Transform(context->state, context->buffer, context->state); - context->bitcount += SHA1_BLOCK_LENGTH << 3; - len -= SHA1_BLOCK_LENGTH; - data += SHA1_BLOCK_LENGTH; - } - if (len > 0) { - /* There's left-overs, so save 'em */ - MEMCPY_BCOPY(context->buffer, data, len); - context->bitcount += len << 3; - } - /* Clean up: */ - usedspace = freespace = 0; -} - -void sha1_Final(SHA1_CTX* context, sha2_byte digest[SHA1_DIGEST_LENGTH]) { - unsigned int usedspace = 0; - - /* If no digest buffer is passed, we don't bother doing this: */ - if (digest != (sha2_byte*)0) { - usedspace = (context->bitcount >> 3) % SHA1_BLOCK_LENGTH; - /* Begin padding with a 1 bit: */ - ((uint8_t*)context->buffer)[usedspace++] = 0x80; - - if (usedspace > SHA1_SHORT_BLOCK_LENGTH) { - memzero(((uint8_t*)context->buffer) + usedspace, SHA1_BLOCK_LENGTH - usedspace); - -#if BYTE_ORDER == LITTLE_ENDIAN - /* Convert TO host byte order */ - for (int j = 0; j < 16; j++) { - REVERSE32(context->buffer[j],context->buffer[j]); - } -#endif - /* Do second-to-last transform: */ - sha1_Transform(context->state, context->buffer, context->state); - - /* And prepare the last transform: */ - usedspace = 0; - } - /* Set-up for the last transform: */ - memzero(((uint8_t*)context->buffer) + usedspace, SHA1_SHORT_BLOCK_LENGTH - usedspace); - -#if BYTE_ORDER == LITTLE_ENDIAN - /* Convert TO host byte order */ - for (int j = 0; j < 14; j++) { - REVERSE32(context->buffer[j],context->buffer[j]); - } -#endif - /* Set the bit count: */ - context->buffer[14] = context->bitcount >> 32; - context->buffer[15] = context->bitcount & 0xffffffff; - - /* Final transform: */ - sha1_Transform(context->state, context->buffer, context->state); - -#if BYTE_ORDER == LITTLE_ENDIAN - /* Convert FROM host byte order */ - for (int j = 0; j < 5; j++) { - REVERSE32(context->state[j],context->state[j]); - } -#endif - MEMCPY_BCOPY(digest, context->state, SHA1_DIGEST_LENGTH); - } - - /* Clean up state data: */ - memzero(context, sizeof(SHA1_CTX)); - usedspace = 0; -} - -char *sha1_End(SHA1_CTX* context, char buffer[SHA1_DIGEST_STRING_LENGTH]) { - sha2_byte digest[SHA1_DIGEST_LENGTH] = {0}, *d = digest; - int i = 0; - - if (buffer != (char*)0) { - sha1_Final(context, digest); - - for (i = 0; i < SHA1_DIGEST_LENGTH; i++) { - *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; - *buffer++ = sha2_hex_digits[*d & 0x0f]; - d++; - } - *buffer = (char)0; - } else { - memzero(context, sizeof(SHA1_CTX)); - } - memzero(digest, SHA1_DIGEST_LENGTH); - return buffer; -} - -void sha1_Raw(const sha2_byte* data, size_t len, uint8_t digest[SHA1_DIGEST_LENGTH]) { - SHA1_CTX context = {0}; - sha1_Init(&context); - sha1_Update(&context, data, len); - sha1_Final(&context, digest); -} - -char* sha1_Data(const sha2_byte* data, size_t len, char digest[SHA1_DIGEST_STRING_LENGTH]) { - SHA1_CTX context = {0}; - - sha1_Init(&context); - sha1_Update(&context, data, len); - return sha1_End(&context, digest); -} - -/*** SHA-256: *********************************************************/ -void sha256_Init(SHA256_CTX* context) { - if (context == (SHA256_CTX*)0) { - return; - } - MEMCPY_BCOPY(context->state, sha256_initial_hash_value, SHA256_DIGEST_LENGTH); - memzero(context->buffer, SHA256_BLOCK_LENGTH); - context->bitcount = 0; -} - -#ifdef SHA2_UNROLL_TRANSFORM - -/* Unrolled SHA-256 round macros: */ - -#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ - T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ - K256[j] + (W256[j] = *data++); \ - (d) += T1; \ - (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ - j++ - -#define ROUND256(a,b,c,d,e,f,g,h) \ - s0 = W256[(j+1)&0x0f]; \ - s0 = sigma0_256(s0); \ - s1 = W256[(j+14)&0x0f]; \ - s1 = sigma1_256(s1); \ - T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \ - (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \ - (d) += T1; \ - (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ - j++ - -void sha256_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2_word32* state_out) { - sha2_word32 a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0, s0 = 0, s1 = 0; - sha2_word32 T1 = 0; - sha2_word32 W256[16] = {0}; - int j = 0; - - /* Initialize registers with the prev. intermediate value */ - a = state_in[0]; - b = state_in[1]; - c = state_in[2]; - d = state_in[3]; - e = state_in[4]; - f = state_in[5]; - g = state_in[6]; - h = state_in[7]; - - j = 0; - do { - /* Rounds 0 to 15 (unrolled): */ - ROUND256_0_TO_15(a,b,c,d,e,f,g,h); - ROUND256_0_TO_15(h,a,b,c,d,e,f,g); - ROUND256_0_TO_15(g,h,a,b,c,d,e,f); - ROUND256_0_TO_15(f,g,h,a,b,c,d,e); - ROUND256_0_TO_15(e,f,g,h,a,b,c,d); - ROUND256_0_TO_15(d,e,f,g,h,a,b,c); - ROUND256_0_TO_15(c,d,e,f,g,h,a,b); - ROUND256_0_TO_15(b,c,d,e,f,g,h,a); - } while (j < 16); - - /* Now for the remaining rounds to 64: */ - do { - ROUND256(a,b,c,d,e,f,g,h); - ROUND256(h,a,b,c,d,e,f,g); - ROUND256(g,h,a,b,c,d,e,f); - ROUND256(f,g,h,a,b,c,d,e); - ROUND256(e,f,g,h,a,b,c,d); - ROUND256(d,e,f,g,h,a,b,c); - ROUND256(c,d,e,f,g,h,a,b); - ROUND256(b,c,d,e,f,g,h,a); - } while (j < 64); - - /* Compute the current intermediate hash value */ - state_out[0] = state_in[0] + a; - state_out[1] = state_in[1] + b; - state_out[2] = state_in[2] + c; - state_out[3] = state_in[3] + d; - state_out[4] = state_in[4] + e; - state_out[5] = state_in[5] + f; - state_out[6] = state_in[6] + g; - state_out[7] = state_in[7] + h; - - /* Clean up */ - a = b = c = d = e = f = g = h = T1 = 0; -} - -#else /* SHA2_UNROLL_TRANSFORM */ - -void sha256_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2_word32* state_out) { - sha2_word32 a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0, s0 = 0, s1 = 0; - sha2_word32 T1 = 0, T2 = 0 , W256[16] = {0}; - int j = 0; - - /* Initialize registers with the prev. intermediate value */ - a = state_in[0]; - b = state_in[1]; - c = state_in[2]; - d = state_in[3]; - e = state_in[4]; - f = state_in[5]; - g = state_in[6]; - h = state_in[7]; - - j = 0; - do { - /* Apply the SHA-256 compression function to update a..h with copy */ - T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++); - T2 = Sigma0_256(a) + Maj(a, b, c); - h = g; - g = f; - f = e; - e = d + T1; - d = c; - c = b; - b = a; - a = T1 + T2; - - j++; - } while (j < 16); - - do { - /* Part of the message block expansion: */ - s0 = W256[(j+1)&0x0f]; - s0 = sigma0_256(s0); - s1 = W256[(j+14)&0x0f]; - s1 = sigma1_256(s1); - - /* Apply the SHA-256 compression function to update a..h */ - T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + - (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); - T2 = Sigma0_256(a) + Maj(a, b, c); - h = g; - g = f; - f = e; - e = d + T1; - d = c; - c = b; - b = a; - a = T1 + T2; - - j++; - } while (j < 64); - - /* Compute the current intermediate hash value */ - state_out[0] = state_in[0] + a; - state_out[1] = state_in[1] + b; - state_out[2] = state_in[2] + c; - state_out[3] = state_in[3] + d; - state_out[4] = state_in[4] + e; - state_out[5] = state_in[5] + f; - state_out[6] = state_in[6] + g; - state_out[7] = state_in[7] + h; - - /* Clean up */ - a = b = c = d = e = f = g = h = T1 = T2 = 0; -} - -#endif /* SHA2_UNROLL_TRANSFORM */ - -void sha256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { - unsigned int freespace = 0, usedspace = 0; - - if (len == 0) { - /* Calling with no data is valid - we do nothing */ - return; - } - - usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; - if (usedspace > 0) { - /* Calculate how much free space is available in the buffer */ - freespace = SHA256_BLOCK_LENGTH - usedspace; - - if (len >= freespace) { - /* Fill the buffer completely and process it */ - MEMCPY_BCOPY(((uint8_t*)context->buffer) + usedspace, data, freespace); - context->bitcount += freespace << 3; - len -= freespace; - data += freespace; -#if BYTE_ORDER == LITTLE_ENDIAN - /* Convert TO host byte order */ - for (int j = 0; j < 16; j++) { - REVERSE32(context->buffer[j],context->buffer[j]); - } -#endif - sha256_Transform(context->state, context->buffer, context->state); - } else { - /* The buffer is not yet full */ - MEMCPY_BCOPY(((uint8_t*)context->buffer) + usedspace, data, len); - context->bitcount += len << 3; - /* Clean up: */ - usedspace = freespace = 0; - return; - } - } - while (len >= SHA256_BLOCK_LENGTH) { - /* Process as many complete blocks as we can */ - MEMCPY_BCOPY(context->buffer, data, SHA256_BLOCK_LENGTH); -#if BYTE_ORDER == LITTLE_ENDIAN - /* Convert TO host byte order */ - for (int j = 0; j < 16; j++) { - REVERSE32(context->buffer[j],context->buffer[j]); - } -#endif - sha256_Transform(context->state, context->buffer, context->state); - context->bitcount += SHA256_BLOCK_LENGTH << 3; - len -= SHA256_BLOCK_LENGTH; - data += SHA256_BLOCK_LENGTH; - } - if (len > 0) { - /* There's left-overs, so save 'em */ - MEMCPY_BCOPY(context->buffer, data, len); - context->bitcount += len << 3; - } - /* Clean up: */ - usedspace = freespace = 0; -} - -void sha256_Final(SHA256_CTX* context, sha2_byte digest[SHA256_DIGEST_LENGTH]) { - unsigned int usedspace = 0; - - /* If no digest buffer is passed, we don't bother doing this: */ - if (digest != (sha2_byte*)0) { - usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; - /* Begin padding with a 1 bit: */ - ((uint8_t*)context->buffer)[usedspace++] = 0x80; - - if (usedspace > SHA256_SHORT_BLOCK_LENGTH) { - memzero(((uint8_t*)context->buffer) + usedspace, SHA256_BLOCK_LENGTH - usedspace); - -#if BYTE_ORDER == LITTLE_ENDIAN - /* Convert TO host byte order */ - for (int j = 0; j < 16; j++) { - REVERSE32(context->buffer[j],context->buffer[j]); - } -#endif - /* Do second-to-last transform: */ - sha256_Transform(context->state, context->buffer, context->state); - - /* And prepare the last transform: */ - usedspace = 0; - } - /* Set-up for the last transform: */ - memzero(((uint8_t*)context->buffer) + usedspace, SHA256_SHORT_BLOCK_LENGTH - usedspace); - -#if BYTE_ORDER == LITTLE_ENDIAN - /* Convert TO host byte order */ - for (int j = 0; j < 14; j++) { - REVERSE32(context->buffer[j],context->buffer[j]); - } -#endif - /* Set the bit count: */ - context->buffer[14] = context->bitcount >> 32; - context->buffer[15] = context->bitcount & 0xffffffff; - - /* Final transform: */ - sha256_Transform(context->state, context->buffer, context->state); - -#if BYTE_ORDER == LITTLE_ENDIAN - /* Convert FROM host byte order */ - for (int j = 0; j < 8; j++) { - REVERSE32(context->state[j],context->state[j]); - } -#endif - MEMCPY_BCOPY(digest, context->state, SHA256_DIGEST_LENGTH); - } - - /* Clean up state data: */ - memzero(context, sizeof(SHA256_CTX)); - usedspace = 0; -} - -char *sha256_End(SHA256_CTX* context, char buffer[SHA256_DIGEST_STRING_LENGTH]) { - sha2_byte digest[SHA256_DIGEST_LENGTH] = {0}, *d = digest; - int i = 0; - - if (buffer != (char*)0) { - sha256_Final(context, digest); - - for (i = 0; i < SHA256_DIGEST_LENGTH; i++) { - *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; - *buffer++ = sha2_hex_digits[*d & 0x0f]; - d++; - } - *buffer = (char)0; - } else { - memzero(context, sizeof(SHA256_CTX)); - } - memzero(digest, SHA256_DIGEST_LENGTH); - return buffer; -} - -void sha256_Raw(const sha2_byte* data, size_t len, uint8_t digest[SHA256_DIGEST_LENGTH]) { - SHA256_CTX context = {0}; - sha256_Init(&context); - sha256_Update(&context, data, len); - sha256_Final(&context, digest); -} - -char* sha256_Data(const sha2_byte* data, size_t len, char digest[SHA256_DIGEST_STRING_LENGTH]) { - SHA256_CTX context = {0}; - - sha256_Init(&context); - sha256_Update(&context, data, len); - return sha256_End(&context, digest); -} - - -/*** SHA-512: *********************************************************/ -void sha512_Init(SHA512_CTX* context) { - if (context == (SHA512_CTX*)0) { - return; - } - MEMCPY_BCOPY(context->state, sha512_initial_hash_value, SHA512_DIGEST_LENGTH); - memzero(context->buffer, SHA512_BLOCK_LENGTH); - context->bitcount[0] = context->bitcount[1] = 0; -} - -#ifdef SHA2_UNROLL_TRANSFORM - -/* Unrolled SHA-512 round macros: */ -#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ - T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ - K512[j] + (W512[j] = *data++); \ - (d) += T1; \ - (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ - j++ - -#define ROUND512(a,b,c,d,e,f,g,h) \ - s0 = W512[(j+1)&0x0f]; \ - s0 = sigma0_512(s0); \ - s1 = W512[(j+14)&0x0f]; \ - s1 = sigma1_512(s1); \ - T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \ - (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \ - (d) += T1; \ - (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ - j++ - -void sha512_Transform(const sha2_word64* state_in, const sha2_word64* data, sha2_word64* state_out) { - sha2_word64 a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0, s0 = 0, s1 = 0; - sha2_word64 T1 = 0, W512[16] = {0}; - int j = 0; - - /* Initialize registers with the prev. intermediate value */ - a = state_in[0]; - b = state_in[1]; - c = state_in[2]; - d = state_in[3]; - e = state_in[4]; - f = state_in[5]; - g = state_in[6]; - h = state_in[7]; - - j = 0; - do { - ROUND512_0_TO_15(a,b,c,d,e,f,g,h); - ROUND512_0_TO_15(h,a,b,c,d,e,f,g); - ROUND512_0_TO_15(g,h,a,b,c,d,e,f); - ROUND512_0_TO_15(f,g,h,a,b,c,d,e); - ROUND512_0_TO_15(e,f,g,h,a,b,c,d); - ROUND512_0_TO_15(d,e,f,g,h,a,b,c); - ROUND512_0_TO_15(c,d,e,f,g,h,a,b); - ROUND512_0_TO_15(b,c,d,e,f,g,h,a); - } while (j < 16); - - /* Now for the remaining rounds up to 79: */ - do { - ROUND512(a,b,c,d,e,f,g,h); - ROUND512(h,a,b,c,d,e,f,g); - ROUND512(g,h,a,b,c,d,e,f); - ROUND512(f,g,h,a,b,c,d,e); - ROUND512(e,f,g,h,a,b,c,d); - ROUND512(d,e,f,g,h,a,b,c); - ROUND512(c,d,e,f,g,h,a,b); - ROUND512(b,c,d,e,f,g,h,a); - } while (j < 80); - - /* Compute the current intermediate hash value */ - state_out[0] = state_in[0] + a; - state_out[1] = state_in[1] + b; - state_out[2] = state_in[2] + c; - state_out[3] = state_in[3] + d; - state_out[4] = state_in[4] + e; - state_out[5] = state_in[5] + f; - state_out[6] = state_in[6] + g; - state_out[7] = state_in[7] + h; - - /* Clean up */ - a = b = c = d = e = f = g = h = T1 = 0; -} - -#else /* SHA2_UNROLL_TRANSFORM */ - -void sha512_Transform(const sha2_word64* state_in, const sha2_word64* data, sha2_word64* state_out) { - sha2_word64 a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0, s0 = 0, s1 = 0; - sha2_word64 T1 = 0, T2 = 0, W512[16] = {0}; - int j = 0; - - /* Initialize registers with the prev. intermediate value */ - a = state_in[0]; - b = state_in[1]; - c = state_in[2]; - d = state_in[3]; - e = state_in[4]; - f = state_in[5]; - g = state_in[6]; - h = state_in[7]; - - j = 0; - do { - /* Apply the SHA-512 compression function to update a..h with copy */ - T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++); - T2 = Sigma0_512(a) + Maj(a, b, c); - h = g; - g = f; - f = e; - e = d + T1; - d = c; - c = b; - b = a; - a = T1 + T2; - - j++; - } while (j < 16); - - do { - /* Part of the message block expansion: */ - s0 = W512[(j+1)&0x0f]; - s0 = sigma0_512(s0); - s1 = W512[(j+14)&0x0f]; - s1 = sigma1_512(s1); - - /* Apply the SHA-512 compression function to update a..h */ - T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + - (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); - T2 = Sigma0_512(a) + Maj(a, b, c); - h = g; - g = f; - f = e; - e = d + T1; - d = c; - c = b; - b = a; - a = T1 + T2; - - j++; - } while (j < 80); - - /* Compute the current intermediate hash value */ - state_out[0] = state_in[0] + a; - state_out[1] = state_in[1] + b; - state_out[2] = state_in[2] + c; - state_out[3] = state_in[3] + d; - state_out[4] = state_in[4] + e; - state_out[5] = state_in[5] + f; - state_out[6] = state_in[6] + g; - state_out[7] = state_in[7] + h; - - /* Clean up */ - a = b = c = d = e = f = g = h = T1 = T2 = 0; -} - -#endif /* SHA2_UNROLL_TRANSFORM */ - -void sha512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { - unsigned int freespace = 0, usedspace = 0; - - if (len == 0) { - /* Calling with no data is valid - we do nothing */ - return; - } - - usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; - if (usedspace > 0) { - /* Calculate how much free space is available in the buffer */ - freespace = SHA512_BLOCK_LENGTH - usedspace; - - if (len >= freespace) { - /* Fill the buffer completely and process it */ - MEMCPY_BCOPY(((uint8_t*)context->buffer) + usedspace, data, freespace); - ADDINC128(context->bitcount, freespace << 3); - len -= freespace; - data += freespace; -#if BYTE_ORDER == LITTLE_ENDIAN - /* Convert TO host byte order */ - for (int j = 0; j < 16; j++) { - REVERSE64(context->buffer[j],context->buffer[j]); - } -#endif - sha512_Transform(context->state, context->buffer, context->state); - } else { - /* The buffer is not yet full */ - MEMCPY_BCOPY(((uint8_t*)context->buffer) + usedspace, data, len); - ADDINC128(context->bitcount, len << 3); - /* Clean up: */ - usedspace = freespace = 0; - return; - } - } - while (len >= SHA512_BLOCK_LENGTH) { - /* Process as many complete blocks as we can */ - MEMCPY_BCOPY(context->buffer, data, SHA512_BLOCK_LENGTH); -#if BYTE_ORDER == LITTLE_ENDIAN - /* Convert TO host byte order */ - for (int j = 0; j < 16; j++) { - REVERSE64(context->buffer[j],context->buffer[j]); - } -#endif - sha512_Transform(context->state, context->buffer, context->state); - ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3); - len -= SHA512_BLOCK_LENGTH; - data += SHA512_BLOCK_LENGTH; - } - if (len > 0) { - /* There's left-overs, so save 'em */ - MEMCPY_BCOPY(context->buffer, data, len); - ADDINC128(context->bitcount, len << 3); - } - /* Clean up: */ - usedspace = freespace = 0; -} - -static void sha512_Last(SHA512_CTX* context) { - unsigned int usedspace = 0; - - usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; - /* Begin padding with a 1 bit: */ - ((uint8_t*)context->buffer)[usedspace++] = 0x80; - - if (usedspace > SHA512_SHORT_BLOCK_LENGTH) { - memzero(((uint8_t*)context->buffer) + usedspace, SHA512_BLOCK_LENGTH - usedspace); - -#if BYTE_ORDER == LITTLE_ENDIAN - /* Convert TO host byte order */ - for (int j = 0; j < 16; j++) { - REVERSE64(context->buffer[j],context->buffer[j]); - } -#endif - /* Do second-to-last transform: */ - sha512_Transform(context->state, context->buffer, context->state); - - /* And prepare the last transform: */ - usedspace = 0; - } - /* Set-up for the last transform: */ - memzero(((uint8_t*)context->buffer) + usedspace, SHA512_SHORT_BLOCK_LENGTH - usedspace); - -#if BYTE_ORDER == LITTLE_ENDIAN - /* Convert TO host byte order */ - for (int j = 0; j < 14; j++) { - REVERSE64(context->buffer[j],context->buffer[j]); - } -#endif - /* Store the length of input data (in bits): */ - context->buffer[14] = context->bitcount[1]; - context->buffer[15] = context->bitcount[0]; - - /* Final transform: */ - sha512_Transform(context->state, context->buffer, context->state); -} - -void sha512_Final(SHA512_CTX* context, sha2_byte digest[SHA512_DIGEST_LENGTH]) { - /* If no digest buffer is passed, we don't bother doing this: */ - if (digest != (sha2_byte*)0) { - sha512_Last(context); - - /* Save the hash data for output: */ -#if BYTE_ORDER == LITTLE_ENDIAN - /* Convert FROM host byte order */ - for (int j = 0; j < 8; j++) { - REVERSE64(context->state[j],context->state[j]); - } -#endif - MEMCPY_BCOPY(digest, context->state, SHA512_DIGEST_LENGTH); - } - - /* Zero out state data */ - memzero(context, sizeof(SHA512_CTX)); -} - -char *sha512_End(SHA512_CTX* context, char buffer[SHA512_DIGEST_STRING_LENGTH]) { - sha2_byte digest[SHA512_DIGEST_LENGTH] = {0}, *d = digest; - int i = 0; - - if (buffer != (char*)0) { - sha512_Final(context, digest); - - for (i = 0; i < SHA512_DIGEST_LENGTH; i++) { - *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; - *buffer++ = sha2_hex_digits[*d & 0x0f]; - d++; - } - *buffer = (char)0; - } else { - memzero(context, sizeof(SHA512_CTX)); - } - memzero(digest, SHA512_DIGEST_LENGTH); - return buffer; -} - -void sha512_Raw(const sha2_byte* data, size_t len, uint8_t digest[SHA512_DIGEST_LENGTH]) { - SHA512_CTX context = {0}; - sha512_Init(&context); - sha512_Update(&context, data, len); - sha512_Final(&context, digest); -} - -char* sha512_Data(const sha2_byte* data, size_t len, char digest[SHA512_DIGEST_STRING_LENGTH]) { - SHA512_CTX context = {0}; - - sha512_Init(&context); - sha512_Update(&context, data, len); - return sha512_End(&context, digest); -} diff --git a/deps/crypto/trezor-crypto/sha2.h b/deps/crypto/trezor-crypto/sha2.h deleted file mode 100644 index 7f519c50b..000000000 --- a/deps/crypto/trezor-crypto/sha2.h +++ /dev/null @@ -1,116 +0,0 @@ -/** - * Copyright (c) 2000-2001 Aaron D. Gifford - * Copyright (c) 2013-2014 Pavol Rusnak - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holder nor the names of contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef __SHA2_H__ -#define __SHA2_H__ - -#include -#include - -#define SHA1_BLOCK_LENGTH 64 -#define SHA1_DIGEST_LENGTH 20 -#define SHA1_DIGEST_STRING_LENGTH (SHA1_DIGEST_LENGTH * 2 + 1) -#define SHA256_BLOCK_LENGTH 64 -#define SHA256_DIGEST_LENGTH 32 -#define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) -#define SHA512_BLOCK_LENGTH 128 -#define SHA512_DIGEST_LENGTH 64 -#define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) - -typedef struct _SHA1_CTX { - uint32_t state[5]; - uint64_t bitcount; - uint32_t buffer[SHA1_BLOCK_LENGTH/sizeof(uint32_t)]; -} SHA1_CTX; -typedef struct _SHA256_CTX { - uint32_t state[8]; - uint64_t bitcount; - uint32_t buffer[SHA256_BLOCK_LENGTH/sizeof(uint32_t)]; -} SHA256_CTX; -typedef struct _SHA512_CTX { - uint64_t state[8]; - uint64_t bitcount[2]; - uint64_t buffer[SHA512_BLOCK_LENGTH/sizeof(uint64_t)]; -} SHA512_CTX; - -/*** ENDIAN REVERSAL MACROS *******************************************/ -#ifndef LITTLE_ENDIAN -#define LITTLE_ENDIAN 1234 -#define BIG_ENDIAN 4321 -#endif - -#ifndef BYTE_ORDER -#define BYTE_ORDER LITTLE_ENDIAN -#endif - -#if BYTE_ORDER == LITTLE_ENDIAN -#define REVERSE32(w,x) { \ - uint32_t tmp = (w); \ - tmp = (tmp >> 16) | (tmp << 16); \ - (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \ -} -#define REVERSE64(w,x) { \ - uint64_t tmp = (w); \ - tmp = (tmp >> 32) | (tmp << 32); \ - tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \ - ((tmp & 0x00ff00ff00ff00ffULL) << 8); \ - (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \ - ((tmp & 0x0000ffff0000ffffULL) << 16); \ -} -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ - -extern const uint32_t sha256_initial_hash_value[8]; -extern const uint64_t sha512_initial_hash_value[8]; - -void sha1_Transform(const uint32_t* state_in, const uint32_t* data, uint32_t* state_out); -void sha1_Init(SHA1_CTX *); -void sha1_Update(SHA1_CTX*, const uint8_t*, size_t); -void sha1_Final(SHA1_CTX*, uint8_t[SHA1_DIGEST_LENGTH]); -char* sha1_End(SHA1_CTX*, char[SHA1_DIGEST_STRING_LENGTH]); -void sha1_Raw(const uint8_t*, size_t, uint8_t[SHA1_DIGEST_LENGTH]); -char* sha1_Data(const uint8_t*, size_t, char[SHA1_DIGEST_STRING_LENGTH]); - -void sha256_Transform(const uint32_t* state_in, const uint32_t* data, uint32_t* state_out); -void sha256_Init(SHA256_CTX *); -void sha256_Update(SHA256_CTX*, const uint8_t*, size_t); -void sha256_Final(SHA256_CTX*, uint8_t[SHA256_DIGEST_LENGTH]); -char* sha256_End(SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]); -void sha256_Raw(const uint8_t*, size_t, uint8_t[SHA256_DIGEST_LENGTH]); -char* sha256_Data(const uint8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]); - -void sha512_Transform(const uint64_t* state_in, const uint64_t* data, uint64_t* state_out); -void sha512_Init(SHA512_CTX*); -void sha512_Update(SHA512_CTX*, const uint8_t*, size_t); -void sha512_Final(SHA512_CTX*, uint8_t[SHA512_DIGEST_LENGTH]); -char* sha512_End(SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH]); -void sha512_Raw(const uint8_t*, size_t, uint8_t[SHA512_DIGEST_LENGTH]); -char* sha512_Data(const uint8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH]); - -#endif diff --git a/deps/crypto/trezor-crypto/sha3.c b/deps/crypto/trezor-crypto/sha3.c deleted file mode 100644 index 0a6eb4405..000000000 --- a/deps/crypto/trezor-crypto/sha3.c +++ /dev/null @@ -1,399 +0,0 @@ -/* sha3.c - an implementation of Secure Hash Algorithm 3 (Keccak). - * based on the - * The Keccak SHA-3 submission. Submission to NIST (Round 3), 2011 - * by Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche - * - * Copyright: 2013 Aleksey Kravchenko - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk! - */ - -#include -#include - -#include "sha3.h" -#include "memzero.h" - -#define I64(x) x##LL -#define ROTL64(qword, n) ((qword) << (n) ^ ((qword) >> (64 - (n)))) -#define le2me_64(x) (x) -#define IS_ALIGNED_64(p) (0 == (((uintptr_t)(const void *)(p) & 0x7))) -# define me64_to_le_str(to, from, length) memcpy((to), (from), (length)) - -/* constants */ -#define NumberOfRounds 24 - -/* SHA3 (Keccak) constants for 24 rounds */ -static uint64_t keccak_round_constants[NumberOfRounds] = { - I64(0x0000000000000001), I64(0x0000000000008082), I64(0x800000000000808A), I64(0x8000000080008000), - I64(0x000000000000808B), I64(0x0000000080000001), I64(0x8000000080008081), I64(0x8000000000008009), - I64(0x000000000000008A), I64(0x0000000000000088), I64(0x0000000080008009), I64(0x000000008000000A), - I64(0x000000008000808B), I64(0x800000000000008B), I64(0x8000000000008089), I64(0x8000000000008003), - I64(0x8000000000008002), I64(0x8000000000000080), I64(0x000000000000800A), I64(0x800000008000000A), - I64(0x8000000080008081), I64(0x8000000000008080), I64(0x0000000080000001), I64(0x8000000080008008) -}; - -/* Initializing a sha3 context for given number of output bits */ -static void keccak_Init(SHA3_CTX *ctx, unsigned bits) -{ - /* NB: The Keccak capacity parameter = bits * 2 */ - unsigned rate = 1600 - bits * 2; - - memzero(ctx, sizeof(SHA3_CTX)); - ctx->block_size = rate / 8; - assert(rate <= 1600 && (rate % 64) == 0); -} - -/** - * Initialize context before calculating hash. - * - * @param ctx context to initialize - */ -void sha3_224_Init(SHA3_CTX *ctx) -{ - keccak_Init(ctx, 224); -} - -/** - * Initialize context before calculating hash. - * - * @param ctx context to initialize - */ -void sha3_256_Init(SHA3_CTX *ctx) -{ - keccak_Init(ctx, 256); -} - -/** - * Initialize context before calculating hash. - * - * @param ctx context to initialize - */ -void sha3_384_Init(SHA3_CTX *ctx) -{ - keccak_Init(ctx, 384); -} - -/** - * Initialize context before calculating hash. - * - * @param ctx context to initialize - */ -void sha3_512_Init(SHA3_CTX *ctx) -{ - keccak_Init(ctx, 512); -} - -/* Keccak theta() transformation */ -static void keccak_theta(uint64_t *A) -{ - unsigned int x = 0; - uint64_t C[5] = {0}, D[5] = {0}; - - for (x = 0; x < 5; x++) { - C[x] = A[x] ^ A[x + 5] ^ A[x + 10] ^ A[x + 15] ^ A[x + 20]; - } - D[0] = ROTL64(C[1], 1) ^ C[4]; - D[1] = ROTL64(C[2], 1) ^ C[0]; - D[2] = ROTL64(C[3], 1) ^ C[1]; - D[3] = ROTL64(C[4], 1) ^ C[2]; - D[4] = ROTL64(C[0], 1) ^ C[3]; - - for (x = 0; x < 5; x++) { - A[x] ^= D[x]; - A[x + 5] ^= D[x]; - A[x + 10] ^= D[x]; - A[x + 15] ^= D[x]; - A[x + 20] ^= D[x]; - } -} - -/* Keccak pi() transformation */ -static void keccak_pi(uint64_t *A) -{ - uint64_t A1 = 0; - A1 = A[1]; - A[ 1] = A[ 6]; - A[ 6] = A[ 9]; - A[ 9] = A[22]; - A[22] = A[14]; - A[14] = A[20]; - A[20] = A[ 2]; - A[ 2] = A[12]; - A[12] = A[13]; - A[13] = A[19]; - A[19] = A[23]; - A[23] = A[15]; - A[15] = A[ 4]; - A[ 4] = A[24]; - A[24] = A[21]; - A[21] = A[ 8]; - A[ 8] = A[16]; - A[16] = A[ 5]; - A[ 5] = A[ 3]; - A[ 3] = A[18]; - A[18] = A[17]; - A[17] = A[11]; - A[11] = A[ 7]; - A[ 7] = A[10]; - A[10] = A1; - /* note: A[ 0] is left as is */ -} - -/* Keccak chi() transformation */ -static void keccak_chi(uint64_t *A) -{ - int i = 0; - for (i = 0; i < 25; i += 5) { - uint64_t A0 = A[0 + i], A1 = A[1 + i]; - A[0 + i] ^= ~A1 & A[2 + i]; - A[1 + i] ^= ~A[2 + i] & A[3 + i]; - A[2 + i] ^= ~A[3 + i] & A[4 + i]; - A[3 + i] ^= ~A[4 + i] & A0; - A[4 + i] ^= ~A0 & A1; - } -} - -static void sha3_permutation(uint64_t *state) -{ - int round = 0; - for (round = 0; round < NumberOfRounds; round++) - { - keccak_theta(state); - - /* apply Keccak rho() transformation */ - state[ 1] = ROTL64(state[ 1], 1); - state[ 2] = ROTL64(state[ 2], 62); - state[ 3] = ROTL64(state[ 3], 28); - state[ 4] = ROTL64(state[ 4], 27); - state[ 5] = ROTL64(state[ 5], 36); - state[ 6] = ROTL64(state[ 6], 44); - state[ 7] = ROTL64(state[ 7], 6); - state[ 8] = ROTL64(state[ 8], 55); - state[ 9] = ROTL64(state[ 9], 20); - state[10] = ROTL64(state[10], 3); - state[11] = ROTL64(state[11], 10); - state[12] = ROTL64(state[12], 43); - state[13] = ROTL64(state[13], 25); - state[14] = ROTL64(state[14], 39); - state[15] = ROTL64(state[15], 41); - state[16] = ROTL64(state[16], 45); - state[17] = ROTL64(state[17], 15); - state[18] = ROTL64(state[18], 21); - state[19] = ROTL64(state[19], 8); - state[20] = ROTL64(state[20], 18); - state[21] = ROTL64(state[21], 2); - state[22] = ROTL64(state[22], 61); - state[23] = ROTL64(state[23], 56); - state[24] = ROTL64(state[24], 14); - - keccak_pi(state); - keccak_chi(state); - - /* apply iota(state, round) */ - *state ^= keccak_round_constants[round]; - } -} - -/** - * The core transformation. Process the specified block of data. - * - * @param hash the algorithm state - * @param block the message block to process - * @param block_size the size of the processed block in bytes - */ -static void sha3_process_block(uint64_t hash[25], const uint64_t *block, size_t block_size) -{ - /* expanded loop */ - hash[ 0] ^= le2me_64(block[ 0]); - hash[ 1] ^= le2me_64(block[ 1]); - hash[ 2] ^= le2me_64(block[ 2]); - hash[ 3] ^= le2me_64(block[ 3]); - hash[ 4] ^= le2me_64(block[ 4]); - hash[ 5] ^= le2me_64(block[ 5]); - hash[ 6] ^= le2me_64(block[ 6]); - hash[ 7] ^= le2me_64(block[ 7]); - hash[ 8] ^= le2me_64(block[ 8]); - /* if not sha3-512 */ - if (block_size > 72) { - hash[ 9] ^= le2me_64(block[ 9]); - hash[10] ^= le2me_64(block[10]); - hash[11] ^= le2me_64(block[11]); - hash[12] ^= le2me_64(block[12]); - /* if not sha3-384 */ - if (block_size > 104) { - hash[13] ^= le2me_64(block[13]); - hash[14] ^= le2me_64(block[14]); - hash[15] ^= le2me_64(block[15]); - hash[16] ^= le2me_64(block[16]); - /* if not sha3-256 */ - if (block_size > 136) { - hash[17] ^= le2me_64(block[17]); -#ifdef FULL_SHA3_FAMILY_SUPPORT - /* if not sha3-224 */ - if (block_size > 144) { - hash[18] ^= le2me_64(block[18]); - hash[19] ^= le2me_64(block[19]); - hash[20] ^= le2me_64(block[20]); - hash[21] ^= le2me_64(block[21]); - hash[22] ^= le2me_64(block[22]); - hash[23] ^= le2me_64(block[23]); - hash[24] ^= le2me_64(block[24]); - } -#endif - } - } - } - /* make a permutation of the hash */ - sha3_permutation(hash); -} - -#define SHA3_FINALIZED 0x80000000 - -/** - * Calculate message hash. - * Can be called repeatedly with chunks of the message to be hashed. - * - * @param ctx the algorithm context containing current hashing state - * @param msg message chunk - * @param size length of the message chunk - */ -void sha3_Update(SHA3_CTX *ctx, const unsigned char *msg, size_t size) -{ - if (size == 0) return; - - size_t idx = (size_t)ctx->rest; - size_t block_size = (size_t)ctx->block_size; - - if (ctx->rest & SHA3_FINALIZED) return; /* too late for additional input */ - ctx->rest = (unsigned)((ctx->rest + size) % block_size); - - /* fill partial block */ - if (idx) { - size_t left = block_size - idx; - memcpy((char*)ctx->message + idx, msg, (size < left ? size : left)); - if (size < left) return; - - /* process partial block */ - sha3_process_block(ctx->hash, ctx->message, block_size); - msg += left; - size -= left; - } - while (size >= block_size) { - uint64_t *aligned_message_block = NULL; - if (IS_ALIGNED_64(msg)) { - /* the most common case is processing of an already aligned message - without copying it */ - aligned_message_block = (uint64_t*)(void*)msg; - } else { - memcpy(ctx->message, msg, block_size); - aligned_message_block = ctx->message; - } - - sha3_process_block(ctx->hash, aligned_message_block, block_size); - msg += block_size; - size -= block_size; - } - if (size) { - memcpy(ctx->message, msg, size); /* save leftovers */ - } -} - -/** - * Store calculated hash into the given array. - * - * @param ctx the algorithm context containing current hashing state - * @param result calculated hash in binary form - */ -void sha3_Final(SHA3_CTX *ctx, unsigned char* result) -{ - size_t digest_length = 100 - ctx->block_size / 2; - const size_t block_size = ctx->block_size; - - if (!(ctx->rest & SHA3_FINALIZED)) - { - /* clear the rest of the data queue */ - memzero((char*)ctx->message + ctx->rest, block_size - ctx->rest); - ((char*)ctx->message)[ctx->rest] |= 0x06; - ((char*)ctx->message)[block_size - 1] |= 0x80; - - /* process final block */ - sha3_process_block(ctx->hash, ctx->message, block_size); - ctx->rest = SHA3_FINALIZED; /* mark context as finalized */ - } - - assert(block_size > digest_length); - if (result) me64_to_le_str(result, ctx->hash, digest_length); - memzero(ctx, sizeof(SHA3_CTX)); -} - -#if USE_KECCAK -/** -* Store calculated hash into the given array. -* -* @param ctx the algorithm context containing current hashing state -* @param result calculated hash in binary form -*/ -void keccak_Final(SHA3_CTX *ctx, unsigned char* result) -{ - size_t digest_length = 100 - ctx->block_size / 2; - const size_t block_size = ctx->block_size; - - if (!(ctx->rest & SHA3_FINALIZED)) - { - /* clear the rest of the data queue */ - memzero((char*)ctx->message + ctx->rest, block_size - ctx->rest); - ((char*)ctx->message)[ctx->rest] |= 0x01; - ((char*)ctx->message)[block_size - 1] |= 0x80; - - /* process final block */ - sha3_process_block(ctx->hash, ctx->message, block_size); - ctx->rest = SHA3_FINALIZED; /* mark context as finalized */ - } - - assert(block_size > digest_length); - if (result) me64_to_le_str(result, ctx->hash, digest_length); - memzero(ctx, sizeof(SHA3_CTX)); -} - -void keccak_256(const unsigned char* data, size_t len, unsigned char* digest) -{ - SHA3_CTX ctx = {0}; - keccak_256_Init(&ctx); - keccak_Update(&ctx, data, len); - keccak_Final(&ctx, digest); -} - -void keccak_512(const unsigned char* data, size_t len, unsigned char* digest) -{ - SHA3_CTX ctx = {0}; - keccak_512_Init(&ctx); - keccak_Update(&ctx, data, len); - keccak_Final(&ctx, digest); -} -#endif /* USE_KECCAK */ - -void sha3_256(const unsigned char* data, size_t len, unsigned char* digest) -{ - SHA3_CTX ctx = {0}; - sha3_256_Init(&ctx); - sha3_Update(&ctx, data, len); - sha3_Final(&ctx, digest); -} - -void sha3_512(const unsigned char* data, size_t len, unsigned char* digest) -{ - SHA3_CTX ctx = {0}; - sha3_512_Init(&ctx); - sha3_Update(&ctx, data, len); - sha3_Final(&ctx, digest); -} diff --git a/deps/crypto/trezor-crypto/sha3.h b/deps/crypto/trezor-crypto/sha3.h deleted file mode 100644 index 367369d4d..000000000 --- a/deps/crypto/trezor-crypto/sha3.h +++ /dev/null @@ -1,89 +0,0 @@ -/* sha3.h - an implementation of Secure Hash Algorithm 3 (Keccak). - * based on the - * The Keccak SHA-3 submission. Submission to NIST (Round 3), 2011 - * by Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche - * - * Copyright: 2013 Aleksey Kravchenko - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk! - */ - -#ifndef __SHA3_H__ -#define __SHA3_H__ - -#include -#include "options.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define sha3_224_hash_size 28 -#define sha3_256_hash_size 32 -#define sha3_384_hash_size 48 -#define sha3_512_hash_size 64 -#define sha3_max_permutation_size 25 -#define sha3_max_rate_in_qwords 24 - -#define SHA3_224_BLOCK_LENGTH 144 -#define SHA3_256_BLOCK_LENGTH 136 -#define SHA3_384_BLOCK_LENGTH 104 -#define SHA3_512_BLOCK_LENGTH 72 - -#define SHA3_224_DIGEST_LENGTH sha3_224_hash_size -#define SHA3_256_DIGEST_LENGTH sha3_256_hash_size -#define SHA3_384_DIGEST_LENGTH sha3_384_hash_size -#define SHA3_512_DIGEST_LENGTH sha3_512_hash_size - -/** - * SHA3 Algorithm context. - */ -typedef struct SHA3_CTX -{ - /* 1600 bits algorithm hashing state */ - uint64_t hash[sha3_max_permutation_size]; - /* 1536-bit buffer for leftovers */ - uint64_t message[sha3_max_rate_in_qwords]; - /* count of bytes in the message[] buffer */ - unsigned rest; - /* size of a message block processed at once */ - unsigned block_size; -} SHA3_CTX; - -/* methods for calculating the hash function */ - -void sha3_224_Init(SHA3_CTX *ctx); -void sha3_256_Init(SHA3_CTX *ctx); -void sha3_384_Init(SHA3_CTX *ctx); -void sha3_512_Init(SHA3_CTX *ctx); -void sha3_Update(SHA3_CTX *ctx, const unsigned char* msg, size_t size); -void sha3_Final(SHA3_CTX *ctx, unsigned char* result); - -#if USE_KECCAK -#define keccak_224_Init sha3_224_Init -#define keccak_256_Init sha3_256_Init -#define keccak_384_Init sha3_384_Init -#define keccak_512_Init sha3_512_Init -#define keccak_Update sha3_Update -void keccak_Final(SHA3_CTX *ctx, unsigned char* result); -void keccak_256(const unsigned char* data, size_t len, unsigned char* digest); -void keccak_512(const unsigned char* data, size_t len, unsigned char* digest); -#endif - -void sha3_256(const unsigned char* data, size_t len, unsigned char* digest); -void sha3_512(const unsigned char* data, size_t len, unsigned char* digest); - -#ifdef __cplusplus -} /* extern "C" */ -#endif /* __cplusplus */ - -#endif /* __SHA3_H__ */ diff --git a/deps/crypto/trezor-crypto/shamir.c b/deps/crypto/trezor-crypto/shamir.c deleted file mode 100644 index 82b5e29a2..000000000 --- a/deps/crypto/trezor-crypto/shamir.c +++ /dev/null @@ -1,335 +0,0 @@ -/* - * Implementation of the hazardous parts of the SSS library - * - * Copyright (c) 2017 Daan Sprenkels - * Copyright (c) 2019 SatoshiLabs - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * This code contains the actual Shamir secret sharing functionality. The - * implementation of this code is based on the idea that the user likes to - * generate/combine 32 shares (in GF(2^8)) at the same time, because a 256 bit - * key will be exactly 32 bytes. Therefore we bitslice all the input and - * unbitslice the output right before returning. - * - * This bitslice approach optimizes natively on all architectures that are 32 - * bit or more. Care is taken to use not too many registers, to ensure that no - * values have to be leaked to the stack. - * - * All functions in this module are implemented constant time and constant - * lookup operations, as all proper crypto code must be. - */ - -#include "shamir.h" -#include -#include "memzero.h" - -static void bitslice(uint32_t r[8], const uint8_t *x, size_t len) { - size_t bit_idx = 0, arr_idx = 0; - uint32_t cur = 0; - - memset(r, 0, sizeof(uint32_t[8])); - for (arr_idx = 0; arr_idx < len; arr_idx++) { - cur = (uint32_t)x[arr_idx]; - for (bit_idx = 0; bit_idx < 8; bit_idx++) { - r[bit_idx] |= ((cur >> bit_idx) & 1) << arr_idx; - } - } -} - -static void unbitslice(uint8_t *r, const uint32_t x[8], size_t len) { - size_t bit_idx = 0, arr_idx = 0; - uint32_t cur = 0; - - memset(r, 0, sizeof(uint8_t) * len); - for (bit_idx = 0; bit_idx < 8; bit_idx++) { - cur = (uint32_t)x[bit_idx]; - for (arr_idx = 0; arr_idx < len; arr_idx++) { - r[arr_idx] |= ((cur >> arr_idx) & 1) << bit_idx; - } - } -} - -static void bitslice_setall(uint32_t r[8], const uint8_t x) { - size_t idx = 0; - for (idx = 0; idx < 8; idx++) { - r[idx] = -((x >> idx) & 1); - } -} - -/* - * Add (XOR) `r` with `x` and store the result in `r`. - */ -static void gf256_add(uint32_t r[8], const uint32_t x[8]) { - size_t idx = 0; - for (idx = 0; idx < 8; idx++) r[idx] ^= x[idx]; -} - -/* - * Safely multiply two bitsliced polynomials in GF(2^8) reduced by - * x^8 + x^4 + x^3 + x + 1. `r` and `a` may overlap, but overlapping of `r` - * and `b` will produce an incorrect result! If you need to square a polynomial - * use `gf256_square` instead. - */ -static void gf256_mul(uint32_t r[8], const uint32_t a[8], const uint32_t b[8]) { - /* This function implements Russian Peasant multiplication on two - * bitsliced polynomials. - * - * I personally think that these kinds of long lists of operations - * are often a bit ugly. A double for loop would be nicer and would - * take up a lot less lines of code. - * However, some compilers seem to fail in optimizing these kinds of - * loops. So we will just have to do this by hand. - */ - uint32_t a2[8] = {0}; - memcpy(a2, a, sizeof(uint32_t[8])); - - r[0] = a2[0] & b[0]; /* add (assignment, because r is 0) */ - r[1] = a2[1] & b[0]; - r[2] = a2[2] & b[0]; - r[3] = a2[3] & b[0]; - r[4] = a2[4] & b[0]; - r[5] = a2[5] & b[0]; - r[6] = a2[6] & b[0]; - r[7] = a2[7] & b[0]; - a2[0] ^= a2[7]; /* reduce */ - a2[2] ^= a2[7]; - a2[3] ^= a2[7]; - - r[0] ^= a2[7] & b[1]; /* add */ - r[1] ^= a2[0] & b[1]; - r[2] ^= a2[1] & b[1]; - r[3] ^= a2[2] & b[1]; - r[4] ^= a2[3] & b[1]; - r[5] ^= a2[4] & b[1]; - r[6] ^= a2[5] & b[1]; - r[7] ^= a2[6] & b[1]; - a2[7] ^= a2[6]; /* reduce */ - a2[1] ^= a2[6]; - a2[2] ^= a2[6]; - - r[0] ^= a2[6] & b[2]; /* add */ - r[1] ^= a2[7] & b[2]; - r[2] ^= a2[0] & b[2]; - r[3] ^= a2[1] & b[2]; - r[4] ^= a2[2] & b[2]; - r[5] ^= a2[3] & b[2]; - r[6] ^= a2[4] & b[2]; - r[7] ^= a2[5] & b[2]; - a2[6] ^= a2[5]; /* reduce */ - a2[0] ^= a2[5]; - a2[1] ^= a2[5]; - - r[0] ^= a2[5] & b[3]; /* add */ - r[1] ^= a2[6] & b[3]; - r[2] ^= a2[7] & b[3]; - r[3] ^= a2[0] & b[3]; - r[4] ^= a2[1] & b[3]; - r[5] ^= a2[2] & b[3]; - r[6] ^= a2[3] & b[3]; - r[7] ^= a2[4] & b[3]; - a2[5] ^= a2[4]; /* reduce */ - a2[7] ^= a2[4]; - a2[0] ^= a2[4]; - - r[0] ^= a2[4] & b[4]; /* add */ - r[1] ^= a2[5] & b[4]; - r[2] ^= a2[6] & b[4]; - r[3] ^= a2[7] & b[4]; - r[4] ^= a2[0] & b[4]; - r[5] ^= a2[1] & b[4]; - r[6] ^= a2[2] & b[4]; - r[7] ^= a2[3] & b[4]; - a2[4] ^= a2[3]; /* reduce */ - a2[6] ^= a2[3]; - a2[7] ^= a2[3]; - - r[0] ^= a2[3] & b[5]; /* add */ - r[1] ^= a2[4] & b[5]; - r[2] ^= a2[5] & b[5]; - r[3] ^= a2[6] & b[5]; - r[4] ^= a2[7] & b[5]; - r[5] ^= a2[0] & b[5]; - r[6] ^= a2[1] & b[5]; - r[7] ^= a2[2] & b[5]; - a2[3] ^= a2[2]; /* reduce */ - a2[5] ^= a2[2]; - a2[6] ^= a2[2]; - - r[0] ^= a2[2] & b[6]; /* add */ - r[1] ^= a2[3] & b[6]; - r[2] ^= a2[4] & b[6]; - r[3] ^= a2[5] & b[6]; - r[4] ^= a2[6] & b[6]; - r[5] ^= a2[7] & b[6]; - r[6] ^= a2[0] & b[6]; - r[7] ^= a2[1] & b[6]; - a2[2] ^= a2[1]; /* reduce */ - a2[4] ^= a2[1]; - a2[5] ^= a2[1]; - - r[0] ^= a2[1] & b[7]; /* add */ - r[1] ^= a2[2] & b[7]; - r[2] ^= a2[3] & b[7]; - r[3] ^= a2[4] & b[7]; - r[4] ^= a2[5] & b[7]; - r[5] ^= a2[6] & b[7]; - r[6] ^= a2[7] & b[7]; - r[7] ^= a2[0] & b[7]; - - memzero(a2, sizeof(a2)); -} - -/* - * Square `x` in GF(2^8) and write the result to `r`. `r` and `x` may overlap. - */ -static void gf256_square(uint32_t r[8], const uint32_t x[8]) { - uint32_t r8 = 0, r10 = 0, r12 = 0, r14 = 0; - /* Use the Freshman's Dream rule to square the polynomial - * Assignments are done from 7 downto 0, because this allows the user - * to execute this function in-place (e.g. `gf256_square(r, r);`). - */ - r14 = x[7]; - r12 = x[6]; - r10 = x[5]; - r8 = x[4]; - r[6] = x[3]; - r[4] = x[2]; - r[2] = x[1]; - r[0] = x[0]; - - /* Reduce with x^8 + x^4 + x^3 + x + 1 until order is less than 8 */ - r[7] = r14; /* r[7] was 0 */ - r[6] ^= r14; - r10 ^= r14; - /* Skip, because r13 is always 0 */ - r[4] ^= r12; - r[5] = r12; /* r[5] was 0 */ - r[7] ^= r12; - r8 ^= r12; - /* Skip, because r11 is always 0 */ - r[2] ^= r10; - r[3] = r10; /* r[3] was 0 */ - r[5] ^= r10; - r[6] ^= r10; - r[1] = r14; /* r[1] was 0 */ - r[2] ^= r14; /* Substitute r9 by r14 because they will always be equal*/ - r[4] ^= r14; - r[5] ^= r14; - r[0] ^= r8; - r[1] ^= r8; - r[3] ^= r8; - r[4] ^= r8; -} - -/* - * Invert `x` in GF(2^8) and write the result to `r` - */ -static void gf256_inv(uint32_t r[8], uint32_t x[8]) { - uint32_t y[8] = {0}, z[8] = {0}; - - gf256_square(y, x); // y = x^2 - gf256_square(y, y); // y = x^4 - gf256_square(r, y); // r = x^8 - gf256_mul(z, r, x); // z = x^9 - gf256_square(r, r); // r = x^16 - gf256_mul(r, r, z); // r = x^25 - gf256_square(r, r); // r = x^50 - gf256_square(z, r); // z = x^100 - gf256_square(z, z); // z = x^200 - gf256_mul(r, r, z); // r = x^250 - gf256_mul(r, r, y); // r = x^254 - - memzero(y, sizeof(y)); - memzero(z, sizeof(z)); -} - -bool shamir_interpolate(uint8_t *result, uint8_t result_index, - const uint8_t *share_indices, - const uint8_t **share_values, uint8_t share_count, - size_t len) { - size_t i = 0, j = 0; - uint32_t x[8] = {0}; - uint32_t xs[share_count][8]; - memset(xs, 0, sizeof(xs)); - uint32_t ys[share_count][8]; - memset(ys, 0, sizeof(ys)); - uint32_t num[8] = {~0}; /* num is the numerator (=1) */ - uint32_t denom[8] = {0}; - uint32_t tmp[8] = {0}; - uint32_t secret[8] = {0}; - bool ret = true; - - if (len > SHAMIR_MAX_LEN) return false; - - /* Collect the x and y values */ - for (i = 0; i < share_count; i++) { - bitslice_setall(xs[i], share_indices[i]); - bitslice(ys[i], share_values[i], len); - } - bitslice_setall(x, result_index); - - for (i = 0; i < share_count; i++) { - memcpy(tmp, x, sizeof(uint32_t[8])); - gf256_add(tmp, xs[i]); - gf256_mul(num, num, tmp); - } - - /* Use Lagrange basis polynomials to calculate the secret coefficient */ - for (i = 0; i < share_count; i++) { - /* The code below assumes that none of the share_indices are equal to - * result_index. We need to treat that as a special case. */ - if (share_indices[i] != result_index) { - memcpy(denom, x, sizeof(denom)); - gf256_add(denom, xs[i]); - } else { - bitslice_setall(denom, 1); - gf256_add(secret, ys[i]); - } - for (j = 0; j < share_count; j++) { - if (i == j) continue; - memcpy(tmp, xs[i], sizeof(uint32_t[8])); - gf256_add(tmp, xs[j]); - gf256_mul(denom, denom, tmp); - } - if ((denom[0] | denom[1] | denom[2] | denom[3] | denom[4] | denom[5] | - denom[6] | denom[7]) == 0) { - /* The share_indices are not unique. */ - ret = false; - break; - } - gf256_inv(tmp, denom); /* inverted denominator */ - gf256_mul(tmp, tmp, num); /* basis polynomial */ - gf256_mul(tmp, tmp, ys[i]); /* scaled coefficient */ - gf256_add(secret, tmp); - } - - if (ret == true) { - unbitslice(result, secret, len); - } - - memzero(x, sizeof(x)); - memzero(xs, sizeof(xs)); - memzero(ys, sizeof(ys)); - memzero(num, sizeof(num)); - memzero(denom, sizeof(denom)); - memzero(tmp, sizeof(tmp)); - memzero(secret, sizeof(secret)); - return ret; -} diff --git a/deps/crypto/trezor-crypto/shamir.h b/deps/crypto/trezor-crypto/shamir.h deleted file mode 100644 index ef04a3063..000000000 --- a/deps/crypto/trezor-crypto/shamir.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Low level API for Daan Sprenkels' Shamir secret sharing library - * Copyright (c) 2017 Daan Sprenkels - * Copyright (c) 2019 SatoshiLabs - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Usage of this API is hazardous and is only reserved for beings with a - * good understanding of the Shamir secret sharing scheme and who know how - * crypto code is implemented. If you are unsure about this, use the - * intermediate level API. You have been warned! - */ - -#ifndef __SHAMIR_H__ -#define __SHAMIR_H__ - -#include -#include -#include - -#define SHAMIR_MAX_LEN 32 - -/* - * Computes f(x) given the Shamir shares (x_1, f(x_1)), ... , (x_m, f(x_m)). - * The x coordinates of the shares must be pairwise distinct. Returns true on - * success, otherwise false. - * result: Array of length len where the evaluations of the polynomials in x - * will be written. - * result_index: The x coordinate of the result. - * share_indices: Points to the array of integers x_1, ... , x_m. - * share_values: Points to the array of y_1, ... , y_m, where each y_i is an - * array of bytes of length len representing the evaluations of the - * polynomials in x_i. - * share_count: The number of shares m. - * len: The length of the result array and of each of the y_1, ... , y_m arrays. - * - * The number of shares used to compute the result may be larger than the - * required threshold. - * - * This function does *not* do *any* checking for integrity. If any of the - * shares are not original, this will result in an invalid restored value. - * All values written to `result` should be treated as secret. Even if some of - * the shares that were provided as input were incorrect, the result *still* - * allows an attacker to gain information about the correct result. - * - * This function treats `shares_values`, `share_indices` and `result` as secret - * values. `share_count` is treated as a public value (for performance reasons). - */ -bool shamir_interpolate(uint8_t *result, uint8_t result_index, - const uint8_t *share_indices, - const uint8_t **share_values, uint8_t share_count, - size_t len); - -#endif /* __SHAMIR_H__ */ diff --git a/deps/crypto/trezor-crypto/slip39.c b/deps/crypto/trezor-crypto/slip39.c deleted file mode 100644 index 2dd39fa4a..000000000 --- a/deps/crypto/trezor-crypto/slip39.c +++ /dev/null @@ -1,151 +0,0 @@ -/** - * This file is part of the TREZOR project, https://trezor.io/ - * - * Copyright (c) SatoshiLabs - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "slip39.h" -#include -#include -#include "slip39_wordlist.h" - -/** - * Returns word at position `index`. - */ -const char* get_word(uint16_t index) { - if (index >= WORDS_COUNT) { - return NULL; - } - - return slip39_wordlist[index]; -} - -/** - * Finds the index of a given word. - * Returns true on success and stores result in `index`. - */ -bool word_index(uint16_t* index, const char* word, uint8_t word_length) { - uint16_t lo = 0; - uint16_t hi = WORDS_COUNT; - uint16_t mid = 0; - - while ((hi - lo) > 1) { - mid = (hi + lo) / 2; - if (strncmp(slip39_wordlist[mid], word, word_length) > 0) { - hi = mid; - } else { - lo = mid; - } - } - if (strncmp(slip39_wordlist[lo], word, word_length) != 0) { - return false; - } - *index = lo; - return true; -} - -/** - * Returns the index of the first sequence in words_button_seq[] which is not - * less than the given sequence. Returns WORDS_COUNT if there is no such - * sequence. - */ -static uint16_t find_sequence(uint16_t sequence) { - if (sequence <= words_button_seq[0].sequence) { - return 0; - } - - uint16_t lo = 0; - uint16_t hi = WORDS_COUNT; - - while (hi - lo > 1) { - uint16_t mid = (hi + lo) / 2; - if (words_button_seq[mid].sequence >= sequence) { - hi = mid; - } else { - lo = mid; - } - } - - return hi; -} - -/** - * Returns a word matching the button sequence prefix or NULL if no match is - * found. - */ -const char* button_sequence_to_word(uint16_t sequence) { - if (sequence == 0) { - return slip39_wordlist[words_button_seq[0].index]; - } - - uint16_t multiplier = 1; - while (sequence < 1000) { - sequence *= 10; - multiplier *= 10; - } - - uint16_t i = find_sequence(sequence); - if (i >= WORDS_COUNT || - words_button_seq[i].sequence - sequence >= multiplier) { - return NULL; - } - - return slip39_wordlist[words_button_seq[i].index]; -} - -/** - * Calculates which buttons on the T9 keyboard can still be pressed after the - * prefix was entered. Returns a 9-bit bitmask, where each bit specifies which - * buttons can be pressed (there are still words in this combination). The least - * significant bit corresponds to the first button. - * - * Example: 110000110 - second, third, eighth and ninth button still can be - * pressed. - */ -uint16_t slip39_word_completion_mask(uint16_t prefix) { - if (prefix >= 1000) { - // Four char prefix -> the mask is zero. - return 0; - } - - // Determine the range of sequences [min, max), which have the given prefix. - uint16_t min = prefix; - uint16_t max = prefix + 1; - uint16_t divider = 1; - while (max <= 1000) { - min *= 10; - max *= 10; - divider *= 10; - } - divider /= 10; - - // Determine the range we will be searching in words_button_seq[]. - min = find_sequence(min); - max = find_sequence(max); - - uint16_t bitmap = 0; - for (uint16_t i = min; i < max; ++i) { - uint8_t digit = (words_button_seq[i].sequence / divider) % 10; - bitmap |= 1 << (digit - 1); - } - - return bitmap; -} diff --git a/deps/crypto/trezor-crypto/slip39.h b/deps/crypto/trezor-crypto/slip39.h deleted file mode 100644 index 0bc24fa74..000000000 --- a/deps/crypto/trezor-crypto/slip39.h +++ /dev/null @@ -1,39 +0,0 @@ -/** - * This file is part of the TREZOR project, https://trezor.io/ - * - * Copyright (c) SatoshiLabs - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __SLIP39_H__ -#define __SLIP39_H__ - -#include -#include - -const char* get_word(uint16_t index); - -bool word_index(uint16_t* index, const char* word, uint8_t word_length); - -uint16_t slip39_word_completion_mask(uint16_t prefix); - -const char* button_sequence_to_word(uint16_t prefix); - -#endif diff --git a/deps/crypto/trezor-crypto/slip39_wordlist.h b/deps/crypto/trezor-crypto/slip39_wordlist.h deleted file mode 100644 index 3464aae94..000000000 --- a/deps/crypto/trezor-crypto/slip39_wordlist.h +++ /dev/null @@ -1,1246 +0,0 @@ -/** - * This file is part of the TREZOR project, https://trezor.io/ - * - * Copyright (c) SatoshiLabs - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __SLIP39_WORDLIST_H__ -#define __SLIP39_WORDLIST_H__ - -#include - -#define WORDS_COUNT 1024 - -static const char* const slip39_wordlist[WORDS_COUNT] = { - "academic", "acid", "acne", "acquire", "acrobat", "activity", - "actress", "adapt", "adequate", "adjust", "admit", "adorn", - "adult", "advance", "advocate", "afraid", "again", "agency", - "agree", "aide", "aircraft", "airline", "airport", "ajar", - "alarm", "album", "alcohol", "alien", "alive", "alpha", - "already", "alto", "aluminum", "always", "amazing", "ambition", - "amount", "amuse", "analysis", "anatomy", "ancestor", "ancient", - "angel", "angry", "animal", "answer", "antenna", "anxiety", - "apart", "aquatic", "arcade", "arena", "argue", "armed", - "artist", "artwork", "aspect", "auction", "august", "aunt", - "average", "aviation", "avoid", "award", "away", "axis", - "axle", "beam", "beard", "beaver", "become", "bedroom", - "behavior", "being", "believe", "belong", "benefit", "best", - "beyond", "bike", "biology", "birthday", "bishop", "black", - "blanket", "blessing", "blimp", "blind", "blue", "body", - "bolt", "boring", "born", "both", "boundary", "bracelet", - "branch", "brave", "breathe", "briefing", "broken", "brother", - "browser", "bucket", "budget", "building", "bulb", "bulge", - "bumpy", "bundle", "burden", "burning", "busy", "buyer", - "cage", "calcium", "camera", "campus", "canyon", "capacity", - "capital", "capture", "carbon", "cards", "careful", "cargo", - "carpet", "carve", "category", "cause", "ceiling", "center", - "ceramic", "champion", "change", "charity", "check", "chemical", - "chest", "chew", "chubby", "cinema", "civil", "class", - "clay", "cleanup", "client", "climate", "clinic", "clock", - "clogs", "closet", "clothes", "club", "cluster", "coal", - "coastal", "coding", "column", "company", "corner", "costume", - "counter", "course", "cover", "cowboy", "cradle", "craft", - "crazy", "credit", "cricket", "criminal", "crisis", "critical", - "crowd", "crucial", "crunch", "crush", "crystal", "cubic", - "cultural", "curious", "curly", "custody", "cylinder", "daisy", - "damage", "dance", "darkness", "database", "daughter", "deadline", - "deal", "debris", "debut", "decent", "decision", "declare", - "decorate", "decrease", "deliver", "demand", "density", "deny", - "depart", "depend", "depict", "deploy", "describe", "desert", - "desire", "desktop", "destroy", "detailed", "detect", "device", - "devote", "diagnose", "dictate", "diet", "dilemma", "diminish", - "dining", "diploma", "disaster", "discuss", "disease", "dish", - "dismiss", "display", "distance", "dive", "divorce", "document", - "domain", "domestic", "dominant", "dough", "downtown", "dragon", - "dramatic", "dream", "dress", "drift", "drink", "drove", - "drug", "dryer", "duckling", "duke", "duration", "dwarf", - "dynamic", "early", "earth", "easel", "easy", "echo", - "eclipse", "ecology", "edge", "editor", "educate", "either", - "elbow", "elder", "election", "elegant", "element", "elephant", - "elevator", "elite", "else", "email", "emerald", "emission", - "emperor", "emphasis", "employer", "empty", "ending", "endless", - "endorse", "enemy", "energy", "enforce", "engage", "enjoy", - "enlarge", "entrance", "envelope", "envy", "epidemic", "episode", - "equation", "equip", "eraser", "erode", "escape", "estate", - "estimate", "evaluate", "evening", "evidence", "evil", "evoke", - "exact", "example", "exceed", "exchange", "exclude", "excuse", - "execute", "exercise", "exhaust", "exotic", "expand", "expect", - "explain", "express", "extend", "extra", "eyebrow", "facility", - "fact", "failure", "faint", "fake", "false", "family", - "famous", "fancy", "fangs", "fantasy", "fatal", "fatigue", - "favorite", "fawn", "fiber", "fiction", "filter", "finance", - "findings", "finger", "firefly", "firm", "fiscal", "fishing", - "fitness", "flame", "flash", "flavor", "flea", "flexible", - "flip", "float", "floral", "fluff", "focus", "forbid", - "force", "forecast", "forget", "formal", "fortune", "forward", - "founder", "fraction", "fragment", "frequent", "freshman", "friar", - "fridge", "friendly", "frost", "froth", "frozen", "fumes", - "funding", "furl", "fused", "galaxy", "game", "garbage", - "garden", "garlic", "gasoline", "gather", "general", "genius", - "genre", "genuine", "geology", "gesture", "glad", "glance", - "glasses", "glen", "glimpse", "goat", "golden", "graduate", - "grant", "grasp", "gravity", "gray", "greatest", "grief", - "grill", "grin", "grocery", "gross", "group", "grownup", - "grumpy", "guard", "guest", "guilt", "guitar", "gums", - "hairy", "hamster", "hand", "hanger", "harvest", "have", - "havoc", "hawk", "hazard", "headset", "health", "hearing", - "heat", "helpful", "herald", "herd", "hesitate", "hobo", - "holiday", "holy", "home", "hormone", "hospital", "hour", - "huge", "human", "humidity", "hunting", "husband", "hush", - "husky", "hybrid", "idea", "identify", "idle", "image", - "impact", "imply", "improve", "impulse", "include", "income", - "increase", "index", "indicate", "industry", "infant", "inform", - "inherit", "injury", "inmate", "insect", "inside", "install", - "intend", "intimate", "invasion", "involve", "iris", "island", - "isolate", "item", "ivory", "jacket", "jerky", "jewelry", - "join", "judicial", "juice", "jump", "junction", "junior", - "junk", "jury", "justice", "kernel", "keyboard", "kidney", - "kind", "kitchen", "knife", "knit", "laden", "ladle", - "ladybug", "lair", "lamp", "language", "large", "laser", - "laundry", "lawsuit", "leader", "leaf", "learn", "leaves", - "lecture", "legal", "legend", "legs", "lend", "length", - "level", "liberty", "library", "license", "lift", "likely", - "lilac", "lily", "lips", "liquid", "listen", "literary", - "living", "lizard", "loan", "lobe", "location", "losing", - "loud", "loyalty", "luck", "lunar", "lunch", "lungs", - "luxury", "lying", "lyrics", "machine", "magazine", "maiden", - "mailman", "main", "makeup", "making", "mama", "manager", - "mandate", "mansion", "manual", "marathon", "march", "market", - "marvel", "mason", "material", "math", "maximum", "mayor", - "meaning", "medal", "medical", "member", "memory", "mental", - "merchant", "merit", "method", "metric", "midst", "mild", - "military", "mineral", "minister", "miracle", "mixed", "mixture", - "mobile", "modern", "modify", "moisture", "moment", "morning", - "mortgage", "mother", "mountain", "mouse", "move", "much", - "mule", "multiple", "muscle", "museum", "music", "mustang", - "nail", "national", "necklace", "negative", "nervous", "network", - "news", "nuclear", "numb", "numerous", "nylon", "oasis", - "obesity", "object", "observe", "obtain", "ocean", "often", - "olympic", "omit", "oral", "orange", "orbit", "order", - "ordinary", "organize", "ounce", "oven", "overall", "owner", - "paces", "pacific", "package", "paid", "painting", "pajamas", - "pancake", "pants", "papa", "paper", "parcel", "parking", - "party", "patent", "patrol", "payment", "payroll", "peaceful", - "peanut", "peasant", "pecan", "penalty", "pencil", "percent", - "perfect", "permit", "petition", "phantom", "pharmacy", "photo", - "phrase", "physics", "pickup", "picture", "piece", "pile", - "pink", "pipeline", "pistol", "pitch", "plains", "plan", - "plastic", "platform", "playoff", "pleasure", "plot", "plunge", - "practice", "prayer", "preach", "predator", "pregnant", "premium", - "prepare", "presence", "prevent", "priest", "primary", "priority", - "prisoner", "privacy", "prize", "problem", "process", "profile", - "program", "promise", "prospect", "provide", "prune", "public", - "pulse", "pumps", "punish", "puny", "pupal", "purchase", - "purple", "python", "quantity", "quarter", "quick", "quiet", - "race", "racism", "radar", "railroad", "rainbow", "raisin", - "random", "ranked", "rapids", "raspy", "reaction", "realize", - "rebound", "rebuild", "recall", "receiver", "recover", "regret", - "regular", "reject", "relate", "remember", "remind", "remove", - "render", "repair", "repeat", "replace", "require", "rescue", - "research", "resident", "response", "result", "retailer", "retreat", - "reunion", "revenue", "review", "reward", "rhyme", "rhythm", - "rich", "rival", "river", "robin", "rocky", "romantic", - "romp", "roster", "round", "royal", "ruin", "ruler", - "rumor", "sack", "safari", "salary", "salon", "salt", - "satisfy", "satoshi", "saver", "says", "scandal", "scared", - "scatter", "scene", "scholar", "science", "scout", "scramble", - "screw", "script", "scroll", "seafood", "season", "secret", - "security", "segment", "senior", "shadow", "shaft", "shame", - "shaped", "sharp", "shelter", "sheriff", "short", "should", - "shrimp", "sidewalk", "silent", "silver", "similar", "simple", - "single", "sister", "skin", "skunk", "slap", "slavery", - "sled", "slice", "slim", "slow", "slush", "smart", - "smear", "smell", "smirk", "smith", "smoking", "smug", - "snake", "snapshot", "sniff", "society", "software", "soldier", - "solution", "soul", "source", "space", "spark", "speak", - "species", "spelling", "spend", "spew", "spider", "spill", - "spine", "spirit", "spit", "spray", "sprinkle", "square", - "squeeze", "stadium", "staff", "standard", "starting", "station", - "stay", "steady", "step", "stick", "stilt", "story", - "strategy", "strike", "style", "subject", "submit", "sugar", - "suitable", "sunlight", "superior", "surface", "surprise", "survive", - "sweater", "swimming", "swing", "switch", "symbolic", "sympathy", - "syndrome", "system", "tackle", "tactics", "tadpole", "talent", - "task", "taste", "taught", "taxi", "teacher", "teammate", - "teaspoon", "temple", "tenant", "tendency", "tension", "terminal", - "testify", "texture", "thank", "that", "theater", "theory", - "therapy", "thorn", "threaten", "thumb", "thunder", "ticket", - "tidy", "timber", "timely", "ting", "tofu", "together", - "tolerate", "total", "toxic", "tracks", "traffic", "training", - "transfer", "trash", "traveler", "treat", "trend", "trial", - "tricycle", "trip", "triumph", "trouble", "true", "trust", - "twice", "twin", "type", "typical", "ugly", "ultimate", - "umbrella", "uncover", "undergo", "unfair", "unfold", "unhappy", - "union", "universe", "unkind", "unknown", "unusual", "unwrap", - "upgrade", "upstairs", "username", "usher", "usual", "valid", - "valuable", "vampire", "vanish", "various", "vegan", "velvet", - "venture", "verdict", "verify", "very", "veteran", "vexed", - "victim", "video", "view", "vintage", "violence", "viral", - "visitor", "visual", "vitamins", "vocal", "voice", "volume", - "voter", "voting", "walnut", "warmth", "warn", "watch", - "wavy", "wealthy", "weapon", "webcam", "welcome", "welfare", - "western", "width", "wildlife", "window", "wine", "wireless", - "wisdom", "withdraw", "wits", "wolf", "woman", "work", - "worthy", "wrap", "wrist", "writing", "wrote", "year", - "yelp", "yield", "yoga", "zero", -}; - -/** - * This array contains number representations of SLIP-39 words. - * These numbers are determined how the words were entered on a - * T9 keyboard with the following layout: - * ab (1) cd (2) ef (3) - * ghij (4) klm (5) nopq (6) - * rs (7) tuv (8) wxyz (9) - * - * Each word is uniquely defined by four buttons. - */ -static const struct { - uint16_t sequence; - uint16_t index; -} words_button_seq[WORDS_COUNT] = { - {1212, 0}, // academic - {1216, 7}, // adapt - {1236, 8}, // adequate - {1242, 1}, // acid - {1248, 9}, // adjust - {1254, 10}, // admit - {1263, 2}, // acne - {1267, 11}, // adorn - {1268, 3}, // acquire - {1276, 4}, // acrobat - {1281, 13}, // advance - {1284, 5}, // activity - {1285, 12}, // adult - {1286, 14}, // advocate - {1287, 6}, // actress - {1315, 67}, // beam - {1317, 68}, // beard - {1318, 69}, // beaver - {1326, 70}, // become - {1327, 71}, // bedroom - {1341, 72}, // behavior - {1346, 73}, // being - {1354, 74}, // believe - {1356, 75}, // belong - {1363, 76}, // benefit - {1371, 15}, // afraid - {1378, 77}, // best - {1396, 78}, // beyond - {1414, 16}, // again - {1417, 23}, // ajar - {1423, 19}, // aide - {1436, 17}, // agency - {1453, 79}, // bike - {1465, 80}, // biology - {1472, 20}, // aircraft - {1473, 18}, // agree - {1474, 82}, // bishop - {1475, 21}, // airline - {1476, 22}, // airport - {1478, 81}, // birthday - {1512, 83}, // black - {1514, 35}, // ambition - {1516, 84}, // blanket - {1517, 24}, // alarm - {1518, 25}, // album - {1519, 34}, // amazing - {1526, 26}, // alcohol - {1537, 85}, // blessing - {1543, 27}, // alien - {1545, 86}, // blimp - {1546, 87}, // blind - {1548, 28}, // alive - {1564, 29}, // alpha - {1568, 36}, // amount - {1573, 30}, // already - {1583, 88}, // blue - {1585, 32}, // aluminum - {1586, 31}, // alto - {1587, 37}, // amuse - {1591, 33}, // always - {1615, 38}, // analysis - {1617, 48}, // apart - {1618, 39}, // anatomy - {1623, 40}, // ancestor - {1624, 41}, // ancient - {1629, 89}, // body - {1643, 42}, // angel - {1645, 44}, // animal - {1647, 43}, // angry - {1658, 90}, // bolt - {1674, 91}, // boring - {1676, 92}, // born - {1679, 45}, // answer - {1681, 49}, // aquatic - {1683, 46}, // antenna - {1684, 93}, // both - {1686, 94}, // boundary - {1694, 47}, // anxiety - {1712, 95}, // bracelet - {1716, 96}, // branch - {1718, 97}, // brave - {1721, 50}, // arcade - {1731, 98}, // breathe - {1736, 51}, // arena - {1743, 99}, // briefing - {1748, 52}, // argue - {1753, 53}, // armed - {1763, 56}, // aspect - {1765, 100}, // broken - {1768, 101}, // brother - {1769, 102}, // browser - {1784, 54}, // artist - {1789, 55}, // artwork - {1824, 104}, // budget - {1825, 103}, // bucket - {1828, 57}, // auction - {1837, 60}, // average - {1841, 61}, // aviation - {1845, 105}, // building - {1848, 58}, // august - {1851, 106}, // bulb - {1854, 107}, // bulge - {1856, 108}, // bumpy - {1862, 109}, // bundle - {1864, 62}, // avoid - {1868, 59}, // aunt - {1872, 110}, // burden - {1876, 111}, // burning - {1879, 112}, // busy - {1893, 113}, // buyer - {1917, 63}, // award - {1919, 64}, // away - {1947, 65}, // axis - {1953, 66}, // axle - {2143, 114}, // cage - {2147, 185}, // daisy - {2151, 186}, // damage - {2152, 115}, // calcium - {2153, 116}, // camera - {2156, 117}, // campus - {2161, 119}, // capacity - {2162, 187}, // dance - {2164, 120}, // capital - {2168, 121}, // capture - {2169, 118}, // canyon - {2171, 122}, // carbon - {2172, 123}, // cards - {2173, 124}, // careful - {2174, 125}, // cargo - {2175, 188}, // darkness - {2176, 126}, // carpet - {2178, 127}, // carve - {2181, 189}, // database - {2183, 128}, // category - {2184, 190}, // daughter - {2187, 129}, // cause - {2312, 191}, // deadline - {2315, 192}, // deal - {2317, 193}, // debris - {2318, 194}, // debut - {2323, 195}, // decent - {2324, 196}, // decision - {2325, 197}, // declare - {2326, 198}, // decorate - {2327, 199}, // decrease - {2345, 130}, // ceiling - {2351, 201}, // demand - {2354, 200}, // deliver - {2361, 204}, // depart - {2363, 205}, // depend - {2364, 206}, // depict - {2365, 207}, // deploy - {2367, 202}, // density - {2368, 131}, // center - {2369, 203}, // deny - {2371, 132}, // ceramic - {2372, 208}, // describe - {2373, 209}, // desert - {2374, 210}, // desire - {2375, 211}, // desktop - {2378, 212}, // destroy - {2381, 213}, // detailed - {2383, 214}, // detect - {2384, 215}, // device - {2386, 216}, // devote - {2414, 217}, // diagnose - {2415, 133}, // champion - {2416, 134}, // change - {2417, 135}, // charity - {2428, 218}, // dictate - {2432, 136}, // check - {2435, 137}, // chemical - {2437, 138}, // chest - {2438, 219}, // diet - {2439, 139}, // chew - {2453, 220}, // dilemma - {2454, 221}, // diminish - {2463, 141}, // cinema - {2464, 222}, // dining - {2465, 223}, // diploma - {2471, 224}, // disaster - {2472, 225}, // discuss - {2473, 226}, // disease - {2474, 227}, // dish - {2475, 228}, // dismiss - {2476, 229}, // display - {2478, 230}, // distance - {2481, 140}, // chubby - {2483, 231}, // dive - {2484, 142}, // civil - {2486, 232}, // divorce - {2517, 143}, // class - {2519, 144}, // clay - {2531, 145}, // cleanup - {2543, 146}, // client - {2545, 147}, // climate - {2546, 148}, // clinic - {2562, 149}, // clock - {2564, 150}, // clogs - {2567, 151}, // closet - {2568, 152}, // clothes - {2581, 153}, // club - {2587, 154}, // cluster - {2615, 155}, // coal - {2617, 156}, // coastal - {2624, 157}, // coding - {2628, 233}, // document - {2651, 234}, // domain - {2653, 235}, // domestic - {2654, 236}, // dominant - {2656, 159}, // company - {2658, 158}, // column - {2676, 160}, // corner - {2678, 161}, // costume - {2683, 164}, // cover - {2684, 237}, // dough - {2686, 162}, // counter - {2687, 163}, // course - {2691, 165}, // cowboy - {2696, 238}, // downtown - {2712, 166}, // cradle - {2713, 167}, // craft - {2714, 239}, // dragon - {2715, 240}, // dramatic - {2719, 168}, // crazy - {2731, 241}, // dream - {2732, 169}, // credit - {2737, 242}, // dress - {2742, 170}, // cricket - {2743, 243}, // drift - {2745, 171}, // criminal - {2746, 244}, // drink - {2747, 172}, // crisis - {2748, 173}, // critical - {2768, 245}, // drove - {2769, 174}, // crowd - {2782, 175}, // crucial - {2784, 246}, // drug - {2786, 176}, // crunch - {2787, 177}, // crush - {2793, 247}, // dryer - {2797, 178}, // crystal - {2814, 179}, // cubic - {2825, 248}, // duckling - {2853, 249}, // duke - {2858, 180}, // cultural - {2871, 250}, // duration - {2874, 181}, // curious - {2875, 182}, // curly - {2878, 183}, // custody - {2917, 251}, // dwarf - {2954, 184}, // cylinder - {2961, 252}, // dynamic - {3124, 323}, // facility - {3128, 324}, // fact - {3145, 325}, // failure - {3146, 326}, // faint - {3153, 327}, // fake - {3154, 329}, // family - {3156, 330}, // famous - {3157, 328}, // false - {3162, 331}, // fancy - {3164, 332}, // fangs - {3168, 333}, // fantasy - {3173, 255}, // easel - {3175, 253}, // early - {3178, 254}, // earth - {3179, 256}, // easy - {3181, 334}, // fatal - {3184, 335}, // fatigue - {3186, 336}, // favorite - {3196, 337}, // fawn - {3243, 260}, // edge - {3246, 257}, // echo - {3248, 261}, // editor - {3254, 258}, // eclipse - {3265, 259}, // ecology - {3282, 262}, // educate - {3413, 338}, // fiber - {3428, 339}, // fiction - {3458, 340}, // filter - {3461, 341}, // finance - {3462, 342}, // findings - {3464, 343}, // finger - {3472, 346}, // fiscal - {3473, 344}, // firefly - {3474, 347}, // fishing - {3475, 345}, // firm - {3484, 263}, // either - {3486, 348}, // fitness - {3514, 273}, // email - {3515, 349}, // flame - {3516, 264}, // elbow - {3517, 350}, // flash - {3518, 351}, // flavor - {3523, 265}, // elder - {3531, 352}, // flea - {3532, 266}, // election - {3534, 267}, // elegant - {3535, 268}, // element - {3536, 269}, // elephant - {3537, 274}, // emerald - {3538, 270}, // elevator - {3539, 353}, // flexible - {3546, 354}, // flip - {3547, 275}, // emission - {3548, 271}, // elite - {3561, 355}, // float - {3563, 276}, // emperor - {3564, 277}, // emphasis - {3565, 278}, // employer - {3567, 356}, // floral - {3568, 279}, // empty - {3573, 272}, // else - {3583, 357}, // fluff - {3624, 280}, // ending - {3625, 281}, // endless - {3626, 282}, // endorse - {3628, 358}, // focus - {3635, 283}, // enemy - {3636, 285}, // enforce - {3637, 284}, // energy - {3641, 286}, // engage - {3642, 292}, // epidemic - {3646, 287}, // enjoy - {3647, 293}, // episode - {3651, 288}, // enlarge - {3671, 359}, // forbid - {3672, 360}, // force - {3673, 361}, // forecast - {3674, 362}, // forget - {3675, 363}, // formal - {3678, 364}, // fortune - {3679, 365}, // forward - {3681, 294}, // equation - {3683, 290}, // envelope - {3684, 295}, // equip - {3686, 366}, // founder - {3687, 289}, // entrance - {3689, 291}, // envy - {3712, 367}, // fraction - {3714, 368}, // fragment - {3717, 296}, // eraser - {3721, 298}, // escape - {3736, 369}, // frequent - {3737, 370}, // freshman - {3741, 371}, // friar - {3742, 372}, // fridge - {3743, 373}, // friendly - {3762, 297}, // erode - {3767, 374}, // frost - {3768, 375}, // froth - {3769, 376}, // frozen - {3781, 299}, // estate - {3784, 300}, // estimate - {3815, 301}, // evaluate - {3836, 302}, // evening - {3842, 303}, // evidence - {3845, 304}, // evil - {3853, 377}, // fumes - {3862, 378}, // funding - {3865, 305}, // evoke - {3873, 380}, // fused - {3875, 379}, // furl - {3912, 306}, // exact - {3915, 307}, // example - {3923, 308}, // exceed - {3924, 309}, // exchange - {3925, 310}, // exclude - {3928, 311}, // excuse - {3931, 322}, // eyebrow - {3932, 312}, // execute - {3937, 313}, // exercise - {3941, 314}, // exhaust - {3961, 316}, // expand - {3963, 317}, // expect - {3965, 318}, // explain - {3967, 319}, // express - {3968, 315}, // exotic - {3983, 320}, // extend - {3987, 321}, // extra - {4125, 483}, // jacket - {4147, 420}, // hairy - {4151, 381}, // galaxy - {4153, 382}, // game - {4157, 421}, // hamster - {4162, 422}, // hand - {4164, 423}, // hanger - {4171, 383}, // garbage - {4172, 384}, // garden - {4175, 385}, // garlic - {4176, 386}, // gasoline - {4178, 424}, // harvest - {4183, 425}, // have - {4184, 387}, // gather - {4186, 426}, // havoc - {4191, 428}, // hazard - {4195, 427}, // hawk - {4231, 452}, // idea - {4236, 453}, // identify - {4253, 454}, // idle - {4312, 429}, // headset - {4315, 430}, // health - {4317, 431}, // hearing - {4318, 432}, // heat - {4356, 433}, // helpful - {4363, 388}, // general - {4364, 389}, // genius - {4365, 392}, // geology - {4367, 390}, // genre - {4368, 391}, // genuine - {4371, 434}, // herald - {4372, 435}, // herd - {4374, 436}, // hesitate - {4375, 484}, // jerky - {4378, 393}, // gesture - {4393, 485}, // jewelry - {4512, 394}, // glad - {4514, 455}, // image - {4516, 395}, // glance - {4517, 396}, // glasses - {4536, 397}, // glen - {4545, 398}, // glimpse - {4561, 456}, // impact - {4565, 457}, // imply - {4567, 458}, // improve - {4568, 459}, // impulse - {4616, 437}, // hobo - {4618, 399}, // goat - {4623, 463}, // index - {4624, 464}, // indicate - {4625, 460}, // include - {4626, 461}, // income - {4627, 462}, // increase - {4628, 465}, // industry - {4631, 466}, // infant - {4636, 467}, // inform - {4643, 468}, // inherit - {4646, 486}, // join - {4648, 469}, // injury - {4651, 470}, // inmate - {4652, 400}, // golden - {4653, 440}, // home - {4654, 438}, // holiday - {4659, 439}, // holy - {4673, 471}, // insect - {4674, 472}, // inside - {4675, 441}, // hormone - {4676, 442}, // hospital - {4678, 473}, // install - {4681, 476}, // invasion - {4683, 474}, // intend - {4684, 475}, // intimate - {4686, 477}, // involve - {4687, 443}, // hour - {4712, 401}, // graduate - {4716, 402}, // grant - {4717, 403}, // grasp - {4718, 404}, // gravity - {4719, 405}, // gray - {4731, 406}, // greatest - {4743, 407}, // grief - {4745, 408}, // grill - {4746, 409}, // grin - {4747, 478}, // iris - {4751, 479}, // island - {4762, 410}, // grocery - {4765, 480}, // isolate - {4767, 411}, // gross - {4768, 412}, // group - {4769, 413}, // grownup - {4785, 414}, // grumpy - {4817, 415}, // guard - {4824, 487}, // judicial - {4835, 481}, // item - {4837, 416}, // guest - {4842, 488}, // juice - {4843, 444}, // huge - {4845, 417}, // guilt - {4848, 418}, // guitar - {4851, 445}, // human - {4854, 446}, // humidity - {4856, 489}, // jump - {4857, 419}, // gums - {4862, 490}, // junction - {4864, 491}, // junior - {4865, 492}, // junk - {4867, 482}, // ivory - {4868, 447}, // hunting - {4871, 448}, // husband - {4874, 449}, // hush - {4875, 450}, // husky - {4878, 494}, // justice - {4879, 493}, // jury - {4917, 451}, // hybrid - {5123, 502}, // laden - {5124, 549}, // machine - {5125, 503}, // ladle - {5129, 504}, // ladybug - {5141, 550}, // magazine - {5142, 551}, // maiden - {5145, 552}, // mailman - {5146, 553}, // main - {5147, 505}, // lair - {5151, 556}, // mama - {5153, 554}, // makeup - {5154, 555}, // making - {5156, 506}, // lamp - {5161, 557}, // manager - {5162, 558}, // mandate - {5164, 507}, // language - {5167, 559}, // mansion - {5168, 560}, // manual - {5171, 561}, // marathon - {5172, 562}, // march - {5173, 509}, // laser - {5174, 508}, // large - {5175, 563}, // market - {5176, 565}, // mason - {5178, 564}, // marvel - {5183, 566}, // material - {5184, 567}, // math - {5186, 510}, // laundry - {5194, 568}, // maximum - {5196, 569}, // mayor - {5197, 511}, // lawsuit - {5312, 512}, // leader - {5313, 513}, // leaf - {5316, 570}, // meaning - {5317, 514}, // learn - {5318, 515}, // leaves - {5321, 571}, // medal - {5324, 572}, // medical - {5328, 516}, // lecture - {5341, 517}, // legal - {5343, 518}, // legend - {5347, 519}, // legs - {5351, 573}, // member - {5356, 574}, // memory - {5362, 520}, // lend - {5364, 521}, // length - {5368, 575}, // mental - {5372, 576}, // merchant - {5374, 577}, // merit - {5376, 495}, // kernel - {5383, 522}, // level - {5384, 578}, // method - {5387, 579}, // metric - {5391, 496}, // keyboard - {5413, 523}, // liberty - {5417, 524}, // library - {5423, 525}, // license - {5426, 497}, // kidney - {5427, 580}, // midst - {5438, 526}, // lift - {5451, 528}, // lilac - {5452, 581}, // mild - {5453, 527}, // likely - {5454, 582}, // military - {5459, 529}, // lily - {5462, 498}, // kind - {5463, 583}, // mineral - {5464, 584}, // minister - {5467, 530}, // lips - {5468, 531}, // liquid - {5471, 585}, // miracle - {5478, 532}, // listen - {5482, 499}, // kitchen - {5483, 533}, // literary - {5484, 534}, // living - {5491, 535}, // lizard - {5493, 586}, // mixed - {5498, 587}, // mixture - {5613, 537}, // lobe - {5614, 588}, // mobile - {5616, 536}, // loan - {5621, 538}, // location - {5623, 589}, // modern - {5624, 590}, // modify - {5643, 500}, // knife - {5647, 591}, // moisture - {5648, 501}, // knit - {5653, 592}, // moment - {5674, 539}, // losing - {5676, 593}, // morning - {5678, 594}, // mortgage - {5682, 540}, // loud - {5683, 598}, // move - {5684, 595}, // mother - {5686, 596}, // mountain - {5687, 597}, // mouse - {5691, 541}, // loyalty - {5824, 599}, // much - {5825, 542}, // luck - {5853, 600}, // mule - {5858, 601}, // multiple - {5861, 543}, // lunar - {5862, 544}, // lunch - {5864, 545}, // lungs - {5872, 602}, // muscle - {5873, 603}, // museum - {5874, 604}, // music - {5878, 605}, // mustang - {5898, 546}, // luxury - {5946, 547}, // lying - {5974, 548}, // lyrics - {6123, 636}, // paces - {6124, 637}, // pacific - {6125, 638}, // package - {6137, 618}, // obesity - {6141, 641}, // pajamas - {6142, 639}, // paid - {6143, 619}, // object - {6145, 606}, // nail - {6146, 640}, // painting - {6161, 644}, // papa - {6162, 642}, // pancake - {6163, 645}, // paper - {6168, 643}, // pants - {6172, 646}, // parcel - {6173, 620}, // observe - {6174, 617}, // oasis - {6175, 647}, // parking - {6178, 648}, // party - {6181, 621}, // obtain - {6183, 649}, // patent - {6184, 607}, // national - {6187, 650}, // patrol - {6195, 651}, // payment - {6197, 652}, // payroll - {6231, 622}, // ocean - {6312, 653}, // peaceful - {6316, 654}, // peanut - {6317, 655}, // peasant - {6321, 656}, // pecan - {6325, 608}, // necklace - {6341, 609}, // negative - {6361, 657}, // penalty - {6362, 658}, // pencil - {6372, 659}, // percent - {6373, 660}, // perfect - {6375, 661}, // permit - {6378, 610}, // nervous - {6383, 623}, // often - {6384, 662}, // petition - {6389, 611}, // network - {6397, 612}, // news - {6416, 663}, // phantom - {6417, 664}, // pharmacy - {6425, 668}, // pickup - {6428, 669}, // picture - {6432, 670}, // piece - {6453, 671}, // pile - {6463, 673}, // pipeline - {6465, 672}, // pink - {6468, 665}, // photo - {6471, 666}, // phrase - {6478, 674}, // pistol - {6482, 675}, // pitch - {6497, 667}, // physics - {6514, 676}, // plains - {6516, 677}, // plan - {6517, 678}, // plastic - {6518, 679}, // platform - {6519, 680}, // playoff - {6531, 681}, // pleasure - {6548, 625}, // omit - {6568, 682}, // plot - {6586, 683}, // plunge - {6595, 624}, // olympic - {6712, 684}, // practice - {6714, 628}, // orbit - {6715, 626}, // oral - {6716, 627}, // orange - {6719, 685}, // prayer - {6723, 629}, // order - {6724, 630}, // ordinary - {6731, 686}, // preach - {6732, 687}, // predator - {6734, 688}, // pregnant - {6735, 689}, // premium - {6736, 690}, // prepare - {6737, 691}, // presence - {6738, 692}, // prevent - {6741, 631}, // organize - {6743, 693}, // priest - {6745, 694}, // primary - {6746, 695}, // priority - {6747, 696}, // prisoner - {6748, 697}, // privacy - {6749, 698}, // prize - {6761, 699}, // problem - {6762, 700}, // process - {6763, 701}, // profile - {6764, 702}, // program - {6765, 703}, // promise - {6767, 704}, // prospect - {6768, 705}, // provide - {6786, 706}, // prune - {6815, 707}, // public - {6816, 716}, // quantity - {6817, 717}, // quarter - {6825, 613}, // nuclear - {6836, 633}, // oven - {6837, 634}, // overall - {6842, 718}, // quick - {6843, 719}, // quiet - {6851, 614}, // numb - {6853, 615}, // numerous - {6856, 709}, // pumps - {6857, 708}, // pulse - {6861, 712}, // pupal - {6862, 632}, // ounce - {6864, 710}, // punish - {6869, 711}, // puny - {6872, 713}, // purchase - {6876, 714}, // purple - {6956, 616}, // nylon - {6963, 635}, // owner - {6984, 715}, // python - {7121, 722}, // radar - {7123, 720}, // race - {7124, 721}, // racism - {7125, 775}, // sack - {7131, 776}, // safari - {7145, 723}, // railroad - {7146, 724}, // rainbow - {7147, 725}, // raisin - {7151, 777}, // salary - {7156, 778}, // salon - {7158, 779}, // salt - {7162, 726}, // random - {7164, 728}, // rapids - {7165, 727}, // ranked - {7176, 729}, // raspy - {7183, 782}, // saver - {7184, 780}, // satisfy - {7186, 781}, // satoshi - {7197, 783}, // says - {7216, 784}, // scandal - {7217, 785}, // scared - {7218, 786}, // scatter - {7236, 787}, // scene - {7243, 789}, // science - {7246, 788}, // scholar - {7268, 790}, // scout - {7271, 791}, // scramble - {7273, 792}, // screw - {7274, 793}, // script - {7276, 794}, // scroll - {7312, 730}, // reaction - {7313, 795}, // seafood - {7315, 731}, // realize - {7316, 732}, // rebound - {7317, 796}, // season - {7318, 733}, // rebuild - {7321, 734}, // recall - {7323, 735}, // receiver - {7326, 736}, // recover - {7327, 797}, // secret - {7328, 798}, // security - {7343, 739}, // reject - {7345, 799}, // segment - {7347, 737}, // regret - {7348, 738}, // regular - {7351, 740}, // relate - {7353, 741}, // remember - {7354, 742}, // remind - {7356, 743}, // remove - {7361, 745}, // repair - {7362, 744}, // render - {7363, 746}, // repeat - {7364, 800}, // senior - {7365, 747}, // replace - {7368, 748}, // require - {7372, 749}, // rescue - {7373, 750}, // research - {7374, 751}, // resident - {7376, 752}, // response - {7378, 753}, // result - {7381, 754}, // retailer - {7383, 757}, // revenue - {7384, 758}, // review - {7386, 756}, // reunion - {7387, 755}, // retreat - {7391, 759}, // reward - {7412, 801}, // shadow - {7413, 802}, // shaft - {7415, 803}, // shame - {7416, 804}, // shaped - {7417, 805}, // sharp - {7423, 811}, // sidewalk - {7424, 762}, // rich - {7435, 806}, // shelter - {7437, 807}, // sheriff - {7453, 812}, // silent - {7454, 814}, // similar - {7456, 815}, // simple - {7458, 813}, // silver - {7464, 816}, // single - {7467, 808}, // short - {7468, 809}, // should - {7474, 810}, // shrimp - {7478, 817}, // sister - {7481, 763}, // rival - {7483, 764}, // river - {7495, 760}, // rhyme - {7498, 761}, // rhythm - {7516, 820}, // slap - {7517, 827}, // smart - {7518, 821}, // slavery - {7531, 828}, // smear - {7532, 822}, // sled - {7535, 829}, // smell - {7542, 823}, // slice - {7545, 824}, // slim - {7546, 818}, // skin - {7547, 830}, // smirk - {7548, 831}, // smith - {7565, 832}, // smoking - {7569, 825}, // slow - {7584, 833}, // smug - {7586, 819}, // skunk - {7587, 826}, // slush - {7612, 843}, // space - {7614, 765}, // robin - {7615, 834}, // snake - {7616, 835}, // snapshot - {7617, 844}, // spark - {7624, 837}, // society - {7625, 766}, // rocky - {7631, 845}, // speak - {7632, 846}, // species - {7635, 847}, // spelling - {7636, 848}, // spend - {7638, 838}, // software - {7639, 849}, // spew - {7642, 850}, // spider - {7643, 836}, // sniff - {7645, 851}, // spill - {7646, 852}, // spine - {7647, 853}, // spirit - {7648, 854}, // spit - {7651, 767}, // romantic - {7652, 839}, // soldier - {7656, 768}, // romp - {7658, 840}, // solution - {7671, 855}, // spray - {7674, 856}, // sprinkle - {7678, 769}, // roster - {7681, 857}, // square - {7683, 858}, // squeeze - {7685, 841}, // soul - {7686, 770}, // round - {7687, 842}, // source - {7691, 771}, // royal - {7812, 859}, // stadium - {7813, 860}, // staff - {7814, 873}, // subject - {7815, 874}, // submit - {7816, 861}, // standard - {7817, 862}, // starting - {7818, 863}, // station - {7819, 864}, // stay - {7831, 865}, // steady - {7836, 866}, // step - {7841, 875}, // sugar - {7842, 867}, // stick - {7845, 868}, // stilt - {7846, 772}, // ruin - {7848, 876}, // suitable - {7853, 773}, // ruler - {7856, 774}, // rumor - {7863, 878}, // superior - {7865, 877}, // sunlight - {7867, 869}, // story - {7871, 870}, // strategy - {7873, 879}, // surface - {7874, 871}, // strike - {7876, 880}, // surprise - {7878, 881}, // survive - {7895, 872}, // style - {7931, 882}, // sweater - {7945, 883}, // swimming - {7946, 884}, // swing - {7948, 885}, // switch - {7951, 886}, // symbolic - {7956, 887}, // sympathy - {7962, 888}, // syndrome - {7978, 889}, // system - {8125, 890}, // tackle - {8126, 892}, // tadpole - {8128, 891}, // tactics - {8153, 893}, // talent - {8154, 965}, // valid - {8156, 967}, // vampire - {8158, 966}, // valuable - {8164, 968}, // vanish - {8174, 969}, // various - {8175, 894}, // task - {8178, 895}, // taste - {8184, 896}, // taught - {8194, 897}, // taxi - {8312, 898}, // teacher - {8315, 899}, // teammate - {8317, 900}, // teaspoon - {8341, 970}, // vegan - {8356, 901}, // temple - {8358, 971}, // velvet - {8361, 902}, // tenant - {8362, 903}, // tendency - {8367, 904}, // tension - {8368, 972}, // venture - {8372, 973}, // verdict - {8374, 974}, // verify - {8375, 905}, // terminal - {8378, 906}, // testify - {8379, 975}, // very - {8383, 976}, // veteran - {8393, 977}, // vexed - {8398, 907}, // texture - {8416, 908}, // thank - {8418, 909}, // that - {8423, 979}, // video - {8425, 917}, // ticket - {8428, 978}, // victim - {8429, 918}, // tidy - {8431, 910}, // theater - {8436, 911}, // theory - {8437, 912}, // therapy - {8439, 980}, // view - {8451, 919}, // timber - {8453, 920}, // timely - {8459, 946}, // ugly - {8464, 921}, // ting - {8465, 982}, // violence - {8467, 913}, // thorn - {8468, 981}, // vintage - {8471, 983}, // viral - {8473, 914}, // threaten - {8474, 984}, // visitor - {8478, 985}, // visual - {8481, 986}, // vitamins - {8485, 915}, // thumb - {8486, 916}, // thunder - {8517, 948}, // umbrella - {8584, 947}, // ultimate - {8621, 987}, // vocal - {8623, 950}, // undergo - {8626, 949}, // uncover - {8631, 951}, // unfair - {8636, 952}, // unfold - {8638, 922}, // tofu - {8641, 953}, // unhappy - {8642, 988}, // voice - {8643, 923}, // together - {8646, 954}, // union - {8647, 960}, // upgrade - {8648, 955}, // universe - {8653, 924}, // tolerate - {8654, 956}, // unkind - {8656, 957}, // unknown - {8658, 989}, // volume - {8678, 961}, // upstairs - {8681, 925}, // total - {8683, 990}, // voter - {8684, 991}, // voting - {8687, 958}, // unusual - {8694, 926}, // toxic - {8697, 959}, // unwrap - {8712, 927}, // tracks - {8713, 928}, // traffic - {8714, 929}, // training - {8716, 930}, // transfer - {8717, 931}, // trash - {8718, 932}, // traveler - {8731, 933}, // treat - {8736, 934}, // trend - {8737, 962}, // username - {8741, 935}, // trial - {8742, 936}, // tricycle - {8743, 963}, // usher - {8746, 937}, // trip - {8748, 938}, // triumph - {8768, 939}, // trouble - {8781, 964}, // usual - {8783, 940}, // true - {8787, 941}, // trust - {8942, 942}, // twice - {8946, 943}, // twin - {8963, 944}, // type - {8964, 945}, // typical - {9156, 992}, // walnut - {9175, 993}, // warmth - {9176, 994}, // warn - {9182, 995}, // watch - {9189, 996}, // wavy - {9312, 999}, // webcam - {9315, 997}, // wealthy - {9316, 998}, // weapon - {9317, 1019}, // year - {9352, 1000}, // welcome - {9353, 1001}, // welfare - {9356, 1020}, // yelp - {9376, 1023}, // zero - {9378, 1002}, // western - {9428, 1003}, // width - {9435, 1021}, // yield - {9452, 1004}, // wildlife - {9462, 1005}, // window - {9463, 1006}, // wine - {9472, 1008}, // wisdom - {9473, 1007}, // wireless - {9484, 1009}, // withdraw - {9487, 1010}, // wits - {9641, 1022}, // yoga - {9651, 1012}, // woman - {9653, 1011}, // wolf - {9675, 1013}, // work - {9678, 1014}, // worthy - {9716, 1015}, // wrap - {9747, 1016}, // wrist - {9748, 1017}, // writing - {9768, 1018}, // wrote -}; - -#endif diff --git a/deps/crypto/trezor-crypto/tests/test_bignum.py b/deps/crypto/trezor-crypto/tests/test_bignum.py deleted file mode 100755 index b99685a1a..000000000 --- a/deps/crypto/trezor-crypto/tests/test_bignum.py +++ /dev/null @@ -1,1032 +0,0 @@ -#!/usr/bin/python -import ctypes -import itertools -import os -import random -from ctypes import ( - c_bool, - c_int, - c_size_t, - c_uint, - c_uint8, - c_uint16, - c_uint32, - c_uint64, -) -from math import floor, log, sqrt - -import pytest - -dir = os.path.abspath(os.path.dirname(__file__)) -lib = ctypes.cdll.LoadLibrary(os.path.join(dir, "libtrezor-crypto.so")) - -limbs_number = 9 -bits_per_limb = 29 - - -@pytest.fixture() -def prime(request): - return 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F - - -@pytest.fixture(params=range(limbs_number * bits_per_limb)) -def bignum_bit_index(request): - return request.param - - -max_decimal_digits = floor(limbs_number * bits_per_limb * log(2, 10)) - - -@pytest.fixture(params=range(max_decimal_digits)) -def bignum_decimal_digit_index(request): - return request.param - - -iterations = int(os.environ.get("ITERS", 1000)) - - -@pytest.fixture(params=range(iterations)) -def r(request): - return Random(request.param) - - -def implication(p, c): - return not p or c - - -def uint32_p_to_int(pointer): - return pointer.contents.value - - -def uint32_p(): - return ctypes.POINTER(c_int)(c_int()) - - -limb_type = c_uint32 - - -def bignum(limbs_number=limbs_number): - return (limbs_number * limb_type)() - - -def limbs_to_bignum(limbs): - return (limbs_number * limb_type)(*limbs) - - -def int_to_bignum(number, limbs_number=limbs_number): - assert number >= 0 - assert number.bit_length() <= limbs_number * bits_per_limb - - bn = (limbs_number * limb_type)() - for i in range(limbs_number): - bn[i] = number % 2 ** bits_per_limb - number //= 2 ** bits_per_limb - - return bn - - -def bignum_to_int(bignum, limbs_number=limbs_number): - number = 0 - - for i in reversed(range(limbs_number)): - number *= 2 ** bits_per_limb - number += bignum[i] - - return number - - -def raw_number(): - return (32 * c_uint8)() - - -def raw_number_to_integer(raw_number, endianess): - return int.from_bytes(raw_number, endianess) - - -def integer_to_raw_number(number, endianess): - return (32 * c_uint8)(*number.to_bytes(32, endianess)) - - -def bignum_is_normalised(bignum): - for limb in bignum: - if limb > 2 ** bits_per_limb: - return False - return True - - -def number_is_partly_reduced(number, prime): - return number < 2 * prime - - -def number_is_fully_reduced(number, prime): - return number < prime - - -class Random(random.Random): - def rand_int_normalized(self): - return self.randrange(0, 2 ** (limbs_number * bits_per_limb)) - - def rand_int_256(self): - return self.randrange(0, 2 ** 256) - - def rand_int_reduced(self, p): - return self.randrange(0, 2 * p) - - def rand_int_bitsize(self, bitsize): - return self.randrange(0, 2 ** bitsize) - - def rand_bit_index(self): - return self.randrange(0, limbs_number * bits_per_limb) - - def rand_bignum(self, limbs_number=limbs_number): - return (limb_type * limbs_number)( - *[self.randrange(0, 256 ** 4) for _ in range(limbs_number)] - ) - - -def assert_bn_read_be(in_number): - raw_in_number = integer_to_raw_number(in_number, "big") - bn_out_number = bignum() - lib.bn_read_be(raw_in_number, bn_out_number) - out_number = bignum_to_int(bn_out_number) - - assert bignum_is_normalised(bn_out_number) - assert out_number == in_number - - -def assert_bn_read_le(in_number): - raw_in_number = integer_to_raw_number(in_number, "little") - bn_out_number = bignum() - lib.bn_read_le(raw_in_number, bn_out_number) - out_number = bignum_to_int(bn_out_number) - - assert bignum_is_normalised(bn_out_number) - assert out_number == in_number - - -def assert_bn_write_be(in_number): - bn_in_number = int_to_bignum(in_number) - raw_out_number = raw_number() - lib.bn_write_be(bn_in_number, raw_out_number) - out_number = raw_number_to_integer(raw_out_number, "big") - - assert out_number == in_number - - -def assert_bn_write_le(in_number): - bn_in_number = int_to_bignum(in_number) - raw_out_number = raw_number() - lib.bn_write_le(bn_in_number, raw_out_number) - out_number = raw_number_to_integer(raw_out_number, "little") - - assert out_number == in_number - - -def assert_bn_read_uint32(x): - bn_out_number = bignum() - lib.bn_read_uint32(c_uint32(x), bn_out_number) - out_number = bignum_to_int(bn_out_number) - - assert bignum_is_normalised(bn_out_number) - assert out_number == x - - -def assert_bn_read_uint64(x): - bn_out_number = bignum() - lib.bn_read_uint64(c_uint64(x), bn_out_number) - out_number = bignum_to_int(bn_out_number) - - assert bignum_is_normalised(bn_out_number) - assert out_number == x - - -def assert_bn_bitcount(x): - bn_x = int_to_bignum(x) - return_value = lib.bn_bitcount(bn_x) - - assert return_value == x.bit_length() - - -def assert_bn_digitcount(x): - bn_x = int_to_bignum(x) - return_value = lib.bn_digitcount(bn_x) - - assert return_value == len(str(x)) - - -def assert_bn_zero(): - bn_x = bignum() - lib.bn_zero(bn_x) - x = bignum_to_int(bn_x) - - assert bignum_is_normalised(bn_x) - assert x == 0 - - -def assert_bn_one(): - bn_x = bignum() - lib.bn_one(bn_x) - x = bignum_to_int(bn_x) - - assert bignum_is_normalised(bn_x) - assert x == 1 - - -def assert_bn_is_zero(x): - bn_x = int_to_bignum(x) - return_value = lib.bn_is_zero(bn_x) - - assert return_value == (x == 0) - - -def assert_bn_is_one(x): - bn_x = int_to_bignum(x) - return_value = lib.bn_is_one(bn_x) - - assert return_value == (x == 1) - - -def assert_bn_is_less(x, y): - bn_x = int_to_bignum(x) - bn_y = int_to_bignum(y) - return_value = lib.bn_is_less(bn_x, bn_y) - - assert return_value == (x < y) - - -def assert_bn_is_equal(x, y): - bn_x = int_to_bignum(x) - bn_y = int_to_bignum(y) - return_value = lib.bn_is_equal(bn_x, bn_y) - - assert return_value == (x == y) - - -def assert_bn_cmov(cond, truecase, falsecase): - bn_res = bignum() - bn_truecase = int_to_bignum(truecase) - bn_falsecase = int_to_bignum(falsecase) - lib.bn_cmov(bn_res, c_uint32(cond), bn_truecase, bn_falsecase) - res = bignum_to_int(bn_res) - - assert res == truecase if cond else falsecase - - -def assert_bn_cnegate(cond, x_old, prime): - bn_x = int_to_bignum(x_old) - bn_prime = int_to_bignum(prime) - lib.bn_cnegate(c_uint32(cond), bn_x, bn_prime) - x_new = bignum_to_int(bn_x) - - assert bignum_is_normalised(bn_x) - assert number_is_partly_reduced(x_new, prime) - assert x_new % prime == -x_old % prime if cond else x_old % prime - - -def assert_bn_lshift(x_old): - bn_x = int_to_bignum(x_old) - lib.bn_lshift(bn_x) - x_new = bignum_to_int(bn_x) - - assert bignum_is_normalised(bn_x) - assert x_new == (x_old << 1) - - -def assert_bn_rshift(x_old): - bn_x = int_to_bignum(x_old) - lib.bn_rshift(bn_x) - x_new = bignum_to_int(bn_x) - - assert bignum_is_normalised(bn_x) - assert x_new == (x_old >> 1) - - -def assert_bn_setbit(x_old, i): - bn_x = int_to_bignum(x_old) - lib.bn_setbit(bn_x, c_uint16(i)) - x_new = bignum_to_int(bn_x) - - assert bignum_is_normalised(bn_x) - assert x_new == x_old | (1 << i) - - -def assert_bn_clearbit(x_old, i): - bn_x = int_to_bignum(x_old) - lib.bn_clearbit(bn_x, c_uint16(i)) - x_new = bignum_to_int(bn_x) - - assert bignum_is_normalised(bn_x) - assert x_new == x_old & ~(1 << i) - - -def assert_bn_testbit(x_old, i): - bn_x = int_to_bignum(x_old) - return_value = lib.bn_testbit(bn_x, c_uint16(i)) - - assert return_value == x_old >> i & 1 - - -def assert_bn_xor(x, y): - bn_res = bignum() - bn_x = int_to_bignum(x) - bn_y = int_to_bignum(y) - lib.bn_xor(bn_res, bn_x, bn_y) - res = bignum_to_int(bn_res) - - assert res == x ^ y - - -def assert_bn_mult_half(x_old, prime): - bn_x = int_to_bignum(x_old) - bn_prime = int_to_bignum(prime) - lib.bn_mult_half(bn_x, bn_prime) - x_new = bignum_to_int(bn_x) - - assert implication( - number_is_partly_reduced(x_old, prime), number_is_partly_reduced(x_new, prime) - ) - assert x_new == (x_old + prime) >> 1 if x_old & 1 else x_old >> 1 - - -def assert_bn_mult_k(x_old, k, prime): - bn_x = int_to_bignum(x_old) - bn_prime = int_to_bignum(prime) - lib.bn_mult_k(bn_x, c_uint8(k), bn_prime) - x_new = bignum_to_int(bn_x) - - assert bignum_is_normalised(bn_x) - assert number_is_partly_reduced(x_new, prime) - assert x_new == (x_old * k) % prime - - -def assert_bn_mod(x_old, prime): - bn_x = int_to_bignum(x_old) - bn_prime = int_to_bignum(prime) - lib.bn_mod(bn_x, bn_prime) - x_new = bignum_to_int(bn_x) - - assert bignum_is_normalised(bn_x) - assert number_is_fully_reduced(x_new, prime) - assert x_new == x_old % prime - - -def assert_bn_multiply_long(k_old, x_old): - bn_k = int_to_bignum(k_old) - bn_x = int_to_bignum(x_old) - bn_res = bignum(2 * limbs_number) - lib.bn_multiply_long(bn_k, bn_x, bn_res) - res = bignum_to_int(bn_res, 2 * limbs_number) - - assert res == k_old * x_old - - -def assert_bn_multiply_reduce_step(res_old, prime, d): - bn_res = int_to_bignum(res_old, 2 * limbs_number) - bn_prime = int_to_bignum(prime) - lib.bn_multiply_reduce_step(bn_res, bn_prime, d) - res_new = bignum_to_int(bn_res, 2 * limbs_number) - - assert bignum_is_normalised(bn_res) - assert res_new < 2 * prime * 2 ** (d * bits_per_limb) - - -def assert_bn_multiply(k, x_old, prime): - bn_k = int_to_bignum(k) - bn_x = int_to_bignum(x_old) - bn_prime = int_to_bignum(prime) - lib.bn_multiply(bn_k, bn_x, bn_prime) - x_new = bignum_to_int(bn_x) - - assert bignum_is_normalised(bn_x) - assert number_is_partly_reduced(x_new, prime) - assert x_new == (k * x_old) % prime - - -def assert_bn_fast_mod(x_old, prime): - bn_x = int_to_bignum(x_old) - bn_prime = int_to_bignum(prime) - lib.bn_fast_mod(bn_x, bn_prime) - x_new = bignum_to_int(bn_x) - - assert bignum_is_normalised(bn_x) - assert number_is_partly_reduced(x_new, prime) - assert x_new % prime == x_old % prime - - -def assert_bn_fast_mod_bn(bn_x, prime): - bn_x - x_old = bignum_to_int(bn_x) - bn_prime = int_to_bignum(prime) - lib.bn_fast_mod(bn_x, bn_prime) - x_new = bignum_to_int(bn_x) - - assert bignum_is_normalised(bn_x) - assert number_is_partly_reduced(x_new, prime) - assert x_new % prime == x_old % prime - - -def assert_bn_power_mod(x, e, prime): - bn_x = int_to_bignum(x) - bn_e = int_to_bignum(e) - bn_prime = int_to_bignum(prime) - bn_res_new = bignum() - lib.bn_power_mod(bn_x, bn_e, bn_prime, bn_res_new) - res_new = bignum_to_int(bn_res_new) - - assert bignum_is_normalised(bn_res_new) - assert number_is_partly_reduced(res_new, prime) - assert res_new % prime == pow(x, e, prime) - - -def assert_bn_sqrt(x_old, prime): - bn_x = int_to_bignum(x_old) - bn_prime = int_to_bignum(prime) - lib.bn_sqrt(bn_x, bn_prime) - x_new = bignum_to_int(bn_x) - - assert bignum_is_normalised(bn_x) - assert number_is_fully_reduced(x_new, prime) - assert x_new ** 2 % prime == x_old % prime - - -def assert_inverse_mod_power_two(x, m): - return_value = lib.inverse_mod_power_two(c_uint32(x), c_uint32(m)) - - assert return_value * x % 2 ** m == 1 - - -def assert_bn_divide_base(x_old, prime): - bn_x = int_to_bignum(x_old) - bn_prime = int_to_bignum(prime) - lib.bn_divide_base(bn_x, bn_prime) - x_new = bignum_to_int(bn_x) - - assert implication( - number_is_fully_reduced(x_old, prime), number_is_fully_reduced(x_new, prime) - ) - assert implication( - number_is_partly_reduced(x_old, prime), number_is_partly_reduced(x_new, prime) - ) - assert x_new * 2 ** bits_per_limb % prime == x_old % prime - - -def assert_bn_inverse(x_old, prime): - bn_x = int_to_bignum(x_old) - bn_prime = int_to_bignum(prime) - lib.bn_inverse(bn_x, bn_prime) - x_new = bignum_to_int(bn_x) - - assert bignum_is_normalised(bn_x) - assert number_is_fully_reduced(x_new, prime) - assert (x_old == 0 and x_new == 0) or (x_old != 0 and (x_old * x_new) % prime == 1) - - -def assert_bn_normalize(bn_x): - x_old = bignum_to_int(bn_x) - lib.bn_normalize(bn_x) - x_new = bignum_to_int(bn_x) - - assert x_new == x_old % 2 ** (bits_per_limb * limbs_number) - assert bignum_is_normalised(bn_x) - - -def assert_bn_add(x_old, y): - bn_x = int_to_bignum(x_old) - bn_y = int_to_bignum(y) - lib.bn_add(bn_x, bn_y) - x_new = bignum_to_int(bn_x) - y = bignum_to_int(bn_y) - - assert bignum_is_normalised(bn_x) - assert x_new == x_old + y - - -def assert_bn_addmod(x_old, y, prime): - bn_x = int_to_bignum(x_old) - bn_y = int_to_bignum(y) - bn_prime = int_to_bignum(prime) - lib.bn_addmod(bn_x, bn_y, bn_prime) - x_new = bignum_to_int(bn_x) - - assert bignum_is_normalised(bn_x) - assert number_is_partly_reduced(x_new, prime) - assert x_new % prime == (x_old + y) % prime - - -def assert_bn_addi(x_old, y): - bn_x = int_to_bignum(x_old) - lib.bn_addi(bn_x, c_uint32(y)) - x_new = bignum_to_int(bn_x) - - assert bignum_is_normalised(bn_x) - assert x_new == x_old + y - - -def assert_bn_subi(x_old, y, prime): - bn_x = int_to_bignum(x_old) - bn_prime = int_to_bignum(prime) - lib.bn_subi(bn_x, c_uint32(y), bn_prime) - x_new = bignum_to_int(bn_x) - - assert bignum_is_normalised(bn_x) - assert implication( - number_is_fully_reduced(x_old, prime), number_is_partly_reduced(x_new, prime) - ) - assert x_new % prime == (x_old - y) % prime - - -def assert_bn_subtractmod(x, y, prime): - bn_x = int_to_bignum(x) - bn_y = int_to_bignum(y) - bn_prime = int_to_bignum(prime) - bn_res = bignum() - lib.bn_subtractmod(bn_x, bn_y, bn_res, bn_prime) - res = bignum_to_int(bn_res) - - assert bignum_is_normalised(bn_x) - assert res % prime == (x - y) % prime - - -def assert_bn_subtract(x, y): - bn_x = int_to_bignum(x) - bn_y = int_to_bignum(y) - bn_res = bignum() - lib.bn_subtract(bn_x, bn_y, bn_res) - res = bignum_to_int(bn_res) - - assert bignum_is_normalised(bn_x) - assert res == x - y - - -def assert_bn_long_division(x, d): - bn_x = int_to_bignum(x) - bn_q = bignum() - uint32_p_r = uint32_p() - lib.bn_long_division(bn_x, d, bn_q, uint32_p_r) - r = uint32_p_to_int(uint32_p_r) - q = bignum_to_int(bn_q) - - assert bignum_is_normalised(bn_q) - assert q == x // d - assert r == x % d - - -def assert_bn_divmod58(x_old): - bn_x = int_to_bignum(x_old) - uint32_p_r = uint32_p() - lib.bn_divmod58(bn_x, uint32_p_r) - x_new = bignum_to_int(bn_x) - r = uint32_p_to_int(uint32_p_r) - - assert bignum_is_normalised(bn_x) - assert x_new == x_old // 58 - assert r == x_old % 58 - - -def assert_bn_divmod1000(x_old): - bn_x = int_to_bignum(x_old) - uint32_p_r = uint32_p() - lib.bn_divmod1000(bn_x, uint32_p_r) - x_new = bignum_to_int(bn_x) - r = uint32_p_to_int(uint32_p_r) - - assert bignum_is_normalised(bn_x) - assert x_new == x_old // 1000 - assert r == x_old % 1000 - - -def assert_bn_divmod10(x_old): - bn_x = int_to_bignum(x_old) - uint32_p_r = uint32_p() - lib.bn_divmod10(bn_x, uint32_p_r) - x_new = bignum_to_int(bn_x) - r = uint32_p_to_int(uint32_p_r) - - assert bignum_is_normalised(bn_x) - assert x_new == x_old // 10 - assert r == x_old % 10 - - -def assert_bn_format(x, prefix, suffix, decimals, exponent, trailing): - def format(amount, prefix, suffix, decimals, exponent, trailing): - if exponent >= 0: - amount *= 10 ** exponent - else: - amount //= 10 ** (-exponent) - - d = pow(10, decimals) - - if decimals: - output = "%d.%0*d" % (amount // d, decimals, amount % d) - if not trailing: - output = output.rstrip("0").rstrip(".") - else: - output = "%d" % (amount // d) - - return prefix + output + suffix - - def string_to_char_p(string): - return ctypes.create_string_buffer(string.encode("ascii")) - - def char_p_to_string(pointer): - return str(pointer.value, "ascii") - - bn_x = int_to_bignum(x) - output_length = 100 - output = string_to_char_p("?" * output_length) - return_value = lib.bn_format( - bn_x, - string_to_char_p(prefix), - string_to_char_p(suffix), - c_uint(decimals), - c_int(exponent), - c_bool(trailing), - output, - c_size_t(output_length), - ) - - correct_output = format(x, prefix, suffix, decimals, exponent, trailing) - correct_return_value = len(correct_output) - if len(correct_output) >= output_length: - correct_output = "" - correct_return_value = 0 - - assert char_p_to_string(output) == correct_output - assert return_value == correct_return_value - - -def test_bn_read_be(r): - assert_bn_read_be(r.rand_int_256()) - - -def test_bn_read_le(r): - assert_bn_read_le(r.rand_int_256()) - - -def test_bn_write_be(r): - assert_bn_write_be(r.rand_int_256()) - - -def test_bn_write_le(r): - assert_bn_write_le(r.rand_int_256()) - - -def test_bn_read_uint32(r): - assert_bn_read_uint32(r.rand_int_bitsize(32)) - - -def test_bn_read_uint64(r): - assert_bn_read_uint64(r.rand_int_bitsize(64)) - - -def test_bn_bitcount_1(r): - assert_bn_bitcount(r.rand_int_normalized()) - - -def test_bn_bitcount_2(bignum_bit_index): - assert_bn_bitcount(2 ** bignum_bit_index - 1) - assert_bn_bitcount(2 ** bignum_bit_index) - - -def test_bn_digitcount_1(r): - assert_bn_digitcount(r.rand_int_normalized()) - - -def test_bn_digitcount_2(bignum_decimal_digit_index): - assert_bn_digitcount(10 ** bignum_decimal_digit_index - 1) - assert_bn_digitcount(10 ** bignum_decimal_digit_index) - - -def test_bn_zero(): - assert_bn_zero() - - -def test_bn_one(): - assert_bn_one() - - -def test_bn_is_zero_1(): - assert_bn_is_zero(0) - assert_bn_is_zero(1) - - -def test_bn_is_zero_2(bignum_bit_index): - assert_bn_is_zero(2 ** bignum_bit_index) - - -def test_bn_is_one_1(): - assert_bn_is_one(0) - assert_bn_is_one(1) - - -def test_bn_is_one_2(bignum_bit_index): - assert_bn_is_one(2 ** bignum_bit_index) - - -def test_bn_is_less_1(r): - a = r.rand_int_normalized() - b = r.rand_int_normalized() - assert_bn_is_less(a, a) - assert_bn_is_less(a, b) - assert_bn_is_less(b, a) - - -def test_bn_is_less_2(r): - a = r.rand_int_normalized() - i = r.rand_bit_index() - b = a ^ 2 ** i - assert_bn_is_less(a, b) - - -def test_bn_is_less_3(): - assert_bn_is_less(0, 0) - assert_bn_is_less(1, 0) - assert_bn_is_less(0, 1) - assert_bn_is_less(1, 1) - - -def test_bn_is_equal_1(r): - a = r.rand_int_normalized() - b = r.rand_int_normalized() - assert_bn_is_equal(a, a) - assert_bn_is_equal(a, b) - - -def test_bn_is_equal_2(): - assert_bn_is_equal(0, 0) - assert_bn_is_equal(1, 0) - assert_bn_is_equal(0, 1) - assert_bn_is_equal(1, 1) - - -def test_bn_cmov(r): - a = r.rand_int_normalized() - b = r.rand_int_normalized() - assert_bn_cmov(0, a, b) - assert_bn_cmov(1, a, b) - - -def test_bn_cnegate(r, prime): - a = r.rand_int_reduced(prime) - assert_bn_cnegate(0, a, prime) - assert_bn_cnegate(1, a, prime) - - -def test_bn_lshift(r): - assert_bn_lshift(r.rand_int_normalized() // 2) - - -def test_bn_rshift(r): - assert_bn_rshift(r.rand_int_normalized()) - - -def test_bn_testbit(r): - assert_bn_testbit(r.rand_int_normalized(), r.rand_bit_index()) - - -def test_bn_setbit(r): - assert_bn_setbit(r.rand_int_normalized(), r.rand_bit_index()) - - -def test_bn_clearbit(r): - assert_bn_clearbit(r.rand_int_normalized(), r.rand_bit_index()) - - -def test_bn_xor(r): - assert_bn_xor(r.rand_int_normalized(), r.rand_int_normalized()) - - -def test_bn_mult_half_1(r, prime): - assert_bn_mult_half(r.rand_int_reduced(prime), prime) - - -def test_bn_mult_half_2(r, prime): - assert_bn_mult_half(r.rand_int_normalized(), prime) - - -def test_bn_mult_k(r, prime): - assert_bn_mult_k(r.rand_int_normalized(), r.randrange(9), prime) - - -def test_bn_mod_1(r, prime): - assert_bn_mod(r.rand_int_reduced(prime), prime) - - -def test_bn_mod_2(r, prime): - for x in [ - 0, - 1, - 2, - prime - 2, - prime - 1, - prime, - prime + 1, - prime + 2, - 2 * prime - 2, - 2 * prime - 1, - ]: - assert_bn_mod(x, prime) - - -def test_bn_multiply_long(r, prime): - x = r.randrange(floor(sqrt(2 ** 519))) - k = r.randrange(floor(sqrt(2 ** 519))) - assert_bn_multiply_long(k, x) - - -def test_bn_multiply_reduce_step(r, prime): - k = r.randrange(0, limbs_number) - res = r.randrange(2 ** (256 + 29 * k + 31)) - assert_bn_multiply_reduce_step(res, prime, k) - - -def test_bn_multiply(r, prime): - x = r.randrange(floor(sqrt(2 ** 519))) - k = r.randrange(floor(sqrt(2 ** 519))) - assert_bn_multiply(k, x, prime) - - -def test_bn_fast_mod_1(r, prime): - assert_bn_fast_mod(r.rand_int_normalized(), prime) - - -def test_bn_fast_mod_2(r, prime): - bn_x = r.rand_bignum() - assert_bn_fast_mod_bn(bn_x, prime) - - -def test_bn_power_mod(r, prime): - x = r.rand_int_bitsize(259) - e = r.rand_int_normalized() - assert_bn_power_mod(x, e, prime) - - -def test_bn_sqrt_1(prime): - assert_bn_sqrt(0, prime) - assert_bn_sqrt(1, prime) - - -def test_bn_sqrt_2(r, prime): - def is_quadratic_residuum(x, p): - return pow(x, (p - 1) // 2, p) == 1 - - while True: - x = r.rand_int_bitsize(259) - if is_quadratic_residuum(x, prime): - break - - assert_bn_sqrt(x, prime) - - -def test_inverse_mod_power_two(r): - m = r.randrange(1, 33) - i = r.randrange(1, 2 ** 29, 2) - assert_inverse_mod_power_two(i, m) - - -def test_bn_divide_base(r, prime): - assert_bn_divide_base(r.rand_int_256(), prime) - - -def test_bn_inverse_1(prime): - assert_bn_inverse(0, prime) - assert_bn_inverse(1, prime) - - -def test_bn_inverse_2(r, prime): - from math import gcd - - while True: - n = r.randrange(0, prime) - if gcd(n, prime) == 1: - break - - assert_bn_inverse(n, prime) - - -def test_bn_normalize(r): - assert_bn_normalize(r.rand_bignum()) - - -def test_bn_add_1(r): - assert_bn_add(r.rand_int_256(), r.rand_int_256()) - - -def test_bn_add_2(r): - while True: - a = r.rand_int_normalized() - b = r.rand_int_normalized() - if a + b < 2 ** (limbs_number * bits_per_limb): - break - assert_bn_add(a, b) - - -def test_bn_add_3(): - a = Random().rand_int_normalized() - b = 2 ** (limbs_number * bits_per_limb) - 1 - a - assert_bn_add(a, b) - - -def test_bn_addmod(r, prime): - assert_bn_addmod(r.rand_int_normalized(), r.rand_int_normalized(), prime) - - -def test_bn_addi_1(r): - while True: - a = r.rand_int_normalized() - b = r.randrange(2 ** 32 - 2 ** bits_per_limb + 1) - if a + b < 2 ** (limbs_number * bits_per_limb): - break - assert_bn_addi(a, b) - - -def test_bn_addi_2(): - b = 2 ** 32 - 2 ** bits_per_limb - a = 2 ** (limbs_number * bits_per_limb) - 1 - b - assert_bn_addi(a, b) - - -def test_bn_subi_1(r, prime): - while True: - a = r.rand_int_normalized() - b = r.randrange(prime % 2 ** bits_per_limb) - if a + prime - b < 2 ** (limbs_number * bits_per_limb): - break - assert_bn_subi(a, b, prime) - - -def test_bn_subi_2(prime): - b = (prime % 2 ** bits_per_limb) - 1 - a = 2 ** (limbs_number * bits_per_limb) - 1 - prime + b - assert_bn_subi(a, b, prime) - - -def test_bn_subtractmod_1(r, prime): - assert_bn_subtractmod(r.rand_int_256(), r.rand_int_256(), prime) - - -def test_bn_subtractmod_2(r, prime): - while True: - a = r.rand_int_normalized() - b = r.rand_int_reduced(prime) - if a + 2 * prime - b < 2 ** (limbs_number * bits_per_limb): - break - assert_bn_subtractmod(a, b, prime) - - -def test_bn_subtractmod_3(prime): - b = 2 * prime - 1 - a = 2 ** (limbs_number * bits_per_limb) - 1 - (2 * prime - b) - assert_bn_subtractmod(a, b, prime) - - -def test_bn_subtract_1(r): - a = r.rand_int_256() - b = r.rand_int_256() - if a < b: - a, b = b, a - assert_bn_subtract(a, b) - - -def test_bn_subtract_2(r): - a = r.rand_int_normalized() - b = r.rand_int_normalized() - if a < b: - a, b = b, a - assert_bn_subtract(a, b) - - -def test_bn_long_division(r): - x = r.rand_int_normalized() - d = r.randrange(1, 61304 + 1) - assert_bn_long_division(x, d) - - -def test_bn_divmod58(r): - x = r.rand_int_normalized() - assert_bn_divmod58(x) - - -def test_bn_divmod1000(r): - x = r.rand_int_normalized() - assert_bn_divmod1000(x) - - -def test_bn_divmod10(r): - x = r.rand_int_normalized() - assert_bn_divmod10(x) - - -@pytest.mark.parametrize( - "decimals,exponent,trailing,prefix,suffix,value", - itertools.product( - range(0, 5), - range(-5, 5), - [True, False], - ["", "prefix"], - ["", "suffix"], - [123, 120], - ), -) -def test_bn_format(decimals, exponent, trailing, prefix, suffix, value): - assert_bn_format(value, prefix, suffix, decimals, exponent, trailing) diff --git a/deps/crypto/trezor-crypto/tests/test_check.c b/deps/crypto/trezor-crypto/tests/test_check.c deleted file mode 100644 index 6192b6342..000000000 --- a/deps/crypto/trezor-crypto/tests/test_check.c +++ /dev/null @@ -1,9514 +0,0 @@ -/** - * Copyright (c) 2013-2014 Tomas Dzetkulic - * Copyright (c) 2013-2014 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "check_mem.h" - -#if VALGRIND -#include -#include -#endif - -#include "options.h" - -#include "address.h" -#include "aes/aes.h" -#include "base32.h" -#include "base58.h" -#include "bignum.h" -#include "bip32.h" -#include "bip39.h" -#include "blake256.h" -#include "blake2b.h" -#include "blake2s.h" -#include "chacha_drbg.h" -#include "curves.h" -#include "ecdsa.h" -#include "ed25519-donna/ed25519-donna.h" -#include "ed25519-donna/ed25519-keccak.h" -#include "ed25519-donna/ed25519.h" -#include "hmac_drbg.h" -#include "memzero.h" -#include "monero/monero.h" -#include "nem.h" -#include "nist256p1.h" -#include "pbkdf2.h" -#include "rand.h" -#include "rc4.h" -#include "rfc6979.h" -#include "schnorr.h" -#include "script.h" -#include "secp256k1.h" -#include "sha2.h" -#include "sha3.h" -#include "shamir.h" -#include "slip39.h" -#include "slip39_wordlist.h" - -#if VALGRIND -/* - * This is a clever trick to make Valgrind's Memcheck verify code - * is constant-time with respect to secret data. - */ - -/* Call after secret data is written, before first use */ -#define MARK_SECRET_DATA(addr, len) VALGRIND_MAKE_MEM_UNDEFINED(addr, len) -/* Call before secret data is freed or to mark non-secret data (public keys or - * signatures) */ -#define UNMARK_SECRET_DATA(addr, len) VALGRIND_MAKE_MEM_DEFINED(addr, len) -#else -#define MARK_SECRET_DATA(addr, len) -#define UNMARK_SECRET_DATA(addr, len) -#endif - -#define FROMHEX_MAXLEN 512 - -#define VERSION_PUBLIC 0x0488b21e -#define VERSION_PRIVATE 0x0488ade4 - -#define DECRED_VERSION_PUBLIC 0x02fda926 -#define DECRED_VERSION_PRIVATE 0x02fda4e8 - -const uint8_t *fromhex(const char *str) { - static uint8_t buf[FROMHEX_MAXLEN]; - size_t len = strlen(str) / 2; - if (len > FROMHEX_MAXLEN) len = FROMHEX_MAXLEN; - for (size_t i = 0; i < len; i++) { - uint8_t c = 0; - if (str[i * 2] >= '0' && str[i * 2] <= '9') c += (str[i * 2] - '0') << 4; - if ((str[i * 2] & ~0x20) >= 'A' && (str[i * 2] & ~0x20) <= 'F') - c += (10 + (str[i * 2] & ~0x20) - 'A') << 4; - if (str[i * 2 + 1] >= '0' && str[i * 2 + 1] <= '9') - c += (str[i * 2 + 1] - '0'); - if ((str[i * 2 + 1] & ~0x20) >= 'A' && (str[i * 2 + 1] & ~0x20) <= 'F') - c += (10 + (str[i * 2 + 1] & ~0x20) - 'A'); - buf[i] = c; - } - return buf; -} - -void nem_private_key(const char *reversed_hex, ed25519_secret_key private_key) { - const uint8_t *reversed_key = fromhex(reversed_hex); - for (size_t j = 0; j < sizeof(ed25519_secret_key); j++) { - private_key[j] = reversed_key[sizeof(ed25519_secret_key) - j - 1]; - } -} - -START_TEST(test_bignum_read_be) { - bignum256 a; - uint8_t input[32]; - - memcpy( - input, - fromhex( - "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), - 32); - - bn_read_be(input, &a); - - bignum256 b = {{0x086d8bd5, 0x1018f82f, 0x11a8bb07, 0x0bc3f7af, 0x0437cd3b, - 0x14087f0a, 0x15498fe5, 0x10b161bb, 0xc55ece}}; - - for (int i = 0; i < 9; i++) { - ck_assert_uint_eq(a.val[i], b.val[i]); - } -} -END_TEST - -START_TEST(test_bignum_write_be) { - bignum256 a = {{0x086d8bd5, 0x1018f82f, 0x11a8bb07, 0x0bc3f7af, 0x0437cd3b, - 0x14087f0a, 0x15498fe5, 0x10b161bb, 0xc55ece}}; - uint8_t tmp[32]; - - bn_write_be(&a, tmp); - - ck_assert_mem_eq( - tmp, - fromhex( - "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), - 32); -} -END_TEST - -START_TEST(test_bignum_is_equal) { - bignum256 a = {{0x086d8bd5, 0x1018f82f, 0x11a8bb07, 0x0bc3f7af, 0x0437cd3b, - 0x14087f0a, 0x15498fe5, 0x10b161bb, 0xc55ece}}; - bignum256 b = {{0x086d8bd5, 0x1018f82f, 0x11a8bb07, 0x0bc3f7af, 0x0437cd3b, - 0x14087f0a, 0x15498fe5, 0x10b161bb, 0xc55ece}}; - bignum256 c = {{ - 0, - }}; - - ck_assert_int_eq(bn_is_equal(&a, &b), 1); - ck_assert_int_eq(bn_is_equal(&c, &c), 1); - ck_assert_int_eq(bn_is_equal(&a, &c), 0); -} -END_TEST - -START_TEST(test_bignum_zero) { - bignum256 a; - bignum256 b; - - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000000000000000000000"), - &a); - bn_zero(&b); - - ck_assert_int_eq(bn_is_equal(&a, &b), 1); -} -END_TEST - -START_TEST(test_bignum_is_zero) { - bignum256 a; - - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000000000000000000000"), - &a); - ck_assert_int_eq(bn_is_zero(&a), 1); - - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000000000000000000001"), - &a); - ck_assert_int_eq(bn_is_zero(&a), 0); - - bn_read_be( - fromhex( - "1000000000000000000000000000000000000000000000000000000000000000"), - &a); - ck_assert_int_eq(bn_is_zero(&a), 0); - - bn_read_be( - fromhex( - "f000000000000000000000000000000000000000000000000000000000000000"), - &a); - ck_assert_int_eq(bn_is_zero(&a), 0); -} -END_TEST - -START_TEST(test_bignum_one) { - bignum256 a; - bignum256 b; - - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000000000000000000001"), - &a); - bn_one(&b); - - ck_assert_int_eq(bn_is_equal(&a, &b), 1); -} -END_TEST - -START_TEST(test_bignum_read_le) { - bignum256 a; - bignum256 b; - - bn_read_be( - fromhex( - "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), - &a); - bn_read_le( - fromhex( - "d58b6de8051f031eeca2c6d7fbe1b5d37c4314fe1068f96352dd0d8b85ce5ec5"), - &b); - - ck_assert_int_eq(bn_is_equal(&a, &b), 1); -} -END_TEST - -START_TEST(test_bignum_write_le) { - bignum256 a; - bignum256 b; - uint8_t tmp[32]; - - bn_read_be( - fromhex( - "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), - &a); - bn_write_le(&a, tmp); - - bn_read_le(tmp, &b); - ck_assert_int_eq(bn_is_equal(&a, &b), 1); - - bn_read_be( - fromhex( - "d58b6de8051f031eeca2c6d7fbe1b5d37c4314fe1068f96352dd0d8b85ce5ec5"), - &a); - bn_read_be(tmp, &b); - ck_assert_int_eq(bn_is_equal(&a, &b), 1); -} -END_TEST - -START_TEST(test_bignum_read_uint32) { - bignum256 a; - bignum256 b; - - // lowest 30 bits set - bn_read_be( - fromhex( - "000000000000000000000000000000000000000000000000000000003fffffff"), - &a); - bn_read_uint32(0x3fffffff, &b); - - ck_assert_int_eq(bn_is_equal(&a, &b), 1); - - // bit 31 set - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000000000000040000000"), - &a); - bn_read_uint32(0x40000000, &b); - ck_assert_int_eq(bn_is_equal(&a, &b), 1); -} -END_TEST - -START_TEST(test_bignum_read_uint64) { - bignum256 a; - bignum256 b; - - // lowest 30 bits set - bn_read_be( - fromhex( - "000000000000000000000000000000000000000000000000000000003fffffff"), - &a); - bn_read_uint64(0x3fffffff, &b); - ck_assert_int_eq(bn_is_equal(&a, &b), 1); - - // bit 31 set - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000000000000040000000"), - &a); - bn_read_uint64(0x40000000, &b); - ck_assert_int_eq(bn_is_equal(&a, &b), 1); - - // bit 33 set - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000000000000100000000"), - &a); - bn_read_uint64(0x100000000LL, &b); - ck_assert_int_eq(bn_is_equal(&a, &b), 1); - - // bit 61 set - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000002000000000000000"), - &a); - bn_read_uint64(0x2000000000000000LL, &b); - ck_assert_int_eq(bn_is_equal(&a, &b), 1); - - // all 64 bits set - bn_read_be( - fromhex( - "000000000000000000000000000000000000000000000000ffffffffffffffff"), - &a); - bn_read_uint64(0xffffffffffffffffLL, &b); - ck_assert_int_eq(bn_is_equal(&a, &b), 1); -} -END_TEST - -START_TEST(test_bignum_write_uint32) { - bignum256 a; - - // lowest 29 bits set - bn_read_be( - fromhex( - "000000000000000000000000000000000000000000000000000000001fffffff"), - &a); - ck_assert_uint_eq(bn_write_uint32(&a), 0x1fffffff); - - // lowest 30 bits set - bn_read_be( - fromhex( - "000000000000000000000000000000000000000000000000000000003fffffff"), - &a); - ck_assert_uint_eq(bn_write_uint32(&a), 0x3fffffff); - - // bit 31 set - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000000000000040000000"), - &a); - ck_assert_uint_eq(bn_write_uint32(&a), 0x40000000); -} -END_TEST - -START_TEST(test_bignum_write_uint64) { - bignum256 a; - - // lowest 30 bits set - bn_read_be( - fromhex( - "000000000000000000000000000000000000000000000000000000003fffffff"), - &a); - ck_assert_uint_eq(bn_write_uint64(&a), 0x3fffffff); - - // bit 31 set - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000000000000040000000"), - &a); - ck_assert_uint_eq(bn_write_uint64(&a), 0x40000000); - - // bit 33 set - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000000000000100000000"), - &a); - ck_assert_uint_eq(bn_write_uint64(&a), 0x100000000LL); - - // bit 61 set - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000002000000000000000"), - &a); - ck_assert_uint_eq(bn_write_uint64(&a), 0x2000000000000000LL); - - // all 64 bits set - bn_read_be( - fromhex( - "000000000000000000000000000000000000000000000000ffffffffffffffff"), - &a); - ck_assert_uint_eq(bn_write_uint64(&a), 0xffffffffffffffffLL); -} -END_TEST - -START_TEST(test_bignum_copy) { - bignum256 a; - bignum256 b; - - bn_read_be( - fromhex( - "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), - &a); - bn_copy(&a, &b); - - ck_assert_int_eq(bn_is_equal(&a, &b), 1); -} -END_TEST - -START_TEST(test_bignum_is_even) { - bignum256 a; - - bn_read_be( - fromhex( - "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), - &a); - ck_assert_int_eq(bn_is_even(&a), 0); - - bn_read_be( - fromhex( - "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd2"), - &a); - ck_assert_int_eq(bn_is_even(&a), 1); - - bn_read_be( - fromhex( - "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd0"), - &a); - ck_assert_int_eq(bn_is_even(&a), 1); -} -END_TEST - -START_TEST(test_bignum_is_odd) { - bignum256 a; - - bn_read_be( - fromhex( - "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), - &a); - ck_assert_int_eq(bn_is_odd(&a), 1); - - bn_read_be( - fromhex( - "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd2"), - &a); - ck_assert_int_eq(bn_is_odd(&a), 0); - - bn_read_be( - fromhex( - "c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd0"), - &a); - ck_assert_int_eq(bn_is_odd(&a), 0); -} -END_TEST - -START_TEST(test_bignum_is_less) { - bignum256 a; - bignum256 b; - - bn_read_uint32(0x1234, &a); - bn_read_uint32(0x8765, &b); - - ck_assert_int_eq(bn_is_less(&a, &b), 1); - ck_assert_int_eq(bn_is_less(&b, &a), 0); - - bn_zero(&a); - bn_read_be( - fromhex( - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), - &b); - - ck_assert_int_eq(bn_is_less(&a, &b), 1); - ck_assert_int_eq(bn_is_less(&b, &a), 0); -} -END_TEST - -START_TEST(test_bignum_bitcount) { - bignum256 a, b; - - bn_zero(&a); - ck_assert_int_eq(bn_bitcount(&a), 0); - - bn_one(&a); - ck_assert_int_eq(bn_bitcount(&a), 1); - - // test for 10000 and 11111 when i=5 - for (int i = 2; i <= 256; i++) { - bn_one(&a); - bn_one(&b); - for (int j = 2; j <= i; j++) { - bn_lshift(&a); - bn_lshift(&b); - bn_addi(&b, 1); - } - ck_assert_int_eq(bn_bitcount(&a), i); - ck_assert_int_eq(bn_bitcount(&b), i); - } - - bn_read_uint32(0x3fffffff, &a); - ck_assert_int_eq(bn_bitcount(&a), 30); - - bn_read_uint32(0xffffffff, &a); - ck_assert_int_eq(bn_bitcount(&a), 32); - - bn_read_be( - fromhex( - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), - &a); - ck_assert_int_eq(bn_bitcount(&a), 256); -} -END_TEST - -START_TEST(test_bignum_digitcount) { - bignum256 a; - - bn_zero(&a); - ck_assert_int_eq(bn_digitcount(&a), 1); - - // test for (10^i) and (10^i) - 1 - uint64_t m = 1; - for (int i = 0; i <= 19; i++, m *= 10) { - bn_read_uint64(m, &a); - ck_assert_int_eq(bn_digitcount(&a), i + 1); - - uint64_t n = m - 1; - bn_read_uint64(n, &a); - ck_assert_int_eq(bn_digitcount(&a), n == 0 ? 1 : i); - } - - bn_read_uint32(0x3fffffff, &a); - ck_assert_int_eq(bn_digitcount(&a), 10); - - bn_read_uint32(0xffffffff, &a); - ck_assert_int_eq(bn_digitcount(&a), 10); - - bn_read_be( - fromhex( - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), - &a); - ck_assert_int_eq(bn_digitcount(&a), 78); -} -END_TEST - -START_TEST(test_bignum_format_uint64) { - char buf[128], str[128]; - size_t r; - // test for (10^i) and (10^i) - 1 - uint64_t m = 1; - for (int i = 0; i <= 19; i++, m *= 10) { - sprintf(str, "%" PRIu64, m); - r = bn_format_uint64(m, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, strlen(str)); - ck_assert_str_eq(buf, str); - - uint64_t n = m - 1; - sprintf(str, "%" PRIu64, n); - r = bn_format_uint64(n, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, strlen(str)); - ck_assert_str_eq(buf, str); - } -} -END_TEST - -START_TEST(test_bignum_format) { - bignum256 a; - char buf[128]; - size_t r; - - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000000000000000000000"), - &a); - r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 1); - ck_assert_str_eq(buf, "0"); - - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000000000000000000000"), - &a); - r = bn_format(&a, NULL, NULL, 20, 0, true, buf, sizeof(buf)); - ck_assert_uint_eq(r, 22); - ck_assert_str_eq(buf, "0.00000000000000000000"); - - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000000000000000000000"), - &a); - r = bn_format(&a, NULL, NULL, 0, 5, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 1); - ck_assert_str_eq(buf, "0"); - - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000000000000000000000"), - &a); - r = bn_format(&a, NULL, NULL, 0, -5, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 1); - ck_assert_str_eq(buf, "0"); - - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000000000000000000000"), - &a); - r = bn_format(&a, "", "", 0, 0, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 1); - ck_assert_str_eq(buf, "0"); - - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000000000000000000000"), - &a); - r = bn_format(&a, NULL, "SFFX", 0, 0, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 1 + 4); - ck_assert_str_eq(buf, "0SFFX"); - - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000000000000000000000"), - &a); - r = bn_format(&a, "PRFX", NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 4 + 1); - ck_assert_str_eq(buf, "PRFX0"); - - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000000000000000000000"), - &a); - r = bn_format(&a, "PRFX", "SFFX", 0, 0, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 4 + 1 + 4); - ck_assert_str_eq(buf, "PRFX0SFFX"); - - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000000000000000000000"), - &a); - r = bn_format(&a, NULL, NULL, 18, 0, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 1); - ck_assert_str_eq(buf, "0"); - - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000000000000000000001"), - &a); - r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 1); - ck_assert_str_eq(buf, "1"); - - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000000000000000000001"), - &a); - r = bn_format(&a, NULL, NULL, 6, 6, true, buf, sizeof(buf)); - ck_assert_uint_eq(r, 8); - ck_assert_str_eq(buf, "1.000000"); - - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000000000000000000002"), - &a); - r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 1); - ck_assert_str_eq(buf, "2"); - - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000000000000000000005"), - &a); - r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 1); - ck_assert_str_eq(buf, "5"); - - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000000000000000000009"), - &a); - r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 1); - ck_assert_str_eq(buf, "9"); - - bn_read_be( - fromhex( - "000000000000000000000000000000000000000000000000000000000000000a"), - &a); - r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 2); - ck_assert_str_eq(buf, "10"); - - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000000000000000000014"), - &a); - r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 2); - ck_assert_str_eq(buf, "20"); - - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000000000000000000032"), - &a); - r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 2); - ck_assert_str_eq(buf, "50"); - - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000000000000000000063"), - &a); - r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 2); - ck_assert_str_eq(buf, "99"); - - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000000000000000000064"), - &a); - r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 3); - ck_assert_str_eq(buf, "100"); - - bn_read_be( - fromhex( - "00000000000000000000000000000000000000000000000000000000000000c8"), - &a); - r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 3); - ck_assert_str_eq(buf, "200"); - - bn_read_be( - fromhex( - "00000000000000000000000000000000000000000000000000000000000001f4"), - &a); - r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 3); - ck_assert_str_eq(buf, "500"); - - bn_read_be( - fromhex( - "00000000000000000000000000000000000000000000000000000000000003e7"), - &a); - r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 3); - ck_assert_str_eq(buf, "999"); - - bn_read_be( - fromhex( - "00000000000000000000000000000000000000000000000000000000000003e8"), - &a); - r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 4); - ck_assert_str_eq(buf, "1000"); - - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000000000000000989680"), - &a); - r = bn_format(&a, NULL, NULL, 7, 0, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 1); - ck_assert_str_eq(buf, "1"); - - bn_read_be( - fromhex( - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), - &a); - r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 78); - ck_assert_str_eq(buf, - "11579208923731619542357098500868790785326998466564056403945" - "7584007913129639935"); - - bn_read_be( - fromhex( - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), - &a); - r = bn_format(&a, NULL, NULL, 1, 0, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 79); - ck_assert_str_eq(buf, - "11579208923731619542357098500868790785326998466564056403945" - "758400791312963993.5"); - - bn_read_be( - fromhex( - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), - &a); - r = bn_format(&a, NULL, NULL, 2, 0, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 79); - ck_assert_str_eq(buf, - "11579208923731619542357098500868790785326998466564056403945" - "75840079131296399.35"); - - bn_read_be( - fromhex( - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), - &a); - r = bn_format(&a, NULL, NULL, 8, 0, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 79); - ck_assert_str_eq(buf, - "11579208923731619542357098500868790785326998466564056403945" - "75840079131.29639935"); - - bn_read_be( - fromhex( - "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffe3bbb00"), - &a); - r = bn_format(&a, NULL, NULL, 8, 0, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 70); - ck_assert_str_eq(buf, - "11579208923731619542357098500868790785326998466564056403945" - "75840079131"); - - bn_read_be( - fromhex( - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), - &a); - r = bn_format(&a, NULL, NULL, 18, 0, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 79); - ck_assert_str_eq(buf, - "11579208923731619542357098500868790785326998466564056403945" - "7.584007913129639935"); - - bn_read_be( - fromhex( - "fffffffffffffffffffffffffffffffffffffffffffffffff7e52fe5afe40000"), - &a); - r = bn_format(&a, NULL, NULL, 18, 0, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 60); - ck_assert_str_eq( - buf, "115792089237316195423570985008687907853269984665640564039457"); - - bn_read_be( - fromhex( - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), - &a); - r = bn_format(&a, NULL, NULL, 78, 0, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 80); - ck_assert_str_eq(buf, - "0." - "11579208923731619542357098500868790785326998466564056403945" - "7584007913129639935"); - - bn_read_be( - fromhex( - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), - &a); - r = bn_format(&a, NULL, NULL, 0, 10, false, buf, sizeof(buf)); - ck_assert_uint_eq(r, 88); - ck_assert_str_eq(buf, - "11579208923731619542357098500868790785326998466564056403945" - "75840079131296399350000000000"); - - bn_read_be( - fromhex( - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), - &a); - r = bn_format(&a, "quite a long prefix", "even longer suffix", 60, 0, false, - buf, sizeof(buf)); - ck_assert_uint_eq(r, 116); - ck_assert_str_eq(buf, - "quite a long " - "prefix115792089237316195." - "42357098500868790785326998466564056403945758400791312963993" - "5even longer suffix"); - - bn_read_be( - fromhex( - "0000000000000000000000000000000000000000000000000123456789abcdef"), - &a); - memset(buf, 'a', sizeof(buf)); - r = bn_format(&a, "prefix", "suffix", 10, 0, false, buf, 31); - ck_assert_str_eq(buf, "prefix8198552.9216486895suffix"); - ck_assert_uint_eq(r, 30); - - memset(buf, 'a', sizeof(buf)); - r = bn_format(&a, "prefix", "suffix", 10, 0, false, buf, 30); - ck_assert_uint_eq(r, 0); - ck_assert_str_eq(buf, ""); -} -END_TEST - -START_TEST(test_bignum_sqrt) { - uint32_t quadratic_residua[] = { - 1, 2, 4, 8, 9, 11, 15, 16, 17, 18, 19, 21, 22, 25, 29, - 30, 31, 32, 34, 35, 36, 38, 39, 42, 43, 44, 47, 49, 50, 58, - 59, 60, 61, 62, 64, 65, 67, 68, 69, 70, 71, 72, 76, 78, 81, - 83, 84, 86, 88, 91, 94, 98, 99, 100, 103, 107, 111, 115, 116, 118, - 120, 121, 122, 123, 124, 127, 128, 130, 131, 134, 135, 136, 137, 138, 139, - 140, 142, 144, 149, 152, 153, 156, 159, 161, 162, 165, 166, 167, 168, 169, - 171, 172, 176, 181, 182, 185, 187, 188, 189, 191, 193, 196, 197, 198, 200, - 205, 206, 209, 214, 219, 222, 223, 225, 229, 230, 231, 232, 233, 236, 237, - 239, 240, 242, 244, 246, 248, 254, 255, 256, 259, 260, 261, 262, 265, 267, - 268, 269, 270, 272, 274, 275, 276, 277, 278, 279, 280, 281, 284, 285, 287, - 288, 289, 291, 293, 298, 299, 303, 304, 306, 311, 312, 315, 318, 319, 322, - 323, 324, 327, 330, 331, 332, 334, 336, 337, 338, 339, 341, 342, 344, 349, - 351, 352, 353, 357, 359, 361, 362, 364, 365, 370, 371, 373, 374, 375, 376, - 378, 379, 382, 383, 385, 386, 387, 389, 392, 394, 395, 396, 399, 400, 409, - 410, 412, 418, 421, 423, 425, 428, 429, 431, 435, 438, 439, 441, 443, 444, - 445, 446, 450, 453, 458, 460, 461, 462, 463, 464, 465, 466, 467, 471, 472, - 473, 474, 475, 478, 479, 480, 481, 484, 485, 487, 488, 489, 492, 493, 496, - 503, 505, 508, 510, 511, 512, 517, 518, 519, 520, 521, 522, 523, 524, 525, - 527, 529, 530, 531, 533, 534, 536, 537, 538, 539, 540, 541, 544, 545, 547, - 548, 549, 550, 551, 552, 553, 554, 556, 557, 558, 560, 562, 563, 565, 568, - 570, 571, 574, 576, 578, 582, 585, 586, 587, 589, 595, 596, 597, 598, 599, - 603, 606, 607, 608, 609, 612, 613, 619, 621, 622, 623, 624, 625, 630, 633, - 636, 638, 639, 644, 645, 646, 648, 649, 651, 653, 654, 660, 662, 663, 664, - 665, 668, 671, 672, 673, 674, 676, 678, 679, 681, 682, 684, 688, 689, 698, - 702, 704, 705, 706, 707, 714, 715, 718, 722, 723, 724, 725, 728, 729, 730, - 731, 733, 735, 737, 740, 741, 742, 746, 747, 748, 750, 751, 752, 753, 755, - 756, 758, 759, 761, 763, 764, 766, 769, 770, 771, 772, 774, 775, 778, 781, - 784, 785, 788, 789, 790, 791, 792, 797, 798, 799, 800, 813, 815, 817, 818, - 819, 820, 823, 824, 833, 836, 841, 842, 846, 849, 850, 851, 856, 857, 858, - 862, 865, 870, 875, 876, 878, 882, 885, 886, 887, 888, 890, 891, 892, 893, - 895, 899, 900, 903, 906, 907, 911, 913, 915, 916, 919, 920, 921, 922, 924, - 926, 927, 928, 930, 931, 932, 934, 937, 939, 942, 943, 944, 946, 948, 949, - 950, 951, 953, 956, 958, 960, 961, 962, 963, 968, 970, 971, 974, 975, 976, - 977, 978, 984, 986, 987, 992, 995, 999}; - - bignum256 a, b; - - bn_zero(&a); - b = a; - bn_sqrt(&b, &secp256k1.prime); - ck_assert_int_eq(bn_is_equal(&a, &b), 1); - - bn_one(&a); - b = a; - bn_sqrt(&b, &secp256k1.prime); - ck_assert_int_eq(bn_is_equal(&a, &b), 1); - - // test some quadratic residua - for (size_t i = 0; i < sizeof(quadratic_residua) / sizeof(*quadratic_residua); - i++) { - bn_read_uint32(quadratic_residua[i], &a); - b = a; - bn_sqrt(&b, &secp256k1.prime); - bn_multiply(&b, &b, &secp256k1.prime); - bn_mod(&b, &secp256k1.prime); - ck_assert_int_eq(bn_is_equal(&a, &b), 1); - } -} -END_TEST - -// https://tools.ietf.org/html/rfc4648#section-10 -START_TEST(test_base32_rfc4648) { - static const struct { - const char *decoded; - const char *encoded; - const char *encoded_lowercase; - } tests[] = { - {"", "", ""}, - {"f", "MY", "my"}, - {"fo", "MZXQ", "mzxq"}, - {"foo", "MZXW6", "mzxw6"}, - {"foob", "MZXW6YQ", "mzxw6yq"}, - {"fooba", "MZXW6YTB", "mzxw6ytb"}, - {"foobar", "MZXW6YTBOI", "mzxw6ytboi"}, - }; - - char buffer[64]; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - const char *in = tests[i].decoded; - const char *out = tests[i].encoded; - const char *out_lowercase = tests[i].encoded_lowercase; - - size_t inlen = strlen(in); - size_t outlen = strlen(out); - - ck_assert_uint_eq(outlen, base32_encoded_length(inlen)); - ck_assert_uint_eq(inlen, base32_decoded_length(outlen)); - - ck_assert(base32_encode((uint8_t *)in, inlen, buffer, sizeof(buffer), - BASE32_ALPHABET_RFC4648) != NULL); - ck_assert_str_eq(buffer, out); - - char *ret = (char *)base32_decode(out, outlen, (uint8_t *)buffer, - sizeof(buffer), BASE32_ALPHABET_RFC4648); - ck_assert(ret != NULL); - *ret = '\0'; - ck_assert_str_eq(buffer, in); - - ret = (char *)base32_decode(out_lowercase, outlen, (uint8_t *)buffer, - sizeof(buffer), BASE32_ALPHABET_RFC4648); - ck_assert(ret != NULL); - *ret = '\0'; - ck_assert_str_eq(buffer, in); - } -} -END_TEST - -// from -// https://github.com/bitcoin/bitcoin/blob/master/src/test/data/base58_keys_valid.json -START_TEST(test_base58) { - static const char *base58_vector[] = { - "0065a16059864a2fdbc7c99a4723a8395bc6f188eb", - "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", - "0574f209f6ea907e2ea48f74fae05782ae8a665257", - "3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou", - "6f53c0307d6851aa0ce7825ba883c6bd9ad242b486", - "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", - "c46349a418fc4578d10a372b54b45c280cc8c4382f", - "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br", - "80eddbdc1168f1daeadbd3e44c1e3f8f5a284c2029f78ad26af98583a499de5b19", - "5Kd3NBUAdUnhyzenEwVLy9pBKxSwXvE9FMPyR4UKZvpe6E3AgLr", - "8055c9bccb9ed68446d1b75273bbce89d7fe013a8acd1625514420fb2aca1a21c401", - "Kz6UJmQACJmLtaQj5A3JAge4kVTNQ8gbvXuwbmCj7bsaabudb3RD", - "ef36cb93b9ab1bdabf7fb9f2c04f1b9cc879933530ae7842398eef5a63a56800c2", - "9213qJab2HNEpMpYNBa7wHGFKKbkDn24jpANDs2huN3yi4J11ko", - "efb9f4892c9e8282028fea1d2667c4dc5213564d41fc5783896a0d843fc15089f301", - "cTpB4YiyKiBcPxnefsDpbnDxFDffjqJob8wGCEDXxgQ7zQoMXJdH", - "006d23156cbbdcc82a5a47eee4c2c7c583c18b6bf4", - "1Ax4gZtb7gAit2TivwejZHYtNNLT18PUXJ", - "05fcc5460dd6e2487c7d75b1963625da0e8f4c5975", - "3QjYXhTkvuj8qPaXHTTWb5wjXhdsLAAWVy", - "6ff1d470f9b02370fdec2e6b708b08ac431bf7a5f7", - "n3ZddxzLvAY9o7184TB4c6FJasAybsw4HZ", - "c4c579342c2c4c9220205e2cdc285617040c924a0a", - "2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n", - "80a326b95ebae30164217d7a7f57d72ab2b54e3be64928a19da0210b9568d4015e", - "5K494XZwps2bGyeL71pWid4noiSNA2cfCibrvRWqcHSptoFn7rc", - "807d998b45c219a1e38e99e7cbd312ef67f77a455a9b50c730c27f02c6f730dfb401", - "L1RrrnXkcKut5DEMwtDthjwRcTTwED36thyL1DebVrKuwvohjMNi", - "efd6bca256b5abc5602ec2e1c121a08b0da2556587430bcf7e1898af2224885203", - "93DVKyFYwSN6wEo3E2fCrFPUp17FtrtNi2Lf7n4G3garFb16CRj", - "efa81ca4e8f90181ec4b61b6a7eb998af17b2cb04de8a03b504b9e34c4c61db7d901", - "cTDVKtMGVYWTHCb1AFjmVbEbWjvKpKqKgMaR3QJxToMSQAhmCeTN", - "007987ccaa53d02c8873487ef919677cd3db7a6912", - "1C5bSj1iEGUgSTbziymG7Cn18ENQuT36vv", - "0563bcc565f9e68ee0189dd5cc67f1b0e5f02f45cb", - "3AnNxabYGoTxYiTEZwFEnerUoeFXK2Zoks", - "6fef66444b5b17f14e8fae6e7e19b045a78c54fd79", - "n3LnJXCqbPjghuVs8ph9CYsAe4Sh4j97wk", - "c4c3e55fceceaa4391ed2a9677f4a4d34eacd021a0", - "2NB72XtkjpnATMggui83aEtPawyyKvnbX2o", - "80e75d936d56377f432f404aabb406601f892fd49da90eb6ac558a733c93b47252", - "5KaBW9vNtWNhc3ZEDyNCiXLPdVPHCikRxSBWwV9NrpLLa4LsXi9", - "808248bd0375f2f75d7e274ae544fb920f51784480866b102384190b1addfbaa5c01", - "L1axzbSyynNYA8mCAhzxkipKkfHtAXYF4YQnhSKcLV8YXA874fgT", - "ef44c4f6a096eac5238291a94cc24c01e3b19b8d8cef72874a079e00a242237a52", - "927CnUkUbasYtDwYwVn2j8GdTuACNnKkjZ1rpZd2yBB1CLcnXpo", - "efd1de707020a9059d6d3abaf85e17967c6555151143db13dbb06db78df0f15c6901", - "cUcfCMRjiQf85YMzzQEk9d1s5A4K7xL5SmBCLrezqXFuTVefyhY7", - "00adc1cc2081a27206fae25792f28bbc55b831549d", - "1Gqk4Tv79P91Cc1STQtU3s1W6277M2CVWu", - "05188f91a931947eddd7432d6e614387e32b244709", - "33vt8ViH5jsr115AGkW6cEmEz9MpvJSwDk", - "6f1694f5bc1a7295b600f40018a618a6ea48eeb498", - "mhaMcBxNh5cqXm4aTQ6EcVbKtfL6LGyK2H", - "c43b9b3fd7a50d4f08d1a5b0f62f644fa7115ae2f3", - "2MxgPqX1iThW3oZVk9KoFcE5M4JpiETssVN", - "80091035445ef105fa1bb125eccfb1882f3fe69592265956ade751fd095033d8d0", - "5HtH6GdcwCJA4ggWEL1B3jzBBUB8HPiBi9SBc5h9i4Wk4PSeApR", - "80ab2b4bcdfc91d34dee0ae2a8c6b6668dadaeb3a88b9859743156f462325187af01", - "L2xSYmMeVo3Zek3ZTsv9xUrXVAmrWxJ8Ua4cw8pkfbQhcEFhkXT8", - "efb4204389cef18bbe2b353623cbf93e8678fbc92a475b664ae98ed594e6cf0856", - "92xFEve1Z9N8Z641KQQS7ByCSb8kGjsDzw6fAmjHN1LZGKQXyMq", - "efe7b230133f1b5489843260236b06edca25f66adb1be455fbd38d4010d48faeef01", - "cVM65tdYu1YK37tNoAyGoJTR13VBYFva1vg9FLuPAsJijGvG6NEA", - "00c4c1b72491ede1eedaca00618407ee0b772cad0d", - "1JwMWBVLtiqtscbaRHai4pqHokhFCbtoB4", - "05f6fe69bcb548a829cce4c57bf6fff8af3a5981f9", - "3QCzvfL4ZRvmJFiWWBVwxfdaNBT8EtxB5y", - "6f261f83568a098a8638844bd7aeca039d5f2352c0", - "mizXiucXRCsEriQCHUkCqef9ph9qtPbZZ6", - "c4e930e1834a4d234702773951d627cce82fbb5d2e", - "2NEWDzHWwY5ZZp8CQWbB7ouNMLqCia6YRda", - "80d1fab7ab7385ad26872237f1eb9789aa25cc986bacc695e07ac571d6cdac8bc0", - "5KQmDryMNDcisTzRp3zEq9e4awRmJrEVU1j5vFRTKpRNYPqYrMg", - "80b0bbede33ef254e8376aceb1510253fc3550efd0fcf84dcd0c9998b288f166b301", - "L39Fy7AC2Hhj95gh3Yb2AU5YHh1mQSAHgpNixvm27poizcJyLtUi", - "ef037f4192c630f399d9271e26c575269b1d15be553ea1a7217f0cb8513cef41cb", - "91cTVUcgydqyZLgaANpf1fvL55FH53QMm4BsnCADVNYuWuqdVys", - "ef6251e205e8ad508bab5596bee086ef16cd4b239e0cc0c5d7c4e6035441e7d5de01", - "cQspfSzsgLeiJGB2u8vrAiWpCU4MxUT6JseWo2SjXy4Qbzn2fwDw", - "005eadaf9bb7121f0f192561a5a62f5e5f54210292", - "19dcawoKcZdQz365WpXWMhX6QCUpR9SY4r", - "053f210e7277c899c3a155cc1c90f4106cbddeec6e", - "37Sp6Rv3y4kVd1nQ1JV5pfqXccHNyZm1x3", - "6fc8a3c2a09a298592c3e180f02487cd91ba3400b5", - "myoqcgYiehufrsnnkqdqbp69dddVDMopJu", - "c499b31df7c9068d1481b596578ddbb4d3bd90baeb", - "2N7FuwuUuoTBrDFdrAZ9KxBmtqMLxce9i1C", - "80c7666842503db6dc6ea061f092cfb9c388448629a6fe868d068c42a488b478ae", - "5KL6zEaMtPRXZKo1bbMq7JDjjo1bJuQcsgL33je3oY8uSJCR5b4", - "8007f0803fc5399e773555ab1e8939907e9badacc17ca129e67a2f5f2ff84351dd01", - "KwV9KAfwbwt51veZWNscRTeZs9CKpojyu1MsPnaKTF5kz69H1UN2", - "efea577acfb5d1d14d3b7b195c321566f12f87d2b77ea3a53f68df7ebf8604a801", - "93N87D6uxSBzwXvpokpzg8FFmfQPmvX4xHoWQe3pLdYpbiwT5YV", - "ef0b3b34f0958d8a268193a9814da92c3e8b58b4a4378a542863e34ac289cd830c01", - "cMxXusSihaX58wpJ3tNuuUcZEQGt6DKJ1wEpxys88FFaQCYjku9h", - "001ed467017f043e91ed4c44b4e8dd674db211c4e6", - "13p1ijLwsnrcuyqcTvJXkq2ASdXqcnEBLE", - "055ece0cadddc415b1980f001785947120acdb36fc", - "3ALJH9Y951VCGcVZYAdpA3KchoP9McEj1G", - 0, - 0, - }; - const char **raw = base58_vector; - const char **str = base58_vector + 1; - uint8_t rawn[34]; - char strn[53]; - int r; - while (*raw && *str) { - int len = strlen(*raw) / 2; - - memcpy(rawn, fromhex(*raw), len); - r = base58_encode_check(rawn, len, HASHER_SHA2D, strn, sizeof(strn)); - ck_assert_int_eq((size_t)r, strlen(*str) + 1); - ck_assert_str_eq(strn, *str); - - r = base58_decode_check(strn, HASHER_SHA2D, rawn, len); - ck_assert_int_eq(r, len); - ck_assert_mem_eq(rawn, fromhex(*raw), len); - - raw += 2; - str += 2; - } -} -END_TEST - -#if USE_GRAPHENE - -// Graphene Base85CheckEncoding -START_TEST(test_base58gph) { - static const char *base58_vector[] = { - "02e649f63f8e8121345fd7f47d0d185a3ccaa843115cd2e9392dcd9b82263bc680", - "6dumtt9swxCqwdPZBGXh9YmHoEjFFnNfwHaTqRbQTghGAY2gRz", - "021c7359cd885c0e319924d97e3980206ad64387aff54908241125b3a88b55ca16", - "5725vivYpuFWbeyTifZ5KevnHyqXCi5hwHbNU9cYz1FHbFXCxX", - "02f561e0b57a552df3fa1df2d87a906b7a9fc33a83d5d15fa68a644ecb0806b49a", - "6kZKHSuxqAwdCYsMvwTcipoTsNE2jmEUNBQufGYywpniBKXWZK", - "03e7595c3e6b58f907bee951dc29796f3757307e700ecf3d09307a0cc4a564eba3", - "8b82mpnH8YX1E9RHnU2a2YgLTZ8ooevEGP9N15c1yFqhoBvJur", - 0, - 0, - }; - const char **raw = base58_vector; - const char **str = base58_vector + 1; - uint8_t rawn[34]; - char strn[53]; - int r; - while (*raw && *str) { - int len = strlen(*raw) / 2; - - memcpy(rawn, fromhex(*raw), len); - r = base58gph_encode_check(rawn, len, strn, sizeof(strn)); - ck_assert_int_eq((size_t)r, strlen(*str) + 1); - ck_assert_str_eq(strn, *str); - - r = base58gph_decode_check(strn, rawn, len); - ck_assert_int_eq(r, len); - ck_assert_mem_eq(rawn, fromhex(*raw), len); - - raw += 2; - str += 2; - } -} -END_TEST - -#endif - -START_TEST(test_bignum_divmod) { - uint32_t r; - int i; - - bignum256 a; - uint32_t ar[] = {15, 14, 55, 29, 44, 24, 53, 49, 18, 55, 2, 28, 5, 4, 12, - 43, 18, 37, 28, 14, 30, 46, 12, 11, 17, 10, 10, 13, 24, 45, - 4, 33, 44, 42, 2, 46, 34, 43, 45, 28, 21, 18, 13, 17}; - - bn_read_be( - fromhex( - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), - &a); - - i = 0; - while (!bn_is_zero(&a) && i < 44) { - bn_divmod58(&a, &r); - ck_assert_uint_eq(r, ar[i]); - i++; - } - ck_assert_int_eq(i, 44); - - bignum256 b; - uint32_t br[] = {935, 639, 129, 913, 7, 584, 457, 39, 564, - 640, 665, 984, 269, 853, 907, 687, 8, 985, - 570, 423, 195, 316, 237, 89, 792, 115}; - - bn_read_be( - fromhex( - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), - &b); - i = 0; - while (!bn_is_zero(&b) && i < 26) { - bn_divmod1000(&b, &r); - ck_assert_uint_eq(r, br[i]); - i++; - } - ck_assert_int_eq(i, 26); -} -END_TEST - -// test vector 1 from -// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vector-1 -START_TEST(test_bip32_vector_1) { - HDNode node, node2, node3; - uint32_t fingerprint; - char str[XPUB_MAXLEN]; - int r; - - // init m - hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, - SECP256K1_NAME, &node); - - // [Chain m] - fingerprint = 0; - ck_assert_uint_eq(fingerprint, 0x00000000); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2"), - 33); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, - sizeof(str)); - ck_assert_str_eq(str, - "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqji" - "ChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"); - r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, - "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2" - "gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"); - r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0'] - fingerprint = hdnode_fingerprint(&node); - hdnode_private_ckd_prime(&node, 0); - ck_assert_uint_eq(fingerprint, 0x3442193e); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56"), - 33); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, - sizeof(str)); - ck_assert_str_eq(str, - "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4" - "cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7"); - r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, - "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP" - "6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw"); - r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0'/1] - fingerprint = hdnode_fingerprint(&node); - hdnode_private_ckd(&node, 1); - ck_assert_uint_eq(fingerprint, 0x5c1bd648); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c"), - 33); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, - sizeof(str)); - ck_assert_str_eq(str, - "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSx" - "qu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs"); - r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, - "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFH" - "KkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ"); - r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0'/1/2'] - fingerprint = hdnode_fingerprint(&node); - hdnode_private_ckd_prime(&node, 2); - ck_assert_uint_eq(fingerprint, 0xbef5a2f9); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2"), - 33); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, - sizeof(str)); - ck_assert_str_eq(str, - "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptW" - "mT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM"); - r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, - "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgq" - "FJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5"); - r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0'/1/2'/2] - fingerprint = hdnode_fingerprint(&node); - hdnode_private_ckd(&node, 2); - ck_assert_uint_eq(fingerprint, 0xee7ab90c); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "0f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29"), - 33); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, - sizeof(str)); - ck_assert_str_eq(str, - "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Ty" - "h8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334"); - r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, - "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJ" - "AyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV"); - r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0'/1/2'/2/1000000000] - fingerprint = hdnode_fingerprint(&node); - hdnode_private_ckd(&node, 1000000000); - ck_assert_uint_eq(fingerprint, 0xd880d7d8); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011"), - 33); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, - sizeof(str)); - ck_assert_str_eq(str, - "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8" - "kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76"); - r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, - "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNT" - "EcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy"); - r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); -} -END_TEST - -// test vector 2 from -// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vector-2 -START_TEST(test_bip32_vector_2) { - HDNode node, node2, node3; - uint32_t fingerprint; - char str[XPUB_MAXLEN]; - int r; - - // init m - hdnode_from_seed( - fromhex( - "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c" - "999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), - 64, SECP256K1_NAME, &node); - - // [Chain m] - fingerprint = 0; - ck_assert_uint_eq(fingerprint, 0x00000000); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "60499f801b896d83179a4374aeb7822aaeaceaa0db1f85ee3e904c4defbd9689"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "4b03d6fc340455b363f51020ad3ecca4f0850280cf436c70c727923f6db46c3e"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "03cbcaa9c98c877a26977d00825c956a238e8dddfbd322cce4f74b0b5bd6ace4a7"), - 33); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, - sizeof(str)); - ck_assert_str_eq(str, - "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGds" - "o3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U"); - r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, - "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSC" - "Gu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB"); - r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd(&node, 0); - ck_assert_int_eq(r, 1); - ck_assert_uint_eq(fingerprint, 0xbd16bee5); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "abe74a98f6c7eabee0428f53798f0ab8aa1bd37873999041703c742f15ac7e1e"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"), - 33); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, - sizeof(str)); - ck_assert_str_eq(str, - "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT" - "3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt"); - r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, - "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGm" - "XUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH"); - r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0/2147483647'] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd_prime(&node, 2147483647); - ck_assert_int_eq(r, 1); - ck_assert_uint_eq(fingerprint, 0x5a61ff8e); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "be17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d9"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "877c779ad9687164e9c2f4f0f4ff0340814392330693ce95a58fe18fd52e6e93"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "03c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b"), - 33); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, - sizeof(str)); - ck_assert_str_eq(str, - "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYE" - "eEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9"); - r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, - "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ" - "85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a"); - r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0/2147483647'/1] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd(&node, 1); - ck_assert_int_eq(r, 1); - ck_assert_uint_eq(fingerprint, 0xd8ab4937); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "704addf544a06e5ee4bea37098463c23613da32020d604506da8c0518e1da4b7"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9"), - 33); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, - sizeof(str)); - ck_assert_str_eq(str, - "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd" - "25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef"); - r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, - "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5Ew" - "VvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon"); - r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0/2147483647'/1/2147483646'] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd_prime(&node, 2147483646); - ck_assert_int_eq(r, 1); - ck_assert_uint_eq(fingerprint, 0x78412e3a); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e29"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "f1c7c871a54a804afe328b4c83a1c33b8e5ff48f5087273f04efa83b247d6a2d"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "02d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0"), - 33); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, - sizeof(str)); - ck_assert_str_eq(str, - "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz" - "7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc"); - r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, - "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJ" - "bZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL"); - r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0/2147483647'/1/2147483646'/2] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd(&node, 2); - ck_assert_int_eq(r, 1); - ck_assert_uint_eq(fingerprint, 0x31a507b8); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "9452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58eedf394ed271"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "bb7d39bdb83ecf58f2fd82b6d918341cbef428661ef01ab97c28a4842125ac23"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c"), - 33); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, - sizeof(str)); - ck_assert_str_eq(str, - "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw" - "7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j"); - r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, - "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLF" - "bdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt"); - r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // init m - hdnode_from_seed( - fromhex( - "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c" - "999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), - 64, SECP256K1_NAME, &node); - - // test public derivation - // [Chain m/0] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_public_ckd(&node, 0); - ck_assert_int_eq(r, 1); - ck_assert_uint_eq(fingerprint, 0xbd16bee5); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "0000000000000000000000000000000000000000000000000000000000000000"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"), - 33); -} -END_TEST - -// test vector 3 from -// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vector-3 -START_TEST(test_bip32_vector_3) { - HDNode node, node2, node3; - uint32_t fingerprint; - char str[XPUB_MAXLEN]; - int r; - - // init m - hdnode_from_seed( - fromhex( - "4b381541583be4423346c643850da4b320e46a87ae3d2a4e6da11eba819cd4acba45" - "d239319ac14f863b8d5ab5a0d0c64d2e8a1e7d1457df2e5a3c51c73235be"), - 64, SECP256K1_NAME, &node); - - // [Chain m] - fingerprint = 0; - ck_assert_uint_eq(fingerprint, 0x00000000); - hdnode_fill_public_key(&node); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, - sizeof(str)); - ck_assert_str_eq(str, - "xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7" - "KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6"); - r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, - "xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhR" - "oP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13"); - r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0'] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd_prime(&node, 0); - ck_assert_int_eq(r, 1); - hdnode_fill_public_key(&node); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, - sizeof(str)); - ck_assert_str_eq(str, - "xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu" - "2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L"); - r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, - "xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrAD" - "WgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y"); - r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); -} -END_TEST - -// test vector 4 from -// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vector-4 -START_TEST(test_bip32_vector_4) { - HDNode node, node2, node3; - uint32_t fingerprint; - char str[XPUB_MAXLEN]; - int r; - - // init m - hdnode_from_seed( - fromhex( - "3ddd5602285899a946114506157c7997e5444528f3003f6134712147db19b678"), - 32, SECP256K1_NAME, &node); - - // [Chain m] - fingerprint = 0; - ck_assert_int_eq(fingerprint, 0x00000000); - hdnode_fill_public_key(&node); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, - sizeof(str)); - ck_assert_str_eq(str, - "xprv9s21ZrQH143K48vGoLGRPxgo2JNkJ3J3fqkirQC2zVdk5Dgd5w14S7f" - "RDyHH4dWNHUgkvsvNDCkvAwcSHNAQwhwgNMgZhLtQC63zxwhQmRv"); - r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, - "xpub661MyMwAqRbcGczjuMoRm6dXaLDEhW1u34gKenbeYqAix21mdUKJyuy" - "u5F1rzYGVxyL6tmgBUAEPrEz92mBXjByMRiJdba9wpnN37RLLAXa"); - r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0'] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd_prime(&node, 0); - ck_assert_int_eq(r, 1); - hdnode_fill_public_key(&node); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, - sizeof(str)); - ck_assert_str_eq(str, - "xprv9vB7xEWwNp9kh1wQRfCCQMnZUEG21LpbR9NPCNN1dwhiZkjjeGRnaAL" - "mPXCX7SgjFTiCTT6bXes17boXtjq3xLpcDjzEuGLQBM5ohqkao9G"); - r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, - "xpub69AUMk3qDBi3uW1sXgjCmVjJ2G6WQoYSnNHyzkmdCHEhSZ4tBok37xf" - "FEqHd2AddP56Tqp4o56AePAgCjYdvpW2PU2jbUPFKsav5ut6Ch1m"); - r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0'/1'] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd_prime(&node, 1); - ck_assert_int_eq(r, 1); - hdnode_fill_public_key(&node); - hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, - sizeof(str)); - ck_assert_str_eq(str, - "xprv9xJocDuwtYCMNAo3Zw76WENQeAS6WGXQ55RCy7tDJ8oALr4FWkuVoHJ" - "eHVAcAqiZLE7Je3vZJHxspZdFHfnBEjHqU5hG1Jaj32dVoS6XLT1"); - r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); - ck_assert_str_eq(str, - "xpub6BJA1jSqiukeaesWfxe6sNK9CCGaujFFSJLomWHprUL9DePQ4JDkM5d" - "88n49sMGJxrhpjazuXYWdMf17C9T5XnxkopaeS7jGk1GyyVziaMt"); - r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, - NULL); - ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); -} -END_TEST - -START_TEST(test_bip32_compare) { - HDNode node1, node2, node3; - int i, r; - hdnode_from_seed( - fromhex( - "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" - "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), - 64, SECP256K1_NAME, &node1); - hdnode_from_seed( - fromhex( - "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" - "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), - 64, SECP256K1_NAME, &node2); - hdnode_fill_public_key(&node2); - for (i = 0; i < 100; i++) { - memcpy(&node3, &node1, sizeof(HDNode)); - hdnode_fill_public_key(&node3); - r = hdnode_private_ckd(&node1, i); - ck_assert_int_eq(r, 1); - r = hdnode_public_ckd(&node2, i); - ck_assert_int_eq(r, 1); - r = hdnode_public_ckd(&node3, i); - ck_assert_int_eq(r, 1); - ck_assert_uint_eq(node1.depth, node2.depth); - ck_assert_uint_eq(node1.depth, node3.depth); - ck_assert_uint_eq(node1.child_num, node2.child_num); - ck_assert_uint_eq(node1.child_num, node3.child_num); - ck_assert_mem_eq(node1.chain_code, node2.chain_code, 32); - ck_assert_mem_eq(node1.chain_code, node3.chain_code, 32); - ck_assert_mem_eq( - node2.private_key, - fromhex( - "0000000000000000000000000000000000000000000000000000000000000000"), - 32); - ck_assert_mem_eq( - node3.private_key, - fromhex( - "0000000000000000000000000000000000000000000000000000000000000000"), - 32); - hdnode_fill_public_key(&node1); - ck_assert_mem_eq(node1.public_key, node2.public_key, 33); - ck_assert_mem_eq(node1.public_key, node3.public_key, 33); - } -} -END_TEST - -START_TEST(test_bip32_optimized) { - HDNode root; - hdnode_from_seed((uint8_t *)"NothingToSeeHere", 16, SECP256K1_NAME, &root); - hdnode_fill_public_key(&root); - - curve_point pub; - ecdsa_read_pubkey(&secp256k1, root.public_key, &pub); - - HDNode node; - char addr1[MAX_ADDR_SIZE], addr2[MAX_ADDR_SIZE]; - - for (int i = 0; i < 40; i++) { - // unoptimized - memcpy(&node, &root, sizeof(HDNode)); - hdnode_public_ckd(&node, i); - hdnode_fill_public_key(&node); - ecdsa_get_address(node.public_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, - addr1, sizeof(addr1)); - // optimized - hdnode_public_ckd_address_optimized(&pub, root.chain_code, i, 0, - HASHER_SHA2_RIPEMD, HASHER_SHA2D, addr2, - sizeof(addr2), 0); - // check - ck_assert_str_eq(addr1, addr2); - } -} -END_TEST - -START_TEST(test_bip32_cache_1) { - HDNode node1, node2; - int i, r; - - // test 1 .. 8 - hdnode_from_seed( - fromhex( - "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" - "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), - 64, SECP256K1_NAME, &node1); - hdnode_from_seed( - fromhex( - "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" - "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), - 64, SECP256K1_NAME, &node2); - - uint32_t ii[] = {0x80000001, 0x80000002, 0x80000003, 0x80000004, - 0x80000005, 0x80000006, 0x80000007, 0x80000008}; - - for (i = 0; i < 8; i++) { - r = hdnode_private_ckd(&node1, ii[i]); - ck_assert_int_eq(r, 1); - } - r = hdnode_private_ckd_cached(&node2, ii, 8, NULL); - ck_assert_int_eq(r, 1); - ck_assert_mem_eq(&node1, &node2, sizeof(HDNode)); - - hdnode_from_seed( - fromhex( - "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" - "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), - 64, SECP256K1_NAME, &node1); - hdnode_from_seed( - fromhex( - "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" - "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), - 64, SECP256K1_NAME, &node2); - - // test 1 .. 7, 20 - ii[7] = 20; - for (i = 0; i < 8; i++) { - r = hdnode_private_ckd(&node1, ii[i]); - ck_assert_int_eq(r, 1); - } - r = hdnode_private_ckd_cached(&node2, ii, 8, NULL); - ck_assert_int_eq(r, 1); - ck_assert_mem_eq(&node1, &node2, sizeof(HDNode)); - - // test different root node - hdnode_from_seed( - fromhex( - "000000002ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" - "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), - 64, SECP256K1_NAME, &node1); - hdnode_from_seed( - fromhex( - "000000002ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" - "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), - 64, SECP256K1_NAME, &node2); - - for (i = 0; i < 8; i++) { - r = hdnode_private_ckd(&node1, ii[i]); - ck_assert_int_eq(r, 1); - } - r = hdnode_private_ckd_cached(&node2, ii, 8, NULL); - ck_assert_int_eq(r, 1); - ck_assert_mem_eq(&node1, &node2, sizeof(HDNode)); -} -END_TEST - -START_TEST(test_bip32_cache_2) { - HDNode nodea[9], nodeb[9]; - int i, j, r; - - for (j = 0; j < 9; j++) { - hdnode_from_seed( - fromhex( - "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d627" - "88f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), - 64, SECP256K1_NAME, &(nodea[j])); - hdnode_from_seed( - fromhex( - "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d627" - "88f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), - 64, SECP256K1_NAME, &(nodeb[j])); - } - - uint32_t ii[] = {0x80000001, 0x80000002, 0x80000003, 0x80000004, - 0x80000005, 0x80000006, 0x80000007, 0x80000008}; - for (j = 0; j < 9; j++) { - // non cached - for (i = 1; i <= j; i++) { - r = hdnode_private_ckd(&(nodea[j]), ii[i - 1]); - ck_assert_int_eq(r, 1); - } - // cached - r = hdnode_private_ckd_cached(&(nodeb[j]), ii, j, NULL); - ck_assert_int_eq(r, 1); - } - - ck_assert_mem_eq(&(nodea[0]), &(nodeb[0]), sizeof(HDNode)); - ck_assert_mem_eq(&(nodea[1]), &(nodeb[1]), sizeof(HDNode)); - ck_assert_mem_eq(&(nodea[2]), &(nodeb[2]), sizeof(HDNode)); - ck_assert_mem_eq(&(nodea[3]), &(nodeb[3]), sizeof(HDNode)); - ck_assert_mem_eq(&(nodea[4]), &(nodeb[4]), sizeof(HDNode)); - ck_assert_mem_eq(&(nodea[5]), &(nodeb[5]), sizeof(HDNode)); - ck_assert_mem_eq(&(nodea[6]), &(nodeb[6]), sizeof(HDNode)); - ck_assert_mem_eq(&(nodea[7]), &(nodeb[7]), sizeof(HDNode)); - ck_assert_mem_eq(&(nodea[8]), &(nodeb[8]), sizeof(HDNode)); -} -END_TEST - -START_TEST(test_bip32_cache_overflow_regression) { - HDNode node1 = {0}; - HDNode node2 = {0}; - const uint8_t *seed = fromhex( - "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f1" - "74429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"); - uint32_t path[BIP32_CACHE_MAXDEPTH + 2] = {0}; - size_t depth = sizeof(path) / sizeof(path[0]); - - hdnode_from_seed(seed, 64, SECP256K1_NAME, &node1); - hdnode_from_seed(seed, 64, SECP256K1_NAME, &node2); - ck_assert_int_eq(hdnode_private_ckd_cached(&node1, path, depth, NULL), 1); - - // A path deeper than the cache must not corrupt the fixed-size cache key. - path[BIP32_CACHE_MAXDEPTH] = BIP32_CACHE_MAXDEPTH + 1; - ck_assert_int_eq(hdnode_private_ckd_cached(&node2, path, depth, NULL), 1); - ck_assert_mem_ne(node1.private_key, node2.private_key, - sizeof(node1.private_key)); -} -END_TEST - -START_TEST(test_bip32_depth_overflow_regression) { - HDNode node = {0}; - hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, - SECP256K1_NAME, &node); - hdnode_fill_public_key(&node); - node.depth = UINT32_MAX; - - ck_assert_int_eq(hdnode_private_ckd(&node, 1), 0); - ck_assert_uint_eq(node.depth, UINT32_MAX); - - memzero(node.private_key, sizeof(node.private_key)); - ck_assert_int_eq(hdnode_public_ckd(&node, 1), 0); - ck_assert_uint_eq(node.depth, UINT32_MAX); -} -END_TEST - -START_TEST(test_bip32_nist_seed) { - HDNode node; - - // init m - hdnode_from_seed( - fromhex( - "a7305bc8df8d0951f0cb224c0e95d7707cbdf2c6ce7e8d481fec69c7ff5e9446"), - 32, NIST256P1_NAME, &node); - - // [Chain m] - ck_assert_mem_eq( - node.private_key, - fromhex( - "3b8c18469a4634517d6d0b65448f8e6c62091b45540a1743c5846be55d47d88f"), - 32); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "7762f9729fed06121fd13f326884c82f59aa95c57ac492ce8c9654e60efd130c"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "0383619fadcde31063d8c5cb00dbfe1713f3e6fa169d8541a798752a1c1ca0cb20"), - 33); - - // init m - hdnode_from_seed( - fromhex( - "aa305bc8df8d0951f0cb29ad4568d7707cbdf2c6ce7e8d481fec69c7ff5e9446"), - 32, NIST256P1_NAME, &node); - - // [Chain m] - ck_assert_mem_eq( - node.chain_code, - fromhex( - "a81d21f36f987fa0be3b065301bfb6aa9deefbf3dfef6744c37b9a4abc3c68f1"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "0e49dc46ce1d8c29d9b80a05e40f5d0cd68cbf02ae98572186f5343be18084bf"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "03aaa4c89acd9a98935330773d3dae55122f3591bac4a40942681768de8df6ba63"), - 33); -} -END_TEST - -START_TEST(test_bip32_nist_vector_1) { - HDNode node; - uint32_t fingerprint; - - // init m - hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, - NIST256P1_NAME, &node); - - // [Chain m] - fingerprint = 0; - ck_assert_uint_eq(fingerprint, 0x00000000); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "beeb672fe4621673f722f38529c07392fecaa61015c80c34f29ce8b41b3cb6ea"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "612091aaa12e22dd2abef664f8a01a82cae99ad7441b7ef8110424915c268bc2"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "0266874dc6ade47b3ecd096745ca09bcd29638dd52c2c12117b11ed3e458cfa9e8"), - 33); - - // [Chain m/0'] - fingerprint = hdnode_fingerprint(&node); - hdnode_private_ckd_prime(&node, 0); - ck_assert_uint_eq(fingerprint, 0xbe6105b5); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "3460cea53e6a6bb5fb391eeef3237ffd8724bf0a40e94943c98b83825342ee11"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "6939694369114c67917a182c59ddb8cafc3004e63ca5d3b84403ba8613debc0c"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "0384610f5ecffe8fda089363a41f56a5c7ffc1d81b59a612d0d649b2d22355590c"), - 33); - - // [Chain m/0'/1] - fingerprint = hdnode_fingerprint(&node); - hdnode_private_ckd(&node, 1); - ck_assert_uint_eq(fingerprint, 0x9b02312f); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "4187afff1aafa8445010097fb99d23aee9f599450c7bd140b6826ac22ba21d0c"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "284e9d38d07d21e4e281b645089a94f4cf5a5a81369acf151a1c3a57f18b2129"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "03526c63f8d0b4bbbf9c80df553fe66742df4676b241dabefdef67733e070f6844"), - 33); - - // [Chain m/0'/1/2'] - fingerprint = hdnode_fingerprint(&node); - hdnode_private_ckd_prime(&node, 2); - ck_assert_uint_eq(fingerprint, 0xb98005c1); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "98c7514f562e64e74170cc3cf304ee1ce54d6b6da4f880f313e8204c2a185318"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "694596e8a54f252c960eb771a3c41e7e32496d03b954aeb90f61635b8e092aa7"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "0359cf160040778a4b14c5f4d7b76e327ccc8c4a6086dd9451b7482b5a4972dda0"), - 33); - - // [Chain m/0'/1/2'/2] - fingerprint = hdnode_fingerprint(&node); - hdnode_private_ckd(&node, 2); - ck_assert_uint_eq(fingerprint, 0x0e9f3274); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "ba96f776a5c3907d7fd48bde5620ee374d4acfd540378476019eab70790c63a0"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "5996c37fd3dd2679039b23ed6f70b506c6b56b3cb5e424681fb0fa64caf82aaa"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "029f871f4cb9e1c97f9f4de9ccd0d4a2f2a171110c61178f84430062230833ff20"), - 33); - - // [Chain m/0'/1/2'/2/1000000000] - fingerprint = hdnode_fingerprint(&node); - hdnode_private_ckd(&node, 1000000000); - ck_assert_uint_eq(fingerprint, 0x8b2b5c4b); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "b9b7b82d326bb9cb5b5b121066feea4eb93d5241103c9e7a18aad40f1dde8059"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "21c4f269ef0a5fd1badf47eeacebeeaa3de22eb8e5b0adcd0f27dd99d34d0119"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "02216cd26d31147f72427a453c443ed2cde8a1e53c9cc44e5ddf739725413fe3f4"), - 33); -} -END_TEST - -START_TEST(test_bip32_nist_vector_2) { - HDNode node; - uint32_t fingerprint; - int r; - - // init m - hdnode_from_seed( - fromhex( - "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c" - "999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), - 64, NIST256P1_NAME, &node); - - // [Chain m] - fingerprint = 0; - ck_assert_uint_eq(fingerprint, 0x00000000); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "96cd4465a9644e31528eda3592aa35eb39a9527769ce1855beafc1b81055e75d"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "eaa31c2e46ca2962227cf21d73a7ef0ce8b31c756897521eb6c7b39796633357"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "02c9e16154474b3ed5b38218bb0463e008f89ee03e62d22fdcc8014beab25b48fa"), - 33); - - // [Chain m/0] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd(&node, 0); - ck_assert_int_eq(r, 1); - ck_assert_uint_eq(fingerprint, 0x607f628f); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "84e9c258bb8557a40e0d041115b376dd55eda99c0042ce29e81ebe4efed9b86a"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "d7d065f63a62624888500cdb4f88b6d59c2927fee9e6d0cdff9cad555884df6e"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "039b6df4bece7b6c81e2adfeea4bcf5c8c8a6e40ea7ffa3cf6e8494c61a1fc82cc"), - 33); - - // [Chain m/0/2147483647'] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd_prime(&node, 2147483647); - ck_assert_int_eq(r, 1); - ck_assert_uint_eq(fingerprint, 0x946d2a54); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "f235b2bc5c04606ca9c30027a84f353acf4e4683edbd11f635d0dcc1cd106ea6"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "96d2ec9316746a75e7793684ed01e3d51194d81a42a3276858a5b7376d4b94b9"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "02f89c5deb1cae4fedc9905f98ae6cbf6cbab120d8cb85d5bd9a91a72f4c068c76"), - 33); - - // [Chain m/0/2147483647'/1] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd(&node, 1); - ck_assert_int_eq(r, 1); - ck_assert_uint_eq(fingerprint, 0x218182d8); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "7c0b833106235e452eba79d2bdd58d4086e663bc8cc55e9773d2b5eeda313f3b"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "974f9096ea6873a915910e82b29d7c338542ccde39d2064d1cc228f371542bbc"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "03abe0ad54c97c1d654c1852dfdc32d6d3e487e75fa16f0fd6304b9ceae4220c64"), - 33); - - // [Chain m/0/2147483647'/1/2147483646'] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd_prime(&node, 2147483646); - ck_assert_int_eq(r, 1); - ck_assert_uint_eq(fingerprint, 0x931223e4); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "5794e616eadaf33413aa309318a26ee0fd5163b70466de7a4512fd4b1a5c9e6a"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "da29649bbfaff095cd43819eda9a7be74236539a29094cd8336b07ed8d4eff63"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "03cb8cb067d248691808cd6b5a5a06b48e34ebac4d965cba33e6dc46fe13d9b933"), - 33); - - // [Chain m/0/2147483647'/1/2147483646'/2] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd(&node, 2); - ck_assert_int_eq(r, 1); - ck_assert_uint_eq(fingerprint, 0x956c4629); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "3bfb29ee8ac4484f09db09c2079b520ea5616df7820f071a20320366fbe226a7"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "bb0a77ba01cc31d77205d51d08bd313b979a71ef4de9b062f8958297e746bd67"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "020ee02e18967237cf62672983b253ee62fa4dd431f8243bfeccdf39dbe181387f"), - 33); - - // init m - hdnode_from_seed( - fromhex( - "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c" - "999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), - 64, NIST256P1_NAME, &node); - - // test public derivation - // [Chain m/0] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_public_ckd(&node, 0); - ck_assert_int_eq(r, 1); - ck_assert_uint_eq(fingerprint, 0x607f628f); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "84e9c258bb8557a40e0d041115b376dd55eda99c0042ce29e81ebe4efed9b86a"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "0000000000000000000000000000000000000000000000000000000000000000"), - 32); - ck_assert_mem_eq( - node.public_key, - fromhex( - "039b6df4bece7b6c81e2adfeea4bcf5c8c8a6e40ea7ffa3cf6e8494c61a1fc82cc"), - 33); -} -END_TEST - -START_TEST(test_bip32_nist_compare) { - HDNode node1, node2, node3; - int i, r; - hdnode_from_seed( - fromhex( - "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" - "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), - 64, NIST256P1_NAME, &node1); - hdnode_from_seed( - fromhex( - "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" - "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), - 64, NIST256P1_NAME, &node2); - hdnode_fill_public_key(&node2); - for (i = 0; i < 100; i++) { - memcpy(&node3, &node1, sizeof(HDNode)); - hdnode_fill_public_key(&node3); - r = hdnode_private_ckd(&node1, i); - ck_assert_int_eq(r, 1); - r = hdnode_public_ckd(&node2, i); - ck_assert_int_eq(r, 1); - r = hdnode_public_ckd(&node3, i); - ck_assert_int_eq(r, 1); - ck_assert_uint_eq(node1.depth, node2.depth); - ck_assert_uint_eq(node1.depth, node3.depth); - ck_assert_uint_eq(node1.child_num, node2.child_num); - ck_assert_uint_eq(node1.child_num, node3.child_num); - ck_assert_mem_eq(node1.chain_code, node2.chain_code, 32); - ck_assert_mem_eq(node1.chain_code, node3.chain_code, 32); - ck_assert_mem_eq( - node2.private_key, - fromhex( - "0000000000000000000000000000000000000000000000000000000000000000"), - 32); - ck_assert_mem_eq( - node3.private_key, - fromhex( - "0000000000000000000000000000000000000000000000000000000000000000"), - 32); - hdnode_fill_public_key(&node1); - ck_assert_mem_eq(node1.public_key, node2.public_key, 33); - ck_assert_mem_eq(node1.public_key, node3.public_key, 33); - } -} -END_TEST - -START_TEST(test_bip32_nist_repeat) { - HDNode node, node2; - uint32_t fingerprint; - int r; - - // init m - hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, - NIST256P1_NAME, &node); - - // [Chain m/28578'] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd_prime(&node, 28578); - ck_assert_int_eq(r, 1); - ck_assert_uint_eq(fingerprint, 0xbe6105b5); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "e94c8ebe30c2250a14713212f6449b20f3329105ea15b652ca5bdfc68f6c65c2"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "06f0db126f023755d0b8d86d4591718a5210dd8d024e3e14b6159d63f53aa669"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "02519b5554a4872e8c9c1c847115363051ec43e93400e030ba3c36b52a3e70a5b7"), - 33); - - memcpy(&node2, &node, sizeof(HDNode)); - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd(&node2, 33941); - ck_assert_int_eq(r, 1); - ck_assert_uint_eq(fingerprint, 0x3e2b7bc6); - ck_assert_mem_eq( - node2.chain_code, - fromhex( - "9e87fe95031f14736774cd82f25fd885065cb7c358c1edf813c72af535e83071"), - 32); - ck_assert_mem_eq( - node2.private_key, - fromhex( - "092154eed4af83e078ff9b84322015aefe5769e31270f62c3f66c33888335f3a"), - 32); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq( - node2.public_key, - fromhex( - "0235bfee614c0d5b2cae260000bb1d0d84b270099ad790022c1ae0b2e782efe120"), - 33); - - memcpy(&node2, &node, sizeof(HDNode)); - memzero(&node2.private_key, 32); - r = hdnode_public_ckd(&node2, 33941); - ck_assert_int_eq(r, 1); - ck_assert_uint_eq(fingerprint, 0x3e2b7bc6); - ck_assert_mem_eq( - node2.chain_code, - fromhex( - "9e87fe95031f14736774cd82f25fd885065cb7c358c1edf813c72af535e83071"), - 32); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq( - node2.public_key, - fromhex( - "0235bfee614c0d5b2cae260000bb1d0d84b270099ad790022c1ae0b2e782efe120"), - 33); -} -END_TEST - -// test vector 1 from https://en.bitcoin.it/wiki/BIP_0032_TestVectors -START_TEST(test_bip32_ed25519_vector_1) { - HDNode node; - - // init m - hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, - ED25519_NAME, &node); - - // [Chain m] - ck_assert_mem_eq( - node.chain_code, - fromhex( - "90046a93de5380a72b5e45010748567d5ea02bbf6522f979e05c0d8d8ca9fffb"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "2b4be7f19ee27bbf30c667b642d5f4aa69fd169872f8fc3059c08ebae2eb19e7"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "01a4b2856bfec510abab89753fac1ac0e1112364e7d250545963f135f2a33188ed"), - 33); - - // [Chain m/0'] - hdnode_private_ckd_prime(&node, 0); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "8b59aa11380b624e81507a27fedda59fea6d0b779a778918a2fd3590e16e9c69"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "68e0fe46dfb67e368c75379acec591dad19df3cde26e63b93a8e704f1dade7a3"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "018c8a13df77a28f3445213a0f432fde644acaa215fc72dcdf300d5efaa85d350c"), - 33); - - // [Chain m/0'/1'] - hdnode_private_ckd_prime(&node, 1); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "a320425f77d1b5c2505a6b1b27382b37368ee640e3557c315416801243552f14"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "b1d0bad404bf35da785a64ca1ac54b2617211d2777696fbffaf208f746ae84f2"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "011932a5270f335bed617d5b935c80aedb1a35bd9fc1e31acafd5372c30f5c1187"), - 33); - - // [Chain m/0'/1'/2'] - hdnode_private_ckd_prime(&node, 2); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "2e69929e00b5ab250f49c3fb1c12f252de4fed2c1db88387094a0f8c4c9ccd6c"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "92a5b23c0b8a99e37d07df3fb9966917f5d06e02ddbd909c7e184371463e9fc9"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "01ae98736566d30ed0e9d2f4486a64bc95740d89c7db33f52121f8ea8f76ff0fc1"), - 33); - - // [Chain m/0'/1'/2'/2'] - hdnode_private_ckd_prime(&node, 2); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "8f6d87f93d750e0efccda017d662a1b31a266e4a6f5993b15f5c1f07f74dd5cc"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "30d1dc7e5fc04c31219ab25a27ae00b50f6fd66622f6e9c913253d6511d1e662"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "018abae2d66361c879b900d204ad2cc4984fa2aa344dd7ddc46007329ac76c429c"), - 33); - - // [Chain m/0'/1'/2'/2'/1000000000'] - hdnode_private_ckd_prime(&node, 1000000000); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "68789923a0cac2cd5a29172a475fe9e0fb14cd6adb5ad98a3fa70333e7afa230"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "8f94d394a8e8fd6b1bc2f3f49f5c47e385281d5c17e65324b0f62483e37e8793"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "013c24da049451555d51a7014a37337aa4e12d41e485abccfa46b47dfb2af54b7a"), - 33); -} -END_TEST - -// test vector 2 from https://en.bitcoin.it/wiki/BIP_0032_TestVectors -START_TEST(test_bip32_ed25519_vector_2) { - HDNode node; - int r; - - // init m - hdnode_from_seed( - fromhex( - "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c" - "999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), - 64, ED25519_NAME, &node); - - // [Chain m] - ck_assert_mem_eq( - node.chain_code, - fromhex( - "ef70a74db9c3a5af931b5fe73ed8e1a53464133654fd55e7a66f8570b8e33c3b"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "171cb88b1b3c1db25add599712e36245d75bc65a1a5c9e18d76f9f2b1eab4012"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "018fe9693f8fa62a4305a140b9764c5ee01e455963744fe18204b4fb948249308a"), - 33); - - // [Chain m/0'] - r = hdnode_private_ckd_prime(&node, 0); - ck_assert_int_eq(r, 1); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "0b78a3226f915c082bf118f83618a618ab6dec793752624cbeb622acb562862d"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "1559eb2bbec5790b0c65d8693e4d0875b1747f4970ae8b650486ed7470845635"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "0186fab68dcb57aa196c77c5f264f215a112c22a912c10d123b0d03c3c28ef1037"), - 33); - - // [Chain m/0'/2147483647'] - r = hdnode_private_ckd_prime(&node, 2147483647); - ck_assert_int_eq(r, 1); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "138f0b2551bcafeca6ff2aa88ba8ed0ed8de070841f0c4ef0165df8181eaad7f"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "ea4f5bfe8694d8bb74b7b59404632fd5968b774ed545e810de9c32a4fb4192f4"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "015ba3b9ac6e90e83effcd25ac4e58a1365a9e35a3d3ae5eb07b9e4d90bcf7506d"), - 33); - - // [Chain m/0'/2147483647'/1'] - r = hdnode_private_ckd_prime(&node, 1); - ck_assert_int_eq(r, 1); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "73bd9fff1cfbde33a1b846c27085f711c0fe2d66fd32e139d3ebc28e5a4a6b90"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "3757c7577170179c7868353ada796c839135b3d30554bbb74a4b1e4a5a58505c"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "012e66aa57069c86cc18249aecf5cb5a9cebbfd6fadeab056254763874a9352b45"), - 33); - - // [Chain m/0'/2147483647'/1'/2147483646'] - r = hdnode_private_ckd_prime(&node, 2147483646); - ck_assert_int_eq(r, 1); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "0902fe8a29f9140480a00ef244bd183e8a13288e4412d8389d140aac1794825a"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "5837736c89570de861ebc173b1086da4f505d4adb387c6a1b1342d5e4ac9ec72"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "01e33c0f7d81d843c572275f287498e8d408654fdf0d1e065b84e2e6f157aab09b"), - 33); - - // [Chain m/0'/2147483647'/1'/2147483646'/2'] - r = hdnode_private_ckd_prime(&node, 2); - ck_assert_int_eq(r, 1); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "5d70af781f3a37b829f0d060924d5e960bdc02e85423494afc0b1a41bbe196d4"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "551d333177df541ad876a60ea71f00447931c0a9da16f227c11ea080d7391b8d"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "0147150c75db263559a70d5778bf36abbab30fb061ad69f69ece61a72b0cfa4fc0"), - 33); -} -END_TEST - -// test vector 1 from -// https://github.com/decred/dcrd/blob/master/hdkeychain/extendedkey_test.go -START_TEST(test_bip32_decred_vector_1) { - HDNode node, node2, node3; - uint32_t fingerprint; - char str[XPUB_MAXLEN]; - int r; - - // init m - hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, - SECP256K1_NAME, &node); - - // secp256k1_decred_info.bip32_name != "Bitcoin seed" so we cannot use it in - // hdnode_from_seed - node.curve = &secp256k1_decred_info; - - // [Chain m] - fingerprint = 0; - ck_assert_uint_eq(fingerprint, 0x00000000); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2"), - 33); - hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, - sizeof(str)); - ck_assert_str_eq(str, - "dprv3hCznBesA6jBtmoyVFPfyMSZ1qYZ3WdjdebquvkEfmRfxC9VFEFi2YD" - "aJqHnx7uGe75eGSa3Mn3oHK11hBW7KZUrPxwbCPBmuCi1nwm182s"); - r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, - SECP256K1_DECRED_NAME, &node2, NULL); - ck_assert_int_eq(r, 0); - ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, - sizeof(str)); - ck_assert_str_eq(str, - "dpubZ9169KDAEUnyoBhjjmT2VaEodr6pUTDoqCEAeqgbfr2JfkB88BbK77j" - "bTYbcYXb2FVz7DKBdW4P618yd51MwF8DjKVopSbS7Lkgi6bowX5w"); - r = hdnode_deserialize_public(str, DECRED_VERSION_PUBLIC, - SECP256K1_DECRED_NAME, &node2, NULL); - ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0'] - fingerprint = hdnode_fingerprint(&node); - hdnode_private_ckd_prime(&node, 0); - ck_assert_uint_eq(fingerprint, 0xbc495588); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56"), - 33); - hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, - sizeof(str)); - ck_assert_str_eq(str, - "dprv3kUQDBztdyjKuwnaL3hfKYpT7W6X2huYH5d61YSWFBebSYwEBHAXJkC" - "pQ7rvMAxPzKqxVCGLvBqWvGxXjAyMJsV1XwKkfnQCM9KctC8k8bk"); - r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, - SECP256K1_DECRED_NAME, &node2, NULL); - ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, - sizeof(str)); - ck_assert_str_eq(str, - "dpubZCGVaKZBiMo7pMgLaZm1qmchjWenTeVcUdFQkTNsFGFEA6xs4EW8PKi" - "qYqP7HBAitt9Hw16VQkQ1tjsZQSHNWFc6bEK6bLqrbco24FzBTY4"); - r = hdnode_deserialize_public(str, DECRED_VERSION_PUBLIC, - SECP256K1_DECRED_NAME, &node2, NULL); - ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0'/1] - fingerprint = hdnode_fingerprint(&node); - hdnode_private_ckd(&node, 1); - ck_assert_uint_eq(fingerprint, 0xc67bc2ef); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c"), - 33); - hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, - sizeof(str)); - ck_assert_str_eq(str, - "dprv3nRtCZ5VAoHW4RUwQgRafSNRPUDFrmsgyY71A5eoZceVfuyL9SbZe2r" - "cbwDW2UwpkEniE4urffgbypegscNchPajWzy9QS4cRxF8QYXsZtq"); - r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, - SECP256K1_DECRED_NAME, &node2, NULL); - ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, - sizeof(str)); - ck_assert_str_eq(str, - "dpubZEDyZgdnFBMHxqNhfCUwBfAg1UmXHiTmB5jKtzbAZhF8PTzy2PwAicN" - "dkg1CmW6TARxQeUbgC7nAQenJts4YoG3KMiqcjsjgeMvwLc43w6C"); - r = hdnode_deserialize_public(str, DECRED_VERSION_PUBLIC, - SECP256K1_DECRED_NAME, &node2, NULL); - ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0'/1/2'] - fingerprint = hdnode_fingerprint(&node); - hdnode_private_ckd_prime(&node, 2); - ck_assert_uint_eq(fingerprint, 0xe7072187); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2"), - 33); - hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, - sizeof(str)); - ck_assert_str_eq(str, - "dprv3pYtkZK168vgrU38gXkUSjHQ2LGpEUzQ9fXrR8fGUR59YviSnm6U82X" - "jQYhpJEUPnVcC9bguJBQU5xVM4VFcDHu9BgScGPA6mQMH4bn5Cth"); - r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, - SECP256K1_DECRED_NAME, &node2, NULL); - ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, - sizeof(str)); - ck_assert_str_eq(str, - "dpubZGLz7gsJAWzUksvtw3opxx5eeLq5fRaUMDABA3bdUVfnGUk5fiS5Cc3" - "kZGTjWtYr3jrEavQQnAF6jv2WCpZtFX4uFgifXqev6ED1TM9rTCB"); - r = hdnode_deserialize_public(str, DECRED_VERSION_PUBLIC, - SECP256K1_DECRED_NAME, &node2, NULL); - ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0'/1/2'/2] - fingerprint = hdnode_fingerprint(&node); - hdnode_private_ckd(&node, 2); - ck_assert_uint_eq(fingerprint, 0xbcbbc1c4); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "0f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29"), - 33); - hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, - sizeof(str)); - ck_assert_str_eq(str, - "dprv3r7zqYFjT3NiNzdnwGxGpYh6S1TJCp1zA6mSEGaqLBJFnCB94cRMp7Y" - "YLR49aTZHZ7ya1CXwQJ6rodKeU9NgQTxkPSK7pzgZRgjYkQ7rgJh"); - r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, - SECP256K1_DECRED_NAME, &node2, NULL); - ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, - sizeof(str)); - ck_assert_str_eq(str, - "dpubZHv6Cfp2XRSWHQXZBo1dLmVM421Zdkc4MePkyBXCLFttVkCmwZkxth4" - "ZV9PzkFP3DtD5xcVq2CPSYpJMWMaoxu1ixz4GNZFVcE2xnHP6chJ"); - r = hdnode_deserialize_public(str, DECRED_VERSION_PUBLIC, - SECP256K1_DECRED_NAME, &node2, NULL); - ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0'/1/2'/2/1000000000] - fingerprint = hdnode_fingerprint(&node); - hdnode_private_ckd(&node, 1000000000); - ck_assert_uint_eq(fingerprint, 0xe58b52e4); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011"), - 33); - hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, - sizeof(str)); - ck_assert_str_eq(str, - "dprv3tJXnTDSb3uE6Euo6WvvhFKfBMNfxuJt5smqyPoHEoomoBMQyhYoQSK" - "JAHWtWxmuqdUVb8q9J2NaTkF6rYm6XDrSotkJ55bM21fffa7VV97"); - r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, - SECP256K1_DECRED_NAME, &node2, NULL); - ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, - sizeof(str)); - ck_assert_str_eq(str, - "dpubZL6d9amjfRy1zeoZM2zHDU7uoMvwPqtxHRQAiJjeEtQQWjP3retQV1q" - "KJyzUd6ZJNgbJGXjtc5pdoBcTTYTLoxQzvV9JJCzCjB2eCWpRf8T"); - r = hdnode_deserialize_public(str, DECRED_VERSION_PUBLIC, - SECP256K1_DECRED_NAME, &node2, NULL); - ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); -} -END_TEST - -// test vector 2 from -// https://github.com/decred/dcrd/blob/master/hdkeychain/extendedkey_test.go -START_TEST(test_bip32_decred_vector_2) { - HDNode node, node2, node3; - uint32_t fingerprint; - char str[XPUB_MAXLEN]; - int r; - - // init m - hdnode_from_seed( - fromhex( - "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c" - "999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), - 64, SECP256K1_NAME, &node); - - // secp256k1_decred_info.bip32_name != "Bitcoin seed" so we cannot use it in - // hdnode_from_seed - node.curve = &secp256k1_decred_info; - - // [Chain m] - fingerprint = 0; - ck_assert_uint_eq(fingerprint, 0x00000000); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "60499f801b896d83179a4374aeb7822aaeaceaa0db1f85ee3e904c4defbd9689"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "4b03d6fc340455b363f51020ad3ecca4f0850280cf436c70c727923f6db46c3e"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "03cbcaa9c98c877a26977d00825c956a238e8dddfbd322cce4f74b0b5bd6ace4a7"), - 33); - hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, - sizeof(str)); - ck_assert_str_eq(str, - "dprv3hCznBesA6jBtPKJbQTxRZAKG2gyj8tZKEPaCsV4e9YYFBAgRP2eTSP" - "Aeu4r8dTMt9q51j2Vdt5zNqj7jbtovvocrP1qLj6WUTLF9xYQt4y"); - r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, - SECP256K1_DECRED_NAME, &node2, NULL); - ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, - sizeof(str)); - ck_assert_str_eq(str, - "dpubZ9169KDAEUnynoD4qvXJwmxZt3FFA5UdWn1twnRReE9AxjCKJLNFY1u" - "BoegbFmwzA4Du7yqnu8tLivhrCCH6P3DgBS1HH5vmf8MpNXvvYT9"); - r = hdnode_deserialize_public(str, DECRED_VERSION_PUBLIC, - SECP256K1_DECRED_NAME, &node2, NULL); - ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd(&node, 0); - ck_assert_int_eq(r, 1); - ck_assert_uint_eq(fingerprint, 0x2524c9d3); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "abe74a98f6c7eabee0428f53798f0ab8aa1bd37873999041703c742f15ac7e1e"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"), - 33); - hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, - sizeof(str)); - ck_assert_str_eq(str, - "dprv3jMy45BuuDETfxi59P8NTSjHPrNVq4wPRfLgRd57923L2hosj5NUEqi" - "LYQ4i7fJtUpiXZLr2wUeToJY2Tm5sCpAJdajEHDmieVJiPQNXwu9"); - r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, - SECP256K1_DECRED_NAME, &node2, NULL); - ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, - sizeof(str)); - ck_assert_str_eq(str, - "dpubZBA4RCkCybJFaNbqPuBiyfXY1rvmG1XTdCy1AY1U96dxkFqWc2i5KRE" - "Mh7NYPpy7ZPMhdpFMAesex3JdFDfX4J5FEW3HjSacqEYPfwb9Cj7"); - r = hdnode_deserialize_public(str, DECRED_VERSION_PUBLIC, - SECP256K1_DECRED_NAME, &node2, NULL); - ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0/2147483647'] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd_prime(&node, 2147483647); - ck_assert_int_eq(r, 1); - ck_assert_uint_eq(fingerprint, 0x6035c6ad); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "be17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d9"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "877c779ad9687164e9c2f4f0f4ff0340814392330693ce95a58fe18fd52e6e93"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "03c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b"), - 33); - hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, - sizeof(str)); - ck_assert_str_eq(str, - "dprv3mgHPRgK838mLK6T1p6WeBoJoJtXA1pGTHjqFuyHekcM7UTuER8fGwe" - "RRsoLqSuHa98uskVPnJnfWZEBUC1AVmXnSCPDvUFKydXNnnPHTuQ"); - r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, - SECP256K1_DECRED_NAME, &node2, NULL); - ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, - sizeof(str)); - ck_assert_str_eq(str, - "dpubZDUNkZEcCRCZEizDGL9sAQbZRKSnaxQLeqN9zpueeqCyq2VY7NUGMXA" - "SacsK96S8XzNjq3YgFgwLtj8MJBToW6To9U5zxuazEyh89bjR1xA"); - r = hdnode_deserialize_public(str, DECRED_VERSION_PUBLIC, - SECP256K1_DECRED_NAME, &node2, NULL); - ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0/2147483647'/1] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd(&node, 1); - ck_assert_int_eq(r, 1); - ck_assert_uint_eq(fingerprint, 0x36fc7080); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "704addf544a06e5ee4bea37098463c23613da32020d604506da8c0518e1da4b7"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9"), - 33); - hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, - sizeof(str)); - ck_assert_str_eq(str, - "dprv3oFqwZZ9bJcUmhAeJyyshvrTWtrAsHfcRYQbEzNiiH5nGvM6wVTDn6w" - "oQEz92b2EHTYZBtLi82jKEnxSouA3cVaW8YWBsw5c3f4mwAhA3d2"); - r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, - SECP256K1_DECRED_NAME, &node2, NULL); - ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, - sizeof(str)); - ck_assert_str_eq(str, - "dpubZF3wJh7SfggGg74QZW3EE9ei8uQSJEFgd62uyuK5iMgQzUNjpSnprgT" - "pYz3d6Q3fXXtEEXQqpzWcP4LUVuXFsgA8JKt1Hot5kyUk4pPRhDz"); - r = hdnode_deserialize_public(str, DECRED_VERSION_PUBLIC, - SECP256K1_DECRED_NAME, &node2, NULL); - ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0/2147483647'/1/2147483646'] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd_prime(&node, 2147483646); - ck_assert_int_eq(r, 1); - ck_assert_uint_eq(fingerprint, 0x45309b4c); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e29"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "f1c7c871a54a804afe328b4c83a1c33b8e5ff48f5087273f04efa83b247d6a2d"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "02d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0"), - 33); - hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, - sizeof(str)); - ck_assert_str_eq(str, - "dprv3qF3177i87wMirg6sraDvqty8yZg6THpXFPSXuM5AShBiiUQbq8FhSZ" - "DGkYmBNR3RKfBrxzkKDBpsRFJfTnQfLsvpPPqRnakat6hHQA43X9"); - r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, - SECP256K1_DECRED_NAME, &node2, NULL); - ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, - sizeof(str)); - ck_assert_str_eq(str, - "dpubZH38NEg1CW19dGZs8NdaT4hDkz7wXPstio1mGpHSAXHpSGW3UnTrn25" - "ERT1Mp8ae5GMoQHMbgQiPrChMXQMdx3UqS8YqFkT1pqait8fY92u"); - r = hdnode_deserialize_public(str, DECRED_VERSION_PUBLIC, - SECP256K1_DECRED_NAME, &node2, NULL); - ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // [Chain m/0/2147483647'/1/2147483646'/2] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_private_ckd(&node, 2); - ck_assert_int_eq(r, 1); - ck_assert_uint_eq(fingerprint, 0x3491a5e6); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "9452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58eedf394ed271"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "bb7d39bdb83ecf58f2fd82b6d918341cbef428661ef01ab97c28a4842125ac23"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key, - fromhex( - "024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c"), - 33); - hdnode_serialize_private(&node, fingerprint, DECRED_VERSION_PRIVATE, str, - sizeof(str)); - ck_assert_str_eq(str, - "dprv3s15tfqzxhw8Kmo7RBEqMeyvC7uGekLniSmvbs3bckpxQ6ks1KKqfmH" - "144Jgh3PLxkyZRcS367kp7DrtUmnG16NpnsoNhxSXRgKbJJ7MUQR"); - r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, - SECP256K1_DECRED_NAME, &node2, NULL); - ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); - ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); - hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, - sizeof(str)); - ck_assert_str_eq(str, - "dpubZJoBFoQJ35zvEBgsfhJBssnAp8TY5gvruzQFLmyxcqRb7enVtGfSkLo" - "2CkAZJMpa6T2fx6fUtvTgXtUvSVgAZ56bEwGxQsToeZfFV8VadE1"); - r = hdnode_deserialize_public(str, DECRED_VERSION_PUBLIC, - SECP256K1_DECRED_NAME, &node2, NULL); - ck_assert_int_eq(r, 0); - memcpy(&node3, &node, sizeof(HDNode)); - memzero(&node3.private_key, 32); - ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); - - // init m - hdnode_deserialize_public( - "dpubZF4LSCdF9YKZfNzTVYhz4RBxsjYXqms8AQnMBHXZ8GUKoRSigG7kQnKiJt5pzk93Q8Fx" - "cdVBEkQZruSXduGtWnkwXzGnjbSovQ97dCxqaXc", - DECRED_VERSION_PUBLIC, SECP256K1_DECRED_NAME, &node, NULL); - - // test public derivation - // [Chain m/0] - fingerprint = hdnode_fingerprint(&node); - r = hdnode_public_ckd(&node, 0); - ck_assert_int_eq(r, 1); - ck_assert_uint_eq(fingerprint, 0x6a19cfb3); - ck_assert_mem_eq( - node.chain_code, - fromhex( - "dcfe00831741a3a4803955147cdfc7053d69b167b1d03b5f9e63934217a005fd"), - 32); - ck_assert_mem_eq( - node.public_key, - fromhex( - "029555ea7bde276cd2c42c4502f40b5d16469fb310ae3aeee2a9000455f41b0866"), - 33); - hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, - sizeof(str)); - ck_assert_str_eq(str, - "dpubZHJs2Z3PtHbbpaXQCi5wBKPhU8tC5ztBKUYBCYNGKk8eZ1EmBs3MhnL" - "JbxHFMAahGnDnZT7qZxC7AXKP8PB6BDNUZgkG77moNMRmXyQ6s6s"); - r = hdnode_deserialize_public(str, DECRED_VERSION_PUBLIC, - SECP256K1_DECRED_NAME, &node2, NULL); - ck_assert_int_eq(r, 0); - ck_assert_mem_eq(&node2, &node, sizeof(HDNode)); -} -END_TEST - -START_TEST(test_ecdsa_signature) { - int res; - uint8_t digest[32]; - uint8_t pubkey[65]; - uint8_t sig[64]; - const ecdsa_curve *curve = &secp256k1; - - // Signature verification for a digest which is equal to the group order. - // https://github.com/trezor/trezor-firmware/pull/1374 - memcpy( - pubkey, - fromhex( - "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179848" - "3ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"), - sizeof(pubkey)); - memcpy( - digest, - fromhex( - "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"), - sizeof(digest)); - memcpy(sig, - fromhex( - "a0b37f8fba683cc68f6574cd43b39f0343a50008bf6ccea9d13231d9e7e2e1e41" - "1edc8d307254296264aebfc3dc76cd8b668373a072fd64665b50000e9fcce52"), - sizeof(sig)); - res = ecdsa_verify_digest(curve, pubkey, sig, digest); - ck_assert_int_eq(res, 0); - - // sha2(sha2("\x18Bitcoin Signed Message:\n\x0cHello World!")) - memcpy( - digest, - fromhex( - "de4e9524586d6fce45667f9ff12f661e79870c4105fa0fb58af976619bb11432"), - 32); - // r = 2: Four points should exist - res = ecdsa_recover_pub_from_sig( - curve, pubkey, - fromhex( - "00000000000000000000000000000000000000000000000000000000000000020123" - "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), - digest, 0); - ck_assert_int_eq(res, 0); - ck_assert_mem_eq( - pubkey, - fromhex( - "043fc5bf5fec35b6ffe6fd246226d312742a8c296bfa57dd22da509a2e348529b7dd" - "b9faf8afe1ecda3c05e7b2bda47ee1f5a87e952742b22afca560b29d972fcf"), - 65); - res = ecdsa_recover_pub_from_sig( - curve, pubkey, - fromhex( - "00000000000000000000000000000000000000000000000000000000000000020123" - "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), - digest, 1); - ck_assert_int_eq(res, 0); - ck_assert_mem_eq( - pubkey, - fromhex( - "0456d8089137b1fd0d890f8c7d4a04d0fd4520a30b19518ee87bd168ea12ed809032" - "9274c4c6c0d9df04515776f2741eeffc30235d596065d718c3973e19711ad0"), - 65); - res = ecdsa_recover_pub_from_sig( - curve, pubkey, - fromhex( - "00000000000000000000000000000000000000000000000000000000000000020123" - "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), - digest, 2); - ck_assert_int_eq(res, 0); - ck_assert_mem_eq( - pubkey, - fromhex( - "04cee0e740f41aab39156844afef0182dea2a8026885b10454a2d539df6f6df9023a" - "bfcb0f01c50bef3c0fa8e59a998d07441e18b1c60583ef75cc8b912fb21a15"), - 65); - res = ecdsa_recover_pub_from_sig( - curve, pubkey, - fromhex( - "00000000000000000000000000000000000000000000000000000000000000020123" - "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), - digest, 3); - ck_assert_int_eq(res, 0); - ck_assert_mem_eq( - pubkey, - fromhex( - "0490d2bd2e9a564d6e1d8324fc6ad00aa4ae597684ecf4abea58bdfe7287ea4fa729" - "68c2e5b0b40999ede3d7898d94e82c3f8dc4536a567a4bd45998c826a4c4b2"), - 65); - // A recovered point at infinity is not a valid public key. - res = ecdsa_recover_pub_from_sig( - curve, pubkey, - fromhex( - "220cf4c7b6d568f2256a8c30cc1784a625a28c3627dac404aa9a9ecd08314ec81a88" - "828f20d69d102bab5de5f6ee7ef040cb0ff7b8e1ba3f29d79efb5250f47d"), - digest, 0); - ck_assert_int_eq(res, 1); - - memcpy( - digest, - fromhex( - "0000000000000000000000000000000000000000000000000000000000000000"), - 32); - // r = 7: No point P with P.x = 7, but P.x = (order + 7) exists - res = ecdsa_recover_pub_from_sig( - curve, pubkey, - fromhex( - "00000000000000000000000000000000000000000000000000000000000000070123" - "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), - digest, 2); - ck_assert_int_eq(res, 0); - ck_assert_mem_eq( - pubkey, - fromhex( - "044d81bb47a31ffc6cf1f780ecb1e201ec47214b651650867c07f13ad06e12a1b040" - "de78f8dbda700f4d3cd7ee21b3651a74c7661809699d2be7ea0992b0d39797"), - 65); - res = ecdsa_recover_pub_from_sig( - curve, pubkey, - fromhex( - "00000000000000000000000000000000000000000000000000000000000000070123" - "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), - digest, 3); - ck_assert_int_eq(res, 0); - ck_assert_mem_eq( - pubkey, - fromhex( - "044d81bb47a31ffc6cf1f780ecb1e201ec47214b651650867c07f13ad06e12a1b0bf" - "21870724258ff0b2c32811de4c9ae58b3899e7f69662d41815f66c4f2c6498"), - 65); - res = ecdsa_recover_pub_from_sig( - curve, pubkey, - fromhex( - "00000000000000000000000000000000000000000000000000000000000000070123" - "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), - digest, 0); - ck_assert_int_eq(res, 1); - - memcpy( - digest, - fromhex( - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), - 32); - // r = 1: Two points P with P.x = 1, but P.x = (order + 7) doesn't exist - res = ecdsa_recover_pub_from_sig( - curve, pubkey, - fromhex( - "00000000000000000000000000000000000000000000000000000000000000010123" - "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), - digest, 0); - ck_assert_int_eq(res, 0); - ck_assert_mem_eq( - pubkey, - fromhex( - "045d330b2f89dbfca149828277bae852dd4aebfe136982cb531a88e9e7a89463fe71" - "519f34ea8feb9490c707f14bc38c9ece51762bfd034ea014719b7c85d2871b"), - 65); - res = ecdsa_recover_pub_from_sig( - curve, pubkey, - fromhex( - "00000000000000000000000000000000000000000000000000000000000000010123" - "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), - digest, 1); - ck_assert_int_eq(res, 0); - ck_assert_mem_eq( - pubkey, - fromhex( - "049e609c3950e70d6f3e3f3c81a473b1d5ca72739d51debdd80230ae80cab05134a9" - "4285375c834a417e8115c546c41da83a263087b79ef1cae25c7b3c738daa2b"), - 65); - - // r = 0 is always invalid - res = ecdsa_recover_pub_from_sig( - curve, pubkey, - fromhex( - "00000000000000000000000000000000000000000000000000000000000000010123" - "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), - digest, 2); - ck_assert_int_eq(res, 1); - res = ecdsa_recover_pub_from_sig( - curve, pubkey, - fromhex( - "00000000000000000000000000000000000000000000000000000000000000000123" - "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), - digest, 0); - ck_assert_int_eq(res, 1); - // r >= order is always invalid - res = ecdsa_recover_pub_from_sig( - curve, pubkey, - fromhex( - "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410123" - "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), - digest, 0); - ck_assert_int_eq(res, 1); - // check that overflow of r is handled - res = ecdsa_recover_pub_from_sig( - curve, pubkey, - fromhex( - "000000000000000000000000000000014551231950B75FC4402DA1722FC9BAEE0123" - "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), - digest, 2); - ck_assert_int_eq(res, 1); - // s = 0 is always invalid - res = ecdsa_recover_pub_from_sig( - curve, pubkey, - fromhex( - "00000000000000000000000000000000000000000000000000000000000000020000" - "000000000000000000000000000000000000000000000000000000000000"), - digest, 0); - ck_assert_int_eq(res, 1); - // s >= order is always invalid - res = ecdsa_recover_pub_from_sig( - curve, pubkey, - fromhex( - "0000000000000000000000000000000000000000000000000000000000000002ffff" - "fffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"), - digest, 0); - ck_assert_int_eq(res, 1); -} -END_TEST - -#define test_deterministic(KEY, MSG, K) \ - do { \ - sha256_Raw((uint8_t *)MSG, strlen(MSG), buf); \ - init_rfc6979(fromhex(KEY), buf, NULL, &rng); \ - generate_k_rfc6979(&k, &rng); \ - bn_write_be(&k, buf); \ - ck_assert_mem_eq(buf, fromhex(K), 32); \ - } while (0) - -START_TEST(test_rfc6979) { - bignum256 k; - uint8_t buf[32]; - rfc6979_state rng; - - test_deterministic( - "c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721", - "sample", - "a6e3c57dd01abe90086538398355dd4c3b17aa873382b0f24d6129493d8aad60"); - test_deterministic( - "cca9fbcc1b41e5a95d369eaa6ddcff73b61a4efaa279cfc6567e8daa39cbaf50", - "sample", - "2df40ca70e639d89528a6b670d9d48d9165fdc0febc0974056bdce192b8e16a3"); - test_deterministic( - "0000000000000000000000000000000000000000000000000000000000000001", - "Satoshi Nakamoto", - "8f8a276c19f4149656b280621e358cce24f5f52542772691ee69063b74f15d15"); - test_deterministic( - "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", - "Satoshi Nakamoto", - "33a19b60e25fb6f4435af53a3d42d493644827367e6453928554f43e49aa6f90"); - test_deterministic( - "f8b8af8ce3c7cca5e300d33939540c10d45ce001b8f252bfbc57ba0342904181", - "Alan Turing", - "525a82b70e67874398067543fd84c83d30c175fdc45fdeee082fe13b1d7cfdf1"); - test_deterministic( - "0000000000000000000000000000000000000000000000000000000000000001", - "All those moments will be lost in time, like tears in rain. Time to " - "die...", - "38aa22d72376b4dbc472e06c3ba403ee0a394da63fc58d88686c611aba98d6b3"); - test_deterministic( - "e91671c46231f833a6406ccbea0e3e392c76c167bac1cb013f6f1013980455c2", - "There is a computer disease that anybody who works with computers knows " - "about. It's a very serious disease and it interferes completely with " - "the work. The trouble with computers is that you 'play' with them!", - "1f4b84c23a86a221d233f2521be018d9318639d5b8bbd6374a8a59232d16ad3d"); -} -END_TEST - -START_TEST(test_ecdsa_sign_digest_deterministic_regression) { - static const struct { - const char *priv_key; - const char *digest; - const char *sig; - } vectors[] = { - {"312155017c70a204106e034520e0cdf17b3e54516e2ece38e38e38e38e38e38e", - "ffffffffffffffffffffffffffffffff20202020202020202020202020202020", - "e3d70248ea2fc771fc8d5e62d76b9cfd5402c96990333549eaadce1ae9f737eb" - "5cfbdc7d1e0ec18cc9b57bbb18f0a57dc929ec3c4dfac9073c581705015f6a8a"}, - {"312155017c70a204106e034520e0cdf17b3e54516e2ece38e38e38e38e38e38e", - "2020202020202020202020202020202020202020202020202020202020202020", - "40666188895430715552a7e4c6b53851f37a93030fb94e043850921242db78e8" - "75aa2ac9fd7e5a19402973e60e64382cdc29a09ebf6cb37e92f23be5b9251aee"}, - }; - uint8_t priv_key[32] = {0}; - uint8_t digest[32] = {0}; - uint8_t sig[64] = {0}; - - for (size_t i = 0; i < sizeof(vectors) / sizeof(*vectors); i++) { - memcpy(priv_key, fromhex(vectors[i].priv_key), sizeof(priv_key)); - memcpy(digest, fromhex(vectors[i].digest), sizeof(digest)); - ck_assert_int_eq( - ecdsa_sign_digest(&secp256k1, priv_key, digest, sig, NULL, NULL), - 0); - ck_assert_mem_eq(sig, fromhex(vectors[i].sig), sizeof(sig)); - } -} -END_TEST - -// test vectors from -// http://www.inconteam.com/software-development/41-encryption/55-aes-test-vectors -START_TEST(test_aes) { - aes_encrypt_ctx ctxe; - aes_decrypt_ctx ctxd; - uint8_t ibuf[16], obuf[16], iv[16], cbuf[16]; - const char **ivp, **plainp, **cipherp; - - // ECB - static const char *ecb_vector[] = { - // plain cipher - "6bc1bee22e409f96e93d7e117393172a", - "f3eed1bdb5d2a03c064b5a7e3db181f8", - "ae2d8a571e03ac9c9eb76fac45af8e51", - "591ccb10d410ed26dc5ba74a31362870", - "30c81c46a35ce411e5fbc1191a0a52ef", - "b6ed21b99ca6f4f9f153e7b1beafed1d", - "f69f2445df4f9b17ad2b417be66c3710", - "23304b7a39f9f3ff067d8d8f9e24ecc7", - 0, - 0, - }; - plainp = ecb_vector; - cipherp = ecb_vector + 1; - while (*plainp && *cipherp) { - // encrypt - aes_encrypt_key256( - fromhex( - "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), - &ctxe); - memcpy(ibuf, fromhex(*plainp), 16); - aes_ecb_encrypt(ibuf, obuf, 16, &ctxe); - ck_assert_mem_eq(obuf, fromhex(*cipherp), 16); - // decrypt - aes_decrypt_key256( - fromhex( - "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), - &ctxd); - memcpy(ibuf, fromhex(*cipherp), 16); - aes_ecb_decrypt(ibuf, obuf, 16, &ctxd); - ck_assert_mem_eq(obuf, fromhex(*plainp), 16); - plainp += 2; - cipherp += 2; - } - - // CBC - static const char *cbc_vector[] = { - // iv plain cipher - "000102030405060708090A0B0C0D0E0F", - "6bc1bee22e409f96e93d7e117393172a", - "f58c4c04d6e5f1ba779eabfb5f7bfbd6", - "F58C4C04D6E5F1BA779EABFB5F7BFBD6", - "ae2d8a571e03ac9c9eb76fac45af8e51", - "9cfc4e967edb808d679f777bc6702c7d", - "9CFC4E967EDB808D679F777BC6702C7D", - "30c81c46a35ce411e5fbc1191a0a52ef", - "39f23369a9d9bacfa530e26304231461", - "39F23369A9D9BACFA530E26304231461", - "f69f2445df4f9b17ad2b417be66c3710", - "b2eb05e2c39be9fcda6c19078c6a9d1b", - 0, - 0, - 0, - }; - ivp = cbc_vector; - plainp = cbc_vector + 1; - cipherp = cbc_vector + 2; - while (*plainp && *cipherp) { - // encrypt - aes_encrypt_key256( - fromhex( - "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), - &ctxe); - memcpy(iv, fromhex(*ivp), 16); - memcpy(ibuf, fromhex(*plainp), 16); - aes_cbc_encrypt(ibuf, obuf, 16, iv, &ctxe); - ck_assert_mem_eq(obuf, fromhex(*cipherp), 16); - // decrypt - aes_decrypt_key256( - fromhex( - "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), - &ctxd); - memcpy(iv, fromhex(*ivp), 16); - memcpy(ibuf, fromhex(*cipherp), 16); - aes_cbc_decrypt(ibuf, obuf, 16, iv, &ctxd); - ck_assert_mem_eq(obuf, fromhex(*plainp), 16); - ivp += 3; - plainp += 3; - cipherp += 3; - } - - // CFB - static const char *cfb_vector[] = { - "000102030405060708090A0B0C0D0E0F", - "6bc1bee22e409f96e93d7e117393172a", - "DC7E84BFDA79164B7ECD8486985D3860", - "DC7E84BFDA79164B7ECD8486985D3860", - "ae2d8a571e03ac9c9eb76fac45af8e51", - "39ffed143b28b1c832113c6331e5407b", - "39FFED143B28B1C832113C6331E5407B", - "30c81c46a35ce411e5fbc1191a0a52ef", - "df10132415e54b92a13ed0a8267ae2f9", - "DF10132415E54B92A13ED0A8267AE2F9", - "f69f2445df4f9b17ad2b417be66c3710", - "75a385741ab9cef82031623d55b1e471", - 0, - 0, - 0, - }; - ivp = cfb_vector; - plainp = cfb_vector + 1; - cipherp = cfb_vector + 2; - while (*plainp && *cipherp) { - // encrypt - aes_encrypt_key256( - fromhex( - "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), - &ctxe); - memcpy(iv, fromhex(*ivp), 16); - memcpy(ibuf, fromhex(*plainp), 16); - aes_cfb_encrypt(ibuf, obuf, 16, iv, &ctxe); - ck_assert_mem_eq(obuf, fromhex(*cipherp), 16); - // decrypt (uses encryption) - aes_encrypt_key256( - fromhex( - "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), - &ctxe); - memcpy(iv, fromhex(*ivp), 16); - memcpy(ibuf, fromhex(*cipherp), 16); - aes_cfb_decrypt(ibuf, obuf, 16, iv, &ctxe); - ck_assert_mem_eq(obuf, fromhex(*plainp), 16); - ivp += 3; - plainp += 3; - cipherp += 3; - } - - // OFB - static const char *ofb_vector[] = { - "000102030405060708090A0B0C0D0E0F", - "6bc1bee22e409f96e93d7e117393172a", - "dc7e84bfda79164b7ecd8486985d3860", - "B7BF3A5DF43989DD97F0FA97EBCE2F4A", - "ae2d8a571e03ac9c9eb76fac45af8e51", - "4febdc6740d20b3ac88f6ad82a4fb08d", - "E1C656305ED1A7A6563805746FE03EDC", - "30c81c46a35ce411e5fbc1191a0a52ef", - "71ab47a086e86eedf39d1c5bba97c408", - "41635BE625B48AFC1666DD42A09D96E7", - "f69f2445df4f9b17ad2b417be66c3710", - "0126141d67f37be8538f5a8be740e484", - 0, - 0, - 0, - }; - ivp = ofb_vector; - plainp = ofb_vector + 1; - cipherp = ofb_vector + 2; - while (*plainp && *cipherp) { - // encrypt - aes_encrypt_key256( - fromhex( - "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), - &ctxe); - memcpy(iv, fromhex(*ivp), 16); - memcpy(ibuf, fromhex(*plainp), 16); - aes_ofb_encrypt(ibuf, obuf, 16, iv, &ctxe); - ck_assert_mem_eq(obuf, fromhex(*cipherp), 16); - // decrypt (uses encryption) - aes_encrypt_key256( - fromhex( - "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), - &ctxe); - memcpy(iv, fromhex(*ivp), 16); - memcpy(ibuf, fromhex(*cipherp), 16); - aes_ofb_decrypt(ibuf, obuf, 16, iv, &ctxe); - ck_assert_mem_eq(obuf, fromhex(*plainp), 16); - ivp += 3; - plainp += 3; - cipherp += 3; - } - - // CTR - static const char *ctr_vector[] = { - // plain cipher - "6bc1bee22e409f96e93d7e117393172a", - "601ec313775789a5b7a7f504bbf3d228", - "ae2d8a571e03ac9c9eb76fac45af8e51", - "f443e3ca4d62b59aca84e990cacaf5c5", - "30c81c46a35ce411e5fbc1191a0a52ef", - "2b0930daa23de94ce87017ba2d84988d", - "f69f2445df4f9b17ad2b417be66c3710", - "dfc9c58db67aada613c2dd08457941a6", - 0, - 0, - }; - // encrypt - plainp = ctr_vector; - cipherp = ctr_vector + 1; - memcpy(cbuf, fromhex("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"), 16); - aes_encrypt_key256( - fromhex( - "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), - &ctxe); - while (*plainp && *cipherp) { - memcpy(ibuf, fromhex(*plainp), 16); - aes_ctr_encrypt(ibuf, obuf, 16, cbuf, aes_ctr_cbuf_inc, &ctxe); - ck_assert_mem_eq(obuf, fromhex(*cipherp), 16); - plainp += 2; - cipherp += 2; - } - // decrypt (uses encryption) - plainp = ctr_vector; - cipherp = ctr_vector + 1; - memcpy(cbuf, fromhex("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"), 16); - aes_encrypt_key256( - fromhex( - "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), - &ctxe); - while (*plainp && *cipherp) { - memcpy(ibuf, fromhex(*cipherp), 16); - aes_ctr_decrypt(ibuf, obuf, 16, cbuf, aes_ctr_cbuf_inc, &ctxe); - ck_assert_mem_eq(obuf, fromhex(*plainp), 16); - plainp += 2; - cipherp += 2; - } -} -END_TEST - -#define TEST1 "abc" -#define TEST2_1 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" -#define TEST2_2a "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" -#define TEST2_2b "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" -#define TEST2_2 TEST2_2a TEST2_2b -#define TEST3 "a" /* times 1000000 */ -#define TEST4a "01234567012345670123456701234567" -#define TEST4b "01234567012345670123456701234567" -/* an exact multiple of 512 bits */ -#define TEST4 TEST4a TEST4b /* times 10 */ - -#define TEST7_1 "\x49\xb2\xae\xc2\x59\x4b\xbe\x3a\x3b\x11\x75\x42\xd9\x4a\xc8" -#define TEST8_1 \ - "\x9a\x7d\xfd\xf1\xec\xea\xd0\x6e\xd6\x46\xaa\x55\xfe\x75\x71\x46" -#define TEST9_1 \ - "\x65\xf9\x32\x99\x5b\xa4\xce\x2c\xb1\xb4\xa2\xe7\x1a\xe7\x02\x20" \ - "\xaa\xce\xc8\x96\x2d\xd4\x49\x9c\xbd\x7c\x88\x7a\x94\xea\xaa\x10" \ - "\x1e\xa5\xaa\xbc\x52\x9b\x4e\x7e\x43\x66\x5a\x5a\xf2\xcd\x03\xfe" \ - "\x67\x8e\xa6\xa5\x00\x5b\xba\x3b\x08\x22\x04\xc2\x8b\x91\x09\xf4" \ - "\x69\xda\xc9\x2a\xaa\xb3\xaa\x7c\x11\xa1\xb3\x2a" -#define TEST10_1 \ - "\xf7\x8f\x92\x14\x1b\xcd\x17\x0a\xe8\x9b\x4f\xba\x15\xa1\xd5\x9f" \ - "\x3f\xd8\x4d\x22\x3c\x92\x51\xbd\xac\xbb\xae\x61\xd0\x5e\xd1\x15" \ - "\xa0\x6a\x7c\xe1\x17\xb7\xbe\xea\xd2\x44\x21\xde\xd9\xc3\x25\x92" \ - "\xbd\x57\xed\xea\xe3\x9c\x39\xfa\x1f\xe8\x94\x6a\x84\xd0\xcf\x1f" \ - "\x7b\xee\xad\x17\x13\xe2\xe0\x95\x98\x97\x34\x7f\x67\xc8\x0b\x04" \ - "\x00\xc2\x09\x81\x5d\x6b\x10\xa6\x83\x83\x6f\xd5\x56\x2a\x56\xca" \ - "\xb1\xa2\x8e\x81\xb6\x57\x66\x54\x63\x1c\xf1\x65\x66\xb8\x6e\x3b" \ - "\x33\xa1\x08\xb0\x53\x07\xc0\x0a\xff\x14\xa7\x68\xed\x73\x50\x60" \ - "\x6a\x0f\x85\xe6\xa9\x1d\x39\x6f\x5b\x5c\xbe\x57\x7f\x9b\x38\x80" \ - "\x7c\x7d\x52\x3d\x6d\x79\x2f\x6e\xbc\x24\xa4\xec\xf2\xb3\xa4\x27" \ - "\xcd\xbb\xfb" -#define length(x) (sizeof(x) - 1) - -// test vectors from rfc-4634 -START_TEST(test_sha1) { - struct { - const char *test; - int length; - int repeatcount; - int extrabits; - int numberExtrabits; - const char *result; - } tests[] = { - /* 1 */ {TEST1, length(TEST1), 1, 0, 0, - "A9993E364706816ABA3E25717850C26C9CD0D89D"}, - /* 2 */ - {TEST2_1, length(TEST2_1), 1, 0, 0, - "84983E441C3BD26EBAAE4AA1F95129E5E54670F1"}, - /* 3 */ - {TEST3, length(TEST3), 1000000, 0, 0, - "34AA973CD4C4DAA4F61EEB2BDBAD27316534016F"}, - /* 4 */ - {TEST4, length(TEST4), 10, 0, 0, - "DEA356A2CDDD90C7A7ECEDC5EBB563934F460452"}, - /* 5 */ {"", 0, 0, 0x98, 5, "29826B003B906E660EFF4027CE98AF3531AC75BA"}, - /* 6 */ {"\x5e", 1, 1, 0, 0, "5E6F80A34A9798CAFC6A5DB96CC57BA4C4DB59C2"}, - /* 7 */ - {TEST7_1, length(TEST7_1), 1, 0x80, 3, - "6239781E03729919C01955B3FFA8ACB60B988340"}, - /* 8 */ - {TEST8_1, length(TEST8_1), 1, 0, 0, - "82ABFF6605DBE1C17DEF12A394FA22A82B544A35"}, - /* 9 */ - {TEST9_1, length(TEST9_1), 1, 0xE0, 3, - "8C5B2A5DDAE5A97FC7F9D85661C672ADBF7933D4"}, - /* 10 */ - {TEST10_1, length(TEST10_1), 1, 0, 0, - "CB0082C8F197D260991BA6A460E76E202BAD27B3"}}; - - for (int i = 0; i < 10; i++) { - SHA1_CTX ctx; - uint8_t digest[SHA1_DIGEST_LENGTH]; - sha1_Init(&ctx); - /* extra bits are not supported */ - if (tests[i].numberExtrabits) continue; - for (int j = 0; j < tests[i].repeatcount; j++) { - sha1_Update(&ctx, (const uint8_t *)tests[i].test, tests[i].length); - } - sha1_Final(&ctx, digest); - ck_assert_mem_eq(digest, fromhex(tests[i].result), SHA1_DIGEST_LENGTH); - } -} -END_TEST - -#define TEST7_256 "\xbe\x27\x46\xc6\xdb\x52\x76\x5f\xdb\x2f\x88\x70\x0f\x9a\x73" -#define TEST8_256 \ - "\xe3\xd7\x25\x70\xdc\xdd\x78\x7c\xe3\x88\x7a\xb2\xcd\x68\x46\x52" -#define TEST9_256 \ - "\x3e\x74\x03\x71\xc8\x10\xc2\xb9\x9f\xc0\x4e\x80\x49\x07\xef\x7c" \ - "\xf2\x6b\xe2\x8b\x57\xcb\x58\xa3\xe2\xf3\xc0\x07\x16\x6e\x49\xc1" \ - "\x2e\x9b\xa3\x4c\x01\x04\x06\x91\x29\xea\x76\x15\x64\x25\x45\x70" \ - "\x3a\x2b\xd9\x01\xe1\x6e\xb0\xe0\x5d\xeb\xa0\x14\xeb\xff\x64\x06" \ - "\xa0\x7d\x54\x36\x4e\xff\x74\x2d\xa7\x79\xb0\xb3" -#define TEST10_256 \ - "\x83\x26\x75\x4e\x22\x77\x37\x2f\x4f\xc1\x2b\x20\x52\x7a\xfe\xf0" \ - "\x4d\x8a\x05\x69\x71\xb1\x1a\xd5\x71\x23\xa7\xc1\x37\x76\x00\x00" \ - "\xd7\xbe\xf6\xf3\xc1\xf7\xa9\x08\x3a\xa3\x9d\x81\x0d\xb3\x10\x77" \ - "\x7d\xab\x8b\x1e\x7f\x02\xb8\x4a\x26\xc7\x73\x32\x5f\x8b\x23\x74" \ - "\xde\x7a\x4b\x5a\x58\xcb\x5c\x5c\xf3\x5b\xce\xe6\xfb\x94\x6e\x5b" \ - "\xd6\x94\xfa\x59\x3a\x8b\xeb\x3f\x9d\x65\x92\xec\xed\xaa\x66\xca" \ - "\x82\xa2\x9d\x0c\x51\xbc\xf9\x33\x62\x30\xe5\xd7\x84\xe4\xc0\xa4" \ - "\x3f\x8d\x79\xa3\x0a\x16\x5c\xba\xbe\x45\x2b\x77\x4b\x9c\x71\x09" \ - "\xa9\x7d\x13\x8f\x12\x92\x28\x96\x6f\x6c\x0a\xdc\x10\x6a\xad\x5a" \ - "\x9f\xdd\x30\x82\x57\x69\xb2\xc6\x71\xaf\x67\x59\xdf\x28\xeb\x39" \ - "\x3d\x54\xd6" - -// test vectors from rfc-4634 -START_TEST(test_sha256) { - struct { - const char *test; - int length; - int repeatcount; - int extrabits; - int numberExtrabits; - const char *result; - } tests[] = { - /* 1 */ {TEST1, length(TEST1), 1, 0, 0, - "BA7816BF8F01CFEA4141" - "40DE5DAE2223B00361A396177A9CB410FF61F20015AD"}, - /* 2 */ - {TEST2_1, length(TEST2_1), 1, 0, 0, - "248D6A61D20638B8" - "E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1"}, - /* 3 */ - {TEST3, length(TEST3), 1000000, 0, 0, - "CDC76E5C9914FB92" - "81A1C7E284D73E67F1809A48A497200E046D39CCC7112CD0"}, - /* 4 */ - {TEST4, length(TEST4), 10, 0, 0, - "594847328451BDFA" - "85056225462CC1D867D877FB388DF0CE35F25AB5562BFBB5"}, - /* 5 */ - {"", 0, 0, 0x68, 5, - "D6D3E02A31A84A8CAA9718ED6C2057BE" - "09DB45E7823EB5079CE7A573A3760F95"}, - /* 6 */ - {"\x19", 1, 1, 0, 0, - "68AA2E2EE5DFF96E3355E6C7EE373E3D" - "6A4E17F75F9518D843709C0C9BC3E3D4"}, - /* 7 */ - {TEST7_256, length(TEST7_256), 1, 0x60, 3, - "77EC1DC8" - "9C821FF2A1279089FA091B35B8CD960BCAF7DE01C6A7680756BEB972"}, - /* 8 */ - {TEST8_256, length(TEST8_256), 1, 0, 0, - "175EE69B02BA" - "9B58E2B0A5FD13819CEA573F3940A94F825128CF4209BEABB4E8"}, - /* 9 */ - {TEST9_256, length(TEST9_256), 1, 0xA0, 3, - "3E9AD646" - "8BBBAD2AC3C2CDC292E018BA5FD70B960CF1679777FCE708FDB066E9"}, - /* 10 */ - {TEST10_256, length(TEST10_256), 1, 0, 0, - "97DBCA7D" - "F46D62C8A422C941DD7E835B8AD3361763F7E9B2D95F4F0DA6E1CCBC"}, - }; - - for (int i = 0; i < 10; i++) { - SHA256_CTX ctx; - uint8_t digest[SHA256_DIGEST_LENGTH]; - sha256_Init(&ctx); - /* extra bits are not supported */ - if (tests[i].numberExtrabits) continue; - for (int j = 0; j < tests[i].repeatcount; j++) { - sha256_Update(&ctx, (const uint8_t *)tests[i].test, tests[i].length); - } - sha256_Final(&ctx, digest); - ck_assert_mem_eq(digest, fromhex(tests[i].result), SHA256_DIGEST_LENGTH); - } -} -END_TEST - -#define TEST7_512 "\x08\xec\xb5\x2e\xba\xe1\xf7\x42\x2d\xb6\x2b\xcd\x54\x26\x70" -#define TEST8_512 \ - "\x8d\x4e\x3c\x0e\x38\x89\x19\x14\x91\x81\x6e\x9d\x98\xbf\xf0\xa0" -#define TEST9_512 \ - "\x3a\xdd\xec\x85\x59\x32\x16\xd1\x61\x9a\xa0\x2d\x97\x56\x97\x0b" \ - "\xfc\x70\xac\xe2\x74\x4f\x7c\x6b\x27\x88\x15\x10\x28\xf7\xb6\xa2" \ - "\x55\x0f\xd7\x4a\x7e\x6e\x69\xc2\xc9\xb4\x5f\xc4\x54\x96\x6d\xc3" \ - "\x1d\x2e\x10\xda\x1f\x95\xce\x02\xbe\xb4\xbf\x87\x65\x57\x4c\xbd" \ - "\x6e\x83\x37\xef\x42\x0a\xdc\x98\xc1\x5c\xb6\xd5\xe4\xa0\x24\x1b" \ - "\xa0\x04\x6d\x25\x0e\x51\x02\x31\xca\xc2\x04\x6c\x99\x16\x06\xab" \ - "\x4e\xe4\x14\x5b\xee\x2f\xf4\xbb\x12\x3a\xab\x49\x8d\x9d\x44\x79" \ - "\x4f\x99\xcc\xad\x89\xa9\xa1\x62\x12\x59\xed\xa7\x0a\x5b\x6d\xd4" \ - "\xbd\xd8\x77\x78\xc9\x04\x3b\x93\x84\xf5\x49\x06" -#define TEST10_512 \ - "\xa5\x5f\x20\xc4\x11\xaa\xd1\x32\x80\x7a\x50\x2d\x65\x82\x4e\x31" \ - "\xa2\x30\x54\x32\xaa\x3d\x06\xd3\xe2\x82\xa8\xd8\x4e\x0d\xe1\xde" \ - "\x69\x74\xbf\x49\x54\x69\xfc\x7f\x33\x8f\x80\x54\xd5\x8c\x26\xc4" \ - "\x93\x60\xc3\xe8\x7a\xf5\x65\x23\xac\xf6\xd8\x9d\x03\xe5\x6f\xf2" \ - "\xf8\x68\x00\x2b\xc3\xe4\x31\xed\xc4\x4d\xf2\xf0\x22\x3d\x4b\xb3" \ - "\xb2\x43\x58\x6e\x1a\x7d\x92\x49\x36\x69\x4f\xcb\xba\xf8\x8d\x95" \ - "\x19\xe4\xeb\x50\xa6\x44\xf8\xe4\xf9\x5e\xb0\xea\x95\xbc\x44\x65" \ - "\xc8\x82\x1a\xac\xd2\xfe\x15\xab\x49\x81\x16\x4b\xbb\x6d\xc3\x2f" \ - "\x96\x90\x87\xa1\x45\xb0\xd9\xcc\x9c\x67\xc2\x2b\x76\x32\x99\x41" \ - "\x9c\xc4\x12\x8b\xe9\xa0\x77\xb3\xac\xe6\x34\x06\x4e\x6d\x99\x28" \ - "\x35\x13\xdc\x06\xe7\x51\x5d\x0d\x73\x13\x2e\x9a\x0d\xc6\xd3\xb1" \ - "\xf8\xb2\x46\xf1\xa9\x8a\x3f\xc7\x29\x41\xb1\xe3\xbb\x20\x98\xe8" \ - "\xbf\x16\xf2\x68\xd6\x4f\x0b\x0f\x47\x07\xfe\x1e\xa1\xa1\x79\x1b" \ - "\xa2\xf3\xc0\xc7\x58\xe5\xf5\x51\x86\x3a\x96\xc9\x49\xad\x47\xd7" \ - "\xfb\x40\xd2" - -// test vectors from rfc-4634 -START_TEST(test_sha512) { - struct { - const char *test; - int length; - int repeatcount; - int extrabits; - int numberExtrabits; - const char *result; - } tests[] = {/* 1 */ {TEST1, length(TEST1), 1, 0, 0, - "DDAF35A193617ABACC417349AE20413112E6FA4E89A97EA2" - "0A9EEEE64B55D39A2192992A274FC1A836BA3C23A3FEEBBD" - "454D4423643CE80E2A9AC94FA54CA49F"}, - /* 2 */ - {TEST2_2, length(TEST2_2), 1, 0, 0, - "8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA1" - "7299AEADB6889018501D289E4900F7E4331B99DEC4B5433A" - "C7D329EEB6DD26545E96E55B874BE909"}, - /* 3 */ - {TEST3, length(TEST3), 1000000, 0, 0, - "E718483D0CE769644E2E42C7BC15B4638E1F98B13B204428" - "5632A803AFA973EBDE0FF244877EA60A4CB0432CE577C31B" - "EB009C5C2C49AA2E4EADB217AD8CC09B"}, - /* 4 */ - {TEST4, length(TEST4), 10, 0, 0, - "89D05BA632C699C31231DED4FFC127D5A894DAD412C0E024" - "DB872D1ABD2BA8141A0F85072A9BE1E2AA04CF33C765CB51" - "0813A39CD5A84C4ACAA64D3F3FB7BAE9"}, - /* 5 */ - {"", 0, 0, 0xB0, 5, - "D4EE29A9E90985446B913CF1D1376C836F4BE2C1CF3CADA0" - "720A6BF4857D886A7ECB3C4E4C0FA8C7F95214E41DC1B0D2" - "1B22A84CC03BF8CE4845F34DD5BDBAD4"}, - /* 6 */ - {"\xD0", 1, 1, 0, 0, - "9992202938E882E73E20F6B69E68A0A7149090423D93C81B" - "AB3F21678D4ACEEEE50E4E8CAFADA4C85A54EA8306826C4A" - "D6E74CECE9631BFA8A549B4AB3FBBA15"}, - /* 7 */ - {TEST7_512, length(TEST7_512), 1, 0x80, 3, - "ED8DC78E8B01B69750053DBB7A0A9EDA0FB9E9D292B1ED71" - "5E80A7FE290A4E16664FD913E85854400C5AF05E6DAD316B" - "7359B43E64F8BEC3C1F237119986BBB6"}, - /* 8 */ - {TEST8_512, length(TEST8_512), 1, 0, 0, - "CB0B67A4B8712CD73C9AABC0B199E9269B20844AFB75ACBD" - "D1C153C9828924C3DDEDAAFE669C5FDD0BC66F630F677398" - "8213EB1B16F517AD0DE4B2F0C95C90F8"}, - /* 9 */ - {TEST9_512, length(TEST9_512), 1, 0x80, 3, - "32BA76FC30EAA0208AEB50FFB5AF1864FDBF17902A4DC0A6" - "82C61FCEA6D92B783267B21080301837F59DE79C6B337DB2" - "526F8A0A510E5E53CAFED4355FE7C2F1"}, - /* 10 */ - {TEST10_512, length(TEST10_512), 1, 0, 0, - "C665BEFB36DA189D78822D10528CBF3B12B3EEF726039909" - "C1A16A270D48719377966B957A878E720584779A62825C18" - "DA26415E49A7176A894E7510FD1451F5"}}; - - for (int i = 0; i < 10; i++) { - SHA512_CTX ctx; - uint8_t digest[SHA512_DIGEST_LENGTH]; - sha512_Init(&ctx); - /* extra bits are not supported */ - if (tests[i].numberExtrabits) continue; - for (int j = 0; j < tests[i].repeatcount; j++) { - sha512_Update(&ctx, (const uint8_t *)tests[i].test, tests[i].length); - } - sha512_Final(&ctx, digest); - ck_assert_mem_eq(digest, fromhex(tests[i].result), SHA512_DIGEST_LENGTH); - } -} -END_TEST - -// test vectors from http://www.di-mgt.com.au/sha_testvectors.html -START_TEST(test_sha3_256) { - static const struct { - const char *data; - const char *hash; - } tests[] = { - { - "", - "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", - }, - { - "abc", - "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", - }, - { - "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", - "41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376", - }, - { - "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijkl" - "mnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", - "916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18", - }, - }; - - uint8_t digest[SHA3_256_DIGEST_LENGTH]; - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - size_t len = strlen(tests[i].data); - sha3_256((uint8_t *)tests[i].data, len, digest); - ck_assert_mem_eq(digest, fromhex(tests[i].hash), SHA3_256_DIGEST_LENGTH); - - // Test progressive hashing. - size_t part_len = len; - SHA3_CTX ctx; - sha3_256_Init(&ctx); - sha3_Update(&ctx, (uint8_t *)tests[i].data, part_len); - sha3_Update(&ctx, NULL, 0); - sha3_Update(&ctx, (uint8_t *)tests[i].data + part_len, len - part_len); - sha3_Final(&ctx, digest); - ck_assert_mem_eq(digest, fromhex(tests[i].hash), SHA3_256_DIGEST_LENGTH); - } -} -END_TEST - -// test vectors from http://www.di-mgt.com.au/sha_testvectors.html -START_TEST(test_sha3_512) { - static const struct { - const char *data; - const char *hash; - } tests[] = { - { - "", - "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2" - "123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26", - }, - { - "abc", - "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e1" - "16e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0", - }, - { - "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", - "04a371e84ecfb5b8b77cb48610fca8182dd457ce6f326a0fd3d7ec2f1e91636dee69" - "1fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e", - }, - { - "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijkl" - "mnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", - "afebb2ef542e6579c50cad06d2e578f9f8dd6881d7dc824d26360feebf18a4fa73e3" - "261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185", - }, - }; - - uint8_t digest[SHA3_512_DIGEST_LENGTH]; - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - size_t len = strlen(tests[i].data); - sha3_512((uint8_t *)tests[i].data, len, digest); - ck_assert_mem_eq(digest, fromhex(tests[i].hash), SHA3_512_DIGEST_LENGTH); - - // Test progressive hashing. - size_t part_len = len; - SHA3_CTX ctx; - sha3_512_Init(&ctx); - sha3_Update(&ctx, (const uint8_t *)tests[i].data, part_len); - sha3_Update(&ctx, NULL, 0); - sha3_Update(&ctx, (const uint8_t *)tests[i].data + part_len, - len - part_len); - sha3_Final(&ctx, digest); - ck_assert_mem_eq(digest, fromhex(tests[i].hash), SHA3_512_DIGEST_LENGTH); - } -} -END_TEST - -// test vectors from -// https://raw.githubusercontent.com/NemProject/nem-test-vectors/master/0.test-sha3-256.dat -START_TEST(test_keccak_256) { - static const struct { - const char *hash; - size_t length; - const char *data; - } tests[] = { - { - "4e9e79ab7434f6c7401fb3305d55052ee829b9e46d5d05d43b59fefb32e9a619", - 293, - "a6151d4904e18ec288243028ceda30556e6c42096af7150d6a7232ca5dba52bd2192" - "e23daa5fa2bea3d4bd95efa2389cd193fcd3376e70a5c097b32c1c62c80af9d71021" - "1545f7cdddf63747420281d64529477c61e721273cfd78f8890abb4070e97baa52ac" - "8ff61c26d195fc54c077def7a3f6f79b36e046c1a83ce9674ba1983ec2fb58947de6" - "16dd797d6499b0385d5e8a213db9ad5078a8e0c940ff0cb6bf92357ea5609f778c3d" - "1fb1e7e36c35db873361e2be5c125ea7148eff4a035b0cce880a41190b2e22924ad9" - "d1b82433d9c023924f2311315f07b88bfd42850047bf3be785c4ce11c09d7e02065d" - "30f6324365f93c5e7e423a07d754eb314b5fe9db4614275be4be26af017abdc9c338" - "d01368226fe9af1fb1f815e7317bdbb30a0f36dc69", - }, - { - "c1268babc42d00c3463dc388222100f7e525a74a64665c39f112f788ddb5da42", - 376, - "9db801077952c2324e0044a4994edfb09b3edfcf669bfdd029f4bf42d5b0eab3056b" - "0bf82708ca7bfadba43c9de806b10a19d0f00c2351ef1086b6b108f306e035c6b61b" - "2e70fd7087ba848601c8a3f626a66666423717ef305a1068bfa3a1f7ffc1e5a78cb6" - "182ffc8a577ca2a821630bf900d0fbba848bdf94b77c5946771b6c3f8c02269bc772" - "ca56098f724536d96be68c284ee1d81697989d40029b8ea63ac1fd85f8b3cae8b194" - "f6834ff65a5858f9498ddbb467995eb2d49cdfc6c05d92038c6e9aaeee85f8222b37" - "84165f12a2c3df4c7a142e26dddfd831d07e22dfecc0eded48a69c8a9e1b97f1a4e0" - "efcd4edd310de0edf82af38a6e4d5ab2a19da586e61210d4f75e7a07e2201f9c8154" - "ca52a414a70d2eb2ac1c5b9a2900b4d871f62fa56f70d03b3dd3704bd644808c45a1" - "3231918ea884645b8ec054e8bab2935a66811fe590ddc119ae901dfeb54fc2a87c1e" - "0a236778baab2fa8843709c6676d3c1888ba19d75ec52d73a7d035c143179b938237" - "26b7", - }, - { - "e83b50e8c83cb676a7dd64c055f53e5110d5a4c62245ceb8f683fd87b2b3ec77", - 166, - "c070a957550b7b34113ee6543a1918d96d241f27123425db7f7b9004e047ffbe0561" - "2e7fa8c54b23c83ea427e625e97b7a28b09a70bf6d91e478eeed01d7907931c29ea8" - "6e70f2cdcfb243ccf7f24a1619abf4b5b9e6f75cbf63fc02baf4a820a9790a6b053e" - "50fd94e0ed57037cfc2bab4d95472b97d3c25f434f1cc0b1ede5ba7f15907a42a223" - "933e5e2dfcb518c3531975268c326d60fa911fbb7997eee3ba87656c4fe7", - }, - { - "8ebd2c9d4ff00e285a9b6b140bfc3cef672016f0098100e1f6f250220af7ce1a", - 224, - "b502fbdce4045e49e147eff5463d4b3f37f43461518868368e2c78008c84c2db79d1" - "2b58107034f67e7d0abfee67add0342dd23dce623f26b9156def87b1d7ac15a6e073" - "01f832610fe869ada13a2b0e3d60aa6bb81bc04487e2e800f5106b0402ee0331df74" - "5e021b5ea5e32faf1c7fc1322041d221a54191c0af19948b5f34411937182e30d5cd" - "39b5a6c959d77d92d21bb1de51f1b3411cb6eec00600429916227fb62d2c88e69576" - "f4ac8e5efcde8efa512cc80ce7fb0dfaa6c74d26e898cefe9d4f7dce232a69f2a6a9" - "477aa08366efcdfca117c89cb79eba15a23755e0", - }, - { - "db3961fdddd0c314289efed5d57363459a6700a7bd015e7a03d3e1d03f046401", - 262, - "22e203a98ba2c43d8bc3658f0a48a35766df356d6a5e98b0c7222d16d85a00b31720" - "7d4aef3fc7cabb67b9d8f5838de0b733e1fd59c31f0667e53286972d7090421ad90d" - "54db2ea40047d0d1700c86f53dbf48da532396307e68edad877dcae481848801b0a5" - "db44dbdba6fc7c63b5cd15281d57ca9e6be96f530b209b59d6127ad2bd8750f3f807" - "98f62521f0d5b42633c2f5a9aaefbed38779b7aded2338d66850b0bb0e33c48e040c" - "99f2dcee7a7ebb3d7416e1c5bf038c19d09682dab67c96dbbfad472e45980aa27d1b" - "301b15f7de4d4f549bad2501931c9d4f1a3b1692dcb4b1b834ddd4a636126702307d" - "daeec61841693b21887d56e76cc2069dafb557fd6682160f", - }, - { - "25dd3acacd6bf688c0eace8d33eb7cc550271969142deb769a05b4012f7bb722", - 122, - "99e7f6e0ed46ec866c43a1ab494998d47e9309a79fde2a629eb63bb2160a5ffd0f22" - "06de9c32dd20e9b23e57ab7422cf82971cc2873ec0e173fe93281c7b33e1c76ac792" - "23a6f435f230bdd30260c00d00986c72a399d3ba70f6e783d834bbf8a6127844def5" - "59b8b6db742b2cfd715f7ff29e7b42bf7d567beb", - }, - { - "00d747c9045c093484290afc161437f11c2ddf5f8a9fc2acae9c7ef5fcf511e5", - 440, - "50c392f97f8788377f0ab2e2aab196cb017ad157c6f9d022673d39072cc198b06622" - "a5cbd269d1516089fa59e28c3373a92bd54b2ebf1a79811c7e40fdd7bce200e80983" - "fda6e77fc44c44c1b5f87e01cef2f41e1141103f73364e9c2f25a4597e6517ef31b3" - "16300b770c69595e0fa6d011df1566a8676a88c7698562273bbfa217cc69d4b5c89a" - "8907b902f7dc14481fefc7da4a810c15a60f5641aae854d2f8cc50cbc393015560f0" - "1c94e0d0c075dbcb150ad6eba29dc747919edcaf0231dba3eb3f2b1a87e136a1f0fd" - "4b3d8ee61bad2729e9526a32884f7bcfa41e361add1b4c51dc81463528372b4ec321" - "244de0c541ba00df22b8773cdf4cf898510c867829fa6b4ff11f9627338b9686d905" - "cb7bcdf085080ab842146e0035c808be58cce97827d8926a98bd1ff7c529be3bc14f" - "68c91b2ca4d2f6fc748f56bcf14853b7f8b9aa6d388f0fd82f53fdc4bacf9d9ba10a" - "165f404cf427e199f51bf6773b7c82531e17933f6d8b8d9181e22f8921a2dbb20fc7" - "c8023a87e716e245017c399d0942934f5e085219b3f8d26a196bf8b239438b8e561c" - "28a61ff08872ecb052c5fcb19e2fdbc09565924a50ebee1461c4b414219d4257", - }, - { - "dadcde7c3603ef419d319ba3d50cf00ad57f3e81566fd11b9b6f461cbb9dcb0f", - 338, - "18e1df97abccc91e07dc7b7ffab5ee8919d5610721453176aa2089fb96d9a477e147" - "6f507fa1129f04304e960e8017ff41246cacc0153055fc4b1dc6168a74067ebb077c" - "b5aa80a9df6e8b5b821e906531159668c4c164b9e511d8724aedbe17c1f41da88094" - "17d3c30b79ea5a2e3c961f6bac5436d9af6be24a36eebcb17863fed82c0eb8962339" - "eb612d58659dddd2ea06a120b3a2d8a17050be2de367db25a5bef4290c209bdb4c16" - "c4df5a1fe1ead635169a1c35f0a56bc07bcf6ef0e4c2d8573ed7a3b58030fa268c1a" - "5974b097288f01f34d5a1087946410688016882c6c7621aad680d9a25c7a3e5dbcbb" - "07ffdb7243b91031c08a121b40785e96b7ee46770c760f84aca8f36b7c7da64d25c8" - "f73b4d88ff3acb7eeefc0b75144dffea66d2d1f6b42b905b61929ab3f38538393ba5" - "ca9d3c62c61f46fa63789cac14e4e1d8722bf03cceef6e3de91f783b0072616c", - }, - { - "d184e84a2507fc0f187b640dd5b849a366c0383d9cbdbc6fa30904f054111255", - 141, - "13b8df9c1bcfddd0aa39b3055f52e2bc36562b6677535994b173f07041d141699db4" - "2589d6091ef0e71b645b41ab57577f58c98da966562d24823158f8e1d43b54edea4e" - "61dd66fe8c59ad8405f5a0d9a3eb509a77ae3d8ae4adf926fd3d8d31c3dcccfc1408" - "14541010937024cc554e1daaee1b333a66316e7fbebb07ac8dfb134a918b9090b141" - "68012c4824", - }, - { - "20c19635364a00b151d0168fe5ae03bac6dd7d06030475b40d2e8c577a192f53", - 84, - "e1e96da4b7d8dcc2b316006503a990ea26a5b200cb7a7edfc14f5ce827f06d8d232e" - "c95b1acdc1422ffc16da11d258f0c7b378f026d64c74b2fb41df8bfd3cd30066caec" - "dc6f76c8163de9309d9fd0cf33d54a29", - }, - { - "86cc2c428d469e43fb4ee8d38dffbf5128d20d1659dbc45edf4a855399ca730e", - 319, - "30391840ad14e66c53e1a5aaa03989ff059940b60c44c3b21295a93d023f2e6c7cdc" - "f60208b7d87a7605fb5cee94630d94cad90bc6955328357fa37fea47c09f9cee759c" - "31537187321c7d572e3554eeb90f441a9494575454dfbf8cfd86128da15de9418821" - "ca158856eb84ff6a29a2c8380711e9e6d4955388374fcd3c1ca45b49e0679fc7157f" - "96bc6e4f86ce20a89c12d4449b1ca7056e0b7296fc646f68f6ddbfa6a48e384d63ab" - "68bc75fd69a2add59b8e41c4a0f753935df9a703d7df82a430798b0a67710a780614" - "85a9d15de16f154582082459b4462485ce8a82d35ac6b9498ae40df3a23d5f00e0e8" - "6661cb02c52f677fd374c32969ec63028b5dd2c1d4bce67a6d9f79ba5e7eeb5a2763" - "dc9fe2a05aa2ebaad36aaec2541e343a677fb4e6b6a180eff33c93744a4624f6a79f" - "054c6c9e9c5b6928dbe7ba5fca", - }, - { - "e80eee72a76e6957f7cb7f68c41b92f0ad9aac6e58aa8fc272c1e7364af11c70", - 108, - "3c210ed15889ae938781d2cebd49d4a8007f163ffba1f7669bccdccf6ad5a1418299" - "d5f4348f5cd03b0ba9e6999ab154e46836c3546feb395d17bcc60f23d7ba0e8efe6a" - "a616c00b6bf552fe1cb5e28e3e7bc39dfc20c63ae3901035e91ddd110e43fe59ed74" - "4beeedb6bc1e", - }, - { - "f971bbae97dd8a034835269fb246867de358a889de6de13672e771d6fb4c89b7", - 468, - "64e9a3a99c021df8bea59368cfe1cd3b0a4aca33ffcd5cf6028d9307c0b904b8037d" - "056a3c12803f196f74c4d360a3132452d365922b1157e5b0d76f91fb94bebfdcb4d5" - "0fa23ed5be3d3c5712219e8666debc8abcd5e6c69a542761a6cbbd1b3c0f05248752" - "04b64d2788465f90cb19b6f6da9f8bec6d6e684196e713549ec83e47cbaeff77838a" - "c4936b312562e2de17c970449d49d214ec2597c6d4f642e6c94a613a0c53285abccd" - "7794a3d72241808594fb4e6e4d5d2c310ef1cdcbfd34805ca2408f554797a6cfd49d" - "0f25ed8927f206acb127e6436e1234902489ec2e7f3058e26c0eba80341bc7ad0da8" - "b8bd80bd1b43c9099269e3f8b68445c69b79d8cf5693d4a0d47a44f9e9114dbb3399" - "2d2ea9d3b5b86e4ea57a44a638848de4ac365bb6bb7855305ade62b07ebf0954d70b" - "7c2fb5e6fcc154c7a36fb1756df5f20a84d35696627ebf22d44f40f805c0878ad110" - "bc17dcd66821084ca87902e05bc0afa61161086956b85a6ea900d35c7784d4c361a4" - "3fe294e267d5762408be58962cdb4f45a9c0efd7d2335916df3acb98ccfbcf5ee395" - "30540e5f3d3c5f3326a9a536d7bfa37aae2b143e2499b81bf0670e3a418c26c7dc82" - "b293d9bd182dd6435670514237df88d8286e19ce93e0a0db2790", - }, - { - "b97fd51f4e4eaa40c7a2853010fc46be5be2f43b9520ea0c533b68f728c978a2", - 214, - "ced3a43193caceb269d2517f4ecb892bb7d57d7201869e28e669b0b17d1c44d286e0" - "2734e2210ea9009565832975cc6303b9b6008fe1165b99ae5f1b29962ef042ebad8b" - "676d7433ed2fe0d0d6f4f32b2cb4c519da61552328c2caea799bb2fd907308173a1c" - "d2b798fb0df7d2eaf2ff0be733af74f42889e211843fc80b09952ae7eb246725b91d" - "31c1f7a5503fdf3bc9c269c76519cf2dc3225e862436b587bb74adbad88c773056cf" - "ea3bddb1f6533c01125eeae0986e5c817359912c9d0472bf8320b824ee097f82a8e0" - "5b9f53a5be7d153225de", - }, - { - "f0fecf766e4f7522568b3be71843cce3e5fcb10ea96b1a236c8c0a71c9ad55c9", - 159, - "8aca4de41275f5c4102f66266d70cff1a2d56f58df8d12061c64cb6cd8f616a5bf19" - "c2bb3c91585c695326f561a2d0eb4eef2e202d82dcc9089e4bee82b62a199a11963c" - "d08987d3abd5914def2cdd3c1e4748d46b654f338e3959121e869c18d5327e88090d" - "0ba0ac6762a2b14514cc505af7499f1a22f421dbe978494f9ffe1e88f1c59228f21d" - "a5bc9fcc911d022300a443bca17258bdd6cfbbf52fde61", - }, - { - "5c4f16043c0084bf98499fc7dc4d674ce9c730b7135210acdbf5e41d3dcf317b", - 87, - "01bbc193d0ee2396a7d8267ad63f18149667b31d8f7f48c8bb0c634755febc9ef1a7" - "9e93c475f6cd137ee37d4dc243ea2fdcdc0d098844af2208337b7bbf6930e39e74e2" - "3952ac1a19b4d38b83810a10c3b069e4fafb06", - }, - { - "14b61fc981f7d9449b7b6a2d57eb48cc8f7896f4dced2005291b2a2f38cb4a63", - 358, - "cbc1709a531438d5ead32cea20a9e4ddc0101ec555ab42b2e378145013cc05a97b9e" - "2c43c89bfa63ae5e9e9ce1fc022035c6b68f0a906ee1f53396d9dbe41cb2bc4bfeb1" - "44b005b0f40e0fec872d9c4aca9929ba3cbacd84c58ab43c26f10d345a24692bbd55" - "a76506876768e8e32a461bf160cee953da88920d36ad4aff6eea7126aa6f44a7a6fc" - "e770ce43f0f90a20590bdaad3ffcda30ca8e3700f832c62caa5df030c16bcf74aff4" - "92466f781eb69863a80663535fc154abd7cfdd02eef1019221cf608b9780f807e507" - "fbbf559b1dfe4e971b4d08fe45263a3c697ba90f9f71bec97e12438b4b12f6a84ab6" - "6872b888097089d76c9c2502d9ed2eece6bef8eee1d439782e218f5cc75d38f98860" - "12cdcb4bbe6caf812e97c5a336bcceae38b1109e3243a291ce23d097aaee7d9a711d" - "e6886749a7a6d15d7e7cbc4a51b1b4da9fcf139e4a6fd7dc0bc017db624b17fc9b8f" - "847592ed42467c25ad9fe96acbf20c0ffd18", - }, - { - "47ec7f3a362becbb110867995a0f066a66152603c4d433f11bf51870c67e2864", - 354, - "0636983353c9ea3f75256ed00b70e8b7cfc6f4e4c0ba3aa9a8da59b6e6ad9dfb5bc2" - "c49f48cc0b4237f87dedf34b888e54ecebf1d435bcd4aab72eb4ce39e5262fb68c6f" - "86423dac123bf59e903989eda7df4a982822d0831521403cedcfe9a5bbea648bb2e7" - "ef8cd81442ea5abe468b3ee8b06376ef8099447255c2fdc1b73af37fe0e0b852ffbc" - "9339868db756680db99e6e9837dbd28c39a69f229044ad7ec772524a6e01f679d25f" - "dc2e736a2418e5dfd7c2ab1348d0f821b777c975244c6cfc2fca5c36ccae7cf1d07b" - "190a9d17a088a1276bd096250b92f53b29b6ef88ef69d744b56fb2ec5078cc0b68a9" - "106943ef242b466097b9e29df11eb5cb0c06c29d7917410ba1097215d6aa4dafd90a" - "dff0c3e7221b9e8832613bd9aca8bcc6b2aa7b43acedcbc11aee1b5ba56f77a210be" - "7cf3485ee813e1126c3eeccd8419bbf22c412cad32cc0fc7a73aca4e379651caac3d" - "13d6cf5ca05508fd2d96f3ad94e7", - }, - { - "73778e7f1943646a89d3c78909e0afbe584071ba5230546a39cd73e44e36d78a", - 91, - "6217504a26b3395855eab6ddeb79f2e3490d74b80eff343721150ee0c1c02b071867" - "43589f93c22a03dc5ed29fb5bf592de0a089763e83e5b95f9dd524d66c8da3e04c18" - "14e65e68b2810c1b517648aabc266ad62896c51864a7f4", - }, - { - "35ef6868e750cf0c1d5285992c231d93ec644670fb79cf85324067a9f77fde78", - 185, - "0118b7fb15f927a977e0b330b4fa351aeeec299d6ba090eb16e5114fc4a6749e5915" - "434a123c112697390c96ea2c26dc613eb5c75f5ecfb6c419317426367e34da0ddc6d" - "7b7612cefa70a22fea0025f5186593b22449dab71f90a49f7de7352e54e0c0bd8837" - "e661ca2127c3313a7268cafdd5ccfbf3bdd7c974b0e7551a2d96766579ef8d2e1f37" - "6af74cd1ab62162fc2dc61a8b7ed4163c1caccf20ed73e284da2ed257ec974eee96b" - "502acb2c60a04886465e44debb0317", - }, - }; - - uint8_t hash[SHA3_256_DIGEST_LENGTH]; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - keccak_256(fromhex(tests[i].data), tests[i].length, hash); - ck_assert_mem_eq(hash, fromhex(tests[i].hash), SHA3_256_DIGEST_LENGTH); - - // Test progressive hashing. - size_t part_len = tests[i].length / 2; - SHA3_CTX ctx = {0}; - keccak_256_Init(&ctx); - keccak_Update(&ctx, fromhex(tests[i].data), part_len); - keccak_Update(&ctx, fromhex(tests[i].data), 0); - keccak_Update(&ctx, fromhex(tests[i].data) + part_len, - tests[i].length - part_len); - keccak_Final(&ctx, hash); - ck_assert_mem_eq(hash, fromhex(tests[i].hash), SHA3_256_DIGEST_LENGTH); - } -} -END_TEST - -// test vectors from -// https://raw.githubusercontent.com/monero-project/monero/master/tests/hash/tests-extra-blake.txt -START_TEST(test_blake256) { - static const struct { - const char *hash; - const char *data; - } tests[] = { - { - "716f6e863f744b9ac22c97ec7b76ea5f5908bc5b2f67c61510bfc4751384ea7a", - "", - }, - { - "e104256a2bc501f459d03fac96b9014f593e22d30f4de525fa680c3aa189eb4f", - "cc", - }, - { - "8f341148be7e354fdf38b693d8c6b4e0bd57301a734f6fd35cd85b8491c3ddcd", - "41fb", - }, - { - "bc334d1069099f10c601883ac6f3e7e9787c6aa53171f76a21923cc5ad3ab937", - "1f877c", - }, - { - "b672a16f53982bab1e77685b71c0a5f6703ffd46a1c834be69f614bd128d658e", - "c1ecfdfc", - }, - { - "d9134b2899057a7d8d320cc99e3e116982bc99d3c69d260a7f1ed3da8be68d99", - "21f134ac57", - }, - { - "637923bd29a35aa3ecbbd2a50549fc32c14cf0fdcaf41c3194dd7414fd224815", - "c6f50bb74e29", - }, - { - "70c092fd5c8c21e9ef4bbc82a5c7819e262a530a748caf285ff0cba891954f1e", - "119713cc83eeef", - }, - { - "fdf092993edbb7a0dc7ca67f04051bbd14481639da0808947aff8bfab5abed4b", - "4a4f202484512526", - }, - { - "6f6fc234bf35beae1a366c44c520c59ad5aa70351b5f5085e21e1fe2bfcee709", - "1f66ab4185ed9b6375", - }, - { - "4fdaf89e2a0e78c000061b59455e0ea93a4445b440e7562c8f0cfa165c93de2e", - "eed7422227613b6f53c9", - }, - { - "d6b780eee9c811f664393dc2c58b5a68c92b3c9fe9ceb70371d33ece63b5787e", - "eaeed5cdffd89dece455f1", - }, - { - "d0015071d3e7ed048c764850d76406eceae52b8e2e6e5a2c3aa92ae880485b34", - "5be43c90f22902e4fe8ed2d3", - }, - { - "9b0207902f9932f7a85c24722e93e31f6ed2c75c406509aa0f2f6d1cab046ce4", - "a746273228122f381c3b46e4f1", - }, - { - "258020d5b04a814f2b72c1c661e1f5a5c395d9799e5eee8b8519cf7300e90cb1", - "3c5871cd619c69a63b540eb5a625", - }, - { - "4adae3b55baa907fefc253365fdd99d8398befd0551ed6bf9a2a2784d3c304d1", - "fa22874bcc068879e8ef11a69f0722", - }, - { - "6dd10d772f8d5b4a96c3c5d30878cd9a1073fa835bfe6d2b924fa64a1fab1711", - "52a608ab21ccdd8a4457a57ede782176", - }, - { - "0b8741ddf2259d3af2901eb1ae354f22836442c965556f5c1eb89501191cb46a", - "82e192e4043ddcd12ecf52969d0f807eed", - }, - { - "f48a754ca8193a82643150ab94038b5dd170b4ebd1e0751b78cfb0a98fa5076a", - "75683dcb556140c522543bb6e9098b21a21e", - }, - { - "5698409ab856b74d9fa5e9b259dfa46001f89041752da424e56e491577b88c86", - "06e4efe45035e61faaf4287b4d8d1f12ca97e5", - }, - }; - - uint8_t hash[BLAKE256_DIGEST_LENGTH]; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - size_t len = strlen(tests[i].data) / 2; - blake256(fromhex(tests[i].data), len, hash); - ck_assert_mem_eq(hash, fromhex(tests[i].hash), BLAKE256_DIGEST_LENGTH); - - // Test progressive hashing. - size_t part_len = len / 2; - BLAKE256_CTX ctx; - blake256_Init(&ctx); - blake256_Update(&ctx, fromhex(tests[i].data), part_len); - blake256_Update(&ctx, NULL, 0); - blake256_Update(&ctx, fromhex(tests[i].data) + part_len, len - part_len); - blake256_Final(&ctx, hash); - ck_assert_mem_eq(hash, fromhex(tests[i].hash), BLAKE256_DIGEST_LENGTH); - } -} -END_TEST - -// test vectors from -// https://raw.githubusercontent.com/BLAKE2/BLAKE2/master/testvectors/blake2b-kat.txt -START_TEST(test_blake2b) { - static const struct { - const char *msg; - const char *hash; - } tests[] = { - { - "", - "10ebb67700b1868efb4417987acf4690ae9d972fb7a590c2f02871799aaa4786b5e9" - "96e8f0f4eb981fc214b005f42d2ff4233499391653df7aefcbc13fc51568", - }, - { - "000102", - "33d0825dddf7ada99b0e7e307104ad07ca9cfd9692214f1561356315e784f3e5a17e" - "364ae9dbb14cb2036df932b77f4b292761365fb328de7afdc6d8998f5fc1", - }, - { - "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021" - "22232425262728292a2b2c2d2e2f3031323334353637", - "f8f3726ac5a26cc80132493a6fedcb0e60760c09cfc84cad178175986819665e7684" - "2d7b9fedf76dddebf5d3f56faaad4477587af21606d396ae570d8e719af2", - }, - { - "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021" - "22232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243" - "4445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465" - "666768696a6b6c6d6e6f", - "227e3aed8d2cb10b918fcb04f9de3e6d0a57e08476d93759cd7b2ed54a1cbf0239c5" - "28fb04bbf288253e601d3bc38b21794afef90b17094a182cac557745e75f", - }, - }; - - uint8_t key[BLAKE2B_KEY_LENGTH]; - memcpy(key, - fromhex( - "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2" - "02122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"), - BLAKE2B_KEY_LENGTH); - - uint8_t digest[BLAKE2B_DIGEST_LENGTH]; - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - size_t msg_len = strlen(tests[i].msg) / 2; - blake2b_Key(fromhex(tests[i].msg), msg_len, key, sizeof(key), digest, - sizeof(digest)); - ck_assert_mem_eq(digest, fromhex(tests[i].hash), sizeof(digest)); - - // Test progressive hashing. - size_t part_len = msg_len / 2; - BLAKE2B_CTX ctx; - ck_assert_int_eq(blake2b_InitKey(&ctx, sizeof(digest), key, sizeof(key)), - 0); - ck_assert_int_eq(blake2b_Update(&ctx, fromhex(tests[i].msg), part_len), 0); - ck_assert_int_eq(blake2b_Update(&ctx, NULL, 0), 0); - ck_assert_int_eq(blake2b_Update(&ctx, fromhex(tests[i].msg) + part_len, - msg_len - part_len), - 0); - ck_assert_int_eq(blake2b_Final(&ctx, digest, sizeof(digest)), 0); - ck_assert_mem_eq(digest, fromhex(tests[i].hash), BLAKE2B_DIGEST_LENGTH); - } -} -END_TEST - -// test vectors from -// https://raw.githubusercontent.com/BLAKE2/BLAKE2/master/testvectors/blake2s-kat.txt -START_TEST(test_blake2s) { - static const struct { - const char *msg; - const char *hash; - } tests[] = { - { - "", - "48a8997da407876b3d79c0d92325ad3b89cbb754d86ab71aee047ad345fd2c49", - }, - { - "000102", - "1d220dbe2ee134661fdf6d9e74b41704710556f2f6e5a091b227697445dbea6b", - }, - { - "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021" - "22232425262728292a2b2c2d2e2f3031323334353637", - "2966b3cfae1e44ea996dc5d686cf25fa053fb6f67201b9e46eade85d0ad6b806", - }, - { - "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021" - "22232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243" - "4445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465" - "666768696a6b6c6d6e6f", - "90a83585717b75f0e9b725e055eeeeb9e7a028ea7e6cbc07b20917ec0363e38c", - }, - }; - - uint8_t key[BLAKE2S_KEY_LENGTH]; - memcpy( - key, - fromhex( - "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"), - BLAKE2S_KEY_LENGTH); - - uint8_t digest[BLAKE2S_DIGEST_LENGTH]; - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - size_t msg_len = strlen(tests[i].msg) / 2; - blake2s_Key(fromhex(tests[i].msg), msg_len, key, sizeof(key), digest, - sizeof(digest)); - ck_assert_mem_eq(digest, fromhex(tests[i].hash), sizeof(digest)); - - // Test progressive hashing. - size_t part_len = msg_len / 2; - BLAKE2S_CTX ctx; - ck_assert_int_eq(blake2s_InitKey(&ctx, sizeof(digest), key, sizeof(key)), - 0); - ck_assert_int_eq(blake2s_Update(&ctx, fromhex(tests[i].msg), part_len), 0); - ck_assert_int_eq(blake2s_Update(&ctx, NULL, 0), 0); - ck_assert_int_eq(blake2s_Update(&ctx, fromhex(tests[i].msg) + part_len, - msg_len - part_len), - 0); - ck_assert_int_eq(blake2s_Final(&ctx, digest, sizeof(digest)), 0); - ck_assert_mem_eq(digest, fromhex(tests[i].hash), BLAKE2S_DIGEST_LENGTH); - } -} -END_TEST - -#include - -START_TEST(test_chacha_drbg) { - char entropy[] = - "06032cd5eed33f39265f49ecb142c511da9aff2af71203bffaf34a9ca5bd9c0d"; - char nonce[] = "0e66f71edc43e42a45ad3c6fc6cdc4df"; - char reseed[] = - "01920a4e669ed3a85ae8a33b35a74ad7fb2a6bb4cf395ce00334a9c9a5a5d552"; - char expected[] = - "e172c5d18f3e8c77e9f66f9e1c24560772117161a9a0a237ab490b0769ad5d910f5dfb36" - "22edc06c18be0495c52588b200893d90fd80ff2149ead0c45d062c90f5890149c0f9591c" - "41bf4110865129a0fe524f210cca1340bd16f71f57906946cbaaf1fa863897d70d203b5a" - "f9996f756eec08861ee5875f9d915adcddc38719"; - uint8_t result[128]; - uint8_t null_bytes[128] = {0}; - - uint8_t nonce_bytes[16]; - memcpy(nonce_bytes, fromhex(nonce), sizeof(nonce_bytes)); - CHACHA_DRBG_CTX ctx; - chacha_drbg_init(&ctx, fromhex(entropy), strlen(entropy) / 2, nonce_bytes, - strlen(nonce) / 2); - chacha_drbg_reseed(&ctx, fromhex(reseed), strlen(reseed) / 2, NULL, 0); - chacha_drbg_generate(&ctx, result, sizeof(result)); - chacha_drbg_generate(&ctx, result, sizeof(result)); - ck_assert_mem_eq(result, fromhex(expected), sizeof(result)); - - for (size_t i = 0; i <= sizeof(result); ++i) { - chacha_drbg_init(&ctx, fromhex(entropy), strlen(entropy) / 2, nonce_bytes, - strlen(nonce) / 2); - chacha_drbg_reseed(&ctx, fromhex(reseed), strlen(reseed) / 2, NULL, 0); - chacha_drbg_generate(&ctx, result, sizeof(result) - 13); - memset(result, 0, sizeof(result)); - chacha_drbg_generate(&ctx, result, i); - ck_assert_mem_eq(result, fromhex(expected), i); - ck_assert_mem_eq(result + i, null_bytes, sizeof(result) - i); - } -} -END_TEST - -START_TEST(test_pbkdf2_hmac_sha256) { - uint8_t k[64]; - - // test vectors from - // https://stackoverflow.com/questions/5130513/pbkdf2-hmac-sha2-test-vectors - pbkdf2_hmac_sha256((const uint8_t *)"password", 8, (const uint8_t *)"salt", 4, - 1, k, 32); - ck_assert_mem_eq( - k, - fromhex( - "120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b"), - 32); - - pbkdf2_hmac_sha256((const uint8_t *)"password", 8, (const uint8_t *)"salt", 4, - 2, k, 32); - ck_assert_mem_eq( - k, - fromhex( - "ae4d0c95af6b46d32d0adff928f06dd02a303f8ef3c251dfd6e2d85a95474c43"), - 32); - - pbkdf2_hmac_sha256((const uint8_t *)"password", 8, (const uint8_t *)"salt", 4, - 4096, k, 32); - ck_assert_mem_eq( - k, - fromhex( - "c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a"), - 32); - - pbkdf2_hmac_sha256((const uint8_t *)"passwordPASSWORDpassword", 3 * 8, - (const uint8_t *)"saltSALTsaltSALTsaltSALTsaltSALTsalt", - 9 * 4, 4096, k, 40); - ck_assert_mem_eq(k, - fromhex("348c89dbcbd32b2f32d814b8116e84cf2b17347ebc1800181c4" - "e2a1fb8dd53e1c635518c7dac47e9"), - 40); - - pbkdf2_hmac_sha256((const uint8_t *)"pass\x00word", 9, - (const uint8_t *)"sa\x00lt", 5, 4096, k, 16); - ck_assert_mem_eq(k, fromhex("89b69d0516f829893c696226650a8687"), 16); - - // test vector from https://tools.ietf.org/html/rfc7914.html#section-11 - pbkdf2_hmac_sha256((const uint8_t *)"passwd", 6, (const uint8_t *)"salt", 4, - 1, k, 64); - ck_assert_mem_eq( - k, - fromhex( - "55ac046e56e3089fec1691c22544b605f94185216dde0465e68b9d57c20dacbc49ca" - "9cccf179b645991664b39d77ef317c71b845b1e30bd509112041d3a19783"), - 64); -} -END_TEST - -// test vectors from -// http://stackoverflow.com/questions/15593184/pbkdf2-hmac-sha-512-test-vectors -START_TEST(test_pbkdf2_hmac_sha512) { - uint8_t k[64]; - - pbkdf2_hmac_sha512((uint8_t *)"password", 8, (const uint8_t *)"salt", 4, 1, k, - 64); - ck_assert_mem_eq( - k, - fromhex( - "867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5d513554e1c8cf252c02d" - "470a285a0501bad999bfe943c08f050235d7d68b1da55e63f73b60a57fce"), - 64); - - pbkdf2_hmac_sha512((uint8_t *)"password", 8, (const uint8_t *)"salt", 4, 2, k, - 64); - ck_assert_mem_eq( - k, - fromhex( - "e1d9c16aa681708a45f5c7c4e215ceb66e011a2e9f0040713f18aefdb866d53cf76c" - "ab2868a39b9f7840edce4fef5a82be67335c77a6068e04112754f27ccf4e"), - 64); - - pbkdf2_hmac_sha512((uint8_t *)"password", 8, (const uint8_t *)"salt", 4, 4096, - k, 64); - ck_assert_mem_eq( - k, - fromhex( - "d197b1b33db0143e018b12f3d1d1479e6cdebdcc97c5c0f87f6902e072f457b5143f" - "30602641b3d55cd335988cb36b84376060ecd532e039b742a239434af2d5"), - 64); - - pbkdf2_hmac_sha512((uint8_t *)"passwordPASSWORDpassword", 3 * 8, - (const uint8_t *)"saltSALTsaltSALTsaltSALTsaltSALTsalt", - 9 * 4, 4096, k, 64); - ck_assert_mem_eq( - k, - fromhex( - "8c0511f4c6e597c6ac6315d8f0362e225f3c501495ba23b868c005174dc4ee71115b" - "59f9e60cd9532fa33e0f75aefe30225c583a186cd82bd4daea9724a3d3b8"), - 64); -} -END_TEST - -START_TEST(test_hmac_drbg) { - char entropy[] = - "06032cd5eed33f39265f49ecb142c511da9aff2af71203bffaf34a9ca5bd9c0d"; - char nonce[] = "0e66f71edc43e42a45ad3c6fc6cdc4df"; - char reseed[] = - "01920a4e669ed3a85ae8a33b35a74ad7fb2a6bb4cf395ce00334a9c9a5a5d552"; - char expected[] = - "76fc79fe9b50beccc991a11b5635783a83536add03c157fb30645e611c2898bb2b1bc215" - "000209208cd506cb28da2a51bdb03826aaf2bd2335d576d519160842e7158ad0949d1a9e" - "c3e66ea1b1a064b005de914eac2e9d4f2d72a8616a80225422918250ff66a41bd2f864a6" - "a38cc5b6499dc43f7f2bd09e1e0f8f5885935124"; - uint8_t result[128]; - uint8_t null_bytes[128] = {0}; - - uint8_t nonce_bytes[16]; - memcpy(nonce_bytes, fromhex(nonce), sizeof(nonce_bytes)); - HMAC_DRBG_CTX ctx; - hmac_drbg_init(&ctx, fromhex(entropy), strlen(entropy) / 2, nonce_bytes, - strlen(nonce) / 2); - hmac_drbg_reseed(&ctx, fromhex(reseed), strlen(reseed) / 2, NULL, 0); - hmac_drbg_generate(&ctx, result, sizeof(result)); - hmac_drbg_generate(&ctx, result, sizeof(result)); - ck_assert_mem_eq(result, fromhex(expected), sizeof(result)); - - for (size_t i = 0; i <= sizeof(result); ++i) { - hmac_drbg_init(&ctx, fromhex(entropy), strlen(entropy) / 2, nonce_bytes, - strlen(nonce) / 2); - hmac_drbg_reseed(&ctx, fromhex(reseed), strlen(reseed) / 2, NULL, 0); - hmac_drbg_generate(&ctx, result, sizeof(result) - 13); - memset(result, 0, sizeof(result)); - hmac_drbg_generate(&ctx, result, i); - ck_assert_mem_eq(result, fromhex(expected), i); - ck_assert_mem_eq(result + i, null_bytes, sizeof(result) - i); - } -} -END_TEST - -START_TEST(test_mnemonic) { - static const char *vectors[] = { - "00000000000000000000000000000000", - "abandon abandon abandon abandon abandon abandon abandon abandon abandon " - "abandon abandon about", - "c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e53495531f09a698" - "7599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04", - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", - "legal winner thank year wave sausage worth useful legal winner thank " - "yellow", - "2e8905819b8723fe2c1d161860e5ee1830318dbf49a83bd451cfb8440c28bd6fa457fe12" - "96106559a3c80937a1c1069be3a3a5bd381ee6260e8d9739fce1f607", - "80808080808080808080808080808080", - "letter advice cage absurd amount doctor acoustic avoid letter advice " - "cage above", - "d71de856f81a8acc65e6fc851a38d4d7ec216fd0796d0a6827a3ad6ed5511a30fa280f12" - "eb2e47ed2ac03b5c462a0358d18d69fe4f985ec81778c1b370b652a8", - "ffffffffffffffffffffffffffffffff", - "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", - "ac27495480225222079d7be181583751e86f571027b0497b5b5d11218e0a8a1333257291" - "7f0f8e5a589620c6f15b11c61dee327651a14c34e18231052e48c069", - "000000000000000000000000000000000000000000000000", - "abandon abandon abandon abandon abandon abandon abandon abandon abandon " - "abandon abandon abandon abandon abandon abandon abandon abandon agent", - "035895f2f481b1b0f01fcf8c289c794660b289981a78f8106447707fdd9666ca06da5a9a" - "565181599b79f53b844d8a71dd9f439c52a3d7b3e8a79c906ac845fa", - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", - "legal winner thank year wave sausage worth useful legal winner thank " - "year wave sausage worth useful legal will", - "f2b94508732bcbacbcc020faefecfc89feafa6649a5491b8c952cede496c214a0c7b3c39" - "2d168748f2d4a612bada0753b52a1c7ac53c1e93abd5c6320b9e95dd", - "808080808080808080808080808080808080808080808080", - "letter advice cage absurd amount doctor acoustic avoid letter advice " - "cage absurd amount doctor acoustic avoid letter always", - "107d7c02a5aa6f38c58083ff74f04c607c2d2c0ecc55501dadd72d025b751bc27fe913ff" - "b796f841c49b1d33b610cf0e91d3aa239027f5e99fe4ce9e5088cd65", - "ffffffffffffffffffffffffffffffffffffffffffffffff", - "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " - "when", - "0cd6e5d827bb62eb8fc1e262254223817fd068a74b5b449cc2f667c3f1f985a76379b433" - "48d952e2265b4cd129090758b3e3c2c49103b5051aac2eaeb890a528", - "0000000000000000000000000000000000000000000000000000000000000000", - "abandon abandon abandon abandon abandon abandon abandon abandon abandon " - "abandon abandon abandon abandon abandon abandon abandon abandon abandon " - "abandon abandon abandon abandon abandon art", - "bda85446c68413707090a52022edd26a1c9462295029f2e60cd7c4f2bbd3097170af7a4d" - "73245cafa9c3cca8d561a7c3de6f5d4a10be8ed2a5e608d68f92fcc8", - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", - "legal winner thank year wave sausage worth useful legal winner thank " - "year wave sausage worth useful legal winner thank year wave sausage " - "worth title", - "bc09fca1804f7e69da93c2f2028eb238c227f2e9dda30cd63699232578480a4021b146ad" - "717fbb7e451ce9eb835f43620bf5c514db0f8add49f5d121449d3e87", - "8080808080808080808080808080808080808080808080808080808080808080", - "letter advice cage absurd amount doctor acoustic avoid letter advice " - "cage absurd amount doctor acoustic avoid letter advice cage absurd " - "amount doctor acoustic bless", - "c0c519bd0e91a2ed54357d9d1ebef6f5af218a153624cf4f2da911a0ed8f7a09e2ef61af" - "0aca007096df430022f7a2b6fb91661a9589097069720d015e4e982f", - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " - "zoo zoo zoo zoo zoo vote", - "dd48c104698c30cfe2b6142103248622fb7bb0ff692eebb00089b32d22484e1613912f0a" - "5b694407be899ffd31ed3992c456cdf60f5d4564b8ba3f05a69890ad", - "77c2b00716cec7213839159e404db50d", - "jelly better achieve collect unaware mountain thought cargo oxygen act " - "hood bridge", - "b5b6d0127db1a9d2226af0c3346031d77af31e918dba64287a1b44b8ebf63cdd52676f67" - "2a290aae502472cf2d602c051f3e6f18055e84e4c43897fc4e51a6ff", - "b63a9c59a6e641f288ebc103017f1da9f8290b3da6bdef7b", - "renew stay biology evidence goat welcome casual join adapt armor " - "shuffle fault little machine walk stumble urge swap", - "9248d83e06f4cd98debf5b6f010542760df925ce46cf38a1bdb4e4de7d21f5c39366941c" - "69e1bdbf2966e0f6e6dbece898a0e2f0a4c2b3e640953dfe8b7bbdc5", - "3e141609b97933b66a060dcddc71fad1d91677db872031e85f4c015c5e7e8982", - "dignity pass list indicate nasty swamp pool script soccer toe leaf " - "photo multiply desk host tomato cradle drill spread actor shine dismiss " - "champion exotic", - "ff7f3184df8696d8bef94b6c03114dbee0ef89ff938712301d27ed8336ca89ef9635da20" - "af07d4175f2bf5f3de130f39c9d9e8dd0472489c19b1a020a940da67", - "0460ef47585604c5660618db2e6a7e7f", - "afford alter spike radar gate glance object seek swamp infant panel " - "yellow", - "65f93a9f36b6c85cbe634ffc1f99f2b82cbb10b31edc7f087b4f6cb9e976e9faf76ff41f" - "8f27c99afdf38f7a303ba1136ee48a4c1e7fcd3dba7aa876113a36e4", - "72f60ebac5dd8add8d2a25a797102c3ce21bc029c200076f", - "indicate race push merry suffer human cruise dwarf pole review arch " - "keep canvas theme poem divorce alter left", - "3bbf9daa0dfad8229786ace5ddb4e00fa98a044ae4c4975ffd5e094dba9e0bb289349dbe" - "2091761f30f382d4e35c4a670ee8ab50758d2c55881be69e327117ba", - "2c85efc7f24ee4573d2b81a6ec66cee209b2dcbd09d8eddc51e0215b0b68e416", - "clutch control vehicle tonight unusual clog visa ice plunge glimpse " - "recipe series open hour vintage deposit universe tip job dress radar " - "refuse motion taste", - "fe908f96f46668b2d5b37d82f558c77ed0d69dd0e7e043a5b0511c48c2f1064694a956f8" - "6360c93dd04052a8899497ce9e985ebe0c8c52b955e6ae86d4ff4449", - "eaebabb2383351fd31d703840b32e9e2", - "turtle front uncle idea crush write shrug there lottery flower risk " - "shell", - "bdfb76a0759f301b0b899a1e3985227e53b3f51e67e3f2a65363caedf3e32fde42a66c40" - "4f18d7b05818c95ef3ca1e5146646856c461c073169467511680876c", - "7ac45cfe7722ee6c7ba84fbc2d5bd61b45cb2fe5eb65aa78", - "kiss carry display unusual confirm curtain upgrade antique rotate hello " - "void custom frequent obey nut hole price segment", - "ed56ff6c833c07982eb7119a8f48fd363c4a9b1601cd2de736b01045c5eb8ab4f57b0794" - "03485d1c4924f0790dc10a971763337cb9f9c62226f64fff26397c79", - "4fa1a8bc3e6d80ee1316050e862c1812031493212b7ec3f3bb1b08f168cabeef", - "exile ask congress lamp submit jacket era scheme attend cousin alcohol " - "catch course end lucky hurt sentence oven short ball bird grab wing top", - "095ee6f817b4c2cb30a5a797360a81a40ab0f9a4e25ecd672a3f58a0b5ba0687c096a6b1" - "4d2c0deb3bdefce4f61d01ae07417d502429352e27695163f7447a8c", - "18ab19a9f54a9274f03e5209a2ac8a91", - "board flee heavy tunnel powder denial science ski answer betray cargo " - "cat", - "6eff1bb21562918509c73cb990260db07c0ce34ff0e3cc4a8cb3276129fbcb300bddfe00" - "5831350efd633909f476c45c88253276d9fd0df6ef48609e8bb7dca8", - "18a2e1d81b8ecfb2a333adcb0c17a5b9eb76cc5d05db91a4", - "board blade invite damage undo sun mimic interest slam gaze truly " - "inherit resist great inject rocket museum chief", - "f84521c777a13b61564234bf8f8b62b3afce27fc4062b51bb5e62bdfecb23864ee6ecf07" - "c1d5a97c0834307c5c852d8ceb88e7c97923c0a3b496bedd4e5f88a9", - "15da872c95a13dd738fbf50e427583ad61f18fd99f628c417a61cf8343c90419", - "beyond stage sleep clip because twist token leaf atom beauty genius " - "food business side grid unable middle armed observe pair crouch tonight " - "away coconut", - "b15509eaa2d09d3efd3e006ef42151b30367dc6e3aa5e44caba3fe4d3e352e65101fbdb8" - "6a96776b91946ff06f8eac594dc6ee1d3e82a42dfe1b40fef6bcc3fd", - 0, - 0, - 0, - }; - - const char **a, **b, **c, *m; - uint8_t seed[64]; - - a = vectors; - b = vectors + 1; - c = vectors + 2; - while (*a && *b && *c) { - m = mnemonic_from_data(fromhex(*a), strlen(*a) / 2); - ck_assert_str_eq(m, *b); - mnemonic_to_seed(m, "TREZOR", seed, 0); - ck_assert_mem_eq(seed, fromhex(*c), strlen(*c) / 2); -#if USE_BIP39_CACHE - // try second time to check whether caching results work - mnemonic_to_seed(m, "TREZOR", seed, 0); - ck_assert_mem_eq(seed, fromhex(*c), strlen(*c) / 2); -#endif - a += 3; - b += 3; - c += 3; - } -} -END_TEST - -START_TEST(test_mnemonic_check) { - static const char *vectors_ok[] = { - "abandon abandon abandon abandon abandon abandon abandon abandon abandon " - "abandon abandon about", - "legal winner thank year wave sausage worth useful legal winner thank " - "yellow", - "letter advice cage absurd amount doctor acoustic avoid letter advice " - "cage above", - "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", - "abandon abandon abandon abandon abandon abandon abandon abandon abandon " - "abandon abandon abandon abandon abandon abandon abandon abandon agent", - "legal winner thank year wave sausage worth useful legal winner thank " - "year wave sausage worth useful legal will", - "letter advice cage absurd amount doctor acoustic avoid letter advice " - "cage absurd amount doctor acoustic avoid letter always", - "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " - "when", - "abandon abandon abandon abandon abandon abandon abandon abandon abandon " - "abandon abandon abandon abandon abandon abandon abandon abandon abandon " - "abandon abandon abandon abandon abandon art", - "legal winner thank year wave sausage worth useful legal winner thank " - "year wave sausage worth useful legal winner thank year wave sausage " - "worth title", - "letter advice cage absurd amount doctor acoustic avoid letter advice " - "cage absurd amount doctor acoustic avoid letter advice cage absurd " - "amount doctor acoustic bless", - "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " - "zoo zoo zoo zoo zoo vote", - "jelly better achieve collect unaware mountain thought cargo oxygen act " - "hood bridge", - "renew stay biology evidence goat welcome casual join adapt armor " - "shuffle fault little machine walk stumble urge swap", - "dignity pass list indicate nasty swamp pool script soccer toe leaf " - "photo multiply desk host tomato cradle drill spread actor shine dismiss " - "champion exotic", - "afford alter spike radar gate glance object seek swamp infant panel " - "yellow", - "indicate race push merry suffer human cruise dwarf pole review arch " - "keep canvas theme poem divorce alter left", - "clutch control vehicle tonight unusual clog visa ice plunge glimpse " - "recipe series open hour vintage deposit universe tip job dress radar " - "refuse motion taste", - "turtle front uncle idea crush write shrug there lottery flower risk " - "shell", - "kiss carry display unusual confirm curtain upgrade antique rotate hello " - "void custom frequent obey nut hole price segment", - "exile ask congress lamp submit jacket era scheme attend cousin alcohol " - "catch course end lucky hurt sentence oven short ball bird grab wing top", - "board flee heavy tunnel powder denial science ski answer betray cargo " - "cat", - "board blade invite damage undo sun mimic interest slam gaze truly " - "inherit resist great inject rocket museum chief", - "beyond stage sleep clip because twist token leaf atom beauty genius " - "food business side grid unable middle armed observe pair crouch tonight " - "away coconut", - 0, - }; - static const char *vectors_fail[] = { - "above abandon abandon abandon abandon abandon abandon abandon abandon " - "abandon abandon about", - "above winner thank year wave sausage worth useful legal winner thank " - "yellow", - "above advice cage absurd amount doctor acoustic avoid letter advice " - "cage above", - "above zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", - "above abandon abandon abandon abandon abandon abandon abandon abandon " - "abandon abandon abandon abandon abandon abandon abandon abandon agent", - "above winner thank year wave sausage worth useful legal winner thank " - "year wave sausage worth useful legal will", - "above advice cage absurd amount doctor acoustic avoid letter advice " - "cage absurd amount doctor acoustic avoid letter always", - "above zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " - "when", - "above abandon abandon abandon abandon abandon abandon abandon abandon " - "abandon abandon abandon abandon abandon abandon abandon abandon abandon " - "abandon abandon abandon abandon abandon art", - "above winner thank year wave sausage worth useful legal winner thank " - "year wave sausage worth useful legal winner thank year wave sausage " - "worth title", - "above advice cage absurd amount doctor acoustic avoid letter advice " - "cage absurd amount doctor acoustic avoid letter advice cage absurd " - "amount doctor acoustic bless", - "above zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " - "zoo zoo zoo zoo zoo zoo vote", - "above better achieve collect unaware mountain thought cargo oxygen act " - "hood bridge", - "above stay biology evidence goat welcome casual join adapt armor " - "shuffle fault little machine walk stumble urge swap", - "above pass list indicate nasty swamp pool script soccer toe leaf photo " - "multiply desk host tomato cradle drill spread actor shine dismiss " - "champion exotic", - "above alter spike radar gate glance object seek swamp infant panel " - "yellow", - "above race push merry suffer human cruise dwarf pole review arch keep " - "canvas theme poem divorce alter left", - "above control vehicle tonight unusual clog visa ice plunge glimpse " - "recipe series open hour vintage deposit universe tip job dress radar " - "refuse motion taste", - "above front uncle idea crush write shrug there lottery flower risk " - "shell", - "above carry display unusual confirm curtain upgrade antique rotate " - "hello void custom frequent obey nut hole price segment", - "above ask congress lamp submit jacket era scheme attend cousin alcohol " - "catch course end lucky hurt sentence oven short ball bird grab wing top", - "above flee heavy tunnel powder denial science ski answer betray cargo " - "cat", - "above blade invite damage undo sun mimic interest slam gaze truly " - "inherit resist great inject rocket museum chief", - "above stage sleep clip because twist token leaf atom beauty genius food " - "business side grid unable middle armed observe pair crouch tonight away " - "coconut", - "abandon abandon abandon abandon abandon abandon abandon abandon abandon " - "abandon about", - "winner thank year wave sausage worth useful legal winner thank yellow", - "advice cage absurd amount doctor acoustic avoid letter advice cage " - "above", - "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", - "abandon abandon abandon abandon abandon abandon abandon abandon abandon " - "abandon abandon abandon abandon abandon abandon abandon agent", - "winner thank year wave sausage worth useful legal winner thank year " - "wave sausage worth useful legal will", - "advice cage absurd amount doctor acoustic avoid letter advice cage " - "absurd amount doctor acoustic avoid letter always", - "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when", - "abandon abandon abandon abandon abandon abandon abandon abandon abandon " - "abandon abandon abandon abandon abandon abandon abandon abandon abandon " - "abandon abandon abandon abandon art", - "winner thank year wave sausage worth useful legal winner thank year " - "wave sausage worth useful legal winner thank year wave sausage worth " - "title", - "advice cage absurd amount doctor acoustic avoid letter advice cage " - "absurd amount doctor acoustic avoid letter advice cage absurd amount " - "doctor acoustic bless", - "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " - "zoo zoo zoo zoo vote", - "better achieve collect unaware mountain thought cargo oxygen act hood " - "bridge", - "stay biology evidence goat welcome casual join adapt armor shuffle " - "fault little machine walk stumble urge swap", - "pass list indicate nasty swamp pool script soccer toe leaf photo " - "multiply desk host tomato cradle drill spread actor shine dismiss " - "champion exotic", - "alter spike radar gate glance object seek swamp infant panel yellow", - "race push merry suffer human cruise dwarf pole review arch keep canvas " - "theme poem divorce alter left", - "control vehicle tonight unusual clog visa ice plunge glimpse recipe " - "series open hour vintage deposit universe tip job dress radar refuse " - "motion taste", - "front uncle idea crush write shrug there lottery flower risk shell", - "carry display unusual confirm curtain upgrade antique rotate hello void " - "custom frequent obey nut hole price segment", - "ask congress lamp submit jacket era scheme attend cousin alcohol catch " - "course end lucky hurt sentence oven short ball bird grab wing top", - "flee heavy tunnel powder denial science ski answer betray cargo cat", - "blade invite damage undo sun mimic interest slam gaze truly inherit " - "resist great inject rocket museum chief", - "stage sleep clip because twist token leaf atom beauty genius food " - "business side grid unable middle armed observe pair crouch tonight away " - "coconut", - 0, - }; - - const char **m; - int r; - m = vectors_ok; - while (*m) { - r = mnemonic_check(*m); - ck_assert_int_eq(r, 1); - m++; - } - m = vectors_fail; - while (*m) { - r = mnemonic_check(*m); - ck_assert_int_eq(r, 0); - m++; - } -} -END_TEST - -START_TEST(test_mnemonic_to_bits) { - static const char *vectors[] = { - "00000000000000000000000000000000", - "abandon abandon abandon abandon abandon abandon abandon abandon abandon " - "abandon abandon about", - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", - "legal winner thank year wave sausage worth useful legal winner thank " - "yellow", - "80808080808080808080808080808080", - "letter advice cage absurd amount doctor acoustic avoid letter advice " - "cage above", - "ffffffffffffffffffffffffffffffff", - "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", - "000000000000000000000000000000000000000000000000", - "abandon abandon abandon abandon abandon abandon abandon abandon abandon " - "abandon abandon abandon abandon abandon abandon abandon abandon agent", - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", - "legal winner thank year wave sausage worth useful legal winner thank " - "year wave sausage worth useful legal will", - "808080808080808080808080808080808080808080808080", - "letter advice cage absurd amount doctor acoustic avoid letter advice " - "cage absurd amount doctor acoustic avoid letter always", - "ffffffffffffffffffffffffffffffffffffffffffffffff", - "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " - "when", - "0000000000000000000000000000000000000000000000000000000000000000", - "abandon abandon abandon abandon abandon abandon abandon abandon abandon " - "abandon abandon abandon abandon abandon abandon abandon abandon abandon " - "abandon abandon abandon abandon abandon art", - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", - "legal winner thank year wave sausage worth useful legal winner thank " - "year wave sausage worth useful legal winner thank year wave sausage " - "worth title", - "8080808080808080808080808080808080808080808080808080808080808080", - "letter advice cage absurd amount doctor acoustic avoid letter advice " - "cage absurd amount doctor acoustic avoid letter advice cage absurd " - "amount doctor acoustic bless", - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " - "zoo zoo zoo zoo zoo vote", - "77c2b00716cec7213839159e404db50d", - "jelly better achieve collect unaware mountain thought cargo oxygen act " - "hood bridge", - "b63a9c59a6e641f288ebc103017f1da9f8290b3da6bdef7b", - "renew stay biology evidence goat welcome casual join adapt armor " - "shuffle fault little machine walk stumble urge swap", - "3e141609b97933b66a060dcddc71fad1d91677db872031e85f4c015c5e7e8982", - "dignity pass list indicate nasty swamp pool script soccer toe leaf " - "photo multiply desk host tomato cradle drill spread actor shine dismiss " - "champion exotic", - "0460ef47585604c5660618db2e6a7e7f", - "afford alter spike radar gate glance object seek swamp infant panel " - "yellow", - "72f60ebac5dd8add8d2a25a797102c3ce21bc029c200076f", - "indicate race push merry suffer human cruise dwarf pole review arch " - "keep canvas theme poem divorce alter left", - "2c85efc7f24ee4573d2b81a6ec66cee209b2dcbd09d8eddc51e0215b0b68e416", - "clutch control vehicle tonight unusual clog visa ice plunge glimpse " - "recipe series open hour vintage deposit universe tip job dress radar " - "refuse motion taste", - "eaebabb2383351fd31d703840b32e9e2", - "turtle front uncle idea crush write shrug there lottery flower risk " - "shell", - "7ac45cfe7722ee6c7ba84fbc2d5bd61b45cb2fe5eb65aa78", - "kiss carry display unusual confirm curtain upgrade antique rotate hello " - "void custom frequent obey nut hole price segment", - "4fa1a8bc3e6d80ee1316050e862c1812031493212b7ec3f3bb1b08f168cabeef", - "exile ask congress lamp submit jacket era scheme attend cousin alcohol " - "catch course end lucky hurt sentence oven short ball bird grab wing top", - "18ab19a9f54a9274f03e5209a2ac8a91", - "board flee heavy tunnel powder denial science ski answer betray cargo " - "cat", - "18a2e1d81b8ecfb2a333adcb0c17a5b9eb76cc5d05db91a4", - "board blade invite damage undo sun mimic interest slam gaze truly " - "inherit resist great inject rocket museum chief", - "15da872c95a13dd738fbf50e427583ad61f18fd99f628c417a61cf8343c90419", - "beyond stage sleep clip because twist token leaf atom beauty genius " - "food business side grid unable middle armed observe pair crouch tonight " - "away coconut", - 0, - 0, - }; - - const char **a, **b; - uint8_t mnemonic_bits[64]; - - a = vectors; - b = vectors + 1; - while (*a && *b) { - int mnemonic_bits_len = mnemonic_to_bits(*b, mnemonic_bits); - ck_assert_int_eq(mnemonic_bits_len % 33, 0); - mnemonic_bits_len = mnemonic_bits_len * 4 / 33; - ck_assert_uint_eq((size_t)mnemonic_bits_len, strlen(*a) / 2); - ck_assert_mem_eq(mnemonic_bits, fromhex(*a), mnemonic_bits_len); - a += 2; - b += 2; - } -} -END_TEST - -START_TEST(test_mnemonic_find_word) { - ck_assert_int_eq(-1, mnemonic_find_word("aaaa")); - ck_assert_int_eq(-1, mnemonic_find_word("zzzz")); - for (int i = 0; i < BIP39_WORDS; i++) { - const char *word = mnemonic_get_word(i); - int index = mnemonic_find_word(word); - ck_assert_int_eq(i, index); - } -} -END_TEST - -START_TEST(test_slip39_get_word) { - static const struct { - const int index; - const char *expected_word; - } vectors[] = {{573, "member"}, - {0, "academic"}, - {1023, "zero"}, - {245, "drove"}, - {781, "satoshi"}}; - for (size_t i = 0; i < (sizeof(vectors) / sizeof(*vectors)); i++) { - const char *a = get_word(vectors[i].index); - ck_assert_str_eq(a, vectors[i].expected_word); - } -} -END_TEST - -START_TEST(test_slip39_word_index) { - uint16_t index; - static const struct { - const char *word; - bool expected_result; - uint16_t expected_index; - } vectors[] = {{"academic", true, 0}, - {"zero", true, 1023}, - {"drove", true, 245}, - {"satoshi", true, 781}, - {"member", true, 573}, - // 9999 value is never checked since the word is not in list - {"fakeword", false, 9999}}; - for (size_t i = 0; i < (sizeof(vectors) / sizeof(*vectors)); i++) { - bool result = word_index(&index, vectors[i].word, sizeof(vectors[i].word)); - ck_assert_int_eq(result, vectors[i].expected_result); - if (result) { - ck_assert_uint_eq(index, vectors[i].expected_index); - } - } -} -END_TEST - -START_TEST(test_slip39_word_completion_mask) { - static const struct { - const uint16_t prefix; - const uint16_t expected_mask; - } vectors[] = { - {12, 0xFD}, // 011111101 - {21, 0xF8}, // 011111000 - {75, 0xAD}, // 010101101 - {4, 0x1F7}, // 111110111 - {738, 0x6D}, // 001101101 - {9, 0x6D}, // 001101101 - {0, 0x1FF}, // 111111111 - {10, 0x00}, // 000000000 - {255, 0x00}, // 000000000 - {203, 0x00}, // 000000000 - {9999, 0x00}, // 000000000 - {20000, 0x00}, // 000000000 - }; - for (size_t i = 0; i < (sizeof(vectors) / sizeof(*vectors)); i++) { - uint16_t mask = slip39_word_completion_mask(vectors[i].prefix); - ck_assert_uint_eq(mask, vectors[i].expected_mask); - } -} -END_TEST - -START_TEST(test_slip39_sequence_to_word) { - static const struct { - const uint16_t prefix; - const char *expected_word; - } vectors[] = { - {7945, "swimming"}, {646, "pipeline"}, {5, "laden"}, {34, "fiber"}, - {62, "ocean"}, {0, "academic"}, {10, NULL}, {255, NULL}, - {203, NULL}, {9999, NULL}, {20000, NULL}, - }; - for (size_t i = 0; i < (sizeof(vectors) / sizeof(*vectors)); i++) { - const char *word = button_sequence_to_word(vectors[i].prefix); - if (vectors[i].expected_word != NULL) { - ck_assert_str_eq(word, vectors[i].expected_word); - } else { - ck_assert_ptr_eq(word, NULL); - } - } -} -END_TEST - -START_TEST(test_slip39_word_completion) { - const char t9[] = {1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 5, - 6, 6, 6, 6, 7, 7, 8, 8, 8, 9, 9, 9, 9}; - for (size_t i = 0; i < WORDS_COUNT; ++i) { - const char *word = slip39_wordlist[i]; - uint16_t prefix = t9[word[0] - 'a']; - for (size_t j = 1; j < 4; ++j) { - uint16_t mask = slip39_word_completion_mask(prefix); - uint8_t next = t9[word[j] - 'a']; - ck_assert_uint_ne(mask & (1 << (next - 1)), 0); - prefix = prefix * 10 + next; - } - ck_assert_str_eq(button_sequence_to_word(prefix), word); - } -} -END_TEST - -START_TEST(test_shamir) { -#define SHAMIR_MAX_COUNT 16 - static const struct { - const uint8_t result[SHAMIR_MAX_LEN]; - uint8_t result_index; - const uint8_t share_indices[SHAMIR_MAX_COUNT]; - const uint8_t share_values[SHAMIR_MAX_COUNT][SHAMIR_MAX_LEN]; - uint8_t share_count; - size_t len; - bool ret; - } vectors[] = {{{7, 151, 168, 57, 186, 104, 218, 21, 209, 96, 106, - 152, 252, 35, 210, 208, 43, 47, 13, 21, 142, 122, - 24, 42, 149, 192, 95, 24, 240, 24, 148, 110}, - 0, - {2}, - { - {7, 151, 168, 57, 186, 104, 218, 21, 209, 96, 106, - 152, 252, 35, 210, 208, 43, 47, 13, 21, 142, 122, - 24, 42, 149, 192, 95, 24, 240, 24, 148, 110}, - }, - 1, - 32, - true}, - - {{53}, - 255, - {14, 10, 1, 13, 8, 7, 3, 11, 9, 4, 6, 0, 5, 12, 15, 2}, - { - {114}, - {41}, - {116}, - {67}, - {198}, - {109}, - {232}, - {39}, - {90}, - {241}, - {156}, - {75}, - {46}, - {181}, - {144}, - {175}, - }, - 16, - 1, - true}, - - {{91, 188, 226, 91, 254, 197, 225}, - 1, - {5, 1, 10}, - { - {129, 18, 104, 86, 236, 73, 176}, - {91, 188, 226, 91, 254, 197, 225}, - {69, 53, 151, 204, 224, 37, 19}, - }, - 3, - 7, - true}, - - {{0}, - 1, - {5, 1, 1}, - { - {129, 18, 104, 86, 236, 73, 176}, - {91, 188, 226, 91, 254, 197, 225}, - {69, 53, 151, 204, 224, 37, 19}, - }, - 3, - 7, - false}, - - {{0}, - 255, - {3, 12, 3}, - { - {100, 176, 99, 142, 115, 192, 138}, - {54, 139, 99, 172, 29, 137, 58}, - {216, 119, 222, 40, 87, 25, 147}, - }, - 3, - 7, - false}, - - {{163, 120, 30, 243, 179, 172, 196, 137, 119, 17}, - 3, - {1, 0, 12}, - {{80, 180, 198, 131, 111, 251, 45, 181, 2, 242}, - {121, 9, 79, 98, 132, 164, 9, 165, 19, 230}, - {86, 52, 173, 138, 189, 223, 122, 102, 248, 157}}, - 3, - 10, - true}}; - - for (size_t i = 0; i < (sizeof(vectors) / sizeof(*vectors)); ++i) { - uint8_t result[SHAMIR_MAX_LEN]; - const uint8_t *share_values[SHAMIR_MAX_COUNT]; - for (size_t j = 0; j < vectors[i].share_count; ++j) { - share_values[j] = vectors[i].share_values[j]; - } - ck_assert_int_eq(shamir_interpolate(result, vectors[i].result_index, - vectors[i].share_indices, share_values, - vectors[i].share_count, vectors[i].len), - vectors[i].ret); - if (vectors[i].ret == true) { - ck_assert_mem_eq(result, vectors[i].result, vectors[i].len); - } - } -} -END_TEST - -START_TEST(test_address) { - char address[36]; - uint8_t pub_key[65]; - - memcpy( - pub_key, - fromhex( - "0226659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), - 33); - ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "139MaMHp3Vjo8o4x8N1ZLWEtovLGvBsg6s"); - ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "mhfJsQNnrXB3uuYZqvywARTDfuvyjg4RBh"); - ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "MxiimznnxsqMfLKTQBL8Z2PoY9jKpjgkCu"); - ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "LMNJqZbe89yrPbm7JVzrcXJf28hZ1rKPaH"); - ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, - address, sizeof(address)); - ck_assert_str_eq(address, "FXK52G2BbzRLaQ651U12o23DU5cEQdhvU6"); - ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2_RIPEMD, HASHER_SHA2D, - address, sizeof(address)); - ck_assert_str_eq(address, "34PyTHn74syS796eTgsyoLfwoBC3cwLn6p"); - - memcpy( - pub_key, - fromhex( - "025b1654a0e78d28810094f6c5a96b8efb8a65668b578f170ac2b1f83bc63ba856"), - 33); - ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "19Ywfm3witp6C1yBMy4NRYHY2347WCRBfQ"); - ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "mp4txp8vXvFLy8So5Y2kFTVrt2epN6YzdP"); - ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "N58JsQYveGueiZDgdnNwe4SSkGTAToutAY"); - ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "LTmtvyMmoZ49SpfLY73fhZMJEFRPdyohKh"); - ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, - address, sizeof(address)); - ck_assert_str_eq(address, "Fdif7fnKHPVddczJF53qt45rgCL51yWN6x"); - ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2_RIPEMD, HASHER_SHA2D, - address, sizeof(address)); - ck_assert_str_eq(address, "35trq6eeuHf6VL9L8pQv46x3vegHnHoTuB"); - - memcpy( - pub_key, - fromhex( - "03433f246a12e6486a51ff08802228c61cf895175a9b49ed4766ea9a9294a3c7fe"), - 33); - ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "1FWE2bn3MWhc4QidcF6AvEWpK77sSi2cAP"); - ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "mv2BKes2AY8rqXCFKp4Yk9j9B6iaMfWRLN"); - ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "NB5bEFH2GtoAawy8t4Qk8kfj3LWvQs3MhB"); - ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "LZjBHp5sSAwfKDQnnP5UCFaaXKV9YheGxQ"); - ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, - address, sizeof(address)); - ck_assert_str_eq(address, "FjfwUWWQv1P9W1jkVM5eNkK8yGPq5XyZZy"); - ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2_RIPEMD, HASHER_SHA2D, - address, sizeof(address)); - ck_assert_str_eq(address, "3456DYaKUWuY6RWWw8Hp5CftHLcQN29h9Y"); - - memcpy( - pub_key, - fromhex( - "03aeb03abeee0f0f8b4f7a5d65ce31f9570cef9f72c2dd8a19b4085a30ab033d48"), - 33); - ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "1yrZb8dhdevoqpUEGi2tUccUEeiMKeLcs"); - ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "mgVoreDcWf6BaxJ5wqgQiPpwLEFRLSr8U8"); - ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "MwZDmEdcd1kVLP4yW62c6zmXCU3mNbveDo"); - ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "LLCopoSTnHtz4eWdQQhLAVgNgT1zTi4QBK"); - ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, - address, sizeof(address)); - ck_assert_str_eq(address, "FW9a1Vs1G8LUFSqb7NhWLzQw8PvfwAxmxA"); - ecdsa_get_address_segwit_p2sh(pub_key, 5, HASHER_SHA2_RIPEMD, HASHER_SHA2D, - address, sizeof(address)); - ck_assert_str_eq(address, "3DBU4tJ9tkMR9fnmCtjW48kjvseoNLQZXd"); - - memcpy( - pub_key, - fromhex( - "0496e8f2093f018aff6c2e2da5201ee528e2c8accbf9cac51563d33a7bb74a016054" - "201c025e2a5d96b1629b95194e806c63eb96facaedc733b1a4b70ab3b33e3a"), - 65); - ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "194SZbL75xCCGBbKtMsyWLE5r9s2V6mhVM"); - ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "moaPreR5tydT3J4wbvrMLFSQi9TjPCiZc6"); - ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "N4domEq61LHkniqqABCYirNzaPG5NRU8GH"); - ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "LTHPpodwAcSFWzHV4VsGnMHr4NEJajMnKX"); - ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, - address, sizeof(address)); - ck_assert_str_eq(address, "FdEA1W4UeSsjhncSmTsSxr2QWK8z2xGkjc"); - - memcpy( - pub_key, - fromhex( - "0498010f8a687439ff497d3074beb4519754e72c4b6220fb669224749591dde416f3" - "961f8ece18f8689bb32235e436874d2174048b86118a00afbd5a4f33a24f0f"), - 65); - ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "1A2WfBD4BJFwYHFPc5KgktqtbdJLBuVKc4"); - ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "mpYTxEJ2zKhCKPj1KeJ4ap4DTcu39T3uzD"); - ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "N5bsrpi36gMW4pVtsteFyQzoKrhPE7nkxK"); - ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "LUFTvPWtFxVzo5wYnDJz2uueoqfcMYiuxH"); - ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, - address, sizeof(address)); - ck_assert_str_eq(address, "FeCE75wRjnwUytGWVBKADQeDFnaHpJ8t3B"); - - memcpy( - pub_key, - fromhex( - "04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2" - "a59ebddbdac9e87b816307a7ed5b826b8f40b92719086238e1bebf19b77a4d"), - 65); - ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "19J81hrPnQxg9UGx45ibTieCkb2ttm8CLL"); - ecdsa_get_address(pub_key, 111, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "mop5JkwNbSPvvakZmegyHdrXcadbjLazww"); - ecdsa_get_address(pub_key, 52, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "N4sVDMMNho4Eg1XTKu3AgEo7UpRwq3aNbn"); - ecdsa_get_address(pub_key, 48, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "LTX5GvADs5CjQGy7EDhtjjhxxoQB2Uhicd"); - ecdsa_get_address(pub_key, 36, HASHER_SHA2_RIPEMD, HASHER_GROESTLD_TRUNC, - address, sizeof(address)); - ck_assert_str_eq(address, "FdTqTcamLueDb5J4wBi4vESXQkJrS54H6k"); -} -END_TEST - -START_TEST(test_pubkey_validity) { - uint8_t pub_key[65]; - curve_point pub; - int res; - const ecdsa_curve *curve = &secp256k1; - - memcpy( - pub_key, - fromhex( - "0226659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), - 33); - res = ecdsa_read_pubkey(curve, pub_key, &pub); - ck_assert_int_eq(res, 1); - - memcpy( - pub_key, - fromhex( - "025b1654a0e78d28810094f6c5a96b8efb8a65668b578f170ac2b1f83bc63ba856"), - 33); - res = ecdsa_read_pubkey(curve, pub_key, &pub); - ck_assert_int_eq(res, 1); - - memcpy( - pub_key, - fromhex( - "03433f246a12e6486a51ff08802228c61cf895175a9b49ed4766ea9a9294a3c7fe"), - 33); - res = ecdsa_read_pubkey(curve, pub_key, &pub); - ck_assert_int_eq(res, 1); - - memcpy( - pub_key, - fromhex( - "03aeb03abeee0f0f8b4f7a5d65ce31f9570cef9f72c2dd8a19b4085a30ab033d48"), - 33); - res = ecdsa_read_pubkey(curve, pub_key, &pub); - ck_assert_int_eq(res, 1); - - memcpy( - pub_key, - fromhex( - "0496e8f2093f018aff6c2e2da5201ee528e2c8accbf9cac51563d33a7bb74a016054" - "201c025e2a5d96b1629b95194e806c63eb96facaedc733b1a4b70ab3b33e3a"), - 65); - res = ecdsa_read_pubkey(curve, pub_key, &pub); - ck_assert_int_eq(res, 1); - - memcpy( - pub_key, - fromhex( - "0498010f8a687439ff497d3074beb4519754e72c4b6220fb669224749591dde416f3" - "961f8ece18f8689bb32235e436874d2174048b86118a00afbd5a4f33a24f0f"), - 65); - res = ecdsa_read_pubkey(curve, pub_key, &pub); - ck_assert_int_eq(res, 1); - - memcpy( - pub_key, - fromhex( - "04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2" - "a59ebddbdac9e87b816307a7ed5b826b8f40b92719086238e1bebf19b77a4d"), - 65); - res = ecdsa_read_pubkey(curve, pub_key, &pub); - ck_assert_int_eq(res, 1); - - memcpy( - pub_key, - fromhex( - "04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2" - "a59ebddbdac9e87b816307a7ed5b826b8f40b92719086238e1bebf00000000"), - 65); - res = ecdsa_read_pubkey(curve, pub_key, &pub); - ck_assert_int_eq(res, 0); - - memcpy( - pub_key, - fromhex( - "04f80490839af36d13701ec3f9eebdac901b51c362119d74553a3c537faff31b17e2" - "a59ebddbdac9e87b816307a7ed5b8211111111111111111111111111111111"), - 65); - res = ecdsa_read_pubkey(curve, pub_key, &pub); - ck_assert_int_eq(res, 0); - - memcpy(pub_key, fromhex("00"), 1); - res = ecdsa_read_pubkey(curve, pub_key, &pub); - ck_assert_int_eq(res, 0); -} -END_TEST - -START_TEST(test_pubkey_uncompress) { - uint8_t pub_key[65]; - uint8_t uncompressed[65]; - int res; - const ecdsa_curve *curve = &secp256k1; - - memcpy( - pub_key, - fromhex( - "0226659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), - 33); - res = ecdsa_uncompress_pubkey(curve, pub_key, uncompressed); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq( - uncompressed, - fromhex( - "0426659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37b3" - "cfbad6b39a8ce8cb3a675f53b7b57e120fe067b8035d771fd99e3eba7cf4de"), - 65); - - memcpy( - pub_key, - fromhex( - "03433f246a12e6486a51ff08802228c61cf895175a9b49ed4766ea9a9294a3c7fe"), - 33); - res = ecdsa_uncompress_pubkey(curve, pub_key, uncompressed); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq( - uncompressed, - fromhex( - "04433f246a12e6486a51ff08802228c61cf895175a9b49ed4766ea9a9294a3c7feeb" - "4c25bcb840f720a16e8857a011e6b91e0ab2d03dbb5f9762844bb21a7b8ca7"), - 65); - - memcpy( - pub_key, - fromhex( - "0496e8f2093f018aff6c2e2da5201ee528e2c8accbf9cac51563d33a7bb74a016054" - "201c025e2a5d96b1629b95194e806c63eb96facaedc733b1a4b70ab3b33e3a"), - 65); - res = ecdsa_uncompress_pubkey(curve, pub_key, uncompressed); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq( - uncompressed, - fromhex( - "0496e8f2093f018aff6c2e2da5201ee528e2c8accbf9cac51563d33a7bb74a016054" - "201c025e2a5d96b1629b95194e806c63eb96facaedc733b1a4b70ab3b33e3a"), - 65); - - memcpy(pub_key, fromhex("00"), 1); - res = ecdsa_uncompress_pubkey(curve, pub_key, uncompressed); - ck_assert_int_eq(res, 0); -} -END_TEST - -START_TEST(test_wif) { - uint8_t priv_key[32]; - char wif[53]; - - memcpy( - priv_key, - fromhex( - "1111111111111111111111111111111111111111111111111111111111111111"), - 32); - ecdsa_get_wif(priv_key, 0x80, HASHER_SHA2D, wif, sizeof(wif)); - ck_assert_str_eq(wif, "KwntMbt59tTsj8xqpqYqRRWufyjGunvhSyeMo3NTYpFYzZbXJ5Hp"); - ecdsa_get_wif(priv_key, 0xEF, HASHER_SHA2D, wif, sizeof(wif)); - ck_assert_str_eq(wif, "cN9spWsvaxA8taS7DFMxnk1yJD2gaF2PX1npuTpy3vuZFJdwavaw"); - - memcpy( - priv_key, - fromhex( - "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"), - 32); - ecdsa_get_wif(priv_key, 0x80, HASHER_SHA2D, wif, sizeof(wif)); - ck_assert_str_eq(wif, "L4ezQvyC6QoBhxB4GVs9fAPhUKtbaXYUn8YTqoeXwbevQq4U92vN"); - ecdsa_get_wif(priv_key, 0xEF, HASHER_SHA2D, wif, sizeof(wif)); - ck_assert_str_eq(wif, "cV1ysqy3XUVSsPeKeugH2Utm6ZC1EyeArAgvxE73SiJvfa6AJng7"); - - memcpy( - priv_key, - fromhex( - "47f7616ea6f9b923076625b4488115de1ef1187f760e65f89eb6f4f7ff04b012"), - 32); - ecdsa_get_wif(priv_key, 0x80, HASHER_SHA2D, wif, sizeof(wif)); - ck_assert_str_eq(wif, "KydbzBtk6uc7M6dXwEgTEH2sphZxSPbmDSz6kUUHi4eUpSQuhEbq"); - ecdsa_get_wif(priv_key, 0xEF, HASHER_SHA2D, wif, sizeof(wif)); - ck_assert_str_eq(wif, "cPzbT6tbXyJNWY6oKeVabbXwSvsN6qhTHV8ZrtvoDBJV5BRY1G5Q"); -} -END_TEST - -START_TEST(test_address_decode) { - int res; - uint8_t decode[MAX_ADDR_RAW_SIZE]; - - res = ecdsa_address_decode("1JwSSubhmg6iPtRjtyqhUYYH7bZg3Lfy1T", 0, - HASHER_SHA2D, decode); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(decode, - fromhex("00c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); - - res = ecdsa_address_decode("myTPjxggahXyAzuMcYp5JTkbybANyLsYBW", 111, - HASHER_SHA2D, decode); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(decode, - fromhex("6fc4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); - - res = ecdsa_address_decode("NEWoeZ6gh4CGvRgFAoAGh4hBqpxizGT6gZ", 52, - HASHER_SHA2D, decode); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(decode, - fromhex("34c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); - - res = ecdsa_address_decode("LdAPi7uXrLLmeh7u57pzkZc3KovxEDYRJq", 48, - HASHER_SHA2D, decode); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(decode, - fromhex("30c4c5d791fcb4654a1ef5e03fe0ad3d9c598f9827"), 21); - - res = ecdsa_address_decode("1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8", 0, - HASHER_SHA2D, decode); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(decode, - fromhex("0079fbfc3f34e7745860d76137da68f362380c606c"), 21); - - res = ecdsa_address_decode("mrdwvWkma2D6n9mGsbtkazedQQuoksnqJV", 111, - HASHER_SHA2D, decode); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(decode, - fromhex("6f79fbfc3f34e7745860d76137da68f362380c606c"), 21); - - res = ecdsa_address_decode("N7hMq7AmgNsQXaYARrEwybbDGei9mcPNqr", 52, - HASHER_SHA2D, decode); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(decode, - fromhex("3479fbfc3f34e7745860d76137da68f362380c606c"), 21); - - res = ecdsa_address_decode("LWLwtfycqf1uFqypLAug36W4kdgNwrZdNs", 48, - HASHER_SHA2D, decode); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(decode, - fromhex("3079fbfc3f34e7745860d76137da68f362380c606c"), 21); - - // invalid char - res = ecdsa_address_decode("1JwSSubhmg6i000jtyqhUYYH7bZg3Lfy1T", 0, - HASHER_SHA2D, decode); - ck_assert_int_eq(res, 0); - - // invalid address - res = ecdsa_address_decode("1111Subhmg6iPtRjtyqhUYYH7bZg3Lfy1T", 0, - HASHER_SHA2D, decode); - ck_assert_int_eq(res, 0); - - // invalid version - res = ecdsa_address_decode("LWLwtfycqf1uFqypLAug36W4kdgNwrZdNs", 0, - HASHER_SHA2D, decode); - ck_assert_int_eq(res, 0); -} -END_TEST - -START_TEST(test_ecdsa_der) { - static const struct { - const char *r; - const char *s; - const char *der; - } vectors[] = { - { - "9a0b7be0d4ed3146ee262b42202841834698bb3ee39c24e7437df208b8b70771", - "2b79ab1e7736219387dffe8d615bbdba87e11477104b867ef47afed1a5ede781", - "30450221009a0b7be0d4ed3146ee262b42202841834698bb3ee39c24e7437df208b8" - "b7077102202b79ab1e7736219387dffe8d615bbdba87e11477104b867ef47afed1a5" - "ede781", - }, - { - "6666666666666666666666666666666666666666666666666666666666666666", - "7777777777777777777777777777777777777777777777777777777777777777", - "30440220666666666666666666666666666666666666666666666666666666666666" - "66660220777777777777777777777777777777777777777777777777777777777777" - "7777", - }, - { - "6666666666666666666666666666666666666666666666666666666666666666", - "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", - "30450220666666666666666666666666666666666666666666666666666666666666" - "6666022100eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" - "eeeeee", - }, - { - "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", - "7777777777777777777777777777777777777777777777777777777777777777", - "3045022100eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" - "eeeeee02207777777777777777777777777777777777777777777777777777777777" - "777777", - }, - { - "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "3046022100eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" - "eeeeee022100ffffffffffffffffffffffffffffffffffffffffffffffffffffffff" - "ffffffff", - }, - { - "0000000000000000000000000000000000000000000000000000000000000066", - "0000000000000000000000000000000000000000000000000000000000000077", - "3006020166020177", - }, - { - "0000000000000000000000000000000000000000000000000000000000000066", - "00000000000000000000000000000000000000000000000000000000000000ee", - "3007020166020200ee", - }, - { - "00000000000000000000000000000000000000000000000000000000000000ee", - "0000000000000000000000000000000000000000000000000000000000000077", - "3007020200ee020177", - }, - { - "00000000000000000000000000000000000000000000000000000000000000ee", - "00000000000000000000000000000000000000000000000000000000000000ff", - "3008020200ee020200ff", - }, - { - "0000000000000000000000000000000000000000000000000000000000000000", - "0000000000000000000000000000000000000000000000000000000000000000", - "3006020100020100", - }, - }; - - uint8_t sig[64]; - uint8_t der[72]; - uint8_t out[72]; - for (size_t i = 0; i < (sizeof(vectors) / sizeof(*vectors)); ++i) { - size_t der_len = strlen(vectors[i].der) / 2; - memcpy(der, fromhex(vectors[i].der), der_len); - memcpy(sig, fromhex(vectors[i].r), 32); - memcpy(sig + 32, fromhex(vectors[i].s), 32); - ck_assert_int_eq(ecdsa_sig_to_der(sig, out), der_len); - ck_assert_mem_eq(out, der, der_len); - ck_assert_int_eq(ecdsa_sig_from_der(der, der_len, out), 0); - ck_assert_mem_eq(out, sig, 64); - } -} -END_TEST - -static void test_codepoints_curve(const ecdsa_curve *curve) { - int i, j; - bignum256 a; - curve_point p, p1; - for (i = 0; i < 64; i++) { - for (j = 0; j < 8; j++) { - bn_zero(&a); - a.val[(4 * i) / BN_BITS_PER_LIMB] = (uint32_t)(2 * j + 1) - << (4 * i % BN_BITS_PER_LIMB); - bn_normalize(&a); - // note that this is not a trivial test. We add 64 curve - // points in the table to get that particular curve point. - scalar_multiply(curve, &a, &p); - ck_assert_mem_eq(&p, &curve->cp[i][j], sizeof(curve_point)); - bn_zero(&p.y); // test that point_multiply curve, is not a noop - point_multiply(curve, &a, &curve->G, &p); - ck_assert_mem_eq(&p, &curve->cp[i][j], sizeof(curve_point)); - // mul 2 test. this should catch bugs - bn_lshift(&a); - bn_mod(&a, &curve->order); - p1 = curve->cp[i][j]; - point_double(curve, &p1); - // note that this is not a trivial test. We add 64 curve - // points in the table to get that particular curve point. - scalar_multiply(curve, &a, &p); - ck_assert_mem_eq(&p, &p1, sizeof(curve_point)); - bn_zero(&p.y); // test that point_multiply curve, is not a noop - point_multiply(curve, &a, &curve->G, &p); - ck_assert_mem_eq(&p, &p1, sizeof(curve_point)); - } - } -} - -START_TEST(test_codepoints_secp256k1) { test_codepoints_curve(&secp256k1); } -END_TEST -START_TEST(test_codepoints_nist256p1) { test_codepoints_curve(&nist256p1); } -END_TEST - -static void test_mult_border_cases_curve(const ecdsa_curve *curve) { - bignum256 a; - curve_point p; - curve_point expected; - bn_zero(&a); // a == 0 - scalar_multiply(curve, &a, &p); - ck_assert(point_is_infinity(&p)); - point_multiply(curve, &a, &p, &p); - ck_assert(point_is_infinity(&p)); - point_multiply(curve, &a, &curve->G, &p); - ck_assert(point_is_infinity(&p)); - - bn_addi(&a, 1); // a == 1 - scalar_multiply(curve, &a, &p); - ck_assert_mem_eq(&p, &curve->G, sizeof(curve_point)); - point_multiply(curve, &a, &curve->G, &p); - ck_assert_mem_eq(&p, &curve->G, sizeof(curve_point)); - - bn_subtract(&curve->order, &a, &a); // a == -1 - expected = curve->G; - bn_subtract(&curve->prime, &expected.y, &expected.y); - scalar_multiply(curve, &a, &p); - ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); - point_multiply(curve, &a, &curve->G, &p); - ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); - - bn_subtract(&curve->order, &a, &a); - bn_addi(&a, 1); // a == 2 - expected = curve->G; - point_add(curve, &expected, &expected); - scalar_multiply(curve, &a, &p); - ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); - point_multiply(curve, &a, &curve->G, &p); - ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); - - bn_subtract(&curve->order, &a, &a); // a == -2 - expected = curve->G; - point_add(curve, &expected, &expected); - bn_subtract(&curve->prime, &expected.y, &expected.y); - scalar_multiply(curve, &a, &p); - ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); - point_multiply(curve, &a, &curve->G, &p); - ck_assert_mem_eq(&p, &expected, sizeof(curve_point)); -} - -START_TEST(test_mult_border_cases_secp256k1) { - test_mult_border_cases_curve(&secp256k1); -} -END_TEST -START_TEST(test_mult_border_cases_nist256p1) { - test_mult_border_cases_curve(&nist256p1); -} -END_TEST - -static void test_scalar_mult_curve(const ecdsa_curve *curve) { - int i; - // get two "random" numbers - bignum256 a = curve->G.x; - bignum256 b = curve->G.y; - curve_point p1, p2, p3; - for (i = 0; i < 1000; i++) { - /* test distributivity: (a + b)G = aG + bG */ - bn_mod(&a, &curve->order); - bn_mod(&b, &curve->order); - scalar_multiply(curve, &a, &p1); - scalar_multiply(curve, &b, &p2); - bn_addmod(&a, &b, &curve->order); - bn_mod(&a, &curve->order); - scalar_multiply(curve, &a, &p3); - point_add(curve, &p1, &p2); - ck_assert_mem_eq(&p2, &p3, sizeof(curve_point)); - // new "random" numbers - a = p3.x; - b = p3.y; - } -} - -START_TEST(test_scalar_mult_secp256k1) { test_scalar_mult_curve(&secp256k1); } -END_TEST -START_TEST(test_scalar_mult_nist256p1) { test_scalar_mult_curve(&nist256p1); } -END_TEST - -static void test_point_mult_curve(const ecdsa_curve *curve) { - int i; - // get two "random" numbers and a "random" point - bignum256 a = curve->G.x; - bignum256 b = curve->G.y; - curve_point p = curve->G; - curve_point p1, p2, p3; - for (i = 0; i < 200; i++) { - /* test distributivity: (a + b)P = aP + bP */ - bn_mod(&a, &curve->order); - bn_mod(&b, &curve->order); - point_multiply(curve, &a, &p, &p1); - point_multiply(curve, &b, &p, &p2); - bn_addmod(&a, &b, &curve->order); - bn_mod(&a, &curve->order); - point_multiply(curve, &a, &p, &p3); - point_add(curve, &p1, &p2); - ck_assert_mem_eq(&p2, &p3, sizeof(curve_point)); - // new "random" numbers and a "random" point - a = p1.x; - b = p1.y; - p = p3; - } -} - -START_TEST(test_point_mult_secp256k1) { test_point_mult_curve(&secp256k1); } -END_TEST -START_TEST(test_point_mult_nist256p1) { test_point_mult_curve(&nist256p1); } -END_TEST - -static void test_scalar_point_mult_curve(const ecdsa_curve *curve) { - int i; - // get two "random" numbers - bignum256 a = curve->G.x; - bignum256 b = curve->G.y; - curve_point p1, p2; - for (i = 0; i < 200; i++) { - /* test commutativity and associativity: - * a(bG) = (ab)G = b(aG) - */ - bn_mod(&a, &curve->order); - bn_mod(&b, &curve->order); - scalar_multiply(curve, &a, &p1); - point_multiply(curve, &b, &p1, &p1); - - scalar_multiply(curve, &b, &p2); - point_multiply(curve, &a, &p2, &p2); - - ck_assert_mem_eq(&p1, &p2, sizeof(curve_point)); - - bn_multiply(&a, &b, &curve->order); - bn_mod(&b, &curve->order); - scalar_multiply(curve, &b, &p2); - - ck_assert_mem_eq(&p1, &p2, sizeof(curve_point)); - - // new "random" numbers - a = p1.x; - b = p1.y; - } -} - -START_TEST(test_scalar_point_mult_secp256k1) { - test_scalar_point_mult_curve(&secp256k1); -} -END_TEST -START_TEST(test_scalar_point_mult_nist256p1) { - test_scalar_point_mult_curve(&nist256p1); -} -END_TEST - -START_TEST(test_ed25519) { - // test vectors from - // https://github.com/torproject/tor/blob/master/src/test/ed25519_vectors.inc - static const char *vectors[] = { - "26c76712d89d906e6672dafa614c42e5cb1caac8c6568e4d2493087db51f0d3" - "6", // secret - "c2247870536a192d142d056abefca68d6193158e7c1a59c1654c954eccaff89" - "4", // public - "d23188eac3773a316d46006fa59c095060be8b1a23582a0dd99002a82a0662bd" - "246d8449e172e04c5f46ac0d1404cebe4aabd8a75a1457aa06cae41f3334f10" - "4", // selfsig - "fba7a5366b5cb98c2667a18783f5cf8f4f8d1a2ce939ad22a6e685edde85128" - "d", - "1519a3b15816a1aafab0b213892026ebf5c0dc232c58b21088d88cb90e9b940" - "d", - "3a785ac1201c97ee5f6f0d99323960d5f264c7825e61aa7cc81262f15bef75eb" - "4fa5723add9b9d45b12311b6d403eb3ac79ff8e4e631fc3cd51e4ad2185b200" - "b", - "67e3aa7a14fac8445d15e45e38a523481a69ae35513c9e4143eb1c2196729a0" - "e", - "081faa81992e360ea22c06af1aba096e7a73f1c665bc8b3e4e531c46455fd1d" - "d", - "cf431fd0416bfbd20c9d95ef9b723e2acddffb33900edc72195dea95965d52d8" - "88d30b7b8a677c0bd8ae1417b1e1a0ec6700deadd5d8b54b6689275e04a0450" - "9", - "d51385942033a76dc17f089a59e6a5a7fe80d9c526ae8ddd8c3a506b99d3d0a" - "6", - "73cfa1189a723aad7966137cbffa35140bb40d7e16eae4c40b79b5f0360dd65" - "a", - "2375380cd72d1a6c642aeddff862be8a5804b916acb72c02d9ed052c1561881a" - "a658a5af856fcd6d43113e42f698cd6687c99efeef7f2ce045824440d26c5d0" - "0", - "5c8eac469bb3f1b85bc7cd893f52dc42a9ab66f1b02b5ce6a68e9b175d3bb43" - "3", - "66c1a77104d86461b6f98f73acf3cd229c80624495d2d74d6fda1e940080a96" - "b", - "2385a472f599ca965bbe4d610e391cdeabeba9c336694b0d6249e551458280be" - "122c2441dd9746a81bbfb9cd619364bab0df37ff4ceb7aefd24469c39d3bc50" - "8", - "eda433d483059b6d1ff8b7cfbd0fe406bfb23722c8f3c8252629284573b61b8" - "6", - "d21c294db0e64cb2d8976625786ede1d9754186ae8197a64d72f68c792eecc1" - "9", - "e500cd0b8cfff35442f88008d894f3a2fa26ef7d3a0ca5714ae0d3e2d40caae5" - "8ba7cdf69dd126994dad6be536fcda846d89dd8138d1683cc144c8853dce760" - "7", - "4377c40431c30883c5fbd9bc92ae48d1ed8a47b81d13806beac5351739b5533" - "d", - "c4d58b4cf85a348ff3d410dd936fa460c4f18da962c01b1963792b9dcc8a6ea" - "6", - "d187b9e334b0050154de10bf69b3e4208a584e1a65015ec28b14bcc252cf84b8" - "baa9c94867daa60f2a82d09ba9652d41e8dde292b624afc8d2c26441b95e3c0" - "e", - "c6bbcce615839756aed2cc78b1de13884dd3618f48367a17597a16c1cd7a290" - "b", - "95126f14d86494020665face03f2d42ee2b312a85bc729903eb17522954a1c4" - "a", - "815213640a643d198bd056e02bba74e1c8d2d931643e84497adf3347eb485079" - "c9afe0afce9284cdc084946b561abbb214f1304ca11228ff82702185cf28f60" - "d", - 0, - 0, - 0, - }; - const char **ssk, **spk, **ssig; - ssk = vectors; - spk = vectors + 1; - ssig = vectors + 2; - ed25519_public_key pk; - ed25519_secret_key sk; - ed25519_signature sig; - while (*ssk && *spk && *ssig) { - memcpy(sk, fromhex(*ssk), 32); - MARK_SECRET_DATA(sk, sizeof(sk)); - - ed25519_publickey(sk, pk); - UNMARK_SECRET_DATA(pk, sizeof(pk)); - ck_assert_mem_eq(pk, fromhex(*spk), 32); - - ed25519_sign(pk, 32, sk, sig); - UNMARK_SECRET_DATA(sig, sizeof(sig)); - ck_assert_mem_eq(sig, fromhex(*ssig), 64); - - ssk += 3; - spk += 3; - ssig += 3; - - UNMARK_SECRET_DATA(sk, sizeof(sk)); - } -} -END_TEST - -// test vectors from -// https://raw.githubusercontent.com/NemProject/nem-test-vectors/master/2.test-sign.dat -START_TEST(test_ed25519_keccak) { - static const struct { - const char *private_key; - const char *public_key; - const char *signature; - size_t length; - const char *data; - } tests[] = { - { - "abf4cf55a2b3f742d7543d9cc17f50447b969e6e06f5ea9195d428ab12b7318d", - "8a558c728c21c126181e5e654b404a45b4f0137ce88177435a69978cc6bec1f4", - "d9cec0cc0e3465fab229f8e1d6db68ab9cc99a18cb0435f70deb6100948576cd5c0a" - "a1feb550bdd8693ef81eb10a556a622db1f9301986827b96716a7134230c", - 41, - "8ce03cd60514233b86789729102ea09e867fc6d964dea8c2018ef7d0a2e0e24bf7e3" - "48e917116690b9", - }, - { - "6aa6dad25d3acb3385d5643293133936cdddd7f7e11818771db1ff2f9d3f9215", - "bbc8cbb43dda3ecf70a555981a351a064493f09658fffe884c6fab2a69c845c6", - "98bca58b075d1748f1c3a7ae18f9341bc18e90d1beb8499e8a654c65d8a0b4fbd2e0" - "84661088d1e5069187a2811996ae31f59463668ef0f8cb0ac46a726e7902", - 49, - "e4a92208a6fc52282b620699191ee6fb9cf04daf48b48fd542c5e43daa9897763a19" - "9aaa4b6f10546109f47ac3564fade0", - }, - { - "8e32bc030a4c53de782ec75ba7d5e25e64a2a072a56e5170b77a4924ef3c32a9", - "72d0e65f1ede79c4af0ba7ec14204e10f0f7ea09f2bc43259cd60ea8c3a087e2", - "ef257d6e73706bb04878875c58aa385385bf439f7040ea8297f7798a0ea30c1c5eff" - "5ddc05443f801849c68e98111ae65d088e726d1d9b7eeca2eb93b677860c", - 40, - "13ed795344c4448a3b256f23665336645a853c5c44dbff6db1b9224b5303b6447fbf" - "8240a2249c55", - }, - { - "c83ce30fcb5b81a51ba58ff827ccbc0142d61c13e2ed39e78e876605da16d8d7", - "3ec8923f9ea5ea14f8aaa7e7c2784653ed8c7de44e352ef9fc1dee81fc3fa1a3", - "0c684e71b35fed4d92b222fc60561db34e0d8afe44bdd958aaf4ee965911bef59912" - "36f3e1bced59fc44030693bcac37f34d29e5ae946669dc326e706e81b804", - 49, - "a2704638434e9f7340f22d08019c4c8e3dbee0df8dd4454a1d70844de11694f4c8ca" - "67fdcb08fed0cec9abb2112b5e5f89", - }, - { - "2da2a0aae0f37235957b51d15843edde348a559692d8fa87b94848459899fc27", - "d73d0b14a9754eec825fcb25ef1cfa9ae3b1370074eda53fc64c22334a26c254", - "6f17f7b21ef9d6907a7ab104559f77d5a2532b557d95edffd6d88c073d87ac00fc83" - "8fc0d05282a0280368092a4bd67e95c20f3e14580be28d8b351968c65e03", - 40, - "d2488e854dbcdfdb2c9d16c8c0b2fdbc0abb6bac991bfe2b14d359a6bc99d66c00fd" - "60d731ae06d0", - }, - { - "0c066261fb1b18ebf2a9bcdeda81eb47d5a3745438b3d0b9d19b75885ad0a154", - "2e5773f0e725024bc0359ce93a44e15d6507e7b160b6c592200385fee4a269cf", - "13b5d2dd1b04f62cc2ec1544fed256423684f2dbca4538ceddda1d15c59dc7196c87" - "840ea303ea30f4f6914a6ec9167841980c1d717f47fd641225068de88507", - 41, - "f15cb706e29fcfbcb324e38cbac62bb355deddb845c142e970f0c029ea4d05e59fd6" - "adf85573cf1775", - }, - { - "ef3d8e22a592f04c3a31aa736e10901757a821d053f1a49a525b4ec91eacdee3", - "72a2b4910a502b30e13a96aba643c59c79328c1ba1462be6f254e817ef157fee", - "95f2437a0210d2d2f125a3c377ed666c0d596cd104185e70204924a182a11a6eb3bd" - "ba4395bbfc3f4e827d38805752657ee52d1ce0f17e70f59bfd4999282509", - 50, - "6c3e4387345740b8d62cf0c9dec48f98c292539431b2b54020d8072d9cb55f0197f7" - "d99ff066afcf9e41ea8b7aea78eb082d", - }, - { - "f7fb79743e9ba957d2a4f1bd95ceb1299552abecaf758bf840d2dc2c09f3e3cb", - "8b7d7531280f76a8abac8293d87508e3953894087112ae01b6ad32485d4e9b67", - "c868ecf31cee783fe8799ac7e6a662431c822967351d8b79687f4ddf608f79a080c4" - "ff9eed4fdee8c99fe1be905f734cae2a172f1cfdb00771625c0695a5260e", - 42, - "55d8e60c307ee533b1af9ff677a2de40a6eace722bcc9eb5d79907b420e533bc06db" - "674dafbd9f43d672", - }, - { - "8cc9a2469a77fad18b44b871b2b6932cd354641d2d1e84403f746c4fff829791", - "aed5da202d4983dac560faf6704dc76ac111616318570e244043e82ed1bbcd2b", - "aee9616db4135150818eaffa3e4503c2d7e9e834847a4c7d0a8856e952761d361a65" - "7104d36950c9b75770ded00d56a96e06f383fa2406bc935dcf51f272300e", - 42, - "d9b8be2f71b83261304e333d6e35563dc3c36c2eb5a23e1461b6e95aa7c6f381f9c3" - "bd39deaa1b6df2f9", - }, - { - "a247abbef0c1affbf021d1aff128888550532fc0edd77bc39f6ef5312317ec47", - "98ededbad1e5ad7a0d5a0cf4fcd7a794eb5c6900a65e7e921884a636f19b131d", - "f8cc02933851432f0c5df0b70f2067f740ccb72de7d6fa1e9a9b0d6de1402b9c6c52" - "5fd848e45aaaac1423b52880ec3474a2f64b38db6fc8e008d95a310e6e0c", - 47, - "4a5f07eb713932532fc3132c96efdc45862fe7a954c1d2ae4640afdf4728fb58c65e" - "8a4ebfe0d53d5797d5146442b9", - }, - { - "163d69079ddad1f16695c47d81c3b72f869b2fdd50e6e47113db6c85051a6ede", - "93fe602642ee5773f4aaf6a3bc21e98e354035225353f419e78e43c3ec36c88a", - "da747fa2cb47aae1effc1e4cfde0e39fa79937948592a712a7665bf948b8311e7f3f" - "80f966301679520d5c2afa3eadd60e061f0d264887500d8d03a17e10fd02", - 41, - "65fe5c1a0214a59644892e5ac4216f09fbb4e191b89bfb63d6540177d25ef9e37148" - "50b8453bd6b2b6", - }, - { - "7b061bf90eb760971b9ec66a96fd6609635ca4b531f33e3c126b9ae6fdb3d491", - "cb392ebb6912df4111efeeb1278160daf9da396e9291b83979a5ac479f7276d2", - "f6eebe86f7ea672e0707ee518e1798d6fbd118c11b2aa30be07d10e3882e3721f203" - "0f9f044b77c3a7a9a2f1feba7e7ce75d1f7f3807a96a764fded35d341d02", - 45, - "a17f5ce39b9ba7b7cf1147e515d6aa84b22fd0e2d8323a91367198fc6c3aff04ebb2" - "1fc2bdbe7bc0364e8040a9", - }, - { - "c9f8ccbf761cec00ab236c52651e76b5f46d90f8936d44d40561ed5c277104de", - "a3192641e343b669ffd43677c2e5cd4efaed174e876141f1d773bd6cfe30d875", - "d44f884ec9eae2e99e74194b5acc769b7aa369aaad359e92ba6ff0fe629af2a9a715" - "6c19b720e7de8c7f03c039563f160948073cab6f99b26a56a8bb1023ba08", - 47, - "3d7e33b0ecead8269966e9dcd192b73eb8a12573fc8a5fdfbe5753541026ef2e49f5" - "280cba9bc2515a049b3a1c1b49", - }, - { - "ebfa409ac6f987df476858dd35310879bf564eeb62984a52115d2e6c24590124", - "7bb1601fe7215f3f4da9c8ab5e804dc58f57ba41b03223f57ec80d9c9a2dd0e1", - "f3e7c1abfcc9f35556cb1e4c5a2b34445177ac188312d9148f1d1d8467ea8411fa3c" - "da031d023034e45bbe407ef7d1b937bfb098266138857d35cb4efe407306", - 52, - "0c37564f718eda683aa6f3e9ab2487620b1a8b5c8f20adb3b2d7550af0d635371e53" - "1f27cebe76a2abcc96de0875bdae987a45ac", - }, - { - "f993f61902b7da332f2bb001baa7accaf764d824eb0cd073315f7ec43158b8fb", - "55fc8e0da1b454cab6ddefb235311db2b01504bf9ac3f71c7e3f3d0d1f09f80b", - "178bd147673c0ca330e45da63cbd1f1811906bd5284bb44e4bb00f7d7163d1f39697" - "5610b6f71c1ae4686466fad4c5e7bb9685099e21ca4f1a45bb3fcf56ae0c", - 42, - "b7dd613bc9c364d9eeb9a52636d72bc881dfc81a836b6537bbb928bff5b738313589" - "47ea9edea1570550", - }, - { - "05188c09c31b4bb63f0d49b47ccc1654c2aba907b8c6c0a82ee403e950169167", - "e096d808dfabe8e44eb74950199dadcd586f9de6b141a0ce85ab94b3d97866eb", - "669491c8eb7cedbbc0252f3eafb048b39a2a37f60ac87837777c72c879ac8b726c39" - "e10060750c2f539102999b71889746111bc5f71ec8c158cc81cf566aef03", - 44, - "bb8e22469d1c7f1d5418563e8781f69eccb56678bd36d8919f358c2778562ff6b50d" - "e916c12d44f1a778a7f3", - }, - { - "eabe57e1a916ebbffa4ba7abc7f23e83d4deb1338816cc1784d7495d92e98d0b", - "3aad275642f48a46ed1032f3de9f4053e0fd35cf217e065d2e4579c3683932f7", - "b2e9dac2c83942ca374f29c8eff5a30c377c3db3c1c645e593e524d17484e7705b11" - "f79573e2d63495fc3ce3bf216a209f0cb7bea477ae0f8bd297f193af8805", - 44, - "3f2c2d6682ee597f2a92d7e560ac53d5623550311a4939d68adfb904045ed8d215a9" - "fdb757a2368ea4d89f5f", - }, - { - "fef7b893b4b517fab68ca12d36b603bc00826bf3c9b31a05149642ae10bb3f55", - "b3fb891868708dfa5da5b9b5234058767ab42c117f12c3228c02a1976d1c0f83", - "6243e289314b7c7587802909a9be6173a916b36f9de1e164954dfe5d1ebd57c869a7" - "9552d770e13b51855502be6b15e7be42a3675298a81284df58e609b06503", - 47, - "38c69f884045cdbeebe4478fdbd1ccc6cf00a08d8a3120c74e7167d3a2e26a67a043" - "b8e5bd198f7b0ce0358cef7cf9", - }, - { - "16228bec9b724300a37e88e535fc1c58548d34d7148b57c226f2b3af974c1822", - "3c92423a8360c9a5d9a093730d72831bec4601dcadfe84de19fc8c8f91fc3d4b", - "6aebfa9a4294ec888d54bcb517fcb6821e4c16d2708a2afe701f431a28149ff4f139" - "f9d16a52a63f1f91baf4c8dea37710c73f25c263a8035a39cc118ad0280f", - 44, - "a3d7b122cd4431b396b20d8cc46cc73ed4a5253a44a76fc83db62cdc845a2bf7081d" - "069a857955a161cccf84", - }, - { - "2dc3f5f0a0bc32c6632534e1e8f27e59cbe0bf7617d31aff98098e974c828be7", - "b998a416edc28ded988dcacb1caf2bd96c87354b0d1eeccb6980e54a3104f21f", - "76a2ddfc4bea48c47e0c82bcbfee28a37c61ec626af39a468e643e0ef9f6533056a5" - "a0b44e64d614ba3c641a40e5b003a99463445ae2c3c8e1e9882092d74b07", - 42, - "bdae276d738b9758ea3d322b54fd12fe82b767e8d817d8ef3d41f78705748e28d15e" - "9c506962a1b85901", - }, - }; - - ed25519_secret_key private_key; - ed25519_public_key public_key; - ed25519_signature signature; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - nem_private_key(tests[i].private_key, private_key); - MARK_SECRET_DATA(private_key, sizeof(private_key)); - - ed25519_publickey_keccak(private_key, public_key); - UNMARK_SECRET_DATA(public_key, sizeof(public_key)); - ck_assert_mem_eq(public_key, fromhex(tests[i].public_key), 32); - - ed25519_sign_keccak(fromhex(tests[i].data), tests[i].length, private_key, - signature); - UNMARK_SECRET_DATA(signature, sizeof(signature)); - ck_assert_mem_eq(signature, fromhex(tests[i].signature), 64); - - UNMARK_SECRET_DATA(private_key, sizeof(private_key)); - } -} -END_TEST - -START_TEST(test_ed25519_cosi) { - enum { MAXN = 10 }; - ed25519_secret_key keys[MAXN]; - ed25519_public_key pubkeys[MAXN]; - ed25519_secret_key nonces[MAXN]; - ed25519_public_key Rs[MAXN]; - ed25519_cosi_signature sigs[MAXN]; - uint8_t msg[32]; - rfc6979_state rng; - int res; - - init_rfc6979( - fromhex( - "26c76712d89d906e6672dafa614c42e5cb1caac8c6568e4d2493087db51f0d36"), - fromhex( - "26659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), - NULL, &rng); - - for (int N = 1; N < 11; N++) { - ed25519_public_key pk; - ed25519_public_key R; - ed25519_signature sig; - /* phase 0: create priv/pubkeys and combine pubkeys */ - for (int j = 0; j < N; j++) { - generate_rfc6979(keys[j], &rng); - ed25519_publickey(keys[j], pubkeys[j]); - } - res = ed25519_cosi_combine_publickeys(pk, pubkeys, N); - ck_assert_int_eq(res, 0); - - generate_rfc6979(msg, &rng); - - /* phase 1: create nonces, commitments (R values) and combine commitments */ - for (int j = 0; j < N; j++) { - ed25519_cosi_commit(nonces[j], Rs[j]); - } - res = ed25519_cosi_combine_publickeys(R, Rs, N); - ck_assert_int_eq(res, 0); - - MARK_SECRET_DATA(keys, sizeof(keys)); - /* phase 2: sign and combine signatures */ - for (int j = 0; j < N; j++) { - res = - ed25519_cosi_sign(msg, sizeof(msg), keys[j], nonces[j], R, pk, - sigs[j]); - ck_assert_int_eq(res, 0); - } - UNMARK_SECRET_DATA(sigs, sizeof(sigs)); - - ed25519_cosi_combine_signatures(sig, R, sigs, N); - - /* check signature */ - res = ed25519_sign_open(msg, sizeof(msg), pk, sig); - ck_assert_int_eq(res, 0); - - UNMARK_SECRET_DATA(keys, sizeof(keys)); - } -} -END_TEST - -START_TEST(test_ed25519_modl_add) { - char tests[][3][65] = { - { - "0000000000000000000000000000000000000000000000000000000000000000", - "0000000000000000000000000000000000000000000000000000000000000000", - "0000000000000000000000000000000000000000000000000000000000000000", - }, - - {"eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a", - "0000000000000000000000000000000000000000000000000000000000000000", - "eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a"}, - - {"0000000000000000000000000000000000000000000000000000000000000000", - "eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a", - "eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a"}, - - {"0100000000000000000000000000000000000000000000000000000000000000", - "0200000000000000000000000000000000000000000000000000000000000000", - "0300000000000000000000000000000000000000000000000000000000000000"}, - - {"e3d3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", - "0a00000000000000000000000000000000000000000000000000000000000000", - "0000000000000000000000000000000000000000000000000000000000000000"}, - - {"f7bb3bf42b3e58e2edd06f173fc7bfbc7aaf657217946b75648447101136aa08", - "3c16b013109cc27ff39805be2abe04ba4cd6a8526a1d3023047693e950936c06", - "33d2eb073cda1a62e16975d56985c476c7850ec581b19b9868fadaf961c9160f"}, - }; - - unsigned char buff[32]; - bignum256modm a = {0}, b = {0}, c = {0}; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(a, fromhex(tests[i][0]), 32); - expand256_modm(b, fromhex(tests[i][1]), 32); - add256_modm(c, a, b); - contract256_modm(buff, c); - ck_assert_mem_eq(buff, fromhex(tests[i][2]), 32); - } -} -END_TEST - -START_TEST(test_ed25519_modl_neg) { - char tests[][2][65] = { - {"05d0f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", - "e803000000000000000000000000000000000000000000000000000000000000"}, - - {"4d4df45c1a631258d69cf7a2def9de1400000000000000000000000000000010", - "a086010000000000000000000000000000000000000000000000000000000000"}, - - {"25958944a1b7d4073975ca48996a1d740d0ed98ceec366760c5358da681e9608", - "c83e6c1879ab3d509d272d5a458fc1a0f2f12673113c9989f3aca72597e16907"}, - - {"0100000000000000000000000000000000000000000000000000000000000000", - "ecd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010"}, - - {"ecd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", - "0100000000000000000000000000000000000000000000000000000000000000"}, - - {"0000000000000000000000000000000000000000000000000000000000000000", - "0000000000000000000000000000000000000000000000000000000000000000"}, - }; - - unsigned char buff[32]; - bignum256modm a = {0}, b = {0}; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(a, fromhex(tests[i][0]), 32); - neg256_modm(b, a); - contract256_modm((unsigned char *)buff, b); - ck_assert_mem_eq(buff, fromhex(tests[i][1]), 32); - } -} -END_TEST - -START_TEST(test_ed25519_modl_sub) { - char tests[][3][65] = { - { - "0000000000000000000000000000000000000000000000000000000000000000", - "0000000000000000000000000000000000000000000000000000000000000000", - "0000000000000000000000000000000000000000000000000000000000000000", - }, - - {"eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a", - "53732f60e51ee3a48d21d2d526548c0dadbb79a185678fd7710613d0e76aad0c", - "8859d1d1deee0767a4ff1b72a3e0d0327573c69bbff5fc07cfa61414e6ef3b0e"}, - - {"9d91e26dbe7a14fdca9f5b20d13e828dc8c1ffe03fe90136a6bba507436ce500", - "9ca406705ccce65eb8cbf63706d3df09fcc67216c0dc3990270731aacbb2e607", - "eec0d15a7c1140f6e8705c8ba9658198ccfa8cca7f0cc8a57eb4745d77b9fe08"}, - - {"eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a", - "0000000000000000000000000000000000000000000000000000000000000000", - "eef80ad5a9aad8b35b84f6a4eb3a7e2b222f403d455d8cdf40ad27e4cd5ae90a"}, - - {"0000000000000000000000000000000000000000000000000000000000000000", - "39897fbebf137a34572b014b0638ac0186d17874e3cc142ebdfe24327f5b8509", - "b44a769e5a4f98237f71f657d8c132137a2e878b1c33ebd14201dbcd80a47a06"}, - - {"0200000000000000000000000000000000000000000000000000000000000000", - "e3d3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", - "0c00000000000000000000000000000000000000000000000000000000000000"}, - - {"e3d3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", - "0800000000000000000000000000000000000000000000000000000000000000", - "dbd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010"}, - - {"ecd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", - "0000000000000000000000000000000000000000000000000000000000000000", - "ecd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010"}, - - {"0000000000000000000000000000000000000000000000000000000000000000", - "ecd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010", - "0100000000000000000000000000000000000000000000000000000000000000"}, - - {"0000000000000000000000000000000000000000000000000000000000000000", - "0000000000000000000000000000000000000000000000000000000000000010", - "edd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000000"}, - - {"0000000000000000000000000000000000000000000000000000000000000000", - "ffffff3f00000000000000000000000000000000000000000000000000000010", - "eed3f51c1a631258d69cf7a2def9de1400000000000000000000000000000000"}, - - {"0000000000000000000000000000000000000000000000000000000000000000", - "edd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000000", - "0000000000000000000000000000000000000000000000000000000000000010"}, - - {"0000000000000000000000000000000000000000000000000000000000000000", - "e75f947f11d49d25a137fac8757538a980dec23811235cf63c48ee6bc6e4ed03", - "067461dd088f74323565fdd96884a66b7f213dc7eedca309c3b71194391b120c"}, - - {"0000000000000000000000000000000000000000000000000000000000000000", - "ecd3f55c1a631258d69cf7a2def9de140000000000000000000000000000ff0f", - "0100000000000000000000000000000000000000000000000000000000000100"}, - - {"0000000000000000000000000000000000000000000000000000000000000000", - "edd3f55c1a631258d69cf7a2def9de140000000000000000000004000000ff0f", - "0000000000000000000000000000000000000000000000000000fcffffff0000"}, - - {"0000000000000000000000000000000000000000000000000000000000000000", - "edd3f55c1a631258d69cf7a2def9de150000c0ffffffffffffffffffffffff0f", - "000000000000000000000000000000ffffff3f00000000000000000000000000"}, - - {"0000000000000000000000000000000000000000000000000000000000000000", - "edd3f55c1a631258d69cf7a2def9de1200000000000000000000000000000110", - "edd3f55c1a631258d69cf7a2def9de160000000000000000000000000000ff0f"}, - - {"0000000000000000000000000000000000000000000000000000000000000000", - "edd3f55c1a631258d69cf7a2def9de1300000000000000000000000000000010", - "0000000000000000000000000000000100000000000000000000000000000000"}, - }; - - unsigned char buff[32]; - bignum256modm a = {0}, b = {0}, c = {0}; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(a, fromhex(tests[i][0]), 32); - expand256_modm(b, fromhex(tests[i][1]), 32); - sub256_modm(c, a, b); - contract256_modm(buff, c); - ck_assert_mem_eq(buff, fromhex(tests[i][2]), 32); - } -} -END_TEST - -START_TEST(test_ge25519_double_scalarmult_vartime2) { - char tests[][5][65] = { - {"c537208ed4985e66e9f7a35c9a69448a732ba93960bbbd2823604f7ae9e3ed08", - "365233e5af17c8888d5ce508787464f4642e91a6212b1b104e6c3769535601b1", - "a84f871580176708b4ac21843cb197ad96e8456034442b50859c83c5807b9901", - "f022360d1bce903fa3ac58ae42f997328b31f477b8d576a9f6d26fc1d08f14ea", - "bf25da82c6b210948b823ae48422a2dcd205d3c94842e68ac27e5cbeaa704ebc"}, - {"4abfabc0dda33588a98127ef3bfe724fed286395fe15932e898b5621661ea102", - "e5fd79d03f5df8edfc8def663dcb96bba6cadf857f2ae6f6f51f52f8d14079b7", - "4754c286b23e3c1b50054fe3937ebdc4ec01b28da5d05fb6111798b42fc5bf06", - "b7e7f9464b98de5bfcf6b02c1b7053cc359df407ad59d943523c6d2ee773b2f6", - "6d7d5f729bfa4882dbff8e477cd2b4c354ba347f10e7b178a24f3f16a4e0fec6"}, - {"19f2af4d04cb8181f1fe0d01fe9bb9ecc476c67ceb4a9830dae1bc7fe5fe3b04", - "d3c462f4f30991220387a1fbbd1ba1dc45ce058c70a8fb1475071e7b4f0fc463", - "577790e025c1fd2014db44a8d613c4e2ab1f248a4a6d14b5d39cbbafd7b20f06", - "1376c6837f131f6cd1a45b1056297d2314aa0ac5f7d581d2d878261eb3259b4d", - "ce790760ada87dd819b59e4f6765d836d346567ec34f02bbcfcae0585c1d758f"}, - {"cf209db9e7ee85f1e648924ec97edd86b56a833b25707519d4fbe64fd50e150a", - "804f0806087dc665a26230ed5fd44c062980ee182a6bd7dbdb33df018c983778", - "30d3c448cb08935309753b3051366f52328ca1d9a0b63c72b989edee0da32b0e", - "98e3c973a7e85b5eab8111521c66ca584bed5597f060ab0c6b5cdeece502ac48", - "2646276e1305396a1b2473690066011a39789570a09e10ce1a013c8f32cd5bea"}, - {"b0a0ffeea67b656c4c585ba58ff528a6f45d2f915db98e4a14a8ff17f27fc105", - "4fabe16274f6af526ee053028485db6acd13804e02dcdddccc4183a319ab9e1c", - "1e140bb08a936ac6b7437644ca0769f3c165c7aa5501d49f064a0346179b4008", - "68fc1be64fb68761542a655b8dbebf50980f1fbc1845528df8d8a06bf89a1495", - "7dab86994b47014efe38493fc2b62ffcead806da6e0d73c992db8cb5618a19dc"}, - {"0fee422c2294b06ca83bc3704384dffc580e7ff5921881e51a755e5f9b80af03", - "4359a663ead3f7ffc3a0ead5c3c2bde348017e7bfa620f21759c32e469a16dfe", - "532066e3eec29334fffc37b17178dfbac3bee15f7845f01449ddbaf5e57a7b0c", - "32e46c2fb99402837631c8175db31cdd334c145f922be9070d62e6d9c493c3ea", - "8c7b7d2d61cdb648960434d894787426a76d16dd46949c7aa4b85dcf1054b4d5"}, - {"3a712d5b7ceb5257dcf6e6bb06548de6ef3deba5d456cd91fc305a12b46b5d01", - "5e7da62e3ec42cf3e554639dd4d2006754ee6839b720cadba94a26b73b1665ee", - "2a518ecab17a2d9dde219c775bcf4f2306b190bef2dea34fb65b8e4dccc13405", - "3b5d66a4dfb068923b3bc21cc8b40b59e12f845e0b85a86d394db0fa310bf185", - "2ec17f1cc0be093e9cdb741a991c0f417230dea275cd7babdad35e949e250521"}, - {"5f815f2d65cef584c5e5d48b2d3d3e4cae310d70b328f88af6e9f63c52b4c90d", - "8a539a8c6b2339922b31cf4bc064f1fedeb3912fd89585d79dfcff2a60aee295", - "385f7132b72db04146b9e472736b32adfca29556b4775a743c18e2bfab939007", - "884aaf96d625968ddb2582922a87abca131272884c47f6b86890ebccf0a79d5b", - "a7afdaf24fe8472d8b89e95c3ce4a40bdf700af7cedee44ed3aa5ccca09839bd"}, - {"a043340d072df16a8ab5135f8c1d601bff14c5aba01b9212b886ad71fe164506", - "52f6de5fa0fae32d4020a54d395319509d6b92092a0bf849fb34e73f8e71fc99", - "37d7472d360164da29e6dcb8f9796976022571c5df4ddf7e30e9a579ba13d509", - "8c369e3fd5b1112e4437b1f09e987acca4966f2f8c5227eb15ace240a2c64cc7", - "fc795fe7baff5c3ac98366e6882f25874ea2b0a649d16f139e5c54ea47042a1e"}, - {"97a3268db03fa184c8cba020bf216fc789292fa9615a28962385b86870ffd70f", - "a76c215587022bb9252ece4c5afeb0e65b820834cd41ac76e6c062d3eea75dc6", - "8310271017154cbddf7005e24eb9a9a86777b3f42fa5e35095eafaac4eb24802", - "b822665c2406083c851ecaa91ea67aa740c057e7679b5755cee60a6c63f17fd6", - "f83e2444527056eba595d49bde40b2e8da76d2c145f203331d26e94560993fbc"}, - {"edaad13efad39f26298e86ba8d06a46e59122232c9529bd22f2f656595421e00", - "f38e56a79f5159eb3b581dea537ec12c9c6fac381b2cf6073e27fc621197cb62", - "1eea79485954b5958d9d5478f86133af1088806d923535d483b115ab23099a0f", - "b32c5e57d57db7a349f4ab845f12a5045c52b4a7a5bce7fd54a1a255b0118185", - "3bfb42b4ffd2c6cfc8cce9e4187dc6fbcaecd9d44a4ca1d2b68b97410bb25b81"}, - {"b15eaebe0fc83cb11d755a6f067b710204d4a59101078d8286454b652879080a", - "4667a2e61d9df1690f5c33c4168e480f7e26d2f0998168ebdc0a39712946f741", - "125379da1a88bfdf5b928f8795d3ea5415ef8c3d9106eb16934c3842873fd707", - "8727a692a25e38b1afa98e3dd5bf88815dec6d9810c1fd8a31b56b3de8630f1e", - "540883dde400b909e9955a276c20e13d99252ebe542750b8bfbbe5c3b87c51e3"}, - {"e42bdd4af3121bea644a90a76b2007615621ee5b842b9a74c4334ac309478706", - "6dc4ab715d3bb975ebfd0f08e2b6f3f39922d0121ae518a8f8d2952ea2fe0b5d", - "0285059b0095c97f4a50d43c7726c64c2830bf2b55dfa934ebba7ad71064dc07", - "f738c0a3cee31fd8f438f282aa6c823fccfa49cf7b5c86fbf9d56bf0394b6d8d", - "a1bd106841e55010decd95a170a1d0dd11780fd00759819e024b15ea3a83b4be"}, - {"5077c30fd08795dbdc7a230c050ca07e316fa3b040fd0dac45907036ab25dd0e", - "96f0897f000e49e2439a9166cab40ebc125a31b82851f0541516c19683e7bfaf", - "2b67d79a2efdc6451508e7f3c97c4a61b135bb839c02338bb444ef8208dd970b", - "7ef4cd7cdc29c2b88ccff49898b5d0b7be5993f93c5772476feec9dc57d7b6e3", - "62449b901b25760c964704b28efc184fbd5947e83851ebaf3bbfeb6f742f679f"}, - {"a4b3ce6928fe8f77d13e65ae255eee8310ab0d75bca47028b4570f0511a66006", - "4e9da8d77ee337e3bcce3730ccfff2121728641c7bb4fdeb2155890f998af09a", - "ff01a5075569d0f6afee45da065c72f5841f46ce772917ef75eb4d230473580f", - "36ca32da8a10f4083f5a60ee21868d9d448548d49c56f19cbe6005005e34f816", - "99df362a3b762cc1cbb70bc5ddff3c8614ed306037013102e387ef32e7f2494f"}, - {"074aa76351dceb752aa09887d9aca932d5821f58eedb4988fd64d8548e3f2c09", - "588b4552f3b98b2f77aee2ef8cc72f88acd424c4373b3e3626393ed2ea24cbda", - "f2d9175633f2e3c661b01172b4b4176850cd5b3098ffb0f927e0a5e19c1c8a02", - "a6c34868736b2517fd46f57a4e30805ffd475e44a8b1413078f43d9cb3d6edd6", - "46e1e7d7b1e939dd5c07c8363af01f4f9dae7c3d10f237ff9776ddc4a1903771"}, - {"ae1c8abd5a542208ee0aa93ffbf0b8e5a957edc4854fe2b48153c5c85bbf3d08", - "5e084b9541a70bd5bef400be6525c5a806a5b7fb12de38b07dcd35a22c57edbe", - "d95f179a215fb322d81720bf3aecde78d6d676d6f941455d0e0920f1e3619707", - "c3e5d43221824de51d8f95705de69c80a2440c0483ca88549d639aee15390429", - "df9fea42d3b5ac243244abb4ca4948a69493becddc5d5906f9a4e4c5645b0eab"}, - {"2f1c5adedb7341dc7638bafacc6024bd48255197ea2347fc05714b9341dd4403", - "47f55263001542f796c928988f641f59d0cd43294fc8d8616b184bfe9dddf368", - "aa5e884e782ab116151c609680c37b1a49b52f23bce5e2ebf28dd8532510d20b", - "ef2d6d97ad1a18edfce6450c1e70295b2c7ed2bc749ea8b438a523eae078d1f3", - "2396a355c6ae8e2ac24da8f55a674c96fc4cc69b38678b2bd8eb91b96f462bca"}, - {"0242e14105ced74e91cf4d4dcd22a9c09279018901d2fb8319eb54c2a1c4900a", - "fcb62a6c520d31fa46efeb4a1000330653b3402f575c2ddc0c688f527e7b97be", - "73a7e2e0602e5345f040dedc4db67f6d8e37c5fca3bbb124fa43963d76dbbb08", - "152bf4a3305c656f77e292b1256cc470da4d3f6efc3667199db4316d7f431174", - "c21ba2080013dfb225e06378d9ac27df623df552526cfddbf9e71bb1d4705dd9"}, - {"07fab4fc7b02fbcf868ffb0326cf60425fef2af1fbad83a8926cc62c2b5dff05", - "29ff12c5e052eb5829e8334e0e082c5edde1f293d2b4ed499a79bcca20e48010", - "97afb3dd9167877b432a23503aad1ab39188b9be07cc124ceb3fbdbd8d8b890a", - "ed121240a2f4591eeedbfd880305ccd17e522673900b03279fb66e73583514ae", - "b27f209e88ce5701766565e231e8123adb1df9c9f1dc461920acbc2b38d9f6d7"}, - }; - - unsigned char buff[32]; - bignum256modm a = {0}, b = {0}; - ge25519 A, B, R; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(a, fromhex(tests[i][0]), 32); - expand256_modm(b, fromhex(tests[i][2]), 32); - ge25519_unpack_negative_vartime(&A, fromhex(tests[i][1])); - curve25519_neg(A.x, A.x); - curve25519_neg(A.t, A.t); - ge25519_unpack_negative_vartime(&B, fromhex(tests[i][3])); - curve25519_neg(B.x, B.x); - curve25519_neg(B.t, B.t); - ge25519_double_scalarmult_vartime2(&R, &A, a, &B, b); - ge25519_pack(buff, &R); - ck_assert_mem_eq(buff, fromhex(tests[i][4]), 32); - } -} -END_TEST - -static void test_bip32_ecdh_init_node(HDNode *node, const char *seed_str, - const char *curve_name) { - hdnode_from_seed((const uint8_t *)seed_str, strlen(seed_str), curve_name, - node); - hdnode_fill_public_key(node); - if (node->public_key[0] == 1) { - node->public_key[0] = 0x40; // Curve25519 public keys start with 0x40 byte - } -} - -static void test_bip32_ecdh(const char *curve_name, int expected_key_size, - const uint8_t *expected_key) { - int res, key_size; - HDNode alice, bob; - uint8_t session_key1[expected_key_size], session_key2[expected_key_size]; - - test_bip32_ecdh_init_node(&alice, "Alice", curve_name); - test_bip32_ecdh_init_node(&bob, "Bob", curve_name); - - // Generate shared key from Alice's secret key and Bob's public key - res = hdnode_get_shared_key(&alice, bob.public_key, session_key1, &key_size); - ck_assert_int_eq(res, 0); - ck_assert_int_eq(key_size, expected_key_size); - ck_assert_mem_eq(session_key1, expected_key, key_size); - - // Generate shared key from Bob's secret key and Alice's public key - res = hdnode_get_shared_key(&bob, alice.public_key, session_key2, &key_size); - ck_assert_int_eq(res, 0); - ck_assert_int_eq(key_size, expected_key_size); - ck_assert_mem_eq(session_key2, expected_key, key_size); -} - -START_TEST(test_bip32_ecdh_nist256p1) { - test_bip32_ecdh( - NIST256P1_NAME, 65, - fromhex( - "044aa56f917323f071148cd29aa423f6bee96e7fe87f914d0b91a0f95388c6631646" - "ea92e882773d7b0b1bec356b842c8559a1377673d3965fb931c8fe51e64873")); -} -END_TEST - -START_TEST(test_bip32_ecdh_curve25519) { - test_bip32_ecdh(CURVE25519_NAME, 33, - fromhex("04f34e35516325bb0d4a58507096c444a05ba13524ccf66910f1" - "1ce96c62224169")); -} -END_TEST - -START_TEST(test_bip32_ecdh_errors) { - HDNode node; - const uint8_t peer_public_key[65] = {0}; // invalid public key - uint8_t session_key[65]; - int res, key_size = 0; - - test_bip32_ecdh_init_node(&node, "Seed", ED25519_NAME); - res = hdnode_get_shared_key(&node, peer_public_key, session_key, &key_size); - ck_assert_int_eq(res, 1); - ck_assert_int_eq(key_size, 0); - - test_bip32_ecdh_init_node(&node, "Seed", CURVE25519_NAME); - res = hdnode_get_shared_key(&node, peer_public_key, session_key, &key_size); - ck_assert_int_eq(res, 1); - ck_assert_int_eq(key_size, 0); - - test_bip32_ecdh_init_node(&node, "Seed", NIST256P1_NAME); - res = hdnode_get_shared_key(&node, peer_public_key, session_key, &key_size); - ck_assert_int_eq(res, 1); - ck_assert_int_eq(key_size, 0); -} -END_TEST - -START_TEST(test_output_script) { - static const char *vectors[] = { - "76A914010966776006953D5567439E5E39F86A0D273BEE88AC", - "16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM", - "A914010966776006953D5567439E5E39F86A0D273BEE87", - "31nVrspaydBz8aMpxH9WkS2DuhgqS1fCuG", - "0014010966776006953D5567439E5E39F86A0D273BEE", - "p2xtZoXeX5X8BP8JfFhQK2nD3emtjch7UeFm", - "00200102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20", - "7XhPD7te3C6CVKnJWUhrTJbFTwudhHqfrjpS59AS6sMzL4RYFiCNg", - 0, - 0, - }; - const char **scr, **adr; - scr = vectors; - adr = vectors + 1; - char address[60]; - while (*scr && *adr) { - int r = - script_output_to_address(fromhex(*scr), strlen(*scr) / 2, address, 60); - ck_assert_uint_eq((size_t)r, strlen(*adr) + 1); - ck_assert_str_eq(address, *adr); - scr += 2; - adr += 2; - } -} -END_TEST - -START_TEST(test_ethereum_pubkeyhash) { - uint8_t pubkeyhash[20]; - int res; - HDNode node; - - // init m - hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, - SECP256K1_NAME, &node); - - // [Chain m] - res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, - fromhex("056db290f8ba3250ca64a45d16284d04bc6f5fbf"), 20); - - // [Chain m/0'] - hdnode_private_ckd_prime(&node, 0); - res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, - fromhex("bf6e48966d0dcf553b53e7b56cb2e0e72dca9e19"), 20); - - // [Chain m/0'/1] - hdnode_private_ckd(&node, 1); - res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, - fromhex("29379f45f515c494483298225d1b347f73d1babf"), 20); - - // [Chain m/0'/1/2'] - hdnode_private_ckd_prime(&node, 2); - res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, - fromhex("d8e85fbbb4b3b3c71c4e63a5580d0c12fb4d2f71"), 20); - - // [Chain m/0'/1/2'/2] - hdnode_private_ckd(&node, 2); - res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, - fromhex("1d3462d2319ac0bfc1a52e177a9d372492752130"), 20); - - // [Chain m/0'/1/2'/2/1000000000] - hdnode_private_ckd(&node, 1000000000); - res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, - fromhex("73659c60270d326c06ac204f1a9c63f889a3d14b"), 20); - - // init m - hdnode_from_seed( - fromhex( - "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c" - "999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), - 64, SECP256K1_NAME, &node); - - // [Chain m] - res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, - fromhex("6dd2a6f3b05fd15d901fbeec61b87a34bdcfb843"), 20); - - // [Chain m/0] - hdnode_private_ckd(&node, 0); - res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, - fromhex("abbcd4471a0b6e76a2f6fdc44008fe53831e208e"), 20); - - // [Chain m/0/2147483647'] - hdnode_private_ckd_prime(&node, 2147483647); - res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, - fromhex("40ef2cef1b2588ae862e7a511162ec7ff33c30fd"), 20); - - // [Chain m/0/2147483647'/1] - hdnode_private_ckd(&node, 1); - res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, - fromhex("3f2e8905488f795ebc84a39560d133971ccf9b50"), 20); - - // [Chain m/0/2147483647'/1/2147483646'] - hdnode_private_ckd_prime(&node, 2147483646); - res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, - fromhex("a5016fdf975f767e4e6f355c7a82efa69bf42ea7"), 20); - - // [Chain m/0/2147483647'/1/2147483646'/2] - hdnode_private_ckd(&node, 2); - res = hdnode_get_ethereum_pubkeyhash(&node, pubkeyhash); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(pubkeyhash, - fromhex("8ff2a9f7e7917804e8c8ec150d931d9c5a6fbc50"), 20); -} -END_TEST - -START_TEST(test_ethereum_address) { - static const char *vectors[] = {"52908400098527886E0F7030069857D2E4169EE7", - "8617E340B3D01FA5F11F306F4090FD50E238070D", - "de709f2102306220921060314715629080e2fb77", - "27b1fdb04752bbc536007a920d24acb045561c26", - "5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed", - "fB6916095ca1df60bB79Ce92cE3Ea74c37c5d359", - "dbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB", - "D1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb", - "5A4EAB120fB44eb6684E5e32785702FF45ea344D", - "5be4BDC48CeF65dbCbCaD5218B1A7D37F58A0741", - "a7dD84573f5ffF821baf2205745f768F8edCDD58", - "027a49d11d118c0060746F1990273FcB8c2fC196", - "CD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", - 0}; - uint8_t addr[20]; - char address[41]; - const char **vec = vectors; - while (*vec) { - memcpy(addr, fromhex(*vec), 20); - ethereum_address_checksum(addr, address, false, 0); - ck_assert_str_eq(address, *vec); - vec++; - } -} -END_TEST - -// test vectors from -// https://github.com/rsksmart/RSKIPs/blob/master/IPs/RSKIP60.md -START_TEST(test_rsk_address) { - uint8_t addr[20]; - char address[41]; - - static const char *rskip60_chain30[] = { - "5aaEB6053f3e94c9b9a09f33669435E7ef1bEAeD", - "Fb6916095cA1Df60bb79ce92cE3EA74c37c5d359", - "DBF03B407c01E7CD3cBea99509D93F8Dddc8C6FB", - "D1220A0Cf47c7B9BE7a2e6ba89F429762E7B9adB", 0}; - const char **vec = rskip60_chain30; - while (*vec) { - memcpy(addr, fromhex(*vec), 20); - ethereum_address_checksum(addr, address, true, 30); - ck_assert_str_eq(address, *vec); - vec++; - } - - static const char *rskip60_chain31[] = { - "5aAeb6053F3e94c9b9A09F33669435E7EF1BEaEd", - "Fb6916095CA1dF60bb79CE92ce3Ea74C37c5D359", - "dbF03B407C01E7cd3cbEa99509D93f8dDDc8C6fB", - "d1220a0CF47c7B9Be7A2E6Ba89f429762E7b9adB", 0}; - vec = rskip60_chain31; - while (*vec) { - memcpy(addr, fromhex(*vec), 20); - ethereum_address_checksum(addr, address, true, 31); - ck_assert_str_eq(address, *vec); - vec++; - } -} -END_TEST - -// test vectors from -// https://raw.githubusercontent.com/NemProject/nem-test-vectors/master/1.test-keys.dat -START_TEST(test_nem_address) { - static const struct { - const char *private_key; - const char *public_key; - const char *address; - } tests[] = { - { - "575dbb3062267eff57c970a336ebbc8fbcfe12c5bd3ed7bc11eb0481d7704ced", - "c5f54ba980fcbb657dbaaa42700539b207873e134d2375efeab5f1ab52f87844", - "NDD2CT6LQLIYQ56KIXI3ENTM6EK3D44P5JFXJ4R4", - }, - { - "5b0e3fa5d3b49a79022d7c1e121ba1cbbf4db5821f47ab8c708ef88defc29bfe", - "96eb2a145211b1b7ab5f0d4b14f8abc8d695c7aee31a3cfc2d4881313c68eea3", - "NABHFGE5ORQD3LE4O6B7JUFN47ECOFBFASC3SCAC", - }, - { - "738ba9bb9110aea8f15caa353aca5653b4bdfca1db9f34d0efed2ce1325aeeda", - "2d8425e4ca2d8926346c7a7ca39826acd881a8639e81bd68820409c6e30d142a", - "NAVOZX4HDVOAR4W6K4WJHWPD3MOFU27DFHC7KZOZ", - }, - { - "e8bf9bc0f35c12d8c8bf94dd3a8b5b4034f1063948e3cc5304e55e31aa4b95a6", - "4feed486777ed38e44c489c7c4e93a830e4c4a907fa19a174e630ef0f6ed0409", - "NBZ6JK5YOCU6UPSSZ5D3G27UHAPHTY5HDQMGE6TT", - }, - { - "c325ea529674396db5675939e7988883d59a5fc17a28ca977e3ba85370232a83", - "83ee32e4e145024d29bca54f71fa335a98b3e68283f1a3099c4d4ae113b53e54", - "NCQW2P5DNZ5BBXQVGS367DQ4AHC3RXOEVGRCLY6V", - }, - { - "a811cb7a80a7227ae61f6da536534ee3c2744e3c7e4b85f3e0df3c6a9c5613df", - "6d34c04f3a0e42f0c3c6f50e475ae018cfa2f56df58c481ad4300424a6270cbb", - "NA5IG3XFXZHIPJ5QLKX2FBJPEZYPMBPPK2ZRC3EH", - }, - { - "9c66de1ec77f4dfaaebdf9c8bc599ca7e8e6f0bc71390ffee2c9dd3f3619242a", - "a8fefd72a3b833dc7c7ed7d57ed86906dac22f88f1f4331873eb2da3152a3e77", - "NAABHVFJDBM74XMJJ52R7QN2MTTG2ZUXPQS62QZ7", - }, - { - "c56bc16ecf727878c15e24f4ae68569600ac7b251218a44ef50ce54175776edc", - "c92f761e6d83d20068fd46fe4bd5b97f4c6ba05d23180679b718d1f3e4fb066e", - "NCLK3OLMHR3F2E3KSBUIZ4K5PNWUDN37MLSJBJZP", - }, - { - "9dd73599283882fa1561ddfc9be5830b5dd453c90465d3fe5eeb646a3606374e", - "eaf16a4833e59370a04ccd5c63395058de34877b48c17174c71db5ed37b537ed", - "ND3AHW4VTI5R5QE5V44KIGPRU5FBJ5AFUCJXOY5H", - }, - { - "d9639dc6f49dad02a42fd8c217f1b1b4f8ce31ccd770388b645e639c72ff24fa", - "0f74a2f537cd9c986df018994dde75bdeee05e35eb9fe27adf506ca8475064f7", - "NCTZ4YAP43ONK3UYTASQVNDMBO24ZHJE65F3QPYE", - }, - { - "efc1992cd50b70ca55ac12c07aa5d026a8b78ffe28a7dbffc9228b26e02c38c1", - "2ebff201255f6cf948c78f528658b99a7c13ac791942fa22d59af610558111f5", - "NDQ2TMCMXBSFPZQPE2YKH6XLC24HD6LUMN6Z4GIC", - }, - { - "143a815e92e43f3ed1a921ee48cd143931b88b7c3d8e1e981f743c2a5be3c5ba", - "419ed11d48730e4ae2c93f0ea4df853b8d578713a36dab227517cf965861af4e", - "NA32IDDW2C53BDSBJNFL3Z6UU3J5CJZJMCZDXCF4", - }, - { - "bc1a082f5ac6fdd3a83ade211e5986ac0551bad6c7da96727ec744e5df963e2a", - "a160e6f9112233a7ce94202ed7a4443e1dac444b5095f9fecbb965fba3f92cac", - "NADUCEQLC3FTGB25GTA5HOUTB53CBVQNVOIP7NTJ", - }, - { - "4e47b4c6f4c7886e49ec109c61f4af5cfbb1637283218941d55a7f9fe1053f72", - "fbb91b16df828e21a9802980a44fc757c588bc1382a4cea429d6fa2ae0333f56", - "NBAF3BFLLPWH33MYE6VUPP5T6DQBZBKIDEQKZQOE", - }, - { - "efc4389da48ce49f85365cfa578c746530e9eac42db1b64ec346119b1becd347", - "2232f24dda0f2ded3ecd831210d4e8521a096b50cadd5a34f3f7083374e1ec12", - "NBOGTK2I2ATOGGD7ZFJHROG5MWL7XCKAUKSWIVSA", - }, - { - "bdba57c78ca7da16a3360efd13f06276284db8c40351de7fcd38ba0c35ac754d", - "c334c6c0dad5aaa2a0d0fb4c6032cb6a0edd96bf61125b5ea9062d5a00ee0eee", - "NCLERTEFYXKLK7RA4MVACEFMXMK3P7QMWTM7FBW2", - }, - { - "20694c1ec3c4a311bcdb29ed2edc428f6d4f9a4c429ad6a5bf3222084e35695f", - "518c4de412efa93de06a55947d11f697639443916ec8fcf04ebc3e6d17d0bd93", - "NB5V4BPIJHXVONO7UGMJDPFARMFA73BOBNOOYCOV", - }, - { - "e0d4f3760ac107b33c22c2cac24ab2f520b282684f5f66a4212ff95d926323ce", - "b3d16f4ead9de67c290144da535a0ed2504b03c05e5f1ceb8c7863762f786857", - "NC4PBAO5TPCAVQKBVOC4F6DMZP3CFSQBU46PSKBD", - }, - { - "efa9afc617412093c9c7a7c211a5332dd556f941e1a88c494ec860608610eea2", - "7e7716e4cebceb731d6f1fd28676f34888e9a0000fcfa1471db1c616c2ddf559", - "NCFW2LPXIWLBWAQN2QVIWEOD7IVDO3HQBD2OU56K", - }, - { - "d98499b3db61944684ce06a91735af4e14105338473fcf6ebe2b0bcada3dfd21", - "114171230ad6f8522a000cdc73fbc5c733b30bb71f2b146ccbdf34499f79a810", - "NCUKWDY3J3THKQHAKOK5ALF6ANJQABZHCH7VN6DP", - }, - }; - - HDNode node; - ed25519_secret_key private_key; - uint8_t chain_code[32]; - char address[41]; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - nem_private_key(tests[i].private_key, private_key); - - ck_assert(hdnode_from_xprv(0, 0, chain_code, private_key, - ED25519_KECCAK_NAME, &node)); - - ck_assert(hdnode_get_nem_address(&node, NEM_NETWORK_MAINNET, address)); - ck_assert_str_eq(address, tests[i].address); - - ck_assert_mem_eq(&node.public_key[1], fromhex(tests[i].public_key), 32); - } -} -END_TEST - -// test vectors from -// https://raw.githubusercontent.com/NemProject/nem-test-vectors/master/3.test-derive.dat -START_TEST(test_nem_derive) { - static const struct { - const char *salt; - const char *private_key; - const char *public_key; - const char *mul; - const char *shared_key; - } tests[] = { - { - "ad63ac08f9afc85eb0bf4f8881ca6eaa0215924c87aa2f137d56109bb76c6f98", - "e8857f8e488d4e6d4b71bcd44bb4cff49208c32651e1f6500c3b58cafeb8def6", - "9d8e5f200b05a2638fb084a375408cabd6d5989590d96e3eea5f2cb34668178e", - "a8352060ba5718745ee4d78b9df564e0fbe13f50d50ab15a8dd524159d81d18b", - "990a5f611c65fbcde735378bdec38e1039c5466503511e8c645bbe42795c752b", - }, - { - "96104f0a28f9cca40901c066cd435134662a3b053eb6c8df80ee0d05dc941963", - "d7f67b5f52cbcd1a1367e0376a8eb1012b634acfcf35e8322bae8b22bb9e8dea", - "9735c92d150dcee0ade5a8d1822f46a4db22c9cda25f33773ae856fe374a3e8a", - "ea14d521d83328dba70982d42094300585818cc2da609fdb1f73bb32235576ff", - "b498aa21d4ba4879ea9fd4225e93bacc760dcd9c119f8f38ab0716457d1a6f85", - }, - { - "d8f94a0bbb1de80aea17aab42e2ffb982e73fc49b649a318479e951e392d8728", - "d026ddb445fb3bbf3020e4b55ed7b5f9b7fd1278c34978ca1a6ed6b358dadbae", - "d19e6beca3b26b9d1abc127835ebeb7a6c19c33dec8ec472e1c4d458202f4ec8", - "0d561f54728ad837ae108ec66c2ece2bb3b26041d3ee9b77fdc6d36d9ebfb2e3", - "d012afe3d1d932304e613c91545bf571cf2c7281d6cafa8e81393a551f675540", - }, - { - "3f8c969678a8abdbfb76866a142c284a6f01636c1c1607947436e0d2c30d5245", - "c522b38c391d1c3fa539cc58802bc66ac34bb3c73accd7f41b47f539bedcd016", - "ea5b6a0053237f7712b1d2347c447d3e83e0f2191762d07e1f53f8eb7f2dfeaa", - "23cccd3b63a9456e4425098b6df36f28c8999461a85e4b2b0c8d8f53c62c9ea9", - "7e27efa50eed1c2ac51a12089cbab6a192624709c7330c016d5bc9af146584c1", - }, - { - "e66415c58b981c7f1f2b8f45a42149e9144616ff6de49ff83d97000ac6f6f992", - "2f1b82be8e65d610a4e588f000a89a733a9de98ffc1ac9d55e138b3b0a855da0", - "65aeda1b47f66c978a4a41d4dcdfbd8eab5cdeb135695c2b0c28f54417b1486d", - "43e5b0a5cc8146c03ac63e6f8cf3d8825a9ca1ed53ea4a88304af4ddf5461b33", - "bb4ab31c334e55d378937978c90bb33779b23cd5ef4c68342a394f4ec8fa1ada", - }, - { - "58487c9818c9d28ddf97cb09c13331941e05d0b62bf4c35ee368de80b552e4d1", - "f3869b68183b2e4341307653e8f659bd7cd20e37ea5c00f5a9e203a8fa92359a", - "c7e4153a18b4162f5c1f60e1ba483264aa5bb3f4889dca45b434fcd30b9cf56f", - "5ae9408ab3156b8828c3e639730bd5e5db93d7afe2cee3fcda98079316c5bb3a", - "0224d85ae8f17bfe127ec24b8960b7639a0dbde9c8c39a0575b939448687bb14", - }, - { - "ad66f3b654844e53d6fb3568134fae75672ba63868c113659d3ca58c2c39d24f", - "d38f2ef8dfdc7224fef596130c3f4ff68ac83d3f932a56ee908061466ac28572", - "d0c79d0340dc66f0a895ce5ad60a933cf6be659569096fb9d4b81e5d32292372", - "1ea22db4708ed585ab541a4c70c3069f8e2c0c1faa188ddade3efaa53c8329f6", - "886a7187246934aedf2794748deadfe038c9fd7e78d4b7be76c5a651440ac843", - }, - { - "eed48604eab279c6ad8128aa83483a3da0928271a4cae1a5745671284e1fb89d", - "e2342a8450fc0adfa0ea2fbd0b1d28f100f0a3a905a3da29de34d1353afa7df7", - "d2dbe07e0f2dbc3dbb01c70092e3c4247d12827ddcd8d76534fd740a65c30de2", - "4c4b30eb6a2bfa17312f5729b4212cb51c2eee8fbfaea82a0e957ca68f4f6a30", - "dcae613ac5641ff9d4c3ca58632245f93b0b8657fe4d48bac7b062cc53dd21ad", - }, - { - "f35b315287b268c0d0b386fb5b31810f65e1c4497cffae24527f69a3abac3884", - "049016230dbef7a14a439e5ab2f6d12e78cb8df127db4e0c312673b3c361e350", - "1b3b1925a8a535cd7d78725d25298f45bba8ca3dee2cdaabf14241c9b51b37c4", - "04c9685dae1f8eb72a6438f24a87dc83a56d79c9024edf7e01aa1ae34656f29e", - "b48469d0428c223b93cd1fe34bb2cafd3fb78a8fa15f98f89f1ac9c0ce7c9001", - }, - { - "d6cf082c5d9a96e756a94a2e27703138580a7c7c1af505c96c3abf7ab6802e1d", - "67cd02b0b8b0adcf6fdd4d4d64a1f4193ced68bb8605d0ec941a62011326d140", - "a842d5127c93a435e4672dcadd9fccbfd0e9208c79c5404848b298597eccdbdb", - "d5c6bd6d81b99659d0bafe91025b6ecf73b16c6b07931cf44718b13f00fde3f7", - "8aa160795b587f4be53aa35d26e9b618b4cd6ec765b523bc908e53c258ca8fd4", - }, - { - "dda32c91c95527a645b00dd05d13f0b98ed612a726ce5f5221431430b7660944", - "eba026f92a8ffb5e95060a22e15d597fe838a99a0b2bbcb423c933b6bc718c50", - "7dbaf9c313a1ff9128c54d6cd740c7d0cc46bca588e7910d438dd619ca4fd69a", - "5bb20a145de83ba27a0c261e1f54bfd7dcea61888fc2eebbe6166876f7b000b8", - "3a96f152ad8bf355cccb307e4a40108aa17f8e925522a2b5bb0b3f1e1a262914", - }, - { - "63c500acbd4ff747f7dadde7d3286482894ac4d7fe68f396712bca29879aa65c", - "9663cd3c2030a5fe4a3ea3cc9a1d182b3a63ade68616aaeb4caf40b495f6f227", - "b1e7d9070ac820d986d839b79f7aa594dcf708473529dad87af8682cc6197374", - "1f7a97584d8db9f395b9ac4447de4b33c5c1f5020187cd4996286a49b07eb8a7", - "4d2a974ec12dcf525b5654d31053460850c3092648b7e15598b7131d2930e9fb", - }, - { - "91f340961029398cc8bcd906388044a6801d24328efdf919d8ed0c609862a073", - "45a588500d00142e2226231c01fd11ac6f842ab6a85872418f5b6a1999f8bd98", - "397233c96069b6f4a57d6e93f759fa327222eaef71fc981afa673b248206df3f", - "062123ef9782e3893f7b2e1d557b4ecce92b9f9aa8577e76380f228b75152f84", - "235848cb04230a16d8978aa7c19fe7fbff3ebe29389ea6eb24fb8bc3cb50afc6", - }, - { - "46120b4da6ba4eb54fb65213cfef99b812c86f7c42a1de1107f8e8c12c0c3b6b", - "cc19a97a99ad71ce348bcf831c0218e6a1f0a8d52186cabe6298b56f24e640f9", - "c54631bb62f0f9d86b3301fcb2a671621e655e578c95504af5f78da83f7fec4f", - "ab73cc20c75260ff3a7cefea8039291d4d15114a07a9250375628cca32225bb6", - "70040a360b6a2dfa881272ef4fa6616e2e8fcc45194fa2a21a1eef1160271cd5", - }, - { - "f0a69ded09f1d731ab9561d0c3a40b7ef30bcb2bf60f92beccd8734e2441403d", - "ea732822a381c46a7ac9999bf5ef85e16b7460b26aaf6c1a1c6ffa8c8c82c923", - "110decbff79c382b1e60af4259564a3c473087792350b24fca98ae9a74ba9dd9", - "81bdee95aecdcf821a9d682f79056f1abdcf1245d2f3b55244447881a283e0d4", - "1bc29d4470ccf97d4e35e8d3cd4b12e3ebf2cb0a82425d35984aeedf7ad0f6f9", - }, - { - "e79cf4536fb1547e57626c0f1a87f71a396fdfb985b00731c0c2876a00645eda", - "04213fc02b59c372e3e7f53faa71a2f73b31064102cb6fc8b68432ba7cdf7eb4", - "ca1c750aaed53bc30dac07d0696ed86bcd7cdbbcbd3d15bb90d90cb5c6117bac", - "c68cd0872a42a3a64e8a229ef7fcad3d722047d5af966f7dda4d4e32d0d57203", - "bfdd3d07563d966d95afe4b8abea4b567265fceea8c4ecddb0946256c33e07b2", - }, - { - "81a40db4cddaf076e0206bd2b0fa7470a72cc456bad34aa3a0469a4859f286be", - "52156799fd86cc63345cdbffd65ef4f5f8df0ffd9906a40af5f41d269bbcff5d", - "54d61aa0b0b17a87f1376fe89cd8cd6b314827c1f1b9e5e7b20e7a7eee2a8335", - "4553fb2cab8555068c32f86ceb692bbf1c2beeaf21627ef1b1be57344b52eea8", - "55096b6710ade3bbe38702458ee13faa10c24413261bc076f17675dcbf2c4ee6", - }, - { - "d28e4a9e6832a3a4dad014a2bf1f666f01093cbba8b9ad4d1dcad3ea10cb42b9", - "8ca134404c8fa199b0c72cb53cfa0adcf196dfa560fb521017cce5cbace3ba59", - "3a6c39a1e5f9f550f1debedd9a0bc84210cce5f9834797db8f14122bf5817e45", - "eb632ca818b4f659630226a339a3ce536b31c8e1e686fea8da3760e8abc20b8e", - "9fbb3fbaf1cd54ee0cd90685f59b082545983f1f662ef701332379306a6ad546", - }, - { - "f9c4bfad9e2a3d98c44c12734881a6f217d6c9523cc210772fad1297993454b4", - "b85960fcadda8d0a0960559b6b7818a0d8d4574b4e928b17c9b498fa9ffab4ef", - "6a1d0ef23ce0b40a7077ecb7b7264945054e3bdb58ee25e1b0ee8b3e19dbfcdc", - "bb145dddcb75074a6a03249fca1aa7d6fa9549e3ed965f138ca5e7071b7878f2", - "87d3faea4a98e41009eb8625611ea0fc12094c295af540c126c14a0f55afa76e", - }, - { - "656df4789a369d220aceb7b318517787d27004ecccedea019d623bcb2d79f5ff", - "acf83e30afb2a5066728ec5d93564c08abe5e68e3a2a2ff953bdcf4d44f9da06", - "bdda65efe56d7890286aada1452f62f85ba157d0b4621ba641de15d8d1c9e331", - "958beef5dc6babc6de383c32ad7dd3a6d6eb8bb3236ed5558eec0f9eb31e5458", - "6f6d4ee36d9d76e462c9635adfbb6073134a276cfc7cb86762004ec47197afa0", - }, - }; - - HDNode node; - ed25519_secret_key private_key; - uint8_t chain_code[32]; - ed25519_public_key public_key, mul; - uint8_t shared_key[SHA3_256_DIGEST_LENGTH]; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - nem_private_key(tests[i].private_key, private_key); - - ck_assert(hdnode_from_xprv(0, 0, chain_code, private_key, - ED25519_KECCAK_NAME, &node)); - memcpy(public_key, fromhex(tests[i].public_key), 32); - - ck_assert(hdnode_get_nem_shared_key( - &node, public_key, fromhex(tests[i].salt), mul, shared_key)); - ck_assert_mem_eq(mul, fromhex(tests[i].mul), sizeof(mul)); - ck_assert_mem_eq(shared_key, fromhex(tests[i].shared_key), - sizeof(shared_key)); - } -} -END_TEST - -// test vectors from -// https://raw.githubusercontent.com/NemProject/nem-test-vectors/master/4.test-cipher.dat -START_TEST(test_nem_cipher) { - static const struct { - const char *private_key; - const char *public_key; - const char *salt; - const char *iv; - const char *input; - const char *output; - } tests[] = { - { - "3140f94c79f249787d1ec75a97a885980eb8f0a7d9b7aa03e7200296e422b2b6", - "57a70eb553a7b3fd621f0dba6abf51312ea2e2a2a1e19d0305516730f4bcbd21", - "83616c67f076d356fd1288a6e0fd7a60488ba312a3adf0088b1b33c7655c3e6a", - "a73ff5c32f8fd055b09775817a6a3f95", - "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", - "70815da779b1b954d7a7f00c16940e9917a0412a06a444b539bf147603eef87f", - }, - { - "3140f94c79f249787d1ec75a97a885980eb8f0a7d9b7aa03e7200296e422b2b6", - "57a70eb553a7b3fd621f0dba6abf51312ea2e2a2a1e19d0305516730f4bcbd21", - "703ce0b1d276b10eef35672df03234385a903460db18ba9d4e05b3ad31abb284", - "91246c2d5493867c4fa3e78f85963677", - "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", - "564b2f40d42c0efc1bd6f057115a5abd1564cae36d7ccacf5d825d38401aa894", - }, - { - "3140f94c79f249787d1ec75a97a885980eb8f0a7d9b7aa03e7200296e422b2b6", - "57a70eb553a7b3fd621f0dba6abf51312ea2e2a2a1e19d0305516730f4bcbd21", - "b22e8e8e7373ac31ca7f0f6eb8b93130aba5266772a658593f3a11792e7e8d92", - "9f8e33d82374dad6aac0e3dbe7aea704", - "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", - "7cab88d00a3fc656002eccbbd966e1d5d14a3090d92cf502cdbf843515625dcf", - }, - { - "3140f94c79f249787d1ec75a97a885980eb8f0a7d9b7aa03e7200296e422b2b6", - "57a70eb553a7b3fd621f0dba6abf51312ea2e2a2a1e19d0305516730f4bcbd21", - "af646c54cd153dffe453b60efbceeb85c1e95a414ea0036c4da94afb3366f5d9", - "6acdf8e01acc8074ddc807281b6af888", - "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", - "aa70543a485b63a4dd141bb7fd78019092ac6fad731e914280a287c7467bae1a", - }, - { - "3140f94c79f249787d1ec75a97a885980eb8f0a7d9b7aa03e7200296e422b2b6", - "57a70eb553a7b3fd621f0dba6abf51312ea2e2a2a1e19d0305516730f4bcbd21", - "d9c0d386636c8a024935c024589f9cd39e820a16485b14951e690a967830e269", - "f2e9f18aeb374965f54d2f4e31189a8f", - "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", - "33d97c216ea6498dfddabf94c2e2403d73efc495e9b284d9d90aaff840217d25", - }, - { - "d5c0762ecea2cd6b5c56751b58debcb32713aab348f4a59c493e38beb3244f3a", - "66a35941d615b5644d19c2a602c363ada8b1a8a0dac3682623852dcab4afac04", - "06c227baac1ae3b0b1dc583f4850f13f9ba5d53be4a98fa5c3ea16217847530d", - "3735123e78c44895df6ea33fa57e9a72", - "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", - "d5b5d66ba8cee0eb7ecf95b143fa77a46d6de13749e12eff40f5a7e649167ccb", - }, - { - "d5c0762ecea2cd6b5c56751b58debcb32713aab348f4a59c493e38beb3244f3a", - "66a35941d615b5644d19c2a602c363ada8b1a8a0dac3682623852dcab4afac04", - "92f55ba5bc6fc2f23e3eedc299357c71518e36ba2447a4da7a9dfe9dfeb107b5", - "1cbc4982e53e370052af97ab088fa942", - "86ddb9e713a8ebf67a51830eff03b837e147c20d75e67b2a54aa29e98c", - "d48ef1ef526d805656cfc932aff259eadb17aa3391dde1877a722cba31d935b2", - }, - { - "d5c0762ecea2cd6b5c56751b58debcb32713aab348f4a59c493e38beb3244f3a", - "66a35941d615b5644d19c2a602c363ada8b1a8a0dac3682623852dcab4afac04", - "10f15a39ba49866292a43b7781bc71ca8bbd4889f1616461caf056bcb91b0158", - "c40d531d92bfee969dce91417346c892", - "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a" - "4", - "e6d75afdb542785669b42198577c5b358d95397d71ec6f5835dca46d332cc08dbf73" - "ea790b7bcb169a65719c0d55054c", - }, - { - "d5c0762ecea2cd6b5c56751b58debcb32713aab348f4a59c493e38beb3244f3a", - "66a35941d615b5644d19c2a602c363ada8b1a8a0dac3682623852dcab4afac04", - "9c01ed42b219b3bbe1a43ae9d7af5c1dd09363baacfdba8f4d03d1046915e26e", - "059a35d5f83249e632790015ed6518b9", - "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a" - "4", - "5ef11aadff2eccee8b712dab968fa842eb770818ec0e6663ed242ea8b6bbc1c66d62" - "85ee5b5f03d55dfee382fb4fa25d", - }, - { - "d5c0762ecea2cd6b5c56751b58debcb32713aab348f4a59c493e38beb3244f3a", - "66a35941d615b5644d19c2a602c363ada8b1a8a0dac3682623852dcab4afac04", - "bc1067e2a7415ea45ff1ca9894338c591ff15f2e57ae2789ae31b9d5bea0f11e", - "8c73f0d6613898daeefa3cf8b0686d37", - "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a" - "4", - "6d220213b1878cd40a458f2a1e6e3b48040455fdf504dcd857f4f2ca1ad642e3a44f" - "c401d04e339d302f66a9fad3d919", - }, - { - "9ef87ba8aa2e664bdfdb978b98bc30fb61773d9298e7b8c72911683eeff41921", - "441e76d7e53be0a967181076a842f69c20fd8c0e3f0ce3aa421b490b059fe094", - "cf4a21cb790552165827b678ca9695fcaf77566d382325112ff79483455de667", - "bfbf5482e06f55b88bdd9e053b7eee6e", - "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a" - "4", - "1198a78c29c215d5c450f7b8513ead253160bc9fde80d9cc8e6bee2efe9713cf5a09" - "d6293c41033271c9e8c22036a28b", - }, - { - "9ef87ba8aa2e664bdfdb978b98bc30fb61773d9298e7b8c72911683eeff41921", - "441e76d7e53be0a967181076a842f69c20fd8c0e3f0ce3aa421b490b059fe094", - "eba5eae8aef79114082c3e70baef95bb02edf13b3897e8be7a70272962ef8838", - "af9a56da3da18e2fbd2948a16332532b", - "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a" - "4", - "1062ab5fbbdee9042ad35bdadfd3047c0a2127fe0f001da1be1b0582185edfc9687b" - "e8d68f85795833bb04af9cedd3bb", - }, - { - "9ef87ba8aa2e664bdfdb978b98bc30fb61773d9298e7b8c72911683eeff41921", - "441e76d7e53be0a967181076a842f69c20fd8c0e3f0ce3aa421b490b059fe094", - "518f8dfd0c138f1ffb4ea8029db15441d70abd893c3d767dc668f23ba7770e27", - "42d28307974a1b2a2d921d270cfce03b", - "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a" - "4", - "005e49fb7c5da540a84b034c853fc9f78a6b901ea495aed0c2abd4f08f1a96f9ffef" - "c6a57f1ac09e0aea95ca0f03ffd8", - }, - { - "9ef87ba8aa2e664bdfdb978b98bc30fb61773d9298e7b8c72911683eeff41921", - "441e76d7e53be0a967181076a842f69c20fd8c0e3f0ce3aa421b490b059fe094", - "582fdf58b53715c26e10ba809e8f2ab70502e5a3d4e9a81100b7227732ab0bbc", - "91f2aad3189bb2edc93bc891e73911ba", - "49de3cd5890e0cd0559f143807ff688ff62789b7236a332b7d7255ec0b4e73e6b3a" - "4", - "821a69cb16c57f0cb866e590b38069e35faec3ae18f158bb067db83a11237d29ab1e" - "6b868b3147236a0958f15c2e2167", - }, - { - "9ef87ba8aa2e664bdfdb978b98bc30fb61773d9298e7b8c72911683eeff41921", - "441e76d7e53be0a967181076a842f69c20fd8c0e3f0ce3aa421b490b059fe094", - "a415b4c006118fb72fc37b2746ef288e23ac45c8ff7ade5f368a31557b6ac93a", - "2b7c5f75606c0b8106c6489ea5657a9e", - "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", - "2781d5ee8ef1cb1596f8902b33dfae5045f84a987ca58173af5830dbce386062", - }, - { - "ed93c5a101ab53382ceee4f7e6b5aa112621d3bb9d18891509b1834ede235bcc", - "5a5e14c633d7d269302849d739d80344ff14db51d7bcda86045723f05c4e4541", - "47e73ec362ea82d3a7c5d55532ad51d2cdf5316b981b2b2bd542b0efa027e8ea", - "b2193f59030c8d05a7d3577b7f64dd33", - "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", - "3f43912db8dd6672b9996e5272e18c4b88fec9d7e8372db9c5f4709a4af1d86f", - }, - { - "ed93c5a101ab53382ceee4f7e6b5aa112621d3bb9d18891509b1834ede235bcc", - "5a5e14c633d7d269302849d739d80344ff14db51d7bcda86045723f05c4e4541", - "aaa006c57b6d1e402650577fe9787d8d285f4bacd7c01f998be49c766f8860c7", - "130304ddb9adc8870cf56bcae9487b7f", - "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", - "878cc7d8c0ef8dac0182a78eedc8080a402f59d8062a6b4ca8f4a74f3c3b3de7", - }, - { - "ed93c5a101ab53382ceee4f7e6b5aa112621d3bb9d18891509b1834ede235bcc", - "5a5e14c633d7d269302849d739d80344ff14db51d7bcda86045723f05c4e4541", - "28dc7ccd6c2a939eef64b8be7b9ae248295e7fcd8471c22fa2f98733fea97611", - "cb13890d3a11bc0a7433738263006710", - "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", - "e74ded846bebfa912fa1720e4c1415e6e5df7e7a1a7fedb5665d68f1763209a4", - }, - { - "ed93c5a101ab53382ceee4f7e6b5aa112621d3bb9d18891509b1834ede235bcc", - "5a5e14c633d7d269302849d739d80344ff14db51d7bcda86045723f05c4e4541", - "79974fa2cad95154d0873902c153ccc3e7d54b17f2eeb3f29b6344cad9365a9a", - "22123357979d20f44cc8eb0263d84e0e", - "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", - "eb14dec7b8b64d81a2ee4db07b0adf144d4f79a519bbf332b823583fa2d45405", - }, - { - "ed93c5a101ab53382ceee4f7e6b5aa112621d3bb9d18891509b1834ede235bcc", - "5a5e14c633d7d269302849d739d80344ff14db51d7bcda86045723f05c4e4541", - "3409a6f8c4dcd9bd04144eb67e55a98696b674735b01bf1196191f29871ef966", - "a823a0965969380ea1f8659ea5fd8fdd", - "24512b714aefd5cbc4bcc4ef44ce6c67ffc447c65460a6c6e4a92e85", - "00a7eb708eae745847173f8217efb05be13059710aee632e3f471ac3c6202b51", - }, - { - "a73a0b2686f7d699c018b6b08a352856e556070caa329c26241aec889eefde10", - "9b493403bee45ae6277430ef8d0c4163ffd81ace2db6c7821205da09a664a86c", - "c25701b9b7328c4ac3d23223d10623bd527c0a98e38ae9c62fbc403c80ab20ae", - "4b4ee0e4443779f3af429a749212f476", - "b6926d0ec82cec86c0d27ec9a33a0e0f", - "f39f7d66e0fde39ecdf58be2c0ef361a17cfd6843e310adbe0ec3118cd72800d", - }, - { - "a73a0b2686f7d699c018b6b08a352856e556070caa329c26241aec889eefde10", - "9b493403bee45ae6277430ef8d0c4163ffd81ace2db6c7821205da09a664a86c", - "31d18fdffc480310828778496ff817039df5d6f30bf6d9edd0b4396863d05f93", - "418bcbdf52860a450bfacc96920d02cf", - "b6926d0ec82cec86c0d27ec9a33a0e0f", - "0e6ce9889fe7b3cd82794b0ae27c1f5985d2f2a1f398371a138f8db1df1f54de", - }, - { - "e2e4dee102fad0f47f60202269605589cd9cf70f816b34016796c74b766f3041", - "c5ce283033a3255ae14d42dff1e4c18a224ac79d084b285123421b105ee654c9", - "56b4c645f81dbfb6ba0c6d3f1626e1e5cd648eeb36562715f7cd7e9ea86a0d7f", - "dc9bdce76d68d2e4d72267cf4e72b022", - "b6926d0ec82cec86c0d27ec9a33a0e0f", - "dc6f046c3008002041517a7c4f3ababe609cf02616fcccda39c075d1be4175f5", - }, - { - "e2e4dee102fad0f47f60202269605589cd9cf70f816b34016796c74b766f3041", - "c5ce283033a3255ae14d42dff1e4c18a224ac79d084b285123421b105ee654c9", - "df180b91986c8c7000792f96d1faa61e30138330430a402322be1855089b0e7f", - "ccf9b77341c866465b474e2f4a3b1cf8", - "b6926d0ec82cec86c0d27ec9a33a0e0f", - "94e4ae89041437f39826704f02cb5d775226f34344635e592846417497a5020b", - }, - { - "e2e4dee102fad0f47f60202269605589cd9cf70f816b34016796c74b766f3041", - "c5ce283033a3255ae14d42dff1e4c18a224ac79d084b285123421b105ee654c9", - "a0eee7e84c76e63fdae6e938b43330775eaf17d260e40b98c9e6616b668102a7", - "662c681cfec6f6d052ff0e2c1255f2c2", - "b6926d0ec82cec86c0d27ec9a33a0e0f", - "70bba3c48be9c75a144b1888ca3d21a6b21f52eec133981a024390a6a0ba36f9", - }, - { - "e2e4dee102fad0f47f60202269605589cd9cf70f816b34016796c74b766f3041", - "c5ce283033a3255ae14d42dff1e4c18a224ac79d084b285123421b105ee654c9", - "c6acd2d90eb782c3053b366680ffa0e148de81fea198c87bb643869fd97e5cb0", - "908dc33ba80520f2f0f04e7890e3a3c0", - "b6926d0ec82cec86c0d27ec9a33a0e0f", - "f6efe1d76d270aac264aa35d03049d9ce63be1996d543aef00559219c8666f71", - }, - }; - - HDNode node; - ed25519_secret_key private_key; - uint8_t chain_code[32]; - ed25519_public_key public_key; - uint8_t salt[sizeof(public_key)]; - - uint8_t iv[AES_BLOCK_SIZE]; - uint8_t buffer[FROMHEX_MAXLEN]; - - uint8_t input[FROMHEX_MAXLEN]; - uint8_t output[FROMHEX_MAXLEN]; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - nem_private_key(tests[i].private_key, private_key); - - ck_assert(hdnode_from_xprv(0, 0, chain_code, private_key, - ED25519_KECCAK_NAME, &node)); - memcpy(public_key, fromhex(tests[i].public_key), 32); - memcpy(salt, fromhex(tests[i].salt), sizeof(salt)); - - size_t input_size = strlen(tests[i].input) / 2; - size_t output_size = strlen(tests[i].output) / 2; - - memcpy(input, fromhex(tests[i].input), input_size); - memcpy(output, fromhex(tests[i].output), output_size); - - memcpy(iv, fromhex(tests[i].iv), sizeof(iv)); - ck_assert(hdnode_nem_encrypt(&node, public_key, iv, salt, input, input_size, - buffer)); - ck_assert_uint_eq(output_size, NEM_ENCRYPTED_SIZE(input_size)); - ck_assert_mem_eq(buffer, output, output_size); - - memcpy(iv, fromhex(tests[i].iv), sizeof(iv)); - ck_assert(hdnode_nem_decrypt(&node, public_key, iv, salt, output, - output_size, buffer)); - ck_assert_uint_eq(input_size, NEM_DECRYPTED_SIZE(buffer, output_size)); - ck_assert_mem_eq(buffer, input, input_size); - } -} -END_TEST - -START_TEST(test_nem_transaction_transfer) { - nem_transaction_ctx ctx; - - uint8_t buffer[1024], hash[SHA3_256_DIGEST_LENGTH]; - - // http://bob.nem.ninja:8765/#/transfer/0acbf8df91e6a65dc56c56c43d65f31ff2a6a48d06fc66e78c7f3436faf3e74f - - nem_transaction_start( - &ctx, - fromhex( - "e59ef184a612d4c3c4d89b5950eb57262c69862b2f96e59c5043bf41765c482f"), - buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_transfer( - &ctx, NEM_NETWORK_TESTNET, 0, NULL, 0, 0, - "TBGIMRE4SBFRUJXMH7DVF2IBY36L2EDWZ37GVSC4", 50000000000000, NULL, 0, - false, 0)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq( - hash, - fromhex( - "0acbf8df91e6a65dc56c56c43d65f31ff2a6a48d06fc66e78c7f3436faf3e74f"), - sizeof(hash)); - - // http://bob.nem.ninja:8765/#/transfer/3409d9ece28d6296d6d5e220a7e3cb8641a3fb235ffcbd20c95da64f003ace6c - - nem_transaction_start( - &ctx, - fromhex( - "994793ba1c789fa9bdea918afc9b06e2d0309beb1081ac5b6952991e4defd324"), - buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_transfer( - &ctx, NEM_NETWORK_TESTNET, 14072100, NULL, 194000000, 14075700, - "TBLOODPLWOWMZ2TARX4RFPOSOWLULHXMROBN2WXI", 3000000, - (uint8_t *)"sending you 3 pairs of paddles\n", 31, false, 2)); - - ck_assert( - nem_transaction_write_mosaic(&ctx, "gimre.games.pong", "paddles", 2)); - - ck_assert(nem_transaction_write_mosaic(&ctx, "nem", "xem", 44000000)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq( - hash, - fromhex( - "3409d9ece28d6296d6d5e220a7e3cb8641a3fb235ffcbd20c95da64f003ace6c"), - sizeof(hash)); - - // http://chain.nem.ninja/#/transfer/e90e98614c7598fbfa4db5411db1b331d157c2f86b558fb7c943d013ed9f71cb - - nem_transaction_start( - &ctx, - fromhex( - "8d07f90fb4bbe7715fa327c926770166a11be2e494a970605f2e12557f66c9b9"), - buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_transfer( - &ctx, NEM_NETWORK_MAINNET, 0, NULL, 0, 0, - "NBT3WHA2YXG2IR4PWKFFMO772JWOITTD2V4PECSB", 5175000000000, - (uint8_t *)"Good luck!", 10, false, 0)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq( - hash, - fromhex( - "e90e98614c7598fbfa4db5411db1b331d157c2f86b558fb7c943d013ed9f71cb"), - sizeof(hash)); - - // http://chain.nem.ninja/#/transfer/40e89160e6f83d37f7c82defc0afe2c1605ae8c919134570a51dd27ea1bb516c - - nem_transaction_start( - &ctx, - fromhex( - "f85ab43dad059b9d2331ddacc384ad925d3467f03207182e01296bacfb242d01"), - buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_transfer( - &ctx, NEM_NETWORK_MAINNET, 77229, NULL, 30000000, 80829, - "NALICEPFLZQRZGPRIJTMJOCPWDNECXTNNG7QLSG3", 30000000, - fromhex("4d9dcf9186967d30be93d6d5404ded22812dbbae7c3f0de5" - "01bcd7228cba45bded13000eec7b4c6215fc4d3588168c92" - "18167cec98e6977359153a4132e050f594548e61e0dc61c1" - "53f0f53c5e65c595239c9eb7c4e7d48e0f4bb8b1dd2f5ddc"), - 96, true, 0)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq( - hash, - fromhex( - "40e89160e6f83d37f7c82defc0afe2c1605ae8c919134570a51dd27ea1bb516c"), - sizeof(hash)); - - // http://chain.nem.ninja/#/transfer/882dca18dcbe075e15e0ec5a1d7e6ccd69cc0f1309ffd3fde227bfbc107b3f6e - - nem_transaction_start( - &ctx, - fromhex( - "f85ab43dad059b9d2331ddacc384ad925d3467f03207182e01296bacfb242d01"), - buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_transfer( - &ctx, NEM_NETWORK_MAINNET, 26730750, NULL, 179500000, 26734350, - "NBE223WPKEBHQPCYUC4U4CDUQCRRFMPZLOQLB5OP", 1000000, - (uint8_t *)"enjoy! :)", 9, false, 1)); - - ck_assert(nem_transaction_write_mosaic(&ctx, "imre.g", "tokens", 1)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq( - hash, - fromhex( - "882dca18dcbe075e15e0ec5a1d7e6ccd69cc0f1309ffd3fde227bfbc107b3f6e"), - sizeof(hash)); -} -END_TEST - -START_TEST(test_nem_transaction_multisig) { - nem_transaction_ctx ctx, other_trans; - - uint8_t buffer[1024], inner[1024]; - const uint8_t *signature; - - // http://bob.nem.ninja:8765/#/multisig/7d3a7087023ee29005262016706818579a2b5499eb9ca76bad98c1e6f4c46642 - - nem_transaction_start( - &other_trans, - fromhex( - "abac2ee3d4aaa7a3bfb65261a00cc04c761521527dd3f2cf741e2815cbba83ac"), - inner, sizeof(inner)); - - ck_assert(nem_transaction_create_aggregate_modification( - &other_trans, NEM_NETWORK_TESTNET, 3939039, NULL, 16000000, 3960639, 1, - false)); - - ck_assert(nem_transaction_write_cosignatory_modification( - &other_trans, 2, - fromhex( - "e6cff9b3725a91f31089c3acca0fac3e341c00b1c8c6e9578f66c4514509c3b3"))); - - nem_transaction_start( - &ctx, - fromhex( - "59d89076964742ef2a2089d26a5aa1d2c7a7bb052a46c1de159891e91ad3d76e"), - buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_multisig(&ctx, NEM_NETWORK_TESTNET, 3939039, - NULL, 6000000, 3960639, - &other_trans)); - - signature = fromhex( - "933930a8828b560168bddb3137df9252048678d829aa5135fa27bb306ff6562efb927554" - "62988b852b0314bde058487d00e47816b6fb7df6bcfd7e1f150d1d00"); - ck_assert_int_eq(ed25519_sign_open_keccak(ctx.buffer, ctx.offset, - ctx.public_key, signature), - 0); - - nem_transaction_start( - &ctx, - fromhex( - "71cba4f2a28fd19f902ba40e9937994154d9eeaad0631d25d525ec37922567d4"), - buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_multisig_signature(&ctx, NEM_NETWORK_TESTNET, - 3939891, NULL, 6000000, - 3961491, &other_trans)); - - signature = fromhex( - "a849f13bfeeba808a8a4a79d579febe584d831a3a6ad03da3b9d008530b3d7a79fcf7156" - "121cd7ee847029d94af7ea7a683ca8e643dc5e5f489557c2054b830b"); - ck_assert_int_eq(ed25519_sign_open_keccak(ctx.buffer, ctx.offset, - ctx.public_key, signature), - 0); - - // http://chain.nem.ninja/#/multisig/1016cf3bdd61bd57b9b2b07b6ff2dee390279d8d899265bdc23d42360abe2e6c - - nem_transaction_start( - &other_trans, - fromhex( - "a1df5306355766bd2f9a64efdc089eb294be265987b3359093ae474c051d7d5a"), - inner, sizeof(inner)); - - ck_assert(nem_transaction_create_provision_namespace( - &other_trans, NEM_NETWORK_MAINNET, 59414272, NULL, 20000000, 59500672, - "dim", NULL, "NAMESPACEWH4MKFMBCVFERDPOOP4FK7MTBXDPZZA", 5000000000)); - - nem_transaction_start( - &ctx, - fromhex( - "cfe58463f0eaebceb5d00717f8aead49171a5d7c08f6b1299bd534f11715acc9"), - buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_multisig(&ctx, NEM_NETWORK_MAINNET, 59414272, - NULL, 6000000, 59500672, - &other_trans)); - - signature = fromhex( - "52a876a37511068fe214bd710b2284823921ec7318c01e083419a062eae5369c9c11c3ab" - "fdb590f65c717fab82873431d52be62e10338cb5656d1833bbdac70c"); - ck_assert_int_eq(ed25519_sign_open_keccak(ctx.buffer, ctx.offset, - ctx.public_key, signature), - 0); - - nem_transaction_start( - &ctx, - fromhex( - "1b49b80203007117d034e45234ffcdf402c044aeef6dbb06351f346ca892bce2"), - buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_multisig_signature(&ctx, NEM_NETWORK_MAINNET, - 59414342, NULL, 6000000, - 59500742, &other_trans)); - - signature = fromhex( - "b9a59239e5d06992c28840034ff7a7f13da9c4e6f4a6f72c1b1806c3b602f83a7d727a34" - "5371f5d15abf958208a32359c6dd77bde92273ada8ea6fda3dc76b00"); - ck_assert_int_eq(ed25519_sign_open_keccak(ctx.buffer, ctx.offset, - ctx.public_key, signature), - 0); - - nem_transaction_start( - &ctx, - fromhex( - "7ba4b39209f1b9846b098fe43f74381e43cb2882ccde780f558a63355840aa87"), - buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_multisig_signature(&ctx, NEM_NETWORK_MAINNET, - 59414381, NULL, 6000000, - 59500781, &other_trans)); - - signature = fromhex( - "e874ae9f069f0538008631d2df9f2e8a59944ff182e8672f743d2700fb99224aafb7a0ab" - "09c4e9ea39ee7c8ca04a8a3d6103ae1122d87772e871761d4f00ca01"); - ck_assert_int_eq(ed25519_sign_open_keccak(ctx.buffer, ctx.offset, - ctx.public_key, signature), - 0); -} -END_TEST - -START_TEST(test_nem_transaction_provision_namespace) { - nem_transaction_ctx ctx; - - uint8_t buffer[1024], hash[SHA3_256_DIGEST_LENGTH]; - - // http://bob.nem.ninja:8765/#/namespace/f7cab28da57204d01a907c697836577a4ae755e6c9bac60dcc318494a22debb3 - - nem_transaction_start( - &ctx, - fromhex( - "84afa1bbc993b7f5536344914dde86141e61f8cbecaf8c9cefc07391f3287cf5"), - buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_provision_namespace( - &ctx, NEM_NETWORK_TESTNET, 56999445, NULL, 20000000, 57003045, "gimre", - NULL, "TAMESPACEWH4MKFMBCVFERDPOOP4FK7MTDJEYP35", 5000000000)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq( - hash, - fromhex( - "f7cab28da57204d01a907c697836577a4ae755e6c9bac60dcc318494a22debb3"), - sizeof(hash)); - - // http://bob.nem.ninja:8765/#/namespace/7ddd5fe607e1bfb5606e0ac576024c318c8300d237273117d4db32a60c49524d - - nem_transaction_start( - &ctx, - fromhex( - "244fa194e2509ac0d2fbc18779c2618d8c2ebb61c16a3bcbebcf448c661ba8dc"), - buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_provision_namespace( - &ctx, NEM_NETWORK_TESTNET, 21496797, NULL, 108000000, 21500397, "misc", - "alice", "TAMESPACEWH4MKFMBCVFERDPOOP4FK7MTDJEYP35", 5000000000)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq( - hash, - fromhex( - "7ddd5fe607e1bfb5606e0ac576024c318c8300d237273117d4db32a60c49524d"), - sizeof(hash)); - - // http://chain.nem.ninja/#/namespace/57071aad93ca125dc231dc02c07ad8610cd243d35068f9b36a7d231383907569 - - nem_transaction_start( - &ctx, - fromhex( - "9f3c14f304309c8b72b2821339c4428793b1518bea72d58dd01f19d523518614"), - buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_provision_namespace( - &ctx, NEM_NETWORK_MAINNET, 26699717, NULL, 108000000, 26703317, "sex", - NULL, "NAMESPACEWH4MKFMBCVFERDPOOP4FK7MTBXDPZZA", 50000000000)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq( - hash, - fromhex( - "57071aad93ca125dc231dc02c07ad8610cd243d35068f9b36a7d231383907569"), - sizeof(hash)); -} -END_TEST - -START_TEST(test_nem_transaction_mosaic_creation) { - nem_transaction_ctx ctx; - - uint8_t buffer[1024], hash[SHA3_256_DIGEST_LENGTH]; - - // http://bob.nem.ninja:8765/#/mosaic/68364353c29105e6d361ad1a42abbccbf419cfc7adb8b74c8f35d8f8bdaca3fa/0 - - nem_transaction_start( - &ctx, - fromhex( - "994793ba1c789fa9bdea918afc9b06e2d0309beb1081ac5b6952991e4defd324"), - buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_mosaic_creation( - &ctx, NEM_NETWORK_TESTNET, 14070896, NULL, 108000000, 14074496, - "gimre.games.pong", "paddles", "Paddles for the bong game.\n", 0, 10000, - true, true, 0, 0, NULL, NULL, NULL, - "TBMOSAICOD4F54EE5CDMR23CCBGOAM2XSJBR5OLC", 50000000000)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq( - hash, - fromhex( - "68364353c29105e6d361ad1a42abbccbf419cfc7adb8b74c8f35d8f8bdaca3fa"), - sizeof(hash)); - - // http://bob.nem.ninja:8765/#/mosaic/b2f4a98113ff1f3a8f1e9d7197aa982545297fe0aa3fa6094af8031569953a55/0 - - nem_transaction_start( - &ctx, - fromhex( - "244fa194e2509ac0d2fbc18779c2618d8c2ebb61c16a3bcbebcf448c661ba8dc"), - buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_mosaic_creation( - &ctx, NEM_NETWORK_TESTNET, 21497248, NULL, 108000000, 21500848, - "alice.misc", "bar", "Special offer: get one bar extra by bying one foo!", - 0, 1000, false, true, 1, 1, "TALICE2GMA34CXHD7XLJQ536NM5UNKQHTORNNT2J", - "nem", "xem", "TBMOSAICOD4F54EE5CDMR23CCBGOAM2XSJBR5OLC", 50000000000)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq( - hash, - fromhex( - "b2f4a98113ff1f3a8f1e9d7197aa982545297fe0aa3fa6094af8031569953a55"), - sizeof(hash)); - - // http://chain.nem.ninja/#/mosaic/269c6fda657aba3053a0e5b138c075808cc20e244e1182d9b730798b60a1f77b/0 - - nem_transaction_start( - &ctx, - fromhex( - "58956ac77951622dc5f1c938affbf017c458e30e6b21ddb5783d38b302531f23"), - buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_mosaic_creation( - &ctx, NEM_NETWORK_MAINNET, 26729938, NULL, 108000000, 26733538, "jabo38", - "red_token", - "This token is to celebrate the release of Namespaces and Mosaics on the " - "NEM system. " - "This token was the fist ever mosaic created other than nem.xem. " - "There are only 10,000 Red Tokens that will ever be created. " - "It has no levy and can be traded freely among third parties.", - 2, 10000, false, true, 0, 0, NULL, NULL, NULL, - "NBMOSAICOD4F54EE5CDMR23CCBGOAM2XSIUX6TRS", 50000000000)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq( - hash, - fromhex( - "269c6fda657aba3053a0e5b138c075808cc20e244e1182d9b730798b60a1f77b"), - sizeof(hash)); - - // http://chain.nem.ninja/#/mosaic/e8dc14821dbea4831d9051f86158ef348001447968fc22c01644fdaf2bda75c6/0 - - nem_transaction_start( - &ctx, - fromhex( - "a1df5306355766bd2f9a64efdc089eb294be265987b3359093ae474c051d7d5a"), - buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_mosaic_creation( - &ctx, NEM_NETWORK_MAINNET, 69251020, NULL, 20000000, 69337420, "dim", - "coin", "DIM COIN", 6, 9000000000, false, true, 2, 10, - "NCGGLVO2G3CUACVI5GNX2KRBJSQCN4RDL2ZWJ4DP", "dim", "coin", - "NBMOSAICOD4F54EE5CDMR23CCBGOAM2XSIUX6TRS", 500000000)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq( - hash, - fromhex( - "e8dc14821dbea4831d9051f86158ef348001447968fc22c01644fdaf2bda75c6"), - sizeof(hash)); -} -END_TEST - -START_TEST(test_nem_transaction_mosaic_supply_change) { - nem_transaction_ctx ctx; - - uint8_t buffer[1024], hash[SHA3_256_DIGEST_LENGTH]; - - // http://bigalice2.nem.ninja:7890/transaction/get?hash=33a50fdd4a54913643a580b2af08b9a5b51b7cee922bde380e84c573a7969c50 - - nem_transaction_start( - &ctx, - fromhex( - "994793ba1c789fa9bdea918afc9b06e2d0309beb1081ac5b6952991e4defd324"), - buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_mosaic_supply_change( - &ctx, NEM_NETWORK_TESTNET, 14071648, NULL, 108000000, 14075248, - "gimre.games.pong", "paddles", 1, 1234)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq( - hash, - fromhex( - "33a50fdd4a54913643a580b2af08b9a5b51b7cee922bde380e84c573a7969c50"), - sizeof(hash)); - - // http://bigalice2.nem.ninja:7890/transaction/get?hash=1ce8e8894d077a66ff22294b000825d090a60742ec407efd80eb8b19657704f2 - - nem_transaction_start( - &ctx, - fromhex( - "84afa1bbc993b7f5536344914dde86141e61f8cbecaf8c9cefc07391f3287cf5"), - buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_mosaic_supply_change( - &ctx, NEM_NETWORK_TESTNET, 14126909, NULL, 108000000, 14130509, - "jabo38_ltd.fuzzy_kittens_cafe", "coupons", 2, 1)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq( - hash, - fromhex( - "1ce8e8894d077a66ff22294b000825d090a60742ec407efd80eb8b19657704f2"), - sizeof(hash)); - - // http://bigalice3.nem.ninja:7890/transaction/get?hash=694e493e9576d2bcf60d85747e302ac2e1cc27783187947180d4275a713ff1ff - - nem_transaction_start( - &ctx, - fromhex( - "b7ccc27b21ba6cf5c699a8dc86ba6ba98950442597ff9fa30e0abe0f5f4dd05d"), - buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_mosaic_supply_change( - &ctx, NEM_NETWORK_MAINNET, 53377685, NULL, 20000000, 53464085, "abvapp", - "abv", 1, 9000000)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq( - hash, - fromhex( - "694e493e9576d2bcf60d85747e302ac2e1cc27783187947180d4275a713ff1ff"), - sizeof(hash)); - - // http://bigalice3.nem.ninja:7890/transaction/get?hash=09836334e123970e068d5b411e4d1df54a3ead10acf1ad5935a2cdd9f9680185 - - nem_transaction_start( - &ctx, - fromhex( - "75f001a8641e2ce5c4386883dda561399ed346177411b492a677b73899502f13"), - buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_mosaic_supply_change( - &ctx, NEM_NETWORK_MAINNET, 55176304, NULL, 20000000, 55262704, "sushi", - "wasabi", 2, 20)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq( - hash, - fromhex( - "09836334e123970e068d5b411e4d1df54a3ead10acf1ad5935a2cdd9f9680185"), - sizeof(hash)); -} -END_TEST - -START_TEST(test_nem_transaction_aggregate_modification) { - nem_transaction_ctx ctx; - - uint8_t buffer[1024], hash[SHA3_256_DIGEST_LENGTH]; - - // http://bob.nem.ninja:8765/#/aggregate/6a55471b17159e5b6cd579c421e95a4e39d92e3f78b0a55ee337e785a601d3a2 - - nem_transaction_start( - &ctx, - fromhex( - "462ee976890916e54fa825d26bdd0235f5eb5b6a143c199ab0ae5ee9328e08ce"), - buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_aggregate_modification( - &ctx, NEM_NETWORK_TESTNET, 0, NULL, 22000000, 0, 2, false)); - - ck_assert(nem_transaction_write_cosignatory_modification( - &ctx, 1, - fromhex( - "994793ba1c789fa9bdea918afc9b06e2d0309beb1081ac5b6952991e4defd324"))); - ck_assert(nem_transaction_write_cosignatory_modification( - &ctx, 1, - fromhex( - "c54d6e33ed1446eedd7f7a80a588dd01857f723687a09200c1917d5524752f8b"))); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq( - hash, - fromhex( - "6a55471b17159e5b6cd579c421e95a4e39d92e3f78b0a55ee337e785a601d3a2"), - sizeof(hash)); - - // http://bob.nem.ninja:8765/#/aggregate/1fbdae5ba753e68af270930413ae90f671eb8ab58988116684bac0abd5726584 - - nem_transaction_start( - &ctx, - fromhex( - "6bf7849c1eec6a2002995cc457dc00c4e29bad5c88de63f51e42dfdcd7b2131d"), - buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_aggregate_modification( - &ctx, NEM_NETWORK_TESTNET, 6542254, NULL, 40000000, 6545854, 4, true)); - - ck_assert(nem_transaction_write_cosignatory_modification( - &ctx, 1, - fromhex( - "5f53d076c8c3ec3110b98364bc423092c3ec2be2b1b3c40fd8ab68d54fa39295"))); - ck_assert(nem_transaction_write_cosignatory_modification( - &ctx, 1, - fromhex( - "9eb199c2b4d406f64cb7aa5b2b0815264b56ba8fe44d558a6cb423a31a33c4c2"))); - ck_assert(nem_transaction_write_cosignatory_modification( - &ctx, 1, - fromhex( - "94b2323dab23a3faba24fa6ddda0ece4fbb06acfedd74e76ad9fae38d006882b"))); - ck_assert(nem_transaction_write_cosignatory_modification( - &ctx, 1, - fromhex( - "d88c6ee2a2cd3929d0d76b6b14ecb549d21296ab196a2b3a4cb2536bcce32e87"))); - - ck_assert(nem_transaction_write_minimum_cosignatories(&ctx, 2)); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq( - hash, - fromhex( - "1fbdae5ba753e68af270930413ae90f671eb8ab58988116684bac0abd5726584"), - sizeof(hash)); - - // http://chain.nem.ninja/#/aggregate/cc64ca69bfa95db2ff7ac1e21fe6d27ece189c603200ebc9778d8bb80ca25c3c - - nem_transaction_start( - &ctx, - fromhex( - "f41b99320549741c5cce42d9e4bb836d98c50ed5415d0c3c2912d1bb50e6a0e5"), - buffer, sizeof(buffer)); - - ck_assert(nem_transaction_create_aggregate_modification( - &ctx, NEM_NETWORK_MAINNET, 0, NULL, 40000000, 0, 5, false)); - - ck_assert(nem_transaction_write_cosignatory_modification( - &ctx, 1, - fromhex( - "1fbdbdde28daf828245e4533765726f0b7790e0b7146e2ce205df3e86366980b"))); - ck_assert(nem_transaction_write_cosignatory_modification( - &ctx, 1, - fromhex( - "f94e8702eb1943b23570b1b83be1b81536df35538978820e98bfce8f999e2d37"))); - ck_assert(nem_transaction_write_cosignatory_modification( - &ctx, 1, - fromhex( - "826cedee421ff66e708858c17815fcd831a4bb68e3d8956299334e9e24380ba8"))); - ck_assert(nem_transaction_write_cosignatory_modification( - &ctx, 1, - fromhex( - "719862cd7d0f4e875a6a0274c9a1738f38f40ad9944179006a54c34724c1274d"))); - ck_assert(nem_transaction_write_cosignatory_modification( - &ctx, 1, - fromhex( - "43aa69177018fc3e2bdbeb259c81cddf24be50eef9c5386db51d82386c41475a"))); - - keccak_256(ctx.buffer, ctx.offset, hash); - ck_assert_mem_eq( - hash, - fromhex( - "cc64ca69bfa95db2ff7ac1e21fe6d27ece189c603200ebc9778d8bb80ca25c3c"), - sizeof(hash)); -} -END_TEST - -START_TEST(test_multibyte_address) { - uint8_t priv_key[32]; - char wif[57]; - uint8_t pub_key[33]; - char address[40]; - uint8_t decode[24]; - int res; - - memcpy( - priv_key, - fromhex( - "47f7616ea6f9b923076625b4488115de1ef1187f760e65f89eb6f4f7ff04b012"), - 32); - ecdsa_get_wif(priv_key, 0, HASHER_SHA2D, wif, sizeof(wif)); - ck_assert_str_eq(wif, "13QtoXmbhELWcrwD9YA9KzvXy5rTaptiNuFR8L8ArpBNn4xmQj4N"); - ecdsa_get_wif(priv_key, 0x12, HASHER_SHA2D, wif, sizeof(wif)); - ck_assert_str_eq(wif, "3hrF6SFnqzpzABB36uGDf8dJSuUCcMmoJrTmCWMshRkBr2Vx86qJ"); - ecdsa_get_wif(priv_key, 0x1234, HASHER_SHA2D, wif, sizeof(wif)); - ck_assert_str_eq(wif, - "CtPTF9awbVbfDWGepGdVhB3nBhr4HktUGya8nf8dLxgC8tbqBreB9"); - ecdsa_get_wif(priv_key, 0x123456, HASHER_SHA2D, wif, sizeof(wif)); - ck_assert_str_eq(wif, - "uTrDevVQt5QZgoL3iJ1cPWHaCz7ZMBncM7QXZfCegtxiMHqBvWoYJa"); - ecdsa_get_wif(priv_key, 0x12345678, HASHER_SHA2D, wif, sizeof(wif)); - ck_assert_str_eq(wif, - "4zZWMzv1SVbs95pmLXWrXJVp9ntPEam1mfwb6CXBLn9MpWNxLg9huYgv"); - ecdsa_get_wif(priv_key, 0xffffffff, HASHER_SHA2D, wif, sizeof(wif)); - ck_assert_str_eq(wif, - "y9KVfV1RJXcTxpVjeuh6WYWh8tMwnAUeyUwDEiRviYdrJ61njTmnfUjE"); - - memcpy( - pub_key, - fromhex( - "0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71"), - 33); - ecdsa_get_address(pub_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8"); - ecdsa_get_address(pub_key, 0x12, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "8SCrMR2yYF7ciqoDbav7VLLTsVx5dTVPPq"); - ecdsa_get_address(pub_key, 0x1234, HASHER_SHA2_RIPEMD, HASHER_SHA2D, address, - sizeof(address)); - ck_assert_str_eq(address, "ZLH8q1UgMPg8o2s1MD55YVMpPV7vqms9kiV"); - ecdsa_get_address(pub_key, 0x123456, HASHER_SHA2_RIPEMD, HASHER_SHA2D, - address, sizeof(address)); - ck_assert_str_eq(address, "3ThqvsQVFnbiF66NwHtfe2j6AKn75DpLKpQSq"); - ecdsa_get_address(pub_key, 0x12345678, HASHER_SHA2_RIPEMD, HASHER_SHA2D, - address, sizeof(address)); - ck_assert_str_eq(address, "BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44"); - ecdsa_get_address(pub_key, 0xffffffff, HASHER_SHA2_RIPEMD, HASHER_SHA2D, - address, sizeof(address)); - ck_assert_str_eq(address, "3diW7paWGJyZRLGqMJZ55DMfPExob8QxQHkrfYT"); - - res = ecdsa_address_decode("1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8", 0, - HASHER_SHA2D, decode); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(decode, - fromhex("0079fbfc3f34e7745860d76137da68f362380c606c"), 21); - res = ecdsa_address_decode("8SCrMR2yYF7ciqoDbav7VLLTsVx5dTVPPq", 0x12, - HASHER_SHA2D, decode); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(decode, - fromhex("1279fbfc3f34e7745860d76137da68f362380c606c"), 21); - res = ecdsa_address_decode("ZLH8q1UgMPg8o2s1MD55YVMpPV7vqms9kiV", 0x1234, - HASHER_SHA2D, decode); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq(decode, - fromhex("123479fbfc3f34e7745860d76137da68f362380c606c"), 21); - res = ecdsa_address_decode("3ThqvsQVFnbiF66NwHtfe2j6AKn75DpLKpQSq", 0x123456, - HASHER_SHA2D, decode); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq( - decode, fromhex("12345679fbfc3f34e7745860d76137da68f362380c606c"), 21); - res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", - 0x12345678, HASHER_SHA2D, decode); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq( - decode, fromhex("1234567879fbfc3f34e7745860d76137da68f362380c606c"), 21); - res = ecdsa_address_decode("3diW7paWGJyZRLGqMJZ55DMfPExob8QxQHkrfYT", - 0xffffffff, HASHER_SHA2D, decode); - ck_assert_int_eq(res, 1); - ck_assert_mem_eq( - decode, fromhex("ffffffff79fbfc3f34e7745860d76137da68f362380c606c"), 21); - - // wrong length - res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", 0x123456, - HASHER_SHA2D, decode); - ck_assert_int_eq(res, 0); - - // wrong address prefix - res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", - 0x22345678, HASHER_SHA2D, decode); - ck_assert_int_eq(res, 0); - - // wrong checksum - res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL45", - 0x12345678, HASHER_SHA2D, decode); - ck_assert_int_eq(res, 0); -} -END_TEST - -// https://tools.ietf.org/html/rfc6229#section-2 -START_TEST(test_rc4_rfc6229) { - static const size_t offsets[] = { - 0x0, 0xf0, 0x1f0, 0x2f0, 0x3f0, 0x5f0, 0x7f0, 0xbf0, 0xff0, - }; - - static const struct { - char key[65]; - char vectors[sizeof(offsets) / sizeof(*offsets)][65]; - } tests[] = { - {"0102030405", - { - "b2396305f03dc027ccc3524a0a1118a8" - "6982944f18fc82d589c403a47a0d0919", - "28cb1132c96ce286421dcaadb8b69eae" - "1cfcf62b03eddb641d77dfcf7f8d8c93", - "42b7d0cdd918a8a33dd51781c81f4041" - "6459844432a7da923cfb3eb4980661f6", - "ec10327bde2beefd18f9277680457e22" - "eb62638d4f0ba1fe9fca20e05bf8ff2b", - "45129048e6a0ed0b56b490338f078da5" - "30abbcc7c20b01609f23ee2d5f6bb7df", - "3294f744d8f9790507e70f62e5bbceea" - "d8729db41882259bee4f825325f5a130", - "1eb14a0c13b3bf47fa2a0ba93ad45b8b" - "cc582f8ba9f265e2b1be9112e975d2d7", - "f2e30f9bd102ecbf75aaade9bc35c43c" - "ec0e11c479dc329dc8da7968fe965681", - "068326a2118416d21f9d04b2cd1ca050" - "ff25b58995996707e51fbdf08b34d875", - }}, - {"01020304050607", - { - "293f02d47f37c9b633f2af5285feb46b" - "e620f1390d19bd84e2e0fd752031afc1", - "914f02531c9218810df60f67e338154c" - "d0fdb583073ce85ab83917740ec011d5", - "75f81411e871cffa70b90c74c592e454" - "0bb87202938dad609e87a5a1b079e5e4", - "c2911246b612e7e7b903dfeda1dad866" - "32828f91502b6291368de8081de36fc2", - "f3b9a7e3b297bf9ad804512f9063eff1" - "8ecb67a9ba1f55a5a067e2b026a3676f", - "d2aa902bd42d0d7cfd340cd45810529f" - "78b272c96e42eab4c60bd914e39d06e3", - "f4332fd31a079396ee3cee3f2a4ff049" - "05459781d41fda7f30c1be7e1246c623", - "adfd3868b8e51485d5e610017e3dd609" - "ad26581c0c5be45f4cea01db2f3805d5", - "f3172ceffc3b3d997c85ccd5af1a950c" - "e74b0b9731227fd37c0ec08a47ddd8b8", - }}, - {"0102030405060708", - { - "97ab8a1bf0afb96132f2f67258da15a8" - "8263efdb45c4a18684ef87e6b19e5b09", - "9636ebc9841926f4f7d1f362bddf6e18" - "d0a990ff2c05fef5b90373c9ff4b870a", - "73239f1db7f41d80b643c0c52518ec63" - "163b319923a6bdb4527c626126703c0f", - "49d6c8af0f97144a87df21d91472f966" - "44173a103b6616c5d5ad1cee40c863d0", - "273c9c4b27f322e4e716ef53a47de7a4" - "c6d0e7b226259fa9023490b26167ad1d", - "1fe8986713f07c3d9ae1c163ff8cf9d3" - "8369e1a965610be887fbd0c79162aafb", - "0a0127abb44484b9fbef5abcae1b579f" - "c2cdadc6402e8ee866e1f37bdb47e42c", - "26b51ea37df8e1d6f76fc3b66a7429b3" - "bc7683205d4f443dc1f29dda3315c87b", - "d5fa5a3469d29aaaf83d23589db8c85b" - "3fb46e2c8f0f068edce8cdcd7dfc5862", - }}, - {"0102030405060708090a", - { - "ede3b04643e586cc907dc21851709902" - "03516ba78f413beb223aa5d4d2df6711", - "3cfd6cb58ee0fdde640176ad0000044d" - "48532b21fb6079c9114c0ffd9c04a1ad", - "3e8cea98017109979084b1ef92f99d86" - "e20fb49bdb337ee48b8d8dc0f4afeffe", - "5c2521eacd7966f15e056544bea0d315" - "e067a7031931a246a6c3875d2f678acb", - "a64f70af88ae56b6f87581c0e23e6b08" - "f449031de312814ec6f319291f4a0516", - "bdae85924b3cb1d0a2e33a30c6d79599" - "8a0feddbac865a09bcd127fb562ed60a", - "b55a0a5b51a12a8be34899c3e047511a" - "d9a09cea3ce75fe39698070317a71339", - "552225ed1177f44584ac8cfa6c4eb5fc" - "7e82cbabfc95381b080998442129c2f8", - "1f135ed14ce60a91369d2322bef25e3c" - "08b6be45124a43e2eb77953f84dc8553", - }}, - {"0102030405060708090a0b0c0d0e0f10", - { - "9ac7cc9a609d1ef7b2932899cde41b97" - "5248c4959014126a6e8a84f11d1a9e1c", - "065902e4b620f6cc36c8589f66432f2b" - "d39d566bc6bce3010768151549f3873f", - "b6d1e6c4a5e4771cad79538df295fb11" - "c68c1d5c559a974123df1dbc52a43b89", - "c5ecf88de897fd57fed301701b82a259" - "eccbe13de1fcc91c11a0b26c0bc8fa4d", - "e7a72574f8782ae26aabcf9ebcd66065" - "bdf0324e6083dcc6d3cedd3ca8c53c16", - "b40110c4190b5622a96116b0017ed297" - "ffa0b514647ec04f6306b892ae661181", - "d03d1bc03cd33d70dff9fa5d71963ebd" - "8a44126411eaa78bd51e8d87a8879bf5", - "fabeb76028ade2d0e48722e46c4615a3" - "c05d88abd50357f935a63c59ee537623", - "ff38265c1642c1abe8d3c2fe5e572bf8" - "a36a4c301ae8ac13610ccbc12256cacc", - }}, - {"0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20", - { - "eaa6bd25880bf93d3f5d1e4ca2611d91" - "cfa45c9f7e714b54bdfa80027cb14380", - "114ae344ded71b35f2e60febad727fd8" - "02e1e7056b0f623900496422943e97b6", - "91cb93c787964e10d9527d999c6f936b" - "49b18b42f8e8367cbeb5ef104ba1c7cd", - "87084b3ba700bade955610672745b374" - "e7a7b9e9ec540d5ff43bdb12792d1b35", - "c799b596738f6b018c76c74b1759bd90" - "7fec5bfd9f9b89ce6548309092d7e958", - "40f250b26d1f096a4afd4c340a588815" - "3e34135c79db010200767651cf263073", - "f656abccf88dd827027b2ce917d464ec" - "18b62503bfbc077fbabb98f20d98ab34", - "8aed95ee5b0dcbfbef4eb21d3a3f52f9" - "625a1ab00ee39a5327346bddb01a9c18", - "a13a7c79c7e119b5ab0296ab28c300b9" - "f3e4c0a2e02d1d01f7f0a74618af2b48", - }}, - {"833222772a", - { - "80ad97bdc973df8a2e879e92a497efda" - "20f060c2f2e5126501d3d4fea10d5fc0", - "faa148e99046181fec6b2085f3b20ed9" - "f0daf5bab3d596839857846f73fbfe5a", - "1c7e2fc4639232fe297584b296996bc8" - "3db9b249406cc8edffac55ccd322ba12", - "e4f9f7e0066154bbd125b745569bc897" - "75d5ef262b44c41a9cf63ae14568e1b9", - "6da453dbf81e82334a3d8866cb50a1e3" - "7828d074119cab5c22b294d7a9bfa0bb", - "adb89cea9a15fbe617295bd04b8ca05c" - "6251d87fd4aaae9a7e4ad5c217d3f300", - "e7119bd6dd9b22afe8f89585432881e2" - "785b60fd7ec4e9fcb6545f350d660fab", - "afecc037fdb7b0838eb3d70bcd268382" - "dbc1a7b49d57358cc9fa6d61d73b7cf0", - "6349d126a37afcba89794f9804914fdc" - "bf42c3018c2f7c66bfde524975768115", - }}, - {"1910833222772a", - { - "bc9222dbd3274d8fc66d14ccbda6690b" - "7ae627410c9a2be693df5bb7485a63e3", - "3f0931aa03defb300f060103826f2a64" - "beaa9ec8d59bb68129f3027c96361181", - "74e04db46d28648d7dee8a0064b06cfe" - "9b5e81c62fe023c55be42f87bbf932b8", - "ce178fc1826efecbc182f57999a46140" - "8bdf55cd55061c06dba6be11de4a578a", - "626f5f4dce652501f3087d39c92cc349" - "42daac6a8f9ab9a7fd137c6037825682", - "cc03fdb79192a207312f53f5d4dc33d9" - "f70f14122a1c98a3155d28b8a0a8a41d", - "2a3a307ab2708a9c00fe0b42f9c2d6a1" - "862617627d2261eab0b1246597ca0ae9", - "55f877ce4f2e1ddbbf8e13e2cde0fdc8" - "1b1556cb935f173337705fbb5d501fc1", - "ecd0e96602be7f8d5092816cccf2c2e9" - "027881fab4993a1c262024a94fff3f61", - }}, - {"641910833222772a", - { - "bbf609de9413172d07660cb680716926" - "46101a6dab43115d6c522b4fe93604a9", - "cbe1fff21c96f3eef61e8fe0542cbdf0" - "347938bffa4009c512cfb4034b0dd1a7", - "7867a786d00a7147904d76ddf1e520e3" - "8d3e9e1caefcccb3fbf8d18f64120b32", - "942337f8fd76f0fae8c52d7954810672" - "b8548c10f51667f6e60e182fa19b30f7", - "0211c7c6190c9efd1237c34c8f2e06c4" - "bda64f65276d2aacb8f90212203a808e", - "bd3820f732ffb53ec193e79d33e27c73" - "d0168616861907d482e36cdac8cf5749", - "97b0f0f224b2d2317114808fb03af7a0" - "e59616e469787939a063ceea9af956d1", - "c47e0dc1660919c11101208f9e69aa1f" - "5ae4f12896b8379a2aad89b5b553d6b0", - "6b6b098d0c293bc2993d80bf0518b6d9" - "8170cc3ccd92a698621b939dd38fe7b9", - }}, - {"8b37641910833222772a", - { - "ab65c26eddb287600db2fda10d1e605c" - "bb759010c29658f2c72d93a2d16d2930", - "b901e8036ed1c383cd3c4c4dd0a6ab05" - "3d25ce4922924c55f064943353d78a6c", - "12c1aa44bbf87e75e611f69b2c38f49b" - "28f2b3434b65c09877470044c6ea170d", - "bd9ef822de5288196134cf8af7839304" - "67559c23f052158470a296f725735a32", - "8bab26fbc2c12b0f13e2ab185eabf241" - "31185a6d696f0cfa9b42808b38e132a2", - "564d3dae183c5234c8af1e51061c44b5" - "3c0778a7b5f72d3c23a3135c7d67b9f4", - "f34369890fcf16fb517dcaae4463b2dd" - "02f31c81e8200731b899b028e791bfa7", - "72da646283228c14300853701795616f" - "4e0a8c6f7934a788e2265e81d6d0c8f4", - "438dd5eafea0111b6f36b4b938da2a68" - "5f6bfc73815874d97100f086979357d8", - }}, - {"ebb46227c6cc8b37641910833222772a", - { - "720c94b63edf44e131d950ca211a5a30" - "c366fdeacf9ca80436be7c358424d20b", - "b3394a40aabf75cba42282ef25a0059f" - "4847d81da4942dbc249defc48c922b9f", - "08128c469f275342adda202b2b58da95" - "970dacef40ad98723bac5d6955b81761", - "3cb89993b07b0ced93de13d2a11013ac" - "ef2d676f1545c2c13dc680a02f4adbfe", - "b60595514f24bc9fe522a6cad7393644" - "b515a8c5011754f59003058bdb81514e", - "3c70047e8cbc038e3b9820db601da495" - "1175da6ee756de46a53e2b075660b770", - "00a542bba02111cc2c65b38ebdba587e" - "5865fdbb5b48064104e830b380f2aede", - "34b21ad2ad44e999db2d7f0863f0d9b6" - "84a9218fc36e8a5f2ccfbeae53a27d25", - "a2221a11b833ccb498a59540f0545f4a" - "5bbeb4787d59e5373fdbea6c6f75c29b", - }}, - {"c109163908ebe51debb46227c6cc8b37641910833222772a", - { - "54b64e6b5a20b5e2ec84593dc7989da7" - "c135eee237a85465ff97dc03924f45ce", - "cfcc922fb4a14ab45d6175aabbf2d201" - "837b87e2a446ad0ef798acd02b94124f", - "17a6dbd664926a0636b3f4c37a4f4694" - "4a5f9f26aeeed4d4a25f632d305233d9", - "80a3d01ef00c8e9a4209c17f4eeb358c" - "d15e7d5ffaaabc0207bf200a117793a2", - "349682bf588eaa52d0aa1560346aeafa" - "f5854cdb76c889e3ad63354e5f7275e3", - "532c7ceccb39df3236318405a4b1279c" - "baefe6d9ceb651842260e0d1e05e3b90", - "e82d8c6db54e3c633f581c952ba04207" - "4b16e50abd381bd70900a9cd9a62cb23", - "3682ee33bd148bd9f58656cd8f30d9fb" - "1e5a0b8475045d9b20b2628624edfd9e", - "63edd684fb826282fe528f9c0e9237bc" - "e4dd2e98d6960fae0b43545456743391", - }}, - {"1ada31d5cf688221c109163908ebe51debb46227c6cc8b37641910833222772a", - { - "dd5bcb0018e922d494759d7c395d02d3" - "c8446f8f77abf737685353eb89a1c9eb", - "af3e30f9c095045938151575c3fb9098" - "f8cb6274db99b80b1d2012a98ed48f0e", - "25c3005a1cb85de076259839ab7198ab" - "9dcbc183e8cb994b727b75be3180769c", - "a1d3078dfa9169503ed9d4491dee4eb2" - "8514a5495858096f596e4bcd66b10665", - "5f40d59ec1b03b33738efa60b2255d31" - "3477c7f764a41baceff90bf14f92b7cc", - "ac4e95368d99b9eb78b8da8f81ffa795" - "8c3c13f8c2388bb73f38576e65b7c446", - "13c4b9c1dfb66579eddd8a280b9f7316" - "ddd27820550126698efaadc64b64f66e", - "f08f2e66d28ed143f3a237cf9de73559" - "9ea36c525531b880ba124334f57b0b70", - "d5a39e3dfcc50280bac4a6b5aa0dca7d" - "370b1c1fe655916d97fd0d47ca1d72b8", - }}}; - - RC4_CTX ctx; - uint8_t key[64]; - uint8_t buffer[0x1010]; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - size_t length = strlen(tests[i].key) / 2; - memcpy(key, fromhex(tests[i].key), length); - memzero(buffer, sizeof(buffer)); - - rc4_init(&ctx, key, length); - rc4_encrypt(&ctx, buffer, sizeof(buffer)); - - for (size_t j = 0; j < (sizeof(offsets) / sizeof(*offsets)); j++) { - size_t size = strlen(tests[i].vectors[j]) / 2; - ck_assert_mem_eq(&buffer[offsets[j]], fromhex(tests[i].vectors[j]), size); - } - } -} -END_TEST - -static void test_compress_coord(const char *k_raw) { - const ecdsa_curve *curve = &secp256k1; - curve_point expected_coords; - - bignum256 k = {0}; - - bn_read_be(fromhex(k_raw), &k); - - point_multiply(curve, &k, &curve->G, &expected_coords); - - uint8_t compress[33] = {0}; - compress_coords(&expected_coords, compress); - - bignum256 x = {0}, y = {0}; - bn_read_be(compress + 1, &x); - uncompress_coords(curve, compress[0], &x, &y); - - ck_assert(bn_is_equal(&expected_coords.x, &x)); - ck_assert(bn_is_equal(&expected_coords.y, &y)); -} - -START_TEST(test_compress_coords) { - static const char *k_raw[] = { - "dc05960ac673fd59554c98655e26722d007bb7ada0c8ff00883fdee70783d0be", - "41e41e0a218c980411108a0a58cf88f528c828b4d6f0d2c86234bc2504bdc3cd", - "1d963ddcb79f6028a32cadd2421ff7fff969bff5774f73063dab41519b3da175", - "2414141f96da0874dbc374b58861589935b7f940806ddf8d2e6b911f62e240f3", - "01cc1fb182e29f60fe43e22d250de34f2d3f956bbef2aa9b182d09e5d9176873", - "89b3d621d813682692fd61b2baea6b2ea696a44abc76925d29c4887fc4db9367", - "20c80c633e05a3a7dfac05fa0e0a7c7a6b708b02323e687735cff81ea5944f59", - "5a803c263aa93a4f74648066c03e63fb00641193bae93dfa254dabd634e8b49c", - "05efbcc87007797dca68315b9271ac8fb75bddbece53f4dcbfb83fc21cb91fc0", - "0bed78ef43474630bd646eef2d7ec19a1acb8e9eecf6a0a3ac7241ac40a7706f", - }; - - for (int i = 0; i < (int)(sizeof(k_raw) / sizeof(*k_raw)); i++) - test_compress_coord(k_raw[i]); -} -END_TEST - -START_TEST(test_schnorr_sign_verify_digest) { - static struct { - const char *digest; - const char *priv_key; - const char *sig; - } tests[] = { - { - /* Very deterministic message */ - "5255683DA567900BFD3E786ED8836A4E7763C221BF1AC20ECE2A5171B9199E8A", - "12B004FFF7F4B69EF8650E767F18F11EDE158148B425660723B9F9A66E61F747", - "2C56731AC2F7A7E7F11518FC7722A166B02438924CA9D8B4D111347B81D07175" - "71846DE67AD3D913A8FDF9D8F3F73161A4C48AE81CB183B214765FEB86E255CE", - }, - }; - - const ecdsa_curve *curve = &secp256k1; - uint8_t digest[SHA256_DIGEST_LENGTH] = {0}; - uint8_t priv_key[32] = {0}; - uint8_t pub_key[33] = {0}; - uint8_t result[SCHNORR_SIG_LENGTH] = {0}; - uint8_t expected[SCHNORR_SIG_LENGTH] = {0}; - int res = 0; - - for (size_t i = 0; i < sizeof(tests) / sizeof(*tests); i++) { - memcpy(digest, fromhex(tests[i].digest), SHA256_DIGEST_LENGTH); - memcpy(priv_key, fromhex(tests[i].priv_key), 32); - memcpy(expected, fromhex(tests[i].sig), SCHNORR_SIG_LENGTH); - - ecdsa_get_public_key33(curve, priv_key, pub_key); - - schnorr_sign_digest(curve, priv_key, digest, result); - - ck_assert_mem_eq(expected, result, SCHNORR_SIG_LENGTH); - - res = schnorr_verify_digest(curve, pub_key, digest, result); - ck_assert_int_eq(res, 0); - } -} -END_TEST - -START_TEST(test_schnorr_verify_digest) { - static struct { - const char *digest; - const char *pub_key; - const char *sig; - const int res; - } tests[] = { - { - /* Very deterministic message */ - "5255683DA567900BFD3E786ED8836A4E7763C221BF1AC20ECE2A5171B9199E8A", - "030B4C866585DD868A9D62348A9CD008D6A312937048FFF31670E7E920CFC7A744", - "2C56731AC2F7A7E7F11518FC7722A166B02438924CA9D8B4D111347B81D07175" - "71846DE67AD3D913A8FDF9D8F3F73161A4C48AE81CB183B214765FEB86E255CE", - 0, /* Success */ - }, - { - /* - * From Bitcoin ABC libsecp256k1, test vector 1. - * https://github.com/Bitcoin-ABC/secp256k1/blob/master/src/modules/schnorr/tests_impl.h - */ - "0000000000000000000000000000000000000000000000000000000000000000", - "0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", - "787A848E71043D280C50470E8E1532B2DD5D20EE912A45DBDD2BD1DFBF187EF6" - "7031A98831859DC34DFFEEDDA86831842CCD0079E1F92AF177F7F22CC1DCED05", - 0, /* Success */ - }, - { - /* - * From Bitcoin ABC libsecp256k1, test vector 2. - * https://github.com/Bitcoin-ABC/secp256k1/blob/master/src/modules/schnorr/tests_impl.h - */ - "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", - "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", - "2A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D" - "1E51A22CCEC35599B8F266912281F8365FFC2D035A230434A1A64DC59F7013FD", - 0, /* Success */ - }, - { - /* - * From Bitcoin ABC libsecp256k1, test vector 3. - * https://github.com/Bitcoin-ABC/secp256k1/blob/master/src/modules/schnorr/tests_impl.h - */ - "5E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C", - "03FAC2114C2FBB091527EB7C64ECB11F8021CB45E8E7809D3C0938E4B8C0E5F84B", - "00DA9B08172A9B6F0466A2DEFD817F2D7AB437E0D253CB5395A963866B3574BE" - "00880371D01766935B92D2AB4CD5C8A2A5837EC57FED7660773A05F0DE142380", - 0, /* Success */ - }, - { - /* - * From Bitcoin ABC libsecp256k1, test vector 4. - * https://github.com/Bitcoin-ABC/secp256k1/blob/master/src/modules/schnorr/tests_impl.h - */ - "4DF3C3F68FCC83B27E9D42C90431A72499F17875C81A599B566C9889B9696703", - "03DEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34", - "00000000000000000000003B78CE563F89A0ED9414F5AA28AD0D96D6795F9C63" - "02A8DC32E64E86A333F20EF56EAC9BA30B7246D6D25E22ADB8C6BE1AEB08D49D", - 0, /* Success */ - }, - { - /* - * From Bitcoin ABC libsecp256k1, test vector 4b. - * https://github.com/Bitcoin-ABC/secp256k1/blob/master/src/modules/schnorr/tests_impl.h - */ - "0000000000000000000000000000000000000000000000000000000000000000", - "031B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F", - "52818579ACA59767E3291D91B76B637BEF062083284992F2D95F564CA6CB4E35" - "30B1DA849C8E8304ADC0CFE870660334B3CFC18E825EF1DB34CFAE3DFC5D8187", - 0, /* Success */ - }, - { - /* - * From Bitcoin ABC libsecp256k1, test vector 6. - * https://github.com/Bitcoin-ABC/secp256k1/blob/master/src/modules/schnorr/tests_impl.h - */ - "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", - "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", - "2A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D" - "FA16AEE06609280A19B67A24E1977E4697712B5FD2943914ECD5F730901B4AB7", - 6, /* R.y is not a quadratic residue */ - }, - { - /* - * From Bitcoin ABC libsecp256k1, test vector 7. - * https://github.com/Bitcoin-ABC/secp256k1/blob/master/src/modules/schnorr/tests_impl.h - */ - "5E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C", - "03FAC2114C2FBB091527EB7C64ECB11F8021CB45E8E7809D3C0938E4B8C0E5F84B", - "00DA9B08172A9B6F0466A2DEFD817F2D7AB437E0D253CB5395A963866B3574BE" - "D092F9D860F1776A1F7412AD8A1EB50DACCC222BC8C0E26B2056DF2F273EFDEC", - 5, /* Negated message hash, R.x mismatch */ - }, - { - /* - * From Bitcoin ABC libsecp256k1, test vector 8. - * https://github.com/Bitcoin-ABC/secp256k1/blob/master/src/modules/schnorr/tests_impl.h - */ - "0000000000000000000000000000000000000000000000000000000000000000", - "0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", - "787A848E71043D280C50470E8E1532B2DD5D20EE912A45DBDD2BD1DFBF187EF6" - "8FCE5677CE7A623CB20011225797CE7A8DE1DC6CCD4F754A47DA6C600E59543C", - 5, /* Negated s, R.x mismatch */ - }, - { - /* - * From Bitcoin ABC libsecp256k1, test vector 9. - * https://github.com/Bitcoin-ABC/secp256k1/blob/master/src/modules/schnorr/tests_impl.h - */ - "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", - "03DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", - "2A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D" - "1E51A22CCEC35599B8F266912281F8365FFC2D035A230434A1A64DC59F7013FD", - 5, /* Negated P, R.x mismatch */ - }, - { - /* - * From Bitcoin ABC libsecp256k1, test vector 10. - * https://github.com/Bitcoin-ABC/secp256k1/blob/master/src/modules/schnorr/tests_impl.h - */ - "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", - "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", - "2A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D" - "8C3428869A663ED1E954705B020CBB3E7BB6AC31965B9EA4C73E227B17C5AF5A", - 4, /* s * G = e * P, R = 0 */ - }, - { - /* - * From Bitcoin ABC libsecp256k1, test vector 11. - * https://github.com/Bitcoin-ABC/secp256k1/blob/master/src/modules/schnorr/tests_impl.h - */ - "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", - "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", - "4A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D" - "1E51A22CCEC35599B8F266912281F8365FFC2D035A230434A1A64DC59F7013FD", - 5, /* R.x not on the curve, R.x mismatch */ - }, - { - /* - * From Bitcoin ABC libsecp256k1, test vector 12. - * https://github.com/Bitcoin-ABC/secp256k1/blob/master/src/modules/schnorr/tests_impl.h - */ - "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", - "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC2F" - "1E51A22CCEC35599B8F266912281F8365FFC2D035A230434A1A64DC59F7013FD", - 1, /* r = p */ - }, - { - /* - * From Bitcoin ABC libsecp256k1, test vector 13. - * https://github.com/Bitcoin-ABC/secp256k1/blob/master/src/modules/schnorr/tests_impl.h - */ - "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", - "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", - "2A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D" - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", - 1, /* s = n */ - }, - { - /* Very deterministic message */ - "5255683DA567900BFD3E786ED8836A4E7763C221BF1AC20ECE2A5171B9199E8A", - "010B4C866585DD868A9D62348A9CD008D6A312937048FFF31670E7E920CFC7A744", - "2C56731AC2F7A7E7F11518FC7722A166B02438924CA9D8B4D111347B81D07175" - "71846DE67AD3D913A8FDF9D8F3F73161A4C48AE81CB183B214765FEB86E255CE", - 2, /* Invalid public key */ - }, - }; - - const ecdsa_curve *curve = &secp256k1; - uint8_t digest[SHA256_DIGEST_LENGTH] = {0}; - uint8_t pub_key[33] = {0}; - uint8_t signature[SCHNORR_SIG_LENGTH] = {0}; - int res = 0; - - for (size_t i = 0; i < sizeof(tests) / sizeof(*tests); i++) { - memcpy(digest, fromhex(tests[i].digest), SHA256_DIGEST_LENGTH); - memcpy(pub_key, fromhex(tests[i].pub_key), 33); - memcpy(signature, fromhex(tests[i].sig), SCHNORR_SIG_LENGTH); - - res = schnorr_verify_digest(curve, pub_key, digest, signature); - ck_assert_int_eq(res, tests[i].res); - } -} -END_TEST - -static int my_strncasecmp(const char *s1, const char *s2, size_t n) { - size_t i = 0; - while (i < n) { - char c1 = s1[i]; - char c2 = s2[i]; - if (c1 >= 'A' && c1 <= 'Z') c1 = (c1 - 'A') + 'a'; - if (c2 >= 'A' && c2 <= 'Z') c2 = (c2 - 'A') + 'a'; - if (c1 < c2) return -1; - if (c1 > c2) return 1; - if (c1 == 0) return 0; - ++i; - } - return 0; -} - -#include "test_check_cashaddr.h" -#include "test_check_segwit.h" - -#if USE_CARDANO -#include "test_check_cardano.h" -#endif - -#if USE_MONERO -#include "test_check_monero.h" -#endif - -// define test suite and cases -Suite *test_suite(void) { - Suite *s = suite_create("trezor-crypto"); - TCase *tc; - - tc = tcase_create("bignum"); - tcase_add_test(tc, test_bignum_read_be); - tcase_add_test(tc, test_bignum_write_be); - tcase_add_test(tc, test_bignum_is_equal); - tcase_add_test(tc, test_bignum_zero); - tcase_add_test(tc, test_bignum_is_zero); - tcase_add_test(tc, test_bignum_one); - tcase_add_test(tc, test_bignum_read_le); - tcase_add_test(tc, test_bignum_write_le); - tcase_add_test(tc, test_bignum_read_uint32); - tcase_add_test(tc, test_bignum_read_uint64); - tcase_add_test(tc, test_bignum_write_uint32); - tcase_add_test(tc, test_bignum_write_uint64); - tcase_add_test(tc, test_bignum_copy); - tcase_add_test(tc, test_bignum_is_even); - tcase_add_test(tc, test_bignum_is_odd); - tcase_add_test(tc, test_bignum_bitcount); - tcase_add_test(tc, test_bignum_digitcount); - tcase_add_test(tc, test_bignum_is_less); - tcase_add_test(tc, test_bignum_format); - tcase_add_test(tc, test_bignum_format_uint64); - tcase_add_test(tc, test_bignum_sqrt); - suite_add_tcase(s, tc); - - tc = tcase_create("base32"); - tcase_add_test(tc, test_base32_rfc4648); - suite_add_tcase(s, tc); - - tc = tcase_create("base58"); - tcase_add_test(tc, test_base58); - suite_add_tcase(s, tc); - -#if USE_GRAPHENE - tc = tcase_create("base58gph"); - tcase_add_test(tc, test_base58gph); - suite_add_tcase(s, tc); -#endif - - tc = tcase_create("bignum_divmod"); - tcase_add_test(tc, test_bignum_divmod); - suite_add_tcase(s, tc); - - tc = tcase_create("bip32"); - tcase_add_test(tc, test_bip32_vector_1); - tcase_add_test(tc, test_bip32_vector_2); - tcase_add_test(tc, test_bip32_vector_3); - tcase_add_test(tc, test_bip32_vector_4); - tcase_add_test(tc, test_bip32_compare); - tcase_add_test(tc, test_bip32_optimized); - tcase_add_test(tc, test_bip32_cache_1); - tcase_add_test(tc, test_bip32_cache_2); - tcase_add_test(tc, test_bip32_cache_overflow_regression); - tcase_add_test(tc, test_bip32_depth_overflow_regression); - suite_add_tcase(s, tc); - - tc = tcase_create("bip32-nist"); - tcase_add_test(tc, test_bip32_nist_seed); - tcase_add_test(tc, test_bip32_nist_vector_1); - tcase_add_test(tc, test_bip32_nist_vector_2); - tcase_add_test(tc, test_bip32_nist_compare); - tcase_add_test(tc, test_bip32_nist_repeat); - suite_add_tcase(s, tc); - - tc = tcase_create("bip32-ed25519"); - tcase_add_test(tc, test_bip32_ed25519_vector_1); - tcase_add_test(tc, test_bip32_ed25519_vector_2); - suite_add_tcase(s, tc); - - tc = tcase_create("bip32-ecdh"); - tcase_add_test(tc, test_bip32_ecdh_nist256p1); - tcase_add_test(tc, test_bip32_ecdh_curve25519); - tcase_add_test(tc, test_bip32_ecdh_errors); - suite_add_tcase(s, tc); - - tc = tcase_create("bip32-decred"); - tcase_add_test(tc, test_bip32_decred_vector_1); - tcase_add_test(tc, test_bip32_decred_vector_2); - suite_add_tcase(s, tc); - - tc = tcase_create("ecdsa"); - tcase_add_test(tc, test_ecdsa_signature); - tcase_add_test(tc, test_ecdsa_sign_digest_deterministic_regression); - suite_add_tcase(s, tc); - - tc = tcase_create("rfc6979"); - tcase_add_test(tc, test_rfc6979); - suite_add_tcase(s, tc); - - tc = tcase_create("address"); - tcase_add_test(tc, test_address); - suite_add_tcase(s, tc); - - tc = tcase_create("address_decode"); - tcase_add_test(tc, test_address_decode); - suite_add_tcase(s, tc); - - tc = tcase_create("ethereum_address"); - tcase_add_test(tc, test_ethereum_address); - suite_add_tcase(s, tc); - - tc = tcase_create("rsk_address"); - tcase_add_test(tc, test_rsk_address); - suite_add_tcase(s, tc); - - tc = tcase_create("wif"); - tcase_add_test(tc, test_wif); - suite_add_tcase(s, tc); - - tc = tcase_create("ecdsa_der"); - tcase_add_test(tc, test_ecdsa_der); - suite_add_tcase(s, tc); - - tc = tcase_create("aes"); - tcase_add_test(tc, test_aes); - suite_add_tcase(s, tc); - - tc = tcase_create("sha2"); - tcase_add_test(tc, test_sha1); - tcase_add_test(tc, test_sha256); - tcase_add_test(tc, test_sha512); - suite_add_tcase(s, tc); - - tc = tcase_create("sha3"); - tcase_add_test(tc, test_sha3_256); - tcase_add_test(tc, test_sha3_512); - tcase_add_test(tc, test_keccak_256); - suite_add_tcase(s, tc); - - tc = tcase_create("blake"); - tcase_add_test(tc, test_blake256); - suite_add_tcase(s, tc); - - tc = tcase_create("blake2"); - tcase_add_test(tc, test_blake2b); - tcase_add_test(tc, test_blake2s); - suite_add_tcase(s, tc); - - tc = tcase_create("chacha_drbg"); - tcase_add_test(tc, test_chacha_drbg); - suite_add_tcase(s, tc); - - tc = tcase_create("pbkdf2"); - tcase_add_test(tc, test_pbkdf2_hmac_sha256); - tcase_add_test(tc, test_pbkdf2_hmac_sha512); - suite_add_tcase(s, tc); - - tc = tcase_create("hmac_drbg"); - tcase_add_test(tc, test_hmac_drbg); - suite_add_tcase(s, tc); - - tc = tcase_create("bip39"); - tcase_add_test(tc, test_mnemonic); - tcase_add_test(tc, test_mnemonic_check); - tcase_add_test(tc, test_mnemonic_to_bits); - tcase_add_test(tc, test_mnemonic_find_word); - suite_add_tcase(s, tc); - - tc = tcase_create("slip39"); - tcase_add_test(tc, test_slip39_get_word); - tcase_add_test(tc, test_slip39_word_index); - tcase_add_test(tc, test_slip39_word_completion_mask); - tcase_add_test(tc, test_slip39_sequence_to_word); - tcase_add_test(tc, test_slip39_word_completion); - suite_add_tcase(s, tc); - - tc = tcase_create("shamir"); - tcase_add_test(tc, test_shamir); - suite_add_tcase(s, tc); - - tc = tcase_create("pubkey_validity"); - tcase_add_test(tc, test_pubkey_validity); - suite_add_tcase(s, tc); - - tc = tcase_create("pubkey_uncompress"); - tcase_add_test(tc, test_pubkey_uncompress); - suite_add_tcase(s, tc); - - tc = tcase_create("codepoints"); - tcase_add_test(tc, test_codepoints_secp256k1); - tcase_add_test(tc, test_codepoints_nist256p1); - suite_add_tcase(s, tc); - - tc = tcase_create("mult_border_cases"); - tcase_add_test(tc, test_mult_border_cases_secp256k1); - tcase_add_test(tc, test_mult_border_cases_nist256p1); - suite_add_tcase(s, tc); - - tc = tcase_create("scalar_mult"); - tcase_add_test(tc, test_scalar_mult_secp256k1); - tcase_add_test(tc, test_scalar_mult_nist256p1); - suite_add_tcase(s, tc); - - tc = tcase_create("point_mult"); - tcase_add_test(tc, test_point_mult_secp256k1); - tcase_add_test(tc, test_point_mult_nist256p1); - suite_add_tcase(s, tc); - - tc = tcase_create("scalar_point_mult"); - tcase_add_test(tc, test_scalar_point_mult_secp256k1); - tcase_add_test(tc, test_scalar_point_mult_nist256p1); - suite_add_tcase(s, tc); - - tc = tcase_create("ed25519"); - tcase_add_test(tc, test_ed25519); - suite_add_tcase(s, tc); - - tc = tcase_create("ed25519_keccak"); - tcase_add_test(tc, test_ed25519_keccak); - suite_add_tcase(s, tc); - - tc = tcase_create("ed25519_cosi"); - tcase_add_test(tc, test_ed25519_cosi); - suite_add_tcase(s, tc); - - tc = tcase_create("ed25519_modm"); - tcase_add_test(tc, test_ed25519_modl_add); - tcase_add_test(tc, test_ed25519_modl_neg); - tcase_add_test(tc, test_ed25519_modl_sub); - suite_add_tcase(s, tc); - -#if USE_MONERO - tc = tcase_create("ed25519_ge"); - tcase_add_test(tc, test_ge25519_double_scalarmult_vartime2); - suite_add_tcase(s, tc); -#endif - - tc = tcase_create("script"); - tcase_add_test(tc, test_output_script); - suite_add_tcase(s, tc); - - tc = tcase_create("ethereum_pubkeyhash"); - tcase_add_test(tc, test_ethereum_pubkeyhash); - suite_add_tcase(s, tc); - - tc = tcase_create("nem_address"); - tcase_add_test(tc, test_nem_address); - suite_add_tcase(s, tc); - - tc = tcase_create("nem_encryption"); - tcase_add_test(tc, test_nem_derive); - tcase_add_test(tc, test_nem_cipher); - suite_add_tcase(s, tc); - - tc = tcase_create("nem_transaction"); - tcase_add_test(tc, test_nem_transaction_transfer); - tcase_add_test(tc, test_nem_transaction_multisig); - tcase_add_test(tc, test_nem_transaction_provision_namespace); - tcase_add_test(tc, test_nem_transaction_mosaic_creation); - tcase_add_test(tc, test_nem_transaction_mosaic_supply_change); - tcase_add_test(tc, test_nem_transaction_aggregate_modification); - suite_add_tcase(s, tc); - - tc = tcase_create("multibyte_address"); - tcase_add_test(tc, test_multibyte_address); - suite_add_tcase(s, tc); - - tc = tcase_create("rc4"); - tcase_add_test(tc, test_rc4_rfc6229); - suite_add_tcase(s, tc); - - tc = tcase_create("segwit"); - tcase_add_test(tc, test_segwit); - suite_add_tcase(s, tc); - - tc = tcase_create("cashaddr"); - tcase_add_test(tc, test_cashaddr); - suite_add_tcase(s, tc); - - tc = tcase_create("compress_coords"); - tcase_add_test(tc, test_compress_coords); - suite_add_tcase(s, tc); - - tc = tcase_create("schnorr"); - tcase_add_test(tc, test_schnorr_sign_verify_digest); - tcase_add_test(tc, test_schnorr_verify_digest); - suite_add_tcase(s, tc); - -#if USE_CARDANO - tc = tcase_create("bip32-cardano"); - - tcase_add_test(tc, test_bip32_cardano_hdnode_vector_1); - tcase_add_test(tc, test_bip32_cardano_hdnode_vector_2); - tcase_add_test(tc, test_bip32_cardano_hdnode_vector_3); - tcase_add_test(tc, test_bip32_cardano_hdnode_vector_4); - tcase_add_test(tc, test_bip32_cardano_hdnode_vector_5); - tcase_add_test(tc, test_bip32_cardano_hdnode_vector_6); - tcase_add_test(tc, test_bip32_cardano_hdnode_vector_7); - tcase_add_test(tc, test_bip32_cardano_hdnode_vector_8); - tcase_add_test(tc, test_bip32_cardano_hdnode_vector_9); - - tcase_add_test(tc, test_ed25519_cardano_sign_vectors); - suite_add_tcase(s, tc); -#endif - -#if USE_MONERO - tc = tcase_create("xmr_base58"); - tcase_add_test(tc, test_xmr_base58); - suite_add_tcase(s, tc); - - tc = tcase_create("xmr_crypto"); - tcase_add_test(tc, test_xmr_getset256_modm); - tcase_add_test(tc, test_xmr_cmp256_modm); - tcase_add_test(tc, test_xmr_copy_check_modm); - tcase_add_test(tc, test_xmr_mulsub256_modm); - tcase_add_test(tc, test_xmr_muladd256_modm); - tcase_add_test(tc, test_xmr_curve25519_set); - tcase_add_test(tc, test_xmr_curve25519_consts); - tcase_add_test(tc, test_xmr_curve25519_tests); - tcase_add_test(tc, test_xmr_curve25519_expand_reduce); - tcase_add_test(tc, test_xmr_ge25519_base); - tcase_add_test(tc, test_xmr_ge25519_check); - tcase_add_test(tc, test_xmr_ge25519_scalarmult_base_wrapper); - tcase_add_test(tc, test_xmr_ge25519_scalarmult); - tcase_add_test(tc, test_xmr_ge25519_ops); - suite_add_tcase(s, tc); - - tc = tcase_create("xmr_xmr"); - tcase_add_test(tc, test_xmr_check_point); - tcase_add_test(tc, test_xmr_h); - tcase_add_test(tc, test_xmr_fast_hash); - tcase_add_test(tc, test_xmr_hasher); - tcase_add_test(tc, test_xmr_hash_to_scalar); - tcase_add_test(tc, test_xmr_hash_to_ec); - tcase_add_test(tc, test_xmr_derivation_to_scalar); - tcase_add_test(tc, test_xmr_generate_key_derivation); - tcase_add_test(tc, test_xmr_derive_private_key); - tcase_add_test(tc, test_xmr_derive_public_key); - tcase_add_test(tc, test_xmr_add_keys2); - tcase_add_test(tc, test_xmr_add_keys3); - tcase_add_test(tc, test_xmr_get_subaddress_secret_key); - tcase_add_test(tc, test_xmr_gen_c); - tcase_add_test(tc, test_xmr_varint); - tcase_add_test(tc, test_xmr_gen_range_sig); - suite_add_tcase(s, tc); -#endif - return s; -} - -// run suite -int main(void) { - int number_failed; - Suite *s = test_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_VERBOSE); - number_failed = srunner_ntests_failed(sr); - srunner_free(sr); - if (number_failed == 0) { - printf("PASSED ALL TESTS\n"); - } - return number_failed; -} diff --git a/deps/crypto/trezor-crypto/tests/test_check_cardano.h b/deps/crypto/trezor-crypto/tests/test_check_cardano.h deleted file mode 100644 index 3abe5c715..000000000 --- a/deps/crypto/trezor-crypto/tests/test_check_cardano.h +++ /dev/null @@ -1,468 +0,0 @@ -// https://github.com/input-output-hk/cardano-crypto/blob/master/tests/goldens/cardano/crypto/wallet/BIP39-128 -START_TEST(test_ed25519_cardano_sign_vectors) { - ed25519_public_key public_key; - ed25519_secret_key secret_key; - ed25519_secret_key secret_key_extension; - ed25519_signature signature; - - static const char *vectors[] = { - "6065a956b1b34145c4416fdc3ba3276801850e91a77a31a7be782463288aea5" - "3", // private key - "60ba6e25b1a02157fb69c5d1d7b96c4619736e545447069a6a6f0ba90844bc8" - "e", // private key extension - "64b20fa082b3143d6b5eed42c6ef63f99599d0888afe060620abc1b319935fe" - "1", // public key - "45b1a75fe3119e13c6f60ab9ba674b42f946fdc558e07c83dfa0751c2eba69c7" - "9331bd8a4a975662b23628a438a0eba76367e44c12ca91b39ec59063f860f10" - "d", // signature - - "e7d27516538403a53a8b041656a3f570909df641a0ab811fe7d87c9ba02a830" - "c", // private key - "794a2c54ad8b525b781773c87d38cbf4197636bc427a9d551368286fe4c294a" - "4", // private key extension - "95bb82ffd5707716bc65170ab4e8dafeed90fbe0ce9258713b7751e962d931d" - "f", // public key - "f2c9171782e7df7665126ac545ae53b05964b0160536efdb545e2460dbbec2b1" - "9ec6b338b8f1bf4dfee94360ed024b115e37b1d7e6f3f9ae4beb79539428560" - "f", // signature - - "9b5a3d9a4c60bcd49bb64b72c082b164314d0f61d842f2575fd1d4fb30a28a0" - "c", // private key - "b093e376f41eb7bf80abcd0073a52455d25b5d21815bc758e5f6f81536aedeb" - "b", // private key extension - "79fc8154554b97e4c56ef2f9dbb4c1421ff19509688931a1e964bda5dec0f19" - "f", // public key - "2ba1439ae648a7e8da7c9ab1ee6da94fd4ebe37abd0978306e8fba2afa8f111a" - "88a993dbf008bedae9167f4f68409e4c9ddaf02cba12418447b1848907ad800" - "f", // signature - - "52e0c98aa600cfdcd1ff28fcda5227ed87063f4a98547a78b771052cf102b40" - "c", // private key - "6c18d9f8075b1a6a1833540607479bd58b7beb8a83d2bb01ca7ae02452a2580" - "3", // private key extension - "dc907c7c06e6314eedd9e18c9f6c6f9cc4e205fb1c70da608234c319f1f7b0d" - "6", // public key - "0cd34f84e0d2fcb1800bdb0e869b9041349955ced66aedbe6bda187ebe8d36a6" - "2a05b39647e92fcc42aa7a7368174240afba08b8c81f981a22f942d6bd78160" - "2", // signature - - "11fd6462a3a92b35c22703f6f1c124ddcf36b7c2b09cc2784f320e1cfa12ec0" - "4", // private key - "c2785803c61c46aeca192a1bb1b7b20a8c4cc7fa01db57fc5d1d8a547340235" - "2", // private key extension - "839775a41876e328986aa26168958bba1176e67819b357eea84afceab8b1db7" - "8", // public key - "e41f73db2f8d2896a687802b2be76b7cabb73dfbb4891494883a0cbd9bbb9e5f" - "9d3e14d2d0b06c6674333508496db660936737c0efd9511514147dac79fa490" - "5", // signature - - "5b1e5cad02274ba461f4708d8598d3497faf8fe3e894a379573aa6ac3a03e50" - "5", // private key - "ba179d2e3c67aabb486c48d16002b51ad32eab434c738a1550962313b07098c" - "d", // private key extension - "75eb8d197ec8627c85af88e66aa1e49065dd8ac98ed8991db52ece01635dfb7" - "6", // public key - "631015357cee3051116b4c2ff4d1c5beb13b6e5023635aa1eeb0563cadf0d4fb" - "c10bd5e31b4a4220c67875558c41b5cc0328104ae39cc7ff20ff0c2bda59890" - "6", // signature - - "624b47150f58dfa44284fbc63c9f99b9b79f808c4955a461f0e2be44eb0be50" - "d", // private key - "097aa006d694b165ef37cf23562e5967c96e49255d2f20faae478dee83aa5b0" - "2", // private key extension - "0588589cd9b51dfc028cf225674069cbe52e0e70deb02dc45b79b26ee3548b0" - "0", // public key - "1de1d275428ba9491a433cd473cd076c027f61e7a8b5391df9dea5cb4bc88d8a" - "57b095906a30b13e68259851a8dd3f57b6f0ffa37a5d3ffc171240f2d404f90" - "1", // signature - - 0, - 0, - }; - - const char **test_data; - test_data = vectors; - while (*test_data) { - memcpy(secret_key, fromhex(*test_data), 32); - MARK_SECRET_DATA(secret_key, sizeof(secret_key)); - - memcpy(secret_key_extension, fromhex(*(test_data + 1)), 32); - MARK_SECRET_DATA(secret_key_extension, sizeof(secret_key_extension)); - - ed25519_publickey_ext(secret_key, secret_key_extension, public_key); - UNMARK_SECRET_DATA(public_key, sizeof(public_key)); - - ck_assert_mem_eq(public_key, fromhex(*(test_data + 2)), 32); - - const uint8_t *message = (const uint8_t *)"Hello World"; - ed25519_sign_ext(message, 11, secret_key, secret_key_extension, signature); - UNMARK_SECRET_DATA(signature, sizeof(signature)); - - ck_assert_mem_eq(signature, fromhex(*(test_data + 3)), 64); - - UNMARK_SECRET_DATA(secret_key, sizeof(secret_key)); - UNMARK_SECRET_DATA(secret_key_extension, sizeof(secret_key_extension)); - - test_data += 4; - } -} -END_TEST - -START_TEST(test_bip32_cardano_hdnode_vector_1) { - HDNode node; - - uint8_t mnemonic_bits[66]; - int mnemonic_bits_len = mnemonic_to_bits( - "ring crime symptom enough erupt lady behave ramp apart settle citizen " - "junk", - mnemonic_bits); - ck_assert_int_eq(mnemonic_bits_len, 132); - hdnode_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, - mnemonic_bits_len / 8, &node); - - ck_assert_mem_eq( - node.chain_code, - fromhex( - "affbc325d9027c0f2d9f925b1dcf6c12bf5c1dd08904474066a4f2c00db56173"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "08a14df748e477a69d21c97c56db151fc19e2521f31dd0ac5360f269e5b6ea46"), - 32); - ck_assert_mem_eq( - node.private_key_extension, - fromhex( - "daeb991f2d2128e2525415c56a07f4366baa26c1e48572a5e073934b6de35fbc"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key + 1, - fromhex( - "9a1d04808b4c0682816961cf666e82a7fd35949658aba5354c517eccf12aacb4"), - 32); -} -END_TEST - -START_TEST(test_bip32_cardano_hdnode_vector_2) { - HDNode node; - - uint8_t mnemonic_bits[66]; - int mnemonic_bits_len = mnemonic_to_bits( - "ring crime symptom enough erupt lady behave ramp apart settle citizen " - "junk", - mnemonic_bits); - ck_assert_int_eq(mnemonic_bits_len, 132); - hdnode_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, - mnemonic_bits_len / 8, &node); - - hdnode_private_ckd_cardano(&node, 0x80000000); - - ck_assert_mem_eq( - node.chain_code, - fromhex( - "104c6a0736e501c9bfe2966ba3773f5320495b19c3f2ed222234850af2ccd5b1"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "6064bf06b2e981d7c9792b1482eeecd40ec3cfa12143f4a1f149d48ce8b6ea46"), - 32); - ck_assert_mem_eq( - node.private_key_extension, - fromhex( - "64aa9a16331f14c981b769efcf96addcc4c6db44047fe7a7feae0be23d33bf54"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key + 1, - fromhex( - "c651c14a13c2311fc30a7acf244add1fdac3683e7ba89b4571e4cbcab509b915"), - 32); -} -END_TEST - -START_TEST(test_bip32_cardano_hdnode_vector_3) { - HDNode node; - - uint8_t mnemonic_bits[66]; - int mnemonic_bits_len = mnemonic_to_bits( - "ring crime symptom enough erupt lady behave ramp apart settle citizen " - "junk", - mnemonic_bits); - ck_assert_int_eq(mnemonic_bits_len, 132); - hdnode_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, - mnemonic_bits_len / 8, &node); - - hdnode_private_ckd_cardano(&node, 0x80000001); - - ck_assert_mem_eq( - node.chain_code, - fromhex( - "da99870d7e69de2a76f255ba8c7ed22428c7e5b0a8df978753c707c95ec3d4ca"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "c85fa69f4a1891fd98d1d1fc5f0cf9b1d6e44b0e6906744ab23ea766edb6ea46"), - 32); - ck_assert_mem_eq( - node.private_key_extension, - fromhex( - "b4fc241feffe840b8a54a26ab447f5a5caa31032db3a8091fca14f38b86ed539"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key + 1, - fromhex( - "5a5b0c92530cd366f05cf072509c806f904262c259e79a0080bbd5ee35706bb1"), - 32); -} -END_TEST - -START_TEST(test_bip32_cardano_hdnode_vector_4) { - HDNode node; - - uint8_t mnemonic_bits[66]; - int mnemonic_bits_len = mnemonic_to_bits( - "ring crime symptom enough erupt lady behave ramp apart settle citizen " - "junk", - mnemonic_bits); - ck_assert_int_eq(mnemonic_bits_len, 132); - hdnode_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, - mnemonic_bits_len / 8, &node); - - hdnode_private_ckd_cardano(&node, 0x80000000); - hdnode_private_ckd_cardano(&node, 0x80000001); - - ck_assert_mem_eq( - node.chain_code, - fromhex( - "b40c44dfd9be08591b62be7f9991c85f812d8196927f3c824d9fcb17d275089e"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "d064dcf1449d9c3e47f5b422680343561989035bf2e4e23fc34cb61fedb6ea46"), - 32); - ck_assert_mem_eq( - node.private_key_extension, - fromhex( - "a3071959013af95aaecf78a7a2e1b9838bbbc4864d6a8a2295243782078345cd"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key + 1, - fromhex( - "aaaca5e7adc69a03ef1f5c017ed02879e8ca871df028461ed9bf19fb8fa15038"), - 32); -} -END_TEST - -START_TEST(test_bip32_cardano_hdnode_vector_5) { - HDNode node; - - uint8_t mnemonic_bits[66]; - int mnemonic_bits_len = mnemonic_to_bits( - "ring crime symptom enough erupt lady behave ramp apart settle citizen " - "junk", - mnemonic_bits); - ck_assert_int_eq(mnemonic_bits_len, 132); - hdnode_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, - mnemonic_bits_len / 8, &node); - - hdnode_private_ckd_cardano(&node, 0x80000000); - hdnode_private_ckd_cardano(&node, 0x80000001); - hdnode_private_ckd_cardano(&node, 0x80000002); - - ck_assert_mem_eq( - node.chain_code, - fromhex( - "2593896baf92f6ab2c0f253787ab16be0244ba95e0d48ba09da1a7fd3f926c72"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "0811b6d5d6f7120cb05d4ce5453d6ce42825c2a8e53b6d370a6b05ccf4b6ea46"), - 32); - ck_assert_mem_eq( - node.private_key_extension, - fromhex( - "5bebf1eea68acd04932653d944b064b10baaf5886dd73c185cc285059bf93363"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key + 1, - fromhex( - "1c87a32c5babad2fe33e0586bdc523574c6126f8368bc76598e17ea46201f980"), - 32); -} -END_TEST - -START_TEST(test_bip32_cardano_hdnode_vector_6) { - HDNode node; - - uint8_t mnemonic_bits[66]; - int mnemonic_bits_len = mnemonic_to_bits( - "ring crime symptom enough erupt lady behave ramp apart settle citizen " - "junk", - mnemonic_bits); - ck_assert_int_eq(mnemonic_bits_len, 132); - hdnode_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, - mnemonic_bits_len / 8, &node); - - hdnode_private_ckd_cardano(&node, 0x80000000); - hdnode_private_ckd_cardano(&node, 0x80000001); - hdnode_private_ckd_cardano(&node, 0x80000002); - hdnode_private_ckd_cardano(&node, 0x80000002); - - ck_assert_mem_eq( - node.chain_code, - fromhex( - "fe8c6c2ab1e30385513fcffb49dcfe3e7805260425ea76b3b72b9f5bbe3b3d40"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "6019b9f5ef6ca530b657bcdb500de5455db8d51afb951fa045b6fbb3f6b6ea46"), - 32); - ck_assert_mem_eq( - node.private_key_extension, - fromhex( - "466332cb097934b43008701e7e27044aa56c7859019e4eba18d91a3bea23dff7"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key + 1, - fromhex( - "0b8f04755481ced76b4e5795aaafdb3cbd757c10fe60e9c58f48cf29a7ec3575"), - 32); -} -END_TEST - -START_TEST(test_bip32_cardano_hdnode_vector_7) { - HDNode node; - - uint8_t mnemonic_bits[66]; - int mnemonic_bits_len = mnemonic_to_bits( - "ring crime symptom enough erupt lady behave ramp apart settle citizen " - "junk", - mnemonic_bits); - ck_assert_int_eq(mnemonic_bits_len, 132); - hdnode_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, - mnemonic_bits_len / 8, &node); - - hdnode_private_ckd_cardano(&node, 0x80000000); - hdnode_private_ckd_cardano(&node, 0x80000001); - hdnode_private_ckd_cardano(&node, 0x80000002); - hdnode_private_ckd_cardano(&node, 0x80000002); - hdnode_private_ckd_cardano(&node, 0xBB9ACA00); - - ck_assert_mem_eq( - node.chain_code, - fromhex( - "ff77c08d37471c1d4cedd3fae2642c009324d9712492efc74dedab09c9bf973c"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "488f34840bba516f7920f91676b8681d0dd833b4ce14468e0810b255f9b6ea46"), - 32); - ck_assert_mem_eq( - node.private_key_extension, - fromhex( - "01eccef768a79859f824a1d3c3e35e131184e2940c3fca9a4c9b307741f65363"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key + 1, - fromhex( - "148605be54585773b44ba87e79265149ae444c4cc37cb1f8db8c08482fba293b"), - 32); -} -END_TEST - -START_TEST(test_bip32_cardano_hdnode_vector_8) { - HDNode node; - - uint8_t mnemonic_bits[66]; - int mnemonic_bits_len = mnemonic_to_bits( - "found differ bulb shadow wrist blue bind vessel deposit tip pelican " - "action surprise weapon check fiction muscle this", - mnemonic_bits); - ck_assert_int_eq(mnemonic_bits_len, 198); - hdnode_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, - mnemonic_bits_len / 8, &node); - - hdnode_private_ckd_cardano(&node, 0x80000000); - hdnode_private_ckd_cardano(&node, 0x80000001); - hdnode_private_ckd_cardano(&node, 0x80000002); - hdnode_private_ckd_cardano(&node, 0x80000002); - hdnode_private_ckd_cardano(&node, 0xBB9ACA00); - - ck_assert_mem_eq( - node.chain_code, - fromhex( - "6fb22a4531ad79e828c4907c5fff3ecf686c16cb195f81243f1f0330173380e4"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "a0baa34e4e24f0500ed6e5e90ab41984b965b7464b0b28640528778dd8a6b854"), - 32); - ck_assert_mem_eq( - node.private_key_extension, - fromhex( - "170e0d3b65ba8d71f27a6db60d0ac26dcb16e52e08cc259db72066f206b258d5"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key + 1, - fromhex( - "3dae0c06d87db618d73ee808425898cdd882f9eb43bf139c6b3a4760551ee89f"), - 32); -} -END_TEST - -START_TEST(test_bip32_cardano_hdnode_vector_9) { - HDNode node; - - uint8_t mnemonic_bits[66]; - int mnemonic_bits_len = mnemonic_to_bits( - "balance exotic ranch knife glory slow tape favorite yard gym awake " - "ill exist useless parent aim pig stay effort into square gasp credit " - "butter", - mnemonic_bits); - ck_assert_int_eq(mnemonic_bits_len, 264); - hdnode_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, - mnemonic_bits_len / 8, &node); - - hdnode_private_ckd_cardano(&node, 0x80000000); - hdnode_private_ckd_cardano(&node, 0x80000001); - hdnode_private_ckd_cardano(&node, 0x80000002); - hdnode_private_ckd_cardano(&node, 0x80000002); - hdnode_private_ckd_cardano(&node, 0xBB9ACA00); - - ck_assert_mem_eq( - node.chain_code, - fromhex( - "9b226add79f90086ea18b260da633089fe121db758aa31284ad1affaf3c9bb68"), - 32); - ck_assert_mem_eq( - node.private_key, - fromhex( - "38eb2a79486e516cb6658700503a3e2c870c03e9d1aec731f780aa6fb7f7de44"), - 32); - ck_assert_mem_eq( - node.private_key_extension, - fromhex( - "80d2c677638e5dbd4395cdec279bf2a42077f2797c9e887949d37cdb317fce6a"), - 32); - hdnode_fill_public_key(&node); - ck_assert_mem_eq( - node.public_key + 1, - fromhex( - "115a365b2aad1d8eba7d379de518f1fa8553855110af24e5695011c32ce9a300"), - 32); -} -END_TEST diff --git a/deps/crypto/trezor-crypto/tests/test_check_cashaddr.h b/deps/crypto/trezor-crypto/tests/test_check_cashaddr.h deleted file mode 100644 index 7f2a68c55..000000000 --- a/deps/crypto/trezor-crypto/tests/test_check_cashaddr.h +++ /dev/null @@ -1,68 +0,0 @@ -#include "cash_addr.h" - -static const char* valid_cashchecksum[] = { - "prefix:x64nx6hz", - "p:gpf8m4h7", - "bitcoincash:qpzry9x8gf2tvdw0s3jn54khce6mua7lcw20ayyn", - "bchtest:testnetaddress4d6njnut", - "bchreg:555555555555555555555555555555555555555555555udxmlmrz", -}; - -struct valid_cashaddr_data { - const char* legacy; - const char* cashaddress; -}; - -static struct valid_cashaddr_data valid_cashaddr[] = { - {"1BpEi6DfDAUFd7GtittLSdBeYJvcoaVggu", - "bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a"}, - {"1KXrWXciRDZUpQwQmuM1DbwsKDLYAYsVLR", - "bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy"}, - {"16w1D5WRVKJuZUsSRzdLp9w3YGcgoxDXb", - "bitcoincash:qqq3728yw0y47sqn6l2na30mcw6zm78dzqre909m2r"}, - {"3CWFddi6m4ndiGyKqzYvsFYagqDLPVMTzC", - "bitcoincash:ppm2qsznhks23z7629mms6s4cwef74vcwvn0h829pq"}, - {"3LDsS579y7sruadqu11beEJoTjdFiFCdX4", - "bitcoincash:pr95sy3j9xwd2ap32xkykttr4cvcu7as4yc93ky28e"}, - {"31nwvkZwyPdgzjBJZXfDmSWsC4ZLKpYyUw", - "bitcoincash:pqq3728yw0y47sqn6l2na30mcw6zm78dzq5ucqzc37"}}; - -START_TEST(test_cashaddr) { - size_t i; - for (i = 0; i < sizeof(valid_cashchecksum) / sizeof(valid_cashchecksum[0]); - ++i) { - uint8_t data[82]; - char rebuild[92]; - char hrp[84]; - size_t data_len; - int res = cash_decode(hrp, data, &data_len, valid_cashchecksum[i]); - ck_assert_int_eq(res, 1); - res = cash_encode(rebuild, hrp, data, data_len); - ck_assert_int_eq(res, 1); - ck_assert_int_eq(my_strncasecmp(rebuild, valid_cashchecksum[i], 92), 0); - } - for (i = 0; i < sizeof(valid_cashaddr) / sizeof(valid_cashaddr[0]); ++i) { - uint8_t prog[65]; - size_t prog_len; - const char* hrp = "bitcoincash"; - uint8_t rawdata[65]; - size_t rawdata_len; - char rebuild[93]; - int ret = - cash_addr_decode(prog, &prog_len, hrp, valid_cashaddr[i].cashaddress); - ck_assert_int_eq(ret, 1); - ck_assert_uint_eq(prog_len, 21); - rawdata_len = base58_decode_check(valid_cashaddr[i].legacy, HASHER_SHA2D, - rawdata, sizeof(rawdata)); - ck_assert_uint_eq(rawdata_len, 21); - ck_assert_uint_eq(prog[0], rawdata[0] == 0 ? 0x00 - : rawdata[0] == 5 ? 0x08 - : -1); - ck_assert_int_eq(memcmp(rawdata + 1, prog + 1, 20), 0); - ret = cash_addr_encode(rebuild, hrp, prog, 21); - ck_assert_int_eq(ret, 1); - ck_assert_int_eq(my_strncasecmp(rebuild, valid_cashaddr[i].cashaddress, 92), - 0); - } -} -END_TEST diff --git a/deps/crypto/trezor-crypto/tests/test_check_monero.h b/deps/crypto/trezor-crypto/tests/test_check_monero.h deleted file mode 100644 index eb247d939..000000000 --- a/deps/crypto/trezor-crypto/tests/test_check_monero.h +++ /dev/null @@ -1,1180 +0,0 @@ -#if USE_MONERO -START_TEST(test_xmr_base58) { - static const struct { - uint64_t tag; - char *v1; - char *v2; - } tests[] = { - {0x12, - "3bec484c5d7f0246af520aab550452b5b6013733feabebd681c4a60d457b7fc12d5918e" - "31d3c003da3c778592c07b398ad6f961a67082a75fd49394d51e69bbe", - "43tpGG9PKbwCpjRvNLn1jwXPpnacw2uVUcszAtgmDiVcZK4VgHwjJT9BJz1WGF9eMxSYASp" - "8yNMkuLjeQfWqJn3CNWdWfzV"}, - {0x12, - "639050436fa36c8288706771412c5972461578d564188cd7fc6f81d6973d064fa461afe" - "66fb23879936d7225051bebbf7f3ae0c801a90bb99fbb346b2fd4d702", - "45PwgoUKaDHNqLL8o3okzLL7biv7GqPVmd8LTcTrYVrMEKdSYwFcyJfMLSRpfU3nh8Z2m81" - "FJD4sUY3nXCdGe61k1HAp8T1"}, - {53, - "5a10cca900ee47a7f412cd661b29f5ab356d6a1951884593bb170b5ec8b6f2e83b1da41" - "1527d062c9fedeb2dad669f2f5585a00a88462b8c95c809a630e5734c", - "9vacMKaj8JJV6MnwDzh2oNVdwTLJfTDyNRiB6NzV9TT7fqvzLivH2dB8Tv7VYR3ncn8vCb3" - "KdNMJzQWrPAF1otYJ9cPKpkr"}, - }; - - uint8_t rawn[512]; - char strn[512]; - int r; - uint64_t tag; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - const char *raw = tests[i].v1; - const char *str = tests[i].v2; - const size_t len = strlen(raw) / 2; - - memcpy(rawn, fromhex(raw), len); - - r = xmr_base58_addr_encode_check(tests[i].tag, rawn, len, strn, - sizeof(strn)); - ck_assert_uint_eq((size_t)r, strlen(str)); - ck_assert_mem_eq(strn, str, r); - - r = xmr_base58_addr_decode_check(strn, r, &tag, rawn, len); - ck_assert_uint_eq((size_t)r, len); - ck_assert_mem_eq(rawn, fromhex(raw), len); - } -} -END_TEST - -START_TEST(test_xmr_getset256_modm) { - static const struct { - uint64_t val; - int r; - char *a; - } tests[] = { - {0x0, 1, - "0000000000000000000000000000000000000000000000000000000000000000"}, - {0x7fffffffULL, 1, - "ffffff7f00000000000000000000000000000000000000000000000000000000"}, - {0x7fffffffffffffffULL, 1, - "ffffffffffffff7f000000000000000000000000000000000000000000000000"}, - {0xdeadc0deULL, 1, - "dec0adde00000000000000000000000000000000000000000000000000000000"}, - {0x0, 0, - "dec0adde000000000000000000000000000000000000000000000000000000ff"}, - {0x0, 0, - "ffffffffffffffffff0000000000000000000000000000000000000000000000"}, - }; - - uint8_t rawn[32]; - uint64_t v1; - bignum256modm a1 = {0}; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - int get_res = tests[i].r; - if (get_res) { - set256_modm(a1, tests[i].val); - ck_assert_int_eq(get256_modm(&v1, a1), 1); - ck_assert(v1 == tests[i].val); - - contract256_modm(rawn, a1); - ck_assert_mem_eq(rawn, fromhex(tests[i].a), 32); - - } else { - expand256_modm(a1, fromhex(tests[i].a), 32); - ck_assert_int_eq(get256_modm(&v1, a1), 0); - } - } -} -END_TEST - -START_TEST(test_xmr_cmp256_modm) { - static const struct { - char *a; - char *b; - int res_eq; - int res_cmp; - int res_is_zero_a; - } tests[] = { - {"0000000000000000000000000000000000000000000000000000000000000000", - "0000000000000000000000000000000000000000000000000000000000000000", 1, 0, - 1}, - {"0000000000000000000000000000000000000000000000000000000000000000", - "0100000000000000000000000000000000000000000000000000000000000000", 0, - -1, 1}, - {"dec0adde00000000000000000000000000000000000000000000000000000000", - "dec0adde00000000000000000000000000000000000000000000000000000000", 1, 0, - 0}, - {"863346d8863c461cde2ec7c2759352c2b952228f33a86ca06bb79574bbe5c30d", - "3ddbd65a6d3ba5e2ab120603685a353a27ce3fd21dfdbea7952d2dd26f1ca00a", 0, 1, - 0}, - {"f7667f392edbea6e224b1aa9fbf2a3b238b4f977fb4a8f39130cc45f49b5c40a", - "b41b9b1e7e80be71cf290ed4bded58924086b8ac6bdfa1faa0c80c255f074d07", 0, 1, - 0}, - {"0e4005c7826de8f9978749903f40efd140e4ae6d3bed09e558fcce8367b27501", - "0e4005c7826de8f9978749903f40efd140e4ae6d3bed09e558fcce8367b27504", 0, - -1, 0}, - {"0e4005c7826de8f9978749903f40efd140e4ae6d3bed09e558fcce8367b27504", - "0e4005c7826de8f9978749903f40efd140e4ae6d3bed09e558fcce8367b27504", 1, 0, - 0}, - {"0e4005c7826de8f9978749903f40efd140e4ae6d3bed09e558fcce8367b27504", - "0e4005c7826de8f9978749903f41efd140e4ae6d3bed09e558fcce8367b27504", 0, - -1, 0}, - }; - - bignum256modm a1 = {0}, a2 = {0}; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(a1, fromhex(tests[i].a), 32); - expand256_modm(a2, fromhex(tests[i].b), 32); - - ck_assert_int_eq(eq256_modm(a1, a2), tests[i].res_eq); - ck_assert_int_eq(cmp256_modm(a1, a2), tests[i].res_cmp); - ck_assert_int_eq(iszero256_modm(a1), tests[i].res_is_zero_a); - } -} -END_TEST - -START_TEST(test_xmr_copy_check_modm) { - static const struct { - int check; - char *a; - } tests[] = { - {0, "0000000000000000000000000000000000000000000000000000000000000000"}, - {1, "ffffff7f00000000000000000000000000000000000000000000000000000000"}, - {1, "ffffffffffffff7f000000000000000000000000000000000000000000000000"}, - {1, "dec0adde00000000000000000000000000000000000000000000000000000000"}, - {0, "dec0adde000000000000000000000fffffffffffffffffffffffffffffffffff"}, - }; - - bignum256modm a1 = {0}, a2 = {0}; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand_raw256_modm(a1, fromhex(tests[i].a)); - copy256_modm(a2, a1); - ck_assert_int_eq(eq256_modm(a1, a2), 1); - ck_assert_int_eq(check256_modm(a1), tests[i].check); - } -} -END_TEST - -START_TEST(test_xmr_mulsub256_modm) { - static const struct { - char *a; - char *b; - char *c; - char *r; - } tests[] = { - { - "713c199348cf7d14b67ae6265ea49c02c8647f07afcbcb6f8d3254b3db972e02", - "4e48a7b7a03ab1106fdfa9441a03c97c644395a12ac4b8effac7344e0719c200", - "1a5711b8c43bcab0161a620368d82727e1d027dc248f420d9bb4db2486c16405", - "6edcc08aa6ec3a5b3d333b5f826be7de9c268be8aaf9521586fbcccbed3b1c0c", - }, - { - "d4ade2c62d34af8cfd9daec6f46bf7e57962a8aa46935cb11fab64fa599b4700", - "22ea7989a9f4d34cd8c9442e03b5062dfe8493757cd18a63411cb1a25e44960f", - "772053e613f0859387badcefeb7fbe551a05b00b9337539c8d72661de5929806", - "a5063258df4520b33e97c0a46d80feeace5c251fc7ef7a938d160b8f25795106", - }, - { - "01fd2ef25c8221277a2b6daf1f1642bacb8d6ac0dd4f62731cdd73e26eb77900", - "0611b9357530aa638428002769ce0ad553421e971bea1f10d7009bf26d9af805", - "dfece232068b2f8059ca569f345baaed13ab464eb3bebb99de5625dc90a8cf03", - "85752e62bd8085c7c02d5edeb74969d22f1a5bb34349258d2e96de300176bb07", - }, - }; - - bignum256modm a = {0}, b = {0}, c = {0}, r = {0}, r2 = {0}; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(a, fromhex(tests[i].a), 32); - expand256_modm(b, fromhex(tests[i].b), 32); - expand256_modm(c, fromhex(tests[i].c), 32); - expand256_modm(r, fromhex(tests[i].r), 32); - mulsub256_modm(r2, a, b, c); - ck_assert_int_eq(eq256_modm(r, r2), 1); - } -} -END_TEST - -START_TEST(test_xmr_muladd256_modm) { - static const struct { - char *a; - char *b; - char *c; - char *r; - } tests[] = { - { - "7c3fd8abfbe2be3739d91679ac8dbda086961b941e0d4a00561f758927d8aa09", - "ac2d8d37e4f344aa4040d0f0fc29d45423ab7e69ecacb94ca9fc36819e0e990e", - "2f03f1bac09bc7d002848b68be069dc98b2db028390ae37e13a5166fcae08105", - "dce113add3392f08e3b38b7d31e237eba5066e5a95a1fdbf755b92d05e1ec70b", - }, - { - "6979b70f6198d043f4b14e2069f7b89cc9f09e3465e71d472946443989e0e80c", - "8dd5177bc8d7c5bd58c0be74b336952a73ac259ebb812ac8cd755773c6aab807", - "d7658e508a7454ccfb29e2890d6156ac10e18ebe6e00cc5a2d2d87a5080c7f06", - "51b33f6263772781cdbab26ef48870eaf94899894a437dac39496f15b9d0ae00", - }, - { - "ebfdb4eabedb1fb9a45b3204735b0511871e20358392fa16a851c519e3a29b09", - "59d98831e9f9e24260158986c4d4035438de9b8876cc11bdcf4c364c75f72908", - "93bce4764eee97dc67f2e37da40bc5641f2cdc637285d273287a3d4383b68f02", - "21547ca6855c85d5adcd673b9d801d0cb0f10dced8f8b68a8c2f74163defde0e", - }, - }; - - bignum256modm a = {0}, b = {0}, c = {0}, r = {0}, r2 = {0}; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(a, fromhex(tests[i].a), 32); - expand256_modm(b, fromhex(tests[i].b), 32); - expand256_modm(c, fromhex(tests[i].c), 32); - expand256_modm(r, fromhex(tests[i].r), 32); - muladd256_modm(r2, a, b, c); - ck_assert_int_eq(eq256_modm(r, r2), 1); - } -} -END_TEST - -START_TEST(test_xmr_curve25519_set) { - static const struct { - uint32_t val; - char *a; - } tests[] = { - {0x0, "0000000000000000000000000000000000000000000000000000000000000000"}, - {0x1, "0100000000000000000000000000000000000000000000000000000000000000"}, - {0xdeadc0deUL, - "dec0adde00000000000000000000000000000000000000000000000000000000"}, - }; - - unsigned char buff[32]; - bignum25519 a = {0}; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - curve25519_set(a, tests[i].val); - curve25519_contract(buff, a); - ck_assert_mem_eq(buff, fromhex(tests[i].a), 32); - } -} -END_TEST - -START_TEST(test_xmr_curve25519_consts) { - char *d = "a3785913ca4deb75abd841414d0a700098e879777940c78c73fe6f2bee6c0352"; - char *d2 = "59f1b226949bd6eb56b183829a14e00030d1f3eef2808e19e7fcdf56dcd90624"; - char *sqrtneg1 = - "b0a00e4a271beec478e42fad0618432fa7d7fb3d99004d2b0bdfc14f8024832b"; - - unsigned char buff[32]; - bignum25519 a = {0}; - - curve25519_set_d(a); - curve25519_contract(buff, a); - ck_assert_mem_eq(buff, fromhex(d), 32); - - curve25519_set_2d(a); - curve25519_contract(buff, a); - ck_assert_mem_eq(buff, fromhex(d2), 32); - - curve25519_set_sqrtneg1(a); - curve25519_contract(buff, a); - ck_assert_mem_eq(buff, fromhex(sqrtneg1), 32); -} -END_TEST - -START_TEST(test_xmr_curve25519_tests) { - static const struct { - char *a; - int res_neg; - int res_nonzero; - } tests[] = { - { - "0000000000000000000000000000000000000000000000000000000000000000", - 0, - 0, - }, - { - "0100000000000000000000000000000000000000000000000000000000000000", - 1, - 1, - }, - { - "05737aa6100ee54283dc0d483b8e39e61846f6b3736908243d0c824d250b3139", - 1, - 1, - }, - { - "95587a5ef6900fa8e32d6a41bd8090b1e33e694284323d1d1f02d69865f2bc15", - 1, - 1, - }, - { - "02587a5ef6900fa8e32d6a41bd8090b1e33e694284323d1d1f02d69865f2bc15", - 0, - 1, - }, - }; - - bignum25519 a = {0}; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - curve25519_expand(a, fromhex(tests[i].a)); - ck_assert_int_eq(curve25519_isnegative(a), tests[i].res_neg); - ck_assert_int_eq(curve25519_isnonzero(a), tests[i].res_nonzero); - } -} -END_TEST - -START_TEST(test_xmr_curve25519_expand_reduce) { - static const struct { - char *a; - char *b; - } tests[] = { - {"dec0adde00000000000000000000000000000000000000000000000000000000", - "dec0adde00000000000000000000000000000000000000000000000000000000"}, - {"95587a5ef6900fa8e32d6a41bd8090b1e33e694284323d1d1f02d69865f2bc15", - "95587a5ef6900fa8e32d6a41bd8090b1e33e694284323d1d1f02d69865f2bc15"}, - {"95587a5ef6900fa8e32d6a41bd8090b1e33e694284323d1d1f02d69865f2bcff", - "a8587a5ef6900fa8e32d6a41bd8090b1e33e694284323d1d1f02d69865f2bc7f"}, - {"95587a5ef6900fa8e32d6affbd8090b1e33e694284323fffff02d69865f2bcff", - "a8587a5ef6900fa8e32d6affbd8090b1e33e694284323fffff02d69865f2bc7f"}, - }; - - unsigned char buff[32]; - bignum25519 a = {0}; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - curve25519_expand_reduce(a, fromhex(tests[i].a)); - curve25519_contract(buff, a); - ck_assert_mem_eq(buff, fromhex(tests[i].b), 32); - } -} -END_TEST - -START_TEST(test_xmr_ge25519_base) { - unsigned char buff[32]; - char *base = - "5866666666666666666666666666666666666666666666666666666666666666"; - ge25519 b; - ge25519_set_base(&b); - ge25519_pack(buff, &b); - ck_assert_mem_eq(buff, fromhex(base), 32); -} -END_TEST - -START_TEST(test_xmr_ge25519_check) { - static const struct { - char *x; - char *y; - char *z; - char *t; - int r; - } tests[] = { - {"4ff97748221f954414f836d84e8e7e207786bcd20eb67044756dca307e792c60", - "2c7be86ab07488ba43e8e03d85a67625cfbf98c8544de4c877241b7aaafc7f63", - "0100000000000000000000000000000000000000000000000000000000000000", - "3ec65b03954ce7432525b9b3f4a9f5747f57b40903d1bf8892527366325fe036", 1}, - {"358fd25e4b84397d207e23cf3a75819bd6b2254cabc990b31ad63873cc38fc7c", - "ca48045f790145a1eec3946dfd73747fde0fdb4238607e0a203f8ef5bef90e0e", - "0100000000000000000000000000000000000000000000000000000000000000", - "6c5e5cbae4b05e149d0aca50bf7b4112acbbe6233ace9c8bd5bcedf34df9ce0b", 1}, - {"4ff97748221f954414f836d84e8e7e207786bcd20eb6704475ffca307e792c60", - "2c7be86ab07488ba43e8e03d85a67625cfbf98c8544de4c877241b7aaafc7f63", - "0100000000000000000000000000000000000000000000000000000000000000", - "3ec65b03954ce7432525b9b3f4a9f5747f57b40903d1bf8892527366325fe036", 0}, - {"358fd25e4b84397d207e23cf3a75819bd6b2254cabc990b31ad63873cc38fc7c", - "ca48045f790145a1eec3946dfd73747fdfffdb4238607e0a203f8ef5bef90e0e", - "0100000000000000000000000000000000000000000000000000000000000000", - "6c5e5cbae4b05e149d0aca50bf7b4112acbbe6233ace9c8bd5bcedf34df9ce0b", 0}, - {"358fd25e4b84397d207e23cf3a75819bd6b2254cabc990b31ad63873cc38fc7c", - "ca48045f790145a1eec3946dfd73747fdfffdb4238607e0a203f8ef5bef90e0e", - "0100000000000000000000000000000000000000000000000000000000000000", - "6c5e5ffae4b05e149d0aca50bf7b4112acbbe6233ace9c8bd5bcedf34df9ce0b", 0}, - }; - - struct ge25519_t p; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - curve25519_expand_reduce(p.x, fromhex(tests[i].x)); - curve25519_expand_reduce(p.y, fromhex(tests[i].y)); - curve25519_expand_reduce(p.z, fromhex(tests[i].z)); - curve25519_expand_reduce(p.t, fromhex(tests[i].t)); - ck_assert_int_eq(ge25519_check(&p), tests[i].r); - } -} -END_TEST - -START_TEST(test_xmr_ge25519_scalarmult_base_wrapper) { - static const struct { - char *sc; - char *pt; - } tests[] = { - { - "40be740e26bd1c84f5a8fec737c0ed30e87bd45adfcd91e320f8dfb68b1a870e", - "b7a8b2f3dbfd41b38d20aec733a316dbfc2633503799cd36f38570cafc8ea887", - }, - { - "1b3746add992215d427e43a58354c11ff9e6dfa1c187250938f7f9334fa41d05", - "e2a1bfbe38a9749fe6ede79d923b778fa4c89393473d633bec01fa68617d0828", - }, - { - "69af25c54090a9746d3f6043348452429ffd53c1530fa114fd0055b70d61020f", - "6bf1783b0a7495d5f6c36605dca95e723ca120a306c255084787f09b12771124", - }, - { - "0000000000000000000000000000000000000000000000000000000000000000", - "0100000000000000000000000000000000000000000000000000000000000000", - }, - { - "0100000000000000000000000000000000000000000000000000000000000000", - "5866666666666666666666666666666666666666666666666666666666666666", - }, - { - "0800000000000000000000000000000000000000000000000000000000000000", - "b4b937fca95b2f1e93e41e62fc3c78818ff38a66096fad6e7973e5c90006d321", - }, - { - "ffffffffffffffff000000000000000000000000000000000000000000000000", - "e185757a3fdc6519a6e7bebd97aa52bdc999e4c87d5c3aad0d995763ab6c6985", - }, - }; - - ge25519 pt, pt2; - bignum256modm sc; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(sc, fromhex(tests[i].sc), 32); - ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); - ge25519_scalarmult_base_wrapper(&pt2, sc); - ck_assert_int_eq(ge25519_eq(&pt, &pt2), 1); - } -} -END_TEST - -START_TEST(test_xmr_ge25519_scalarmult) { - static const struct { - char *sc; - char *pt; - char *pt2; - } tests[] = { - { - "0000000000000000000000000000000000000000000000000000000000000000", - "5cbb3b2784c16f0e7eb4f2a7f93288552bb24ec51c5e01504c1e6885cfbca6d0", - "0100000000000000000000000000000000000000000000000000000000000000", - }, - { - "0100000000000000000000000000000000000000000000000000000000000000", - "f39b6770008d069acb92eb95329dec2cb0054da024e437a1bdf1ae06527deff6", - "f39b6770008d069acb92eb95329dec2cb0054da024e437a1bdf1ae06527deff6", - }, - { - "3930000000000000000000000000000000000000000000000000000000000000", - "2835b3983e3cc01a640fd188bf6bbbafbf997a3344d800eed22e4e82a412941c", - "2fe8b2dd0f23e02fca6989e170135584d684583c0a44f6a7d3ebd964685d36c7", - }, - { - "ffffffffffffffff000000000000000000000000000000000000000000000000", - "bb8af7a53a8f1b477c810e833a84cdc789a6b81a6b6417be4f97ffd9ae0fe0b8", - "3a5c9a7dacca9dd8827881f38c36aad7d402a5efc2cab58c7553b903876e1491", - }, - { - "864203a09e1c788a482685c739af07355ebb2c840b7de6af87eff5f19ee3b807", - "d404a9bbf351e7320ea6d11cdeeccaf505f706731cb5e5d839b950edb7ba6286", - "11e09c89e0be7663e0e2d4a01fb05d6a3fd84a78a6fa4fd7daaacf2d19311a38", - }, - { - "3e01f05920a238e33766814d10f0c3a3e975072399ad90a823d4808db1d85209", - "52a2d35798a0ac209b8fa194fe398b869aba5f20d80ee3d8ca77759a8e0bae0d", - "4256addc2f036150f3fdc0a7905f01285239d6dd4eecc4be8e3b134eef4639fe", - }, - { - "ad63d591716a9e89a024a074bc6ce661268d1bb3665f91e8b981f189b1a49507", - "3928bde7a92e1341c3dfee35a66fa5639204f5b9747963278af430145028648d", - "9c959003ba91004956df98800a5024d94031db5ac659675b26350657d93c34f9", - }, - }; - - ge25519 pt, pt2, pt3; - bignum256modm sc; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(sc, fromhex(tests[i].sc), 32); - ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); - ge25519_unpack_vartime(&pt2, fromhex(tests[i].pt2)); - ge25519_scalarmult(&pt3, &pt, sc); - ck_assert_int_eq(ge25519_eq(&pt3, &pt2), 1); - } -} -END_TEST - -START_TEST(test_xmr_ge25519_ops) { - int tests[] = {1, 2, 7, 8, 637, 9912, 12345}; - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - struct ge25519_t a, b, c, d; - bignum256modm s1 = {0}, s2 = {0}, s3 = {0}, s4 = {0}; - - set256_modm(s1, tests[i]); - set256_modm(s2, 8 * tests[i]); - set256_modm(s3, 8); - set256_modm(s4, 2); - - ge25519_scalarmult_base_niels(&a, ge25519_niels_base_multiples, s1); - ge25519_scalarmult_base_niels(&b, ge25519_niels_base_multiples, s2); - ge25519_scalarmult(&c, &a, s4); - ge25519_scalarmult(&c, &c, s4); - ge25519_scalarmult(&c, &c, s4); - ck_assert_int_eq(ge25519_eq(&c, &b), 1); - ck_assert_int_eq(ge25519_eq(&a, &b), 0); - - ge25519_scalarmult_base_wrapper(&a, s1); - ge25519_mul8(&b, &a); - ge25519_scalarmult_base_wrapper(&c, s2); - ck_assert_int_eq(ge25519_eq(&b, &c), 1); - - ge25519_scalarmult(&d, &a, s3); - ck_assert_int_eq(ge25519_eq(&d, &c), 1); - - ge25519_copy(&a, &b); - ge25519_neg_full(&b); - ck_assert_int_eq(ge25519_eq(&b, &c), 0); - - ge25519_add(&c, &a, &b, 0); - set256_modm(s2, 0); - ge25519_scalarmult_base_wrapper(&a, s2); - ck_assert_int_eq(ge25519_eq(&a, &c), 1); - } -} -END_TEST - -START_TEST(test_xmr_check_point) { - static const struct { - char *p; - bool on; - } tests[] = { - {"001000a93e0e6937b4feaf079e418a028ca85459aa39ac3871b94076f88ca608", - true}, - {"54863a0464c008acc99cffb179bc6cf34eb1bbdf6c29f7a070a7c6376ae30ab5", - true}, - {"bebe3c84092c0f7a92704cafb16562cc45c47f45e84baec8d4bba3559d1c1808", - true}, - {"00000000000000c60073ec000000000000ff0000000000000000000000000080", - false}, - {"00000000000000004e0000000000000000000000000000000000000000000000", - false}, - {"0000008b0000000000000000b200000000000000000000000000000000000080", - false}, - {"a0953eebe2f676256c37af4f6f84f32d397aaf3b73606e96c5ddfcecbb1ceec8", - false}, - {"a82cd837efee505ec8425769ea925bee869ec3c78a57708c64c2ef2bd6ad3b88", - false}, - {"031c56cfc99758f6f025630e77c6dea0b853c3ab0bf6cf8c8dab03d1a4618178", - false}, - }; - - ge25519 tmp; - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - int res = ge25519_unpack_negative_vartime(&tmp, fromhex(tests[i].p)); - ck_assert_int_eq(ge25519_check(&tmp), tests[i].on); - ck_assert_int_eq(res, tests[i].on); - } -} -END_TEST - -START_TEST(test_xmr_h) { - char *H = "8b655970153799af2aeadc9ff1add0ea6c7251d54154cfa92c173a0dd39c1f94"; - ge25519 H2, Z; - ge25519_p1p1 P_11; - ge25519_pniels P_ni; - uint8_t buff[32] = {0}; - - ge25519_pack(buff, &xmr_h); - ck_assert_mem_eq(buff, fromhex(H), 32); - - int res = ge25519_unpack_vartime(&H2, buff); - ck_assert_int_eq(res, 1); - ck_assert_int_eq(ge25519_eq(&xmr_h, &xmr_h), 1); - ck_assert_int_eq(ge25519_eq(&H2, &xmr_h), 1); - - res = ge25519_unpack_negative_vartime(&H2, buff); - ck_assert_int_eq(res, 1); - ck_assert_int_eq(ge25519_eq(&H2, &xmr_h), 0); - ge25519_neg_full(&H2); - ck_assert_int_eq(ge25519_eq(&H2, &xmr_h), 1); - - ge25519_full_to_pniels(&P_ni, &xmr_h); - ge25519_pnielsadd_p1p1(&P_11, &H2, &P_ni, 1); - ge25519_p1p1_to_full(&H2, &P_11); - ge25519_set_neutral(&Z); - ck_assert_int_eq(ge25519_eq(&Z, &H2), 1); -} -END_TEST - -START_TEST(test_xmr_fast_hash) { - uint8_t hash[32]; - char tests[][2][65] = { - {"", "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"}, - {"00", - "bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a"}, - {"000102", - "f84a97f1f0a956e738abd85c2e0a5026f8874e3ec09c8f012159dfeeaab2b156"}, - {"000102030405", - "51e8babe8b42352100dffa7f7b3843c95245d3d545c6cbf5052e80258ae80627"}, - {"000102030406", - "74e7a0111ee2390dc68269a549a76dcfb553ca1260035eae982d669ff6494f32"}, - {"000102030407", - "3a81c5d02a87786343f88414aae150a09f6933b1d3bb660d0a9ac54e12e5cd86"}, - {"259ef2aba8feb473cf39058a0fe30b9ff6d245b42b6826687ebd6b63128aff64", - "7fb4d1c8e32f7414fe8c7b2774ec05bff6845e4278565d17f95559513a244da2"}, - {"44caa1c26187afe8dacc5d91cb8a51282334d9308a818fe4d3607275e2a61f05", - "2998fe52f8b9883149babd9c546912c3edfbd3cd98896a0e57b1b5929fa5ff7b"}, - }; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - xmr_fast_hash(hash, fromhex(tests[i][0]), strlen(tests[i][0]) / 2); - ck_assert_mem_eq(hash, fromhex(tests[i][1]), 32); - } -} -END_TEST - -START_TEST(test_xmr_hasher) { - Hasher hasher; - uint8_t hash[32]; - - static const struct { - char *chunk[3]; - char *hash; - } tests[] = { - {{"00", "01", "02"}, - "f84a97f1f0a956e738abd85c2e0a5026f8874e3ec09c8f012159dfeeaab2b156"}, - {{"001122334455667788", "00", ""}, - "72a228ee8d0d01c815f112ce315cfc215a0594abcec24162304ae0ffda139d9e"}, - {{"001000a93e0e6937b4feaf079e418a028ca85459aa39ac3871b94076f88ca608", "", - "00112233445566"}, - "c3deafd96ff10cc190c6024548c344f6401cfe5151ab2fcd40df7cc501147e01"}, - }; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - xmr_hasher_init(&hasher); - for (int j = 0; j < 3; j++) { - xmr_hasher_update(&hasher, fromhex(tests[i].chunk[j]), - strlen(tests[i].chunk[j]) / 2); - } - xmr_hasher_final(&hasher, hash); - ck_assert_mem_eq(hash, fromhex(tests[i].hash), 32); - } -} -END_TEST - -START_TEST(test_xmr_hash_to_scalar) { - bignum256modm a1; - unsigned char out[32]; - char tests[][2][65] = { - {"", "4a078e76cd41a3d3b534b83dc6f2ea2de500b653ca82273b7bfad8045d85a400"}, - {"00", - "5497c9b6a7059553835f85118dc089d66512f7b477d66591ff96a9e064bcc90a"}, - {"000102", - "5727ca206dbafa2e099b022ed528f5bdf7874e3ec09c8f012159dfeeaab2b106"}, - {"000102030405", - "7740cf04577c107153a50b3abe44859f5245d3d545c6cbf5052e80258ae80607"}, - {"000102030406", - "ad6bbffaceb8020543ac82bcadb9d090b553ca1260035eae982d669ff6494f02"}, - {"000102030407", - "d2e116e9576ee5a29011c8fcb41259f99e6933b1d3bb660d0a9ac54e12e5cd06"}, - {"259ef2aba8feb473cf39058a0fe30b9ff6d245b42b6826687ebd6b63128aff64", - "3d6d3727dc50bca39e6ccfc9c12950eef5845e4278565d17f95559513a244d02"}, - {"44caa1c26187afe8dacc5d91cb8a51282334d9308a818fe4d3607275e2a61f05", - "aecc45c83f0408c96c70f8273e94f930edfbd3cd98896a0e57b1b5929fa5ff0b"}, - }; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - xmr_hash_to_scalar(a1, fromhex(tests[i][0]), strlen(tests[i][0]) / 2); - contract256_modm(out, a1); - ck_assert_mem_eq(out, fromhex(tests[i][1]), 32); - } -} -END_TEST - -START_TEST(test_xmr_hash_to_ec) { - ge25519 p1; - unsigned char out[32]; - char tests[][2][65] = { - {"", "d6d7d783ab18e1be65586adb7902a4175b737ef0b902875e1d1d5c5cf0478c0b"}, - {"00", - "8e2fecb36320bc4e192e10ef54afc7c83fbeb0c38b7debd4fea51301f0bd4f3d"}, - {"000102", - "73b233e2e75d81b9657a857e38e7ab2bc3600e5c56622b9fe4b976ff312220fa"}, - {"000102030405", - "bebe3c84092c0f7a92704cafb16562cc45c47f45e84baec8d4bba3559d1c1808"}, - {"000102030406", - "525567a6a40a94f2d916bc1efea234bbd3b9162403ec2faba871a90f8d0d487e"}, - {"000102030407", - "99b1be2a92cbd22b24b48fb7a9daadd4d13a56915c4f6ed696f271ad5bdbc149"}, - {"42f6835bf83114a1f5f6076fe79bdfa0bd67c74b88f127d54572d3910dd09201", - "54863a0464c008acc99cffb179bc6cf34eb1bbdf6c29f7a070a7c6376ae30ab5"}, - {"44caa1c26187afe8dacc5d91cb8a51282334d9308a818fe4d3607275e2a61f05", - "001000a93e0e6937b4feaf079e418a028ca85459aa39ac3871b94076f88ca608"}, - }; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - xmr_hash_to_ec(&p1, fromhex(tests[i][0]), strlen(tests[i][0]) / 2); - ge25519_pack(out, &p1); - ck_assert_mem_eq(out, fromhex(tests[i][1]), 32); - } -} -END_TEST - -START_TEST(test_xmr_derivation_to_scalar) { - static const struct { - char *pt; - uint32_t idx; - char *sc; - } tests[] = { - { - "c655b2d9d2670a1c9f26f7586b6d6b1ec5173b8b33bca64c3d305a42d66738b1", - 0, - "ca7ce31b273dd1ac00dc3553e654fb66036804800e27c826bd2b78649243900b", - }, - { - "2b1dbd7a007dcc4d729fa8359705595599737fcef60afb36b379fe033095dca7", - 1, - "60afd5a63b14845d3b92d16eac386713e4ff617fdc5c1a07c3212098c1f5610c", - }, - { - "a48ed3797225dab4b4316b5e40107b6bd63e5f4dc517ba602774d703576ec771", - 24, - "fe81804091e50a5c2233faa6277360fbe1948ea15dddbae62c1d40bbd1918606", - }, - { - "fa27b5b39741f5341b4e89269e3a05ff7e76ec7739843872468fc4bec8475410", - 65537, - "1ba36841f57aa8b799c4dd02b39d53e5fb7780d3f09f91a57a86dcb418d8d506", - }, - }; - - ge25519 pt; - bignum256modm sc, sc2; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(sc, fromhex(tests[i].sc), 32); - ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); - - xmr_derivation_to_scalar(sc2, &pt, tests[i].idx); - ck_assert_int_eq(eq256_modm(sc, sc2), 1); - - xmr_derivation_to_scalar(sc2, &pt, tests[i].idx + 1); - ck_assert_int_eq(eq256_modm(sc, sc2), 0); - } -} -END_TEST - -START_TEST(test_xmr_generate_key_derivation) { - static const struct { - char *pt; - char *sc; - char *r; - } tests[] = { - { - "38f94f27c8037aff025e365275ed1029fd636dda5f69e5f98fdcf92e0a28f31a", - "8f1c73ee5327a43264a7b60b9e7882312b582f33e89846a8694dbf094bb3a90a", - "1fbfe4dcc8c824c274649545f297fa320cd4c1689b1d0ff4887567c4d4a75649", - }, - { - "26785c3941a32f194228eb659c5ee305e63868896defc50ee6c4e0e92d1e246a", - "dbbffec4686ba8ab25e2f1b04c0e7ae51c5143c91353bfb5998430ebe365a609", - "cca34db8dd682ec164d8973b555253934596b77849ef7709d9321121c25aba02", - }, - { - "43505a8ce7248f70d3aae4f57fb59c254ce2b2a0cc2bcf50f2344e51d59b36b3", - "19a802e35f6ff94efe96ec016effe04e635bbd9c1ce2612d5ba2ee4659456b06", - "fc6c93a93f77ff89c18b9abf95b28ec8591ab97eee8e4afee93aa766a4bd3934", - }, - }; - - ge25519 pt, pt2, pt3; - bignum256modm sc; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(sc, fromhex(tests[i].sc), 32); - ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); - ge25519_unpack_vartime(&pt2, fromhex(tests[i].r)); - xmr_generate_key_derivation(&pt3, &pt, sc); - ck_assert_int_eq(ge25519_eq(&pt3, &pt2), 1); - ck_assert_int_eq(ge25519_eq(&pt3, &pt), 0); - } -} -END_TEST - -START_TEST(test_xmr_derive_private_key) { - static const struct { - char *pt; - uint32_t idx; - char *base; - char *r; - } tests[] = { - { - "0541d8f069e5e80a892e39bbf1944ef578008cf9ecf1d100760a05858c1b709e", - 0, - "76967eeb0a3d181bb0b384be71c680a4287599f27b2ddbd07f8e06ab6f2c880e", - "45728c5cb658e470790f124a01699d2126832b7e5c6b7760b6f11119b96ad603", - }, - { - "fc6e0bd785a84e62c9ac8a97e0e604a79494bc2cf7b3b38ef8af7791c87b5bb8", - 1, - "32fbe149562b7ccb34bc4105b87b2a834024799336c8eea5e94df77f1ae9a807", - "64508e83bbadf63f8ecfae4d9dcdd39a4ba23508a545e1a37026f0fa2539d601", - }, - { - "f6bd7a72dc9444dc7e09a0eb4d312d36fe173693d6405b132a5b090297a04ea9", - 65537, - "333a8fcce6726457e4222a87b9b475c1fcf985f756c2029fcb39184c0a5c4804", - "37c16a22da4c0082ebf4bf807403b169f75142a9bd8560ed45f3f9347218260e", - }, - }; - - ge25519 pt; - bignum256modm base, res, res_exp; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(base, fromhex(tests[i].base), 32); - expand256_modm(res_exp, fromhex(tests[i].r), 32); - ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); - - xmr_derive_private_key(res, &pt, tests[i].idx, base); - ck_assert_int_eq(eq256_modm(res, res_exp), 1); - ck_assert_int_eq(eq256_modm(res, base), 0); - } -} -END_TEST - -START_TEST(test_xmr_derive_public_key) { - static const struct { - char *pt; - uint32_t idx; - char *base; - char *r; - } tests[] = { - { - "653f03e7766d472826aa49793bc0cfde698e6745ae5e4217980ba307739f2ed9", - 0, - "2a393f0858732970ac8dea003b17e1ce9371f0a045bd9b7af0d998262739f4cc", - "f7a3db27c45f265f6a68a30137ca44289a6cf1a6db2cf482c59ebfb0142ad419", - }, - { - "338e93f61e6470a5cc71c07b8caedd1a9a28da037aab65c1ca5538501b012c81", - 1, - "af3a1d39397d778731c4510110fd117dc02f756e390713d58f94a06203ce39eb", - "779e2a043c881f06aba1952741fd753098615c4fafa8f62748467ab9bac43241", - }, - { - "7735e9476440927b89b18d7a1e0645b218a1a6d28c642aebb16c1dba0926d5e4", - 65537, - "62c3eed062bd602f7f2164c69ad0b5a8eb3ea560c930f6b41abfc1c4839ea432", - "6da4ebd29498d16c4e813abb3e328c83f9b01a7ba1da6e818071f8ec563626c8", - }, - }; - - ge25519 pt, base, res, res_exp; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - ge25519_unpack_vartime(&pt, fromhex(tests[i].pt)); - ge25519_unpack_vartime(&base, fromhex(tests[i].base)); - ge25519_unpack_vartime(&res_exp, fromhex(tests[i].r)); - - xmr_derive_public_key(&res, &pt, tests[i].idx, &base); - - ck_assert_int_eq(ge25519_eq(&res, &res_exp), 1); - ck_assert_int_eq(ge25519_eq(&res, &base), 0); - } -} -END_TEST - -START_TEST(test_xmr_add_keys2) { - static const struct { - char *a; - char *b; - char *B; - char *r; - } tests[] = { - { - "631238da9578d7cb8db16fc4322671bfcb251cc5228b060664800ec1895be608", - "f9a73fca0be058415a148f9e2871be59e1fc7ae6f6193199125237e0d7c1630f", - "ef5ca4fc90f330e825adcdc953da0b3becd853aa819219842790bb39775f2255", - "06623fd0e7a3d787a4d224f6ca2fdab2dcd9d1221578515974b9c4dee65fdcf5", - }, - { - "dac2e629e5c75c312253b19d1d3a0a423158fdd9cdcf4c7a7bf2717d0b748602", - "0483d98d750d4977b499cefd558a0a61580823a37da2b011501e24718e6c7f0a", - "51fd3cd2f1a603ec7be3b35da9c105d91c4304e6a63facf48d7730712cedc0ee", - "f7a5d645ba01a5b7ccbe9636d14422bb587fc529317b23761f0e39222b783b87", - }, - { - "817c4d2fd3e841d860bdab6b7ccf098f3e637eca468d0a3825c50b71f61d0e0c", - "1f6c4795d7fb0d53b5775874ac4c0963607d2b7bd11a7c5d10735badc4a27207", - "bef0e0ed09d602bbe1dd38358b5f8fca27fcad60a69440f104441c3fc68df9c7", - "bc0fc824d74eca0e10eacd0bc2f3322e0bcb02a44ce53f2f5f1fc472f99be8d2", - }, - }; - - bignum256modm a, b; - ge25519 B, res, res_exp; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(a, fromhex(tests[i].a), 32); - expand256_modm(b, fromhex(tests[i].b), 32); - ge25519_unpack_vartime(&B, fromhex(tests[i].B)); - ge25519_unpack_vartime(&res_exp, fromhex(tests[i].r)); - - xmr_add_keys2(&res, a, b, &B); - ck_assert_int_eq(ge25519_eq(&res, &res_exp), 1); - ck_assert_int_eq(ge25519_eq(&res, &B), 0); - - xmr_add_keys2_vartime(&res, a, b, &B); - ck_assert_int_eq(ge25519_eq(&res, &res_exp), 1); - ck_assert_int_eq(ge25519_eq(&res, &B), 0); - } -} -END_TEST - -START_TEST(test_xmr_add_keys3) { - static const struct { - char *a; - char *A; - char *b; - char *B; - char *r; - } tests[] = { - { - "7048b8c4603ae194c502fa458b0e11a4c7a330852bbef66b7c1d67e9f919f509", - "9167c5b182758699baeb421e7f1200272fc775e4c7c7c183cc47261dccbb569f", - "c2cb2bc0249fc7be8eb9b3bed7d37aa6f2c3f433abb3a4a00b13bed64b61f30b", - "b3ec53b07a1be70ac8d0fa365b86f0d6d4cbf98641e7704b3d684558e2ea59ef", - "4dc016d702d599bde5eaeb2bf0c2d0d3f6b9cede961bc539bcb369c3b3086358", - }, - { - "e9794a6652940474958936f07f3904d514228553247633cfb7ae8ffa9fa0f406", - "0e51cea6df2f6f56a9935689364f0d295a7c89f51d40efb2518c17d1b9db792b", - "c132e7be08afdd93984c52c6e1c596edc6b8fc8f1faed95f55e2f819ee806706", - "1a0e03c6858f6cf1b43f4b8456c03144af553bbbd050e152834fd1615b577cb3", - "088f19c6727f8704373d391a36c230395d386f69edb4151ecf8afcd27793fff5", - }, - { - "88920b0c96b15cc04e879f53a76f85f3c7a2a5f275b2772b5b74ee83372aea00", - "e95731ab61a98fedcded475cf21b4ecf2ef9f1adecefba8fdc476a5bb1cf60f9", - "c86026b66c1045fb69e4f24ff6c15d4fad4d565e646938a2ffb7db37ccb4100d", - "d80cbf2986c12e4c7ebac1e55abbdfc4212c00aec8bc90c965becf863262a074", - "047cebaeb3ec2132e7386ba52531b04070206ba1106565c0fbd7d7280694568a", - }, - }; - - bignum256modm a, b; - ge25519 A, B, res, res_exp; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(a, fromhex(tests[i].a), 32); - expand256_modm(b, fromhex(tests[i].b), 32); - ge25519_unpack_vartime(&A, fromhex(tests[i].A)); - ge25519_unpack_vartime(&B, fromhex(tests[i].B)); - ge25519_unpack_vartime(&res_exp, fromhex(tests[i].r)); - - xmr_add_keys3(&res, a, &A, b, &B); - ck_assert_int_eq(ge25519_eq(&res, &res_exp), 1); - ck_assert_int_eq(ge25519_eq(&res, &B), 0); - - xmr_add_keys3_vartime(&res, a, &A, b, &B); - ck_assert_int_eq(ge25519_eq(&res, &res_exp), 1); - ck_assert_int_eq(ge25519_eq(&res, &B), 0); - } -} -END_TEST - -START_TEST(test_xmr_get_subaddress_secret_key) { - static const struct { - uint32_t major, minor; - char *m; - char *r; - } tests[] = { - { - 0, - 0, - "36fad9f7bff465c15a755f1482fb2ecc3a4e434303df906882234e42b5813207", - "8a510a9fe1824b49abbae05958084f9c9098775f29e15427309177882471cf01", - }, - { - 0, - 1, - "36fad9f7bff465c15a755f1482fb2ecc3a4e434303df906882234e42b5813207", - "2bbc9366c04abb0523e2b2d6e709670ffe6645bacedfee968d9c6bc8eefe9c0f", - }, - { - 100, - 100, - "36fad9f7bff465c15a755f1482fb2ecc3a4e434303df906882234e42b5813207", - "c3837d41fedeaed126cf4fc1a5ea47b8b7f38f6a64aa534e3dd45a3c93f37600", - }, - }; - - bignum256modm m, res, res_exp; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(m, fromhex(tests[i].m), 32); - expand256_modm(res_exp, fromhex(tests[i].r), 32); - xmr_get_subaddress_secret_key(res, tests[i].major, tests[i].minor, m); - - ck_assert_int_eq(eq256_modm(res, res_exp), 1); - ck_assert_int_eq(eq256_modm(res, m), 0); - } -} -END_TEST - -START_TEST(test_xmr_gen_c) { - static const struct { - char *a; - uint64_t amount; - char *r; - } tests[] = { - { - "e3e6558c291bbb98aa691d068b67d59dc520afb23fdd51bf65283626fc2ad903", - 0, - "ef19d73bdf3749240b80ee7695f53ad7c2fc2cf868a93209799f41212d099750", - }, - { - "6788c9579c377f3228680bd0e6d01b1ee0c763b35ed39d36fa2146cc2ee16e0e", - 1, - "4913b9af4f2725d87a4404c22cf366597d1c1e6a1f510ae14081d8b7c5a9de77", - }, - { - "ad9e89d67012935540427c241756d6a9d260c5e134603c41d31e24f8651bef08", - 65537, - "f005721da08f24e68314abed3ddfd94165e4be3813398fb126e3f366820b9c90", - }, - { - "fdbb70ff07be24d98de3bffa0a33756646497224318fb7fe136f0e7789d12607", - 0xffffffffffffffffULL, - "a9c38927f299c5f14c98a1a9c9981e59c606ff597274b9b709e1356f12e1498c", - }, - }; - - bignum256modm a; - ge25519 res, res_exp; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - expand256_modm(a, fromhex(tests[i].a), 32); - ge25519_unpack_vartime(&res_exp, fromhex(tests[i].r)); - xmr_gen_c(&res, a, tests[i].amount); - - ck_assert_int_eq(ge25519_eq(&res, &res_exp), 1); - } -} -END_TEST - -START_TEST(test_xmr_varint) { - static const struct { - uint64_t x; - char *r; - } tests[] = { - { - 0, - "00", - }, - { - 24, - "18", - }, - { - 65535, - "ffff03", - }, - { - 65537, - "818004", - }, - { - 0x7fffffffULL, - "ffffffff07", - }, - { - 0xffffffffULL, - "ffffffff0f", - }, - { - 0xffffffffffffffffULL, - "ffffffffffffffffff01", - }, - { - 0xdeadc0deULL, - "de81b7f50d", - }, - }; - - uint64_t val; - unsigned char buff[64]; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - int s1 = xmr_size_varint(tests[i].x); - int written = 0; - int read = 0; - - ck_assert_uint_eq((size_t)s1, strlen(tests[i].r) / 2); - written = xmr_write_varint(buff, sizeof(buff), tests[i].x); - ck_assert_int_eq(s1, written); - ck_assert_mem_eq(buff, fromhex(tests[i].r), strlen(tests[i].r) / 2); - - read = xmr_read_varint(buff, sizeof(buff), &val); - ck_assert_int_eq(read, written); - ck_assert(tests[i].x == val); - } -} -END_TEST - -START_TEST(test_xmr_gen_range_sig) { - uint64_t tests[] = { - 0, 1, 65535, 65537, 0xffffffffffffffffULL, 0xdeadc0deULL, - }; - - unsigned char buff[32]; - xmr_range_sig_t sig; - ge25519 C, Ctmp, Cb, Ch, P1, P2, LL; - bignum256modm mask, hsh, ee, s, ee_comp; - Hasher hasher; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - xmr_gen_range_sig(&sig, &C, mask, tests[i], NULL); - - ge25519_set_neutral(&Ctmp); - for (int j = 0; j < XMR_ATOMS; j++) { - ge25519_unpack_vartime(&Cb, sig.Ci[j]); - ge25519_add(&Ctmp, &Ctmp, &Cb, 0); - } - - ck_assert_int_eq(ge25519_eq(&C, &Ctmp), 1); - - xmr_hasher_init(&hasher); - ge25519_set_xmr_h(&Ch); - expand256_modm(ee, sig.asig.ee, 32); - - for (int j = 0; j < XMR_ATOMS; j++) { - ge25519_unpack_vartime(&P1, sig.Ci[j]); - ge25519_add(&P2, &P1, &Ch, 1); - expand256_modm(s, sig.asig.s0[j], 32); - - xmr_add_keys2(&LL, s, ee, &P1); - ge25519_pack(buff, &LL); - xmr_hash_to_scalar(hsh, buff, 32); - - expand256_modm(s, sig.asig.s1[j], 32); - xmr_add_keys2(&LL, s, hsh, &P2); - - ge25519_pack(buff, &LL); - xmr_hasher_update(&hasher, buff, 32); - - ge25519_double(&Ch, &Ch); - } - - xmr_hasher_final(&hasher, buff); - expand256_modm(ee_comp, buff, 32); - ck_assert_int_eq(eq256_modm(ee, ee_comp), 1); - } -} -END_TEST -#endif diff --git a/deps/crypto/trezor-crypto/tests/test_check_nano.h b/deps/crypto/trezor-crypto/tests/test_check_nano.h deleted file mode 100644 index 7f4a98873..000000000 --- a/deps/crypto/trezor-crypto/tests/test_check_nano.h +++ /dev/null @@ -1,111 +0,0 @@ -#if USE_NANO -#include "nano.h" - -START_TEST(test_bip32_nano_vector_1) -{ - const char *mnemonic = "edge defense waste choose enrich upon flee junk siren film clown finish luggage leader kid quick brick print evidence swap drill paddle truly occur"; - const char *password = "some password"; - - uint8_t seed[64]; - mnemonic_to_seed(mnemonic, password, seed, NULL); - - HDNode node; - hdnode_from_seed(seed, sizeof(seed), ED25519_BLAKE2B_NANO_NAME, &node); - hdnode_private_ckd_prime(&node, 44); - hdnode_private_ckd_prime(&node, 165); - hdnode_private_ckd_prime(&node, 0); - hdnode_fill_public_key(&node); - - ck_assert_mem_eq(node.private_key, fromhex("3be4fc2ef3f3b7374e6fc4fb6e7bb153f8a2998b3b3dab50853eabe128024143"), 32); - ck_assert_mem_eq(node.public_key+1, fromhex("5b65b0e8173ee0802c2c3e6c9080d1a16b06de1176c938a924f58670904e82c4"), 32); -} -END_TEST - -START_TEST(test_base32_nano) -{ - const char *in_hex = "0000005114aad86a390897d2a91b33b931b3a59a7df9e63eb3694f9430122f5622ae505c6ff6b58e"; - const char *out = "11111nanode8ngaakzbck8smq6ru9bethqwyehomf79sae1k7xd47dkidjqzffeg"; - - uint8_t in[40]; - memcpy(in, fromhex(in_hex), sizeof(in)); - - char buffer[96]; - - ck_assert(base32_encode(in, sizeof(in), buffer, sizeof(buffer), BASE32_ALPHABET_NANO) != NULL); - ck_assert_str_eq(buffer, out); - - ck_assert(base32_decode(out, strlen(out), (uint8_t *)buffer, sizeof(buffer), BASE32_ALPHABET_NANO) != NULL); - ck_assert_mem_eq(buffer, in, sizeof(in)); -} -END_TEST - -START_TEST(test_nano_get_address) -{ - const char *prefix = "nano_"; - - struct { - const char *pk_hex; - const char *address; - } tests[] = { - /* 1 */ { "5114aad86a390897d2a91b33b931b3a59a7df9e63eb3694f9430122f5622ae50", - "nano_1nanode8ngaakzbck8smq6ru9bethqwyehomf79sae1k7xd47dkidjqzffeg" }, - /* 2 */ { "ea6f44048f04bf1f7083f5ad115a9f4e62ecb61b89a83e8bc68ad1e4d9575469", - "nano_3tmhai4ay37z5xra9xff47fbymm4xku3q4fa9t7wf4pjwmeogo5ba8wyccku" }, - /* 3 */ { "0000000000000000000000000000000000000000000000000000000000000000", - "nano_1111111111111111111111111111111111111111111111111111hifc8npp" }, - /* 4 */ { "e89208dd038fbb269987689621d52292ae9c35941a7484756ecced92a65093ba", - "nano_3t6k35gi95xu6tergt6p69ck76ogmitsa8mnijtpxm9fkcm736xtoncuohr3" }, - }; - - for (int i = 0; i < 4; i++) { - ed25519_public_key public_key; - memcpy(public_key, fromhex(tests[i].pk_hex), sizeof(public_key)); - - char buffer[96]; - size_t count; - count = nano_get_address( - public_key, - prefix, strlen(prefix), - buffer, sizeof(buffer) - ); - ck_assert_int_eq(count, 66); - ck_assert_str_eq(buffer, tests[i].address); - } -} - -END_TEST -START_TEST(test_nano_validate_address) -{ - const char *prefix = "nano_"; - - struct { - const char *address; - const char *pk_hex; - } tests[] = { - /* 1 */ { "nano_1nanode8ngaakzbck8smq6ru9bethqwyehomf79sae1k7xd47dkidjqzffeg", - "5114aad86a390897d2a91b33b931b3a59a7df9e63eb3694f9430122f5622ae50" }, - /* 2 */ { "xrb_1nanode8ngaakzbck8smq6ru9bethqwyehomf79sae1k7xd47dkidjqzffeg", - NULL }, - /* 3 */ { "nano_1nanode7ngaakzbck8smq6ru9bethqwyehomf79sae1k7xd47dkidjqzffeg", - NULL }, - }; - - for (int i = 0; i < 3; i++) { - ed25519_public_key public_key; - bool is_valid; - is_valid = nano_validate_address( - prefix, strlen(prefix), - tests[i].address, strlen(tests[i].address), - &public_key - ); - if (tests[i].pk_hex == NULL) { - ck_assert(is_valid == false); - } else { - ck_assert(is_valid == true); - ck_assert_mem_eq(public_key, fromhex(tests[i].pk_hex), sizeof(public_key)); - } - } -} - -END_TEST -#endif diff --git a/deps/crypto/trezor-crypto/tests/test_check_segwit.h b/deps/crypto/trezor-crypto/tests/test_check_segwit.h deleted file mode 100644 index 6cd618092..000000000 --- a/deps/crypto/trezor-crypto/tests/test_check_segwit.h +++ /dev/null @@ -1,149 +0,0 @@ -#include "segwit_addr.h" - -static const char* valid_checksum[] = { - "A12UEL5L", - "an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedchar" - "actersbio1tt5tgs", - "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", - "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq" - "qqqqqqqqqqc8247j", - "split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", -}; - -static const char* invalid_checksum[] = { - " 1nwldj5", - "\x7f" - "1axkwrx", - "an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcha" - "ractersbio1569pvx", - "pzry9x0s0muk", - "1pzry9x0s0muk", - "x1b4n0q5v", - "li1dgmt3", - "de1lg7wt\xff", -}; - -struct valid_address_data { - const char* address; - size_t scriptPubKeyLen; - const uint8_t scriptPubKey[42]; -}; - -struct invalid_address_data { - const char* hrp; - int version; - size_t program_length; -}; - -static struct valid_address_data valid_address[] = { - {"BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4", - 22, - {0x00, 0x14, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, - 0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6}}, - {"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7", - 34, - {0x00, 0x20, 0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68, 0x04, 0xbd, - 0x19, 0x20, 0x33, 0x56, 0xda, 0x13, 0x6c, 0x98, 0x56, 0x78, 0xcd, 0x4d, - 0x27, 0xa1, 0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32, 0x62}}, - {"tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy", - 34, - {0x00, 0x20, 0x00, 0x00, 0x00, 0xc4, 0xa5, 0xca, 0xd4, 0x62, 0x21, 0xb2, - 0xa1, 0x87, 0x90, 0x5e, 0x52, 0x66, 0x36, 0x2b, 0x99, 0xd5, 0xe9, 0x1c, - 0x6c, 0xe2, 0x4d, 0x16, 0x5d, 0xab, 0x93, 0xe8, 0x64, 0x33}}}; - -static const char* invalid_address[] = { - "tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty", - "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5", - "BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2", - "bc1rw5uspcuh", - ("bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs" - "90"), - "BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P", - "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7", - "bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du", - "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv", - "bc1gmk9yu", -}; - -static struct invalid_address_data invalid_address_enc[] = { - {"BC", 0, 20}, {"bc", 0, 21}, {"bc", 17, 32}, {"bc", 1, 1}, {"bc", 16, 41}, -}; - -static void segwit_scriptpubkey(uint8_t* scriptpubkey, size_t* scriptpubkeylen, - int witver, const uint8_t* witprog, - size_t witprog_len) { - scriptpubkey[0] = witver ? (0x50 + witver) : 0; - scriptpubkey[1] = witprog_len; - memcpy(scriptpubkey + 2, witprog, witprog_len); - *scriptpubkeylen = witprog_len + 2; -} - -START_TEST(test_segwit) { - size_t i; - for (i = 0; i < sizeof(valid_checksum) / sizeof(valid_checksum[0]); ++i) { - uint8_t data[82]; - char rebuild[92]; - char hrp[84]; - size_t data_len; - int res = bech32_decode(hrp, data, &data_len, valid_checksum[i]); - ck_assert_int_eq(res, 1); - res = bech32_encode(rebuild, hrp, data, data_len, - BECH32_ENCODING_BECH32); - ck_assert_int_eq(res, 1); - ck_assert_int_eq(my_strncasecmp(rebuild, valid_checksum[i], 92), 0); - } - for (i = 0; i < sizeof(invalid_checksum) / sizeof(invalid_checksum[0]); ++i) { - uint8_t data[82]; - char hrp[84]; - size_t data_len; - int res = bech32_decode(hrp, data, &data_len, invalid_checksum[i]); - ck_assert_int_eq(res, 0); - } - for (i = 0; i < sizeof(valid_address) / sizeof(valid_address[0]); ++i) { - uint8_t witprog[40]; - size_t witprog_len; - int witver; - const char* hrp = "bc"; - uint8_t scriptpubkey[42]; - size_t scriptpubkey_len; - char rebuild[93]; - int ret = segwit_addr_decode(&witver, witprog, &witprog_len, hrp, - valid_address[i].address); - if (!ret) { - hrp = "tb"; - ret = segwit_addr_decode(&witver, witprog, &witprog_len, hrp, - valid_address[i].address); - } - ck_assert_int_eq(ret, 1); - segwit_scriptpubkey(scriptpubkey, &scriptpubkey_len, witver, witprog, - witprog_len); - ck_assert_uint_eq(scriptpubkey_len, valid_address[i].scriptPubKeyLen); - ck_assert_int_eq( - memcmp(scriptpubkey, valid_address[i].scriptPubKey, scriptpubkey_len), - 0); - ck_assert_int_eq( - segwit_addr_encode(rebuild, hrp, witver, witprog, witprog_len), 1); - ck_assert_int_eq(my_strncasecmp(valid_address[i].address, rebuild, 93), 0); - } - for (i = 0; i < sizeof(invalid_address) / sizeof(invalid_address[0]); ++i) { - uint8_t witprog[40]; - size_t witprog_len; - int witver; - int ret = segwit_addr_decode(&witver, witprog, &witprog_len, "bc", - invalid_address[i]); - ck_assert_int_eq(ret, 0); - ret = segwit_addr_decode(&witver, witprog, &witprog_len, "tb", - invalid_address[i]); - ck_assert_int_eq(ret, 0); - } - for (i = 0; i < sizeof(invalid_address_enc) / sizeof(invalid_address_enc[0]); - ++i) { - char rebuild[93]; - static const uint8_t program[42] = {0}; - int ret = segwit_addr_encode(rebuild, invalid_address_enc[i].hrp, - invalid_address_enc[i].version, program, - invalid_address_enc[i].program_length); - ck_assert_int_eq(ret, 0); - } -} -END_TEST diff --git a/deps/crypto/trezor-crypto/tests/test_curves.py b/deps/crypto/trezor-crypto/tests/test_curves.py deleted file mode 100755 index 6897cea87..000000000 --- a/deps/crypto/trezor-crypto/tests/test_curves.py +++ /dev/null @@ -1,353 +0,0 @@ -#!/usr/bin/py.test -import binascii -import ctypes as c -import hashlib -import os -import random - -import curve25519 -import ecdsa -import pytest - - -def bytes2num(s): - res = 0 - for i, b in enumerate(reversed(bytearray(s))): - res += b << (i * 8) - return res - - -curves = {"nist256p1": ecdsa.curves.NIST256p, "secp256k1": ecdsa.curves.SECP256k1} - - -class Point: - def __init__(self, name, x, y): - self.curve = name - self.x = x - self.y = y - - -points = [ - Point( - "secp256k1", - 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798, - 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8, - ), - Point( - "secp256k1", - 0x1, - 0x4218F20AE6C646B363DB68605822FB14264CA8D2587FDD6FBC750D587E76A7EE, - ), - Point( - "secp256k1", - 0x2, - 0x66FBE727B2BA09E09F5A98D70A5EFCE8424C5FA425BBDA1C511F860657B8535E, - ), - Point( - "secp256k1", - 0x1B, - 0x1ADCEA1CF831B0AD1653E769D1A229091D0CC68D4B0328691B9CAACC76E37C90, - ), - Point( - "nist256p1", - 0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296, - 0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5, - ), - Point( - "nist256p1", - 0x0, - 0x66485C780E2F83D72433BD5D84A06BB6541C2AF31DAE871728BF856A174F93F4, - ), - Point( - "nist256p1", - 0x0, - 0x99B7A386F1D07C29DBCC42A27B5F9449ABE3D50DE25178E8D7407A95E8B06C0B, - ), - Point( - "nist256p1", - 0xAF8BBDFE8CDD5577ACBF345B543D28CF402F4E94D3865B97EA0787F2D3AA5D22, - 0x35802B8B376B995265918B078BC109C21A535176585C40F519ACA52D6AFC147C, - ), - Point( - "nist256p1", - 0x80000, - 0x580610071F440F0DCC14A22E2D5D5AFC1224C0CD11A3B4B51B8ECD2224EE1CE2, - ), -] - -random_iters = int(os.environ.get("ITERS", 1)) - -DIR = os.path.abspath(os.path.dirname(__file__)) -lib = c.cdll.LoadLibrary(os.path.join(DIR, "libtrezor-crypto.so")) - -BIGNUM = c.c_uint32 * 9 - - -class curve_info(c.Structure): - _fields_ = [("bip32_name", c.c_char_p), ("params", c.c_void_p)] - - -class curve_point(c.Structure): - _fields_ = [("x", BIGNUM), ("y", BIGNUM)] - - -class ecdsa_curve(c.Structure): - _fields_ = [ - ("prime", BIGNUM), - ("G", curve_point), - ("order", BIGNUM), - ("order_half", BIGNUM), - ("a", c.c_int), - ("b", BIGNUM), - ] - - -lib.get_curve_by_name.restype = c.POINTER(curve_info) - - -class Random(random.Random): - def randbytes(self, n): - buf = (c.c_uint8 * n)() - for i in range(n): - buf[i] = self.randrange(0, 256) - return buf - - def randpoint(self, curve): - k = self.randrange(0, curve.order) - return k * curve.generator - - -def int2bn(x, bn_type=BIGNUM): - b = bn_type() - b._int = x - for i in range(len(b)): - b[i] = x % (1 << 29) - x = x >> 29 - return b - - -def bn2int(b): - x = 0 - for i in range(len(b)): - x += b[i] << (29 * i) - return x - - -@pytest.fixture(params=range(random_iters)) -def r(request): - seed = request.param - return Random(seed + int(os.environ.get("SEED", 0))) - - -@pytest.fixture(params=list(sorted(curves))) -def curve(request): - name = request.param - curve_ptr = lib.get_curve_by_name(bytes(name, "ascii")).contents.params - assert curve_ptr, "curve {} not found".format(name) - curve_obj = curves[name] - curve_obj.ptr = c.cast(curve_ptr, c.POINTER(ecdsa_curve)) - curve_obj.p = curve_obj.curve.p() # shorthand - return curve_obj - - -@pytest.fixture(params=points) -def point(request): - name = request.param.curve - curve_ptr = lib.get_curve_by_name(bytes(name, "ascii")).contents.params - assert curve_ptr, "curve {} not found".format(name) - curve_obj = curves[name] - curve_obj.ptr = c.c_void_p(curve_ptr) - curve_obj.p = ecdsa.ellipticcurve.Point( - curve_obj.curve, request.param.x, request.param.y - ) - return curve_obj - - -POINT = BIGNUM * 2 - - -def to_POINT(p): - return POINT(int2bn(p.x()), int2bn(p.y())) - - -def from_POINT(p): - return (bn2int(p[0]), bn2int(p[1])) - - -JACOBIAN = BIGNUM * 3 - - -def to_JACOBIAN(jp): - return JACOBIAN(int2bn(jp[0]), int2bn(jp[1]), int2bn(jp[2])) - - -def from_JACOBIAN(p): - return (bn2int(p[0]), bn2int(p[1]), bn2int(p[2])) - - -def test_curve_parameters(curve): - assert curve.curve.p() == bn2int(curve.ptr.contents.prime) - assert curve.generator.x() == bn2int(curve.ptr.contents.G.x) - assert curve.generator.y() == bn2int(curve.ptr.contents.G.y) - assert curve.order == bn2int(curve.ptr.contents.order) - assert curve.order // 2 == bn2int(curve.ptr.contents.order_half) - assert curve.curve.a() == curve.ptr.contents.a - assert curve.curve.b() == bn2int(curve.ptr.contents.b) - - -def test_point_multiply(curve, r): - p = r.randpoint(curve) - k = r.randrange(0, 2 ** 256) - kp = k * p - res = POINT(int2bn(0), int2bn(0)) - lib.point_multiply(curve.ptr, int2bn(k), to_POINT(p), res) - res = from_POINT(res) - assert res == (kp.x(), kp.y()) - - -def test_point_add(curve, r): - p1 = r.randpoint(curve) - p2 = r.randpoint(curve) - # print '-' * 80 - q = p1 + p2 - q1 = to_POINT(p1) - q2 = to_POINT(p2) - lib.point_add(curve.ptr, q1, q2) - q_ = from_POINT(q2) - assert q_ == (q.x(), q.y()) - - -def test_point_double(curve, r): - p = r.randpoint(curve) - q = p.double() - q_ = to_POINT(p) - lib.point_double(curve.ptr, q_) - q_ = from_POINT(q_) - assert q_ == (q.x(), q.y()) - - -def test_point_to_jacobian(curve, r): - p = r.randpoint(curve) - jp = JACOBIAN() - lib.curve_to_jacobian(to_POINT(p), jp, int2bn(curve.p)) - jx, jy, jz = from_JACOBIAN(jp) - assert jx % curve.p == (p.x() * jz ** 2) % curve.p - assert jy % curve.p == (p.y() * jz ** 3) % curve.p - - q = POINT() - lib.jacobian_to_curve(jp, q, int2bn(curve.p)) - q = from_POINT(q) - assert q == (p.x(), p.y()) - - -def test_jacobian_add(curve, r): - p1 = r.randpoint(curve) - p2 = r.randpoint(curve) - prime = int2bn(curve.p) - q = POINT() - jp2 = JACOBIAN() - lib.curve_to_jacobian(to_POINT(p2), jp2, prime) - lib.point_jacobian_add(to_POINT(p1), jp2, curve.ptr) - lib.jacobian_to_curve(jp2, q, prime) - q = from_POINT(q) - p_ = p1 + p2 - assert (p_.x(), p_.y()) == q - - -def test_jacobian_add_double(curve, r): - p1 = r.randpoint(curve) - p2 = p1 - prime = int2bn(curve.p) - q = POINT() - jp2 = JACOBIAN() - lib.curve_to_jacobian(to_POINT(p2), jp2, prime) - lib.point_jacobian_add(to_POINT(p1), jp2, curve.ptr) - lib.jacobian_to_curve(jp2, q, prime) - q = from_POINT(q) - p_ = p1 + p2 - assert (p_.x(), p_.y()) == q - - -def test_jacobian_double(curve, r): - p = r.randpoint(curve) - p2 = p.double() - prime = int2bn(curve.p) - q = POINT() - jp = JACOBIAN() - lib.curve_to_jacobian(to_POINT(p), jp, prime) - lib.point_jacobian_double(jp, curve.ptr) - lib.jacobian_to_curve(jp, q, prime) - q = from_POINT(q) - assert (p2.x(), p2.y()) == q - - -def sigdecode(sig, _): - return map(bytes2num, [sig[:32], sig[32:]]) - - -def test_sign(curve, r): - priv = r.randbytes(32) - digest = r.randbytes(32) - sig = r.randbytes(64) - - lib.ecdsa_sign_digest(curve.ptr, priv, digest, sig, c.c_void_p(0), c.c_void_p(0)) - - exp = bytes2num(priv) - sk = ecdsa.SigningKey.from_secret_exponent(exp, curve, hashfunc=hashlib.sha256) - vk = sk.get_verifying_key() - - sig_ref = sk.sign_digest_deterministic( - digest, hashfunc=hashlib.sha256, sigencode=ecdsa.util.sigencode_string_canonize - ) - assert binascii.hexlify(sig) == binascii.hexlify(sig_ref) - - assert vk.verify_digest(sig, digest, sigdecode) - - -def test_validate_pubkey(curve, r): - p = r.randpoint(curve) - assert lib.ecdsa_validate_pubkey(curve.ptr, to_POINT(p)) - - -def test_validate_pubkey_direct(point): - assert lib.ecdsa_validate_pubkey(point.ptr, to_POINT(point.p)) - - -def test_curve25519(r): - sec1 = bytes(bytearray(r.randbytes(32))) - sec2 = bytes(bytearray(r.randbytes(32))) - pub1 = curve25519.Private(sec1).get_public() - pub2 = curve25519.Private(sec2).get_public() - - session1 = r.randbytes(32) - lib.curve25519_scalarmult(session1, sec2, pub1.public) - session2 = r.randbytes(32) - lib.curve25519_scalarmult(session2, sec1, pub2.public) - assert bytearray(session1) == bytearray(session2) - - shared1 = curve25519.Private(sec2).get_shared_key(pub1, hashfunc=lambda x: x) - shared2 = curve25519.Private(sec1).get_shared_key(pub2, hashfunc=lambda x: x) - assert shared1 == shared2 - assert bytearray(session1) == shared1 - assert bytearray(session2) == shared2 - - -def test_curve25519_pubkey(r): - sec = bytes(bytearray(r.randbytes(32))) - pub = curve25519.Private(sec).get_public() - res = r.randbytes(32) - lib.curve25519_scalarmult_basepoint(res, sec) - assert bytearray(res) == pub.public - - -def test_curve25519_scalarmult_from_gpg(r): - sec = binascii.unhexlify( - "4a1e76f133afb29dbc7860bcbc16d0e829009cc15c2f81ed26de1179b1d9c938" - ) - pub = binascii.unhexlify( - "5d6fc75c016e85b17f54e0128a216d5f9229f25bac1ec85cecab8daf48621b31" - ) - res = r.randbytes(32) - lib.curve25519_scalarmult(res, sec[::-1], pub[::-1]) - expected = "a93dbdb23e5c99da743e203bd391af79f2b83fb8d0fd6ec813371c71f08f2d4d" - assert binascii.hexlify(bytearray(res)) == bytes(expected, "ascii") diff --git a/deps/crypto/trezor-crypto/tests/test_openssl.c b/deps/crypto/trezor-crypto/tests/test_openssl.c deleted file mode 100644 index c6ce47894..000000000 --- a/deps/crypto/trezor-crypto/tests/test_openssl.c +++ /dev/null @@ -1,143 +0,0 @@ -/** - * Copyright (c) 2013-2014 Tomas Dzetkulic - * Copyright (c) 2013-2014 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -/* OpenSSL's SHA256_CTX/SHA512_CTX conflicts with our own */ -#define SHA256_CTX _openssl_SHA256_CTX -#define SHA512_CTX _openssl_SHA512_CTX -#include -#include -#include -#include -#include -#undef SHA256_CTX -#undef SHA512_CTX - -#include -#include -#include - -#include "ecdsa.h" -#include "hasher.h" -#include "rand.h" - -#include "nist256p1.h" -#include "secp256k1.h" - -#include "memzero.h" - -void openssl_check(unsigned int iterations, int nid, const ecdsa_curve *curve) { - uint8_t sig[64], pub_key33[33], pub_key65[65], priv_key[32], msg[256], - hash[32]; - struct SHA256state_st sha256; - EC_GROUP *ecgroup; - - ecgroup = EC_GROUP_new_by_curve_name(nid); - - for (unsigned int iter = 0; iter < iterations; iter++) { - // random message len between 1 and 256 - int msg_len = (random32() & 0xFF) + 1; - // create random message - random_buffer(msg, msg_len); - - // new ECDSA key - EC_KEY *eckey = EC_KEY_new(); - EC_KEY_set_group(eckey, ecgroup); - - // generate the key - EC_KEY_generate_key(eckey); - // copy key to buffer - const BIGNUM *K = EC_KEY_get0_private_key(eckey); - int bn_off = sizeof(priv_key) - BN_num_bytes(K); - memzero(priv_key, bn_off); - BN_bn2bin(K, priv_key + bn_off); - - // use our ECDSA signer to sign the message with the key - if (ecdsa_sign(curve, HASHER_SHA2, priv_key, msg, msg_len, sig, NULL, - NULL) != 0) { - printf("trezor-crypto signing failed\n"); - return; - } - - // generate public key from private key - ecdsa_get_public_key33(curve, priv_key, pub_key33); - ecdsa_get_public_key65(curve, priv_key, pub_key65); - - // use our ECDSA verifier to verify the message signature - if (ecdsa_verify(curve, HASHER_SHA2, pub_key65, sig, msg, msg_len) != 0) { - printf("trezor-crypto verification failed (pub_key_len = 65)\n"); - return; - } - if (ecdsa_verify(curve, HASHER_SHA2, pub_key33, sig, msg, msg_len) != 0) { - printf("trezor-crypto verification failed (pub_key_len = 33)\n"); - return; - } - - // copy signature to the OpenSSL struct - ECDSA_SIG *signature = ECDSA_SIG_new(); -#if OPENSSL_VERSION_NUMBER < 0x10100000L - BN_bin2bn(sig, 32, signature->r); - BN_bin2bn(sig + 32, 32, signature->s); -#else - BIGNUM *R = BN_bin2bn(sig, 32, NULL); - BIGNUM *S = BN_bin2bn(sig + 32, 32, NULL); - ECDSA_SIG_set0(signature, R, S); -#endif - - // compute the digest of the message - // note: these are OpenSSL functions, not our own - SHA256_Init(&sha256); - SHA256_Update(&sha256, msg, msg_len); - SHA256_Final(hash, &sha256); - - // verify all went well, i.e. we can decrypt our signature with OpenSSL - int v = ECDSA_do_verify(hash, 32, signature, eckey); - if (v != 1) { - printf("OpenSSL verification failed (%d)\n", v); - return; - } - - ECDSA_SIG_free(signature); - EC_KEY_free(eckey); - if (((iter + 1) % 100) == 0) printf("Passed ... %d\n", iter + 1); - } - EC_GROUP_free(ecgroup); - printf("All OK\n"); -} - -int main(int argc, char *argv[]) { - if (argc != 2) { - printf("Usage: test_openssl iterations\n"); - return 1; - } - - unsigned int iterations; - sscanf(argv[1], "%u", &iterations); - - printf("Testing secp256k1:\n"); - openssl_check(iterations, NID_secp256k1, &secp256k1); - - printf("Testing nist256p1:\n"); - openssl_check(iterations, NID_X9_62_prime256v1, &nist256p1); - - return 0; -} diff --git a/deps/crypto/trezor-crypto/tests/test_pallas_ct.c b/deps/crypto/trezor-crypto/tests/test_pallas_ct.c deleted file mode 100644 index d0e810a01..000000000 --- a/deps/crypto/trezor-crypto/tests/test_pallas_ct.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Secret-flow regression harness for Pallas scalar multiplication. - * - * With VALGRIND=1, scalar bytes are marked undefined before multiplication. - * Memcheck then reports any conditional branch or memory address derived from - * the scalar (the standard ctgrind technique already used by test_check.c). - */ - -#include -#include -#include - -#if VALGRIND -#include -#include -#endif - -#include "pallas_ct.h" - -static const curve_point PALLAS_GENERATOR = { - {/* x = p - 1 */ {0x00000000, 0x09698768, 0x133e46e6, 0x0d31f812, - 0x00000224, 0x00000000, 0x00000000, 0x00000000, - 0x00400000}}, - {/* y = 2 */ {0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000}}, -}; - -static bignum256 scalar_with_bit(unsigned bit) { - bignum256 scalar = {{0}}; - scalar.val[bit / BN_BITS_PER_LIMB] = UINT32_C(1) << (bit % BN_BITS_PER_LIMB); - return scalar; -} - -static bignum256 dense_scalar(void) { - bignum256 scalar; - size_t i; - for (i = 0; i < BN_LIMBS - 1; ++i) { - scalar.val[i] = BN_LIMB_MASK; - } - scalar.val[BN_LIMBS - 1] = (UINT32_C(1) << 22) - 1; - return scalar; -} - -static bignum256 max_256(void) { - bignum256 value; - size_t i; - for (i = 0; i < BN_LIMBS - 1; ++i) { - value.val[i] = BN_LIMB_MASK; - } - value.val[BN_LIMBS - 1] = UINT32_C(0x00ffffff); - return value; -} - -static void multiply_secret(const bignum256* input, curve_point* result) { - bignum256 scalar = *input; -#if VALGRIND - VALGRIND_MAKE_MEM_UNDEFINED(&scalar, sizeof(scalar)); -#endif - pallas_ct_point_mult(&scalar, &PALLAS_GENERATOR, result); -#if VALGRIND - VALGRIND_MAKE_MEM_DEFINED(&scalar, sizeof(scalar)); - VALGRIND_MAKE_MEM_DEFINED(result, sizeof(*result)); -#endif - memset(&scalar, 0, sizeof(scalar)); -} - -static void normalize_secret(const bignum256* input) { - bignum256 scalar = *input; -#if VALGRIND - VALGRIND_MAKE_MEM_UNDEFINED(&scalar, sizeof(scalar)); -#endif - pallas_ct_scalar_replace_zero_with_one(&scalar); -#if VALGRIND - VALGRIND_MAKE_MEM_DEFINED(&scalar, sizeof(scalar)); -#endif - memset(&scalar, 0, sizeof(scalar)); -} - -int main(void) { - const bignum256 scalars[] = { - {{0}}, - scalar_with_bit(0), - scalar_with_bit(17), - scalar_with_bit(254), - dense_scalar(), - max_256(), - }; - const curve_point identity = {{{0}}, {{0}}}; - curve_point result; - size_t i; - -#if VALGRIND - if (!RUNNING_ON_VALGRIND) { - fprintf(stderr, "VALGRIND=1 harness must run under Valgrind\n"); - return 2; - } -#endif - - for (i = 0; i < sizeof(scalars) / sizeof(scalars[0]); ++i) { - normalize_secret(&scalars[i]); - multiply_secret(&scalars[i], &result); - } - - multiply_secret(&scalars[0], &result); - if (memcmp(&result, &identity, sizeof(result)) != 0) { - fprintf(stderr, "zero scalar did not produce the identity\n"); - return 1; - } - - multiply_secret(&scalars[1], &result); - if (memcmp(&result, &PALLAS_GENERATOR, sizeof(result)) != 0) { - fprintf(stderr, "one scalar did not reproduce the generator\n"); - return 1; - } - - memset(&result, 0, sizeof(result)); - puts("Pallas constant-time secret-flow harness: PASS"); - return 0; -} diff --git a/deps/crypto/trezor-crypto/tests/test_speed.c b/deps/crypto/trezor-crypto/tests/test_speed.c deleted file mode 100644 index 4d29e0c46..000000000 --- a/deps/crypto/trezor-crypto/tests/test_speed.c +++ /dev/null @@ -1,233 +0,0 @@ -#include -#include -#include -#include -#include -#include "bip32.h" -#include "curves.h" -#include "ecdsa.h" -#include "ed25519-donna/ed25519.h" -#include "hasher.h" -#include "nist256p1.h" -#include "secp256k1.h" - -static uint8_t msg[256]; - -void prepare_msg(void) { - for (size_t i = 0; i < sizeof(msg); i++) { - msg[i] = i * 1103515245; - } -} - -void bench_sign_secp256k1(int iterations) { - uint8_t sig[64], priv[32], pby; - - const ecdsa_curve *curve = &secp256k1; - - memcpy(priv, - "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3" - "\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", - 32); - - for (int i = 0; i < iterations; i++) { - ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL); - } -} - -void bench_sign_nist256p1(int iterations) { - uint8_t sig[64], priv[32], pby; - - const ecdsa_curve *curve = &nist256p1; - - memcpy(priv, - "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3" - "\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", - 32); - - for (int i = 0; i < iterations; i++) { - ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL); - } -} - -void bench_sign_ed25519(int iterations) { - ed25519_public_key pk; - ed25519_secret_key sk; - ed25519_signature sig; - - memcpy(pk, - "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3" - "\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", - 32); - ed25519_publickey(sk, pk); - - for (int i = 0; i < iterations; i++) { - ed25519_sign(msg, sizeof(msg), sk, sig); - } -} - -void bench_verify_secp256k1_33(int iterations) { - uint8_t sig[64], pub[33], priv[32], pby; - - const ecdsa_curve *curve = &secp256k1; - - memcpy(priv, - "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3" - "\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", - 32); - ecdsa_get_public_key33(curve, priv, pub); - ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL); - - for (int i = 0; i < iterations; i++) { - ecdsa_verify(curve, HASHER_SHA2, pub, sig, msg, sizeof(msg)); - } -} - -void bench_verify_secp256k1_65(int iterations) { - uint8_t sig[64], pub[65], priv[32], pby; - - const ecdsa_curve *curve = &secp256k1; - - memcpy(priv, - "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3" - "\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", - 32); - ecdsa_get_public_key65(curve, priv, pub); - ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL); - - for (int i = 0; i < iterations; i++) { - ecdsa_verify(curve, HASHER_SHA2, pub, sig, msg, sizeof(msg)); - } -} - -void bench_verify_nist256p1_33(int iterations) { - uint8_t sig[64], pub[33], priv[32], pby; - - const ecdsa_curve *curve = &nist256p1; - - memcpy(priv, - "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3" - "\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", - 32); - ecdsa_get_public_key33(curve, priv, pub); - ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL); - - for (int i = 0; i < iterations; i++) { - ecdsa_verify(curve, HASHER_SHA2, pub, sig, msg, sizeof(msg)); - } -} - -void bench_verify_nist256p1_65(int iterations) { - uint8_t sig[64], pub[65], priv[32], pby; - - const ecdsa_curve *curve = &nist256p1; - - memcpy(priv, - "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3" - "\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", - 32); - ecdsa_get_public_key65(curve, priv, pub); - ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL); - - for (int i = 0; i < iterations; i++) { - ecdsa_verify(curve, HASHER_SHA2, pub, sig, msg, sizeof(msg)); - } -} - -void bench_verify_ed25519(int iterations) { - ed25519_public_key pk; - ed25519_secret_key sk; - ed25519_signature sig; - - memcpy(pk, - "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3" - "\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", - 32); - ed25519_publickey(sk, pk); - ed25519_sign(msg, sizeof(msg), sk, sig); - - for (int i = 0; i < iterations; i++) { - ed25519_sign_open(msg, sizeof(msg), pk, sig); - } -} - -void bench_multiply_curve25519(int iterations) { - uint8_t result[32]; - uint8_t secret[32]; - uint8_t basepoint[32]; - - memcpy(secret, - "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3" - "\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", - 32); - memcpy(basepoint, - "\x96\x47\xda\xbe\x1e\xea\xaf\x25\x47\x1e\x68\x0b\x4d\x7c\x6f\xd1\x14" - "\x38\x76\xbb\x77\x59\xd8\x3d\x0f\xf7\xa2\x49\x08\xfd\xda\xbc", - 32); - - for (int i = 0; i < iterations; i++) { - curve25519_scalarmult(result, secret, basepoint); - } -} - -static HDNode root; - -void prepare_node(void) { - hdnode_from_seed((uint8_t *)"NothingToSeeHere", 16, SECP256K1_NAME, &root); - hdnode_fill_public_key(&root); -} - -void bench_ckd_normal(int iterations) { - char addr[MAX_ADDR_SIZE]; - HDNode node; - for (int i = 0; i < iterations; i++) { - memcpy(&node, &root, sizeof(HDNode)); - hdnode_public_ckd(&node, i); - hdnode_fill_public_key(&node); - ecdsa_get_address(node.public_key, HASHER_SHA2, HASHER_SHA2D, 0, addr, - sizeof(addr)); - } -} - -void bench_ckd_optimized(int iterations) { - char addr[MAX_ADDR_SIZE]; - curve_point pub; - ecdsa_read_pubkey(&secp256k1, root.public_key, &pub); - for (int i = 0; i < iterations; i++) { - hdnode_public_ckd_address_optimized(&pub, root.chain_code, i, 0, - HASHER_SHA2, HASHER_SHA2D, addr, - sizeof(addr), false); - } -} - -void bench(void (*func)(int), const char *name, int iterations) { - clock_t t = clock(); - func(iterations); - float speed = iterations / ((float)(clock() - t) / CLOCKS_PER_SEC); - printf("%25s: %8.2f ops/s\n", name, speed); -} - -#define BENCH(FUNC, ITER) bench(FUNC, #FUNC, ITER) - -int main(void) { - prepare_msg(); - - BENCH(bench_sign_secp256k1, 500); - BENCH(bench_verify_secp256k1_33, 500); - BENCH(bench_verify_secp256k1_65, 500); - - BENCH(bench_sign_nist256p1, 500); - BENCH(bench_verify_nist256p1_33, 500); - BENCH(bench_verify_nist256p1_65, 500); - - BENCH(bench_sign_ed25519, 4000); - BENCH(bench_verify_ed25519, 4000); - - BENCH(bench_multiply_curve25519, 4000); - - prepare_node(); - - BENCH(bench_ckd_normal, 1000); - BENCH(bench_ckd_optimized, 1000); - - return 0; -} diff --git a/deps/crypto/trezor-crypto/tests/test_wycheproof.py b/deps/crypto/trezor-crypto/tests/test_wycheproof.py deleted file mode 100755 index c449b29c8..000000000 --- a/deps/crypto/trezor-crypto/tests/test_wycheproof.py +++ /dev/null @@ -1,721 +0,0 @@ -#!/usr/bin/env python -import ctypes -import json -import os -from binascii import hexlify, unhexlify - -import pytest -from pyasn1.codec.ber.decoder import decode as ber_decode -from pyasn1.codec.der.decoder import decode as der_decode -from pyasn1.codec.der.encoder import encode as der_encode -from pyasn1.type import namedtype, univ - - -class EcSignature(univ.Sequence): - componentType = namedtype.NamedTypes( - namedtype.NamedType("r", univ.Integer()), - namedtype.NamedType("s", univ.Integer()), - ) - - -class EcKeyInfo(univ.Sequence): - componentType = namedtype.NamedTypes( - namedtype.NamedType("key_type", univ.ObjectIdentifier()), - namedtype.NamedType("curve_name", univ.ObjectIdentifier()), - ) - - -class EcPublicKey(univ.Sequence): - componentType = namedtype.NamedTypes( - namedtype.NamedType("key_info", EcKeyInfo()), - namedtype.NamedType("public_key", univ.BitString()), - ) - - -class EdKeyInfo(univ.Sequence): - componentType = namedtype.NamedTypes( - namedtype.NamedType("key_type", univ.ObjectIdentifier()) - ) - - -class EdPublicKey(univ.Sequence): - componentType = namedtype.NamedTypes( - namedtype.NamedType("key_info", EdKeyInfo()), - namedtype.NamedType("public_key", univ.BitString()), - ) - - -class ParseError(Exception): - pass - - -class NotSupported(Exception): - pass - - -class DataError(Exception): - pass - - -class curve_info(ctypes.Structure): - _fields_ = [("bip32_name", ctypes.c_char_p), ("params", ctypes.c_void_p)] - - -def keys_in_dict(dictionary, keys): - return keys <= set(dictionary.keys()) - - -def parse_eddsa_signature(signature): - if len(signature) != 64: - raise ParseError("Not a valid EdDSA signature") - return signature - - -def parse_ecdh256_privkey(private_key): - if private_key < 0 or private_key.bit_length() > 256: - raise ParseError("Not a valid 256 bit ECDH private key") - return private_key.to_bytes(32, byteorder="big") - - -def parse_signed_hex(string): - if len(string) % 2 == 1: - string = "0" + string - number = int(string, 16) - if int(string[0], 16) & 8: - return -number - else: - return number - - -def parse_result(result): - if result == "valid": - return True - elif result == "invalid": - return False - elif result == "acceptable": - return None - else: - raise DataError() - - -def is_valid_der(data): - try: - structure, _ = der_decode(data) - return data == der_encode(structure) - except Exception: - return False - - -def parse_ed_pubkey(public_key): - try: - public_key, _ = ber_decode(public_key, asn1Spec=EdPublicKey()) - except Exception: - raise ParseError("Not a BER encoded Edwards curve public key") - - if not public_key["key_info"]["key_type"] == univ.ObjectIdentifier("1.3.101.112"): - raise ParseError("Not a BER encoded Edwards curve public key") - - public_key = bytes(public_key["public_key"].asOctets()) - - return public_key - - -def parse_ec_pubkey(public_key): - try: - public_key, _ = ber_decode(public_key, asn1Spec=EcPublicKey()) - except Exception: - raise ParseError("Not a BER encoded named elliptic curve public key") - - if not public_key["key_info"]["key_type"] == univ.ObjectIdentifier( - "1.2.840.10045.2.1" - ): - raise ParseError("Not a BER encoded named elliptic curve public key") - curve_identifier = public_key["key_info"]["curve_name"] - curve_name = get_curve_name_by_identifier(curve_identifier) - - if curve_name is None: - raise NotSupported( - "Unsupported named elliptic curve: {}".format(curve_identifier) - ) - - try: - public_key = bytes(public_key["public_key"].asOctets()) - except Exception: - raise ParseError("Not a BER encoded named elliptic curve public key") - - return curve_name, public_key - - -def parse_ecdsa256_signature(signature): - s = signature - if not is_valid_der(signature): - raise ParseError("Not a valid DER") - try: - signature, _ = der_decode(signature, asn1Spec=EcSignature()) - except Exception: - raise ParseError("Not a valid DER encoded ECDSA signature") - try: - r = int(signature["r"]).to_bytes(32, byteorder="big") - s = int(signature["s"]).to_bytes(32, byteorder="big") - signature = r + s - except Exception: - raise ParseError("Not a valid DER encoded 256 bit ECDSA signature") - return signature - - -def parse_digest(name): - if name == "SHA-256": - return 0 - else: - raise NotSupported("Unsupported hash function: {}".format(name)) - - -def get_curve_by_name(name): - lib.get_curve_by_name.restype = ctypes.c_void_p - curve = lib.get_curve_by_name(bytes(name, "ascii")) - if curve is None: - return None - curve = ctypes.cast(curve, ctypes.POINTER(curve_info)) - return ctypes.c_void_p(curve.contents.params) - - -def parse_curve_name(name): - if name == "secp256r1": - return "nist256p1" - elif name == "secp256k1": - return "secp256k1" - elif name == "curve25519": - return "curve25519" - else: - return None - - -def get_curve_name_by_identifier(identifier): - if identifier == univ.ObjectIdentifier("1.3.132.0.10"): - return "secp256k1" - elif identifier == univ.ObjectIdentifier("1.2.840.10045.3.1.7"): - return "nist256p1" - else: - return None - - -def chacha_poly_encrypt(key, iv, associated_data, plaintext): - context = bytes(context_structure_length) - tag = bytes(16) - ciphertext = bytes(len(plaintext)) - lib.rfc7539_init(context, key, iv) - lib.rfc7539_auth(context, associated_data, len(associated_data)) - lib.chacha20poly1305_encrypt(context, plaintext, ciphertext, len(plaintext)) - lib.rfc7539_finish(context, len(associated_data), len(plaintext), tag) - return ciphertext, tag - - -def chacha_poly_decrypt(key, iv, associated_data, ciphertext, tag): - context = bytes(context_structure_length) - computed_tag = bytes(16) - plaintext = bytes(len(ciphertext)) - lib.rfc7539_init(context, key, iv) - lib.rfc7539_auth(context, associated_data, len(associated_data)) - lib.chacha20poly1305_decrypt(context, ciphertext, plaintext, len(ciphertext)) - lib.rfc7539_finish(context, len(associated_data), len(ciphertext), computed_tag) - return plaintext if tag == computed_tag else False - - -def add_pkcs_padding(data): - padding_length = 16 - len(data) % 16 - return data + bytes([padding_length] * padding_length) - - -def remove_pkcs_padding(data): - padding_length = data[-1] - if not ( - 0 < padding_length <= 16 - and data[-padding_length:] == bytes([padding_length] * padding_length) - ): - return False - else: - return data[:-padding_length] - - -def aes_encrypt_initialise(key, context): - if len(key) == (128 / 8): - lib.aes_encrypt_key128(key, context) - elif len(key) == (192 / 8): - lib.aes_encrypt_key192(key, context) - elif len(key) == (256 / 8): - lib.aes_encrypt_key256(key, context) - else: - raise NotSupported("Unsupported key length: {}".format(len(key) * 8)) - - -def aes_cbc_encrypt(key, iv, plaintext): - plaintext = add_pkcs_padding(plaintext) - context = bytes(context_structure_length) - ciphertext = bytes(len(plaintext)) - aes_encrypt_initialise(key, context) - lib.aes_cbc_encrypt( - plaintext, ciphertext, len(plaintext), bytes(bytearray(iv)), context - ) - return ciphertext - - -def aes_decrypt_initialise(key, context): - if len(key) == (128 / 8): - lib.aes_decrypt_key128(key, context) - elif len(key) == (192 / 8): - lib.aes_decrypt_key192(key, context) - elif len(key) == (256 / 8): - lib.aes_decrypt_key256(key, context) - else: - raise NotSupported("Unsupported AES key length: {}".format(len(key) * 8)) - - -def aes_cbc_decrypt(key, iv, ciphertext): - context = bytes(context_structure_length) - plaintext = bytes(len(ciphertext)) - aes_decrypt_initialise(key, context) - lib.aes_cbc_decrypt(ciphertext, plaintext, len(ciphertext), iv, context) - return remove_pkcs_padding(plaintext) - - -def load_json_testvectors(filename): - try: - result = json.loads(open(os.path.join(testvectors_directory, filename)).read()) - except Exception: - raise DataError() - return result - - -def generate_aes(filename): - vectors = [] - - data = load_json_testvectors(filename) - - if not keys_in_dict(data, {"algorithm", "testGroups"}): - raise DataError() - - if data["algorithm"] != "AES-CBC-PKCS5": - raise DataError() - - for test_group in data["testGroups"]: - if not keys_in_dict(test_group, {"tests"}): - raise DataError() - - for test in test_group["tests"]: - if not keys_in_dict(test, {"key", "iv", "msg", "ct", "result"}): - raise DataError() - try: - key = unhexlify(test["key"]) - iv = unhexlify(test["iv"]) - plaintext = unhexlify(test["msg"]) - ciphertext = unhexlify(test["ct"]) - result = parse_result(test["result"]) - except Exception: - raise DataError() - - if len(key) not in [128 / 8, 192 / 8, 256 / 8]: - continue - - if result is None: - continue - - vectors.append( - ( - hexlify(key), - hexlify(iv), - hexlify(plaintext), - hexlify(ciphertext), - result, - ) - ) - return vectors - - -def generate_chacha_poly(filename): - vectors = [] - - data = load_json_testvectors(filename) - - if not keys_in_dict(data, {"algorithm", "testGroups"}): - raise DataError() - - if data["algorithm"] != "CHACHA20-POLY1305": - raise DataError() - - for test_group in data["testGroups"]: - if not keys_in_dict(test_group, {"tests"}): - raise DataError() - - for test in test_group["tests"]: - if not keys_in_dict( - test, {"key", "iv", "aad", "msg", "ct", "tag", "result"} - ): - raise DataError() - try: - key = unhexlify(test["key"]) - iv = unhexlify(test["iv"]) - associated_data = unhexlify(test["aad"]) - plaintext = unhexlify(test["msg"]) - ciphertext = unhexlify(test["ct"]) - tag = unhexlify(test["tag"]) - result = parse_result(test["result"]) - except Exception: - raise DataError() - - if result is None: - continue - - vectors.append( - ( - hexlify(key), - hexlify(iv), - hexlify(associated_data), - hexlify(plaintext), - hexlify(ciphertext), - hexlify(tag), - result, - ) - ) - return vectors - - -def generate_curve25519_dh(filename): - vectors = [] - - data = load_json_testvectors(filename) - - if not keys_in_dict(data, {"algorithm", "testGroups"}): - raise DataError() - - if data["algorithm"] != "X25519": - raise DataError() - - for test_group in data["testGroups"]: - if not keys_in_dict(test_group, {"tests"}): - raise DataError() - - for test in test_group["tests"]: - if not keys_in_dict( - test, {"public", "private", "shared", "result", "curve"} - ): - raise DataError() - - try: - public_key = unhexlify(test["public"]) - curve_name = parse_curve_name(test["curve"]) - private_key = unhexlify(test["private"]) - shared = unhexlify(test["shared"]) - result = parse_result(test["result"]) - except Exception: - raise DataError() - - if curve_name != "curve25519": - continue - if result is None: - continue - - vectors.append( - (hexlify(public_key), hexlify(private_key), hexlify(shared), result) - ) - - return vectors - - -def generate_ecdh(filename): - vectors = [] - - data = load_json_testvectors(filename) - - if not keys_in_dict(data, {"algorithm", "testGroups"}): - raise DataError() - - if data["algorithm"] != "ECDH": - raise DataError() - - for test_group in data["testGroups"]: - if not keys_in_dict(test_group, {"tests"}): - raise DataError() - - for test in test_group["tests"]: - if not keys_in_dict( - test, {"public", "private", "shared", "result", "curve"} - ): - raise DataError() - - try: - public_key = unhexlify(test["public"]) - curve_name = parse_curve_name(test["curve"]) - private_key = parse_signed_hex(test["private"]) - shared = unhexlify(test["shared"]) - result = parse_result(test["result"]) - except Exception: - raise DataError() - - try: - private_key = parse_ecdh256_privkey(private_key) - except ParseError: - continue - - try: - key_curve_name, public_key = parse_ec_pubkey(public_key) - except NotSupported: - continue - except ParseError: - continue - - if key_curve_name != curve_name: - continue - if result is None: - continue - - vectors.append( - ( - curve_name, - hexlify(public_key), - hexlify(private_key), - hexlify(shared), - result, - ) - ) - - return vectors - - -def generate_ecdsa(filename): - vectors = [] - - data = load_json_testvectors(filename) - - if not keys_in_dict(data, {"algorithm", "testGroups"}): - raise DataError() - - if data["algorithm"] != "ECDSA": - raise DataError() - - for test_group in data["testGroups"]: - if not keys_in_dict(test_group, {"tests", "keyDer", "sha"}): - raise DataError() - - try: - public_key = unhexlify(test_group["keyDer"]) - except Exception: - raise DataError() - - try: - curve_name, public_key = parse_ec_pubkey(public_key) - except NotSupported: - continue - except ParseError: - continue - - try: - hasher = parse_digest(test_group["sha"]) - except NotSupported: - continue - - for test in test_group["tests"]: - if not keys_in_dict(test, {"sig", "msg", "result"}): - raise DataError() - - try: - signature = unhexlify(test["sig"]) - message = unhexlify(test["msg"]) - result = parse_result(test["result"]) - except Exception: - raise DataError() - - if result is None: - continue - - try: - signature = parse_ecdsa256_signature(signature) - except ParseError: - continue - - vectors.append( - ( - curve_name, - hexlify(public_key), - hasher, - hexlify(message), - hexlify(signature), - result, - ) - ) - - return vectors - - -def generate_eddsa(filename): - vectors = [] - - data = load_json_testvectors(filename) - - if not keys_in_dict(data, {"algorithm", "testGroups"}): - raise DataError() - - if data["algorithm"] != "EDDSA": - raise DataError() - - for test_group in data["testGroups"]: - if not keys_in_dict(test_group, {"tests", "keyDer"}): - raise DataError() - - try: - public_key = unhexlify(test_group["keyDer"]) - except Exception: - raise DataError() - - try: - public_key = parse_ed_pubkey(public_key) - except ParseError: - continue - - for test in test_group["tests"]: - if not keys_in_dict(test, {"sig", "msg", "result"}): - raise DataError() - - try: - signature = unhexlify(test["sig"]) - message = unhexlify(test["msg"]) - result = parse_result(test["result"]) - except Exception: - raise DataError() - - if result is None: - continue - - try: - signature = parse_eddsa_signature(signature) - except ParseError: - continue - - vectors.append( - (hexlify(public_key), hexlify(message), hexlify(signature), result) - ) - - return vectors - - -dir = os.path.abspath(os.path.dirname(__file__)) -lib = ctypes.cdll.LoadLibrary(os.path.join(dir, "libtrezor-crypto.so")) -testvectors_directory = os.path.join(dir, "wycheproof/testvectors") -context_structure_length = 1024 - -ecdh_vectors = generate_ecdh("ecdh_test.json") -curve25519_dh_vectors = generate_curve25519_dh("x25519_test.json") -eddsa_vectors = generate_eddsa("eddsa_test.json") -ecdsa_vectors = ( - generate_ecdsa("ecdsa_test.json") - + generate_ecdsa("ecdsa_secp256k1_sha256_test.json") - + generate_ecdsa("ecdsa_secp256r1_sha256_test.json") -) -ecdh_vectors = ( - generate_ecdh("ecdh_test.json") - + generate_ecdh("ecdh_secp256k1_test.json") - + generate_ecdh("ecdh_secp256r1_test.json") -) -chacha_poly_vectors = generate_chacha_poly("chacha20_poly1305_test.json") -aes_vectors = generate_aes("aes_cbc_pkcs5_test.json") - - -@pytest.mark.parametrize("public_key, message, signature, result", eddsa_vectors) -def test_eddsa(public_key, message, signature, result): - public_key = unhexlify(public_key) - signature = unhexlify(signature) - message = unhexlify(message) - - computed_result = ( - lib.ed25519_sign_open(message, len(message), public_key, signature) == 0 - ) - assert result == computed_result - - -@pytest.mark.parametrize( - "curve_name, public_key, hasher, message, signature, result", ecdsa_vectors -) -def test_ecdsa(curve_name, public_key, hasher, message, signature, result): - curve = get_curve_by_name(curve_name) - if curve is None: - raise NotSupported("Curve not supported: {}".format(curve_name)) - - public_key = unhexlify(public_key) - signature = unhexlify(signature) - message = unhexlify(message) - - computed_result = ( - lib.ecdsa_verify(curve, hasher, public_key, signature, message, len(message)) - == 0 - ) - assert result == computed_result - - -@pytest.mark.parametrize( - "public_key, private_key, shared, result", curve25519_dh_vectors -) -def test_curve25519_dh(public_key, private_key, shared, result): - public_key = unhexlify(public_key) - private_key = unhexlify(private_key) - shared = unhexlify(shared) - - computed_shared = bytes([0] * 32) - lib.curve25519_scalarmult(computed_shared, private_key, public_key) - computed_result = shared == computed_shared - assert result == computed_result - - -@pytest.mark.parametrize( - "curve_name, public_key, private_key, shared, result", ecdh_vectors -) -def test_ecdh(curve_name, public_key, private_key, shared, result): - curve = get_curve_by_name(curve_name) - if curve is None: - raise NotSupported("Curve not supported: {}".format(curve_name)) - - public_key = unhexlify(public_key) - private_key = unhexlify(private_key) - shared = unhexlify(shared) - - computed_shared = bytes([0] * 2 * 32) - lib.ecdh_multiply(curve, private_key, public_key, computed_shared) - computed_shared = computed_shared[1:33] - computed_result = shared == computed_shared - assert result == computed_result - - -@pytest.mark.parametrize( - "key, iv, associated_data, plaintext, ciphertext, tag, result", chacha_poly_vectors -) -def test_chacha_poly(key, iv, associated_data, plaintext, ciphertext, tag, result): - key = unhexlify(key) - iv = unhexlify(iv) - associated_data = unhexlify(associated_data) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - tag = unhexlify(tag) - - computed_ciphertext, computed_tag = chacha_poly_encrypt( - key, iv, associated_data, plaintext - ) - computed_result = ciphertext == computed_ciphertext and tag == computed_tag - assert result == computed_result - - computed_plaintext = chacha_poly_decrypt(key, iv, associated_data, ciphertext, tag) - computed_result = plaintext == computed_plaintext - assert result == computed_result - - -@pytest.mark.parametrize("key, iv, plaintext, ciphertext, result", aes_vectors) -def test_aes(key, iv, plaintext, ciphertext, result): - key = unhexlify(key) - iv = unhexlify(iv) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - computed_ciphertext = aes_cbc_encrypt(key, iv, plaintext) - computed_result = ciphertext == computed_ciphertext - assert result == computed_result - - computed_plaintext = aes_cbc_decrypt(key, bytes(iv), ciphertext) - computed_result = plaintext == computed_plaintext - assert result == computed_result diff --git a/deps/crypto/trezor-crypto/tools/.gitignore b/deps/crypto/trezor-crypto/tools/.gitignore deleted file mode 100644 index da1bc3702..000000000 --- a/deps/crypto/trezor-crypto/tools/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -xpubaddrgen -mktable -bip39bruteforce diff --git a/deps/crypto/trezor-crypto/tools/README.md b/deps/crypto/trezor-crypto/tools/README.md deleted file mode 100644 index 7786244de..000000000 --- a/deps/crypto/trezor-crypto/tools/README.md +++ /dev/null @@ -1,54 +0,0 @@ -trezor-crypto tools -=================== - -Set of small utilities using the trezor-crypto library. - -xpubaddrgen ------------ - -xpubaddrgen reads job specification from stdin in format: - -``` - -``` - -and prints the results to stdout in format: - -``` -
-``` - -Example input: - -``` -23 xpub6BcjTvRCYD4VvFQ8whztSXhbNyhS56eTd5P3g9Zvd3zPEeUeL5CUqBYX8NSd1b6Thitr8bZcSnesmXZH7KerMcc4tUkenBShYCtQ1L8ebVe 0 0 5 -42 xpub6AT2YrLinU4Be5UWUxMaUz3zTA99CSGvXt1jt2Lgym8PqXbTzmpQ8MHjoLnx8YJiMMUP5iEfR97YQVmgF6B2tAhbCZrXqn65ur526NkZ6ey 1 1000 1005 -``` - -Example output: - -``` -23 0 14vb5Cws75p2i5rmSiF5CKMyezUX4hxSb9 -23 1 1Lf4ciA36dsi1niF6smVcpCiHcpj2skaPq -23 2 1LraByp7gQAipvHnFS1gTSzixBtYaVyQGp -23 3 1Hy6n56qZj1EefLVfDAeEpmveNteY9jpiG -23 4 183Nn4mrUjPizM3xu8C6SrmViaWrk8YyRS -42 1000 12eAFGAqGUtszc9R7euRqk7DUcQNXvQZSg -42 1001 1BrLbFCD3MNYedJaz92U9iqy9ukHrtQ1A6 -42 1002 1Jhv33bJy229ThM7HKxUa92cMK5gi7DyPC -42 1003 13LxbTjQPByisj4F4sZEivUBdnJwigzg6R -42 1004 1BWBpSWkPwcKxVr2WDyUqQbmvk5SGihcx9 -``` - -It will print ``` error``` when there was an error processing job jobid. - -It will print ```error``` when it encountered a malformed line. - - -mktable ------------ - -mktable computes the points of the form `(2*j+1)*16^i*G` and prints them in the format to be included in `secp256k1.c` and `nist256p1.c`. -These points are used by the fast ECC multiplication. - -It is only meant to be run if the `scalar_mult` algorithm changes. diff --git a/deps/crypto/trezor-crypto/tools/bip39bruteforce.c b/deps/crypto/trezor-crypto/tools/bip39bruteforce.c deleted file mode 100644 index d15132b14..000000000 --- a/deps/crypto/trezor-crypto/tools/bip39bruteforce.c +++ /dev/null @@ -1,100 +0,0 @@ -#include -#include -#include -#include "bip32.h" -#include "bip39.h" -#include "curves.h" -#include "ecdsa.h" -#include "secp256k1.h" - -char iter[256]; -uint8_t seed[512 / 8]; -char addr[MAX_ADDR_SIZE]; -int count = 0, found = 0; -HDNode node; -clock_t start; - -#define ACCOUNT_LEGACY 0 - -// around 280 tries per second - -// testing data: -// -// mnemonic: "all all all all all all all all all all all all" -// address: legacy: "1JAd7XCBzGudGpJQSDSfpmJhiygtLQWaGL" -// segwit: "3L6TyTisPBmrDAj6RoKmDzNnj4eQi54gD2" -// passphrase: "" -// -// mnemonic: "all all all all all all all all all all all all" -// address: legacy: "1N3uJ5AU3FTYQ1ZQgTMtYmgSvMBmQiGVBS" -// segwit: "3NcXPfbDP4UHSbuHASALJEBtDeAcWYMMcS" -// passphrase: "testing" - -int main(int argc, char **argv) { - if (argc != 2 && argc != 3) { - fprintf(stderr, "Usage: bip39bruteforce address [mnemonic]\n"); - return 1; - } - const char *address = argv[1]; - const char *mnemonic, *item; - if (argc == 3) { - mnemonic = argv[2]; - item = "passphrase"; - } else { - mnemonic = NULL; - item = "mnemonic"; - } - if (mnemonic && !mnemonic_check(mnemonic)) { - fprintf(stderr, "\"%s\" is not a valid mnemonic\n", mnemonic); - return 2; - } - printf("Reading %ss from stdin ...\n", item); - start = clock(); - for (;;) { - if (fgets(iter, 256, stdin) == NULL) break; - int len = strlen(iter); - if (len <= 0) { - continue; - } - count++; - iter[len - 1] = 0; - if (mnemonic) { - mnemonic_to_seed(mnemonic, iter, seed, NULL); - } else { - mnemonic_to_seed(iter, "", seed, NULL); - } - hdnode_from_seed(seed, 512 / 8, SECP256K1_NAME, &node); -#if ACCOUNT_LEGACY - hdnode_private_ckd_prime(&node, 44); -#else - hdnode_private_ckd_prime(&node, 49); -#endif - hdnode_private_ckd_prime(&node, 0); - hdnode_private_ckd_prime(&node, 0); - hdnode_private_ckd(&node, 0); - hdnode_private_ckd(&node, 0); - hdnode_fill_public_key(&node); -#if ACCOUNT_LEGACY - // Legacy address - ecdsa_get_address(node.public_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, - addr, sizeof(addr)); -#else - // Segwit-in-P2SH - ecdsa_get_address_segwit_p2sh(node.public_key, 5, HASHER_SHA2_RIPEMD, - HASHER_SHA2D, addr, sizeof(addr)); -#endif - if (strcmp(address, addr) == 0) { - found = 1; - break; - } - } - float dur = (float)(clock() - start) / CLOCKS_PER_SEC; - printf("Tried %d %ss in %f seconds = %f tries/second\n", count, item, dur, - (float)count / dur); - if (found) { - printf("Correct %s found! :-)\n\"%s\"\n", item, iter); - return 0; - } - printf("Correct %s not found. :-(\n", item); - return 4; -} diff --git a/deps/crypto/trezor-crypto/tools/mktable.c b/deps/crypto/trezor-crypto/tools/mktable.c deleted file mode 100644 index 2760d7495..000000000 --- a/deps/crypto/trezor-crypto/tools/mktable.c +++ /dev/null @@ -1,69 +0,0 @@ -#include -#include -#include "bignum.h" -#include "bip32.h" -#include "ecdsa.h" -#include "rand.h" - -/* - * This program prints the contents of the ecdsa_curve.cp array. - * The entry cp[i][j] contains the number (2*j+1)*16^i*G, - * where G is the generator of the specified elliptic curve. - */ -int main(int argc, char **argv) { - int i, j, k; - if (argc != 2) { - printf("Usage: %s CURVE_NAME\n", argv[0]); - return 1; - } - const char *name = argv[1]; - const curve_info *info = get_curve_by_name(name); - const ecdsa_curve *curve = info->params; - if (curve == 0) { - printf("Unknown curve '%s'\n", name); - return 1; - } - - curve_point ng = curve->G; - curve_point pow2ig = curve->G; - for (i = 0; i < 64; i++) { - // invariants: - // pow2ig = 16^i * G - // ng = pow2ig - printf("\t{\n"); - for (j = 0; j < 8; j++) { - // invariants: - // pow2ig = 16^i * G - // ng = (2*j+1) * 16^i * G -#ifndef NDEBUG - curve_point checkresult; - bignum256 a; - bn_zero(&a); - a.val[(4 * i) / BN_BITS_PER_LIMB] = ((uint32_t)2 * j + 1) - << ((4 * i) % BN_BITS_PER_LIMB); - bn_normalize(&a); - point_multiply(curve, &a, &curve->G, &checkresult); - assert(point_is_equal(&checkresult, &ng)); -#endif - printf("\t\t/* %2d*16^%d*G: */\n\t\t{{{", 2 * j + 1, i); - // print x coordinate - for (k = 0; k < 9; k++) { - printf((k < 8 ? "0x%08x, " : "0x%04x"), ng.x.val[k]); - } - printf("}},\n\t\t {{"); - // print y coordinate - for (k = 0; k < 9; k++) { - printf((k < 8 ? "0x%08x, " : "0x%04x"), ng.y.val[k]); - } - if (j == 7) { - printf("}}}\n\t},\n"); - } else { - printf("}}},\n"); - point_add(curve, &pow2ig, &ng); - } - point_add(curve, &pow2ig, &ng); - } - pow2ig = ng; - } - return 0; -} diff --git a/deps/crypto/trezor-crypto/tools/nem_test_vectors.erb b/deps/crypto/trezor-crypto/tools/nem_test_vectors.erb deleted file mode 100644 index 0e7ed946e..000000000 --- a/deps/crypto/trezor-crypto/tools/nem_test_vectors.erb +++ /dev/null @@ -1,18 +0,0 @@ -// test vectors from <%= source_url %> -START_TEST(<%= test_name %>) -{ - static const struct { -<% fields.each do |(name, type)| -%> - <%= if type.nil? then 'const char *' else "#{type} " end %><%= name %>; -<% end -%> - } tests[] = { -<% data.each do |values| -%> - { <% values.each do |value| %><%= value %>, <% end %>}, -<% end -%> - }; - - for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - // TODO: Implement test - } -} -END_TEST diff --git a/deps/crypto/trezor-crypto/tools/nem_test_vectors.rb b/deps/crypto/trezor-crypto/tools/nem_test_vectors.rb deleted file mode 100755 index 9bb487927..000000000 --- a/deps/crypto/trezor-crypto/tools/nem_test_vectors.rb +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/env ruby -require 'highline' -require 'open-uri' - -TEMPLATE_NAME = (Pathname.new(__FILE__).sub_ext '.erb').to_s.freeze - -@terminal = HighLine.new($stdin, $stderr) - -def github_files - require 'octokit' - - @github_files ||= Octokit.contents('NemProject/nem-test-vectors') - .select do |file| - file.name.end_with? '.dat' - end -end - -def choose_data_file - @terminal.choose do |menu| - github_files.each do |file| - menu.choice(file.name) { file.download_url } - end - - menu.prompt = 'Which file? ' - - menu.index = :none - menu.select_by = :name - end -end - -def load_header(line) - line = line.dup - abort 'Header is not a comment' unless line.slice!(0) == '#' - - header = line.split(':').each(&:strip!) - header.shift if header.first.empty? - - header -end - -def parse_field_answer(answer) - if answer.empty? - nil - elsif /^(?:(?\w+) )?(?\w+)$/ =~ answer - [identifier, type] - else - raise NotValidQuestionError - end -end - -def ask_fields(header) - header.map do |name| - @terminal.ask "Field for `#{name}'? " do |question| - question.answer_type = lambda(&method(:parse_field_answer)) - end - end -end - -def load_data_line(line) - abort 'Line does not begin with colon' unless line.slice!(0) == ':' - - line.strip! - line.chomp!(',') - - values = line.split(':').each(&:strip!) - values.pop if values.last.empty? - - values -end - -def load_data(file, count) - file.each_line.lazy.reject { |line| line.start_with? '#' } - .take(count) - .map(&method(:load_data_line)) - .to_a -end - -def remove_skipped_fields(fields, data) - data.each do |values| - abort 'Line does not match header' unless values.size == fields.size - - values.reject!.each_with_index { |_, index| fields[index].nil? } - end - - fields.compact! -end - -def format_data_fields(fields, data) - data.each do |values| - fields.each_with_index do |(_, type), index| - values[index] = values[index].dump if type.nil? - end - end -end - -def template(source_url, fields, data) - test_name = @terminal.ask('Name for test? ') do |question| - question.validate = /./ - end - - erb = ERB.new(File.read(TEMPLATE_NAME), nil, '-') - erb.filename = TEMPLATE_NAME - - erb.result(binding) -end - -download_url = choose_data_file - -source_code = open download_url do |file| - line = file.readline - - header = load_header(line) - @terminal.say line - - count = @terminal.ask('How many vectors to import? ', Integer) - - fields = ask_fields(header) - data = load_data(file, count) - - remove_skipped_fields(fields, data) - format_data_fields(fields, data) - - template(download_url, fields, data) -end - -puts source_code diff --git a/deps/crypto/trezor-crypto/tools/xpubaddrgen.c b/deps/crypto/trezor-crypto/tools/xpubaddrgen.c deleted file mode 100644 index cce472923..000000000 --- a/deps/crypto/trezor-crypto/tools/xpubaddrgen.c +++ /dev/null @@ -1,48 +0,0 @@ -#include -#include -#include -#include -#include "bip32.h" -#include "curves.h" -#include "ecdsa.h" - -#define VERSION_PUBLIC 0x0488b21e - -void process_job(uint32_t jobid, const char *xpub, uint32_t change, - uint32_t from, uint32_t to) { - HDNode node, child; - if (change > 1 || to <= from || - hdnode_deserialize_public(xpub, VERSION_PUBLIC, SECP256K1_NAME, &node, - NULL) != 0) { - printf("%d error\n", jobid); - return; - } - hdnode_public_ckd(&node, change); - uint32_t i; - char address[36]; - for (i = from; i < to; i++) { - memcpy(&child, &node, sizeof(HDNode)); - hdnode_public_ckd(&child, i); - ecdsa_get_address(child.public_key, 0, HASHER_SHA2, HASHER_SHA2D, address, - sizeof(address)); - printf("%d %d %s\n", jobid, i, address); - } -} - -int main(void) { - char line[1024], xpub[1024]; - uint32_t jobid, change, from, to; - int r; - for (;;) { - if (!fgets(line, sizeof(line), stdin)) break; - r = sscanf(line, "%u %s %u %u %u\n", &jobid, xpub, &change, &from, &to); - if (r < 1) { - printf("error\n"); - } else if (r != 5) { - printf("%d error\n", jobid); - } else { - process_job(jobid, xpub, change, from, to); - } - } - return 0; -} diff --git a/deps/crypto/trezor-crypto/zcash_zip316.c b/deps/crypto/trezor-crypto/zcash_zip316.c deleted file mode 100644 index c5a6e33b4..000000000 --- a/deps/crypto/trezor-crypto/zcash_zip316.c +++ /dev/null @@ -1,271 +0,0 @@ -/** - * Copyright (c) 2026 KeepKey - * - * Minimal ZIP-316 helpers needed for Orchard-only unified addresses. - */ - -#include "zcash_zip316.h" - -#include -#include - -#include "blake2b.h" -#include "memzero.h" - -#define ZCASH_ZIP316_BLAKE2B_OUT_LEN 64 - -static const char BECH32_CHARSET[] = - "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; - -static size_t min_size(size_t a, size_t b) { return a < b ? a : b; } - -static size_t ceil_div(size_t num, size_t den) { - return (num + den - 1) / den; -} - -static int valid_f4jumble_len(size_t len) { - return len >= ZCASH_ZIP316_F4JUMBLE_MIN_LEN && - len <= ZCASH_ZIP316_F4JUMBLE_MAX_LEN; -} - -static void xor_bytes(uint8_t *target, size_t target_len, const uint8_t *source, - size_t source_len) { - size_t len = min_size(target_len, source_len); - for (size_t i = 0; i < len; i++) { - target[i] ^= source[i]; - } -} - -static int h_round(uint8_t *left, size_t left_len, const uint8_t *right, - size_t right_len, uint8_t round) { - uint8_t personal[BLAKE2B_PERSONALBYTES] = { - 'U', 'A', '_', 'F', '4', 'J', 'u', 'm', - 'b', 'l', 'e', '_', 'H', round, 0, 0, - }; - uint8_t hash[ZCASH_ZIP316_BLAKE2B_OUT_LEN]; - BLAKE2B_CTX ctx; - - if (blake2b_InitPersonal(&ctx, left_len, personal, sizeof(personal)) != 0) { - memzero(hash, sizeof(hash)); - memzero(&ctx, sizeof(ctx)); - return -1; - } - if (blake2b_Update(&ctx, right, right_len) != 0 || - blake2b_Final(&ctx, hash, left_len) != 0) { - memzero(hash, sizeof(hash)); - memzero(&ctx, sizeof(ctx)); - return -1; - } - xor_bytes(left, left_len, hash, left_len); - - memzero(hash, sizeof(hash)); - memzero(&ctx, sizeof(ctx)); - return 0; -} - -static int g_round(const uint8_t *left, size_t left_len, uint8_t *right, - size_t right_len, uint8_t round) { - uint8_t hash[ZCASH_ZIP316_BLAKE2B_OUT_LEN]; - for (size_t j = 0; j < ceil_div(right_len, ZCASH_ZIP316_BLAKE2B_OUT_LEN); - j++) { - uint8_t personal[BLAKE2B_PERSONALBYTES] = { - 'U', - 'A', - '_', - 'F', - '4', - 'J', - 'u', - 'm', - 'b', - 'l', - 'e', - '_', - 'G', - round, - (uint8_t)(j & 0xff), - (uint8_t)(j >> 8), - }; - BLAKE2B_CTX ctx; - - if (j > 0xffff) { - memzero(hash, sizeof(hash)); - return -1; - } - if (blake2b_InitPersonal(&ctx, sizeof(hash), personal, sizeof(personal)) != - 0) { - memzero(hash, sizeof(hash)); - memzero(&ctx, sizeof(ctx)); - return -1; - } - if (blake2b_Update(&ctx, left, left_len) != 0 || - blake2b_Final(&ctx, hash, sizeof(hash)) != 0) { - memzero(hash, sizeof(hash)); - memzero(&ctx, sizeof(ctx)); - return -1; - } - xor_bytes(right + j * ZCASH_ZIP316_BLAKE2B_OUT_LEN, - right_len - j * ZCASH_ZIP316_BLAKE2B_OUT_LEN, hash, - sizeof(hash)); - memzero(&ctx, sizeof(ctx)); - } - - memzero(hash, sizeof(hash)); - return 0; -} - -static int f4jumble_apply(uint8_t *message, size_t message_len, int inverse) { - if (!message || !valid_f4jumble_len(message_len)) return -1; - - size_t left_len = min_size(ZCASH_ZIP316_BLAKE2B_OUT_LEN, message_len / 2); - uint8_t *left = message; - uint8_t *right = message + left_len; - size_t right_len = message_len - left_len; - - if (inverse) { - return h_round(left, left_len, right, right_len, 1) == 0 && - g_round(left, left_len, right, right_len, 1) == 0 && - h_round(left, left_len, right, right_len, 0) == 0 && - g_round(left, left_len, right, right_len, 0) == 0 - ? 0 - : -1; - } - - return g_round(left, left_len, right, right_len, 0) == 0 && - h_round(left, left_len, right, right_len, 0) == 0 && - g_round(left, left_len, right, right_len, 1) == 0 && - h_round(left, left_len, right, right_len, 1) == 0 - ? 0 - : -1; -} - -int zcash_zip316_f4jumble(uint8_t *message, size_t message_len) { - return f4jumble_apply(message, message_len, 0); -} - -int zcash_zip316_f4jumble_inv(uint8_t *message, size_t message_len) { - return f4jumble_apply(message, message_len, 1); -} - -static uint32_t bech32_polymod_step(uint32_t pre) { - uint8_t b = pre >> 25; - return ((pre & 0x1FFFFFF) << 5) ^ - (-((b >> 0) & 1) & 0x3b6a57b2UL) ^ - (-((b >> 1) & 1) & 0x26508e6dUL) ^ - (-((b >> 2) & 1) & 0x1ea119faUL) ^ - (-((b >> 3) & 1) & 0x3d4233ddUL) ^ - (-((b >> 4) & 1) & 0x2a1462b3UL); -} - -static int convert_bits_8_to_5(uint8_t *out, size_t *out_len, - size_t out_capacity, const uint8_t *in, - size_t in_len) { - uint32_t val = 0; - int bits = 0; - *out_len = 0; - - while (in_len--) { - val = (val << 8) | *(in++); - bits += 8; - while (bits >= 5) { - bits -= 5; - if (*out_len >= out_capacity) return -1; - out[(*out_len)++] = (val >> bits) & 0x1f; - } - } - if (bits) { - if (*out_len >= out_capacity) return -1; - out[(*out_len)++] = (val << (5 - bits)) & 0x1f; - } - return 0; -} - -static int bech32m_encode_5bit(char *output, size_t output_len, - const char *hrp, const uint8_t *data, - size_t data_len) { - uint32_t chk = 1; - size_t hrp_len = 0; - while (hrp[hrp_len] != 0) { - int ch = hrp[hrp_len]; - if (ch < 33 || ch > 126 || (ch >= 'A' && ch <= 'Z')) { - return -1; - } - chk = bech32_polymod_step(chk) ^ (ch >> 5); - hrp_len++; - } - - if (hrp_len == 0 || output_len < hrp_len + 1 + data_len + 6 + 1) { - return -1; - } - - chk = bech32_polymod_step(chk); - for (size_t i = 0; i < hrp_len; i++) { - chk = bech32_polymod_step(chk) ^ (hrp[i] & 0x1f); - output[i] = hrp[i]; - } - output[hrp_len] = '1'; - - for (size_t i = 0; i < data_len; i++) { - if (data[i] >> 5) return -1; - chk = bech32_polymod_step(chk) ^ data[i]; - output[hrp_len + 1 + i] = BECH32_CHARSET[data[i]]; - } - - for (size_t i = 0; i < 6; i++) { - chk = bech32_polymod_step(chk); - } - chk ^= 0x2bc830a3UL; - - for (size_t i = 0; i < 6; i++) { - output[hrp_len + 1 + data_len + i] = - BECH32_CHARSET[(chk >> ((5 - i) * 5)) & 0x1f]; - } - output[hrp_len + 1 + data_len + 6] = 0; - return 0; -} - -static int bech32m_encode_bytes(char *output, size_t output_len, - const char *hrp, const uint8_t *data, - size_t data_len) { - if (!output || !hrp || (!data && data_len != 0)) return -1; - - size_t data5_capacity = (data_len * 8 + 4) / 5; - uint8_t data5[ZCASH_ZIP316_ORCHARD_ONLY_DATA5_LEN]; - if (data5_capacity > sizeof(data5)) return -1; - - size_t data5_len = 0; - if (convert_bits_8_to_5(data5, &data5_len, sizeof(data5), data, data_len) != - 0) { - memzero(data5, sizeof(data5)); - return -1; - } - - int ret = bech32m_encode_5bit(output, output_len, hrp, data5, data5_len); - memzero(data5, sizeof(data5)); - return ret; -} - -int zcash_zip316_encode_orchard_unified_address( - const char *hrp, - const uint8_t receiver[ZCASH_ZIP316_ORCHARD_RAW_RECEIVER_LEN], - char *output, size_t output_len) { - if (!hrp || !receiver || !output) return -1; - - size_t hrp_len = strlen(hrp); - if (hrp_len == 0 || hrp_len > ZCASH_ZIP316_PADDING_LEN) return -1; - - uint8_t payload[ZCASH_ZIP316_ORCHARD_ONLY_PAYLOAD_LEN] = {0}; - payload[0] = 0x03; /* Orchard receiver typecode. */ - payload[1] = ZCASH_ZIP316_ORCHARD_RAW_RECEIVER_LEN; - memcpy(payload + 2, receiver, ZCASH_ZIP316_ORCHARD_RAW_RECEIVER_LEN); - memcpy(payload + 2 + ZCASH_ZIP316_ORCHARD_RAW_RECEIVER_LEN, hrp, hrp_len); - - int ret = zcash_zip316_f4jumble(payload, sizeof(payload)); - if (ret == 0) { - ret = bech32m_encode_bytes(output, output_len, hrp, payload, - sizeof(payload)); - } - - memzero(payload, sizeof(payload)); - return ret; -} diff --git a/deps/crypto/trezor-crypto/zcash_zip316.h b/deps/crypto/trezor-crypto/zcash_zip316.h deleted file mode 100644 index b48cbd72a..000000000 --- a/deps/crypto/trezor-crypto/zcash_zip316.h +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) 2026 KeepKey - * - * ZIP-316 helpers for Zcash unified address encoding. - */ - -#ifndef __ZCASH_ZIP316_H__ -#define __ZCASH_ZIP316_H__ - -#include -#include - -#define ZCASH_ZIP316_F4JUMBLE_MIN_LEN 48 -#define ZCASH_ZIP316_F4JUMBLE_MAX_LEN 4194368 - -#define ZCASH_ZIP316_ORCHARD_RAW_RECEIVER_LEN 43 -#define ZCASH_ZIP316_PADDING_LEN 16 -#define ZCASH_ZIP316_ORCHARD_ONLY_PAYLOAD_LEN \ - (2 + ZCASH_ZIP316_ORCHARD_RAW_RECEIVER_LEN + ZCASH_ZIP316_PADDING_LEN) -#define ZCASH_ZIP316_ORCHARD_ONLY_DATA5_LEN \ - ((ZCASH_ZIP316_ORCHARD_ONLY_PAYLOAD_LEN * 8 + 4) / 5) -#define ZCASH_ZIP316_ORCHARD_ONLY_MAX_HRP_LEN ZCASH_ZIP316_PADDING_LEN -#define ZCASH_ZIP316_ORCHARD_ONLY_MAX_ADDRESS_LEN \ - (ZCASH_ZIP316_ORCHARD_ONLY_MAX_HRP_LEN + 1 + \ - ZCASH_ZIP316_ORCHARD_ONLY_DATA5_LEN + 6) -#define ZCASH_ZIP316_ORCHARD_ONLY_MAX_ADDRESS_SIZE \ - (ZCASH_ZIP316_ORCHARD_ONLY_MAX_ADDRESS_LEN + 1) - -int zcash_zip316_f4jumble(uint8_t *message, size_t message_len); -int zcash_zip316_f4jumble_inv(uint8_t *message, size_t message_len); - -int zcash_zip316_encode_orchard_unified_address( - const char *hrp, - const uint8_t receiver[ZCASH_ZIP316_ORCHARD_RAW_RECEIVER_LEN], - char *output, size_t output_len); - -#endif diff --git a/deps/crypto/trezor-firmware b/deps/crypto/trezor-firmware new file mode 160000 index 000000000..323e50d19 --- /dev/null +++ b/deps/crypto/trezor-firmware @@ -0,0 +1 @@ +Subproject commit 323e50d19c0eb727dc9de9197fd07842ce93b1f7 diff --git a/fuzzer/firmware/CMakeLists.txt b/fuzzer/firmware/CMakeLists.txt index e38b4f8f5..99591be6a 100644 --- a/fuzzer/firmware/CMakeLists.txt +++ b/fuzzer/firmware/CMakeLists.txt @@ -2,7 +2,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/lib/firmware ${CMAKE_BINARY_DIR}/include - ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-crypto) + ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-firmware/crypto) set(libraries kkfirmware diff --git a/include/trezor/crypto b/include/trezor/crypto index 9e26be76d..5bac4fafe 120000 --- a/include/trezor/crypto +++ b/include/trezor/crypto @@ -1 +1 @@ -../../deps/crypto/trezor-crypto \ No newline at end of file +../../deps/crypto/trezor-firmware/crypto \ No newline at end of file diff --git a/lib/board/CMakeLists.txt b/lib/board/CMakeLists.txt index 10c30b424..bb2c376dc 100644 --- a/lib/board/CMakeLists.txt +++ b/lib/board/CMakeLists.txt @@ -51,7 +51,7 @@ endif() include_directories( ${CMAKE_SOURCE_DIR}/include ${CMAKE_BINARY_DIR}/include - ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-crypto + ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-firmware/crypto ${CMAKE_CURRENT_SOURCE_DIR}) add_library(kkboard ${sources}) diff --git a/lib/emulator/CMakeLists.txt b/lib/emulator/CMakeLists.txt index 51eba7e81..7d7eef5f8 100644 --- a/lib/emulator/CMakeLists.txt +++ b/lib/emulator/CMakeLists.txt @@ -36,7 +36,7 @@ if(${KK_EMULATOR}) target_include_directories(kkemulator_dylib PRIVATE ${CMAKE_SOURCE_DIR}/include ${CMAKE_BINARY_DIR}/include - ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-crypto) + ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-firmware/crypto) # libkkemu.c runs the firmware event loop on a dedicated thread (POSIX # pthreads; Win32 CreateThread under MinGW). Threads::Threads is a no-op on # the Win32 path and pulls in -lpthread on POSIX. Use the PLAIN signature — diff --git a/lib/firmware/CMakeLists.txt b/lib/firmware/CMakeLists.txt index ff28a5e86..a1b11000d 100644 --- a/lib/firmware/CMakeLists.txt +++ b/lib/firmware/CMakeLists.txt @@ -62,7 +62,7 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/scm_revision.h.in" include_directories( ${CMAKE_BINARY_DIR}/include - ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-crypto + ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-firmware/crypto ${CMAKE_SOURCE_DIR}/lib/firmware ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/tools/blupdater/CMakeLists.txt b/tools/blupdater/CMakeLists.txt index 990529f70..d5dc99764 100644 --- a/tools/blupdater/CMakeLists.txt +++ b/tools/blupdater/CMakeLists.txt @@ -9,7 +9,7 @@ if(NOT ${KK_EMULATOR}) include_directories( ${CMAKE_SOURCE_DIR}/include ${CMAKE_BINARY_DIR}/include - ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-crypto) + ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-firmware/crypto) set(linker_script ${CMAKE_CURRENT_SOURCE_DIR}/blupdater.ld) diff --git a/tools/bootloader/CMakeLists.txt b/tools/bootloader/CMakeLists.txt index 60b2c46a8..e1f4180ae 100644 --- a/tools/bootloader/CMakeLists.txt +++ b/tools/bootloader/CMakeLists.txt @@ -10,7 +10,7 @@ if(NOT ${KK_EMULATOR}) include_directories( ${CMAKE_SOURCE_DIR}/include ${CMAKE_BINARY_DIR}/include - ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-crypto) + ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-firmware/crypto) set(linker_script ${CMAKE_CURRENT_SOURCE_DIR}/bootloader.ld) diff --git a/tools/bootstrap/CMakeLists.txt b/tools/bootstrap/CMakeLists.txt index 9b2853b12..393dee36d 100644 --- a/tools/bootstrap/CMakeLists.txt +++ b/tools/bootstrap/CMakeLists.txt @@ -7,7 +7,7 @@ if(NOT ${KK_EMULATOR}) include_directories( ${CMAKE_SOURCE_DIR}/include ${CMAKE_BINARY_DIR}/include - ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-crypto) + ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-firmware/crypto) set(linker_script ${CMAKE_CURRENT_SOURCE_DIR}/bootstrap.ld) diff --git a/tools/check_pallas_api_boundary.py b/tools/check_pallas_api_boundary.py index 9e56a371a..d30c4b2ad 100644 --- a/tools/check_pallas_api_boundary.py +++ b/tools/check_pallas_api_boundary.py @@ -44,9 +44,9 @@ def forbid(body, token, where): def main(): - pallas = source("deps/crypto/trezor-crypto/pallas.c") - sinsemilla = source("deps/crypto/trezor-crypto/pallas_sinsemilla.c") - redpallas = source("deps/crypto/trezor-crypto/redpallas.c") + pallas = source("deps/crypto/trezor-firmware/crypto/pallas.c") + sinsemilla = source("deps/crypto/trezor-firmware/crypto/pallas_sinsemilla.c") + redpallas = source("deps/crypto/trezor-firmware/crypto/redpallas.c") zcash = source("lib/firmware/zcash.c") zcash_fsm = source("lib/firmware/fsm_msg_zcash.h") storage = source("lib/firmware/storage.c") diff --git a/tools/display_test/CMakeLists.txt b/tools/display_test/CMakeLists.txt index 0d280ab80..86da3d16d 100644 --- a/tools/display_test/CMakeLists.txt +++ b/tools/display_test/CMakeLists.txt @@ -6,7 +6,7 @@ if(NOT ${KK_EMULATOR}) include_directories( ${CMAKE_SOURCE_DIR}/include ${CMAKE_BINARY_DIR}/include - ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-crypto) + ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-firmware/crypto) set(linker_script ${CMAKE_CURRENT_SOURCE_DIR}/display_test.ld) diff --git a/tools/emulator/CMakeLists.txt b/tools/emulator/CMakeLists.txt index 3ef8bc442..2882f47a1 100644 --- a/tools/emulator/CMakeLists.txt +++ b/tools/emulator/CMakeLists.txt @@ -6,7 +6,7 @@ if(${KK_EMULATOR}) include_directories( ${CMAKE_SOURCE_DIR}/include ${CMAKE_BINARY_DIR}/include - ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-crypto) + ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-firmware/crypto) set(FIRMWARE_LIBS kkfirmware diff --git a/tools/firmware/CMakeLists.txt b/tools/firmware/CMakeLists.txt index 3c91156e6..0db0bf6e2 100644 --- a/tools/firmware/CMakeLists.txt +++ b/tools/firmware/CMakeLists.txt @@ -9,7 +9,7 @@ if(NOT ${KK_EMULATOR}) include_directories( ${CMAKE_SOURCE_DIR}/include ${CMAKE_BINARY_DIR}/include - ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-crypto) + ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-firmware/crypto) set(linker_script ${CMAKE_CURRENT_SOURCE_DIR}/keepkey.ld) diff --git a/unittests/board/CMakeLists.txt b/unittests/board/CMakeLists.txt index ddad5512d..65fb7c8a3 100644 --- a/unittests/board/CMakeLists.txt +++ b/unittests/board/CMakeLists.txt @@ -5,7 +5,7 @@ set(sources include_directories( ${CMAKE_SOURCE_DIR}/include ${CMAKE_BINARY_DIR}/include - ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-crypto) + ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-firmware/crypto) add_executable(board-unit ${sources}) target_link_libraries(board-unit diff --git a/unittests/crypto/CMakeLists.txt b/unittests/crypto/CMakeLists.txt index 7b32fab34..6b4cbf8d6 100644 --- a/unittests/crypto/CMakeLists.txt +++ b/unittests/crypto/CMakeLists.txt @@ -5,7 +5,7 @@ set(sources include_directories( ${CMAKE_SOURCE_DIR}/include ${CMAKE_BINARY_DIR}/include - ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-crypto) + ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-firmware/crypto) add_executable(crypto-unit ${sources}) target_link_libraries(crypto-unit @@ -30,13 +30,13 @@ if(${KK_ZCASH_PRIVACY}) # counters are never present in firmware or the normal emulator binary. add_executable(pallas-ct-unit pallas_ct.cpp - ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-crypto/pallas_ct.c - ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-crypto/memzero.c) + ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-firmware/crypto/pallas_ct.c + ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-firmware/crypto/memzero.c) target_compile_definitions(pallas-ct-unit PRIVATE PALLAS_CT_TESTING) target_include_directories(pallas-ct-unit PRIVATE ${CMAKE_SOURCE_DIR}/include ${CMAKE_BINARY_DIR}/include - ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-crypto) + ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-firmware/crypto) target_link_libraries(pallas-ct-unit gtest_main) add_executable(zcash-crypto-unit @@ -46,8 +46,8 @@ if(${KK_ZCASH_PRIVACY}) target_include_directories(zcash-crypto-unit PRIVATE ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/lib/firmware - ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-crypto - ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-crypto/ed25519-donna) + ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-firmware/crypto + ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-firmware/crypto/ed25519-donna) target_link_libraries(zcash-crypto-unit gtest_main trezorcrypto diff --git a/unittests/firmware/CMakeLists.txt b/unittests/firmware/CMakeLists.txt index 26052ac2f..667911741 100644 --- a/unittests/firmware/CMakeLists.txt +++ b/unittests/firmware/CMakeLists.txt @@ -39,7 +39,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/lib/firmware ${CMAKE_BINARY_DIR}/include - ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-crypto) + ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-firmware/crypto) add_executable(firmware-unit ${sources}) target_link_libraries(firmware-unit From a049a8b48fca4af65c99965fdac131565febaa5c Mon Sep 17 00:00:00 2001 From: highlander Date: Sun, 26 Jul 2026 16:49:22 -0300 Subject: [PATCH 19/22] ci(gitleaks): preserve historical crypto allowlists --- .gitleaks.toml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.gitleaks.toml b/.gitleaks.toml index 25ede9cca..5c16230d6 100644 --- a/.gitleaks.toml +++ b/.gitleaks.toml @@ -4,20 +4,25 @@ title = "KeepKey firmware Gitleaks configuration" useDefault = true [[allowlists]] -description = "Published AES test vectors in the pinned trezor-crypto fork" +description = "Published AES test vectors in current and historical trezor-crypto layouts" targetRules = ["generic-api-key"] condition = "AND" regexTarget = "line" -paths = ['''^deps/crypto/trezor-firmware/crypto/aes/aestst\.c$'''] +paths = [ + '''^deps/crypto/trezor-firmware/crypto/aes/aestst\.c$''', + '''^deps/crypto/trezor-crypto/aes/aestst\.c$''', +] regexes = ['''(?i)^[[:space:]]*//[[:space:]]*key[[:space:]]*=[[:space:]]*[0-9a-f]+[[:space:]]*$'''] [[allowlists]] -description = "Ed25519 C type names in the pinned trezor-crypto fork" +description = "Ed25519 C type names in current and historical trezor-crypto layouts" targetRules = ["generic-api-key"] condition = "AND" regexTarget = "line" paths = [ '''^deps/crypto/trezor-firmware/crypto/ed25519-donna/ed25519-(blake2b|keccak|sha3)\.h$''', '''^deps/crypto/trezor-firmware/crypto/ed25519-donna/ed25519\.[ch]$''', + '''^deps/crypto/trezor-crypto/ed25519-donna/ed25519-(blake2b|keccak|sha3)\.h$''', + '''^deps/crypto/trezor-crypto/ed25519-donna/ed25519\.[ch]$''', ] regexes = ['''ed25519.*secret_key.*signature'''] From 5003ee6279d3cdbaad267d6a452d863d06a19133 Mon Sep 17 00:00:00 2001 From: highlander Date: Sun, 26 Jul 2026 17:21:47 -0300 Subject: [PATCH 20/22] chore(rc18): repin corrected Python audit report --- deps/python-keepkey | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/python-keepkey b/deps/python-keepkey index 737361d6e..addc02428 160000 --- a/deps/python-keepkey +++ b/deps/python-keepkey @@ -1 +1 @@ -Subproject commit 737361d6eec884216c86a7d98ad9e898999193d4 +Subproject commit addc0242847cd7be9c402980498b321b344bef34 From a643f627a67b5d633007b54d541a0faf061fce21 Mon Sep 17 00:00:00 2001 From: highlander Date: Sun, 26 Jul 2026 18:04:10 -0300 Subject: [PATCH 21/22] chore(rc18): repin merged crypto dependency --- deps/crypto/trezor-firmware | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/crypto/trezor-firmware b/deps/crypto/trezor-firmware index 323e50d19..62230ee62 160000 --- a/deps/crypto/trezor-firmware +++ b/deps/crypto/trezor-firmware @@ -1 +1 @@ -Subproject commit 323e50d19c0eb727dc9de9197fd07842ce93b1f7 +Subproject commit 62230ee620fa9ea2bdd2c8067be7fde3f9362248 From fd1012c5adbacf88e2ca521a95b335a2849d528f Mon Sep 17 00:00:00 2001 From: highlander Date: Sun, 26 Jul 2026 18:17:30 -0300 Subject: [PATCH 22/22] docs(rc18): drop out-of-scope Tendermint roadmap --- docs/Generalized-Tendermint-Signing.md | 537 ------------------------- docs/README.md | 1 - 2 files changed, 538 deletions(-) delete mode 100644 docs/Generalized-Tendermint-Signing.md diff --git a/docs/Generalized-Tendermint-Signing.md b/docs/Generalized-Tendermint-Signing.md deleted file mode 100644 index 69ee80588..000000000 --- a/docs/Generalized-Tendermint-Signing.md +++ /dev/null @@ -1,537 +0,0 @@ -# Generalized Cosmos and Tendermint signing - -Status: future design proposal - -This document describes a path to full Cosmos SDK `SIGN_MODE_DIRECT` support, -generalized Tendermint/CometBFT-family signing, and IBC transfers across supported -chains. It is not part of the 7.15.0-rc17 release scope and does not change that -release's acceptance criteria. - -The name "Tendermint" is retained where it refers to the existing KeepKey -protocol. New code should use the more precise terms "Cosmos SDK" and -"CometBFT-family." - -## Product position - -Blind signing with an explicit warning is a valid first support tier for a new -chain or message type. KeepKey already uses this phased model for Ethereum -contract data and opaque Solana, TRON, TON, and EOS operations. Generalized -Cosmos support should follow the same model: - -1. Sign the exact transaction bytes in Advanced Mode after an unmistakable blind - signing warning. -2. Parse and display transaction envelope fields that can be bound to those - exact bytes. -3. Add clear-signing adapters for common messages over time. -4. Automatically replace blind review with clear review as message adapters - become available. - -Unknown does not mean forbidden. It means the device must never present an -unknown message as understood. - -This distinction makes broad compatibility practical: - -- A Cosmos SDK transaction using a supported key algorithm and - `SIGN_MODE_DIRECT` can be signed even when one or more `Any` message values are - not understood by the firmware. -- Recognized messages receive semantic clear-signing screens. -- Unrecognized messages receive blind-signing screens and an exact transaction - commitment. -- A non-Cosmos application built on Tendermint or CometBFT can reuse the - generalized byte-signing engine, but still needs an adapter defining its - signing domain, preimage, and key algorithm. A Cosmos `SignDoc` is not a - universal transaction format for every CometBFT application. - -The target is therefore universal signing compatibility for supported -algorithms and defined signing domains, not a claim that the firmware -semantically understands every application. - -## Goals - -- Implement Cosmos SDK protobuf `SIGN_MODE_DIRECT`. -- Preserve legacy Amino support for chains that still require it. -- Blind-sign otherwise valid, unsupported Cosmos messages behind Advanced Mode. -- Progressively clear-sign known bank, staking, distribution, governance, IBC, - authz, feegrant, CosmWasm, and chain-specific messages. -- Derive and display addresses for arbitrary compatible chains without - conflating display names, registry identities, and Bech32 prefixes. -- Support arbitrary Cosmos coin denoms, canonical integer amounts, multiple - coins, fee grants, and fee payers within explicit resource limits. -- Clear-sign ICS-20 transfers for all valid routes and assets, including - voucher, factory, and long trace-derived denoms. -- Reuse a bounded, session-oriented byte-signing core for non-Cosmos - CometBFT-family adapters. -- Keep every reviewed value cryptographically bound to the exact signed - preimage. - -## Non-goals and boundaries - -- The firmware does not discover IBC paths, channels, counterparty chains, or - relayers. The host builds the route; the device reviews the source-chain - transaction. -- Blind signing does not provide semantic verification. A digest and byte count - prove which bytes were approved, not what an unknown message will do. -- Host-provided labels, symbols, decimals, recipients, or amounts must never - substitute for values parsed from the signed bytes. -- `SIGN_MODE_DIRECT` does not cover every non-Cosmos CometBFT application. - Applications with different signing preimages or algorithms require explicit - adapters. -- Multisig, `SIGN_MODE_DIRECT_AUX`, `SIGN_MODE_TEXTUAL`, and non-secp256k1 keys - are not implied by the first implementation. They require explicit protocol - and UX decisions. - -## Current implementation and gaps - -The existing generic Tendermint protocol is a legacy Amino implementation. It is -useful compatibility code, but it is not a base for universal support. - -| Area | Current behavior | Required v2 behavior | -| --- | --- | --- | -| Sign mode | Legacy Amino JSON only | Exact protobuf `SignDoc` bytes for `SIGN_MODE_DIRECT`, plus legacy Amino | -| Generic messages | Wire schema advertises several message types; firmware handler accepts only `send` | Known messages clear-sign; every other valid `Any` can blind-sign | -| IBC | Generic IBC schema has no amount field | Bind token, sender, receiver, port, channel, timeouts, and memo | -| Amounts | Message amount is `uint64`; fee is `uint32` | Canonical unsigned decimal strings with an explicit maximum | -| Denoms | Generic denom is limited to 9 characters | Long exact denoms, including `ibc/<64-hex>` and factory denoms | -| Fees | One session-wide denom is reused | Repeated fee coins, independent message coins, gas, payer, and granter | -| Chain identity | `chain_name` is both coin lookup name and address HRP; `address_prefix` is ignored | Immutable, separate chain ID, registry ID, display name, and HRPs | -| Address support | Limited by the compiled coin registry | Validated chain descriptors and explicit path policy | -| Tests | Generic coverage is primarily session/config binding | Cross-SDK vectors, parser adversarial tests, emulator UX, and hardware QA | -| Host integration | Generic address support is partial; generic signing is not end-to-end | Protocol, hdwallet, Vault, registry, builder, and broadcast support | - -The existing `Tendermint*`, `Cosmos*`, and `Osmosis*` message IDs must remain -compatible. The new design should use new v2 message IDs and implementation -state rather than changing the meaning or size limits of old fields. - -## Signing and review tiers - -The transaction is assigned the least-trusted tier required by any component. -One unknown message downgrades the transaction to blind or mixed review; it must -not inherit a clear-sign label from neighboring known messages. - -### Tier A: clear signing - -All security-relevant fields are parsed from the exact signed bytes and displayed: - -- chain ID and signing account; -- message actions, senders, recipients, validators, contracts, and parameters; -- exact coin amounts and denoms; -- memo and timeout values; -- fees, gas, payer, granter, and sequence as applicable. - -Friendly symbols or decimal conversion may supplement raw values only when the -metadata is trusted and the exact denom remains reviewable. - -### Tier B: mixed review - -The firmware understands the transaction envelope and some messages, but at -least one message or extension is opaque. It: - -- clearly labels the whole transaction as containing unverified actions; -- displays all safely parsed envelope and known-message fields; -- displays each unknown `type_url`, value byte count, and value digest; -- displays an overall signing-preimage digest and byte count; -- requires Advanced Mode and explicit blind-sign confirmation. - -### Tier C: blind signing - -The adapter can validate the signing domain and sign the exact preimage, but -cannot semantically parse the application payload. It: - -- requires Advanced Mode; -- displays a prominent "Blind Sign" warning; -- displays the chain/signing domain, derivation path or derived address, exact - byte count, and full transaction digest; -- never displays host side-channel values as if they came from the transaction; -- signs only after an explicit final confirmation. - -Malformed framing, an unsupported key algorithm, a path that cannot be bound to -the signer, an oversized payload, or an ambiguous/non-canonical clear-sign parse -is rejected. Unsupported semantics alone may fall back to Tier B or C. - -Advanced Mode is a hard gate, not the only warning. Enabling it once does not -silently approve future blind signatures. - -## Exact-byte invariant - -The principal invariant is: - -> The device hashes and signs exactly the bytes whose properties and digest it -> reviewed. - -For `SIGN_MODE_DIRECT`, the secp256k1 signature is over the SHA-256 digest of the -serialized `cosmos.tx.v1beta1.SignDoc`: - -- `body_bytes` -- `auth_info_bytes` -- `chain_id` -- `account_number` - -The preferred protocol streams the serialized `SignDoc` bytes to the device. -The device simultaneously: - -1. validates ordered chunk framing and the declared total length; -2. hashes the exact incoming bytes; -3. parses display information from those same immutable bytes; -4. binds the selected key and signer information; -5. performs the required review flow; -6. signs the accumulated digest without reconstructing a different `SignDoc`. - -Hashing host-provided structured fields and later reserializing them creates an -avoidable display/signature mismatch risk. If structured transport is retained -for memory reasons, the framing itself must define one canonical serialized -preimage and the firmware must both parse and hash that exact stream. - -For Tier A clear signing, protobuf handling must reject encodings whose meaning -could differ between the firmware and a node, including ambiguous duplicate -singular fields, malformed or overlong varints, invalid lengths, truncated -submessages, conflicting signer modes, and unsupported critical extension -options. A structurally valid unknown `Any` is not malformed and may use the -blind tier. - -For Tier B or C, the transaction digest should be shown in full using the -existing exact-byte pager. The digest is an exact commitment, not a semantic -summary. - -## Proposed v2 protocol - -Exact names and field numbers require a device-protocol review. The logical flow -is: - -```text -CosmosSignDirectInit - -> CosmosSignDirectRequest(offset, max_chunk) - -> CosmosSignDirectChunk(offset, bytes) - -> ... repeat ... - -> device review - -> CosmosSignedDirect(public_key, signature, sign_doc_hash) -``` - -`CosmosSignDirectInit` should bind at least: - -- derivation path; -- expected serialized `SignDoc` length; -- expected SHA-256 digest, used only as a transport cross-check; -- requested signing mode and key algorithm; -- optional registry identity and descriptor version; -- host-declared review expectation, which the device may only downgrade. - -The device owns the running offset, remaining length, parser state, and hash. -Chunks must be contiguous and accepted exactly once. Any unexpected message, -offset, length, initialization attempt, cancellation, USB reset, or parser error -aborts and wipes the session. - -The response returns the compressed public key, compact 64-byte signature, and -the device-computed `SignDoc` digest so the host can cross-check the exact -preimage. - -The implementation should not accept a host-computed digest as the only thing -to sign. A future prehashed expert primitive, if ever required by a distinct -application, must be a separately named domain, use a stronger warning, and -display the complete digest. - -## Direct-mode parser - -The parser operates incrementally with bounded memory. It recognizes: - -- `TxBody.messages` as repeated `Any { type_url, value }`; -- memo and timeout height; -- extension and non-critical extension options; -- `AuthInfo.signer_infos`, public keys, `ModeInfo`, and sequence; -- `Fee.amount`, gas limit, payer, and granter; -- tip fields where the target SDK supports them. - -Initial scope should require one signer and `SIGN_MODE_DIRECT`. The firmware -derives the public key, verifies that the signer info and account address belong -to that key where those values are available, and rejects a mode substitution. -Multisig and multi-signer transactions should remain unsupported until the -review flow and signature assembly contract are specified. - -Message adapters consume the exact `Any.value` bytes. They may promote a message -to clear signing only after: - -- the `type_url` is an exact supported value; -- required fields and canonical encodings validate; -- signer/owner/sender fields bind to the derived key where applicable; -- all security-relevant fields fit and are reviewable; -- unknown critical fields cannot change the reviewed meaning. - -An adapter failure caused by unknown semantics downgrades to blind review. A -failure caused by malformed or contradictory encoding rejects the transaction. - -## Chain descriptors and addresses - -A v2 chain descriptor separates values that the legacy protocol conflates: - -- immutable registry ID and descriptor version; -- network chain ID; -- display name; -- account, validator, and consensus Bech32 HRPs; -- derivation path policy and SLIP-0044 coin type; -- public-key/signature algorithm; -- allowed sign modes; -- trusted native asset metadata, if any. - -The transaction-bound chain ID is always displayed. A friendly chain name cannot -replace it. - -Descriptors may be firmware-curated or supplied by a host registry with an -authenticated provenance model. Until that trust model is implemented, -host-supplied metadata is untrusted: display raw chain ID, HRP, path, exact denom, -and atomic amount. An unknown descriptor may still use blind signing when its -algorithm and address construction are supported. - -Address requests must use the explicit account HRP, not a coin lookup name. -Non-standard paths require the existing path warning policy. The displayed -address and the signing key must be derived from the same descriptor and path. - -The first algorithm target is Cosmos-style secp256k1. Ethermint -`ethsecp256k1`, ed25519, and other application key types require explicit -derivation, address, signature, and test-vector support; they must not be -silently treated as standard Cosmos secp256k1. - -## Coins, amounts, and fees - -The v2 schema should model Cosmos `Coin` directly: - -```text -Coin { - string denom - string amount -} -``` - -- `amount` is a canonical unsigned base-10 integer string: digits only, no sign, - whitespace, decimal point, exponent, or leading zeroes except `"0"`. -- Firmware defines and tests an explicit maximum digit count. A 256-bit ceiling - is a reasonable initial engineering target, subject to SDK compatibility and - OLED/resource tests. -- `denom` has a documented byte maximum large enough for IBC and factory denoms - and validates the relevant Cosmos SDK grammar. -- Every message owns its own coin list; fee coins are independent and repeated. -- Unknown metadata displays atomic amount plus exact denom. Trusted metadata may - add a decimal rendering but cannot hide the atomic pair. - -## IBC support - -The first clear-sign IBC adapter should support the protobuf -`ibc.applications.transfer.v1.MsgTransfer` forms used by target SDK versions. -Review must bind and show: - -- source port and channel; -- token amount and exact denom; -- sender and receiver; -- timeout height revision number and revision height; -- timeout timestamp; -- memo, including packet-forwarding JSON as exact text unless a separately - validated adapter interprets it. - -This works for native denoms, `ibc/` voucher denoms, factory denoms, and -other valid source-chain denominations. The firmware does not need a compiled -pairwise matrix of every source and destination chain. - -"IBC between all supported chains" means the host may construct any valid -source-chain ICS-20 route and the device can sign it. It does not mean the device -asserts that a channel reaches the host-claimed destination. Without trusted, -fresh channel proofs, the device should display the exact port/channel and -receiver rather than invent a destination-chain guarantee. - -IBC messages from unknown modules remain viable through the blind tier. - -## Legacy Amino - -Legacy Amino remains available for older chains but should also receive a v2 -transport rather than extending the current fixed-width schema. - -Two safe approaches are possible: - -1. stream the exact canonical Amino JSON sign bytes and blind-sign them; or -2. stream typed fields while the firmware constructs one canonical JSON - preimage and clear-signs supported message adapters. - -The first approach provides broad compatibility sooner. The second provides -stronger semantic review. They can coexist, with exact-byte blind support first -and structured adapters added incrementally. - -The v2 Amino model must separate message and fee denoms, use string amounts, -support long denoms and multiple coins, and bind all configuration to one -session. The old protocol continues unchanged for compatibility. - -## Non-Cosmos CometBFT applications - -The generalized core should expose an internal adapter contract: - -```text -domain identifier -preimage framing rules -hash function -key/signature algorithm -optional bounded parser -review classification -``` - -A new application can begin at Tier C by defining and testing its exact signing -preimage. Later parser adapters can promote its operations to Tier B or A. This -is the path to genuinely broad Tendermint/CometBFT support without pretending -all applications share Cosmos protobuf transaction semantics. - -Every external protocol gets a distinct domain identifier. Cross-domain ACKs, -chunks, finalization calls, and session reuse are rejected. - -## Rollout - -### Phase 0: specification and vectors - -- Freeze v2 threat model, wire flow, limits, canonical protobuf policy, and abort - behavior. -- Collect `SIGN_MODE_DIRECT` golden vectors from Cosmos SDK and at least one - independent host implementation. -- Choose an initial descriptor trust model and supported key algorithms. - -### Phase 1: universal Cosmos direct blind signing - -- Stream and hash exact `SignDoc` bytes on device. -- Validate the envelope enough to establish domain, chain ID, signer mode, - signer key, and resource safety. -- Permit unknown `Any` messages through Tier B/C in Advanced Mode. -- Show the blind warning, path/address, byte count, and full digest. -- Return signature, public key, and device-computed digest. - -This phase deliberately provides useful new-chain support before every module -has a clear-signing adapter. - -### Phase 2: envelope clear signing - -- Clear-sign chain ID, account number, sequence, memo, timeout, fee coins, gas, - payer, and granter when parsed unambiguously. -- Add trusted/untrusted chain descriptor UX. -- Downgrade extension options that are valid but not understood. - -### Phase 3: common message clear signing - -- Bank send and multi-send. -- Staking delegate, undelegate, redelegate, and cancel-unbonding. -- Distribution rewards and validator commission. -- Governance vote, deposit, and proposal variants. -- ICS-20 transfer. - -### Phase 4: application adapters - -- CosmWasm execute/instantiate/migrate, with contract payload remaining blind - until schema-aware review exists. -- Authz and feegrant, including nested-message downgrade rules. -- Chain-specific modules chosen by use and risk. -- Additional CometBFT signing domains and key algorithms. - -### Phase 5: default clear signing - -- Promote well-tested chains and message families to Tier A by default. -- Keep Advanced Mode fallback for valid unknown additions so protocol upgrades - do not make the chain unusable. - -## Workstreams - -| Repository/layer | Work | -| --- | --- | -| device-protocol | Add v2 init/chunk/request/response messages, limits, generated bindings, and message IDs | -| firmware transport | Session isolation, ordered streaming, abort/wipe behavior, and response framing | -| firmware crypto | Exact-byte hashing, secp256k1 signing, key/signer binding, and domain separation | -| firmware parser | Bounded `SignDoc`, `TxBody`, `AuthInfo`, `Any`, `Coin`, and message adapters | -| firmware UX | Tier labels, blind warning, digest/byte count, exact-value paging, and cancellation | -| hdwallet | Generic address and sign APIs, chunk driver, registry plumbing, and signature cross-checks | -| Vault | Generic address/sign endpoints, policy errors, transport recovery, and no metadata substitution | -| chain registry | Versioned descriptors, HRPs, paths, algorithms, assets, and provenance | -| host integrations | Transaction building, IBC route discovery, broadcast, and chain test vectors | -| QA/release | Unit, emulator, hardware OLED, fuzzing, interoperability, and downgrade tests | - -## Test and release gates - -### Cryptographic and interoperability - -- Device signatures match Cosmos SDK and independent host vectors. -- The returned digest equals SHA-256 of the exact serialized `SignDoc`. -- Signatures verify and broadcast on representative SDK versions and chains. -- Legacy Amino behavior remains byte-for-byte compatible. - -### Parser and transport adversarial tests - -- truncated fields and submessages; -- oversized lengths, integer overflow, and resource-limit boundaries; -- non-minimal/overlong varints and duplicate singular fields; -- unknown fields, unknown `Any` values, and extension options; -- chunk replay, gaps, overlap, reordering, early finalization, and excess bytes; -- session replacement, cross-domain ACKs, stale chunks, and USB interruption; -- signer-mode, public-key, path, chain-ID, fee, and sequence substitution; -- cancellation from every screen, proving that no signature is returned. - -### Review classification - -- fully known transactions are Tier A; -- any opaque nested or top-level action forces Tier B/C; -- unknown semantics can blind-sign in Advanced Mode; -- malformed transactions never downgrade to blind signing; -- no host-only label is presented as signed data; -- blind review always shows warning, byte count, and full digest; -- disabling Advanced Mode blocks every blind path. - -### Asset and IBC matrix - -- native, IBC voucher, factory, slash-containing, and maximum-length denoms; -- maximum amount values and multiple message/fee coins; -- native and non-native fee denoms; -- IBC timeout height, timeout timestamp, memo, and no-timeout edge cases; -- receivers with different valid HRPs and maximum supported length; -- packet-forwarding memos and unknown IBC module messages; -- representative Cosmos Hub, Osmosis, THORChain/MAYAChain-style legacy, and - additional SDK chains. - -### Device evidence - -- full firmware and constrained configurations fit ROM/SRAM budgets; -- parser stack frames retain the required reserve; -- fuzz targets and sanitizer builds pass on the host; -- emulator and physical OLED captures prove every maximum-length field can be - reviewed; -- cancellation and blind-sign policy behavior pass on physical hardware. - -## Open decisions - -- Stream a complete serialized `SignDoc`, or stream its exact field framing? - Complete exact bytes are preferred if the incremental parser can meet memory - limits. -- Require canonical protobuf for all tiers, or only for clear signing? The - safest initial policy is canonical envelope encoding for every tier. -- Use only global Advanced Mode, or add a per-session blind-sign capability? - Initial recommendation: Advanced Mode plus confirmation on every transaction. -- What descriptor provenance is trusted enough for symbols and decimals? -- What exact maxima apply to transaction bytes, nesting, messages, denoms, - amounts, HRPs, and type URLs? -- Which Ethermint key/address variants are in the first supported algorithm set? -- How should multisig, multiple signer infos, tips, fee payers, authz nesting, - and fee grants be reviewed? -- When should `SIGN_MODE_DIRECT_AUX` and `SIGN_MODE_TEXTUAL` be added? -- Which legacy Amino chains require exact JSON streaming before direct-mode - support? - -## Definition of done - -The generalized Cosmos milestone is complete when: - -- any structurally valid, resource-bounded Cosmos SDK `SIGN_MODE_DIRECT` - transaction using a supported key algorithm can be signed through an explicit - Advanced Mode blind path, even when its messages are unknown; -- known message adapters clear-sign only values parsed from the exact signed - bytes; -- arbitrary valid coin denoms and integer amounts work within documented limits; -- any valid host-constructed ICS-20 source-chain transfer can be signed, without - a compiled pairwise chain matrix; -- the address, signer key, signing mode, chain ID, and signed preimage are bound - to one isolated session; -- malformed data, ambiguous clear-sign encodings, and unsupported algorithms - fail closed; -- cancellation never produces a signature; -- protocol, firmware, hdwallet, Vault, registry, and hardware QA are delivered - together. - -The broader CometBFT-family milestone is complete only when each additional -application has an explicit, tested signing-domain adapter. Its initial adapter -may be blind-only; semantic clear signing can follow. diff --git a/docs/README.md b/docs/README.md index 0fe1dae06..d2ccbb7ec 100644 --- a/docs/README.md +++ b/docs/README.md @@ -6,4 +6,3 @@ * [Host Communications](Host.md) * [Release Process](Release.md) * [7.15.0 RC18 Release Shape](security/7.15.0-rc18-release-shape.md) -* [Generalized Cosmos and Tendermint Signing](Generalized-Tendermint-Signing.md)