From 54cf181e44f0610585c9cc00838267f40e985a5d Mon Sep 17 00:00:00 2001 From: brianp Date: Mon, 8 Apr 2024 10:47:01 +0200 Subject: [PATCH 01/49] Update ledger wallet app scaffold --- .../minotari_ledger_wallet/.cargo/config.toml | 15 + .../minotari_ledger_wallet/.gitignore | 22 + .../minotari_ledger_wallet/Cargo.lock | 612 ++++++++++++++++-- .../minotari_ledger_wallet/Cargo.toml | 56 +- applications/minotari_ledger_wallet/README.md | 90 ++- .../minotari_ledger_wallet/app_nanosplus.json | 10 +- applications/minotari_ledger_wallet/build.rs | 3 + applications/minotari_ledger_wallet/key.gif | Bin 0 -> 892 bytes .../minotari_ledger_wallet/key_14x14.gif | Bin 145 -> 880 bytes .../minotari_ledger_wallet/key_16x16.gif | Bin 155 -> 0 bytes .../minotari_ledger_wallet/ledger_app.toml | 4 + .../rust-toolchain.toml | 2 +- .../minotari_ledger_wallet/rustfmt.toml | 27 - .../src/app_ui/address.rs | 39 ++ .../minotari_ledger_wallet/src/app_ui/menu.rs | 47 ++ .../minotari_ledger_wallet/src/app_ui/sign.rs | 66 ++ .../src/handlers/get_private_key.rs | 49 ++ .../src/handlers/get_public_key.rs | 50 ++ .../src/handlers/get_version.rs | 28 + .../src/handlers/sign_tx.rs | 104 +++ .../minotari_ledger_wallet/src/hashing.rs | 2 +- .../minotari_ledger_wallet/src/main.rs | 249 +++---- .../minotari_ledger_wallet/src/utils.rs | 95 ++- 23 files changed, 1261 insertions(+), 309 deletions(-) create mode 100644 applications/minotari_ledger_wallet/.cargo/config.toml create mode 100644 applications/minotari_ledger_wallet/.gitignore create mode 100644 applications/minotari_ledger_wallet/build.rs create mode 100644 applications/minotari_ledger_wallet/key.gif delete mode 100644 applications/minotari_ledger_wallet/key_16x16.gif create mode 100644 applications/minotari_ledger_wallet/ledger_app.toml delete mode 100644 applications/minotari_ledger_wallet/rustfmt.toml create mode 100644 applications/minotari_ledger_wallet/src/app_ui/address.rs create mode 100644 applications/minotari_ledger_wallet/src/app_ui/menu.rs create mode 100644 applications/minotari_ledger_wallet/src/app_ui/sign.rs create mode 100644 applications/minotari_ledger_wallet/src/handlers/get_private_key.rs create mode 100644 applications/minotari_ledger_wallet/src/handlers/get_public_key.rs create mode 100644 applications/minotari_ledger_wallet/src/handlers/get_version.rs create mode 100644 applications/minotari_ledger_wallet/src/handlers/sign_tx.rs diff --git a/applications/minotari_ledger_wallet/.cargo/config.toml b/applications/minotari_ledger_wallet/.cargo/config.toml new file mode 100644 index 0000000000..9884d86c67 --- /dev/null +++ b/applications/minotari_ledger_wallet/.cargo/config.toml @@ -0,0 +1,15 @@ +[target.nanosplus] +runner = "speculos -m nanosp" + +[build] +target = "nanosplus" + +[unstable] +avoid-dev-deps = true +build-std = ["std", "alloc"] +build-std-features = ["compiler-builtins-mem"] +host-config = true +target-applies-to-host = true + +[host] +rustflags = ["-Ctarget-feature=-crt-static"] \ No newline at end of file diff --git a/applications/minotari_ledger_wallet/.gitignore b/applications/minotari_ledger_wallet/.gitignore new file mode 100644 index 0000000000..3735321888 --- /dev/null +++ b/applications/minotari_ledger_wallet/.gitignore @@ -0,0 +1,22 @@ +target +app.json +app_nanos.json +app_nanosplus.json +app_nanox.json + +# Temporary directory with snapshots taken during test runs +tests/snapshots-tmp/ + +# Python +*.pyc[cod] +*.egg +__pycache__/ +*.egg-info/ +.eggs/ +.python-version + +# Related to the Ledger VSCode extension +# Virtual env for sideload (macOS and Windows) +ledger/ +# Build directory +build/ \ No newline at end of file diff --git a/applications/minotari_ledger_wallet/Cargo.lock b/applications/minotari_ledger_wallet/Cargo.lock index 17fa7e0271..90f57ae850 100644 --- a/applications/minotari_ledger_wallet/Cargo.lock +++ b/applications/minotari_ledger_wallet/Cargo.lock @@ -2,6 +2,27 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "atomic-polyfill" version = "1.0.3" @@ -13,9 +34,44 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" + +[[package]] +name = "bindgen" +version = "0.65.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" +dependencies = [ + "bitflags 1.3.2", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.55", + "which", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "blake2" @@ -37,20 +93,68 @@ dependencies = [ [[package]] name = "borsh" -version = "1.0.0" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" +dependencies = [ + "borsh-derive", + "hashbrown", +] + +[[package]] +name = "borsh-derive" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e6cb63579996213e822f6d828b0a47e1d23b1e8708f52d18a6b1af5670dd207" +checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7" dependencies = [ - "cfg_aliases", + "borsh-derive-internal", + "borsh-schema-derive-internal", + "proc-macro-crate", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive-internal" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", ] +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "cc" -version = "1.0.82" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01" +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ - "libc", + "nom", ] [[package]] @@ -60,10 +164,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "cfg_aliases" -version = "0.1.1" +name = "clang-sys" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" +dependencies = [ + "glob", + "libc", + "libloading", +] [[package]] name = "color_quant" @@ -73,9 +182,9 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "cpufeatures" -version = "0.2.9" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] @@ -98,13 +207,13 @@ dependencies = [ [[package]] name = "curve25519-dalek-derive" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.55", ] [[package]] @@ -124,16 +233,32 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +[[package]] +name = "either" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" + [[package]] name = "embedded-alloc" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8931e47e33c5d3194fbcf9cc82df0919193bd2fa40008f388eb1d28fd9c9ea6b" +checksum = "ddae17915accbac2cfbc64ea0ae6e3b330e6ea124ba108dada63646fd3c6f815" dependencies = [ "critical-section", "linked_list_allocator", ] +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys", +] + [[package]] name = "fiat-crypto" version = "0.1.20" @@ -160,16 +285,69 @@ dependencies = [ "weezl", ] +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "stable_deref_trait", +] + [[package]] name = "heck" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys", +] + [[package]] name = "include_gif" -version = "0.1.0" -source = "git+https://github.com/LedgerHQ/sdk_include_gif#699d28c6157518c4493899e2eeaa8af08346e5e7" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "132290d08a42868f8f90e96a9206e955b0aae1e5a5df54c0029e8c2ab8652625" dependencies = [ "gif", "syn 1.0.109", @@ -177,18 +355,64 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" dependencies = [ "cpufeatures", ] +[[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 = "ledger_device_sdk" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f99d39260bbde6dfef6a2420440b79f7a486ab2fbf43d251600a759697a79361" +dependencies = [ + "include_gif", + "ledger_secure_sdk_sys", + "num-traits", + "numtoa", + "rand_core", + "zeroize", +] + +[[package]] +name = "ledger_secure_sdk_sys" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60e201ddad57baebaf48c694341d1e0aa910d3516cafee32fc385fa73c01381c" +dependencies = [ + "bindgen", + "cc", +] + [[package]] name = "libc" -version = "0.2.147" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "libloading" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +dependencies = [ + "cfg-if", + "windows-targets", +] [[package]] name = "linked_list_allocator" @@ -196,54 +420,74 @@ version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286" +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + [[package]] name = "log" -version = "0.4.19" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "memchr" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] -name = "minotari_ledger_wallet" -version = "0.52.0-pre.0" +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "minotari_ledger_wallet2" +version = "1.0.0-pre.11a" dependencies = [ "blake2", "borsh", "critical-section", "digest", "embedded-alloc", - "nanos_sdk", - "nanos_ui", + "hex", + "include_gif", + "ledger_device_sdk", + "numtoa", + "once_cell", + "serde", + "serde-json-core", "tari_crypto", ] [[package]] -name = "nanos_sdk" -version = "0.2.1" -source = "git+https://github.com/LedgerHQ/ledger-nanos-sdk.git#4d9bfc6183d94cee6edb239c39286be3825cc179" -dependencies = [ - "cc", - "num-traits", - "rand_core", -] - -[[package]] -name = "nanos_ui" -version = "0.2.0" -source = "git+https://github.com/LedgerHQ/ledger-nanos-ui.git?rev=6a7c4a3eb41ee0b09c8fd4dcc5be4f3a1f5d7b45#6a7c4a3eb41ee0b09c8fd4dcc5be4f3a1f5d7b45" +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ - "include_gif", - "nanos_sdk", + "memchr", + "minimal-lexical", ] [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", ] +[[package]] +name = "numtoa" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aa2c4e539b869820a2b82e1aef6ff40aa85e65decdd5185e83fb4b1249cd00f" + [[package]] name = "once_cell" version = "1.18.0" @@ -254,11 +498,17 @@ dependencies = [ "critical-section", ] +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + [[package]] name = "platforms" -version = "3.0.2" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" +checksum = "db23d408679286588f4d4644f965003d056e3dd5abcaaa938116871d7ce2fee7" [[package]] name = "ppv-lite86" @@ -266,20 +516,39 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "prettyplease" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d3928fb5db768cb86f891ff014f0144589297e3c6a1aba6ed7cecfdace270c7" +dependencies = [ + "proc-macro2", + "syn 2.0.55", +] + +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml", +] + [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.32" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -300,6 +569,41 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +[[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", + "regex-syntax", +] + +[[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", +] + +[[package]] +name = "regex-syntax" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc_version" version = "0.4.0" @@ -309,11 +613,60 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "0.38.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" +dependencies = [ + "bitflags 2.5.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "ryu" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + [[package]] name = "semver" -version = "1.0.18" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" + +[[package]] +name = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-json-core" +version = "0.5.1" +source = "git+https://github.com/rust-embedded-community/serde-json-core#9327a14e74ad3b4fd37a9ac34e72b61aa5fcc9bf" +dependencies = [ + "heapless", + "ryu", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", +] [[package]] name = "sha3" @@ -325,6 +678,12 @@ dependencies = [ "keccak", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "snafu" version = "0.7.5" @@ -347,6 +706,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "subtle" version = "2.5.0" @@ -366,9 +731,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.28" +version = "2.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" +checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" dependencies = [ "proc-macro2", "quote", @@ -394,9 +759,9 @@ dependencies = [ [[package]] name = "tari_crypto" -version = "0.18.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc09581fc1a9709e54be25e0a50437dc405370b3f5795ee65dc913f4f7e726e5" +checksum = "63a3ed2c551101eb42b7f9386c207e28d53e6816f7b4c9a0883548922f317b3e" dependencies = [ "blake2", "digest", @@ -413,26 +778,35 @@ dependencies = [ [[package]] name = "tari_utilities" -version = "0.5.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "367d17d09cf48e4cf45222fd48536e206f8ef3aaa5eed449c7df38d2ab4586c6" +checksum = "8c1bb0e5d1d812f2be2d6ad861caad68f75adb5b2e8376264850300deb16ddc7" dependencies = [ "generic-array", "snafu", "zeroize", ] +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "version_check" @@ -442,15 +816,113 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "weezl" -version = "0.1.7" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" + +[[package]] +name = "which" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", +] [[package]] name = "zeroize" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" dependencies = [ "zeroize_derive", ] @@ -463,5 +935,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.55", ] diff --git a/applications/minotari_ledger_wallet/Cargo.toml b/applications/minotari_ledger_wallet/Cargo.toml index ff78777fae..7ab7a15f20 100644 --- a/applications/minotari_ledger_wallet/Cargo.toml +++ b/applications/minotari_ledger_wallet/Cargo.toml @@ -1,36 +1,50 @@ [package] name = "minotari_ledger_wallet" -version = "0.52.0-pre.0" +version = "1.0.0-pre.11a" authors = ["The Tari Development Community"] license = "BSD-3-Clause" edition = "2021" - [dependencies] -# lock to rev as soon as this is fixed: https://github.com/rust-lang/rust/issues/98666 -nanos_sdk = { git = "https://github.com/LedgerHQ/ledger-nanos-sdk.git" } -nanos_ui = { git = "https://github.com/LedgerHQ/ledger-nanos-ui.git", rev = "6a7c4a3eb41ee0b09c8fd4dcc5be4f3a1f5d7b45" } - -tari_crypto = { version = "0.18", default-features = false } - -embedded-alloc = "0.5.0" +blake2 = { version = "0.10", default-features = false } +borsh = { version = "0.10", default-features = false } critical-section = { version = "1.1.1" } digest = { version = "0.10", default-features = false } -borsh = { version = "1.0", default-features = false } -blake2 = { version = "0.10", default-features = false } +embedded-alloc = "0.5.0" +hex = { version = "0.4.3", default-features = false, features = ["serde"] } +include_gif = "1.0.1" +ledger_device_sdk = "1.7.1" +numtoa = "0.2.4" +serde = { version="1.0.192", default_features = false, features = ["derive"] } +serde-json-core = { git = "https://github.com/rust-embedded-community/serde-json-core"} +tari_crypto = { version = "0.20.0", default-features = false } + +# once_cell defined here just to lock the version. Other dependencies may try to go to 1.19 which is incompatabile with +# ledger at this time. 1.19 removes "atomic-polyfill" and replaces it with "portable-atomic" which can not build due to +# target mismatches. +once_cell = { version = "=1.18.0", default-features = false } [profile.release] -opt-level = 's' -lto = "fat" # same as `true` -panic = "abort" +opt-level = 'z' +lto = true -[package.metadata.nanos] -name = "MinoTari Wallet" +[features] +default = ["pending_review_screen"] +pending_review_screen = [] + +[package.metadata.ledger] curve = ["secp256k1", "ed25519"] flags = "0" -icon = "key_16x16.gif" -icon_small = "key_14x14.gif" -path = ["44'/1022'","m/5261654'","m/44'"] -api_level = "1" +path = ["44'/1022'", "m/5261654", "m/44"] +name = "MinoTari Wallet" + +[package.metadata.ledger.nanos] +icon = "key.gif" + +[package.metadata.ledger.nanox] +icon = "key_14x14.gif" + +[package.metadata.ledger.nanosplus] +icon = "key_14x14.gif" -[workspace] +[workspace] \ No newline at end of file diff --git a/applications/minotari_ledger_wallet/README.md b/applications/minotari_ledger_wallet/README.md index 3d03356929..cec55ac991 100644 --- a/applications/minotari_ledger_wallet/README.md +++ b/applications/minotari_ledger_wallet/README.md @@ -1,38 +1,13 @@ # Instructions -## Setup - -Ledger does not build with the standard library, so we need to install `rust-src`. This can be done with: -``` -rustup component add rust-src --toolchain nightly -``` - -For loading a BOLOS application to a Ledger device, Ledger has actually written a command, called -[Cargo Ledger](https://github.com/LedgerHQ/cargo-ledger). This we need to install with: -``` -cargo install --git https://github.com/LedgerHQ/cargo-ledger -``` - -As per the [Cargo Ledger setup instructions](https://github.com/LedgerHQ/cargo-ledger#setup) run the following to add -new build targets for the current rust toolchain: - -``` -cargo ledger setup -``` - -Next up we need install the supporting Python libraries from Ledger to control Ledger devices, +To control ledger devices we use the ledgerctl library. +We install the supporting Python libraries from Ledger to control Ledger devices, [LedgerCTL](https://github.com/LedgerHQ/ledgerctl). This we do with: ``` pip3 install --upgrade protobuf setuptools ecdsa pip3 install git+https://github.com/LedgerHQ/ledgerctl ``` -Lastly install the ARM GCC toolchain: `arm-none-eabi-gcc` for your OS (https://developer.arm.com/downloads/-/gnu-rm). -For MacOS, we can use brew with: -``` -brew install armmbed/formulae/arm-none-eabi-gcc -``` - ## Device configuration See https://github.com/LedgerHQ/ledgerctl#device-configuration @@ -47,38 +22,26 @@ Once in recovery mode run the following where is simply the name of the C ledgerctl install-ca ``` -## Runtime +## Building -Open a terminal in the subfolder `./applications/ledger` - -_**Note:** Windows users should start a "x64 Native Tools Command Prompt for VS 2019" to have the build tools available -and then start a python shell within that terminal to have the Python libraries available._ - -### Build `ledger` - -To build, run +Ledger does not easily compile locally and it is easiest to compile via docker using their provided [ledger-app-builder](https://github.com/LedgerHQ/ledger-app-builder/). +See their readme for setup. +Once installed you can build the Tari Wallet for ledger by navigating to `./applications/minotari_ledger_wallet` and running the docker command: ``` -cargo ledger build {TARGET} -- "-Zbuild-std=std,alloc" +docker run --rm -it -v ".:/app" ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder ``` +This will load you into the docker vm where you can now build the ledger app. where TARGET = nanosplus, nanos, etc. -### Build and install `ledger` - -This must be run from a Python shell (`pip3 --version` should work). To build and load, run - ``` -cargo ledger build {TARGET} --load -- "-Zbuild-std=std,alloc" +cargo ledger build {TARGET} ``` -where TARGET = nanosplus, nanos, etc. -**Errors** +Please note docker has no access to usb devices on MacOS. So the use of `cargo ledger build {TARGET} --load` will fail. -If the auto-load does not work ("ledgerwallet.client.CommException: Exception : Invalid status 6512 (Unknown reason)"), -try to do a manual installation. - -### Manual installation +### Install `ledger` - First delete the application if it was already installed @@ -91,19 +54,19 @@ try to do a manual installation. ``` `ledgerctl install app_nanosplus.json` ``` -**Note:** In some cases the `cargo ledger build` action will invalidate `app_nanosplus.json` by setting the first line +**Note:** In some cases the `cargo ledger build` action will invalidate `app_nanosplus.json` by setting the first line to `"apiLevel": "0",` - ensure it is set to `"apiLevel": "1",` ### Running the ledger application -Start the `MinoTari Wallet` application on the Ledger by navigating to the app and pressing both buttons. You should +Start the `MinoTari Wallet` application on the Ledger by navigating to the app and pressing both buttons. You should see `MinoTari Wallet` displayed on the screen. Now your device is ready to be used with the console wallet. _**Note:** To manually exit the application, press both buttons on the Ledger._ **Errors** -- If the `MinoTari Wallet` application on the Ledger is not started when trying to access it with a desktop +- If the `MinoTari Wallet` application on the Ledger is not started when trying to access it with a desktop application, you should see the following error on the desktop: `Error: Ledger application not started` @@ -115,3 +78,28 @@ _**Note:** To manually exit the application, press both buttons on the Ledger._ - If the `MinoTari Wallet` application has an incorrect version, you should see the following error on the desktop: `Error: Processing error 'MinoTari Wallet application version mismatch: expected ...'` + +## Emulator + +Ledger has provided an in browser ledger emulator [Speculos](https://github.com/LedgerHQ/speculos) + +To build on M1 devices clone the repository + +``` +$ git checkout df84117d2ac300cd277d58913a9f56e061b5fb2f + +// Now build the docker image +$ docker build -t speculos-builder:latest -f build.Dockerfile . + +// Now build the main docker image, which will be based of the builder image. + +$ docker build -t speculos:latest . +``` + +Once built, run the emulator with: + +``` +docker run --rm -it -v $(pwd):/speculos/apps -p 1234:1234 -p 3000:3000 -p 40000:40000 -p 41000:41000 speculos --display headless --api-port 3000 --vnc-port 41000 apps/target/nanosplus/release/minotari_ledger_wallet --model nanosp +``` + +Browse to the address `http://localhost:3000` \ No newline at end of file diff --git a/applications/minotari_ledger_wallet/app_nanosplus.json b/applications/minotari_ledger_wallet/app_nanosplus.json index e1545ac66b..70502c35f5 100644 --- a/applications/minotari_ledger_wallet/app_nanosplus.json +++ b/applications/minotari_ledger_wallet/app_nanosplus.json @@ -1,7 +1,7 @@ { - "apiLevel": "1", + "apiLevel": "5", "binary": "target/nanosplus/release/app.hex", - "dataSize": 0, + "dataSize": 7680, "derivationPath": { "curves": [ "secp256k1", @@ -9,13 +9,13 @@ ], "paths": [ "44'/1022'", - "m/5261654'", - "m/44'" + "m/5261654", + "m/44" ] }, "flags": "0", "icon": "key_14x14.gif", "name": "MinoTari Wallet", "targetId": "0x33100004", - "version": "0.52.0-pre.0" + "version": "1.0.0-pre.11a" } \ No newline at end of file diff --git a/applications/minotari_ledger_wallet/build.rs b/applications/minotari_ledger_wallet/build.rs new file mode 100644 index 0000000000..6d36ea8066 --- /dev/null +++ b/applications/minotari_ledger_wallet/build.rs @@ -0,0 +1,3 @@ +fn main() { + println!("cargo:rerun-if-changed=script.ld"); +} diff --git a/applications/minotari_ledger_wallet/key.gif b/applications/minotari_ledger_wallet/key.gif new file mode 100644 index 0000000000000000000000000000000000000000..287a8df0d61170883490f87d222ed878509aa4d7 GIT binary patch literal 892 zcmZ?wbhEHb6krfwXlDR{|NsAk=}}@d1V&s4DE{a6a}5c0b_{Se(lcOY1O|ZOPZm}t zAgu!m3{W;<;BaGLD>()DVbWF3OqWEDr~2@9Addo p72ViltHI;4{yR5crR&3u(_)MoPo-YAjO`L)eeNsp!j*x+8URtMFlqn* diff --git a/applications/minotari_ledger_wallet/key_16x16.gif b/applications/minotari_ledger_wallet/key_16x16.gif deleted file mode 100644 index 55e198b16c9411d3bbf49cdda5273592c1a154a7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 155 zcmZ?wbh9u|6krfw*vtR|%F4=`nwk+25lu}^vuDpJ$v=))!Vmkzj^cK z%a Result { + let mut addr_hex = [0u8; DISPLAY_ADDR_BYTES_LEN * 2 + 2]; + addr_hex[..2].copy_from_slice("0x".as_bytes()); + hex::encode_to_slice(&addr[addr.len() - DISPLAY_ADDR_BYTES_LEN..], &mut addr_hex[2..]).unwrap(); + let addr_hex = from_utf8_mut(&mut addr_hex).unwrap(); + addr_hex[2..].make_ascii_uppercase(); + + let my_field = [Field { + name: "Address", + value: addr_hex, + }]; + + let my_review = MultiFieldReview::new( + &my_field, + &["Confirm Address"], + Some(&EYE), + "Approve", + Some(&VALIDATE_14), + "Reject", + Some(&CROSSMARK), + ); + + Ok(my_review.show()) +} diff --git a/applications/minotari_ledger_wallet/src/app_ui/menu.rs b/applications/minotari_ledger_wallet/src/app_ui/menu.rs new file mode 100644 index 0000000000..be1d7d2963 --- /dev/null +++ b/applications/minotari_ledger_wallet/src/app_ui/menu.rs @@ -0,0 +1,47 @@ +// Copyright 2024 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use include_gif::include_gif; +use ledger_device_sdk::{ + io::{Comm, Event}, + ui::{ + bitmaps::{Glyph, BACK, CERTIFICATE, DASHBOARD_X}, + gadgets::{EventOrPageIndex, MultiPageMenu, Page}, + }, +}; + +use crate::Instruction; + +fn ui_about_menu(comm: &mut Comm) -> Event { + let pages = [ + &Page::from((["MinoTari Wallet", "(c) 2024 The Tari Project"], true)), + &Page::from(("Back", &BACK)), + ]; + loop { + match MultiPageMenu::new(comm, &pages).show() { + EventOrPageIndex::Event(e) => return e, + EventOrPageIndex::Index(1) => return ui_menu_main(comm), + EventOrPageIndex::Index(_) => (), + } + } +} + +pub fn ui_menu_main(comm: &mut Comm) -> Event { + const APP_ICON: Glyph = Glyph::from_include(include_gif!("key.gif")); + let pages = [ + // The from trait allows to create different styles of pages + // without having to use the new() function. + &Page::from((["MinoTari", "Wallet"], &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 ui_about_menu(comm), + EventOrPageIndex::Index(3) => ledger_device_sdk::exit_app(0), + EventOrPageIndex::Index(_) => (), + } + } +} diff --git a/applications/minotari_ledger_wallet/src/app_ui/sign.rs b/applications/minotari_ledger_wallet/src/app_ui/sign.rs new file mode 100644 index 0000000000..b11897b46a --- /dev/null +++ b/applications/minotari_ledger_wallet/src/app_ui/sign.rs @@ -0,0 +1,66 @@ +// Copyright 2024 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use ledger_device_sdk::ui::{ + bitmaps::{CROSSMARK, EYE, VALIDATE_14}, + gadgets::{Field, MultiFieldReview}, +}; +use numtoa::NumToA; + +use crate::{handlers::sign_tx::Tx, utils::concatenate, AppSW}; + +const MAX_COIN_LENGTH: usize = 10; + +/// Displays a transaction and returns true if user approved it. +/// +/// This method can return [`AppSW::TxDisplayFail`] error if the coin name length is too long. +/// +/// # Arguments +/// +/// * `tx` - Transaction to be displayed for validation +pub fn ui_display_tx(tx: &Tx) -> Result { + // Generate string for amount + let mut numtoa_buf = [0u8; 20]; + let mut value_buf = [0u8; 20 + MAX_COIN_LENGTH + 1]; + + let value_str = concatenate( + &[tx.coin, " ", tx.value.numtoa_str(10, &mut numtoa_buf)], + &mut value_buf, + ) + .map_err(|_| AppSW::TxDisplayFail)?; // Fails if value_buf is too small + + // Generate destination address string in hexadecimal format. + let mut to_str = [0u8; 42]; + to_str[..2].copy_from_slice("0x".as_bytes()); + hex::encode_to_slice(tx.to, &mut to_str[2..]).unwrap(); + to_str[2..].make_ascii_uppercase(); + + // Define transaction review fields + let my_fields = [ + Field { + name: "Amount", + value: value_str, + }, + Field { + name: "Destination", + value: core::str::from_utf8(&to_str).unwrap(), + }, + Field { + name: "Memo", + value: tx.memo, + }, + ]; + + // Create transaction review + let my_review = MultiFieldReview::new( + &my_fields, + &["Review ", "Transaction"], + Some(&EYE), + "Approve", + Some(&VALIDATE_14), + "Reject", + Some(&CROSSMARK), + ); + + Ok(my_review.show()) +} diff --git a/applications/minotari_ledger_wallet/src/handlers/get_private_key.rs b/applications/minotari_ledger_wallet/src/handlers/get_private_key.rs new file mode 100644 index 0000000000..b4a3bae253 --- /dev/null +++ b/applications/minotari_ledger_wallet/src/handlers/get_private_key.rs @@ -0,0 +1,49 @@ +// Copyright 2024 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use alloc::string::ToString; + +use ledger_device_sdk::{ecc::make_bip32_path, io::Comm, ui::gadgets::SingleMessage}; +use tari_crypto::{ristretto::RistrettoSecretKey, tari_utilities::ByteArray}; + +use crate::{ + utils::{get_raw_key, u64_to_string}, + AppSW, +}; + +static MINOTARI_BIP32_COIN_TYPE: u32 = 535348; + +pub fn handler_get_public_key(comm: &mut Comm, _display: bool) -> Result<(), AppSW> { + // first 5 bytes are instruction details + let offset = 5; + let mut address_index_bytes = [0u8; 8]; + address_index_bytes.clone_from_slice(comm.get(offset, offset + 8)); + let address_index = u64_to_string(u64::from_le_bytes(address_index_bytes)); + + let mut msg = "GetPrivateKey... ".to_string(); + msg.push_str(&address_index); + SingleMessage::new(&msg).show(); + + let mut bip32_path = "m/44'/".to_string(); + bip32_path.push_str(&MINOTARI_BIP32_COIN_TYPE.to_string()); + bip32_path.push_str(&"'/"); + bip32_path.push_str(&account); + bip32_path.push_str(&"'/0/"); + bip32_path.push_str(&address_index); + let path: [u32; 5] = make_bip32_path(bip32_path.as_bytes()); + + let raw_key = get_raw_key(&path).map_err(|_| AppSW::KeyDeriveFail)?; + + let k = match RistrettoSecretKey::from_canonical_bytes(&raw_key) { + Ok(val) => val, + Err(_) => { + SingleMessage::new("Err: key conversion").show(); + return Err(AppSW::KeyDeriveFail); + }, + }; + comm.append(&[1]); // version + comm.append(k.as_bytes()); + comm.reply_ok(); + + Ok(()) +} diff --git a/applications/minotari_ledger_wallet/src/handlers/get_public_key.rs b/applications/minotari_ledger_wallet/src/handlers/get_public_key.rs new file mode 100644 index 0000000000..a9533c1d66 --- /dev/null +++ b/applications/minotari_ledger_wallet/src/handlers/get_public_key.rs @@ -0,0 +1,50 @@ +// Copyright 2024 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use alloc::string::ToString; + +use ledger_device_sdk::{ecc::make_bip32_path, io::Comm, ui::gadgets::SingleMessage}; +use tari_crypto::{ristretto::RistrettoSecretKey, tari_utilities::ByteArray}; + +use crate::{ + utils::{get_raw_key, u64_to_string}, + AppSW, +}; + +static MINOTARI_LEDGER_ID: u32 = 535348; +static MINOTARI_ACCOUNT_ID: u32 = 7041; + +pub fn handler_get_public_key(comm: &mut Comm, _display: bool) -> Result<(), AppSW> { + // first 5 bytes are instruction details + let offset = 5; + let mut address_index_bytes = [0u8; 8]; + address_index_bytes.clone_from_slice(comm.get(offset, offset + 8)); + let address_index = u64_to_string(u64::from_le_bytes(address_index_bytes)); + + let mut msg = "GetPrivateKey... ".to_string(); + msg.push_str(&address_index); + SingleMessage::new(&msg).show(); + + let mut bip32_path = "m/44'/".to_string(); + bip32_path.push_str(&MINOTARI_LEDGER_ID.to_string()); + bip32_path.push_str(&"'/"); + bip32_path.push_str(&MINOTARI_ACCOUNT_ID.to_string()); + bip32_path.push_str(&"'/0/"); + bip32_path.push_str(&address_index); + let path: [u32; 5] = make_bip32_path(bip32_path.as_bytes()); + + let raw_key = get_raw_key(&path).map_err(|_| AppSW::KeyDeriveFail)?; + + let k = match RistrettoSecretKey::from_canonical_bytes(&raw_key) { + Ok(val) => val, + Err(_) => { + SingleMessage::new("Err: key conversion").show(); + return Err(AppSW::KeyDeriveFail); + }, + }; + comm.append(&[1]); // version + comm.append(k.as_bytes()); + comm.reply_ok(); + + Ok(()) +} diff --git a/applications/minotari_ledger_wallet/src/handlers/get_version.rs b/applications/minotari_ledger_wallet/src/handlers/get_version.rs new file mode 100644 index 0000000000..08581a833d --- /dev/null +++ b/applications/minotari_ledger_wallet/src/handlers/get_version.rs @@ -0,0 +1,28 @@ +// Copyright 2024 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use core::str::FromStr; + +use ledger_device_sdk::io; + +use crate::AppSW; + +pub fn handler_get_version(comm: &mut io::Comm) -> Result<(), AppSW> { + if let Some((major, minor, patch)) = parse_version_string(env!("CARGO_PKG_VERSION")) { + comm.append(&[major, minor, patch]); + Ok(()) + } else { + Err(AppSW::VersionParsingFail) + } +} + +fn parse_version_string(input: &str) -> Option<(u8, u8, u8)> { + // Split the input string by '.'. + // Input should be of the form "major.minor.patch", + // where "major", "minor", and "patch" are integers. + let mut parts = input.split('.'); + let major = u8::from_str(parts.next()?).ok()?; + let minor = u8::from_str(parts.next()?).ok()?; + let patch = u8::from_str(parts.next()?).ok()?; + Some((major, minor, patch)) +} diff --git a/applications/minotari_ledger_wallet/src/handlers/sign_tx.rs b/applications/minotari_ledger_wallet/src/handlers/sign_tx.rs new file mode 100644 index 0000000000..e87c5f70c3 --- /dev/null +++ b/applications/minotari_ledger_wallet/src/handlers/sign_tx.rs @@ -0,0 +1,104 @@ +// Copyright 2024 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use ledger_device_sdk::{ + ecc::{Secp256k1, SeedDerive}, + hash::{sha3::Keccak256, HashInit}, + io::Comm, +}; +use serde::Deserialize; +use serde_json_core::from_slice; + +use crate::{app_ui::sign::ui_display_tx, utils::Bip32Path, AppSW}; + +const MAX_TRANSACTION_LEN: usize = 510; + +#[derive(Deserialize)] +pub struct Tx<'a> { + #[allow(dead_code)] + nonce: u64, + pub coin: &'a str, + pub value: u64, + #[serde(with = "hex::serde")] // Allows JSON deserialization from hex string + pub to: [u8; 20], + pub memo: &'a str, +} + +pub struct TxContext { + raw_tx: [u8; MAX_TRANSACTION_LEN], // raw transaction serialized + raw_tx_len: usize, // length of raw transaction + path: Bip32Path, +} + +// Implement constructor for TxInfo with default values +impl TxContext { + pub fn new() -> TxContext { + TxContext { + raw_tx: [0u8; MAX_TRANSACTION_LEN], + raw_tx_len: 0, + path: Default::default(), + } + } + + // Implement reset for TxInfo + fn reset(&mut self) { + self.raw_tx = [0u8; MAX_TRANSACTION_LEN]; + self.raw_tx_len = 0; + self.path = Default::default(); + } +} + +pub fn handler_sign_tx(comm: &mut Comm, chunk: u8, more: bool, ctx: &mut TxContext) -> Result<(), AppSW> { + // Try to get data from comm + let data = comm.get_data().map_err(|_| AppSW::WrongApduLength)?; + // First chunk, try to parse the path + if chunk == 0 { + // Reset transaction context + ctx.reset(); + // This will propagate the error if the path is invalid + ctx.path = data.try_into()?; + Ok(()) + // Next chunks, append data to raw_tx and return or parse + // the transaction if it is the last chunk. + } else { + if ctx.raw_tx_len + data.len() > MAX_TRANSACTION_LEN { + return Err(AppSW::TxWrongLength); + } + + // Append data to raw_tx + ctx.raw_tx[ctx.raw_tx_len..ctx.raw_tx_len + data.len()].copy_from_slice(data); + ctx.raw_tx_len += data.len(); + + // If we expect more chunks, return + if more { + Ok(()) + // Otherwise, try to parse the transaction + } else { + // Try to deserialize the transaction + let (tx, _): (Tx, usize) = from_slice(&ctx.raw_tx[..ctx.raw_tx_len]).map_err(|_| AppSW::TxParsingFail)?; + // Display transaction. If user approves + // the transaction, sign it. Otherwise, + // return a "deny" status word. + if ui_display_tx(&tx)? { + compute_signature_and_append(comm, ctx) + } else { + Err(AppSW::Deny) + } + } + } +} + +fn compute_signature_and_append(comm: &mut Comm, ctx: &mut TxContext) -> Result<(), AppSW> { + let mut keccak256 = Keccak256::new(); + let mut message_hash: [u8; 32] = [0u8; 32]; + + let _ = keccak256.hash(&ctx.raw_tx[..ctx.raw_tx_len], &mut message_hash); + + let (sig, siglen, parity) = Secp256k1::derive_from_path(ctx.path.as_ref()) + .deterministic_sign(&message_hash) + .map_err(|_| AppSW::TxSignFail)?; + comm.append(&[siglen as u8]); + comm.append(&sig[..siglen as usize]); + comm.append(&[parity as u8]); + Ok(()) +} diff --git a/applications/minotari_ledger_wallet/src/hashing.rs b/applications/minotari_ledger_wallet/src/hashing.rs index 9528a300cd..b3ba28f5aa 100644 --- a/applications/minotari_ledger_wallet/src/hashing.rs +++ b/applications/minotari_ledger_wallet/src/hashing.rs @@ -1,4 +1,4 @@ -// Copyright 2022 The Tari Project +// Copyright 2024 The Tari Project // SPDX-License-Identifier: BSD-3-Clause //! # MinoTari Ledger Wallet - Hashing diff --git a/applications/minotari_ledger_wallet/src/main.rs b/applications/minotari_ledger_wallet/src/main.rs index 48e2d0e8a9..661c4a6cda 100644 --- a/applications/minotari_ledger_wallet/src/main.rs +++ b/applications/minotari_ledger_wallet/src/main.rs @@ -1,36 +1,45 @@ -// Copyright 2022 The Tari Project +// Copyright 2024 The Tari Project // SPDX-License-Identifier: BSD-3-Clause -//! # MinoTari Ledger Wallet - #![no_std] #![no_main] #![feature(alloc_error_handler)] extern crate alloc; -use core::{cmp::min, mem::MaybeUninit}; -use critical_section::RawRestoreState; -use nanos_sdk::{ - buttons::ButtonEvent, - io, - io::{ApduHeader, Reply, StatusWords, SyscallError}, -}; -use nanos_ui::ui; -use tari_crypto::{ristretto::RistrettoSecretKey, tari_utilities::ByteArray}; +mod hashing; +mod utils; -use crate::{ - alloc::string::ToString, - utils::{byte_to_hex, get_raw_key, u64_to_string}, -}; +mod app_ui { + pub mod address; + pub mod menu; + pub mod sign; +} +mod handlers { + pub mod get_private_key; + pub mod get_public_key; + pub mod get_version; + pub mod sign_tx; +} -static MINOTARI_LEDGER_ID: u32 = 535348; -static MINOTARI_ACCOUNT_ID: u32 = 7041; +use core::mem::MaybeUninit; -pub mod hashing; -pub mod utils; +use app_ui::menu::ui_menu_main; +use critical_section::RawRestoreState; +use handlers::{ + get_private_key::handler_get_private_key, + get_public_key::handler_get_public_key, + get_version::handler_get_version, + sign_tx::{handler_sign_tx, TxContext}, +}; +#[cfg(feature = "pending_review_screen")] +use ledger_device_sdk::ui::gadgets::display_pending_review; +use ledger_device_sdk::{ + io::{ApduHeader, Comm, Event, Reply, StatusWords}, + ui::gadgets::SingleMessage, +}; -nanos_sdk::set_panic!(nanos_sdk::exiting_panic); +ledger_device_sdk::set_panic!(ledger_device_sdk::exiting_panic); /// Allocator heap size const HEAP_SIZE: usize = 1024 * 26; @@ -45,8 +54,8 @@ static HEAP: embedded_alloc::Heap = embedded_alloc::Heap::empty(); /// Error handler for allocation #[alloc_error_handler] fn alloc_error(_: core::alloc::Layout) -> ! { - ui::SingleMessage::new("allocation error!").show_and_wait(); - nanos_sdk::exit_app(250) + SingleMessage::new("allocation error!").show_and_wait(); + ledger_device_sdk::exit_app(250) } /// Initialise allocator @@ -67,123 +76,115 @@ unsafe impl critical_section::Impl for MyCriticalSection { } } -/// App Version parameters -const NAME: &str = env!("CARGO_PKG_NAME"); -const VERSION: &str = env!("CARGO_PKG_VERSION"); +// P2 for last APDU to receive. +const P2_SIGN_TX_LAST: u8 = 0x00; +// P2 for more APDU to receive. +const P2_SIGN_TX_MORE: u8 = 0x80; +// P1 for first APDU number. +const P1_SIGN_TX_START: u8 = 0x00; +// P1 for maximum APDU number. +const P1_SIGN_TX_MAX: u8 = 0x03; + +// Application status words. +#[repr(u16)] +pub enum AppSW { + Deny = 0x6985, + WrongP1P2 = 0x6A86, + InsNotSupported = 0x6D00, + ClaNotSupported = 0x6E00, + TxDisplayFail = 0xB001, + AddrDisplayFail = 0xB002, + TxWrongLength = 0xB004, + TxParsingFail = 0xB005, + TxHashFail = 0xB006, + TxSignFail = 0xB008, + KeyDeriveFail = 0xB009, + VersionParsingFail = 0xB00A, + WrongApduLength = StatusWords::BadLen as u16, +} + +impl From for Reply { + fn from(sw: AppSW) -> Reply { + Reply(sw as u16) + } +} -enum Instruction { +/// Possible input commands received through APDUs. +pub enum Instruction { GetVersion, - GetPrivateKey, - BadInstruction(u8), - Exit, + GetAppName, + GetPrivateKey { display: bool }, + GetPubkey { display: bool }, + SignTx { chunk: u8, more: bool }, } -impl From for Instruction { - fn from(header: io::ApduHeader) -> Instruction { - match header.ins { - 0x01 => Self::GetVersion, - 0x02 => Self::GetPrivateKey, - 0x03 => Self::Exit, - other => Self::BadInstruction(other), +impl TryFrom for Instruction { + type Error = AppSW; + + /// APDU parsing logic. + /// + /// Parses INS, P1 and P2 bytes to build an [`Instruction`]. P1 and P2 are translated to + /// strongly typed variables depending on the APDU instruction code. Invalid INS, P1 or P2 + /// values result in errors with a status word, which are automatically sent to the host by the + /// SDK. + /// + /// This design allows a clear separation of the APDU parsing logic and commands handling. + /// + /// Note that CLA is not checked here. Instead the method [`Comm::set_expected_cla`] is used in + /// [`sample_main`] to have this verification automatically performed by the SDK. + fn try_from(value: ApduHeader) -> Result { + match (value.ins, value.p1, value.p2) { + (3, 0, 0) => Ok(Instruction::GetVersion), + (4, 0, 0) => Ok(Instruction::GetAppName), + (2, 0, 0) => Ok(Instruction::GetPrivateKey { display: value.p1 != 0 }), + (5, 0 | 1, 0) => Ok(Instruction::GetPubkey { display: value.p1 != 0 }), + (6, P1_SIGN_TX_START, P2_SIGN_TX_MORE) | (6, 1..=P1_SIGN_TX_MAX, P2_SIGN_TX_LAST | P2_SIGN_TX_MORE) => { + Ok(Instruction::SignTx { + chunk: value.p1, + more: value.p2 == P2_SIGN_TX_MORE, + }) + }, + (3..=6, _, _) => Err(AppSW::WrongP1P2), + (_, _, _) => Err(AppSW::InsNotSupported), } } } #[no_mangle] extern "C" fn sample_main() { - let mut comm = io::Comm::new(); - init(); - let messages = alloc::vec!["MinoTari Wallet", "keep the app open..", "[exit = both buttons]"]; - let mut index = 0; - ui::SingleMessage::new(messages[index]).show(); + // Create the communication manager, and configure it to accept only APDU from the 0xe0 class. + // If any APDU with a wrong class value is received, comm will respond automatically with + // BadCla status word. + let mut comm = Comm::new().set_expected_cla(0x80); + + // Developer mode / pending review popup + // must be cleared with user interaction + #[cfg(feature = "pending_review_screen")] + display_pending_review(&mut comm); + + let mut tx_ctx = TxContext::new(); + loop { - let event = comm.next_event::(); - match event { - io::Event::Button(ButtonEvent::BothButtonsRelease) => nanos_sdk::exit_app(0), - io::Event::Button(ButtonEvent::RightButtonRelease) => { - index = min(index + 1, messages.len() - 1); - ui::SingleMessage::new(messages[index]).show() - }, - io::Event::Button(ButtonEvent::LeftButtonRelease) => { - if index > 0 { - index -= 1; - } - ui::SingleMessage::new(messages[index]).show() - }, - io::Event::Button(_) => {}, - io::Event::Command(apdu_header) => match handle_apdu(&mut comm, apdu_header.into()) { + // Wait for either a specific button push to exit the app + // or an APDU command + if let Event::Command(ins) = ui_menu_main(&mut comm) { + match handle_apdu(&mut comm, ins, &mut tx_ctx) { Ok(()) => comm.reply_ok(), - Err(e) => comm.reply(e), - }, - io::Event::Ticker => {}, + Err(sw) => comm.reply(sw), + } } } } -// Perform ledger instructions -fn handle_apdu(comm: &mut io::Comm, instruction: Instruction) -> Result<(), Reply> { - if comm.rx == 0 { - return Err(io::StatusWords::NothingReceived.into()); - } - - match instruction { - Instruction::GetVersion => { - ui::SingleMessage::new("GetVersion...").show(); - let name_bytes = NAME.as_bytes(); - let version_bytes = VERSION.as_bytes(); - comm.append(&[1]); // Format - comm.append(&[name_bytes.len() as u8]); - comm.append(name_bytes); - comm.append(&[version_bytes.len() as u8]); - comm.append(version_bytes); - comm.append(&[0]); // No flags - ui::SingleMessage::new("GetVersion... Done").show(); - comm.reply_ok(); - }, - Instruction::GetPrivateKey => { - // first 5 bytes are instruction details - let offset = 5; - let mut address_index_bytes = [0u8; 8]; - address_index_bytes.clone_from_slice(comm.get(offset, offset + 8)); - let address_index = crate::u64_to_string(u64::from_le_bytes(address_index_bytes)); - - let mut msg = "GetPrivateKey... ".to_string(); - msg.push_str(&address_index); - ui::SingleMessage::new(&msg).show(); - - let mut bip32_path = "m/44'/".to_string(); - bip32_path.push_str(&MINOTARI_LEDGER_ID.to_string()); - bip32_path.push_str(&"'/"); - bip32_path.push_str(&MINOTARI_ACCOUNT_ID.to_string()); - bip32_path.push_str(&"'/0/"); - bip32_path.push_str(&address_index); - let path: [u32; 5] = nanos_sdk::ecc::make_bip32_path(bip32_path.as_bytes()); - - let raw_key = get_raw_key(&path)?; - - let k = match RistrettoSecretKey::from_bytes(&raw_key) { - Ok(val) => val, - Err(_) => { - ui::SingleMessage::new("Err: key conversion").show(); - return Err(SyscallError::InvalidParameter.into()); - }, - }; - comm.append(&[1]); // version - comm.append(k.as_bytes()); - comm.reply_ok(); - }, - Instruction::BadInstruction(val) => { - let mut error = "BadInstruction... ! (".to_string(); - error.push_str(&crate::byte_to_hex(val)); - error.push_str(&")"); - ui::SingleMessage::new(&error).show(); - return Err(StatusWords::BadIns.into()); - }, - Instruction::Exit => { - ui::SingleMessage::new("Exit...").show(); - comm.reply_ok(); - nanos_sdk::exit_app(0) +fn handle_apdu(comm: &mut Comm, ins: Instruction, ctx: &mut TxContext) -> Result<(), AppSW> { + match ins { + Instruction::GetAppName => { + comm.append(env!("CARGO_PKG_NAME").as_bytes()); + Ok(()) }, + Instruction::GetPrivateKey { display } => handler_get_private_key(comm, display), + Instruction::GetVersion => handler_get_version(comm), + Instruction::GetPubkey { display } => handler_get_public_key(comm, display), + Instruction::SignTx { chunk, more } => handler_sign_tx(comm, chunk, more, ctx), } - Ok(()) } diff --git a/applications/minotari_ledger_wallet/src/utils.rs b/applications/minotari_ledger_wallet/src/utils.rs index e7c609f46a..7332c6b9ad 100644 --- a/applications/minotari_ledger_wallet/src/utils.rs +++ b/applications/minotari_ledger_wallet/src/utils.rs @@ -1,13 +1,90 @@ -// Copyright 2022 The Tari Project +// Copyright 2024 The Tari Project // SPDX-License-Identifier: BSD-3-Clause -//! # MinoTari Ledger Wallet - Utils +use core::str::from_utf8; -use nanos_sdk::{ +use crate::AppSW; + +/// BIP32 path stored as an array of [`u32`]. +/// +/// # Generic arguments +/// +/// * `S` - Maximum possible path length, i.e. the capacity of the internal buffer. +pub struct Bip32Path { + buffer: [u32; S], + len: usize, +} + +impl AsRef<[u32]> for Bip32Path { + fn as_ref(&self) -> &[u32] { + &self.buffer[..self.len] + } +} + +impl Default for Bip32Path { + fn default() -> Self { + Self { + buffer: [0u32; S], + len: 0, + } + } +} + +impl TryFrom<&[u8]> for Bip32Path { + type Error = AppSW; + + /// Constructs a [`Bip32Path`] from a given byte array. + /// + /// This method will return an error in the following cases: + /// - the input array is empty, + /// - the number of bytes in the input array is not a multiple of 4, + /// - the input array exceeds the capacity of the [`Bip32Path`] internal buffer. + /// + /// # Arguments + /// + /// * `data` - Encoded BIP32 path. First byte is the length of the path, as encoded by ragger. + fn try_from(data: &[u8]) -> Result { + let input_path_len = (data.len() - 1) / 4; + // Check data length + if data.is_empty() // At least the length byte is required + || (input_path_len > S) + || (data[0] as usize * 4 != data.len() - 1) + { + return Err(AppSW::WrongApduLength); + } + + let mut path = [0; S]; + for (chunk, p) in data[1..].chunks(4).zip(path.iter_mut()) { + *p = u32::from_be_bytes(chunk.try_into().unwrap()); + } + + Ok(Self { + buffer: path, + len: input_path_len, + }) + } +} + +/// Returns concatenated strings, or an error if the concatenation buffer is too small. +pub fn concatenate<'a>(strings: &[&str], output: &'a mut [u8]) -> Result<&'a str, ()> { + let mut offset = 0; + + for s in strings { + let s_len = s.len(); + if offset + s_len > output.len() { + return Err(()); + } + + output[offset..offset + s_len].copy_from_slice(s.as_bytes()); + offset += s_len; + } + + Ok(from_utf8(&output[..offset]).unwrap()) +} +use ledger_device_sdk::{ ecc::{bip32_derive, CurvesId, CxError, Secret}, io::SyscallError, }; -use nanos_ui::ui; use tari_crypto::hash_domain; use crate::{ @@ -15,7 +92,7 @@ use crate::{ hashing::DomainSeparatedConsensusHasher, }; -hash_domain!(LedgerHashDomain, "com.tari.genesis_tools.applications.mp_ldeger", 0); +hash_domain!(LedgerHashDomain, "com.tari.minotari_ledger_wallet", 0); /// Convert a u64 to a string without using the standard library pub fn u64_to_string(number: u64) -> String { @@ -91,7 +168,7 @@ fn cx_error_to_string(e: CxError) -> String { // uniformly distributed random bytes. fn get_raw_key_hash(path: &[u32]) -> Result<[u8; 64], String> { let mut key = Secret::<96>::new(); - let raw_key_64 = match bip32_derive(CurvesId::Ed25519, path, key.as_mut()) { + let raw_key_64 = match bip32_derive(CurvesId::Ed25519, path, key.as_mut(), None) { Ok(_) => { let binding = &key.as_ref()[..64]; let raw_key_64: [u8; 64] = match binding.try_into() { @@ -112,11 +189,11 @@ fn get_raw_key_hash(path: &[u32]) -> Result<[u8; 64], String> { pub fn get_raw_key(path: &[u32]) -> Result<[u8; 64], SyscallError> { match get_raw_key_hash(&path) { Ok(val) => Ok(val), - Err(e) => { + Err(_e) => { let mut msg = "".to_string(); msg.push_str("Err: raw key >>..."); - ui::SingleMessage::new(&msg).show_and_wait(); - ui::SingleMessage::new(&e).show(); + // ui::SingleMessage::new(&msg).show_and_wait(); + // ui::SingleMessage::new(&e).show(); Err(SyscallError::InvalidParameter.into()) }, } From 9a9644e88de9722e81cc01a1bc4ffe61ac5132cb Mon Sep 17 00:00:00 2001 From: brianp Date: Wed, 10 Apr 2024 12:53:06 +0200 Subject: [PATCH 02/49] Trim down the ledger app to needed functions --- .../minotari_console_wallet/src/lib.rs | 1 - .../minotari_ledger_wallet/Cargo.toml | 14 +-- .../minotari_ledger_wallet/app_nanosplus.json | 7 +- .../src/app_ui/address.rs | 39 ------- .../minotari_ledger_wallet/src/app_ui/sign.rs | 66 ----------- .../src/handlers/get_private_key.rs | 43 +++++--- .../src/handlers/get_public_key.rs | 50 --------- .../src/handlers/get_version.rs | 22 +--- .../src/handlers/sign_tx.rs | 104 ------------------ .../minotari_ledger_wallet/src/hashing.rs | 75 ------------- .../minotari_ledger_wallet/src/main.rs | 49 ++------- .../minotari_ledger_wallet/src/utils.rs | 85 ++++++-------- 12 files changed, 81 insertions(+), 474 deletions(-) delete mode 100644 applications/minotari_ledger_wallet/src/app_ui/address.rs delete mode 100644 applications/minotari_ledger_wallet/src/app_ui/sign.rs delete mode 100644 applications/minotari_ledger_wallet/src/handlers/get_public_key.rs delete mode 100644 applications/minotari_ledger_wallet/src/handlers/sign_tx.rs delete mode 100644 applications/minotari_ledger_wallet/src/hashing.rs diff --git a/applications/minotari_console_wallet/src/lib.rs b/applications/minotari_console_wallet/src/lib.rs index 95cb8c32da..1b066c8a76 100644 --- a/applications/minotari_console_wallet/src/lib.rs +++ b/applications/minotari_console_wallet/src/lib.rs @@ -128,7 +128,6 @@ pub fn run_wallet_with_cli( let recovery_seed = get_recovery_seed(boot_mode, &cli)?; - // This is deactivated at the moment as full support is not yet complete let wallet_type = prompt_wallet_type(boot_mode, &config.wallet, cli.non_interactive_mode); // get command line password if provided diff --git a/applications/minotari_ledger_wallet/Cargo.toml b/applications/minotari_ledger_wallet/Cargo.toml index 7ab7a15f20..c662b748f7 100644 --- a/applications/minotari_ledger_wallet/Cargo.toml +++ b/applications/minotari_ledger_wallet/Cargo.toml @@ -11,13 +11,10 @@ borsh = { version = "0.10", default-features = false } critical-section = { version = "1.1.1" } digest = { version = "0.10", default-features = false } embedded-alloc = "0.5.0" -hex = { version = "0.4.3", default-features = false, features = ["serde"] } include_gif = "1.0.1" ledger_device_sdk = "1.7.1" -numtoa = "0.2.4" -serde = { version="1.0.192", default_features = false, features = ["derive"] } -serde-json-core = { git = "https://github.com/rust-embedded-community/serde-json-core"} tari_crypto = { version = "0.20.0", default-features = false } +zeroize = { version = "1" , default-features = false } # once_cell defined here just to lock the version. Other dependencies may try to go to 1.19 which is incompatabile with # ledger at this time. 1.19 removes "atomic-polyfill" and replaces it with "portable-atomic" which can not build due to @@ -25,17 +22,18 @@ tari_crypto = { version = "0.20.0", default-features = false } once_cell = { version = "=1.18.0", default-features = false } [profile.release] -opt-level = 'z' -lto = true +opt-level = 's' +lto = "fat" # same as `true` +panic = "abort" [features] default = ["pending_review_screen"] pending_review_screen = [] [package.metadata.ledger] -curve = ["secp256k1", "ed25519"] +curve = ["ed25519"] flags = "0" -path = ["44'/1022'", "m/5261654", "m/44"] +path = ["44'/535348'"] name = "MinoTari Wallet" [package.metadata.ledger.nanos] diff --git a/applications/minotari_ledger_wallet/app_nanosplus.json b/applications/minotari_ledger_wallet/app_nanosplus.json index 70502c35f5..91a9fc124b 100644 --- a/applications/minotari_ledger_wallet/app_nanosplus.json +++ b/applications/minotari_ledger_wallet/app_nanosplus.json @@ -1,16 +1,13 @@ { "apiLevel": "5", "binary": "target/nanosplus/release/app.hex", - "dataSize": 7680, + "dataSize": 6144, "derivationPath": { "curves": [ - "secp256k1", "ed25519" ], "paths": [ - "44'/1022'", - "m/5261654", - "m/44" + "44'/535348'" ] }, "flags": "0", diff --git a/applications/minotari_ledger_wallet/src/app_ui/address.rs b/applications/minotari_ledger_wallet/src/app_ui/address.rs deleted file mode 100644 index f3e615f316..0000000000 --- a/applications/minotari_ledger_wallet/src/app_ui/address.rs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2024 The Tari Project -// SPDX-License-Identifier: BSD-3-Clause - -use core::str::from_utf8_mut; - -use ledger_device_sdk::ui::{ - bitmaps::{CROSSMARK, EYE, VALIDATE_14}, - gadgets::{Field, MultiFieldReview}, -}; - -use crate::AppSW; - -// Display only the last 20 bytes of the address -const DISPLAY_ADDR_BYTES_LEN: usize = 20; - -pub fn ui_display_pk(addr: &[u8]) -> Result { - let mut addr_hex = [0u8; DISPLAY_ADDR_BYTES_LEN * 2 + 2]; - addr_hex[..2].copy_from_slice("0x".as_bytes()); - hex::encode_to_slice(&addr[addr.len() - DISPLAY_ADDR_BYTES_LEN..], &mut addr_hex[2..]).unwrap(); - let addr_hex = from_utf8_mut(&mut addr_hex).unwrap(); - addr_hex[2..].make_ascii_uppercase(); - - let my_field = [Field { - name: "Address", - value: addr_hex, - }]; - - let my_review = MultiFieldReview::new( - &my_field, - &["Confirm Address"], - Some(&EYE), - "Approve", - Some(&VALIDATE_14), - "Reject", - Some(&CROSSMARK), - ); - - Ok(my_review.show()) -} diff --git a/applications/minotari_ledger_wallet/src/app_ui/sign.rs b/applications/minotari_ledger_wallet/src/app_ui/sign.rs deleted file mode 100644 index b11897b46a..0000000000 --- a/applications/minotari_ledger_wallet/src/app_ui/sign.rs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2024 The Tari Project -// SPDX-License-Identifier: BSD-3-Clause - -use ledger_device_sdk::ui::{ - bitmaps::{CROSSMARK, EYE, VALIDATE_14}, - gadgets::{Field, MultiFieldReview}, -}; -use numtoa::NumToA; - -use crate::{handlers::sign_tx::Tx, utils::concatenate, AppSW}; - -const MAX_COIN_LENGTH: usize = 10; - -/// Displays a transaction and returns true if user approved it. -/// -/// This method can return [`AppSW::TxDisplayFail`] error if the coin name length is too long. -/// -/// # Arguments -/// -/// * `tx` - Transaction to be displayed for validation -pub fn ui_display_tx(tx: &Tx) -> Result { - // Generate string for amount - let mut numtoa_buf = [0u8; 20]; - let mut value_buf = [0u8; 20 + MAX_COIN_LENGTH + 1]; - - let value_str = concatenate( - &[tx.coin, " ", tx.value.numtoa_str(10, &mut numtoa_buf)], - &mut value_buf, - ) - .map_err(|_| AppSW::TxDisplayFail)?; // Fails if value_buf is too small - - // Generate destination address string in hexadecimal format. - let mut to_str = [0u8; 42]; - to_str[..2].copy_from_slice("0x".as_bytes()); - hex::encode_to_slice(tx.to, &mut to_str[2..]).unwrap(); - to_str[2..].make_ascii_uppercase(); - - // Define transaction review fields - let my_fields = [ - Field { - name: "Amount", - value: value_str, - }, - Field { - name: "Destination", - value: core::str::from_utf8(&to_str).unwrap(), - }, - Field { - name: "Memo", - value: tx.memo, - }, - ]; - - // Create transaction review - let my_review = MultiFieldReview::new( - &my_fields, - &["Review ", "Transaction"], - Some(&EYE), - "Approve", - Some(&VALIDATE_14), - "Reject", - Some(&CROSSMARK), - ); - - Ok(my_review.show()) -} diff --git a/applications/minotari_ledger_wallet/src/handlers/get_private_key.rs b/applications/minotari_ledger_wallet/src/handlers/get_private_key.rs index b4a3bae253..2878285861 100644 --- a/applications/minotari_ledger_wallet/src/handlers/get_private_key.rs +++ b/applications/minotari_ledger_wallet/src/handlers/get_private_key.rs @@ -1,29 +1,30 @@ // Copyright 2024 The Tari Project // SPDX-License-Identifier: BSD-3-Clause -use alloc::string::ToString; +use alloc::format; use ledger_device_sdk::{ecc::make_bip32_path, io::Comm, ui::gadgets::SingleMessage}; -use tari_crypto::{ristretto::RistrettoSecretKey, tari_utilities::ByteArray}; +use tari_crypto::{keys::SecretKey, ristretto::RistrettoSecretKey, tari_utilities::ByteArray}; use crate::{ + alloc::string::ToString, utils::{get_raw_key, u64_to_string}, AppSW, }; static MINOTARI_BIP32_COIN_TYPE: u32 = 535348; -pub fn handler_get_public_key(comm: &mut Comm, _display: bool) -> Result<(), AppSW> { - // first 5 bytes are instruction details - let offset = 5; +pub fn handler_get_private_key(comm: &mut Comm) -> Result<(), AppSW> { + let data = comm.get_data().map_err(|_| AppSW::WrongApduLength)?; + + let mut account_bytes = [0u8; 8]; + account_bytes.clone_from_slice(&data[0..8]); + let account = u64_to_string(u64::from_le_bytes(account_bytes)); + let mut address_index_bytes = [0u8; 8]; - address_index_bytes.clone_from_slice(comm.get(offset, offset + 8)); + address_index_bytes.clone_from_slice(&data[8..16]); let address_index = u64_to_string(u64::from_le_bytes(address_index_bytes)); - let mut msg = "GetPrivateKey... ".to_string(); - msg.push_str(&address_index); - SingleMessage::new(&msg).show(); - let mut bip32_path = "m/44'/".to_string(); bip32_path.push_str(&MINOTARI_BIP32_COIN_TYPE.to_string()); bip32_path.push_str(&"'/"); @@ -32,15 +33,29 @@ pub fn handler_get_public_key(comm: &mut Comm, _display: bool) -> Result<(), App bip32_path.push_str(&address_index); let path: [u32; 5] = make_bip32_path(bip32_path.as_bytes()); - let raw_key = get_raw_key(&path).map_err(|_| AppSW::KeyDeriveFail)?; + SingleMessage::new(&bip32_path).show_and_wait(); - let k = match RistrettoSecretKey::from_canonical_bytes(&raw_key) { + let raw_key = match get_raw_key(&path) { Ok(val) => val, - Err(_) => { - SingleMessage::new("Err: key conversion").show(); + Err(e) => { + SingleMessage::new(&format!("Key error {:?}", e)).show_and_wait(); return Err(AppSW::KeyDeriveFail); }, }; + + let k = match RistrettoSecretKey::from_uniform_bytes(&raw_key.as_ref()) { + Ok(val) => val, + Err(e) => { + SingleMessage::new(&format!( + "Err: key conversion {:?}. Length: {:?}", + e.to_string(), + &raw_key.len() + )) + .show(); + return Err(AppSW::KeyDeriveFail); + }, + }; + comm.append(&[1]); // version comm.append(k.as_bytes()); comm.reply_ok(); diff --git a/applications/minotari_ledger_wallet/src/handlers/get_public_key.rs b/applications/minotari_ledger_wallet/src/handlers/get_public_key.rs deleted file mode 100644 index a9533c1d66..0000000000 --- a/applications/minotari_ledger_wallet/src/handlers/get_public_key.rs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2024 The Tari Project -// SPDX-License-Identifier: BSD-3-Clause - -use alloc::string::ToString; - -use ledger_device_sdk::{ecc::make_bip32_path, io::Comm, ui::gadgets::SingleMessage}; -use tari_crypto::{ristretto::RistrettoSecretKey, tari_utilities::ByteArray}; - -use crate::{ - utils::{get_raw_key, u64_to_string}, - AppSW, -}; - -static MINOTARI_LEDGER_ID: u32 = 535348; -static MINOTARI_ACCOUNT_ID: u32 = 7041; - -pub fn handler_get_public_key(comm: &mut Comm, _display: bool) -> Result<(), AppSW> { - // first 5 bytes are instruction details - let offset = 5; - let mut address_index_bytes = [0u8; 8]; - address_index_bytes.clone_from_slice(comm.get(offset, offset + 8)); - let address_index = u64_to_string(u64::from_le_bytes(address_index_bytes)); - - let mut msg = "GetPrivateKey... ".to_string(); - msg.push_str(&address_index); - SingleMessage::new(&msg).show(); - - let mut bip32_path = "m/44'/".to_string(); - bip32_path.push_str(&MINOTARI_LEDGER_ID.to_string()); - bip32_path.push_str(&"'/"); - bip32_path.push_str(&MINOTARI_ACCOUNT_ID.to_string()); - bip32_path.push_str(&"'/0/"); - bip32_path.push_str(&address_index); - let path: [u32; 5] = make_bip32_path(bip32_path.as_bytes()); - - let raw_key = get_raw_key(&path).map_err(|_| AppSW::KeyDeriveFail)?; - - let k = match RistrettoSecretKey::from_canonical_bytes(&raw_key) { - Ok(val) => val, - Err(_) => { - SingleMessage::new("Err: key conversion").show(); - return Err(AppSW::KeyDeriveFail); - }, - }; - comm.append(&[1]); // version - comm.append(k.as_bytes()); - comm.reply_ok(); - - Ok(()) -} diff --git a/applications/minotari_ledger_wallet/src/handlers/get_version.rs b/applications/minotari_ledger_wallet/src/handlers/get_version.rs index 08581a833d..00932f27a0 100644 --- a/applications/minotari_ledger_wallet/src/handlers/get_version.rs +++ b/applications/minotari_ledger_wallet/src/handlers/get_version.rs @@ -1,28 +1,12 @@ // Copyright 2024 The Tari Project // SPDX-License-Identifier: BSD-3-Clause -use core::str::FromStr; - use ledger_device_sdk::io; use crate::AppSW; pub fn handler_get_version(comm: &mut io::Comm) -> Result<(), AppSW> { - if let Some((major, minor, patch)) = parse_version_string(env!("CARGO_PKG_VERSION")) { - comm.append(&[major, minor, patch]); - Ok(()) - } else { - Err(AppSW::VersionParsingFail) - } -} - -fn parse_version_string(input: &str) -> Option<(u8, u8, u8)> { - // Split the input string by '.'. - // Input should be of the form "major.minor.patch", - // where "major", "minor", and "patch" are integers. - let mut parts = input.split('.'); - let major = u8::from_str(parts.next()?).ok()?; - let minor = u8::from_str(parts.next()?).ok()?; - let patch = u8::from_str(parts.next()?).ok()?; - Some((major, minor, patch)) + let version = env!("CARGO_PKG_VERSION").as_bytes(); + comm.append(version); + Ok(()) } diff --git a/applications/minotari_ledger_wallet/src/handlers/sign_tx.rs b/applications/minotari_ledger_wallet/src/handlers/sign_tx.rs deleted file mode 100644 index e87c5f70c3..0000000000 --- a/applications/minotari_ledger_wallet/src/handlers/sign_tx.rs +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2024 The Tari Project -// SPDX-License-Identifier: BSD-3-Clause - -use ledger_device_sdk::{ - ecc::{Secp256k1, SeedDerive}, - hash::{sha3::Keccak256, HashInit}, - io::Comm, -}; -use serde::Deserialize; -use serde_json_core::from_slice; - -use crate::{app_ui::sign::ui_display_tx, utils::Bip32Path, AppSW}; - -const MAX_TRANSACTION_LEN: usize = 510; - -#[derive(Deserialize)] -pub struct Tx<'a> { - #[allow(dead_code)] - nonce: u64, - pub coin: &'a str, - pub value: u64, - #[serde(with = "hex::serde")] // Allows JSON deserialization from hex string - pub to: [u8; 20], - pub memo: &'a str, -} - -pub struct TxContext { - raw_tx: [u8; MAX_TRANSACTION_LEN], // raw transaction serialized - raw_tx_len: usize, // length of raw transaction - path: Bip32Path, -} - -// Implement constructor for TxInfo with default values -impl TxContext { - pub fn new() -> TxContext { - TxContext { - raw_tx: [0u8; MAX_TRANSACTION_LEN], - raw_tx_len: 0, - path: Default::default(), - } - } - - // Implement reset for TxInfo - fn reset(&mut self) { - self.raw_tx = [0u8; MAX_TRANSACTION_LEN]; - self.raw_tx_len = 0; - self.path = Default::default(); - } -} - -pub fn handler_sign_tx(comm: &mut Comm, chunk: u8, more: bool, ctx: &mut TxContext) -> Result<(), AppSW> { - // Try to get data from comm - let data = comm.get_data().map_err(|_| AppSW::WrongApduLength)?; - // First chunk, try to parse the path - if chunk == 0 { - // Reset transaction context - ctx.reset(); - // This will propagate the error if the path is invalid - ctx.path = data.try_into()?; - Ok(()) - // Next chunks, append data to raw_tx and return or parse - // the transaction if it is the last chunk. - } else { - if ctx.raw_tx_len + data.len() > MAX_TRANSACTION_LEN { - return Err(AppSW::TxWrongLength); - } - - // Append data to raw_tx - ctx.raw_tx[ctx.raw_tx_len..ctx.raw_tx_len + data.len()].copy_from_slice(data); - ctx.raw_tx_len += data.len(); - - // If we expect more chunks, return - if more { - Ok(()) - // Otherwise, try to parse the transaction - } else { - // Try to deserialize the transaction - let (tx, _): (Tx, usize) = from_slice(&ctx.raw_tx[..ctx.raw_tx_len]).map_err(|_| AppSW::TxParsingFail)?; - // Display transaction. If user approves - // the transaction, sign it. Otherwise, - // return a "deny" status word. - if ui_display_tx(&tx)? { - compute_signature_and_append(comm, ctx) - } else { - Err(AppSW::Deny) - } - } - } -} - -fn compute_signature_and_append(comm: &mut Comm, ctx: &mut TxContext) -> Result<(), AppSW> { - let mut keccak256 = Keccak256::new(); - let mut message_hash: [u8; 32] = [0u8; 32]; - - let _ = keccak256.hash(&ctx.raw_tx[..ctx.raw_tx_len], &mut message_hash); - - let (sig, siglen, parity) = Secp256k1::derive_from_path(ctx.path.as_ref()) - .deterministic_sign(&message_hash) - .map_err(|_| AppSW::TxSignFail)?; - comm.append(&[siglen as u8]); - comm.append(&sig[..siglen as usize]); - comm.append(&[parity as u8]); - Ok(()) -} diff --git a/applications/minotari_ledger_wallet/src/hashing.rs b/applications/minotari_ledger_wallet/src/hashing.rs deleted file mode 100644 index b3ba28f5aa..0000000000 --- a/applications/minotari_ledger_wallet/src/hashing.rs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2024 The Tari Project -// SPDX-License-Identifier: BSD-3-Clause - -//! # MinoTari Ledger Wallet - Hashing - -use core::marker::PhantomData; - -use blake2::Blake2b; -use borsh::{ - maybestd::io::{Result as BorshResult, Write}, - BorshSerialize, -}; -use digest::{consts::U64, Digest}; -use tari_crypto::hashing::DomainSeparation; - -/// Domain separated consensus hasher -pub struct DomainSeparatedConsensusHasher(PhantomData); - -impl DomainSeparatedConsensusHasher { - /// Create a new hasher with the given label - pub fn new(label: &'static str) -> ConsensusHasher> { - let mut digest = Blake2b::::new(); - M::add_domain_separation_tag(&mut digest, label); - ConsensusHasher::from_digest(digest) - } -} - -/// Consensus hasher -#[derive(Clone)] -pub struct ConsensusHasher { - writer: WriteHashWrapper, -} - -impl ConsensusHasher { - fn from_digest(digest: D) -> Self { - Self { - writer: WriteHashWrapper(digest), - } - } -} - -impl ConsensusHasher -where D: Digest -{ - /// Finalize the hasher and return the hash - pub fn finalize(self) -> [u8; 64] { - self.writer.0.finalize().into() - } - - /// Update the hasher with the given data - pub fn update_consensus_encode(&mut self, data: &T) { - BorshSerialize::serialize(data, &mut self.writer) - .expect("Incorrect implementation of BorshSerialize encountered. Implementations MUST be infallible."); - } - - /// Update the hasher with the given data - pub fn chain(mut self, data: &T) -> Self { - self.update_consensus_encode(data); - self - } -} - -#[derive(Clone)] -struct WriteHashWrapper(D); - -impl Write for WriteHashWrapper { - fn write(&mut self, buf: &[u8]) -> BorshResult { - self.0.update(buf); - Ok(buf.len()) - } - - fn flush(&mut self) -> BorshResult<()> { - Ok(()) - } -} diff --git a/applications/minotari_ledger_wallet/src/main.rs b/applications/minotari_ledger_wallet/src/main.rs index 661c4a6cda..fad9b21436 100644 --- a/applications/minotari_ledger_wallet/src/main.rs +++ b/applications/minotari_ledger_wallet/src/main.rs @@ -7,31 +7,21 @@ extern crate alloc; -mod hashing; mod utils; mod app_ui { - pub mod address; pub mod menu; - pub mod sign; } mod handlers { pub mod get_private_key; - pub mod get_public_key; pub mod get_version; - pub mod sign_tx; } use core::mem::MaybeUninit; use app_ui::menu::ui_menu_main; use critical_section::RawRestoreState; -use handlers::{ - get_private_key::handler_get_private_key, - get_public_key::handler_get_public_key, - get_version::handler_get_version, - sign_tx::{handler_sign_tx, TxContext}, -}; +use handlers::{get_private_key::handler_get_private_key, get_version::handler_get_version}; #[cfg(feature = "pending_review_screen")] use ledger_device_sdk::ui::gadgets::display_pending_review; use ledger_device_sdk::{ @@ -76,15 +66,6 @@ unsafe impl critical_section::Impl for MyCriticalSection { } } -// P2 for last APDU to receive. -const P2_SIGN_TX_LAST: u8 = 0x00; -// P2 for more APDU to receive. -const P2_SIGN_TX_MORE: u8 = 0x80; -// P1 for first APDU number. -const P1_SIGN_TX_START: u8 = 0x00; -// P1 for maximum APDU number. -const P1_SIGN_TX_MAX: u8 = 0x03; - // Application status words. #[repr(u16)] pub enum AppSW { @@ -113,9 +94,7 @@ impl From for Reply { pub enum Instruction { GetVersion, GetAppName, - GetPrivateKey { display: bool }, - GetPubkey { display: bool }, - SignTx { chunk: u8, more: bool }, + GetPrivateKey, } impl TryFrom for Instruction { @@ -134,16 +113,9 @@ impl TryFrom for Instruction { /// [`sample_main`] to have this verification automatically performed by the SDK. fn try_from(value: ApduHeader) -> Result { match (value.ins, value.p1, value.p2) { - (3, 0, 0) => Ok(Instruction::GetVersion), - (4, 0, 0) => Ok(Instruction::GetAppName), - (2, 0, 0) => Ok(Instruction::GetPrivateKey { display: value.p1 != 0 }), - (5, 0 | 1, 0) => Ok(Instruction::GetPubkey { display: value.p1 != 0 }), - (6, P1_SIGN_TX_START, P2_SIGN_TX_MORE) | (6, 1..=P1_SIGN_TX_MAX, P2_SIGN_TX_LAST | P2_SIGN_TX_MORE) => { - Ok(Instruction::SignTx { - chunk: value.p1, - more: value.p2 == P2_SIGN_TX_MORE, - }) - }, + (1, 0, 0) => Ok(Instruction::GetVersion), + (2, 0, 0) => Ok(Instruction::GetAppName), + (3, 0, 0) => Ok(Instruction::GetPrivateKey), (3..=6, _, _) => Err(AppSW::WrongP1P2), (_, _, _) => Err(AppSW::InsNotSupported), } @@ -152,6 +124,7 @@ impl TryFrom for Instruction { #[no_mangle] extern "C" fn sample_main() { + init(); // Create the communication manager, and configure it to accept only APDU from the 0xe0 class. // If any APDU with a wrong class value is received, comm will respond automatically with // BadCla status word. @@ -162,13 +135,11 @@ extern "C" fn sample_main() { #[cfg(feature = "pending_review_screen")] display_pending_review(&mut comm); - let mut tx_ctx = TxContext::new(); - loop { // Wait for either a specific button push to exit the app // or an APDU command if let Event::Command(ins) = ui_menu_main(&mut comm) { - match handle_apdu(&mut comm, ins, &mut tx_ctx) { + match handle_apdu(&mut comm, ins) { Ok(()) => comm.reply_ok(), Err(sw) => comm.reply(sw), } @@ -176,15 +147,13 @@ extern "C" fn sample_main() { } } -fn handle_apdu(comm: &mut Comm, ins: Instruction, ctx: &mut TxContext) -> Result<(), AppSW> { +fn handle_apdu(comm: &mut Comm, ins: Instruction) -> Result<(), AppSW> { match ins { Instruction::GetAppName => { comm.append(env!("CARGO_PKG_NAME").as_bytes()); Ok(()) }, - Instruction::GetPrivateKey { display } => handler_get_private_key(comm, display), + Instruction::GetPrivateKey => handler_get_private_key(comm), Instruction::GetVersion => handler_get_version(comm), - Instruction::GetPubkey { display } => handler_get_public_key(comm, display), - Instruction::SignTx { chunk, more } => handler_sign_tx(comm, chunk, more, ctx), } } diff --git a/applications/minotari_ledger_wallet/src/utils.rs b/applications/minotari_ledger_wallet/src/utils.rs index 7332c6b9ad..f62e2dc419 100644 --- a/applications/minotari_ledger_wallet/src/utils.rs +++ b/applications/minotari_ledger_wallet/src/utils.rs @@ -1,7 +1,19 @@ // Copyright 2024 The Tari Project // SPDX-License-Identifier: BSD-3-Clause -use core::str::from_utf8; +use blake2::{Blake2b, Digest}; +use digest::consts::U64; +use ledger_device_sdk::{ + ecc::{bip32_derive, CurvesId, CxError}, + io::SyscallError, + ui::gadgets::SingleMessage, +}; +use tari_crypto::{hash_domain, hashing::DomainSeparatedHasher}; +use zeroize::Zeroizing; + +use crate::alloc::string::{String, ToString}; + +hash_domain!(LedgerHashDomain, "com.tari.minotari_ledger_wallet", 0); use crate::AppSW; @@ -65,35 +77,6 @@ impl TryFrom<&[u8]> for Bip32Path { } } -/// Returns concatenated strings, or an error if the concatenation buffer is too small. -pub fn concatenate<'a>(strings: &[&str], output: &'a mut [u8]) -> Result<&'a str, ()> { - let mut offset = 0; - - for s in strings { - let s_len = s.len(); - if offset + s_len > output.len() { - return Err(()); - } - - output[offset..offset + s_len].copy_from_slice(s.as_bytes()); - offset += s_len; - } - - Ok(from_utf8(&output[..offset]).unwrap()) -} -use ledger_device_sdk::{ - ecc::{bip32_derive, CurvesId, CxError, Secret}, - io::SyscallError, -}; -use tari_crypto::hash_domain; - -use crate::{ - alloc::string::{String, ToString}, - hashing::DomainSeparatedConsensusHasher, -}; - -hash_domain!(LedgerHashDomain, "com.tari.minotari_ledger_wallet", 0); - /// Convert a u64 to a string without using the standard library pub fn u64_to_string(number: u64) -> String { let mut buffer = [0u8; 20]; // Maximum length for a 64-bit integer (including null terminator) @@ -124,13 +107,6 @@ pub fn u64_to_string(number: u64) -> String { String::from_utf8_lossy(&buffer[..pos]).to_string() } -/// Convert a single byte to a hex string -pub fn byte_to_hex(byte: u8) -> String { - const HEX_CHARS: [u8; 16] = *b"0123456789abcdef"; - let hex = [HEX_CHARS[(byte >> 4) as usize], HEX_CHARS[(byte & 0x0F) as usize]]; - String::from_utf8_lossy(&hex).to_string() -} - // Convert CxError to a string for display fn cx_error_to_string(e: CxError) -> String { let err = match e { @@ -166,34 +142,37 @@ fn cx_error_to_string(e: CxError) -> String { // d8a57c1be0c52e9643485e77aac56d72fa6c4eb831466c2abd2d320c82d3d14929811c598c13d431bad433e037dbd97265492cea42bc2e3aad15440210a20a2d0000000000000000000000000000000000000000000000000000000000000000 // - This function applies domain separated hashing to the 64 byte private key of the returned buffer to get 32 // uniformly distributed random bytes. -fn get_raw_key_hash(path: &[u32]) -> Result<[u8; 64], String> { - let mut key = Secret::<96>::new(); - let raw_key_64 = match bip32_derive(CurvesId::Ed25519, path, key.as_mut(), None) { +fn get_raw_key_hash(path: &[u32]) -> Result, String> { + let mut key_buffer = Zeroizing::new([0u8; 96]); + const BIP32_KEY_LENGTH: usize = 64; + let raw_key_64 = match bip32_derive(CurvesId::Ed25519, path, key_buffer.as_mut(), Some(&mut [])) { Ok(_) => { - let binding = &key.as_ref()[..64]; - let raw_key_64: [u8; 64] = match binding.try_into() { - Ok(v) => v, - Err(_) => return Err("Err: get_raw_key".to_string()), - }; - raw_key_64 + let binding = &key_buffer.as_ref()[..BIP32_KEY_LENGTH]; + let mut key_bytes = Zeroizing::new([0u8; BIP32_KEY_LENGTH]); + // `copy_from_slice` will not panic as the length of the slice is equal to the length of the array + key_bytes.as_mut().copy_from_slice(binding); + key_bytes }, Err(e) => return Err(cx_error_to_string(e)), }; - Ok(DomainSeparatedConsensusHasher::::new("raw_key") - .chain(&raw_key_64) - .finalize()) + let mut raw_key_hashed = Zeroizing::new([0u8; 64]); + DomainSeparatedHasher::, LedgerHashDomain>::new_with_label("raw_key") + .chain(&raw_key_64.as_ref()) + .finalize_into(raw_key_hashed.as_mut().into()); + + Ok(raw_key_hashed) } /// Get a raw 32 byte key hash from the BIP32 path. In cas of an error, display an interactive message on the device. -pub fn get_raw_key(path: &[u32]) -> Result<[u8; 64], SyscallError> { +pub fn get_raw_key(path: &[u32]) -> Result, SyscallError> { match get_raw_key_hash(&path) { Ok(val) => Ok(val), - Err(_e) => { + Err(e) => { let mut msg = "".to_string(); msg.push_str("Err: raw key >>..."); - // ui::SingleMessage::new(&msg).show_and_wait(); - // ui::SingleMessage::new(&e).show(); + SingleMessage::new(&msg).show_and_wait(); + SingleMessage::new(&e).show_and_wait(); Err(SyscallError::InvalidParameter.into()) }, } From 9f831bbc7db34339e05f502ec7613fbfc516bc0d Mon Sep 17 00:00:00 2001 From: brianp Date: Wed, 10 Apr 2024 12:54:06 +0200 Subject: [PATCH 03/49] update payload to ledger script key generation --- .../src/transactions/key_manager/inner.rs | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index 94bbe955c2..e0e1b8b8b7 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -19,8 +19,6 @@ // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#[cfg(feature = "ledger")] -use std::sync::{Arc, Mutex}; use std::{collections::HashMap, ops::Shl}; use blake2::Blake2b; @@ -28,10 +26,8 @@ use digest::consts::U64; #[cfg(feature = "ledger")] use ledger_transport::APDUCommand; #[cfg(feature = "ledger")] -use ledger_transport_hid::TransportNativeHID; +use ledger_transport_hid::{hidapi::HidApi, TransportNativeHID}; use log::*; -#[cfg(feature = "ledger")] -use once_cell::sync::Lazy; use rand::rngs::OsRng; use strum::IntoEnumIterator; use tari_common_types::{ @@ -108,9 +104,6 @@ pub struct TransactionKeyManagerInner { wallet_type: WalletType, } -#[cfg(feature = "ledger")] -pub static TRANSPORT: Lazy>>> = Lazy::new(|| Arc::new(Mutex::new(None))); - impl TransactionKeyManagerInner where TBackend: KeyManagerBackend + 'static { @@ -446,24 +439,28 @@ where TBackend: KeyManagerBackend + 'static // ----------------------------------------------------------------------------------------------------------------- pub async fn get_script_private_key(&self, script_key_id: &TariKeyId) -> Result { + let k = self.get_private_key(script_key_id).await.map_err(|e| e.into()); match self.wallet_type { - WalletType::Software => self.get_private_key(script_key_id).await.map_err(|e| e.into()), - WalletType::Ledger(_account) => { + WalletType::Software => k, + WalletType::Ledger(account) => { #[cfg(not(feature = "ledger"))] return Err(TransactionError::LedgerDeviceError(LedgerDeviceError::NotSupported)); #[cfg(feature = "ledger")] { - let data = script_key_id.managed_index().expect("and index").to_le_bytes().to_vec(); + let transport = TransportNativeHID::new(&HidApi::new().expect("Ledger not attached")) + .map_err(|e| LedgerDeviceError::HidApi(e.to_string()))?; + + let mut data = (account as u64).to_le_bytes().to_vec(); + data.extend_from_slice(k?.as_bytes()); // Static index. Fix this. let command = APDUCommand { cla: 0x80, - ins: 0x02, // GetPrivateKey - see `./applications/mp_ledger/src/main.rs/Instruction` + ins: 0x03, p1: 0x00, p2: 0x00, data, }; - let binding = TRANSPORT.lock().expect("lock exists"); - let transport = binding.as_ref().expect("transport exists"); + match transport.exchange(&command) { Ok(result) => { if result.data().len() < 33 { From 1f3ebc4303961a26f02847f440c84145ab626a28 Mon Sep 17 00:00:00 2001 From: brianp Date: Wed, 10 Apr 2024 14:20:48 +0200 Subject: [PATCH 04/49] Only use ledger for outputs that have managed keys --- base_layer/core/src/transactions/key_manager/inner.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index e0e1b8b8b7..160d7ed265 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -439,10 +439,11 @@ where TBackend: KeyManagerBackend + 'static // ----------------------------------------------------------------------------------------------------------------- pub async fn get_script_private_key(&self, script_key_id: &TariKeyId) -> Result { - let k = self.get_private_key(script_key_id).await.map_err(|e| e.into()); - match self.wallet_type { - WalletType::Software => k, - WalletType::Ledger(account) => { + match (self.wallet_type, script_key_id) { + (WalletType::Software, _) | (WalletType::Ledger(_), TariKeyId::Imported { .. } | TariKeyId::Zero) => { + self.get_private_key(script_key_id).await.map_err(|e| e.into()) + }, + (WalletType::Ledger(account), TariKeyId::Managed { branch: _, index }) => { #[cfg(not(feature = "ledger"))] return Err(TransactionError::LedgerDeviceError(LedgerDeviceError::NotSupported)); @@ -452,7 +453,7 @@ where TBackend: KeyManagerBackend + 'static .map_err(|e| LedgerDeviceError::HidApi(e.to_string()))?; let mut data = (account as u64).to_le_bytes().to_vec(); - data.extend_from_slice(k?.as_bytes()); // Static index. Fix this. + data.extend_from_slice(&index.to_le_bytes()); // Static index. Fix this. let command = APDUCommand { cla: 0x80, ins: 0x03, From 36418e528ec45d258467729cb472f1f4c9773f96 Mon Sep 17 00:00:00 2001 From: brianp Date: Fri, 19 Apr 2024 12:18:57 +0200 Subject: [PATCH 05/49] Moved ledger device app to new folder --- .../minotari_ledger_wallet/app_nanosplus.json | 18 ------------------ .../{ => wallet}/.cargo/config.toml | 2 +- .../{ => wallet}/.gitignore | 0 .../{ => wallet}/Cargo.lock | 0 .../{ => wallet}/Cargo.toml | 0 .../{ => wallet}/README.md | 0 .../{ => wallet}/build.rs | 0 .../{ => wallet}/key.gif | Bin .../{ => wallet}/key_14x14.gif | Bin .../{ => wallet}/ledger_app.toml | 0 .../{ => wallet}/rust-toolchain.toml | 0 .../{ => wallet}/src/app_ui/menu.rs | 0 .../src/handlers/get_private_key.rs | 0 .../{ => wallet}/src/handlers/get_version.rs | 0 .../{ => wallet}/src/main.rs | 0 .../{ => wallet}/src/utils.rs | 0 16 files changed, 1 insertion(+), 19 deletions(-) delete mode 100644 applications/minotari_ledger_wallet/app_nanosplus.json rename applications/minotari_ledger_wallet/{ => wallet}/.cargo/config.toml (87%) rename applications/minotari_ledger_wallet/{ => wallet}/.gitignore (100%) rename applications/minotari_ledger_wallet/{ => wallet}/Cargo.lock (100%) rename applications/minotari_ledger_wallet/{ => wallet}/Cargo.toml (100%) rename applications/minotari_ledger_wallet/{ => wallet}/README.md (100%) rename applications/minotari_ledger_wallet/{ => wallet}/build.rs (100%) rename applications/minotari_ledger_wallet/{ => wallet}/key.gif (100%) rename applications/minotari_ledger_wallet/{ => wallet}/key_14x14.gif (100%) rename applications/minotari_ledger_wallet/{ => wallet}/ledger_app.toml (100%) rename applications/minotari_ledger_wallet/{ => wallet}/rust-toolchain.toml (100%) rename applications/minotari_ledger_wallet/{ => wallet}/src/app_ui/menu.rs (100%) rename applications/minotari_ledger_wallet/{ => wallet}/src/handlers/get_private_key.rs (100%) rename applications/minotari_ledger_wallet/{ => wallet}/src/handlers/get_version.rs (100%) rename applications/minotari_ledger_wallet/{ => wallet}/src/main.rs (100%) rename applications/minotari_ledger_wallet/{ => wallet}/src/utils.rs (100%) diff --git a/applications/minotari_ledger_wallet/app_nanosplus.json b/applications/minotari_ledger_wallet/app_nanosplus.json deleted file mode 100644 index 91a9fc124b..0000000000 --- a/applications/minotari_ledger_wallet/app_nanosplus.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "apiLevel": "5", - "binary": "target/nanosplus/release/app.hex", - "dataSize": 6144, - "derivationPath": { - "curves": [ - "ed25519" - ], - "paths": [ - "44'/535348'" - ] - }, - "flags": "0", - "icon": "key_14x14.gif", - "name": "MinoTari Wallet", - "targetId": "0x33100004", - "version": "1.0.0-pre.11a" -} \ No newline at end of file diff --git a/applications/minotari_ledger_wallet/.cargo/config.toml b/applications/minotari_ledger_wallet/wallet/.cargo/config.toml similarity index 87% rename from applications/minotari_ledger_wallet/.cargo/config.toml rename to applications/minotari_ledger_wallet/wallet/.cargo/config.toml index 9884d86c67..d8db64960b 100644 --- a/applications/minotari_ledger_wallet/.cargo/config.toml +++ b/applications/minotari_ledger_wallet/wallet/.cargo/config.toml @@ -6,7 +6,7 @@ target = "nanosplus" [unstable] avoid-dev-deps = true -build-std = ["std", "alloc"] +build-std = ["core", "std", "alloc"] build-std-features = ["compiler-builtins-mem"] host-config = true target-applies-to-host = true diff --git a/applications/minotari_ledger_wallet/.gitignore b/applications/minotari_ledger_wallet/wallet/.gitignore similarity index 100% rename from applications/minotari_ledger_wallet/.gitignore rename to applications/minotari_ledger_wallet/wallet/.gitignore diff --git a/applications/minotari_ledger_wallet/Cargo.lock b/applications/minotari_ledger_wallet/wallet/Cargo.lock similarity index 100% rename from applications/minotari_ledger_wallet/Cargo.lock rename to applications/minotari_ledger_wallet/wallet/Cargo.lock diff --git a/applications/minotari_ledger_wallet/Cargo.toml b/applications/minotari_ledger_wallet/wallet/Cargo.toml similarity index 100% rename from applications/minotari_ledger_wallet/Cargo.toml rename to applications/minotari_ledger_wallet/wallet/Cargo.toml diff --git a/applications/minotari_ledger_wallet/README.md b/applications/minotari_ledger_wallet/wallet/README.md similarity index 100% rename from applications/minotari_ledger_wallet/README.md rename to applications/minotari_ledger_wallet/wallet/README.md diff --git a/applications/minotari_ledger_wallet/build.rs b/applications/minotari_ledger_wallet/wallet/build.rs similarity index 100% rename from applications/minotari_ledger_wallet/build.rs rename to applications/minotari_ledger_wallet/wallet/build.rs diff --git a/applications/minotari_ledger_wallet/key.gif b/applications/minotari_ledger_wallet/wallet/key.gif similarity index 100% rename from applications/minotari_ledger_wallet/key.gif rename to applications/minotari_ledger_wallet/wallet/key.gif diff --git a/applications/minotari_ledger_wallet/key_14x14.gif b/applications/minotari_ledger_wallet/wallet/key_14x14.gif similarity index 100% rename from applications/minotari_ledger_wallet/key_14x14.gif rename to applications/minotari_ledger_wallet/wallet/key_14x14.gif diff --git a/applications/minotari_ledger_wallet/ledger_app.toml b/applications/minotari_ledger_wallet/wallet/ledger_app.toml similarity index 100% rename from applications/minotari_ledger_wallet/ledger_app.toml rename to applications/minotari_ledger_wallet/wallet/ledger_app.toml diff --git a/applications/minotari_ledger_wallet/rust-toolchain.toml b/applications/minotari_ledger_wallet/wallet/rust-toolchain.toml similarity index 100% rename from applications/minotari_ledger_wallet/rust-toolchain.toml rename to applications/minotari_ledger_wallet/wallet/rust-toolchain.toml diff --git a/applications/minotari_ledger_wallet/src/app_ui/menu.rs b/applications/minotari_ledger_wallet/wallet/src/app_ui/menu.rs similarity index 100% rename from applications/minotari_ledger_wallet/src/app_ui/menu.rs rename to applications/minotari_ledger_wallet/wallet/src/app_ui/menu.rs diff --git a/applications/minotari_ledger_wallet/src/handlers/get_private_key.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_private_key.rs similarity index 100% rename from applications/minotari_ledger_wallet/src/handlers/get_private_key.rs rename to applications/minotari_ledger_wallet/wallet/src/handlers/get_private_key.rs diff --git a/applications/minotari_ledger_wallet/src/handlers/get_version.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_version.rs similarity index 100% rename from applications/minotari_ledger_wallet/src/handlers/get_version.rs rename to applications/minotari_ledger_wallet/wallet/src/handlers/get_version.rs diff --git a/applications/minotari_ledger_wallet/src/main.rs b/applications/minotari_ledger_wallet/wallet/src/main.rs similarity index 100% rename from applications/minotari_ledger_wallet/src/main.rs rename to applications/minotari_ledger_wallet/wallet/src/main.rs diff --git a/applications/minotari_ledger_wallet/src/utils.rs b/applications/minotari_ledger_wallet/wallet/src/utils.rs similarity index 100% rename from applications/minotari_ledger_wallet/src/utils.rs rename to applications/minotari_ledger_wallet/wallet/src/utils.rs From 946e38f587538161ee9775e6910fbb74afe0c4c8 Mon Sep 17 00:00:00 2001 From: brianp Date: Fri, 19 Apr 2024 12:19:52 +0200 Subject: [PATCH 06/49] Add ledger interface library --- .../minotari_ledger_wallet/comms/Cargo.toml | 17 +++ .../minotari_ledger_wallet/comms/src/error.rs | 57 +++++++++ .../comms/src/ledger_wallet.rs | 115 ++++++++++++++++++ .../minotari_ledger_wallet/comms/src/lib.rs | 24 ++++ 4 files changed, 213 insertions(+) create mode 100644 applications/minotari_ledger_wallet/comms/Cargo.toml create mode 100644 applications/minotari_ledger_wallet/comms/src/error.rs create mode 100644 applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs create mode 100644 applications/minotari_ledger_wallet/comms/src/lib.rs diff --git a/applications/minotari_ledger_wallet/comms/Cargo.toml b/applications/minotari_ledger_wallet/comms/Cargo.toml new file mode 100644 index 0000000000..c6afaddc6a --- /dev/null +++ b/applications/minotari_ledger_wallet/comms/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "minotari_ledger_wallet_comms" +version = "1.0.0-pre.11a" +authors = ["The Tari Development Community"] +license = "BSD-3-Clause" +edition = "2021" + +[dependencies] +tari_crypto = { version = "0.20.0", default-features = false } + +ledger-transport = { git = "https://github.com/Zondax/ledger-rs", rev = "20e2a20" } +ledger-transport-hid = { git = "https://github.com/Zondax/ledger-rs", rev = "20e2a20" } +log = "0.4.20" +num-derive = "0.3.3" +num-traits = "0.2.15" +serde = { version = "1.0.106", features = ["derive"] } +thiserror = "1.0.26" \ No newline at end of file diff --git a/applications/minotari_ledger_wallet/comms/src/error.rs b/applications/minotari_ledger_wallet/comms/src/error.rs new file mode 100644 index 0000000000..c9afc2e03f --- /dev/null +++ b/applications/minotari_ledger_wallet/comms/src/error.rs @@ -0,0 +1,57 @@ +// Copyright 2024 The Tari Project +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +// following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +// disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +// following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote +// products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +use serde::{Deserialize, Serialize}; +use tari_crypto::tari_utilities::ByteArrayError; +use thiserror::Error; + +/// Ledger device errors. +#[derive(Debug, Error, Clone, PartialEq, Eq, Deserialize, Serialize)] +pub enum LedgerDeviceError { + /// HID API error + #[error("HID API error `{0}`")] + HidApi(String), + /// Native HID transport error + #[error("Native HID transport error `{0}`")] + NativeTransport(String), + /// Ledger application not started + #[error("Ledger application not started")] + ApplicationNotStarted, + /// Ledger application instruction error + #[error("Ledger application instruction error `{0}`")] + Instruction(String), + /// Ledger application processing error + #[error("Processing error `{0}`")] + Processing(String), + /// Conversion error to or from ledger + #[error("Conversion failed: {0}")] + ByteArrayError(String), + /// Not yet supported + #[error("Ledger is not fully supported")] + NotSupported, +} + +impl From for LedgerDeviceError { + fn from(e: ByteArrayError) -> Self { + LedgerDeviceError::ByteArrayError(e.to_string()) + } +} diff --git a/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs b/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs new file mode 100644 index 0000000000..3452986e80 --- /dev/null +++ b/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs @@ -0,0 +1,115 @@ +// Copyright 2024 The Tari Project +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +// following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +// disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +// following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote +// products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +use std::{ + fmt, + fmt::{Display, Formatter}, + ops::Deref, +}; + +use ledger_transport::{APDUAnswer, APDUCommand}; +use ledger_transport_hid::{hidapi::HidApi, TransportNativeHID}; +use num_derive::FromPrimitive; +use num_traits::FromPrimitive; +use serde::{Deserialize, Serialize}; +use tari_crypto::ristretto::RistrettoPublicKey; + +use crate::error::LedgerDeviceError; + +const WALLET_CLA: u8 = 0x80; +// const LOG_TARGET: &str = "wallet::ledger_wallet::comms"; + +#[repr(u8)] +#[derive(FromPrimitive, Debug, Copy, Clone, PartialEq)] +pub enum Instruction { + GetVersion = 0x01, + GetAppName = 0x02, + GetPrivateKey = 0x03, + GetPublicKey = 0x04, +} + +impl Instruction { + pub fn as_byte(self) -> u8 { + self as u8 + } + + pub fn from_byte(value: u8) -> Option { + FromPrimitive::from_u8(value) + } +} + +pub fn get_transport() -> Result { + let hid = HidApi::new().map_err(|e| LedgerDeviceError::HidApi(e.to_string()))?; + TransportNativeHID::new(&hid).map_err(|e| LedgerDeviceError::NativeTransport(e.to_string())) +} + +#[derive(Debug, Clone)] +pub struct Command { + inner: APDUCommand, +} + +impl> Command { + pub fn execute(&self) -> Result>, LedgerDeviceError> { + get_transport()? + .exchange(&self.inner) + .map_err(|e| LedgerDeviceError::NativeTransport(e.to_string())) + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct LedgerWallet { + account: u64, + pubkey: Option, +} + +impl Display for LedgerWallet { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "account {}", self.account)?; + write!(f, "pubkey {}", self.pubkey.is_some())?; + Ok(()) + } +} + +impl LedgerWallet { + pub fn new(account: u64, pubkey: Option) -> Self { + Self { account, pubkey } + } + + pub fn account_bytes(&self) -> Vec { + self.account.to_le_bytes().to_vec() + } + + pub fn build_command(&self, instruction: Instruction, data: Vec) -> Command> { + let mut base_data = self.account_bytes(); + base_data.extend_from_slice(&data); + + Command { + inner: APDUCommand { + cla: WALLET_CLA, + ins: instruction.as_byte(), + p1: 0x00, + p2: 0x00, + data: base_data, + }, + } + } +} diff --git a/applications/minotari_ledger_wallet/comms/src/lib.rs b/applications/minotari_ledger_wallet/comms/src/lib.rs new file mode 100644 index 0000000000..a14b091c78 --- /dev/null +++ b/applications/minotari_ledger_wallet/comms/src/lib.rs @@ -0,0 +1,24 @@ +// Copyright 2024 The Tari Project +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +// following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +// disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +// following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote +// products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +pub mod error; +pub mod ledger_wallet; From 860a1d2d086312526878b3ebe5f6811c42c6bcb7 Mon Sep 17 00:00:00 2001 From: brianp Date: Fri, 19 Apr 2024 12:21:13 +0200 Subject: [PATCH 07/49] Add public key function to ledger --- .../minotari_ledger_wallet/wallet/.gitignore | 2 +- .../wallet/src/handlers/get_private_key.rs | 5 +- .../wallet/src/handlers/get_public_key.rs | 63 +++++++++++++++++++ .../minotari_ledger_wallet/wallet/src/main.rs | 21 +++++-- 4 files changed, 82 insertions(+), 9 deletions(-) create mode 100644 applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs diff --git a/applications/minotari_ledger_wallet/wallet/.gitignore b/applications/minotari_ledger_wallet/wallet/.gitignore index 3735321888..2e4f43b784 100644 --- a/applications/minotari_ledger_wallet/wallet/.gitignore +++ b/applications/minotari_ledger_wallet/wallet/.gitignore @@ -1,4 +1,4 @@ -target +../target app.json app_nanos.json app_nanosplus.json diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_private_key.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_private_key.rs index 2878285861..7ff030e610 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_private_key.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_private_key.rs @@ -10,10 +10,9 @@ use crate::{ alloc::string::ToString, utils::{get_raw_key, u64_to_string}, AppSW, + BIP32_COIN_TYPE, }; -static MINOTARI_BIP32_COIN_TYPE: u32 = 535348; - pub fn handler_get_private_key(comm: &mut Comm) -> Result<(), AppSW> { let data = comm.get_data().map_err(|_| AppSW::WrongApduLength)?; @@ -26,7 +25,7 @@ pub fn handler_get_private_key(comm: &mut Comm) -> Result<(), AppSW> { let address_index = u64_to_string(u64::from_le_bytes(address_index_bytes)); let mut bip32_path = "m/44'/".to_string(); - bip32_path.push_str(&MINOTARI_BIP32_COIN_TYPE.to_string()); + bip32_path.push_str(&BIP32_COIN_TYPE.to_string()); bip32_path.push_str(&"'/"); bip32_path.push_str(&account); bip32_path.push_str(&"'/0/"); diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs new file mode 100644 index 0000000000..97ce579250 --- /dev/null +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs @@ -0,0 +1,63 @@ +// Copyright 2024 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use alloc::format; + +use ledger_device_sdk::{ecc::make_bip32_path, io::Comm, ui::gadgets::SingleMessage}; +use tari_crypto::{ + keys::{PublicKey, SecretKey}, + ristretto::{RistrettoPublicKey, RistrettoSecretKey}, + tari_utilities::ByteArray, +}; + +use crate::{ + alloc::string::ToString, + utils::{get_raw_key, u64_to_string}, + AppSW, + BIP32_COIN_TYPE, +}; + +const STATIC_INDEX: &str = "42"; + +pub fn handler_get_public_key(comm: &mut Comm) -> Result<(), AppSW> { + let data = comm.get_data().map_err(|_| AppSW::WrongApduLength)?; + + let mut account_bytes = [0u8; 8]; + account_bytes.clone_from_slice(&data[0..8]); + let account = u64_to_string(u64::from_le_bytes(account_bytes)); + + let mut bip32_path = "m/44'/".to_string(); + bip32_path.push_str(&BIP32_COIN_TYPE.to_string()); + bip32_path.push_str(&"'/"); + bip32_path.push_str(&account); + bip32_path.push_str(&"'/0/"); + bip32_path.push_str(STATIC_INDEX); + let path: [u32; 5] = make_bip32_path(bip32_path.as_bytes()); + + let raw_key = match get_raw_key(&path) { + Ok(val) => val, + Err(e) => { + SingleMessage::new(&format!("Key error {:?}", e)).show_and_wait(); + return Err(AppSW::KeyDeriveFail); + }, + }; + + let pk = match RistrettoSecretKey::from_uniform_bytes(&raw_key.as_ref()) { + Ok(k) => RistrettoPublicKey::from_secret_key(&k), + Err(e) => { + SingleMessage::new(&format!( + "Err: key conversion {:?}. Length: {:?}", + e.to_string(), + &raw_key.len() + )) + .show(); + return Err(AppSW::KeyDeriveFail); + }, + }; + + comm.append(&[1]); // version + comm.append(pk.as_bytes()); + comm.reply_ok(); + + Ok(()) +} diff --git a/applications/minotari_ledger_wallet/wallet/src/main.rs b/applications/minotari_ledger_wallet/wallet/src/main.rs index fad9b21436..600259b360 100644 --- a/applications/minotari_ledger_wallet/wallet/src/main.rs +++ b/applications/minotari_ledger_wallet/wallet/src/main.rs @@ -14,6 +14,7 @@ mod app_ui { } mod handlers { pub mod get_private_key; + pub mod get_public_key; pub mod get_version; } @@ -21,7 +22,11 @@ use core::mem::MaybeUninit; use app_ui::menu::ui_menu_main; use critical_section::RawRestoreState; -use handlers::{get_private_key::handler_get_private_key, get_version::handler_get_version}; +use handlers::{ + get_private_key::handler_get_private_key, + get_public_key::handler_get_public_key, + get_version::handler_get_version, +}; #[cfg(feature = "pending_review_screen")] use ledger_device_sdk::ui::gadgets::display_pending_review; use ledger_device_sdk::{ @@ -31,6 +36,9 @@ use ledger_device_sdk::{ ledger_device_sdk::set_panic!(ledger_device_sdk::exiting_panic); +static BIP32_COIN_TYPE: u32 = 535348; +static CLA: u8 = 0x80; + /// Allocator heap size const HEAP_SIZE: usize = 1024 * 26; @@ -95,6 +103,7 @@ pub enum Instruction { GetVersion, GetAppName, GetPrivateKey, + GetPublicKey, } impl TryFrom for Instruction { @@ -116,7 +125,8 @@ impl TryFrom for Instruction { (1, 0, 0) => Ok(Instruction::GetVersion), (2, 0, 0) => Ok(Instruction::GetAppName), (3, 0, 0) => Ok(Instruction::GetPrivateKey), - (3..=6, _, _) => Err(AppSW::WrongP1P2), + (4, 0, 0) => Ok(Instruction::GetPublicKey), + (3..=4, _, _) => Err(AppSW::WrongP1P2), (_, _, _) => Err(AppSW::InsNotSupported), } } @@ -125,10 +135,10 @@ impl TryFrom for Instruction { #[no_mangle] extern "C" fn sample_main() { init(); - // Create the communication manager, and configure it to accept only APDU from the 0xe0 class. + // Create the communication manager, and configure it to accept only APDU from the 0x80 class. // If any APDU with a wrong class value is received, comm will respond automatically with // BadCla status word. - let mut comm = Comm::new().set_expected_cla(0x80); + let mut comm = Comm::new().set_expected_cla(CLA); // Developer mode / pending review popup // must be cleared with user interaction @@ -149,11 +159,12 @@ extern "C" fn sample_main() { fn handle_apdu(comm: &mut Comm, ins: Instruction) -> Result<(), AppSW> { match ins { + Instruction::GetVersion => handler_get_version(comm), Instruction::GetAppName => { comm.append(env!("CARGO_PKG_NAME").as_bytes()); Ok(()) }, Instruction::GetPrivateKey => handler_get_private_key(comm), - Instruction::GetVersion => handler_get_version(comm), + Instruction::GetPublicKey => handler_get_public_key(comm), } } From 2b0b10d9d7a447d18dbbf50ce3a8cee784d712c9 Mon Sep 17 00:00:00 2001 From: brianp Date: Fri, 19 Apr 2024 12:22:59 +0200 Subject: [PATCH 08/49] fetch the script key pair for derivation --- Cargo.lock | 17 ++++++ Cargo.toml | 1 + .../minotari_console_wallet/Cargo.toml | 3 +- .../minotari_console_wallet/src/init/mod.rs | 52 ++++++++++++++----- base_layer/common_types/Cargo.toml | 5 +- base_layer/common_types/src/wallet_types.rs | 23 ++++++-- base_layer/core/Cargo.toml | 2 + .../src/transactions/key_manager/error.rs | 34 ------------ .../transactions/key_manager/initializer.rs | 2 +- .../src/transactions/key_manager/inner.rs | 34 ++++-------- .../key_manager/memory_db_key_manager.rs | 3 +- .../core/src/transactions/key_manager/mod.rs | 2 +- .../transaction_components/error.rs | 3 +- base_layer/wallet/src/wallet.rs | 4 +- .../transaction_service_tests/service.rs | 2 +- base_layer/wallet_ffi/src/lib.rs | 2 +- 16 files changed, 104 insertions(+), 85 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 881a2bb948..6928f13115 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3296,6 +3296,7 @@ dependencies = [ "log4rs", "minotari_app_grpc", "minotari_app_utilities", + "minotari_ledger_wallet_comms", "minotari_wallet", "qrcode", "rand", @@ -3334,6 +3335,20 @@ dependencies = [ "zxcvbn", ] +[[package]] +name = "minotari_ledger_wallet_comms" +version = "1.0.0-pre.11a" +dependencies = [ + "ledger-transport 0.10.0 (git+https://github.com/Zondax/ledger-rs?rev=20e2a20)", + "ledger-transport-hid", + "log", + "num-derive 0.3.3", + "num-traits", + "serde", + "tari_crypto", + "thiserror", +] + [[package]] name = "minotari_merge_mining_proxy" version = "1.0.0-pre.13" @@ -6009,6 +6024,7 @@ dependencies = [ "borsh", "chacha20poly1305", "digest 0.10.7", + "minotari_ledger_wallet_comms", "newtype-ops", "once_cell", "primitive-types", @@ -6191,6 +6207,7 @@ dependencies = [ "lmdb-zero", "log", "log-mdc", + "minotari_ledger_wallet_comms", "monero", "newtype-ops", "num-derive 0.3.3", diff --git a/Cargo.toml b/Cargo.toml index 705ad4cfd0..4cd0e63af4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ members = [ "applications/minotari_app_utilities", "applications/minotari_merge_mining_proxy", "applications/minotari_miner", + "applications/minotari_ledger_wallet/comms", "integration_tests", "hashing", ] diff --git a/applications/minotari_console_wallet/Cargo.toml b/applications/minotari_console_wallet/Cargo.toml index b6a417e75a..5ecd6d6ef6 100644 --- a/applications/minotari_console_wallet/Cargo.toml +++ b/applications/minotari_console_wallet/Cargo.toml @@ -8,6 +8,7 @@ license = "BSD-3-Clause" [dependencies] minotari_app_grpc = { path = "../minotari_app_grpc" } minotari_app_utilities = { path = "../minotari_app_utilities" } +minotari_ledger_wallet_comms = { path = "../../applications/minotari_ledger_wallet/comms", version = "1.0.0-pre.11a", optional = true } tari_common = { path = "../../common" } tari_common_types = { path = "../../base_layer/common_types" } tari_comms = { path = "../../comms/core" } @@ -88,7 +89,7 @@ tari_features = { path = "../../common/tari_features", version = "1.0.0-pre.13" [features] default = ["libtor"] grpc = [] -ledger = ["ledger-transport-hid"] +ledger = ["ledger-transport-hid", "minotari_ledger_wallet_comms"] libtor = ["tari_libtor"] [package.metadata.cargo-machete] diff --git a/applications/minotari_console_wallet/src/init/mod.rs b/applications/minotari_console_wallet/src/init/mod.rs index 749345b82f..5ed8c97904 100644 --- a/applications/minotari_console_wallet/src/init/mod.rs +++ b/applications/minotari_console_wallet/src/init/mod.rs @@ -28,6 +28,10 @@ use std::{fs, io, path::PathBuf, str::FromStr, sync::Arc, time::Instant}; use ledger_transport_hid::{hidapi::HidApi, TransportNativeHID}; use log::*; use minotari_app_utilities::{consts, identity_management::setup_node_identity}; +use minotari_ledger_wallet_comms::{ + error::LedgerDeviceError, + ledger_wallet::{get_transport, Instruction, LedgerWallet}, +}; use minotari_wallet::{ error::{WalletError, WalletStorageError}, output_manager_service::storage::database::OutputManagerDatabase, @@ -50,15 +54,18 @@ use tari_common::{ }, exit_codes::{ExitCode, ExitError}, }; -use tari_common_types::wallet_types::WalletType; +use tari_common_types::{types::PrivateKey, wallet_types::WalletType}; use tari_comms::{ multiaddr::Multiaddr, peer_manager::{Peer, PeerFeatures, PeerQuery}, types::CommsPublicKey, NodeIdentity, }; -use tari_core::{consensus::ConsensusManager, transactions::CryptoFactories}; -use tari_crypto::keys::PublicKey; +use tari_core::{ + consensus::ConsensusManager, + transactions::{transaction_components::TransactionError, CryptoFactories}, +}; +use tari_crypto::{keys::PublicKey, ristretto::RistrettoPublicKey}; use tari_key_manager::{cipher_seed::CipherSeed, mnemonic::MnemonicLanguage}; use tari_p2p::{peer_seeds::SeedPeer, TransportType}; use tari_shutdown::ShutdownSignal; @@ -818,11 +825,11 @@ pub fn prompt_wallet_type( non_interactive: bool, ) -> Option { if non_interactive { - return Some(WalletType::Software); + return Some(WalletType::default()); } if wallet_config.wallet_type.is_some() { - return wallet_config.wallet_type; + return wallet_config.wallet_type.clone(); } match boot_mode { @@ -834,18 +841,39 @@ pub fn prompt_wallet_type( { if prompt("\r\nWould you like to use a connected hardware wallet? (Supported types: Ledger)") { print!("Scanning for connected Ledger hardware device... "); - let err = "No connected device was found. Please make sure the device is plugged in before - continuing."; - match TransportNativeHID::new(&HidApi::new().expect(err)) { - Ok(_) => { + match get_transport() { + Ok(hid) => { + drop(hid); // Need to release it before we reuse it. println!("Device found."); let account = prompt_ledger_account().expect("An account value"); - Some(WalletType::Ledger(account)) + let ledger = LedgerWallet::new(account, None); + match ledger.build_command(Instruction::GetPublicKey, vec![]).execute() { + Ok(result) => { + debug!(target: LOG_TARGET, "result length: {}, data: {:?}", result.data().len(), result.data()); + if result.data().len() < 33 { + debug!(target: LOG_TARGET, "result less than 33"); + panic!( + "'get_public_key' insufficient data - expected 33 got {} bytes ({:?})", + result.data().len(), + result + ); + } + + let key = match RistrettoPublicKey::from_canonical_bytes(&result.data()[1..33]) { + Ok(k) => k, + Err(e) => panic!("{}", e), + }; + + let ledger = LedgerWallet::new(account, Some(key)); + Some(WalletType::Ledger(ledger)) + }, + Err(e) => panic!("{}", e), + } }, Err(e) => panic!("{}", e), } } else { - Some(WalletType::Software) + Some(WalletType::default()) } } }, @@ -853,7 +881,7 @@ pub fn prompt_wallet_type( } } -pub fn prompt_ledger_account() -> Option { +pub fn prompt_ledger_account() -> Option { let question = "\r\nPlease enter an account number for your ledger. A simple 1-9, easily remembered numbers are suggested."; println!("{}", question); diff --git a/base_layer/common_types/Cargo.toml b/base_layer/common_types/Cargo.toml index d3c902b98e..507cffcb7a 100644 --- a/base_layer/common_types/Cargo.toml +++ b/base_layer/common_types/Cargo.toml @@ -7,11 +7,11 @@ version = "1.0.0-pre.13" edition = "2018" [dependencies] +minotari_ledger_wallet_comms = { path = "../../applications/minotari_ledger_wallet/comms", version = "1.0.0-pre.11a", optional = true } tari_crypto = { version = "0.20" } tari_utilities = { version = "0.7" } tari_common = { path = "../../common", version = "1.0.0-pre.13" } - chacha20poly1305 = "0.10.1" borsh = "1.2" digest = "0.10" @@ -26,5 +26,8 @@ base64 = "0.21.0" blake2 = "0.10" primitive-types = { version = "0.12", features = ["serde"] } +[features] +ledger = ["minotari_ledger_wallet_comms"] + [package.metadata.cargo-machete] ignored = ["strum", "strum_macros"] # this is so we can run cargo machete without getting false positive about macro dependancies diff --git a/base_layer/common_types/src/wallet_types.rs b/base_layer/common_types/src/wallet_types.rs index 052df957ea..729dcb3de7 100644 --- a/base_layer/common_types/src/wallet_types.rs +++ b/base_layer/common_types/src/wallet_types.rs @@ -25,20 +25,33 @@ use std::{ fmt::{Display, Formatter}, }; +use chacha20poly1305::aead::OsRng; +use minotari_ledger_wallet_comms::ledger_wallet::LedgerWallet; use serde::{Deserialize, Serialize}; -use strum_macros::EnumString; +use tari_crypto::{ + keys::{PublicKey, SecretKey}, + ristretto::{RistrettoPublicKey, RistrettoSecretKey}, +}; +use tari_utilities::ByteArray; -#[derive(Debug, EnumString, Clone, Copy, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub enum WalletType { - Software, - Ledger(usize), + Software(Vec, Vec), // Make them a priv and pub + Ledger(LedgerWallet), } impl Display for WalletType { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { - WalletType::Software => write!(f, "Software"), + WalletType::Software(pk, _k) => write!(f, "Software({:?})", pk), WalletType::Ledger(account) => write!(f, "Ledger({account})"), } } } + +impl Default for WalletType { + fn default() -> Self { + let k = RistrettoSecretKey::random(&mut OsRng); + WalletType::Software(RistrettoPublicKey::from_secret_key(&k).to_vec(), k.to_vec()) + } +} diff --git a/base_layer/core/Cargo.toml b/base_layer/core/Cargo.toml index df92d1f0d6..a21ac8f301 100644 --- a/base_layer/core/Cargo.toml +++ b/base_layer/core/Cargo.toml @@ -24,12 +24,14 @@ base_node = [ base_node_proto = [] benches = ["base_node"] ledger = [ + "minotari_ledger_wallet_comms", "ledger-transport", "ledger-transport-hid" ] metrics = ["tari_metrics"] [dependencies] +minotari_ledger_wallet_comms = { path = "../../applications/minotari_ledger_wallet/comms", version = "1.0.0-pre.11a", optional = true } tari_common = { path = "../../common", version = "1.0.0-pre.13" } tari_common_types = { path = "../../base_layer/common_types", version = "1.0.0-pre.13" } tari_comms = { path = "../../comms/core", version = "1.0.0-pre.13" } diff --git a/base_layer/core/src/transactions/key_manager/error.rs b/base_layer/core/src/transactions/key_manager/error.rs index c26a7f618d..ef92873c28 100644 --- a/base_layer/core/src/transactions/key_manager/error.rs +++ b/base_layer/core/src/transactions/key_manager/error.rs @@ -20,10 +20,8 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -use serde::{Deserialize, Serialize}; use tari_crypto::signatures::CommitmentAndPublicKeySignatureError; use tari_key_manager::error::KeyManagerError; -use tari_utilities::ByteArrayError; use thiserror::Error; use crate::transactions::transaction_components::TransactionError; @@ -43,35 +41,3 @@ impl From for CoreKeyManagerError { CoreKeyManagerError::CommitmentAndPublicKeySignatureError(err.to_string()) } } - -/// Ledger device errors. -#[derive(Debug, PartialEq, Error, Deserialize, Serialize, Clone, Eq)] -pub enum LedgerDeviceError { - /// HID API error - #[error("HID API error `{0}`")] - HidApi(String), - /// Native HID transport error - #[error("Native HID transport error `{0}`")] - NativeTransport(String), - /// Ledger application not started - #[error("Ledger application not started")] - ApplicationNotStarted, - /// Ledger application instruction error - #[error("Ledger application instruction error `{0}`")] - Instruction(String), - /// Ledger application processing error - #[error("Processing error `{0}`")] - Processing(String), - /// Conversion error to or from ledger - #[error("Conversion failed: {0}")] - ByteArrayError(String), - /// Not yet supported - #[error("Ledger is not fully supported")] - NotSupported, -} - -impl From for LedgerDeviceError { - fn from(e: ByteArrayError) -> Self { - LedgerDeviceError::ByteArrayError(e.to_string()) - } -} diff --git a/base_layer/core/src/transactions/key_manager/initializer.rs b/base_layer/core/src/transactions/key_manager/initializer.rs index 55c6824cbe..3b2c4be68c 100644 --- a/base_layer/core/src/transactions/key_manager/initializer.rs +++ b/base_layer/core/src/transactions/key_manager/initializer.rs @@ -80,7 +80,7 @@ where T: KeyManagerBackend + 'static self.master_seed.clone(), KeyManagerDatabase::new(backend), self.crypto_factories.clone(), - self.wallet_type, + self.wallet_type.clone(), )?; context.register_handle(key_manager); diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index 160d7ed265..8330431529 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -23,11 +23,9 @@ use std::{collections::HashMap, ops::Shl}; use blake2::Blake2b; use digest::consts::U64; -#[cfg(feature = "ledger")] -use ledger_transport::APDUCommand; -#[cfg(feature = "ledger")] -use ledger_transport_hid::{hidapi::HidApi, TransportNativeHID}; use log::*; +#[cfg(feature = "ledger")] +use minotari_ledger_wallet_comms::{error::LedgerDeviceError, ledger_wallet::Instruction}; use rand::rngs::OsRng; use strum::IntoEnumIterator; use tari_common_types::{ @@ -61,7 +59,7 @@ use tari_key_manager::{ use tari_utilities::{hex::Hex, ByteArray}; use tokio::sync::RwLock; -const LOG_TARGET: &str = "key_manager::key_manager_service"; +const LOG_TARGET: &str = "c::bn::key_manager::key_manager_service"; const KEY_MANAGER_MAX_SEARCH_DEPTH: u64 = 1_000_000; use crate::{ @@ -70,7 +68,6 @@ use crate::{ transactions::{ key_manager::{ interface::{TransactionKeyManagerBranch, TxoStage}, - LedgerDeviceError, TariKeyId, }, tari_amount::MicroMinotari, @@ -439,32 +436,23 @@ where TBackend: KeyManagerBackend + 'static // ----------------------------------------------------------------------------------------------------------------- pub async fn get_script_private_key(&self, script_key_id: &TariKeyId) -> Result { - match (self.wallet_type, script_key_id) { - (WalletType::Software, _) | (WalletType::Ledger(_), TariKeyId::Imported { .. } | TariKeyId::Zero) => { + match (&self.wallet_type, script_key_id) { + (WalletType::Software(_, _), _) | (WalletType::Ledger(_), TariKeyId::Imported { .. } | TariKeyId::Zero) => { self.get_private_key(script_key_id).await.map_err(|e| e.into()) }, - (WalletType::Ledger(account), TariKeyId::Managed { branch: _, index }) => { + (WalletType::Ledger(ledger), TariKeyId::Managed { branch: _, index }) => { #[cfg(not(feature = "ledger"))] return Err(TransactionError::LedgerDeviceError(LedgerDeviceError::NotSupported)); #[cfg(feature = "ledger")] { - let transport = TransportNativeHID::new(&HidApi::new().expect("Ledger not attached")) - .map_err(|e| LedgerDeviceError::HidApi(e.to_string()))?; - - let mut data = (account as u64).to_le_bytes().to_vec(); - data.extend_from_slice(&index.to_le_bytes()); // Static index. Fix this. - let command = APDUCommand { - cla: 0x80, - ins: 0x03, - p1: 0x00, - p2: 0x00, - data, - }; - - match transport.exchange(&command) { + let data = index.to_le_bytes().to_vec(); + + match ledger.build_command(Instruction::GetPrivateKey, data).execute() { Ok(result) => { + debug!(target: LOG_TARGET, "result length: {}, data: {:?}", result.data().len(), result.data()); if result.data().len() < 33 { + debug!(target: LOG_TARGET, "result less than 33"); return Err(LedgerDeviceError::Processing(format!( "'get_private_key' insufficient data - expected 33 got {} bytes ({:?})", result.data().len(), diff --git a/base_layer/core/src/transactions/key_manager/memory_db_key_manager.rs b/base_layer/core/src/transactions/key_manager/memory_db_key_manager.rs index d5c35fe2a6..6bfd384d10 100644 --- a/base_layer/core/src/transactions/key_manager/memory_db_key_manager.rs +++ b/base_layer/core/src/transactions/key_manager/memory_db_key_manager.rs @@ -51,13 +51,12 @@ pub fn create_memory_db_key_manager_with_range_proof_size(size: usize) -> Memory let key_ga = Key::from_slice(&key); let db_cipher = XChaCha20Poly1305::new(key_ga); let factory = CryptoFactories::new(size); - let wallet_type = WalletType::Software; TransactionKeyManagerWrapper::>::new( cipher, KeyManagerDatabase::new(KeyManagerSqliteDatabase::init(connection, db_cipher)), factory, - wallet_type, + WalletType::default(), ) .unwrap() } diff --git a/base_layer/core/src/transactions/key_manager/mod.rs b/base_layer/core/src/transactions/key_manager/mod.rs index ec8033b7df..2d803f06f0 100644 --- a/base_layer/core/src/transactions/key_manager/mod.rs +++ b/base_layer/core/src/transactions/key_manager/mod.rs @@ -46,4 +46,4 @@ pub use memory_db_key_manager::{ }; mod error; -pub use error::{CoreKeyManagerError, LedgerDeviceError}; +pub use error::CoreKeyManagerError; diff --git a/base_layer/core/src/transactions/transaction_components/error.rs b/base_layer/core/src/transactions/transaction_components/error.rs index ab038bffa5..047f9378ed 100644 --- a/base_layer/core/src/transactions/transaction_components/error.rs +++ b/base_layer/core/src/transactions/transaction_components/error.rs @@ -23,6 +23,7 @@ // Portions of this file were originally copyrighted (c) 2018 The Grin Developers, issued under the Apache License, // Version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0. +use minotari_ledger_wallet_comms::error::LedgerDeviceError; use serde::{Deserialize, Serialize}; use tari_crypto::{ errors::RangeProofError, @@ -32,7 +33,7 @@ use tari_key_manager::key_manager_service::KeyManagerServiceError; use tari_script::ScriptError; use thiserror::Error; -use crate::transactions::{key_manager::LedgerDeviceError, transaction_components::EncryptedDataError}; +use crate::transactions::transaction_components::EncryptedDataError; //---------------------------------------- TransactionError ----------------------------------------------------// #[derive(Clone, Debug, PartialEq, Error, Deserialize, Serialize, Eq)] diff --git a/base_layer/wallet/src/wallet.rs b/base_layer/wallet/src/wallet.rs index 3258101720..4e27ac052f 100644 --- a/base_layer/wallet/src/wallet.rs +++ b/base_layer/wallet/src/wallet.rs @@ -780,8 +780,8 @@ pub fn read_or_create_wallet_type( Ok(wallet_type) }, (None, Some(t)) => { - db.set_wallet_type(t)?; - Ok(t) + db.set_wallet_type(t.clone())?; + Ok(t.clone()) }, (Some(t), _) => Ok(t), } diff --git a/base_layer/wallet/tests/transaction_service_tests/service.rs b/base_layer/wallet/tests/transaction_service_tests/service.rs index 5a25872894..7a2e8d32bf 100644 --- a/base_layer/wallet/tests/transaction_service_tests/service.rs +++ b/base_layer/wallet/tests/transaction_service_tests/service.rs @@ -242,7 +242,7 @@ async fn setup_transaction_service>( kms_backend, cipher, factories.clone(), - WalletType::Software, + WalletType::default(), )) .add_initializer(TransactionServiceInitializer::<_, _, MemoryDbKeyManager>::new( TransactionServiceConfig { diff --git a/base_layer/wallet_ffi/src/lib.rs b/base_layer/wallet_ffi/src/lib.rs index a5fff1dadc..4644556039 100644 --- a/base_layer/wallet_ffi/src/lib.rs +++ b/base_layer/wallet_ffi/src/lib.rs @@ -5551,7 +5551,7 @@ pub unsafe extern "C" fn wallet_create( key_manager_backend, shutdown.to_signal(), master_seed, - WalletType::Software, + WalletType::default(), user_agent, )); From 66085704498a18a0c9d8d3cff14211538af4c66e Mon Sep 17 00:00:00 2001 From: SW van Heerden Date: Fri, 19 Apr 2024 11:50:11 +0200 Subject: [PATCH 09/49] change script key derivation --- .../src/transactions/key_manager/inner.rs | 34 +++++++++++++++---- .../src/transactions/key_manager/interface.rs | 2 -- .../core/src/transactions/test_helpers.rs | 7 ++-- .../src/key_manager_service/interface.rs | 8 +++++ .../src/key_manager_service/service.rs | 9 +++++ .../recovery/standard_outputs_recoverer.rs | 17 +++------- 6 files changed, 52 insertions(+), 25 deletions(-) diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index 8330431529..d4ddf6ab46 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -23,6 +23,7 @@ use std::{collections::HashMap, ops::Shl}; use blake2::Blake2b; use digest::consts::U64; +use futures::AsyncReadExt; use log::*; #[cfg(feature = "ledger")] use minotari_ledger_wallet_comms::{error::LedgerDeviceError, ledger_wallet::Instruction}; @@ -200,6 +201,15 @@ where TBackend: KeyManagerBackend + 'static .await; Ok(km.derive_public_key(*index)?.key) }, + KeyId::Derived { branch, index } => { + let km = self + .key_managers + .get(branch) + .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .read() + .await; + Ok(km.derive_public_key(*index)?.key) + }, KeyId::Imported { key } => Ok(key.clone()), KeyId::Zero => Ok(PublicKey::default()), } @@ -214,10 +224,8 @@ where TBackend: KeyManagerBackend + 'static let index = spend_key_id .managed_index() .ok_or(KeyManagerServiceError::KyeIdWithoutIndex)?; - self.db - .set_key_index(&TransactionKeyManagerBranch::ScriptKey.get_branch_key(), index)?; - let script_key_id = KeyId::Managed { - branch: TransactionKeyManagerBranch::ScriptKey.get_branch_key(), + let script_key_id = KeyId::Derived { + branch: TransactionKeyManagerBranch::CommitmentMask.get_branch_key(), index, }; let script_public_key = self.get_public_key_at_key_id(&script_key_id).await?; @@ -233,11 +241,12 @@ where TBackend: KeyManagerBackend + 'static ) -> Result, KeyManagerServiceError> { let index = match spend_key_id { KeyId::Managed { index, .. } => *index, + KeyId::Derived { index, .. } => return Ok(None), KeyId::Imported { .. } => return Ok(None), KeyId::Zero => return Ok(None), }; - let script_key_id = KeyId::Managed { - branch: TransactionKeyManagerBranch::ScriptKey.get_branch_key(), + let script_key_id = KeyId::Derived { + branch: TransactionKeyManagerBranch::CommitmentMask.get_branch_key(), index, }; @@ -337,6 +346,19 @@ where TBackend: KeyManagerBackend + 'static let key = km.get_private_key(*index)?; Ok(key) }, + KeyId::Derived { branch, index } => match self.wallet_type { + WalletType::Ledger(_) => panic!(), + WalletType::Software => { + let km = self + .key_managers + .get(branch) + .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .read() + .await; + let key = km.get_private_key(*index)?; + Ok(key) + }, + }, KeyId::Imported { key } => { let pvt_key = self.db.get_imported_key(key)?; Ok(pvt_key) diff --git a/base_layer/core/src/transactions/key_manager/interface.rs b/base_layer/core/src/transactions/key_manager/interface.rs index ff3082e72a..2a69168e4c 100644 --- a/base_layer/core/src/transactions/key_manager/interface.rs +++ b/base_layer/core/src/transactions/key_manager/interface.rs @@ -58,7 +58,6 @@ pub enum TransactionKeyManagerBranch { CommitmentMask, Nonce, KernelNonce, - ScriptKey, SenderOffset, } @@ -73,7 +72,6 @@ impl TransactionKeyManagerBranch { TransactionKeyManagerBranch::CommitmentMask => "commitment mask".to_string(), TransactionKeyManagerBranch::Nonce => "nonce".to_string(), TransactionKeyManagerBranch::KernelNonce => "kernel nonce".to_string(), - TransactionKeyManagerBranch::ScriptKey => "script key".to_string(), TransactionKeyManagerBranch::SenderOffset => "sender offset".to_string(), } } diff --git a/base_layer/core/src/transactions/test_helpers.rs b/base_layer/core/src/transactions/test_helpers.rs index 586f6c7e3b..309a38c3a9 100644 --- a/base_layer/core/src/transactions/test_helpers.rs +++ b/base_layer/core/src/transactions/test_helpers.rs @@ -27,7 +27,7 @@ use tari_common::configuration::Network; use tari_common_sqlite::{error::SqliteStorageError, sqlite_connection_pool::PooledDbConnection}; use tari_common_types::types::{Commitment, PrivateKey, PublicKey, Signature}; use tari_crypto::keys::{PublicKey as PK, SecretKey}; -use tari_key_manager::key_manager_service::{storage::sqlite_db::KeyManagerSqliteDatabase, KeyManagerInterface}; +use tari_key_manager::key_manager_service::{storage::sqlite_db::KeyManagerSqliteDatabase, KeyManagerInterface, KeyId}; use tari_script::{inputs, script, ExecutionStack, TariScript}; use super::transaction_components::{TransactionInputVersion, TransactionOutputVersion}; @@ -729,10 +729,7 @@ pub async fn create_stx_protocol_internal( .get_next_key(TransactionKeyManagerBranch::SenderOffset.get_branch_key()) .await .unwrap(); - let (script_key_id, _) = key_manager - .get_next_key(TransactionKeyManagerBranch::ScriptKey.get_branch_key()) - .await - .unwrap(); + let script_key_id = KeyId::Derived {branch: TransactionKeyManagerBranch::CommitmentMask.get_branch_key(), index:spending_key.managed_index().unwrap() }; let script_public_key = key_manager.get_public_key_at_key_id(&script_key_id).await.unwrap(); let input_data = match &schema.input_data { Some(data) => data.clone(), diff --git a/base_layer/key_manager/src/key_manager_service/interface.rs b/base_layer/key_manager/src/key_manager_service/interface.rs index 80acc85864..82c287406c 100644 --- a/base_layer/key_manager/src/key_manager_service/interface.rs +++ b/base_layer/key_manager/src/key_manager_service/interface.rs @@ -44,6 +44,10 @@ pub enum KeyId { branch: String, index: u64, }, + Derived { + branch: String, + index: u64, + }, Imported { key: PK, }, @@ -57,6 +61,7 @@ where PK: Clone pub fn managed_index(&self) -> Option { match self { KeyId::Managed { index, .. } => Some(*index), + KeyId::Derived { index, .. } => Some(*index), KeyId::Imported { .. } => None, KeyId::Zero => None, } @@ -65,6 +70,7 @@ where PK: Clone pub fn managed_branch(&self) -> Option { match self { KeyId::Managed { branch, .. } => Some(branch.clone()), + KeyId::Derived { branch, .. } => Some(branch.clone()), KeyId::Imported { .. } => None, KeyId::Zero => None, } @@ -73,6 +79,7 @@ where PK: Clone pub fn imported(&self) -> Option { match self { KeyId::Managed { .. } => None, + KeyId::Derived { .. } => None, KeyId::Imported { key } => Some(key.clone()), KeyId::Zero => None, } @@ -90,6 +97,7 @@ where PK: ByteArray fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { KeyId::Managed { branch: b, index: i } => write!(f, "{}.{}.{}", MANAGED_KEY_BRANCH, b, i), + KeyId::Derived { branch: b, index: i } => write!(f, "{}.{}.{}", MANAGED_KEY_BRANCH, b, i), KeyId::Imported { key: public_key } => write!(f, "{}.{}", IMPORTED_KEY_BRANCH, public_key.to_hex()), KeyId::Zero => write!(f, "{}", ZERO_KEY_BRANCH), } diff --git a/base_layer/key_manager/src/key_manager_service/service.rs b/base_layer/key_manager/src/key_manager_service/service.rs index acd914b16b..eded59975b 100644 --- a/base_layer/key_manager/src/key_manager_service/service.rs +++ b/base_layer/key_manager/src/key_manager_service/service.rs @@ -128,6 +128,15 @@ where .await; Ok(km.derive_public_key(*index)?.key) }, + KeyId::Derived { branch, index } => { + let km = self + .key_managers + .get(branch) + .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .lock() + .await; + Ok(km.derive_public_key(*index)?.key) + }, KeyId::Imported { key } => Ok(key.clone()), KeyId::Zero => Ok(PK::default()), } diff --git a/base_layer/wallet/src/output_manager_service/recovery/standard_outputs_recoverer.rs b/base_layer/wallet/src/output_manager_service/recovery/standard_outputs_recoverer.rs index 949b255d06..af92c2850a 100644 --- a/base_layer/wallet/src/output_manager_service/recovery/standard_outputs_recoverer.rs +++ b/base_layer/wallet/src/output_manager_service/recovery/standard_outputs_recoverer.rs @@ -31,6 +31,7 @@ use tari_core::transactions::{ }; use tari_script::{inputs, script, ExecutionStack, Opcode, TariScript}; use tari_utilities::hex::Hex; +use tari_key_manager::key_manager_service::KeyId; use crate::output_manager_service::{ error::{OutputManagerError, OutputManagerStorageError}, @@ -193,10 +194,8 @@ where ) -> Result, OutputManagerError> { let (input_data, script_key) = if script == &script!(Nop) { // This is a nop, so we can just create a new key an create the input stack. - let (key, public_key) = self - .master_key_manager - .get_next_key(TransactionKeyManagerBranch::ScriptKey.get_branch_key()) - .await?; + let key = KeyId::Derived {branch: TransactionKeyManagerBranch::CommitmentMask.get_branch_key(), index:spending_key.managed_index().unwrap() }; + let public_key = self.master_key_manager.get_public_key_at_key_id(&key).await?; (inputs!(public_key), key) } else { // This is a known script so lets fill in the details @@ -275,15 +274,9 @@ where found_index, ) .await?; - self.master_key_manager - .update_current_key_index_if_higher( - TransactionKeyManagerBranch::ScriptKey.get_branch_key(), - found_index, - ) - .await?; - TariKeyId::Managed { - branch: TransactionKeyManagerBranch::ScriptKey.get_branch_key(), + TariKeyId::Derived { + branch: TransactionKeyManagerBranch::CommitmentMask.get_branch_key(), index: found_index, } }; From 069f963a63813fd889702172b6b9ebc23c6140cb Mon Sep 17 00:00:00 2001 From: brianp Date: Tue, 23 Apr 2024 11:17:26 +0200 Subject: [PATCH 10/49] Make the software wallet use priv and pub key types --- .../comms/src/ledger_wallet.rs | 3 ++- base_layer/common_types/src/wallet_types.rs | 16 +++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs b/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs index 3452986e80..284a894937 100644 --- a/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs +++ b/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs @@ -45,6 +45,7 @@ pub enum Instruction { GetAppName = 0x02, GetPrivateKey = 0x03, GetPublicKey = 0x04, + GetScriptSignature = 0x05, } impl Instruction { @@ -78,7 +79,7 @@ impl> Command { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct LedgerWallet { account: u64, - pubkey: Option, + pub pubkey: Option, } impl Display for LedgerWallet { diff --git a/base_layer/common_types/src/wallet_types.rs b/base_layer/common_types/src/wallet_types.rs index 729dcb3de7..7b66efeeaa 100644 --- a/base_layer/common_types/src/wallet_types.rs +++ b/base_layer/common_types/src/wallet_types.rs @@ -28,22 +28,20 @@ use std::{ use chacha20poly1305::aead::OsRng; use minotari_ledger_wallet_comms::ledger_wallet::LedgerWallet; use serde::{Deserialize, Serialize}; -use tari_crypto::{ - keys::{PublicKey, SecretKey}, - ristretto::{RistrettoPublicKey, RistrettoSecretKey}, -}; -use tari_utilities::ByteArray; +use tari_crypto::keys::{PublicKey as PublicKeyTrait, SecretKey}; + +use crate::types::{PrivateKey, PublicKey}; #[derive(Debug, Clone, Serialize, Deserialize)] pub enum WalletType { - Software(Vec, Vec), // Make them a priv and pub + Software(PrivateKey, PublicKey), // Make them a priv and pub Ledger(LedgerWallet), } impl Display for WalletType { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { - WalletType::Software(pk, _k) => write!(f, "Software({:?})", pk), + WalletType::Software(_k, pk) => write!(f, "Software({:?})", pk), WalletType::Ledger(account) => write!(f, "Ledger({account})"), } } @@ -51,7 +49,7 @@ impl Display for WalletType { impl Default for WalletType { fn default() -> Self { - let k = RistrettoSecretKey::random(&mut OsRng); - WalletType::Software(RistrettoPublicKey::from_secret_key(&k).to_vec(), k.to_vec()) + let k: PrivateKey = SecretKey::random(&mut OsRng); + WalletType::Software(k.clone(), PublicKey::from_secret_key(&k)) } } From 5a77d23ff6247c9baeca4f7b246d68842ccb1939 Mon Sep 17 00:00:00 2001 From: brianp Date: Tue, 23 Apr 2024 11:18:43 +0200 Subject: [PATCH 11/49] Code fork for script signing on the ledger --- .../src/transactions/key_manager/inner.rs | 155 ++++++++++-------- .../core/tests/tests/node_comms_interface.rs | 2 +- .../output_manager_service_tests/service.rs | 2 +- .../transaction_service_tests/storage.rs | 2 +- 4 files changed, 90 insertions(+), 71 deletions(-) diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index d4ddf6ab46..4b5feb687f 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -23,7 +23,6 @@ use std::{collections::HashMap, ops::Shl}; use blake2::Blake2b; use digest::consts::U64; -use futures::AsyncReadExt; use log::*; #[cfg(feature = "ledger")] use minotari_ledger_wallet_comms::{error::LedgerDeviceError, ledger_wallet::Instruction}; @@ -45,6 +44,7 @@ use tari_crypto::{ bulletproofs_plus::{RistrettoExtendedMask, RistrettoExtendedWitness}, RistrettoComSig, }, + signatures::CommitmentAndPublicKeySignature, }; use tari_key_manager::{ cipher_seed::CipherSeed, @@ -201,14 +201,20 @@ where TBackend: KeyManagerBackend + 'static .await; Ok(km.derive_public_key(*index)?.key) }, - KeyId::Derived { branch, index } => { - let km = self - .key_managers - .get(branch) - .ok_or(KeyManagerServiceError::UnknownKeyBranch)? - .read() - .await; - Ok(km.derive_public_key(*index)?.key) + KeyId::Derived { branch, index } => match &self.wallet_type { + WalletType::Software(k, pk) => Ok(pk.clone()), + WalletType::Ledger(ledger) => { + #[cfg(not(feature = "ledger"))] + return Err(TransactionError::LedgerDeviceError(LedgerDeviceError::NotSupported)); + + #[cfg(feature = "ledger")] + { + match &ledger.pubkey { + Some(pk) => Ok(pk.clone()), + None => Err(KeyManagerServiceError::UnknownKeyBranch), + } + } + }, }, KeyId::Imported { key } => Ok(key.clone()), KeyId::Zero => Ok(PublicKey::default()), @@ -346,18 +352,9 @@ where TBackend: KeyManagerBackend + 'static let key = km.get_private_key(*index)?; Ok(key) }, - KeyId::Derived { branch, index } => match self.wallet_type { + KeyId::Derived { branch, index } => match &self.wallet_type { WalletType::Ledger(_) => panic!(), - WalletType::Software => { - let km = self - .key_managers - .get(branch) - .ok_or(KeyManagerServiceError::UnknownKeyBranch)? - .read() - .await; - let key = km.get_private_key(*index)?; - Ok(key) - }, + WalletType::Software(k, pk) => Ok(k.clone()), }, KeyId::Imported { key } => { let pvt_key = self.db.get_imported_key(key)?; @@ -457,41 +454,44 @@ where TBackend: KeyManagerBackend + 'static // Transaction input section (transactions > transaction_components > transaction_input) // ----------------------------------------------------------------------------------------------------------------- - pub async fn get_script_private_key(&self, script_key_id: &TariKeyId) -> Result { - match (&self.wallet_type, script_key_id) { - (WalletType::Software(_, _), _) | (WalletType::Ledger(_), TariKeyId::Imported { .. } | TariKeyId::Zero) => { - self.get_private_key(script_key_id).await.map_err(|e| e.into()) - }, - (WalletType::Ledger(ledger), TariKeyId::Managed { branch: _, index }) => { - #[cfg(not(feature = "ledger"))] - return Err(TransactionError::LedgerDeviceError(LedgerDeviceError::NotSupported)); - - #[cfg(feature = "ledger")] - { - let data = index.to_le_bytes().to_vec(); - - match ledger.build_command(Instruction::GetPrivateKey, data).execute() { - Ok(result) => { - debug!(target: LOG_TARGET, "result length: {}, data: {:?}", result.data().len(), result.data()); - if result.data().len() < 33 { - debug!(target: LOG_TARGET, "result less than 33"); - return Err(LedgerDeviceError::Processing(format!( - "'get_private_key' insufficient data - expected 33 got {} bytes ({:?})", - result.data().len(), - result - )) - .into()); - } - PrivateKey::from_canonical_bytes(&result.data()[1..33]) - .map_err(|e| TransactionError::InvalidSignatureError(e.to_string())) - }, - Err(e) => Err(LedgerDeviceError::Instruction(format!("GetPrivateKey: {}", e)).into()), - } - } - // end script private key - }, - } - } + // pub async fn get_script_private_key(&self, script_key_id: &TariKeyId) -> Result { + // match (&self.wallet_type, script_key_id { + // TariKeyId::Derived { branch, index } => { + // match (&self.wallet_type) { + // WalletType::Software(_, _) => self.get_private_key(script_key_id).await.map_err(|e| e.into()), + // WalletType::Ledger(ledger) => { + // #[cfg(not(feature = "ledger"))] + // return Err(TransactionError::LedgerDeviceError(LedgerDeviceError::NotSupported)); + + // #[cfg(feature = "ledger")] + // { + // let data = index.to_le_bytes().to_vec(); + + // match ledger.build_command(Instruction::GetPrivateKey, data).execute() { + // Ok(result) => { + // debug!(target: LOG_TARGET, "result length: {}, data: {:?}", result.data().len(), + // result.data()); if result.data().len() < 33 { + // debug!(target: LOG_TARGET, "result less than 33"); + // return Err(LedgerDeviceError::Processing(format!( + // "'get_private_key' insufficient data - expected 33 got {} bytes ({:?})", + // result.data().len(), + // result + // )) + // .into()); + // } + // PrivateKey::from_canonical_bytes(&result.data()[1..33]) + // .map_err(|e| TransactionError::InvalidSignatureError(e.to_string())) + // }, + // Err(e) => Err(LedgerDeviceError::Instruction(format!("GetPrivateKey: {}", e)).into()), + // } + // } + // // end script private key + // }, + // } + // }, + // _ => {}, + // } + // } pub async fn get_script_signature( &self, @@ -508,28 +508,47 @@ where TBackend: KeyManagerBackend + 'static let ephemeral_pubkey = PublicKey::from_secret_key(&r_y); let commitment = self.get_commitment(spend_key_id, value).await?; let spend_private_key = self.get_private_key(spend_key_id).await?; - let script_private_key = self.get_script_private_key(script_key_id).await?; let challenge = TransactionInput::finalize_script_signature_challenge( txi_version, &ephemeral_commitment, &ephemeral_pubkey, - &PublicKey::from_secret_key(&script_private_key), + &self.get_public_key_at_key_id(script_key_id).await?, &commitment, script_message, ); - let script_signature = ComAndPubSignature::sign( - value, - &spend_private_key, - &script_private_key, - &r_a, - &r_x, - &r_y, - &challenge, - &*self.crypto_factories.commitment, - )?; - Ok(script_signature) + match &self.wallet_type { + WalletType::Software(k, pk) => { + let script_private_key = self.get_private_key(script_key_id).await?; + let script_signature = ComAndPubSignature::sign( + value, + &spend_private_key, + &script_private_key, + &r_a, + &r_x, + &r_y, + &challenge, + &*self.crypto_factories.commitment, + )?; + Ok(script_signature) + }, + WalletType::Ledger(ledger) => { + #[cfg(not(feature = "ledger"))] + { + return Err(TransactionError::LedgerDeviceError(LedgerDeviceError::NotSupported)); + } + + #[cfg(feature = "ledger")] + { + let data: Vec = vec![]; + match ledger.build_command(Instruction::GetScriptSignature, data).execute() { + Ok(result) => Ok(CommitmentAndPublicKeySignature::default()), // Fix this + Err(e) => Err(LedgerDeviceError::Instruction(format!("GetScriptSignature: {}", e)).into()), + } + } + }, + } } // ----------------------------------------------------------------------------------------------------------------- diff --git a/base_layer/core/tests/tests/node_comms_interface.rs b/base_layer/core/tests/tests/node_comms_interface.rs index 576702189a..91463d9062 100644 --- a/base_layer/core/tests/tests/node_comms_interface.rs +++ b/base_layer/core/tests/tests/node_comms_interface.rs @@ -304,7 +304,7 @@ async fn initialize_sender_transaction_protocol_for_overflow_test( .await .unwrap(); let (script_key_id, _) = key_manager - .get_next_key(TransactionKeyManagerBranch::ScriptKey.get_branch_key()) + .get_next_key(TransactionKeyManagerBranch::CommitmentMask.get_branch_key()) .await .unwrap(); let script_public_key = key_manager.get_public_key_at_key_id(&script_key_id).await.unwrap(); diff --git a/base_layer/wallet/tests/output_manager_service_tests/service.rs b/base_layer/wallet/tests/output_manager_service_tests/service.rs index d879c86c1a..3e8b737a92 100644 --- a/base_layer/wallet/tests/output_manager_service_tests/service.rs +++ b/base_layer/wallet/tests/output_manager_service_tests/service.rs @@ -2178,7 +2178,7 @@ async fn scan_for_recovery_test() { .unwrap(); let (script_key, public_script_key) = oms .key_manager_handle - .get_next_key(TransactionKeyManagerBranch::ScriptKey.get_branch_key()) + .get_next_key(TransactionKeyManagerBranch::CommitmentMask.get_branch_key()) .await .unwrap(); let amount = 1_000 * i as u64; diff --git a/base_layer/wallet/tests/transaction_service_tests/storage.rs b/base_layer/wallet/tests/transaction_service_tests/storage.rs index bf32ac5ca4..bbd7e873f2 100644 --- a/base_layer/wallet/tests/transaction_service_tests/storage.rs +++ b/base_layer/wallet/tests/transaction_service_tests/storage.rs @@ -180,7 +180,7 @@ pub async fn test_db_backend(backend: T) { .await .unwrap(); let (script_key_id, public_script_key) = key_manager - .get_next_key(TransactionKeyManagerBranch::ScriptKey.get_branch_key()) + .get_next_key(TransactionKeyManagerBranch::CommitmentMask.get_branch_key()) .await .unwrap(); let encrypted_data = key_manager From 9bd7b8827180e8346acc0e375e09a89df16e5269 Mon Sep 17 00:00:00 2001 From: brianp Date: Tue, 23 Apr 2024 22:55:42 +0200 Subject: [PATCH 12/49] Allow the transport to be reused --- .../comms/src/ledger_wallet.rs | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs b/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs index 284a894937..ceffdc5c32 100644 --- a/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs +++ b/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs @@ -74,6 +74,15 @@ impl> Command { .exchange(&self.inner) .map_err(|e| LedgerDeviceError::NativeTransport(e.to_string())) } + + pub fn execute_with_transport( + &self, + transport: &TransportNativeHID, + ) -> Result>, LedgerDeviceError> { + transport + .exchange(&self.inner) + .map_err(|e| LedgerDeviceError::NativeTransport(e.to_string())) + } } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -113,4 +122,33 @@ impl LedgerWallet { }, } } + + pub fn chunk_command(&self, instruction: Instruction, data: Vec>) -> Vec>> { + let num_chunks = data.len(); + let mut more = 0; + let mut commands = vec![]; + + for (i, chunk) in data.iter().enumerate() { + if i + 1 == num_chunks { + more = 0; + } else { + more = 1; + } + + let mut base_data = self.account_bytes(); + base_data.extend_from_slice(&chunk); + + commands.push(Command { + inner: APDUCommand { + cla: WALLET_CLA, + ins: instruction.as_byte(), + p1: i as u8, + p2: more, + data: base_data, + }, + }); + } + + commands + } } From 70b1a18d67d5eddb43919bb0f78261c55f1d258e Mon Sep 17 00:00:00 2001 From: brianp Date: Tue, 23 Apr 2024 23:02:21 +0200 Subject: [PATCH 13/49] Generate the ComAndPubSig entirely on the ledger --- .../wallet/src/handlers/get_private_key.rs | 20 +-- .../wallet/src/handlers/get_public_key.rs | 23 +--- .../src/handlers/get_script_signature.rs | 129 ++++++++++++++++++ .../minotari_ledger_wallet/wallet/src/main.rs | 26 ++-- .../wallet/src/utils.rs | 42 +++++- .../src/transactions/key_manager/inner.rs | 95 +++++++------ 6 files changed, 249 insertions(+), 86 deletions(-) create mode 100644 applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_private_key.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_private_key.rs index 7ff030e610..057767358a 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_private_key.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_private_key.rs @@ -4,13 +4,14 @@ use alloc::format; use ledger_device_sdk::{ecc::make_bip32_path, io::Comm, ui::gadgets::SingleMessage}; -use tari_crypto::{keys::SecretKey, ristretto::RistrettoSecretKey, tari_utilities::ByteArray}; +use tari_crypto::tari_utilities::ByteArray; use crate::{ alloc::string::ToString, - utils::{get_raw_key, u64_to_string}, + utils::{get_key_from_uniform_bytes, get_raw_key, u64_to_string}, AppSW, BIP32_COIN_TYPE, + RESPONSE_VERSION, }; pub fn handler_get_private_key(comm: &mut Comm) -> Result<(), AppSW> { @@ -42,20 +43,9 @@ pub fn handler_get_private_key(comm: &mut Comm) -> Result<(), AppSW> { }, }; - let k = match RistrettoSecretKey::from_uniform_bytes(&raw_key.as_ref()) { - Ok(val) => val, - Err(e) => { - SingleMessage::new(&format!( - "Err: key conversion {:?}. Length: {:?}", - e.to_string(), - &raw_key.len() - )) - .show(); - return Err(AppSW::KeyDeriveFail); - }, - }; + let k = get_key_from_uniform_bytes(&raw_key.as_ref())?; - comm.append(&[1]); // version + comm.append(&[RESPONSE_VERSION]); // version comm.append(k.as_bytes()); comm.reply_ok(); diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs index 97ce579250..d1c7cc2a0a 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs @@ -4,17 +4,14 @@ use alloc::format; use ledger_device_sdk::{ecc::make_bip32_path, io::Comm, ui::gadgets::SingleMessage}; -use tari_crypto::{ - keys::{PublicKey, SecretKey}, - ristretto::{RistrettoPublicKey, RistrettoSecretKey}, - tari_utilities::ByteArray, -}; +use tari_crypto::{keys::PublicKey, ristretto::RistrettoPublicKey, tari_utilities::ByteArray}; use crate::{ alloc::string::ToString, - utils::{get_raw_key, u64_to_string}, + utils::{get_key_from_uniform_bytes, get_raw_key, u64_to_string}, AppSW, BIP32_COIN_TYPE, + RESPONSE_VERSION, }; const STATIC_INDEX: &str = "42"; @@ -42,20 +39,12 @@ pub fn handler_get_public_key(comm: &mut Comm) -> Result<(), AppSW> { }, }; - let pk = match RistrettoSecretKey::from_uniform_bytes(&raw_key.as_ref()) { + let pk = match get_key_from_uniform_bytes(&raw_key.as_ref()) { Ok(k) => RistrettoPublicKey::from_secret_key(&k), - Err(e) => { - SingleMessage::new(&format!( - "Err: key conversion {:?}. Length: {:?}", - e.to_string(), - &raw_key.len() - )) - .show(); - return Err(AppSW::KeyDeriveFail); - }, + Err(e) => return Err(e), }; - comm.append(&[1]); // version + comm.append(&[RESPONSE_VERSION]); // version comm.append(pk.as_bytes()); comm.reply_ok(); diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs new file mode 100644 index 0000000000..5e6bf8b07b --- /dev/null +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs @@ -0,0 +1,129 @@ +// Copyright 2024 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use alloc::format; + +use ledger_device_sdk::{ecc::make_bip32_path, io::Comm, ui::gadgets::SingleMessage}; +use tari_crypto::ristretto::{ + pedersen::extended_commitment_factory::ExtendedPedersenCommitmentFactory, + RistrettoComAndPubSig, +}; + +use crate::{ + alloc::string::ToString, + utils::{get_key_from_canonical_bytes, get_key_from_uniform_bytes, get_raw_key, u64_to_string}, + AppSW, + BIP32_COIN_TYPE, + RESPONSE_VERSION, +}; + +const STATIC_INDEX: &str = "42"; + +const MAX_TRANSACTION_LEN: usize = 272; +pub struct SignerCtx { + payload: [u8; MAX_TRANSACTION_LEN], + payload_len: usize, +} + +// Implement constructor for TxInfo with default values +impl SignerCtx { + pub fn new() -> Self { + Self { + payload: [0u8; MAX_TRANSACTION_LEN], + payload_len: 0, + } + } + + // Implement reset for TxInfo + fn reset(&mut self) { + self.payload = [0u8; MAX_TRANSACTION_LEN]; + self.payload_len = 0; + } +} + +pub fn handler_get_script_signature( + comm: &mut Comm, + chunk: u8, + more: bool, + signer_ctx: &mut SignerCtx, +) -> Result<(), AppSW> { + let data = comm.get_data().map_err(|_| AppSW::WrongApduLength)?; + + if chunk == 0 { + // Reset transaction context + signer_ctx.reset(); + } + + if signer_ctx.payload_len + data.len() > MAX_TRANSACTION_LEN { + return Err(AppSW::ScriptSignatureFail); + } + + // Append data to signer_ctx + signer_ctx.payload[signer_ctx.payload_len..signer_ctx.payload_len + data.len()].copy_from_slice(data); + signer_ctx.payload_len += data.len(); + + // If we expect more chunks, return + if more { + return Ok(()); + } + + // Derive private key + let mut account_bytes = [0u8; 8]; + account_bytes.clone_from_slice(&signer_ctx.payload[0..8]); + let account = u64_to_string(u64::from_le_bytes(account_bytes)); + + let mut bip32_path = "m/44'/".to_string(); + bip32_path.push_str(&BIP32_COIN_TYPE.to_string()); + bip32_path.push_str(&"'/"); + bip32_path.push_str(&account); + bip32_path.push_str(&"'/0/"); + bip32_path.push_str(STATIC_INDEX); + let path: [u32; 5] = make_bip32_path(bip32_path.as_bytes()); + + SingleMessage::new(&bip32_path).show_and_wait(); + + let raw_key = match get_raw_key(&path) { + Ok(val) => val, + Err(e) => { + SingleMessage::new(&format!("Key error {:?}", e)).show_and_wait(); + return Err(AppSW::KeyDeriveFail); + }, + }; + + let script_private_key = get_key_from_uniform_bytes(&raw_key.as_ref())?; + let value = get_key_from_canonical_bytes(&signer_ctx.payload[8..40])?; + let spend_private_key = get_key_from_canonical_bytes(&signer_ctx.payload[48..80])?; + let r_a = get_key_from_canonical_bytes(&signer_ctx.payload[88..120])?; + let r_x = get_key_from_canonical_bytes(&signer_ctx.payload[128..160])?; + let r_y = get_key_from_canonical_bytes(&signer_ctx.payload[168..200])?; + let challenge = &signer_ctx.payload[208..272]; + + let factory = ExtendedPedersenCommitmentFactory::default(); + + SingleMessage::new(&"Signing...".to_string()).show(); + + let script_signature = match RistrettoComAndPubSig::sign( + &value, + &spend_private_key, + &script_private_key, + &r_a, + &r_x, + &r_y, + &challenge, + &factory, + ) { + Ok(sig) => sig, + Err(e) => { + SingleMessage::new(&format!("Signing error: {:?}", e.to_string())).show_and_wait(); + return Err(AppSW::ScriptSignatureFail); + }, + }; + + SingleMessage::new(&"Success!".to_string()).show_and_wait(); + + comm.append(&[RESPONSE_VERSION]); // version + comm.append(&script_signature.to_vec()); + comm.reply_ok(); + + Ok(()) +} diff --git a/applications/minotari_ledger_wallet/wallet/src/main.rs b/applications/minotari_ledger_wallet/wallet/src/main.rs index 600259b360..7c37b71a8c 100644 --- a/applications/minotari_ledger_wallet/wallet/src/main.rs +++ b/applications/minotari_ledger_wallet/wallet/src/main.rs @@ -15,6 +15,7 @@ mod app_ui { mod handlers { pub mod get_private_key; pub mod get_public_key; + pub mod get_script_signature; pub mod get_version; } @@ -25,6 +26,7 @@ use critical_section::RawRestoreState; use handlers::{ get_private_key::handler_get_private_key, get_public_key::handler_get_public_key, + get_script_signature::{handler_get_script_signature, SignerCtx}, get_version::handler_get_version, }; #[cfg(feature = "pending_review_screen")] @@ -39,6 +41,8 @@ ledger_device_sdk::set_panic!(ledger_device_sdk::exiting_panic); static BIP32_COIN_TYPE: u32 = 535348; static CLA: u8 = 0x80; +static RESPONSE_VERSION: u8 = 1; + /// Allocator heap size const HEAP_SIZE: usize = 1024 * 26; @@ -81,12 +85,7 @@ pub enum AppSW { WrongP1P2 = 0x6A86, InsNotSupported = 0x6D00, ClaNotSupported = 0x6E00, - TxDisplayFail = 0xB001, - AddrDisplayFail = 0xB002, - TxWrongLength = 0xB004, - TxParsingFail = 0xB005, - TxHashFail = 0xB006, - TxSignFail = 0xB008, + ScriptSignatureFail = 0xB001, KeyDeriveFail = 0xB009, VersionParsingFail = 0xB00A, WrongApduLength = StatusWords::BadLen as u16, @@ -104,8 +103,11 @@ pub enum Instruction { GetAppName, GetPrivateKey, GetPublicKey, + GetScriptSignature { chunk: u8, more: bool }, } +const P2_SCRIPT_SIG_MORE: u8 = 0x01; + impl TryFrom for Instruction { type Error = AppSW; @@ -126,6 +128,10 @@ impl TryFrom for Instruction { (2, 0, 0) => Ok(Instruction::GetAppName), (3, 0, 0) => Ok(Instruction::GetPrivateKey), (4, 0, 0) => Ok(Instruction::GetPublicKey), + (5, 0..=6, 0 | P2_SCRIPT_SIG_MORE) => Ok(Instruction::GetScriptSignature { + chunk: value.p1, + more: value.p2 == P2_SCRIPT_SIG_MORE, + }), (3..=4, _, _) => Err(AppSW::WrongP1P2), (_, _, _) => Err(AppSW::InsNotSupported), } @@ -145,11 +151,14 @@ extern "C" fn sample_main() { #[cfg(feature = "pending_review_screen")] display_pending_review(&mut comm); + // This is long lived over the span the ledger app is open, across multiple interactions + let mut signer_ctx = SignerCtx::new(); + loop { // Wait for either a specific button push to exit the app // or an APDU command if let Event::Command(ins) = ui_menu_main(&mut comm) { - match handle_apdu(&mut comm, ins) { + match handle_apdu(&mut comm, ins, &mut signer_ctx) { Ok(()) => comm.reply_ok(), Err(sw) => comm.reply(sw), } @@ -157,7 +166,7 @@ extern "C" fn sample_main() { } } -fn handle_apdu(comm: &mut Comm, ins: Instruction) -> Result<(), AppSW> { +fn handle_apdu(comm: &mut Comm, ins: Instruction, signer_ctx: &mut SignerCtx) -> Result<(), AppSW> { match ins { Instruction::GetVersion => handler_get_version(comm), Instruction::GetAppName => { @@ -166,5 +175,6 @@ fn handle_apdu(comm: &mut Comm, ins: Instruction) -> Result<(), AppSW> { }, Instruction::GetPrivateKey => handler_get_private_key(comm), Instruction::GetPublicKey => handler_get_public_key(comm), + Instruction::GetScriptSignature { chunk, more } => handler_get_script_signature(comm, chunk, more, signer_ctx), } } diff --git a/applications/minotari_ledger_wallet/wallet/src/utils.rs b/applications/minotari_ledger_wallet/wallet/src/utils.rs index f62e2dc419..1998be1c53 100644 --- a/applications/minotari_ledger_wallet/wallet/src/utils.rs +++ b/applications/minotari_ledger_wallet/wallet/src/utils.rs @@ -1,6 +1,8 @@ // Copyright 2024 The Tari Project // SPDX-License-Identifier: BSD-3-Clause +use alloc::format; + use blake2::{Blake2b, Digest}; use digest::consts::U64; use ledger_device_sdk::{ @@ -8,7 +10,13 @@ use ledger_device_sdk::{ io::SyscallError, ui::gadgets::SingleMessage, }; -use tari_crypto::{hash_domain, hashing::DomainSeparatedHasher}; +use tari_crypto::{ + hash_domain, + hashing::DomainSeparatedHasher, + keys::SecretKey, + ristretto::RistrettoSecretKey, + tari_utilities::ByteArray, +}; use zeroize::Zeroizing; use crate::alloc::string::{String, ToString}; @@ -177,3 +185,35 @@ pub fn get_raw_key(path: &[u32]) -> Result, SyscallError> { }, } } + +pub fn get_key_from_uniform_bytes(bytes: &[u8]) -> Result { + match RistrettoSecretKey::from_uniform_bytes(bytes) { + Ok(val) => Ok(val), + Err(e) => { + SingleMessage::new(&format!( + "Err: key conversion {:?}. Length: {:?}", + e.to_string(), + &bytes.len() + )) + .show_and_wait(); + SingleMessage::new(&format!("Error Length: {:?}", &bytes.len())).show_and_wait(); + return Err(AppSW::KeyDeriveFail); + }, + } +} + +pub fn get_key_from_canonical_bytes(bytes: &[u8]) -> Result { + match RistrettoSecretKey::from_canonical_bytes(bytes) { + Ok(val) => Ok(val), + Err(e) => { + SingleMessage::new(&format!( + "Err: key conversion {:?}. Length: {:?}", + e.to_string(), + &bytes.len() + )) + .show_and_wait(); + SingleMessage::new(&format!("Error Length: {:?}", &bytes.len())).show_and_wait(); + return Err(AppSW::KeyDeriveFail); + }, + } +} diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index 4b5feb687f..8ac3c01bf5 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -19,11 +19,12 @@ // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -use std::{collections::HashMap, ops::Shl}; +use std::{collections::HashMap, ops::Shl, thread, thread::sleep, time::Duration}; use blake2::Blake2b; use digest::consts::U64; use log::*; +use minotari_ledger_wallet_comms::ledger_wallet::get_transport; #[cfg(feature = "ledger")] use minotari_ledger_wallet_comms::{error::LedgerDeviceError, ledger_wallet::Instruction}; use rand::rngs::OsRng; @@ -44,7 +45,6 @@ use tari_crypto::{ bulletproofs_plus::{RistrettoExtendedMask, RistrettoExtendedWitness}, RistrettoComSig, }, - signatures::CommitmentAndPublicKeySignature, }; use tari_key_manager::{ cipher_seed::CipherSeed, @@ -454,45 +454,6 @@ where TBackend: KeyManagerBackend + 'static // Transaction input section (transactions > transaction_components > transaction_input) // ----------------------------------------------------------------------------------------------------------------- - // pub async fn get_script_private_key(&self, script_key_id: &TariKeyId) -> Result { - // match (&self.wallet_type, script_key_id { - // TariKeyId::Derived { branch, index } => { - // match (&self.wallet_type) { - // WalletType::Software(_, _) => self.get_private_key(script_key_id).await.map_err(|e| e.into()), - // WalletType::Ledger(ledger) => { - // #[cfg(not(feature = "ledger"))] - // return Err(TransactionError::LedgerDeviceError(LedgerDeviceError::NotSupported)); - - // #[cfg(feature = "ledger")] - // { - // let data = index.to_le_bytes().to_vec(); - - // match ledger.build_command(Instruction::GetPrivateKey, data).execute() { - // Ok(result) => { - // debug!(target: LOG_TARGET, "result length: {}, data: {:?}", result.data().len(), - // result.data()); if result.data().len() < 33 { - // debug!(target: LOG_TARGET, "result less than 33"); - // return Err(LedgerDeviceError::Processing(format!( - // "'get_private_key' insufficient data - expected 33 got {} bytes ({:?})", - // result.data().len(), - // result - // )) - // .into()); - // } - // PrivateKey::from_canonical_bytes(&result.data()[1..33]) - // .map_err(|e| TransactionError::InvalidSignatureError(e.to_string())) - // }, - // Err(e) => Err(LedgerDeviceError::Instruction(format!("GetPrivateKey: {}", e)).into()), - // } - // } - // // end script private key - // }, - // } - // }, - // _ => {}, - // } - // } - pub async fn get_script_signature( &self, script_key_id: &TariKeyId, @@ -541,11 +502,55 @@ where TBackend: KeyManagerBackend + 'static #[cfg(feature = "ledger")] { - let data: Vec = vec![]; - match ledger.build_command(Instruction::GetScriptSignature, data).execute() { - Ok(result) => Ok(CommitmentAndPublicKeySignature::default()), // Fix this - Err(e) => Err(LedgerDeviceError::Instruction(format!("GetScriptSignature: {}", e)).into()), + let mut data: Vec> = vec![]; + data.push(value.as_bytes().to_vec()); + data.push(spend_private_key.as_bytes().to_vec()); + data.push(r_a.as_bytes().to_vec()); + data.push(r_x.as_bytes().to_vec()); + data.push(r_y.as_bytes().to_vec()); + data.push(challenge.to_vec()); + debug!(target: LOG_TARGET, "challenge: {:?} challenge size {:?}", challenge, challenge.len()); + + let commands = ledger.chunk_command(Instruction::GetScriptSignature, data); + let transport = get_transport()?; + + let mut result = None; + for command in commands { + match command.execute_with_transport(&transport) { + Ok(r) => result = Some(r), + Err(e) => { + return Err(LedgerDeviceError::Instruction(format!("GetScriptSignature: {}", e)).into()) + }, + } + } + + if let Some(result) = result { + if result.data().len() < 161 { + debug!(target: LOG_TARGET, "result less than 161"); + return Err(LedgerDeviceError::Processing(format!( + "'get_script_signature' insufficient data - expected 161 got {} bytes ({:?})", + result.data().len(), + result + )) + .into()); + } + let data = result.data(); + debug!(target: LOG_TARGET, "result length: {}, data: {:?}", result.data().len(), result.data()); + return Ok(ComAndPubSignature::new( + Commitment::from_canonical_bytes(&data[1..33]) + .map_err(|e| TransactionError::InvalidSignatureError(e.to_string()))?, + PublicKey::from_canonical_bytes(&data[33..65]) + .map_err(|e| TransactionError::InvalidSignatureError(e.to_string()))?, + PrivateKey::from_canonical_bytes(&data[65..97]) + .map_err(|e| TransactionError::InvalidSignatureError(e.to_string()))?, + PrivateKey::from_canonical_bytes(&data[97..129]) + .map_err(|e| TransactionError::InvalidSignatureError(e.to_string()))?, + PrivateKey::from_canonical_bytes(&data[129..161]) + .map_err(|e| TransactionError::InvalidSignatureError(e.to_string()))?, + )); } + + Err(LedgerDeviceError::Instruction("GetScriptSignature didn't end right".to_string()).into()) } }, } From 8f6b3ad7c98d1f3d46b244496ecbf3110bc77ffe Mon Sep 17 00:00:00 2001 From: SW van Heerden Date: Wed, 24 Apr 2024 12:03:14 +0200 Subject: [PATCH 14/49] derive script key (#5) --- .../src/transactions/key_manager/inner.rs | 72 ++++++++++++++----- .../src/transactions/key_manager/interface.rs | 30 +++++++- .../core/src/transactions/key_manager/mod.rs | 1 + .../core/src/transactions/test_helpers.rs | 9 ++- .../src/key_manager_service/error.rs | 4 ++ .../src/key_manager_service/interface.rs | 21 +++++- .../src/key_manager_service/service.rs | 27 +++++-- .../recovery/standard_outputs_recoverer.rs | 10 ++- 8 files changed, 146 insertions(+), 28 deletions(-) diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index 8ac3c01bf5..b7d53affe9 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -23,6 +23,7 @@ use std::{collections::HashMap, ops::Shl, thread, thread::sleep, time::Duration} use blake2::Blake2b; use digest::consts::U64; +use futures::AsyncReadExt; use log::*; use minotari_ledger_wallet_comms::ledger_wallet::get_transport; #[cfg(feature = "ledger")] @@ -87,6 +88,7 @@ use crate::{ CryptoFactories, }, }; +use crate::transactions::key_manager::interface::{TransactionKeyManagerLabel}; hash_domain!( KeyManagerHashingDomain, @@ -201,26 +203,43 @@ where TBackend: KeyManagerBackend + 'static .await; Ok(km.derive_public_key(*index)?.key) }, - KeyId::Derived { branch, index } => match &self.wallet_type { - WalletType::Software(k, pk) => Ok(pk.clone()), - WalletType::Ledger(ledger) => { - #[cfg(not(feature = "ledger"))] - return Err(TransactionError::LedgerDeviceError(LedgerDeviceError::NotSupported)); - - #[cfg(feature = "ledger")] - { - match &ledger.pubkey { - Some(pk) => Ok(pk.clone()), - None => Err(KeyManagerServiceError::UnknownKeyBranch), - } - } - }, + KeyId::Derived { branch, label, index } => { + let public_alpha = match &self.wallet_type { + WalletType::Software(_k, pk) => pk, + WalletType::Ledger(ledger) => ledger.pubkey.as_ref().ok_or(KeyManagerServiceError::LedgerError( + "Key manager set to use ledger, ledger alpha public key missing".to_string(), + ))?, + }; + let km = self + .key_managers + .get(branch) + .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .read() + .await; + let branch_key = km.get_private_key(*index)?; + let hasher = Self::get_domain_hasher(label)?; + let hasher = hasher.chain(branch_key.as_bytes()).finalize(); + let private_key = PrivateKey::from_uniform_bytes(hasher.as_ref()).map_err(|_| { + KeyManagerServiceError::UnknownError( + "Invalid private key for sender offset private key".to_string(), + ) + })?; + let public_key = PublicKey::from_secret_key(&private_key); + let public_key = public_alpha + &public_key; + Ok(public_key) }, KeyId::Imported { key } => Ok(key.clone()), KeyId::Zero => Ok(PublicKey::default()), } } + fn get_domain_hasher(label: &str)->Result, KeyManagerHashingDomain>,KeyManagerServiceError>{ + let tx_label = label.parse::().map_err(|e| KeyManagerServiceError::UnknownError(format!("Could not retrieve label for derived key: {}", e)))?; + match tx_label{ + TransactionKeyManagerLabel::ScriptKey => {Ok(DomainSeparatedHasher::, KeyManagerHashingDomain>::new_with_label("script key"))}, + } + } + pub async fn get_next_spend_and_script_key_ids( &self, ) -> Result<(TariKeyId, PublicKey, TariKeyId, PublicKey), KeyManagerServiceError> { @@ -232,6 +251,7 @@ where TBackend: KeyManagerBackend + 'static .ok_or(KeyManagerServiceError::KyeIdWithoutIndex)?; let script_key_id = KeyId::Derived { branch: TransactionKeyManagerBranch::CommitmentMask.get_branch_key(), + label: TransactionKeyManagerLabel::ScriptKey.get_branch_key(), index, }; let script_public_key = self.get_public_key_at_key_id(&script_key_id).await?; @@ -247,12 +267,13 @@ where TBackend: KeyManagerBackend + 'static ) -> Result, KeyManagerServiceError> { let index = match spend_key_id { KeyId::Managed { index, .. } => *index, - KeyId::Derived { index, .. } => return Ok(None), + KeyId::Derived { .. } => return Ok(None), KeyId::Imported { .. } => return Ok(None), KeyId::Zero => return Ok(None), }; let script_key_id = KeyId::Derived { branch: TransactionKeyManagerBranch::CommitmentMask.get_branch_key(), + label: TransactionKeyManagerLabel::ScriptKey.get_branch_key(), index, }; @@ -352,9 +373,26 @@ where TBackend: KeyManagerBackend + 'static let key = km.get_private_key(*index)?; Ok(key) }, - KeyId::Derived { branch, index } => match &self.wallet_type { + KeyId::Derived { branch, label, index } => match &self.wallet_type { WalletType::Ledger(_) => panic!(), - WalletType::Software(k, pk) => Ok(k.clone()), + WalletType::Software(k, _pk) => { + let km = self + .key_managers + .get(branch) + .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .read() + .await; + let branch_key = km.get_private_key(*index)?; + let hasher = Self::get_domain_hasher(label)?; + let hasher = hasher.chain(branch_key.as_bytes()).finalize(); + let private_key = PrivateKey::from_uniform_bytes(hasher.as_ref()).map_err(|_| { + KeyManagerServiceError::UnknownError( + format!("Invalid private key for {}", label), + ) + })?; + let private_key = private_key + k; + Ok(private_key) + }, }, KeyId::Imported { key } => { let pvt_key = self.db.get_imported_key(key)?; diff --git a/base_layer/core/src/transactions/key_manager/interface.rs b/base_layer/core/src/transactions/key_manager/interface.rs index 2a69168e4c..16926eae52 100644 --- a/base_layer/core/src/transactions/key_manager/interface.rs +++ b/base_layer/core/src/transactions/key_manager/interface.rs @@ -20,6 +20,7 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +use std::str::FromStr; use blake2::Blake2b; use digest::consts::U64; use strum_macros::EnumIter; @@ -54,7 +55,6 @@ pub enum TxoStage { pub enum TransactionKeyManagerBranch { DataEncryption, Coinbase, - CoinbaseScript, CommitmentMask, Nonce, KernelNonce, @@ -68,7 +68,6 @@ impl TransactionKeyManagerBranch { match self { TransactionKeyManagerBranch::DataEncryption => "data encryption".to_string(), TransactionKeyManagerBranch::Coinbase => "coinbase".to_string(), - TransactionKeyManagerBranch::CoinbaseScript => "coinbase script".to_string(), TransactionKeyManagerBranch::CommitmentMask => "commitment mask".to_string(), TransactionKeyManagerBranch::Nonce => "nonce".to_string(), TransactionKeyManagerBranch::KernelNonce => "kernel nonce".to_string(), @@ -77,6 +76,33 @@ impl TransactionKeyManagerBranch { } } +#[derive(Clone, Copy, EnumIter)] +pub enum TransactionKeyManagerLabel { + ScriptKey +} + +impl TransactionKeyManagerLabel { + /// Warning: Changing these strings will affect the backwards compatibility of the wallet with older databases or + /// recovery. + pub fn get_branch_key(self) -> String { + match self { + TransactionKeyManagerLabel::ScriptKey => "script key".to_string(), + } + } +} + +impl FromStr for TransactionKeyManagerLabel +{ + type Err = String; + + fn from_str(id: &str) -> Result { + match id{ + "script key" => Ok(TransactionKeyManagerLabel::ScriptKey), + _ => Err("Unknown label".to_string()), + } + } +} + #[async_trait::async_trait] pub trait TransactionKeyManagerInterface: KeyManagerInterface { /// Gets the pedersen commitment for the specified index diff --git a/base_layer/core/src/transactions/key_manager/mod.rs b/base_layer/core/src/transactions/key_manager/mod.rs index 2d803f06f0..7b85c13bca 100644 --- a/base_layer/core/src/transactions/key_manager/mod.rs +++ b/base_layer/core/src/transactions/key_manager/mod.rs @@ -28,6 +28,7 @@ pub use interface::{ SecretTransactionKeyManagerInterface, TariKeyId, TransactionKeyManagerBranch, + TransactionKeyManagerLabel, TransactionKeyManagerInterface, TxoStage, }; diff --git a/base_layer/core/src/transactions/test_helpers.rs b/base_layer/core/src/transactions/test_helpers.rs index 309a38c3a9..c7bd4e3b9c 100644 --- a/base_layer/core/src/transactions/test_helpers.rs +++ b/base_layer/core/src/transactions/test_helpers.rs @@ -27,7 +27,7 @@ use tari_common::configuration::Network; use tari_common_sqlite::{error::SqliteStorageError, sqlite_connection_pool::PooledDbConnection}; use tari_common_types::types::{Commitment, PrivateKey, PublicKey, Signature}; use tari_crypto::keys::{PublicKey as PK, SecretKey}; -use tari_key_manager::key_manager_service::{storage::sqlite_db::KeyManagerSqliteDatabase, KeyManagerInterface, KeyId}; +use tari_key_manager::key_manager_service::{storage::sqlite_db::KeyManagerSqliteDatabase, KeyId, KeyManagerInterface}; use tari_script::{inputs, script, ExecutionStack, TariScript}; use super::transaction_components::{TransactionInputVersion, TransactionOutputVersion}; @@ -43,6 +43,7 @@ use crate::{ MemoryDbKeyManager, TariKeyId, TransactionKeyManagerBranch, + TransactionKeyManagerLabel, TransactionKeyManagerInterface, TransactionKeyManagerWrapper, TxoStage, @@ -729,7 +730,11 @@ pub async fn create_stx_protocol_internal( .get_next_key(TransactionKeyManagerBranch::SenderOffset.get_branch_key()) .await .unwrap(); - let script_key_id = KeyId::Derived {branch: TransactionKeyManagerBranch::CommitmentMask.get_branch_key(), index:spending_key.managed_index().unwrap() }; + let script_key_id = KeyId::Derived { + branch: TransactionKeyManagerBranch::CommitmentMask.get_branch_key(), + label: TransactionKeyManagerLabel::ScriptKey.get_branch_key(), + index: spending_key.managed_index().unwrap(), + }; let script_public_key = key_manager.get_public_key_at_key_id(&script_key_id).await.unwrap(); let input_data = match &schema.input_data { Some(data) => data.clone(), diff --git a/base_layer/key_manager/src/key_manager_service/error.rs b/base_layer/key_manager/src/key_manager_service/error.rs index 73f78ae60d..c3cb9e3276 100644 --- a/base_layer/key_manager/src/key_manager_service/error.rs +++ b/base_layer/key_manager/src/key_manager_service/error.rs @@ -47,6 +47,10 @@ pub enum KeyManagerServiceError { RangeProofError(String), #[error("Tari Key Manager error: `{0}`")] TariKeyManagerError(#[from] KMError), + #[error("Unknown error: `{0}`")] + UnknownError(String), + #[error("Ledger error: `{0}`")] + LedgerError(String), } impl From for KeyManagerServiceError { diff --git a/base_layer/key_manager/src/key_manager_service/interface.rs b/base_layer/key_manager/src/key_manager_service/interface.rs index 82c287406c..7f1bb8f17e 100644 --- a/base_layer/key_manager/src/key_manager_service/interface.rs +++ b/base_layer/key_manager/src/key_manager_service/interface.rs @@ -46,6 +46,7 @@ pub enum KeyId { }, Derived { branch: String, + label: String, index: u64, }, Imported { @@ -87,6 +88,7 @@ where PK: Clone } pub const MANAGED_KEY_BRANCH: &str = "managed"; +pub const DERIVED_KEY_BRANCH: &str = "derived"; pub const IMPORTED_KEY_BRANCH: &str = "imported"; pub const ZERO_KEY_BRANCH: &str = "zero"; @@ -97,7 +99,11 @@ where PK: ByteArray fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { KeyId::Managed { branch: b, index: i } => write!(f, "{}.{}.{}", MANAGED_KEY_BRANCH, b, i), - KeyId::Derived { branch: b, index: i } => write!(f, "{}.{}.{}", MANAGED_KEY_BRANCH, b, i), + KeyId::Derived { + branch: b, + label: l, + index: i, + } => write!(f, "{}.{}.{}.{}", DERIVED_KEY_BRANCH, b, l, i), KeyId::Imported { key: public_key } => write!(f, "{}.{}", IMPORTED_KEY_BRANCH, public_key.to_hex()), KeyId::Zero => write!(f, "{}", ZERO_KEY_BRANCH), } @@ -134,6 +140,19 @@ where PK: ByteArray Ok(KeyId::Imported { key }) }, ZERO_KEY_BRANCH => Ok(KeyId::Zero), + DERIVED_KEY_BRANCH =>{ + if parts.len() != 4 { + return Err("Wrong format".to_string()); + } + let index = parts[3] + .parse() + .map_err(|_| "Index for default, invalid u64".to_string())?; + Ok(KeyId::Derived { + branch: parts[1].into(), + label: parts[2].into(), + index, + }) + } _ => Err("Wrong format".to_string()), }, } diff --git a/base_layer/key_manager/src/key_manager_service/service.rs b/base_layer/key_manager/src/key_manager_service/service.rs index eded59975b..21c53e4820 100644 --- a/base_layer/key_manager/src/key_manager_service/service.rs +++ b/base_layer/key_manager/src/key_manager_service/service.rs @@ -21,10 +21,16 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use std::collections::HashMap; +use blake2::Blake2b; +use digest::consts::U64; use futures::lock::Mutex; use log::*; -use tari_crypto::keys::PublicKey; -use tari_utilities::hex::Hex; +use tari_crypto::{ + hash_domain, + hashing::DomainSeparatedHasher, + keys::{PublicKey, SecretKey}, +}; +use tari_utilities::{hex::Hex, ByteArray}; use crate::{ cipher_seed::CipherSeed, @@ -41,6 +47,8 @@ use crate::{ const LOG_TARGET: &str = "key_manager::key_manager_service"; const KEY_MANAGER_MAX_SEARCH_DEPTH: u64 = 1_000_000; +hash_domain!(KeyManagerHashingDomain, "com.tari.base_layer.key_manager", 1); + pub struct KeyManagerInner { key_managers: HashMap>>, db: KeyManagerDatabase, @@ -128,14 +136,25 @@ where .await; Ok(km.derive_public_key(*index)?.key) }, - KeyId::Derived { branch, index } => { + KeyId::Derived { branch, index, .. } => { let km = self .key_managers .get(branch) .ok_or(KeyManagerServiceError::UnknownKeyBranch)? .lock() .await; - Ok(km.derive_public_key(*index)?.key) + let branch_key = km.get_private_key(*index)?; + + let public_key = { + let hasher = DomainSeparatedHasher::, KeyManagerHashingDomain>::new_with_label("Key manager derived key"); + let hasher = hasher.chain(branch_key.as_bytes()).finalize(); + let private_key = PK::K::from_uniform_bytes(hasher.as_ref()).map_err(|_| { + KeyManagerServiceError::UnknownError("Invalid private key for Key manager derived key".to_string() + ) + })?; + PK::from_secret_key(&private_key) + }; + Ok(public_key) }, KeyId::Imported { key } => Ok(key.clone()), KeyId::Zero => Ok(PK::default()), diff --git a/base_layer/wallet/src/output_manager_service/recovery/standard_outputs_recoverer.rs b/base_layer/wallet/src/output_manager_service/recovery/standard_outputs_recoverer.rs index af92c2850a..e151ef7aae 100644 --- a/base_layer/wallet/src/output_manager_service/recovery/standard_outputs_recoverer.rs +++ b/base_layer/wallet/src/output_manager_service/recovery/standard_outputs_recoverer.rs @@ -29,9 +29,10 @@ use tari_core::transactions::{ tari_amount::MicroMinotari, transaction_components::{OutputType, TransactionError, TransactionOutput, WalletOutput}, }; +use tari_key_manager::key_manager_service::KeyId; use tari_script::{inputs, script, ExecutionStack, Opcode, TariScript}; use tari_utilities::hex::Hex; -use tari_key_manager::key_manager_service::KeyId; +use tari_core::transactions::key_manager::TransactionKeyManagerLabel; use crate::output_manager_service::{ error::{OutputManagerError, OutputManagerStorageError}, @@ -194,7 +195,11 @@ where ) -> Result, OutputManagerError> { let (input_data, script_key) = if script == &script!(Nop) { // This is a nop, so we can just create a new key an create the input stack. - let key = KeyId::Derived {branch: TransactionKeyManagerBranch::CommitmentMask.get_branch_key(), index:spending_key.managed_index().unwrap() }; + let key = KeyId::Derived { + branch: TransactionKeyManagerBranch::CommitmentMask.get_branch_key(), + label: TransactionKeyManagerLabel::ScriptKey.get_branch_key(), + index: spending_key.managed_index().unwrap(), + }; let public_key = self.master_key_manager.get_public_key_at_key_id(&key).await?; (inputs!(public_key), key) } else { @@ -277,6 +282,7 @@ where TariKeyId::Derived { branch: TransactionKeyManagerBranch::CommitmentMask.get_branch_key(), + label: TransactionKeyManagerLabel::ScriptKey.get_branch_key(), index: found_index, } }; From b1454c0a9a771a9edc397d489a99a514fb4c54ee Mon Sep 17 00:00:00 2001 From: brianp Date: Wed, 24 Apr 2024 12:15:25 +0200 Subject: [PATCH 15/49] minor changes --- .../wallet/src/handlers/get_script_offset.rs | 17 +++++++++++++++++ .../wallet/src/handlers/get_script_signature.rs | 2 ++ .../minotari_ledger_wallet/wallet/src/main.rs | 5 +++++ .../core/src/transactions/key_manager/inner.rs | 6 ++++-- 4 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs new file mode 100644 index 0000000000..626ce4549b --- /dev/null +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs @@ -0,0 +1,17 @@ +// Copyright 2024 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use ledger_device_sdk::{io::Comm, ui::gadgets::SingleMessage}; + +use crate::{alloc::string::ToString, AppSW, RESPONSE_VERSION}; + +pub fn handler_get_script_offset(comm: &mut Comm) -> Result<(), AppSW> { + let data = comm.get_data().map_err(|_| AppSW::WrongApduLength)?; + + SingleMessage::new(&"Finished".to_string()).show_and_wait(); + + comm.append(&[RESPONSE_VERSION]); // version + comm.reply_ok(); + + Ok(()) +} diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs index 5e6bf8b07b..1c12947eb1 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs @@ -90,6 +90,7 @@ pub fn handler_get_script_signature( }, }; + // We offset 8 everytime because each independent payload contains the account let script_private_key = get_key_from_uniform_bytes(&raw_key.as_ref())?; let value = get_key_from_canonical_bytes(&signer_ctx.payload[8..40])?; let spend_private_key = get_key_from_canonical_bytes(&signer_ctx.payload[48..80])?; @@ -125,5 +126,6 @@ pub fn handler_get_script_signature( comm.append(&script_signature.to_vec()); comm.reply_ok(); + signer_ctx.reset(); Ok(()) } diff --git a/applications/minotari_ledger_wallet/wallet/src/main.rs b/applications/minotari_ledger_wallet/wallet/src/main.rs index 7c37b71a8c..2321c06a33 100644 --- a/applications/minotari_ledger_wallet/wallet/src/main.rs +++ b/applications/minotari_ledger_wallet/wallet/src/main.rs @@ -15,6 +15,7 @@ mod app_ui { mod handlers { pub mod get_private_key; pub mod get_public_key; + pub mod get_script_offset; pub mod get_script_signature; pub mod get_version; } @@ -26,6 +27,7 @@ use critical_section::RawRestoreState; use handlers::{ get_private_key::handler_get_private_key, get_public_key::handler_get_public_key, + get_script_offset::handler_get_script_offset, get_script_signature::{handler_get_script_signature, SignerCtx}, get_version::handler_get_version, }; @@ -104,6 +106,7 @@ pub enum Instruction { GetPrivateKey, GetPublicKey, GetScriptSignature { chunk: u8, more: bool }, + GetScriptOffset, } const P2_SCRIPT_SIG_MORE: u8 = 0x01; @@ -132,6 +135,7 @@ impl TryFrom for Instruction { chunk: value.p1, more: value.p2 == P2_SCRIPT_SIG_MORE, }), + (6, 0, 0) => Ok(Instruction::GetScriptOffset), (3..=4, _, _) => Err(AppSW::WrongP1P2), (_, _, _) => Err(AppSW::InsNotSupported), } @@ -176,5 +180,6 @@ fn handle_apdu(comm: &mut Comm, ins: Instruction, signer_ctx: &mut SignerCtx) -> Instruction::GetPrivateKey => handler_get_private_key(comm), Instruction::GetPublicKey => handler_get_public_key(comm), Instruction::GetScriptSignature { chunk, more } => handler_get_script_signature(comm, chunk, more, signer_ctx), + Instruction::GetScriptOffset => handler_get_script_offset(comm), } } diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index b7d53affe9..a214ae1d38 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -547,7 +547,6 @@ where TBackend: KeyManagerBackend + 'static data.push(r_x.as_bytes().to_vec()); data.push(r_y.as_bytes().to_vec()); data.push(challenge.to_vec()); - debug!(target: LOG_TARGET, "challenge: {:?} challenge size {:?}", challenge, challenge.len()); let commands = ledger.chunk_command(Instruction::GetScriptSignature, data); let transport = get_transport()?; @@ -588,7 +587,10 @@ where TBackend: KeyManagerBackend + 'static )); } - Err(LedgerDeviceError::Instruction("GetScriptSignature didn't end right".to_string()).into()) + Err( + LedgerDeviceError::Instruction("GetScriptSignature failed to process correctly".to_string()) + .into(), + ) } }, } From a5ee62777ec9eddd133093b0639c03d6f0fdbd74 Mon Sep 17 00:00:00 2001 From: brianp Date: Wed, 24 Apr 2024 15:27:27 +0200 Subject: [PATCH 16/49] fmt --- .../src/transactions/key_manager/inner.rs | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index a214ae1d38..517670afbe 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -69,7 +69,7 @@ use crate::{ one_sided::diffie_hellman_stealth_domain_hasher, transactions::{ key_manager::{ - interface::{TransactionKeyManagerBranch, TxoStage}, + interface::{TransactionKeyManagerBranch, TransactionKeyManagerLabel, TxoStage}, TariKeyId, }, tari_amount::MicroMinotari, @@ -88,7 +88,6 @@ use crate::{ CryptoFactories, }, }; -use crate::transactions::key_manager::interface::{TransactionKeyManagerLabel}; hash_domain!( KeyManagerHashingDomain, @@ -233,10 +232,16 @@ where TBackend: KeyManagerBackend + 'static } } - fn get_domain_hasher(label: &str)->Result, KeyManagerHashingDomain>,KeyManagerServiceError>{ - let tx_label = label.parse::().map_err(|e| KeyManagerServiceError::UnknownError(format!("Could not retrieve label for derived key: {}", e)))?; - match tx_label{ - TransactionKeyManagerLabel::ScriptKey => {Ok(DomainSeparatedHasher::, KeyManagerHashingDomain>::new_with_label("script key"))}, + fn get_domain_hasher( + label: &str, + ) -> Result, KeyManagerHashingDomain>, KeyManagerServiceError> { + let tx_label = label.parse::().map_err(|e| { + KeyManagerServiceError::UnknownError(format!("Could not retrieve label for derived key: {}", e)) + })?; + match tx_label { + TransactionKeyManagerLabel::ScriptKey => { + Ok(DomainSeparatedHasher::, KeyManagerHashingDomain>::new_with_label("script key")) + }, } } @@ -267,7 +272,7 @@ where TBackend: KeyManagerBackend + 'static ) -> Result, KeyManagerServiceError> { let index = match spend_key_id { KeyId::Managed { index, .. } => *index, - KeyId::Derived { .. } => return Ok(None), + KeyId::Derived { .. } => return Ok(None), KeyId::Imported { .. } => return Ok(None), KeyId::Zero => return Ok(None), }; @@ -386,9 +391,7 @@ where TBackend: KeyManagerBackend + 'static let hasher = Self::get_domain_hasher(label)?; let hasher = hasher.chain(branch_key.as_bytes()).finalize(); let private_key = PrivateKey::from_uniform_bytes(hasher.as_ref()).map_err(|_| { - KeyManagerServiceError::UnknownError( - format!("Invalid private key for {}", label), - ) + KeyManagerServiceError::UnknownError(format!("Invalid private key for {}", label)) })?; let private_key = private_key + k; Ok(private_key) From c922f0f37634af429257316c02a423395f851314 Mon Sep 17 00:00:00 2001 From: brianp Date: Wed, 24 Apr 2024 15:27:48 +0200 Subject: [PATCH 17/49] Only hit the ledger for derived keys --- .../src/transactions/key_manager/inner.rs | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index 517670afbe..7af6bda7b8 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -520,22 +520,8 @@ where TBackend: KeyManagerBackend + 'static script_message, ); - match &self.wallet_type { - WalletType::Software(k, pk) => { - let script_private_key = self.get_private_key(script_key_id).await?; - let script_signature = ComAndPubSignature::sign( - value, - &spend_private_key, - &script_private_key, - &r_a, - &r_x, - &r_y, - &challenge, - &*self.crypto_factories.commitment, - )?; - Ok(script_signature) - }, - WalletType::Ledger(ledger) => { + match (&self.wallet_type, script_key_id) { + (WalletType::Ledger(ledger), KeyId::Derived { .. }) => { #[cfg(not(feature = "ledger"))] { return Err(TransactionError::LedgerDeviceError(LedgerDeviceError::NotSupported)); @@ -596,6 +582,20 @@ where TBackend: KeyManagerBackend + 'static ) } }, + (_, _) => { + let script_private_key = self.get_private_key(script_key_id).await?; + let script_signature = ComAndPubSignature::sign( + value, + &spend_private_key, + &script_private_key, + &r_a, + &r_x, + &r_y, + &challenge, + &*self.crypto_factories.commitment, + )?; + Ok(script_signature) + }, } } From 34f03a9368a656f48541fabeb653bbab7b24fec0 Mon Sep 17 00:00:00 2001 From: brianp Date: Thu, 25 Apr 2024 17:03:52 +0200 Subject: [PATCH 18/49] Mask alpha on the ledger --- .../comms/src/ledger_wallet.rs | 4 +- .../src/handlers/get_script_signature.rs | 27 ++++++------- .../wallet/src/utils.rs | 9 +++++ .../src/transactions/key_manager/inner.rs | 38 ++++++++++++++----- 4 files changed, 51 insertions(+), 27 deletions(-) diff --git a/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs b/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs index ceffdc5c32..2c976436f4 100644 --- a/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs +++ b/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs @@ -125,7 +125,7 @@ impl LedgerWallet { pub fn chunk_command(&self, instruction: Instruction, data: Vec>) -> Vec>> { let num_chunks = data.len(); - let mut more = 0; + let mut more; let mut commands = vec![]; for (i, chunk) in data.iter().enumerate() { @@ -136,7 +136,7 @@ impl LedgerWallet { } let mut base_data = self.account_bytes(); - base_data.extend_from_slice(&chunk); + base_data.extend_from_slice(chunk); commands.push(Command { inner: APDUCommand { diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs index 1c12947eb1..d408bd5c78 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs @@ -11,7 +11,7 @@ use tari_crypto::ristretto::{ use crate::{ alloc::string::ToString, - utils::{get_key_from_canonical_bytes, get_key_from_uniform_bytes, get_raw_key, u64_to_string}, + utils::{get_key_from_canonical_bytes, get_key_from_uniform_bytes, get_raw_key, mask_a, u64_to_string}, AppSW, BIP32_COIN_TYPE, RESPONSE_VERSION, @@ -19,7 +19,7 @@ use crate::{ const STATIC_INDEX: &str = "42"; -const MAX_TRANSACTION_LEN: usize = 272; +const MAX_TRANSACTION_LEN: usize = 312; pub struct SignerCtx { payload: [u8; MAX_TRANSACTION_LEN], payload_len: usize, @@ -80,8 +80,6 @@ pub fn handler_get_script_signature( bip32_path.push_str(STATIC_INDEX); let path: [u32; 5] = make_bip32_path(bip32_path.as_bytes()); - SingleMessage::new(&bip32_path).show_and_wait(); - let raw_key = match get_raw_key(&path) { Ok(val) => val, Err(e) => { @@ -91,17 +89,18 @@ pub fn handler_get_script_signature( }; // We offset 8 everytime because each independent payload contains the account - let script_private_key = get_key_from_uniform_bytes(&raw_key.as_ref())?; - let value = get_key_from_canonical_bytes(&signer_ctx.payload[8..40])?; - let spend_private_key = get_key_from_canonical_bytes(&signer_ctx.payload[48..80])?; - let r_a = get_key_from_canonical_bytes(&signer_ctx.payload[88..120])?; - let r_x = get_key_from_canonical_bytes(&signer_ctx.payload[128..160])?; - let r_y = get_key_from_canonical_bytes(&signer_ctx.payload[168..200])?; - let challenge = &signer_ctx.payload[208..272]; + let alpha = get_key_from_uniform_bytes(&raw_key.as_ref())?; + let commitment = get_key_from_canonical_bytes(&signer_ctx.payload[8..40])?; + let script_private_key = mask_a(alpha, commitment)?; - let factory = ExtendedPedersenCommitmentFactory::default(); + let value = get_key_from_canonical_bytes(&signer_ctx.payload[48..80])?; + let spend_private_key = get_key_from_canonical_bytes(&signer_ctx.payload[88..120])?; + let r_a = get_key_from_canonical_bytes(&signer_ctx.payload[128..160])?; + let r_x = get_key_from_canonical_bytes(&signer_ctx.payload[168..200])?; + let r_y = get_key_from_canonical_bytes(&signer_ctx.payload[208..240])?; + let challenge = &signer_ctx.payload[248..312]; - SingleMessage::new(&"Signing...".to_string()).show(); + let factory = ExtendedPedersenCommitmentFactory::default(); let script_signature = match RistrettoComAndPubSig::sign( &value, @@ -120,8 +119,6 @@ pub fn handler_get_script_signature( }, }; - SingleMessage::new(&"Success!".to_string()).show_and_wait(); - comm.append(&[RESPONSE_VERSION]); // version comm.append(&script_signature.to_vec()); comm.reply_ok(); diff --git a/applications/minotari_ledger_wallet/wallet/src/utils.rs b/applications/minotari_ledger_wallet/wallet/src/utils.rs index 1998be1c53..ffb386214a 100644 --- a/applications/minotari_ledger_wallet/wallet/src/utils.rs +++ b/applications/minotari_ledger_wallet/wallet/src/utils.rs @@ -22,6 +22,7 @@ use zeroize::Zeroizing; use crate::alloc::string::{String, ToString}; hash_domain!(LedgerHashDomain, "com.tari.minotari_ledger_wallet", 0); +hash_domain!(KeyManagerHashingDomain, "com.tari.base_layer.key_manager", 1); use crate::AppSW; @@ -217,3 +218,11 @@ pub fn get_key_from_canonical_bytes(bytes: &[u8]) -> Result Result { + let hasher = DomainSeparatedHasher::, KeyManagerHashingDomain>::new_with_label("script key"); + let hasher = hasher.chain(commitment.as_bytes()).finalize(); + let private_key = get_key_from_uniform_bytes(hasher.as_ref())?; + + Ok(private_key + alpha) +} diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index 7af6bda7b8..4b680e5b5c 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -19,11 +19,10 @@ // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -use std::{collections::HashMap, ops::Shl, thread, thread::sleep, time::Duration}; +use std::{collections::HashMap, ops::Shl}; use blake2::Blake2b; use digest::consts::U64; -use futures::AsyncReadExt; use log::*; use minotari_ledger_wallet_comms::ledger_wallet::get_transport; #[cfg(feature = "ledger")] @@ -521,7 +520,14 @@ where TBackend: KeyManagerBackend + 'static ); match (&self.wallet_type, script_key_id) { - (WalletType::Ledger(ledger), KeyId::Derived { .. }) => { + ( + WalletType::Ledger(ledger), + KeyId::Derived { + branch, + label: _, + index, + }, + ) => { #[cfg(not(feature = "ledger"))] { return Err(TransactionError::LedgerDeviceError(LedgerDeviceError::NotSupported)); @@ -529,13 +535,25 @@ where TBackend: KeyManagerBackend + 'static #[cfg(feature = "ledger")] { - let mut data: Vec> = vec![]; - data.push(value.as_bytes().to_vec()); - data.push(spend_private_key.as_bytes().to_vec()); - data.push(r_a.as_bytes().to_vec()); - data.push(r_x.as_bytes().to_vec()); - data.push(r_y.as_bytes().to_vec()); - data.push(challenge.to_vec()); + let km = self + .key_managers + .get(branch) + .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .read() + .await; + let branch_key = km + .get_private_key(*index) + .map_err(|e| TransactionError::KeyManagerError(e.to_string()))?; + + let data: Vec> = vec![ + branch_key.as_bytes().to_vec(), + value.as_bytes().to_vec(), + spend_private_key.as_bytes().to_vec(), + r_a.as_bytes().to_vec(), + r_x.as_bytes().to_vec(), + r_y.as_bytes().to_vec(), + challenge.to_vec(), + ]; let commands = ledger.chunk_command(Instruction::GetScriptSignature, data); let transport = get_transport()?; From 192a3378d27edffb43f38a78534249de6b1f6eb3 Mon Sep 17 00:00:00 2001 From: brianp Date: Thu, 25 Apr 2024 17:18:03 +0200 Subject: [PATCH 19/49] Move key derivation into helper --- .../src/handlers/get_script_signature.rs | 23 ++------------- .../wallet/src/utils.rs | 28 ++++++++++++++++--- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs index d408bd5c78..bcfb517152 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs @@ -3,7 +3,7 @@ use alloc::format; -use ledger_device_sdk::{ecc::make_bip32_path, io::Comm, ui::gadgets::SingleMessage}; +use ledger_device_sdk::{io::Comm, ui::gadgets::SingleMessage}; use tari_crypto::ristretto::{ pedersen::extended_commitment_factory::ExtendedPedersenCommitmentFactory, RistrettoComAndPubSig, @@ -11,9 +11,8 @@ use tari_crypto::ristretto::{ use crate::{ alloc::string::ToString, - utils::{get_key_from_canonical_bytes, get_key_from_uniform_bytes, get_raw_key, mask_a, u64_to_string}, + utils::{derive_from_bip32_key, get_key_from_canonical_bytes, mask_a, u64_to_string}, AppSW, - BIP32_COIN_TYPE, RESPONSE_VERSION, }; @@ -72,24 +71,8 @@ pub fn handler_get_script_signature( account_bytes.clone_from_slice(&signer_ctx.payload[0..8]); let account = u64_to_string(u64::from_le_bytes(account_bytes)); - let mut bip32_path = "m/44'/".to_string(); - bip32_path.push_str(&BIP32_COIN_TYPE.to_string()); - bip32_path.push_str(&"'/"); - bip32_path.push_str(&account); - bip32_path.push_str(&"'/0/"); - bip32_path.push_str(STATIC_INDEX); - let path: [u32; 5] = make_bip32_path(bip32_path.as_bytes()); - - let raw_key = match get_raw_key(&path) { - Ok(val) => val, - Err(e) => { - SingleMessage::new(&format!("Key error {:?}", e)).show_and_wait(); - return Err(AppSW::KeyDeriveFail); - }, - }; - // We offset 8 everytime because each independent payload contains the account - let alpha = get_key_from_uniform_bytes(&raw_key.as_ref())?; + let alpha = derive_from_bip32_key(account, STATIC_INDEX.to_string())?; let commitment = get_key_from_canonical_bytes(&signer_ctx.payload[8..40])?; let script_private_key = mask_a(alpha, commitment)?; diff --git a/applications/minotari_ledger_wallet/wallet/src/utils.rs b/applications/minotari_ledger_wallet/wallet/src/utils.rs index ffb386214a..773e400327 100644 --- a/applications/minotari_ledger_wallet/wallet/src/utils.rs +++ b/applications/minotari_ledger_wallet/wallet/src/utils.rs @@ -6,7 +6,7 @@ use alloc::format; use blake2::{Blake2b, Digest}; use digest::consts::U64; use ledger_device_sdk::{ - ecc::{bip32_derive, CurvesId, CxError}, + ecc::{bip32_derive, make_bip32_path, CurvesId, CxError}, io::SyscallError, ui::gadgets::SingleMessage, }; @@ -19,13 +19,15 @@ use tari_crypto::{ }; use zeroize::Zeroizing; -use crate::alloc::string::{String, ToString}; +use crate::{ + alloc::string::{String, ToString}, + AppSW, + BIP32_COIN_TYPE, +}; hash_domain!(LedgerHashDomain, "com.tari.minotari_ledger_wallet", 0); hash_domain!(KeyManagerHashingDomain, "com.tari.base_layer.key_manager", 1); -use crate::AppSW; - /// BIP32 path stored as an array of [`u32`]. /// /// # Generic arguments @@ -226,3 +228,21 @@ pub fn mask_a(alpha: RistrettoSecretKey, commitment: RistrettoSecretKey) -> Resu Ok(private_key + alpha) } + +pub fn derive_from_bip32_key(account: String, index: String) -> Result { + let mut bip32_path = "m/44'/".to_string(); + bip32_path.push_str(&BIP32_COIN_TYPE.to_string()); + bip32_path.push_str(&"'/"); + bip32_path.push_str(&account); + bip32_path.push_str(&"'/0/"); + bip32_path.push_str(&index); + let path: [u32; 5] = make_bip32_path(bip32_path.as_bytes()); + + match get_raw_key(&path) { + Ok(val) => get_key_from_uniform_bytes(&val.as_ref()), + Err(e) => { + SingleMessage::new(&format!("Key error {:?}", e)).show_and_wait(); + return Err(AppSW::KeyDeriveFail); + }, + } +} From 0512bccfa4e4131f4fa7cf41ba86a3eae37a3085 Mon Sep 17 00:00:00 2001 From: brianp Date: Thu, 25 Apr 2024 17:31:35 +0200 Subject: [PATCH 20/49] Remove GetPrivateKey function at no point should the private key be revealed --- .../wallet/src/handlers/get_private_key.rs | 53 ------------------- .../minotari_ledger_wallet/wallet/src/main.rs | 5 -- 2 files changed, 58 deletions(-) delete mode 100644 applications/minotari_ledger_wallet/wallet/src/handlers/get_private_key.rs diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_private_key.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_private_key.rs deleted file mode 100644 index 057767358a..0000000000 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_private_key.rs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2024 The Tari Project -// SPDX-License-Identifier: BSD-3-Clause - -use alloc::format; - -use ledger_device_sdk::{ecc::make_bip32_path, io::Comm, ui::gadgets::SingleMessage}; -use tari_crypto::tari_utilities::ByteArray; - -use crate::{ - alloc::string::ToString, - utils::{get_key_from_uniform_bytes, get_raw_key, u64_to_string}, - AppSW, - BIP32_COIN_TYPE, - RESPONSE_VERSION, -}; - -pub fn handler_get_private_key(comm: &mut Comm) -> Result<(), AppSW> { - let data = comm.get_data().map_err(|_| AppSW::WrongApduLength)?; - - let mut account_bytes = [0u8; 8]; - account_bytes.clone_from_slice(&data[0..8]); - let account = u64_to_string(u64::from_le_bytes(account_bytes)); - - let mut address_index_bytes = [0u8; 8]; - address_index_bytes.clone_from_slice(&data[8..16]); - let address_index = u64_to_string(u64::from_le_bytes(address_index_bytes)); - - let mut bip32_path = "m/44'/".to_string(); - bip32_path.push_str(&BIP32_COIN_TYPE.to_string()); - bip32_path.push_str(&"'/"); - bip32_path.push_str(&account); - bip32_path.push_str(&"'/0/"); - bip32_path.push_str(&address_index); - let path: [u32; 5] = make_bip32_path(bip32_path.as_bytes()); - - SingleMessage::new(&bip32_path).show_and_wait(); - - let raw_key = match get_raw_key(&path) { - Ok(val) => val, - Err(e) => { - SingleMessage::new(&format!("Key error {:?}", e)).show_and_wait(); - return Err(AppSW::KeyDeriveFail); - }, - }; - - let k = get_key_from_uniform_bytes(&raw_key.as_ref())?; - - comm.append(&[RESPONSE_VERSION]); // version - comm.append(k.as_bytes()); - comm.reply_ok(); - - Ok(()) -} diff --git a/applications/minotari_ledger_wallet/wallet/src/main.rs b/applications/minotari_ledger_wallet/wallet/src/main.rs index 2321c06a33..e96dbc421d 100644 --- a/applications/minotari_ledger_wallet/wallet/src/main.rs +++ b/applications/minotari_ledger_wallet/wallet/src/main.rs @@ -13,7 +13,6 @@ mod app_ui { pub mod menu; } mod handlers { - pub mod get_private_key; pub mod get_public_key; pub mod get_script_offset; pub mod get_script_signature; @@ -25,7 +24,6 @@ use core::mem::MaybeUninit; use app_ui::menu::ui_menu_main; use critical_section::RawRestoreState; use handlers::{ - get_private_key::handler_get_private_key, get_public_key::handler_get_public_key, get_script_offset::handler_get_script_offset, get_script_signature::{handler_get_script_signature, SignerCtx}, @@ -103,7 +101,6 @@ impl From for Reply { pub enum Instruction { GetVersion, GetAppName, - GetPrivateKey, GetPublicKey, GetScriptSignature { chunk: u8, more: bool }, GetScriptOffset, @@ -129,7 +126,6 @@ impl TryFrom for Instruction { match (value.ins, value.p1, value.p2) { (1, 0, 0) => Ok(Instruction::GetVersion), (2, 0, 0) => Ok(Instruction::GetAppName), - (3, 0, 0) => Ok(Instruction::GetPrivateKey), (4, 0, 0) => Ok(Instruction::GetPublicKey), (5, 0..=6, 0 | P2_SCRIPT_SIG_MORE) => Ok(Instruction::GetScriptSignature { chunk: value.p1, @@ -177,7 +173,6 @@ fn handle_apdu(comm: &mut Comm, ins: Instruction, signer_ctx: &mut SignerCtx) -> comm.append(env!("CARGO_PKG_NAME").as_bytes()); Ok(()) }, - Instruction::GetPrivateKey => handler_get_private_key(comm), Instruction::GetPublicKey => handler_get_public_key(comm), Instruction::GetScriptSignature { chunk, more } => handler_get_script_signature(comm, chunk, more, signer_ctx), Instruction::GetScriptOffset => handler_get_script_offset(comm), From ce695e55e6472eeda439e3b097f2562646a8354e Mon Sep 17 00:00:00 2001 From: brianp Date: Fri, 26 Apr 2024 09:35:35 +0200 Subject: [PATCH 21/49] Update script offset key manager function --- .../comms/src/ledger_wallet.rs | 2 +- .../wallet/src/handlers/get_public_key.rs | 25 +---- .../src/transactions/key_manager/inner.rs | 95 +++++++++++++++++-- 3 files changed, 91 insertions(+), 31 deletions(-) diff --git a/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs b/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs index 2c976436f4..509e1fd6dd 100644 --- a/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs +++ b/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs @@ -43,9 +43,9 @@ const WALLET_CLA: u8 = 0x80; pub enum Instruction { GetVersion = 0x01, GetAppName = 0x02, - GetPrivateKey = 0x03, GetPublicKey = 0x04, GetScriptSignature = 0x05, + GetScriptOffset = 0x06, } impl Instruction { diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs index d1c7cc2a0a..f329f05593 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs @@ -1,16 +1,13 @@ // Copyright 2024 The Tari Project // SPDX-License-Identifier: BSD-3-Clause -use alloc::format; - -use ledger_device_sdk::{ecc::make_bip32_path, io::Comm, ui::gadgets::SingleMessage}; +use ledger_device_sdk::io::Comm; use tari_crypto::{keys::PublicKey, ristretto::RistrettoPublicKey, tari_utilities::ByteArray}; use crate::{ alloc::string::ToString, - utils::{get_key_from_uniform_bytes, get_raw_key, u64_to_string}, + utils::{derive_from_bip32_key, u64_to_string}, AppSW, - BIP32_COIN_TYPE, RESPONSE_VERSION, }; @@ -23,23 +20,7 @@ pub fn handler_get_public_key(comm: &mut Comm) -> Result<(), AppSW> { account_bytes.clone_from_slice(&data[0..8]); let account = u64_to_string(u64::from_le_bytes(account_bytes)); - let mut bip32_path = "m/44'/".to_string(); - bip32_path.push_str(&BIP32_COIN_TYPE.to_string()); - bip32_path.push_str(&"'/"); - bip32_path.push_str(&account); - bip32_path.push_str(&"'/0/"); - bip32_path.push_str(STATIC_INDEX); - let path: [u32; 5] = make_bip32_path(bip32_path.as_bytes()); - - let raw_key = match get_raw_key(&path) { - Ok(val) => val, - Err(e) => { - SingleMessage::new(&format!("Key error {:?}", e)).show_and_wait(); - return Err(AppSW::KeyDeriveFail); - }, - }; - - let pk = match get_key_from_uniform_bytes(&raw_key.as_ref()) { + let pk = match derive_from_bip32_key(account, STATIC_INDEX.to_string()) { Ok(k) => RistrettoPublicKey::from_secret_key(&k), Err(e) => return Err(e), }; diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index 4b680e5b5c..e70e34e229 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -682,17 +682,96 @@ where TBackend: KeyManagerBackend + 'static script_key_ids: &[TariKeyId], sender_offset_key_ids: &[TariKeyId], ) -> Result { - let mut total_sender_offset_private_key = PrivateKey::default(); - for sender_offset_key_id in sender_offset_key_ids { - total_sender_offset_private_key = - total_sender_offset_private_key + self.get_private_key(sender_offset_key_id).await?; + let mut sender_offset_keys = vec![]; + for script_key_id in sender_offset_key_ids { + sender_offset_keys.push(self.get_private_key(script_key_id).await?); } - let mut total_script_private_key = PrivateKey::default(); + + let mut managed_script_keys: Vec = vec![]; + let mut derived_key_commitments = vec![]; for script_key_id in script_key_ids { - total_script_private_key = total_script_private_key + self.get_private_key(script_key_id).await?; + match script_key_id { + KeyId::Derived { + branch, + label: _, + index, + } => { + // Early exit + if let WalletType::Software(_, _) = self.wallet_type { + // If this happens we actually expect a panic, so pushing to the array is + // pointless but ya never know eh? + managed_script_keys.push(self.get_private_key(script_key_id).await?); + continue; + } + + let km = self + .key_managers + .get(branch) + .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .read() + .await; + let branch_key = km + .get_private_key(*index) + .map_err(|e| TransactionError::KeyManagerError(e.to_string()))?; + derived_key_commitments.push((branch_key, index)); + }, + KeyId::Imported { .. } | KeyId::Managed { .. } | KeyId::Zero => { + managed_script_keys.push(self.get_private_key(script_key_id).await?) + }, + } + managed_script_keys.push(self.get_private_key(script_key_id).await?); + } + + match &self.wallet_type { + WalletType::Ledger(ledger) => { + let data: Vec> = vec![ + //branch_key.as_bytes().to_vec(), + ]; + + let commands = ledger.chunk_command(Instruction::GetScriptOffset, data); + let transport = get_transport()?; + + let mut result = None; + for command in commands { + match command.execute_with_transport(&transport) { + Ok(r) => result = Some(r), + Err(e) => { + return Err(LedgerDeviceError::Instruction(format!("GetScriptSignature: {}", e)).into()) + }, + } + } + + if let Some(result) = result { + if result.data().len() < 33 { + debug!(target: LOG_TARGET, "result less than 33"); + return Err(LedgerDeviceError::Processing(format!( + "'get_script_offset' insufficient data - expected 33 got {} bytes ({:?})", + result.data().len(), + result + )) + .into()); + } + let data = result.data(); + debug!(target: LOG_TARGET, "result length: {}, data: {:?}", result.data().len(), result.data()); + return PrivateKey::from_canonical_bytes(&data[1..33]) + .map_err(|e| TransactionError::InvalidSignatureError(e.to_string())); + } + + Err(LedgerDeviceError::Instruction("GetScriptSignature failed to process correctly".to_string()).into()) + }, + WalletType::Software(_p, _pk) => { + let mut total_sender_offset_private_key = PrivateKey::default(); + for sender_offset_key_id in sender_offset_keys { + total_sender_offset_private_key = total_sender_offset_private_key + sender_offset_key_id; + } + let mut total_script_private_key = PrivateKey::default(); + for script_key_id in managed_script_keys { + total_script_private_key = total_script_private_key + script_key_id; + } + let script_offset = total_script_private_key - total_sender_offset_private_key; + Ok(script_offset) + }, } - let script_offset = total_script_private_key - total_sender_offset_private_key; - Ok(script_offset) } async fn get_metadata_signature_ephemeral_private_key_pair( From ec6974c0f6713be9523469dcb891ff9748e16c6e Mon Sep 17 00:00:00 2001 From: brianp Date: Fri, 26 Apr 2024 13:48:39 +0200 Subject: [PATCH 22/49] Only append and read the account once per process --- .../comms/src/ledger_wallet.rs | 6 ++++- .../src/handlers/get_script_signature.rs | 27 +++++++++---------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs b/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs index 509e1fd6dd..33834c88da 100644 --- a/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs +++ b/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs @@ -135,7 +135,11 @@ impl LedgerWallet { more = 1; } - let mut base_data = self.account_bytes(); + // Prepend the account on the first payload + let mut base_data = vec![]; + if i == 0 { + base_data.extend_from_slice(&self.account_bytes()); + } base_data.extend_from_slice(chunk); commands.push(Command { diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs index bcfb517152..3ee0ca89ac 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs @@ -44,13 +44,18 @@ pub fn handler_get_script_signature( comm: &mut Comm, chunk: u8, more: bool, - signer_ctx: &mut SignerCtx, + signer_ctx: &mut ScriptSignatureCtx, ) -> Result<(), AppSW> { let data = comm.get_data().map_err(|_| AppSW::WrongApduLength)?; if chunk == 0 { // Reset transaction context signer_ctx.reset(); + + // Set the account for the transaction + let mut account_bytes = [0u8; 8]; + account_bytes.clone_from_slice(&signer_ctx.payload[0..8]); + signer_ctx.account = u64::from_le_bytes(account_bytes); } if signer_ctx.payload_len + data.len() > MAX_TRANSACTION_LEN { @@ -66,22 +71,16 @@ pub fn handler_get_script_signature( return Ok(()); } - // Derive private key - let mut account_bytes = [0u8; 8]; - account_bytes.clone_from_slice(&signer_ctx.payload[0..8]); - let account = u64_to_string(u64::from_le_bytes(account_bytes)); - - // We offset 8 everytime because each independent payload contains the account - let alpha = derive_from_bip32_key(account, STATIC_INDEX.to_string())?; + let alpha = derive_from_bip32_key(signer_ctx.account, STATIC_INDEX)?; let commitment = get_key_from_canonical_bytes(&signer_ctx.payload[8..40])?; let script_private_key = mask_a(alpha, commitment)?; - let value = get_key_from_canonical_bytes(&signer_ctx.payload[48..80])?; - let spend_private_key = get_key_from_canonical_bytes(&signer_ctx.payload[88..120])?; - let r_a = get_key_from_canonical_bytes(&signer_ctx.payload[128..160])?; - let r_x = get_key_from_canonical_bytes(&signer_ctx.payload[168..200])?; - let r_y = get_key_from_canonical_bytes(&signer_ctx.payload[208..240])?; - let challenge = &signer_ctx.payload[248..312]; + let value = get_key_from_canonical_bytes(&signer_ctx.payload[40..72])?; + let spend_private_key = get_key_from_canonical_bytes(&signer_ctx.payload[72..104])?; + let r_a = get_key_from_canonical_bytes(&signer_ctx.payload[104..136])?; + let r_x = get_key_from_canonical_bytes(&signer_ctx.payload[136..168])?; + let r_y = get_key_from_canonical_bytes(&signer_ctx.payload[168..200])?; + let challenge = &signer_ctx.payload[200..264]; let factory = ExtendedPedersenCommitmentFactory::default(); From 86eb90b05f3438713632714b678d7a4df7b24eb1 Mon Sep 17 00:00:00 2001 From: brianp Date: Fri, 26 Apr 2024 13:51:56 +0200 Subject: [PATCH 23/49] Update the key derivation params --- .../wallet/src/handlers/get_public_key.rs | 13 ++++--------- .../wallet/src/handlers/get_script_signature.rs | 13 +++++++++---- .../minotari_ledger_wallet/wallet/src/main.rs | 16 +++++++++++----- .../minotari_ledger_wallet/wallet/src/utils.rs | 5 ++++- 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs index f329f05593..b43b19631b 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs @@ -4,23 +4,18 @@ use ledger_device_sdk::io::Comm; use tari_crypto::{keys::PublicKey, ristretto::RistrettoPublicKey, tari_utilities::ByteArray}; -use crate::{ - alloc::string::ToString, - utils::{derive_from_bip32_key, u64_to_string}, - AppSW, - RESPONSE_VERSION, -}; +use crate::{utils::derive_from_bip32_key, AppSW, RESPONSE_VERSION}; -const STATIC_INDEX: &str = "42"; +const STATIC_INDEX: u64 = 42; pub fn handler_get_public_key(comm: &mut Comm) -> Result<(), AppSW> { let data = comm.get_data().map_err(|_| AppSW::WrongApduLength)?; let mut account_bytes = [0u8; 8]; account_bytes.clone_from_slice(&data[0..8]); - let account = u64_to_string(u64::from_le_bytes(account_bytes)); + let account = u64::from_le_bytes(account_bytes); - let pk = match derive_from_bip32_key(account, STATIC_INDEX.to_string()) { + let pk = match derive_from_bip32_key(account, STATIC_INDEX) { Ok(k) => RistrettoPublicKey::from_secret_key(&k), Err(e) => return Err(e), }; diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs index 3ee0ca89ac..93bf077229 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs @@ -11,25 +11,27 @@ use tari_crypto::ristretto::{ use crate::{ alloc::string::ToString, - utils::{derive_from_bip32_key, get_key_from_canonical_bytes, mask_a, u64_to_string}, + utils::{derive_from_bip32_key, get_key_from_canonical_bytes, mask_a}, AppSW, RESPONSE_VERSION, }; -const STATIC_INDEX: &str = "42"; +const STATIC_INDEX: u64 = 42; const MAX_TRANSACTION_LEN: usize = 312; -pub struct SignerCtx { +pub struct ScriptSignatureCtx { payload: [u8; MAX_TRANSACTION_LEN], payload_len: usize, + account: u64, } // Implement constructor for TxInfo with default values -impl SignerCtx { +impl ScriptSignatureCtx { pub fn new() -> Self { Self { payload: [0u8; MAX_TRANSACTION_LEN], payload_len: 0, + account: 0, } } @@ -37,6 +39,7 @@ impl SignerCtx { fn reset(&mut self) { self.payload = [0u8; MAX_TRANSACTION_LEN]; self.payload_len = 0; + self.account = 0; } } @@ -105,6 +108,8 @@ pub fn handler_get_script_signature( comm.append(&script_signature.to_vec()); comm.reply_ok(); + SingleMessage::new(&format!("Finished Signature!")).show_and_wait(); + signer_ctx.reset(); Ok(()) } diff --git a/applications/minotari_ledger_wallet/wallet/src/main.rs b/applications/minotari_ledger_wallet/wallet/src/main.rs index e96dbc421d..8362057a0e 100644 --- a/applications/minotari_ledger_wallet/wallet/src/main.rs +++ b/applications/minotari_ledger_wallet/wallet/src/main.rs @@ -25,8 +25,8 @@ use app_ui::menu::ui_menu_main; use critical_section::RawRestoreState; use handlers::{ get_public_key::handler_get_public_key, - get_script_offset::handler_get_script_offset, - get_script_signature::{handler_get_script_signature, SignerCtx}, + get_script_offset::{handler_get_script_offset, ScriptOffsetCtx}, + get_script_signature::{handler_get_script_signature, ScriptSignatureCtx}, get_version::handler_get_version, }; #[cfg(feature = "pending_review_screen")] @@ -152,13 +152,14 @@ extern "C" fn sample_main() { display_pending_review(&mut comm); // This is long lived over the span the ledger app is open, across multiple interactions - let mut signer_ctx = SignerCtx::new(); + let mut signer_ctx = ScriptSignatureCtx::new(); + let mut offset_ctx = ScriptOffsetCtx::new(); loop { // Wait for either a specific button push to exit the app // or an APDU command if let Event::Command(ins) = ui_menu_main(&mut comm) { - match handle_apdu(&mut comm, ins, &mut signer_ctx) { + match handle_apdu(&mut comm, ins, &mut signer_ctx, &mut offset_ctx) { Ok(()) => comm.reply_ok(), Err(sw) => comm.reply(sw), } @@ -166,7 +167,12 @@ extern "C" fn sample_main() { } } -fn handle_apdu(comm: &mut Comm, ins: Instruction, signer_ctx: &mut SignerCtx) -> Result<(), AppSW> { +fn handle_apdu( + comm: &mut Comm, + ins: Instruction, + signer_ctx: &mut ScriptSignatureCtx, + offset_ctx: &mut ScriptOffsetCtx, +) -> Result<(), AppSW> { match ins { Instruction::GetVersion => handler_get_version(comm), Instruction::GetAppName => { diff --git a/applications/minotari_ledger_wallet/wallet/src/utils.rs b/applications/minotari_ledger_wallet/wallet/src/utils.rs index 773e400327..25361909af 100644 --- a/applications/minotari_ledger_wallet/wallet/src/utils.rs +++ b/applications/minotari_ledger_wallet/wallet/src/utils.rs @@ -229,7 +229,10 @@ pub fn mask_a(alpha: RistrettoSecretKey, commitment: RistrettoSecretKey) -> Resu Ok(private_key + alpha) } -pub fn derive_from_bip32_key(account: String, index: String) -> Result { +pub fn derive_from_bip32_key(u64_account: u64, u64_index: u64) -> Result { + let account = u64_to_string(u64_account); + let index = u64_to_string(u64_index); + let mut bip32_path = "m/44'/".to_string(); bip32_path.push_str(&BIP32_COIN_TYPE.to_string()); bip32_path.push_str(&"'/"); From b14d4e0d4334d2802ce9f87387ab4c9b81c82e9a Mon Sep 17 00:00:00 2001 From: brianp Date: Fri, 26 Apr 2024 13:52:20 +0200 Subject: [PATCH 24/49] Calculate offset from ledger --- .../wallet/src/handlers/get_script_offset.rs | 103 +++++++++++++++++- .../minotari_ledger_wallet/wallet/src/main.rs | 15 ++- .../src/transactions/key_manager/inner.rs | 37 +++++-- 3 files changed, 135 insertions(+), 20 deletions(-) diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs index 626ce4549b..75cd603fa6 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs @@ -2,16 +2,113 @@ // SPDX-License-Identifier: BSD-3-Clause use ledger_device_sdk::{io::Comm, ui::gadgets::SingleMessage}; +use tari_crypto::{ristretto::RistrettoSecretKey, tari_utilities::ByteArray}; -use crate::{alloc::string::ToString, AppSW, RESPONSE_VERSION}; +use crate::{ + alloc::string::ToString, + utils::{derive_from_bip32_key, get_key_from_canonical_bytes, mask_a}, + AppSW, + RESPONSE_VERSION, +}; -pub fn handler_get_script_offset(comm: &mut Comm) -> Result<(), AppSW> { +pub struct ScriptOffsetCtx { + total_sender_offset_private_key: RistrettoSecretKey, + total_script_private_key: RistrettoSecretKey, + account: u64, + total_offset_keys: u64, + total_script_keys: u64, + total_commitment_keys: u64, +} + +// Implement constructor for TxInfo with default values +impl ScriptOffsetCtx { + pub fn new() -> Self { + Self { + total_sender_offset_private_key: RistrettoSecretKey::default(), + total_script_private_key: RistrettoSecretKey::default(), + account: 0, + total_offset_keys: 0, + total_script_keys: 0, + total_commitment_keys: 0, + } + } + + // Implement reset for TxInfo + fn reset(&mut self) { + self.total_sender_offset_private_key = RistrettoSecretKey::default(); + self.total_script_private_key = RistrettoSecretKey::default(); + self.account = 0; + self.total_offset_keys = 0; + self.total_script_keys = 0; + self.total_commitment_keys = 0; + } +} + +fn read_instructions(offset_ctx: &mut ScriptOffsetCtx, data: &[u8]) { + let mut account_bytes = [0u8; 8]; + account_bytes.clone_from_slice(&data[0..8]); + offset_ctx.account = u64::from_le_bytes(account_bytes); + + let mut total_offset_keys = [0u8; 8]; + total_offset_keys.clone_from_slice(&data[24..32]); + offset_ctx.total_offset_keys = u64::from_le_bytes(total_offset_keys); + + let mut total_script_keys = [0u8; 8]; + total_script_keys.clone_from_slice(&data[8..16]); + offset_ctx.total_script_keys = u64::from_le_bytes(total_script_keys); + + let mut total_commitment_keys = [0u8; 8]; + total_commitment_keys.clone_from_slice(&data[16..24]); + offset_ctx.total_commitment_keys = u64::from_le_bytes(total_commitment_keys); +} +pub fn handler_get_script_offset( + comm: &mut Comm, + chunk: u8, + more: bool, + offset_ctx: &mut ScriptOffsetCtx, +) -> Result<(), AppSW> { let data = comm.get_data().map_err(|_| AppSW::WrongApduLength)?; - SingleMessage::new(&"Finished".to_string()).show_and_wait(); + if chunk == 0 { + // Reset offset context + offset_ctx.reset(); + read_instructions(offset_ctx, data); + } + + if (1..offset_ctx.total_offset_keys).contains(&(chunk as u64)) { + let k = get_key_from_canonical_bytes(&data[0..32])?; + offset_ctx.total_sender_offset_private_key = &offset_ctx.total_sender_offset_private_key + &k; + } + + if (offset_ctx.total_offset_keys..offset_ctx.total_script_keys).contains(&(chunk as u64)) { + let k = get_key_from_canonical_bytes(&data[0..32])?; + offset_ctx.total_script_private_key = &offset_ctx.total_script_private_key + &k; + } + + if (offset_ctx.total_script_keys..offset_ctx.total_commitment_keys).contains(&(chunk as u64)) { + let mut index_bytes = [0u8; 8]; + index_bytes.clone_from_slice(&data[32..40]); + let index = u64::from_le_bytes(index_bytes); + + let alpha = derive_from_bip32_key(offset_ctx.account, index)?; + let commitment = get_key_from_canonical_bytes(&data[0..32])?; + let k = mask_a(alpha, commitment)?; + + offset_ctx.total_script_private_key = &offset_ctx.total_script_private_key + &k; + } + + if more { + return Ok(()); + } + + let script_offset = &offset_ctx.total_script_private_key - &offset_ctx.total_sender_offset_private_key; comm.append(&[RESPONSE_VERSION]); // version + comm.append(&script_offset.to_vec()); comm.reply_ok(); + SingleMessage::new(&"Finished Offset!".to_string()).show_and_wait(); + + offset_ctx.reset(); Ok(()) } diff --git a/applications/minotari_ledger_wallet/wallet/src/main.rs b/applications/minotari_ledger_wallet/wallet/src/main.rs index 8362057a0e..5bd2442cee 100644 --- a/applications/minotari_ledger_wallet/wallet/src/main.rs +++ b/applications/minotari_ledger_wallet/wallet/src/main.rs @@ -103,10 +103,10 @@ pub enum Instruction { GetAppName, GetPublicKey, GetScriptSignature { chunk: u8, more: bool }, - GetScriptOffset, + GetScriptOffset { chunk: u8, more: bool }, } -const P2_SCRIPT_SIG_MORE: u8 = 0x01; +const P2_MORE: u8 = 0x01; impl TryFrom for Instruction { type Error = AppSW; @@ -127,11 +127,14 @@ impl TryFrom for Instruction { (1, 0, 0) => Ok(Instruction::GetVersion), (2, 0, 0) => Ok(Instruction::GetAppName), (4, 0, 0) => Ok(Instruction::GetPublicKey), - (5, 0..=6, 0 | P2_SCRIPT_SIG_MORE) => Ok(Instruction::GetScriptSignature { + (5, 0..=6, 0 | P2_MORE) => Ok(Instruction::GetScriptSignature { chunk: value.p1, - more: value.p2 == P2_SCRIPT_SIG_MORE, + more: value.p2 == P2_MORE, + }), + (6, 0..=6, 0 | P2_MORE) => Ok(Instruction::GetScriptOffset { + chunk: value.p1, + more: value.p2 == P2_MORE, }), - (6, 0, 0) => Ok(Instruction::GetScriptOffset), (3..=4, _, _) => Err(AppSW::WrongP1P2), (_, _, _) => Err(AppSW::InsNotSupported), } @@ -181,6 +184,6 @@ fn handle_apdu( }, Instruction::GetPublicKey => handler_get_public_key(comm), Instruction::GetScriptSignature { chunk, more } => handler_get_script_signature(comm, chunk, more, signer_ctx), - Instruction::GetScriptOffset => handler_get_script_offset(comm), + Instruction::GetScriptOffset { chunk, more } => handler_get_script_offset(comm, chunk, more, offset_ctx), } } diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index e70e34e229..eae6fa916f 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -696,10 +696,7 @@ where TBackend: KeyManagerBackend + 'static label: _, index, } => { - // Early exit if let WalletType::Software(_, _) = self.wallet_type { - // If this happens we actually expect a panic, so pushing to the array is - // pointless but ya never know eh? managed_script_keys.push(self.get_private_key(script_key_id).await?); continue; } @@ -724,9 +721,29 @@ where TBackend: KeyManagerBackend + 'static match &self.wallet_type { WalletType::Ledger(ledger) => { - let data: Vec> = vec![ - //branch_key.as_bytes().to_vec(), - ]; + let num_script_keys = managed_script_keys.len() as u64; + let num_commitments = derived_key_commitments.len() as u64; + let num_offset_key = sender_offset_keys.len() as u64; + + let mut instructions = num_offset_key.to_le_bytes().to_vec(); + instructions.clone_from_slice(&num_script_keys.to_le_bytes()); + instructions.clone_from_slice(&num_commitments.to_le_bytes()); + + let mut data: Vec> = vec![instructions.to_vec()]; + for sender_offset_key in sender_offset_keys { + data.push(sender_offset_key.to_vec()); + } + for managed_script_key in managed_script_keys { + // Managed keys will just be the key in the payload + data.push(managed_script_key.to_vec()); + } + for (derived_key_commitment, index) in derived_key_commitments { + // Derived keys will have the commitment and their index in the payload + let mut derived = derived_key_commitment.to_vec(); + derived.copy_from_slice(&index.to_le_bytes()); + + data.push(derived); + } let commands = ledger.chunk_command(Instruction::GetScriptOffset, data); let transport = get_transport()?; @@ -735,9 +752,7 @@ where TBackend: KeyManagerBackend + 'static for command in commands { match command.execute_with_transport(&transport) { Ok(r) => result = Some(r), - Err(e) => { - return Err(LedgerDeviceError::Instruction(format!("GetScriptSignature: {}", e)).into()) - }, + Err(e) => return Err(LedgerDeviceError::Instruction(format!("GetScriptOffset: {}", e)).into()), } } @@ -757,9 +772,9 @@ where TBackend: KeyManagerBackend + 'static .map_err(|e| TransactionError::InvalidSignatureError(e.to_string())); } - Err(LedgerDeviceError::Instruction("GetScriptSignature failed to process correctly".to_string()).into()) + Err(LedgerDeviceError::Instruction("GetScriptOffset failed to process correctly".to_string()).into()) }, - WalletType::Software(_p, _pk) => { + WalletType::Software(_, _) => { let mut total_sender_offset_private_key = PrivateKey::default(); for sender_offset_key_id in sender_offset_keys { total_sender_offset_private_key = total_sender_offset_private_key + sender_offset_key_id; From 29ae815f4cdcdbef3ed45cb7a92b0d5b50458207 Mon Sep 17 00:00:00 2001 From: brianp Date: Mon, 29 Apr 2024 11:15:09 +0200 Subject: [PATCH 25/49] More offset key fixes as per review --- .../minotari_console_wallet/src/init/mod.rs | 6 +- .../wallet/src/handlers/get_public_key.rs | 6 +- .../wallet/src/handlers/get_script_offset.rs | 41 +++++----- .../src/handlers/get_script_signature.rs | 6 +- .../minotari_ledger_wallet/wallet/src/main.rs | 19 +++++ .../wallet/src/utils.rs | 12 ++- .../src/transactions/key_manager/inner.rs | 79 ++++++++++--------- base_layer/wallet/src/wallet.rs | 4 +- 8 files changed, 101 insertions(+), 72 deletions(-) diff --git a/applications/minotari_console_wallet/src/init/mod.rs b/applications/minotari_console_wallet/src/init/mod.rs index 5ed8c97904..d301439ee7 100644 --- a/applications/minotari_console_wallet/src/init/mod.rs +++ b/applications/minotari_console_wallet/src/init/mod.rs @@ -843,11 +843,13 @@ pub fn prompt_wallet_type( print!("Scanning for connected Ledger hardware device... "); match get_transport() { Ok(hid) => { - drop(hid); // Need to release it before we reuse it. println!("Device found."); let account = prompt_ledger_account().expect("An account value"); let ledger = LedgerWallet::new(account, None); - match ledger.build_command(Instruction::GetPublicKey, vec![]).execute() { + match ledger + .build_command(Instruction::GetPublicKey, vec![]) + .execute_with_transport(&hid) + { Ok(result) => { debug!(target: LOG_TARGET, "result length: {}, data: {:?}", result.data().len(), result.data()); if result.data().len() < 33 { diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs index b43b19631b..a2e7decd25 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs @@ -4,9 +4,7 @@ use ledger_device_sdk::io::Comm; use tari_crypto::{keys::PublicKey, ristretto::RistrettoPublicKey, tari_utilities::ByteArray}; -use crate::{utils::derive_from_bip32_key, AppSW, RESPONSE_VERSION}; - -const STATIC_INDEX: u64 = 42; +use crate::{utils::derive_from_bip32_key, AppSW, KeyType, RESPONSE_VERSION, STATIC_ALPHA_INDEX}; pub fn handler_get_public_key(comm: &mut Comm) -> Result<(), AppSW> { let data = comm.get_data().map_err(|_| AppSW::WrongApduLength)?; @@ -15,7 +13,7 @@ pub fn handler_get_public_key(comm: &mut Comm) -> Result<(), AppSW> { account_bytes.clone_from_slice(&data[0..8]); let account = u64::from_le_bytes(account_bytes); - let pk = match derive_from_bip32_key(account, STATIC_INDEX) { + let pk = match derive_from_bip32_key(account, STATIC_ALPHA_INDEX, KeyType::Alpha) { Ok(k) => RistrettoPublicKey::from_secret_key(&k), Err(e) => return Err(e), }; diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs index 75cd603fa6..c677c3d7b8 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs @@ -8,15 +8,16 @@ use crate::{ alloc::string::ToString, utils::{derive_from_bip32_key, get_key_from_canonical_bytes, mask_a}, AppSW, + KeyType, RESPONSE_VERSION, + STATIC_ALPHA_INDEX, }; pub struct ScriptOffsetCtx { total_sender_offset_private_key: RistrettoSecretKey, total_script_private_key: RistrettoSecretKey, account: u64, - total_offset_keys: u64, - total_script_keys: u64, + total_offset_indexes: u64, total_commitment_keys: u64, } @@ -27,8 +28,7 @@ impl ScriptOffsetCtx { total_sender_offset_private_key: RistrettoSecretKey::default(), total_script_private_key: RistrettoSecretKey::default(), account: 0, - total_offset_keys: 0, - total_script_keys: 0, + total_offset_indexes: 0, total_commitment_keys: 0, } } @@ -38,8 +38,7 @@ impl ScriptOffsetCtx { self.total_sender_offset_private_key = RistrettoSecretKey::default(); self.total_script_private_key = RistrettoSecretKey::default(); self.account = 0; - self.total_offset_keys = 0; - self.total_script_keys = 0; + self.total_offset_indexes = 0; self.total_commitment_keys = 0; } } @@ -51,11 +50,7 @@ fn read_instructions(offset_ctx: &mut ScriptOffsetCtx, data: &[u8]) { let mut total_offset_keys = [0u8; 8]; total_offset_keys.clone_from_slice(&data[24..32]); - offset_ctx.total_offset_keys = u64::from_le_bytes(total_offset_keys); - - let mut total_script_keys = [0u8; 8]; - total_script_keys.clone_from_slice(&data[8..16]); - offset_ctx.total_script_keys = u64::from_le_bytes(total_script_keys); + offset_ctx.total_offset_indexes = u64::from_le_bytes(total_offset_keys); let mut total_commitment_keys = [0u8; 8]; total_commitment_keys.clone_from_slice(&data[16..24]); @@ -75,22 +70,26 @@ pub fn handler_get_script_offset( read_instructions(offset_ctx, data); } - if (1..offset_ctx.total_offset_keys).contains(&(chunk as u64)) { + if chunk == 1 { + // The sum of managed private keys let k = get_key_from_canonical_bytes(&data[0..32])?; - offset_ctx.total_sender_offset_private_key = &offset_ctx.total_sender_offset_private_key + &k; + offset_ctx.total_script_private_key = &offset_ctx.total_script_private_key + k; } - if (offset_ctx.total_offset_keys..offset_ctx.total_script_keys).contains(&(chunk as u64)) { - let k = get_key_from_canonical_bytes(&data[0..32])?; - offset_ctx.total_script_private_key = &offset_ctx.total_script_private_key + &k; - } - - if (offset_ctx.total_script_keys..offset_ctx.total_commitment_keys).contains(&(chunk as u64)) { + let payload_offset = 2; + let end_offset_indexes = payload_offset + offset_ctx.total_offset_indexes; + if (payload_offset..end_offset_indexes).contains(&(chunk as u64)) { let mut index_bytes = [0u8; 8]; - index_bytes.clone_from_slice(&data[32..40]); + index_bytes.clone_from_slice(&data[0..8]); let index = u64::from_le_bytes(index_bytes); - let alpha = derive_from_bip32_key(offset_ctx.account, index)?; + let offset = derive_from_bip32_key(offset_ctx.account, index, KeyType::ScriptOffset)?; + offset_ctx.total_offset_indexes = &offset_ctx.total_offset_indexes + &offset; + } + + let end_commitment_keys = end_offset_indexes + offset_ctx.total_commitment_keys; + if (end_offset_indexes..end_commitment_keys).contains(&(chunk as u64)) { + let alpha = derive_from_bip32_key(offset_ctx.account, STATIC_ALPHA_INDEX, KeyType::Alpha)?; let commitment = get_key_from_canonical_bytes(&data[0..32])?; let k = mask_a(alpha, commitment)?; diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs index 93bf077229..2643a710c3 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs @@ -13,11 +13,11 @@ use crate::{ alloc::string::ToString, utils::{derive_from_bip32_key, get_key_from_canonical_bytes, mask_a}, AppSW, + KeyType, RESPONSE_VERSION, + STATIC_ALPHA_INDEX, }; -const STATIC_INDEX: u64 = 42; - const MAX_TRANSACTION_LEN: usize = 312; pub struct ScriptSignatureCtx { payload: [u8; MAX_TRANSACTION_LEN], @@ -74,7 +74,7 @@ pub fn handler_get_script_signature( return Ok(()); } - let alpha = derive_from_bip32_key(signer_ctx.account, STATIC_INDEX)?; + let alpha = derive_from_bip32_key(signer_ctx.account, STATIC_ALPHA_INDEX, KeyType::Alpha)?; let commitment = get_key_from_canonical_bytes(&signer_ctx.payload[8..40])?; let script_private_key = mask_a(alpha, commitment)?; diff --git a/applications/minotari_ledger_wallet/wallet/src/main.rs b/applications/minotari_ledger_wallet/wallet/src/main.rs index 5bd2442cee..c9cecb450d 100644 --- a/applications/minotari_ledger_wallet/wallet/src/main.rs +++ b/applications/minotari_ledger_wallet/wallet/src/main.rs @@ -107,6 +107,25 @@ pub enum Instruction { } const P2_MORE: u8 = 0x01; +const STATIC_ALPHA_INDEX: u64 = 42; + +pub enum KeyType { + Alpha, + Nonce, + Recovery, + ScriptOffset, +} + +impl KeyType { + fn to_byte(&self) -> u8 { + match self { + Self::Alpha => 1, + Self::Nonce => 2, + Self::Recovery => 3, + Self::ScriptOffset => 4, + } + } +} impl TryFrom for Instruction { type Error = AppSW; diff --git a/applications/minotari_ledger_wallet/wallet/src/utils.rs b/applications/minotari_ledger_wallet/wallet/src/utils.rs index 25361909af..de8b6b2ddc 100644 --- a/applications/minotari_ledger_wallet/wallet/src/utils.rs +++ b/applications/minotari_ledger_wallet/wallet/src/utils.rs @@ -22,6 +22,7 @@ use zeroize::Zeroizing; use crate::{ alloc::string::{String, ToString}, AppSW, + KeyType, BIP32_COIN_TYPE, }; @@ -229,9 +230,14 @@ pub fn mask_a(alpha: RistrettoSecretKey, commitment: RistrettoSecretKey) -> Resu Ok(private_key + alpha) } -pub fn derive_from_bip32_key(u64_account: u64, u64_index: u64) -> Result { +pub fn derive_from_bip32_key( + u64_account: u64, + u64_index: u64, + u64_key_type: KeyType, +) -> Result { let account = u64_to_string(u64_account); let index = u64_to_string(u64_index); + let key_type = u64_to_string(u64_key_type.to_byte() as u64); let mut bip32_path = "m/44'/".to_string(); bip32_path.push_str(&BIP32_COIN_TYPE.to_string()); @@ -239,7 +245,9 @@ pub fn derive_from_bip32_key(u64_account: u64, u64_index: u64) -> Result get_key_from_uniform_bytes(&val.as_ref()), diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index eae6fa916f..c3b2bd280e 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -682,22 +682,22 @@ where TBackend: KeyManagerBackend + 'static script_key_ids: &[TariKeyId], sender_offset_key_ids: &[TariKeyId], ) -> Result { - let mut sender_offset_keys = vec![]; - for script_key_id in sender_offset_key_ids { - sender_offset_keys.push(self.get_private_key(script_key_id).await?); - } - - let mut managed_script_keys: Vec = vec![]; + debug!(target: LOG_TARGET, "BRIAN HERE"); + let mut total_script_private_key = PrivateKey::default(); let mut derived_key_commitments = vec![]; for script_key_id in script_key_ids { match script_key_id { + KeyId::Imported { .. } | KeyId::Managed { .. } | KeyId::Zero => { + total_script_private_key = total_script_private_key + self.get_private_key(script_key_id).await? + }, KeyId::Derived { branch, label: _, index, } => { if let WalletType::Software(_, _) = self.wallet_type { - managed_script_keys.push(self.get_private_key(script_key_id).await?); + total_script_private_key = + total_script_private_key + self.get_private_key(script_key_id).await?; continue; } @@ -710,39 +710,54 @@ where TBackend: KeyManagerBackend + 'static let branch_key = km .get_private_key(*index) .map_err(|e| TransactionError::KeyManagerError(e.to_string()))?; - derived_key_commitments.push((branch_key, index)); - }, - KeyId::Imported { .. } | KeyId::Managed { .. } | KeyId::Zero => { - managed_script_keys.push(self.get_private_key(script_key_id).await?) + derived_key_commitments.push(branch_key); }, } - managed_script_keys.push(self.get_private_key(script_key_id).await?); } match &self.wallet_type { + WalletType::Software(_, _) => { + debug!(target: LOG_TARGET, "SOFTWARE WALLET"); + let mut total_sender_offset_private_key = PrivateKey::default(); + for sender_offset_key_id in sender_offset_key_ids { + total_sender_offset_private_key = + total_sender_offset_private_key + self.get_private_key(sender_offset_key_id).await?; + } + let script_offset = total_script_private_key - total_sender_offset_private_key; + Ok(script_offset) + }, WalletType::Ledger(ledger) => { - let num_script_keys = managed_script_keys.len() as u64; + debug!(target: LOG_TARGET, "HARDWARE WALLET"); + let mut sender_offset_indexes = vec![]; + for sender_offset_key_id in sender_offset_key_ids { + match sender_offset_key_id { + TariKeyId::Managed { branch: _, index } | + TariKeyId::Derived { + branch: _, + label: _, + index, + } => { + sender_offset_indexes.push(index); + }, + TariKeyId::Imported { .. } | TariKeyId::Zero => {}, + } + } + let num_commitments = derived_key_commitments.len() as u64; - let num_offset_key = sender_offset_keys.len() as u64; + let num_offset_key = sender_offset_indexes.len() as u64; let mut instructions = num_offset_key.to_le_bytes().to_vec(); - instructions.clone_from_slice(&num_script_keys.to_le_bytes()); instructions.clone_from_slice(&num_commitments.to_le_bytes()); let mut data: Vec> = vec![instructions.to_vec()]; - for sender_offset_key in sender_offset_keys { - data.push(sender_offset_key.to_vec()); - } - for managed_script_key in managed_script_keys { - // Managed keys will just be the key in the payload - data.push(managed_script_key.to_vec()); + data.push(total_script_private_key.to_vec()); + + for sender_offset_index in sender_offset_indexes { + data.push(sender_offset_index.to_le_bytes().to_vec()); } - for (derived_key_commitment, index) in derived_key_commitments { - // Derived keys will have the commitment and their index in the payload - let mut derived = derived_key_commitment.to_vec(); - derived.copy_from_slice(&index.to_le_bytes()); - data.push(derived); + for derived_key_commitment in derived_key_commitments { + data.push(derived_key_commitment.to_vec()); } let commands = ledger.chunk_command(Instruction::GetScriptOffset, data); @@ -774,18 +789,6 @@ where TBackend: KeyManagerBackend + 'static Err(LedgerDeviceError::Instruction("GetScriptOffset failed to process correctly".to_string()).into()) }, - WalletType::Software(_, _) => { - let mut total_sender_offset_private_key = PrivateKey::default(); - for sender_offset_key_id in sender_offset_keys { - total_sender_offset_private_key = total_sender_offset_private_key + sender_offset_key_id; - } - let mut total_script_private_key = PrivateKey::default(); - for script_key_id in managed_script_keys { - total_script_private_key = total_script_private_key + script_key_id; - } - let script_offset = total_script_private_key - total_sender_offset_private_key; - Ok(script_offset) - }, } } diff --git a/base_layer/wallet/src/wallet.rs b/base_layer/wallet/src/wallet.rs index 4e27ac052f..726f5ddb42 100644 --- a/base_layer/wallet/src/wallet.rs +++ b/base_layer/wallet/src/wallet.rs @@ -775,8 +775,8 @@ pub fn read_or_create_wallet_type( match (db_wallet_type, wallet_type) { (None, None) => { // this is most likely an older wallet pre ledger support, lets put it in software - let wallet_type = WalletType::Software; - db.set_wallet_type(wallet_type)?; + let wallet_type = WalletType::default(); + db.set_wallet_type(wallet_type.clone())?; Ok(wallet_type) }, (None, Some(t)) => { From bf76040b2d86cb6773e4226e42d2b1f46c67e565 Mon Sep 17 00:00:00 2001 From: brianp Date: Tue, 30 Apr 2024 18:47:56 +0200 Subject: [PATCH 26/49] Allow 0 values for offset keys, and commitments --- .../wallet/src/handlers/get_script_offset.rs | 31 +++++++++++++------ .../src/handlers/get_script_signature.rs | 4 +-- .../minotari_ledger_wallet/wallet/src/main.rs | 4 +-- .../src/transactions/key_manager/inner.rs | 3 -- 4 files changed, 24 insertions(+), 18 deletions(-) diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs index c677c3d7b8..3a692dba18 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs @@ -48,14 +48,23 @@ fn read_instructions(offset_ctx: &mut ScriptOffsetCtx, data: &[u8]) { account_bytes.clone_from_slice(&data[0..8]); offset_ctx.account = u64::from_le_bytes(account_bytes); - let mut total_offset_keys = [0u8; 8]; - total_offset_keys.clone_from_slice(&data[24..32]); - offset_ctx.total_offset_indexes = u64::from_le_bytes(total_offset_keys); + if data.len() < 15 { + offset_ctx.total_offset_indexes = 0; + } else { + let mut total_offset_keys = [0u8; 8]; + total_offset_keys.clone_from_slice(&data[8..16]); + offset_ctx.total_offset_indexes = u64::from_le_bytes(total_offset_keys); + } - let mut total_commitment_keys = [0u8; 8]; - total_commitment_keys.clone_from_slice(&data[16..24]); - offset_ctx.total_commitment_keys = u64::from_le_bytes(total_commitment_keys); + if data.len() < 23 { + offset_ctx.total_commitment_keys = 0; + } else { + let mut total_commitment_keys = [0u8; 8]; + total_commitment_keys.clone_from_slice(&data[16..24]); + offset_ctx.total_commitment_keys = u64::from_le_bytes(total_commitment_keys); + } } + pub fn handler_get_script_offset( comm: &mut Comm, chunk: u8, @@ -68,12 +77,14 @@ pub fn handler_get_script_offset( // Reset offset context offset_ctx.reset(); read_instructions(offset_ctx, data); + return Ok(()); } if chunk == 1 { // The sum of managed private keys let k = get_key_from_canonical_bytes(&data[0..32])?; offset_ctx.total_script_private_key = &offset_ctx.total_script_private_key + k; + return Ok(()); } let payload_offset = 2; @@ -84,7 +95,8 @@ pub fn handler_get_script_offset( let index = u64::from_le_bytes(index_bytes); let offset = derive_from_bip32_key(offset_ctx.account, index, KeyType::ScriptOffset)?; - offset_ctx.total_offset_indexes = &offset_ctx.total_offset_indexes + &offset; + offset_ctx.total_sender_offset_private_key = &offset_ctx.total_sender_offset_private_key + &offset; + return Ok(()); } let end_commitment_keys = end_offset_indexes + offset_ctx.total_commitment_keys; @@ -94,6 +106,7 @@ pub fn handler_get_script_offset( let k = mask_a(alpha, commitment)?; offset_ctx.total_script_private_key = &offset_ctx.total_script_private_key + &k; + return Ok(()); } if more { @@ -104,10 +117,8 @@ pub fn handler_get_script_offset( comm.append(&[RESPONSE_VERSION]); // version comm.append(&script_offset.to_vec()); + offset_ctx.reset(); comm.reply_ok(); - SingleMessage::new(&"Finished Offset!".to_string()).show_and_wait(); - - offset_ctx.reset(); Ok(()) } diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs index 2643a710c3..4dc976eb0f 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs @@ -106,10 +106,8 @@ pub fn handler_get_script_signature( comm.append(&[RESPONSE_VERSION]); // version comm.append(&script_signature.to_vec()); + signer_ctx.reset(); comm.reply_ok(); - SingleMessage::new(&format!("Finished Signature!")).show_and_wait(); - - signer_ctx.reset(); Ok(()) } diff --git a/applications/minotari_ledger_wallet/wallet/src/main.rs b/applications/minotari_ledger_wallet/wallet/src/main.rs index c9cecb450d..df52dfdd8a 100644 --- a/applications/minotari_ledger_wallet/wallet/src/main.rs +++ b/applications/minotari_ledger_wallet/wallet/src/main.rs @@ -146,11 +146,11 @@ impl TryFrom for Instruction { (1, 0, 0) => Ok(Instruction::GetVersion), (2, 0, 0) => Ok(Instruction::GetAppName), (4, 0, 0) => Ok(Instruction::GetPublicKey), - (5, 0..=6, 0 | P2_MORE) => Ok(Instruction::GetScriptSignature { + (5, 0..=250, 0 | P2_MORE) => Ok(Instruction::GetScriptSignature { chunk: value.p1, more: value.p2 == P2_MORE, }), - (6, 0..=6, 0 | P2_MORE) => Ok(Instruction::GetScriptOffset { + (6, 0..=250, 0 | P2_MORE) => Ok(Instruction::GetScriptOffset { chunk: value.p1, more: value.p2 == P2_MORE, }), diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index c3b2bd280e..0026891a95 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -682,7 +682,6 @@ where TBackend: KeyManagerBackend + 'static script_key_ids: &[TariKeyId], sender_offset_key_ids: &[TariKeyId], ) -> Result { - debug!(target: LOG_TARGET, "BRIAN HERE"); let mut total_script_private_key = PrivateKey::default(); let mut derived_key_commitments = vec![]; for script_key_id in script_key_ids { @@ -717,7 +716,6 @@ where TBackend: KeyManagerBackend + 'static match &self.wallet_type { WalletType::Software(_, _) => { - debug!(target: LOG_TARGET, "SOFTWARE WALLET"); let mut total_sender_offset_private_key = PrivateKey::default(); for sender_offset_key_id in sender_offset_key_ids { total_sender_offset_private_key = @@ -727,7 +725,6 @@ where TBackend: KeyManagerBackend + 'static Ok(script_offset) }, WalletType::Ledger(ledger) => { - debug!(target: LOG_TARGET, "HARDWARE WALLET"); let mut sender_offset_indexes = vec![]; for sender_offset_key_id in sender_offset_key_ids { match sender_offset_key_id { From 0a1d66a687e5d3862052d7acfb6f8ceed2cf37ac Mon Sep 17 00:00:00 2001 From: brianp Date: Thu, 2 May 2024 16:32:21 +0200 Subject: [PATCH 27/49] Update dependencies like borsh for better version matching --- Cargo.lock | 1 + .../minotari_ledger_wallet/comms/Cargo.toml | 1 + .../minotari_ledger_wallet/wallet/Cargo.lock | 321 ++++++++---------- .../minotari_ledger_wallet/wallet/Cargo.toml | 4 +- 4 files changed, 138 insertions(+), 189 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6928f13115..ea08f23421 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3345,6 +3345,7 @@ dependencies = [ "num-derive 0.3.3", "num-traits", "serde", + "tari_common", "tari_crypto", "thiserror", ] diff --git a/applications/minotari_ledger_wallet/comms/Cargo.toml b/applications/minotari_ledger_wallet/comms/Cargo.toml index c6afaddc6a..9fdae22e16 100644 --- a/applications/minotari_ledger_wallet/comms/Cargo.toml +++ b/applications/minotari_ledger_wallet/comms/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" [dependencies] tari_crypto = { version = "0.20.0", default-features = false } +tari_common = { path = "../../../common", version = "1.0.0-pre.12" } ledger-transport = { git = "https://github.com/Zondax/ledger-rs", rev = "20e2a20" } ledger-transport-hid = { git = "https://github.com/Zondax/ledger-rs", rev = "20e2a20" } diff --git a/applications/minotari_ledger_wallet/wallet/Cargo.lock b/applications/minotari_ledger_wallet/wallet/Cargo.lock index 90f57ae850..32689bca1b 100644 --- a/applications/minotari_ledger_wallet/wallet/Cargo.lock +++ b/applications/minotari_ledger_wallet/wallet/Cargo.lock @@ -2,18 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - [[package]] name = "aho-corasick" version = "1.1.3" @@ -57,7 +45,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.55", + "syn 2.0.60", "which", ] @@ -93,60 +81,33 @@ dependencies = [ [[package]] name = "borsh" -version = "0.10.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" +checksum = "dbe5b10e214954177fb1dc9fbd20a1a2608fe99e6c832033bdc7cea287a20d77" dependencies = [ "borsh-derive", - "hashbrown", + "cfg_aliases", ] [[package]] name = "borsh-derive" -version = "0.10.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7" +checksum = "d7a8646f94ab393e43e8b35a2558b1624bed28b97ee09c5d15456e3c9463f46d" dependencies = [ - "borsh-derive-internal", - "borsh-schema-derive-internal", + "once_cell", "proc-macro-crate", - "proc-macro2", - "syn 1.0.109", -] - -[[package]] -name = "borsh-derive-internal" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "borsh-schema-derive-internal" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd" -dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.60", + "syn_derive", ] -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - [[package]] name = "cc" -version = "1.0.90" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +checksum = "065a29261d53ba54260972629f9ca6bffa69bac13cd1fed61420f7fa68b9f8bd" [[package]] name = "cexpr" @@ -163,6 +124,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + [[package]] name = "clang-sys" version = "1.7.0" @@ -213,7 +180,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.60", ] [[package]] @@ -235,9 +202,9 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" [[package]] name = "either" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" [[package]] name = "embedded-alloc" @@ -249,6 +216,12 @@ dependencies = [ "linked_list_allocator", ] +[[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.8" @@ -291,33 +264,11 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" -[[package]] -name = "hash32" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" -dependencies = [ - "byteorder", -] - [[package]] name = "hashbrown" -version = "0.13.2" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" -dependencies = [ - "ahash", -] - -[[package]] -name = "heapless" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" -dependencies = [ - "hash32", - "stable_deref_trait", -] +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "heck" @@ -325,15 +276,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -dependencies = [ - "serde", -] - [[package]] name = "home" version = "0.5.9" @@ -353,6 +295,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "keccak" version = "0.1.5" @@ -376,9 +328,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "ledger_device_sdk" -version = "1.8.0" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f99d39260bbde6dfef6a2420440b79f7a486ab2fbf43d251600a759697a79361" +checksum = "f6ff8da28601abd5150650f1ebd4e6d95fe8ac59c4a6ea24ac418cf2ffa6459c" dependencies = [ "include_gif", "ledger_secure_sdk_sys", @@ -400,9 +352,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.153" +version = "0.2.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" [[package]] name = "libloading" @@ -445,7 +397,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] -name = "minotari_ledger_wallet2" +name = "minotari_ledger_wallet" version = "1.0.0-pre.11a" dependencies = [ "blake2", @@ -453,14 +405,11 @@ dependencies = [ "critical-section", "digest", "embedded-alloc", - "hex", "include_gif", "ledger_device_sdk", - "numtoa", "once_cell", - "serde", - "serde-json-core", "tari_crypto", + "zeroize", ] [[package]] @@ -518,37 +467,60 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "prettyplease" -version = "0.2.17" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d3928fb5db768cb86f891ff014f0144589297e3c6a1aba6ed7cecfdace270c7" +checksum = "5ac2cf0f2e4f42b49f5ffd07dae8d746508ef7526c13940e5f524012ae6c6550" dependencies = [ "proc-macro2", - "syn 2.0.55", + "syn 2.0.60", ] [[package]] name = "proc-macro-crate" -version = "0.1.5" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" dependencies = [ - "toml", + "toml_edit", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", ] [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -615,9 +587,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.32" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ "bitflags 2.5.0", "errno", @@ -626,48 +598,12 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "ryu" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" - [[package]] name = "semver" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" -[[package]] -name = "serde" -version = "1.0.197" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde-json-core" -version = "0.5.1" -source = "git+https://github.com/rust-embedded-community/serde-json-core#9327a14e74ad3b4fd37a9ac34e72b61aa5fcc9bf" -dependencies = [ - "heapless", - "ryu", - "serde", -] - -[[package]] -name = "serde_derive" -version = "1.0.197" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.55", -] - [[package]] name = "sha3" version = "0.10.8" @@ -706,12 +642,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - [[package]] name = "subtle" version = "2.5.0" @@ -731,15 +661,27 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.55" +version = "2.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" +checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "syn_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.60", +] + [[package]] name = "tari-curve25519-dalek" version = "4.0.3" @@ -764,6 +706,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63a3ed2c551101eb42b7f9386c207e28d53e6816f7b4c9a0883548922f317b3e" dependencies = [ "blake2", + "borsh", "digest", "log", "once_cell", @@ -788,12 +731,20 @@ dependencies = [ ] [[package]] -name = "toml" -version = "0.5.11" +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" + +[[package]] +name = "toml_edit" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ - "serde", + "indexmap", + "toml_datetime", + "winnow", ] [[package]] @@ -843,13 +794,14 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", + "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", @@ -858,64 +810,59 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] -name = "zerocopy" -version = "0.7.32" +name = "winnow" +version = "0.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.55", + "memchr", ] [[package]] @@ -935,5 +882,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.60", ] diff --git a/applications/minotari_ledger_wallet/wallet/Cargo.toml b/applications/minotari_ledger_wallet/wallet/Cargo.toml index c662b748f7..39582ab241 100644 --- a/applications/minotari_ledger_wallet/wallet/Cargo.toml +++ b/applications/minotari_ledger_wallet/wallet/Cargo.toml @@ -7,13 +7,13 @@ edition = "2021" [dependencies] blake2 = { version = "0.10", default-features = false } -borsh = { version = "0.10", default-features = false } +borsh = { version = "1.2", default-features = false } critical-section = { version = "1.1.1" } digest = { version = "0.10", default-features = false } embedded-alloc = "0.5.0" include_gif = "1.0.1" ledger_device_sdk = "1.7.1" -tari_crypto = { version = "0.20.0", default-features = false } +tari_crypto = { version = "0.20.0", default-features = false, features = ["borsh"]} zeroize = { version = "1" , default-features = false } # once_cell defined here just to lock the version. Other dependencies may try to go to 1.19 which is incompatabile with From 8699586125b45fd96e4ca180b0521448c418a6ab Mon Sep 17 00:00:00 2001 From: brianp Date: Thu, 2 May 2024 16:33:31 +0200 Subject: [PATCH 28/49] refactoring improvements and metadata signature signing --- .../minotari_console_wallet/src/init/mod.rs | 4 +- .../comms/src/ledger_wallet.rs | 17 ++- .../src/handlers/get_metadata_signature.rs | 109 ++++++++++++++++++ .../wallet/src/handlers/get_script_offset.rs | 5 +- .../src/handlers/get_script_signature.rs | 7 +- .../wallet/src/hashing.rs | 78 +++++++++++++ .../minotari_ledger_wallet/wallet/src/main.rs | 21 +++- .../wallet/src/utils.rs | 31 ++++- .../src/transactions/key_manager/inner.rs | 106 +++++++++++++---- 9 files changed, 332 insertions(+), 46 deletions(-) create mode 100644 applications/minotari_ledger_wallet/wallet/src/handlers/get_metadata_signature.rs create mode 100644 applications/minotari_ledger_wallet/wallet/src/hashing.rs diff --git a/applications/minotari_console_wallet/src/init/mod.rs b/applications/minotari_console_wallet/src/init/mod.rs index d301439ee7..5584a778d7 100644 --- a/applications/minotari_console_wallet/src/init/mod.rs +++ b/applications/minotari_console_wallet/src/init/mod.rs @@ -845,7 +845,7 @@ pub fn prompt_wallet_type( Ok(hid) => { println!("Device found."); let account = prompt_ledger_account().expect("An account value"); - let ledger = LedgerWallet::new(account, None); + let ledger = LedgerWallet::new(account, wallet_config.network, None); match ledger .build_command(Instruction::GetPublicKey, vec![]) .execute_with_transport(&hid) @@ -866,7 +866,7 @@ pub fn prompt_wallet_type( Err(e) => panic!("{}", e), }; - let ledger = LedgerWallet::new(account, Some(key)); + let ledger = LedgerWallet::new(account, wallet_config.network, Some(key)); Some(WalletType::Ledger(ledger)) }, Err(e) => panic!("{}", e), diff --git a/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs b/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs index 33834c88da..0dfc52e778 100644 --- a/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs +++ b/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs @@ -31,6 +31,7 @@ use ledger_transport_hid::{hidapi::HidApi, TransportNativeHID}; use num_derive::FromPrimitive; use num_traits::FromPrimitive; use serde::{Deserialize, Serialize}; +use tari_common::configuration::Network; use tari_crypto::ristretto::RistrettoPublicKey; use crate::error::LedgerDeviceError; @@ -43,9 +44,10 @@ const WALLET_CLA: u8 = 0x80; pub enum Instruction { GetVersion = 0x01, GetAppName = 0x02, - GetPublicKey = 0x04, - GetScriptSignature = 0x05, - GetScriptOffset = 0x06, + GetPublicKey = 0x03, + GetScriptSignature = 0x04, + GetScriptOffset = 0x05, + GetMetadataSignature = 0x06, } impl Instruction { @@ -89,6 +91,7 @@ impl> Command { pub struct LedgerWallet { account: u64, pub pubkey: Option, + network: Network, } impl Display for LedgerWallet { @@ -100,8 +103,12 @@ impl Display for LedgerWallet { } impl LedgerWallet { - pub fn new(account: u64, pubkey: Option) -> Self { - Self { account, pubkey } + pub fn new(account: u64, network: Network, pubkey: Option) -> Self { + Self { + account, + pubkey, + network, + } } pub fn account_bytes(&self) -> Vec { diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_metadata_signature.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_metadata_signature.rs new file mode 100644 index 0000000000..56901d1dd2 --- /dev/null +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_metadata_signature.rs @@ -0,0 +1,109 @@ +// Copyright 2024 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use alloc::format; + +use ledger_device_sdk::{io::Comm, ui::gadgets::SingleMessage}; +use tari_crypto::{ + keys::PublicKey, + ristretto::{ + pedersen::{extended_commitment_factory::ExtendedPedersenCommitmentFactory, PedersenCommitment}, + RistrettoComAndPubSig, + RistrettoPublicKey, + RistrettoSecretKey, + }, +}; + +use crate::{ + alloc::string::ToString, + utils::{derive_from_bip32_key, finalize_metadata_signature_challenge, get_key_from_canonical_bytes}, + AppSW, + KeyType, + RESPONSE_VERSION, +}; + +pub fn handler_get_metadata_signature(comm: &mut Comm) -> Result<(), AppSW> { + let data = comm.get_data().map_err(|_| AppSW::WrongApduLength)?; + + SingleMessage::new(&"got data").show_and_wait(); + + let mut account_bytes = [0u8; 8]; + account_bytes.clone_from_slice(&data[0..8]); + let account = u64::from_le_bytes(account_bytes); + SingleMessage::new(&"got account").show_and_wait(); + + let mut network_bytes = [0u8; 8]; + network_bytes.clone_from_slice(&data[8..16]); + let network = u64::from_le_bytes(network_bytes); + SingleMessage::new(&"got network").show_and_wait(); + + let mut txo_version_bytes = [0u8; 8]; + txo_version_bytes.clone_from_slice(&data[16..24]); + let txo_version = u64::from_le_bytes(txo_version_bytes); + SingleMessage::new(&"got txo version").show_and_wait(); + + let mut ephemeral_private_nonce_index_bytes = [0u8; 8]; + ephemeral_private_nonce_index_bytes.clone_from_slice(&data[24..32]); + let ephemeral_private_nonce_index = u64::from_le_bytes(ephemeral_private_nonce_index_bytes); + SingleMessage::new(&"got eph nonce").show_and_wait(); + + let mut sender_offset_key_index_bytes = [0u8; 8]; + sender_offset_key_index_bytes.clone_from_slice(&data[32..40]); + let sender_offset_key_index = u64::from_le_bytes(sender_offset_key_index_bytes); + SingleMessage::new(&"got offsets").show_and_wait(); + + let commitment: PedersenCommitment = get_key_from_canonical_bytes(&data[40..72])?; + SingleMessage::new(&"gen commit").show_and_wait(); + let ephemeral_commitment: PedersenCommitment = get_key_from_canonical_bytes(&data[72..104])?; + SingleMessage::new(&"gen eph commit").show_and_wait(); + + let mut metadata_signature_message = [0u8; 32]; + metadata_signature_message.clone_from_slice(&data[104..136]); + SingleMessage::new(&"got message").show_and_wait(); + + let ephemeral_private_key = derive_from_bip32_key(account, ephemeral_private_nonce_index, KeyType::Nonce)?; + let ephemeral_pubkey = RistrettoPublicKey::from_secret_key(&ephemeral_private_key); + SingleMessage::new(&"derived eph keys").show_and_wait(); + + let sender_offset_private_key = derive_from_bip32_key(account, sender_offset_key_index, KeyType::SenderOffset)?; + let sender_offset_public_key = RistrettoPublicKey::from_secret_key(&sender_offset_private_key); + SingleMessage::new(&"derived offset keys").show_and_wait(); + + let challenge = finalize_metadata_signature_challenge( + txo_version, + network, + &sender_offset_public_key, + &ephemeral_commitment, + &ephemeral_pubkey, + &commitment, + &metadata_signature_message, + ); + SingleMessage::new(&"challenge").show_and_wait(); + + let factory = ExtendedPedersenCommitmentFactory::default(); + SingleMessage::new(&"factory").show_and_wait(); + + let metadata_signature = match RistrettoComAndPubSig::sign( + &RistrettoSecretKey::default(), + &RistrettoSecretKey::default(), + &sender_offset_private_key, + &RistrettoSecretKey::default(), + &RistrettoSecretKey::default(), + &ephemeral_private_key, + &challenge, + &factory, + ) { + Ok(sig) => sig, + Err(e) => { + SingleMessage::new(&format!("Signing error: {:?}", e.to_string())).show_and_wait(); + return Err(AppSW::ScriptSignatureFail); + }, + }; + SingleMessage::new(&"complete").show_and_wait(); + + comm.append(&[RESPONSE_VERSION]); // version + comm.append(&metadata_signature.to_vec()); + comm.reply_ok(); + + Ok(()) +} diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs index 3a692dba18..20019d7158 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs @@ -1,11 +1,10 @@ // Copyright 2024 The Tari Project // SPDX-License-Identifier: BSD-3-Clause -use ledger_device_sdk::{io::Comm, ui::gadgets::SingleMessage}; +use ledger_device_sdk::io::Comm; use tari_crypto::{ristretto::RistrettoSecretKey, tari_utilities::ByteArray}; use crate::{ - alloc::string::ToString, utils::{derive_from_bip32_key, get_key_from_canonical_bytes, mask_a}, AppSW, KeyType, @@ -82,7 +81,7 @@ pub fn handler_get_script_offset( if chunk == 1 { // The sum of managed private keys - let k = get_key_from_canonical_bytes(&data[0..32])?; + let k: RistrettoSecretKey = get_key_from_canonical_bytes(&data[0..32])?; offset_ctx.total_script_private_key = &offset_ctx.total_script_private_key + k; return Ok(()); } diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs index 4dc976eb0f..21f1210903 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs @@ -7,6 +7,7 @@ use ledger_device_sdk::{io::Comm, ui::gadgets::SingleMessage}; use tari_crypto::ristretto::{ pedersen::extended_commitment_factory::ExtendedPedersenCommitmentFactory, RistrettoComAndPubSig, + RistrettoSecretKey, }; use crate::{ @@ -75,11 +76,11 @@ pub fn handler_get_script_signature( } let alpha = derive_from_bip32_key(signer_ctx.account, STATIC_ALPHA_INDEX, KeyType::Alpha)?; - let commitment = get_key_from_canonical_bytes(&signer_ctx.payload[8..40])?; + let commitment: RistrettoSecretKey = get_key_from_canonical_bytes(&signer_ctx.payload[8..40])?; let script_private_key = mask_a(alpha, commitment)?; - let value = get_key_from_canonical_bytes(&signer_ctx.payload[40..72])?; - let spend_private_key = get_key_from_canonical_bytes(&signer_ctx.payload[72..104])?; + let value: RistrettoSecretKey = get_key_from_canonical_bytes(&signer_ctx.payload[40..72])?; + let spend_private_key: RistrettoSecretKey = get_key_from_canonical_bytes(&signer_ctx.payload[72..104])?; let r_a = get_key_from_canonical_bytes(&signer_ctx.payload[104..136])?; let r_x = get_key_from_canonical_bytes(&signer_ctx.payload[136..168])?; let r_y = get_key_from_canonical_bytes(&signer_ctx.payload[168..200])?; diff --git a/applications/minotari_ledger_wallet/wallet/src/hashing.rs b/applications/minotari_ledger_wallet/wallet/src/hashing.rs new file mode 100644 index 0000000000..343c2ad44a --- /dev/null +++ b/applications/minotari_ledger_wallet/wallet/src/hashing.rs @@ -0,0 +1,78 @@ +// Copyright 2024 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use alloc::format; +use core::marker::PhantomData; + +use borsh::{io, io::Write, BorshSerialize}; +use digest::Digest; +use tari_crypto::hashing::DomainSeparation; + +pub struct DomainSeparatedConsensusHasher { + hasher: DomainSeparatedBorshHasher, +} + +impl DomainSeparatedConsensusHasher +where D: Default +{ + pub fn new(label: &'static str, network: u64) -> Self { + let hasher = DomainSeparatedBorshHasher::::new_with_label(&format!("{}.n{}", label, network)); + Self { hasher } + } + + pub fn finalize(self) -> digest::Output { + self.hasher.finalize() + } + + pub fn update_consensus_encode(&mut self, data: &T) { + self.hasher.update_consensus_encode(data); + } + + pub fn chain(mut self, data: &T) -> Self { + self.update_consensus_encode(data); + self + } +} + +/// Domain separated borsh-encoding hasher. +pub struct DomainSeparatedBorshHasher { + writer: WriteHashWrapper, + _m: PhantomData, +} + +impl DomainSeparatedBorshHasher { + #[allow(clippy::new_ret_no_self)] + pub fn new_with_label(label: &str) -> Self { + let mut digest = D::default(); + M::add_domain_separation_tag(&mut digest, label); + Self { + writer: WriteHashWrapper(digest), + _m: PhantomData, + } + } + + pub fn finalize(self) -> digest::Output { + self.writer.0.finalize() + } + + pub fn update_consensus_encode(&mut self, data: &T) { + BorshSerialize::serialize(data, &mut self.writer) + .expect("Incorrect implementation of BorshSerialize encountered. Implementations MUST be infallible."); + } +} + +/// This private struct wraps a Digest and implements the Write trait to satisfy the consensus encoding trait. +/// Do not use the DomainSeparatedHasher with this. +#[derive(Clone)] +struct WriteHashWrapper(D); + +impl Write for WriteHashWrapper { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.update(buf); + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} diff --git a/applications/minotari_ledger_wallet/wallet/src/main.rs b/applications/minotari_ledger_wallet/wallet/src/main.rs index df52dfdd8a..4845a6c1f9 100644 --- a/applications/minotari_ledger_wallet/wallet/src/main.rs +++ b/applications/minotari_ledger_wallet/wallet/src/main.rs @@ -7,12 +7,14 @@ extern crate alloc; +mod hashing; mod utils; mod app_ui { pub mod menu; } mod handlers { + pub mod get_metadata_signature; pub mod get_public_key; pub mod get_script_offset; pub mod get_script_signature; @@ -24,6 +26,7 @@ use core::mem::MaybeUninit; use app_ui::menu::ui_menu_main; use critical_section::RawRestoreState; use handlers::{ + get_metadata_signature::handler_get_metadata_signature, get_public_key::handler_get_public_key, get_script_offset::{handler_get_script_offset, ScriptOffsetCtx}, get_script_signature::{handler_get_script_signature, ScriptSignatureCtx}, @@ -40,7 +43,6 @@ ledger_device_sdk::set_panic!(ledger_device_sdk::exiting_panic); static BIP32_COIN_TYPE: u32 = 535348; static CLA: u8 = 0x80; - static RESPONSE_VERSION: u8 = 1; /// Allocator heap size @@ -87,7 +89,10 @@ pub enum AppSW { ClaNotSupported = 0x6E00, ScriptSignatureFail = 0xB001, KeyDeriveFail = 0xB009, + KeyDeriveFromCanonical = 0xB010, + KeyDeriveFromUniform = 0xB011, VersionParsingFail = 0xB00A, + TooManyPayloads = 0xB002, WrongApduLength = StatusWords::BadLen as u16, } @@ -104,16 +109,19 @@ pub enum Instruction { GetPublicKey, GetScriptSignature { chunk: u8, more: bool }, GetScriptOffset { chunk: u8, more: bool }, + GetMetadataSignature, } const P2_MORE: u8 = 0x01; const STATIC_ALPHA_INDEX: u64 = 42; +const MAX_PAYLOADS: u8 = 250; pub enum KeyType { Alpha, Nonce, Recovery, ScriptOffset, + SenderOffset, } impl KeyType { @@ -123,6 +131,7 @@ impl KeyType { Self::Nonce => 2, Self::Recovery => 3, Self::ScriptOffset => 4, + Self::SenderOffset => 5, } } } @@ -145,16 +154,17 @@ impl TryFrom for Instruction { match (value.ins, value.p1, value.p2) { (1, 0, 0) => Ok(Instruction::GetVersion), (2, 0, 0) => Ok(Instruction::GetAppName), - (4, 0, 0) => Ok(Instruction::GetPublicKey), - (5, 0..=250, 0 | P2_MORE) => Ok(Instruction::GetScriptSignature { + (3, 0, 0) => Ok(Instruction::GetPublicKey), + (4, 0..=MAX_PAYLOADS, 0 | P2_MORE) => Ok(Instruction::GetScriptSignature { chunk: value.p1, more: value.p2 == P2_MORE, }), - (6, 0..=250, 0 | P2_MORE) => Ok(Instruction::GetScriptOffset { + (5, 0..=MAX_PAYLOADS, 0 | P2_MORE) => Ok(Instruction::GetScriptOffset { chunk: value.p1, more: value.p2 == P2_MORE, }), - (3..=4, _, _) => Err(AppSW::WrongP1P2), + (6, 0, 0) => Ok(Instruction::GetMetadataSignature), + (4..=5, _, _) => Err(AppSW::WrongP1P2), (_, _, _) => Err(AppSW::InsNotSupported), } } @@ -204,5 +214,6 @@ fn handle_apdu( Instruction::GetPublicKey => handler_get_public_key(comm), Instruction::GetScriptSignature { chunk, more } => handler_get_script_signature(comm, chunk, more, signer_ctx), Instruction::GetScriptOffset { chunk, more } => handler_get_script_offset(comm, chunk, more, offset_ctx), + Instruction::GetMetadataSignature => handler_get_metadata_signature(comm), } } diff --git a/applications/minotari_ledger_wallet/wallet/src/utils.rs b/applications/minotari_ledger_wallet/wallet/src/utils.rs index de8b6b2ddc..25d341f76d 100644 --- a/applications/minotari_ledger_wallet/wallet/src/utils.rs +++ b/applications/minotari_ledger_wallet/wallet/src/utils.rs @@ -14,13 +14,14 @@ use tari_crypto::{ hash_domain, hashing::DomainSeparatedHasher, keys::SecretKey, - ristretto::RistrettoSecretKey, + ristretto::{pedersen::PedersenCommitment, RistrettoPublicKey, RistrettoSecretKey}, tari_utilities::ByteArray, }; use zeroize::Zeroizing; use crate::{ alloc::string::{String, ToString}, + hashing::DomainSeparatedConsensusHasher, AppSW, KeyType, BIP32_COIN_TYPE, @@ -28,6 +29,7 @@ use crate::{ hash_domain!(LedgerHashDomain, "com.tari.minotari_ledger_wallet", 0); hash_domain!(KeyManagerHashingDomain, "com.tari.base_layer.key_manager", 1); +hash_domain!(TransactionHashDomain, "com.tari.base_layer.core.transactions", 0); /// BIP32 path stored as an array of [`u32`]. /// @@ -201,13 +203,13 @@ pub fn get_key_from_uniform_bytes(bytes: &[u8]) -> Result Result { - match RistrettoSecretKey::from_canonical_bytes(bytes) { +pub fn get_key_from_canonical_bytes(bytes: &[u8]) -> Result { + match T::from_canonical_bytes(bytes) { Ok(val) => Ok(val), Err(e) => { SingleMessage::new(&format!( @@ -217,7 +219,7 @@ pub fn get_key_from_canonical_bytes(bytes: &[u8]) -> Result [u8; 64] { + DomainSeparatedConsensusHasher::>::new("metadata_signature", network) + .chain(&ephemeral_pubkey) + .chain(&ephemeral_commitment) + .chain(&sender_offset_public_key) + .chain(&commitment) + .chain(&message) + .finalize() + .into() +} diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index 0026891a95..93ed676c76 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -48,6 +48,7 @@ use tari_crypto::{ }; use tari_key_manager::{ cipher_seed::CipherSeed, + error::KeyManagerError, key_manager::KeyManager, key_manager_service::{ storage::database::{KeyManagerBackend, KeyManagerDatabase, KeyManagerState}, @@ -880,6 +881,7 @@ where TBackend: KeyManagerBackend + 'static range_proof_type: RangeProofType, ) -> Result { let sender_offset_public_key = self.get_public_key_at_key_id(sender_offset_key_id).await?; + // Use the pubkey, but generate the nonce on ledger let (ephemeral_private_nonce_id, ephemeral_pubkey) = self .get_next_key(&TransactionKeyManagerBranch::Nonce.get_branch_key()) .await?; @@ -960,31 +962,89 @@ where TBackend: KeyManagerBackend + 'static txo_version: &TransactionOutputVersion, metadata_signature_message: &[u8; 32], ) -> Result { - let ephemeral_private_key = self.get_private_key(ephemeral_private_nonce_id).await?; - let ephemeral_pubkey = PublicKey::from_secret_key(&ephemeral_private_key); - let sender_offset_private_key = self.get_private_key(sender_offset_key_id).await?; - let sender_offset_public_key = PublicKey::from_secret_key(&sender_offset_private_key); + match &self.wallet_type { + WalletType::Software(_, _) => { + let ephemeral_private_key = self.get_private_key(ephemeral_private_nonce_id).await?; + let ephemeral_pubkey = PublicKey::from_secret_key(&ephemeral_private_key); + let sender_offset_private_key = self.get_private_key(sender_offset_key_id).await?; // Take the index and use it to find the key from ledger + let sender_offset_public_key = PublicKey::from_secret_key(&sender_offset_private_key); + + let challenge = TransactionOutput::finalize_metadata_signature_challenge( + txo_version, + &sender_offset_public_key, + ephemeral_commitment, + &ephemeral_pubkey, + commitment, + metadata_signature_message, + ); - let challenge = TransactionOutput::finalize_metadata_signature_challenge( - txo_version, - &sender_offset_public_key, - ephemeral_commitment, - &ephemeral_pubkey, - commitment, - metadata_signature_message, - ); + let metadata_signature = ComAndPubSignature::sign( + &PrivateKey::default(), + &PrivateKey::default(), + &sender_offset_private_key, + &PrivateKey::default(), + &PrivateKey::default(), + &ephemeral_private_key, + &challenge, + &*self.crypto_factories.commitment, + )?; + Ok(metadata_signature) + }, + WalletType::Ledger(ledger) => { + let ephemeral_private_nonce_index = + ephemeral_private_nonce_id + .managed_index() + .ok_or(TransactionError::KeyManagerError( + KeyManagerError::InvalidKeyID.to_string(), + ))?; + let sender_offset_key_index = + sender_offset_key_id + .managed_index() + .ok_or(TransactionError::KeyManagerError( + KeyManagerError::InvalidKeyID.to_string(), + ))?; + + let mut data = (txo_version.as_u8() as u64).to_le_bytes().to_vec(); + data.extend_from_slice(&(txo_version.as_u8() as u64).to_le_bytes()); + data.extend_from_slice(&ephemeral_private_nonce_index.to_le_bytes()); + data.extend_from_slice(&sender_offset_key_index.to_le_bytes()); + data.extend_from_slice(&commitment.to_vec()); + data.extend_from_slice(&ephemeral_commitment.to_vec()); + data.extend_from_slice(&metadata_signature_message.to_vec()); + + let command = ledger.build_command(Instruction::GetMetadataSignature, data); + let transport = get_transport()?; - let metadata_signature = ComAndPubSignature::sign( - &PrivateKey::default(), - &PrivateKey::default(), - &sender_offset_private_key, - &PrivateKey::default(), - &PrivateKey::default(), - &ephemeral_private_key, - &challenge, - &*self.crypto_factories.commitment, - )?; - Ok(metadata_signature) + match command.execute_with_transport(&transport) { + Ok(result) => { + if result.data().len() < 161 { + debug!(target: LOG_TARGET, "result less than 161"); + return Err(LedgerDeviceError::Processing(format!( + "'get_metadata_signature' insufficient data - expected 161 got {} bytes ({:?})", + result.data().len(), + result + )) + .into()); + } + let data = result.data(); + debug!(target: LOG_TARGET, "result length: {}, data: {:?}", result.data().len(), result.data()); + Ok(ComAndPubSignature::new( + Commitment::from_canonical_bytes(&data[1..33]) + .map_err(|e| TransactionError::InvalidSignatureError(e.to_string()))?, + PublicKey::from_canonical_bytes(&data[33..65]) + .map_err(|e| TransactionError::InvalidSignatureError(e.to_string()))?, + PrivateKey::from_canonical_bytes(&data[65..97]) + .map_err(|e| TransactionError::InvalidSignatureError(e.to_string()))?, + PrivateKey::from_canonical_bytes(&data[97..129]) + .map_err(|e| TransactionError::InvalidSignatureError(e.to_string()))?, + PrivateKey::from_canonical_bytes(&data[129..161]) + .map_err(|e| TransactionError::InvalidSignatureError(e.to_string()))?, + )) + }, + Err(e) => Err(LedgerDeviceError::Instruction(format!("GetMetadataSignature: {}", e)).into()), + } + }, + } } // ----------------------------------------------------------------------------------------------------------------- From 50e11801fa323a5e11e1b8aa90cbc4d942a2651c Mon Sep 17 00:00:00 2001 From: SW van Heerden Date: Fri, 3 May 2024 10:47:25 +0200 Subject: [PATCH 29/49] some change (#6) --- .../src/transactions/key_manager/inner.rs | 21 ++++++++++++------- .../src/transactions/key_manager/interface.rs | 1 + .../transaction_initializer.rs | 2 +- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index 93ed676c76..1e1f94e259 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -23,6 +23,7 @@ use std::{collections::HashMap, ops::Shl}; use blake2::Blake2b; use digest::consts::U64; +use futures::AsyncReadExt; use log::*; use minotari_ledger_wallet_comms::ledger_wallet::get_transport; #[cfg(feature = "ledger")] @@ -194,13 +195,17 @@ where TBackend: KeyManagerBackend + 'static pub async fn get_public_key_at_key_id(&self, key_id: &TariKeyId) -> Result { match key_id { KeyId::Managed { branch, index } => { - let km = self - .key_managers - .get(branch) - .ok_or(KeyManagerServiceError::UnknownKeyBranch)? - .read() - .await; - Ok(km.derive_public_key(*index)?.key) + match branch{ + "LedgerNonde" => {} + _ => {let km = self + .key_managers + .get(branch) + .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .read() + .await; + Ok(km.derive_public_key(*index)?.key)} + } + }, KeyId::Derived { branch, label, index } => { let public_alpha = match &self.wallet_type { @@ -883,7 +888,7 @@ where TBackend: KeyManagerBackend + 'static let sender_offset_public_key = self.get_public_key_at_key_id(sender_offset_key_id).await?; // Use the pubkey, but generate the nonce on ledger let (ephemeral_private_nonce_id, ephemeral_pubkey) = self - .get_next_key(&TransactionKeyManagerBranch::Nonce.get_branch_key()) + .get_next_key(&TransactionKeyManagerBranch::MetadataEphemiralNonce.get_branch_key()) .await?; let receiver_partial_metadata_signature = self .get_receiver_partial_metadata_signature( diff --git a/base_layer/core/src/transactions/key_manager/interface.rs b/base_layer/core/src/transactions/key_manager/interface.rs index 16926eae52..47e6c212ae 100644 --- a/base_layer/core/src/transactions/key_manager/interface.rs +++ b/base_layer/core/src/transactions/key_manager/interface.rs @@ -55,6 +55,7 @@ pub enum TxoStage { pub enum TransactionKeyManagerBranch { DataEncryption, Coinbase, + MetadataEphemiralNonce, CommitmentMask, Nonce, KernelNonce, diff --git a/base_layer/core/src/transactions/transaction_protocol/transaction_initializer.rs b/base_layer/core/src/transactions/transaction_protocol/transaction_initializer.rs index a96691dd75..c53b40c5c2 100644 --- a/base_layer/core/src/transactions/transaction_protocol/transaction_initializer.rs +++ b/base_layer/core/src/transactions/transaction_protocol/transaction_initializer.rs @@ -153,7 +153,7 @@ where KM: TransactionKeyManagerInterface ) -> Result<&mut Self, KeyManagerServiceError> { let (recipient_ephemeral_public_key_nonce, _) = self .key_manager - .get_next_key(TransactionKeyManagerBranch::Nonce.get_branch_key()) + .get_next_key(TransactionKeyManagerBranch::MetadataEphemiralNonce.get_branch_key()) .await?; let (recipient_sender_offset_key_id, _) = self .key_manager From 197c74dc4ebb80e7a92fc48b4892d9b0b338298b Mon Sep 17 00:00:00 2001 From: brianp Date: Fri, 3 May 2024 11:56:51 +0200 Subject: [PATCH 30/49] Enhance public none fetching and fix bugs --- .../minotari_console_wallet/src/init/mod.rs | 11 +++--- .../comms/src/ledger_wallet.rs | 11 +++--- .../wallet/src/handlers/get_public_alpha.rs | 26 ++++++++++++++ .../wallet/src/handlers/get_public_key.rs | 8 +++-- .../wallet/src/handlers/get_script_offset.rs | 4 +-- .../minotari_ledger_wallet/wallet/src/main.rs | 19 +++++----- .../src/transactions/key_manager/inner.rs | 35 ++++++++++++++----- .../src/transactions/key_manager/interface.rs | 9 ++--- 8 files changed, 89 insertions(+), 34 deletions(-) create mode 100644 applications/minotari_ledger_wallet/wallet/src/handlers/get_public_alpha.rs diff --git a/applications/minotari_console_wallet/src/init/mod.rs b/applications/minotari_console_wallet/src/init/mod.rs index 5584a778d7..46ca157f47 100644 --- a/applications/minotari_console_wallet/src/init/mod.rs +++ b/applications/minotari_console_wallet/src/init/mod.rs @@ -54,7 +54,10 @@ use tari_common::{ }, exit_codes::{ExitCode, ExitError}, }; -use tari_common_types::{types::PrivateKey, wallet_types::WalletType}; +use tari_common_types::{ + types::{PrivateKey, PublicKey}, + wallet_types::WalletType, +}; use tari_comms::{ multiaddr::Multiaddr, peer_manager::{Peer, PeerFeatures, PeerQuery}, @@ -65,7 +68,7 @@ use tari_core::{ consensus::ConsensusManager, transactions::{transaction_components::TransactionError, CryptoFactories}, }; -use tari_crypto::{keys::PublicKey, ristretto::RistrettoPublicKey}; +use tari_crypto::{keys::PublicKey as PublicKeyTrait, ristretto::RistrettoPublicKey}; use tari_key_manager::{cipher_seed::CipherSeed, mnemonic::MnemonicLanguage}; use tari_p2p::{peer_seeds::SeedPeer, TransportType}; use tari_shutdown::ShutdownSignal; @@ -847,7 +850,7 @@ pub fn prompt_wallet_type( let account = prompt_ledger_account().expect("An account value"); let ledger = LedgerWallet::new(account, wallet_config.network, None); match ledger - .build_command(Instruction::GetPublicKey, vec![]) + .build_command(Instruction::GetPublicAlpha, vec![]) .execute_with_transport(&hid) { Ok(result) => { @@ -861,7 +864,7 @@ pub fn prompt_wallet_type( ); } - let key = match RistrettoPublicKey::from_canonical_bytes(&result.data()[1..33]) { + let key = match PublicKey::from_canonical_bytes(&result.data()[1..33]) { Ok(k) => k, Err(e) => panic!("{}", e), }; diff --git a/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs b/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs index 0dfc52e778..bd77a6933a 100644 --- a/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs +++ b/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs @@ -44,10 +44,11 @@ const WALLET_CLA: u8 = 0x80; pub enum Instruction { GetVersion = 0x01, GetAppName = 0x02, - GetPublicKey = 0x03, - GetScriptSignature = 0x04, - GetScriptOffset = 0x05, - GetMetadataSignature = 0x06, + GetPublicAlpha = 0x03, + GetPublicKey = 0x04, + GetScriptSignature = 0x05, + GetScriptOffset = 0x06, + GetMetadataSignature = 0x07, } impl Instruction { @@ -91,7 +92,7 @@ impl> Command { pub struct LedgerWallet { account: u64, pub pubkey: Option, - network: Network, + pub network: Network, } impl Display for LedgerWallet { diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_alpha.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_alpha.rs new file mode 100644 index 0000000000..3904303734 --- /dev/null +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_alpha.rs @@ -0,0 +1,26 @@ +// Copyright 2024 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use ledger_device_sdk::io::Comm; +use tari_crypto::{keys::PublicKey, ristretto::RistrettoPublicKey, tari_utilities::ByteArray}; + +use crate::{utils::derive_from_bip32_key, AppSW, KeyType, RESPONSE_VERSION, STATIC_ALPHA_INDEX}; + +pub fn handler_get_public_alpha(comm: &mut Comm) -> Result<(), AppSW> { + let data = comm.get_data().map_err(|_| AppSW::WrongApduLength)?; + + let mut account_bytes = [0u8; 8]; + account_bytes.clone_from_slice(&data[0..8]); + let account = u64::from_le_bytes(account_bytes); + + let pk = match derive_from_bip32_key(account, STATIC_ALPHA_INDEX, KeyType::Alpha) { + Ok(k) => RistrettoPublicKey::from_secret_key(&k), + Err(e) => return Err(e), + }; + + comm.append(&[RESPONSE_VERSION]); // version + comm.append(pk.as_bytes()); + comm.reply_ok(); + + Ok(()) +} diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs index a2e7decd25..293ead5eda 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs @@ -4,7 +4,7 @@ use ledger_device_sdk::io::Comm; use tari_crypto::{keys::PublicKey, ristretto::RistrettoPublicKey, tari_utilities::ByteArray}; -use crate::{utils::derive_from_bip32_key, AppSW, KeyType, RESPONSE_VERSION, STATIC_ALPHA_INDEX}; +use crate::{utils::derive_from_bip32_key, AppSW, KeyType, RESPONSE_VERSION}; pub fn handler_get_public_key(comm: &mut Comm) -> Result<(), AppSW> { let data = comm.get_data().map_err(|_| AppSW::WrongApduLength)?; @@ -13,7 +13,11 @@ pub fn handler_get_public_key(comm: &mut Comm) -> Result<(), AppSW> { account_bytes.clone_from_slice(&data[0..8]); let account = u64::from_le_bytes(account_bytes); - let pk = match derive_from_bip32_key(account, STATIC_ALPHA_INDEX, KeyType::Alpha) { + let mut index_bytes = [0u8; 8]; + index_bytes.clone_from_slice(&data[8..16]); + let index = u64::from_le_bytes(index_bytes); + + let pk = match derive_from_bip32_key(account, index, KeyType::Nonce) { Ok(k) => RistrettoPublicKey::from_secret_key(&k), Err(e) => return Err(e), }; diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs index 20019d7158..f60da0e0ad 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs @@ -5,7 +5,7 @@ use ledger_device_sdk::io::Comm; use tari_crypto::{ristretto::RistrettoSecretKey, tari_utilities::ByteArray}; use crate::{ - utils::{derive_from_bip32_key, get_key_from_canonical_bytes, mask_a}, + utils::{alpha_hasher, derive_from_bip32_key, get_key_from_canonical_bytes}, AppSW, KeyType, RESPONSE_VERSION, @@ -93,7 +93,7 @@ pub fn handler_get_script_offset( index_bytes.clone_from_slice(&data[0..8]); let index = u64::from_le_bytes(index_bytes); - let offset = derive_from_bip32_key(offset_ctx.account, index, KeyType::ScriptOffset)?; + let offset = derive_from_bip32_key(offset_ctx.account, index, KeyType::SenderOffset)?; offset_ctx.total_sender_offset_private_key = &offset_ctx.total_sender_offset_private_key + &offset; return Ok(()); } diff --git a/applications/minotari_ledger_wallet/wallet/src/main.rs b/applications/minotari_ledger_wallet/wallet/src/main.rs index 4845a6c1f9..f4eb9ab4f4 100644 --- a/applications/minotari_ledger_wallet/wallet/src/main.rs +++ b/applications/minotari_ledger_wallet/wallet/src/main.rs @@ -15,6 +15,7 @@ mod app_ui { } mod handlers { pub mod get_metadata_signature; + pub mod get_public_alpha; pub mod get_public_key; pub mod get_script_offset; pub mod get_script_signature; @@ -27,6 +28,7 @@ use app_ui::menu::ui_menu_main; use critical_section::RawRestoreState; use handlers::{ get_metadata_signature::handler_get_metadata_signature, + get_public_alpha::handler_get_public_alpha, get_public_key::handler_get_public_key, get_script_offset::{handler_get_script_offset, ScriptOffsetCtx}, get_script_signature::{handler_get_script_signature, ScriptSignatureCtx}, @@ -107,6 +109,7 @@ pub enum Instruction { GetVersion, GetAppName, GetPublicKey, + GetPublicAlpha, GetScriptSignature { chunk: u8, more: bool }, GetScriptOffset { chunk: u8, more: bool }, GetMetadataSignature, @@ -120,7 +123,6 @@ pub enum KeyType { Alpha, Nonce, Recovery, - ScriptOffset, SenderOffset, } @@ -130,8 +132,7 @@ impl KeyType { Self::Alpha => 1, Self::Nonce => 2, Self::Recovery => 3, - Self::ScriptOffset => 4, - Self::SenderOffset => 5, + Self::SenderOffset => 4, } } } @@ -154,17 +155,18 @@ impl TryFrom for Instruction { match (value.ins, value.p1, value.p2) { (1, 0, 0) => Ok(Instruction::GetVersion), (2, 0, 0) => Ok(Instruction::GetAppName), - (3, 0, 0) => Ok(Instruction::GetPublicKey), - (4, 0..=MAX_PAYLOADS, 0 | P2_MORE) => Ok(Instruction::GetScriptSignature { + (3, 0, 0) => Ok(Instruction::GetPublicAlpha), + (4, 0, 0) => Ok(Instruction::GetPublicKey), + (5, 0..=MAX_PAYLOADS, 0 | P2_MORE) => Ok(Instruction::GetScriptSignature { chunk: value.p1, more: value.p2 == P2_MORE, }), - (5, 0..=MAX_PAYLOADS, 0 | P2_MORE) => Ok(Instruction::GetScriptOffset { + (6, 0..=MAX_PAYLOADS, 0 | P2_MORE) => Ok(Instruction::GetScriptOffset { chunk: value.p1, more: value.p2 == P2_MORE, }), - (6, 0, 0) => Ok(Instruction::GetMetadataSignature), - (4..=5, _, _) => Err(AppSW::WrongP1P2), + (7, 0, 0) => Ok(Instruction::GetMetadataSignature), + (5..=6, _, _) => Err(AppSW::WrongP1P2), (_, _, _) => Err(AppSW::InsNotSupported), } } @@ -212,6 +214,7 @@ fn handle_apdu( Ok(()) }, Instruction::GetPublicKey => handler_get_public_key(comm), + Instruction::GetPublicAlpha => handler_get_public_alpha(comm), Instruction::GetScriptSignature { chunk, more } => handler_get_script_signature(comm, chunk, more, signer_ctx), Instruction::GetScriptOffset { chunk, more } => handler_get_script_offset(comm, chunk, more, offset_ctx), Instruction::GetMetadataSignature => handler_get_metadata_signature(comm), diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index 1e1f94e259..c5cec2503e 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -23,7 +23,6 @@ use std::{collections::HashMap, ops::Shl}; use blake2::Blake2b; use digest::consts::U64; -use futures::AsyncReadExt; use log::*; use minotari_ledger_wallet_comms::ledger_wallet::get_transport; #[cfg(feature = "ledger")] @@ -194,18 +193,36 @@ where TBackend: KeyManagerBackend + 'static pub async fn get_public_key_at_key_id(&self, key_id: &TariKeyId) -> Result { match key_id { - KeyId::Managed { branch, index } => { - match branch{ - "LedgerNonde" => {} - _ => {let km = self + KeyId::Managed { branch, index } => match ( + branch == &TransactionKeyManagerBranch::MetadataEphemiralNonce.get_branch_key(), + &self.wallet_type, + ) { + (true, WalletType::Ledger(ledger)) => { + let transport = get_transport().map_err(|e| KeyManagerServiceError::LedgerError(e.to_string()))?; + let command = ledger.build_command(Instruction::GetPublicKey, index.to_le_bytes().to_vec()); + + match command.execute_with_transport(&transport) { + Ok(result) => { + debug!(target: LOG_TARGET, "result length: {}, data: {:?}", result.data().len(), result.data()); + if result.data().len() < 33 { + debug!(target: LOG_TARGET, "result less than 33"); + } + + PublicKey::from_canonical_bytes(&result.data()[1..33]) + .map_err(|e| KeyManagerServiceError::LedgerError(e.to_string())) + }, + Err(e) => Err(KeyManagerServiceError::LedgerError(e.to_string())), + } + }, + (_, _) => { + let km = self .key_managers .get(branch) .ok_or(KeyManagerServiceError::UnknownKeyBranch)? .read() .await; - Ok(km.derive_public_key(*index)?.key)} - } - + Ok(km.derive_public_key(*index)?.key) + }, }, KeyId::Derived { branch, label, index } => { let public_alpha = match &self.wallet_type { @@ -1009,7 +1026,7 @@ where TBackend: KeyManagerBackend + 'static KeyManagerError::InvalidKeyID.to_string(), ))?; - let mut data = (txo_version.as_u8() as u64).to_le_bytes().to_vec(); + let mut data = (ledger.network.as_byte() as u64).to_le_bytes().to_vec(); data.extend_from_slice(&(txo_version.as_u8() as u64).to_le_bytes()); data.extend_from_slice(&ephemeral_private_nonce_index.to_le_bytes()); data.extend_from_slice(&sender_offset_key_index.to_le_bytes()); diff --git a/base_layer/core/src/transactions/key_manager/interface.rs b/base_layer/core/src/transactions/key_manager/interface.rs index 47e6c212ae..cfa6cbe243 100644 --- a/base_layer/core/src/transactions/key_manager/interface.rs +++ b/base_layer/core/src/transactions/key_manager/interface.rs @@ -21,6 +21,7 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use std::str::FromStr; + use blake2::Blake2b; use digest::consts::U64; use strum_macros::EnumIter; @@ -71,6 +72,7 @@ impl TransactionKeyManagerBranch { TransactionKeyManagerBranch::Coinbase => "coinbase".to_string(), TransactionKeyManagerBranch::CommitmentMask => "commitment mask".to_string(), TransactionKeyManagerBranch::Nonce => "nonce".to_string(), + TransactionKeyManagerBranch::MetadataEphemiralNonce => "metadata ephemiral nonce".to_string(), TransactionKeyManagerBranch::KernelNonce => "kernel nonce".to_string(), TransactionKeyManagerBranch::SenderOffset => "sender offset".to_string(), } @@ -79,7 +81,7 @@ impl TransactionKeyManagerBranch { #[derive(Clone, Copy, EnumIter)] pub enum TransactionKeyManagerLabel { - ScriptKey + ScriptKey, } impl TransactionKeyManagerLabel { @@ -92,12 +94,11 @@ impl TransactionKeyManagerLabel { } } -impl FromStr for TransactionKeyManagerLabel -{ +impl FromStr for TransactionKeyManagerLabel { type Err = String; fn from_str(id: &str) -> Result { - match id{ + match id { "script key" => Ok(TransactionKeyManagerLabel::ScriptKey), _ => Err("Unknown label".to_string()), } From a85ab69efd885d9500131fe4209a87554545e67f Mon Sep 17 00:00:00 2001 From: brianp Date: Fri, 3 May 2024 11:57:21 +0200 Subject: [PATCH 31/49] refactoring --- .../wallet/src/handlers/get_script_offset.rs | 4 ++-- .../wallet/src/handlers/get_script_signature.rs | 6 +++--- applications/minotari_ledger_wallet/wallet/src/utils.rs | 7 +++++-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs index f60da0e0ad..1cb19e5f30 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs @@ -101,8 +101,8 @@ pub fn handler_get_script_offset( let end_commitment_keys = end_offset_indexes + offset_ctx.total_commitment_keys; if (end_offset_indexes..end_commitment_keys).contains(&(chunk as u64)) { let alpha = derive_from_bip32_key(offset_ctx.account, STATIC_ALPHA_INDEX, KeyType::Alpha)?; - let commitment = get_key_from_canonical_bytes(&data[0..32])?; - let k = mask_a(alpha, commitment)?; + let blinding_factor = get_key_from_canonical_bytes(&data[0..32])?; + let k = alpha_hasher(alpha, blinding_factor)?; offset_ctx.total_script_private_key = &offset_ctx.total_script_private_key + &k; return Ok(()); diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs index 21f1210903..942f7d5737 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs @@ -12,7 +12,7 @@ use tari_crypto::ristretto::{ use crate::{ alloc::string::ToString, - utils::{derive_from_bip32_key, get_key_from_canonical_bytes, mask_a}, + utils::{alpha_hasher, derive_from_bip32_key, get_key_from_canonical_bytes}, AppSW, KeyType, RESPONSE_VERSION, @@ -76,8 +76,8 @@ pub fn handler_get_script_signature( } let alpha = derive_from_bip32_key(signer_ctx.account, STATIC_ALPHA_INDEX, KeyType::Alpha)?; - let commitment: RistrettoSecretKey = get_key_from_canonical_bytes(&signer_ctx.payload[8..40])?; - let script_private_key = mask_a(alpha, commitment)?; + let blinding_factor: RistrettoSecretKey = get_key_from_canonical_bytes(&signer_ctx.payload[8..40])?; + let script_private_key = alpha_hasher(alpha, blinding_factor)?; let value: RistrettoSecretKey = get_key_from_canonical_bytes(&signer_ctx.payload[40..72])?; let spend_private_key: RistrettoSecretKey = get_key_from_canonical_bytes(&signer_ctx.payload[72..104])?; diff --git a/applications/minotari_ledger_wallet/wallet/src/utils.rs b/applications/minotari_ledger_wallet/wallet/src/utils.rs index 25d341f76d..7785725c40 100644 --- a/applications/minotari_ledger_wallet/wallet/src/utils.rs +++ b/applications/minotari_ledger_wallet/wallet/src/utils.rs @@ -224,9 +224,12 @@ pub fn get_key_from_canonical_bytes(bytes: &[u8]) -> Result Result { +pub fn alpha_hasher( + alpha: RistrettoSecretKey, + blinding_factor: RistrettoSecretKey, +) -> Result { let hasher = DomainSeparatedHasher::, KeyManagerHashingDomain>::new_with_label("script key"); - let hasher = hasher.chain(commitment.as_bytes()).finalize(); + let hasher = hasher.chain(blinding_factor.as_bytes()).finalize(); let private_key = get_key_from_uniform_bytes(hasher.as_ref())?; Ok(private_key + alpha) From 4e413449bc00b538cf5e734bbbec3e7cf0484f6f Mon Sep 17 00:00:00 2001 From: brianp Date: Fri, 3 May 2024 15:40:47 +0200 Subject: [PATCH 32/49] debugging --- .../src/handlers/get_metadata_signature.rs | 18 +++--------------- .../core/src/transactions/key_manager/inner.rs | 3 ++- .../transaction_output.rs | 4 ++++ 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_metadata_signature.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_metadata_signature.rs index 56901d1dd2..dd3013529a 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_metadata_signature.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_metadata_signature.rs @@ -25,49 +25,37 @@ use crate::{ pub fn handler_get_metadata_signature(comm: &mut Comm) -> Result<(), AppSW> { let data = comm.get_data().map_err(|_| AppSW::WrongApduLength)?; - SingleMessage::new(&"got data").show_and_wait(); - let mut account_bytes = [0u8; 8]; account_bytes.clone_from_slice(&data[0..8]); let account = u64::from_le_bytes(account_bytes); - SingleMessage::new(&"got account").show_and_wait(); let mut network_bytes = [0u8; 8]; network_bytes.clone_from_slice(&data[8..16]); let network = u64::from_le_bytes(network_bytes); - SingleMessage::new(&"got network").show_and_wait(); let mut txo_version_bytes = [0u8; 8]; txo_version_bytes.clone_from_slice(&data[16..24]); let txo_version = u64::from_le_bytes(txo_version_bytes); - SingleMessage::new(&"got txo version").show_and_wait(); let mut ephemeral_private_nonce_index_bytes = [0u8; 8]; ephemeral_private_nonce_index_bytes.clone_from_slice(&data[24..32]); let ephemeral_private_nonce_index = u64::from_le_bytes(ephemeral_private_nonce_index_bytes); - SingleMessage::new(&"got eph nonce").show_and_wait(); let mut sender_offset_key_index_bytes = [0u8; 8]; sender_offset_key_index_bytes.clone_from_slice(&data[32..40]); let sender_offset_key_index = u64::from_le_bytes(sender_offset_key_index_bytes); - SingleMessage::new(&"got offsets").show_and_wait(); let commitment: PedersenCommitment = get_key_from_canonical_bytes(&data[40..72])?; - SingleMessage::new(&"gen commit").show_and_wait(); let ephemeral_commitment: PedersenCommitment = get_key_from_canonical_bytes(&data[72..104])?; - SingleMessage::new(&"gen eph commit").show_and_wait(); let mut metadata_signature_message = [0u8; 32]; metadata_signature_message.clone_from_slice(&data[104..136]); - SingleMessage::new(&"got message").show_and_wait(); let ephemeral_private_key = derive_from_bip32_key(account, ephemeral_private_nonce_index, KeyType::Nonce)?; let ephemeral_pubkey = RistrettoPublicKey::from_secret_key(&ephemeral_private_key); - SingleMessage::new(&"derived eph keys").show_and_wait(); let sender_offset_private_key = derive_from_bip32_key(account, sender_offset_key_index, KeyType::SenderOffset)?; let sender_offset_public_key = RistrettoPublicKey::from_secret_key(&sender_offset_private_key); - SingleMessage::new(&"derived offset keys").show_and_wait(); let challenge = finalize_metadata_signature_challenge( txo_version, @@ -78,10 +66,8 @@ pub fn handler_get_metadata_signature(comm: &mut Comm) -> Result<(), AppSW> { &commitment, &metadata_signature_message, ); - SingleMessage::new(&"challenge").show_and_wait(); let factory = ExtendedPedersenCommitmentFactory::default(); - SingleMessage::new(&"factory").show_and_wait(); let metadata_signature = match RistrettoComAndPubSig::sign( &RistrettoSecretKey::default(), @@ -99,10 +85,12 @@ pub fn handler_get_metadata_signature(comm: &mut Comm) -> Result<(), AppSW> { return Err(AppSW::ScriptSignatureFail); }, }; - SingleMessage::new(&"complete").show_and_wait(); comm.append(&[RESPONSE_VERSION]); // version comm.append(&metadata_signature.to_vec()); + comm.append(&[255, 255, 255, 0, 0, 0, 255]); + comm.append(&challenge.to_vec()); + comm.append(&[255, 255, 255, 0, 0, 0, 255]); comm.reply_ok(); Ok(()) diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index c5cec2503e..76c8ea2f64 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -194,7 +194,8 @@ where TBackend: KeyManagerBackend + 'static pub async fn get_public_key_at_key_id(&self, key_id: &TariKeyId) -> Result { match key_id { KeyId::Managed { branch, index } => match ( - branch == &TransactionKeyManagerBranch::MetadataEphemiralNonce.get_branch_key(), + branch == &TransactionKeyManagerBranch::MetadataEphemiralNonce.get_branch_key() || + branch == &TransactionKeyManagerBranch::SenderOffset.get_branch_key(), &self.wallet_type, ) { (true, WalletType::Ledger(ledger)) => { diff --git a/base_layer/core/src/transactions/transaction_components/transaction_output.rs b/base_layer/core/src/transactions/transaction_components/transaction_output.rs index 51d856cd1e..b044001027 100644 --- a/base_layer/core/src/transactions/transaction_components/transaction_output.rs +++ b/base_layer/core/src/transactions/transaction_components/transaction_output.rs @@ -31,6 +31,7 @@ use std::{ use blake2::Blake2b; use borsh::{BorshDeserialize, BorshSerialize}; use digest::consts::{U32, U64}; +use log::debug; use rand::rngs::OsRng; use serde::{Deserialize, Serialize}; use tari_common_types::types::{ @@ -318,6 +319,9 @@ impl TransactionOutput { &self.encrypted_data, self.minimum_value_promise, ); + + debug!(target: "c::brian::test", "BRIAN HERE: {:?}", challenge); + if !self.metadata_signature.verify_challenge( &self.commitment, &self.sender_offset_public_key, From caf235ef09c0c451a8c666da066a837fdc44176a Mon Sep 17 00:00:00 2001 From: brianp Date: Mon, 6 May 2024 12:04:56 +0200 Subject: [PATCH 33/49] More debugging --- .../src/handlers/get_metadata_signature.rs | 4 +-- .../wallet/src/handlers/get_public_key.rs | 20 ++++++++++-- .../wallet/src/hashing.rs | 2 +- .../minotari_ledger_wallet/wallet/src/main.rs | 24 ++++++++------ .../wallet/src/utils.rs | 29 +++++++++++------ .../src/transactions/key_manager/inner.rs | 5 ++- .../src/transactions/key_manager/interface.rs | 31 ++++++++++++++----- .../transaction_output.rs | 18 ++++++++++- 8 files changed, 97 insertions(+), 36 deletions(-) diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_metadata_signature.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_metadata_signature.rs index dd3013529a..0db153d9ca 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_metadata_signature.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_metadata_signature.rs @@ -12,6 +12,7 @@ use tari_crypto::{ RistrettoPublicKey, RistrettoSecretKey, }, + tari_utilities::ByteArray, }; use crate::{ @@ -88,9 +89,6 @@ pub fn handler_get_metadata_signature(comm: &mut Comm) -> Result<(), AppSW> { comm.append(&[RESPONSE_VERSION]); // version comm.append(&metadata_signature.to_vec()); - comm.append(&[255, 255, 255, 0, 0, 0, 255]); - comm.append(&challenge.to_vec()); - comm.append(&[255, 255, 255, 0, 0, 0, 255]); comm.reply_ok(); Ok(()) diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs index 293ead5eda..4304a78468 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs @@ -1,10 +1,15 @@ // Copyright 2024 The Tari Project // SPDX-License-Identifier: BSD-3-Clause -use ledger_device_sdk::io::Comm; +use ledger_device_sdk::{io::Comm, ui::gadgets::SingleMessage}; use tari_crypto::{keys::PublicKey, ristretto::RistrettoPublicKey, tari_utilities::ByteArray}; -use crate::{utils::derive_from_bip32_key, AppSW, KeyType, RESPONSE_VERSION}; +use crate::{ + utils::{derive_from_bip32_key, u64_to_string}, + AppSW, + KeyType, + RESPONSE_VERSION, +}; pub fn handler_get_public_key(comm: &mut Comm) -> Result<(), AppSW> { let data = comm.get_data().map_err(|_| AppSW::WrongApduLength)?; @@ -17,7 +22,16 @@ pub fn handler_get_public_key(comm: &mut Comm) -> Result<(), AppSW> { index_bytes.clone_from_slice(&data[8..16]); let index = u64::from_le_bytes(index_bytes); - let pk = match derive_from_bip32_key(account, index, KeyType::Nonce) { + let mut key_bytes = [0u8; 8]; + key_bytes.clone_from_slice(&data[16..24]); + let key_int = u64::from_le_bytes(key_bytes); + let key = KeyType::from_branch_key(key_int); + let second_key = KeyType::from_branch_key(key_int); + + let what_key = u64_to_string(second_key.as_byte() as u64); + SingleMessage::new(&what_key).show_and_wait(); + + let pk = match derive_from_bip32_key(account, index, key) { Ok(k) => RistrettoPublicKey::from_secret_key(&k), Err(e) => return Err(e), }; diff --git a/applications/minotari_ledger_wallet/wallet/src/hashing.rs b/applications/minotari_ledger_wallet/wallet/src/hashing.rs index 343c2ad44a..384a7932f0 100644 --- a/applications/minotari_ledger_wallet/wallet/src/hashing.rs +++ b/applications/minotari_ledger_wallet/wallet/src/hashing.rs @@ -16,7 +16,7 @@ impl DomainSeparatedConsensusHasher where D: Default { pub fn new(label: &'static str, network: u64) -> Self { - let hasher = DomainSeparatedBorshHasher::::new_with_label(&format!("{}.n{}", label, network)); + let hasher = DomainSeparatedBorshHasher::::new_with_label(&format!("{}.n{}", label, network as u8)); Self { hasher } } diff --git a/applications/minotari_ledger_wallet/wallet/src/main.rs b/applications/minotari_ledger_wallet/wallet/src/main.rs index f4eb9ab4f4..106021eaf3 100644 --- a/applications/minotari_ledger_wallet/wallet/src/main.rs +++ b/applications/minotari_ledger_wallet/wallet/src/main.rs @@ -119,20 +119,24 @@ const P2_MORE: u8 = 0x01; const STATIC_ALPHA_INDEX: u64 = 42; const MAX_PAYLOADS: u8 = 250; +#[repr(u8)] pub enum KeyType { - Alpha, - Nonce, - Recovery, - SenderOffset, + Alpha = 0x01, + Nonce = 0x02, + Recovery = 0x03, + SenderOffset = 0x04, } impl KeyType { - fn to_byte(&self) -> u8 { - match self { - Self::Alpha => 1, - Self::Nonce => 2, - Self::Recovery => 3, - Self::SenderOffset => 4, + pub fn as_byte(self) -> u8 { + self as u8 + } + + fn from_branch_key(n: u64) -> Self { + match n { + 1 => Self::Alpha, + 6 => Self::SenderOffset, + 5 | 2 | _ => Self::Nonce, } } } diff --git a/applications/minotari_ledger_wallet/wallet/src/utils.rs b/applications/minotari_ledger_wallet/wallet/src/utils.rs index 7785725c40..8aa62fe818 100644 --- a/applications/minotari_ledger_wallet/wallet/src/utils.rs +++ b/applications/minotari_ledger_wallet/wallet/src/utils.rs @@ -8,7 +8,7 @@ use digest::consts::U64; use ledger_device_sdk::{ ecc::{bip32_derive, make_bip32_path, CurvesId, CxError}, io::SyscallError, - ui::gadgets::SingleMessage, + ui::gadgets::{MessageScroller, SingleMessage}, }; use tari_crypto::{ hash_domain, @@ -242,7 +242,7 @@ pub fn derive_from_bip32_key( ) -> Result { let account = u64_to_string(u64_account); let index = u64_to_string(u64_index); - let key_type = u64_to_string(u64_key_type.to_byte() as u64); + let key_type = u64_to_string(u64_key_type.as_byte() as u64); let mut bip32_path = "m/44'/".to_string(); bip32_path.push_str(&BIP32_COIN_TYPE.to_string()); @@ -272,12 +272,21 @@ pub fn finalize_metadata_signature_challenge( commitment: &PedersenCommitment, message: &[u8; 32], ) -> [u8; 64] { - DomainSeparatedConsensusHasher::>::new("metadata_signature", network) - .chain(&ephemeral_pubkey) - .chain(&ephemeral_commitment) - .chain(&sender_offset_public_key) - .chain(&commitment) - .chain(&message) - .finalize() - .into() + let network_str = u64_to_string(network); + MessageScroller::new(&network_str).event_loop(); + MessageScroller::new(&sender_offset_public_key.to_string()).event_loop(); + MessageScroller::new(&ephemeral_commitment.as_public_key().to_string()).event_loop(); + MessageScroller::new(&ephemeral_pubkey.to_string()).event_loop(); + MessageScroller::new(&commitment.as_public_key().to_string()).event_loop(); + + let challenge = + DomainSeparatedConsensusHasher::>::new("metadata_signature", network) + .chain(ephemeral_pubkey) + .chain(ephemeral_commitment) + .chain(sender_offset_public_key) + .chain(commitment) + .chain(&message) + .finalize(); + + challenge.into() } diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index 76c8ea2f64..3c384243ea 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -200,7 +200,10 @@ where TBackend: KeyManagerBackend + 'static ) { (true, WalletType::Ledger(ledger)) => { let transport = get_transport().map_err(|e| KeyManagerServiceError::LedgerError(e.to_string()))?; - let command = ledger.build_command(Instruction::GetPublicKey, index.to_le_bytes().to_vec()); + let mut data = index.to_le_bytes().to_vec(); + let branch_u8 = TransactionKeyManagerBranch::from_key(branch).as_byte(); + data.extend_from_slice(&(branch_u8 as u64).to_le_bytes()); + let command = ledger.build_command(Instruction::GetPublicKey, data); match command.execute_with_transport(&transport) { Ok(result) => { diff --git a/base_layer/core/src/transactions/key_manager/interface.rs b/base_layer/core/src/transactions/key_manager/interface.rs index cfa6cbe243..50aaaacabb 100644 --- a/base_layer/core/src/transactions/key_manager/interface.rs +++ b/base_layer/core/src/transactions/key_manager/interface.rs @@ -52,15 +52,16 @@ pub enum TxoStage { Output, } +#[repr(u8)] #[derive(Clone, Copy, EnumIter)] pub enum TransactionKeyManagerBranch { - DataEncryption, - Coinbase, - MetadataEphemiralNonce, - CommitmentMask, - Nonce, - KernelNonce, - SenderOffset, + DataEncryption = 0x00, + Coinbase = 0x01, + MetadataEphemiralNonce = 0x02, + CommitmentMask = 0x03, + Nonce = 0x04, + KernelNonce = 0x05, + SenderOffset = 0x06, } impl TransactionKeyManagerBranch { @@ -77,6 +78,22 @@ impl TransactionKeyManagerBranch { TransactionKeyManagerBranch::SenderOffset => "sender offset".to_string(), } } + + pub fn from_key(key: &str) -> Self { + match key { + "data encryption" => TransactionKeyManagerBranch::DataEncryption, + "coinbase" => TransactionKeyManagerBranch::Coinbase, + "commitment mask" => TransactionKeyManagerBranch::CommitmentMask, + "metadata ephemiral nonce" => TransactionKeyManagerBranch::MetadataEphemiralNonce, + "kernel nonce" => TransactionKeyManagerBranch::KernelNonce, + "sender offset" => TransactionKeyManagerBranch::SenderOffset, + "nonce" | _ => TransactionKeyManagerBranch::Nonce, + } + } + + pub fn as_byte(self) -> u8 { + self as u8 + } } #[derive(Clone, Copy, EnumIter)] diff --git a/base_layer/core/src/transactions/transaction_components/transaction_output.rs b/base_layer/core/src/transactions/transaction_components/transaction_output.rs index b044001027..d83582cfe4 100644 --- a/base_layer/core/src/transactions/transaction_components/transaction_output.rs +++ b/base_layer/core/src/transactions/transaction_components/transaction_output.rs @@ -34,6 +34,7 @@ use digest::consts::{U32, U64}; use log::debug; use rand::rngs::OsRng; use serde::{Deserialize, Serialize}; +use tari_common::configuration::Network; use tari_common_types::types::{ ComAndPubSignature, Commitment, @@ -54,6 +55,7 @@ use tari_crypto::{ }; use tari_hashing::TransactionHashDomain; use tari_script::TariScript; +use tari_utilities::ByteArray; use super::TransactionOutputVersion; use crate::{ @@ -320,7 +322,7 @@ impl TransactionOutput { self.minimum_value_promise, ); - debug!(target: "c::brian::test", "BRIAN HERE: {:?}", challenge); + debug!(target: "c::brian::test", "challenge: {:?}", &challenge); if !self.metadata_signature.verify_challenge( &self.commitment, @@ -408,6 +410,20 @@ impl TransactionOutput { encrypted_data, &minimum_value_promise, ); + + debug!(target: "c::brian::test", "version: {:?}", &version); + debug!(target: "c::brian::test", "network: {:?}", &Network::LocalNet.as_byte()); + debug!(target: "c::brian::test", "sender_offset_public_key: {:?}", &sender_offset_public_key); + debug!(target: "c::brian::test", "sender_offset_public_key: {:?}", &sender_offset_public_key.to_vec()); + debug!(target: "c::brian::test", "ephemeral_commitment: {:?}", &ephemeral_commitment.as_public_key()); + debug!(target: "c::brian::test", "ephemeral_commitment: {:?}", &ephemeral_commitment.to_vec()); + debug!(target: "c::brian::test", "ephemeral_pubkey: {:?}", &ephemeral_pubkey); + debug!(target: "c::brian::test", "ephemeral_pubkey: {:?}", &ephemeral_pubkey.to_vec()); + debug!(target: "c::brian::test", "commitment: {:?}", &commitment.as_public_key()); + debug!(target: "c::brian::test", "commitment: {:?}", &commitment.to_vec()); + debug!(target: "c::brian::test", "message: {:?}", &message.to_hex()); + debug!(target: "c::brian::test", "message: {:?}", &message.to_vec()); + TransactionOutput::finalize_metadata_signature_challenge( version, sender_offset_public_key, From 539635e352d4902e981437568f02720d9ef3cfa2 Mon Sep 17 00:00:00 2001 From: brianp Date: Mon, 6 May 2024 15:32:49 +0200 Subject: [PATCH 34/49] fix spelling --- base_layer/core/src/transactions/key_manager/inner.rs | 4 ++-- base_layer/core/src/transactions/key_manager/interface.rs | 6 +++--- .../transaction_protocol/transaction_initializer.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index 3c384243ea..0e2ce04de7 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -194,7 +194,7 @@ where TBackend: KeyManagerBackend + 'static pub async fn get_public_key_at_key_id(&self, key_id: &TariKeyId) -> Result { match key_id { KeyId::Managed { branch, index } => match ( - branch == &TransactionKeyManagerBranch::MetadataEphemiralNonce.get_branch_key() || + branch == &TransactionKeyManagerBranch::MetadataEphemeralNonce.get_branch_key() || branch == &TransactionKeyManagerBranch::SenderOffset.get_branch_key(), &self.wallet_type, ) { @@ -909,7 +909,7 @@ where TBackend: KeyManagerBackend + 'static let sender_offset_public_key = self.get_public_key_at_key_id(sender_offset_key_id).await?; // Use the pubkey, but generate the nonce on ledger let (ephemeral_private_nonce_id, ephemeral_pubkey) = self - .get_next_key(&TransactionKeyManagerBranch::MetadataEphemiralNonce.get_branch_key()) + .get_next_key(&TransactionKeyManagerBranch::MetadataEphemeralNonce.get_branch_key()) .await?; let receiver_partial_metadata_signature = self .get_receiver_partial_metadata_signature( diff --git a/base_layer/core/src/transactions/key_manager/interface.rs b/base_layer/core/src/transactions/key_manager/interface.rs index 50aaaacabb..e30a4e32e3 100644 --- a/base_layer/core/src/transactions/key_manager/interface.rs +++ b/base_layer/core/src/transactions/key_manager/interface.rs @@ -57,7 +57,7 @@ pub enum TxoStage { pub enum TransactionKeyManagerBranch { DataEncryption = 0x00, Coinbase = 0x01, - MetadataEphemiralNonce = 0x02, + MetadataEphemeralNonce = 0x02, CommitmentMask = 0x03, Nonce = 0x04, KernelNonce = 0x05, @@ -73,7 +73,7 @@ impl TransactionKeyManagerBranch { TransactionKeyManagerBranch::Coinbase => "coinbase".to_string(), TransactionKeyManagerBranch::CommitmentMask => "commitment mask".to_string(), TransactionKeyManagerBranch::Nonce => "nonce".to_string(), - TransactionKeyManagerBranch::MetadataEphemiralNonce => "metadata ephemiral nonce".to_string(), + TransactionKeyManagerBranch::MetadataEphemeralNonce => "metadata ephemeral nonce".to_string(), TransactionKeyManagerBranch::KernelNonce => "kernel nonce".to_string(), TransactionKeyManagerBranch::SenderOffset => "sender offset".to_string(), } @@ -84,7 +84,7 @@ impl TransactionKeyManagerBranch { "data encryption" => TransactionKeyManagerBranch::DataEncryption, "coinbase" => TransactionKeyManagerBranch::Coinbase, "commitment mask" => TransactionKeyManagerBranch::CommitmentMask, - "metadata ephemiral nonce" => TransactionKeyManagerBranch::MetadataEphemiralNonce, + "metadata ephemeral nonce" => TransactionKeyManagerBranch::MetadataEphemeralNonce, "kernel nonce" => TransactionKeyManagerBranch::KernelNonce, "sender offset" => TransactionKeyManagerBranch::SenderOffset, "nonce" | _ => TransactionKeyManagerBranch::Nonce, diff --git a/base_layer/core/src/transactions/transaction_protocol/transaction_initializer.rs b/base_layer/core/src/transactions/transaction_protocol/transaction_initializer.rs index c53b40c5c2..5c30c7a7ba 100644 --- a/base_layer/core/src/transactions/transaction_protocol/transaction_initializer.rs +++ b/base_layer/core/src/transactions/transaction_protocol/transaction_initializer.rs @@ -153,7 +153,7 @@ where KM: TransactionKeyManagerInterface ) -> Result<&mut Self, KeyManagerServiceError> { let (recipient_ephemeral_public_key_nonce, _) = self .key_manager - .get_next_key(TransactionKeyManagerBranch::MetadataEphemiralNonce.get_branch_key()) + .get_next_key(TransactionKeyManagerBranch::MetadataEphemeralNonce.get_branch_key()) .await?; let (recipient_sender_offset_key_id, _) = self .key_manager From 9f4b028903644874e6efb8d61bd086b9cd75ade6 Mon Sep 17 00:00:00 2001 From: brianp Date: Mon, 6 May 2024 15:33:28 +0200 Subject: [PATCH 35/49] pub key derive --- .../core/src/transactions/key_manager/inner.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index 0e2ce04de7..f27fa1569c 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -171,14 +171,12 @@ where TBackend: KeyManagerBackend + 'static .await; self.db.increment_key_index(branch)?; let index = km.increment_key_index(1); - let key = km.derive_public_key(index)?.key; - Ok(( - KeyId::Managed { - branch: branch.to_string(), - index, - }, - key, - )) + let key_id = KeyId::Managed { + branch: branch.to_string(), + index, + }; + let key = self.get_public_key_at_key_id(&key_id).await?; + Ok((key_id, key)) } pub async fn get_static_key(&self, branch: &str) -> Result { From c1d01d696123fd5eb8c6b4a3c659648003e22388 Mon Sep 17 00:00:00 2001 From: brianp Date: Mon, 6 May 2024 21:50:38 +0200 Subject: [PATCH 36/49] Get proper account on script signature --- .../src/handlers/get_metadata_signature.rs | 1 - .../wallet/src/handlers/get_public_alpha.rs | 13 +++++- .../wallet/src/handlers/get_public_key.rs | 13 +----- .../src/handlers/get_script_signature.rs | 45 ++++++++++++------- .../wallet/src/utils.rs | 17 ++++--- .../src/transactions/key_manager/inner.rs | 25 +++++++---- .../transaction_input.rs | 13 ++++++ 7 files changed, 84 insertions(+), 43 deletions(-) diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_metadata_signature.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_metadata_signature.rs index 0db153d9ca..a05801b258 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_metadata_signature.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_metadata_signature.rs @@ -12,7 +12,6 @@ use tari_crypto::{ RistrettoPublicKey, RistrettoSecretKey, }, - tari_utilities::ByteArray, }; use crate::{ diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_alpha.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_alpha.rs index 3904303734..983c617730 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_alpha.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_alpha.rs @@ -1,10 +1,17 @@ // Copyright 2024 The Tari Project // SPDX-License-Identifier: BSD-3-Clause -use ledger_device_sdk::io::Comm; +use ledger_device_sdk::{io::Comm, ui::gadgets::MessageScroller}; use tari_crypto::{keys::PublicKey, ristretto::RistrettoPublicKey, tari_utilities::ByteArray}; -use crate::{utils::derive_from_bip32_key, AppSW, KeyType, RESPONSE_VERSION, STATIC_ALPHA_INDEX}; +use crate::{ + alloc::string::ToString, + utils::derive_from_bip32_key, + AppSW, + KeyType, + RESPONSE_VERSION, + STATIC_ALPHA_INDEX, +}; pub fn handler_get_public_alpha(comm: &mut Comm) -> Result<(), AppSW> { let data = comm.get_data().map_err(|_| AppSW::WrongApduLength)?; @@ -18,6 +25,8 @@ pub fn handler_get_public_alpha(comm: &mut Comm) -> Result<(), AppSW> { Err(e) => return Err(e), }; + MessageScroller::new(&pk.to_string()).event_loop(); + comm.append(&[RESPONSE_VERSION]); // version comm.append(pk.as_bytes()); comm.reply_ok(); diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs index 4304a78468..449cc8c218 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_key.rs @@ -1,15 +1,10 @@ // Copyright 2024 The Tari Project // SPDX-License-Identifier: BSD-3-Clause -use ledger_device_sdk::{io::Comm, ui::gadgets::SingleMessage}; +use ledger_device_sdk::io::Comm; use tari_crypto::{keys::PublicKey, ristretto::RistrettoPublicKey, tari_utilities::ByteArray}; -use crate::{ - utils::{derive_from_bip32_key, u64_to_string}, - AppSW, - KeyType, - RESPONSE_VERSION, -}; +use crate::{utils::derive_from_bip32_key, AppSW, KeyType, RESPONSE_VERSION}; pub fn handler_get_public_key(comm: &mut Comm) -> Result<(), AppSW> { let data = comm.get_data().map_err(|_| AppSW::WrongApduLength)?; @@ -26,10 +21,6 @@ pub fn handler_get_public_key(comm: &mut Comm) -> Result<(), AppSW> { key_bytes.clone_from_slice(&data[16..24]); let key_int = u64::from_le_bytes(key_bytes); let key = KeyType::from_branch_key(key_int); - let second_key = KeyType::from_branch_key(key_int); - - let what_key = u64_to_string(second_key.as_byte() as u64); - SingleMessage::new(&what_key).show_and_wait(); let pk = match derive_from_bip32_key(account, index, key) { Ok(k) => RistrettoPublicKey::from_secret_key(&k), diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs index 942f7d5737..095f14d7a5 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs @@ -1,18 +1,26 @@ // Copyright 2024 The Tari Project // SPDX-License-Identifier: BSD-3-Clause -use alloc::format; +use alloc::{format, str::from_utf8}; -use ledger_device_sdk::{io::Comm, ui::gadgets::SingleMessage}; -use tari_crypto::ristretto::{ - pedersen::extended_commitment_factory::ExtendedPedersenCommitmentFactory, - RistrettoComAndPubSig, - RistrettoSecretKey, +use ledger_device_sdk::{ + io::Comm, + ui::gadgets::{MessageScroller, SingleMessage}, +}; +use tari_crypto::{ + keys::PublicKey, + ristretto::{ + pedersen::extended_commitment_factory::ExtendedPedersenCommitmentFactory, + RistrettoComAndPubSig, + RistrettoPublicKey, + RistrettoSecretKey, + }, + tari_utilities::{hex::Hex, ByteArray}, }; use crate::{ alloc::string::ToString, - utils::{alpha_hasher, derive_from_bip32_key, get_key_from_canonical_bytes}, + utils::{alpha_hasher, derive_from_bip32_key, get_key_from_canonical_bytes, u64_to_string}, AppSW, KeyType, RESPONSE_VERSION, @@ -55,11 +63,6 @@ pub fn handler_get_script_signature( if chunk == 0 { // Reset transaction context signer_ctx.reset(); - - // Set the account for the transaction - let mut account_bytes = [0u8; 8]; - account_bytes.clone_from_slice(&signer_ctx.payload[0..8]); - signer_ctx.account = u64::from_le_bytes(account_bytes); } if signer_ctx.payload_len + data.len() > MAX_TRANSACTION_LEN { @@ -75,15 +78,27 @@ pub fn handler_get_script_signature( return Ok(()); } + // Set the account for the transaction + let mut account_bytes = [0u8; 8]; + account_bytes.clone_from_slice(&signer_ctx.payload[0..8]); + signer_ctx.account = u64::from_le_bytes(account_bytes); + MessageScroller::new(&u64_to_string(signer_ctx.account)).event_loop(); + let alpha = derive_from_bip32_key(signer_ctx.account, STATIC_ALPHA_INDEX, KeyType::Alpha)?; let blinding_factor: RistrettoSecretKey = get_key_from_canonical_bytes(&signer_ctx.payload[8..40])?; + let alpha_pk = RistrettoPublicKey::from_secret_key(&alpha); let script_private_key = alpha_hasher(alpha, blinding_factor)?; + let pk = RistrettoPublicKey::from_secret_key(&script_private_key); + + MessageScroller::new(&alpha_pk.to_string()).event_loop(); + MessageScroller::new(&pk.to_string()).event_loop(); + let value: RistrettoSecretKey = get_key_from_canonical_bytes(&signer_ctx.payload[40..72])?; let spend_private_key: RistrettoSecretKey = get_key_from_canonical_bytes(&signer_ctx.payload[72..104])?; - let r_a = get_key_from_canonical_bytes(&signer_ctx.payload[104..136])?; - let r_x = get_key_from_canonical_bytes(&signer_ctx.payload[136..168])?; - let r_y = get_key_from_canonical_bytes(&signer_ctx.payload[168..200])?; + let r_a: RistrettoSecretKey = get_key_from_canonical_bytes(&signer_ctx.payload[104..136])?; + let r_x: RistrettoSecretKey = get_key_from_canonical_bytes(&signer_ctx.payload[136..168])?; + let r_y: RistrettoSecretKey = get_key_from_canonical_bytes(&signer_ctx.payload[168..200])?; let challenge = &signer_ctx.payload[200..264]; let factory = ExtendedPedersenCommitmentFactory::default(); diff --git a/applications/minotari_ledger_wallet/wallet/src/utils.rs b/applications/minotari_ledger_wallet/wallet/src/utils.rs index 8aa62fe818..57ca0d2e20 100644 --- a/applications/minotari_ledger_wallet/wallet/src/utils.rs +++ b/applications/minotari_ledger_wallet/wallet/src/utils.rs @@ -244,6 +244,11 @@ pub fn derive_from_bip32_key( let index = u64_to_string(u64_index); let key_type = u64_to_string(u64_key_type.as_byte() as u64); + // MessageScroller::new(&"derive").event_loop(); + // MessageScroller::new(&account).event_loop(); + // MessageScroller::new(&index).event_loop(); + // MessageScroller::new(&key_type).event_loop(); + let mut bip32_path = "m/44'/".to_string(); bip32_path.push_str(&BIP32_COIN_TYPE.to_string()); bip32_path.push_str(&"'/"); @@ -272,12 +277,12 @@ pub fn finalize_metadata_signature_challenge( commitment: &PedersenCommitment, message: &[u8; 32], ) -> [u8; 64] { - let network_str = u64_to_string(network); - MessageScroller::new(&network_str).event_loop(); - MessageScroller::new(&sender_offset_public_key.to_string()).event_loop(); - MessageScroller::new(&ephemeral_commitment.as_public_key().to_string()).event_loop(); - MessageScroller::new(&ephemeral_pubkey.to_string()).event_loop(); - MessageScroller::new(&commitment.as_public_key().to_string()).event_loop(); + // let network_str = u64_to_string(network); + // MessageScroller::new(&network_str).event_loop(); + // MessageScroller::new(&sender_offset_public_key.to_string()).event_loop(); + // MessageScroller::new(&ephemeral_commitment.as_public_key().to_string()).event_loop(); + // MessageScroller::new(&ephemeral_pubkey.to_string()).event_loop(); + // MessageScroller::new(&commitment.as_public_key().to_string()).event_loop(); let challenge = DomainSeparatedConsensusHasher::>::new("metadata_signature", network) diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index f27fa1569c..df97a0745a 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -163,14 +163,16 @@ where TBackend: KeyManagerBackend + 'static } pub async fn get_next_key(&self, branch: &str) -> Result<(TariKeyId, PublicKey), KeyManagerServiceError> { - let mut km = self - .key_managers - .get(branch) - .ok_or(KeyManagerServiceError::UnknownKeyBranch)? - .write() - .await; - self.db.increment_key_index(branch)?; - let index = km.increment_key_index(1); + let index = { + let mut km = self + .key_managers + .get(branch) + .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .write() + .await; + self.db.increment_key_index(branch)?; + km.increment_key_index(1) + }; let key_id = KeyId::Managed { branch: branch.to_string(), index, @@ -544,6 +546,13 @@ where TBackend: KeyManagerBackend + 'static script_message, ); + debug!(target: "c::brian::test", "before sending"); + debug!(target: "c::brian::test", "ephemeral_commitment: {:?}", &ephemeral_commitment.as_public_key()); + debug!(target: "c::brian::test", "ephemeral_pubkey: {:?}", &ephemeral_pubkey.to_string()); + debug!(target: "c::brian::test", "script_public_key: {:?}", &&self.get_public_key_at_key_id(script_key_id).await?.to_string()); + debug!(target: "c::brian::test", "commitment: {:?}", &commitment.to_hex()); + debug!(target: "c::brian::test", "challenge: {:?}", &challenge); + match (&self.wallet_type, script_key_id) { ( WalletType::Ledger(ledger), diff --git a/base_layer/core/src/transactions/transaction_components/transaction_input.rs b/base_layer/core/src/transactions/transaction_components/transaction_input.rs index 8186dbabd6..3cc91d7034 100644 --- a/base_layer/core/src/transactions/transaction_components/transaction_input.rs +++ b/base_layer/core/src/transactions/transaction_components/transaction_input.rs @@ -31,12 +31,14 @@ use std::{ use blake2::Blake2b; use borsh::{BorshDeserialize, BorshSerialize}; use digest::consts::{U32, U64}; +use log::debug; use rand::rngs::OsRng; use serde::{Deserialize, Serialize}; use tari_common_types::types::{ComAndPubSignature, Commitment, CommitmentFactory, FixedHash, HashOutput, PublicKey}; use tari_crypto::tari_utilities::hex::Hex; use tari_hashing::TransactionHashDomain; use tari_script::{ExecutionStack, ScriptContext, StackItem, TariScript}; +use tari_utilities::ByteArray; use super::{TransactionInputVersion, TransactionOutputVersion}; use crate::{ @@ -383,6 +385,17 @@ impl TransactionInput { script_public_key, commitment, ); + + debug!(target: "c::brian::test", "version: {:?}", &self.version); + debug!(target: "c::brian::test", "script_signature.ephemeral_commitment: {:?}", &self.script_signature.ephemeral_commitment().as_public_key()); + debug!(target: "c::brian::test", "script_signature.ephemeral_commitment: {:?}", &self.script_signature.ephemeral_commitment().to_vec()); + debug!(target: "c::brian::test", "script_signature.ephemeral_pubkey: {:?}", &self.script_signature.ephemeral_pubkey()); + debug!(target: "c::brian::test", "script_signature.ephemeral_pubkey: {:?}", &self.script_signature.ephemeral_pubkey().to_vec()); + debug!(target: "c::brian::test", "script_public_key: {:?}", &script_public_key); + debug!(target: "c::brian::test", "script_public_key: {:?}", &script_public_key.to_vec()); + debug!(target: "c::brian::test", "commitment: {:?}", &script_public_key.to_vec()); + debug!(target: "c::brian::test", "challenge: {:?}", &challenge); + if self.script_signature.verify_challenge( commitment, script_public_key, From a30a18283ce87fc8092909cd6ffc17144cfd100f Mon Sep 17 00:00:00 2001 From: brianp Date: Tue, 7 May 2024 10:54:50 +0200 Subject: [PATCH 37/49] Validate and correct the domain hashers --- .../src/handlers/get_script_signature.rs | 4 ++- .../wallet/src/utils.rs | 22 ++++++++++++--- .../src/transactions/key_manager/inner.rs | 28 +++++++++++++------ .../transaction_output.rs | 11 ++++++++ 4 files changed, 51 insertions(+), 14 deletions(-) diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs index 095f14d7a5..611e8833f4 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs @@ -20,7 +20,7 @@ use tari_crypto::{ use crate::{ alloc::string::ToString, - utils::{alpha_hasher, derive_from_bip32_key, get_key_from_canonical_bytes, u64_to_string}, + utils::{alpha_hasher, derive_from_bip32_key, get_key_from_canonical_bytes, special_hash, u64_to_string}, AppSW, KeyType, RESPONSE_VERSION, @@ -93,6 +93,8 @@ pub fn handler_get_script_signature( MessageScroller::new(&alpha_pk.to_string()).event_loop(); MessageScroller::new(&pk.to_string()).event_loop(); + MessageScroller::new(&(&pk + alpha_pk).to_string()).event_loop(); + special_hash(); let value: RistrettoSecretKey = get_key_from_canonical_bytes(&signer_ctx.payload[40..72])?; let spend_private_key: RistrettoSecretKey = get_key_from_canonical_bytes(&signer_ctx.payload[72..104])?; diff --git a/applications/minotari_ledger_wallet/wallet/src/utils.rs b/applications/minotari_ledger_wallet/wallet/src/utils.rs index 57ca0d2e20..39b0d7e9da 100644 --- a/applications/minotari_ledger_wallet/wallet/src/utils.rs +++ b/applications/minotari_ledger_wallet/wallet/src/utils.rs @@ -13,9 +13,9 @@ use ledger_device_sdk::{ use tari_crypto::{ hash_domain, hashing::DomainSeparatedHasher, - keys::SecretKey, + keys::{PublicKey, SecretKey}, ristretto::{pedersen::PedersenCommitment, RistrettoPublicKey, RistrettoSecretKey}, - tari_utilities::ByteArray, + tari_utilities::{hex::Hex, ByteArray}, }; use zeroize::Zeroizing; @@ -28,7 +28,11 @@ use crate::{ }; hash_domain!(LedgerHashDomain, "com.tari.minotari_ledger_wallet", 0); -hash_domain!(KeyManagerHashingDomain, "com.tari.base_layer.key_manager", 1); +hash_domain!( + KeyManagerTransactionsHashDomain, + "com.tari.base_layer.core.transactions.key_manager", + 1 +); hash_domain!(TransactionHashDomain, "com.tari.base_layer.core.transactions", 0); /// BIP32 path stored as an array of [`u32`]. @@ -228,7 +232,7 @@ pub fn alpha_hasher( alpha: RistrettoSecretKey, blinding_factor: RistrettoSecretKey, ) -> Result { - let hasher = DomainSeparatedHasher::, KeyManagerHashingDomain>::new_with_label("script key"); + let hasher = DomainSeparatedHasher::, KeyManagerTransactionsHashDomain>::new_with_label("script key"); let hasher = hasher.chain(blinding_factor.as_bytes()).finalize(); let private_key = get_key_from_uniform_bytes(hasher.as_ref())?; @@ -295,3 +299,13 @@ pub fn finalize_metadata_signature_challenge( challenge.into() } + +pub fn special_hash() { + let hasher = DomainSeparatedHasher::, KeyManagerTransactionsHashDomain>::new_with_label("script key"); + let hasher = hasher.chain("test input".as_bytes()).finalize(); + let private_key = RistrettoSecretKey::from_uniform_bytes(hasher.as_ref()).unwrap(); + MessageScroller::new(&private_key.to_hex()).event_loop(); + let public_key = RistrettoPublicKey::from_secret_key(&private_key); + + MessageScroller::new(&public_key.to_string()).event_loop(); +} diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index df97a0745a..579820b255 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -90,7 +90,7 @@ use crate::{ }; hash_domain!( - KeyManagerHashingDomain, + KeyManagerTransactionsHashDomain, "com.tari.base_layer.core.transactions.key_manager", 1 ); @@ -260,14 +260,15 @@ where TBackend: KeyManagerBackend + 'static fn get_domain_hasher( label: &str, - ) -> Result, KeyManagerHashingDomain>, KeyManagerServiceError> { + ) -> Result, KeyManagerTransactionsHashDomain>, KeyManagerServiceError> { let tx_label = label.parse::().map_err(|e| { KeyManagerServiceError::UnknownError(format!("Could not retrieve label for derived key: {}", e)) })?; match tx_label { - TransactionKeyManagerLabel::ScriptKey => { - Ok(DomainSeparatedHasher::, KeyManagerHashingDomain>::new_with_label("script key")) - }, + TransactionKeyManagerLabel::ScriptKey => Ok(DomainSeparatedHasher::< + Blake2b, + KeyManagerTransactionsHashDomain, + >::new_with_label("script key")), } } @@ -553,6 +554,14 @@ where TBackend: KeyManagerBackend + 'static debug!(target: "c::brian::test", "commitment: {:?}", &commitment.to_hex()); debug!(target: "c::brian::test", "challenge: {:?}", &challenge); + let hasher = + DomainSeparatedHasher::, KeyManagerTransactionsHashDomain>::new_with_label("script key"); + let hasher = hasher.chain("test input".as_bytes()).finalize(); + let private_key = PrivateKey::from_uniform_bytes(hasher.as_ref()).unwrap(); + debug!(target: "c::brian::test", "hasher k: {:?}", &private_key.to_hex()); + let public_key = PublicKey::from_secret_key(&private_key); + debug!(target: "c::brian::test", "hasher pk: {:?}", &public_key.to_string()); + match (&self.wallet_type, script_key_id) { ( WalletType::Ledger(ledger), @@ -833,7 +842,7 @@ where TBackend: KeyManagerBackend + 'static // With RevealedValue type range proofs, the nonce is always 0 and the minimum value promise equal to the value let nonce_a = match range_proof_type { RangeProofType::BulletProofPlus => { - let hasher_a = DomainSeparatedHasher::, KeyManagerHashingDomain>::new_with_label( + let hasher_a = DomainSeparatedHasher::, KeyManagerTransactionsHashDomain>::new_with_label( "metadata_signature_ephemeral_nonce_a", ); let a_hash = hasher_a.chain(nonce_private_key.as_bytes()).finalize(); @@ -844,7 +853,7 @@ where TBackend: KeyManagerBackend + 'static RangeProofType::RevealedValue => Ok(PrivateKey::default()), }?; - let hasher_b = DomainSeparatedHasher::, KeyManagerHashingDomain>::new_with_label( + let hasher_b = DomainSeparatedHasher::, KeyManagerTransactionsHashDomain>::new_with_label( "metadata_signature_ephemeral_nonce_b", ); let b_hash = hasher_b.chain(nonce_private_key.as_bytes()).finalize(); @@ -1089,8 +1098,9 @@ where TBackend: KeyManagerBackend + 'static spend_key_id: &TariKeyId, nonce_id: &TariKeyId, ) -> Result { - let hasher = - DomainSeparatedHasher::, KeyManagerHashingDomain>::new_with_label("kernel_excess_offset"); + let hasher = DomainSeparatedHasher::, KeyManagerTransactionsHashDomain>::new_with_label( + "kernel_excess_offset", + ); let spending_private_key = self.get_private_key(spend_key_id).await?; let nonce_private_key = self.get_private_key(nonce_id).await?; let key_hash = hasher diff --git a/base_layer/core/src/transactions/transaction_components/transaction_output.rs b/base_layer/core/src/transactions/transaction_components/transaction_output.rs index d83582cfe4..43209048a9 100644 --- a/base_layer/core/src/transactions/transaction_components/transaction_output.rs +++ b/base_layer/core/src/transactions/transaction_components/transaction_output.rs @@ -423,6 +423,17 @@ impl TransactionOutput { debug!(target: "c::brian::test", "commitment: {:?}", &commitment.to_vec()); debug!(target: "c::brian::test", "message: {:?}", &message.to_hex()); debug!(target: "c::brian::test", "message: {:?}", &message.to_vec()); + let label = "metadata_signature"; + let input = [1u8; 64]; + + // Generate a mainnet hash + let hash_mainnet = DomainSeparatedConsensusHasher::>::new_with_network( + label, + Network::LocalNet, + ) + .chain(&input) + .finalize(); + debug!(target: "c::brian::test", "hash_mainnet: {:?}", &hash_mainnet); TransactionOutput::finalize_metadata_signature_challenge( version, From a227d0d0046323dce1422bddd22af761edd213ee Mon Sep 17 00:00:00 2001 From: brianp Date: Tue, 7 May 2024 16:37:23 +0200 Subject: [PATCH 38/49] Fix instructions issue to script offset function --- .../wallet/src/handlers/get_script_offset.rs | 18 +++++++++++------- .../core/src/transactions/key_manager/inner.rs | 8 +++++++- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs index 1cb19e5f30..12749630e8 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs @@ -1,11 +1,17 @@ // Copyright 2024 The Tari Project // SPDX-License-Identifier: BSD-3-Clause -use ledger_device_sdk::io::Comm; -use tari_crypto::{ristretto::RistrettoSecretKey, tari_utilities::ByteArray}; +use ledger_device_sdk::{ + io::Comm, + ui::gadgets::{MessageScroller, SingleMessage}, +}; +use tari_crypto::{ + ristretto::RistrettoSecretKey, + tari_utilities::{hex::Hex, ByteArray}, +}; use crate::{ - utils::{alpha_hasher, derive_from_bip32_key, get_key_from_canonical_bytes}, + utils::{alpha_hasher, derive_from_bip32_key, get_key_from_canonical_bytes, u64_to_string}, AppSW, KeyType, RESPONSE_VERSION, @@ -47,7 +53,7 @@ fn read_instructions(offset_ctx: &mut ScriptOffsetCtx, data: &[u8]) { account_bytes.clone_from_slice(&data[0..8]); offset_ctx.account = u64::from_le_bytes(account_bytes); - if data.len() < 15 { + if data.len() < 16 { offset_ctx.total_offset_indexes = 0; } else { let mut total_offset_keys = [0u8; 8]; @@ -55,7 +61,7 @@ fn read_instructions(offset_ctx: &mut ScriptOffsetCtx, data: &[u8]) { offset_ctx.total_offset_indexes = u64::from_le_bytes(total_offset_keys); } - if data.len() < 23 { + if data.len() < 24 { offset_ctx.total_commitment_keys = 0; } else { let mut total_commitment_keys = [0u8; 8]; @@ -95,7 +101,6 @@ pub fn handler_get_script_offset( let offset = derive_from_bip32_key(offset_ctx.account, index, KeyType::SenderOffset)?; offset_ctx.total_sender_offset_private_key = &offset_ctx.total_sender_offset_private_key + &offset; - return Ok(()); } let end_commitment_keys = end_offset_indexes + offset_ctx.total_commitment_keys; @@ -105,7 +110,6 @@ pub fn handler_get_script_offset( let k = alpha_hasher(alpha, blinding_factor)?; offset_ctx.total_script_private_key = &offset_ctx.total_script_private_key + &k; - return Ok(()); } if more { diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index 579820b255..83c8316999 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -786,17 +786,23 @@ where TBackend: KeyManagerBackend + 'static let num_commitments = derived_key_commitments.len() as u64; let num_offset_key = sender_offset_indexes.len() as u64; + debug!(target: "c::brian::test", "num_offset_key {:?}", num_offset_key); + debug!(target: "c::brian::test", "num_commitments {:?}", num_commitments); + let mut instructions = num_offset_key.to_le_bytes().to_vec(); - instructions.clone_from_slice(&num_commitments.to_le_bytes()); + instructions.extend_from_slice(&num_commitments.to_le_bytes()); let mut data: Vec> = vec![instructions.to_vec()]; data.push(total_script_private_key.to_vec()); + debug!(target: "c::brian::test", "total script private key {:?}", total_script_private_key.to_hex()); for sender_offset_index in sender_offset_indexes { + debug!(target: "c::brian::test", "offset index {:?}", sender_offset_index); data.push(sender_offset_index.to_le_bytes().to_vec()); } for derived_key_commitment in derived_key_commitments { + debug!(target: "c::brian::test", "commitments {:?}", derived_key_commitment.to_hex()); data.push(derived_key_commitment.to_vec()); } From f41d5ec78a7c3b00a811e938c7b8fdf8826aefc7 Mon Sep 17 00:00:00 2001 From: brianp Date: Mon, 13 May 2024 16:56:02 -0700 Subject: [PATCH 39/49] Remove debug lines --- Cargo.lock | 1 - .../minotari_ledger_wallet/comms/Cargo.toml | 1 - .../src/transactions/key_manager/inner.rs | 15 ---------- .../transaction_input.rs | 12 -------- .../transaction_output.rs | 29 ------------------- 5 files changed, 58 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ea08f23421..506255c815 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3341,7 +3341,6 @@ version = "1.0.0-pre.11a" dependencies = [ "ledger-transport 0.10.0 (git+https://github.com/Zondax/ledger-rs?rev=20e2a20)", "ledger-transport-hid", - "log", "num-derive 0.3.3", "num-traits", "serde", diff --git a/applications/minotari_ledger_wallet/comms/Cargo.toml b/applications/minotari_ledger_wallet/comms/Cargo.toml index 9fdae22e16..2e52f99db0 100644 --- a/applications/minotari_ledger_wallet/comms/Cargo.toml +++ b/applications/minotari_ledger_wallet/comms/Cargo.toml @@ -11,7 +11,6 @@ tari_common = { path = "../../../common", version = "1.0.0-pre.12" } ledger-transport = { git = "https://github.com/Zondax/ledger-rs", rev = "20e2a20" } ledger-transport-hid = { git = "https://github.com/Zondax/ledger-rs", rev = "20e2a20" } -log = "0.4.20" num-derive = "0.3.3" num-traits = "0.2.15" serde = { version = "1.0.106", features = ["derive"] } diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index 83c8316999..3958118243 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -547,21 +547,6 @@ where TBackend: KeyManagerBackend + 'static script_message, ); - debug!(target: "c::brian::test", "before sending"); - debug!(target: "c::brian::test", "ephemeral_commitment: {:?}", &ephemeral_commitment.as_public_key()); - debug!(target: "c::brian::test", "ephemeral_pubkey: {:?}", &ephemeral_pubkey.to_string()); - debug!(target: "c::brian::test", "script_public_key: {:?}", &&self.get_public_key_at_key_id(script_key_id).await?.to_string()); - debug!(target: "c::brian::test", "commitment: {:?}", &commitment.to_hex()); - debug!(target: "c::brian::test", "challenge: {:?}", &challenge); - - let hasher = - DomainSeparatedHasher::, KeyManagerTransactionsHashDomain>::new_with_label("script key"); - let hasher = hasher.chain("test input".as_bytes()).finalize(); - let private_key = PrivateKey::from_uniform_bytes(hasher.as_ref()).unwrap(); - debug!(target: "c::brian::test", "hasher k: {:?}", &private_key.to_hex()); - let public_key = PublicKey::from_secret_key(&private_key); - debug!(target: "c::brian::test", "hasher pk: {:?}", &public_key.to_string()); - match (&self.wallet_type, script_key_id) { ( WalletType::Ledger(ledger), diff --git a/base_layer/core/src/transactions/transaction_components/transaction_input.rs b/base_layer/core/src/transactions/transaction_components/transaction_input.rs index 3cc91d7034..d659e4bfe4 100644 --- a/base_layer/core/src/transactions/transaction_components/transaction_input.rs +++ b/base_layer/core/src/transactions/transaction_components/transaction_input.rs @@ -31,14 +31,12 @@ use std::{ use blake2::Blake2b; use borsh::{BorshDeserialize, BorshSerialize}; use digest::consts::{U32, U64}; -use log::debug; use rand::rngs::OsRng; use serde::{Deserialize, Serialize}; use tari_common_types::types::{ComAndPubSignature, Commitment, CommitmentFactory, FixedHash, HashOutput, PublicKey}; use tari_crypto::tari_utilities::hex::Hex; use tari_hashing::TransactionHashDomain; use tari_script::{ExecutionStack, ScriptContext, StackItem, TariScript}; -use tari_utilities::ByteArray; use super::{TransactionInputVersion, TransactionOutputVersion}; use crate::{ @@ -386,16 +384,6 @@ impl TransactionInput { commitment, ); - debug!(target: "c::brian::test", "version: {:?}", &self.version); - debug!(target: "c::brian::test", "script_signature.ephemeral_commitment: {:?}", &self.script_signature.ephemeral_commitment().as_public_key()); - debug!(target: "c::brian::test", "script_signature.ephemeral_commitment: {:?}", &self.script_signature.ephemeral_commitment().to_vec()); - debug!(target: "c::brian::test", "script_signature.ephemeral_pubkey: {:?}", &self.script_signature.ephemeral_pubkey()); - debug!(target: "c::brian::test", "script_signature.ephemeral_pubkey: {:?}", &self.script_signature.ephemeral_pubkey().to_vec()); - debug!(target: "c::brian::test", "script_public_key: {:?}", &script_public_key); - debug!(target: "c::brian::test", "script_public_key: {:?}", &script_public_key.to_vec()); - debug!(target: "c::brian::test", "commitment: {:?}", &script_public_key.to_vec()); - debug!(target: "c::brian::test", "challenge: {:?}", &challenge); - if self.script_signature.verify_challenge( commitment, script_public_key, diff --git a/base_layer/core/src/transactions/transaction_components/transaction_output.rs b/base_layer/core/src/transactions/transaction_components/transaction_output.rs index 43209048a9..03cec2ab6b 100644 --- a/base_layer/core/src/transactions/transaction_components/transaction_output.rs +++ b/base_layer/core/src/transactions/transaction_components/transaction_output.rs @@ -31,10 +31,8 @@ use std::{ use blake2::Blake2b; use borsh::{BorshDeserialize, BorshSerialize}; use digest::consts::{U32, U64}; -use log::debug; use rand::rngs::OsRng; use serde::{Deserialize, Serialize}; -use tari_common::configuration::Network; use tari_common_types::types::{ ComAndPubSignature, Commitment, @@ -55,7 +53,6 @@ use tari_crypto::{ }; use tari_hashing::TransactionHashDomain; use tari_script::TariScript; -use tari_utilities::ByteArray; use super::TransactionOutputVersion; use crate::{ @@ -322,8 +319,6 @@ impl TransactionOutput { self.minimum_value_promise, ); - debug!(target: "c::brian::test", "challenge: {:?}", &challenge); - if !self.metadata_signature.verify_challenge( &self.commitment, &self.sender_offset_public_key, @@ -411,30 +406,6 @@ impl TransactionOutput { &minimum_value_promise, ); - debug!(target: "c::brian::test", "version: {:?}", &version); - debug!(target: "c::brian::test", "network: {:?}", &Network::LocalNet.as_byte()); - debug!(target: "c::brian::test", "sender_offset_public_key: {:?}", &sender_offset_public_key); - debug!(target: "c::brian::test", "sender_offset_public_key: {:?}", &sender_offset_public_key.to_vec()); - debug!(target: "c::brian::test", "ephemeral_commitment: {:?}", &ephemeral_commitment.as_public_key()); - debug!(target: "c::brian::test", "ephemeral_commitment: {:?}", &ephemeral_commitment.to_vec()); - debug!(target: "c::brian::test", "ephemeral_pubkey: {:?}", &ephemeral_pubkey); - debug!(target: "c::brian::test", "ephemeral_pubkey: {:?}", &ephemeral_pubkey.to_vec()); - debug!(target: "c::brian::test", "commitment: {:?}", &commitment.as_public_key()); - debug!(target: "c::brian::test", "commitment: {:?}", &commitment.to_vec()); - debug!(target: "c::brian::test", "message: {:?}", &message.to_hex()); - debug!(target: "c::brian::test", "message: {:?}", &message.to_vec()); - let label = "metadata_signature"; - let input = [1u8; 64]; - - // Generate a mainnet hash - let hash_mainnet = DomainSeparatedConsensusHasher::>::new_with_network( - label, - Network::LocalNet, - ) - .chain(&input) - .finalize(); - debug!(target: "c::brian::test", "hash_mainnet: {:?}", &hash_mainnet); - TransactionOutput::finalize_metadata_signature_challenge( version, sender_offset_public_key, From 6aa533624f84bf511c20b06e2a30ba3a06761e06 Mon Sep 17 00:00:00 2001 From: brianp Date: Mon, 13 May 2024 16:57:18 -0700 Subject: [PATCH 40/49] Fix clippy warnings and conditional compilation --- Cargo.lock | 2 +- .../minotari_console_wallet/Cargo.toml | 4 +- .../minotari_console_wallet/src/init/mod.rs | 2 +- .../minotari_ledger_wallet/comms/Cargo.toml | 2 +- .../comms/src/ledger_wallet.rs | 2 +- .../minotari_ledger_wallet/wallet/Cargo.toml | 2 +- base_layer/common_types/Cargo.toml | 4 +- base_layer/common_types/src/wallet_types.rs | 2 +- base_layer/core/Cargo.toml | 2 +- .../src/transactions/key_manager/inner.rs | 283 ++++++++++-------- .../src/transactions/key_manager/interface.rs | 3 +- .../core/src/transactions/key_manager/mod.rs | 2 +- .../core/src/transactions/test_helpers.rs | 2 +- .../transaction_components/error.rs | 4 + .../src/key_manager_service/interface.rs | 4 +- .../src/key_manager_service/service.rs | 7 +- .../recovery/standard_outputs_recoverer.rs | 3 +- 17 files changed, 188 insertions(+), 142 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 506255c815..746f3297ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3337,7 +3337,7 @@ dependencies = [ [[package]] name = "minotari_ledger_wallet_comms" -version = "1.0.0-pre.11a" +version = "1.0.0-pre.13" dependencies = [ "ledger-transport 0.10.0 (git+https://github.com/Zondax/ledger-rs?rev=20e2a20)", "ledger-transport-hid", diff --git a/applications/minotari_console_wallet/Cargo.toml b/applications/minotari_console_wallet/Cargo.toml index 5ecd6d6ef6..87a2b3edde 100644 --- a/applications/minotari_console_wallet/Cargo.toml +++ b/applications/minotari_console_wallet/Cargo.toml @@ -8,7 +8,7 @@ license = "BSD-3-Clause" [dependencies] minotari_app_grpc = { path = "../minotari_app_grpc" } minotari_app_utilities = { path = "../minotari_app_utilities" } -minotari_ledger_wallet_comms = { path = "../../applications/minotari_ledger_wallet/comms", version = "1.0.0-pre.11a", optional = true } +minotari_ledger_wallet_comms = { path = "../../applications/minotari_ledger_wallet/comms", version = "1.0.0-pre.13" } tari_common = { path = "../../common" } tari_common_types = { path = "../../base_layer/common_types" } tari_comms = { path = "../../comms/core" } @@ -89,7 +89,7 @@ tari_features = { path = "../../common/tari_features", version = "1.0.0-pre.13" [features] default = ["libtor"] grpc = [] -ledger = ["ledger-transport-hid", "minotari_ledger_wallet_comms"] +ledger = ["ledger-transport-hid", ] libtor = ["tari_libtor"] [package.metadata.cargo-machete] diff --git a/applications/minotari_console_wallet/src/init/mod.rs b/applications/minotari_console_wallet/src/init/mod.rs index 46ca157f47..204564d677 100644 --- a/applications/minotari_console_wallet/src/init/mod.rs +++ b/applications/minotari_console_wallet/src/init/mod.rs @@ -838,7 +838,7 @@ pub fn prompt_wallet_type( match boot_mode { WalletBoot::New => { #[cfg(not(feature = "ledger"))] - return Some(WalletType::Software); + return Some(WalletType::default()); #[cfg(feature = "ledger")] { diff --git a/applications/minotari_ledger_wallet/comms/Cargo.toml b/applications/minotari_ledger_wallet/comms/Cargo.toml index 2e52f99db0..a2282b4974 100644 --- a/applications/minotari_ledger_wallet/comms/Cargo.toml +++ b/applications/minotari_ledger_wallet/comms/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "minotari_ledger_wallet_comms" -version = "1.0.0-pre.11a" +version = "1.0.0-pre.13" authors = ["The Tari Development Community"] license = "BSD-3-Clause" edition = "2021" diff --git a/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs b/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs index bd77a6933a..0fa84bbeab 100644 --- a/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs +++ b/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs @@ -154,7 +154,7 @@ impl LedgerWallet { inner: APDUCommand { cla: WALLET_CLA, ins: instruction.as_byte(), - p1: i as u8, + p1: u8::try_from(i).unwrap_or(0), p2: more, data: base_data, }, diff --git a/applications/minotari_ledger_wallet/wallet/Cargo.toml b/applications/minotari_ledger_wallet/wallet/Cargo.toml index 39582ab241..9147235a4c 100644 --- a/applications/minotari_ledger_wallet/wallet/Cargo.toml +++ b/applications/minotari_ledger_wallet/wallet/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "minotari_ledger_wallet" -version = "1.0.0-pre.11a" +version = "1.0.0-pre.13" authors = ["The Tari Development Community"] license = "BSD-3-Clause" edition = "2021" diff --git a/base_layer/common_types/Cargo.toml b/base_layer/common_types/Cargo.toml index 507cffcb7a..11430f5ed5 100644 --- a/base_layer/common_types/Cargo.toml +++ b/base_layer/common_types/Cargo.toml @@ -7,7 +7,7 @@ version = "1.0.0-pre.13" edition = "2018" [dependencies] -minotari_ledger_wallet_comms = { path = "../../applications/minotari_ledger_wallet/comms", version = "1.0.0-pre.11a", optional = true } +minotari_ledger_wallet_comms = { path = "../../applications/minotari_ledger_wallet/comms", version = "1.0.0-pre.13" } tari_crypto = { version = "0.20" } tari_utilities = { version = "0.7" } tari_common = { path = "../../common", version = "1.0.0-pre.13" } @@ -27,7 +27,7 @@ blake2 = "0.10" primitive-types = { version = "0.12", features = ["serde"] } [features] -ledger = ["minotari_ledger_wallet_comms"] +ledger = [] [package.metadata.cargo-machete] ignored = ["strum", "strum_macros"] # this is so we can run cargo machete without getting false positive about macro dependancies diff --git a/base_layer/common_types/src/wallet_types.rs b/base_layer/common_types/src/wallet_types.rs index 7b66efeeaa..7ead057f7e 100644 --- a/base_layer/common_types/src/wallet_types.rs +++ b/base_layer/common_types/src/wallet_types.rs @@ -34,7 +34,7 @@ use crate::types::{PrivateKey, PublicKey}; #[derive(Debug, Clone, Serialize, Deserialize)] pub enum WalletType { - Software(PrivateKey, PublicKey), // Make them a priv and pub + Software(PrivateKey, PublicKey), Ledger(LedgerWallet), } diff --git a/base_layer/core/Cargo.toml b/base_layer/core/Cargo.toml index a21ac8f301..a1cb7fa101 100644 --- a/base_layer/core/Cargo.toml +++ b/base_layer/core/Cargo.toml @@ -31,7 +31,7 @@ ledger = [ metrics = ["tari_metrics"] [dependencies] -minotari_ledger_wallet_comms = { path = "../../applications/minotari_ledger_wallet/comms", version = "1.0.0-pre.11a", optional = true } +minotari_ledger_wallet_comms = { path = "../../applications/minotari_ledger_wallet/comms", version = "1.0.0-pre.13", optional = true } tari_common = { path = "../../common", version = "1.0.0-pre.13" } tari_common_types = { path = "../../base_layer/common_types", version = "1.0.0-pre.13" } tari_comms = { path = "../../comms/core", version = "1.0.0-pre.13" } diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index 3958118243..ed61d9bb22 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -24,9 +24,11 @@ use std::{collections::HashMap, ops::Shl}; use blake2::Blake2b; use digest::consts::U64; use log::*; -use minotari_ledger_wallet_comms::ledger_wallet::get_transport; #[cfg(feature = "ledger")] -use minotari_ledger_wallet_comms::{error::LedgerDeviceError, ledger_wallet::Instruction}; +use minotari_ledger_wallet_comms::{ + error::LedgerDeviceError, + ledger_wallet::{get_transport, Instruction}, +}; use rand::rngs::OsRng; use strum::IntoEnumIterator; use tari_common_types::{ @@ -46,9 +48,10 @@ use tari_crypto::{ RistrettoComSig, }, }; +#[cfg(feature = "ledger")] +use tari_key_manager::error::KeyManagerError; use tari_key_manager::{ cipher_seed::CipherSeed, - error::KeyManagerError, key_manager::KeyManager, key_manager_service::{ storage::database::{KeyManagerBackend, KeyManagerDatabase, KeyManagerState}, @@ -198,24 +201,40 @@ where TBackend: KeyManagerBackend + 'static branch == &TransactionKeyManagerBranch::SenderOffset.get_branch_key(), &self.wallet_type, ) { + #[allow(unused_variables)] // This is to avoid the code blocks where ledger isn't used (true, WalletType::Ledger(ledger)) => { - let transport = get_transport().map_err(|e| KeyManagerServiceError::LedgerError(e.to_string()))?; - let mut data = index.to_le_bytes().to_vec(); - let branch_u8 = TransactionKeyManagerBranch::from_key(branch).as_byte(); - data.extend_from_slice(&(branch_u8 as u64).to_le_bytes()); - let command = ledger.build_command(Instruction::GetPublicKey, data); + #[cfg(not(feature = "ledger"))] + { + let km = self + .key_managers + .get(branch) + .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .read() + .await; + Ok(km.derive_public_key(*index)?.key) + } - match command.execute_with_transport(&transport) { - Ok(result) => { - debug!(target: LOG_TARGET, "result length: {}, data: {:?}", result.data().len(), result.data()); - if result.data().len() < 33 { - debug!(target: LOG_TARGET, "result less than 33"); - } + #[cfg(feature = "ledger")] + { + let transport = + get_transport().map_err(|e| KeyManagerServiceError::LedgerError(e.to_string()))?; + let mut data = index.to_le_bytes().to_vec(); + let branch_u8 = TransactionKeyManagerBranch::from_key(branch).as_byte(); + data.extend_from_slice(&u64::from(branch_u8).to_le_bytes()); + let command = ledger.build_command(Instruction::GetPublicKey, data); - PublicKey::from_canonical_bytes(&result.data()[1..33]) - .map_err(|e| KeyManagerServiceError::LedgerError(e.to_string())) - }, - Err(e) => Err(KeyManagerServiceError::LedgerError(e.to_string())), + match command.execute_with_transport(&transport) { + Ok(result) => { + debug!(target: LOG_TARGET, "result length: {}, data: {:?}", result.data().len(), result.data()); + if result.data().len() < 33 { + debug!(target: LOG_TARGET, "result less than 33"); + } + + PublicKey::from_canonical_bytes(&result.data()[1..33]) + .map_err(|e| KeyManagerServiceError::LedgerError(e.to_string())) + }, + Err(e) => Err(KeyManagerServiceError::LedgerError(e.to_string())), + } } }, (_, _) => { @@ -522,6 +541,7 @@ where TBackend: KeyManagerBackend + 'static // Transaction input section (transactions > transaction_components > transaction_input) // ----------------------------------------------------------------------------------------------------------------- + #[allow(clippy::too_many_lines)] pub async fn get_script_signature( &self, script_key_id: &TariKeyId, @@ -547,6 +567,7 @@ where TBackend: KeyManagerBackend + 'static script_message, ); + #[allow(unused_variables)] // When ledger isn't enabled match (&self.wallet_type, script_key_id) { ( WalletType::Ledger(ledger), @@ -558,7 +579,7 @@ where TBackend: KeyManagerBackend + 'static ) => { #[cfg(not(feature = "ledger"))] { - return Err(TransactionError::LedgerDeviceError(LedgerDeviceError::NotSupported)); + Err(TransactionError::LedgerNotSupported) } #[cfg(feature = "ledger")] @@ -705,6 +726,7 @@ where TBackend: KeyManagerBackend + 'static }) } + #[allow(clippy::too_many_lines)] pub async fn get_script_offset( &self, script_key_ids: &[TariKeyId], @@ -752,73 +774,81 @@ where TBackend: KeyManagerBackend + 'static let script_offset = total_script_private_key - total_sender_offset_private_key; Ok(script_offset) }, + #[allow(unused_variables)] WalletType::Ledger(ledger) => { - let mut sender_offset_indexes = vec![]; - for sender_offset_key_id in sender_offset_key_ids { - match sender_offset_key_id { - TariKeyId::Managed { branch: _, index } | - TariKeyId::Derived { - branch: _, - label: _, - index, - } => { - sender_offset_indexes.push(index); - }, - TariKeyId::Imported { .. } | TariKeyId::Zero => {}, - } + #[cfg(not(feature = "ledger"))] + { + Err(TransactionError::LedgerNotSupported) } - let num_commitments = derived_key_commitments.len() as u64; - let num_offset_key = sender_offset_indexes.len() as u64; + #[cfg(feature = "ledger")] + { + let mut sender_offset_indexes = vec![]; + for sender_offset_key_id in sender_offset_key_ids { + match sender_offset_key_id { + TariKeyId::Managed { branch: _, index } | + TariKeyId::Derived { + branch: _, + label: _, + index, + } => { + sender_offset_indexes.push(index); + }, + TariKeyId::Imported { .. } | TariKeyId::Zero => {}, + } + } - debug!(target: "c::brian::test", "num_offset_key {:?}", num_offset_key); - debug!(target: "c::brian::test", "num_commitments {:?}", num_commitments); + let num_commitments = derived_key_commitments.len() as u64; + let num_offset_key = sender_offset_indexes.len() as u64; - let mut instructions = num_offset_key.to_le_bytes().to_vec(); - instructions.extend_from_slice(&num_commitments.to_le_bytes()); + let mut instructions = num_offset_key.to_le_bytes().to_vec(); + instructions.extend_from_slice(&num_commitments.to_le_bytes()); - let mut data: Vec> = vec![instructions.to_vec()]; - data.push(total_script_private_key.to_vec()); - debug!(target: "c::brian::test", "total script private key {:?}", total_script_private_key.to_hex()); + let mut data: Vec> = vec![instructions.to_vec()]; + data.push(total_script_private_key.to_vec()); - for sender_offset_index in sender_offset_indexes { - debug!(target: "c::brian::test", "offset index {:?}", sender_offset_index); - data.push(sender_offset_index.to_le_bytes().to_vec()); - } + for sender_offset_index in sender_offset_indexes { + data.push(sender_offset_index.to_le_bytes().to_vec()); + } - for derived_key_commitment in derived_key_commitments { - debug!(target: "c::brian::test", "commitments {:?}", derived_key_commitment.to_hex()); - data.push(derived_key_commitment.to_vec()); - } + for derived_key_commitment in derived_key_commitments { + data.push(derived_key_commitment.to_vec()); + } - let commands = ledger.chunk_command(Instruction::GetScriptOffset, data); - let transport = get_transport()?; + let commands = ledger.chunk_command(Instruction::GetScriptOffset, data); + let transport = get_transport()?; - let mut result = None; - for command in commands { - match command.execute_with_transport(&transport) { - Ok(r) => result = Some(r), - Err(e) => return Err(LedgerDeviceError::Instruction(format!("GetScriptOffset: {}", e)).into()), + let mut result = None; + for command in commands { + match command.execute_with_transport(&transport) { + Ok(r) => result = Some(r), + Err(e) => { + return Err(LedgerDeviceError::Instruction(format!("GetScriptOffset: {}", e)).into()) + }, + } } - } - if let Some(result) = result { - if result.data().len() < 33 { - debug!(target: LOG_TARGET, "result less than 33"); - return Err(LedgerDeviceError::Processing(format!( - "'get_script_offset' insufficient data - expected 33 got {} bytes ({:?})", - result.data().len(), - result - )) - .into()); + if let Some(result) = result { + if result.data().len() < 33 { + debug!(target: LOG_TARGET, "result less than 33"); + return Err(LedgerDeviceError::Processing(format!( + "'get_script_offset' insufficient data - expected 33 got {} bytes ({:?})", + result.data().len(), + result + )) + .into()); + } + let data = result.data(); + debug!(target: LOG_TARGET, "result length: {}, data: {:?}", result.data().len(), result.data()); + return PrivateKey::from_canonical_bytes(&data[1..33]) + .map_err(|e| TransactionError::InvalidSignatureError(e.to_string())); } - let data = result.data(); - debug!(target: LOG_TARGET, "result length: {}, data: {:?}", result.data().len(), result.data()); - return PrivateKey::from_canonical_bytes(&data[1..33]) - .map_err(|e| TransactionError::InvalidSignatureError(e.to_string())); - } - Err(LedgerDeviceError::Instruction("GetScriptOffset failed to process correctly".to_string()).into()) + Err( + LedgerDeviceError::Instruction("GetScriptOffset failed to process correctly".to_string()) + .into(), + ) + } }, } } @@ -1023,58 +1053,67 @@ where TBackend: KeyManagerBackend + 'static )?; Ok(metadata_signature) }, + #[allow(unused_variables)] WalletType::Ledger(ledger) => { - let ephemeral_private_nonce_index = - ephemeral_private_nonce_id - .managed_index() - .ok_or(TransactionError::KeyManagerError( - KeyManagerError::InvalidKeyID.to_string(), - ))?; - let sender_offset_key_index = - sender_offset_key_id - .managed_index() - .ok_or(TransactionError::KeyManagerError( - KeyManagerError::InvalidKeyID.to_string(), - ))?; - - let mut data = (ledger.network.as_byte() as u64).to_le_bytes().to_vec(); - data.extend_from_slice(&(txo_version.as_u8() as u64).to_le_bytes()); - data.extend_from_slice(&ephemeral_private_nonce_index.to_le_bytes()); - data.extend_from_slice(&sender_offset_key_index.to_le_bytes()); - data.extend_from_slice(&commitment.to_vec()); - data.extend_from_slice(&ephemeral_commitment.to_vec()); - data.extend_from_slice(&metadata_signature_message.to_vec()); - - let command = ledger.build_command(Instruction::GetMetadataSignature, data); - let transport = get_transport()?; - - match command.execute_with_transport(&transport) { - Ok(result) => { - if result.data().len() < 161 { - debug!(target: LOG_TARGET, "result less than 161"); - return Err(LedgerDeviceError::Processing(format!( - "'get_metadata_signature' insufficient data - expected 161 got {} bytes ({:?})", - result.data().len(), - result + #[cfg(not(feature = "ledger"))] + { + Err(TransactionError::LedgerNotSupported) + } + + #[cfg(feature = "ledger")] + { + let ephemeral_private_nonce_index = + ephemeral_private_nonce_id + .managed_index() + .ok_or(TransactionError::KeyManagerError( + KeyManagerError::InvalidKeyID.to_string(), + ))?; + let sender_offset_key_index = + sender_offset_key_id + .managed_index() + .ok_or(TransactionError::KeyManagerError( + KeyManagerError::InvalidKeyID.to_string(), + ))?; + + let mut data = u64::from(ledger.network.as_byte()).to_le_bytes().to_vec(); + data.extend_from_slice(&u64::from(txo_version.as_u8()).to_le_bytes()); + data.extend_from_slice(&ephemeral_private_nonce_index.to_le_bytes()); + data.extend_from_slice(&sender_offset_key_index.to_le_bytes()); + data.extend_from_slice(&commitment.to_vec()); + data.extend_from_slice(&ephemeral_commitment.to_vec()); + data.extend_from_slice(&metadata_signature_message.to_vec()); + + let command = ledger.build_command(Instruction::GetMetadataSignature, data); + let transport = get_transport()?; + + match command.execute_with_transport(&transport) { + Ok(result) => { + if result.data().len() < 161 { + debug!(target: LOG_TARGET, "result less than 161"); + return Err(LedgerDeviceError::Processing(format!( + "'get_metadata_signature' insufficient data - expected 161 got {} bytes ({:?})", + result.data().len(), + result + )) + .into()); + } + let data = result.data(); + debug!(target: LOG_TARGET, "result length: {}, data: {:?}", result.data().len(), result.data()); + Ok(ComAndPubSignature::new( + Commitment::from_canonical_bytes(&data[1..33]) + .map_err(|e| TransactionError::InvalidSignatureError(e.to_string()))?, + PublicKey::from_canonical_bytes(&data[33..65]) + .map_err(|e| TransactionError::InvalidSignatureError(e.to_string()))?, + PrivateKey::from_canonical_bytes(&data[65..97]) + .map_err(|e| TransactionError::InvalidSignatureError(e.to_string()))?, + PrivateKey::from_canonical_bytes(&data[97..129]) + .map_err(|e| TransactionError::InvalidSignatureError(e.to_string()))?, + PrivateKey::from_canonical_bytes(&data[129..161]) + .map_err(|e| TransactionError::InvalidSignatureError(e.to_string()))?, )) - .into()); - } - let data = result.data(); - debug!(target: LOG_TARGET, "result length: {}, data: {:?}", result.data().len(), result.data()); - Ok(ComAndPubSignature::new( - Commitment::from_canonical_bytes(&data[1..33]) - .map_err(|e| TransactionError::InvalidSignatureError(e.to_string()))?, - PublicKey::from_canonical_bytes(&data[33..65]) - .map_err(|e| TransactionError::InvalidSignatureError(e.to_string()))?, - PrivateKey::from_canonical_bytes(&data[65..97]) - .map_err(|e| TransactionError::InvalidSignatureError(e.to_string()))?, - PrivateKey::from_canonical_bytes(&data[97..129]) - .map_err(|e| TransactionError::InvalidSignatureError(e.to_string()))?, - PrivateKey::from_canonical_bytes(&data[129..161]) - .map_err(|e| TransactionError::InvalidSignatureError(e.to_string()))?, - )) - }, - Err(e) => Err(LedgerDeviceError::Instruction(format!("GetMetadataSignature: {}", e)).into()), + }, + Err(e) => Err(LedgerDeviceError::Instruction(format!("GetMetadataSignature: {}", e)).into()), + } } }, } diff --git a/base_layer/core/src/transactions/key_manager/interface.rs b/base_layer/core/src/transactions/key_manager/interface.rs index e30a4e32e3..e3eae15ecb 100644 --- a/base_layer/core/src/transactions/key_manager/interface.rs +++ b/base_layer/core/src/transactions/key_manager/interface.rs @@ -87,7 +87,8 @@ impl TransactionKeyManagerBranch { "metadata ephemeral nonce" => TransactionKeyManagerBranch::MetadataEphemeralNonce, "kernel nonce" => TransactionKeyManagerBranch::KernelNonce, "sender offset" => TransactionKeyManagerBranch::SenderOffset, - "nonce" | _ => TransactionKeyManagerBranch::Nonce, + "nonce" => TransactionKeyManagerBranch::Nonce, + _ => TransactionKeyManagerBranch::Nonce, } } diff --git a/base_layer/core/src/transactions/key_manager/mod.rs b/base_layer/core/src/transactions/key_manager/mod.rs index 7b85c13bca..b622a3715e 100644 --- a/base_layer/core/src/transactions/key_manager/mod.rs +++ b/base_layer/core/src/transactions/key_manager/mod.rs @@ -28,8 +28,8 @@ pub use interface::{ SecretTransactionKeyManagerInterface, TariKeyId, TransactionKeyManagerBranch, - TransactionKeyManagerLabel, TransactionKeyManagerInterface, + TransactionKeyManagerLabel, TxoStage, }; diff --git a/base_layer/core/src/transactions/test_helpers.rs b/base_layer/core/src/transactions/test_helpers.rs index c7bd4e3b9c..bd8c9e8d16 100644 --- a/base_layer/core/src/transactions/test_helpers.rs +++ b/base_layer/core/src/transactions/test_helpers.rs @@ -43,8 +43,8 @@ use crate::{ MemoryDbKeyManager, TariKeyId, TransactionKeyManagerBranch, - TransactionKeyManagerLabel, TransactionKeyManagerInterface, + TransactionKeyManagerLabel, TransactionKeyManagerWrapper, TxoStage, }, diff --git a/base_layer/core/src/transactions/transaction_components/error.rs b/base_layer/core/src/transactions/transaction_components/error.rs index 047f9378ed..2647ea713f 100644 --- a/base_layer/core/src/transactions/transaction_components/error.rs +++ b/base_layer/core/src/transactions/transaction_components/error.rs @@ -23,6 +23,7 @@ // Portions of this file were originally copyrighted (c) 2018 The Grin Developers, issued under the Apache License, // Version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0. +#[cfg(feature = "ledger")] use minotari_ledger_wallet_comms::error::LedgerDeviceError; use serde::{Deserialize, Serialize}; use tari_crypto::{ @@ -74,8 +75,11 @@ pub enum TransactionError { KeyManagerError(String), #[error("EncryptedData error: {0}")] EncryptedDataError(String), + #[cfg(feature = "ledger")] #[error("Ledger device error: {0}")] LedgerDeviceError(#[from] LedgerDeviceError), + #[error("Ledger is not supported")] + LedgerNotSupported, #[error("Transaction has a zero weight, not possible")] ZeroWeight, } diff --git a/base_layer/key_manager/src/key_manager_service/interface.rs b/base_layer/key_manager/src/key_manager_service/interface.rs index 7f1bb8f17e..5b5886b783 100644 --- a/base_layer/key_manager/src/key_manager_service/interface.rs +++ b/base_layer/key_manager/src/key_manager_service/interface.rs @@ -140,7 +140,7 @@ where PK: ByteArray Ok(KeyId::Imported { key }) }, ZERO_KEY_BRANCH => Ok(KeyId::Zero), - DERIVED_KEY_BRANCH =>{ + DERIVED_KEY_BRANCH => { if parts.len() != 4 { return Err("Wrong format".to_string()); } @@ -152,7 +152,7 @@ where PK: ByteArray label: parts[2].into(), index, }) - } + }, _ => Err("Wrong format".to_string()), }, } diff --git a/base_layer/key_manager/src/key_manager_service/service.rs b/base_layer/key_manager/src/key_manager_service/service.rs index 21c53e4820..f6ec353827 100644 --- a/base_layer/key_manager/src/key_manager_service/service.rs +++ b/base_layer/key_manager/src/key_manager_service/service.rs @@ -146,10 +146,13 @@ where let branch_key = km.get_private_key(*index)?; let public_key = { - let hasher = DomainSeparatedHasher::, KeyManagerHashingDomain>::new_with_label("Key manager derived key"); + let hasher = DomainSeparatedHasher::, KeyManagerHashingDomain>::new_with_label( + "Key manager derived key", + ); let hasher = hasher.chain(branch_key.as_bytes()).finalize(); let private_key = PK::K::from_uniform_bytes(hasher.as_ref()).map_err(|_| { - KeyManagerServiceError::UnknownError("Invalid private key for Key manager derived key".to_string() + KeyManagerServiceError::UnknownError( + "Invalid private key for Key manager derived key".to_string(), ) })?; PK::from_secret_key(&private_key) diff --git a/base_layer/wallet/src/output_manager_service/recovery/standard_outputs_recoverer.rs b/base_layer/wallet/src/output_manager_service/recovery/standard_outputs_recoverer.rs index e151ef7aae..b8e18bbbe2 100644 --- a/base_layer/wallet/src/output_manager_service/recovery/standard_outputs_recoverer.rs +++ b/base_layer/wallet/src/output_manager_service/recovery/standard_outputs_recoverer.rs @@ -25,14 +25,13 @@ use std::time::Instant; use log::*; use tari_common_types::{transaction::TxId, types::FixedHash}; use tari_core::transactions::{ - key_manager::{TariKeyId, TransactionKeyManagerBranch, TransactionKeyManagerInterface}, + key_manager::{TariKeyId, TransactionKeyManagerBranch, TransactionKeyManagerInterface, TransactionKeyManagerLabel}, tari_amount::MicroMinotari, transaction_components::{OutputType, TransactionError, TransactionOutput, WalletOutput}, }; use tari_key_manager::key_manager_service::KeyId; use tari_script::{inputs, script, ExecutionStack, Opcode, TariScript}; use tari_utilities::hex::Hex; -use tari_core::transactions::key_manager::TransactionKeyManagerLabel; use crate::output_manager_service::{ error::{OutputManagerError, OutputManagerStorageError}, From 8cbfe1010f7bee588bb2069421c52af89aada0b8 Mon Sep 17 00:00:00 2001 From: brianp Date: Mon, 13 May 2024 17:12:43 -0700 Subject: [PATCH 41/49] machete warnings --- Cargo.lock | 2 -- applications/minotari_ledger_wallet/wallet/Cargo.toml | 3 +++ applications/minotari_ledger_wallet/wallet/build.rs | 3 +++ base_layer/core/Cargo.toml | 4 ---- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 746f3297ce..8efb6dbfb4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6201,8 +6201,6 @@ dependencies = [ "futures 0.3.29", "hex", "integer-encoding", - "ledger-transport 0.10.0 (git+https://github.com/Zondax/ledger-rs?rev=20e2a20)", - "ledger-transport-hid", "libsqlite3-sys", "lmdb-zero", "log", diff --git a/applications/minotari_ledger_wallet/wallet/Cargo.toml b/applications/minotari_ledger_wallet/wallet/Cargo.toml index 9147235a4c..75cda8e9aa 100644 --- a/applications/minotari_ledger_wallet/wallet/Cargo.toml +++ b/applications/minotari_ledger_wallet/wallet/Cargo.toml @@ -21,6 +21,9 @@ zeroize = { version = "1" , default-features = false } # target mismatches. once_cell = { version = "=1.18.0", default-features = false } +[package.metadata.cargo-machete] +ignored = ["once_cell"] + [profile.release] opt-level = 's' lto = "fat" # same as `true` diff --git a/applications/minotari_ledger_wallet/wallet/build.rs b/applications/minotari_ledger_wallet/wallet/build.rs index 6d36ea8066..78d986af60 100644 --- a/applications/minotari_ledger_wallet/wallet/build.rs +++ b/applications/minotari_ledger_wallet/wallet/build.rs @@ -1,3 +1,6 @@ +// Copyright 2024 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + fn main() { println!("cargo:rerun-if-changed=script.ld"); } diff --git a/base_layer/core/Cargo.toml b/base_layer/core/Cargo.toml index a1cb7fa101..110ab13856 100644 --- a/base_layer/core/Cargo.toml +++ b/base_layer/core/Cargo.toml @@ -25,8 +25,6 @@ base_node_proto = [] benches = ["base_node"] ledger = [ "minotari_ledger_wallet_comms", - "ledger-transport", - "ledger-transport-hid" ] metrics = ["tari_metrics"] @@ -68,8 +66,6 @@ fs2 = "0.4.0" futures = { version = "^0.3.16", features = ["async-await"] } hex = "0.4.2" integer-encoding = "3.0" -ledger-transport = { git = "https://github.com/Zondax/ledger-rs", rev = "20e2a20", optional = true } -ledger-transport-hid = { git = "https://github.com/Zondax/ledger-rs", rev = "20e2a20", optional = true } lmdb-zero = "0.4.4" log = "0.4" log-mdc = "0.1.0" From 11edae539da9088db299ba852b12195a854ee348 Mon Sep 17 00:00:00 2001 From: brianp Date: Mon, 13 May 2024 17:29:52 -0700 Subject: [PATCH 42/49] Clean up ledger code debugs --- .../wallet/src/handlers/get_public_alpha.rs | 13 ++------ .../wallet/src/handlers/get_script_offset.rs | 19 +++++------- .../src/handlers/get_script_signature.rs | 31 +++++-------------- .../wallet/src/utils.rs | 28 ++--------------- 4 files changed, 20 insertions(+), 71 deletions(-) diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_alpha.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_alpha.rs index 983c617730..3904303734 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_alpha.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_alpha.rs @@ -1,17 +1,10 @@ // Copyright 2024 The Tari Project // SPDX-License-Identifier: BSD-3-Clause -use ledger_device_sdk::{io::Comm, ui::gadgets::MessageScroller}; +use ledger_device_sdk::io::Comm; use tari_crypto::{keys::PublicKey, ristretto::RistrettoPublicKey, tari_utilities::ByteArray}; -use crate::{ - alloc::string::ToString, - utils::derive_from_bip32_key, - AppSW, - KeyType, - RESPONSE_VERSION, - STATIC_ALPHA_INDEX, -}; +use crate::{utils::derive_from_bip32_key, AppSW, KeyType, RESPONSE_VERSION, STATIC_ALPHA_INDEX}; pub fn handler_get_public_alpha(comm: &mut Comm) -> Result<(), AppSW> { let data = comm.get_data().map_err(|_| AppSW::WrongApduLength)?; @@ -25,8 +18,6 @@ pub fn handler_get_public_alpha(comm: &mut Comm) -> Result<(), AppSW> { Err(e) => return Err(e), }; - MessageScroller::new(&pk.to_string()).event_loop(); - comm.append(&[RESPONSE_VERSION]); // version comm.append(pk.as_bytes()); comm.reply_ok(); diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs index 12749630e8..ec2b8e768d 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs @@ -1,17 +1,11 @@ // Copyright 2024 The Tari Project // SPDX-License-Identifier: BSD-3-Clause -use ledger_device_sdk::{ - io::Comm, - ui::gadgets::{MessageScroller, SingleMessage}, -}; -use tari_crypto::{ - ristretto::RistrettoSecretKey, - tari_utilities::{hex::Hex, ByteArray}, -}; +use ledger_device_sdk::io::Comm; +use tari_crypto::{ristretto::RistrettoSecretKey, tari_utilities::ByteArray}; use crate::{ - utils::{alpha_hasher, derive_from_bip32_key, get_key_from_canonical_bytes, u64_to_string}, + utils::{alpha_hasher, derive_from_bip32_key, get_key_from_canonical_bytes}, AppSW, KeyType, RESPONSE_VERSION, @@ -89,11 +83,13 @@ pub fn handler_get_script_offset( // The sum of managed private keys let k: RistrettoSecretKey = get_key_from_canonical_bytes(&data[0..32])?; offset_ctx.total_script_private_key = &offset_ctx.total_script_private_key + k; + return Ok(()); } let payload_offset = 2; let end_offset_indexes = payload_offset + offset_ctx.total_offset_indexes; + if (payload_offset..end_offset_indexes).contains(&(chunk as u64)) { let mut index_bytes = [0u8; 8]; index_bytes.clone_from_slice(&data[0..8]); @@ -104,11 +100,12 @@ pub fn handler_get_script_offset( } let end_commitment_keys = end_offset_indexes + offset_ctx.total_commitment_keys; + if (end_offset_indexes..end_commitment_keys).contains(&(chunk as u64)) { let alpha = derive_from_bip32_key(offset_ctx.account, STATIC_ALPHA_INDEX, KeyType::Alpha)?; - let blinding_factor = get_key_from_canonical_bytes(&data[0..32])?; - let k = alpha_hasher(alpha, blinding_factor)?; + let blinding_factor: RistrettoSecretKey = get_key_from_canonical_bytes(&data[0..32])?; + let k = alpha_hasher(alpha, blinding_factor)?; offset_ctx.total_script_private_key = &offset_ctx.total_script_private_key + &k; } diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs index 611e8833f4..af0abd371a 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs @@ -1,26 +1,18 @@ // Copyright 2024 The Tari Project // SPDX-License-Identifier: BSD-3-Clause -use alloc::{format, str::from_utf8}; +use alloc::format; -use ledger_device_sdk::{ - io::Comm, - ui::gadgets::{MessageScroller, SingleMessage}, -}; -use tari_crypto::{ - keys::PublicKey, - ristretto::{ - pedersen::extended_commitment_factory::ExtendedPedersenCommitmentFactory, - RistrettoComAndPubSig, - RistrettoPublicKey, - RistrettoSecretKey, - }, - tari_utilities::{hex::Hex, ByteArray}, +use ledger_device_sdk::{io::Comm, ui::gadgets::SingleMessage}; +use tari_crypto::ristretto::{ + pedersen::extended_commitment_factory::ExtendedPedersenCommitmentFactory, + RistrettoComAndPubSig, + RistrettoSecretKey, }; use crate::{ alloc::string::ToString, - utils::{alpha_hasher, derive_from_bip32_key, get_key_from_canonical_bytes, special_hash, u64_to_string}, + utils::{alpha_hasher, derive_from_bip32_key, get_key_from_canonical_bytes}, AppSW, KeyType, RESPONSE_VERSION, @@ -82,20 +74,11 @@ pub fn handler_get_script_signature( let mut account_bytes = [0u8; 8]; account_bytes.clone_from_slice(&signer_ctx.payload[0..8]); signer_ctx.account = u64::from_le_bytes(account_bytes); - MessageScroller::new(&u64_to_string(signer_ctx.account)).event_loop(); let alpha = derive_from_bip32_key(signer_ctx.account, STATIC_ALPHA_INDEX, KeyType::Alpha)?; let blinding_factor: RistrettoSecretKey = get_key_from_canonical_bytes(&signer_ctx.payload[8..40])?; - let alpha_pk = RistrettoPublicKey::from_secret_key(&alpha); let script_private_key = alpha_hasher(alpha, blinding_factor)?; - let pk = RistrettoPublicKey::from_secret_key(&script_private_key); - - MessageScroller::new(&alpha_pk.to_string()).event_loop(); - MessageScroller::new(&pk.to_string()).event_loop(); - MessageScroller::new(&(&pk + alpha_pk).to_string()).event_loop(); - special_hash(); - let value: RistrettoSecretKey = get_key_from_canonical_bytes(&signer_ctx.payload[40..72])?; let spend_private_key: RistrettoSecretKey = get_key_from_canonical_bytes(&signer_ctx.payload[72..104])?; let r_a: RistrettoSecretKey = get_key_from_canonical_bytes(&signer_ctx.payload[104..136])?; diff --git a/applications/minotari_ledger_wallet/wallet/src/utils.rs b/applications/minotari_ledger_wallet/wallet/src/utils.rs index 39b0d7e9da..dda4c61086 100644 --- a/applications/minotari_ledger_wallet/wallet/src/utils.rs +++ b/applications/minotari_ledger_wallet/wallet/src/utils.rs @@ -8,14 +8,14 @@ use digest::consts::U64; use ledger_device_sdk::{ ecc::{bip32_derive, make_bip32_path, CurvesId, CxError}, io::SyscallError, - ui::gadgets::{MessageScroller, SingleMessage}, + ui::gadgets::SingleMessage, }; use tari_crypto::{ hash_domain, hashing::DomainSeparatedHasher, - keys::{PublicKey, SecretKey}, + keys::SecretKey, ristretto::{pedersen::PedersenCommitment, RistrettoPublicKey, RistrettoSecretKey}, - tari_utilities::{hex::Hex, ByteArray}, + tari_utilities::ByteArray, }; use zeroize::Zeroizing; @@ -248,11 +248,6 @@ pub fn derive_from_bip32_key( let index = u64_to_string(u64_index); let key_type = u64_to_string(u64_key_type.as_byte() as u64); - // MessageScroller::new(&"derive").event_loop(); - // MessageScroller::new(&account).event_loop(); - // MessageScroller::new(&index).event_loop(); - // MessageScroller::new(&key_type).event_loop(); - let mut bip32_path = "m/44'/".to_string(); bip32_path.push_str(&BIP32_COIN_TYPE.to_string()); bip32_path.push_str(&"'/"); @@ -281,13 +276,6 @@ pub fn finalize_metadata_signature_challenge( commitment: &PedersenCommitment, message: &[u8; 32], ) -> [u8; 64] { - // let network_str = u64_to_string(network); - // MessageScroller::new(&network_str).event_loop(); - // MessageScroller::new(&sender_offset_public_key.to_string()).event_loop(); - // MessageScroller::new(&ephemeral_commitment.as_public_key().to_string()).event_loop(); - // MessageScroller::new(&ephemeral_pubkey.to_string()).event_loop(); - // MessageScroller::new(&commitment.as_public_key().to_string()).event_loop(); - let challenge = DomainSeparatedConsensusHasher::>::new("metadata_signature", network) .chain(ephemeral_pubkey) @@ -299,13 +287,3 @@ pub fn finalize_metadata_signature_challenge( challenge.into() } - -pub fn special_hash() { - let hasher = DomainSeparatedHasher::, KeyManagerTransactionsHashDomain>::new_with_label("script key"); - let hasher = hasher.chain("test input".as_bytes()).finalize(); - let private_key = RistrettoSecretKey::from_uniform_bytes(hasher.as_ref()).unwrap(); - MessageScroller::new(&private_key.to_hex()).event_loop(); - let public_key = RistrettoPublicKey::from_secret_key(&private_key); - - MessageScroller::new(&public_key.to_string()).event_loop(); -} From 16648ceb47969a87d51262ac5f97cbd2769c1f57 Mon Sep 17 00:00:00 2001 From: brianp Date: Tue, 14 May 2024 17:11:09 -0700 Subject: [PATCH 43/49] Simplify the matching of public key fetching --- .../src/transactions/key_manager/inner.rs | 89 +++++++++---------- 1 file changed, 43 insertions(+), 46 deletions(-) diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index ed61d9bb22..94ce0fa13b 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -196,56 +196,53 @@ where TBackend: KeyManagerBackend + 'static pub async fn get_public_key_at_key_id(&self, key_id: &TariKeyId) -> Result { match key_id { - KeyId::Managed { branch, index } => match ( - branch == &TransactionKeyManagerBranch::MetadataEphemeralNonce.get_branch_key() || - branch == &TransactionKeyManagerBranch::SenderOffset.get_branch_key(), - &self.wallet_type, - ) { - #[allow(unused_variables)] // This is to avoid the code blocks where ledger isn't used - (true, WalletType::Ledger(ledger)) => { - #[cfg(not(feature = "ledger"))] - { - let km = self - .key_managers - .get(branch) - .ok_or(KeyManagerServiceError::UnknownKeyBranch)? - .read() - .await; - Ok(km.derive_public_key(*index)?.key) - } - - #[cfg(feature = "ledger")] + KeyId::Managed { branch, index } => { + // If we have the unique case of being a ledger wallet, and the key is a Managed EphemeralNonce, or + // SenderOffset than we fetch from the ledger, all other keys are fetched below. + #[allow(unused_variables)] + if let WalletType::Ledger(ledger) = &self.wallet_type { + if branch == &TransactionKeyManagerBranch::MetadataEphemeralNonce.get_branch_key() || + branch == &TransactionKeyManagerBranch::SenderOffset.get_branch_key() { - let transport = - get_transport().map_err(|e| KeyManagerServiceError::LedgerError(e.to_string()))?; - let mut data = index.to_le_bytes().to_vec(); - let branch_u8 = TransactionKeyManagerBranch::from_key(branch).as_byte(); - data.extend_from_slice(&u64::from(branch_u8).to_le_bytes()); - let command = ledger.build_command(Instruction::GetPublicKey, data); + #[cfg(not(feature = "ledger"))] + { + return Err(KeyManagerServiceError::LedgerError( + "Ledger is not supported".to_string(), + )); + } - match command.execute_with_transport(&transport) { - Ok(result) => { - debug!(target: LOG_TARGET, "result length: {}, data: {:?}", result.data().len(), result.data()); - if result.data().len() < 33 { - debug!(target: LOG_TARGET, "result less than 33"); - } - - PublicKey::from_canonical_bytes(&result.data()[1..33]) - .map_err(|e| KeyManagerServiceError::LedgerError(e.to_string())) - }, - Err(e) => Err(KeyManagerServiceError::LedgerError(e.to_string())), + #[cfg(feature = "ledger")] + { + let transport = + get_transport().map_err(|e| KeyManagerServiceError::LedgerError(e.to_string()))?; + let mut data = index.to_le_bytes().to_vec(); + let branch_u8 = TransactionKeyManagerBranch::from_key(branch).as_byte(); + data.extend_from_slice(&u64::from(branch_u8).to_le_bytes()); + let command = ledger.build_command(Instruction::GetPublicKey, data); + + match command.execute_with_transport(&transport) { + Ok(result) => { + debug!(target: LOG_TARGET, "result length: {}, data: {:?}", result.data().len(), result.data()); + if result.data().len() < 33 { + debug!(target: LOG_TARGET, "result less than 33"); + } + + return PublicKey::from_canonical_bytes(&result.data()[1..33]) + .map_err(|e| KeyManagerServiceError::LedgerError(e.to_string())); + }, + Err(e) => return Err(KeyManagerServiceError::LedgerError(e.to_string())), + } } } - }, - (_, _) => { - let km = self - .key_managers - .get(branch) - .ok_or(KeyManagerServiceError::UnknownKeyBranch)? - .read() - .await; - Ok(km.derive_public_key(*index)?.key) - }, + } + + let km = self + .key_managers + .get(branch) + .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .read() + .await; + Ok(km.derive_public_key(*index)?.key) }, KeyId::Derived { branch, label, index } => { let public_alpha = match &self.wallet_type { From ee4f0715c3df71a4e808ee382c9a5e1e1322ed75 Mon Sep 17 00:00:00 2001 From: brianp Date: Tue, 14 May 2024 17:15:12 -0700 Subject: [PATCH 44/49] Remove panic for proper error --- base_layer/core/src/transactions/key_manager/inner.rs | 2 +- base_layer/key_manager/src/key_manager_service/error.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index 94ce0fa13b..4eaccea127 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -422,7 +422,7 @@ where TBackend: KeyManagerBackend + 'static Ok(key) }, KeyId::Derived { branch, label, index } => match &self.wallet_type { - WalletType::Ledger(_) => panic!(), + WalletType::Ledger(_) => Err(KeyManagerServiceError::LedgerPrivateKeyInaccessible), WalletType::Software(k, _pk) => { let km = self .key_managers diff --git a/base_layer/key_manager/src/key_manager_service/error.rs b/base_layer/key_manager/src/key_manager_service/error.rs index c3cb9e3276..9d15bec776 100644 --- a/base_layer/key_manager/src/key_manager_service/error.rs +++ b/base_layer/key_manager/src/key_manager_service/error.rs @@ -51,6 +51,8 @@ pub enum KeyManagerServiceError { UnknownError(String), #[error("Ledger error: `{0}`")] LedgerError(String), + #[error("The Ledger private key cannot be access or read")] + LedgerPrivateKeyInaccessible, } impl From for KeyManagerServiceError { From 6a814ec85b576e0b395be1b8d9cde28c5c0f8666 Mon Sep 17 00:00:00 2001 From: brianp Date: Tue, 14 May 2024 17:28:54 -0700 Subject: [PATCH 45/49] Minor refactoring for readability and convention --- .../src/transactions/key_manager/inner.rs | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index 4eaccea127..e9c209b45b 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -740,23 +740,23 @@ where TBackend: KeyManagerBackend + 'static branch, label: _, index, - } => { - if let WalletType::Software(_, _) = self.wallet_type { + } => match &self.wallet_type { + WalletType::Software(_, _) => { total_script_private_key = total_script_private_key + self.get_private_key(script_key_id).await?; - continue; - } - - let km = self - .key_managers - .get(branch) - .ok_or(KeyManagerServiceError::UnknownKeyBranch)? - .read() - .await; - let branch_key = km - .get_private_key(*index) - .map_err(|e| TransactionError::KeyManagerError(e.to_string()))?; - derived_key_commitments.push(branch_key); + }, + WalletType::Ledger(_) => { + let km = self + .key_managers + .get(branch) + .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .read() + .await; + let branch_key = km + .get_private_key(*index) + .map_err(|e| TransactionError::KeyManagerError(e.to_string()))?; + derived_key_commitments.push(branch_key); + }, }, } } From aa9cae0b72a62795315c4f1100dcabda928cb0ce Mon Sep 17 00:00:00 2001 From: brianp Date: Wed, 15 May 2024 14:52:26 -0700 Subject: [PATCH 46/49] Upgrade tari-crypto to 0.20.1 --- .../minotari_ledger_wallet/wallet/Cargo.lock | 66 ++++++++++++------- .../minotari_ledger_wallet/wallet/Cargo.toml | 2 +- 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/applications/minotari_ledger_wallet/wallet/Cargo.lock b/applications/minotari_ledger_wallet/wallet/Cargo.lock index 32689bca1b..133d3565f8 100644 --- a/applications/minotari_ledger_wallet/wallet/Cargo.lock +++ b/applications/minotari_ledger_wallet/wallet/Cargo.lock @@ -103,6 +103,12 @@ dependencies = [ "syn_derive", ] +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "cc" version = "1.0.96" @@ -172,6 +178,23 @@ dependencies = [ "typenum", ] +[[package]] +name = "curve25519-dalek" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a677b8922c94e01bdbb12126b0bc852f00447528dee1782229af9c720c3f348" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "fiat-crypto", + "platforms", + "rand_core", + "rustc_version", + "subtle", + "zeroize", +] + [[package]] name = "curve25519-dalek-derive" version = "0.1.1" @@ -234,9 +257,9 @@ dependencies = [ [[package]] name = "fiat-crypto" -version = "0.1.20" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "generic-array" @@ -390,6 +413,18 @@ version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core", + "zeroize", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -398,7 +433,7 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "minotari_ledger_wallet" -version = "1.0.0-pre.11a" +version = "1.0.0-pre.13" dependencies = [ "blake2", "borsh", @@ -682,39 +717,24 @@ dependencies = [ "syn 2.0.60", ] -[[package]] -name = "tari-curve25519-dalek" -version = "4.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b8e2644aae57a832e475ebc31199ab1114ebd7fe4d2621e67e89bdd9c8ac38" -dependencies = [ - "cfg-if", - "cpufeatures", - "curve25519-dalek-derive", - "fiat-crypto", - "platforms", - "rand_core", - "rustc_version", - "subtle", - "zeroize", -] - [[package]] name = "tari_crypto" -version = "0.20.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63a3ed2c551101eb42b7f9386c207e28d53e6816f7b4c9a0883548922f317b3e" +checksum = "40833db37f54c3b176da3d07199c76ec7a062b19fbf74bf270d614804114ee58" dependencies = [ "blake2", "borsh", + "curve25519-dalek", "digest", "log", + "merlin", "once_cell", "rand_chacha", "rand_core", "sha3", "snafu", - "tari-curve25519-dalek", + "subtle", "tari_utilities", "zeroize", ] diff --git a/applications/minotari_ledger_wallet/wallet/Cargo.toml b/applications/minotari_ledger_wallet/wallet/Cargo.toml index 75cda8e9aa..0d2a7530be 100644 --- a/applications/minotari_ledger_wallet/wallet/Cargo.toml +++ b/applications/minotari_ledger_wallet/wallet/Cargo.toml @@ -13,7 +13,7 @@ digest = { version = "0.10", default-features = false } embedded-alloc = "0.5.0" include_gif = "1.0.1" ledger_device_sdk = "1.7.1" -tari_crypto = { version = "0.20.0", default-features = false, features = ["borsh"]} +tari_crypto = { version = "0.20.1", default-features = false, features = ["borsh"]} zeroize = { version = "1" , default-features = false } # once_cell defined here just to lock the version. Other dependencies may try to go to 1.19 which is incompatabile with From 5a04e0ab66928a7e0130734a8ad58c896d7fc6db Mon Sep 17 00:00:00 2001 From: brianp Date: Wed, 15 May 2024 14:54:08 -0700 Subject: [PATCH 47/49] Zeroize all the secret keys --- .../src/handlers/get_metadata_signature.rs | 7 ++++- .../wallet/src/handlers/get_script_offset.rs | 31 ++++++++++++------- .../src/handlers/get_script_signature.rs | 19 ++++++++---- .../wallet/src/utils.rs | 15 ++++----- 4 files changed, 46 insertions(+), 26 deletions(-) diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_metadata_signature.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_metadata_signature.rs index a05801b258..643fe5ac98 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_metadata_signature.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_metadata_signature.rs @@ -13,6 +13,7 @@ use tari_crypto::{ RistrettoSecretKey, }, }; +use zeroize::Zeroizing; use crate::{ alloc::string::ToString, @@ -54,7 +55,11 @@ pub fn handler_get_metadata_signature(comm: &mut Comm) -> Result<(), AppSW> { let ephemeral_private_key = derive_from_bip32_key(account, ephemeral_private_nonce_index, KeyType::Nonce)?; let ephemeral_pubkey = RistrettoPublicKey::from_secret_key(&ephemeral_private_key); - let sender_offset_private_key = derive_from_bip32_key(account, sender_offset_key_index, KeyType::SenderOffset)?; + let sender_offset_private_key = Zeroizing::new(derive_from_bip32_key( + account, + sender_offset_key_index, + KeyType::SenderOffset, + )?); let sender_offset_public_key = RistrettoPublicKey::from_secret_key(&sender_offset_private_key); let challenge = finalize_metadata_signature_challenge( diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs index ec2b8e768d..ff79c8cf75 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_offset.rs @@ -1,8 +1,11 @@ // Copyright 2024 The Tari Project // SPDX-License-Identifier: BSD-3-Clause +use core::ops::Deref; + use ledger_device_sdk::io::Comm; use tari_crypto::{ristretto::RistrettoSecretKey, tari_utilities::ByteArray}; +use zeroize::Zeroizing; use crate::{ utils::{alpha_hasher, derive_from_bip32_key, get_key_from_canonical_bytes}, @@ -13,8 +16,8 @@ use crate::{ }; pub struct ScriptOffsetCtx { - total_sender_offset_private_key: RistrettoSecretKey, - total_script_private_key: RistrettoSecretKey, + total_sender_offset_private_key: Zeroizing, + total_script_private_key: Zeroizing, account: u64, total_offset_indexes: u64, total_commitment_keys: u64, @@ -24,8 +27,8 @@ pub struct ScriptOffsetCtx { impl ScriptOffsetCtx { pub fn new() -> Self { Self { - total_sender_offset_private_key: RistrettoSecretKey::default(), - total_script_private_key: RistrettoSecretKey::default(), + total_sender_offset_private_key: Zeroizing::new(RistrettoSecretKey::default()), + total_script_private_key: Zeroizing::new(RistrettoSecretKey::default()), account: 0, total_offset_indexes: 0, total_commitment_keys: 0, @@ -34,8 +37,8 @@ impl ScriptOffsetCtx { // Implement reset for TxInfo fn reset(&mut self) { - self.total_sender_offset_private_key = RistrettoSecretKey::default(); - self.total_script_private_key = RistrettoSecretKey::default(); + self.total_sender_offset_private_key = Zeroizing::new(RistrettoSecretKey::default()); + self.total_script_private_key = Zeroizing::new(RistrettoSecretKey::default()); self.account = 0; self.total_offset_indexes = 0; self.total_commitment_keys = 0; @@ -81,8 +84,8 @@ pub fn handler_get_script_offset( if chunk == 1 { // The sum of managed private keys - let k: RistrettoSecretKey = get_key_from_canonical_bytes(&data[0..32])?; - offset_ctx.total_script_private_key = &offset_ctx.total_script_private_key + k; + let k: Zeroizing = get_key_from_canonical_bytes::(&data[0..32])?.into(); + offset_ctx.total_script_private_key = Zeroizing::new(offset_ctx.total_script_private_key.deref() + k.deref()); return Ok(()); } @@ -96,24 +99,28 @@ pub fn handler_get_script_offset( let index = u64::from_le_bytes(index_bytes); let offset = derive_from_bip32_key(offset_ctx.account, index, KeyType::SenderOffset)?; - offset_ctx.total_sender_offset_private_key = &offset_ctx.total_sender_offset_private_key + &offset; + offset_ctx.total_sender_offset_private_key = + Zeroizing::new(offset_ctx.total_sender_offset_private_key.deref() + offset.deref()); } let end_commitment_keys = end_offset_indexes + offset_ctx.total_commitment_keys; if (end_offset_indexes..end_commitment_keys).contains(&(chunk as u64)) { let alpha = derive_from_bip32_key(offset_ctx.account, STATIC_ALPHA_INDEX, KeyType::Alpha)?; - let blinding_factor: RistrettoSecretKey = get_key_from_canonical_bytes(&data[0..32])?; + let blinding_factor: Zeroizing = + get_key_from_canonical_bytes::(&data[0..32])?.into(); let k = alpha_hasher(alpha, blinding_factor)?; - offset_ctx.total_script_private_key = &offset_ctx.total_script_private_key + &k; + offset_ctx.total_script_private_key = Zeroizing::new(offset_ctx.total_script_private_key.deref() + k.deref()); } if more { return Ok(()); } - let script_offset = &offset_ctx.total_script_private_key - &offset_ctx.total_sender_offset_private_key; + let script_offset = Zeroizing::new( + offset_ctx.total_script_private_key.deref() - offset_ctx.total_sender_offset_private_key.deref(), + ); comm.append(&[RESPONSE_VERSION]); // version comm.append(&script_offset.to_vec()); diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs index af0abd371a..3a565b36fc 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_script_signature.rs @@ -9,6 +9,7 @@ use tari_crypto::ristretto::{ RistrettoComAndPubSig, RistrettoSecretKey, }; +use zeroize::Zeroizing; use crate::{ alloc::string::ToString, @@ -76,14 +77,20 @@ pub fn handler_get_script_signature( signer_ctx.account = u64::from_le_bytes(account_bytes); let alpha = derive_from_bip32_key(signer_ctx.account, STATIC_ALPHA_INDEX, KeyType::Alpha)?; - let blinding_factor: RistrettoSecretKey = get_key_from_canonical_bytes(&signer_ctx.payload[8..40])?; + let blinding_factor: Zeroizing = + get_key_from_canonical_bytes::(&signer_ctx.payload[8..40])?.into(); let script_private_key = alpha_hasher(alpha, blinding_factor)?; - let value: RistrettoSecretKey = get_key_from_canonical_bytes(&signer_ctx.payload[40..72])?; - let spend_private_key: RistrettoSecretKey = get_key_from_canonical_bytes(&signer_ctx.payload[72..104])?; - let r_a: RistrettoSecretKey = get_key_from_canonical_bytes(&signer_ctx.payload[104..136])?; - let r_x: RistrettoSecretKey = get_key_from_canonical_bytes(&signer_ctx.payload[136..168])?; - let r_y: RistrettoSecretKey = get_key_from_canonical_bytes(&signer_ctx.payload[168..200])?; + let value: Zeroizing = + get_key_from_canonical_bytes::(&signer_ctx.payload[40..72])?.into(); + let spend_private_key: Zeroizing = + get_key_from_canonical_bytes::(&signer_ctx.payload[72..104])?.into(); + let r_a: Zeroizing = + get_key_from_canonical_bytes::(&signer_ctx.payload[104..136])?.into(); + let r_x: Zeroizing = + get_key_from_canonical_bytes::(&signer_ctx.payload[136..168])?.into(); + let r_y: Zeroizing = + get_key_from_canonical_bytes::(&signer_ctx.payload[168..200])?.into(); let challenge = &signer_ctx.payload[200..264]; let factory = ExtendedPedersenCommitmentFactory::default(); diff --git a/applications/minotari_ledger_wallet/wallet/src/utils.rs b/applications/minotari_ledger_wallet/wallet/src/utils.rs index dda4c61086..a4ff709bd1 100644 --- a/applications/minotari_ledger_wallet/wallet/src/utils.rs +++ b/applications/minotari_ledger_wallet/wallet/src/utils.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: BSD-3-Clause use alloc::format; +use core::ops::Deref; use blake2::{Blake2b, Digest}; use digest::consts::U64; @@ -196,9 +197,9 @@ pub fn get_raw_key(path: &[u32]) -> Result, SyscallError> { } } -pub fn get_key_from_uniform_bytes(bytes: &[u8]) -> Result { +pub fn get_key_from_uniform_bytes(bytes: &[u8]) -> Result, AppSW> { match RistrettoSecretKey::from_uniform_bytes(bytes) { - Ok(val) => Ok(val), + Ok(val) => Ok(Zeroizing::new(val)), Err(e) => { SingleMessage::new(&format!( "Err: key conversion {:?}. Length: {:?}", @@ -229,21 +230,21 @@ pub fn get_key_from_canonical_bytes(bytes: &[u8]) -> Result Result { + alpha: Zeroizing, + blinding_factor: Zeroizing, +) -> Result, AppSW> { let hasher = DomainSeparatedHasher::, KeyManagerTransactionsHashDomain>::new_with_label("script key"); let hasher = hasher.chain(blinding_factor.as_bytes()).finalize(); let private_key = get_key_from_uniform_bytes(hasher.as_ref())?; - Ok(private_key + alpha) + Ok(Zeroizing::new(private_key.deref() + alpha.deref())) } pub fn derive_from_bip32_key( u64_account: u64, u64_index: u64, u64_key_type: KeyType, -) -> Result { +) -> Result, AppSW> { let account = u64_to_string(u64_account); let index = u64_to_string(u64_index); let key_type = u64_to_string(u64_key_type.as_byte() as u64); From 43a1df5672e6f514e37b13f8ee1f90862e0f93af Mon Sep 17 00:00:00 2001 From: brianp Date: Wed, 15 May 2024 14:54:24 -0700 Subject: [PATCH 48/49] Add additional custom error type --- .../wallet/src/handlers/get_metadata_signature.rs | 2 +- applications/minotari_ledger_wallet/wallet/src/main.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_metadata_signature.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_metadata_signature.rs index 643fe5ac98..c727f48e52 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_metadata_signature.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_metadata_signature.rs @@ -87,7 +87,7 @@ pub fn handler_get_metadata_signature(comm: &mut Comm) -> Result<(), AppSW> { Ok(sig) => sig, Err(e) => { SingleMessage::new(&format!("Signing error: {:?}", e.to_string())).show_and_wait(); - return Err(AppSW::ScriptSignatureFail); + return Err(AppSW::MetadataSignatureFail); }, }; diff --git a/applications/minotari_ledger_wallet/wallet/src/main.rs b/applications/minotari_ledger_wallet/wallet/src/main.rs index 106021eaf3..f3a7dd5243 100644 --- a/applications/minotari_ledger_wallet/wallet/src/main.rs +++ b/applications/minotari_ledger_wallet/wallet/src/main.rs @@ -90,11 +90,12 @@ pub enum AppSW { InsNotSupported = 0x6D00, ClaNotSupported = 0x6E00, ScriptSignatureFail = 0xB001, + MetadataSignatureFail = 0xB002, KeyDeriveFail = 0xB009, KeyDeriveFromCanonical = 0xB010, KeyDeriveFromUniform = 0xB011, VersionParsingFail = 0xB00A, - TooManyPayloads = 0xB002, + TooManyPayloads = 0xB003, WrongApduLength = StatusWords::BadLen as u16, } From 147d5b9d35209f41ca3b889e2902e8d15dcc856c Mon Sep 17 00:00:00 2001 From: brianp Date: Wed, 15 May 2024 15:01:47 -0700 Subject: [PATCH 49/49] update tests --- .../core/tests/tests/node_comms_interface.rs | 14 ++++++++----- .../output_manager_service_tests/service.rs | 15 ++++++++++---- .../transaction_service_tests/storage.rs | 20 +++++++++++++------ 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/base_layer/core/tests/tests/node_comms_interface.rs b/base_layer/core/tests/tests/node_comms_interface.rs index 91463d9062..1b03c14cdd 100644 --- a/base_layer/core/tests/tests/node_comms_interface.rs +++ b/base_layer/core/tests/tests/node_comms_interface.rs @@ -46,6 +46,7 @@ use tari_core::{ MemoryDbKeyManager, TransactionKeyManagerBranch, TransactionKeyManagerInterface, + TransactionKeyManagerLabel, }, tari_amount::MicroMinotari, test_helpers::{create_utxo, TestParams, TransactionSchema}, @@ -63,7 +64,7 @@ use tari_core::{ validation::{mocks::MockValidator, transaction::TransactionChainLinkedValidator}, OutputSmt, }; -use tari_key_manager::key_manager_service::KeyManagerInterface; +use tari_key_manager::key_manager_service::{KeyId, KeyManagerInterface}; use tari_script::{inputs, script, ExecutionStack}; use tari_service_framework::reply_channel; use tokio::sync::{broadcast, mpsc}; @@ -303,10 +304,13 @@ async fn initialize_sender_transaction_protocol_for_overflow_test( .get_next_key(TransactionKeyManagerBranch::SenderOffset.get_branch_key()) .await .unwrap(); - let (script_key_id, _) = key_manager - .get_next_key(TransactionKeyManagerBranch::CommitmentMask.get_branch_key()) - .await - .unwrap(); + + let script_key_id = KeyId::Derived { + branch: TransactionKeyManagerBranch::CommitmentMask.get_branch_key(), + label: TransactionKeyManagerLabel::ScriptKey.get_branch_key(), + index: spending_key.managed_index().unwrap(), + }; + let script_public_key = key_manager.get_public_key_at_key_id(&script_key_id).await.unwrap(); let input_data = match &txn_schema.input_data { Some(data) => data.clone(), diff --git a/base_layer/wallet/tests/output_manager_service_tests/service.rs b/base_layer/wallet/tests/output_manager_service_tests/service.rs index 3e8b737a92..91b61ba84e 100644 --- a/base_layer/wallet/tests/output_manager_service_tests/service.rs +++ b/base_layer/wallet/tests/output_manager_service_tests/service.rs @@ -66,6 +66,7 @@ use tari_core::{ MemoryDbKeyManager, TransactionKeyManagerBranch, TransactionKeyManagerInterface, + TransactionKeyManagerLabel, }, tari_amount::{uT, MicroMinotari, T}, test_helpers::{create_wallet_output_with_data, TestParams}, @@ -76,7 +77,7 @@ use tari_core::{ SenderTransactionProtocol, }, }; -use tari_key_manager::key_manager_service::KeyManagerInterface; +use tari_key_manager::key_manager_service::{KeyId, KeyManagerInterface}; use tari_script::{inputs, script, TariScript}; use tari_service_framework::reply_channel; use tari_shutdown::Shutdown; @@ -2176,11 +2177,17 @@ async fn scan_for_recovery_test() { .get_next_key(TransactionKeyManagerBranch::CommitmentMask.get_branch_key()) .await .unwrap(); - let (script_key, public_script_key) = oms + let script_key_id = KeyId::Derived { + branch: TransactionKeyManagerBranch::CommitmentMask.get_branch_key(), + label: TransactionKeyManagerLabel::ScriptKey.get_branch_key(), + index: spending_key_result.managed_index().unwrap(), + }; + let public_script_key = oms .key_manager_handle - .get_next_key(TransactionKeyManagerBranch::CommitmentMask.get_branch_key()) + .get_public_key_at_key_id(&script_key_id) .await .unwrap(); + let amount = 1_000 * i as u64; let features = OutputFeatures::default(); let encrypted_data = oms @@ -2195,7 +2202,7 @@ async fn scan_for_recovery_test() { features, script!(Nop), inputs!(public_script_key), - script_key, + script_key_id, PublicKey::default(), ComAndPubSignature::default(), 0, diff --git a/base_layer/wallet/tests/transaction_service_tests/storage.rs b/base_layer/wallet/tests/transaction_service_tests/storage.rs index bbd7e873f2..19a0cc1004 100644 --- a/base_layer/wallet/tests/transaction_service_tests/storage.rs +++ b/base_layer/wallet/tests/transaction_service_tests/storage.rs @@ -50,7 +50,12 @@ use tari_common_types::{ use tari_core::{ covenants::Covenant, transactions::{ - key_manager::{create_memory_db_key_manager, TransactionKeyManagerBranch, TransactionKeyManagerInterface}, + key_manager::{ + create_memory_db_key_manager, + TransactionKeyManagerBranch, + TransactionKeyManagerInterface, + TransactionKeyManagerLabel, + }, tari_amount::{uT, MicroMinotari}, test_helpers::{create_wallet_output_with_data, TestParams}, transaction_components::{ @@ -67,7 +72,7 @@ use tari_core::{ }, }; use tari_crypto::keys::{PublicKey as PublicKeyTrait, SecretKey as SecretKeyTrait}; -use tari_key_manager::key_manager_service::KeyManagerInterface; +use tari_key_manager::key_manager_service::{KeyId, KeyManagerInterface}; use tari_script::{inputs, script}; use tari_test_utils::random; use tempfile::tempdir; @@ -179,10 +184,13 @@ pub async fn test_db_backend(backend: T) { .get_next_key(TransactionKeyManagerBranch::CommitmentMask.get_branch_key()) .await .unwrap(); - let (script_key_id, public_script_key) = key_manager - .get_next_key(TransactionKeyManagerBranch::CommitmentMask.get_branch_key()) - .await - .unwrap(); + let script_key_id = KeyId::Derived { + branch: TransactionKeyManagerBranch::CommitmentMask.get_branch_key(), + label: TransactionKeyManagerLabel::ScriptKey.get_branch_key(), + index: spending_key_id.managed_index().unwrap(), + }; + let public_script_key = key_manager.get_public_key_at_key_id(&script_key_id).await.unwrap(); + let encrypted_data = key_manager .encrypt_data_for_recovery(&spending_key_id, None, sender.amount.as_u64()) .await