diff --git a/.github/workflows/rust_fmt.yml b/.github/workflows/rust_fmt.yml index 587ade3..4bfd928 100644 --- a/.github/workflows/rust_fmt.yml +++ b/.github/workflows/rust_fmt.yml @@ -15,18 +15,11 @@ env: jobs: rust_fmt: runs-on: ubuntu-latest + container: + image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest steps: - name: Checkout uses: actions/checkout@v3 - - uses: actions-rs/toolchain@v1 - with: - toolchain: nightly - override: true - components: rustfmt - - name: Cargo fmt - uses: actions-rs/cargo@v1 - with: - command: fmt - args: --all -- --check \ No newline at end of file + run: cargo fmt --all -- --check \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 5c52b9a..40e5527 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,32 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +dependencies = [ + "gimli", +] + [[package]] name = "adler" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -17,12 +37,152 @@ dependencies = [ "memchr", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" + +[[package]] +name = "anstyle-parse" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "apdu-generator" +version = "1.0.0" +dependencies = [ + "clap", + "ethereum-types", + "hex", + "serde", + "serde_json", + "starknet 0.11.0", +] + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "async-trait" +version = "0.1.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "atomic-polyfill" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" +dependencies = [ + "critical-section", +] + +[[package]] +name = "auto_impl" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + [[package]] name = "autocfg" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "backtrace" +version = "0.3.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bindgen" version = "0.65.1" @@ -46,6 +206,12 @@ dependencies = [ "which", ] +[[package]] +name = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" + [[package]] name = "bitflags" version = "1.3.2" @@ -59,398 +225,3059 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] -name = "cc" -version = "1.0.98" +name = "bitvec" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] [[package]] -name = "cexpr" -version = "0.6.0" +name = "block" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "nom", + "generic-array", ] [[package]] -name = "cfg-if" -version = "1.0.0" +name = "bluez-async" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "5ce7d4413c940e8e3cb6afc122d3f4a07096aca259d286781128683fc9f39d9b" +dependencies = [ + "async-trait", + "bitflags 2.5.0", + "bluez-generated", + "dbus", + "dbus-tokio", + "futures", + "itertools", + "log", + "serde", + "serde-xml-rs", + "thiserror", + "tokio", + "uuid 1.10.0", +] [[package]] -name = "clang-sys" -version = "1.8.1" +name = "bluez-generated" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +checksum = "4d1c659dbc82f0b8ca75606c91a371e763589b7f6acf36858eeed0c705afe367" dependencies = [ - "glob", + "dbus", +] + +[[package]] +name = "btleplug" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790e133b9d27f6dbd1289e046e735cef97fb0b4c840f18db52c959521dfb8145" +dependencies = [ + "async-trait", + "bitflags 1.3.2", + "bluez-async", + "cocoa", + "dashmap", + "dbus", + "futures", + "jni", + "jni-utils", "libc", - "libloading", + "log", + "objc", + "once_cell", + "static_assertions", + "thiserror", + "tokio", + "tokio-stream", + "uuid 1.10.0", + "windows", ] [[package]] -name = "color_quant" -version = "1.1.0" +name = "bumpalo" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] -name = "const-zero" -version = "0.1.1" +name = "byte-slice-cast" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3c6565524986fe3225da0beb9b4aa55ebc73cd57ff8cb4ccf016ca4c8d006af" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" [[package]] -name = "crc32fast" -version = "1.4.2" +name = "bytemuck" +version = "1.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "102087e286b4677862ea56cf8fc58bb2cdfa8725c40ffb80fe3a008eb7f2fc83" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952" + +[[package]] +name = "cc" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ - "cfg-if", + "nom", ] [[package]] -name = "critical-section" -version = "1.1.2" +name = "cfg-if" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "either" -version = "1.12.0" +name = "check-signature" +version = "0.1.0" +dependencies = [ + "clap", + "ledger-lib", + "starknet 0.11.0", + "starknet-types-core", + "tokio", + "url", +] + +[[package]] +name = "chrono" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "serde", + "windows-targets 0.52.5", +] [[package]] -name = "embedded-alloc" -version = "0.5.1" +name = "cipher" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddae17915accbac2cfbc64ea0ae6e3b330e6ea124ba108dada63646fd3c6f815" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "critical-section", - "linked_list_allocator", + "crypto-common", + "inout", ] [[package]] -name = "errno" -version = "0.3.9" +name = "clang-sys" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ + "glob", "libc", - "windows-sys", + "libloading", ] [[package]] -name = "flate2" -version = "1.0.30" +name = "clap" +version = "4.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +checksum = "8f6b81fb3c84f5563d509c59b5a48d935f689e993afa90fe39047f05adef9142" dependencies = [ - "crc32fast", - "miniz_oxide", + "clap_builder", + "clap_derive", ] [[package]] -name = "gif" -version = "0.11.4" +name = "clap_builder" +version = "4.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3edd93c6756b4dfaf2709eafcc345ba2636565295c198a9cfbf75fa5e3e00b06" +checksum = "5ca6706fd5224857d9ac5eb9355f6683563cc0541c7cd9d014043b57cbec78ac" dependencies = [ - "color_quant", - "weezl", + "anstream", + "anstyle", + "clap_lex", + "strsim 0.11.1", ] [[package]] -name = "glob" -version = "0.3.1" +name = "clap_derive" +version = "4.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.66", +] [[package]] -name = "hex" -version = "0.4.3" +name = "clap_lex" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" [[package]] -name = "home" -version = "0.5.9" +name = "cocoa" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a" dependencies = [ - "windows-sys", + "bitflags 1.3.2", + "block", + "cocoa-foundation", + "core-foundation", + "core-graphics", + "foreign-types", + "libc", + "objc", ] [[package]] -name = "include_gif" -version = "1.1.0" +name = "cocoa-foundation" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c18f099f85187e07161246cc0346968f76084266ddc1f286d11a7bad67ec4b59" +checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" dependencies = [ - "flate2", - "gif", - "syn 1.0.109", + "bitflags 1.3.2", + "block", + "core-foundation", + "core-graphics-types", + "libc", + "objc", ] [[package]] -name = "lazy_static" -version = "1.4.0" +name = "color_quant" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] -name = "lazycell" -version = "1.3.0" +name = "colorchoice" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" [[package]] -name = "ledger_device_sdk" -version = "1.10.5" +name = "combine" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2332f96119aeca963cc804469d99f08c16d492d7abbab8d210f64e40e5b5e6c0" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ - "const-zero", - "include_gif", - "ledger_secure_sdk_sys", - "num-traits", - "numtoa", - "rand_core", - "zeroize", + "bytes", + "memchr", ] [[package]] -name = "ledger_secure_sdk_sys" -version = "1.4.1" +name = "const-zero" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3c6565524986fe3225da0beb9b4aa55ebc73cd57ff8cb4ccf016ca4c8d006af" + +[[package]] +name = "core-foundation" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74ec7655a140a2a77c85ee733e93537b891ce5cef3265bda3ea1ef437b9205c4" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ - "bindgen", - "cc", - "critical-section", - "embedded-alloc", - "glob", + "core-foundation-sys", + "libc", ] [[package]] -name = "libc" -version = "0.2.155" +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "core-graphics" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "critical-section" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core 0.14.4", + "darling_macro 0.14.4", +] + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core 0.20.10", + "darling_macro 0.20.10", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn 1.0.109", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.11.1", + "syn 2.0.66", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core 0.14.4", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core 0.20.10", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "dbus" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bb21987b9fb1613058ba3843121dd18b163b254d8a6e797e144cbac14d96d1b" +dependencies = [ + "futures-channel", + "futures-util", + "libc", + "libdbus-sys", + "winapi", +] + +[[package]] +name = "dbus-tokio" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "007688d459bc677131c063a3a77fb899526e17b7980f390b69644bdbc41fad13" +dependencies = [ + "dbus", + "libc", + "tokio", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "either" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" + +[[package]] +name = "embedded-alloc" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddae17915accbac2cfbc64ea0ae6e3b330e6ea124ba108dada63646fd3c6f815" +dependencies = [ + "critical-section", + "linked_list_allocator", +] + +[[package]] +name = "encdec" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25de94e10baa85551f7c65730423239370ed5bed60bf8d2a9cbf2683327ba421" +dependencies = [ + "encdec-base 0.9.0", + "encdec-macros", +] + +[[package]] +name = "encdec-base" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f8542ff2a35da7fc94ffcf280f35dc759219c4b48fa930e0a0f268220d7fb6a" +dependencies = [ + "byteorder", + "num-traits", +] + +[[package]] +name = "encdec-base" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516ae3c7d00515548bf26a6531883335ceac2e9cde4938e70feea7456569be09" +dependencies = [ + "byteorder", + "heapless", + "num-traits", + "thiserror", +] + +[[package]] +name = "encdec-macros" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15497932aae6b53bf8548cc63c65929b4fab6be54e28709c80fc72f5707eeed" +dependencies = [ + "darling 0.14.4", + "encdec-base 0.8.3", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "encoding_rs" +version = "0.8.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "eth-keystore" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" +dependencies = [ + "aes", + "ctr", + "digest", + "hex", + "hmac", + "pbkdf2", + "rand", + "scrypt", + "serde", + "serde_json", + "sha2", + "sha3", + "thiserror", + "uuid 0.8.2", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-rlp", + "impl-serde", + "tiny-keccak", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-rlp", + "impl-serde", + "primitive-types", + "uint", +] + +[[package]] +name = "exr" +version = "1.72.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "887d93f60543e9a9362ef8a21beedd0a833c5d9610e18c67abe15a5963dcb1a4" +dependencies = [ + "bit_field", + "flume", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + +[[package]] +name = "fdeflate" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "flate2" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "spin", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gif" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap 2.2.6", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "heapless" +version = "0.7.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" +dependencies = [ + "atomic-polyfill", + "hash32", + "rustc_version", + "spin", + "stable_deref_trait", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hidapi" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e58251020fe88fe0dae5ebcc1be92b4995214af84725b375d08354d0311c23c" +dependencies = [ + "cc", + "cfg-if", + "libc", + "pkg-config", + "windows-sys 0.48.0", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http", + "hyper", + "rustls", + "tokio", + "tokio-rustls", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "image" +version = "0.24.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "exr", + "gif", + "jpeg-decoder", + "num-traits", + "png", + "qoi", + "tiff", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "include_gif" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8511434ad4b61bf0be7c61707d0172b6ad091519da93bf95d66555f3f0d994ac" +dependencies = [ + "flate2", + "image", + "syn 1.0.109", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown 0.14.5", + "serde", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jni-utils" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "259e9f2c3ead61de911f147000660511f07ab00adeed1d84f5ac4d0386e7a6c4" +dependencies = [ + "dashmap", + "futures", + "jni", + "log", + "once_cell", + "static_assertions", + "uuid 1.10.0", +] + +[[package]] +name = "jpeg-decoder" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" +dependencies = [ + "rayon", +] + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lambdaworks-crypto" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fb5d4f22241504f7c7b8d2c3a7d7835d7c07117f10bff2a7d96a9ef6ef217c3" +dependencies = [ + "lambdaworks-math", + "serde", + "sha2", + "sha3", +] + +[[package]] +name = "lambdaworks-math" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "358e172628e713b80a530a59654154bfc45783a6ed70ea284839800cebdf8f97" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "lebe" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" + +[[package]] +name = "ledger-lib" +version = "0.1.0" +source = "git+https://github.com/LedgerHQ/ledger-rust.git?branch=y333/fix_timeout#8a514af25270a263942a8f3d9a541e4d55d80491" +dependencies = [ + "async-trait", + "btleplug", + "displaydoc", + "encdec", + "futures", + "hidapi", + "ledger-proto", + "once_cell", + "strum", + "thiserror", + "tokio", + "tracing", + "tracing-subscriber", + "uuid 1.10.0", +] + +[[package]] +name = "ledger-proto" +version = "0.1.0" +source = "git+https://github.com/LedgerHQ/ledger-rust.git?branch=y333/fix_timeout#8a514af25270a263942a8f3d9a541e4d55d80491" +dependencies = [ + "bitflags 2.5.0", + "displaydoc", + "encdec", + "num_enum", + "thiserror", +] + +[[package]] +name = "ledger_device_sdk" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b094c3a2c653b1dc6bcedbcf2515f78ff40f5177bf4571348ced1fce45b4442" +dependencies = [ + "const-zero", + "include_gif", + "ledger_secure_sdk_sys", + "num-traits", + "numtoa", + "rand_core", + "zeroize", +] + +[[package]] +name = "ledger_secure_sdk_sys" +version = "1.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4b14a7a8ce8eda765e81a53a89b70f6d6d2875f2b706376c4e3dfa2db496788" +dependencies = [ + "bindgen", + "cc", + "critical-section", + "embedded-alloc", + "glob", +] + +[[package]] +name = "libc" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] -name = "libloading" -version = "0.8.3" +name = "libdbus-sys" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06085512b750d640299b79be4bad3d2fa90a9c00b1fd9e1b46364f66f0485c72" +dependencies = [ + "pkg-config", +] + +[[package]] +name = "libloading" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +dependencies = [ + "cfg-if", + "windows-targets 0.52.5", +] + +[[package]] +name = "linked_list_allocator" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" +dependencies = [ + "adler", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "numtoa" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aa2c4e539b869820a2b82e1aef6ff40aa85e65decdd5185e83fb4b1249cd00f" + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[package]] +name = "object" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "parity-scale-codec" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.5", +] + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", +] + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "png" +version = "0.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "prettyplease" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" +dependencies = [ + "proc-macro2", + "syn 2.0.66", +] + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" +dependencies = [ + "bitflags 2.5.0", +] + +[[package]] +name = "regex" +version = "1.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.6", + "regex-syntax 0.8.3", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.3", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" + +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-rustls", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-rustls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", + "winreg", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags 2.5.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scrypt" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" +dependencies = [ + "hmac", + "pbkdf2", + "salsa20", + "sha2", +] + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "serde" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-xml-rs" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb3aa78ecda1ebc9ec9847d5d3aba7d618823446a049ba2491940506da6e2782" +dependencies = [ + "log", + "serde", + "thiserror", + "xml-rs", +] + +[[package]] +name = "serde_derive" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "serde_json" +version = "1.0.120" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_json_pythonic" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62212da9872ca2a0cad0093191ee33753eddff9266cbbc1b4a602d13a3a768db" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "3.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.2.6", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" +dependencies = [ + "darling 0.20.10", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "starknet" +version = "0.11.0" +source = "git+https://github.com/xJonathanLEI/starknet-rs#f6d339c6b897fb38c839485608ca2fe374a6275d" +dependencies = [ + "starknet-accounts", + "starknet-contract", + "starknet-core", + "starknet-crypto", + "starknet-macros", + "starknet-providers", + "starknet-signers", +] + +[[package]] +name = "starknet" +version = "2.0.0" +dependencies = [ + "hex", + "include_gif", + "ledger_device_sdk", + "ledger_secure_sdk_sys", + "num-bigint", +] + +[[package]] +name = "starknet-accounts" +version = "0.10.0" +source = "git+https://github.com/xJonathanLEI/starknet-rs#f6d339c6b897fb38c839485608ca2fe374a6275d" +dependencies = [ + "async-trait", + "auto_impl", + "starknet-core", + "starknet-crypto", + "starknet-providers", + "starknet-signers", + "thiserror", +] + +[[package]] +name = "starknet-contract" +version = "0.10.0" +source = "git+https://github.com/xJonathanLEI/starknet-rs#f6d339c6b897fb38c839485608ca2fe374a6275d" +dependencies = [ + "serde", + "serde_json", + "serde_with", + "starknet-accounts", + "starknet-core", + "starknet-providers", + "thiserror", +] + +[[package]] +name = "starknet-core" +version = "0.11.1" +source = "git+https://github.com/xJonathanLEI/starknet-rs#f6d339c6b897fb38c839485608ca2fe374a6275d" +dependencies = [ + "base64 0.21.7", + "crypto-bigint", + "flate2", + "hex", + "serde", + "serde_json", + "serde_json_pythonic", + "serde_with", + "sha3", + "starknet-crypto", + "starknet-types-core", +] + +[[package]] +name = "starknet-crypto" +version = "0.7.1" +source = "git+https://github.com/xJonathanLEI/starknet-rs#f6d339c6b897fb38c839485608ca2fe374a6275d" +dependencies = [ + "crypto-bigint", + "hex", + "hmac", + "num-bigint", + "num-integer", + "num-traits", + "rfc6979", + "sha2", + "starknet-crypto-codegen", + "starknet-curve", + "starknet-types-core", + "zeroize", +] + +[[package]] +name = "starknet-crypto-codegen" +version = "0.4.0" +source = "git+https://github.com/xJonathanLEI/starknet-rs#f6d339c6b897fb38c839485608ca2fe374a6275d" +dependencies = [ + "starknet-curve", + "starknet-types-core", + "syn 2.0.66", +] + +[[package]] +name = "starknet-curve" +version = "0.5.0" +source = "git+https://github.com/xJonathanLEI/starknet-rs#f6d339c6b897fb38c839485608ca2fe374a6275d" +dependencies = [ + "starknet-types-core", +] + +[[package]] +name = "starknet-macros" +version = "0.2.0" +source = "git+https://github.com/xJonathanLEI/starknet-rs#f6d339c6b897fb38c839485608ca2fe374a6275d" +dependencies = [ + "starknet-core", + "syn 2.0.66", +] + +[[package]] +name = "starknet-providers" +version = "0.11.0" +source = "git+https://github.com/xJonathanLEI/starknet-rs#f6d339c6b897fb38c839485608ca2fe374a6275d" +dependencies = [ + "async-trait", + "auto_impl", + "ethereum-types", + "flate2", + "getrandom", + "log", + "reqwest", + "serde", + "serde_json", + "serde_with", + "starknet-core", + "thiserror", + "url", +] + +[[package]] +name = "starknet-signers" +version = "0.9.0" +source = "git+https://github.com/xJonathanLEI/starknet-rs#f6d339c6b897fb38c839485608ca2fe374a6275d" +dependencies = [ + "async-trait", + "auto_impl", + "crypto-bigint", + "eth-keystore", + "getrandom", + "rand", + "starknet-core", + "starknet-crypto", + "thiserror", +] + +[[package]] +name = "starknet-types-core" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6bacf0ba19bc721e518bc4bf389ff13daa8a7c5db5fd320600473b8aa9fcbd" +dependencies = [ + "lambdaworks-crypto", + "lambdaworks-math", + "num-bigint", + "num-integer", + "num-traits", + "serde", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 1.0.109", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "thiserror" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "tiff" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.38.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb2caba9f80616f438e09748d5acda951967e1ea58508ef53d9c6402485a46df" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" dependencies = [ - "cfg-if", - "windows-targets", + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", ] [[package]] -name = "linked_list_allocator" -version = "0.10.5" +name = "tokio-util" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] [[package]] -name = "linux-raw-sys" -version = "0.4.14" +name = "toml_datetime" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" [[package]] -name = "log" -version = "0.4.21" +name = "toml_edit" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap 2.2.6", + "toml_datetime", + "winnow", +] [[package]] -name = "memchr" -version = "2.7.2" +name = "tower-service" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] -name = "minimal-lexical" -version = "0.2.1" +name = "tracing" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] [[package]] -name = "miniz_oxide" -version = "0.7.3" +name = "tracing-attributes" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ - "adler", + "proc-macro2", + "quote", + "syn 2.0.66", ] [[package]] -name = "nom" -version = "7.1.3" +name = "tracing-core" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ - "memchr", - "minimal-lexical", + "once_cell", + "valuable", ] [[package]] -name = "num-traits" -version = "0.2.19" +name = "tracing-log" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ - "autocfg", + "log", + "once_cell", + "tracing-core", ] [[package]] -name = "numtoa" -version = "0.2.4" +name = "tracing-subscriber" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aa2c4e539b869820a2b82e1aef6ff40aa85e65decdd5185e83fb4b1249cd00f" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] [[package]] -name = "once_cell" -version = "1.19.0" +name = "try-lock" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] -name = "peeking_take_while" -version = "0.1.2" +name = "typenum" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] -name = "prettyplease" -version = "0.2.20" +name = "uint" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" dependencies = [ - "proc-macro2", - "syn 2.0.66", + "byteorder", + "crunchy", + "hex", + "static_assertions", ] [[package]] -name = "proc-macro2" -version = "1.0.85" +name = "unicode-bidi" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ - "unicode-ident", + "tinyvec", ] [[package]] -name = "quote" -version = "1.0.36" +name = "untrusted" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ - "proc-macro2", + "form_urlencoded", + "idna", + "percent-encoding", ] [[package]] -name = "rand_core" -version = "0.6.4" +name = "utf8parse" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] -name = "regex" -version = "1.10.4" +name = "uuid" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", + "getrandom", + "serde", ] [[package]] -name = "regex-automata" -version = "0.4.6" +name = "uuid" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", + "same-file", + "winapi-util", ] [[package]] -name = "regex-syntax" -version = "0.8.3" +name = "want" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] [[package]] -name = "rustc-hash" -version = "1.1.0" +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] -name = "rustix" -version = "0.38.34" +name = "wasm-bindgen" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ - "bitflags 2.5.0", - "errno", - "libc", - "linux-raw-sys", - "windows-sys", + "cfg-if", + "wasm-bindgen-macro", ] [[package]] -name = "shlex" -version = "1.3.0" +name = "wasm-bindgen-backend" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.66", + "wasm-bindgen-shared", +] [[package]] -name = "starknet" -version = "1.2.2" +name = "wasm-bindgen-futures" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ - "hex", - "include_gif", - "ledger_device_sdk", + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", ] [[package]] -name = "syn" -version = "1.0.109" +name = "wasm-bindgen-macro" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ - "proc-macro2", "quote", - "unicode-ident", + "wasm-bindgen-macro-support", ] [[package]] -name = "syn" -version = "2.0.66" +name = "wasm-bindgen-macro-support" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "unicode-ident", + "syn 2.0.66", + "wasm-bindgen-backend", + "wasm-bindgen-shared", ] [[package]] -name = "unicode-ident" -version = "1.0.12" +name = "wasm-bindgen-shared" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "weezl" @@ -470,13 +3297,86 @@ dependencies = [ "rustix", ] +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.5", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.5", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -485,28 +3385,46 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.5" @@ -519,32 +3437,99 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "xml-rs" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" + [[package]] name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] diff --git a/Cargo.toml b/Cargo.toml index 2ab227f..a9e8771 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,17 +1,11 @@ -[package] -name = "starknet" -version = "1.2.2" -edition = "2021" -authors = ["Ledger"] +[workspace] +members = [ + "tools/apdu-generator", + "tools/check-signature", + "starknet" +] -[dependencies] -ledger_device_sdk = "1.10.5" -include_gif = "1.1.0" -hex = { version = "0.4", default-features = false } - -[features] -default = [] -pending_review_screen = [] +resolver = "2" [profile.dev] panic = "abort" @@ -20,22 +14,3 @@ panic = "abort" panic = "abort" opt-level = 'z' lto = true - -[package.metadata.ledger] -curve = ["secp256k1"] -path = ["2645'"] -name = "Starknet" -flags = "0" - -[package.metadata.ledger.nanox] -icon = "starknet_small.gif" - -[package.metadata.ledger.nanosplus] -icon = "starknet_small.gif" - -[package.metadata.ledger.stax] -icon = "starknet_32x32.gif" - -[package.metadata.ledger.flex] -icon = "starknet_40x40.gif" - diff --git a/bench.sh b/bench.sh new file mode 100755 index 0000000..24829ca --- /dev/null +++ b/bench.sh @@ -0,0 +1,7 @@ +#!/bin/zsh + +start=$(($(gdate +%s%0N)/1000000)) +ledgercomm-send --hid file test/poseidon_single.apdu +end=$(($(gdate +%s%0N)/1000000)) +elapsed=$((end-start)) +echo "Elapsed time: $elapsed ms" diff --git a/docs/apdu.md b/docs/apdu.md index a8f6315..1304880 100644 --- a/docs/apdu.md +++ b/docs/apdu.md @@ -92,20 +92,19 @@ This command returns the public key corresponding to the secret key found at the | PKEY | byte (??) | Public key bytes | 32 (x) + 32 (y) | | SW1-SW2 | byte (2) | Return code | see list of return codes | -### Sign +### Sign Tx (see [Starnet Tx v3](https://docs.starknet.io/architecture-and-concepts/network-architecture/transactions/#v3_hash_calculation)) -This command will return a signature of the passed payload +This command will return the hash and signature of a Starknet Tx version 3 -#### Command #1 +#### Command #0: Set private key | Field | Type | Content | Expected | |-------|----------|-----------------------------|-------------------| -| CLA | byte (1) | Application Identifier | 0x80 | -| INS | byte (1) | Instruction ID | 0x02 | -| P1 | byte (1) | Payload desc | 0 | +| CLA | byte (1) | Application Identifier | 0x5A | +| INS | byte (1) | Instruction ID | 0x03 | +| P1 | byte (1) | Payload desc | 0x00 | | P2 | byte (1) | ignored | | | L | byte (1) | Bytes in payload | (depends) | -| PathN | byte (1) | Number of path components | 6 | | Path[0] | byte (4) | Derivation Path Data | 0x80000A55 | | Path[1] | byte (4) | Derivation Path Data | ? | | Path[2] | byte (4) | Derivation Path Data | ? | @@ -119,21 +118,102 @@ This command will return a signature of the passed payload |----------|-----------|-------------|---------------------------------------| | SW1-SW2 | byte (2) | Return code | see list of return codes | -#### Command #2 +#### Command #1: Send Starknet Tx main fields + +| Field | Type | Content | Expected | +|------------------|----------|-----------------------------|-------------------| +| CLA | byte (1) | Application Identifier | 0x5A | +| INS | byte (1) | Instruction ID | 0x03 | +| P1 | byte (1) | Payload desc | 0x01 | +| P2 | byte (1) | ignored | | +| L | byte (1) | Bytes in payload | 0xE0 (7x32 = 224) | +| Account Address | byte (32)| sender address | (depends) | +| Tip | byte (32)| tip | (depends) | +| Fee L1 | byte (32)| l1_gas_bounds | (depends) | +| Fee L2 | byte (32)| l2_gas_bounds | (depends) | +| ChainID | byte (32)| chain_id | (depends) | +| Nonce | byte (32)| nonce | (depends) | +| DA mode | byte (32)| data_availability_mode | (depends) | -| Field | Type | Content | Expected | -|-------|----------|-----------------------------|-------------------| -| CLA | byte (1) | Application Identifier | 0x80 | -| INS | byte (1) | Instruction ID | 0x02 | -| P1 | byte (1) | Payload desc | 1 | -| P2 | byte (1) | ignored | | -| L | byte (1) | Bytes in payload | 0x20 | -| Hash | byte (32)| Pedersen hash | (depends) | +#### Response + +| Field | Type | Content | Note | +|----------|-----------|-------------|---------------------------------------| +| SW1-SW2 | byte (2) | Return code | see list of return codes | + +#### Command #2: Send Paymaster data + +| Field | Type | Content | Expected | +|------------------|----------|-----------------------------|-------------------| +| CLA | byte (1) | Application Identifier | 0x5A | +| INS | byte (1) | Instruction ID | 0x03 | +| P1 | byte (1) | Payload desc | 0x02 | +| P2 | byte (1) | ignored | 0x00 | +| L | byte (1) | Bytes in payload | 0x00 | + +#### Response + +| Field | Type | Content | Note | +|----------|-----------|-------------|---------------------------------------| +| SW1-SW2 | byte (2) | Return code | see list of return codes | + +#### Command #3: Send Account Deployment data + +| Field | Type | Content | Expected | +|------------------|----------|-----------------------------|-------------------| +| CLA | byte (1) | Application Identifier | 0x5A | +| INS | byte (1) | Instruction ID | 0x03 | +| P1 | byte (1) | Payload desc | 0x03 | +| P2 | byte (1) | ignored | 0x00 | +| L | byte (1) | Bytes in payload | 0x00 | + +#### Response + +| Field | Type | Content | Note | +|----------|-----------|-------------|---------------------------------------| +| SW1-SW2 | byte (2) | Return code | see list of return codes | + +#### Command #4: Number of Calls + +| Field | Type | Content | Expected | +|------------------|------------|-----------------------------|-------------------| +| CLA | byte (1) | Application Identifier | 0x5A | +| INS | byte (1) | Instruction ID | 0x03 | +| P1 | byte (1) | Payload desc | 0x04 | +| P2 | byte (1) | ignored | 0x00 | +| L | byte (1) | Bytes in payload | 0x20 | +| Num of calls | bytes (32) | Bytes in payload | (depends) | #### Response | Field | Type | Content | Note | |----------|-----------|-------------|---------------------------------------| -| L | byte (1) | Sig Length | 0x41 = 65 | -| SIG | byte (65) | Signature | (R,S, V) encoded signature | | SW1-SW2 | byte (2) | Return code | see list of return codes | + +#### Command #5: Call + +| Field | Type | Content | Expected | +|------------------|------------|-----------------------------|-------------------| +| CLA | byte (1) | Application Identifier | 0x5A | +| INS | byte (1) | Instruction ID | 0x03 | +| P1 | byte (1) | Payload desc | 0x05 | +| P2 | byte (1) | New call or next calldata | 0x00 or 0x01 | +| L | byte (1) | Bytes in payload | (depends) | +| calldata | bytes (32) | to | (depends) | +| calldata | bytes (32) | selector | (depends) | +| calldata | bytes (32) | calldata #0 | (depends) | +| calldata | bytes (32) | calldata #1 | (depends) | +| calldata | bytes (32) | .... | (depends) | +| calldata | bytes (32) | calldata #x | (depends) | + + +#### Response + +| Field | Type | Content | Note | +|----------|-----------|-------------------|---------------------------------------| +| Tx Hash | byte (32) | Tx Poseidon Hash | 32 bytes | +| L | byte (1) | Sig Length | 0x41 = 65 | +| R | byte (32) | Signature | (R,S,V) encoded signature | +| S | byte (32) | Signature | (R,S,V) encoded signature | +| V | byte (1) | Signature | (R,S,V) encoded signature | +| SW1-SW2 | byte (2) | Return code | see list of return codes | diff --git a/docs/build.md b/docs/build.md index 7bd134c..205fe81 100644 --- a/docs/build.md +++ b/docs/build.md @@ -3,15 +3,15 @@ Use [ledger_app_builder](https://github.com/LedgerHQ/ledger-app-builder) Docker Prerequisite: ``` # Pull Docker image container -docker pull ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder +docker pull ghcr.io/ledgerhq/ledger-app-builder/ledger-app-dev-tools # Checkout LedgerHQ Starknet app repository git clone https://github.com/LedgerHQ/app-starknet.git ``` Build for Nano S+/X/Stax/Flex: ``` -docker run --rm -it -v "$(pwd -P):/apps" ghcr.io/ledgerhq ledger-app-builder/ledger-app-builder -cd /apps/app-starknet/ +docker run --rm -it -v "$(pwd -P):/apps" --publish 5001:5001 --publish 9999:9999 -e DISPLAY='host.docker.internal:0' -v '/tmp/.X11-unix:/tmp/.X11-unix' --privileged ghcr.io/ledgerhq/ledger-app-builder/ledger-app-dev-tools +cd /apps/app-starknet/starknet cargo clean cargo ledger build nanosplus|nanox|stax|flex ``` \ No newline at end of file diff --git a/docs/test.md b/docs/test.md index e9cbb47..7f4a055 100644 --- a/docs/test.md +++ b/docs/test.md @@ -8,7 +8,7 @@ docker pull ghcr.io/ledgerhq/ledger-app-builder/ledger-app-dev-tools ` ### Run Ragger tests ``` -docker run --rm -it -v "$(pwd -P):/apps" --publish 5001:5001 --publish 9999:9999 ghcr.io/ledgerhq/ledger-app-builder/ledger-app-dev-tools +docker run --rm -it -v "$(pwd -P):/apps" --publish 5001:5001 --publish 9999:9999 -e DISPLAY='host.docker.internal:0' -v '/tmp/.X11-unix:/tmp/.X11-unix' --privileged ghcr.io/ledgerhq/ledger-app-builder/ledger-app-dev-tools cd /apps/app-starknet pip install -r tests/requirements.txt pytest tests/ --tb=short -v --device {nanosp | nanox | stax | flex} @@ -18,7 +18,11 @@ pytest tests/ --tb=short -v --device {nanosp | nanox | stax | flex} From the Docker container, you can also run the app directly with the [Speculos](https://github.com/LedgerHQ/speculos) emulator. For instance, for Nano S+: ``` -speculos -m nanosp --apdu-port 9999 --api-port 5001 target/nanosplus/release/starknet +speculos -m nanosp --apdu-port 9999 --api-port 5001 --display headless target/nanosplus/release/starknet +``` +or for Stax: +``` +speculos -m stax --apdu-port 9999 --api-port 5001 target/stax/release/starknet ``` # Device @@ -28,5 +32,5 @@ ledgerctl install -f app_nanosplus.json ``` Use [ledgercomm](https://github.com/LedgerHQ/ledgercomm) to send APDU e.g : ``` -ledgercomm-send --hid file test/sign.apdu +ledgercomm-send --hid file tools/apdu-generator/apdu_samples/get_pub_key_confirm.dat ``` \ No newline at end of file diff --git a/ledger_app.toml b/ledger_app.toml index 557d555..d96147e 100644 --- a/ledger_app.toml +++ b/ledger_app.toml @@ -1,5 +1,5 @@ [app] -build_directory = "./" +build_directory = "starknet/" sdk = "Rust" devices = ["nanox", "nanos+", "stax", "flex"] diff --git a/scripts.txt b/scripts.txt deleted file mode 100644 index a5e6d3e..0000000 --- a/scripts.txt +++ /dev/null @@ -1,6 +0,0 @@ -speculos -m nanosp --apdu-port 9999 --api-port 5001 --display headless target/nanosplus/release/starknet - -speculos -m stax --apdu-port 9999 --api-port 5001 target/stax/release/starknet - -docker run --rm -it -v "$(pwd -P):/apps" --publish 5001:5001 --publish 9999:9999 -e DISPLAY='host.docker.internal:0' -v '/tmp/.X11-unix:/tmp/.X11-unix' --privileged ghcr.io/ledgerhq/ledger-app-builder/ledger-app-dev-tools - diff --git a/src/context.rs b/src/context.rs deleted file mode 100644 index 32c171f..0000000 --- a/src/context.rs +++ /dev/null @@ -1,212 +0,0 @@ -#[derive(Debug, Copy, Clone)] -pub struct FieldElement { - pub value: [u8; 32], -} - -impl FieldElement { - pub const INVOKE: FieldElement = FieldElement { - value: [ - 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, 0x69, 0x6e, - 0x76, 0x6f, 0x6b, 0x65, - ], - }; - - pub const ZERO: FieldElement = FieldElement { value: [0u8; 32] }; - - pub fn new() -> Self { - Self { value: [0u8; 32] } - } - - pub fn clear(&mut self) { - self.value.fill(0); - } -} - -impl Default for FieldElement { - fn default() -> Self { - Self::new() - } -} - -impl From<&[u8]> for FieldElement { - fn from(data: &[u8]) -> Self { - let mut value: [u8; 32] = [0; 32]; - value.copy_from_slice(data); - Self { value } - } -} - -impl From for FieldElement { - fn from(data: u8) -> Self { - let mut f = FieldElement::new(); - f.value[31] = data; - f - } -} - -impl From for u8 { - fn from(fe: FieldElement) -> u8 { - fe.value[31] - } -} - -#[derive(Debug, Copy, Clone)] -pub struct CallArray { - pub to: FieldElement, - pub entry_point_length: u8, - pub entry_point: [u8; 32], - pub selector: FieldElement, - pub data_offset: FieldElement, - pub data_len: FieldElement, -} - -impl CallArray { - pub fn new() -> Self { - Self { - to: FieldElement::new(), - entry_point_length: 0, - entry_point: [0u8; 32], - selector: FieldElement::new(), - data_offset: FieldElement::new(), - data_len: FieldElement::new(), - } - } - - pub fn clear(&mut self) { - self.to.clear(); - self.entry_point_length = 0; - self.entry_point.fill(0); - self.selector.clear(); - self.data_offset.clear(); - self.data_len.clear(); - } -} - -/// Maximum numbers of calls in a multicall Tx (out of memory) -/// NanoS = 3 -/// NanoS+ = 10 (maybe more ?) -const MAX_TX_CALLS: usize = 3; - -pub struct CallData { - pub call_array_len: FieldElement, - pub calls: [CallArray; MAX_TX_CALLS], - pub calldata_len: FieldElement, -} - -impl CallData { - pub fn new() -> Self { - Self { - call_array_len: FieldElement::new(), - calls: [CallArray::new(); MAX_TX_CALLS], - calldata_len: FieldElement::new(), - } - } - - pub fn clear(&mut self) { - self.call_array_len.clear(); - for i in 1..self.calls.len() { - self.calls[i].clear(); - } - self.calldata_len.clear(); - } -} - -pub struct Transaction { - pub sender_address: FieldElement, - pub calldata: CallData, - pub max_fee: FieldElement, - pub nonce: FieldElement, - pub version: FieldElement, - pub chain_id: FieldElement, -} - -impl Transaction { - pub fn new() -> Self { - Self { - sender_address: FieldElement::new(), - calldata: CallData::new(), - max_fee: FieldElement::new(), - nonce: FieldElement::new(), - version: FieldElement::new(), - chain_id: FieldElement::new(), - } - } - - pub fn clear(&mut self) { - self.sender_address.clear(); - self.calldata.clear(); - self.max_fee.clear(); - self.nonce.clear(); - self.version.clear(); - self.chain_id.clear(); - } -} - -pub enum RequestType { - Unknown, - GetPubkey, - SignHash, -} - -pub struct HashInfo { - /// message hash digest (Pedersen) - pub m_hash: FieldElement, - /// calldata_hash - pub calldata_hash: FieldElement, - /// signature r - pub r: [u8; 32], - /// signature s - pub s: [u8; 32], - /// parity of y-coordinate of R in ECDSA signature - pub v: u8, -} - -impl HashInfo { - pub fn new() -> Self { - Self { - m_hash: FieldElement::new(), - calldata_hash: FieldElement::new(), - r: [0u8; 32], - s: [0u8; 32], - v: 0, - } - } - - pub fn clear(&mut self) { - self.m_hash.clear(); - self.calldata_hash.clear(); - self.r.fill(0); - self.s.fill(0); - self.v = 0; - } -} - -pub struct Ctx { - //state_e state; /// state of the context - pub req_type: RequestType, - pub tx_info: Transaction, - pub hash_info: HashInfo, - pub bip32_path: [u32; 6], - pub bip32_path_len: u8, -} - -impl Ctx { - pub fn new() -> Self { - Self { - tx_info: Transaction::new(), - hash_info: HashInfo::new(), - req_type: RequestType::Unknown, - bip32_path: [0u32; 6], - bip32_path_len: 0, - } - } - - pub fn clear(&mut self) { - self.req_type = RequestType::Unknown; - self.bip32_path.fill(0); - self.bip32_path_len = 0; - self.tx_info.clear(); - self.hash_info.clear(); - } -} diff --git a/src/display.rs b/src/display.rs deleted file mode 100644 index 1892ff7..0000000 --- a/src/display.rs +++ /dev/null @@ -1,176 +0,0 @@ -use include_gif::include_gif; -use ledger_device_sdk::io::{Comm, Event}; - -#[cfg(not(any(target_os = "stax", target_os = "flex")))] -use ledger_device_sdk::ui::{ - bitmaps::{Glyph, BACK, CERTIFICATE, CROSSMARK, DASHBOARD_X, EYE, VALIDATE_14}, - gadgets::{EventOrPageIndex, Field, MultiFieldReview, MultiPageMenu, Page}, -}; - -#[cfg(any(target_os = "stax", target_os = "flex"))] -use ledger_device_sdk::nbgl::{ - Field, NbglAddressReview, NbglGlyph, NbglHomeAndSettings, NbglReview, -}; - -use crate::Ins; - -/// This is the UI flow for signing, composed of a scroller -/// to read the incoming message, a panel that requests user -/// validation, and an exit message. -pub fn sign_ui(message: &[u8]) -> bool { - let mut hash_hex = [0u8; 64]; - hex::encode_to_slice(&message[0..32], &mut hash_hex[0..]).unwrap(); - let hash = core::str::from_utf8_mut(&mut hash_hex[..63]).unwrap(); - hash.make_ascii_uppercase(); - - #[cfg(not(any(target_os = "stax", target_os = "flex")))] - { - /*let hash = core::str::from_utf8_mut(&mut hash_hex[..63]).unwrap(); - hash.make_ascii_uppercase();*/ - - let my_field = [Field { - name: "Hash", - value: hash, - }]; - - let my_review = MultiFieldReview::new( - &my_field, - &["Confirm Hash to sign"], - Some(&EYE), - "Approve", - Some(&VALIDATE_14), - "Reject", - Some(&CROSSMARK), - ); - - my_review.show() - } - - #[cfg(any(target_os = "stax", target_os = "flex"))] - { - /*hash_hex[63] = 0u8; - let hash = core::str::from_utf8_mut(&mut hash_hex[..64]).unwrap(); - hash.make_ascii_uppercase();*/ - - // Load glyph from 64x64 4bpp gif file with include_gif macro. Creates an NBGL compatible glyph. - const APP_ICON: NbglGlyph = - NbglGlyph::from_include(include_gif!("starknet_64x64.gif", NBGL)); - // Display Tx Review screen. - let my_fields = [Field { - name: "Transaction Hash", - value: hash, - }]; - - let mut review = NbglReview::new() - .titles("Review", "Transaction Hash", "Sign Transaction") - .glyph(&APP_ICON); - review.show(&my_fields) - } -} - -pub fn pkey_ui(key: &[u8]) -> bool { - let mut pk_hex = [0u8; 64]; - hex::encode_to_slice(&key[1..33], &mut pk_hex[0..]).unwrap(); - let m = core::str::from_utf8_mut(&mut pk_hex).unwrap(); - m[0..].make_ascii_uppercase(); - - #[cfg(not(any(target_os = "stax", target_os = "flex")))] - { - /*let mut pk_hex = [0u8; 64]; - hex::encode_to_slice(&key[1..33], &mut pk_hex[0..]).unwrap(); - let m = core::str::from_utf8_mut(&mut pk_hex).unwrap(); - m[0..].make_ascii_uppercase();*/ - - let my_field = [Field { - name: "Public Key", - value: m, - }]; - - let my_review = MultiFieldReview::new( - &my_field, - &["Confirm Public Key"], - Some(&EYE), - "Approve", - Some(&VALIDATE_14), - "Reject", - Some(&CROSSMARK), - ); - - my_review.show() - } - #[cfg(any(target_os = "stax", target_os = "flex"))] - { - /*let mut pk_hex = [0u8; 65]; - hex::encode_to_slice(&key[1..33], &mut pk_hex[0..64]).unwrap(); - pk_hex[64] = 0u8; - let m = core::str::from_utf8_mut(&mut pk_hex).unwrap(); - m[0..].make_ascii_uppercase();*/ - - // Load glyph from 64x64 4bpp gif file with include_gif macro. Creates an NBGL compatible glyph. - const APP_ICON: NbglGlyph = - NbglGlyph::from_include(include_gif!("starknet_64x64.gif", NBGL)); - NbglAddressReview::new() - .glyph(&APP_ICON) - .verify_str("Verify public key") - .show(m) - } -} - -#[cfg(not(any(target_os = "stax", target_os = "flex")))] -fn about_ui(comm: &mut Comm) -> Event { - #[cfg(not(any(target_os = "stax", target_os = "flex")))] - { - let pages = [ - &Page::from((["Starknet", "(c) 2024 Ledger"], true)), - &Page::from(("Back", &BACK)), - ]; - loop { - match MultiPageMenu::new(comm, &pages).show() { - EventOrPageIndex::Event(e) => return e, - EventOrPageIndex::Index(1) => return main_ui(comm), - EventOrPageIndex::Index(_) => (), - } - } - } -} - -#[cfg(not(any(target_os = "stax", target_os = "flex")))] -pub fn main_ui(comm: &mut Comm) -> Event { - const APP_ICON: Glyph = Glyph::from_include(include_gif!("starknet_small.gif")); - let pages = [ - // The from trait allows to create different styles of pages - // without having to use the new() function. - &Page::from((["Starknet", "is ready"], &APP_ICON)), - &Page::from((["Version", env!("CARGO_PKG_VERSION")], true)), - &Page::from(("About", &CERTIFICATE)), - &Page::from(("Quit", &DASHBOARD_X)), - ]; - loop { - match MultiPageMenu::new(comm, &pages).show() { - EventOrPageIndex::Event(e) => return e, - EventOrPageIndex::Index(2) => return about_ui(comm), - EventOrPageIndex::Index(3) => ledger_device_sdk::exit_app(0), - EventOrPageIndex::Index(_) => (), - } - } -} - -#[cfg(any(target_os = "stax", target_os = "flex"))] -pub fn main_ui(_comm: &mut Comm) -> Event { - // Load glyph from 64x64 4bpp gif file with include_gif macro. Creates an NBGL compatible glyph. - const APP_ICON: NbglGlyph = NbglGlyph::from_include(include_gif!("starknet_64x64.gif", NBGL)); - - // Display the home screen. - NbglHomeAndSettings::new( - //concat!("Starknet", "\0"), - //concat!(env!("CARGO_PKG_VERSION"), "\0"), - //concat!(env!("CARGO_PKG_AUTHORS"), "\0"), - ) - .glyph(&APP_ICON) - .infos( - "Starknet", - env!("CARGO_PKG_VERSION"), - env!("CARGO_PKG_AUTHORS"), - ) - .show() -} diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index 9003f1b..0000000 --- a/src/main.rs +++ /dev/null @@ -1,146 +0,0 @@ -#![no_std] -#![no_main] - -mod context; -mod crypto; -mod display; - -use crypto::{get_pubkey, set_derivation_path, sign_hash}; - -use context::{Ctx, RequestType}; - -use ledger_device_sdk::io; - -ledger_device_sdk::set_panic!(ledger_device_sdk::exiting_panic); - -#[cfg(any(target_os = "stax", target_os = "flex"))] -use ledger_device_sdk::nbgl::init_comm; - -#[no_mangle] -extern "C" fn sample_main() { - let mut comm = io::Comm::new(); - - // Initialize reference to Comm instance for NBGL - // API calls. - #[cfg(any(target_os = "stax", target_os = "flex"))] - init_comm(&mut comm); - - let mut ctx: Ctx = Ctx::new(); - - loop { - // Wait for either a specific button push to exit the app - // or an APDU command - if let io::Event::Command(ins) = display::main_ui(&mut comm) { - match handle_apdu(&mut comm, ins, &mut ctx) { - Ok(()) => comm.reply_ok(), - Err(sw) => comm.reply(sw), - } - } - } -} - -#[repr(u8)] -enum Ins { - GetVersion, - GetPubkey { display: bool }, - SignHash, -} - -impl TryFrom for Ins { - type Error = io::StatusWords; - fn try_from(header: io::ApduHeader) -> Result { - match (header.ins, header.p1, header.p2) { - (0, 0, 0) => Ok(Ins::GetVersion), - (0, _, _) => Err(io::StatusWords::BadP1P2), - (1, 0 | 1, 0) => Ok(Ins::GetPubkey { - display: header.p1 != 0, - }), - (1, _, _) => Err(io::StatusWords::BadP1P2), - (2, _, _) => Ok(Ins::SignHash), - (_, _, _) => Err(io::StatusWords::BadIns), - } - } -} - -use ledger_device_sdk::io::Reply; - -fn handle_apdu(comm: &mut io::Comm, ins: Ins, ctx: &mut Ctx) -> Result<(), Reply> { - if comm.rx == 0 { - return Err(io::StatusWords::NothingReceived.into()); - } - - let apdu_header = comm.get_apdu_metadata(); - if apdu_header.cla != 0x5A { - return Err(io::StatusWords::BadCla.into()); - } - - match ins { - Ins::GetVersion => { - let version_major = env!("CARGO_PKG_VERSION_MAJOR").parse::().unwrap(); - let version_minor = env!("CARGO_PKG_VERSION_MINOR").parse::().unwrap(); - let version_patch = env!("CARGO_PKG_VERSION_PATCH").parse::().unwrap(); - comm.append([version_major, version_minor, version_patch].as_slice()); - } - Ins::GetPubkey { display } => { - ctx.clear(); - ctx.req_type = RequestType::GetPubkey; - - let mut data = comm.get_data()?; - - let res = set_derivation_path(&mut data, ctx); - match res { - Err(e) => { - return Err(e.into()); - } - Ok(()) => { - let pub_key = get_pubkey(ctx); - match pub_key { - Err(e) => { - return Err(Reply::from(e)); - } - Ok(key) => { - let ret = match display { - false => true, - true => display::pkey_ui(key.as_ref()), - }; - if ret { - comm.append(key.as_ref()); - } else { - return Err(io::StatusWords::UserCancelled.into()); - } - } - } - } - } - } - Ins::SignHash => { - let p1 = apdu_header.p1; - let mut data = comm.get_data()?; - - match p1 { - 0 => { - ctx.clear(); - ctx.req_type = RequestType::SignHash; - - set_derivation_path(&mut data, ctx)?; - } - _ => { - ctx.hash_info.m_hash = data.into(); - match display::sign_ui(data) { - true => { - sign_hash(ctx).unwrap(); - } - false => { - return Err(io::StatusWords::UserCancelled.into()); - } - } - comm.append([0x41].as_slice()); - comm.append(ctx.hash_info.r.as_ref()); - comm.append(ctx.hash_info.s.as_ref()); - comm.append([ctx.hash_info.v].as_slice()); - } - } - } - } - Ok(()) -} diff --git a/.cargo/config.toml b/starknet/.cargo/config.toml similarity index 100% rename from .cargo/config.toml rename to starknet/.cargo/config.toml diff --git a/starknet/Cargo.toml b/starknet/Cargo.toml new file mode 100644 index 0000000..a2648da --- /dev/null +++ b/starknet/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "starknet" +version = "2.0.0" +edition = "2021" +authors = ["Ledger"] + +[dependencies] +ledger_device_sdk = "1.15.2" +ledger_secure_sdk_sys = { version = "1.4.6", features = ["heap"]} +include_gif = "1.2.0" +hex = { version = "0.4", default-features = false, features = ["alloc"]} +num-bigint = { version = "0.4", default-features = false } + +[features] +default = [] +poseidon = [] +signhash = [] + +[package.metadata.ledger] +curve = ["secp256k1"] +path = ["2645'"] +name = "Starknet" +flags = "0" + +[package.metadata.ledger.nanox] +icon = "starknet_small.gif" + +[package.metadata.ledger.nanosplus] +icon = "starknet_small.gif" + +[package.metadata.ledger.stax] +icon = "starknet_32x32.gif" + +[package.metadata.ledger.flex] +icon = "starknet_40x40.gif" + diff --git a/starknet/src/context.rs b/starknet/src/context.rs new file mode 100644 index 0000000..07b7931 --- /dev/null +++ b/starknet/src/context.rs @@ -0,0 +1,110 @@ +use crate::types::FieldElement; + +extern crate alloc; +use alloc::vec::Vec; + +#[derive(Default, Debug)] +pub struct Call { + pub to: FieldElement, + pub selector: FieldElement, + pub calldata: Vec, +} + +impl Call { + pub fn reset(&mut self) { + self.to.clear(); + self.selector.clear(); + for c in self.calldata.iter_mut() { + c.clear(); + } + } +} + +#[derive(Default, Debug)] +pub struct Transaction { + pub sender_address: FieldElement, + pub tip: FieldElement, + pub l1_gas_bounds: FieldElement, + pub l2_gas_bounds: FieldElement, + pub paymaster_data: Vec, + pub chain_id: FieldElement, + pub nonce: FieldElement, + pub data_availability_mode: FieldElement, + pub account_deployment_data: Vec, + pub calls: Vec, +} + +impl Transaction { + pub fn reset(&mut self) { + self.sender_address.clear(); + self.tip.clear(); + self.l1_gas_bounds.clear(); + self.l2_gas_bounds.clear(); + self.chain_id.clear(); + self.nonce.clear(); + self.data_availability_mode.clear(); + for c in self.paymaster_data.iter_mut() { + c.clear(); + } + for c in self.account_deployment_data.iter_mut() { + c.clear(); + } + for c in self.calls.iter_mut() { + c.reset(); + } + } +} + +pub enum RequestType { + Unknown, + GetPubkey, + #[cfg(feature = "signhash")] + SignHash, + SignTx, +} + +#[derive(Default, Debug)] +pub struct Hash { + /// tx hash digest (Poseidon) + pub m_hash: FieldElement, + /// signature r + pub r: [u8; 32], + /// signature s + pub s: [u8; 32], + /// parity of y-coordinate of R in ECDSA signature + pub v: u8, +} + +impl Hash { + pub fn reset(&mut self) { + self.m_hash.clear(); + self.r.fill(0); + self.s.fill(0); + self.v = 0; + } +} + +pub struct Ctx { + pub req_type: RequestType, + pub tx: Transaction, + pub hash: Hash, + pub bip32_path: [u32; 6], +} + +impl Ctx { + pub fn new() -> Self { + Self { + tx: Transaction::default(), + hash: Hash::default(), + req_type: RequestType::Unknown, + bip32_path: [0u32; 6], + } + } + + pub fn reset(&mut self) { + self.req_type = RequestType::Unknown; + self.bip32_path.fill(0); + self.tx.reset(); + self.hash.reset(); + } +} diff --git a/src/crypto.rs b/starknet/src/crypto.rs similarity index 74% rename from src/crypto.rs rename to starknet/src/crypto.rs index c0d6512..afb7f9b 100644 --- a/src/crypto.rs +++ b/starknet/src/crypto.rs @@ -1,7 +1,10 @@ use ledger_device_sdk::ecc::{ECPublicKey, SeedDerive, Stark256}; use ledger_device_sdk::io::{Reply, SyscallError}; -use crate::context::Ctx; +pub mod poseidon; + +use crate::context::{Ctx, Transaction}; +use crate::types::FieldElement; /// Length in bytes of an EIP-2645 derivation path (without m), e.g m/2645'/1195502025'/1148870696'/0'/0'/0 /// with every step encoded with 4 bytes (total length = 6 x 4 = 24 bytes) @@ -24,13 +27,15 @@ impl From for Reply { /// Helper function that signs with ECDSA in deterministic nonce pub fn sign_hash(ctx: &mut Ctx) -> Result<(), CryptoError> { + poseidon::poseidon_shift(&mut ctx.hash.m_hash); + match Stark256::derive_from_path(ctx.bip32_path.as_ref()) - .deterministic_sign(ctx.hash_info.m_hash.value.as_ref()) + .deterministic_sign(ctx.hash.m_hash.value.as_ref()) { Ok(s) => { let der = s.0; - convert_der_to_rs(&der[..], &mut ctx.hash_info.r, &mut ctx.hash_info.s).unwrap(); - ctx.hash_info.v = s.2 as u8; + convert_der_to_rs(&der[..], &mut ctx.hash.r, &mut ctx.hash.s).unwrap(); + ctx.hash.v = s.2 as u8; Ok(()) } Err(_) => Err(CryptoError::Sign), @@ -168,3 +173,44 @@ fn convert_der_to_rs( Ok(()) } + +pub fn tx_hash(tx: &Transaction) -> FieldElement { + let mut hasher = poseidon::PoseidonHasher::new(); + /* "invoke" */ + hasher.update(FieldElement::INVOKE); + /* version = 3 */ + hasher.update(FieldElement::from(3u8)); + /* sender_address */ + hasher.update(tx.sender_address); + /* h(tip, l1_gas_bounds, l2_gas_bounds) */ + let fee_hash = + poseidon::PoseidonStark252::hash_many(&[tx.tip, tx.l1_gas_bounds, tx.l2_gas_bounds]); + hasher.update(fee_hash); + /* h(paymaster_data) */ + let paymaster_hash = poseidon::PoseidonStark252::hash_many(&tx.paymaster_data); + hasher.update(paymaster_hash); + /* chain_id */ + hasher.update(tx.chain_id); + /* nonce */ + hasher.update(tx.nonce); + /* data_availability_modes */ + hasher.update(tx.data_availability_mode); + /* h(account_deployment_data) */ + let accound_deployment_data_hash = + poseidon::PoseidonStark252::hash_many(&tx.account_deployment_data); + hasher.update(accound_deployment_data_hash); + /* h(calldata) */ + let mut hasher_calldata = poseidon::PoseidonHasher::new(); + hasher_calldata.update(FieldElement::from(tx.calls.len() as u8)); + tx.calls.iter().for_each(|c| { + hasher_calldata.update(c.to); + hasher_calldata.update(c.selector); + hasher_calldata.update(FieldElement::from(c.calldata.len() as u8)); + c.calldata.iter().for_each(|d| hasher_calldata.update(*d)); + }); + let hash_calldata = hasher_calldata.finalize(); + + hasher.update(hash_calldata); + + hasher.finalize() +} diff --git a/starknet/src/crypto/poseidon.rs b/starknet/src/crypto/poseidon.rs new file mode 100644 index 0000000..0349d6e --- /dev/null +++ b/starknet/src/crypto/poseidon.rs @@ -0,0 +1,500 @@ +// Code ported from the implementation here: +// https://github.com/lambdaclass/lambdaworks/blob/dfe4f0eaf9b0d62d85e881c87622c37f1e1b2ea2/crypto/src/hash/poseidon/mod.rs + +use crate::types::FieldElement; +extern crate alloc; +use crate::types::P; +use alloc::borrow::ToOwned; +use alloc::vec::Vec; +use ledger_secure_sdk_sys::*; + +const RATE: usize = 2; +const CAPACITY: usize = 1; +//const ALPHA: u32 = 3; +const N_FULL_ROUNDS: usize = 8; +const N_PARTIAL_ROUNDS: usize = 83; +const STATE_SIZE: usize = RATE + CAPACITY; + +//const N_ROUND_CONSTANTS_ROWS: usize = 91; +const N_ROUND_CONSTANTS_COLS: usize = 3; +// The following constants are used for an optimized version of Poseidon hash, as suggested in Appendix B from +// the Poseidon paper (available at https://eprint.iacr.org/2019/458.pdf). +// In partial rounds, instead of adding constants to all the state, we add a constant just to the state +// to which the S box is applied (non-linear). The constants for the other positions are "moved forward" and +// added at the end. +const ROUND_CONSTANTS: [&str; 107] = [ + "06861759ea556a2339dd92f9562a30b9e58e2ad98109ae4780b7fd8eac77fe6f", + "03827681995d5af9ffc8397a3d00425a3da43f76abf28a64e4ab1a22f27508c4", + "03a3956d2fad44d0e7f760a2277dc7cb2cac75dc279b2d687a0dbe17704a8309", + "0626c47a7d421fe1f13c4282214aa759291c78f926a2d1c6882031afe67ef4cd", + "078985f8e16505035bd6df5518cfd41f2d327fcc948d772cadfe17baca05d6a6", + "05427f10867514a3204c659875341243c6e26a68b456dc1d142dcf34341696ff", + "05af083f36e4c729454361733f0883c5847cd2c5d9d4cb8b0465e60edce699d7", + "07d71701bde3d06d54fa3f74f7b352a52d3975f92ff84b1ac77e709bfd388882", + "0603da06882019009c26f8a6320a1c5eac1b64f699ffea44e39584467a6b1d3e", + "04332a6f6bde2f288e79ce13f47ad1cdeebd8870fd13a36b613b9721f6453a5d", + "053d0ebf61664c685310a04c4dec2e7e4b9a813aaeff60d6c9e8caeb5cba78e7", + "05346a68894845835ae5ebcb88028d2a6c82f99f928494ee1bfc2d15eaabfebc", + "04B085EB1DF4258C3453CC97445954BF3433B6AB9DD5A99592864C00F54A3F9A", + "0731CFD19D508285965F12A079B2A169FDFE0A8E610E6F2D5CA5D7B0961F6D96", + "0217D08B5339852BCC6F7A774936B3E72ECD9E1F9A73D743F8079C1E3587EEAA", + "000C935DD633B0FD63599B13C850DAB3CB966BA510C81B20959E267008518C6E", + "052AF8D378DD6772EE187ED23F79A7D98CF5A0A387103971467FE940E7B8B2BE", + "0294851C98B2682F1EC9918B9F12FCCEAA6E28A7B79B2E506362CDA595F8AB75", + "011B59990BACC280824D1021418D4F589DA8C30063471494C204B169AB086064", + "04B4DF56E3D7753F91960D59AE099B9BEB2CE690E6BBDCD0B599D49CEB2ACD6A", + "005EECFA15A757DC3ECAE9FBD8FF06E466243534F30629FC5F1CF09EB5161AC4", + "0680BFDD8B9680E04659227634A1EC5282E5A7CEF81B15677F8448BDA4279059", + "01D0BF8FAB0A1A7A14E2930794F7A3065C17E10B1CEDD791B8877D97ACD85053", + "02C2C8C79F808ACE54BA207053C0D412C0FC11A610F14C48876701A37E32F464", + "0354EC9ED01D20EC52AAE19A9B858D3474D8234C11AD7BCE630AD56C54AFA562", + "030DF20FCF6427BAC38BB5D1A42287F4E4136AC5892340E994E6EA28DEEC1E55", + "0528CF329C64E7EE3040BAFBDEFF61E241D99B424091E31472EDA296FC9C6778", + "040416F24F623534634789660DF5435EBF0C3E0C69E6C5B5FF6E757930BD1960", + "00380C8F936E2ED9FD488AE3BAC7DCE315BA21B11E88339CD5444435CCC9EA38", + "01CC4F5D5603D176F1A8E344392EFD2D03AD0541832829D245E0E2291F255B75", + "05728917AF5DA91F9539310D99F5D142E011D6C8E015EA5423C502AA99C09752", + "00EFB450A9E86E1A46E295A348F0F23590925107D17C56D7C788FECC17219AA1", + "02020D74D36C421AE1A025616B342D0784B8FCD977DE6C53A6C26693774DCA99", + "07CFB309B75FD3BF2705558AE511DC82335050969F4BF84FA2B7B4F583989287", + "04651E48B2E9349A5365E009ECE626809D7B7D02A617EB98C785A784812D75E9", + "00D77627B270F65122D0269719DA923CCAE822D9AAD0F0947A3B5C8F71C0DCC7", + "0199AD3D641B54C4D571B3FE37773A8B82B003377F0DD8B7D3B7758C32908EA8", + "044F33640A8ECFD3973E2E9172A7333482B2D297BE2DA289319E72D137CDFE6E", + "07E4ADF9894D964189D00A02DCF1E6BE7F801234F5216EAB6B6F366B6701ABF7", + "03641FA5B3C90452F5FF808F8A9817EDA7C6AECFB5471DFDCA559FB4E711EE90", + "03DE5729EFD2FCBD897A49A78FA923FC306DF32E6E2F0E02D0EEE2C2CC3F3533", + "062691891A3FC1E27F622966CA0BE20C06563500C8F06C9BDB77BD2882D6C994", + "06608D3BF11C18E4688739F72205763D1590CC4F9885AE1D86E96E0604BAA0BE", + "011C9C9B39CAC71E3419726CE779116D07249F51CBDDA4FD98C25CBBF593A316", + "061E23B58203269CAEF0850F74DA27B9748E3312EA40C6844DD68C557C462AD7", + "04182CD9AB1D9488F870A572010BC2A3D9878440B25951E4CE010855CF83BDC8", + "0520FE6C4A096793F9055E6823116D15F1DF2FE89D306F9965F6A59F4F3ECB71", + "0346B2B2D6E5810129E093093DCD3DFA99ED6D71F47723EA3FBE4D4E2FD4AFA1", + "01359CA923E7F1448EC1DD2A3684BEE4E8B682C8E8E973ACEA72877CE9F7E6CF", + "047C655F55CF307800DFEFDAD24DE86FDE9DEADAB145A1B392420F37B95D9675", + "04AB291F16555FA8A968CD7C9C285A9598EFD925F2D58B7AA38AD87DCA8441A8", + "039F409C7C782101223D1F6F7D86C21A22C44EF959510E392C9C7C5D17C629C5", + "044BE36B782F882AD86EECB0CD6BEB02E1A2F9FB5587A3BABFACEAD0CAFB6052", + "050A1DFDE9B504AD2906DB6EB5B507203CD1CEB394C52CE7107679A53A0D538B", + "05C753C14DA89E287B181C0DD11AC6C3680BDD7F1017DAE083E7AEBBEAB183AB", + "02CF6306ED32232106C8015A3B180F386EEE93E15F7B4F4FA57746525FC0520C", + "02C2014634D52E27420873CF347429091DFC6380689BD4F54D7D8E502C1C3A09", + "03CFB9C5BD93E02B2FDACDE2058E33E5975C446345F010D850FC09CDF86ED8A1", + "0363FA71A383CF3897933F1411FC5F806E311E84F72CB50A9EA4E1281F6B0299", + "0728199657067EE16947B3FC76271676B4901B2A3686CFFEBCB960DA91B05DF8", + "03FDFBD47D27F3D34F0723B728E8921DC9BDE34A9872DF5A652A078D7E4EE021", + "07F241379440CACD7DC0EFBE7858EB7DE53CC02CA7D24197945C453398EFF449", + "05B2E8771EA9A0004E3BF056F3727797CBB457A27574D5F104354E52A5C25F0B", + "00A8DDBCE708DE44A7E0B3B0333146E1E910245BE6BF822EA057A081BDA2E23E", + "02D521E0DACA24E431AA47CD90A0F551C12270E533835613EDCE2E19AA9B0F61", + "06CDBC0F2AA54D2CF7D5AC3B93F855AF03EEF7B07AAEE00341A6266C30E08AE6", + "03DD96A17111EC8F4C5DA3AD6794C0961CEEE452CBE92C7A0941112B36ED9BF3", + "05EAFB1EDEEDC5C07AC07FDD06159344A2CFB92196A65D9EC0C5E732C36687DC", + "04AB038D7B09EDA9324577B260FEAEBDBCEC5A7B7C7F449B312CFCD065C207E6", + "04CA71981E4DF6B505D2B0D94E235608463C58052570F68E495FC80C7FDEF220", + "06DEE9C6DA4617E32AA419899C8EA8137E9B59D7E2759FFE573C15B77E413D2F", + "058F9E60B34DDAB84DCBE2396065A4305B4A795A4770E4541E625D0460C6F186", + "047B7B4A802A10C1E6C9C735DB6C34042D290906F274BEA8FCECEF17FC9AF632", + "01849BCDB9AD7171096ECC936A186774084A074BE0BFC0FBB9463A06A2BD430C", + "041870FBE04438348AF5767BDDAECD8AEA3B49B4217547DEC4D699B1466736CC", + "0226C04E598076A9FA02AA64557DAF28C0EC42E3D4DA68D1965029D284738B07", + "01F0E971F0485A5B42EB92D6655C3DDB475CEC4371F269A95335B2A7D6DAC0FB", + "009F31CC2907DCCBF994D35AA47EE3F4EBDF3703F795047A7B40DD3926431563", + "04B40CCE78F3B641E31CE4DF58CE5A42C22CFBC198C84451FFE8CCA4C64BD7D2", + "0191660489E4BD8A3E4563173DE4A226F3AC736962FDFB70F72CB93CE50F8B9F", + "018C0919618DB971F74EB01F293F2DAEA814B475103373DC7ED8DD4C7B467410", + "035B60253848530E845C8753121577D0EF37002E941C3DC1FB240BD57EADC803", + "01AE99DB1575AE91C8B43A9F71A5F362581AD9B413D97FA6FD029134957451D5", + "03E6E1D0F3F8A0F728148EBCBD5D7D337D7CB8FEB58A37D2D1DFB357E172647B", + "018BC36DFFA8F96A659E1A171B55D2706EE3E9AD619E16F5C38DD1F4A209B8F3", + "02C7A3EF1AFB6A302B54AFC3A107FF9199A16EFE9A1CC3AB83FA5B64893DE4ED", + "053A7BD889BED07BF5E27DD8E92F6AE85E4FE4E84B0C6DDE9856E94469DE4BD7", + "04D383FF7FFC6318FDA704ACA35995F86BEC5A02CE9A0BF9D3CC0CC2F03CCEA9", + "04667B6762FB8AD53D07EF7E8A65B21CA96E0B3503037710D1292519C326F5CD", + "002CC8B43E75CF0B42A93C39EA98BCD46055DCCC9589F02EB7FB536422E5921F", + "06B32EE98680871D38751447BFD76086BA4DF0E7BE59C55F4B2CE25582BF9C60", + "03E907927C7182FAAA3B3C81358B82E734EFAC1F0609F0862D635CB1387102A3", + "03F3A5057B3A08975F0253728E512AF78D2F437973F6A93793EA5E8424FBC6EA", + "014B491D73724779F8AA74B3FD8AA5821C21E1017224726A7A946BB6CA68D8F5", + "05C8278C7BBFC30AE7F60E514FE3B9367ACA84C54AD1373861695EA4ABB814EF", + "064851937F9836EE5A08A7DDE65E44B467018A82BA3BF99BBA0B4502755C8074", + "06A9AC84251294769ECA450FFB52B441882BE77CB85F422FF9EA5E73F1D971DC", + "037EC35B710B0D04C9A2B71F2F7BD098C6A81D991D27F0FC1884F5CA545064DE", + "005334f75b052c0235119816883040da72c6d0a61538bdfff46d6a242bfeb7a1", + "05d0af4fcbd9e056c1020cca9d871ae68f80ee4af2ec6547cd49d6dca50aa431", + "030131bce2fba5694114a19c46d24e00b4699dc00f1d53ba5ab99537901b1e65", + "05646a95a7c1ae86b34c0750ed2e641c538f93f13161be3c4957660f2e788965", + "04b9f291d7b430c79fac36230a11f43e78581f5259692b52c90df47b7d4ec01a", + "05006d393d3480f41a98f19127072dc83e00becf6ceb4d73d890e74abae01a13", + "062c9d42199f3b260e7cb8a115143106acf4f702e6b346fd202dc3b26a679d80", + "051274d092db5099f180b1a8a13b7f2c7606836eabd8af54bf1d9ac2dc5717a5", + "061fc552b8eb75e17ad0fb7aaa4ca528f415e14f0d9cdbed861a8db0bfff0c5b", +]; + +#[derive(Clone)] +pub struct PoseidonStark252; + +impl PoseidonStark252 { + pub fn hades_permutation(state: &mut [FieldElement]) { + let mut index = 0; + for _ in 0..N_FULL_ROUNDS / 2 { + Self::full_round(state, index); + index += N_ROUND_CONSTANTS_COLS; + } + Self::partial_round_loop(state, &mut index); + for _ in 0..N_FULL_ROUNDS / 2 { + Self::full_round(state, index); + index += N_ROUND_CONSTANTS_COLS; + } + } + + #[inline] + fn full_round(state: &mut [FieldElement], index: usize) { + unsafe { + let mut bn_s0: cx_bn_t = cx_bn_t::default(); + let mut bn_p: cx_bn_t = cx_bn_t::default(); + let mut bn_res: cx_bn_t = cx_bn_t::default(); + let mut bn_rc: cx_bn_t = cx_bn_t::default(); + let mut bn_e: cx_bn_t = cx_bn_t::default(); + + cx_bn_lock(32, 0); + + cx_bn_alloc(&mut bn_res, 32); + cx_bn_alloc_init(&mut bn_p, 32, P.value.as_ptr(), 32); + cx_bn_alloc_init(&mut bn_e, 32, [3u8; 1].as_ptr(), 1); + cx_bn_alloc(&mut bn_s0, 32); + cx_bn_alloc(&mut bn_rc, 32); + + for (i, value) in state.iter_mut().enumerate() { + /* state[i] = state[i] + ROUND_CONSTANTS[index + i] */ + cx_bn_init(bn_s0, value.value.as_ptr(), 32); + cx_bn_init( + bn_rc, + FieldElement::from(ROUND_CONSTANTS[index + i]) + .value + .as_ptr(), + 32, + ); + cx_bn_mod_add(bn_res, bn_s0, bn_rc, bn_p); + /* state[i] = state[i] * state[i] * state[i] */ + cx_bn_mod_pow_bn(bn_s0, bn_res, bn_e, bn_p); + cx_bn_export(bn_s0, value.value.as_mut_ptr(), 32); + } + + /* Mix */ + let mut bn_s1: cx_bn_t = cx_bn_t::default(); + let mut bn_s2: cx_bn_t = cx_bn_t::default(); + let mut bn_t: cx_bn_t = cx_bn_t::default(); + let mut bn_two: cx_bn_t = cx_bn_t::default(); + let mut bn_three: cx_bn_t = cx_bn_t::default(); + + cx_bn_alloc(&mut bn_t, 32); + cx_bn_init(bn_s0, state[0].value.as_ptr(), 32); + cx_bn_alloc_init(&mut bn_s1, 32, state[1].value.as_ptr(), 32); + cx_bn_alloc_init(&mut bn_s2, 32, state[2].value.as_ptr(), 32); + cx_bn_alloc_init(&mut bn_two, 32, FieldElement::TWO.value.as_ptr(), 32); + cx_bn_alloc_init(&mut bn_three, 32, FieldElement::THREE.value.as_ptr(), 32); + + /* Compute t */ + cx_bn_mod_add(bn_res, bn_s0, bn_s1, bn_p); + cx_bn_mod_add(bn_t, bn_res, bn_s2, bn_p); + + /* Update state */ + /* s0 = t + 2 * s0 */ + cx_bn_mod_mul(bn_res, bn_s0, bn_two, bn_p); + cx_bn_mod_add(bn_s0, bn_t, bn_res, bn_p); + + /* s1 = t - 2 * s1 */ + cx_bn_mod_mul(bn_res, bn_s1, bn_two, bn_p); + cx_bn_mod_sub(bn_s1, bn_t, bn_res, bn_p); + + /* s2 = t - 3 * s2 */ + cx_bn_mod_mul(bn_res, bn_s2, bn_three, bn_p); + cx_bn_mod_sub(bn_s2, bn_t, bn_res, bn_p); + + /* Fix Sandra */ + let mut bn_zero: cx_bn_t = cx_bn_t::default(); + cx_bn_alloc_init(&mut bn_zero, 32, FieldElement::ZERO.value.as_ptr(), 32); + cx_bn_mod_sub(bn_s0, bn_s0, bn_zero, bn_p); + + cx_bn_export(bn_s0, state[0].value.as_mut_ptr(), 32); + cx_bn_export(bn_s1, state[1].value.as_mut_ptr(), 32); + cx_bn_export(bn_s2, state[2].value.as_mut_ptr(), 32); + + cx_bn_unlock(); + } + } + + #[inline] + fn _partial_round(state: &mut [FieldElement], index: usize) { + unsafe { + let mut bn_p: cx_bn_t = cx_bn_t::default(); + let mut bn_res: cx_bn_t = cx_bn_t::default(); + let mut bn_rc: cx_bn_t = cx_bn_t::default(); + let mut bn_e: cx_bn_t = cx_bn_t::default(); + let mut bn_s2: cx_bn_t = cx_bn_t::default(); + + cx_bn_lock(32, 0); + + cx_bn_alloc(&mut bn_res, 32); + + /* s2 = s2 + ROUND_CONSTANTS[index] */ + cx_bn_alloc_init(&mut bn_s2, 32, state[2].value.as_ptr(), 32); + cx_bn_alloc_init(&mut bn_p, 32, P.value.as_ptr(), 32); + cx_bn_alloc_init( + &mut bn_rc, + 32, + FieldElement::from(ROUND_CONSTANTS[index]).value.as_ptr(), + 32, + ); + cx_bn_mod_add(bn_res, bn_s2, bn_rc, bn_p); + + /* s2 = s2 * s2 * s2 */ + cx_bn_alloc_init(&mut bn_e, 32, [3u8; 1].as_ptr(), 1); + cx_bn_mod_pow_bn(bn_s2, bn_res, bn_e, bn_p); + + /**** Mix ****/ + let mut bn_s0: cx_bn_t = cx_bn_t::default(); + let mut bn_s1: cx_bn_t = cx_bn_t::default(); + let mut bn_t: cx_bn_t = cx_bn_t::default(); + let mut bn_two: cx_bn_t = cx_bn_t::default(); + let mut bn_three: cx_bn_t = cx_bn_t::default(); + + cx_bn_alloc(&mut bn_t, 32); + cx_bn_alloc_init(&mut bn_s0, 32, state[0].value.as_ptr(), 32); + cx_bn_alloc_init(&mut bn_s1, 32, state[1].value.as_ptr(), 32); + cx_bn_alloc_init(&mut bn_two, 32, FieldElement::TWO.value.as_ptr(), 32); + cx_bn_alloc_init(&mut bn_three, 32, FieldElement::THREE.value.as_ptr(), 32); + + /* Compute t */ + cx_bn_mod_add(bn_res, bn_s0, bn_s1, bn_p); + cx_bn_mod_add(bn_t, bn_res, bn_s2, bn_p); + + /* Update state */ + /* s0 = t + 2 * s0 */ + cx_bn_mod_mul(bn_res, bn_s0, bn_two, bn_p); + cx_bn_mod_add(bn_s0, bn_t, bn_res, bn_p); + + /* s1 = t - 2 * s1 */ + cx_bn_mod_mul(bn_res, bn_s1, bn_two, bn_p); + cx_bn_mod_sub(bn_s1, bn_t, bn_res, bn_p); + + /* s2 = t - 3 * s2 */ + cx_bn_mod_mul(bn_res, bn_s2, bn_three, bn_p); + cx_bn_mod_sub(bn_s2, bn_t, bn_res, bn_p); + + /* Fix Sandra */ + let mut bn_zero: cx_bn_t = cx_bn_t::default(); + cx_bn_alloc_init(&mut bn_zero, 32, FieldElement::ZERO.value.as_ptr(), 32); + cx_bn_mod_sub(bn_s0, bn_s0, bn_zero, bn_p); + + cx_bn_export(bn_s0, state[0].value.as_mut_ptr(), 32); + cx_bn_export(bn_s1, state[1].value.as_mut_ptr(), 32); + cx_bn_export(bn_s2, state[2].value.as_mut_ptr(), 32); + + cx_bn_unlock(); + } + } + + #[inline] + fn partial_round_loop(state: &mut [FieldElement], index: &mut usize) { + unsafe { + let mut bn_p: cx_bn_t = cx_bn_t::default(); + let mut bn_res: cx_bn_t = cx_bn_t::default(); + let mut bn_rc: cx_bn_t = cx_bn_t::default(); + let mut bn_e: cx_bn_t = cx_bn_t::default(); + let mut bn_s2: cx_bn_t = cx_bn_t::default(); + let mut bn_s0: cx_bn_t = cx_bn_t::default(); + let mut bn_s1: cx_bn_t = cx_bn_t::default(); + let mut bn_t: cx_bn_t = cx_bn_t::default(); + let mut bn_two: cx_bn_t = cx_bn_t::default(); + let mut bn_three: cx_bn_t = cx_bn_t::default(); + let mut bn_zero: cx_bn_t = cx_bn_t::default(); + + cx_bn_lock(32, 0); + + cx_bn_alloc(&mut bn_res, 32); + + cx_bn_alloc_init(&mut bn_s0, 32, state[0].value.as_ptr(), 32); + cx_bn_alloc_init(&mut bn_s1, 32, state[1].value.as_ptr(), 32); + cx_bn_alloc_init(&mut bn_s2, 32, state[2].value.as_ptr(), 32); + cx_bn_alloc_init(&mut bn_p, 32, P.value.as_ptr(), 32); + cx_bn_alloc(&mut bn_rc, 32); + cx_bn_alloc_init(&mut bn_e, 32, [3u8; 1].as_ptr(), 1); + cx_bn_alloc(&mut bn_t, 32); + cx_bn_alloc_init(&mut bn_two, 32, FieldElement::TWO.value.as_ptr(), 32); + cx_bn_alloc_init(&mut bn_three, 32, FieldElement::THREE.value.as_ptr(), 32); + cx_bn_alloc_init(&mut bn_zero, 32, FieldElement::ZERO.value.as_ptr(), 32); + + for _ in 0..N_PARTIAL_ROUNDS { + /* s2 = s2 + ROUND_CONSTANTS[index] */ + cx_bn_init( + bn_rc, + FieldElement::from(ROUND_CONSTANTS[*index]).value.as_ptr(), + 32, + ); + cx_bn_mod_add(bn_res, bn_s2, bn_rc, bn_p); + + /* s2 = s2 * s2 * s2 */ + cx_bn_mod_pow_bn(bn_s2, bn_res, bn_e, bn_p); + + /**** Mix ****/ + + /* Compute t */ + cx_bn_mod_add(bn_res, bn_s0, bn_s1, bn_p); + cx_bn_mod_add(bn_t, bn_res, bn_s2, bn_p); + + /* Update state */ + /* s0 = t + 2 * s0 */ + cx_bn_mod_mul(bn_res, bn_s0, bn_two, bn_p); + cx_bn_mod_add(bn_s0, bn_t, bn_res, bn_p); + + /* s1 = t - 2 * s1 */ + cx_bn_mod_mul(bn_res, bn_s1, bn_two, bn_p); + cx_bn_mod_sub(bn_s1, bn_t, bn_res, bn_p); + + /* s2 = t - 3 * s2 */ + cx_bn_mod_mul(bn_res, bn_s2, bn_three, bn_p); + cx_bn_mod_sub(bn_s2, bn_t, bn_res, bn_p); + + /* Fix Sandra */ + cx_bn_mod_sub(bn_s0, bn_s0, bn_zero, bn_p); + + *index += 1; + } + + cx_bn_export(bn_s0, state[0].value.as_mut_ptr(), 32); + cx_bn_export(bn_s1, state[1].value.as_mut_ptr(), 32); + cx_bn_export(bn_s2, state[2].value.as_mut_ptr(), 32); + + cx_bn_unlock(); + } + } + + #[cfg(feature = "poseidon")] + pub fn hash(x: &FieldElement, y: &FieldElement) -> FieldElement { + let mut state: Vec = Vec::with_capacity(3); + state.push(x.clone()); + state.push(y.clone()); + state.push(FieldElement::from(2u8)); + Self::hades_permutation(&mut state); + let x = &state[0]; + x.clone() + } + + #[cfg(feature = "poseidon")] + pub fn hash_single(x: &FieldElement) -> FieldElement { + let mut state: Vec = Vec::with_capacity(3); + state.push(x.clone()); + state.push(FieldElement::ZERO); + state.push(FieldElement::ONE); + Self::hades_permutation(&mut state); + let x = &state[0]; + x.clone() + } + + pub fn hash_many(inputs: &[FieldElement]) -> FieldElement { + let r = RATE; // chunk size + + // Pad input with 1 followed by 0's (if necessary). + let mut values = inputs.to_owned(); + values.push(FieldElement::from(1u8)); + values.resize(((values.len() + r - 1) / r) * r, FieldElement::ZERO); + + assert!(values.len() % r == 0); + let mut state: Vec = Vec::from([FieldElement::ZERO; STATE_SIZE]); + + // Process each block + for block in values.chunks(r) { + let mut block_state: Vec = state[0..r] + .iter() + .zip(block) + .map(|(s, b)| *s + *b) + .collect(); + + block_state.extend_from_slice(&state[r..]); + + Self::hades_permutation(&mut block_state); + state = block_state; + } + + state[0] + } +} + +// Code ported from the implementation here: +// https://github.com/xJonathanLEI/starknet-rs/blob/7bb13d3f02f23949cf3c263e1b53ffcc43990ce6/starknet-crypto/src/poseidon_hash.rs#L13 +#[derive(Debug, Default)] +pub struct PoseidonHasher { + state: [FieldElement; 3], + buffer: Option, +} + +impl PoseidonHasher { + /// Creates a new [PoseidonHasher]. + pub fn new() -> Self { + Self::default() + } + + /// Absorbs message into the hash. + pub fn update(&mut self, msg: FieldElement) { + match self.buffer.take() { + Some(previous_message) => { + self.state[0] += previous_message; + self.state[1] += msg; + PoseidonStark252::hades_permutation(&mut self.state); + } + None => { + self.buffer = Some(msg); + } + } + } + + /// Finishes and returns hash. + pub fn finalize(mut self) -> FieldElement { + // Applies padding + match self.buffer.take() { + Some(last_message) => { + self.state[0] += last_message; + self.state[1] += FieldElement::ONE; + } + None => { + self.state[0] += FieldElement::ONE; + } + } + PoseidonStark252::hades_permutation(&mut self.state); + + self.state[0] + } +} + +pub fn poseidon_shift(hash: &mut FieldElement) { + let mut hash256: cx_bn_t = cx_bn_t::default(); + + unsafe { + cx_bn_lock(32, 0); + cx_bn_alloc_init(&mut hash256, 32, hash.value[..].as_ptr(), 32); + + let mut bits_count: u32 = 256; + let mut set: bool = false; + while bits_count > 0 { + cx_bn_tst_bit(hash256, bits_count - 1, &mut set); + if set { + break; + } else { + bits_count -= 1; + } + } + + if bits_count < 248 { + cx_bn_unlock(); + } else if bits_count >= 248 && bits_count % 8 >= 1 && bits_count % 8 <= 4 { + cx_bn_shl(hash256, 4); + cx_bn_export(hash256, hash.value[..].as_mut_ptr(), 32); + cx_bn_destroy(&mut hash256); + cx_bn_unlock(); + return; + } + } +} diff --git a/starknet/src/display.rs b/starknet/src/display.rs new file mode 100644 index 0000000..33fee4f --- /dev/null +++ b/starknet/src/display.rs @@ -0,0 +1,350 @@ +extern crate alloc; +use crate::{ + erc20::{ERC20_TOKENS, TRANSFER}, + types::FieldElement, +}; +use alloc::format; +use include_gif::include_gif; +use ledger_device_sdk::{ + io::{Comm, Event}, + testing, +}; + +use crate::context::{Ctx, Transaction}; + +#[cfg(not(any(target_os = "stax", target_os = "flex")))] +use ledger_device_sdk::ui::{ + bitmaps::{Glyph, BACK, CERTIFICATE, CROSSMARK, DASHBOARD_X, EYE, VALIDATE_14, WARNING}, + gadgets::{ + clear_screen, EventOrPageIndex, Field, MultiFieldReview, MultiPageMenu, Page, PageStyle, + }, +}; + +#[cfg(any(target_os = "stax", target_os = "flex"))] +use ledger_device_sdk::nbgl::{ + Field, NbglGenericReview, NbglGlyph, NbglHomeAndSettings, NbglPageContent, NbglReview, + NbglReviewStatus, NbglStatus, TagValueConfirm, TagValueList, TuneIndex, +}; + +use crate::Ins; + +pub fn show_tx(ctx: &mut Ctx) -> Option { + match support_clear_sign(&ctx.tx) { + Some(t) => { + testing::debug_print("Clear sign supported !!! \n"); + let tx = &ctx.tx; + let call = &tx.calls[0]; + + let sender = tx.sender_address.to_hex_string(); + let token = ERC20_TOKENS[t].ticker; + let to = call.calldata[0].to_hex_string(); + let amount = call.calldata[1].to_dec_string(Some(ERC20_TOKENS[t].decimals)); + + testing::debug_print("Compute fees \n"); + + let max_amount = FieldElement::from(&tx.l1_gas_bounds.value[8..16]); + let max_price_per_unit = FieldElement::from(&tx.l1_gas_bounds.value[16..32]); + let max_fees = max_amount * max_price_per_unit; + let mut max_fees_str = max_fees.to_dec_string(None); + max_fees_str.push_str(" fri"); + + testing::debug_print("Compute fees OK \n"); + + let my_fields = [ + Field { + name: "From", + value: sender.as_str(), + }, + Field { + name: "Token", + value: token, + }, + Field { + name: "Amount", + value: amount.as_str(), + }, + Field { + name: "To", + value: to.as_str(), + }, + Field { + name: "Max Fees", + value: max_fees_str.as_str(), + }, + ]; + + testing::debug_print(&format!( + "Token: {}\nTo: {}\nAmount: {}\n", + token, to, amount + )); + + #[cfg(not(any(target_os = "stax", target_os = "flex")))] + { + let my_review = MultiFieldReview::new( + &my_fields, + &["Confirm Tx to sign"], + Some(&EYE), + "Approve", + Some(&VALIDATE_14), + "Reject", + Some(&CROSSMARK), + ); + Some(my_review.show()) + } + #[cfg(any(target_os = "stax", target_os = "flex"))] + { + // Load glyph from 64x64 4bpp gif file with include_gif macro. Creates an NBGL compatible glyph. + const APP_ICON: NbglGlyph = + NbglGlyph::from_include(include_gif!("starknet_64x64.gif", NBGL)); + + let mut review = NbglReview::new() + .titles("Review", "Transaction", "Sign Transaction") + .glyph(&APP_ICON); + + Some(review.show(&my_fields)) + } + } + None => { + testing::debug_print("Clear sign not supported !!! \n"); + None + } + } +} + +pub fn show_hash(ctx: &mut Ctx) -> bool { + let mut hash = ctx.hash.m_hash.to_hex_string(); + hash.make_ascii_uppercase(); + + let my_field = [Field { + name: "Transaction Hash", + value: hash.as_str(), + }]; + + #[cfg(not(any(target_os = "stax", target_os = "flex")))] + { + let page_0 = Page::new( + PageStyle::PictureNormal, + ["This transaction ", "cannot be trusted"], + Some(&WARNING), + ); + let page_1 = Page::new( + PageStyle::PictureNormal, + ["Your Ledger cannot ", "decode this transaction."], + Some(&WARNING), + ); + let page_2 = Page::new( + PageStyle::PictureNormal, + ["If you sign it, you", "could be authorizing"], + Some(&WARNING), + ); + let page_3 = Page::new( + PageStyle::PictureNormal, + ["malicious actions that", "can drain your wallet."], + Some(&WARNING), + ); + + clear_screen(); + page_0.place_and_wait(); + clear_screen(); + page_1.place_and_wait(); + clear_screen(); + page_2.place_and_wait(); + clear_screen(); + page_3.place_and_wait(); + + let warning_accept = MultiFieldReview::new( + &[], + &["I understand the risk"], + Some(&EYE), + "Accept", + Some(&VALIDATE_14), + "Reject", + Some(&CROSSMARK), + ); + + match warning_accept.show() { + false => false, + true => { + let my_review = MultiFieldReview::new( + &my_field, + &["Confirm Hash to sign"], + Some(&EYE), + "Approve", + Some(&VALIDATE_14), + "Reject", + Some(&CROSSMARK), + ); + + my_review.show() + } + } + } + #[cfg(any(target_os = "stax", target_os = "flex"))] + { + // Load glyph from 64x64 4bpp gif file with include_gif macro. Creates an NBGL compatible glyph. + const APP_ICON: NbglGlyph = + NbglGlyph::from_include(include_gif!("starknet_64x64.gif", NBGL)); + + let mut review = NbglReview::new() + .titles("Review", "Transaction", "Sign Transaction") + .glyph(&APP_ICON) + .blind(); + + review.show(&my_field) + } +} + +pub fn show_pending() { + #[cfg(not(any(target_os = "stax", target_os = "flex")))] + { + let page_0 = Page::new( + PageStyle::BoldNormal, + ["Processing ", "Transaction..."], + None, + ); + clear_screen(); + page_0.place(); + } + #[cfg(any(target_os = "stax", target_os = "flex"))] + { + let spinner = NbglStatus::new(); + spinner.text("Processing Transaction...").show(true); + } +} + +pub fn show_status(flag: bool) { + #[cfg(not(any(target_os = "stax", target_os = "flex")))] + { + let content = match flag { + true => ["Transaction ", "signed"], + false => ["Transaction ", "rejected"], + }; + let page_0 = Page::new(PageStyle::BoldNormal, content, None); + clear_screen(); + page_0.place(); + } + #[cfg(any(target_os = "stax", target_os = "flex"))] + { + let status = NbglReviewStatus::new(); + status.show(flag); + } +} + +pub fn pkey_ui(key: &[u8]) -> bool { + let mut pk_hex = [0u8; 64]; + hex::encode_to_slice(&key[1..33], &mut pk_hex[0..]).unwrap(); + let m = core::str::from_utf8_mut(&mut pk_hex).unwrap(); + m[0..].make_ascii_uppercase(); + + let my_field = [Field { + name: "Public Key", + value: m, + }]; + + #[cfg(not(any(target_os = "stax", target_os = "flex")))] + { + let my_review = MultiFieldReview::new( + &my_field, + &["Confirm Public Key"], + Some(&EYE), + "Approve", + Some(&VALIDATE_14), + "Reject", + Some(&CROSSMARK), + ); + + my_review.show() + } + #[cfg(any(target_os = "stax", target_os = "flex"))] + { + let tvl = TagValueList::new(&my_field, 4, false, true); + let tvc = TagValueConfirm::new(&tvl, TuneIndex::LookAtMe, "Approve", ""); + + match NbglGenericReview::new() + .add_content(NbglPageContent::TagValueConfirm(tvc)) + .show("Reject") + { + true => { + let status = NbglStatus::new(); + status.text("Public Key Confirmed").show(true); + true + } + false => { + let status = NbglStatus::new(); + status.text("Public Key Rejected").show(false); + false + } + } + } +} + +#[cfg(not(any(target_os = "stax", target_os = "flex")))] +fn about_ui(comm: &mut Comm) -> Event { + #[cfg(not(any(target_os = "stax", target_os = "flex")))] + { + let pages = [ + &Page::from((["Starknet", "(c) 2024 Ledger"], true)), + &Page::from(("Back", &BACK)), + ]; + loop { + match MultiPageMenu::new(comm, &pages).show() { + EventOrPageIndex::Event(e) => return e, + EventOrPageIndex::Index(1) => return main_ui(comm), + EventOrPageIndex::Index(_) => (), + } + } + } +} + +#[cfg(not(any(target_os = "stax", target_os = "flex")))] +pub fn main_ui(comm: &mut Comm) -> Event { + const APP_ICON: Glyph = Glyph::from_include(include_gif!("starknet_small.gif")); + let pages = [ + // The from trait allows to create different styles of pages + // without having to use the new() function. + &Page::from((["Starknet", "is ready"], &APP_ICON)), + &Page::from((["Version", env!("CARGO_PKG_VERSION")], true)), + &Page::from(("About", &CERTIFICATE)), + &Page::from(("Quit", &DASHBOARD_X)), + ]; + loop { + match MultiPageMenu::new(comm, &pages).show() { + EventOrPageIndex::Event(e) => return e, + EventOrPageIndex::Index(2) => return about_ui(comm), + EventOrPageIndex::Index(3) => ledger_device_sdk::exit_app(0), + EventOrPageIndex::Index(_) => (), + } + } +} + +#[cfg(any(target_os = "stax", target_os = "flex"))] +pub fn main_ui(_comm: &mut Comm) -> Event { + // Load glyph from 64x64 4bpp gif file with include_gif macro. Creates an NBGL compatible glyph. + const APP_ICON: NbglGlyph = NbglGlyph::from_include(include_gif!("starknet_64x64.gif", NBGL)); + + // Display the home screen. + NbglHomeAndSettings::new() + .glyph(&APP_ICON) + .infos( + "Starknet", + env!("CARGO_PKG_VERSION"), + env!("CARGO_PKG_AUTHORS"), + ) + .show() +} + +fn support_clear_sign(tx: &Transaction) -> Option { + match tx.calls.len() { + 1 => { + for (idx, t) in ERC20_TOKENS.iter().enumerate() { + if tx.calls[0].to == FieldElement::from(t.address) + && tx.calls[0].selector == FieldElement::from(TRANSFER) + { + return Some(idx); + } + } + None + } + _ => None, + } +} diff --git a/starknet/src/erc20.rs b/starknet/src/erc20.rs new file mode 100644 index 0000000..f9e2543 --- /dev/null +++ b/starknet/src/erc20.rs @@ -0,0 +1,29 @@ +#[derive(Debug)] +pub struct TokenInfo { + pub address: &'static str, + pub ticker: &'static str, + pub decimals: usize, +} + +pub const NB_ERC20_TOKENS: usize = 3; + +pub const ERC20_TOKENS: [TokenInfo; NB_ERC20_TOKENS] = [ + TokenInfo { + address: "068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8", + ticker: "USDT", + decimals: 6, + }, + TokenInfo { + address: "049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + ticker: "ETH", + decimals: 18, + }, + TokenInfo { + address: "04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + ticker: "STRK", + decimals: 18, + }, +]; + +pub const TRANSFER: &str = "0083afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e"; +//pub const APPROVE: &str = "0219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c"; diff --git a/starknet/src/main.rs b/starknet/src/main.rs new file mode 100644 index 0000000..2681f4c --- /dev/null +++ b/starknet/src/main.rs @@ -0,0 +1,286 @@ +#![no_std] +#![no_main] + +mod context; +mod crypto; +mod display; +mod erc20; +mod transaction; +mod types; + +extern crate alloc; +use alloc::vec::Vec; + +use context::{Ctx, RequestType}; +use ledger_device_sdk::io; +use types::FieldElement; + +ledger_device_sdk::set_panic!(ledger_device_sdk::exiting_panic); + +#[cfg(any(target_os = "stax", target_os = "flex"))] +use ledger_device_sdk::nbgl::init_comm; + +#[no_mangle] +extern "C" fn sample_main() { + // Init comm and set the expected CLA byte for the application + let mut comm = io::Comm::new().set_expected_cla(0x5A); + + // Initialize reference to Comm instance for NBGL + // API calls. + #[cfg(any(target_os = "stax", target_os = "flex"))] + init_comm(&mut comm); + + let mut ctx: Ctx = Ctx::new(); + + loop { + // Wait for either a specific button push to exit the app + // or an APDU command + if let io::Event::Command(ins) = display::main_ui(&mut comm) { + match handle_apdu(&mut comm, ins, &mut ctx) { + Ok(()) => comm.reply_ok(), + Err(sw) => comm.reply(sw), + } + } + } +} + +#[repr(u8)] +enum Ins { + GetVersion, + GetPubkey { + display: bool, + }, + #[cfg(feature = "signhash")] + SignHash, + SignTx, + #[cfg(feature = "poseidon")] + Poseidon, +} + +impl TryFrom for Ins { + type Error = io::StatusWords; + fn try_from(header: io::ApduHeader) -> Result { + match (header.ins, header.p1, header.p2) { + (0, 0, 0) => Ok(Ins::GetVersion), + (0, _, _) => Err(io::StatusWords::BadP1P2), + (1, 0 | 1, 0) => Ok(Ins::GetPubkey { + display: header.p1 != 0, + }), + (1, _, _) => Err(io::StatusWords::BadP1P2), + #[cfg(feature = "signhash")] + (2, _, _) => Ok(Ins::SignHash), + (3, _, _) => Ok(Ins::SignTx), + #[cfg(feature = "poseidon")] + (4, _, _) => Ok(Ins::Poseidon), + (_, _, _) => Err(io::StatusWords::BadIns), + } + } +} + +use ledger_device_sdk::io::Reply; + +fn handle_apdu(comm: &mut io::Comm, ins: Ins, ctx: &mut Ctx) -> Result<(), Reply> { + if comm.rx == 0 { + return Err(io::StatusWords::NothingReceived.into()); + } + + let apdu_header = comm.get_apdu_metadata(); + + match ins { + Ins::GetVersion => { + let version_major = env!("CARGO_PKG_VERSION_MAJOR").parse::().unwrap(); + let version_minor = env!("CARGO_PKG_VERSION_MINOR").parse::().unwrap(); + let version_patch = env!("CARGO_PKG_VERSION_PATCH").parse::().unwrap(); + comm.append([version_major, version_minor, version_patch].as_slice()); + } + Ins::GetPubkey { display } => { + ctx.reset(); + ctx.req_type = RequestType::GetPubkey; + + let mut data = comm.get_data()?; + + let res = crypto::set_derivation_path(&mut data, ctx); + match res { + Err(e) => { + return Err(e.into()); + } + Ok(()) => { + let pub_key = crypto::get_pubkey(ctx); + match pub_key { + Err(e) => { + return Err(Reply::from(e)); + } + Ok(key) => { + let ret = match display { + false => true, + true => display::pkey_ui(key.as_ref()), + }; + if ret { + comm.append(key.as_ref()); + } else { + return Err(io::StatusWords::UserCancelled.into()); + } + } + } + } + } + } + #[cfg(feature = "signhash")] + Ins::SignHash => { + let p1 = apdu_header.p1; + let mut data = comm.get_data()?; + + match p1 { + 0 => { + ctx.reset(); + ctx.req_type = RequestType::SignHash; + + crypto::set_derivation_path(&mut data, ctx)?; + } + _ => { + ctx.hash.m_hash = data.into(); + match display::show_hash(ctx) { + true => { + crypto::sign_hash(ctx).unwrap(); + comm.append([0x41].as_slice()); + comm.append(ctx.hash.r.as_ref()); + comm.append(ctx.hash.s.as_ref()); + comm.append([ctx.hash.v].as_slice()); + } + false => { + return Err(io::StatusWords::UserCancelled.into()); + } + } + } + } + } + Ins::SignTx => { + let mut data = comm.get_data()?; + let p1 = apdu_header.p1; + let p2 = apdu_header.p2; + + match p1 { + 0 => { + ctx.reset(); + ctx.req_type = RequestType::SignTx; + + crypto::set_derivation_path(&mut data, ctx)?; + } + 1 => transaction::set_tx_fields(data, &mut ctx.tx), + 2 => transaction::set_paymaster_data(data, p2, &mut ctx.tx.paymaster_data), + 3 => transaction::set_account_deployment_data( + data, + p2, + &mut ctx.tx.account_deployment_data, + ), + 4 => { + let nb_calls: u8 = FieldElement::from(data).into(); + ctx.tx.calls = Vec::with_capacity(nb_calls as usize); + } + 5 => { + if let Some(err) = + transaction::set_call(data, p2.into(), &mut ctx.tx.calls).err() + { + return Err(Reply(err as u16)); + } + if p2 == transaction::SetCallStep::End.into() + && ctx.tx.calls.len() == ctx.tx.calls.capacity() + { + match display::show_tx(ctx) { + Some(approved) => match approved { + true => { + display::show_pending(); + ctx.hash.m_hash = crypto::tx_hash(&ctx.tx); + comm.append(ctx.hash.m_hash.value.as_ref()); + crypto::sign_hash(ctx).unwrap(); + display::show_status(true); + comm.append([0x41].as_slice()); + comm.append(ctx.hash.r.as_ref()); + comm.append(ctx.hash.s.as_ref()); + comm.append([ctx.hash.v].as_slice()); + } + false => { + display::show_status(false); + return Err(io::StatusWords::UserCancelled.into()); + } + }, + None => { + display::show_pending(); + ctx.hash.m_hash = crypto::tx_hash(&ctx.tx); + match display::show_hash(ctx) { + true => { + comm.append(ctx.hash.m_hash.value.as_ref()); + crypto::sign_hash(ctx).unwrap(); + display::show_status(true); + comm.append([0x41].as_slice()); + comm.append(ctx.hash.r.as_ref()); + comm.append(ctx.hash.s.as_ref()); + comm.append([ctx.hash.v].as_slice()); + } + false => { + display::show_status(false); + return Err(io::StatusWords::UserCancelled.into()); + } + } + } + } + } + } + _ => { + return Err(io::StatusWords::BadP1P2.into()); + } + } + } + #[cfg(feature = "poseidon")] + Ins::Poseidon => { + let data = comm.get_data()?; + let p1 = apdu_header.p1; + + match p1 { + 0 => { + let x = FieldElement::from(&data[0..32]); + let hash = crypto::poseidon::PoseidonStark252::hash_single(&x); + comm.append(hash.value.as_ref()); + } + 1 => { + let x = FieldElement::from(&data[0..32]); + let y = FieldElement::from(&data[32..64]); + let hash = crypto::poseidon::PoseidonStark252::hash(&x, &y); + comm.append(hash.value.as_ref()); + } + 2 => { + let a = FieldElement::from(data[0]); + let b = FieldElement::from(data[1]); + let c = FieldElement::from(data[2]); + let d = FieldElement::from(data[3]); + let e = FieldElement::from(data[4]); + let f = FieldElement::from(data[5]); + + let values: [FieldElement; 6] = [a, b, c, d, e, f]; + let hash = crypto::poseidon::PoseidonStark252::hash_many(&values); + comm.append(hash.value.as_ref()); + } + 3 => { + let a = FieldElement::from(data[0]); + let b = FieldElement::from(data[1]); + let c = FieldElement::from(data[2]); + let d = FieldElement::from(data[3]); + let e = FieldElement::from(data[4]); + let f = FieldElement::from(data[5]); + let mut hasher = crypto::poseidon::PoseidonHasher::new(); + hasher.update(a); + hasher.update(b); + hasher.update(c); + hasher.update(d); + hasher.update(e); + hasher.update(f); + comm.append(hasher.finalize().value.as_ref()); + } + _ => { + return Err(io::StatusWords::BadP1P2.into()); + } + } + } + } + Ok(()) +} diff --git a/starknet/src/transaction.rs b/starknet/src/transaction.rs new file mode 100644 index 0000000..339aaa9 --- /dev/null +++ b/starknet/src/transaction.rs @@ -0,0 +1,91 @@ +use crate::{context::Call, context::Transaction, types::FieldElement}; + +extern crate alloc; +use alloc::vec::Vec; + +const FIELD_ELEMENT_SIZE: usize = 32; + +pub fn set_tx_fields(data: &[u8], tx: &mut Transaction) { + let mut iter = data.chunks(FIELD_ELEMENT_SIZE); + + tx.sender_address = iter.next().unwrap().into(); + tx.tip = iter.next().unwrap().into(); + tx.l1_gas_bounds = iter.next().unwrap().into(); + tx.l2_gas_bounds = iter.next().unwrap().into(); + tx.chain_id = iter.next().unwrap().into(); + tx.nonce = iter.next().unwrap().into(); + tx.data_availability_mode = iter.next().unwrap().into(); +} + +// For future use: currently paymaster_data is always empty. +// See https://docs.starknet.io/architecture-and-concepts/network-architecture/transactions/#v3_transaction_fields +pub fn set_paymaster_data(_data: &[u8], _p2: u8, _paymaster_data: &mut [FieldElement]) {} + +// For future use: currently account_deployment_data is always empty. +// See https://docs.starknet.io/architecture-and-concepts/network-architecture/transactions/#v3_transaction_fields +pub fn set_account_deployment_data( + _data: &[u8], + _p2: u8, + _account_deployment_data: &mut [FieldElement], +) { +} + +pub enum SetCallError { + TooManyCalls = 0xFF01, +} + +pub enum SetCallStep { + New = 0x00, + Add = 0x01, + End = 0x02, +} + +impl From for SetCallStep { + fn from(value: u8) -> Self { + match value { + 0x00 => SetCallStep::New, + 0x01 => SetCallStep::Add, + 0x02 => SetCallStep::End, + _ => panic!("Invalid SetCallStep value"), + } + } +} + +impl From for u8 { + fn from(value: SetCallStep) -> Self { + match value { + SetCallStep::New => 0x00, + SetCallStep::Add => 0x01, + SetCallStep::End => 0x02, + } + } +} + +pub fn set_call(data: &[u8], p2: SetCallStep, calls: &mut Vec) -> Result<(), SetCallError> { + match p2 { + SetCallStep::New => { + if calls.len() == calls.capacity() { + return Err(SetCallError::TooManyCalls); + } + let mut call = Call::default(); + let mut iter = data.chunks(FIELD_ELEMENT_SIZE); + + call.to = iter.next().unwrap().into(); + call.selector = iter.next().unwrap().into(); + for d in iter { + call.calldata.push(d.into()); + } + calls.push(call); + Ok(()) + } + SetCallStep::Add | SetCallStep::End => { + let idx = calls.len() - 1; + let call = calls.get_mut(idx).unwrap(); + let iter = data.chunks(FIELD_ELEMENT_SIZE); + for d in iter { + call.calldata.push(d.into()); + } + Ok(()) + } + } +} diff --git a/starknet/src/types.rs b/starknet/src/types.rs new file mode 100644 index 0000000..705ff57 --- /dev/null +++ b/starknet/src/types.rs @@ -0,0 +1,304 @@ +extern crate alloc; +use alloc::string::{String, ToString}; +use core::ops::{Add, AddAssign, Div, Mul, Rem, Sub}; +use ledger_secure_sdk_sys::*; +use num_bigint::BigUint; + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, PartialOrd)] +pub struct FieldElement { + pub value: [u8; 32], +} + +impl FieldElement { + pub const INVOKE: FieldElement = FieldElement { + value: [ + 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, 0x69, 0x6e, + 0x76, 0x6f, 0x6b, 0x65, + ], + }; + + pub const ZERO: FieldElement = FieldElement { value: [0u8; 32] }; + + pub const ONE: FieldElement = FieldElement { + value: [ + 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, + ], + }; + + pub const TWO: FieldElement = FieldElement { + value: [ + 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, 0x02, + ], + }; + + pub const THREE: FieldElement = FieldElement { + value: [ + 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, 0x03, + ], + }; + + pub fn new() -> Self { + Self::default() + } + + pub fn clear(&mut self) { + self.value.fill(0); + } + + pub fn copy_from(&mut self, f: &FieldElement) { + self.value.copy_from_slice(&f.value); + } + + pub fn div_rem(&self, other: &FieldElement) -> (FieldElement, FieldElement) { + let remainder = *self % *other; + ((*self - remainder) / *other, remainder) + } + + pub fn inverse(&self) -> FieldElement { + let mut res = FieldElement::default(); + + unsafe { + let err = cx_math_invprimem_no_throw( + res.value.as_mut_ptr(), + self.value.as_ptr(), + P.value.as_ptr(), + 32, + ); + match err { + ledger_secure_sdk_sys::CX_OK => res, + _ => panic!("Error inverting FieldElement with error code: {}", err), + } + } + } + + #[allow(clippy::wrong_self_convention)] + pub fn to_dec_string(&self, decimals: Option) -> String { + let bn = BigUint::from_bytes_be(self.value.as_ref()); + match decimals { + Some(d) => { + let bn_str = bn.to_string(); + let len = bn_str.len(); + if len <= d { + let mut s = String::from("0."); + s.push_str(&"0".repeat(d - len)); + s.push_str(&bn_str); + s + } else { + let (int_part, dec_part) = bn_str.split_at(len - d); + let mut s = String::from(int_part); + s.push('.'); + s.push_str(dec_part); + s + } + } + None => bn.to_string(), + } + } + + #[allow(clippy::wrong_self_convention)] + pub fn to_hex_string(&self) -> String { + hex::encode(self.value) + } +} + +// P is the Starknet 252 Prime +pub const P: FieldElement = FieldElement { + value: [ + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + ], +}; + +impl Add for FieldElement { + type Output = Self; + + fn add(self, other: Self) -> Self { + let mut res = FieldElement::default(); + + unsafe { + let err = cx_math_addm_no_throw( + res.value.as_mut_ptr(), + self.value.as_ptr(), + other.value.as_ptr(), + P.value.as_ptr(), + 32, + ); + match err { + ledger_secure_sdk_sys::CX_OK => res, + _ => panic!("Error adding FieldElement with error code: {}", err), + } + } + } +} + +impl Mul for FieldElement { + type Output = Self; + + fn mul(self, other: Self) -> Self { + let mut res = FieldElement::default(); + + unsafe { + let err = cx_math_multm_no_throw( + res.value.as_mut_ptr(), + self.value.as_ptr(), + other.value.as_ptr(), + P.value.as_ptr(), + 32, + ); + match err { + ledger_secure_sdk_sys::CX_OK => res, + _ => panic!("Error multiplying FieldElement with error code: {}", err), + } + } + } +} + +impl Sub for FieldElement { + type Output = Self; + + fn sub(self, other: Self) -> Self { + let mut res = FieldElement::default(); + + unsafe { + let err = cx_math_subm_no_throw( + res.value.as_mut_ptr(), + self.value.as_ptr(), + other.value.as_ptr(), + P.value.as_ptr(), + 32, + ); + match err { + ledger_secure_sdk_sys::CX_OK => res, + _ => panic!("Error subtracting FieldElement with error code: {}", err), + } + } + } +} + +impl Rem for FieldElement { + type Output = Self; + + fn rem(mut self, other: Self) -> Self { + unsafe { + let err = cx_math_modm_no_throw(self.value.as_mut_ptr(), 32, other.value.as_ptr(), 32); + match err { + ledger_secure_sdk_sys::CX_OK => self, + _ => panic!( + "Error taking remainder of FieldElement with error code: {}", + err + ), + } + } + } +} + +#[allow(clippy::suspicious_arithmetic_impl)] +impl Div for FieldElement { + type Output = Self; + + fn div(self, other: Self) -> Self { + let other_inverse = other.inverse(); + + // Use the multiplication method defined earlier + self * other_inverse + } +} + +impl AddAssign for FieldElement { + fn add_assign(&mut self, other: Self) { + unsafe { + let value = self.value; + let err = cx_math_addm_no_throw( + self.value.as_mut_ptr(), + value.as_ptr(), + other.value.as_ptr(), + P.value.as_ptr(), + 32, + ); + match err { + ledger_secure_sdk_sys::CX_OK => (), + _ => panic!("Error adding FieldElement with error code: {}", err), + } + } + } +} + +impl From<&[u8]> for FieldElement { + fn from(data: &[u8]) -> Self { + let mut value: [u8; 32] = [0; 32]; + value[32 - data.len()..].copy_from_slice(data); + Self { value } + } +} + +impl From for FieldElement { + fn from(data: u8) -> Self { + let mut f = FieldElement::new(); + f.value[31] = data; + f + } +} + +impl From for u8 { + fn from(fe: FieldElement) -> u8 { + fe.value[31] + } +} + +// assumes usize < FieldElement (should be true, especially on the nano) +impl From for FieldElement { + fn from(num: usize) -> Self { + let mut f = FieldElement::new(); + let size_of_usize = core::mem::size_of::(); + let offset = if size_of_usize >= f.value.len() { + 0 + } else { + f.value.len() - size_of_usize + }; + + for i in 0..size_of_usize { + f.value[offset + i] = (num >> ((size_of_usize - 1 - i) * 8)) as u8; + } + + f + } +} + +impl From for usize { + fn from(fe: FieldElement) -> usize { + let mut value: usize = 0; + let size_of_usize = core::mem::size_of::(); + let offset = if size_of_usize >= fe.value.len() { + 0 + } else { + fe.value.len() - size_of_usize + }; + + for i in 0..size_of_usize { + value |= (fe.value[i + offset] as usize) << ((size_of_usize - 1 - i) * 8); + } + + value + } +} + +impl From<&str> for FieldElement { + fn from(data: &str) -> Self { + let mut fe = FieldElement::default(); + if data.len() != 64 { + panic!("Invalid hex string length for FieldElement"); + } + match hex::decode_to_slice(data, &mut fe.value[..]) { + Ok(_) => fe, + Err(_) => FieldElement::default(), + } + } +} diff --git a/starknet_32x32.gif b/starknet/starknet_32x32.gif similarity index 100% rename from starknet_32x32.gif rename to starknet/starknet_32x32.gif diff --git a/starknet_40x40.gif b/starknet/starknet_40x40.gif similarity index 100% rename from starknet_40x40.gif rename to starknet/starknet_40x40.gif diff --git a/starknet_64x64.gif b/starknet/starknet_64x64.gif similarity index 100% rename from starknet_64x64.gif rename to starknet/starknet_64x64.gif diff --git a/starknet_small.gif b/starknet/starknet_small.gif similarity index 100% rename from starknet_small.gif rename to starknet/starknet_small.gif diff --git a/test/pedersen.apdu b/test/pedersen.apdu deleted file mode 100644 index da4e181..0000000 --- a/test/pedersen.apdu +++ /dev/null @@ -1,15 +0,0 @@ -a = 01784f8bae775d53ce5afdff7b1754e3863a2bd0332960a48ea56f2c1939d07d -b = 03dec40fc1c0409adde42faeaa70f7e4af2784dca58a01f74e7f08c8d1dd75b4 -p = 005692085625cce3f0325d58f10ba76db4c1d27891a355feb9b9e7676b2b426e - -a = 00784f8bae775d53ce5afdff7b1754e3863a2bd0332960a48ea56f2c1939d07d -b = 03dec40fc1c0409adde42faeaa70f7e4af2784dca58a01f74e7f08c8d1dd75b4 -p = 0493d358a13a4f26ab0530bbabe718476dce7c32fb7f031812ce5eba317c015f - -a = 01784f8bae775d53ce5afdff7b1754e3863a2bd0332960a48ea56f2c1939d07d -b = 00dec40fc1c0409adde42faeaa70f7e4af2784dca58a01f74e7f08c8d1dd75b4 -p = 0333d9e9dfc3cdbf1bcd8cc5f27112c5716989788c371e8608668b5f5d29b473 - -a = 00784f8bae775d53ce5afdff7b1754e3863a2bd0332960a48ea56f2c1939d07d -b = 00dec40fc1c0409adde42faeaa70f7e4af2784dca58a01f74e7f08c8d1dd75b4 -p = 01fb9c74f9d3602bc6d0eb279a6a24ac62bac3cb27fca2908b0f8ac314019a07 diff --git a/test/publickey_confirm.apdu b/test/publickey_confirm.apdu deleted file mode 100644 index ed7aada..0000000 --- a/test/publickey_confirm.apdu +++ /dev/null @@ -1 +0,0 @@ -=> 5A0101001880000a55c741e9c9c47a6028800000008000000000000000 diff --git a/test/publickey_noconfirm.apdu b/test/publickey_noconfirm.apdu deleted file mode 100644 index 333f7b6..0000000 --- a/test/publickey_noconfirm.apdu +++ /dev/null @@ -1 +0,0 @@ -=> 5A0100001880000a55c741e9c9c47a6028800000008000000000000000 diff --git a/test/sign_confirm.apdu b/test/sign_confirm.apdu deleted file mode 100644 index 336ffcb..0000000 --- a/test/sign_confirm.apdu +++ /dev/null @@ -1,2 +0,0 @@ -=> 5A0200011880000a55c741e9c9c47a6028800000008000000000000000 -=> 5A0201012055b8f28706a5008d3103bcb2bfa6356e56b95c34fed265c955846670a6bb4ef0 diff --git a/test/sign_multicall_tx.apdu b/test/sign_multicall_tx.apdu deleted file mode 100644 index 01f0e70..0000000 --- a/test/sign_multicall_tx.apdu +++ /dev/null @@ -1,7 +0,0 @@ -=> 5A0300001880000a55c741e9c9c47a6028800000008000000000000000 -=> 5A030100a007e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a00000000000000000000000000000000000000000000000000038d7ea4c680000000000000000000000000000000000000000000000000534e5f474f45524c4900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001 -=> 5A0302004000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004 -=> 5A030300650507446de5cfcb833d4e786f3a0510deb2429ae753741a836a7efa80c9c747cb046d696e7400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002 -=> 5A030301680507446de5cfcb833d4e786f3a0510deb2429ae753741a836a7efa80c9c747cb07617070726f766500000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002 -=> 5A0304004007e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a00000000000000000000000000000000000000000000000000000000000003e8 -=> 5A0304014007e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a0000000000000000000000000000000000000000000000000000000000002710 diff --git a/test/sign_noconfirm.apdu b/test/sign_noconfirm.apdu deleted file mode 100644 index c9a87b5..0000000 --- a/test/sign_noconfirm.apdu +++ /dev/null @@ -1,2 +0,0 @@ -=> 5A0200011880000a55c741e9c9c47a6028800000008000000000000000 -=> 5A0201002055b8f28706a5008d3103bcb2bfa6356e56b95c34fed265c955846670a6bb4ef0 diff --git a/test/sign_singlecall_tx.apdu b/test/sign_singlecall_tx.apdu deleted file mode 100644 index fcc3a03..0000000 --- a/test/sign_singlecall_tx.apdu +++ /dev/null @@ -1,5 +0,0 @@ -=> 5A0300001880000a55c741e9c9c47a6028800000008000000000000000 -=> 5A030100A007e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a00000000000000000000000000000000000000000000000000038d7ea4c680000000000000000000000000000000000000000000000000534e5f474f45524c4900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001 -=> 5A0302004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002 -=> 5A030300650507446de5cfcb833d4e786f3a0510deb2429ae753741a836a7efa80c9c747cb046d696e7400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002 -=> 5A0304004007e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a00000000000000000000000000000000000000000000000000000000000003e8 diff --git a/test/version.apdu b/test/version.apdu deleted file mode 100644 index 5fe61b4..0000000 --- a/test/version.apdu +++ /dev/null @@ -1 +0,0 @@ -=> 5A00000000 diff --git a/tests/application_client/command_sender.py b/tests/application_client/command_sender.py deleted file mode 100644 index 177416b..0000000 --- a/tests/application_client/command_sender.py +++ /dev/null @@ -1,122 +0,0 @@ -from enum import IntEnum -from typing import Generator, List, Optional -from contextlib import contextmanager - -from ragger.backend.interface import BackendInterface, RAPDU - -def bip32_path_from_string(path: str) -> List[bytes]: - splitted_path: List[str] = path.split("/") - - if not splitted_path: - raise Exception(f"BIP32 path format error: '{path}'") - - if "m" in splitted_path and splitted_path[0] == "m": - splitted_path = splitted_path[1:] - - - - return [int(p).to_bytes(4, byteorder="big") if "'" not in p - else (0x80000000 | int(p[:-1])).to_bytes(4, byteorder="big") - for p in splitted_path] - -MAX_APDU_LEN: int = 255 - -CLA: int = 0x5A - -class InsType(IntEnum): - GET_VERSION = 0x00 - GET_PUBLIC_KEY = 0x01 - SIGN_HASH = 0x02 - -class Errors(IntEnum): - SW_DENY = 0x6E04 - SW_CLA_NOT_SUPPORTED = 0x6E00 - SW_INS_NOT_SUPPORTED = 0x6E01 - SW_WRONG_P1P2 = 0x6E02 - SW_WRONG_APDU_LENGTH = 0x6E03 - SW_WRONG_RESPONSE_LENGTH = 0xB000 - SW_DISPLAY_BIP32_PATH_FAIL = 0xB001 - SW_DISPLAY_ADDRESS_FAIL = 0xB002 - SW_DISPLAY_AMOUNT_FAIL = 0xB003 - SW_WRONG_TX_LENGTH = 0xB004 - SW_TX_PARSING_FAIL = 0xB005 - SW_TX_HASH_FAIL = 0xB006 - SW_BAD_STATE = 0xB007 - SW_SIGNATURE_FAIL = 0xB008 - -class CommandSender: - def __init__(self, backend: BackendInterface) -> None: - self.backend = backend - - - def get_app_and_version(self) -> RAPDU: - return self.backend.exchange(cla=0xB0, # specific CLA for BOLOS - ins=0x01, # specific INS for get_app_and_version - p1=0x00, - p2=0x00, - data=b"") - - - def get_version(self) -> RAPDU: - return self.backend.exchange(cla=CLA, - ins=InsType.GET_VERSION, - p1=0x00, - p2=0x00, - data=b"") - - - #def get_app_name(self) -> RAPDU: - # return self.backend.exchange(cla=CLA, - # ins=InsType.GET_APP_NAME, - # p1=P1.P1_START, - # p2=P2.P2_LAST, - # data=b"") - - - def get_public_key(self, path: str) -> RAPDU: - bip32_paths: List[bytes] = bip32_path_from_string(path) - cdata: bytes = b"".join([ - *bip32_paths - ]) - return self.backend.exchange(cla=CLA, - ins=InsType.GET_PUBLIC_KEY, - p1=0x00, - p2=0x00, - data=cdata) - - - @contextmanager - def get_public_key_with_confirmation(self, path: str) -> Generator[None, None, None]: - bip32_paths: List[bytes] = bip32_path_from_string(path) - cdata: bytes = b"".join([ - *bip32_paths - ]) - with self.backend.exchange_async(cla=CLA, - ins=InsType.GET_PUBLIC_KEY, - p1=0x01, - p2=0x00, - data=cdata) as response: - yield response - - - @contextmanager - def sign_hash(self, path: str, hash: bytes) -> Generator[None, None, None]: - bip32_paths: List[bytes] = bip32_path_from_string(path) - cdata: bytes = b"".join([ - *bip32_paths - ]) - self.backend.exchange(cla=CLA, - ins=InsType.SIGN_HASH, - p1=0x00, - p2=0x01, - data=cdata) - - with self.backend.exchange_async(cla=CLA, - ins=InsType.SIGN_HASH, - p1=0x01, - p2=0x01, - data=hash) as response: - yield response - - def get_async_response(self) -> Optional[RAPDU]: - return self.backend.last_async_response diff --git a/tests/application_client/response_unpacker.py b/tests/application_client/response_unpacker.py index 858a4ac..dd10295 100644 --- a/tests/application_client/response_unpacker.py +++ b/tests/application_client/response_unpacker.py @@ -1,5 +1,6 @@ from typing import Tuple from struct import unpack +from enum import IntEnum # remainder, data def pop_sized_buf_from_buffer(buffer:bytes, size:int) -> Tuple[bytes, bytes]: @@ -56,11 +57,13 @@ def unpack_get_public_key_response(response: bytes) -> Tuple[bytes, bytes]: return pub_key_x, pub_key_y # Unpack from response: -# response = sig_len (1) +# response = hash (32) +# sig_len (1) # r (32) # s (32) # v (1) -def unpack_sign_hash_response(response: bytes) -> Tuple[int, int, int]: +def unpack_sign_tx_response(response: bytes) -> Tuple[int, int, int, int]: + response, hash = pop_sized_buf_from_buffer(response, 32) response, len = pop_sized_buf_from_buffer(response, 1) response, r = pop_sized_buf_from_buffer(response, 32) response, s = pop_sized_buf_from_buffer(response, 32) @@ -68,4 +71,20 @@ def unpack_sign_hash_response(response: bytes) -> Tuple[int, int, int]: #assert len(response) == 0 - return int.from_bytes(r, byteorder='big'), int.from_bytes(s, byteorder='big'), int.from_bytes(v, byteorder='big') + return int.from_bytes(hash, byteorder='big'), int.from_bytes(r, byteorder='big'), int.from_bytes(s, byteorder='big'), int.from_bytes(v, byteorder='big') + +class Errors(IntEnum): + SW_DENY = 0x6E04 + SW_CLA_NOT_SUPPORTED = 0x6E00 + SW_INS_NOT_SUPPORTED = 0x6E01 + SW_WRONG_P1P2 = 0x6E02 + SW_WRONG_APDU_LENGTH = 0x6E03 + SW_WRONG_RESPONSE_LENGTH = 0xB000 + SW_DISPLAY_BIP32_PATH_FAIL = 0xB001 + SW_DISPLAY_ADDRESS_FAIL = 0xB002 + SW_DISPLAY_AMOUNT_FAIL = 0xB003 + SW_WRONG_TX_LENGTH = 0xB004 + SW_TX_PARSING_FAIL = 0xB005 + SW_TX_HASH_FAIL = 0xB006 + SW_BAD_STATE = 0xB007 + SW_SIGNATURE_FAIL = 0xB008 \ No newline at end of file diff --git a/tests/application_client/transaction.py b/tests/application_client/transaction.py deleted file mode 100644 index 3b13034..0000000 --- a/tests/application_client/transaction.py +++ /dev/null @@ -1,30 +0,0 @@ -import json -from dataclasses import dataclass -from .boilerplate_utils import UINT64_MAX - -class TransactionError(Exception): - pass - -@dataclass -class Transaction: - nonce: int - coin: str - value: str - to: str - memo: str - - def serialize(self) -> bytes: - if not 0 <= self.nonce <= UINT64_MAX: - raise TransactionError(f"Bad nonce: '{self.nonce}'!") - - if len(self.to) != 40: - raise TransactionError(f"Bad address: '{self.to}'!") - - # Serialize the transaction data to a JSON-formatted string - return json.dumps({ - "nonce": self.nonce, - "coin": self.coin, - "value": self.value, - "to": self.to, - "memo": self.memo - }).encode('utf-8') diff --git a/tests/application_client/utils.py b/tests/application_client/utils.py deleted file mode 100644 index fd96e62..0000000 --- a/tests/application_client/utils.py +++ /dev/null @@ -1,61 +0,0 @@ -from io import BytesIO -from typing import Optional, Literal - - -UINT64_MAX: int = 2**64-1 -UINT32_MAX: int = 2**32-1 -UINT16_MAX: int = 2**16-1 - - -def write_varint(n: int) -> bytes: - if n < 0xFC: - return n.to_bytes(1, byteorder="little") - - if n <= UINT16_MAX: - return b"\xFD" + n.to_bytes(2, byteorder="little") - - if n <= UINT32_MAX: - return b"\xFE" + n.to_bytes(4, byteorder="little") - - if n <= UINT64_MAX: - return b"\xFF" + n.to_bytes(8, byteorder="little") - - raise ValueError(f"Can't write to varint: '{n}'!") - - -def read_varint(buf: BytesIO, - prefix: Optional[bytes] = None) -> int: - b: bytes = prefix if prefix else buf.read(1) - - if not b: - raise ValueError(f"Can't read prefix: '{b.hex()}'!") - - n: int = {b"\xfd": 2, b"\xfe": 4, b"\xff": 8}.get(b, 1) # default to 1 - - b = buf.read(n) if n > 1 else b - - if len(b) != n: - raise ValueError("Can't read varint!") - - return int.from_bytes(b, byteorder="little") - - -def read(buf: BytesIO, size: int) -> bytes: - b: bytes = buf.read(size) - - if len(b) < size: - raise ValueError(f"Can't read {size} bytes in buffer!") - - return b - - -def read_uint(buf: BytesIO, - bit_len: int, - byteorder: Literal['big', 'little'] = 'little') -> int: - size: int = bit_len // 8 - b: bytes = buf.read(size) - - if len(b) < size: - raise ValueError(f"Can't read u{bit_len} in buffer!") - - return int.from_bytes(b, byteorder) diff --git a/tests/snapshots/flex/test_app_mainmenu/00000.png b/tests/snapshots/flex/test_app_mainmenu/00000.png index e49d799..89ba60a 100644 Binary files a/tests/snapshots/flex/test_app_mainmenu/00000.png and b/tests/snapshots/flex/test_app_mainmenu/00000.png differ diff --git a/tests/snapshots/flex/test_app_mainmenu/00001.png b/tests/snapshots/flex/test_app_mainmenu/00001.png index 59772c4..99309e3 100644 Binary files a/tests/snapshots/flex/test_app_mainmenu/00001.png and b/tests/snapshots/flex/test_app_mainmenu/00001.png differ diff --git a/tests/snapshots/flex/test_app_mainmenu/00002.png b/tests/snapshots/flex/test_app_mainmenu/00002.png index e49d799..89ba60a 100644 Binary files a/tests/snapshots/flex/test_app_mainmenu/00002.png and b/tests/snapshots/flex/test_app_mainmenu/00002.png differ diff --git a/tests/snapshots/flex/test_blind_sign_tx/00000.png b/tests/snapshots/flex/test_blind_sign_tx/00000.png new file mode 100644 index 0000000..8ddf1c5 Binary files /dev/null and b/tests/snapshots/flex/test_blind_sign_tx/00000.png differ diff --git a/tests/snapshots/flex/test_blind_sign_tx/00001.png b/tests/snapshots/flex/test_blind_sign_tx/00001.png new file mode 100644 index 0000000..95d49b4 Binary files /dev/null and b/tests/snapshots/flex/test_blind_sign_tx/00001.png differ diff --git a/tests/snapshots/flex/test_blind_sign_tx/00002.png b/tests/snapshots/flex/test_blind_sign_tx/00002.png new file mode 100644 index 0000000..3ebaf0e Binary files /dev/null and b/tests/snapshots/flex/test_blind_sign_tx/00002.png differ diff --git a/tests/snapshots/flex/test_blind_sign_tx/00003.png b/tests/snapshots/flex/test_blind_sign_tx/00003.png new file mode 100644 index 0000000..6b9adac Binary files /dev/null and b/tests/snapshots/flex/test_blind_sign_tx/00003.png differ diff --git a/tests/snapshots/flex/test_blind_sign_tx/00004.png b/tests/snapshots/flex/test_blind_sign_tx/00004.png new file mode 100644 index 0000000..c24bc7f Binary files /dev/null and b/tests/snapshots/flex/test_blind_sign_tx/00004.png differ diff --git a/tests/snapshots/flex/test_blind_sign_tx/00005.png b/tests/snapshots/flex/test_blind_sign_tx/00005.png new file mode 100644 index 0000000..597f65b Binary files /dev/null and b/tests/snapshots/flex/test_blind_sign_tx/00005.png differ diff --git a/tests/snapshots/flex/test_sign_hash_0/00003.png b/tests/snapshots/flex/test_blind_sign_tx/00006.png similarity index 100% rename from tests/snapshots/flex/test_sign_hash_0/00003.png rename to tests/snapshots/flex/test_blind_sign_tx/00006.png diff --git a/tests/snapshots/flex/test_blind_sign_tx/00007.png b/tests/snapshots/flex/test_blind_sign_tx/00007.png new file mode 100644 index 0000000..89ba60a Binary files /dev/null and b/tests/snapshots/flex/test_blind_sign_tx/00007.png differ diff --git a/tests/snapshots/flex/test_clear_sign_tx/00000.png b/tests/snapshots/flex/test_clear_sign_tx/00000.png new file mode 100644 index 0000000..021b44f Binary files /dev/null and b/tests/snapshots/flex/test_clear_sign_tx/00000.png differ diff --git a/tests/snapshots/flex/test_clear_sign_tx/00001.png b/tests/snapshots/flex/test_clear_sign_tx/00001.png new file mode 100644 index 0000000..430c336 Binary files /dev/null and b/tests/snapshots/flex/test_clear_sign_tx/00001.png differ diff --git a/tests/snapshots/flex/test_clear_sign_tx/00002.png b/tests/snapshots/flex/test_clear_sign_tx/00002.png new file mode 100644 index 0000000..0e24ee7 Binary files /dev/null and b/tests/snapshots/flex/test_clear_sign_tx/00002.png differ diff --git a/tests/snapshots/flex/test_clear_sign_tx/00003.png b/tests/snapshots/flex/test_clear_sign_tx/00003.png new file mode 100644 index 0000000..fc7d079 Binary files /dev/null and b/tests/snapshots/flex/test_clear_sign_tx/00003.png differ diff --git a/tests/snapshots/flex/test_clear_sign_tx/00004.png b/tests/snapshots/flex/test_clear_sign_tx/00004.png new file mode 100644 index 0000000..8ddf1c5 Binary files /dev/null and b/tests/snapshots/flex/test_clear_sign_tx/00004.png differ diff --git a/tests/snapshots/flex/test_sign_hash_1/00003.png b/tests/snapshots/flex/test_clear_sign_tx/00005.png similarity index 100% rename from tests/snapshots/flex/test_sign_hash_1/00003.png rename to tests/snapshots/flex/test_clear_sign_tx/00005.png diff --git a/tests/snapshots/flex/test_get_public_key_confirm_accepted/00000.png b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00000.png index a073c6f..6bad439 100644 Binary files a/tests/snapshots/flex/test_get_public_key_confirm_accepted/00000.png and b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00000.png differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_accepted/00001.png b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00001.png index e231b9c..f1c4981 100644 Binary files a/tests/snapshots/flex/test_get_public_key_confirm_accepted/00001.png and b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00001.png differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_accepted/00002.png b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00002.png index 4321e60..89ba60a 100644 Binary files a/tests/snapshots/flex/test_get_public_key_confirm_accepted/00002.png and b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00002.png differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_accepted/00003.png b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00003.png deleted file mode 100644 index e49d799..0000000 Binary files a/tests/snapshots/flex/test_get_public_key_confirm_accepted/00003.png and /dev/null differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_refused/00000.png b/tests/snapshots/flex/test_get_public_key_confirm_refused/00000.png new file mode 100644 index 0000000..6bad439 Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_refused/00000.png differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_refused/00001.png b/tests/snapshots/flex/test_get_public_key_confirm_refused/00001.png new file mode 100644 index 0000000..910b3c0 Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_refused/00001.png differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_refused/00002.png b/tests/snapshots/flex/test_get_public_key_confirm_refused/00002.png new file mode 100644 index 0000000..89ba60a Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_refused/00002.png differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_refused/part0/00000.png b/tests/snapshots/flex/test_get_public_key_confirm_refused/part0/00000.png deleted file mode 100644 index a073c6f..0000000 Binary files a/tests/snapshots/flex/test_get_public_key_confirm_refused/part0/00000.png and /dev/null differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_refused/part0/00001.png b/tests/snapshots/flex/test_get_public_key_confirm_refused/part0/00001.png deleted file mode 100644 index 45c08d4..0000000 Binary files a/tests/snapshots/flex/test_get_public_key_confirm_refused/part0/00001.png and /dev/null differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_refused/part0/00002.png b/tests/snapshots/flex/test_get_public_key_confirm_refused/part0/00002.png deleted file mode 100644 index e49d799..0000000 Binary files a/tests/snapshots/flex/test_get_public_key_confirm_refused/part0/00002.png and /dev/null differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_refused/part1/00000.png b/tests/snapshots/flex/test_get_public_key_confirm_refused/part1/00000.png deleted file mode 100644 index a073c6f..0000000 Binary files a/tests/snapshots/flex/test_get_public_key_confirm_refused/part1/00000.png and /dev/null differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_refused/part1/00001.png b/tests/snapshots/flex/test_get_public_key_confirm_refused/part1/00001.png deleted file mode 100644 index e231b9c..0000000 Binary files a/tests/snapshots/flex/test_get_public_key_confirm_refused/part1/00001.png and /dev/null differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_refused/part1/00002.png b/tests/snapshots/flex/test_get_public_key_confirm_refused/part1/00002.png deleted file mode 100644 index 45c08d4..0000000 Binary files a/tests/snapshots/flex/test_get_public_key_confirm_refused/part1/00002.png and /dev/null differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_refused/part1/00003.png b/tests/snapshots/flex/test_get_public_key_confirm_refused/part1/00003.png deleted file mode 100644 index e49d799..0000000 Binary files a/tests/snapshots/flex/test_get_public_key_confirm_refused/part1/00003.png and /dev/null differ diff --git a/tests/snapshots/flex/test_sign_hash_0/00000.png b/tests/snapshots/flex/test_sign_hash_0/00000.png deleted file mode 100644 index 18e17e3..0000000 Binary files a/tests/snapshots/flex/test_sign_hash_0/00000.png and /dev/null differ diff --git a/tests/snapshots/flex/test_sign_hash_0/00001.png b/tests/snapshots/flex/test_sign_hash_0/00001.png deleted file mode 100644 index f885c2f..0000000 Binary files a/tests/snapshots/flex/test_sign_hash_0/00001.png and /dev/null differ diff --git a/tests/snapshots/flex/test_sign_hash_0/00002.png b/tests/snapshots/flex/test_sign_hash_0/00002.png deleted file mode 100644 index c368bcc..0000000 Binary files a/tests/snapshots/flex/test_sign_hash_0/00002.png and /dev/null differ diff --git a/tests/snapshots/flex/test_sign_hash_0/00004.png b/tests/snapshots/flex/test_sign_hash_0/00004.png deleted file mode 100644 index e49d799..0000000 Binary files a/tests/snapshots/flex/test_sign_hash_0/00004.png and /dev/null differ diff --git a/tests/snapshots/flex/test_sign_hash_1/00000.png b/tests/snapshots/flex/test_sign_hash_1/00000.png deleted file mode 100644 index 18e17e3..0000000 Binary files a/tests/snapshots/flex/test_sign_hash_1/00000.png and /dev/null differ diff --git a/tests/snapshots/flex/test_sign_hash_1/00001.png b/tests/snapshots/flex/test_sign_hash_1/00001.png deleted file mode 100644 index 56f15f4..0000000 Binary files a/tests/snapshots/flex/test_sign_hash_1/00001.png and /dev/null differ diff --git a/tests/snapshots/flex/test_sign_hash_1/00002.png b/tests/snapshots/flex/test_sign_hash_1/00002.png deleted file mode 100644 index c368bcc..0000000 Binary files a/tests/snapshots/flex/test_sign_hash_1/00002.png and /dev/null differ diff --git a/tests/snapshots/flex/test_sign_hash_1/00004.png b/tests/snapshots/flex/test_sign_hash_1/00004.png deleted file mode 100644 index e49d799..0000000 Binary files a/tests/snapshots/flex/test_sign_hash_1/00004.png and /dev/null differ diff --git a/tests/snapshots/flex/test_sign_hash_2/00000.png b/tests/snapshots/flex/test_sign_hash_2/00000.png deleted file mode 100644 index 18e17e3..0000000 Binary files a/tests/snapshots/flex/test_sign_hash_2/00000.png and /dev/null differ diff --git a/tests/snapshots/flex/test_sign_hash_2/00001.png b/tests/snapshots/flex/test_sign_hash_2/00001.png deleted file mode 100644 index 3c1f15c..0000000 Binary files a/tests/snapshots/flex/test_sign_hash_2/00001.png and /dev/null differ diff --git a/tests/snapshots/flex/test_sign_hash_2/00002.png b/tests/snapshots/flex/test_sign_hash_2/00002.png deleted file mode 100644 index c368bcc..0000000 Binary files a/tests/snapshots/flex/test_sign_hash_2/00002.png and /dev/null differ diff --git a/tests/snapshots/flex/test_sign_hash_2/00003.png b/tests/snapshots/flex/test_sign_hash_2/00003.png deleted file mode 100644 index be51a9d..0000000 Binary files a/tests/snapshots/flex/test_sign_hash_2/00003.png and /dev/null differ diff --git a/tests/snapshots/flex/test_sign_hash_2/00004.png b/tests/snapshots/flex/test_sign_hash_2/00004.png deleted file mode 100644 index e49d799..0000000 Binary files a/tests/snapshots/flex/test_sign_hash_2/00004.png and /dev/null differ diff --git a/tests/snapshots/flex/test_sign_hash_3/00000.png b/tests/snapshots/flex/test_sign_hash_3/00000.png deleted file mode 100644 index 18e17e3..0000000 Binary files a/tests/snapshots/flex/test_sign_hash_3/00000.png and /dev/null differ diff --git a/tests/snapshots/flex/test_sign_hash_3/00001.png b/tests/snapshots/flex/test_sign_hash_3/00001.png deleted file mode 100644 index a1518a0..0000000 Binary files a/tests/snapshots/flex/test_sign_hash_3/00001.png and /dev/null differ diff --git a/tests/snapshots/flex/test_sign_hash_3/00002.png b/tests/snapshots/flex/test_sign_hash_3/00002.png deleted file mode 100644 index c368bcc..0000000 Binary files a/tests/snapshots/flex/test_sign_hash_3/00002.png and /dev/null differ diff --git a/tests/snapshots/flex/test_sign_hash_3/00003.png b/tests/snapshots/flex/test_sign_hash_3/00003.png deleted file mode 100644 index be51a9d..0000000 Binary files a/tests/snapshots/flex/test_sign_hash_3/00003.png and /dev/null differ diff --git a/tests/snapshots/flex/test_sign_hash_3/00004.png b/tests/snapshots/flex/test_sign_hash_3/00004.png deleted file mode 100644 index e49d799..0000000 Binary files a/tests/snapshots/flex/test_sign_hash_3/00004.png and /dev/null differ diff --git a/tests/snapshots/flex/test_sign_hash_4/00000.png b/tests/snapshots/flex/test_sign_hash_4/00000.png deleted file mode 100644 index 18e17e3..0000000 Binary files a/tests/snapshots/flex/test_sign_hash_4/00000.png and /dev/null differ diff --git a/tests/snapshots/flex/test_sign_hash_4/00001.png b/tests/snapshots/flex/test_sign_hash_4/00001.png deleted file mode 100644 index 43eff8e..0000000 Binary files a/tests/snapshots/flex/test_sign_hash_4/00001.png and /dev/null differ diff --git a/tests/snapshots/flex/test_sign_hash_4/00002.png b/tests/snapshots/flex/test_sign_hash_4/00002.png deleted file mode 100644 index c368bcc..0000000 Binary files a/tests/snapshots/flex/test_sign_hash_4/00002.png and /dev/null differ diff --git a/tests/snapshots/flex/test_sign_hash_4/00003.png b/tests/snapshots/flex/test_sign_hash_4/00003.png deleted file mode 100644 index be51a9d..0000000 Binary files a/tests/snapshots/flex/test_sign_hash_4/00003.png and /dev/null differ diff --git a/tests/snapshots/flex/test_sign_hash_4/00004.png b/tests/snapshots/flex/test_sign_hash_4/00004.png deleted file mode 100644 index e49d799..0000000 Binary files a/tests/snapshots/flex/test_sign_hash_4/00004.png and /dev/null differ diff --git a/tests/snapshots/flex/test_sign_hash_refused/00000.png b/tests/snapshots/flex/test_sign_hash_refused/00000.png deleted file mode 100644 index 18e17e3..0000000 Binary files a/tests/snapshots/flex/test_sign_hash_refused/00000.png and /dev/null differ diff --git a/tests/snapshots/flex/test_sign_hash_refused/00001.png b/tests/snapshots/flex/test_sign_hash_refused/00001.png deleted file mode 100644 index f885c2f..0000000 Binary files a/tests/snapshots/flex/test_sign_hash_refused/00001.png and /dev/null differ diff --git a/tests/snapshots/flex/test_sign_hash_refused/00002.png b/tests/snapshots/flex/test_sign_hash_refused/00002.png deleted file mode 100644 index 08bca22..0000000 Binary files a/tests/snapshots/flex/test_sign_hash_refused/00002.png and /dev/null differ diff --git a/tests/snapshots/flex/test_sign_hash_refused/00003.png b/tests/snapshots/flex/test_sign_hash_refused/00003.png deleted file mode 100644 index 6bbdf2f..0000000 Binary files a/tests/snapshots/flex/test_sign_hash_refused/00003.png and /dev/null differ diff --git a/tests/snapshots/flex/test_sign_hash_refused/00004.png b/tests/snapshots/flex/test_sign_hash_refused/00004.png deleted file mode 100644 index e49d799..0000000 Binary files a/tests/snapshots/flex/test_sign_hash_refused/00004.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_app_mainmenu/00000.png b/tests/snapshots/nanos/test_app_mainmenu/00000.png deleted file mode 100644 index f1a35b5..0000000 Binary files a/tests/snapshots/nanos/test_app_mainmenu/00000.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_app_mainmenu/00001.png b/tests/snapshots/nanos/test_app_mainmenu/00001.png deleted file mode 100644 index bfabcc6..0000000 Binary files a/tests/snapshots/nanos/test_app_mainmenu/00001.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_app_mainmenu/00002.png b/tests/snapshots/nanos/test_app_mainmenu/00002.png deleted file mode 100644 index 3476b97..0000000 Binary files a/tests/snapshots/nanos/test_app_mainmenu/00002.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_app_mainmenu/00003.png b/tests/snapshots/nanos/test_app_mainmenu/00003.png deleted file mode 100644 index e227980..0000000 Binary files a/tests/snapshots/nanos/test_app_mainmenu/00003.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_get_public_key_confirm_accepted/00000.png b/tests/snapshots/nanos/test_get_public_key_confirm_accepted/00000.png deleted file mode 100644 index 4e35a9f..0000000 Binary files a/tests/snapshots/nanos/test_get_public_key_confirm_accepted/00000.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_get_public_key_confirm_accepted/00001.png b/tests/snapshots/nanos/test_get_public_key_confirm_accepted/00001.png deleted file mode 100644 index 0a346e6..0000000 Binary files a/tests/snapshots/nanos/test_get_public_key_confirm_accepted/00001.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_get_public_key_confirm_accepted/00002.png b/tests/snapshots/nanos/test_get_public_key_confirm_accepted/00002.png deleted file mode 100644 index 658b89f..0000000 Binary files a/tests/snapshots/nanos/test_get_public_key_confirm_accepted/00002.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_get_public_key_confirm_accepted/00003.png b/tests/snapshots/nanos/test_get_public_key_confirm_accepted/00003.png deleted file mode 100644 index a0a4b8c..0000000 Binary files a/tests/snapshots/nanos/test_get_public_key_confirm_accepted/00003.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_get_public_key_confirm_accepted/00004.png b/tests/snapshots/nanos/test_get_public_key_confirm_accepted/00004.png deleted file mode 100644 index 9722004..0000000 Binary files a/tests/snapshots/nanos/test_get_public_key_confirm_accepted/00004.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_get_public_key_confirm_accepted/00005.png b/tests/snapshots/nanos/test_get_public_key_confirm_accepted/00005.png deleted file mode 100644 index 4a4259c..0000000 Binary files a/tests/snapshots/nanos/test_get_public_key_confirm_accepted/00005.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_get_public_key_confirm_accepted/00006.png b/tests/snapshots/nanos/test_get_public_key_confirm_accepted/00006.png deleted file mode 100644 index 9f595ac..0000000 Binary files a/tests/snapshots/nanos/test_get_public_key_confirm_accepted/00006.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_get_public_key_confirm_accepted/00007.png b/tests/snapshots/nanos/test_get_public_key_confirm_accepted/00007.png deleted file mode 100644 index f1a35b5..0000000 Binary files a/tests/snapshots/nanos/test_get_public_key_confirm_accepted/00007.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_get_public_key_confirm_refused/00000.png b/tests/snapshots/nanos/test_get_public_key_confirm_refused/00000.png deleted file mode 100644 index 4e35a9f..0000000 Binary files a/tests/snapshots/nanos/test_get_public_key_confirm_refused/00000.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_get_public_key_confirm_refused/00001.png b/tests/snapshots/nanos/test_get_public_key_confirm_refused/00001.png deleted file mode 100644 index 0a346e6..0000000 Binary files a/tests/snapshots/nanos/test_get_public_key_confirm_refused/00001.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_get_public_key_confirm_refused/00002.png b/tests/snapshots/nanos/test_get_public_key_confirm_refused/00002.png deleted file mode 100644 index 658b89f..0000000 Binary files a/tests/snapshots/nanos/test_get_public_key_confirm_refused/00002.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_get_public_key_confirm_refused/00003.png b/tests/snapshots/nanos/test_get_public_key_confirm_refused/00003.png deleted file mode 100644 index a0a4b8c..0000000 Binary files a/tests/snapshots/nanos/test_get_public_key_confirm_refused/00003.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_get_public_key_confirm_refused/00004.png b/tests/snapshots/nanos/test_get_public_key_confirm_refused/00004.png deleted file mode 100644 index 9722004..0000000 Binary files a/tests/snapshots/nanos/test_get_public_key_confirm_refused/00004.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_get_public_key_confirm_refused/00005.png b/tests/snapshots/nanos/test_get_public_key_confirm_refused/00005.png deleted file mode 100644 index 4a4259c..0000000 Binary files a/tests/snapshots/nanos/test_get_public_key_confirm_refused/00005.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_get_public_key_confirm_refused/00006.png b/tests/snapshots/nanos/test_get_public_key_confirm_refused/00006.png deleted file mode 100644 index f1a35b5..0000000 Binary files a/tests/snapshots/nanos/test_get_public_key_confirm_refused/00006.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_0/00000.png b/tests/snapshots/nanos/test_sign_hash_0/00000.png deleted file mode 100644 index 80a4f74..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_0/00000.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_0/00001.png b/tests/snapshots/nanos/test_sign_hash_0/00001.png deleted file mode 100644 index 83a4e8c..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_0/00001.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_0/00002.png b/tests/snapshots/nanos/test_sign_hash_0/00002.png deleted file mode 100644 index b5b3aab..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_0/00002.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_0/00003.png b/tests/snapshots/nanos/test_sign_hash_0/00003.png deleted file mode 100644 index 521a23f..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_0/00003.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_0/00004.png b/tests/snapshots/nanos/test_sign_hash_0/00004.png deleted file mode 100644 index ead3737..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_0/00004.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_0/00005.png b/tests/snapshots/nanos/test_sign_hash_0/00005.png deleted file mode 100644 index 4a4259c..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_0/00005.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_0/00006.png b/tests/snapshots/nanos/test_sign_hash_0/00006.png deleted file mode 100644 index 9f595ac..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_0/00006.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_0/00007.png b/tests/snapshots/nanos/test_sign_hash_0/00007.png deleted file mode 100644 index f1a35b5..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_0/00007.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_1/00000.png b/tests/snapshots/nanos/test_sign_hash_1/00000.png deleted file mode 100644 index 80a4f74..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_1/00000.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_1/00001.png b/tests/snapshots/nanos/test_sign_hash_1/00001.png deleted file mode 100644 index c85e079..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_1/00001.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_1/00002.png b/tests/snapshots/nanos/test_sign_hash_1/00002.png deleted file mode 100644 index 7d4712f..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_1/00002.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_1/00003.png b/tests/snapshots/nanos/test_sign_hash_1/00003.png deleted file mode 100644 index 009f47d..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_1/00003.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_1/00004.png b/tests/snapshots/nanos/test_sign_hash_1/00004.png deleted file mode 100644 index 3295a1c..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_1/00004.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_1/00005.png b/tests/snapshots/nanos/test_sign_hash_1/00005.png deleted file mode 100644 index 4a4259c..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_1/00005.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_1/00006.png b/tests/snapshots/nanos/test_sign_hash_1/00006.png deleted file mode 100644 index 9f595ac..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_1/00006.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_1/00007.png b/tests/snapshots/nanos/test_sign_hash_1/00007.png deleted file mode 100644 index f1a35b5..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_1/00007.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_2/00000.png b/tests/snapshots/nanos/test_sign_hash_2/00000.png deleted file mode 100644 index 80a4f74..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_2/00000.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_2/00001.png b/tests/snapshots/nanos/test_sign_hash_2/00001.png deleted file mode 100644 index e0268c2..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_2/00001.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_2/00002.png b/tests/snapshots/nanos/test_sign_hash_2/00002.png deleted file mode 100644 index e8e6593..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_2/00002.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_2/00003.png b/tests/snapshots/nanos/test_sign_hash_2/00003.png deleted file mode 100644 index e71e50e..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_2/00003.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_2/00004.png b/tests/snapshots/nanos/test_sign_hash_2/00004.png deleted file mode 100644 index 87b08ea..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_2/00004.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_2/00005.png b/tests/snapshots/nanos/test_sign_hash_2/00005.png deleted file mode 100644 index 4a4259c..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_2/00005.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_2/00006.png b/tests/snapshots/nanos/test_sign_hash_2/00006.png deleted file mode 100644 index 9f595ac..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_2/00006.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_2/00007.png b/tests/snapshots/nanos/test_sign_hash_2/00007.png deleted file mode 100644 index f1a35b5..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_2/00007.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_3/00000.png b/tests/snapshots/nanos/test_sign_hash_3/00000.png deleted file mode 100644 index 80a4f74..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_3/00000.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_3/00001.png b/tests/snapshots/nanos/test_sign_hash_3/00001.png deleted file mode 100644 index d83f1e1..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_3/00001.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_3/00002.png b/tests/snapshots/nanos/test_sign_hash_3/00002.png deleted file mode 100644 index a05d1e8..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_3/00002.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_3/00003.png b/tests/snapshots/nanos/test_sign_hash_3/00003.png deleted file mode 100644 index b8d4687..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_3/00003.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_3/00004.png b/tests/snapshots/nanos/test_sign_hash_3/00004.png deleted file mode 100644 index 9bb350a..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_3/00004.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_3/00005.png b/tests/snapshots/nanos/test_sign_hash_3/00005.png deleted file mode 100644 index 4a4259c..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_3/00005.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_3/00006.png b/tests/snapshots/nanos/test_sign_hash_3/00006.png deleted file mode 100644 index 9f595ac..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_3/00006.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_3/00007.png b/tests/snapshots/nanos/test_sign_hash_3/00007.png deleted file mode 100644 index f1a35b5..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_3/00007.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_4/00000.png b/tests/snapshots/nanos/test_sign_hash_4/00000.png deleted file mode 100644 index 80a4f74..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_4/00000.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_4/00001.png b/tests/snapshots/nanos/test_sign_hash_4/00001.png deleted file mode 100644 index 0401a72..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_4/00001.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_4/00002.png b/tests/snapshots/nanos/test_sign_hash_4/00002.png deleted file mode 100644 index b1a80e4..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_4/00002.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_4/00003.png b/tests/snapshots/nanos/test_sign_hash_4/00003.png deleted file mode 100644 index 6af79a2..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_4/00003.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_4/00004.png b/tests/snapshots/nanos/test_sign_hash_4/00004.png deleted file mode 100644 index 8f05980..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_4/00004.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_4/00005.png b/tests/snapshots/nanos/test_sign_hash_4/00005.png deleted file mode 100644 index 4a4259c..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_4/00005.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_4/00006.png b/tests/snapshots/nanos/test_sign_hash_4/00006.png deleted file mode 100644 index 9f595ac..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_4/00006.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_4/00007.png b/tests/snapshots/nanos/test_sign_hash_4/00007.png deleted file mode 100644 index f1a35b5..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_4/00007.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_refused/00000.png b/tests/snapshots/nanos/test_sign_hash_refused/00000.png deleted file mode 100644 index 80a4f74..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_refused/00000.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_refused/00001.png b/tests/snapshots/nanos/test_sign_hash_refused/00001.png deleted file mode 100644 index 83a4e8c..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_refused/00001.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_refused/00002.png b/tests/snapshots/nanos/test_sign_hash_refused/00002.png deleted file mode 100644 index b5b3aab..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_refused/00002.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_refused/00003.png b/tests/snapshots/nanos/test_sign_hash_refused/00003.png deleted file mode 100644 index 521a23f..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_refused/00003.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_refused/00004.png b/tests/snapshots/nanos/test_sign_hash_refused/00004.png deleted file mode 100644 index ead3737..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_refused/00004.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_refused/00005.png b/tests/snapshots/nanos/test_sign_hash_refused/00005.png deleted file mode 100644 index 4a4259c..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_refused/00005.png and /dev/null differ diff --git a/tests/snapshots/nanos/test_sign_hash_refused/00006.png b/tests/snapshots/nanos/test_sign_hash_refused/00006.png deleted file mode 100644 index f1a35b5..0000000 Binary files a/tests/snapshots/nanos/test_sign_hash_refused/00006.png and /dev/null differ diff --git a/tests/snapshots/nanosp/test_app_mainmenu/00001.png b/tests/snapshots/nanosp/test_app_mainmenu/00001.png index e9dc659..7d01ff2 100644 Binary files a/tests/snapshots/nanosp/test_app_mainmenu/00001.png and b/tests/snapshots/nanosp/test_app_mainmenu/00001.png differ diff --git a/tests/snapshots/nanosp/test_blind_sign_tx/00000.png b/tests/snapshots/nanosp/test_blind_sign_tx/00000.png new file mode 100644 index 0000000..c119bb3 Binary files /dev/null and b/tests/snapshots/nanosp/test_blind_sign_tx/00000.png differ diff --git a/tests/snapshots/nanosp/test_blind_sign_tx/00001.png b/tests/snapshots/nanosp/test_blind_sign_tx/00001.png new file mode 100644 index 0000000..7e84956 Binary files /dev/null and b/tests/snapshots/nanosp/test_blind_sign_tx/00001.png differ diff --git a/tests/snapshots/nanosp/test_blind_sign_tx/00002.png b/tests/snapshots/nanosp/test_blind_sign_tx/00002.png new file mode 100644 index 0000000..6cb2ed9 Binary files /dev/null and b/tests/snapshots/nanosp/test_blind_sign_tx/00002.png differ diff --git a/tests/snapshots/nanosp/test_blind_sign_tx/00003.png b/tests/snapshots/nanosp/test_blind_sign_tx/00003.png new file mode 100644 index 0000000..62530f7 Binary files /dev/null and b/tests/snapshots/nanosp/test_blind_sign_tx/00003.png differ diff --git a/tests/snapshots/nanosp/test_blind_sign_tx/00004.png b/tests/snapshots/nanosp/test_blind_sign_tx/00004.png new file mode 100644 index 0000000..b7efd00 Binary files /dev/null and b/tests/snapshots/nanosp/test_blind_sign_tx/00004.png differ diff --git a/tests/snapshots/nanosp/test_sign_hash_0/00003.png b/tests/snapshots/nanosp/test_blind_sign_tx/00005.png similarity index 100% rename from tests/snapshots/nanosp/test_sign_hash_0/00003.png rename to tests/snapshots/nanosp/test_blind_sign_tx/00005.png diff --git a/tests/snapshots/nanosp/test_blind_sign_tx/00006.png b/tests/snapshots/nanosp/test_blind_sign_tx/00006.png new file mode 100644 index 0000000..839ace9 Binary files /dev/null and b/tests/snapshots/nanosp/test_blind_sign_tx/00006.png differ diff --git a/tests/snapshots/nanosp/test_sign_hash_0/00000.png b/tests/snapshots/nanosp/test_blind_sign_tx/00007.png similarity index 100% rename from tests/snapshots/nanosp/test_sign_hash_0/00000.png rename to tests/snapshots/nanosp/test_blind_sign_tx/00007.png diff --git a/tests/snapshots/nanosp/test_blind_sign_tx/00008.png b/tests/snapshots/nanosp/test_blind_sign_tx/00008.png new file mode 100644 index 0000000..97984bf Binary files /dev/null and b/tests/snapshots/nanosp/test_blind_sign_tx/00008.png differ diff --git a/tests/snapshots/nanosp/test_blind_sign_tx/00009.png b/tests/snapshots/nanosp/test_blind_sign_tx/00009.png new file mode 100644 index 0000000..a55a82a Binary files /dev/null and b/tests/snapshots/nanosp/test_blind_sign_tx/00009.png differ diff --git a/tests/snapshots/nanosp/test_sign_hash_1/00003.png b/tests/snapshots/nanosp/test_blind_sign_tx/00010.png similarity index 100% rename from tests/snapshots/nanosp/test_sign_hash_1/00003.png rename to tests/snapshots/nanosp/test_blind_sign_tx/00010.png diff --git a/tests/snapshots/nanosp/test_sign_hash_0/00004.png b/tests/snapshots/nanosp/test_blind_sign_tx/00011.png similarity index 100% rename from tests/snapshots/nanosp/test_sign_hash_0/00004.png rename to tests/snapshots/nanosp/test_blind_sign_tx/00011.png diff --git a/tests/snapshots/nanosp/test_sign_hash_0/00005.png b/tests/snapshots/nanosp/test_blind_sign_tx/00012.png similarity index 100% rename from tests/snapshots/nanosp/test_sign_hash_0/00005.png rename to tests/snapshots/nanosp/test_blind_sign_tx/00012.png diff --git a/tests/snapshots/nanosp/test_clear_sign_tx/00000.png b/tests/snapshots/nanosp/test_clear_sign_tx/00000.png new file mode 100644 index 0000000..59eafe1 Binary files /dev/null and b/tests/snapshots/nanosp/test_clear_sign_tx/00000.png differ diff --git a/tests/snapshots/nanosp/test_clear_sign_tx/00001.png b/tests/snapshots/nanosp/test_clear_sign_tx/00001.png new file mode 100644 index 0000000..ccb7ba1 Binary files /dev/null and b/tests/snapshots/nanosp/test_clear_sign_tx/00001.png differ diff --git a/tests/snapshots/nanosp/test_clear_sign_tx/00002.png b/tests/snapshots/nanosp/test_clear_sign_tx/00002.png new file mode 100644 index 0000000..fef303d Binary files /dev/null and b/tests/snapshots/nanosp/test_clear_sign_tx/00002.png differ diff --git a/tests/snapshots/nanosp/test_clear_sign_tx/00003.png b/tests/snapshots/nanosp/test_clear_sign_tx/00003.png new file mode 100644 index 0000000..69c2712 Binary files /dev/null and b/tests/snapshots/nanosp/test_clear_sign_tx/00003.png differ diff --git a/tests/snapshots/nanosp/test_clear_sign_tx/00004.png b/tests/snapshots/nanosp/test_clear_sign_tx/00004.png new file mode 100644 index 0000000..20e4f0e Binary files /dev/null and b/tests/snapshots/nanosp/test_clear_sign_tx/00004.png differ diff --git a/tests/snapshots/nanosp/test_clear_sign_tx/00005.png b/tests/snapshots/nanosp/test_clear_sign_tx/00005.png new file mode 100644 index 0000000..b106acc Binary files /dev/null and b/tests/snapshots/nanosp/test_clear_sign_tx/00005.png differ diff --git a/tests/snapshots/nanosp/test_clear_sign_tx/00006.png b/tests/snapshots/nanosp/test_clear_sign_tx/00006.png new file mode 100644 index 0000000..bdca6c4 Binary files /dev/null and b/tests/snapshots/nanosp/test_clear_sign_tx/00006.png differ diff --git a/tests/snapshots/nanosp/test_clear_sign_tx/00007.png b/tests/snapshots/nanosp/test_clear_sign_tx/00007.png new file mode 100644 index 0000000..5164075 Binary files /dev/null and b/tests/snapshots/nanosp/test_clear_sign_tx/00007.png differ diff --git a/tests/snapshots/nanosp/test_sign_hash_2/00003.png b/tests/snapshots/nanosp/test_clear_sign_tx/00008.png similarity index 100% rename from tests/snapshots/nanosp/test_sign_hash_2/00003.png rename to tests/snapshots/nanosp/test_clear_sign_tx/00008.png diff --git a/tests/snapshots/nanosp/test_sign_hash_1/00004.png b/tests/snapshots/nanosp/test_clear_sign_tx/00009.png similarity index 100% rename from tests/snapshots/nanosp/test_sign_hash_1/00004.png rename to tests/snapshots/nanosp/test_clear_sign_tx/00009.png diff --git a/tests/snapshots/nanosp/test_sign_hash_1/00005.png b/tests/snapshots/nanosp/test_clear_sign_tx/00010.png similarity index 100% rename from tests/snapshots/nanosp/test_sign_hash_1/00005.png rename to tests/snapshots/nanosp/test_clear_sign_tx/00010.png diff --git a/tests/snapshots/nanosp/test_sign_hash_0/00001.png b/tests/snapshots/nanosp/test_sign_hash_0/00001.png deleted file mode 100644 index e13711b..0000000 Binary files a/tests/snapshots/nanosp/test_sign_hash_0/00001.png and /dev/null differ diff --git a/tests/snapshots/nanosp/test_sign_hash_0/00002.png b/tests/snapshots/nanosp/test_sign_hash_0/00002.png deleted file mode 100644 index 82bf276..0000000 Binary files a/tests/snapshots/nanosp/test_sign_hash_0/00002.png and /dev/null differ diff --git a/tests/snapshots/nanosp/test_sign_hash_1/00001.png b/tests/snapshots/nanosp/test_sign_hash_1/00001.png deleted file mode 100644 index 28d9cb1..0000000 Binary files a/tests/snapshots/nanosp/test_sign_hash_1/00001.png and /dev/null differ diff --git a/tests/snapshots/nanosp/test_sign_hash_1/00002.png b/tests/snapshots/nanosp/test_sign_hash_1/00002.png deleted file mode 100644 index 00f9bb2..0000000 Binary files a/tests/snapshots/nanosp/test_sign_hash_1/00002.png and /dev/null differ diff --git a/tests/snapshots/nanosp/test_sign_hash_2/00000.png b/tests/snapshots/nanosp/test_sign_hash_2/00000.png deleted file mode 100644 index 15c7c5e..0000000 Binary files a/tests/snapshots/nanosp/test_sign_hash_2/00000.png and /dev/null differ diff --git a/tests/snapshots/nanosp/test_sign_hash_2/00001.png b/tests/snapshots/nanosp/test_sign_hash_2/00001.png deleted file mode 100644 index 76de081..0000000 Binary files a/tests/snapshots/nanosp/test_sign_hash_2/00001.png and /dev/null differ diff --git a/tests/snapshots/nanosp/test_sign_hash_2/00002.png b/tests/snapshots/nanosp/test_sign_hash_2/00002.png deleted file mode 100644 index 1b22257..0000000 Binary files a/tests/snapshots/nanosp/test_sign_hash_2/00002.png and /dev/null differ diff --git a/tests/snapshots/nanosp/test_sign_hash_3/00000.png b/tests/snapshots/nanosp/test_sign_hash_3/00000.png deleted file mode 100644 index 15c7c5e..0000000 Binary files a/tests/snapshots/nanosp/test_sign_hash_3/00000.png and /dev/null differ diff --git a/tests/snapshots/nanosp/test_sign_hash_3/00001.png b/tests/snapshots/nanosp/test_sign_hash_3/00001.png deleted file mode 100644 index aa74d66..0000000 Binary files a/tests/snapshots/nanosp/test_sign_hash_3/00001.png and /dev/null differ diff --git a/tests/snapshots/nanosp/test_sign_hash_3/00002.png b/tests/snapshots/nanosp/test_sign_hash_3/00002.png deleted file mode 100644 index aff616c..0000000 Binary files a/tests/snapshots/nanosp/test_sign_hash_3/00002.png and /dev/null differ diff --git a/tests/snapshots/nanosp/test_sign_hash_4/00000.png b/tests/snapshots/nanosp/test_sign_hash_4/00000.png deleted file mode 100644 index 15c7c5e..0000000 Binary files a/tests/snapshots/nanosp/test_sign_hash_4/00000.png and /dev/null differ diff --git a/tests/snapshots/nanosp/test_sign_hash_4/00001.png b/tests/snapshots/nanosp/test_sign_hash_4/00001.png deleted file mode 100644 index 9814943..0000000 Binary files a/tests/snapshots/nanosp/test_sign_hash_4/00001.png and /dev/null differ diff --git a/tests/snapshots/nanosp/test_sign_hash_4/00002.png b/tests/snapshots/nanosp/test_sign_hash_4/00002.png deleted file mode 100644 index e01c5cd..0000000 Binary files a/tests/snapshots/nanosp/test_sign_hash_4/00002.png and /dev/null differ diff --git a/tests/snapshots/nanosp/test_sign_hash_4/00004.png b/tests/snapshots/nanosp/test_sign_hash_4/00004.png deleted file mode 100644 index 141aeeb..0000000 Binary files a/tests/snapshots/nanosp/test_sign_hash_4/00004.png and /dev/null differ diff --git a/tests/snapshots/nanosp/test_sign_hash_4/00005.png b/tests/snapshots/nanosp/test_sign_hash_4/00005.png deleted file mode 100644 index 29f7b77..0000000 Binary files a/tests/snapshots/nanosp/test_sign_hash_4/00005.png and /dev/null differ diff --git a/tests/snapshots/nanosp/test_sign_hash_refused/00000.png b/tests/snapshots/nanosp/test_sign_hash_refused/00000.png deleted file mode 100644 index 15c7c5e..0000000 Binary files a/tests/snapshots/nanosp/test_sign_hash_refused/00000.png and /dev/null differ diff --git a/tests/snapshots/nanosp/test_sign_hash_refused/00001.png b/tests/snapshots/nanosp/test_sign_hash_refused/00001.png deleted file mode 100644 index e13711b..0000000 Binary files a/tests/snapshots/nanosp/test_sign_hash_refused/00001.png and /dev/null differ diff --git a/tests/snapshots/nanosp/test_sign_hash_refused/00002.png b/tests/snapshots/nanosp/test_sign_hash_refused/00002.png deleted file mode 100644 index 82bf276..0000000 Binary files a/tests/snapshots/nanosp/test_sign_hash_refused/00002.png and /dev/null differ diff --git a/tests/snapshots/nanosp/test_sign_hash_refused/00004.png b/tests/snapshots/nanosp/test_sign_hash_refused/00004.png deleted file mode 100644 index 29f7b77..0000000 Binary files a/tests/snapshots/nanosp/test_sign_hash_refused/00004.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_app_mainmenu/00001.png b/tests/snapshots/nanox/test_app_mainmenu/00001.png index e9dc659..7d01ff2 100644 Binary files a/tests/snapshots/nanox/test_app_mainmenu/00001.png and b/tests/snapshots/nanox/test_app_mainmenu/00001.png differ diff --git a/tests/snapshots/nanox/test_blind_sign_tx/00000.png b/tests/snapshots/nanox/test_blind_sign_tx/00000.png new file mode 100644 index 0000000..c119bb3 Binary files /dev/null and b/tests/snapshots/nanox/test_blind_sign_tx/00000.png differ diff --git a/tests/snapshots/nanox/test_blind_sign_tx/00001.png b/tests/snapshots/nanox/test_blind_sign_tx/00001.png new file mode 100644 index 0000000..7e84956 Binary files /dev/null and b/tests/snapshots/nanox/test_blind_sign_tx/00001.png differ diff --git a/tests/snapshots/nanox/test_blind_sign_tx/00002.png b/tests/snapshots/nanox/test_blind_sign_tx/00002.png new file mode 100644 index 0000000..6cb2ed9 Binary files /dev/null and b/tests/snapshots/nanox/test_blind_sign_tx/00002.png differ diff --git a/tests/snapshots/nanox/test_blind_sign_tx/00003.png b/tests/snapshots/nanox/test_blind_sign_tx/00003.png new file mode 100644 index 0000000..62530f7 Binary files /dev/null and b/tests/snapshots/nanox/test_blind_sign_tx/00003.png differ diff --git a/tests/snapshots/nanox/test_blind_sign_tx/00004.png b/tests/snapshots/nanox/test_blind_sign_tx/00004.png new file mode 100644 index 0000000..b7efd00 Binary files /dev/null and b/tests/snapshots/nanox/test_blind_sign_tx/00004.png differ diff --git a/tests/snapshots/nanosp/test_sign_hash_3/00003.png b/tests/snapshots/nanox/test_blind_sign_tx/00005.png similarity index 100% rename from tests/snapshots/nanosp/test_sign_hash_3/00003.png rename to tests/snapshots/nanox/test_blind_sign_tx/00005.png diff --git a/tests/snapshots/nanox/test_blind_sign_tx/00006.png b/tests/snapshots/nanox/test_blind_sign_tx/00006.png new file mode 100644 index 0000000..839ace9 Binary files /dev/null and b/tests/snapshots/nanox/test_blind_sign_tx/00006.png differ diff --git a/tests/snapshots/nanosp/test_sign_hash_1/00000.png b/tests/snapshots/nanox/test_blind_sign_tx/00007.png similarity index 100% rename from tests/snapshots/nanosp/test_sign_hash_1/00000.png rename to tests/snapshots/nanox/test_blind_sign_tx/00007.png diff --git a/tests/snapshots/nanox/test_blind_sign_tx/00008.png b/tests/snapshots/nanox/test_blind_sign_tx/00008.png new file mode 100644 index 0000000..97984bf Binary files /dev/null and b/tests/snapshots/nanox/test_blind_sign_tx/00008.png differ diff --git a/tests/snapshots/nanox/test_blind_sign_tx/00009.png b/tests/snapshots/nanox/test_blind_sign_tx/00009.png new file mode 100644 index 0000000..a55a82a Binary files /dev/null and b/tests/snapshots/nanox/test_blind_sign_tx/00009.png differ diff --git a/tests/snapshots/nanosp/test_sign_hash_4/00003.png b/tests/snapshots/nanox/test_blind_sign_tx/00010.png similarity index 100% rename from tests/snapshots/nanosp/test_sign_hash_4/00003.png rename to tests/snapshots/nanox/test_blind_sign_tx/00010.png diff --git a/tests/snapshots/nanosp/test_sign_hash_2/00004.png b/tests/snapshots/nanox/test_blind_sign_tx/00011.png similarity index 100% rename from tests/snapshots/nanosp/test_sign_hash_2/00004.png rename to tests/snapshots/nanox/test_blind_sign_tx/00011.png diff --git a/tests/snapshots/nanosp/test_sign_hash_2/00005.png b/tests/snapshots/nanox/test_blind_sign_tx/00012.png similarity index 100% rename from tests/snapshots/nanosp/test_sign_hash_2/00005.png rename to tests/snapshots/nanox/test_blind_sign_tx/00012.png diff --git a/tests/snapshots/nanox/test_clear_sign_tx/00000.png b/tests/snapshots/nanox/test_clear_sign_tx/00000.png new file mode 100644 index 0000000..59eafe1 Binary files /dev/null and b/tests/snapshots/nanox/test_clear_sign_tx/00000.png differ diff --git a/tests/snapshots/nanox/test_clear_sign_tx/00001.png b/tests/snapshots/nanox/test_clear_sign_tx/00001.png new file mode 100644 index 0000000..ccb7ba1 Binary files /dev/null and b/tests/snapshots/nanox/test_clear_sign_tx/00001.png differ diff --git a/tests/snapshots/nanox/test_clear_sign_tx/00002.png b/tests/snapshots/nanox/test_clear_sign_tx/00002.png new file mode 100644 index 0000000..fef303d Binary files /dev/null and b/tests/snapshots/nanox/test_clear_sign_tx/00002.png differ diff --git a/tests/snapshots/nanox/test_clear_sign_tx/00003.png b/tests/snapshots/nanox/test_clear_sign_tx/00003.png new file mode 100644 index 0000000..69c2712 Binary files /dev/null and b/tests/snapshots/nanox/test_clear_sign_tx/00003.png differ diff --git a/tests/snapshots/nanox/test_clear_sign_tx/00004.png b/tests/snapshots/nanox/test_clear_sign_tx/00004.png new file mode 100644 index 0000000..20e4f0e Binary files /dev/null and b/tests/snapshots/nanox/test_clear_sign_tx/00004.png differ diff --git a/tests/snapshots/nanox/test_clear_sign_tx/00005.png b/tests/snapshots/nanox/test_clear_sign_tx/00005.png new file mode 100644 index 0000000..b106acc Binary files /dev/null and b/tests/snapshots/nanox/test_clear_sign_tx/00005.png differ diff --git a/tests/snapshots/nanox/test_clear_sign_tx/00006.png b/tests/snapshots/nanox/test_clear_sign_tx/00006.png new file mode 100644 index 0000000..bdca6c4 Binary files /dev/null and b/tests/snapshots/nanox/test_clear_sign_tx/00006.png differ diff --git a/tests/snapshots/nanox/test_clear_sign_tx/00007.png b/tests/snapshots/nanox/test_clear_sign_tx/00007.png new file mode 100644 index 0000000..5164075 Binary files /dev/null and b/tests/snapshots/nanox/test_clear_sign_tx/00007.png differ diff --git a/tests/snapshots/nanosp/test_sign_hash_refused/00003.png b/tests/snapshots/nanox/test_clear_sign_tx/00008.png similarity index 100% rename from tests/snapshots/nanosp/test_sign_hash_refused/00003.png rename to tests/snapshots/nanox/test_clear_sign_tx/00008.png diff --git a/tests/snapshots/nanosp/test_sign_hash_3/00004.png b/tests/snapshots/nanox/test_clear_sign_tx/00009.png similarity index 100% rename from tests/snapshots/nanosp/test_sign_hash_3/00004.png rename to tests/snapshots/nanox/test_clear_sign_tx/00009.png diff --git a/tests/snapshots/nanosp/test_sign_hash_3/00005.png b/tests/snapshots/nanox/test_clear_sign_tx/00010.png similarity index 100% rename from tests/snapshots/nanosp/test_sign_hash_3/00005.png rename to tests/snapshots/nanox/test_clear_sign_tx/00010.png diff --git a/tests/snapshots/nanox/test_sign_hash_0/00000.png b/tests/snapshots/nanox/test_sign_hash_0/00000.png deleted file mode 100644 index 15c7c5e..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_0/00000.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_0/00001.png b/tests/snapshots/nanox/test_sign_hash_0/00001.png deleted file mode 100644 index e13711b..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_0/00001.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_0/00002.png b/tests/snapshots/nanox/test_sign_hash_0/00002.png deleted file mode 100644 index 82bf276..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_0/00002.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_0/00003.png b/tests/snapshots/nanox/test_sign_hash_0/00003.png deleted file mode 100644 index 40b6e21..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_0/00003.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_0/00004.png b/tests/snapshots/nanox/test_sign_hash_0/00004.png deleted file mode 100644 index 141aeeb..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_0/00004.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_0/00005.png b/tests/snapshots/nanox/test_sign_hash_0/00005.png deleted file mode 100644 index 29f7b77..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_0/00005.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_1/00000.png b/tests/snapshots/nanox/test_sign_hash_1/00000.png deleted file mode 100644 index 15c7c5e..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_1/00000.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_1/00001.png b/tests/snapshots/nanox/test_sign_hash_1/00001.png deleted file mode 100644 index 28d9cb1..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_1/00001.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_1/00002.png b/tests/snapshots/nanox/test_sign_hash_1/00002.png deleted file mode 100644 index 00f9bb2..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_1/00002.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_1/00003.png b/tests/snapshots/nanox/test_sign_hash_1/00003.png deleted file mode 100644 index 40b6e21..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_1/00003.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_1/00004.png b/tests/snapshots/nanox/test_sign_hash_1/00004.png deleted file mode 100644 index 141aeeb..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_1/00004.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_1/00005.png b/tests/snapshots/nanox/test_sign_hash_1/00005.png deleted file mode 100644 index 29f7b77..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_1/00005.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_2/00000.png b/tests/snapshots/nanox/test_sign_hash_2/00000.png deleted file mode 100644 index 15c7c5e..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_2/00000.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_2/00001.png b/tests/snapshots/nanox/test_sign_hash_2/00001.png deleted file mode 100644 index 76de081..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_2/00001.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_2/00002.png b/tests/snapshots/nanox/test_sign_hash_2/00002.png deleted file mode 100644 index 1b22257..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_2/00002.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_2/00003.png b/tests/snapshots/nanox/test_sign_hash_2/00003.png deleted file mode 100644 index 40b6e21..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_2/00003.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_2/00004.png b/tests/snapshots/nanox/test_sign_hash_2/00004.png deleted file mode 100644 index 141aeeb..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_2/00004.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_2/00005.png b/tests/snapshots/nanox/test_sign_hash_2/00005.png deleted file mode 100644 index 29f7b77..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_2/00005.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_3/00000.png b/tests/snapshots/nanox/test_sign_hash_3/00000.png deleted file mode 100644 index 15c7c5e..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_3/00000.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_3/00001.png b/tests/snapshots/nanox/test_sign_hash_3/00001.png deleted file mode 100644 index aa74d66..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_3/00001.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_3/00002.png b/tests/snapshots/nanox/test_sign_hash_3/00002.png deleted file mode 100644 index aff616c..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_3/00002.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_3/00003.png b/tests/snapshots/nanox/test_sign_hash_3/00003.png deleted file mode 100644 index 40b6e21..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_3/00003.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_3/00004.png b/tests/snapshots/nanox/test_sign_hash_3/00004.png deleted file mode 100644 index 141aeeb..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_3/00004.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_3/00005.png b/tests/snapshots/nanox/test_sign_hash_3/00005.png deleted file mode 100644 index 29f7b77..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_3/00005.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_4/00000.png b/tests/snapshots/nanox/test_sign_hash_4/00000.png deleted file mode 100644 index 15c7c5e..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_4/00000.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_4/00001.png b/tests/snapshots/nanox/test_sign_hash_4/00001.png deleted file mode 100644 index 9814943..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_4/00001.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_4/00002.png b/tests/snapshots/nanox/test_sign_hash_4/00002.png deleted file mode 100644 index e01c5cd..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_4/00002.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_4/00003.png b/tests/snapshots/nanox/test_sign_hash_4/00003.png deleted file mode 100644 index 40b6e21..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_4/00003.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_4/00004.png b/tests/snapshots/nanox/test_sign_hash_4/00004.png deleted file mode 100644 index 141aeeb..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_4/00004.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_4/00005.png b/tests/snapshots/nanox/test_sign_hash_4/00005.png deleted file mode 100644 index 29f7b77..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_4/00005.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_refused/00000.png b/tests/snapshots/nanox/test_sign_hash_refused/00000.png deleted file mode 100644 index 15c7c5e..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_refused/00000.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_refused/00001.png b/tests/snapshots/nanox/test_sign_hash_refused/00001.png deleted file mode 100644 index e13711b..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_refused/00001.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_refused/00002.png b/tests/snapshots/nanox/test_sign_hash_refused/00002.png deleted file mode 100644 index 82bf276..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_refused/00002.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_refused/00003.png b/tests/snapshots/nanox/test_sign_hash_refused/00003.png deleted file mode 100644 index 40b6e21..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_refused/00003.png and /dev/null differ diff --git a/tests/snapshots/nanox/test_sign_hash_refused/00004.png b/tests/snapshots/nanox/test_sign_hash_refused/00004.png deleted file mode 100644 index 29f7b77..0000000 Binary files a/tests/snapshots/nanox/test_sign_hash_refused/00004.png and /dev/null differ diff --git a/tests/snapshots/stax/test_app_mainmenu/00000.png b/tests/snapshots/stax/test_app_mainmenu/00000.png index d4ca2b2..501267e 100644 Binary files a/tests/snapshots/stax/test_app_mainmenu/00000.png and b/tests/snapshots/stax/test_app_mainmenu/00000.png differ diff --git a/tests/snapshots/stax/test_app_mainmenu/00001.png b/tests/snapshots/stax/test_app_mainmenu/00001.png index 859759a..abb6107 100644 Binary files a/tests/snapshots/stax/test_app_mainmenu/00001.png and b/tests/snapshots/stax/test_app_mainmenu/00001.png differ diff --git a/tests/snapshots/stax/test_app_mainmenu/00002.png b/tests/snapshots/stax/test_app_mainmenu/00002.png index d4ca2b2..501267e 100644 Binary files a/tests/snapshots/stax/test_app_mainmenu/00002.png and b/tests/snapshots/stax/test_app_mainmenu/00002.png differ diff --git a/tests/snapshots/stax/test_blind_sign_tx/00000.png b/tests/snapshots/stax/test_blind_sign_tx/00000.png new file mode 100644 index 0000000..8696fba Binary files /dev/null and b/tests/snapshots/stax/test_blind_sign_tx/00000.png differ diff --git a/tests/snapshots/stax/test_blind_sign_tx/00001.png b/tests/snapshots/stax/test_blind_sign_tx/00001.png new file mode 100644 index 0000000..7dd6a67 Binary files /dev/null and b/tests/snapshots/stax/test_blind_sign_tx/00001.png differ diff --git a/tests/snapshots/stax/test_blind_sign_tx/00002.png b/tests/snapshots/stax/test_blind_sign_tx/00002.png new file mode 100644 index 0000000..501ad3d Binary files /dev/null and b/tests/snapshots/stax/test_blind_sign_tx/00002.png differ diff --git a/tests/snapshots/stax/test_blind_sign_tx/00003.png b/tests/snapshots/stax/test_blind_sign_tx/00003.png new file mode 100644 index 0000000..32e1819 Binary files /dev/null and b/tests/snapshots/stax/test_blind_sign_tx/00003.png differ diff --git a/tests/snapshots/stax/test_blind_sign_tx/00004.png b/tests/snapshots/stax/test_blind_sign_tx/00004.png new file mode 100644 index 0000000..1f9a0d0 Binary files /dev/null and b/tests/snapshots/stax/test_blind_sign_tx/00004.png differ diff --git a/tests/snapshots/stax/test_blind_sign_tx/00005.png b/tests/snapshots/stax/test_blind_sign_tx/00005.png new file mode 100644 index 0000000..2898062 Binary files /dev/null and b/tests/snapshots/stax/test_blind_sign_tx/00005.png differ diff --git a/tests/snapshots/stax/test_blind_sign_tx/00006.png b/tests/snapshots/stax/test_blind_sign_tx/00006.png new file mode 100644 index 0000000..392165d Binary files /dev/null and b/tests/snapshots/stax/test_blind_sign_tx/00006.png differ diff --git a/tests/snapshots/stax/test_blind_sign_tx/00007.png b/tests/snapshots/stax/test_blind_sign_tx/00007.png new file mode 100644 index 0000000..501267e Binary files /dev/null and b/tests/snapshots/stax/test_blind_sign_tx/00007.png differ diff --git a/tests/snapshots/stax/test_clear_sign_tx/00000.png b/tests/snapshots/stax/test_clear_sign_tx/00000.png new file mode 100644 index 0000000..4b5c40c Binary files /dev/null and b/tests/snapshots/stax/test_clear_sign_tx/00000.png differ diff --git a/tests/snapshots/stax/test_clear_sign_tx/00001.png b/tests/snapshots/stax/test_clear_sign_tx/00001.png new file mode 100644 index 0000000..2e58c2a Binary files /dev/null and b/tests/snapshots/stax/test_clear_sign_tx/00001.png differ diff --git a/tests/snapshots/stax/test_clear_sign_tx/00002.png b/tests/snapshots/stax/test_clear_sign_tx/00002.png new file mode 100644 index 0000000..58d63a9 Binary files /dev/null and b/tests/snapshots/stax/test_clear_sign_tx/00002.png differ diff --git a/tests/snapshots/stax/test_clear_sign_tx/00003.png b/tests/snapshots/stax/test_clear_sign_tx/00003.png new file mode 100644 index 0000000..0247374 Binary files /dev/null and b/tests/snapshots/stax/test_clear_sign_tx/00003.png differ diff --git a/tests/snapshots/stax/test_clear_sign_tx/00004.png b/tests/snapshots/stax/test_clear_sign_tx/00004.png new file mode 100644 index 0000000..8696fba Binary files /dev/null and b/tests/snapshots/stax/test_clear_sign_tx/00004.png differ diff --git a/tests/snapshots/stax/test_clear_sign_tx/00005.png b/tests/snapshots/stax/test_clear_sign_tx/00005.png new file mode 100644 index 0000000..392165d Binary files /dev/null and b/tests/snapshots/stax/test_clear_sign_tx/00005.png differ diff --git a/tests/snapshots/stax/test_get_public_key_confirm_accepted/00000.png b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00000.png index 82e3368..ccd4353 100644 Binary files a/tests/snapshots/stax/test_get_public_key_confirm_accepted/00000.png and b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00000.png differ diff --git a/tests/snapshots/stax/test_get_public_key_confirm_accepted/00001.png b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00001.png index 97421ae..b6afa5b 100644 Binary files a/tests/snapshots/stax/test_get_public_key_confirm_accepted/00001.png and b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00001.png differ diff --git a/tests/snapshots/stax/test_get_public_key_confirm_accepted/00002.png b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00002.png index 3f906b2..501267e 100644 Binary files a/tests/snapshots/stax/test_get_public_key_confirm_accepted/00002.png and b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00002.png differ diff --git a/tests/snapshots/stax/test_get_public_key_confirm_accepted/00003.png b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00003.png deleted file mode 100644 index d4ca2b2..0000000 Binary files a/tests/snapshots/stax/test_get_public_key_confirm_accepted/00003.png and /dev/null differ diff --git a/tests/snapshots/stax/test_get_public_key_confirm_refused/00000.png b/tests/snapshots/stax/test_get_public_key_confirm_refused/00000.png new file mode 100644 index 0000000..ccd4353 Binary files /dev/null and b/tests/snapshots/stax/test_get_public_key_confirm_refused/00000.png differ diff --git a/tests/snapshots/stax/test_get_public_key_confirm_refused/00001.png b/tests/snapshots/stax/test_get_public_key_confirm_refused/00001.png new file mode 100644 index 0000000..aa2b9aa Binary files /dev/null and b/tests/snapshots/stax/test_get_public_key_confirm_refused/00001.png differ diff --git a/tests/snapshots/stax/test_get_public_key_confirm_refused/00002.png b/tests/snapshots/stax/test_get_public_key_confirm_refused/00002.png new file mode 100644 index 0000000..501267e Binary files /dev/null and b/tests/snapshots/stax/test_get_public_key_confirm_refused/00002.png differ diff --git a/tests/snapshots/stax/test_get_public_key_confirm_refused/part0/00000.png b/tests/snapshots/stax/test_get_public_key_confirm_refused/part0/00000.png deleted file mode 100644 index 82e3368..0000000 Binary files a/tests/snapshots/stax/test_get_public_key_confirm_refused/part0/00000.png and /dev/null differ diff --git a/tests/snapshots/stax/test_get_public_key_confirm_refused/part0/00001.png b/tests/snapshots/stax/test_get_public_key_confirm_refused/part0/00001.png deleted file mode 100644 index b0eba3f..0000000 Binary files a/tests/snapshots/stax/test_get_public_key_confirm_refused/part0/00001.png and /dev/null differ diff --git a/tests/snapshots/stax/test_get_public_key_confirm_refused/part0/00002.png b/tests/snapshots/stax/test_get_public_key_confirm_refused/part0/00002.png deleted file mode 100644 index d4ca2b2..0000000 Binary files a/tests/snapshots/stax/test_get_public_key_confirm_refused/part0/00002.png and /dev/null differ diff --git a/tests/snapshots/stax/test_get_public_key_confirm_refused/part1/00000.png b/tests/snapshots/stax/test_get_public_key_confirm_refused/part1/00000.png deleted file mode 100644 index 82e3368..0000000 Binary files a/tests/snapshots/stax/test_get_public_key_confirm_refused/part1/00000.png and /dev/null differ diff --git a/tests/snapshots/stax/test_get_public_key_confirm_refused/part1/00001.png b/tests/snapshots/stax/test_get_public_key_confirm_refused/part1/00001.png deleted file mode 100644 index 97421ae..0000000 Binary files a/tests/snapshots/stax/test_get_public_key_confirm_refused/part1/00001.png and /dev/null differ diff --git a/tests/snapshots/stax/test_get_public_key_confirm_refused/part1/00002.png b/tests/snapshots/stax/test_get_public_key_confirm_refused/part1/00002.png deleted file mode 100644 index b0eba3f..0000000 Binary files a/tests/snapshots/stax/test_get_public_key_confirm_refused/part1/00002.png and /dev/null differ diff --git a/tests/snapshots/stax/test_get_public_key_confirm_refused/part1/00003.png b/tests/snapshots/stax/test_get_public_key_confirm_refused/part1/00003.png deleted file mode 100644 index d4ca2b2..0000000 Binary files a/tests/snapshots/stax/test_get_public_key_confirm_refused/part1/00003.png and /dev/null differ diff --git a/tests/snapshots/stax/test_sign_hash_0/00000.png b/tests/snapshots/stax/test_sign_hash_0/00000.png deleted file mode 100644 index 106ebbf..0000000 Binary files a/tests/snapshots/stax/test_sign_hash_0/00000.png and /dev/null differ diff --git a/tests/snapshots/stax/test_sign_hash_0/00001.png b/tests/snapshots/stax/test_sign_hash_0/00001.png deleted file mode 100644 index b4d1e29..0000000 Binary files a/tests/snapshots/stax/test_sign_hash_0/00001.png and /dev/null differ diff --git a/tests/snapshots/stax/test_sign_hash_0/00002.png b/tests/snapshots/stax/test_sign_hash_0/00002.png deleted file mode 100644 index 58910de..0000000 Binary files a/tests/snapshots/stax/test_sign_hash_0/00002.png and /dev/null differ diff --git a/tests/snapshots/stax/test_sign_hash_0/00003.png b/tests/snapshots/stax/test_sign_hash_0/00003.png deleted file mode 100644 index 2ba6d27..0000000 Binary files a/tests/snapshots/stax/test_sign_hash_0/00003.png and /dev/null differ diff --git a/tests/snapshots/stax/test_sign_hash_0/00004.png b/tests/snapshots/stax/test_sign_hash_0/00004.png deleted file mode 100644 index d4ca2b2..0000000 Binary files a/tests/snapshots/stax/test_sign_hash_0/00004.png and /dev/null differ diff --git a/tests/snapshots/stax/test_sign_hash_1/00000.png b/tests/snapshots/stax/test_sign_hash_1/00000.png deleted file mode 100644 index 106ebbf..0000000 Binary files a/tests/snapshots/stax/test_sign_hash_1/00000.png and /dev/null differ diff --git a/tests/snapshots/stax/test_sign_hash_1/00001.png b/tests/snapshots/stax/test_sign_hash_1/00001.png deleted file mode 100644 index 1ebd83b..0000000 Binary files a/tests/snapshots/stax/test_sign_hash_1/00001.png and /dev/null differ diff --git a/tests/snapshots/stax/test_sign_hash_1/00002.png b/tests/snapshots/stax/test_sign_hash_1/00002.png deleted file mode 100644 index 58910de..0000000 Binary files a/tests/snapshots/stax/test_sign_hash_1/00002.png and /dev/null differ diff --git a/tests/snapshots/stax/test_sign_hash_1/00003.png b/tests/snapshots/stax/test_sign_hash_1/00003.png deleted file mode 100644 index 2ba6d27..0000000 Binary files a/tests/snapshots/stax/test_sign_hash_1/00003.png and /dev/null differ diff --git a/tests/snapshots/stax/test_sign_hash_1/00004.png b/tests/snapshots/stax/test_sign_hash_1/00004.png deleted file mode 100644 index d4ca2b2..0000000 Binary files a/tests/snapshots/stax/test_sign_hash_1/00004.png and /dev/null differ diff --git a/tests/snapshots/stax/test_sign_hash_2/00000.png b/tests/snapshots/stax/test_sign_hash_2/00000.png deleted file mode 100644 index 106ebbf..0000000 Binary files a/tests/snapshots/stax/test_sign_hash_2/00000.png and /dev/null differ diff --git a/tests/snapshots/stax/test_sign_hash_2/00001.png b/tests/snapshots/stax/test_sign_hash_2/00001.png deleted file mode 100644 index 8d891b0..0000000 Binary files a/tests/snapshots/stax/test_sign_hash_2/00001.png and /dev/null differ diff --git a/tests/snapshots/stax/test_sign_hash_2/00002.png b/tests/snapshots/stax/test_sign_hash_2/00002.png deleted file mode 100644 index 58910de..0000000 Binary files a/tests/snapshots/stax/test_sign_hash_2/00002.png and /dev/null differ diff --git a/tests/snapshots/stax/test_sign_hash_2/00003.png b/tests/snapshots/stax/test_sign_hash_2/00003.png deleted file mode 100644 index 2ba6d27..0000000 Binary files a/tests/snapshots/stax/test_sign_hash_2/00003.png and /dev/null differ diff --git a/tests/snapshots/stax/test_sign_hash_2/00004.png b/tests/snapshots/stax/test_sign_hash_2/00004.png deleted file mode 100644 index d4ca2b2..0000000 Binary files a/tests/snapshots/stax/test_sign_hash_2/00004.png and /dev/null differ diff --git a/tests/snapshots/stax/test_sign_hash_3/00000.png b/tests/snapshots/stax/test_sign_hash_3/00000.png deleted file mode 100644 index 106ebbf..0000000 Binary files a/tests/snapshots/stax/test_sign_hash_3/00000.png and /dev/null differ diff --git a/tests/snapshots/stax/test_sign_hash_3/00001.png b/tests/snapshots/stax/test_sign_hash_3/00001.png deleted file mode 100644 index 50fc14d..0000000 Binary files a/tests/snapshots/stax/test_sign_hash_3/00001.png and /dev/null differ diff --git a/tests/snapshots/stax/test_sign_hash_3/00002.png b/tests/snapshots/stax/test_sign_hash_3/00002.png deleted file mode 100644 index 58910de..0000000 Binary files a/tests/snapshots/stax/test_sign_hash_3/00002.png and /dev/null differ diff --git a/tests/snapshots/stax/test_sign_hash_3/00003.png b/tests/snapshots/stax/test_sign_hash_3/00003.png deleted file mode 100644 index 2ba6d27..0000000 Binary files a/tests/snapshots/stax/test_sign_hash_3/00003.png and /dev/null differ diff --git a/tests/snapshots/stax/test_sign_hash_3/00004.png b/tests/snapshots/stax/test_sign_hash_3/00004.png deleted file mode 100644 index d4ca2b2..0000000 Binary files a/tests/snapshots/stax/test_sign_hash_3/00004.png and /dev/null differ diff --git a/tests/snapshots/stax/test_sign_hash_4/00000.png b/tests/snapshots/stax/test_sign_hash_4/00000.png deleted file mode 100644 index 106ebbf..0000000 Binary files a/tests/snapshots/stax/test_sign_hash_4/00000.png and /dev/null differ diff --git a/tests/snapshots/stax/test_sign_hash_4/00001.png b/tests/snapshots/stax/test_sign_hash_4/00001.png deleted file mode 100644 index 7d92ac5..0000000 Binary files a/tests/snapshots/stax/test_sign_hash_4/00001.png and /dev/null differ diff --git a/tests/snapshots/stax/test_sign_hash_4/00002.png b/tests/snapshots/stax/test_sign_hash_4/00002.png deleted file mode 100644 index 58910de..0000000 Binary files a/tests/snapshots/stax/test_sign_hash_4/00002.png and /dev/null differ diff --git a/tests/snapshots/stax/test_sign_hash_4/00003.png b/tests/snapshots/stax/test_sign_hash_4/00003.png deleted file mode 100644 index 2ba6d27..0000000 Binary files a/tests/snapshots/stax/test_sign_hash_4/00003.png and /dev/null differ diff --git a/tests/snapshots/stax/test_sign_hash_4/00004.png b/tests/snapshots/stax/test_sign_hash_4/00004.png deleted file mode 100644 index d4ca2b2..0000000 Binary files a/tests/snapshots/stax/test_sign_hash_4/00004.png and /dev/null differ diff --git a/tests/snapshots/stax/test_sign_hash_refused/00000.png b/tests/snapshots/stax/test_sign_hash_refused/00000.png deleted file mode 100644 index 106ebbf..0000000 Binary files a/tests/snapshots/stax/test_sign_hash_refused/00000.png and /dev/null differ diff --git a/tests/snapshots/stax/test_sign_hash_refused/00001.png b/tests/snapshots/stax/test_sign_hash_refused/00001.png deleted file mode 100644 index b4d1e29..0000000 Binary files a/tests/snapshots/stax/test_sign_hash_refused/00001.png and /dev/null differ diff --git a/tests/snapshots/stax/test_sign_hash_refused/00002.png b/tests/snapshots/stax/test_sign_hash_refused/00002.png deleted file mode 100644 index babad98..0000000 Binary files a/tests/snapshots/stax/test_sign_hash_refused/00002.png and /dev/null differ diff --git a/tests/snapshots/stax/test_sign_hash_refused/00003.png b/tests/snapshots/stax/test_sign_hash_refused/00003.png deleted file mode 100644 index cebc8be..0000000 Binary files a/tests/snapshots/stax/test_sign_hash_refused/00003.png and /dev/null differ diff --git a/tests/snapshots/stax/test_sign_hash_refused/00004.png b/tests/snapshots/stax/test_sign_hash_refused/00004.png deleted file mode 100644 index d4ca2b2..0000000 Binary files a/tests/snapshots/stax/test_sign_hash_refused/00004.png and /dev/null differ diff --git a/tests/test_error_cmd.py b/tests/test_error_cmd.py index 37e911e..f1484e8 100644 --- a/tests/test_error_cmd.py +++ b/tests/test_error_cmd.py @@ -1,8 +1,16 @@ import pytest from ragger.error import ExceptionRAPDU -from application_client.command_sender import CLA, InsType, Errors +from application_client.response_unpacker import Errors +from enum import IntEnum +CLA: int = 0x5A + +class InsType(IntEnum): + GET_VERSION = 0x00 + GET_PUBLIC_KEY = 0x01 + SIGN_HASH = 0x02 + SIGN_TX = 0x03 # Ensure the app returns an error when a bad CLA is used def test_bad_cla(backend): diff --git a/tests/test_pubkey_cmd.py b/tests/test_pubkey_cmd.py index 2743396..b63e4f6 100644 --- a/tests/test_pubkey_cmd.py +++ b/tests/test_pubkey_cmd.py @@ -1,32 +1,25 @@ import pytest -from application_client.command_sender import CommandSender, Errors -from application_client.response_unpacker import unpack_get_public_key_response -from ragger.bip import calculate_public_key_and_chaincode, CurveChoice +from application_client.response_unpacker import unpack_get_public_key_response, Errors from ragger.error import ExceptionRAPDU -from ragger.navigator import NavInsID, NavIns +from ragger.navigator import NavInsID from utils import ROOT_SCREENSHOT_PATH - # In this test we check that the GET_PUBLIC_KEY works in non-confirmation mode def test_get_public_key_no_confirm(backend): - for path in ["m/2645'/1195502025'/1148870696'/0'/0'/0"]: - client = CommandSender(backend) - response = client.get_public_key(path=path).data - public_key_x, public_key_y = unpack_get_public_key_response(response) + + response = backend.exchange_raw(bytes.fromhex("5a0100001880000a55c741e9c9c47a6028800000008000000000000000")).data + public_key_x, public_key_y = unpack_get_public_key_response(response) - #ref_public_key, _ = calculate_public_key_and_chaincode(CurveChoice.Secp256k1, path=path) - ref_public_key_x = bytes.fromhex("04ac45fea8814cc2c2bbca343f4280b25d2a5f6d65e511dd16977f35c3e64b74") - ref_public_key_y = bytes.fromhex("023e4ce66d2d3a466f4326a2def52c68eae80588a36b26574b369d6716fc16bd") - assert public_key_x == ref_public_key_x - assert public_key_y == ref_public_key_y + ref_public_key_x = bytes.fromhex("04ac45fea8814cc2c2bbca343f4280b25d2a5f6d65e511dd16977f35c3e64b74") + ref_public_key_y = bytes.fromhex("023e4ce66d2d3a466f4326a2def52c68eae80588a36b26574b369d6716fc16bd") + assert public_key_x == ref_public_key_x + assert public_key_y == ref_public_key_y # In this test we check that the GET_PUBLIC_KEY works in confirmation mode def test_get_public_key_confirm_accepted(firmware, backend, navigator, test_name): - client = CommandSender(backend) - path = "m/2645'/1195502025'/1148870696'/0'/0'/0" - with client.get_public_key_with_confirmation(path=path): + with backend.exchange_async_raw(bytes.fromhex("5a0101001880000a55c741e9c9c47a6028800000008000000000000000")): if firmware.device.startswith("nano"): navigator.navigate_until_text_and_compare(NavInsID.RIGHT_CLICK, [NavInsID.BOTH_CLICK], @@ -35,14 +28,13 @@ def test_get_public_key_confirm_accepted(firmware, backend, navigator, test_name test_name) else: instructions = [ - NavInsID.USE_CASE_REVIEW_TAP, - NavIns(NavInsID.USE_CASE_ADDRESS_CONFIRMATION_CONFIRM), - NavIns(NavInsID.USE_CASE_STATUS_DISMISS) + NavInsID.USE_CASE_CHOICE_CONFIRM, + NavInsID.USE_CASE_STATUS_DISMISS ] navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH, test_name, instructions) - response = client.get_async_response().data + response = backend.last_async_response.data public_key_x, public_key_y = unpack_get_public_key_response(response) @@ -55,38 +47,21 @@ def test_get_public_key_confirm_accepted(firmware, backend, navigator, test_name # In this test we check that the GET_PUBLIC_KEY in confirmation mode replies an error if the user refuses def test_get_public_key_confirm_refused(firmware, backend, navigator, test_name): - client = CommandSender(backend) - path = "m/2645'/1195502025'/1148870696'/0'/0'/0" - - if firmware.device.startswith("nano"): - with pytest.raises(ExceptionRAPDU) as e: - with client.get_public_key_with_confirmation(path=path): + with pytest.raises(ExceptionRAPDU) as e: + with backend.exchange_async_raw(bytes.fromhex("5a0101001880000a55c741e9c9c47a6028800000008000000000000000")): + if firmware.device.startswith("nano"): navigator.navigate_until_text_and_compare(NavInsID.RIGHT_CLICK, - [NavInsID.BOTH_CLICK], - "Reject", - ROOT_SCREENSHOT_PATH, - test_name) - # Assert that we have received a refusal - assert e.value.status == Errors.SW_DENY - assert len(e.value.data) == 0 - else: - instructions_set = [ - [ - NavInsID.USE_CASE_REVIEW_REJECT, - NavInsID.USE_CASE_STATUS_DISMISS - ], - [ - NavInsID.USE_CASE_REVIEW_TAP, - NavInsID.USE_CASE_ADDRESS_CONFIRMATION_CANCEL, - NavInsID.USE_CASE_STATUS_DISMISS - ] - ] - for i, instructions in enumerate(instructions_set): - with pytest.raises(ExceptionRAPDU) as e: - with client.get_public_key_with_confirmation(path=path): - navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH, - test_name + f"/part{i}", - instructions) - # Assert that we have received a refusal - assert e.value.status == Errors.SW_DENY - assert len(e.value.data) == 0 + [NavInsID.BOTH_CLICK], + "Reject", + ROOT_SCREENSHOT_PATH, + test_name) + else: + instructions = [ + NavInsID.USE_CASE_CHOICE_REJECT, + NavInsID.USE_CASE_STATUS_DISMISS + ] + navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH, + test_name, + instructions) + assert e.value.status == Errors.SW_DENY + assert len(e.value.data) == 0 \ No newline at end of file diff --git a/tests/test_sign_cmd.py b/tests/test_sign_cmd.py deleted file mode 100644 index ff5590a..0000000 --- a/tests/test_sign_cmd.py +++ /dev/null @@ -1,291 +0,0 @@ -import pytest - -from application_client.command_sender import CommandSender, Errors -from application_client.response_unpacker import unpack_get_public_key_response, unpack_sign_hash_response -from ragger.error import ExceptionRAPDU -from ragger.navigator import NavInsID, NavIns -from utils import ROOT_SCREENSHOT_PATH - -from starknet_py.hash.utils import verify_message_signature - -# In this tests we check the behavior of the device when asked to sign a Tx hash - -# pedersen hashes -hash_0: str = "55b8f28706a5008d3103bcb2bfa6356e56b95c34fed265c955846670a6bb4ef" # 31,5 bytes (63 digits) -hash_1: str = "2bd1d3f8f45a011cbd0674ded291d58985761bbcbc04f4d01c8285d1b35c411" # 31,5 bytes (63 digits) -hash_2: str = "2e672d748fbe3b6e833b61ea8b6e688850247022f06406a1eb83e345ffb417" # 31 bytes (62 digits) -hash_3: str = "936e8798681b391af0c57fe0bf5703b9631bea18b4bc84b3940ebab234744" # 30,5 bytes (61 digits) -hash_4: str = "2534b0f53ccac2347dd51befce72338d9b7c568905f17218d93980ce1fc869f" # 31,5 bytes (63 digits) - -def fix_sign(hash: str) -> str: - # fix hash to fit into 32 bytes - while (len(hash) < 63): - hash = '0' + hash - - assert(len(hash) == 63) - return hash + '0' - -# In this test we send to the device a hash to sign and validate it on screen -# We will ensure that the displayed information is correct by using screenshots comparison -def test_sign_hash_0(firmware, backend, navigator, test_name): - # Use the app interface instead of raw interface - client = CommandSender(backend) - # The path used for this entire test - path: str = "m/2645'/1195502025'/1148870696'/0'/0'/5" - - # First we need to get the public key of the device in order to build the transaction - rapdu = client.get_public_key(path=path) - pub_key_x, _ = unpack_get_public_key_response(rapdu.data) - - # Send the sign device instruction. - # As it requires on-screen validation, the function is asynchronous. - # It will yield the result when the navigation is done - with client.sign_hash(path=path, hash=bytes.fromhex(fix_sign(hash_0))): - # Validate the on-screen request by performing the navigation appropriate for this device - if firmware.device.startswith("nano"): - navigator.navigate_until_text_and_compare(NavInsID.RIGHT_CLICK, - [NavInsID.BOTH_CLICK], - "Approve", - ROOT_SCREENSHOT_PATH, - test_name) - else: - instructions = [ - NavInsID.USE_CASE_REVIEW_TAP, - NavInsID.USE_CASE_REVIEW_TAP, - NavInsID.USE_CASE_REVIEW_CONFIRM, - NavInsID.USE_CASE_STATUS_DISMISS - ] - navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH, - test_name, - instructions) - - # The device as yielded the result, parse it and ensure that the signature is correct - response = client.get_async_response().data - r, s, _ = unpack_sign_hash_response(response) - - assert( - verify_message_signature( - msg_hash=int(hash_0, 16), - signature = [r, s], - public_key=int.from_bytes(pub_key_x, byteorder='big')) - ) - -# In this test we send to the device a hash to sign and validate it on screen -# We will ensure that the displayed information is correct by using screenshots comparison -def test_sign_hash_1(firmware, backend, navigator, test_name): - # Use the app interface instead of raw interface - client = CommandSender(backend) - # The path used for this entire test - path: str = "m/2645'/1195502025'/1148870696'/0'/0'/5" - - # First we need to get the public key of the device in order to build the transaction - rapdu = client.get_public_key(path=path) - pub_key_x, _ = unpack_get_public_key_response(rapdu.data) - - # Send the sign device instruction. - # As it requires on-screen validation, the function is asynchronous. - # It will yield the result when the navigation is done - with client.sign_hash(path=path, hash=bytes.fromhex(fix_sign(hash_1))): - # Validate the on-screen request by performing the navigation appropriate for this device - if firmware.device.startswith("nano"): - navigator.navigate_until_text_and_compare(NavInsID.RIGHT_CLICK, - [NavInsID.BOTH_CLICK], - "Approve", - ROOT_SCREENSHOT_PATH, - test_name) - else: - instructions = [ - NavInsID.USE_CASE_REVIEW_TAP, - NavInsID.USE_CASE_REVIEW_TAP, - NavInsID.USE_CASE_REVIEW_CONFIRM, - NavInsID.USE_CASE_STATUS_DISMISS - ] - navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH, - test_name, - instructions) - - # The device as yielded the result, parse it and ensure that the signature is correct - response = client.get_async_response().data - r, s, _ = unpack_sign_hash_response(response) - - assert( - verify_message_signature( - msg_hash=int(hash_1, 16), - signature = [r, s], - public_key=int.from_bytes(pub_key_x, byteorder='big')) - ) - -# In this test we send to the device a hash to sign and validate it on screen -# We will ensure that the displayed information is correct by using screenshots comparison -def test_sign_hash_2(firmware, backend, navigator, test_name): - # Use the app interface instead of raw interface - client = CommandSender(backend) - # The path used for this entire test - path: str = "m/2645'/1195502025'/1148870696'/0'/0'/5" - - # First we need to get the public key of the device in order to build the transaction - rapdu = client.get_public_key(path=path) - pub_key_x, _ = unpack_get_public_key_response(rapdu.data) - - # Send the sign device instruction. - # As it requires on-screen validation, the function is asynchronous. - # It will yield the result when the navigation is done - with client.sign_hash(path=path, hash=bytes.fromhex(fix_sign(hash_2))): - # Validate the on-screen request by performing the navigation appropriate for this device - if firmware.device.startswith("nano"): - navigator.navigate_until_text_and_compare(NavInsID.RIGHT_CLICK, - [NavInsID.BOTH_CLICK], - "Approve", - ROOT_SCREENSHOT_PATH, - test_name) - else: - instructions = [ - NavInsID.USE_CASE_REVIEW_TAP, - NavInsID.USE_CASE_REVIEW_TAP, - NavInsID.USE_CASE_REVIEW_CONFIRM, - NavInsID.USE_CASE_STATUS_DISMISS - ] - navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH, - test_name, - instructions) - - # The device as yielded the result, parse it and ensure that the signature is correct - response = client.get_async_response().data - r, s, _ = unpack_sign_hash_response(response) - - assert( - verify_message_signature( - msg_hash=int(hash_2, 16), - signature = [r, s], - public_key=int.from_bytes(pub_key_x, byteorder='big')) - ) - - # In this test we send to the device a hash to sign and validate it on screen -# We will ensure that the displayed information is correct by using screenshots comparison -def test_sign_hash_3(firmware, backend, navigator, test_name): - # Use the app interface instead of raw interface - client = CommandSender(backend) - # The path used for this entire test - path: str = "m/2645'/1195502025'/1148870696'/0'/0'/5" - - # First we need to get the public key of the device in order to build the transaction - rapdu = client.get_public_key(path=path) - pub_key_x, _ = unpack_get_public_key_response(rapdu.data) - - # Send the sign device instruction. - # As it requires on-screen validation, the function is asynchronous. - # It will yield the result when the navigation is done - with client.sign_hash(path=path, hash=bytes.fromhex(fix_sign(hash_3))): - # Validate the on-screen request by performing the navigation appropriate for this device - if firmware.device.startswith("nano"): - navigator.navigate_until_text_and_compare(NavInsID.RIGHT_CLICK, - [NavInsID.BOTH_CLICK], - "Approve", - ROOT_SCREENSHOT_PATH, - test_name) - else: - instructions = [ - NavInsID.USE_CASE_REVIEW_TAP, - NavInsID.USE_CASE_REVIEW_TAP, - NavInsID.USE_CASE_REVIEW_CONFIRM, - NavInsID.USE_CASE_STATUS_DISMISS - ] - navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH, - test_name, - instructions) - - # The device as yielded the result, parse it and ensure that the signature is correct - response = client.get_async_response().data - r, s, _ = unpack_sign_hash_response(response) - - assert( - verify_message_signature( - msg_hash=int(hash_3, 16), - signature = [r, s], - public_key=int.from_bytes(pub_key_x, byteorder='big')) - ) - - - -# In this test we send to the device a hash to sign and validate it on screen -# We will ensure that the displayed information is correct by using screenshots comparison -def test_sign_hash_4(firmware, backend, navigator, test_name): - # Use the app interface instead of raw interface - client = CommandSender(backend) - # The path used for this entire test - path: str = "m/2645'/1195502025'/1148870696'/0'/0'/5" - - # First we need to get the public key of the device in order to build the transaction - rapdu = client.get_public_key(path=path) - pub_key_x, _ = unpack_get_public_key_response(rapdu.data) - - # Send the sign device instruction. - # As it requires on-screen validation, the function is asynchronous. - # It will yield the result when the navigation is done - with client.sign_hash(path=path, hash=bytes.fromhex(fix_sign(hash_4))): - # Validate the on-screen request by performing the navigation appropriate for this device - if firmware.device.startswith("nano"): - navigator.navigate_until_text_and_compare(NavInsID.RIGHT_CLICK, - [NavInsID.BOTH_CLICK], - "Approve", - ROOT_SCREENSHOT_PATH, - test_name) - else: - instructions = [ - NavInsID.USE_CASE_REVIEW_TAP, - NavInsID.USE_CASE_REVIEW_TAP, - NavInsID.USE_CASE_REVIEW_CONFIRM, - NavInsID.USE_CASE_STATUS_DISMISS - ] - navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH, - test_name, - instructions) - - # The device as yielded the result, parse it and ensure that the signature is correct - response = client.get_async_response().data - r, s, _ = unpack_sign_hash_response(response) - - assert( - verify_message_signature( - msg_hash=int(hash_4, 16), - signature = [r, s], - public_key=int.from_bytes(pub_key_x, byteorder='big')) - ) - -# Hash signature refused test -# The test will ask for a transaction hash that will be refused on screen -def test_sign_hash_refused(firmware, backend, navigator, test_name): - # Use the app interface instead of raw interface - client = CommandSender(backend) - path: str = "m/2645'/1195502025'/1148870696'/0'/0'/5" - - rapdu = client.get_public_key(path=path) - pub_key_x, _ = unpack_get_public_key_response(rapdu.data) - - if firmware.device.startswith("nano"): - with pytest.raises(ExceptionRAPDU) as e: - with client.sign_hash(path=path, hash=bytes.fromhex(fix_sign(hash_0))): - navigator.navigate_until_text_and_compare(NavInsID.RIGHT_CLICK, - [NavInsID.BOTH_CLICK], - "Reject", - ROOT_SCREENSHOT_PATH, - test_name) - - # Assert that we have received a refusal - assert e.value.status == Errors.SW_DENY - assert len(e.value.data) == 0 - else: - instructions = [ - NavInsID.USE_CASE_REVIEW_TAP, - NavInsID.USE_CASE_REVIEW_REJECT, - NavInsID.USE_CASE_CHOICE_CONFIRM, - NavInsID.USE_CASE_STATUS_DISMISS - ] - with pytest.raises(ExceptionRAPDU) as e: - with client.sign_hash(path=path, hash=bytes.fromhex(fix_sign(hash_0))): - navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH, - test_name, - instructions) - # Assert that we have received a refusal - assert e.value.status == Errors.SW_DENY - assert len(e.value.data) == 0 diff --git a/tests/test_sign_tx.py b/tests/test_sign_tx.py new file mode 100644 index 0000000..9938cd9 --- /dev/null +++ b/tests/test_sign_tx.py @@ -0,0 +1,132 @@ +import pytest + +from application_client.response_unpacker import unpack_get_public_key_response, unpack_sign_tx_response, Errors +from ragger.navigator import NavInsID +from utils import ROOT_SCREENSHOT_PATH + +from starknet_py.hash.utils import verify_message_signature + +# In those tests we check the behavior of the device when asked to sign a Tx (clear or blind signing) + +# In this test we send to the device a tx to sign and validate it on screen +# We will ensure that the displayed information is correct by using screenshots comparison +def test_clear_sign_tx(firmware, backend, navigator, test_name): + + # First we need to get the public key of the device in order to build the transaction + rapdu = backend.exchange_raw(bytes.fromhex("5a0100001880000a55c741e9c9c47a6028800000008000000000000000")) + pub_key_x, _ = unpack_get_public_key_response(rapdu.data) + + # Send the sign tx device instruction. + # As it requires on-screen validation, the function is asynchronous. + # It will yield the result when the navigation is done + apdus = [ + bytes.fromhex("5a0300001880000a55c741e9c9c47a6028800000008000000000000000"), + bytes.fromhex("5a030100e007e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a000000000000000000000000000000000000000000000000000000000000000000004c315f47415300000000000000000000000000000000000000000000000000004c325f47415300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000534e5f4d41494e00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000"), + bytes.fromhex("5a03020000"), + bytes.fromhex("5a03030000"), + bytes.fromhex("5a030400200000000000000000000000000000000000000000000000000000000000000001"), + bytes.fromhex("5a03050080049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc70083afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e07e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a00000000000000000000000000000000000000000000000000000000000003e8"), + bytes.fromhex("5a03050200"), + ] + # send all apdus except last one + for apdu in apdus[:-1]: + backend.exchange_raw(apdu) + # send last apdu and yield the response + with backend.exchange_async_raw(apdus[-1]): + if firmware.device.startswith("nano"): + navigator.navigate_until_text_and_compare(NavInsID.RIGHT_CLICK, + [NavInsID.BOTH_CLICK], + "Approve", + ROOT_SCREENSHOT_PATH, + test_name) + else: + instructions = [ + NavInsID.SWIPE_CENTER_TO_LEFT, + NavInsID.SWIPE_CENTER_TO_LEFT, + NavInsID.SWIPE_CENTER_TO_LEFT, + NavInsID.USE_CASE_REVIEW_CONFIRM, + NavInsID.USE_CASE_STATUS_DISMISS + ] + navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH, + test_name, + instructions) + + response = backend.last_async_response.data + + hash, r, s, _ = unpack_sign_tx_response(response) + + print("hash: ", hash) + + assert( + verify_message_signature( + msg_hash=hash, + signature = [r, s], + public_key=int.from_bytes(pub_key_x, byteorder='big')) + ) + +def test_blind_sign_tx(firmware, backend, navigator, test_name): + + # Use the app interface instead of raw interface + #client = CommandSender(backend) + + # First we need to get the public key of the device in order to build the transaction + #rapdu = client.get_public_key(bytes.fromhex("5a0100001880000a55c741e9c9c47a6028800000008000000000000000")) + rapdu = backend.exchange_raw(bytes.fromhex("5a0100001880000a55c741e9c9c47a6028800000008000000000000000")) + pub_key_x, _ = unpack_get_public_key_response(rapdu.data) + + # Send the sign tx device instruction. + # As it requires on-screen validation, the function is asynchronous. + # It will yield the result when the navigation is done + apdus = [ + bytes.fromhex("5a0300001880000a55c741e9c9c47a6028800000008000000000000000"), + bytes.fromhex("5a030100e007e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a000000000000000000000000000000000000000000000000000000000000000000004c315f47415300000000000000000000000000000000000000000000000000004c325f47415300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000534e5f4d41494e00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000"), + bytes.fromhex("5a03020000"), + bytes.fromhex("5a03030000"), + bytes.fromhex("5a030400200000000000000000000000000000000000000000000000000000000000000001"), + bytes.fromhex("5a03050080049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc702f0b3c5710379609eb5495f1ecd348cb28167711b73609fe565a7273455035407e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a00000000000000000000000000000000000000000000000000000000000003e8"), + bytes.fromhex("5a03050200"), + ] + # send all apdus except last one + for apdu in apdus[:-1]: + backend.exchange_raw(apdu) + # send last apdu and yield the response + with backend.exchange_async_raw(apdus[-1]): + if firmware.device.startswith("nano"): + navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH, + test_name, + [NavInsID.RIGHT_CLICK, + NavInsID.RIGHT_CLICK, + NavInsID.RIGHT_CLICK, + NavInsID.RIGHT_CLICK, + NavInsID.RIGHT_CLICK, + NavInsID.RIGHT_CLICK, + NavInsID.BOTH_CLICK, + NavInsID.RIGHT_CLICK, + NavInsID.RIGHT_CLICK, + NavInsID.RIGHT_CLICK, + NavInsID.RIGHT_CLICK, + NavInsID.BOTH_CLICK]) + else: + instructions = [ + NavInsID.USE_CASE_STATUS_DISMISS, + NavInsID.CENTERED_FOOTER_TAP, + NavInsID.USE_CASE_CHOICE_CONFIRM, + NavInsID.SWIPE_CENTER_TO_LEFT, + NavInsID.SWIPE_CENTER_TO_LEFT, + NavInsID.USE_CASE_REVIEW_CONFIRM, + NavInsID.USE_CASE_STATUS_DISMISS + ] + navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH, + test_name, + instructions) + + response = backend.last_async_response.data + + hash, r, s, _ = unpack_sign_tx_response(response) + + assert( + verify_message_signature( + msg_hash=hash, + signature = [r, s], + public_key=int.from_bytes(pub_key_x, byteorder='big')) + ) \ No newline at end of file diff --git a/tests/test_version_cmd.py b/tests/test_version_cmd.py index dc4220a..1f04fe4 100644 --- a/tests/test_version_cmd.py +++ b/tests/test_version_cmd.py @@ -1,18 +1,14 @@ -from application_client.command_sender import CommandSender from application_client.response_unpacker import unpack_get_version_response - import toml # In this test we check the behavior of the device when asked to provide the app version def test_version(backend): - # Use the app interface instead of raw interface - client = CommandSender(backend) # Send the GET_VERSION instruction - rapdu = client.get_version() + rapdu = backend.exchange_raw(bytes.fromhex("5a00000000")) # Read version from Cargo.toml - with open('Cargo.toml', 'r') as f: + with open('starknet/Cargo.toml', 'r') as f: config = toml.load(f) version = config['package']['version'] major, minor, patch = version.split('.') # Use an helper to parse the response, assert the values - assert unpack_get_version_response(rapdu.data) == (int(major), int(minor), int(patch)) + assert unpack_get_version_response(rapdu.data) == (int(major), int(minor), int(patch)) \ No newline at end of file diff --git a/tests/usage.md b/tests/usage.md index be8890f..599f413 100644 --- a/tests/usage.md +++ b/tests/usage.md @@ -15,12 +15,13 @@ sudo apt-get update && sudo apt-get install qemu-user-static ### Compile the application The application to test must be compiled for all required devices. -You can use for this the container `ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite`: +You can use for this the container `ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder`: ``` -docker pull ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest -cd # replace with the name of your app, (eg boilerplate) -docker run --user "$(id -u)":"$(id -g)" --rm -ti -v "$(realpath .):/app" --privileged -v "/dev/bus/usb:/dev/bus/usb" ledger-app-builder-lite:latest -make clean && make BOLOS_SDK=$_SDK # replace with one of [NANOS, NANOX, NANOSP, STAX] +docker pull ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest +cd app-starknet +docker run --user "$(id -u)":"$(id -g)" --rm -ti -v "$(realpath .):/app" --privileged -v "/dev/bus/usb:/dev/bus/usb" ledger-app-builder:latest +cd /app/starknet +cargo ledger build # replace with one of [nanosplus, nanox, stax, flex] exit ``` @@ -28,7 +29,8 @@ exit You can use the following command to get your first experience with Ragger and Speculos ``` -pytest -v --tb=short --device nanox --display +pip install -r tests/requirement.txt +pytest tests -v --tb=short --device stax ``` Or you can refer to the section `Available pytest options` to configure the options you want to use @@ -36,19 +38,16 @@ Or you can refer to the section `Available pytest options` to configure the opti ### Run a simple test using a real device The application to test must be loaded and started on a Ledger device plugged in USB. -You can use for this the container `ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite`: +You can use `ledgerwallet` to sideload the app on a Ledger device (e.g. Stax): ``` -docker pull ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest -cd app-/ # replace with the name of your app, (eg boilerplate) -docker run --user "$(id -u)":"$(id -g)" --rm -ti -v "$(realpath .):/app" --privileged -v "/dev/bus/usb:/dev/bus/usb" ledger-app-builder-lite:latest -make clean && make BOLOS_SDK=$_SDK load # replace with one of [NANOS, NANOX, NANOSP, STAX] -exit +pip install ledgerwallet +ledgerctl install -f target/stax/release/app_stax.json ``` You can use the following command to get your first experience with Ragger and Ledgerwallet on a NANOX. Make sure that the device is plugged, unlocked, and that the tested application is open. ``` -pytest -v --tb=short --device nanox --backend ledgerwallet +pytest -v --tb=short --device stax --backend ledgerwallet ``` Or you can refer to the section `Available pytest options` to configure the options you want to use diff --git a/tests_ledgercomm/README.md b/tests_ledgercomm/README.md deleted file mode 100644 index f7f01f1..0000000 --- a/tests_ledgercomm/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# Functional tests - -> :point_right: Every path on this document assumes you are at the root of the repository - -`tests/ledgercomm/` contains functional tests which use the - [Python LedgerComm library](https://github.com/LedgerHQ/ledgercomm), which allows the tests to run either on an actual Nano, or on [Speculos](https://github.com/LedgerHQ/speculos) - - Before running the tests you will need to setup a Python virtual env and install all the modules listed in `tests/ledgercomm/requirements.txt` - - To install `cairo-lang` module, please check [Setting up the Cairo env](https://starknet.io/docs/quickstart.html#quickstart) - - Also note that a on Mac M1, check [here](https://github.com/starkware-libs/cairo-lang/issues/68) to install `ecdsa`, `fastecdsa` and `sympy` diff --git a/tests_ledgercomm/ledgercomm/README.md b/tests_ledgercomm/ledgercomm/README.md deleted file mode 100644 index e53ebb0..0000000 --- a/tests_ledgercomm/ledgercomm/README.md +++ /dev/null @@ -1,48 +0,0 @@ -# LedgerComm functional tests - -> :point_right: Every path on this document assumes you are at the root of the repository. - -These tests are implemented in Python and can be executed either using the -[Speculos](https://github.com/LedgerHQ/speculos) emulator or a Ledger Nano S/X. - -Python dependencies are listed in [requirements.txt](requirements.txt), install -them using [pip](https://pypi.org/project/pip/) - -``` -pip install -r tests/ledgercomm/requirements.txt -``` - - -## Launch with Speculos - -You will need Speculos installed first, see [here](../../docs/test.md) then run -``` -pytest --headless tests/ledgercomm/ -``` - -The `--headless` option means the tests will trigger the buttons themselves -(button actions are needed to approve the signing), by connecting on the `42000` -port opened by Speculos (`--button-port 42000`). - -By removing this option, the tests will be stuck, waiting for the someone to -approve the step. The user could validate this step manually, and the test will -continue thereafter. - - -## Launch with your Nano S/X - -To run the tests on your Ledger Nano S/X, you also need to install an optional -dependency: - -``` -pip install ledgercomm[hid] -``` - -Be sure to have the boilerplate application installed (see -[this page](https://developers.ledger.com/docs/nano-app/load/) for installing an -application on a Nano S) and opened on the device, and the device connected -through USB, without any other software interacting with it. Then run: - -``` -pytest --hid tests/ledgercomm/ -``` diff --git a/tests_ledgercomm/ledgercomm/boilerplate_client/__init__.py b/tests_ledgercomm/ledgercomm/boilerplate_client/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests_ledgercomm/ledgercomm/boilerplate_client/boilerplate_cmd.py b/tests_ledgercomm/ledgercomm/boilerplate_client/boilerplate_cmd.py deleted file mode 100644 index ef27350..0000000 --- a/tests_ledgercomm/ledgercomm/boilerplate_client/boilerplate_cmd.py +++ /dev/null @@ -1,195 +0,0 @@ -import struct -import time -from typing import Tuple - -from ledgercomm import Transport - -from boilerplate_client.boilerplate_cmd_builder import BoilerplateCommandBuilder, InsType -from boilerplate_client.button import Button -from boilerplate_client.exception import DeviceException -from boilerplate_client.transaction import Transaction - - -class BoilerplateCommand: - def __init__(self, - transport: Transport, - debug: bool = False) -> None: - self.transport = transport - self.builder = BoilerplateCommandBuilder(debug=debug) - self.debug = debug - - def get_app_and_version(self) -> Tuple[str, str]: - sw, response = self.transport.exchange_raw( - self.builder.get_app_and_version() - ) # type: int, bytes - - if sw != 0x9000: - raise DeviceException(error_code=sw, ins=0x01) - - # response = format_id (1) || - # app_name_len (1) || - # app_name (var) || - # version_len (1) || - # version (var) || - offset: int = 0 - - format_id: int = response[offset] - offset += 1 - app_name_len: int = response[offset] - offset += 1 - app_name: str = response[offset:offset + app_name_len].decode("ascii") - offset += app_name_len - version_len: int = response[offset] - offset += 1 - version: str = response[offset:offset + version_len].decode("ascii") - offset += version_len - - return app_name, version - - def get_version(self) -> Tuple[int, int, int]: - sw, response = self.transport.exchange_raw( - self.builder.get_version() - ) # type: int, bytes - - if sw != 0x9000: - raise DeviceException(error_code=sw, ins=InsType.INS_GET_VERSION) - - # response = MAJOR (1) || MINOR (1) || PATCH (1) - assert len(response) == 3 - - major, minor, patch = struct.unpack( - "BBB", - response - ) # type: int, int, int - - return major, minor, patch - - def get_app_name(self) -> str: - sw, response = self.transport.exchange_raw( - self.builder.get_app_name() - ) # type: int, bytes - - if sw != 0x9000: - raise DeviceException(error_code=sw, ins=InsType.INS_GET_APP_NAME) - - return response.decode("ascii") - - def get_public_key(self, bip32_path: str, display: bool = False) -> Tuple[bytes, bytes]: - sw, response = self.transport.exchange_raw( - self.builder.get_public_key(bip32_path=bip32_path, - display=display) - ) # type: int, bytes - - if sw != 0x9000: - raise DeviceException(error_code=sw, ins=InsType.INS_GET_PUBLIC_KEY) - - # response = pub_key_len (1) || - # pub_key (var) || - - offset: int = 0 - offset += 1 - pub_key_x: bytes = response[offset:offset + 32] - offset += 1 + 32 - pub_key_y: bytes = response[offset:offset + 32] - - assert len(response) == 65 - - return pub_key_x, pub_key_y - - def sign_hash(self, bip32_path: str, hash: bytes, button: Button, model: str) -> Tuple[bytes, bytes, int]: - sw: int - response: bytes = b"" - - for chunk in self.builder.sign_hash(bip32_path=bip32_path, hash=hash): - self.transport.send_raw(chunk) - - sw, response = self.transport.recv() - - if sw != 0x9000: - raise DeviceException(error_code=sw, ins=InsType.INS_SIGN_TX) - - # response = sig_len (1) || - # sig (var) || - # v (1) - offset: int = 0 - sig_len: int = response[offset] - offset += 1 - r: bytes = response[offset:offset + 32] - offset += 32 - s: bytes = response[offset:offset + 32] - offset += 32 - v: int = response[offset] - offset += 1 - - assert len(response) == 1 + sig_len - - return r, s, v - - def compute_pedersen(self, a: bytes, b: bytes, nb: int, version: int) -> bytes: - - chunk = self.builder.pedersen(a=a, b=b, nb=nb, version=version) - - self.transport.send_raw(chunk) - - sw, response = self.transport.recv() - - if sw != 0x9000: - raise DeviceException(error_code=sw, ins=InsType.INS_COMPUTE_PEDERSEN) - - h: bytes = response[0:32] - - return h - - def sign_tx(self, bip32_path: str, transaction: Transaction, button: Button, model: str) -> Tuple[int, bytes]: - sw: int - response: bytes = b"" - - for is_last, chunk in self.builder.sign_tx(bip32_path=bip32_path, transaction=transaction): - self.transport.send_raw(chunk) - - if is_last: - time.sleep(2) - - # Review Transaction - button.right_click() - # Address - # Due to screen size, NanoS needs 2 more screens to display the address - if model == 'nanos': - button.right_click() - button.right_click() - button.right_click() - button.right_click() - # To - button.right_click() - button.right_click() - if model == 'nanos': - button.right_click() - button.right_click() - # Selector - button.right_click() - # Calldata #1 - button.right_click() - button.right_click() - # Calldata #2 - button.right_click() - # Approve - button.both_click() - - sw, response = self.transport.recv() # type: int, bytes - - if sw != 0x9000: - raise DeviceException(error_code=sw, ins=InsType.INS_SIGN_TX) - - offset: int = 0 - sig_len: int = response[offset] - offset += 1 - r: bytes = response[offset:offset + 32] - offset += 32 - s: bytes = response[offset:offset + 32] - offset += 32 - v: int = response[offset] - offset += 1 - - assert len(response) == 1 + sig_len - - return r, s, v diff --git a/tests_ledgercomm/ledgercomm/boilerplate_client/boilerplate_cmd_builder.py b/tests_ledgercomm/ledgercomm/boilerplate_client/boilerplate_cmd_builder.py deleted file mode 100644 index 153542f..0000000 --- a/tests_ledgercomm/ledgercomm/boilerplate_client/boilerplate_cmd_builder.py +++ /dev/null @@ -1,261 +0,0 @@ -import enum -import logging -import struct -from typing import List, Tuple, Union, Iterator, cast - -from boilerplate_client.transaction import Transaction -from boilerplate_client.utils import bip32_path_from_string - -MAX_APDU_LEN: int = 255 - -def chunkify(data: bytes, chunk_len: int) -> Iterator[Tuple[bool, bytes]]: - size: int = len(data) - - if size <= chunk_len: - yield True, data - return - - chunk: int = size // chunk_len - remaining: int = size % chunk_len - offset: int = 0 - - for i in range(chunk): - yield False, data[offset:offset + chunk_len] - offset += chunk_len - - if remaining: - yield True, data[offset:] - - -class InsType(enum.IntEnum): - INS_GET_VERSION = 0x00 - INS_GET_PUBLIC_KEY = 0x01 - INS_SIGN_HASH = 0x02 - INS_SIGN_TX = 0x03 - INS_COMPUTE_PEDERSEN = 0x04 - - -class BoilerplateCommandBuilder: - """APDU command builder for the Boilerplate application. - - Parameters - ---------- - debug: bool - Whether you want to see logging or not. - - Attributes - ---------- - debug: bool - Whether you want to see logging or not. - - """ - CLA: int = 0x5A - - def __init__(self, debug: bool = False): - """Init constructor.""" - self.debug = debug - - def serialize(self, - cla: int, - ins: Union[int, enum.IntEnum], - p1: int = 0, - p2: int = 0, - cdata: bytes = b"") -> bytes: - """Serialize the whole APDU command (header + data). - - Parameters - ---------- - cla : int - Instruction class: CLA (1 byte) - ins : Union[int, IntEnum] - Instruction code: INS (1 byte) - p1 : int - Instruction parameter 1: P1 (1 byte). - p2 : int - Instruction parameter 2: P2 (1 byte). - cdata : bytes - Bytes of command data. - - Returns - ------- - bytes - Bytes of a complete APDU command. - - """ - ins = cast(int, ins.value) if isinstance(ins, enum.IntEnum) else cast(int, ins) - - header: bytes = struct.pack("BBBBB", - cla, - ins, - p1, - p2, - len(cdata)) # add Lc to APDU header - - if self.debug: - logging.info("header: %s", header.hex()) - logging.info("cdata: %s", cdata.hex()) - - return header + cdata - - def get_app_and_version(self) -> bytes: - """Command builder for GET_APP_AND_VERSION (builtin in BOLOS SDK). - - Returns - ------- - bytes - APDU command for GET_APP_AND_VERSION. - - """ - return self.serialize(cla=0xB0, # specific CLA for BOLOS - ins=0x01, - p1=0x00, - p2=0x00, - cdata=b"") - - def get_version(self) -> bytes: - """Command builder for GET_VERSION. - - Returns - ------- - bytes - APDU command for GET_VERSION. - - """ - return self.serialize(cla=self.CLA, - ins=InsType.INS_GET_VERSION, - p1=0x00, - p2=0x00, - cdata=b"") - - def get_app_name(self) -> bytes: - """Command builder for GET_APP_NAME. - - Returns - ------- - bytes - APDU command for GET_APP_NAME. - - """ - return self.serialize(cla=self.CLA, - ins=InsType.INS_GET_APP_NAME, - p1=0x00, - p2=0x00, - cdata=b"") - - def get_public_key(self, bip32_path: str, display: bool = False) -> bytes: - """Command builder for GET_PUBLIC_KEY. - - Parameters - ---------- - bip32_path: str - String representation of BIP32 path. - display : bool - Whether you want to display the address on the device. - - Returns - ------- - bytes - APDU command for GET_PUBLIC_KEY. - - """ - bip32_paths: List[bytes] = bip32_path_from_string(bip32_path) - - cdata: bytes = b"".join([ - *bip32_paths - ]) - - return self.serialize(cla=self.CLA, - ins=InsType.INS_GET_PUBLIC_KEY, - p1=0x01 if display else 0x00, - p2=0x00, - cdata=cdata) - - def sign_hash(self, bip32_path: str, hash: bytes) -> Iterator[bytes]: - """Command builder for INS_SIGN_HASH. - - Parameters - ---------- - bip32_path : str - String representation of BIP32 path. - hash : bytes - Representation of the hash to be signed. - - Yields - ------- - bytes - APDU command chunk for INS_SIGN_HASH. - - """ - bip32_paths: List[bytes] = bip32_path_from_string(bip32_path) - - cdata: bytes = b"".join([ - *bip32_paths - ]) - - yield self.serialize(cla=self.CLA, - ins=InsType.INS_SIGN_HASH, - p1=0x00, - p2=0x00, - cdata=cdata) - - yield self.serialize(cla=self.CLA, - ins=InsType.INS_SIGN_HASH, - p1=0x02, - p2=0x00, - cdata=hash) - - def pedersen(self, a: bytes, b: bytes, nb: int, version: int) -> bytes: - - cdata: bytes = b"".join([ - a, - b - ]) - - return self.serialize(cla=self.CLA, - ins=InsType.INS_COMPUTE_PEDERSEN, - p1=nb, - p2=version, - cdata=cdata) - - def sign_tx(self, bip32_path: str, transaction: Transaction) -> Iterator[Tuple[bool, bytes]]: - """Command builder for INS_SIGN_TX. - - Parameters - ---------- - bip32_path : str - String representation of BIP32 path. - transaction : Transaction - Representation of the transaction to be signed. - - Yields - ------- - bytes - APDU command chunk for INS_SIGN_TX. - - """ - bip32_paths: List[bytes] = bip32_path_from_string(bip32_path) - - cdata: bytes = b"".join([ - len(bip32_paths).to_bytes(1, byteorder="big"), - *bip32_paths - ]) - - yield False, self.serialize(cla=self.CLA, - ins=InsType.INS_SIGN_TX, - p1=0x00, - p2=0x80, - cdata=cdata) - - for i, (is_last, chunk) in enumerate(transaction.serialize()): - if is_last: - yield True, self.serialize(cla=self.CLA, - ins=InsType.INS_SIGN_TX, - p1=i + 1, - p2=0x00, - cdata=chunk) - else: - yield False, self.serialize(cla=self.CLA, - ins=InsType.INS_SIGN_TX, - p1=i + 1, - p2=0x80, - cdata=chunk) diff --git a/tests_ledgercomm/ledgercomm/boilerplate_client/button.py b/tests_ledgercomm/ledgercomm/boilerplate_client/button.py deleted file mode 100644 index bfe962c..0000000 --- a/tests_ledgercomm/ledgercomm/boilerplate_client/button.py +++ /dev/null @@ -1,55 +0,0 @@ -from abc import ABCMeta, abstractmethod -import socket -import requests - - -class Button(metaclass=ABCMeta): - @abstractmethod - def right_click(self): - ... - - @abstractmethod - def left_click(self): - ... - - @abstractmethod - def both_click(self): - ... - - @abstractmethod - def close(self): - ... - - -class ButtonFake(Button): - def right_click(self): - pass - - def left_click(self): - pass - - def both_click(self): - pass - - def close(self): - pass - - -class ButtonTCP(Button): - def __init__(self, url: str, port: int) -> None: - self.url = url+':'+str(port) - - def right_click(self): - action = {"action":"press-and-release"} - requests.post(self.url+'/button/right', json=action) - - def left_click(self): - action = {"action":"press-and-release"} - requests.post(self.url+'/button/left', json=action) - - def both_click(self): - action = {"action":"press-and-release"} - requests.post(self.url+'/button/both', json=action) - - def close(self): - pass diff --git a/tests_ledgercomm/ledgercomm/boilerplate_client/exception/__init__.py b/tests_ledgercomm/ledgercomm/boilerplate_client/exception/__init__.py deleted file mode 100644 index acb2bb8..0000000 --- a/tests_ledgercomm/ledgercomm/boilerplate_client/exception/__init__.py +++ /dev/null @@ -1,35 +0,0 @@ -from .device_exception import DeviceException -from .errors import (UnknownDeviceError, - DenyError, - WrongP1P2Error, - WrongDataLengthError, - InsNotSupportedError, - ClaNotSupportedError, - WrongResponseLengthError, - DisplayBip32PathFailError, - DisplayAddressFailError, - DisplayAmountFailError, - WrongTxLengthError, - TxParsingFailError, - TxHashFail, - BadStateError, - SignatureFailError) - -__all__ = [ - "DeviceException", - "DenyError", - "UnknownDeviceError", - "WrongP1P2Error", - "WrongDataLengthError", - "InsNotSupportedError", - "ClaNotSupportedError", - "WrongResponseLengthError", - "DisplayBip32PathFailError", - "DisplayAddressFailError", - "DisplayAmountFailError", - "WrongTxLengthError", - "TxParsingFailError", - "TxHashFail", - "BadStateError", - "SignatureFailError" -] diff --git a/tests_ledgercomm/ledgercomm/boilerplate_client/exception/device_exception.py b/tests_ledgercomm/ledgercomm/boilerplate_client/exception/device_exception.py deleted file mode 100644 index 8cd9ede..0000000 --- a/tests_ledgercomm/ledgercomm/boilerplate_client/exception/device_exception.py +++ /dev/null @@ -1,39 +0,0 @@ -import enum -from typing import Dict, Any, Union - -from .errors import * - - -class DeviceException(Exception): # pylint: disable=too-few-public-methods - exc: Dict[int, Any] = { - 0x6E00: ClaNotSupportedError, - 0x6E01: InsNotSupportedError, - 0x6E02: WrongP1P2Error, - 0x6E03: WrongDataLengthError, - - 0x6985: DenyError, - 0xB000: WrongResponseLengthError, - 0xB001: DisplayBip32PathFailError, - 0xB002: DisplayAddressFailError, - 0xB003: DisplayAmountFailError, - 0xB004: WrongTxLengthError, - 0xB005: TxParsingFailError, - 0xB006: TxHashFail, - 0xB007: BadStateError, - 0xB008: SignatureFailError - } - - def __new__(cls, - error_code: int, - ins: Union[int, enum.IntEnum, None] = None, - message: str = "" - ) -> Any: - error_message: str = (f"Error in {ins!r} command" - if ins else "Error in command") - - if error_code in DeviceException.exc: - return DeviceException.exc[error_code](hex(error_code), - error_message, - message) - - return UnknownDeviceError(hex(error_code), error_message, message) diff --git a/tests_ledgercomm/ledgercomm/boilerplate_client/exception/errors.py b/tests_ledgercomm/ledgercomm/boilerplate_client/exception/errors.py deleted file mode 100644 index a9a853d..0000000 --- a/tests_ledgercomm/ledgercomm/boilerplate_client/exception/errors.py +++ /dev/null @@ -1,58 +0,0 @@ -class UnknownDeviceError(Exception): - pass - - -class DenyError(Exception): - pass - - -class WrongP1P2Error(Exception): - pass - - -class WrongDataLengthError(Exception): - pass - - -class InsNotSupportedError(Exception): - pass - - -class ClaNotSupportedError(Exception): - pass - - -class WrongResponseLengthError(Exception): - pass - - -class DisplayBip32PathFailError(Exception): - pass - - -class DisplayAddressFailError(Exception): - pass - - -class DisplayAmountFailError(Exception): - pass - - -class WrongTxLengthError(Exception): - pass - - -class TxParsingFailError(Exception): - pass - - -class TxHashFail(Exception): - pass - - -class BadStateError(Exception): - pass - - -class SignatureFailError(Exception): - pass diff --git a/tests_ledgercomm/ledgercomm/boilerplate_client/transaction.py b/tests_ledgercomm/ledgercomm/boilerplate_client/transaction.py deleted file mode 100644 index 0250227..0000000 --- a/tests_ledgercomm/ledgercomm/boilerplate_client/transaction.py +++ /dev/null @@ -1,69 +0,0 @@ -from io import BytesIO -from sys import byteorder -from typing import Iterator, Union, Tuple - -from boilerplate_client.utils import (read, read_uint, read_varint, - write_varint, UINT64_MAX) - - -class TransactionError(Exception): - pass - - -class Transaction: - def __init__(self, aa, maxfee, nonce, version, chainid, to, selector, calldata) -> None: - - self.aa = aa - self.maxfee = maxfee - self.nonce = nonce - self.version = version - self.chainid = chainid - - self.to = to - self.selector = selector - self.calldata = calldata - - def serialize(self) -> Iterator[Tuple[bool, bytes]]: - yield False, b"".join([ - # chunk 1 = accountAddress (32 bytes) + maxFee (32 bytes) + nonce (32 bytes) + version (32 bytes) + chain_id (32 bytes)= 160 bytes - int(self.aa[2:], 16).to_bytes(32, byteorder="big"), - int(self.maxfee).to_bytes(32, byteorder="big"), - self.nonce.to_bytes(32, byteorder="big"), - self.version.to_bytes(32, byteorder="big"), - int(self.chainid, 16).to_bytes(32, byteorder="big")]) - - # chunk 2 = to (32 bytes) + selector length (1 byte) + selector (selector length bytes) + call_data length (1 byte) - yield False, b"".join([int(self.to[2:], 16).to_bytes(32, byteorder="big"), - int(len(self.selector)).to_bytes(1, byteorder="big"), - bytes(self.selector, 'utf-8'), - int(len(self.calldata)).to_bytes(1, byteorder="big")]) - - # chunk n = calldata chunks - for data in self.calldata: - if (data[1][:2] == '0x'): - chunk = b"".join([ - int(len(data[0])).to_bytes(1, byteorder="big"), - data[0].encode('ascii'), - int(data[1][2:], 16).to_bytes(32, byteorder="big")]) - else: - chunk = b"".join([ - int(len(data[0])).to_bytes(1, byteorder="big"), - data[0].encode('ascii'), - int(data[1]).to_bytes(32, byteorder="big")]) - - if (data == self.calldata[-1]): - yield True, chunk - else: - yield False, chunk - - @classmethod - def from_bytes(cls, hexa: Union[bytes, BytesIO]): - buf: BytesIO = BytesIO(hexa) if isinstance(hexa, bytes) else hexa - - nonce: int = read_uint(buf, 64, byteorder="big") - to: bytes = read(buf, 20) - value: int = read_uint(buf, 64, byteorder="big") - memo_len: int = read_varint(buf) - memo: str = read(buf, memo_len).decode("ascii") - - return cls(nonce=nonce, to=to, value=value, memo=memo) diff --git a/tests_ledgercomm/ledgercomm/boilerplate_client/utils.py b/tests_ledgercomm/ledgercomm/boilerplate_client/utils.py deleted file mode 100644 index 6260ed2..0000000 --- a/tests_ledgercomm/ledgercomm/boilerplate_client/utils.py +++ /dev/null @@ -1,75 +0,0 @@ -from io import BytesIO -from typing import List, Optional, Literal - - -UINT64_MAX: int = 18446744073709551615 -UINT32_MAX: int = 4294967295 -UINT16_MAX: int = 65535 - - -def bip32_path_from_string(path: str) -> List[bytes]: - splitted_path: List[str] = path.split("/") - - if not splitted_path: - raise Exception(f"BIP32 path format error: '{path}'") - - if "m" in splitted_path and splitted_path[0] == "m": - splitted_path = splitted_path[1:] - - return [int(p).to_bytes(4, byteorder="big") if "'" not in p - else (0x80000000 | int(p[:-1])).to_bytes(4, byteorder="big") - for p in splitted_path] - - -def write_varint(n: int) -> bytes: - if n < 0xFC: - return n.to_bytes(1, byteorder="little") - - if n <= UINT16_MAX: - return b"\xFD" + n.to_bytes(2, byteorder="little") - - if n <= UINT32_MAX: - return b"\xFE" + n.to_bytes(4, byteorder="little") - - if n <= UINT64_MAX: - return b"\xFF" + n.to_bytes(8, byteorder="little") - - raise ValueError(f"Can't write to varint: '{n}'!") - - -def read_varint(buf: BytesIO, - prefix: Optional[bytes] = None) -> int: - b: bytes = prefix if prefix else buf.read(1) - - if not b: - raise ValueError(f"Can't read prefix: '{b}'!") - - n: int = {b"\xfd": 2, b"\xfe": 4, b"\xff": 8}.get(b, 1) # default to 1 - - b = buf.read(n) if n > 1 else b - - if len(b) != n: - raise ValueError("Can't read varint!") - - return int.from_bytes(b, byteorder="little") - - -def read(buf: BytesIO, size: int) -> bytes: - b: bytes = buf.read(size) - - if len(b) < size: - raise ValueError(f"Can't read {size} bytes in buffer!") - - return b - - -def read_uint(buf: BytesIO, - bit_len: int, - byteorder: Literal['big', 'little'] = 'little') -> int: - size: int = bit_len // 8 - b: bytes = buf.read(size) - - if len(b) < size: - raise ValueError(f"Can't read u{bit_len} in buffer!") - - return int.from_bytes(b, byteorder) diff --git a/tests_ledgercomm/ledgercomm/conftest.py b/tests_ledgercomm/ledgercomm/conftest.py deleted file mode 100644 index 8f30eda..0000000 --- a/tests_ledgercomm/ledgercomm/conftest.py +++ /dev/null @@ -1,75 +0,0 @@ -from pathlib import Path - -import pytest - -from ledgercomm import Transport - -from boilerplate_client.boilerplate_cmd import BoilerplateCommand -from boilerplate_client.button import ButtonTCP, ButtonFake - - -def pytest_addoption(parser): - parser.addoption("--hid", - action="store_true") - parser.addoption("--headless", - action="store_true") - parser.addoption("--model", - action="store", - default="nanosp") - - -@pytest.fixture(scope="module") -def sw_h_path(): - # path with tests - conftest_folder_path: Path = Path(__file__).parent - # sw.h should be in ../../src/sw.h - sw_h_path = conftest_folder_path.parent.parent / "src" / "sw.h" - - if not sw_h_path.is_file(): - raise FileNotFoundError(f"Can't find sw.h: '{sw_h_path}'") - - return sw_h_path - - -@pytest.fixture(scope="session") -def hid(pytestconfig): - return pytestconfig.getoption("hid") - - -@pytest.fixture(scope="session") -def headless(pytestconfig): - return pytestconfig.getoption("headless") - - -@pytest.fixture(scope="session") -def model(pytestconfig): - return pytestconfig.getoption("model") - - -@pytest.fixture(scope="module") -def button(headless): - if headless: - button_client = ButtonTCP(url="http://127.0.0.1", port=5001) - else: - button_client = ButtonFake() - - yield button_client - - button_client.close() - - -@pytest.fixture(scope="session") -def cmd(hid): - transport = (Transport(interface="hid", debug=True) - if hid else Transport(interface="tcp", - server="127.0.0.1", - port=9999, - debug=True)) - command = BoilerplateCommand( - transport=transport, - debug=True - ) - - yield command - - command.transport.close() diff --git a/tests_ledgercomm/ledgercomm/requirements.txt b/tests_ledgercomm/ledgercomm/requirements.txt deleted file mode 100644 index e5ae57f..0000000 --- a/tests_ledgercomm/ledgercomm/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -pytest -starknet-py \ No newline at end of file diff --git a/tests_ledgercomm/ledgercomm/setup.cfg b/tests_ledgercomm/ledgercomm/setup.cfg deleted file mode 100644 index c79fd88..0000000 --- a/tests_ledgercomm/ledgercomm/setup.cfg +++ /dev/null @@ -1,20 +0,0 @@ -[tool:pytest] -addopts = --strict-markers - -[pylint] -disable = C0114, # missing-module-docstring - C0115, # missing-class-docstring - C0116, # missing-function-docstring - C0103, # invalid-name - R0801, # duplicate-code - R0913 # too-many-arguments -extension-pkg-whitelist=hid - -[pycodestyle] -max-line-length = 90 - -[mypy-hid.*] -ignore_missing_imports = True - -[mypy-pytest.*] -ignore_missing_imports = True diff --git a/tests_ledgercomm/ledgercomm/test_error_cmd.py b/tests_ledgercomm/ledgercomm/test_error_cmd.py deleted file mode 100644 index d537291..0000000 --- a/tests_ledgercomm/ledgercomm/test_error_cmd.py +++ /dev/null @@ -1,44 +0,0 @@ -import pytest - -from boilerplate_client.exception import * - - -@pytest.mark.xfail(raises=ClaNotSupportedError) -def test_bad_cla(cmd): - sw, _ = cmd.transport.exchange(cla=0xa0, # 0xa0 instead of 0x5a - ins=0x01, - p1=0x00, - p2=0x00, - cdata=b"") - - raise DeviceException(error_code=sw) - - -@pytest.mark.xfail(raises=InsNotSupportedError) -def test_bad_ins(cmd): - sw, _ = cmd.transport.exchange(cla=0x80, - ins=0xfe, # bad INS - p1=0x00, - p2=0x00, - cdata=b"") - - raise DeviceException(error_code=sw) - - -#@pytest.mark.xfail(raises=WrongP1P2Error) -#def test_wrong_p1p2(cmd): -# sw, _ = cmd.transport.exchange(cla=0x80, -# ins=0x01, -# p1=0x08, -# p2=0x00, -# cdata=b"") -# -# raise DeviceException(error_code=sw) - - -@pytest.mark.xfail(raises=WrongDataLengthError) -def test_wrong_data_length(cmd): - # APDUs must be at least 5 bytes: CLA, INS, P1, P2, Lc. - sw, _ = cmd.transport.exchange_raw("8002000010") - - raise DeviceException(error_code=sw) diff --git a/tests_ledgercomm/ledgercomm/test_pubkey_cmd.py b/tests_ledgercomm/ledgercomm/test_pubkey_cmd.py deleted file mode 100644 index 9294d5b..0000000 --- a/tests_ledgercomm/ledgercomm/test_pubkey_cmd.py +++ /dev/null @@ -1,8 +0,0 @@ -def test_get_public_key(cmd): - (pub_key_x, pub_key_y) = cmd.get_public_key( - bip32_path="m/2645'/1195502025'/1148870696'/0'/0'/0", - display=False - ) # type: bytes - - print(int.from_bytes(pub_key_x, byteorder='big')) - print(int.from_bytes(pub_key_y, byteorder='big')) diff --git a/tests_ledgercomm/ledgercomm/test_sign_hash_cmd.py b/tests_ledgercomm/ledgercomm/test_sign_hash_cmd.py deleted file mode 100644 index 51ddcf6..0000000 --- a/tests_ledgercomm/ledgercomm/test_sign_hash_cmd.py +++ /dev/null @@ -1,44 +0,0 @@ -from starknet_py.hash.utils import verify_message_signature - -bip32_path: str = "m/2645'/1195502025'/1148870696'/0'/0'/0" - -# pedersen hashes -hash_0: str = "55b8f28706a5008d3103bcb2bfa6356e56b95c34fed265c955846670a6bb4ef" # 31,5 bytes (63 digits) -hash_1: str = "2bd1d3f8f45a011cbd0674ded291d58985761bbcbc04f4d01c8285d1b35c411" # 31,5 bytes (63 digits) -hash_2: str = "2e672d748fbe3b6e833b61ea8b6e688850247022f06406a1eb83e345ffb417" # 31 bytes (62 digits) -hash_3: str = "936e8798681b391af0c57fe0bf5703b9631bea18b4bc84b3940ebab234744" # 30,5 bytes (61 digits) -hash_4: str = "2534b0f53ccac2347dd51befce72338d9b7c568905f17218d93980ce1fc869f" # 31,5 bytes (63 digits) - -hashes = [hash_0, hash_1, hash_2, hash_3, hash_4] - -def fix_sign(hash: str) -> str: - # fix hash to fit into 32 bytes - while (len(hash) < 63): - hash = '0' + hash - - assert(len(hash) == 63) - return hash + '0' - -def test_sign_hash(cmd, button, model): - - for hash in hashes: - - pub_key_x, pub_key_y = cmd.get_public_key( - bip32_path=bip32_path, - display=False - ) - - r, s, v = cmd.sign_hash(bip32_path=bip32_path, - hash=bytes.fromhex(fix_sign(hash)), - button=button, - model=model) - - print(int.from_bytes(r, byteorder='big')) - print(int.from_bytes(s, byteorder='big')) - - assert( - verify_message_signature( - msg_hash=int(hash, 16), - signature = [int.from_bytes(r, byteorder='big'), int.from_bytes(s, byteorder='big')], - public_key=int.from_bytes(pub_key_x, byteorder='big')) - ) \ No newline at end of file diff --git a/tests_ledgercomm/ledgercomm/test_version_cmd.py b/tests_ledgercomm/ledgercomm/test_version_cmd.py deleted file mode 100644 index 6d18ce6..0000000 --- a/tests_ledgercomm/ledgercomm/test_version_cmd.py +++ /dev/null @@ -1,2 +0,0 @@ -def test_version(cmd): - assert cmd.get_version() == (1, 0, 0) diff --git a/tools/apdu-generator/Cargo.toml b/tools/apdu-generator/Cargo.toml new file mode 100644 index 0000000..4e96835 --- /dev/null +++ b/tools/apdu-generator/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "apdu-generator" +version = "1.0.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +clap = { version = "4.3.4", features = ["derive"] } +ethereum-types = "0.14.1" +hex = { version = "0.4.3", features = ["serde"] } +serde = { version = "1.0.163", features = ["derive"]} +serde_json = "1.0" +starknet = { git = "https://github.com/xJonathanLEI/starknet-rs" } \ No newline at end of file diff --git a/tools/apdu-generator/README.md b/tools/apdu-generator/README.md new file mode 100644 index 0000000..91bb703 --- /dev/null +++ b/tools/apdu-generator/README.md @@ -0,0 +1,2 @@ +# apdu_generator +This tool can be used to generate ADPUs to be sent to Starknet Nano application. diff --git a/tools/apdu-generator/apdu_samples/erc20_transfer.dat b/tools/apdu-generator/apdu_samples/erc20_transfer.dat new file mode 100644 index 0000000..1c12aa4 --- /dev/null +++ b/tools/apdu-generator/apdu_samples/erc20_transfer.dat @@ -0,0 +1,7 @@ +=> 5a0300001880000a55c741e9c9c47a6028800000008000000000000000 +=> 5a030100e007e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a000000000000000000000000000000000000000000000000000000000000000000004c315f47415300000000000000000000000000000000000000000000000000004c325f47415300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000534e5f4d41494e00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000 +=> 5a03020000 +=> 5a03030000 +=> 5a030400200000000000000000000000000000000000000000000000000000000000000001 +=> 5a03050080049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc70083afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e07e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a00000000000000000000000000000000000000000000000000000000000003e8 +=> 5a03050200 diff --git a/tools/apdu-generator/apdu_samples/erc20_transfer.json b/tools/apdu-generator/apdu_samples/erc20_transfer.json new file mode 100644 index 0000000..a707e26 --- /dev/null +++ b/tools/apdu-generator/apdu_samples/erc20_transfer.json @@ -0,0 +1,65 @@ +[ + { + "header": { + "cla": 90, + "ins": 3, + "p1": 0, + "p2": 0 + }, + "data": "80000a55c741e9c9c47a6028800000008000000000000000" + }, + { + "header": { + "cla": 90, + "ins": 3, + "p1": 1, + "p2": 0 + }, + "data": "07e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a000000000000000000000000000000000000000000000000000000000000000000004c315f47415300000000000000000000000000000000000000000000000000004c325f47415300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000534e5f4d41494e00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000" + }, + { + "header": { + "cla": 90, + "ins": 3, + "p1": 2, + "p2": 0 + }, + "data": "" + }, + { + "header": { + "cla": 90, + "ins": 3, + "p1": 3, + "p2": 0 + }, + "data": "" + }, + { + "header": { + "cla": 90, + "ins": 3, + "p1": 4, + "p2": 0 + }, + "data": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "header": { + "cla": 90, + "ins": 3, + "p1": 5, + "p2": 0 + }, + "data": "049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc70083afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e07e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a00000000000000000000000000000000000000000000000000000000000003e8" + }, + { + "header": { + "cla": 90, + "ins": 3, + "p1": 5, + "p2": 2 + }, + "data": "" + } +] diff --git a/tools/apdu-generator/apdu_samples/get_pubkey.dat b/tools/apdu-generator/apdu_samples/get_pubkey.dat new file mode 100644 index 0000000..a43a15c --- /dev/null +++ b/tools/apdu-generator/apdu_samples/get_pubkey.dat @@ -0,0 +1 @@ +=> 5a0100001880000a55c741e9c9c47a6028800000008000000000000000 \ No newline at end of file diff --git a/tools/apdu-generator/apdu_samples/get_pubkey.json b/tools/apdu-generator/apdu_samples/get_pubkey.json new file mode 100644 index 0000000..b868ec0 --- /dev/null +++ b/tools/apdu-generator/apdu_samples/get_pubkey.json @@ -0,0 +1,11 @@ +[ + { + "header": { + "cla": 90, + "ins": 1, + "p1": 0, + "p2": 0 + }, + "data": "80000a55c741e9c9c47a6028800000008000000000000000" + } +] \ No newline at end of file diff --git a/tools/apdu-generator/apdu_samples/get_pubkey_confirm.dat b/tools/apdu-generator/apdu_samples/get_pubkey_confirm.dat new file mode 100644 index 0000000..29b1c96 --- /dev/null +++ b/tools/apdu-generator/apdu_samples/get_pubkey_confirm.dat @@ -0,0 +1 @@ +=> 5a0101001880000a55c741e9c9c47a6028800000008000000000000000 \ No newline at end of file diff --git a/tools/apdu-generator/apdu_samples/get_pubkey_confirm.json b/tools/apdu-generator/apdu_samples/get_pubkey_confirm.json new file mode 100644 index 0000000..8d9b3e7 --- /dev/null +++ b/tools/apdu-generator/apdu_samples/get_pubkey_confirm.json @@ -0,0 +1,11 @@ +[ + { + "header": { + "cla": 90, + "ins": 1, + "p1": 1, + "p2": 0 + }, + "data": "80000a55c741e9c9c47a6028800000008000000000000000" + } +] \ No newline at end of file diff --git a/tools/apdu-generator/apdu_samples/random.dat b/tools/apdu-generator/apdu_samples/random.dat new file mode 100644 index 0000000..ec7e9d2 --- /dev/null +++ b/tools/apdu-generator/apdu_samples/random.dat @@ -0,0 +1,7 @@ +=> 5a0300001880000a55c741e9c9c47a6028800000008000000000000000 +=> 5a030100e007e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a000000000000000000000000000000000000000000000000000000000000000000004c315f47415300000000000000000000000000000000000000000000000000004c325f47415300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000534e5f4d41494e00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000 +=> 5a03020000 +=> 5a03030000 +=> 5a030400200000000000000000000000000000000000000000000000000000000000000001 +=> 5a03050080049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc702f0b3c5710379609eb5495f1ecd348cb28167711b73609fe565a7273455035407e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a00000000000000000000000000000000000000000000000000000000000003e8 +=> 5a03050200 diff --git a/tools/apdu-generator/apdu_samples/random.json b/tools/apdu-generator/apdu_samples/random.json new file mode 100644 index 0000000..959866c --- /dev/null +++ b/tools/apdu-generator/apdu_samples/random.json @@ -0,0 +1,65 @@ +[ + { + "header": { + "cla": 90, + "ins": 3, + "p1": 0, + "p2": 0 + }, + "data": "80000a55c741e9c9c47a6028800000008000000000000000" + }, + { + "header": { + "cla": 90, + "ins": 3, + "p1": 1, + "p2": 0 + }, + "data": "07e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a000000000000000000000000000000000000000000000000000000000000000000004c315f47415300000000000000000000000000000000000000000000000000004c325f47415300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000534e5f4d41494e00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000" + }, + { + "header": { + "cla": 90, + "ins": 3, + "p1": 2, + "p2": 0 + }, + "data": "" + }, + { + "header": { + "cla": 90, + "ins": 3, + "p1": 3, + "p2": 0 + }, + "data": "" + }, + { + "header": { + "cla": 90, + "ins": 3, + "p1": 4, + "p2": 0 + }, + "data": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "header": { + "cla": 90, + "ins": 3, + "p1": 5, + "p2": 0 + }, + "data": "049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc702f0b3c5710379609eb5495f1ecd348cb28167711b73609fe565a7273455035407e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a00000000000000000000000000000000000000000000000000000000000003e8" + }, + { + "header": { + "cla": 90, + "ins": 3, + "p1": 5, + "p2": 2 + }, + "data": "" + } +] diff --git a/tools/apdu-generator/src/apdu.rs b/tools/apdu-generator/src/apdu.rs new file mode 100644 index 0000000..c810075 --- /dev/null +++ b/tools/apdu-generator/src/apdu.rs @@ -0,0 +1,56 @@ +use serde::Serialize; +use std::fmt; + +const MAX_APDU_DATA_SIZE: usize = 255; + +#[derive(Default, Clone, Copy, Serialize)] +pub struct ApduHeader { + pub cla: u8, + pub ins: u8, + pub p1: u8, + pub p2: u8, +} + +#[derive(Default, Clone, Serialize)] +pub struct Apdu { + pub header: ApduHeader, + #[serde(with = "hex::serde")] + pub data: Vec, +} + +impl Apdu { + pub fn new(header: ApduHeader) -> Self { + Apdu { + header, + data: Vec::new(), + } + } + + pub fn clear(&mut self) { + self.data.fill(0); + } + + pub fn append(&mut self, data: &[u8]) -> Result<(), usize> { + if self.data.len() + data.len() <= MAX_APDU_DATA_SIZE { + self.data.extend_from_slice(data); + Ok(()) + } else { + Err(MAX_APDU_DATA_SIZE - self.data.len()) + } + } +} + +impl fmt::Display for Apdu { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:02x}", self.header.cla)?; + let ins: u8 = self.header.ins; + write!(f, "{:02x}", ins)?; + write!(f, "{:02x}", self.header.p1)?; + write!(f, "{:02x}", self.header.p2)?; + write!(f, "{:02x}", self.data.len())?; + for b in &self.data { + write!(f, "{:02x}", b)?; + } + Ok(()) + } +} diff --git a/tools/apdu-generator/src/builder.rs b/tools/apdu-generator/src/builder.rs new file mode 100644 index 0000000..7b16c81 --- /dev/null +++ b/tools/apdu-generator/src/builder.rs @@ -0,0 +1,230 @@ +use crate::apdu::{Apdu, ApduHeader}; +use crate::types::{Call, FieldElement, Ins, Tx}; +use ethereum_types::U256; + +mod builder_internal; +use builder_internal::fix; + +pub enum ApduError { + InternalError, +} + +pub fn data_to_apdu(data: Vec, cla: u8, ins: u8, p1: u8, p2: u8) -> Apdu { + let apdu_header = ApduHeader { + cla: cla, + ins: ins.into(), + p1, + p2, + }; + let mut apdu = Apdu::new(apdu_header); + + for felt in data { + let arr: [u8; 32] = felt.try_into().unwrap(); + apdu.append(&arr[..]).unwrap(); + } + apdu +} + +pub fn pedersenhash_to_apdu(hash: &str, cla: u8, ins: Ins, sub_ins: u8, show_hash: bool) -> Apdu { + let header: ApduHeader = ApduHeader { + cla: cla, + ins: ins.into(), + p1: sub_ins, + p2: match show_hash { + true => 0x01, + false => 0x00, + }, + }; + let mut apdu = Apdu::new(header); + + let mut fixed_hash = String::from(hash.trim_start_matches("0x")); + fix(&mut fixed_hash); + let data: [u8; 32] = FieldElement(U256::from_str_radix(fixed_hash.as_str(), 16).unwrap()) + .try_into() + .unwrap(); + apdu.append(&data[..]).unwrap(); + apdu +} + +/// Build Derivation path APDU +pub fn derivation_path(path: &str, cla: u8, ins: Ins, p1: u8) -> Apdu { + let apdu_header = ApduHeader { + cla: cla, + ins: ins.into(), + p1, + p2: 0x00, + }; + let mut apdu = Apdu::new(apdu_header); + + let mut bip32_path: Vec = Vec::new(); + if let Some(spath) = path.strip_prefix("m/") { + for s in spath.split('/') { + let val: u32 = match s.ends_with('\'') { + true => 0x80000000 + s.strip_suffix('\'').unwrap().parse::().unwrap(), + false => s.parse::().unwrap(), + }; + bip32_path.push(val); + } + for val in bip32_path { + apdu.append(val.to_be_bytes().as_slice()).unwrap(); + } + } + apdu +} + +pub fn tx_data(tx: &Tx, cla: u8, ins: Ins, p1: u8) -> Apdu { + let apdu_header = ApduHeader { + cla: cla, + ins: ins.into(), + p1, + p2: 0x00, + }; + let mut apdu = Apdu::new(apdu_header); + + let mut fe: FieldElement = FieldElement(U256::from_str_radix(&tx.sender_address, 16).unwrap()); + let mut data: [u8; 32] = fe.try_into().unwrap(); + apdu.append(data.as_slice()).unwrap(); + + fe = FieldElement(U256::from_str_radix(&tx.tip, 10).unwrap()); + data = fe.try_into().unwrap(); + apdu.append(data.as_slice()).unwrap(); + + fe = FieldElement(U256::from_str_radix(&tx.l1_gas_bounds, 16).unwrap()); + data = fe.try_into().unwrap(); + apdu.append(data.as_slice()).unwrap(); + + fe = FieldElement(U256::from_str_radix(&tx.l2_gas_bounds, 16).unwrap()); + data = fe.try_into().unwrap(); + apdu.append(data.as_slice()).unwrap(); + + fe = FieldElement(U256::from_str_radix(&tx.chain_id, 16).unwrap()); + data = fe.try_into().unwrap(); + apdu.append(data.as_slice()).unwrap(); + + fe = FieldElement(U256::from_str_radix(&tx.nonce, 10).unwrap()); + data = fe.try_into().unwrap(); + apdu.append(data.as_slice()).unwrap(); + + fe = FieldElement(U256::from_str_radix(&tx.data_availability_mode, 10).unwrap()); + data = fe.try_into().unwrap(); + apdu.append(data.as_slice()).unwrap(); + + apdu +} + +pub fn paymaster_data(_data: &[String], cla: u8, ins: Ins, p1: u8) -> Apdu { + let apdu_header = ApduHeader { + cla: cla, + ins: ins.into(), + p1, + p2: 0x00, + }; + let apdu = Apdu::new(apdu_header); + apdu +} + +pub fn accound_deployment_data(_tx: &[String], cla: u8, ins: Ins, p1: u8) -> Apdu { + let apdu_header = ApduHeader { + cla: cla, + ins: ins.into(), + p1, + p2: 0x00, + }; + let apdu = Apdu::new(apdu_header); + apdu +} + +pub fn calls_nb(calls: &[Call], cla: u8, ins: Ins, p1: u8) -> Apdu { + let apdu_header = ApduHeader { + cla: cla, + ins: ins.into(), + p1, + p2: 0x00, + }; + let mut apdu = Apdu::new(apdu_header); + + let fe = FieldElement(U256::from(calls.len())); + let data: [u8; 32] = fe.try_into().unwrap(); + apdu.append(data.as_slice()).unwrap(); + apdu +} + +pub fn call(call: &Call, cla: u8, ins: Ins, p1: u8) -> Vec { + let mut apdu_list: Vec = Vec::new(); + let mut fe: [u8; 32] = [0u8; 32]; + let data: Vec = call.into(); + + let nb_apdu = data.chunks(7).len(); + + match nb_apdu { + 1 => { + let apdu_header = ApduHeader { + cla: cla, + ins: ins.into(), + p1, + p2: 0x00, + }; + let mut apdu = Apdu::new(apdu_header); + + let data = data.chunks(7).next().unwrap(); + for d in data { + d.0.to_big_endian(&mut fe); + apdu.append(&fe).unwrap(); + } + apdu_list.push(apdu); + + apdu = Apdu::new(ApduHeader { + p2: 0x02, + ..apdu_header + }); + apdu_list.push(apdu); + } + 2.. => { + let mut iter = data.chunks(7); + + let mut apdu_header = ApduHeader { + cla, + ins: Ins::SignTx.into(), + p1, + p2: 0x00, + }; + let mut apdu = Apdu::new(apdu_header); + let data = iter.next().unwrap(); + for d in data { + d.0.to_big_endian(&mut fe); + apdu.append(&fe).unwrap(); + } + apdu_list.push(apdu); + + loop { + let next = iter.next(); + match next { + Some(felts) => { + apdu_header = ApduHeader { + cla, + ins: Ins::SignTx.into(), + p1, + p2: 0x01, + }; + apdu = Apdu::new(apdu_header); + for d in felts { + d.0.to_big_endian(&mut fe); + apdu.append(&fe).unwrap(); + } + apdu_list.push(apdu); + } + None => { + apdu = Apdu::new(ApduHeader { + p2: 0x02, + ..apdu_header + }); + apdu_list.push(apdu); + break; + } + } + } + } + _ => (), + } + apdu_list +} diff --git a/tools/apdu-generator/src/builder/builder_internal.rs b/tools/apdu-generator/src/builder/builder_internal.rs new file mode 100644 index 0000000..0769f90 --- /dev/null +++ b/tools/apdu-generator/src/builder/builder_internal.rs @@ -0,0 +1,8 @@ +pub fn fix(hash: &mut String) { + // fix pedersen hash to fit into 32 bytes + while hash.len() < 63 { + hash.insert(0, '0'); + } + assert!(hash.len() == 63); + hash.push('0'); +} diff --git a/tools/apdu-generator/src/lib.rs b/tools/apdu-generator/src/lib.rs new file mode 100644 index 0000000..7c1baad --- /dev/null +++ b/tools/apdu-generator/src/lib.rs @@ -0,0 +1,3 @@ +pub mod apdu; +pub mod builder; +pub mod types; diff --git a/tools/apdu-generator/src/main.rs b/tools/apdu-generator/src/main.rs new file mode 100644 index 0000000..1a98a8a --- /dev/null +++ b/tools/apdu-generator/src/main.rs @@ -0,0 +1,103 @@ +use clap::Parser; +use std::io::prelude::*; +use std::{fs::File, path::Path}; + +/// Utility to generate APDUs for Tx blur or clear signing with Starknet Nano application +/// (see https://docs.starknet.io/documentation/architecture_and_concepts/Blocks/transactions/#invoke_transaction_version_1) +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +struct Args { + /// Tx in JSON format + #[arg(short, long)] + json: String, + + /// APDU CLA + #[arg(short, long, default_value_t = 0x5A)] + cla: u8, + + /// APDU INS + #[arg(short, long, default_value_t = 0x03)] + ins: u8, +} + +use apdu_generator::{apdu::Apdu, builder, types::Tx}; + +// Derivation path +const PATH: &str = "m/2645'/1195502025'/1148870696'/0'/0'/0"; +// Hash +// const HASH: &str = "0x55b8f28706a5008d3103bcb2bfa6356e56b95c34fed265c955846670a6bb4ef"; + +fn main() { + let args: Args = Args::parse(); + + let path = Path::new(args.json.as_str()); + + let mut file = File::open(path).unwrap(); + let mut data = String::new(); + file.read_to_string(&mut data).unwrap(); + + let mut tx: Tx = serde_json::from_str(&data).unwrap(); + tx.calls.reverse(); + + let mut apdus: Vec = Vec::new(); + + let dpath_apdu = builder::derivation_path(PATH, args.cla, args.ins.into(), 0); + apdus.push(dpath_apdu.clone()); + + let tx_data_apdu = builder::tx_data(&tx, args.cla, args.ins.into(), 1); + apdus.push(tx_data_apdu.clone()); + + let tx_data_apdu = builder::paymaster_data(&tx.paymaster_data, args.cla, args.ins.into(), 2); + apdus.push(tx_data_apdu.clone()); + + let tx_data_apdu = + builder::accound_deployment_data(&tx.account_deployment_data, args.cla, args.ins.into(), 3); + apdus.push(tx_data_apdu.clone()); + + let tx_data_apdu = builder::calls_nb(&tx.calls, args.cla, args.ins.into(), 4); + apdus.push(tx_data_apdu.clone()); + + while tx.calls.len() > 0 { + let call = tx.calls.pop().unwrap(); + let mut call_apdu = builder::call(&call, args.cla, args.ins.into(), 5); + apdus.append(&mut call_apdu); + } + + let out_name = path.file_name().unwrap().to_str().unwrap(); + let out_name_with_ext_apdu = format!("{}.dat", out_name[0..out_name.len() - 5].to_string()); + let out_name_with_ext_json = format!("{}.json", out_name[0..out_name.len() - 5].to_string()); + + let json_out_name = path + .parent() + .unwrap() + .parent() + .unwrap() + .join("apdu_samples") + .join(out_name_with_ext_json.clone()); + + let raw_out_name = path + .parent() + .unwrap() + .parent() + .unwrap() + .join("apdu_samples") + .join(out_name_with_ext_apdu.clone()); + + println!( + "Writing APDUs to {:?} and {:?}", + json_out_name, raw_out_name + ); + + let mut json_out = File::create(json_out_name).unwrap(); + let mut raw_out = File::create(raw_out_name).unwrap(); + for a in apdus.iter() { + println!("=> {}", a); + writeln!(raw_out, "=> {}", a).unwrap(); + } + writeln!( + json_out, + "{}", + serde_json::to_string_pretty(&apdus).unwrap() + ) + .unwrap(); +} diff --git a/tools/apdu-generator/src/types.rs b/tools/apdu-generator/src/types.rs new file mode 100644 index 0000000..2849c8c --- /dev/null +++ b/tools/apdu-generator/src/types.rs @@ -0,0 +1,131 @@ +use ethereum_types::U256; +use serde::Deserialize; +use starknet::core::utils::starknet_keccak; +use std::fmt; + +const DEFAULT_ENTRY_POINT_NAME: &str = "__default__"; +const DEFAULT_L1_ENTRY_POINT_NAME: &str = "__l1_default__"; + +#[derive(Copy, Clone, Debug)] +pub struct FieldElement(pub U256); + +impl fmt::Display for FieldElement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut s = [0u8; 32]; + self.0.to_big_endian(&mut s[..]); + for b in s { + write!(f, "{:02x}", b)?; + } + Ok(()) + } +} + +impl TryFrom for [u8; 32] { + type Error = (); + fn try_from(fe: FieldElement) -> Result { + let mut s = [0u8; 32]; + fe.0.to_big_endian(&mut s[..]); + Ok(s) + } +} + +impl TryFrom<&str> for FieldElement { + type Error = (); + fn try_from(s: &str) -> Result { + match s.starts_with("0x") { + true => Ok(FieldElement(U256::from_str_radix(s, 16).unwrap())), + false => Ok(FieldElement(U256::from_str_radix(s, 10).unwrap())), + } + } +} + +#[derive(Copy, Clone)] +pub enum Ins { + GetVersion, + GetPubkey, + SignHash, + SignTx, + Unknown, +} + +impl From for u8 { + fn from(value: Ins) -> Self { + match value { + Ins::GetVersion => 0u8, + Ins::GetPubkey => 1u8, + Ins::SignHash => 2u8, + Ins::SignTx => 3u8, + Ins::Unknown => 0xff, + } + } +} + +impl From for Ins { + fn from(v: u8) -> Self { + match v { + 0 => Ins::GetVersion, + 1 => Ins::GetPubkey, + 2 => Ins::SignHash, + 3 => Ins::SignTx, + 4.. => Ins::Unknown, + } + } +} + +#[derive(Deserialize, Debug)] +pub struct Call { + pub to: String, + pub entrypoint: String, + pub calldata: Vec, +} + +impl From<&Call> for Vec { + fn from(c: &Call) -> Self { + let mut v: Vec = Vec::new(); + + let to = FieldElement(U256::from_str_radix(&c.to, 16).unwrap()); + v.push(to); + + //let selector = FieldElement(U256::from_str_radix(&c.selector, 16).unwrap()); + let selector = get_selector_from_name(&c.entrypoint); + + v.push(selector); + + for c in c.calldata.iter() { + let data = FieldElement(U256::from_str_radix(c, 16).unwrap()); + v.push(data); + } + v + } +} + +#[derive(Deserialize, Debug)] +pub struct Tx { + pub sender_address: String, + pub tip: String, + pub l1_gas_bounds: String, + pub l2_gas_bounds: String, + pub paymaster_data: Vec, + pub chain_id: String, + pub nonce: String, + pub data_availability_mode: String, + pub account_deployment_data: Vec, + pub calls: Vec, +} + +#[derive(Deserialize, Debug)] +pub struct Data { + pub felts: Vec, +} + +pub fn get_selector_from_name(func_name: &str) -> FieldElement { + if func_name == DEFAULT_ENTRY_POINT_NAME || func_name == DEFAULT_L1_ENTRY_POINT_NAME { + FieldElement(U256::from(0u8)) + } else { + let name_bytes = func_name.as_bytes(); + + let selector = starknet_keccak(name_bytes); + + FieldElement(U256::from_str_radix(selector.to_fixed_hex_string().as_str(), 16).unwrap()) + } +} diff --git a/tools/apdu-generator/tx_samples/erc20_transfer.json b/tools/apdu-generator/tx_samples/erc20_transfer.json new file mode 100644 index 0000000..debefa9 --- /dev/null +++ b/tools/apdu-generator/tx_samples/erc20_transfer.json @@ -0,0 +1,22 @@ +{ + "sender_address": "0x07e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a", + "tip": "0", + "l1_gas_bounds": "0x00004C315F474153000000000000000000000000000000000000000000000000", + "l2_gas_bounds": "0x00004C325F474153000000000000000000000000000000000000000000000000", + "paymaster_data": [], + "chain_id": "0x534e5f4d41494e", + "nonce": "1", + "data_availability_mode": "0", + "account_deployment_data": [], + "calls": [ + { + "to": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "entrypoint": "transfer", + "selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", + "calldata": [ + "0x07e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a", + "0x00000000000000000000000000000000000000000000000000000000000003e8" + ] + } + ] +} \ No newline at end of file diff --git a/tools/apdu-generator/tx_samples/misc.json b/tools/apdu-generator/tx_samples/misc.json new file mode 100644 index 0000000..cd9cd2b --- /dev/null +++ b/tools/apdu-generator/tx_samples/misc.json @@ -0,0 +1,49 @@ +{ + "sender_address": "0x07e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a", + "max_fee": "1000000000000000", + "nonce": "1", + "version": "1", + "chain_id": "0x534e5f474f45524c49", + "calls": [ + { + "to": "0x0000000000000000000000000000000000000000000000000000000000000000", + "entrypoint": "", + "selector": "", + "calldata": [] + }, + { + "to": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "entrypoint": "transfer", + "selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", + "calldata": [ + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x07e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000000003e8" + ] + }, + { + "to": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "entrypoint": "transfer", + "selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", + "calldata": [ + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x07e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000000003e8", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000002", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000003", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000004", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000005", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000006", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000007" + ] + } + ] +} \ No newline at end of file diff --git a/tools/apdu-generator/tx_samples/random.json b/tools/apdu-generator/tx_samples/random.json new file mode 100644 index 0000000..3f5d4b1 --- /dev/null +++ b/tools/apdu-generator/tx_samples/random.json @@ -0,0 +1,21 @@ +{ + "sender_address": "0x07e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a", + "tip": "0", + "l1_gas_bounds": "0x00004C315F474153000000000000000000000000000000000000000000000000", + "l2_gas_bounds": "0x00004C325F474153000000000000000000000000000000000000000000000000", + "paymaster_data": [], + "chain_id": "0x534e5f4d41494e", + "nonce": "1", + "data_availability_mode": "0", + "account_deployment_data": [], + "calls": [ + { + "to": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "entrypoint": "mint", + "calldata": [ + "0x07e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a", + "0x00000000000000000000000000000000000000000000000000000000000003e8" + ] + } + ] +} \ No newline at end of file diff --git a/tools/apdu-generator/tx_samples/starknetid_bmc.json b/tools/apdu-generator/tx_samples/starknetid_bmc.json new file mode 100644 index 0000000..3012343 --- /dev/null +++ b/tools/apdu-generator/tx_samples/starknetid_bmc.json @@ -0,0 +1,38 @@ +{ + "sender_address": "0x07e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a", + "max_fee": "1000000000000000", + "nonce": "1", + "version": "1", + "chain_id": "0x534e5f474f45524c49", + "calls": [ + { + "to": "0x0000000000000000000000000000000000000000000000000000000000000000", + "entrypoint": "composable_multicall", + "selector": "0x02e269d930f6d7ab92b15ce8ff9f5e63709391617e3465fff79ba6baf278ce60", + "calldata": [] + }, + { + "to": "0x003bab268e932d2cecd1946f100ae67ce3dff9fd234119ea2f6da57d16d29fce", + "entrypoint": "domain_to_address", + "selector": "0x02e269d930f6d7ab92b15ce8ff9f5e63709391617e3465fff79ba6baf278ce60", + "calldata": [ + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000550CF2F5" + ] + }, + { + "to": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "entrypoint": "transfer", + "selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", + "calldata": [ + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000001" + ] + } + ] +} diff --git a/tools/check-signature/Cargo.toml b/tools/check-signature/Cargo.toml new file mode 100644 index 0000000..11fef3e --- /dev/null +++ b/tools/check-signature/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "check-signature" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +starknet = { git = "https://github.com/xJonathanLEI/starknet-rs" } +tokio = { version = "1.15.0", features = ["full"] } +url = "2.3.1" +starknet-types-core = "0.1.5" +clap = { version = "4.5.10", features = ["derive"] } +ledger-lib = { git = "https://github.com/LedgerHQ/ledger-rust.git", branch = "y333/fix_timeout" } \ No newline at end of file diff --git a/tools/check-signature/src/main.rs b/tools/check-signature/src/main.rs new file mode 100644 index 0000000..c011e0c --- /dev/null +++ b/tools/check-signature/src/main.rs @@ -0,0 +1,123 @@ +use clap::Parser; +use starknet::{ + accounts::{Account, Call, ExecutionEncoding, SingleOwnerAccount}, + core::{chain_id, crypto::Signature, utils::get_selector_from_name}, + providers::SequencerGatewayProvider, + signers::{LocalWallet, Signer, SigningKey, VerifyingKey}, +}; +use starknet_types_core::felt::Felt; +use url::Url; + +use ledger_lib::Transport; + +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +struct Args { + /// public key in hexadecimal format (32 bytes) + #[arg(short, long)] + pkey: String, + + /// Tx hash in hexadecimal format (32 bytes) + #[arg(short, long)] + txhash: String, + + /// Signature r value in hexadecimal format (32 bytes) + #[arg(short, long)] + r: String, + + /// Signature s value in hexadecimal format (32 bytes) + #[arg(short, long)] + s: String, +} + +#[tokio::main] +async fn main() { + let args: Args = Args::parse(); + + /* + let provider = SequencerGatewayProvider::new( + Url::parse("http://127.0.0.1:5050/gateway").unwrap(), + Url::parse("http://127.0.0.1:5050/feeder_gateway").unwrap(), + chain_id::MAINNET, + ); + + let private_key = + Felt::from_hex("0139fe4d6f02e666e86a6f58e65060f115cd3c185bd9e98bd829636931458f79").unwrap(); + + let pkey = SigningKey::from_secret_scalar(private_key); + let signer = LocalWallet::from_signing_key(pkey); + + let account = SingleOwnerAccount::new( + provider, + signer.clone(), + Felt::from_hex("07e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a").unwrap(), + chain_id::MAINNET, + ExecutionEncoding::New, + ); + + let tst_token_address = + Felt::from_hex("049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7").unwrap(); + + let execution = account + .execute_v3(vec![Call { + to: tst_token_address, + selector: get_selector_from_name("transfer").unwrap(), + calldata: vec![account.address(), Felt::from_dec_str("1000").unwrap()], + }]) + .gas(0) + .gas_price(0) + .nonce(Felt::ONE); + + let prepared = execution.prepared().unwrap(); + + let hash = prepared.transaction_hash(false); + + println!("Transaction hash: {}", hash.to_biguint()); + println!("Transaction hash: {}", hash.to_hex_string()); + println!("Transaction hash: {}", hash.to_fixed_hex_string()); + */ + + /* Check signature (ref) */ + //let signature = signer.sign_hash(&hash).await.unwrap(); + + //let public_key = signer.get_public_key().await.unwrap(); + + //let verify = public_key.verify(&hash, &signature).unwrap(); + + //println!("Verify: {}", verify); + + /* Check signature (device) */ + + // Initialise provider + let mut p = ledger_lib::LedgerProvider::init().await; + + // Fetch list of available devices + let devices = p.list(ledger_lib::Filters::Hid).await.unwrap(); + + // Connect to device + let d = &devices[0]; + + // Connect to the device using the index offset + let device_handle = match p.connect(d.clone()).await { + Ok(v) => v, + Err(e) => { + println!("Failed to connect to device {:?}: {:?}", d, e); + return; + } + }; + let mut buff = [0u8; 256]; + + let device_public_key = VerifyingKey::from_scalar(Felt::from_hex_unchecked(args.pkey.as_str())); + + let tx_hash = Felt::from_hex_unchecked(args.txhash.as_str()); + + let device_signature = Signature { + r: Felt::from_hex_unchecked(args.r.as_str()), + s: Felt::from_hex_unchecked(args.s.as_str()), + }; + + let device_verify = device_public_key + .verify(&tx_hash, &device_signature) + .unwrap(); + println!("Verify: {}", device_verify); +}